Simplify logic for bindless texture handling (#1667)

* Simplify logic for bindless texture handling

* Nits
This commit is contained in:
gdkchan 2020-11-09 19:35:04 -03:00 committed by GitHub
parent eda6b78894
commit 934a78005e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 131 additions and 191 deletions

View file

@ -111,20 +111,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
Target target = ShaderTexture.GetTarget(descriptor.Type); Target target = ShaderTexture.GetTarget(descriptor.Type);
if (descriptor.IsBindless)
{
textureBindings[index] = new TextureBindingInfo( textureBindings[index] = new TextureBindingInfo(
target, target,
descriptor.Binding, descriptor.Binding,
descriptor.CbufOffset,
descriptor.CbufSlot, descriptor.CbufSlot,
descriptor.HandleIndex,
descriptor.Flags); descriptor.Flags);
} }
else
{
textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags);
}
}
TextureManager.SetComputeTextures(textureBindings); TextureManager.SetComputeTextures(textureBindings);
@ -137,7 +130,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
Target target = ShaderTexture.GetTarget(descriptor.Type); Target target = ShaderTexture.GetTarget(descriptor.Type);
Format format = ShaderTexture.GetFormat(descriptor.Format); Format format = ShaderTexture.GetFormat(descriptor.Format);
imageBindings[index] = new TextureBindingInfo(target, format, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags); imageBindings[index] = new TextureBindingInfo(
target,
format,
descriptor.Binding,
descriptor.CbufSlot,
descriptor.HandleIndex,
descriptor.Flags);
} }
TextureManager.SetComputeImages(imageBindings); TextureManager.SetComputeImages(imageBindings);

View file

@ -1024,14 +1024,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
Target target = ShaderTexture.GetTarget(descriptor.Type); Target target = ShaderTexture.GetTarget(descriptor.Type);
if (descriptor.IsBindless) textureBindings[index] = new TextureBindingInfo(
{ target,
textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.CbufSlot, descriptor.CbufOffset, descriptor.Flags); descriptor.Binding,
} descriptor.CbufSlot,
else descriptor.HandleIndex,
{ descriptor.Flags);
textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags);
}
} }
TextureManager.SetGraphicsTextures(stage, textureBindings); TextureManager.SetGraphicsTextures(stage, textureBindings);
@ -1045,7 +1043,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
Target target = ShaderTexture.GetTarget(descriptor.Type); Target target = ShaderTexture.GetTarget(descriptor.Type);
Format format = ShaderTexture.GetFormat(descriptor.Format); Format format = ShaderTexture.GetFormat(descriptor.Format);
imageBindings[index] = new TextureBindingInfo(target, format, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags); imageBindings[index] = new TextureBindingInfo(
target,
format,
descriptor.Binding,
descriptor.CbufSlot,
descriptor.HandleIndex,
descriptor.Flags);
} }
TextureManager.SetGraphicsImages(stage, imageBindings); TextureManager.SetGraphicsImages(stage, imageBindings);

View file

