Use explicit buffer and texture bindings on shaders (#1666)
* Use explicit buffer and texture bindings on shaders * More XML docs and other nits
This commit is contained in:
parent
5561a3b95e
commit
8d168574eb
20 changed files with 496 additions and 551 deletions
|
@ -2,13 +2,12 @@ namespace Ryujinx.Graphics.Shader
|
|||
{
|
||||
public struct BufferDescriptor
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public int Binding { get; }
|
||||
public int Slot { get; }
|
||||
|
||||
public BufferDescriptor(string name, int slot)
|
||||
public BufferDescriptor(int binding, int slot)
|
||||
{
|
||||
Name = name;
|
||||
Binding = binding;
|
||||
Slot = slot;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,50 +218,46 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
|
||||
if (info.UsesCbIndexing)
|
||||
{
|
||||
int count = info.CBuffers.Max() + 1;
|
||||
|
||||
int[] bindings = new int[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
bindings[i] = context.Config.Counts.IncrementUniformBuffersCount();
|
||||
}
|
||||
|
||||
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
|
||||
{
|
||||
context.CBufferDescriptors.Add(new BufferDescriptor(bindings[cbufSlot], cbufSlot));
|
||||
}
|
||||
|
||||
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
||||
|
||||
ubName += "_" + DefaultNames.UniformNamePrefix;
|
||||
|
||||
string blockName = $"{ubName}_{DefaultNames.BlockSuffix}";
|
||||
|
||||
int maxSlot = 0;
|
||||
|
||||
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
|
||||
{
|
||||
context.CBufferDescriptors.Add(new BufferDescriptor($"{blockName}[{cbufSlot}]", cbufSlot));
|
||||
|
||||
if (maxSlot < cbufSlot)
|
||||
{
|
||||
maxSlot = cbufSlot;
|
||||
}
|
||||
}
|
||||
|
||||
context.AppendLine("layout (std140) uniform " + blockName);
|
||||
|
||||
context.AppendLine($"layout (binding = {bindings[0]}, std140) uniform {blockName}");
|
||||
context.EnterScope();
|
||||
|
||||
context.AppendLine("vec4 " + DefaultNames.DataName + ubSize + ";");
|
||||
|
||||
string arraySize = NumberFormatter.FormatInt(maxSlot + 1);
|
||||
|
||||
context.LeaveScope($" {ubName}[{arraySize}];");
|
||||
context.LeaveScope($" {ubName}[{NumberFormatter.FormatInt(count)}];");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
|
||||
{
|
||||
int binding = context.Config.Counts.IncrementUniformBuffersCount();
|
||||
|
||||
context.CBufferDescriptors.Add(new BufferDescriptor(binding, cbufSlot));
|
||||
|
||||
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
||||
|
||||
ubName += "_" + DefaultNames.UniformNamePrefix + cbufSlot;
|
||||
|
||||
context.CBufferDescriptors.Add(new BufferDescriptor(ubName, cbufSlot));
|
||||
|
||||
context.AppendLine("layout (std140) uniform " + ubName);
|
||||
|
||||
context.AppendLine($"layout (binding = {binding}, std140) uniform {ubName}");
|
||||
context.EnterScope();
|
||||
|
||||
context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Stage, cbufSlot, false) + ubSize + ";");
|
||||
|
||||
context.LeaveScope(";");
|
||||
}
|
||||
}
|
||||
|
@ -275,32 +271,29 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
|
||||
string blockName = $"{sbName}_{DefaultNames.BlockSuffix}";
|
||||
|
||||
int maxSlot = 0;
|
||||
int count = info.SBuffers.Max() + 1;
|
||||
|
||||
int[] bindings = new int[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
bindings[i] = context.Config.Counts.IncrementStorageBuffersCount();
|
||||
}
|
||||
|
||||
foreach (int sbufSlot in info.SBuffers)
|
||||
{
|
||||
context.SBufferDescriptors.Add(new BufferDescriptor($"{blockName}[{sbufSlot}]", sbufSlot));
|
||||
|
||||
if (maxSlot < sbufSlot)
|
||||
{
|
||||
maxSlot = sbufSlot;
|
||||
}
|
||||
context.SBufferDescriptors.Add(new BufferDescriptor(bindings[sbufSlot], sbufSlot));
|
||||
}
|
||||
|
||||
context.AppendLine("layout (std430) buffer " + blockName);
|
||||
|
||||
context.AppendLine($"layout (binding = {bindings[0]}, std430) buffer {blockName}");
|
||||
context.EnterScope();
|
||||
|
||||
context.AppendLine("uint " + DefaultNames.DataName + "[];");
|
||||
|
||||
string arraySize = NumberFormatter.FormatInt(maxSlot + 1);
|
||||
|
||||
context.LeaveScope($" {sbName}[{arraySize}];");
|
||||
context.LeaveScope($" {sbName}[{NumberFormatter.FormatInt(count)}];");
|
||||
}
|
||||
|
||||
private static void DeclareSamplers(CodeGenContext context, StructuredProgramInfo info)
|
||||
{
|
||||
Dictionary<string, AstTextureOperation> samplers = new Dictionary<string, AstTextureOperation>();
|
||||
HashSet<string> samplers = new HashSet<string>();
|
||||
|
||||
// Texture instructions other than TextureSample (like TextureSize)
|
||||
// may have incomplete sampler type information. In those cases,
|
||||
|
@ -312,29 +305,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
|
||||
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||
|
||||
if (!samplers.TryAdd(samplerName, texOp))
|
||||
if (!samplers.Add(samplerName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string samplerTypeName = texOp.Type.ToGlslSamplerType();
|
||||
|
||||
context.AppendLine("uniform " + samplerTypeName + " " + samplerName + ";");
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, AstTextureOperation> kv in samplers)
|
||||
{
|
||||
string samplerName = kv.Key;
|
||||
|
||||
AstTextureOperation texOp = kv.Value;
|
||||
|
||||
TextureDescriptor desc;
|
||||
int firstBinding = -1;
|
||||
|
||||
if ((texOp.Flags & TextureFlags.Bindless) != 0)
|
||||
{
|
||||
AstOperand operand = texOp.GetSource(0) as AstOperand;
|
||||
|
||||
desc = new TextureDescriptor(samplerName, texOp.Type, operand.CbufSlot, operand.CbufOffset);
|
||||
firstBinding = context.Config.Counts.IncrementTexturesCount();
|
||||
|
||||
var desc = new TextureDescriptor(firstBinding, texOp.Type, operand.CbufSlot, operand.CbufOffset);
|
||||
|
||||
context.TextureDescriptors.Add(desc);
|
||||
}
|
||||
|
@ -342,27 +326,36 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
{
|
||||
for (int index = 0; index < texOp.ArraySize; index++)
|
||||
{
|
||||
string indexExpr = NumberFormatter.FormatInt(index);
|
||||
int binding = context.Config.Counts.IncrementTexturesCount();
|
||||
|
||||
string indexedSamplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||
if (firstBinding < 0)
|
||||
{
|
||||
firstBinding = binding;
|
||||
}
|
||||
|
||||
desc = new TextureDescriptor(indexedSamplerName, texOp.Type, texOp.Format, texOp.Handle + index * 2);
|
||||
var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.Handle + index * 2);
|
||||
|
||||
context.TextureDescriptors.Add(desc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
desc = new TextureDescriptor(samplerName, texOp.Type, texOp.Format, texOp.Handle);
|
||||
firstBinding = context.Config.Counts.IncrementTexturesCount();
|
||||
|
||||
var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.Handle);
|
||||
|
||||
context.TextureDescriptors.Add(desc);
|
||||
}
|
||||
|
||||
string samplerTypeName = texOp.Type.ToGlslSamplerType();
|
||||
|
||||
context.AppendLine($"layout (binding = {firstBinding}) uniform {samplerTypeName} {samplerName};");
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareImages(CodeGenContext context, StructuredProgramInfo info)
|
||||
{
|
||||
Dictionary<string, AstTextureOperation> images = new Dictionary<string, AstTextureOperation>();
|
||||
HashSet<string> images = new HashSet<string>();
|
||||
|
||||
foreach (AstTextureOperation texOp in info.Images.OrderBy(x => x.Handle))
|
||||
{
|
||||
|
@ -370,48 +363,48 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
|
||||
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
|
||||
|
||||
if (!images.TryAdd(imageName, texOp))
|
||||
if (!images.Add(imageName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int firstBinding = -1;
|
||||
|
||||
if ((texOp.Type & SamplerType.Indexed) != 0)
|
||||
{
|
||||
for (int index = 0; index < texOp.ArraySize; index++)
|
||||
{
|
||||
int binding = context.Config.Counts.IncrementImagesCount();
|
||||
|
||||
if (firstBinding < 0)
|
||||
{
|
||||
firstBinding = binding;
|
||||
}
|
||||
|
||||
var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.Handle + index * 2);
|
||||
|
||||
context.ImageDescriptors.Add(desc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
firstBinding = context.Config.Counts.IncrementImagesCount();
|
||||
|
||||
var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.Handle);
|
||||
|
||||
context.ImageDescriptors.Add(desc);
|
||||
}
|
||||
|
||||
string layout = texOp.Format.ToGlslFormat();
|
||||
|
||||
if (!string.IsNullOrEmpty(layout))
|
||||
{
|
||||
layout = "layout(" + layout + ") ";
|
||||
layout = ", " + layout;
|
||||
}
|
||||
|
||||
string imageTypeName = texOp.Type.ToGlslImageType(texOp.Format.GetComponentType());
|
||||
|
||||
context.AppendLine("uniform " + layout + imageTypeName + " " + imageName + ";");
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, AstTextureOperation> kv in images)
|
||||
{
|
||||
string imageName = kv.Key;
|
||||
|
||||
AstTextureOperation texOp = kv.Value;
|
||||
|
||||
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);
|
||||
|
||||
var desc = new TextureDescriptor(indexedSamplerName, texOp.Type, texOp.Format, texOp.Handle + index * 2);
|
||||
|
||||
context.TextureDescriptors.Add(desc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var desc = new TextureDescriptor(imageName, texOp.Type, texOp.Format, texOp.Handle);
|
||||
|
||||
context.ImageDescriptors.Add(desc);
|
||||
}
|
||||
context.AppendLine($"layout (binding = {firstBinding}{layout}) uniform {imageTypeName} {imageName};");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,79 +2,79 @@
|
|||
{
|
||||
public interface IGpuAccessor
|
||||
{
|
||||
public void Log(string message)
|
||||
void Log(string message)
|
||||
{
|
||||
// No default log output.
|
||||
}
|
||||
|
||||
T MemoryRead<T>(ulong address) where T : unmanaged;
|
||||
|
||||
public bool MemoryMapped(ulong address)
|
||||
bool MemoryMapped(ulong address)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public int QueryComputeLocalSizeX()
|
||||
int QueryComputeLocalSizeX()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int QueryComputeLocalSizeY()
|
||||
int QueryComputeLocalSizeY()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int QueryComputeLocalSizeZ()
|
||||
int QueryComputeLocalSizeZ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int QueryComputeLocalMemorySize()
|
||||
int QueryComputeLocalMemorySize()
|
||||
{
|
||||
return 0x1000;
|
||||
}
|
||||
|
||||
public int QueryComputeSharedMemorySize()
|
||||
int QueryComputeSharedMemorySize()
|
||||
{
|
||||
return 0xc000;
|
||||
}
|
||||
|
||||
public uint QueryConstantBufferUse()
|
||||
uint QueryConstantBufferUse()
|
||||
{
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
public bool QueryIsTextureBuffer(int handle)
|
||||
bool QueryIsTextureBuffer(int handle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool QueryIsTextureRectangle(int handle)
|
||||
bool QueryIsTextureRectangle(int handle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public InputTopology QueryPrimitiveTopology()
|
||||
InputTopology QueryPrimitiveTopology()
|
||||
{
|
||||
return InputTopology.Points;
|
||||
}
|
||||
|
||||
public int QueryStorageBufferOffsetAlignment()
|
||||
int QueryStorageBufferOffsetAlignment()
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
public bool QuerySupportsImageLoadFormatted()
|
||||
bool QuerySupportsImageLoadFormatted()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool QuerySupportsNonConstantTextureOffset()
|
||||
bool QuerySupportsNonConstantTextureOffset()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public TextureFormat QueryTextureFormat(int handle)
|
||||
TextureFormat QueryTextureFormat(int handle)
|
||||
{
|
||||
return TextureFormat.R8G8B8A8Unorm;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Shader
|
|||
{
|
||||
public struct TextureDescriptor
|
||||
{
|
||||
public string Name { get; }
|
||||
public int Binding { get; }
|
||||
|
||||
public SamplerType Type { get; }
|
||||
|
||||
|
@ -17,9 +17,9 @@ namespace Ryujinx.Graphics.Shader
|
|||
|
||||
public TextureUsageFlags Flags { get; set; }
|
||||
|
||||
public TextureDescriptor(string name, SamplerType type, TextureFormat format, int handleIndex)
|
||||
public TextureDescriptor(int binding, SamplerType type, TextureFormat format, int handleIndex)
|
||||
{
|
||||
Name = name;
|
||||
Binding = binding;
|
||||
Type = type;
|
||||
Format = format;
|
||||
HandleIndex = handleIndex;
|
||||
|
@ -32,9 +32,9 @@ namespace Ryujinx.Graphics.Shader
|
|||
Flags = TextureUsageFlags.None;
|
||||
}
|
||||
|
||||
public TextureDescriptor(string name, SamplerType type, int cbufSlot, int cbufOffset)
|
||||
public TextureDescriptor(int binding, SamplerType type, int cbufSlot, int cbufOffset)
|
||||
{
|
||||
Name = name;
|
||||
Binding = binding;
|
||||
Type = type;
|
||||
Format = TextureFormat.Unknown;
|
||||
HandleIndex = 0;
|
||||
|
|
|
@ -20,11 +20,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
public TranslationFlags Flags { get; }
|
||||
|
||||
public TranslationCounts Counts { get; }
|
||||
|
||||
public int Size { get; private set; }
|
||||
|
||||
public FeatureFlags UsedFeatures { get; private set; }
|
||||
|
||||
public ShaderConfig(IGpuAccessor gpuAccessor, TranslationFlags flags)
|
||||
public ShaderConfig(IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts)
|
||||
{
|
||||
Stage = ShaderStage.Compute;
|
||||
OutputTopology = OutputTopology.PointList;
|
||||
|
@ -38,9 +40,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
Flags = flags;
|
||||
Size = 0;
|
||||
UsedFeatures = FeatureFlags.None;
|
||||
Counts = counts;
|
||||
}
|
||||
|
||||
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags)
|
||||
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts)
|
||||
{
|
||||
Stage = header.Stage;
|
||||
OutputTopology = header.OutputTopology;
|
||||
|
@ -54,6 +57,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
Flags = flags;
|
||||
Size = 0;
|
||||
UsedFeatures = FeatureFlags.None;
|
||||
Counts = counts;
|
||||
}
|
||||
|
||||
public int GetDepthRegister()
|
||||
|
|
30
Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs
Normal file
30
Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
public class TranslationCounts
|
||||
{
|
||||
public int UniformBuffersCount { get; private set; }
|
||||
public int StorageBuffersCount { get; private set; }
|
||||
public int TexturesCount { get; private set; }
|
||||
public int ImagesCount { get; private set; }
|
||||
|
||||
internal int IncrementUniformBuffersCount()
|
||||
{
|
||||
return UniformBuffersCount++;
|
||||
}
|
||||
|
||||
internal int IncrementStorageBuffersCount()
|
||||
{
|
||||
return StorageBuffersCount++;
|
||||
}
|
||||
|
||||
internal int IncrementTexturesCount()
|
||||
{
|
||||
return TexturesCount++;
|
||||
}
|
||||
|
||||
internal int IncrementImagesCount()
|
||||
{
|
||||
return ImagesCount++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,15 +24,28 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
}
|
||||
}
|
||||
|
||||
public static ShaderProgram Translate(ulong address, IGpuAccessor gpuAccessor, TranslationFlags flags)
|
||||
public static ShaderProgram Translate(
|
||||
ulong address,
|
||||
IGpuAccessor gpuAccessor,
|
||||
TranslationFlags flags,
|
||||
TranslationCounts counts = null)
|
||||
{
|
||||
return Translate(DecodeShader(address, gpuAccessor, flags, out ShaderConfig config), config);
|
||||
counts ??= new TranslationCounts();
|
||||
|
||||
return Translate(DecodeShader(address, gpuAccessor, flags, counts, out ShaderConfig config), config);
|
||||
}
|
||||
|
||||
public static ShaderProgram Translate(ulong addressA, ulong addressB, IGpuAccessor gpuAccessor, TranslationFlags flags)
|
||||
public static ShaderProgram Translate(
|
||||
ulong addressA,
|
||||
ulong addressB,
|
||||
IGpuAccessor gpuAccessor,
|
||||
TranslationFlags flags,
|
||||
TranslationCounts counts = null)
|
||||
{
|
||||
FunctionCode[] funcA = DecodeShader(addressA, gpuAccessor, flags | TranslationFlags.VertexA, out ShaderConfig configA);
|
||||
FunctionCode[] funcB = DecodeShader(addressB, gpuAccessor, flags, out ShaderConfig config);
|
||||
counts ??= new TranslationCounts();
|
||||
|
||||
FunctionCode[] funcA = DecodeShader(addressA, gpuAccessor, flags | TranslationFlags.VertexA, counts, out ShaderConfig configA);
|
||||
FunctionCode[] funcB = DecodeShader(addressB, gpuAccessor, flags, counts, out ShaderConfig config);
|
||||
|
||||
config.SetUsedFeature(configA.UsedFeatures);
|
||||
|
||||
|
@ -105,19 +118,24 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
return new ShaderProgram(spInfo, config.Stage, glslCode, config.Size, sizeA);
|
||||
}
|
||||
|
||||
private static FunctionCode[] DecodeShader(ulong address, IGpuAccessor gpuAccessor, TranslationFlags flags, out ShaderConfig config)
|
||||
private static FunctionCode[] DecodeShader(
|
||||
ulong address,
|
||||
IGpuAccessor gpuAccessor,
|
||||
TranslationFlags flags,
|
||||
TranslationCounts counts,
|
||||
out ShaderConfig config)
|
||||
{
|
||||
Block[][] cfg;
|
||||
|
||||
if ((flags & TranslationFlags.Compute) != 0)
|
||||
{
|
||||
config = new ShaderConfig(gpuAccessor, flags);
|
||||
config = new ShaderConfig(gpuAccessor, flags, counts);
|
||||
|
||||
cfg = Decoder.Decode(gpuAccessor, address);
|
||||
}
|
||||
else
|
||||
{
|
||||
config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, flags);
|
||||
config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, flags, counts);
|
||||
|
||||
cfg = Decoder.Decode(gpuAccessor, address + HeaderSize);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue