Add partial support for array of samplers, and add pass to identify them from bindless texture accesses
This commit is contained in:
parent
63345a3098
commit
3ab5c23f49
10 changed files with 210 additions and 39 deletions
|
@ -670,7 +670,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
private static Target GetTarget(SamplerType type)
|
private static Target GetTarget(SamplerType type)
|
||||||
{
|
{
|
||||||
type &= ~SamplerType.Shadow;
|
type &= ~(SamplerType.Indexed | SamplerType.Shadow);
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
|
|
@ -231,7 +231,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
foreach (AstTextureOperation texOp in info.Samplers.OrderBy(x => x.Handle))
|
foreach (AstTextureOperation texOp in info.Samplers.OrderBy(x => x.Handle))
|
||||||
{
|
{
|
||||||
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp);
|
string indexExpr = NumberFormatter.FormatInt(texOp.ArraySize);
|
||||||
|
|
||||||
|
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
if (!samplers.TryAdd(samplerName, texOp))
|
if (!samplers.TryAdd(samplerName, texOp))
|
||||||
{
|
{
|
||||||
|
@ -257,12 +259,25 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
desc = new TextureDescriptor(samplerName, texOp.Type, operand.CbufSlot, operand.CbufOffset);
|
desc = new TextureDescriptor(samplerName, texOp.Type, operand.CbufSlot, operand.CbufOffset);
|
||||||
}
|
}
|
||||||
|
else if ((texOp.Type & SamplerType.Indexed) != 0)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < texOp.ArraySize; index++)
|
||||||
|
{
|
||||||
|
string indexExpr = NumberFormatter.FormatInt(index);
|
||||||
|
|
||||||
|
string indexedSamplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
|
desc = new TextureDescriptor(indexedSamplerName, texOp.Type, texOp.Handle + index * 2);
|
||||||
|
|
||||||
|
context.TextureDescriptors.Add(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
desc = new TextureDescriptor(samplerName, texOp.Type, texOp.Handle);
|
desc = new TextureDescriptor(samplerName, texOp.Type, texOp.Handle);
|
||||||
}
|
|
||||||
|
|
||||||
context.TextureDescriptors.Add(desc);
|
context.TextureDescriptors.Add(desc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +287,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
foreach (AstTextureOperation texOp in info.Images.OrderBy(x => x.Handle))
|
foreach (AstTextureOperation texOp in info.Images.OrderBy(x => x.Handle))
|
||||||
{
|
{
|
||||||
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp);
|
string indexExpr = NumberFormatter.FormatInt(texOp.ArraySize);
|
||||||
|
|
||||||
|
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
if (!images.TryAdd(imageName, texOp))
|
if (!images.TryAdd(imageName, texOp))
|
||||||
{
|
{
|
||||||
|
@ -290,9 +307,25 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
AstTextureOperation texOp = kv.Value;
|
AstTextureOperation texOp = kv.Value;
|
||||||
|
|
||||||
TextureDescriptor desc = new TextureDescriptor(imageName, texOp.Type, texOp.Handle);
|
if ((texOp.Type & SamplerType.Indexed) != 0)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < texOp.ArraySize; index++)
|
||||||
|
{
|
||||||
|
string indexExpr = NumberFormatter.FormatInt(index);
|
||||||
|
|
||||||
context.ImageDescriptors.Add(desc);
|
string indexedSamplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
|
var desc = new TextureDescriptor(indexedSamplerName, texOp.Type, texOp.Handle + index * 2);
|
||||||
|
|
||||||
|
context.TextureDescriptors.Add(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var desc = new TextureDescriptor(imageName, texOp.Type, texOp.Handle);
|
||||||
|
|
||||||
|
context.ImageDescriptors.Add(desc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,26 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
|
|
||||||
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
||||||
|
|
||||||
bool isArray = (texOp.Type & SamplerType.Array) != 0;
|
bool isArray = (texOp.Type & SamplerType.Array) != 0;
|
||||||
|
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
|
||||||
|
|
||||||
string texCall = "imageStore";
|
string texCall = "imageStore";
|
||||||
|
|
||||||
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp);
|
int srcIndex = isBindless ? 1 : 0;
|
||||||
|
|
||||||
|
string Src(VariableType type)
|
||||||
|
{
|
||||||
|
return GetSoureExpr(context, texOp.GetSource(srcIndex++), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
string indexExpr = null;
|
||||||
|
|
||||||
|
if (isIndexed)
|
||||||
|
{
|
||||||
|
indexExpr = Src(VariableType.S32);
|
||||||
|
}
|
||||||
|
|
||||||
|
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
texCall += "(" + imageName;
|
texCall += "(" + imageName;
|
||||||
|
|
||||||
|
@ -34,13 +49,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
arrayIndexElem = pCount++;
|
arrayIndexElem = pCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int srcIndex = isBindless ? 1 : 0;
|
|
||||||
|
|
||||||
string Src(VariableType type)
|
|
||||||
{
|
|
||||||
return GetSoureExpr(context, texOp.GetSource(srcIndex++), type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Append(string str)
|
void Append(string str)
|
||||||
{
|
{
|
||||||
texCall += ", " + str;
|
texCall += ", " + str;
|
||||||
|
@ -174,6 +182,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0;
|
bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0;
|
||||||
|
|
||||||
bool isArray = (texOp.Type & SamplerType.Array) != 0;
|
bool isArray = (texOp.Type & SamplerType.Array) != 0;
|
||||||
|
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
|
||||||
bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0;
|
bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0;
|
||||||
bool isShadow = (texOp.Type & SamplerType.Shadow) != 0;
|
bool isShadow = (texOp.Type & SamplerType.Shadow) != 0;
|
||||||
|
|
||||||
|
@ -209,7 +218,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
texCall += "Offsets";
|
texCall += "Offsets";
|
||||||
}
|
}
|
||||||
|
|
||||||
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp);
|
int srcIndex = isBindless ? 1 : 0;
|
||||||
|
|
||||||
|
string Src(VariableType type)
|
||||||
|
{
|
||||||
|
return GetSoureExpr(context, texOp.GetSource(srcIndex++), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
string indexExpr = null;
|
||||||
|
|
||||||
|
if (isIndexed)
|
||||||
|
{
|
||||||
|
indexExpr = Src(VariableType.S32);
|
||||||
|
}
|
||||||
|
|
||||||
|
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
texCall += "(" + samplerName;
|
texCall += "(" + samplerName;
|
||||||
|
|
||||||
|
@ -249,13 +272,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
hasExtraCompareArg = true;
|
hasExtraCompareArg = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int srcIndex = isBindless ? 1 : 0;
|
|
||||||
|
|
||||||
string Src(VariableType type)
|
|
||||||
{
|
|
||||||
return GetSoureExpr(context, texOp.GetSource(srcIndex++), type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Append(string str)
|
void Append(string str)
|
||||||
{
|
{
|
||||||
texCall += ", " + str;
|
texCall += ", " + str;
|
||||||
|
@ -395,11 +411,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
{
|
{
|
||||||
AstTextureOperation texOp = (AstTextureOperation)operation;
|
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||||
|
|
||||||
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
||||||
|
|
||||||
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp);
|
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
|
||||||
|
|
||||||
IAstNode src0 = operation.GetSource(isBindless ? 1 : 0);
|
string indexExpr = null;
|
||||||
|
|
||||||
|
if (isIndexed)
|
||||||
|
{
|
||||||
|
indexExpr = GetSoureExpr(context, texOp.GetSource(0), VariableType.S32);
|
||||||
|
}
|
||||||
|
|
||||||
|
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
|
IAstNode src0 = operation.GetSource(isBindless || isIndexed ? 1 : 0);
|
||||||
|
|
||||||
string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0));
|
string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0));
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
return ubName + "_" + DefaultNames.UniformNameSuffix;
|
return ubName + "_" + DefaultNames.UniformNameSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp)
|
public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
|
||||||
{
|
{
|
||||||
string suffix;
|
string suffix;
|
||||||
|
|
||||||
|
@ -235,16 +235,26 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
suffix = (texOp.Handle - 8).ToString();
|
suffix = texOp.Handle.ToString();
|
||||||
|
|
||||||
|
if ((texOp.Type & SamplerType.Indexed) != 0)
|
||||||
|
{
|
||||||
|
suffix += $"a[{indexExpr}]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetShaderStagePrefix(stage) + "_" + DefaultNames.SamplerNamePrefix + suffix;
|
return GetShaderStagePrefix(stage) + "_" + DefaultNames.SamplerNamePrefix + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetImageName(ShaderStage stage, AstTextureOperation texOp)
|
public static string GetImageName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
|
||||||
{
|
{
|
||||||
string suffix = texOp.Handle.ToString();
|
string suffix = texOp.Handle.ToString();
|
||||||
|
|
||||||
|
if ((texOp.Type & SamplerType.Indexed) != 0)
|
||||||
|
{
|
||||||
|
suffix += $"a[{indexExpr}]";
|
||||||
|
}
|
||||||
|
|
||||||
return GetShaderStagePrefix(stage) + "_" + DefaultNames.ImageNamePrefix + suffix;
|
return GetShaderStagePrefix(stage) + "_" + DefaultNames.ImageNamePrefix + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
{
|
{
|
||||||
class TextureOperation : Operation
|
class TextureOperation : Operation
|
||||||
{
|
{
|
||||||
public SamplerType Type { get; }
|
public SamplerType Type { get; private set; }
|
||||||
public TextureFlags Flags { get; }
|
public TextureFlags Flags { get; private set; }
|
||||||
|
|
||||||
public int Handle { get; }
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
public TextureOperation(
|
public TextureOperation(
|
||||||
Instruction inst,
|
Instruction inst,
|
||||||
|
@ -20,5 +20,14 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
Handle = handle;
|
Handle = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TurnIntoIndexed(int handle)
|
||||||
|
{
|
||||||
|
Type |= SamplerType.Indexed;
|
||||||
|
|
||||||
|
Flags &= ~TextureFlags.Bindless;
|
||||||
|
|
||||||
|
Handle = handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,8 +14,9 @@ namespace Ryujinx.Graphics.Shader
|
||||||
Mask = 0xff,
|
Mask = 0xff,
|
||||||
|
|
||||||
Array = 1 << 8,
|
Array = 1 << 8,
|
||||||
Multisample = 1 << 9,
|
Indexed = 1 << 9,
|
||||||
Shadow = 1 << 10
|
Multisample = 1 << 10,
|
||||||
|
Shadow = 1 << 11
|
||||||
}
|
}
|
||||||
|
|
||||||
static class SamplerTypeExtensions
|
static class SamplerTypeExtensions
|
||||||
|
|
|
@ -7,19 +7,22 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
public SamplerType Type { get; }
|
public SamplerType Type { get; }
|
||||||
public TextureFlags Flags { get; }
|
public TextureFlags Flags { get; }
|
||||||
|
|
||||||
public int Handle { get; }
|
public int Handle { get; }
|
||||||
|
public int ArraySize { get; }
|
||||||
|
|
||||||
public AstTextureOperation(
|
public AstTextureOperation(
|
||||||
Instruction inst,
|
Instruction inst,
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
int handle,
|
int handle,
|
||||||
|
int arraySize,
|
||||||
int compMask,
|
int compMask,
|
||||||
params IAstNode[] sources) : base(inst, compMask, sources)
|
params IAstNode[] sources) : base(inst, compMask, sources)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
Handle = handle;
|
Handle = handle;
|
||||||
|
ArraySize = arraySize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -60,6 +60,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Flags,
|
texOp.Flags,
|
||||||
texOp.Handle,
|
texOp.Handle,
|
||||||
|
4, // TODO: Non-hardcoded array size.
|
||||||
componentMask,
|
componentMask,
|
||||||
sources);
|
sources);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
{
|
||||||
|
static class BindlessToIndexed
|
||||||
|
{
|
||||||
|
private const int StorageDescsBaseOffset = 0x44; // In words.
|
||||||
|
|
||||||
|
private const int UbeStorageDescsBaseOffset = 0x84; // In words.
|
||||||
|
private const int UbeStorageMaxCount = 14;
|
||||||
|
|
||||||
|
private const int StorageDescSize = 4; // In words.
|
||||||
|
private const int StorageMaxCount = 16;
|
||||||
|
|
||||||
|
private const int StorageDescsSize = StorageDescSize * StorageMaxCount;
|
||||||
|
|
||||||
|
public static void RunPass(BasicBlock block)
|
||||||
|
{
|
||||||
|
// We can turn a bindless texture access into a indexed access,
|
||||||
|
// as long the following conditions are true:
|
||||||
|
// - The handle is loaded using a LDC instruction.
|
||||||
|
// - The handle is loaded from the constant buffer with the handles (CB2 for NVN).
|
||||||
|
// - The load has a constant offset.
|
||||||
|
// The base offset of the array of handles on the constant buffer is the constant offset.
|
||||||
|
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
if (!(node.Value is TextureOperation texOp))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((texOp.Flags & TextureFlags.Bindless) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(texOp.GetSource(0).AsgOp is Operation handleAsgOp))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handleAsgOp.Inst != Instruction.LoadConstant)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand ldcSrc0 = handleAsgOp.GetSource(0);
|
||||||
|
Operand ldcSrc1 = handleAsgOp.GetSource(1);
|
||||||
|
|
||||||
|
if (ldcSrc0.Type != OperandType.Constant || ldcSrc0.Value != 2)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ldcSrc1.AsgOp is Operation addOp))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand addSrc1 = addOp.GetSource(1);
|
||||||
|
|
||||||
|
if (addSrc1.Type != OperandType.Constant)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
texOp.TurnIntoIndexed(addSrc1.Value);
|
||||||
|
|
||||||
|
Operand index = Local();
|
||||||
|
|
||||||
|
Operand source = addOp.GetSource(0);
|
||||||
|
|
||||||
|
Operation shrBy1 = new Operation(Instruction.ShiftRightU32, index, source, Const(1));
|
||||||
|
|
||||||
|
block.Operations.AddBefore(node, shrBy1);
|
||||||
|
|
||||||
|
texOp.SetSource(0, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,6 +84,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (modified);
|
while (modified);
|
||||||
|
|
||||||
|
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
|
||||||
|
{
|
||||||
|
BindlessToIndexed.RunPass(blocks[blkIndex]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PropagateCopy(Operation copyOp)
|
private static void PropagateCopy(Operation copyOp)
|
||||||
|
|
Loading…
Reference in a new issue