@ -25,28 +25,14 @@ namespace Ryujinx.Graphics.Gpu.Image
public int Binding { get; } public int Binding { get; }
/// <summary> /// <summary>
/// Shader texture handle. /// Constant buffer slot with the texture handle.
/// This is an index into the texture constant buffer.
/// </summary>
public int Handle { get; }
/// <summary>
/// Indicates if the texture is a bindless texture.
/// </summary>
/// <remarks>
/// For those textures, Handle is ignored.
/// </remarks>
public bool IsBindless { get; }
/// <summary>
/// Constant buffer slot with the bindless texture handle, for bindless texture.
/// </summary> /// </summary>
public int CbufSlot { get; } public int CbufSlot { get; }
/// <summary> /// <summary>
/// Constant buffer offset of the bindless texture handle, for bindless texture. /// Index of the texture handle on the constant buffer at slot <see cref="CbufSlot"/>.
/// </summary> /// </summary>
public int CbufOffset { get; } public int Handle { get; }
/// <summary> /// <summary>
/// Flags from the texture descriptor that indicate how the texture is used. /// Flags from the texture descriptor that indicate how the texture is used.
@ -59,20 +45,16 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="target">The shader sampler target type</param> /// <param name="target">The shader sampler target type</param>
/// <param name="format">Format of the image as declared on the shader</param> /// <param name="format">Format of the image as declared on the shader</param>
/// <param name="binding">The shader texture binding point</param> /// <param name="binding">The shader texture binding point</param>
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param> /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param> /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
public TextureBindingInfo(Target target, Format format, int binding, int handle, TextureUsageFlags flags) public TextureBindingInfo(Target target, Format format, int binding, int cbufSlot, int handle, TextureUsageFlags flags)
{ {
Target = target; Target = target;
Format = format; Format = format;
Binding = binding; Binding = binding;
CbufSlot = cbufSlot;
Handle = handle; Handle = handle;
IsBindless = false;
CbufSlot = 0;
CbufOffset = 0;
Flags = flags; Flags = flags;
} }
@ -81,33 +63,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
/// <param name="target">The shader sampler target type</param> /// <param name="target">The shader sampler target type</param>
/// <param name="binding">The shader texture binding point</param> /// <param name="binding">The shader texture binding point</param>
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param> /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param> /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
public TextureBindingInfo(Target target, int binding, int handle, TextureUsageFlags flags) : this(target, (Format)0, binding, handle, flags) public TextureBindingInfo(Target target, int binding, int cbufSlot, int handle, TextureUsageFlags flags) : this(target, (Format)0, binding, cbufSlot, handle, flags)
{ {
} }
/// <summary>
/// Constructs the bindless texture binding information structure.
/// </summary>
/// <param name="target">The shader sampler target type</param>
/// <param name="binding">The shader texture binding point</param>
/// <param name="cbufSlot">Constant buffer slot where the bindless texture handle is located</param>
/// <param name="cbufOffset">Constant buffer offset of the bindless texture handle</param>
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
public TextureBindingInfo(Target target, int binding, int cbufSlot, int cbufOffset, TextureUsageFlags flags)
{
Target = target;
Format = 0;
Binding = binding;
Handle = 0;
IsBindless = true;
CbufSlot = cbufSlot;
CbufOffset = cbufOffset;
Flags = flags;
}
} }
} }

View file

@ -267,30 +267,9 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index]; TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index];
int packedId; int textureBufferIndex = bindingInfo.CbufSlot < 0 ? _textureBufferIndex : bindingInfo.CbufSlot;
if (bindingInfo.IsBindless)
{
ulong address;
var bufferManager = _context.Methods.BufferManager;
if (_isCompute)
{
address = bufferManager.GetComputeUniformBufferAddress(bindingInfo.CbufSlot);
}
else
{
address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, bindingInfo.CbufSlot);
}
packedId = _context.PhysicalMemory.Read<int>(address + (ulong)bindingInfo.CbufOffset * 4);
}
else
{
packedId = ReadPackedId(stageIndex, bindingInfo.Handle, _textureBufferIndex);
}
int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex);
int textureId = UnpackTextureId(packedId); int textureId = UnpackTextureId(packedId);
int samplerId; int samplerId;
@ -361,7 +340,9 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index]; TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index];
int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, _textureBufferIndex); int textureBufferIndex = bindingInfo.CbufSlot < 0 ? _textureBufferIndex : bindingInfo.CbufSlot;
int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex);
int textureId = UnpackTextureId(packedId); int textureId = UnpackTextureId(packedId);
Texture texture = pool.Get(textureId); Texture texture = pool.Get(textureId);

View file

@ -86,18 +86,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
private int FindDescriptorIndex(List<TextureDescriptor> list, AstTextureOperation texOp) private int FindDescriptorIndex(List<TextureDescriptor> list, AstTextureOperation texOp)
{ {
AstOperand operand = texOp.GetSource(0) as AstOperand;
bool bindless = (texOp.Flags & TextureFlags.Bindless) > 0;
int cBufSlot = bindless ? operand.CbufSlot : 0;
int cBufOffset = bindless ? operand.CbufOffset : 0;
return list.FindIndex(descriptor => return list.FindIndex(descriptor =>
descriptor.Type == texOp.Type && descriptor.Type == texOp.Type &&
descriptor.CbufSlot == texOp.CbufSlot &&
descriptor.HandleIndex == texOp.Handle && descriptor.HandleIndex == texOp.Handle &&
descriptor.Format == texOp.Format && descriptor.Format == texOp.Format);
descriptor.CbufSlot == cBufSlot &&
descriptor.CbufOffset == cBufOffset);
} }
public int FindTextureDescriptorIndex(AstTextureOperation texOp) public int FindTextureDescriptorIndex(AstTextureOperation texOp)

View file

