Simplify logic for bindless texture handling (#1667)
* Simplify logic for bindless texture handling * Nits
This commit is contained in:
parent
eda6b78894
commit
934a78005e
16 changed files with 131 additions and 191 deletions
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
|
@ -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);
|
||||||
|
|
Reference in a new issue