forked from Mirror/Ryujinx
Stop identifying shader textures with handle and cbuf, use binding instead (#5266)
* 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
This commit is contained in:
parent
3b46bb73f7
commit
1c7a90ef35
25 changed files with 656 additions and 659 deletions
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
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 SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
public readonly byte Slot;
|
public readonly byte Slot;
|
||||||
public readonly byte SbCbSlot;
|
public readonly byte SbCbSlot;
|
||||||
public readonly ushort SbCbOffset;
|
public readonly ushort SbCbOffset;
|
||||||
public BufferUsageFlags Flags;
|
public readonly BufferUsageFlags Flags;
|
||||||
|
|
||||||
public BufferDescriptor(int binding, int slot)
|
public BufferDescriptor(int binding, int slot)
|
||||||
{
|
{
|
||||||
|
@ -16,25 +16,16 @@ namespace Ryujinx.Graphics.Shader
|
||||||
Slot = (byte)slot;
|
Slot = (byte)slot;
|
||||||
SbCbSlot = 0;
|
SbCbSlot = 0;
|
||||||
SbCbOffset = 0;
|
SbCbOffset = 0;
|
||||||
|
|
||||||
Flags = BufferUsageFlags.None;
|
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;
|
Binding = binding;
|
||||||
Slot = (byte)slot;
|
Slot = (byte)slot;
|
||||||
SbCbSlot = (byte)sbCbSlot;
|
SbCbSlot = (byte)sbCbSlot;
|
||||||
SbCbOffset = (ushort)sbCbOffset;
|
SbCbOffset = (ushort)sbCbOffset;
|
||||||
|
Flags = flags;
|
||||||
Flags = BufferUsageFlags.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BufferDescriptor SetFlag(BufferUsageFlags flag)
|
|
||||||
{
|
|
||||||
Flags |= flag;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,22 +75,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values);
|
DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values);
|
||||||
DeclareMemories(context, context.Config.Properties.LocalMemories.Values, isShared: false);
|
DeclareMemories(context, context.Config.Properties.LocalMemories.Values, isShared: false);
|
||||||
DeclareMemories(context, context.Config.Properties.SharedMemories.Values, isShared: true);
|
DeclareMemories(context, context.Config.Properties.SharedMemories.Values, isShared: true);
|
||||||
|
DeclareSamplers(context, context.Config.Properties.Textures.Values);
|
||||||
var textureDescriptors = context.Config.GetTextureDescriptors();
|
DeclareImages(context, context.Config.Properties.Images.Values);
|
||||||
if (textureDescriptors.Length != 0)
|
|
||||||
{
|
|
||||||
DeclareSamplers(context, textureDescriptors);
|
|
||||||
|
|
||||||
context.AppendLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
var imageDescriptors = context.Config.GetImageDescriptors();
|
|
||||||
if (imageDescriptors.Length != 0)
|
|
||||||
{
|
|
||||||
DeclareImages(context, imageDescriptors);
|
|
||||||
|
|
||||||
context.AppendLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.Config.Stage != ShaderStage.Compute)
|
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;
|
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)
|
if (arraySize == 0)
|
||||||
{
|
{
|
||||||
arraySize = ShaderConfig.SamplerArraySize;
|
arraySize = ResourceManager.SamplerArraySize;
|
||||||
}
|
}
|
||||||
else if (--arraySize != 0)
|
else if (--arraySize != 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indexExpr = $"[{NumberFormatter.FormatInt(arraySize)}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
string indexExpr = NumberFormatter.FormatInt(arraySize);
|
string samplerTypeName = definition.Type.ToGlslSamplerType();
|
||||||
|
|
||||||
string samplerName = OperandManager.GetSamplerName(
|
|
||||||
context.Config.Stage,
|
|
||||||
descriptor.CbufSlot,
|
|
||||||
descriptor.HandleIndex,
|
|
||||||
descriptor.Type.HasFlag(SamplerType.Indexed),
|
|
||||||
indexExpr);
|
|
||||||
|
|
||||||
string samplerTypeName = descriptor.Type.ToGlslSamplerType();
|
|
||||||
|
|
||||||
string layout = string.Empty;
|
string layout = string.Empty;
|
||||||
|
|
||||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
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;
|
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)
|
if (arraySize == 0)
|
||||||
{
|
{
|
||||||
arraySize = ShaderConfig.SamplerArraySize;
|
arraySize = ResourceManager.SamplerArraySize;
|
||||||
}
|
}
|
||||||
else if (--arraySize != 0)
|
else if (--arraySize != 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indexExpr = $"[{NumberFormatter.FormatInt(arraySize)}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
string indexExpr = NumberFormatter.FormatInt(arraySize);
|
string imageTypeName = definition.Type.ToGlslImageType(definition.Format.GetComponentType());
|
||||||
|
|
||||||
string imageName = OperandManager.GetImageName(
|
if (definition.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
|
||||||
context.Config.Stage,
|
|
||||||
descriptor.CbufSlot,
|
|
||||||
descriptor.HandleIndex,
|
|
||||||
descriptor.Format,
|
|
||||||
descriptor.Type.HasFlag(SamplerType.Indexed),
|
|
||||||
indexExpr);
|
|
||||||
|
|
||||||
string imageTypeName = descriptor.Type.ToGlslImageType(descriptor.Format.GetComponentType());
|
|
||||||
|
|
||||||
if (descriptor.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
|
|
||||||
{
|
{
|
||||||
imageTypeName = "coherent " + imageTypeName;
|
imageTypeName = "coherent " + imageTypeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
string layout = descriptor.Format.ToGlslFormat();
|
string layout = definition.Format.ToGlslFormat();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(layout))
|
if (!string.IsNullOrEmpty(layout))
|
||||||
{
|
{
|
||||||
|
@ -451,10 +428,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
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};");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
{
|
{
|
||||||
public const string LocalNamePrefix = "temp";
|
public const string LocalNamePrefix = "temp";
|
||||||
|
|
||||||
public const string SamplerNamePrefix = "tex";
|
|
||||||
public const string ImageNamePrefix = "img";
|
|
||||||
|
|
||||||
public const string PerPatchAttributePrefix = "patch_attr_";
|
public const string PerPatchAttributePrefix = "patch_attr_";
|
||||||
public const string IAttributePrefix = "in_attr";
|
public const string IAttributePrefix = "in_attr";
|
||||||
public const string OAttributePrefix = "out_attr";
|
public const string OAttributePrefix = "out_attr";
|
||||||
|
|
|
@ -84,7 +84,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
indexExpr = Src(AggregateType.S32);
|
indexExpr = Src(AggregateType.S32);
|
||||||
}
|
}
|
||||||
|
|
||||||
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
|
string imageName = GetImageName(context.Config, texOp, indexExpr);
|
||||||
|
|
||||||
texCallBuilder.Append('(');
|
texCallBuilder.Append('(');
|
||||||
texCallBuilder.Append(imageName);
|
texCallBuilder.Append(imageName);
|
||||||
|
@ -216,7 +216,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
|
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;
|
int coordsIndex = isBindless || isIndexed ? 1 : 0;
|
||||||
|
|
||||||
|
@ -342,7 +342,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
indexExpr = Src(AggregateType.S32);
|
indexExpr = Src(AggregateType.S32);
|
||||||
}
|
}
|
||||||
|
|
||||||
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
string samplerName = GetSamplerName(context.Config, texOp, indexExpr);
|
||||||
|
|
||||||
texCall += "(" + samplerName;
|
texCall += "(" + samplerName;
|
||||||
|
|
||||||
|
@ -538,7 +538,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
|
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)
|
if (texOp.Index == 3)
|
||||||
{
|
{
|
||||||
|
@ -546,8 +546,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TextureDescriptor descriptor = context.Config.FindTextureDescriptor(texOp);
|
context.Config.Properties.Textures.TryGetValue(texOp.Binding, out TextureDefinition definition);
|
||||||
bool hasLod = !descriptor.Type.HasFlag(SamplerType.Multisample) && descriptor.Type != SamplerType.TextureBuffer;
|
bool hasLod = !definition.Type.HasFlag(SamplerType.Multisample) && (definition.Type & SamplerType.Mask) != SamplerType.TextureBuffer;
|
||||||
string texCall;
|
string texCall;
|
||||||
|
|
||||||
if (hasLod)
|
if (hasLod)
|
||||||
|
@ -715,6 +715,30 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
return varName;
|
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)
|
private static string GetMask(int index)
|
||||||
{
|
{
|
||||||
return $".{"rgba".AsSpan(index, 1)}";
|
return $".{"rgba".AsSpan(index, 1)}";
|
||||||
|
|
|
@ -11,9 +11,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
{
|
{
|
||||||
class OperandManager
|
class OperandManager
|
||||||
{
|
{
|
||||||
private static readonly string[] _stagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" };
|
private Dictionary<AstOperand, string> _locals;
|
||||||
|
|
||||||
private readonly Dictionary<AstOperand, string> _locals;
|
|
||||||
|
|
||||||
public OperandManager()
|
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)
|
public static string GetArgumentName(int argIndex)
|
||||||
{
|
{
|
||||||
return $"{DefaultNames.ArgumentNamePrefix}{argIndex}";
|
return $"{DefaultNames.ArgumentNamePrefix}{argIndex}";
|
||||||
|
|
|
@ -28,9 +28,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
public Dictionary<int, Instruction> StorageBuffers { get; } = new Dictionary<int, Instruction>();
|
public Dictionary<int, Instruction> StorageBuffers { get; } = new Dictionary<int, Instruction>();
|
||||||
public Dictionary<int, Instruction> LocalMemories { 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<int, Instruction> SharedMemories { get; } = new Dictionary<int, Instruction>();
|
||||||
public Dictionary<TextureMeta, SamplerType> SamplersTypes { get; } = new Dictionary<TextureMeta, SamplerType>();
|
public Dictionary<int, SamplerType> SamplersTypes { get; } = new Dictionary<int, SamplerType>();
|
||||||
public Dictionary<TextureMeta, (Instruction, Instruction, Instruction)> Samplers { get; } = new Dictionary<TextureMeta, (Instruction, Instruction, Instruction)>();
|
public Dictionary<int, (Instruction, Instruction, Instruction)> Samplers { get; } = new Dictionary<int, (Instruction, Instruction, Instruction)>();
|
||||||
public Dictionary<TextureMeta, (Instruction, Instruction)> Images { get; } = new Dictionary<TextureMeta, (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> Inputs { get; } = new Dictionary<IoDefinition, Instruction>();
|
||||||
public Dictionary<IoDefinition, Instruction> Outputs { 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>();
|
public Dictionary<IoDefinition, Instruction> InputsPerPatch { get; } = new Dictionary<IoDefinition, Instruction>();
|
||||||
|
|
|
@ -72,8 +72,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values);
|
DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values);
|
||||||
DeclareMemories(context, context.Config.Properties.LocalMemories, context.LocalMemories, StorageClass.Private);
|
DeclareMemories(context, context.Config.Properties.LocalMemories, context.LocalMemories, StorageClass.Private);
|
||||||
DeclareMemories(context, context.Config.Properties.SharedMemories, context.SharedMemories, StorageClass.Workgroup);
|
DeclareMemories(context, context.Config.Properties.SharedMemories, context.SharedMemories, StorageClass.Workgroup);
|
||||||
DeclareSamplers(context, context.Config.GetTextureDescriptors());
|
DeclareSamplers(context, context.Config.Properties.Textures.Values);
|
||||||
DeclareImages(context, context.Config.GetImageDescriptors());
|
DeclareImages(context, context.Config.Properties.Images.Values);
|
||||||
DeclareInputsAndOutputs(context, info);
|
DeclareInputsAndOutputs(context, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
foreach (BufferDefinition buffer in buffers)
|
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 alignment = buffer.Layout == BufferLayout.Std140 ? 16 : 4;
|
||||||
int alignmentMask = alignment - 1;
|
int alignmentMask = alignment - 1;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
@ -163,7 +164,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
var variable = context.Variable(pointerType, StorageClass.Uniform);
|
var variable = context.Variable(pointerType, StorageClass.Uniform);
|
||||||
|
|
||||||
context.Name(variable, buffer.Name);
|
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.Decorate(variable, Decoration.Binding, (LiteralInteger)buffer.Binding);
|
||||||
context.AddGlobalVariable(variable);
|
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))
|
var dim = (sampler.Type & SamplerType.Mask) switch
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 2 : 0;
|
|
||||||
|
|
||||||
var dim = (descriptor.Type & SamplerType.Mask) switch
|
|
||||||
{
|
{
|
||||||
SamplerType.Texture1D => Dim.Dim1D,
|
SamplerType.Texture1D => Dim.Dim1D,
|
||||||
SamplerType.Texture2D => Dim.Dim2D,
|
SamplerType.Texture2D => Dim.Dim2D,
|
||||||
SamplerType.Texture3D => Dim.Dim3D,
|
SamplerType.Texture3D => Dim.Dim3D,
|
||||||
SamplerType.TextureCube => Dim.Cube,
|
SamplerType.TextureCube => Dim.Cube,
|
||||||
SamplerType.TextureBuffer => Dim.Buffer,
|
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(
|
var imageType = context.TypeImage(
|
||||||
context.TypeFP32(),
|
context.TypeFP32(),
|
||||||
dim,
|
dim,
|
||||||
descriptor.Type.HasFlag(SamplerType.Shadow),
|
sampler.Type.HasFlag(SamplerType.Shadow),
|
||||||
descriptor.Type.HasFlag(SamplerType.Array),
|
sampler.Type.HasFlag(SamplerType.Array),
|
||||||
descriptor.Type.HasFlag(SamplerType.Multisample),
|
sampler.Type.HasFlag(SamplerType.Multisample),
|
||||||
1,
|
1,
|
||||||
ImageFormat.Unknown);
|
ImageFormat.Unknown);
|
||||||
|
|
||||||
var nameSuffix = meta.CbufSlot < 0 ? $"_tcb_{meta.Handle:X}" : $"_cb{meta.CbufSlot}_{meta.Handle:X}";
|
|
||||||
|
|
||||||
var sampledImageType = context.TypeSampledImage(imageType);
|
var sampledImageType = context.TypeSampledImage(imageType);
|
||||||
var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageType);
|
var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageType);
|
||||||
var sampledImageVariable = context.Variable(sampledImagePointerType, StorageClass.UniformConstant);
|
var sampledImageVariable = context.Variable(sampledImagePointerType, StorageClass.UniformConstant);
|
||||||
|
|
||||||
context.Samplers.Add(meta, (imageType, sampledImageType, sampledImageVariable));
|
context.Samplers.Add(sampler.Binding, (imageType, sampledImageType, sampledImageVariable));
|
||||||
context.SamplersTypes.Add(meta, descriptor.Type);
|
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.DescriptorSet, (LiteralInteger)setIndex);
|
||||||
context.Decorate(sampledImageVariable, Decoration.Binding, (LiteralInteger)descriptor.Binding);
|
context.Decorate(sampledImageVariable, Decoration.Binding, (LiteralInteger)sampler.Binding);
|
||||||
context.AddGlobalVariable(sampledImageVariable);
|
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))
|
var dim = GetDim(image.Type);
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 3 : 0;
|
|
||||||
|
|
||||||
var dim = GetDim(descriptor.Type);
|
|
||||||
|
|
||||||
var imageType = context.TypeImage(
|
var imageType = context.TypeImage(
|
||||||
context.GetType(meta.Format.GetComponentType()),
|
context.GetType(image.Format.GetComponentType()),
|
||||||
dim,
|
dim,
|
||||||
descriptor.Type.HasFlag(SamplerType.Shadow),
|
image.Type.HasFlag(SamplerType.Shadow),
|
||||||
descriptor.Type.HasFlag(SamplerType.Array),
|
image.Type.HasFlag(SamplerType.Array),
|
||||||
descriptor.Type.HasFlag(SamplerType.Multisample),
|
image.Type.HasFlag(SamplerType.Multisample),
|
||||||
AccessQualifier.ReadWrite,
|
AccessQualifier.ReadWrite,
|
||||||
GetImageFormat(meta.Format));
|
GetImageFormat(image.Format));
|
||||||
|
|
||||||
var nameSuffix = meta.CbufSlot < 0 ?
|
|
||||||
$"_tcb_{meta.Handle:X}_{meta.Format.ToGlslFormat()}" :
|
|
||||||
$"_cb{meta.CbufSlot}_{meta.Handle:X}_{meta.Format.ToGlslFormat()}";
|
|
||||||
|
|
||||||
var imagePointerType = context.TypePointer(StorageClass.UniformConstant, imageType);
|
var imagePointerType = context.TypePointer(StorageClass.UniformConstant, imageType);
|
||||||
var imageVariable = context.Variable(imagePointerType, StorageClass.UniformConstant);
|
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.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);
|
context.Decorate(imageVariable, Decoration.Coherent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -657,7 +657,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
SpvInstruction value = Src(componentType);
|
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);
|
context.Load(imageType, imageVariable);
|
||||||
|
|
||||||
|
@ -742,7 +742,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
pCoords = Src(AggregateType.S32);
|
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 image = context.Load(imageType, imageVariable);
|
||||||
var imageComponentType = context.GetType(componentType);
|
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 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);
|
var image = context.Load(imageType, imageVariable);
|
||||||
|
|
||||||
|
@ -908,9 +908,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
pCoords = Src(AggregateType.FP32);
|
pCoords = Src(AggregateType.FP32);
|
||||||
}
|
}
|
||||||
|
|
||||||
var meta = new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format);
|
(_, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding];
|
||||||
|
|
||||||
var (_, sampledImageType, sampledImageVariable) = context.Samplers[meta];
|
|
||||||
|
|
||||||
var image = context.Load(sampledImageType, sampledImageVariable);
|
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 resultType = colorIsVector ? context.TypeVector(context.TypeFP32(), 4) : context.TypeFP32();
|
||||||
|
|
||||||
var meta = new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format);
|
(var imageType, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding];
|
||||||
|
|
||||||
var (imageType, sampledImageType, sampledImageVariable) = context.Samplers[meta];
|
|
||||||
|
|
||||||
var image = context.Load(sampledImageType, sampledImageVariable);
|
var image = context.Load(sampledImageType, sampledImageVariable);
|
||||||
|
|
||||||
|
@ -1592,9 +1588,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
context.GetS32(texOp.GetSource(0));
|
context.GetS32(texOp.GetSource(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
var meta = new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format);
|
(var imageType, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding];
|
||||||
|
|
||||||
(SpvInstruction imageType, SpvInstruction sampledImageType, SpvInstruction sampledImageVariable) = context.Samplers[meta];
|
|
||||||
|
|
||||||
var image = context.Load(sampledImageType, sampledImageVariable);
|
var image = context.Load(sampledImageType, sampledImageVariable);
|
||||||
image = context.Image(imageType, image);
|
image = context.Image(imageType, image);
|
||||||
|
@ -1605,7 +1599,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var type = context.SamplersTypes[meta];
|
var type = context.SamplersTypes[texOp.Binding];
|
||||||
bool hasLod = !type.HasFlag(SamplerType.Multisample) && type != SamplerType.TextureBuffer;
|
bool hasLod = !type.HasFlag(SamplerType.Multisample) && type != SamplerType.TextureBuffer;
|
||||||
|
|
||||||
int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.GetDimensions();
|
int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.GetDimensions();
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|
||||||
{
|
|
||||||
readonly record struct TextureMeta(int CbufSlot, int Handle, TextureFormat Format);
|
|
||||||
}
|
|
|
@ -218,7 +218,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
return context.Copy(Register(srcB++, RegisterType.Gpr));
|
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();
|
List<Operand> sourcesList = new();
|
||||||
|
|
||||||
|
@ -277,17 +277,17 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
flags |= TextureFlags.Bindless;
|
flags |= TextureFlags.Bindless;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureOperation operation = context.CreateTextureOperation(
|
int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.ImageAtomic,
|
Instruction.ImageAtomic,
|
||||||
type,
|
type,
|
||||||
format,
|
format,
|
||||||
flags,
|
flags,
|
||||||
imm,
|
TextureOperation.DefaultCbufSlot,
|
||||||
0,
|
imm);
|
||||||
new[] { destOperand },
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
Operand res = context.ImageAtomic(type, format, flags, binding, sources);
|
||||||
|
|
||||||
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitSuld(
|
private static void EmitSuld(
|
||||||
|
@ -383,21 +383,17 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
Array.Resize(ref dests, outputIndex);
|
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,
|
Instruction.ImageLoad,
|
||||||
type,
|
type,
|
||||||
|
format,
|
||||||
flags,
|
flags,
|
||||||
handle,
|
TextureOperation.DefaultCbufSlot,
|
||||||
(int)componentMask,
|
handle);
|
||||||
dests,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
if (!isBindless)
|
context.ImageLoad(type, format, flags, binding, (int)componentMask, dests, sources);
|
||||||
{
|
|
||||||
operation.Format = context.Config.GetTextureFormat(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Add(operation);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -430,17 +426,17 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
Array.Resize(ref dests, outputIndex);
|
Array.Resize(ref dests, outputIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureOperation operation = context.CreateTextureOperation(
|
TextureFormat format = GetTextureFormat(size);
|
||||||
|
|
||||||
|
int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.ImageLoad,
|
Instruction.ImageLoad,
|
||||||
type,
|
type,
|
||||||
GetTextureFormat(size),
|
format,
|
||||||
flags,
|
flags,
|
||||||
handle,
|
TextureOperation.DefaultCbufSlot,
|
||||||
compMask,
|
handle);
|
||||||
dests,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
context.ImageLoad(type, format, flags, binding, compMask, dests, sources);
|
||||||
|
|
||||||
switch (size)
|
switch (size)
|
||||||
{
|
{
|
||||||
|
@ -552,17 +548,15 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
flags |= TextureFlags.Bindless;
|
flags |= TextureFlags.Bindless;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureOperation operation = context.CreateTextureOperation(
|
int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.ImageAtomic,
|
Instruction.ImageAtomic,
|
||||||
type,
|
type,
|
||||||
format,
|
format,
|
||||||
flags,
|
flags,
|
||||||
imm,
|
TextureOperation.DefaultCbufSlot,
|
||||||
0,
|
imm);
|
||||||
null,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
context.ImageAtomic(type, format, flags, binding, sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitSust(
|
private static void EmitSust(
|
||||||
|
@ -681,17 +675,15 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
flags |= TextureFlags.Coherent;
|
flags |= TextureFlags.Coherent;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureOperation operation = context.CreateTextureOperation(
|
int binding = isBindless ? 0 : context.Config.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.ImageStore,
|
Instruction.ImageStore,
|
||||||
type,
|
type,
|
||||||
format,
|
format,
|
||||||
flags,
|
flags,
|
||||||
handle,
|
TextureOperation.DefaultCbufSlot,
|
||||||
0,
|
handle);
|
||||||
null,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
context.ImageStore(type, format, flags, binding, sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetComponentSizeInBytesLog2(SuatomSize size)
|
private static int GetComponentSizeInBytesLog2(SuatomSize size)
|
||||||
|
|
|
@ -324,16 +324,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
int handle = !isBindless ? imm : 0;
|
int handle = !isBindless ? imm : 0;
|
||||||
|
|
||||||
TextureOperation operation = context.CreateTextureOperation(
|
EmitTextureSample(context, type, flags, handle, componentMask, dests, sources);
|
||||||
Instruction.TextureSample,
|
|
||||||
type,
|
|
||||||
flags,
|
|
||||||
handle,
|
|
||||||
componentMask,
|
|
||||||
dests,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitTexs(
|
private static void EmitTexs(
|
||||||
|
@ -657,16 +648,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
Array.Resize(ref dests, outputIndex);
|
Array.Resize(ref dests, outputIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureOperation operation = context.CreateTextureOperation(
|
EmitTextureSample(context, type, flags, handle, componentMask, dests, sources);
|
||||||
Instruction.TextureSample,
|
|
||||||
type,
|
|
||||||
flags,
|
|
||||||
handle,
|
|
||||||
componentMask,
|
|
||||||
dests,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
|
||||||
|
|
||||||
if (isF16)
|
if (isF16)
|
||||||
{
|
{
|
||||||
|
@ -812,18 +794,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
Array.Resize(ref dests, outputIndex);
|
Array.Resize(ref dests, outputIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int handle = imm;
|
EmitTextureSample(context, type, flags, imm, componentMask, dests, sources);
|
||||||
|
|
||||||
TextureOperation operation = context.CreateTextureOperation(
|
|
||||||
Instruction.TextureSample,
|
|
||||||
type,
|
|
||||||
flags,
|
|
||||||
handle,
|
|
||||||
componentMask,
|
|
||||||
dests,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitTmml(
|
private static void EmitTmml(
|
||||||
|
@ -913,15 +884,21 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
return Register(dest++, RegisterType.Gpr);
|
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++)
|
for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
|
||||||
{
|
{
|
||||||
if ((compMask & 1) != 0)
|
if ((compMask & 1) != 0)
|
||||||
{
|
{
|
||||||
Operand destOperand = GetDest();
|
Operand d = GetDest();
|
||||||
|
|
||||||
if (destOperand == null)
|
if (d == null)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -930,28 +907,18 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
if (compIndex >= 2)
|
if (compIndex >= 2)
|
||||||
{
|
{
|
||||||
context.Add(new CommentNode("Unsupported component z or w found"));
|
context.Add(new CommentNode("Unsupported component z or w found"));
|
||||||
context.Copy(destOperand, Const(0));
|
context.Copy(d, Const(0));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Operand tempDest = Local();
|
// The instruction component order is the inverse of GLSL's.
|
||||||
|
Operand res = context.Lod(type, flags, binding, compIndex ^ 1, sources);
|
||||||
|
|
||||||
TextureOperation operation = context.CreateTextureOperation(
|
res = context.FPMultiply(res, ConstF(256.0f));
|
||||||
Instruction.Lod,
|
|
||||||
type,
|
|
||||||
flags,
|
|
||||||
handle,
|
|
||||||
compIndex ^ 1, // The instruction component order is the inverse of GLSL's.
|
|
||||||
new[] { tempDest },
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
Operand fixedPointValue = context.FP32ConvertToS32(res);
|
||||||
|
|
||||||
tempDest = context.FPMultiply(tempDest, ConstF(256.0f));
|
context.Copy(d, fixedPointValue);
|
||||||
|
|
||||||
Operand fixedPointValue = context.FP32ConvertToS32(tempDest);
|
|
||||||
|
|
||||||
context.Copy(destOperand, fixedPointValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1081,18 +1048,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
Array.Resize(ref dests, outputIndex);
|
Array.Resize(ref dests, outputIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int handle = imm;
|
EmitTextureSample(context, type, flags, imm, componentMask, dests, sources);
|
||||||
|
|
||||||
TextureOperation operation = context.CreateTextureOperation(
|
|
||||||
Instruction.TextureSample,
|
|
||||||
type,
|
|
||||||
flags,
|
|
||||||
handle,
|
|
||||||
componentMask,
|
|
||||||
dests,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitTxq(
|
private static void EmitTxq(
|
||||||
|
@ -1111,10 +1067,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
context.Config.SetUsedFeature(FeatureFlags.IntegerSampling);
|
context.Config.SetUsedFeature(FeatureFlags.IntegerSampling);
|
||||||
|
|
||||||
// TODO: Validate and use query.
|
|
||||||
Instruction inst = Instruction.TextureSize;
|
|
||||||
TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
|
|
||||||
|
|
||||||
Operand Ra()
|
Operand Ra()
|
||||||
{
|
{
|
||||||
if (srcA > RegisterConsts.RegisterZeroIndex)
|
if (srcA > RegisterConsts.RegisterZeroIndex)
|
||||||
|
@ -1157,31 +1109,55 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
type = context.Config.GpuAccessor.QuerySamplerType(imm);
|
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++)
|
for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
|
||||||
{
|
{
|
||||||
if ((compMask & 1) != 0)
|
if ((compMask & 1) != 0)
|
||||||
{
|
{
|
||||||
Operand destOperand = GetDest();
|
Operand d = GetDest();
|
||||||
|
|
||||||
if (destOperand == null)
|
if (d == null)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureOperation operation = context.CreateTextureOperation(
|
// TODO: Validate and use query parameter.
|
||||||
inst,
|
Operand res = context.TextureSize(type, flags, binding, compIndex, sources);
|
||||||
type,
|
|
||||||
flags,
|
|
||||||
imm,
|
|
||||||
compIndex,
|
|
||||||
new[] { destOperand },
|
|
||||||
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)
|
private static SamplerType ConvertSamplerType(TexDim dimensions)
|
||||||
{
|
{
|
||||||
return dimensions switch
|
return dimensions switch
|
||||||
|
|
|
@ -8,16 +8,14 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
public TextureFormat Format { get; set; }
|
public TextureFormat Format { get; set; }
|
||||||
public TextureFlags Flags { get; private set; }
|
public TextureFlags Flags { get; private set; }
|
||||||
|
|
||||||
public int CbufSlot { get; private set; }
|
public int Binding { get; private set; }
|
||||||
public int Handle { get; private set; }
|
|
||||||
|
|
||||||
public TextureOperation(
|
public TextureOperation(
|
||||||
Instruction inst,
|
Instruction inst,
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFormat format,
|
TextureFormat format,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
int cbufSlot,
|
int binding,
|
||||||
int handle,
|
|
||||||
int compIndex,
|
int compIndex,
|
||||||
Operand[] dests,
|
Operand[] dests,
|
||||||
Operand[] sources) : base(inst, compIndex, dests, sources)
|
Operand[] sources) : base(inst, compIndex, dests, sources)
|
||||||
|
@ -25,30 +23,17 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
Type = type;
|
Type = type;
|
||||||
Format = format;
|
Format = format;
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
CbufSlot = cbufSlot;
|
Binding = binding;
|
||||||
Handle = handle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureOperation(
|
public void TurnIntoIndexed(int binding)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
Type |= SamplerType.Indexed;
|
Type |= SamplerType.Indexed;
|
||||||
Flags &= ~TextureFlags.Bindless;
|
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)
|
if ((Flags & TextureFlags.Bindless) != 0)
|
||||||
{
|
{
|
||||||
|
@ -57,8 +42,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
RemoveSource(0);
|
RemoveSource(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
CbufSlot = cbufSlot;
|
Binding = binding;
|
||||||
Handle = handle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetLodLevelFlag()
|
public void SetLodLevelFlag()
|
||||||
|
|
|
@ -8,24 +8,21 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
public TextureFormat Format { get; }
|
public TextureFormat Format { get; }
|
||||||
public TextureFlags Flags { get; }
|
public TextureFlags Flags { get; }
|
||||||
|
|
||||||
public int CbufSlot { get; }
|
public int Binding { get; }
|
||||||
public int Handle { get; }
|
|
||||||
|
|
||||||
public AstTextureOperation(
|
public AstTextureOperation(
|
||||||
Instruction inst,
|
Instruction inst,
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFormat format,
|
TextureFormat format,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
int cbufSlot,
|
int binding,
|
||||||
int handle,
|
|
||||||
int index,
|
int index,
|
||||||
params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length)
|
params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Format = format;
|
Format = format;
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
CbufSlot = cbufSlot;
|
Binding = binding;
|
||||||
Handle = handle;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
{
|
{
|
||||||
private readonly Dictionary<int, BufferDefinition> _constantBuffers;
|
private readonly Dictionary<int, BufferDefinition> _constantBuffers;
|
||||||
private readonly Dictionary<int, BufferDefinition> _storageBuffers;
|
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> _localMemories;
|
||||||
private readonly Dictionary<int, MemoryDefinition> _sharedMemories;
|
private readonly Dictionary<int, MemoryDefinition> _sharedMemories;
|
||||||
|
|
||||||
public IReadOnlyDictionary<int, BufferDefinition> ConstantBuffers => _constantBuffers;
|
public IReadOnlyDictionary<int, BufferDefinition> ConstantBuffers => _constantBuffers;
|
||||||
public IReadOnlyDictionary<int, BufferDefinition> StorageBuffers => _storageBuffers;
|
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> LocalMemories => _localMemories;
|
||||||
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
|
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
|
||||||
|
|
||||||
|
@ -18,20 +22,32 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
{
|
{
|
||||||
_constantBuffers = new Dictionary<int, BufferDefinition>();
|
_constantBuffers = new Dictionary<int, BufferDefinition>();
|
||||||
_storageBuffers = new Dictionary<int, BufferDefinition>();
|
_storageBuffers = new Dictionary<int, BufferDefinition>();
|
||||||
|
_textures = new Dictionary<int, TextureDefinition>();
|
||||||
|
_images = new Dictionary<int, TextureDefinition>();
|
||||||
_localMemories = new Dictionary<int, MemoryDefinition>();
|
_localMemories = new Dictionary<int, MemoryDefinition>();
|
||||||
_sharedMemories = 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;
|
_constantBuffers[binding] = definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddStorageBuffer(int binding, BufferDefinition definition)
|
public void AddOrUpdateStorageBuffer(int binding, BufferDefinition definition)
|
||||||
{
|
{
|
||||||
_storageBuffers[binding] = 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)
|
public int AddLocalMemory(MemoryDefinition definition)
|
||||||
{
|
{
|
||||||
int id = _localMemories.Count;
|
int id = _localMemories.Count;
|
||||||
|
|
|
@ -125,15 +125,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
|
|
||||||
AstTextureOperation GetAstTextureOperation(TextureOperation texOp)
|
AstTextureOperation GetAstTextureOperation(TextureOperation texOp)
|
||||||
{
|
{
|
||||||
return new AstTextureOperation(
|
return new AstTextureOperation(inst, texOp.Type, texOp.Format, texOp.Flags, texOp.Binding, texOp.Index, sources);
|
||||||
inst,
|
|
||||||
texOp.Type,
|
|
||||||
texOp.Format,
|
|
||||||
texOp.Flags,
|
|
||||||
texOp.CbufSlot,
|
|
||||||
texOp.Handle,
|
|
||||||
texOp.Index,
|
|
||||||
sources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int componentsCount = BitOperations.PopCount((uint)operation.Index);
|
int componentsCount = BitOperations.PopCount((uint)operation.Index);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,23 +12,16 @@ namespace Ryujinx.Graphics.Shader
|
||||||
public readonly int CbufSlot;
|
public readonly int CbufSlot;
|
||||||
public readonly int HandleIndex;
|
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;
|
Binding = binding;
|
||||||
Type = type;
|
Type = type;
|
||||||
Format = format;
|
Format = format;
|
||||||
CbufSlot = cbufSlot;
|
CbufSlot = cbufSlot;
|
||||||
HandleIndex = handleIndex;
|
HandleIndex = handleIndex;
|
||||||
Flags = TextureUsageFlags.None;
|
Flags = flags;
|
||||||
}
|
|
||||||
|
|
||||||
public TextureDescriptor SetFlag(TextureUsageFlags flag)
|
|
||||||
{
|
|
||||||
Flags |= flag;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,36 +115,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
_operations.Add(operation);
|
_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)
|
public void FlagAttributeRead(int attribute)
|
||||||
{
|
{
|
||||||
if (Config.Stage == ShaderStage.Vertex && attribute == AttributeConsts.InstanceId)
|
if (Config.Stage == ShaderStage.Vertex && attribute == AttributeConsts.InstanceId)
|
||||||
|
|
|
@ -604,6 +604,45 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return context.Add(Instruction.Subtract, Local(), a, b);
|
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)
|
public static Operand IsNan(this EmitterContext context, Operand a, Instruction fpType = Instruction.FP32)
|
||||||
{
|
{
|
||||||
return context.Add(fpType | Instruction.IsNan, Local(), a);
|
return context.Add(fpType | Instruction.IsNan, Local(), a);
|
||||||
|
@ -666,6 +705,21 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
: context.Load(storageKind, (int)ioVariable, arrayIndex, elemIndex);
|
: 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)
|
public static Operand MemoryBarrier(this EmitterContext context)
|
||||||
{
|
{
|
||||||
return context.Add(Instruction.MemoryBarrier);
|
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);
|
: 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)
|
public static Operand UnpackDouble2x32High(this EmitterContext context, Operand a)
|
||||||
{
|
{
|
||||||
return UnpackDouble2x32(context, a, 1);
|
return UnpackDouble2x32(context, a, 1);
|
||||||
|
|
|
@ -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)
|
private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType, bool isImage)
|
||||||
{
|
{
|
||||||
texOp.SetHandle(cbufOffset, cbufSlot);
|
|
||||||
|
|
||||||
if (rewriteSamplerType)
|
if (rewriteSamplerType)
|
||||||
{
|
{
|
||||||
SamplerType newType = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot);
|
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)
|
else if (texOp.Type == SamplerType.TextureBuffer && newType == SamplerType.Texture1D)
|
||||||
{
|
{
|
||||||
int coordsCount = 1;
|
int coordsCount = 2;
|
||||||
|
|
||||||
if (InstEmit.Sample1DAs2D)
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
{
|
{
|
||||||
static class BindlessToIndexed
|
static class BindlessToIndexed
|
||||||
{
|
{
|
||||||
|
private const int NvnTextureBufferIndex = 2;
|
||||||
|
|
||||||
public static void RunPass(BasicBlock block, ShaderConfig config)
|
public static void RunPass(BasicBlock block, ShaderConfig config)
|
||||||
{
|
{
|
||||||
// We can turn a bindless texture access into a indexed access,
|
// 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 ||
|
if (ldcSrc0.Type != OperandType.Constant ||
|
||||||
!config.ResourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out int src0CbufSlot) ||
|
!config.ResourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out int src0CbufSlot) ||
|
||||||
src0CbufSlot != 2)
|
src0CbufSlot != NvnTextureBufferIndex)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -102,8 +104,15 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
|
||||||
private static void TurnIntoIndexed(ShaderConfig config, TextureOperation texOp, int handle)
|
private static void TurnIntoIndexed(ShaderConfig config, TextureOperation texOp, int handle)
|
||||||
{
|
{
|
||||||
texOp.TurnIntoIndexed(handle);
|
int binding = config.ResourceManager.GetTextureOrImageBinding(
|
||||||
config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, handle);
|
texOp.Inst,
|
||||||
|
texOp.Type | SamplerType.Indexed,
|
||||||
|
texOp.Format,
|
||||||
|
texOp.Flags & ~TextureFlags.Bindless,
|
||||||
|
NvnTextureBufferIndex,
|
||||||
|
handle);
|
||||||
|
|
||||||
|
texOp.TurnIntoIndexed(binding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -13,9 +14,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
private const int DefaultLocalMemorySize = 128;
|
private const int DefaultLocalMemorySize = 128;
|
||||||
private const int DefaultSharedMemorySize = 4096;
|
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 IGpuAccessor _gpuAccessor;
|
||||||
|
private readonly ShaderStage _stage;
|
||||||
private readonly string _stagePrefix;
|
private readonly string _stagePrefix;
|
||||||
|
|
||||||
private readonly int[] _cbSlotToBindingMap;
|
private readonly int[] _cbSlotToBindingMap;
|
||||||
|
@ -27,6 +32,19 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
private readonly HashSet<int> _usedConstantBufferBindings;
|
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 LocalMemoryId { get; private set; }
|
||||||
public int SharedMemoryId { get; private set; }
|
public int SharedMemoryId { get; private set; }
|
||||||
|
|
||||||
|
@ -36,6 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
{
|
{
|
||||||
_gpuAccessor = gpuAccessor;
|
_gpuAccessor = gpuAccessor;
|
||||||
Properties = properties;
|
Properties = properties;
|
||||||
|
_stage = stage;
|
||||||
_stagePrefix = GetShaderStagePrefix(stage);
|
_stagePrefix = GetShaderStagePrefix(stage);
|
||||||
|
|
||||||
_cbSlotToBindingMap = new int[18];
|
_cbSlotToBindingMap = new int[18];
|
||||||
|
@ -48,7 +67,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
_usedConstantBufferBindings = new HashSet<int>();
|
_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;
|
LocalMemoryId = -1;
|
||||||
SharedMemoryId = -1;
|
SharedMemoryId = -1;
|
||||||
|
@ -166,6 +188,198 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return false;
|
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)
|
public void SetUsedConstantBufferBinding(int binding)
|
||||||
{
|
{
|
||||||
_usedConstantBufferBindings.Add(binding);
|
_usedConstantBufferBindings.Add(binding);
|
||||||
|
@ -208,10 +422,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
if (binding >= 0)
|
if (binding >= 0)
|
||||||
{
|
{
|
||||||
(int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key);
|
(int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key);
|
||||||
descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot, sbCbSlot, sbCbOffset)
|
BufferUsageFlags flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None;
|
||||||
{
|
descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot, sbCbSlot, sbCbOffset, flags);
|
||||||
Flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,6 +435,64 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return descriptors;
|
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)
|
private void AddNewConstantBuffer(int binding, string name)
|
||||||
{
|
{
|
||||||
StructureType type = new(new[]
|
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),
|
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)
|
private void AddNewStorageBuffer(int binding, string name)
|
||||||
|
@ -240,7 +510,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
new StructureField(AggregateType.Array | AggregateType.U32, "data", 0),
|
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)
|
public static string GetShaderStagePrefix(ShaderStage stage)
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
if (texOp.Inst == Instruction.TextureSample)
|
if (texOp.Inst == Instruction.TextureSample)
|
||||||
{
|
{
|
||||||
node = InsertCoordNormalization(node, config);
|
node = InsertCoordNormalization(hfm, node, config);
|
||||||
node = InsertCoordGatherBias(node, config);
|
node = InsertCoordGatherBias(node, config);
|
||||||
node = InsertConstOffsets(node, config);
|
node = InsertConstOffsets(node, config);
|
||||||
|
|
||||||
|
@ -285,8 +285,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
{
|
{
|
||||||
int functionId = hfm.GetOrCreateFunctionId(HelperFunctionName.TexelFetchScale);
|
int functionId = hfm.GetOrCreateFunctionId(HelperFunctionName.TexelFetchScale);
|
||||||
int samplerIndex = isImage
|
int samplerIndex = isImage
|
||||||
? config.GetTextureDescriptors().Length + config.FindImageDescriptorIndex(texOp)
|
? config.ResourceManager.GetTextureDescriptors().Length + config.ResourceManager.FindImageDescriptorIndex(texOp.Binding)
|
||||||
: config.FindTextureDescriptorIndex(texOp);
|
: config.ResourceManager.FindTextureDescriptorIndex(texOp.Binding);
|
||||||
|
|
||||||
for (int index = 0; index < coordsCount; index++)
|
for (int index = 0; index < coordsCount; index++)
|
||||||
{
|
{
|
||||||
|
@ -326,7 +326,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
TypeSupportsScale(texOp.Type))
|
TypeSupportsScale(texOp.Type))
|
||||||
{
|
{
|
||||||
int functionId = hfm.GetOrCreateFunctionId(HelperFunctionName.TextureSizeUnscale);
|
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--)
|
for (int index = texOp.DestsCount - 1; index >= 0; index--)
|
||||||
{
|
{
|
||||||
|
@ -368,7 +368,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return (type & SamplerType.Mask) == SamplerType.Texture2D;
|
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.
|
// 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,
|
// 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;
|
TextureOperation texOp = (TextureOperation)node.Value;
|
||||||
|
|
||||||
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
||||||
|
|
||||||
|
if (isBindless)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0;
|
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)
|
if (isCoordNormalized || intCoords)
|
||||||
{
|
{
|
||||||
|
@ -411,18 +419,17 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
texSizeSources = new Operand[] { Const(0) };
|
texSizeSources = new Operand[] { Const(0) };
|
||||||
}
|
}
|
||||||
|
|
||||||
node.List.AddBefore(node, new TextureOperation(
|
LinkedListNode<INode> textureSizeNode = node.List.AddBefore(node, new TextureOperation(
|
||||||
Instruction.TextureSize,
|
Instruction.TextureSize,
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags,
|
texOp.Flags,
|
||||||
texOp.CbufSlot,
|
texOp.Binding,
|
||||||
texOp.Handle,
|
|
||||||
index,
|
index,
|
||||||
new[] { coordSize },
|
new[] { coordSize },
|
||||||
texSizeSources));
|
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);
|
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)));
|
node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Divide, coordNormalized, source, GenerateI2f(node, coordSize)));
|
||||||
|
|
||||||
texOp.SetSource(coordsIndex + index, coordNormalized);
|
texOp.SetSource(coordsIndex + index, coordNormalized);
|
||||||
|
|
||||||
|
InsertTextureSizeUnscale(hfm, textureSizeNode, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
@ -491,14 +500,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags,
|
texOp.Flags,
|
||||||
texOp.CbufSlot,
|
texOp.Binding,
|
||||||
texOp.Handle,
|
|
||||||
index,
|
index,
|
||||||
new[] { coordSize },
|
new[] { coordSize },
|
||||||
texSizeSources));
|
texSizeSources));
|
||||||
|
|
||||||
config.SetUsedTexture(Instruction.TextureSize, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, texOp.Handle);
|
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List.AddBefore(node, new Operation(
|
||||||
Instruction.FP32 | Instruction.Multiply,
|
Instruction.FP32 | Instruction.Multiply,
|
||||||
scaledSize,
|
scaledSize,
|
||||||
|
@ -686,8 +692,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
for (int index = 0; index < coordsCount; index++)
|
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 offset = Local();
|
||||||
|
|
||||||
Operand intOffset = offsets[index + (hasOffsets ? compIndex * coordsCount : 0)];
|
Operand intOffset = offsets[index + (hasOffsets ? compIndex * coordsCount : 0)];
|
||||||
|
@ -712,8 +716,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||||
texOp.CbufSlot,
|
texOp.Binding,
|
||||||
texOp.Handle,
|
|
||||||
1,
|
1,
|
||||||
new[] { dests[destIndex++] },
|
new[] { dests[destIndex++] },
|
||||||
newSources);
|
newSources);
|
||||||
|
@ -744,8 +747,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
for (int index = 0; index < coordsCount; index++)
|
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 offset = Local();
|
||||||
|
|
||||||
Operand intOffset = offsets[index];
|
Operand intOffset = offsets[index];
|
||||||
|
@ -771,8 +772,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||||
texOp.CbufSlot,
|
texOp.Binding,
|
||||||
texOp.Handle,
|
|
||||||
componentIndex,
|
componentIndex,
|
||||||
dests,
|
dests,
|
||||||
sources);
|
sources);
|
||||||
|
@ -806,8 +806,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags,
|
texOp.Flags,
|
||||||
texOp.CbufSlot,
|
texOp.Binding,
|
||||||
texOp.Handle,
|
|
||||||
0,
|
0,
|
||||||
new[] { lod },
|
new[] { lod },
|
||||||
lodSources));
|
lodSources));
|
||||||
|
@ -832,8 +831,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags,
|
texOp.Flags,
|
||||||
texOp.CbufSlot,
|
texOp.Binding,
|
||||||
texOp.Handle,
|
|
||||||
index,
|
index,
|
||||||
new[] { texSizes[index] },
|
new[] { texSizes[index] },
|
||||||
texSizeSources));
|
texSizeSources));
|
||||||
|
@ -853,7 +851,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return node;
|
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
|
int maxPositive = format switch
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,16 +2,12 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.Translation
|
namespace Ryujinx.Graphics.Shader.Translation
|
||||||
{
|
{
|
||||||
class ShaderConfig
|
class ShaderConfig
|
||||||
{
|
{
|
||||||
// TODO: Non-hardcoded array size.
|
|
||||||
public const int SamplerArraySize = 4;
|
|
||||||
|
|
||||||
private const int ThreadsPerWarp = 32;
|
private const int ThreadsPerWarp = 32;
|
||||||
|
|
||||||
public ShaderStage Stage { get; }
|
public ShaderStage Stage { get; }
|
||||||
|
@ -110,20 +106,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
public UInt128 NextInputAttributesComponents { get; private set; }
|
public UInt128 NextInputAttributesComponents { get; private set; }
|
||||||
public UInt128 ThisInputAttributesComponents { 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)
|
public ShaderConfig(ShaderStage stage, IGpuAccessor gpuAccessor, TranslationOptions options, int localMemorySize)
|
||||||
{
|
{
|
||||||
Stage = stage;
|
Stage = stage;
|
||||||
|
@ -141,9 +123,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
UsedInputAttributesPerPatch = new HashSet<int>();
|
UsedInputAttributesPerPatch = new HashSet<int>();
|
||||||
UsedOutputAttributesPerPatch = new HashSet<int>();
|
UsedOutputAttributesPerPatch = new HashSet<int>();
|
||||||
|
|
||||||
_usedTextures = new Dictionary<TextureInfo, TextureMeta>();
|
|
||||||
_usedImages = new Dictionary<TextureInfo, TextureMeta>();
|
|
||||||
|
|
||||||
ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties());
|
ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties());
|
||||||
|
|
||||||
if (!gpuAccessor.QueryHostSupportsTransformFeedback() && gpuAccessor.QueryTransformFeedbackEnabled())
|
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);
|
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[]
|
StructureType tfeDataStruct = new(new StructureField[]
|
||||||
{
|
{
|
||||||
|
@ -167,7 +146,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
{
|
{
|
||||||
int binding = Constants.TfeBufferBaseBinding + i;
|
int binding = Constants.TfeBufferBaseBinding + i;
|
||||||
BufferDefinition tfeDataBuffer = new(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
|
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;
|
UsedInputAttributes |= other.UsedInputAttributes;
|
||||||
UsedOutputAttributes |= other.UsedOutputAttributes;
|
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)
|
public void SetLayerOutputAttribute(int attr)
|
||||||
|
@ -642,196 +605,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
UsedFeatures |= flags;
|
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)
|
public ShaderProgramInfo CreateProgramInfo(ShaderIdentification identification = ShaderIdentification.None)
|
||||||
{
|
{
|
||||||
return new ShaderProgramInfo(
|
return new ShaderProgramInfo(
|
||||||
ResourceManager.GetConstantBufferDescriptors(),
|
ResourceManager.GetConstantBufferDescriptors(),
|
||||||
ResourceManager.GetStorageBufferDescriptors(),
|
ResourceManager.GetStorageBufferDescriptors(),
|
||||||
GetTextureDescriptors(),
|
ResourceManager.GetTextureDescriptors(),
|
||||||
GetImageDescriptors(),
|
ResourceManager.GetImageDescriptors(),
|
||||||
identification,
|
identification,
|
||||||
GpLayerInputAttribute,
|
GpLayerInputAttribute,
|
||||||
Stage,
|
Stage,
|
||||||
|
|
Loading…
Reference in a new issue