aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-07-03 14:29:27 -0300
committerGitHub <noreply@github.com>2023-07-03 14:29:27 -0300
commit1c7a90ef359d9974e5bd257c4d8e9bf526a6966c (patch)
tree3ab1644927819b90b0aef78ed6749c6434150490
parent3b46bb73f781a011705ecbc8a1d3207dfb145829 (diff)
Stop identifying shader textures with handle and cbuf, use binding instead (#5266)1.1.952
* Stop identifying shader textures with handle and cbuf, use binding instead * Remove now unused code * Consider image operations as having accurate type information too I don't know why that was not the case before * Fix missing unscale on InsertCoordNormalization, stop calling SetUsageFlagsForTextureQuery when not needed * Shader cache version bump * Change get texture methods to return descriptors created from ResourceManager state This is required to ensure that reserved textures and images will not be bound as a guest texture/image * Fix BindlessElimination.SetHandle inserting coords at the wrong place
-rw-r--r--src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs2
-rw-r--r--src/Ryujinx.Graphics.Shader/BufferDescriptor.cs15
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs79
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs3
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs36
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs58
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs6
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs77
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs20
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Spirv/TextureMeta.cs4
-rw-r--r--src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs66
-rw-r--r--src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs132
-rw-r--r--src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs30
-rw-r--r--src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs9
-rw-r--r--src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs20
-rw-r--r--src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs10
-rw-r--r--src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs27
-rw-r--r--src/Ryujinx.Graphics.Shader/TextureDescriptor.cs13
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs30
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs81
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs14
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs15
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs286
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs54
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs228
25 files changed, 656 insertions, 659 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index 95a0a6bd..672b3b8d 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
- private const uint CodeGenVersion = 5311;
+ private const uint CodeGenVersion = 5266;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";
diff --git a/src/Ryujinx.Graphics.Shader/BufferDescriptor.cs b/src/Ryujinx.Graphics.Shader/BufferDescriptor.cs
index d1da9539..d8cad1df 100644
--- a/src/Ryujinx.Graphics.Shader/BufferDescriptor.cs
+++ b/src/Ryujinx.Graphics.Shader/BufferDescriptor.cs
@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Shader
public readonly byte Slot;
public readonly byte SbCbSlot;
public readonly ushort SbCbOffset;
- public BufferUsageFlags Flags;
+ public readonly BufferUsageFlags Flags;
public BufferDescriptor(int binding, int slot)
{
@@ -16,25 +16,16 @@ namespace Ryujinx.Graphics.Shader
Slot = (byte)slot;
SbCbSlot = 0;
SbCbOffset = 0;
-
Flags = BufferUsageFlags.None;
}
- public BufferDescriptor(int binding, int slot, int sbCbSlot, int sbCbOffset)
+ public BufferDescriptor(int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags)
{
Binding = binding;
Slot = (byte)slot;
SbCbSlot = (byte)sbCbSlot;
SbCbOffset = (ushort)sbCbOffset;
-
- Flags = BufferUsageFlags.None;
- }
-
- public BufferDescriptor SetFlag(BufferUsageFlags flag)
- {
- Flags |= flag;
-
- return this;
+ Flags = flags;
}
}
}
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 94b850e7..2370b49f 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -75,22 +75,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values);
DeclareMemories(context, context.Config.Properties.LocalMemories.Values, isShared: false);
DeclareMemories(context, context.Config.Properties.SharedMemories.Values, isShared: true);
-
- var textureDescriptors = context.Config.GetTextureDescriptors();
- if (textureDescriptors.Length != 0)
- {
- DeclareSamplers(context, textureDescriptors);
-
- context.AppendLine();
- }
-
- var imageDescriptors = context.Config.GetImageDescriptors();
- if (imageDescriptors.Length != 0)
- {
- DeclareImages(context, imageDescriptors);
-
- context.AppendLine();
- }
+ DeclareSamplers(context, context.Config.Properties.Textures.Values);
+ DeclareImages(context, context.Config.Properties.Images.Values);
if (context.Config.Stage != ShaderStage.Compute)
{
@@ -369,80 +355,71 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
}
}
- private static void DeclareSamplers(CodeGenContext context, TextureDescriptor[] descriptors)
+ private static void DeclareSamplers(CodeGenContext context, IEnumerable<TextureDefinition> definitions)
{
int arraySize = 0;
- foreach (var descriptor in descriptors)
+
+ foreach (var definition in definitions)
{
- if (descriptor.Type.HasFlag(SamplerType.Indexed))
+ string indexExpr = string.Empty;
+
+ if (definition.Type.HasFlag(SamplerType.Indexed))
{
if (arraySize == 0)
{
- arraySize = ShaderConfig.SamplerArraySize;
+ arraySize = ResourceManager.SamplerArraySize;
}
else if (--arraySize != 0)
{
continue;
}
- }
- string indexExpr = NumberFormatter.FormatInt(arraySize);
-
- string samplerName = OperandManager.GetSamplerName(
- context.Config.Stage,
- descriptor.CbufSlot,
- descriptor.HandleIndex,
- descriptor.Type.HasFlag(SamplerType.Indexed),
- indexExpr);
+ indexExpr = $"[{NumberFormatter.FormatInt(arraySize)}]";
+ }
- string samplerTypeName = descriptor.Type.ToGlslSamplerType();
+ string samplerTypeName = definition.Type.ToGlslSamplerType();
string layout = string.Empty;
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
{
- layout = ", set = 2";
+ layout = $", set = {definition.Set}";
}
- context.AppendLine($"layout (binding = {descriptor.Binding}{layout}) uniform {samplerTypeName} {samplerName};");
+ context.AppendLine($"layout (binding = {definition.Binding}{layout}) uniform {samplerTypeName} {definition.Name}{indexExpr};");
}
}
- private static void DeclareImages(CodeGenContext context, TextureDescriptor[] descriptors)
+ private static void DeclareImages(CodeGenContext context, IEnumerable<TextureDefinition> definitions)
{
int arraySize = 0;
- foreach (var descriptor in descriptors)
+
+ foreach (var definition in definitions)
{
- if (descriptor.Type.HasFlag(SamplerType.Indexed))
+ string indexExpr = string.Empty;
+
+ if (definition.Type.HasFlag(SamplerType.Indexed))
{
if (arraySize == 0)
{
- arraySize = ShaderConfig.SamplerArraySize;
+ arraySize = ResourceManager.SamplerArraySize;
}
else if (--arraySize != 0)
{
continue;
}
- }
- string indexExpr = NumberFormatter.FormatInt(arraySize);
-
- string imageName = OperandManager.GetImageName(
- context.Config.Stage,
- descriptor.CbufSlot,
- descriptor.HandleIndex,
- descriptor.Format,
- descriptor.Type.HasFlag(SamplerType.Indexed),
- indexExpr);
+ indexExpr = $"[{NumberFormatter.FormatInt(arraySize)}]";
+ }
- string imageTypeName = descriptor.Type.ToGlslImageType(descriptor.Format.GetComponentType());
+ string imageTypeName = definition.Type.ToGlslImageType(definition.Format.GetComponentType());
- if (descriptor.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
+ if (definition.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
{
imageTypeName = "coherent " + imageTypeName;
}
- string layout = descriptor.Format.ToGlslFormat();
+ string layout = definition.Format.ToGlslFormat();
if (!string.IsNullOrEmpty(layout))
{
@@ -451,10 +428,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
{
- layout = $", set = 3{layout}";
+ layout = $", set = {definition.Set}{layout}";
}
- context.AppendLine($"layout (binding = {descriptor.Binding}{layout}) uniform {imageTypeName} {imageName};");
+ context.AppendLine($"layout (binding = {definition.Binding}{layout}) uniform {imageTypeName} {definition.Name}{indexExpr};");
}
}
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
index 842228ed..54bf9aeb 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
@@ -4,9 +4,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
public const string LocalNamePrefix = "temp";
- public const string SamplerNamePrefix = "tex";
- public const string ImageNamePrefix = "img";
-
public const string PerPatchAttributePrefix = "patch_attr_";
public const string IAttributePrefix = "in_attr";
public const string OAttributePrefix = "out_attr";
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index e0faed29..7e6d8bb5 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -84,7 +84,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
indexExpr = Src(AggregateType.S32);
}
- string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
+ string imageName = GetImageName(context.Config, texOp, indexExpr);
texCallBuilder.Append('(');
texCallBuilder.Append(imageName);
@@ -216,7 +216,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
}
- string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
+ string samplerName = GetSamplerName(context.Config, texOp, indexExpr);
int coordsIndex = isBindless || isIndexed ? 1 : 0;
@@ -342,7 +342,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
indexExpr = Src(AggregateType.S32);
}
- string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
+ string samplerName = GetSamplerName(context.Config, texOp, indexExpr);
texCall += "(" + samplerName;
@@ -538,7 +538,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
}
- string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
+ string samplerName = GetSamplerName(context.Config, texOp, indexExpr);
if (texOp.Index == 3)
{
@@ -546,8 +546,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
}
else
{
- TextureDescriptor descriptor = context.Config.FindTextureDescriptor(texOp);
- bool hasLod = !descriptor.Type.HasFlag(SamplerType.Multisample) && descriptor.Type != SamplerType.TextureBuffer;
+ context.Config.Properties.Textures.TryGetValue(texOp.Binding, out TextureDefinition definition);
+ bool hasLod = !definition.Type.HasFlag(SamplerType.Multisample) && (definition.Type & SamplerType.Mask) != SamplerType.TextureBuffer;
string texCall;
if (hasLod)
@@ -715,6 +715,30 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
return varName;
}
+ private static string GetSamplerName(ShaderConfig config, AstTextureOperation texOp, string indexExpr)
+ {
+ string name = config.Properties.Textures[texOp.Binding].Name;
+
+ if (texOp.Type.HasFlag(SamplerType.Indexed))
+ {
+ name = $"{name}[{indexExpr}]";
+ }
+
+ return name;
+ }
+
+ private static string GetImageName(ShaderConfig config, AstTextureOperation texOp, string indexExpr)
+ {
+ string name = config.Properties.Images[texOp.Binding].Name;
+
+ if (texOp.Type.HasFlag(SamplerType.Indexed))
+ {
+ name = $"{name}[{indexExpr}]";
+ }
+
+ return name;
+ }
+
private static string GetMask(int index)
{
return $".{"rgba".AsSpan(index, 1)}";
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
index 0ca3b55f..17ffad9a 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
@@ -11,9 +11,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
class OperandManager
{
- private static readonly string[] _stagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" };
-
- private readonly Dictionary<AstOperand, string> _locals;
+ private Dictionary<AstOperand, string> _locals;
public OperandManager()
{
@@ -41,60 +39,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
};
}
- public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
- {
- return GetSamplerName(stage, texOp.CbufSlot, texOp.Handle, texOp.Type.HasFlag(SamplerType.Indexed), indexExpr);
- }
-
- public static string GetSamplerName(ShaderStage stage, int cbufSlot, int handle, bool indexed, string indexExpr)
- {
- string suffix = cbufSlot < 0 ? $"_tcb_{handle:X}" : $"_cb{cbufSlot}_{handle:X}";
-
- if (indexed)
- {
- suffix += $"a[{indexExpr}]";
- }
-
- return GetShaderStagePrefix(stage) + "_" + DefaultNames.SamplerNamePrefix + suffix;
- }
-
- public static string GetImageName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
- {
- return GetImageName(stage, texOp.CbufSlot, texOp.Handle, texOp.Format, texOp.Type.HasFlag(SamplerType.Indexed), indexExpr);
- }
-
- public static string GetImageName(
- ShaderStage stage,
- int cbufSlot,
- int handle,
- TextureFormat format,
- bool indexed,
- string indexExpr)
- {
- string suffix = cbufSlot < 0
- ? $"_tcb_{handle:X}_{format.ToGlslFormat()}"
- : $"_cb{cbufSlot}_{handle:X}_{format.ToGlslFormat()}";
-
- if (indexed)
- {
- suffix += $"a[{indexExpr}]";
- }
-
- return GetShaderStagePrefix(stage) + "_" + DefaultNames.ImageNamePrefix + suffix;
- }
-
- public static string GetShaderStagePrefix(ShaderStage stage)
- {
- int index = (int)stage;
-
- if ((uint)index >= _stagePrefixes.Length)
- {
- return "invalid";
- }
-
- return _stagePrefixes[index];
- }
-
public static string GetArgumentName(int argIndex)
{
return $"{DefaultNames.ArgumentNamePrefix}{argIndex}";
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
index 9956e90a..d4f49045 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
@@ -28,9 +28,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
public Dictionary<int, Instruction> StorageBuffers { get; } = new Dictionary<int, Instruction>();
public Dictionary<int, Instruction> LocalMemories { get; } = new Dictionary<int, Instruction>();
public Dictionary<int, Instruction> SharedMemories { get; } = new Dictionary<int, Instruction>();
- public Dictionary<TextureMeta, SamplerType> SamplersTypes { get; } = new Dictionary<TextureMeta, SamplerType>();
- public Dictionary<TextureMeta, (Instruction, Instruction, Instruction)> Samplers { get; } = new Dictionary<TextureMeta, (Instruction, Instruction, Instruction)>();
- public Dictionary<TextureMeta, (Instruction, Instruction)> Images { get; } = new Dictionary<TextureMeta, (Instruction, Instruction)>();
+ public Dictionary<int, SamplerType> SamplersTypes { get; } = new Dictionary<int, SamplerType>();
+ public Dictionary<int, (Instruction, Instruction, Instruction)> Samplers { get; } = new Dictionary<int, (Instruction, Instruction, Instruction)>();
+ public Dictionary<int, (Instruction, Instruction)> Images { get; } = new Dictionary<int, (Instruction, Instruction)>();
public Dictionary<IoDefinition, Instruction> Inputs { get; } = new Dictionary<IoDefinition, Instruction>();
public Dictionary<IoDefinition, Instruction> Outputs { get; } = new Dictionary<IoDefinition, Instruction>();
public Dictionary<IoDefinition, Instruction> InputsPerPatch { get; } = new Dictionary<IoDefinition, Instruction>();
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
index da1e385a..2c849cd4 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
@@ -72,8 +72,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values);
DeclareMemories(context, context.Config.Properties.LocalMemories, context.LocalMemories, StorageClass.Private);
DeclareMemories(context, context.Config.Properties.SharedMemories, context.SharedMemories, StorageClass.Workgroup);
- DeclareSamplers(context, context.Config.GetTextureDescriptors());
- DeclareImages(context, context.Config.GetImageDescriptors());
+ DeclareSamplers(context, context.Config.Properties.Textures.Values);
+ DeclareImages(context, context.Config.Properties.Images.Values);
DeclareInputsAndOutputs(context, info);
}
@@ -110,6 +110,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
foreach (BufferDefinition buffer in buffers)
{
+ int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? buffer.Set : 0;
int alignment = buffer.Layout == BufferLayout.Std140 ? 16 : 4;
int alignmentMask = alignment - 1;
int offset = 0;
@@ -163,7 +164,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var variable = context.Variable(pointerType, StorageClass.Uniform);
context.Name(variable, buffer.Name);
- context.Decorate(variable, Decoration.DescriptorSet, (LiteralInteger)buffer.Set);
+ context.Decorate(variable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
context.Decorate(variable, Decoration.Binding, (LiteralInteger)buffer.Binding);
context.AddGlobalVariable(variable);
@@ -178,92 +179,72 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
}
}
- private static void DeclareSamplers(CodeGenContext context, TextureDescriptor[] descriptors)
+ private static void DeclareSamplers(CodeGenContext context, IEnumerable<TextureDefinition> samplers)
{
- foreach (var descriptor in descriptors)
+ foreach (var sampler in samplers)
{
- var meta = new TextureMeta(descriptor.CbufSlot, descriptor.HandleIndex, descriptor.Format);
+ int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? sampler.Set : 0;
- if (context.Samplers.ContainsKey(meta))
- {
- continue;
- }
-
- int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 2 : 0;
-
- var dim = (descriptor.Type & SamplerType.Mask) switch
+ var dim = (sampler.Type & SamplerType.Mask) switch
{
SamplerType.Texture1D => Dim.Dim1D,
SamplerType.Texture2D => Dim.Dim2D,
SamplerType.Texture3D => Dim.Dim3D,
SamplerType.TextureCube => Dim.Cube,
SamplerType.TextureBuffer => Dim.Buffer,
- _ => throw new InvalidOperationException($"Invalid sampler type \"{descriptor.Type & SamplerType.Mask}\"."),
+ _ => throw new InvalidOperationException($"Invalid sampler type \"{sampler.Type & SamplerType.Mask}\".")
};
var imageType = context.TypeImage(
context.TypeFP32(),
dim,
- descriptor.Type.HasFlag(SamplerType.Shadow),
- descriptor.Type.HasFlag(SamplerType.Array),
- descriptor.Type.HasFlag(SamplerType.Multisample),
+ sampler.Type.HasFlag(SamplerType.Shadow),
+ sampler.Type.HasFlag(SamplerType.Array),
+ sampler.Type.HasFlag(SamplerType.Multisample),
1,
ImageFormat.Unknown);
- var nameSuffix = meta.CbufSlot < 0 ? $"_tcb_{meta.Handle:X}" : $"_cb{meta.CbufSlot}_{meta.Handle:X}";
-
var sampledImageType = context.TypeSampledImage(imageType);
var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageType);
var sampledImageVariable = context.Variable(sampledImagePointerType, StorageClass.UniformConstant);
- context.Samplers.Add(meta, (imageType, sampledImageType, sampledImageVariable));
- context.SamplersTypes.Add(meta, descriptor.Type);
+ context.Samplers.Add(sampler.Binding, (imageType, sampledImageType, sampledImageVariable));
+ context.SamplersTypes.Add(sampler.Binding, sampler.Type);
- context.Name(sampledImageVariable, $"{GetStagePrefix(context.Config.Stage)}_tex{nameSuffix}");
+ context.Name(sampledImageVariable, sampler.Name);
context.Decorate(sampledImageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
- context.Decorate(sampledImageVariable, Decoration.Binding, (LiteralInteger)descriptor.Binding);
+ context.Decorate(sampledImageVariable, Decoration.Binding, (LiteralInteger)sampler.Binding);
context.AddGlobalVariable(sampledImageVariable);
}
}
- private static void DeclareImages(CodeGenContext context, TextureDescriptor[] descriptors)
+ private static void DeclareImages(CodeGenContext context, IEnumerable<TextureDefinition> images)
{
- foreach (var descriptor in descriptors)
+ foreach (var image in images)
{
- var meta = new TextureMeta(descriptor.CbufSlot, descriptor.HandleIndex, descriptor.Format);
+ int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? image.Set : 0;
- if (context.Images.ContainsKey(meta))
- {
- continue;
- }
-
- int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 3 : 0;
-
- var dim = GetDim(descriptor.Type);
+ var dim = GetDim(image.Type);
var imageType = context.TypeImage(
- context.GetType(meta.Format.GetComponentType()),
+ context.GetType(image.Format.GetComponentType()),
dim,
- descriptor.Type.HasFlag(SamplerType.Shadow),
- descriptor.Type.HasFlag(SamplerType.Array),
- descriptor.Type.HasFlag(SamplerType.Multisample),
+ image.Type.HasFlag(SamplerType.Shadow),
+ image.Type.HasFlag(SamplerType.Array),
+ image.Type.HasFlag(SamplerType.Multisample),
AccessQualifier.ReadWrite,
- GetImageFormat(meta.Format));
-
- var nameSuffix = meta.CbufSlot < 0 ?
- $"_tcb_{meta.Handle:X}_{meta.Format.ToGlslFormat()}" :
- $"_cb{meta.CbufSlot}_{meta.Handle:X}_{meta.Format.ToGlslFormat()}";
+ GetImageFormat(image.Format));
var imagePointerType = context.TypePointer(StorageClass.UniformConstant, imageType);
var imageVariable = context.Variable(imagePointerType, StorageClass.UniformConstant);
- context.Images.Add(meta, (imageType, imageVariable));
+ context.Images.Add(image.Binding, (imageType, imageVariable));
- context.Name(imageVariable, $"{GetStagePrefix(context.Config.Stage)}_img{nameSuffix}");
+ context.Name(imageVariable, image.Name);
context.Decorate(imageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
- context.Decorate(imageVariable, Decoration.Binding, (LiteralInteger)descriptor.Binding);
+ context.Decorate(imageVariable, Decoration.Binding, (LiteralInteger)image.Binding);
- if (descriptor.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
+ if (image.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
{
context.Decorate(imageVariable, Decoration.Coherent);
}
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
index a53b40b2..9489397b 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
@@ -657,7 +657,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
SpvInstruction value = Src(componentType);
- (SpvInstruction imageType, SpvInstruction imageVariable) = context.Images[new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format)];
+ (var imageType, var imageVariable) = context.Images[texOp.Binding];
context.Load(imageType, imageVariable);
@@ -742,7 +742,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
pCoords = Src(AggregateType.S32);
}
- var (imageType, imageVariable) = context.Images[new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format)];
+ (var imageType, var imageVariable) = context.Images[texOp.Binding];
var image = context.Load(imageType, imageVariable);
var imageComponentType = context.GetType(componentType);
@@ -829,7 +829,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var texel = context.CompositeConstruct(context.TypeVector(context.GetType(componentType), ComponentsCount), cElems);
- var (imageType, imageVariable) = context.Images[new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format)];
+ (var imageType, var imageVariable) = context.Images[texOp.Binding];
var image = context.Load(imageType, imageVariable);
@@ -908,9 +908,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
pCoords = Src(AggregateType.FP32);
}
- var meta = new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format);
-
- var (_, sampledImageType, sampledImageVariable) = context.Samplers[meta];
+ (_, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding];
var image = context.Load(sampledImageType, sampledImageVariable);
@@ -1511,9 +1509,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var resultType = colorIsVector ? context.TypeVector(context.TypeFP32(), 4) : context.TypeFP32();
- var meta = new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format);
-
- var (imageType, sampledImageType, sampledImageVariable) = context.Samplers[meta];
+ (var imageType, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding];
var image = context.Load(sampledImageType, sampledImageVariable);
@@ -1592,9 +1588,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
context.GetS32(texOp.GetSource(0));
}
- var meta = new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format);
-
- (SpvInstruction imageType, SpvInstruction sampledImageType, SpvInstruction sampledImageVariable) = context.Samplers[meta];
+ (var imageType, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding];
var image = context.Load(sampledImageType, sampledImageVariable);
image = context.Image(imageType, image);
@@ -1605,7 +1599,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
}
else
{
- var type = context.SamplersTypes[meta];
+ var type = context.SamplersTypes[texOp.Binding];
bool hasLod = !type.HasFlag(SamplerType.Multisample) && type != SamplerType.TextureBuffer;
int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.GetDimensions();
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/TextureMeta.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/TextureMeta.cs
deleted file mode 100644
index 56ea9a2a..00000000
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/TextureMeta.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
-{
- readonly record struct TextureMeta(int CbufSlot, int Handle, TextureFormat Format);
-}
diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs
index 78fc313d..0b929307 100644
--- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs
+++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs
@@ -218,7 +218,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
return context.Copy(Register(srcB++, RegisterType.Gpr));
}
- Operand destOperand = dest != RegisterConsts.RegisterZeroIndex ? Register(dest, RegisterType.Gpr) : null;
+ Operand d = dest != RegisterConsts.RegisterZeroIndex ? Register(dest, RegisterType.Gpr) : null;
List<Operand> sourcesList = new();
@@ -277,17 +277,17 @@ namespace Ryujinx.Graphics.Shader.Instructions
flags |= TextureFlags.Bindless;
}
- TextureOperation operation = context.CreateTextureOperation(
+ int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
Instruction.ImageAtomic,
type,
format,
flags,
- imm,
- 0,
- new[] { destOperand },
- sources);
+ TextureOperation.DefaultCbufSlot,
+ imm);
+
+ Operand res = context.ImageAtomic(type, format, flags, binding, sources);
- context.Add(operation);
+ context.Copy(d, res);
}
private static void EmitSuld(
@@ -383,21 +383,17 @@ namespace Ryujinx.Graphics.Shader.Instructions
Array.Resize(ref dests, outputIndex);
}
- TextureOperation operation = context.CreateTextureOperation(
+ TextureFormat format = isBindless ? TextureFormat.Unknown : context.Config.GetTextureFormat(handle);
+
+ int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
Instruction.ImageLoad,
type,
+ format,
flags,
- handle,
- (int)componentMask,
- dests,
- sources);
-
- if (!isBindless)
- {
- operation.Format = context.Config.GetTextureFormat(handle);
- }
+ TextureOperation.DefaultCbufSlot,
+ handle);
- context.Add(operation);
+ context.ImageLoad(type, format, flags, binding, (int)componentMask, dests, sources);
}
else
{
@@ -430,17 +426,17 @@ namespace Ryujinx.Graphics.Shader.Instructions
Array.Resize(ref dests, outputIndex);
}
- TextureOperation operation = context.CreateTextureOperation(
+ TextureFormat format = GetTextureFormat(size);
+
+ int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
Instruction.ImageLoad,
type,
- GetTextureFormat(size),
+ format,
flags,
- handle,
- compMask,
- dests,
- sources);
+ TextureOperation.DefaultCbufSlot,
+ handle);
- context.Add(operation);
+ context.ImageLoad(type, format, flags, binding, compMask, dests, sources);
switch (size)
{
@@ -552,17 +548,15 @@ namespace Ryujinx.Graphics.Shader.Instructions
flags |= TextureFlags.Bindless;
}
- TextureOperation operation = context.CreateTextureOperation(
+ int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
Instruction.ImageAtomic,
type,
format,
flags,
- imm,
- 0,
- null,
- sources);
+ TextureOperation.DefaultCbufSlot,
+ imm);
- context.Add(operation);
+ context.ImageAtomic(type, format, flags, binding, sources);
}
private static void EmitSust(
@@ -681,17 +675,15 @@ namespace Ryujinx.Graphics.Shader.Instructions
flags |= TextureFlags.Coherent;
}
- TextureOperation operation = context.CreateTextureOperation(
+ int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
Instruction.ImageStore,
type,
format,
flags,
- handle,
- 0,
- null,
- sources);
+ TextureOperation.DefaultCbufSlot,
+ handle);
- context.Add(operation);
+ context.ImageStore(type, format, flags, binding, sources);
}
private static int GetComponentSizeInBytesLog2(SuatomSize size)
diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
index 3701325e..7d3d22d8 100644
--- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
+++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
@@ -324,16 +324,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
int handle = !isBindless ? imm : 0;
- TextureOperation operation = context.CreateTextureOperation(
- Instruction.TextureSample,
- type,
- flags,
- handle,
- componentMask,
- dests,
- sources);
-
- context.Add(operation);
+ EmitTextureSample(context, type, flags, handle, componentMask, dests, sources);
}
private static void EmitTexs(
@@ -657,16 +648,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
Array.Resize(ref dests, outputIndex);
}
- TextureOperation operation = context.CreateTextureOperation(
- Instruction.TextureSample,
- type,
- flags,
- handle,
- componentMask,
- dests,
- sources);
-
- context.Add(operation);
+ EmitTextureSample(context, type, flags, handle, componentMask, dests, sources);
if (isF16)
{
@@ -812,18 +794,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
Array.Resize(ref dests, outputIndex);
}
- int handle = imm;
-
- TextureOperation operation = context.CreateTextureOperation(
- Instruction.TextureSample,
- type,
- flags,
- handle,
- componentMask,
- dests,
- sources);
-
- context.Add(operation);
+ EmitTextureSample(context, type, flags, imm, componentMask, dests, sources);
}
private static void EmitTmml(
@@ -913,15 +884,21 @@ namespace Ryujinx.Graphics.Shader.Instructions
return Register(dest++, RegisterType.Gpr);
}
- int handle = imm;
+ int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
+ Instruction.Lod,
+ type,
+ TextureFormat.Unknown,
+ flags,
+ TextureOperation.DefaultCbufSlot,
+ imm);
for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
{
if ((compMask & 1) != 0)
{
- Operand destOperand = GetDest();
+ Operand d = GetDest();
- if (destOperand == null)
+ if (d == null)
{
break;
}
@@ -930,28 +907,18 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (compIndex >= 2)
{
context.Add(new CommentNode("Unsupported component z or w found"));
- context.Copy(destOperand, Const(0));
+ context.Copy(d, Const(0));
}
else
{
- Operand tempDest = Local();
-
- TextureOperation operation = context.CreateTextureOperation(
- Instruction.Lod,
- type,
- flags,
- handle,
- compIndex ^ 1, // The instruction component order is the inverse of GLSL's.
- new[] { tempDest },
- sources);
-
- context.Add(operation);
+ // The instruction component order is the inverse of GLSL's.
+ Operand res = context.Lod(type, flags, binding, compIndex ^ 1, sources);
- tempDest = context.FPMultiply(tempDest, ConstF(256.0f));
+ res = context.FPMultiply(res, ConstF(256.0f));
- Operand fixedPointValue = context.FP32ConvertToS32(tempDest);
+ Operand fixedPointValue = context.FP32ConvertToS32(res);
- context.Copy(destOperand, fixedPointValue);
+ context.Copy(d, fixedPointValue);
}
}
}
@@ -1081,18 +1048,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
Array.Resize(ref dests, outputIndex);
}
- int handle = imm;
-
- TextureOperation operation = context.CreateTextureOperation(
- Instruction.TextureSample,
- type,
- flags,
- handle,
- componentMask,
- dests,
- sources);
-
- context.Add(operation);
+ EmitTextureSample(context, type, flags, imm, componentMask, dests, sources);
}
private static void EmitTxq(
@@ -1111,10 +1067,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.Config.SetUsedFeature(FeatureFlags.IntegerSampling);
- // TODO: Validate and use query.
- Instruction inst = Instruction.TextureSize;
- TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
-
Operand Ra()
{
if (srcA > RegisterConsts.RegisterZeroIndex)
@@ -1157,31 +1109,55 @@ namespace Ryujinx.Graphics.Shader.Instructions
type = context.Config.GpuAccessor.QuerySamplerType(imm);
}
+ TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
+
+ int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
+ Instruction.TextureSize,
+ type,
+ TextureFormat.Unknown,
+ flags,
+ TextureOperation.DefaultCbufSlot,
+ imm);
+
for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
{
if ((compMask & 1) != 0)
{
- Operand destOperand = GetDest();
+ Operand d = GetDest();
- if (destOperand == null)
+ if (d == null)
{
break;
}
- TextureOperation operation = context.CreateTextureOperation(
- inst,
- type,
- flags,
- imm,
- compIndex,
- new[] { destOperand },
- sources);
+ // TODO: Validate and use query parameter.
+ Operand res = context.TextureSize(type, flags, binding, compIndex, sources);
- context.Add(operation);
+ context.Copy(d, res);
}
}
}
+ private static void EmitTextureSample(
+ EmitterContext context,
+ SamplerType type,
+ TextureFlags flags,
+ int handle,
+ int componentMask,
+ Operand[] dests,
+ Operand[] sources)
+ {
+ int binding = flags.HasFlag(TextureFlags.Bindless) ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
+ Instruction.TextureSample,
+ type,
+ TextureFormat.Unknown,
+ flags,
+ TextureOperation.DefaultCbufSlot,
+ handle);
+
+ context.TextureSample(type, flags, binding, componentMask, dests, sources);
+ }
+
private static SamplerType ConvertSamplerType(TexDim dimensions)
{
return dimensions switch
diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
index b467fe53..fa5550a6 100644
--- a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
+++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
@@ -8,16 +8,14 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public TextureFormat Format { get; set; }
public TextureFlags Flags { get; private set; }
- public int CbufSlot { get; private set; }
- public int Handle { get; private set; }
+ public int Binding { get; private set; }
public TextureOperation(
Instruction inst,
SamplerType type,
TextureFormat format,
TextureFlags flags,
- int cbufSlot,
- int handle,
+ int binding,
int compIndex,
Operand[] dests,
Operand[] sources) : base(inst, compIndex, dests, sources)
@@ -25,30 +23,17 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Type = type;
Format = format;
Flags = flags;
- CbufSlot = cbufSlot;
- Handle = handle;
+ Binding = binding;
}
- public TextureOperation(
- Instruction inst,
- SamplerType type,
- TextureFormat format,
- TextureFlags flags,
- int handle,
- int compIndex,
- Operand[] dests,
- Operand[] sources) : this(inst, type, format, flags, DefaultCbufSlot, handle, compIndex, dests, sources)
- {
- }
-
- public void TurnIntoIndexed(int handle)
+ public void TurnIntoIndexed(int binding)
{
Type |= SamplerType.Indexed;
Flags &= ~TextureFlags.Bindless;
- Handle = handle;
+ Binding = binding;
}
- public void SetHandle(int handle, int cbufSlot = DefaultCbufSlot)
+ public void SetBinding(int binding)
{
if ((Flags & TextureFlags.Bindless) != 0)
{
@@ -57,8 +42,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
RemoveSource(0);
}
- CbufSlot = cbufSlot;
- Handle = handle;
+ Binding = binding;
}
public void SetLodLevelFlag()
diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
index 4ff2035a..3970df1e 100644
--- a/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
+++ b/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
@@ -8,24 +8,21 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
public TextureFormat Format { get; }
public TextureFlags Flags { get; }
- public int CbufSlot { get; }
- public int Handle { get; }
+ public int Binding { get; }
public AstTextureOperation(
Instruction inst,
SamplerType type,
TextureFormat format,
TextureFlags flags,
- int cbufSlot,
- int handle,
+ int binding,
int index,
params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length)
{
Type = type;
Format = format;
Flags = flags;
- CbufSlot = cbufSlot;
- Handle = handle;
+ Binding = binding;
}
}
}
diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs
index 1da5cb65..048a260a 100644
--- a/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs
+++ b/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs
@@ -6,11 +6,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
{
private readonly Dictionary<int, BufferDefinition> _constantBuffers;
private readonly Dictionary<int, BufferDefinition> _storageBuffers;
+ private readonly Dictionary<int, TextureDefinition> _textures;
+ private readonly Dictionary<int, TextureDefinition> _images;
private readonly Dictionary<int, MemoryDefinition> _localMemories;
private readonly Dictionary<int, MemoryDefinition> _sharedMemories;
public IReadOnlyDictionary<int, BufferDefinition> ConstantBuffers => _constantBuffers;
public IReadOnlyDictionary<int, BufferDefinition> StorageBuffers => _storageBuffers;
+ public IReadOnlyDictionary<int, TextureDefinition> Textures => _textures;
+ public IReadOnlyDictionary<int, TextureDefinition> Images => _images;
public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories;
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
@@ -18,20 +22,32 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
{
_constantBuffers = new Dictionary<int, BufferDefinition>();
_storageBuffers = new Dictionary<int, BufferDefinition>();
+ _textures = new Dictionary<int, TextureDefinition>();
+ _images = new Dictionary<int, TextureDefinition>();
_localMemories = new Dictionary<int, MemoryDefinition>();
_sharedMemories = new Dictionary<int, MemoryDefinition>();
}
- public void AddConstantBuffer(int binding, BufferDefinition definition)
+ public void AddOrUpdateConstantBuffer(int binding, BufferDefinition definition)
{
_constantBuffers[binding] = definition;
}
- public void AddStorageBuffer(int binding, BufferDefinition definition)
+ public void AddOrUpdateStorageBuffer(int binding, BufferDefinition definition)
{
_storageBuffers[binding] = definition;
}
+ public void AddOrUpdateTexture(int binding, TextureDefinition descriptor)
+ {
+ _textures[binding] = descriptor;
+ }
+
+ public void AddOrUpdateImage(int binding, TextureDefinition descriptor)
+ {
+ _images[binding] = descriptor;
+ }
+
public int AddLocalMemory(MemoryDefinition definition)
{
int id = _localMemories.Count;
diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
index a4e6444b..87acedf6 100644
--- a/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
+++ b/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
@@ -125,15 +125,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
AstTextureOperation GetAstTextureOperation(TextureOperation texOp)
{
- return new AstTextureOperation(
- inst,
- texOp.Type,
- texOp.Format,
- texOp.Flags,
- texOp.CbufSlot,
- texOp.Handle,
- texOp.Index,
- sources);
+ return new AstTextureOperation(inst, texOp.Type, texOp.Format, texOp.Flags, texOp.Binding, texOp.Index, sources);
}
int componentsCount = BitOperations.PopCount((uint)operation.Index);
diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs
new file mode 100644
index 00000000..ba31dae6
--- /dev/null
+++ b/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs
@@ -0,0 +1,27 @@
+namespace Ryujinx.Graphics.Shader
+{
+ readonly struct TextureDefinition
+ {
+ public int Set { get; }
+ public int Binding { get; }
+ public string Name { get; }
+ public SamplerType Type { get; }
+ public TextureFormat Format { get; }
+ public TextureUsageFlags Flags { get; }
+
+ public TextureDefinition(int set, int binding, string name, SamplerType type, TextureFormat format, TextureUsageFlags flags)
+ {
+ Set = set;
+ Binding = binding;
+ Name = name;
+ Type = type;
+ Format = format;
+ Flags = flags;
+ }
+
+ public TextureDefinition SetFlag(TextureUsageFlags flag)
+ {
+ return new TextureDefinition(Set, Binding, Name, Type, Format, Flags | flag);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs b/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs
index 626faa69..58b8e5a5 100644
--- a/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs
+++ b/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs
@@ -12,23 +12,16 @@ namespace Ryujinx.Graphics.Shader
public readonly int CbufSlot;
public readonly int HandleIndex;
- public TextureUsageFlags Flags;
+ public readonly TextureUsageFlags Flags;
- public TextureDescriptor(int binding, SamplerType type, TextureFormat format, int cbufSlot, int handleIndex)
+ public TextureDescriptor(int binding, SamplerType type, TextureFormat format, int cbufSlot, int handleIndex, TextureUsageFlags flags)
{
Binding = binding;
Type = type;
Format = format;
CbufSlot = cbufSlot;
HandleIndex = handleIndex;
- Flags = TextureUsageFlags.None;
- }
-
- public TextureDescriptor SetFlag(TextureUsageFlags flag)
- {
- Flags |= flag;
-
- return this;
+ Flags = flags;
}
}
}
diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 9eedc3f9..08d4b915 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -115,36 +115,6 @@ namespace Ryujinx.Graphics.Shader.Translation
_operations.Add(operation);
}
- public TextureOperation CreateTextureOperation(
- Instruction inst,
- SamplerType type,
- TextureFlags flags,
- int handle,
- int compIndex,
- Operand[] dests,
- params Operand[] sources)
- {
- return CreateTextureOperation(inst, type, TextureFormat.Unknown, flags, handle, compIndex, dests, sources);
- }
-
- public TextureOperation CreateTextureOperation(
- Instruction inst,
- SamplerType type,
- TextureFormat format,
- TextureFlags flags,
- int handle,
- int compIndex,
- Operand[] dests,
- params Operand[] sources)
- {
- if (!flags.HasFlag(TextureFlags.Bindless))
- {
- Config.SetUsedTexture(inst, type, format, flags, TextureOperation.DefaultCbufSlot, handle);
- }
-
- return new TextureOperation(inst, type, format, flags, handle, compIndex, dests, sources);
- }
-
public void FlagAttributeRead(int attribute)
{
if (Config.Stage == ShaderStage.Vertex && attribute == AttributeConsts.InstanceId)
diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
index c2f1b790..c92d0583 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
@@ -604,6 +604,45 @@ namespace Ryujinx.Graphics.Shader.Translation
return context.Add(Instruction.Subtract, Local(), a, b);
}
+ public static Operand ImageAtomic(
+ this EmitterContext context,
+ SamplerType type,
+ TextureFormat format,
+ TextureFlags flags,
+ int binding,
+ Operand[] sources)
+ {
+ Operand dest = Local();
+
+ context.Add(new TextureOperation(Instruction.ImageAtomic, type, format, flags, binding, 0, new[] { dest }, sources));
+
+ return dest;
+ }
+
+ public static void ImageLoad(
+ this EmitterContext context,
+ SamplerType type,
+ TextureFormat format,
+ TextureFlags flags,
+ int binding,
+ int compMask,
+ Operand[] dests,
+ Operand[] sources)
+ {
+ context.Add(new TextureOperation(Instruction.ImageLoad, type, format, flags, binding, compMask, dests, sources));
+ }
+
+ public static void ImageStore(
+ this EmitterContext context,
+ SamplerType type,
+ TextureFormat format,
+ TextureFlags flags,
+ int binding,
+ Operand[] sources)
+ {
+ context.Add(new TextureOperation(Instruction.ImageStore, type, format, flags, binding, 0, null, sources));
+ }
+
public static Operand IsNan(this EmitterContext context, Operand a, Instruction fpType = Instruction.FP32)
{
return context.Add(fpType | Instruction.IsNan, Local(), a);
@@ -666,6 +705,21 @@ namespace Ryujinx.Graphics.Shader.Translation
: context.Load(storageKind, (int)ioVariable, arrayIndex, elemIndex);
}
+ public static Operand Lod(
+ this EmitterContext context,
+ SamplerType type,
+ TextureFlags flags,
+ int binding,
+ int compIndex,
+ Operand[] sources)
+ {
+ Operand dest = Local();
+
+ context.Add(new TextureOperation(Instruction.Lod, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
+
+ return dest;
+ }
+
public static Operand MemoryBarrier(this EmitterContext context)
{
return context.Add(Instruction.MemoryBarrier);
@@ -797,6 +851,33 @@ namespace Ryujinx.Graphics.Shader.Translation
: context.Add(Instruction.Store, storageKind, null, Const((int)ioVariable), arrayIndex, elemIndex, value);
}
+ public static void TextureSample(
+ this EmitterContext context,
+ SamplerType type,
+ TextureFlags flags,
+ int binding,
+ int compMask,
+ Operand[] dests,
+ Operand[] sources)
+ {
+ context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources));
+ }
+
+ public static Operand TextureSize(
+ this EmitterContext context,
+ SamplerType type,
+ TextureFlags flags,
+ int binding,
+ int compIndex,
+ Operand[] sources)
+ {
+ Operand dest = Local();
+
+ context.Add(new TextureOperation(Instruction.TextureSize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
+
+ return dest;
+ }
+
public static Operand UnpackDouble2x32High(this EmitterContext context, Operand a)
{
return UnpackDouble2x32(context, a, 1);
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index bb25c160..bf087aff 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -222,8 +222,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType, bool isImage)
{
- texOp.SetHandle(cbufOffset, cbufSlot);
-
if (rewriteSamplerType)
{
SamplerType newType = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot);
@@ -234,7 +232,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
}
else if (texOp.Type == SamplerType.TextureBuffer && newType == SamplerType.Texture1D)
{
- int coordsCount = 1;
+ int coordsCount = 2;
if (InstEmit.Sample1DAs2D)
{
@@ -255,7 +253,15 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
}
}
- config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, cbufSlot, cbufOffset);
+ int binding = config.ResourceManager.GetTextureOrImageBinding(
+ texOp.Inst,
+ texOp.Type,
+ texOp.Format,
+ texOp.Flags & ~TextureFlags.Bindless,
+ cbufSlot,
+ cbufOffset);
+
+ texOp.SetBinding(binding);
}
}
}
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs
index f966a4fc..4b1bf76e 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs
@@ -7,6 +7,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{
static class BindlessToIndexed
{
+ private const int NvnTextureBufferIndex = 2;
+
public static void RunPass(BasicBlock block, ShaderConfig config)
{
// We can turn a bindless texture access into a indexed access,
@@ -43,7 +45,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
if (ldcSrc0.Type != OperandType.Constant ||
!config.ResourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out int src0CbufSlot) ||
- src0CbufSlot != 2)
+ src0CbufSlot != NvnTextureBufferIndex)
{
continue;
}
@@ -102,8 +104,15 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
private static void TurnIntoIndexed(ShaderConfig config, TextureOperation texOp, int handle)
{
- texOp.TurnIntoIndexed(handle);
- config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, handle);
+ int binding = config.ResourceManager.GetTextureOrImageBinding(
+ texOp.Inst,
+ texOp.Type | SamplerType.Indexed,
+ texOp.Format,
+ texOp.Flags & ~TextureFlags.Bindless,
+ NvnTextureBufferIndex,
+ handle);
+
+ texOp.TurnIntoIndexed(binding);
}
}
}
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
index f3a5ba6c..5991cd25 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
@@ -1,4 +1,5 @@
using Ryujinx.Common;
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr;
using System;
using System.Collections.Generic;
@@ -13,9 +14,13 @@ namespace Ryujinx.Graphics.Shader.Translation
private const int DefaultLocalMemorySize = 128;
private const int DefaultSharedMemorySize = 4096;
- private static readonly string[] _stagePrefixes = { "cp", "vp", "tcp", "tep", "gp", "fp" };
+ // TODO: Non-hardcoded array size.
+ public const int SamplerArraySize = 4;
+
+ private static readonly string[] _stagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" };
private readonly IGpuAccessor _gpuAccessor;
+ private readonly ShaderStage _stage;
private readonly string _stagePrefix;
private readonly int[] _cbSlotToBindingMap;
@@ -27,6 +32,19 @@ namespace Ryujinx.Graphics.Shader.Translation
private readonly HashSet<int> _usedConstantBufferBindings;
+ private readonly record struct TextureInfo(int CbufSlot, int Handle, bool Indexed, TextureFormat Format);
+
+ private struct TextureMeta
+ {
+ public int Binding;
+ public bool AccurateType;
+ public SamplerType Type;
+ public TextureUsageFlags UsageFlags;
+ }
+
+ private readonly Dictionary<TextureInfo, TextureMeta> _usedTextures;
+ private readonly Dictionary<TextureInfo, TextureMeta> _usedImages;
+
public int LocalMemoryId { get; private set; }
public int SharedMemoryId { get; private set; }
@@ -36,6 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
_gpuAccessor = gpuAccessor;
Properties = properties;
+ _stage = stage;
_stagePrefix = GetShaderStagePrefix(stage);
_cbSlotToBindingMap = new int[18];
@@ -48,7 +67,10 @@ namespace Ryujinx.Graphics.Shader.Translation
_usedConstantBufferBindings = new HashSet<int>();
- properties.AddConstantBuffer(0, new BufferDefinition(BufferLayout.Std140, 0, 0, "support_buffer", SupportBuffer.GetStructureType()));
+ _usedTextures = new Dictionary<TextureInfo, TextureMeta>();
+ _usedImages = new Dictionary<TextureInfo, TextureMeta>();
+
+ properties.AddOrUpdateConstantBuffer(0, new BufferDefinition(BufferLayout.Std140, 0, 0, "support_buffer", SupportBuffer.GetStructureType()));
LocalMemoryId = -1;
SharedMemoryId = -1;
@@ -166,6 +188,198 @@ namespace Ryujinx.Graphics.Shader.Translation
return false;
}
+ public int GetTextureOrImageBinding(
+ Instruction inst,
+ SamplerType type,
+ TextureFormat format,
+ TextureFlags flags,
+ int cbufSlot,
+ int handle)
+ {
+ inst &= Instruction.Mask;
+ bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
+ bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
+ bool accurateType = inst != Instruction.Lod && inst != Instruction.TextureSize;
+ bool intCoords = isImage || flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureSize;
+ bool coherent = flags.HasFlag(TextureFlags.Coherent);
+
+ if (!isImage)
+ {
+ format = TextureFormat.Unknown;
+ }
+
+ int binding = GetTextureOrImageBinding(cbufSlot, handle, type, format, isImage, intCoords, isWrite, accurateType, coherent);
+
+ _gpuAccessor.RegisterTexture(handle, cbufSlot);
+
+ return binding;
+ }
+
+ private int GetTextureOrImageBinding(
+ int cbufSlot,
+ int handle,
+ SamplerType type,
+ TextureFormat format,
+ bool isImage,
+ bool intCoords,
+ bool write,
+ bool accurateType,
+ bool coherent)
+ {
+ var dimensions = type.GetDimensions();
+ var isIndexed = type.HasFlag(SamplerType.Indexed);
+ var dict = isImage ? _usedImages : _usedTextures;
+
+ var usageFlags = TextureUsageFlags.None;
+
+ if (intCoords)
+ {
+ usageFlags |= TextureUsageFlags.NeedsScaleValue;
+
+ var canScale = _stage.SupportsRenderScale() && !isIndexed && !write && dimensions == 2;
+
+ if (!canScale)
+ {
+ // Resolution scaling cannot be applied to this texture right now.
+ // Flag so that we know to blacklist scaling on related textures when binding them.
+ usageFlags |= TextureUsageFlags.ResScaleUnsupported;
+ }
+ }
+
+ if (write)
+ {
+ usageFlags |= TextureUsageFlags.ImageStore;
+ }
+
+ if (coherent)
+ {
+ usageFlags |= TextureUsageFlags.ImageCoherent;
+ }
+
+ int arraySize = isIndexed ? SamplerArraySize : 1;
+ int firstBinding = -1;
+
+ for (int layer = 0; layer < arraySize; layer++)
+ {
+ var info = new TextureInfo(cbufSlot, handle + layer * 2, isIndexed, format);
+ var meta = new TextureMeta()
+ {
+ AccurateType = accurateType,
+ Type = type,
+ UsageFlags = usageFlags
+ };
+
+ int binding;
+
+ if (dict.TryGetValue(info, out var existingMeta))
+ {
+ dict[info] = MergeTextureMeta(meta, existingMeta);
+ binding = existingMeta.Binding;
+ }
+ else
+ {
+ bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer;
+
+ binding = isImage
+ ? _gpuAccessor.QueryBindingImage(dict.Count, isBuffer)
+ : _gpuAccessor.QueryBindingTexture(dict.Count, isBuffer);
+
+ meta.Binding = binding;
+
+ dict.Add(info, meta);
+ }
+
+ string nameSuffix;
+
+ if (isImage)
+ {
+ nameSuffix = cbufSlot < 0
+ ? $"i_tcb_{handle:X}_{format.ToGlslFormat()}"
+ : $"i_cb{cbufSlot}_{handle:X}_{format.ToGlslFormat()}";
+ }
+ else
+ {
+ nameSuffix = cbufSlot < 0 ? $"t_tcb_{handle:X}" : $"t_cb{cbufSlot}_{handle:X}";
+ }
+
+ var definition = new TextureDefinition(
+ isImage ? 3 : 2,
+ binding,
+ $"{_stagePrefix}_{nameSuffix}",
+ meta.Type,
+ info.Format,
+ meta.UsageFlags);
+
+ if (isImage)
+ {
+ Properties.AddOrUpdateImage(binding, definition);
+ }
+ else
+ {
+ Properties.AddOrUpdateTexture(binding, definition);
+ }
+
+ if (layer == 0)
+ {
+ firstBinding = binding;
+ }
+ }
+
+ return firstBinding;
+ }
+
+ private static TextureMeta MergeTextureMeta(TextureMeta meta, TextureMeta existingMeta)
+ {
+ meta.Binding = existingMeta.Binding;
+ meta.UsageFlags |= existingMeta.UsageFlags;
+
+ // If the texture we have has inaccurate type information, then
+ // we prefer the most accurate one.
+ if (existingMeta.AccurateType)
+ {
+ meta.AccurateType = true;
+ meta.Type = existingMeta.Type;
+ }
+
+ return meta;
+ }
+
+ public void SetUsageFlagsForTextureQuery(int binding, SamplerType type)
+ {
+ TextureInfo selectedInfo = default;
+ TextureMeta selectedMeta = default;
+ bool found = false;
+
+ foreach ((TextureInfo info, TextureMeta meta) in _usedTextures)
+ {
+ if (meta.Binding == binding)
+ {
+ selectedInfo = info;
+ selectedMeta = meta;
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ selectedMeta.UsageFlags |= TextureUsageFlags.NeedsScaleValue;
+
+ var dimensions = type.GetDimensions();
+ var isIndexed = type.HasFlag(SamplerType.Indexed);
+ var canScale = _stage.SupportsRenderScale() && !isIndexed && dimensions == 2;
+
+ if (!canScale)
+ {
+ // Resolution scaling cannot be applied to this texture right now.
+ // Flag so that we know to blacklist scaling on related textures when binding them.
+ selectedMeta.UsageFlags |= TextureUsageFlags.ResScaleUnsupported;
+ }
+
+ _usedTextures[selectedInfo] = selectedMeta;
+ }
+ }
+
public void SetUsedConstantBufferBinding(int binding)
{
_usedConstantBufferBindings.Add(binding);
@@ -208,10 +422,8 @@ namespace Ryujinx.Graphics.Shader.Translation
if (binding >= 0)
{
(int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key);
- descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot, sbCbSlot, sbCbOffset)
- {
- Flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None,
- };
+ BufferUsageFlags flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None;
+ descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot, sbCbSlot, sbCbOffset, flags);
}
}
@@ -223,6 +435,64 @@ namespace Ryujinx.Graphics.Shader.Translation
return descriptors;
}
+ public TextureDescriptor[] GetTextureDescriptors()
+ {
+ return GetDescriptors(_usedTextures, _usedTextures.Count);
+ }
+
+ public TextureDescriptor[] GetImageDescriptors()
+ {
+ return GetDescriptors(_usedImages, _usedImages.Count);
+ }
+
+ private static TextureDescriptor[] GetDescriptors(IReadOnlyDictionary<TextureInfo, TextureMeta> usedResources, int count)
+ {
+ TextureDescriptor[] descriptors = new TextureDescriptor[count];
+
+ int descriptorIndex = 0;
+
+ foreach ((TextureInfo info, TextureMeta meta) in usedResources)
+ {
+ descriptors[descriptorIndex++] = new TextureDescriptor(
+ meta.Binding,
+ meta.Type,
+ info.Format,
+ info.CbufSlot,
+ info.Handle,
+ meta.UsageFlags);
+ }
+
+ return descriptors;
+ }
+
+ public (int, int) GetCbufSlotAndHandleForTexture(int binding)
+ {
+ foreach ((TextureInfo info, TextureMeta meta) in _usedTextures)
+ {
+ if (meta.Binding == binding)
+ {
+ return (info.CbufSlot, info.Handle);
+ }
+ }
+
+ throw new ArgumentException($"Binding {binding} is invalid.");
+ }
+
+ private static int FindDescriptorIndex(TextureDescriptor[] array, int binding)
+ {
+ return Array.FindIndex(array, x => x.Binding == binding);
+ }
+
+ public int FindTextureDescriptorIndex(int binding)
+ {
+ return FindDescriptorIndex(GetTextureDescriptors(), binding);
+ }
+
+ public int FindImageDescriptorIndex(int binding)
+ {
+ return FindDescriptorIndex(GetImageDescriptors(), binding);
+ }
+
private void AddNewConstantBuffer(int binding, string name)
{
StructureType type = new(new[]
@@ -230,7 +500,7 @@ namespace Ryujinx.Graphics.Shader.Translation
new StructureField(AggregateType.Array | AggregateType.Vector4 | AggregateType.FP32, "data", Constants.ConstantBufferSize / 16),
});
- Properties.AddConstantBuffer(binding, new BufferDefinition(BufferLayout.Std140, 0, binding, name, type));
+ Properties.AddOrUpdateConstantBuffer(binding, new BufferDefinition(BufferLayout.Std140, 0, binding, name, type));
}
private void AddNewStorageBuffer(int binding, string name)
@@ -240,7 +510,7 @@ namespace Ryujinx.Graphics.Shader.Translation
new StructureField(AggregateType.Array | AggregateType.U32, "data", 0),
});
- Properties.AddStorageBuffer(binding, new BufferDefinition(BufferLayout.Std430, 1, binding, name, type));
+ Properties.AddOrUpdateStorageBuffer(binding, new BufferDefinition(BufferLayout.Std430, 1, binding, name, type));
}
public static string GetShaderStagePrefix(ShaderStage stage)
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs b/src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
index 42e3ecee..0fa75203 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
@@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (texOp.Inst == Instruction.TextureSample)
{
- node = InsertCoordNormalization(node, config);
+ node = InsertCoordNormalization(hfm, node, config);
node = InsertCoordGatherBias(node, config);
node = InsertConstOffsets(node, config);
@@ -285,8 +285,8 @@ namespace Ryujinx.Graphics.Shader.Translation
{
int functionId = hfm.GetOrCreateFunctionId(HelperFunctionName.TexelFetchScale);
int samplerIndex = isImage
- ? config.GetTextureDescriptors().Length + config.FindImageDescriptorIndex(texOp)
- : config.FindTextureDescriptorIndex(texOp);
+ ? config.ResourceManager.GetTextureDescriptors().Length + config.ResourceManager.FindImageDescriptorIndex(texOp.Binding)
+ : config.ResourceManager.FindTextureDescriptorIndex(texOp.Binding);
for (int index = 0; index < coordsCount; index++)
{
@@ -326,7 +326,7 @@ namespace Ryujinx.Graphics.Shader.Translation
TypeSupportsScale(texOp.Type))
{
int functionId = hfm.GetOrCreateFunctionId(HelperFunctionName.TextureSizeUnscale);
- int samplerIndex = config.FindTextureDescriptorIndex(texOp, ignoreType: true);
+ int samplerIndex = config.ResourceManager.FindTextureDescriptorIndex(texOp.Binding);
for (int index = texOp.DestsCount - 1; index >= 0; index--)
{
@@ -368,7 +368,7 @@ namespace Ryujinx.Graphics.Shader.Translation
return (type & SamplerType.Mask) == SamplerType.Texture2D;
}
- private static LinkedListNode<INode> InsertCoordNormalization(LinkedListNode<INode> node, ShaderConfig config)
+ private static LinkedListNode<INode> InsertCoordNormalization(HelperFunctionManager hfm, LinkedListNode<INode> node, ShaderConfig config)
{
// Emulate non-normalized coordinates by normalizing the coordinates on the shader.
// Without normalization, the coordinates are expected to the in the [0, W or H] range,
@@ -378,9 +378,17 @@ namespace Ryujinx.Graphics.Shader.Translation
TextureOperation texOp = (TextureOperation)node.Value;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
+
+ if (isBindless)
+ {
+ return node;
+ }
+
bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0;
- bool isCoordNormalized = isBindless || config.GpuAccessor.QueryTextureCoordNormalized(texOp.Handle, texOp.CbufSlot);
+ (int cbufSlot, int handle) = config.ResourceManager.GetCbufSlotAndHandleForTexture(texOp.Binding);
+
+ bool isCoordNormalized = config.GpuAccessor.QueryTextureCoordNormalized(handle, cbufSlot);
if (isCoordNormalized || intCoords)
{
@@ -411,18 +419,17 @@ namespace Ryujinx.Graphics.Shader.Translation
texSizeSources = new Operand[] { Const(0) };
}
- node.List.AddBefore(node, new TextureOperation(
+ LinkedListNode<INode> textureSizeNode = node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize,
texOp.Type,
texOp.Format,
texOp.Flags,
- texOp.CbufSlot,
- texOp.Handle,
+ texOp.Binding,
index,
new[] { coordSize },
texSizeSources));
- config.SetUsedTexture(Instruction.TextureSize, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, texOp.Handle);
+ config.ResourceManager.SetUsageFlagsForTextureQuery(texOp.Binding, texOp.Type);
Operand source = texOp.GetSource(coordsIndex + index);
@@ -431,6 +438,8 @@ namespace Ryujinx.Graphics.Shader.Translation
node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Divide, coordNormalized, source, GenerateI2f(node, coordSize)));
texOp.SetSource(coordsIndex + index, coordNormalized);
+
+ InsertTextureSizeUnscale(hfm, textureSizeNode, config);
}
return node;
@@ -491,14 +500,11 @@ namespace Ryujinx.Graphics.Shader.Translation
texOp.Type,
texOp.Format,
texOp.Flags,
- texOp.CbufSlot,
- texOp.Handle,
+ texOp.Binding,
index,
new[] { coordSize },
texSizeSources));
- config.SetUsedTexture(Instruction.TextureSize, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, texOp.Handle);
-
node.List.AddBefore(node, new Operation(
Instruction.FP32 | Instruction.Multiply,
scaledSize,
@@ -686,8 +692,6 @@ namespace Ryujinx.Graphics.Shader.Translation
for (int index = 0; index < coordsCount; index++)
{
- config.SetUsedTexture(Instruction.TextureSize, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, texOp.Handle);
-
Operand offset = Local();
Operand intOffset = offsets[index + (hasOffsets ? compIndex * coordsCount : 0)];
@@ -712,8 +716,7 @@ namespace Ryujinx.Graphics.Shader.Translation
texOp.Type,
texOp.Format,
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
- texOp.CbufSlot,
- texOp.Handle,
+ texOp.Binding,
1,
new[] { dests[destIndex++] },
newSources);
@@ -744,8 +747,6 @@ namespace Ryujinx.Graphics.Shader.Translation
for (int index = 0; index < coordsCount; index++)
{
- config.SetUsedTexture(Instruction.TextureSize, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, texOp.Handle);
-
Operand offset = Local();
Operand intOffset = offsets[index];
@@ -771,8 +772,7 @@ namespace Ryujinx.Graphics.Shader.Translation
texOp.Type,
texOp.Format,
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
- texOp.CbufSlot,
- texOp.Handle,
+ texOp.Binding,
componentIndex,
dests,
sources);
@@ -806,8 +806,7 @@ namespace Ryujinx.Graphics.Shader.Translation
texOp.Type,
texOp.Format,
texOp.Flags,
- texOp.CbufSlot,
- texOp.Handle,
+ texOp.Binding,
0,
new[] { lod },
lodSources));
@@ -832,8 +831,7 @@ namespace Ryujinx.Graphics.Shader.Translation
texOp.Type,
texOp.Format,
texOp.Flags,
- texOp.CbufSlot,
- texOp.Handle,
+ texOp.Binding,
index,
new[] { texSizes[index] },
texSizeSources));
@@ -853,7 +851,9 @@ namespace Ryujinx.Graphics.Shader.Translation
return node;
}
- TextureFormat format = config.GpuAccessor.QueryTextureFormat(texOp.Handle, texOp.CbufSlot);
+ (int cbufSlot, int handle) = config.ResourceManager.GetCbufSlotAndHandleForTexture(texOp.Binding);
+
+ TextureFormat format = config.GpuAccessor.QueryTextureFormat(handle, cbufSlot);
int maxPositive = format switch
{
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index e93a709c..5741d028 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -2,16 +2,12 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr;
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Numerics;
namespace Ryujinx.Graphics.Shader.Translation
{
class ShaderConfig
{
- // TODO: Non-hardcoded array size.
- public const int SamplerArraySize = 4;
-
private const int ThreadsPerWarp = 32;
public ShaderStage Stage { get; }
@@ -110,20 +106,6 @@ namespace Ryujinx.Graphics.Shader.Translation
public UInt128 NextInputAttributesComponents { get; private set; }
public UInt128 ThisInputAttributesComponents { get; private set; }
- private readonly record struct TextureInfo(int CbufSlot, int Handle, bool Indexed, TextureFormat Format);
-
- private struct TextureMeta
- {
- public bool AccurateType;
- public SamplerType Type;
- public TextureUsageFlags UsageFlags;
- }
-
- private readonly Dictionary<TextureInfo, TextureMeta> _usedTextures;
- private readonly Dictionary<TextureInfo, TextureMeta> _usedImages;
- private TextureDescriptor[] _cachedTextureDescriptors;
- private TextureDescriptor[] _cachedImageDescriptors;
-
public ShaderConfig(ShaderStage stage, IGpuAccessor gpuAccessor, TranslationOptions options, int localMemorySize)
{
Stage = stage;
@@ -141,9 +123,6 @@ namespace Ryujinx.Graphics.Shader.Translation
UsedInputAttributesPerPatch = new HashSet<int>();
UsedOutputAttributesPerPatch = new HashSet<int>();
- _usedTextures = new Dictionary<TextureInfo, TextureMeta>();
- _usedImages = new Dictionary<TextureInfo, TextureMeta>();
-
ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties());
if (!gpuAccessor.QueryHostSupportsTransformFeedback() && gpuAccessor.QueryTransformFeedbackEnabled())
@@ -156,7 +135,7 @@ namespace Ryujinx.Graphics.Shader.Translation
BufferDefinition tfeInfoBuffer = new(BufferLayout.Std430, 1, Constants.TfeInfoBinding, "tfe_info", tfeInfoStruct);
- Properties.AddStorageBuffer(Constants.TfeInfoBinding, tfeInfoBuffer);
+ Properties.AddOrUpdateStorageBuffer(Constants.TfeInfoBinding, tfeInfoBuffer);
StructureType tfeDataStruct = new(new StructureField[]
{
@@ -167,7 +146,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
int binding = Constants.TfeBufferBaseBinding + i;
BufferDefinition tfeDataBuffer = new(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
- Properties.AddStorageBuffer(binding, tfeDataBuffer);
+ Properties.AddOrUpdateStorageBuffer(binding, tfeDataBuffer);
}
}
}
@@ -443,22 +422,6 @@ namespace Ryujinx.Graphics.Shader.Translation
UsedInputAttributes |= other.UsedInputAttributes;
UsedOutputAttributes |= other.UsedOutputAttributes;
-
- foreach (var kv in other._usedTextures)
- {
- if (!_usedTextures.TryAdd(kv.Key, kv.Value))
- {
- _usedTextures[kv.Key] = MergeTextureMeta(kv.Value, _usedTextures[kv.Key]);
- }
- }
-
- foreach (var kv in other._usedImages)
- {
- if (!_usedImages.TryAdd(kv.Key, kv.Value))
- {
- _usedImages[kv.Key] = MergeTextureMeta(kv.Value, _usedImages[kv.Key]);
- }
- }
}
public void SetLayerOutputAttribute(int attr)
@@ -642,196 +605,13 @@ namespace Ryujinx.Graphics.Shader.Translation
UsedFeatures |= flags;
}
- public void SetUsedTexture(
- Instruction inst,
- SamplerType type,
- TextureFormat format,
- TextureFlags flags,
- int cbufSlot,
- int handle)
- {
- inst &= Instruction.Mask;
- bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
- bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
- bool accurateType = inst != Instruction.Lod && inst != Instruction.TextureSize;
- bool coherent = flags.HasFlag(TextureFlags.Coherent);
-
- if (isImage)
- {
- SetUsedTextureOrImage(_usedImages, cbufSlot, handle, type, format, true, isWrite, false, coherent);
- }
- else
- {
- bool intCoords = flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureSize;
- SetUsedTextureOrImage(_usedTextures, cbufSlot, handle, type, TextureFormat.Unknown, intCoords, false, accurateType, coherent);
- }
-
- GpuAccessor.RegisterTexture(handle, cbufSlot);
- }
-
- private void SetUsedTextureOrImage(
- Dictionary<TextureInfo, TextureMeta> dict,
- int cbufSlot,
- int handle,
- SamplerType type,
- TextureFormat format,
- bool intCoords,
- bool write,
- bool accurateType,
- bool coherent)
- {
- var dimensions = type.GetDimensions();
- var isIndexed = type.HasFlag(SamplerType.Indexed);
-
- var usageFlags = TextureUsageFlags.None;
-
- if (intCoords)
- {
- usageFlags |= TextureUsageFlags.NeedsScaleValue;
-
- var canScale = Stage.SupportsRenderScale() && !isIndexed && !write && dimensions == 2;
-
- if (!canScale)
- {
- // Resolution scaling cannot be applied to this texture right now.
- // Flag so that we know to blacklist scaling on related textures when binding them.
- usageFlags |= TextureUsageFlags.ResScaleUnsupported;
- }
- }
-
- if (write)
- {
- usageFlags |= TextureUsageFlags.ImageStore;
- }
-
- if (coherent)
- {
- usageFlags |= TextureUsageFlags.ImageCoherent;
- }
-
- int arraySize = isIndexed ? SamplerArraySize : 1;
-
- for (int layer = 0; layer < arraySize; layer++)
- {
- var info = new TextureInfo(cbufSlot, handle + layer * 2, isIndexed, format);
- var meta = new TextureMeta()
- {
- AccurateType = accurateType,
- Type = type,
- UsageFlags = usageFlags,
- };
-
- if (dict.TryGetValue(info, out var existingMeta))
- {
- dict[info] = MergeTextureMeta(meta, existingMeta);
- }
- else
- {
- dict.Add(info, meta);
- }
- }
- }
-
- private static TextureMeta MergeTextureMeta(TextureMeta meta, TextureMeta existingMeta)
- {
- meta.UsageFlags |= existingMeta.UsageFlags;
-
- // If the texture we have has inaccurate type information, then
- // we prefer the most accurate one.
- if (existingMeta.AccurateType)
- {
- meta.AccurateType = true;
- meta.Type = existingMeta.Type;
- }
-
- return meta;
- }
-
- public TextureDescriptor[] GetTextureDescriptors()
- {
- return _cachedTextureDescriptors ??= GetTextureOrImageDescriptors(_usedTextures, GpuAccessor.QueryBindingTexture);
- }
-
- public TextureDescriptor[] GetImageDescriptors()
- {
- return _cachedImageDescriptors ??= GetTextureOrImageDescriptors(_usedImages, GpuAccessor.QueryBindingImage);
- }
-
- private static TextureDescriptor[] GetTextureOrImageDescriptors(Dictionary<TextureInfo, TextureMeta> dict, Func<int, bool, int> getBindingCallback)
- {
- var descriptors = new TextureDescriptor[dict.Count];
-
- int i = 0;
- foreach (var kv in dict.OrderBy(x => x.Key.Indexed).ThenBy(x => x.Key.Handle))
- {
- var info = kv.Key;
- var meta = kv.Value;
-
- bool isBuffer = (meta.Type & SamplerType.Mask) == SamplerType.TextureBuffer;
- int binding = getBindingCallback(i, isBuffer);
-
- descriptors[i] = new TextureDescriptor(binding, meta.Type, info.Format, info.CbufSlot, info.Handle);
- descriptors[i].SetFlag(meta.UsageFlags);
- i++;
- }
-
- return descriptors;
- }
-
- public TextureDescriptor FindTextureDescriptor(AstTextureOperation texOp)
- {
- TextureDescriptor[] descriptors = GetTextureDescriptors();
-
- for (int i = 0; i < descriptors.Length; i++)
- {
- var descriptor = descriptors[i];
-
- if (descriptor.CbufSlot == texOp.CbufSlot &&
- descriptor.HandleIndex == texOp.Handle &&
- descriptor.Format == texOp.Format)
- {
- return descriptor;
- }
- }
-
- return default;
- }
-
- private static int FindDescriptorIndex(TextureDescriptor[] array, TextureOperation texOp, bool ignoreType = false)
- {
- for (int i = 0; i < array.Length; i++)
- {
- var descriptor = array[i];
-
- if ((descriptor.Type == texOp.Type || ignoreType) &&
- descriptor.CbufSlot == texOp.CbufSlot &&
- descriptor.HandleIndex == texOp.Handle &&
- descriptor.Format == texOp.Format)
- {
- return i;
- }
- }
-
- return -1;
- }
-
- public int FindTextureDescriptorIndex(TextureOperation texOp, bool ignoreType = false)
- {
- return FindDescriptorIndex(GetTextureDescriptors(), texOp, ignoreType);
- }
-
- public int FindImageDescriptorIndex(TextureOperation texOp)
- {
- return FindDescriptorIndex(GetImageDescriptors(), texOp);
- }
-
public ShaderProgramInfo CreateProgramInfo(ShaderIdentification identification = ShaderIdentification.None)
{
return new ShaderProgramInfo(
ResourceManager.GetConstantBufferDescriptors(),
ResourceManager.GetStorageBufferDescriptors(),
- GetTextureDescriptors(),
- GetImageDescriptors(),
+ ResourceManager.GetTextureDescriptors(),
+ ResourceManager.GetImageDescriptors(),
identification,
GpLayerInputAttribute,
Stage,