@ -305,24 +305,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr); string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
if (!samplers.Add(samplerName)) if ((texOp.Flags & TextureFlags.Bindless) != 0 || !samplers.Add(samplerName))
{ {
continue; continue;
} }
int firstBinding = -1; int firstBinding = -1;
if ((texOp.Flags & TextureFlags.Bindless) != 0) if ((texOp.Type & SamplerType.Indexed) != 0)
{
AstOperand operand = texOp.GetSource(0) as AstOperand;
firstBinding = context.Config.Counts.IncrementTexturesCount();
var desc = new TextureDescriptor(firstBinding, texOp.Type, operand.CbufSlot, operand.CbufOffset);
context.TextureDescriptors.Add(desc);
}
else if ((texOp.Type & SamplerType.Indexed) != 0)
{ {
for (int index = 0; index < texOp.ArraySize; index++) for (int index = 0; index < texOp.ArraySize; index++)
{ {
@ -333,7 +323,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
firstBinding = binding; firstBinding = binding;
} }
var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.Handle + index * 2); var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.CbufSlot, texOp.Handle + index * 2);
context.TextureDescriptors.Add(desc); context.TextureDescriptors.Add(desc);
} }
@ -342,7 +332,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{ {
firstBinding = context.Config.Counts.IncrementTexturesCount(); firstBinding = context.Config.Counts.IncrementTexturesCount();
var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.Handle); var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.CbufSlot, texOp.Handle);
context.TextureDescriptors.Add(desc); context.TextureDescriptors.Add(desc);
} }
@ -363,7 +353,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr); string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
if (!images.Add(imageName)) if ((texOp.Flags & TextureFlags.Bindless) != 0 || !images.Add(imageName))
{ {
continue; continue;
} }
@ -381,7 +371,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
firstBinding = binding; firstBinding = binding;
} }
var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.Handle + index * 2); var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.CbufSlot, texOp.Handle + index * 2);
context.ImageDescriptors.Add(desc); context.ImageDescriptors.Add(desc);
} }
@ -390,7 +380,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{ {
firstBinding = context.Config.Counts.IncrementImagesCount(); firstBinding = context.Config.Counts.IncrementImagesCount();
var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.Handle); var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.CbufSlot, texOp.Handle);
context.ImageDescriptors.Add(desc); context.ImageDescriptors.Add(desc);
} }

View file

@ -15,6 +15,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0/do nothing.
if (isBindless)
{
return texOp.Inst == Instruction.ImageLoad ? NumberFormatter.FormatFloat(0) : "// imageStore(bindless)";
}
bool isArray = (texOp.Type & SamplerType.Array) != 0; bool isArray = (texOp.Type & SamplerType.Array) != 0;
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
@ -79,7 +85,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
flags |= TextureUsageFlags.ResScaleUnsupported; flags |= TextureUsageFlags.ResScaleUnsupported;
} }
if (!isBindless)
{
context.ImageDescriptors[index] = context.ImageDescriptors[index].SetFlag(flags); context.ImageDescriptors[index] = context.ImageDescriptors[index].SetFlag(flags);
}
return vector; return vector;
} }
@ -212,6 +221,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return NumberFormatter.FormatFloat(0);
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
string indexExpr = null; string indexExpr = null;
@ -306,6 +321,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
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;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return NumberFormatter.FormatFloat(0);
}
// This combination is valid, but not available on GLSL. // This combination is valid, but not available on GLSL.
// For now, ignore the LOD level and do a normal sample. // For now, ignore the LOD level and do a normal sample.
// TODO: How to implement it properly? // TODO: How to implement it properly?
@ -469,8 +490,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
flags |= TextureUsageFlags.ResScaleUnsupported; flags |= TextureUsageFlags.ResScaleUnsupported;
} }
if (!isBindless)
{
context.TextureDescriptors[index] = context.TextureDescriptors[index].SetFlag(flags); context.TextureDescriptors[index] = context.TextureDescriptors[index].SetFlag(flags);
} }
}
return vector; return vector;
} }
@ -572,6 +596,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return NumberFormatter.FormatInt(0);
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
string indexExpr = null; string indexExpr = null;

View file

@ -241,30 +241,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp, string indexExpr) public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
{ {
string suffix; string suffix = texOp.CbufSlot < 0 ? $"_tcb_{texOp.Handle:X}" : $"_cb{texOp.CbufSlot}_{texOp.Handle:X}";
if ((texOp.Flags & TextureFlags.Bindless) != 0)
{
AstOperand operand = texOp.GetSource(0) as AstOperand;
suffix = $"_{texOp.Type.ToGlslSamplerType()}_cb{operand.CbufSlot}_{operand.CbufOffset}";
}
else
{
suffix = texOp.Handle.ToString("X");
if ((texOp.Type & SamplerType.Indexed) != 0) if ((texOp.Type & SamplerType.Indexed) != 0)
{ {
suffix += $"a[{indexExpr}]"; suffix += $"a[{indexExpr}]";
} }
}
return GetShaderStagePrefix(stage) + "_" + DefaultNames.SamplerNamePrefix + suffix; return GetShaderStagePrefix(stage) + "_" + DefaultNames.SamplerNamePrefix + suffix;
} }
public static string GetImageName(ShaderStage stage, AstTextureOperation texOp, string indexExpr) public static string GetImageName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
{ {
string suffix = texOp.Handle.ToString("X") + "_" + texOp.Format.ToGlslFormat(); string suffix = texOp.CbufSlot < 0 ? $"_tcb_{texOp.Handle:X}_{texOp.Format.ToGlslFormat()}" : $"_cb{texOp.CbufSlot}_{texOp.Handle:X}_{texOp.Format.ToGlslFormat()}";
if ((texOp.Type & SamplerType.Indexed) != 0) if ((texOp.Type & SamplerType.Indexed) != 0)
{ {

View file

@ -2,9 +2,13 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{ {
class TextureOperation : Operation class TextureOperation : Operation
{ {
private const int DefaultCbufSlot = -1;
public SamplerType Type { get; private set; } public SamplerType Type { get; private set; }
public TextureFlags Flags { get; private set; } public TextureFlags Flags { get; private set; }
public int CbufSlot { get; private set; }
public int Handle { get; private set; } public int Handle { get; private set; }
public TextureFormat Format { get; set; } public TextureFormat Format { get; set; }
@ -20,6 +24,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{ {
Type = type; Type = type;
Flags = flags; Flags = flags;
CbufSlot = DefaultCbufSlot;
Handle = handle; Handle = handle;
} }
@ -30,7 +35,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Handle = handle; Handle = handle;
} }
public void SetHandle(int handle) public void SetHandle(int handle, int cbufSlot = DefaultCbufSlot)
{ {
if ((Flags & TextureFlags.Bindless) != 0) if ((Flags & TextureFlags.Bindless) != 0)
{ {
@ -39,6 +44,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
RemoveSource(0); RemoveSource(0);
} }
CbufSlot = cbufSlot;
Handle = handle; Handle = handle;
} }
} }

View file

@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
public TextureFormat Format { get; } public TextureFormat Format { get; }
public TextureFlags Flags { get; } public TextureFlags Flags { get; }
public int CbufSlot { get; }
public int Handle { get; } public int Handle { get; }
public int ArraySize { get; } public int ArraySize { get; }
@ -16,6 +17,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
SamplerType type, SamplerType type,
TextureFormat format, TextureFormat format,
TextureFlags flags, TextureFlags flags,
int cbufSlot,
int handle, int handle,
int arraySize, int arraySize,
int index, int index,
@ -24,6 +26,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Type = type; Type = type;
Format = format; Format = format;
Flags = flags; Flags = flags;
CbufSlot = cbufSlot;
Handle = handle; Handle = handle;
ArraySize = arraySize; ArraySize = arraySize;
} }

View file

@ -117,6 +117,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
texOp.Type, texOp.Type,
texOp.Format, texOp.Format,
texOp.Flags, texOp.Flags,
texOp.CbufSlot,
texOp.Handle, texOp.Handle,
4, // TODO: Non-hardcoded array size. 4, // TODO: Non-hardcoded array size.
texOp.Index, texOp.Index,

View file

@ -5,45 +5,20 @@ namespace Ryujinx.Graphics.Shader
public int Binding { get; } public int Binding { get; }
public SamplerType Type { get; } public SamplerType Type { get; }
public TextureFormat Format { get; } public TextureFormat Format { get; }
public int HandleIndex { get; }
public bool IsBindless { get; }
public int CbufSlot { get; } public int CbufSlot { get; }
public int CbufOffset { get; } public int HandleIndex { get; }
public TextureUsageFlags Flags { get; set; } public TextureUsageFlags Flags { get; set; }
public TextureDescriptor(int binding, SamplerType type, TextureFormat format, int handleIndex) public TextureDescriptor(int binding, SamplerType type, TextureFormat format, int cbufSlot, int handleIndex)
{ {
Binding = binding; Binding = binding;
Type = type; Type = type;
Format = format; Format = format;
HandleIndex = handleIndex;
IsBindless = false;
CbufSlot = 0;
CbufOffset = 0;
Flags = TextureUsageFlags.None;
}
public TextureDescriptor(int binding, SamplerType type, int cbufSlot, int cbufOffset)
{
Binding = binding;
Type = type;
Format = TextureFormat.Unknown;
HandleIndex = 0;
IsBindless = true;
CbufSlot = cbufSlot; CbufSlot = cbufSlot;
CbufOffset = cbufOffset; HandleIndex = handleIndex;
Flags = TextureUsageFlags.None; Flags = TextureUsageFlags.None;
} }

View file

@ -5,15 +5,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{ {
class BindlessElimination class BindlessElimination
{ {
private const int NvnTextureBufferSlot = 2;
public static void RunPass(BasicBlock block, ShaderConfig config) public static void RunPass(BasicBlock block, ShaderConfig config)
{ {
// We can turn a bindless into regular access by recognizing the pattern // We can turn a bindless into regular access by recognizing the pattern
// produced by the compiler for separate texture and sampler. // produced by the compiler for separate texture and sampler.
// We check for the following conditions: // We check for the following conditions:
// - The handle is a constant buffer value.
// - The handle is the result of a bitwise OR logical operation. // - The handle is the result of a bitwise OR logical operation.
// - Both sources of the OR operation comes from CB2 (used by NVN to hold texture handles). // - Both sources of the OR operation comes from a constant buffer.
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next) for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
{ {
if (!(node.Value is TextureOperation texOp)) if (!(node.Value is TextureOperation texOp))
@ -26,9 +25,19 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue; continue;
} }
if (texOp.Inst == Instruction.TextureSample) if (texOp.Inst == Instruction.Lod ||
texOp.Inst == Instruction.TextureSample ||
texOp.Inst == Instruction.TextureSize)
{ {
if (!(texOp.GetSource(0).AsgOp is Operation handleCombineOp)) Operand bindlessHandle = texOp.GetSource(0);
if (bindlessHandle.Type == OperandType.ConstantBuffer)
{
texOp.SetHandle(bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot());
continue;
}
if (!(bindlessHandle.AsgOp is Operation handleCombineOp))
{ {
continue; continue;
} }
@ -41,21 +50,21 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
Operand src0 = handleCombineOp.GetSource(0); Operand src0 = handleCombineOp.GetSource(0);
Operand src1 = handleCombineOp.GetSource(1); Operand src1 = handleCombineOp.GetSource(1);
if (src0.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != NvnTextureBufferSlot || if (src0.Type != OperandType.ConstantBuffer ||
src1.Type != OperandType.ConstantBuffer || src1.GetCbufSlot() != NvnTextureBufferSlot) src1.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != src1.GetCbufSlot())
{ {
continue; continue;
} }
texOp.SetHandle(src0.GetCbufOffset() | (src1.GetCbufOffset() << 16)); texOp.SetHandle(src0.GetCbufOffset() | (src1.GetCbufOffset() << 16), src0.GetCbufSlot());
} }
else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore) else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)
{ {
Operand src0 = texOp.GetSource(0); Operand src0 = texOp.GetSource(0);
if (src0.Type == OperandType.ConstantBuffer && src0.GetCbufSlot() == NvnTextureBufferSlot) if (src0.Type == OperandType.ConstantBuffer)
{ {
texOp.SetHandle(src0.GetCbufOffset()); texOp.SetHandle(src0.GetCbufOffset(), src0.GetCbufSlot());
texOp.Format = config.GetTextureFormat(texOp.Handle); texOp.Format = config.GetTextureFormat(texOp.Handle);
} }
} }

View file

@ -8,7 +8,7 @@ using static Ryujinx.Graphics.Shader.Translation.GlobalMemory;
namespace Ryujinx.Graphics.Shader.Translation namespace Ryujinx.Graphics.Shader.Translation
{ {
static class Lowering static class Rewriter
{ {
public static void RunPass(BasicBlock[] blocks, ShaderConfig config) public static void RunPass(BasicBlock[] blocks, ShaderConfig config)
{ {

View file

@ -96,7 +96,7 @@ namespace Ryujinx.Graphics.Shader.Translation
Optimizer.RunPass(cfg.Blocks, config); Optimizer.RunPass(cfg.Blocks, config);
Lowering.RunPass(cfg.Blocks, config); Rewriter.RunPass(cfg.Blocks, config);
} }
funcs[i] = new Function(cfg.Blocks, $"fun{i}", false, inArgumentsCount, outArgumentsCount); funcs[i] = new Function(cfg.Blocks, $"fun{i}", false, inArgumentsCount, outArgumentsCount);