aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Translation
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2021-05-19 18:15:26 -0300
committerGitHub <noreply@github.com>2021-05-19 23:15:26 +0200
commit49745cfa37b247c3e49bfae126bafbe41e166bc6 (patch)
tree1a37f2f2c23791244b22529f6e228f008f984409 /Ryujinx.Graphics.Shader/Translation
parentb5c72b44dee2fd977d7cca5aa3c29ef1e2286aa7 (diff)
Move shader resource descriptor creation out of the backend (#2290)
* Move shader resource descriptor creation out of the backend * Remove now unused code, and other nits * Shader cache version bump * Nits * Set format for bindless image load/store * Fix buffer write flag
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation')
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContext.cs30
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs9
-rw-r--r--Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs4
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs16
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs10
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs17
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs2
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Rewriter.cs17
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs295
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Translator.cs14
10 files changed, 360 insertions, 54 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 9b220177..49a89374 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -53,6 +53,36 @@ namespace Ryujinx.Graphics.Shader.Translation
_operations.Add(operation);
}
+ public TextureOperation CreateTextureOperation(
+ Instruction inst,
+ SamplerType type,
+ TextureFlags flags,
+ int handle,
+ int compIndex,
+ Operand dest,
+ params Operand[] sources)
+ {
+ return CreateTextureOperation(inst, type, TextureFormat.Unknown, flags, handle, compIndex, dest, sources);
+ }
+
+ public TextureOperation CreateTextureOperation(
+ Instruction inst,
+ SamplerType type,
+ TextureFormat format,
+ TextureFlags flags,
+ int handle,
+ int compIndex,
+ Operand dest,
+ 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, dest, sources);
+ }
+
public void FlagAttributeRead(int attribute)
{
if (Config.Stage == ShaderStage.Vertex && attribute == AttributeConsts.InstanceId)
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
index dcefb591..e5ba04bc 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
@@ -518,6 +518,15 @@ namespace Ryujinx.Graphics.Shader.Translation
public static Operand LoadConstant(this EmitterContext context, Operand a, Operand b)
{
+ if (a.Type == OperandType.Constant)
+ {
+ context.Config.SetUsedConstantBuffer(a.Value);
+ }
+ else
+ {
+ context.Config.SetUsedFeature(FeatureFlags.CbIndexing);
+ }
+
return context.Add(Instruction.LoadConstant, Local(), a, b);
}
diff --git a/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs b/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
index 1b712896..b0c48410 100644
--- a/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
+++ b/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
@@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Shader.Translation
FragCoordXY = 1 << 1,
Bindless = 1 << 2,
-
- InstanceId = 1 << 3
+ InstanceId = 1 << 3,
+ CbIndexing = 1 << 4
}
}
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index f91a00eb..3a523adc 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
if (bindlessHandle.Type == OperandType.ConstantBuffer)
{
- texOp.SetHandle(bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot());
+ SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot());
continue;
}
@@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue;
}
- texOp.SetHandle(src0.GetCbufOffset() | (src1.GetCbufOffset() << 16), src0.GetCbufSlot());
+ SetHandle(config, texOp, src0.GetCbufOffset() | (src1.GetCbufOffset() << 16), src0.GetCbufSlot());
}
else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)
{
@@ -64,11 +64,19 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
if (src0.Type == OperandType.ConstantBuffer)
{
- texOp.SetHandle(src0.GetCbufOffset(), src0.GetCbufSlot());
- texOp.Format = config.GetTextureFormat(texOp.Handle, texOp.CbufSlot);
+ int cbufOffset = src0.GetCbufOffset();
+ int cbufSlot = src0.GetCbufSlot();
+ texOp.Format = config.GetTextureFormat(cbufOffset, cbufSlot);
+ SetHandle(config, texOp, cbufOffset, cbufSlot);
}
}
}
}
+
+ private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot)
+ {
+ texOp.SetHandle(cbufOffset, cbufSlot);
+ config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, cbufSlot, cbufOffset);
+ }
}
}
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs
index 41f42dad..ca46a1f5 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs
@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{
static class BindlessToIndexed
{
- public static void RunPass(BasicBlock block)
+ public static void RunPass(BasicBlock block, ShaderConfig config)
{
// We can turn a bindless texture access into a indexed access,
// as long the following conditions are true:
@@ -62,7 +62,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue;
}
- texOp.TurnIntoIndexed(addSrc1.Value / 4);
+ TurnIntoIndexed(config, texOp, addSrc1.Value / 4);
Operand index = Local();
@@ -75,5 +75,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
texOp.SetSource(0, index);
}
}
+
+ private static void TurnIntoIndexed(ShaderConfig config, TextureOperation texOp, int handle)
+ {
+ texOp.TurnIntoIndexed(handle);
+ config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, handle);
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
index a3417544..bccb0cbe 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
@@ -58,11 +58,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{
Operation operation = (Operation)node.Value;
+ bool isAtomic = operation.Inst.IsAtomic();
+ bool isWrite = isAtomic || operation.Inst == Instruction.StoreGlobal;
+
+ config.SetUsedStorageBuffer(storageIndex, isWrite);
+
Operand GetStorageOffset()
{
Operand addrLow = operation.GetSource(0);
- Operand baseAddrLow = Cbuf(0, GetStorageCbOffset(config.Stage, storageIndex));
+ Operand baseAddrLow = config.CreateCbuf(0, GetStorageCbOffset(config.Stage, storageIndex));
Operand baseAddrTrunc = Local();
@@ -96,7 +101,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
Operation storageOp;
- if (operation.Inst.IsAtomic())
+ if (isAtomic)
{
Instruction inst = (operation.Inst & ~Instruction.MrMask) | Instruction.MrStorage;
@@ -133,7 +138,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{
Operand addrLow = operation.GetSource(0);
- Operand baseAddrLow = Cbuf(0, UbeBaseOffset + storageIndex * StorageDescSize);
+ Operand baseAddrLow = config.CreateCbuf(0, UbeBaseOffset + storageIndex * StorageDescSize);
Operand baseAddrTrunc = Local();
@@ -157,9 +162,13 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
Operand[] sources = new Operand[operation.SourcesCount];
- sources[0] = Const(UbeFirstCbuf + storageIndex);
+ int cbSlot = UbeFirstCbuf + storageIndex;
+
+ sources[0] = Const(cbSlot);
sources[1] = GetCbufOffset();
+ config.SetUsedConstantBuffer(cbSlot);
+
for (int index = 2; index < operation.SourcesCount; index++)
{
sources[index] = operation.GetSource(index);
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
index ec8d8015..d184e6b4 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
@@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
{
GlobalToStorage.RunPass(blocks[blkIndex], config);
- BindlessToIndexed.RunPass(blocks[blkIndex]);
+ BindlessToIndexed.RunPass(blocks[blkIndex], config);
BindlessElimination.RunPass(blocks[blkIndex], config);
}
diff --git a/Ryujinx.Graphics.Shader/Translation/Rewriter.cs b/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
index 5427c013..07eeae48 100644
--- a/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
@@ -48,6 +48,9 @@ namespace Ryujinx.Graphics.Shader.Translation
{
Operation operation = (Operation)node.Value;
+ bool isAtomic = operation.Inst.IsAtomic();
+ bool isWrite = isAtomic || operation.Inst == Instruction.StoreGlobal;
+
Operation storageOp;
Operand PrependOperation(Instruction inst, params Operand[] sources)
@@ -67,11 +70,13 @@ namespace Ryujinx.Graphics.Shader.Translation
for (int slot = 0; slot < StorageMaxCount; slot++)
{
+ config.SetUsedStorageBuffer(slot, isWrite);
+
int cbOffset = GetStorageCbOffset(config.Stage, slot);
- Operand baseAddrLow = Cbuf(0, cbOffset);
- Operand baseAddrHigh = Cbuf(0, cbOffset + 1);
- Operand size = Cbuf(0, cbOffset + 2);
+ Operand baseAddrLow = config.CreateCbuf(0, cbOffset);
+ Operand baseAddrHigh = config.CreateCbuf(0, cbOffset + 1);
+ Operand size = config.CreateCbuf(0, cbOffset + 2);
Operand offset = PrependOperation(Instruction.Subtract, addrLow, baseAddrLow);
Operand borrow = PrependOperation(Instruction.CompareLessU32, addrLow, baseAddrLow);
@@ -104,7 +109,7 @@ namespace Ryujinx.Graphics.Shader.Translation
sources[index] = operation.GetSource(index);
}
- if (operation.Inst.IsAtomic())
+ if (isAtomic)
{
Instruction inst = (operation.Inst & ~Instruction.MrMask) | Instruction.MrStorage;
@@ -303,6 +308,7 @@ namespace Ryujinx.Graphics.Shader.Translation
node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize,
texOp.Type,
+ texOp.Format,
texOp.Flags,
texOp.Handle,
index,
@@ -350,6 +356,7 @@ namespace Ryujinx.Graphics.Shader.Translation
node.List.AddBefore(node, new TextureOperation(
Instruction.Lod,
texOp.Type,
+ texOp.Format,
texOp.Flags,
texOp.Handle,
1,
@@ -374,6 +381,7 @@ namespace Ryujinx.Graphics.Shader.Translation
node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize,
texOp.Type,
+ texOp.Format,
texOp.Flags,
texOp.Handle,
index,
@@ -409,6 +417,7 @@ namespace Ryujinx.Graphics.Shader.Translation
TextureOperation newTexOp = new TextureOperation(
Instruction.TextureSample,
texOp.Type,
+ texOp.Format,
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
texOp.Handle,
componentIndex,
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 077ce70d..3230f4e6 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -1,9 +1,16 @@
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
namespace Ryujinx.Graphics.Shader.Translation
{
class ShaderConfig
{
+ // TODO: Non-hardcoded array size.
+ public const int SamplerArraySize = 4;
+
public ShaderStage Stage { get; }
public bool GpPassthrough { get; }
@@ -24,8 +31,6 @@ namespace Ryujinx.Graphics.Shader.Translation
public TranslationFlags Flags { get; }
- public TranslationCounts Counts { get; }
-
public int Size { get; private set; }
public byte ClipDistancesWritten { get; private set; }
@@ -34,42 +39,80 @@ namespace Ryujinx.Graphics.Shader.Translation
public HashSet<int> TextureHandlesForCache { get; }
+ private readonly TranslationCounts _counts;
+
+ private int _usedConstantBuffers;
+ private int _usedStorageBuffers;
+ private int _usedStorageBuffersWrite;
+
+ private struct TextureInfo : IEquatable<TextureInfo>
+ {
+ public int CbufSlot { get; }
+ public int Handle { get; }
+ public bool Indexed { get; }
+ public TextureFormat Format { get; }
+
+ public TextureInfo(int cbufSlot, int handle, bool indexed, TextureFormat format)
+ {
+ CbufSlot = cbufSlot;
+ Handle = handle;
+ Indexed = indexed;
+ Format = format;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is TextureInfo other && Equals(other);
+ }
+
+ public bool Equals(TextureInfo other)
+ {
+ return CbufSlot == other.CbufSlot && Handle == other.Handle && Indexed == other.Indexed && Format == other.Format;
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(CbufSlot, Handle, Indexed, 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 BufferDescriptor[] _cachedConstantBufferDescriptors;
+ private BufferDescriptor[] _cachedStorageBufferDescriptors;
+ private TextureDescriptor[] _cachedTextureDescriptors;
+ private TextureDescriptor[] _cachedImageDescriptors;
+
public ShaderConfig(IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts)
{
Stage = ShaderStage.Compute;
- GpPassthrough = false;
- OutputTopology = OutputTopology.PointList;
- MaxOutputVertices = 0;
- LocalMemorySize = 0;
- ImapTypes = null;
- OmapTargets = null;
- OmapSampleMask = false;
- OmapDepth = false;
GpuAccessor = gpuAccessor;
Flags = flags;
- Size = 0;
- UsedFeatures = FeatureFlags.None;
- Counts = counts;
+ _counts = counts;
TextureHandlesForCache = new HashSet<int>();
+ _usedTextures = new Dictionary<TextureInfo, TextureMeta>();
+ _usedImages = new Dictionary<TextureInfo, TextureMeta>();
}
- public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts)
+ public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts) : this(gpuAccessor, flags, counts)
{
- Stage = header.Stage;
- GpPassthrough = header.Stage == ShaderStage.Geometry && header.GpPassthrough;
- OutputTopology = header.OutputTopology;
- MaxOutputVertices = header.MaxOutputVertexCount;
- LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize;
- ImapTypes = header.ImapTypes;
- OmapTargets = header.OmapTargets;
- OmapSampleMask = header.OmapSampleMask;
- OmapDepth = header.OmapDepth;
- GpuAccessor = gpuAccessor;
- Flags = flags;
- Size = 0;
- UsedFeatures = FeatureFlags.None;
- Counts = counts;
- TextureHandlesForCache = new HashSet<int>();
+ Stage = header.Stage;
+ GpPassthrough = header.Stage == ShaderStage.Geometry && header.GpPassthrough;
+ OutputTopology = header.OutputTopology;
+ MaxOutputVertices = header.MaxOutputVertexCount;
+ LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize;
+ ImapTypes = header.ImapTypes;
+ OmapTargets = header.OmapTargets;
+ OmapSampleMask = header.OmapSampleMask;
+ OmapDepth = header.OmapDepth;
}
public int GetDepthRegister()
@@ -126,5 +169,199 @@ namespace Ryujinx.Graphics.Shader.Translation
{
UsedFeatures |= flags;
}
+
+ public Operand CreateCbuf(int slot, int offset)
+ {
+ SetUsedConstantBuffer(slot);
+ return OperandHelper.Cbuf(slot, offset);
+ }
+
+ public void SetUsedConstantBuffer(int slot)
+ {
+ _usedConstantBuffers |= 1 << slot;
+ }
+
+ public void SetUsedStorageBuffer(int slot, bool write)
+ {
+ int mask = 1 << slot;
+ _usedStorageBuffers |= mask;
+
+ if (write)
+ {
+ _usedStorageBuffersWrite |= mask;
+ }
+ }
+
+ 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;
+ bool isWrite = inst == Instruction.ImageStore;
+ bool accurateType = inst != Instruction.TextureSize && inst != Instruction.Lod;
+
+ if (isImage)
+ {
+ SetUsedTextureOrImage(_usedImages, cbufSlot, handle, type, format, true, isWrite, false);
+ }
+ else
+ {
+ SetUsedTextureOrImage(_usedTextures, cbufSlot, handle, type, TextureFormat.Unknown, flags.HasFlag(TextureFlags.IntCoords), false, accurateType);
+ }
+ }
+
+ private static void SetUsedTextureOrImage(
+ Dictionary<TextureInfo, TextureMeta> dict,
+ int cbufSlot,
+ int handle,
+ SamplerType type,
+ TextureFormat format,
+ bool intCoords,
+ bool write,
+ bool accurateType)
+ {
+ var dimensions = type.GetDimensions();
+ var isArray = type.HasFlag(SamplerType.Array);
+ var isIndexed = type.HasFlag(SamplerType.Indexed);
+
+ var usageFlags = TextureUsageFlags.None;
+
+ if (intCoords)
+ {
+ usageFlags |= TextureUsageFlags.NeedsScaleValue;
+
+ var canScale = (dimensions == 2 && !isArray) || (dimensions == 3 && isArray);
+ 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;
+ }
+
+ 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))
+ {
+ 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;
+ }
+
+ dict[info] = meta;
+ }
+ else
+ {
+ dict.Add(info, meta);
+ }
+ }
+ }
+
+ public BufferDescriptor[] GetConstantBufferDescriptors()
+ {
+ if (_cachedConstantBufferDescriptors != null)
+ {
+ return _cachedConstantBufferDescriptors;
+ }
+
+ int usedMask = _usedConstantBuffers;
+
+ if (UsedFeatures.HasFlag(FeatureFlags.CbIndexing))
+ {
+ usedMask = FillMask(usedMask);
+ }
+
+ return _cachedConstantBufferDescriptors = GetBufferDescriptors(usedMask, 0, _counts.IncrementUniformBuffersCount);
+ }
+
+ public BufferDescriptor[] GetStorageBufferDescriptors()
+ {
+ return _cachedStorageBufferDescriptors ??= GetBufferDescriptors(FillMask(_usedStorageBuffers), _usedStorageBuffersWrite, _counts.IncrementStorageBuffersCount);
+ }
+
+ private static int FillMask(int mask)
+ {
+ // When the storage or uniform buffers are used as array, we must allocate a binding
+ // even for the "gaps" that are not used on the shader.
+ // For this reason, fill up the gaps so that all slots up to the highest one are
+ // marked as "used".
+ return mask != 0 ? (int)(uint.MaxValue >> BitOperations.LeadingZeroCount((uint)mask)) : 0;
+ }
+
+ private static BufferDescriptor[] GetBufferDescriptors(int usedMask, int writtenMask, Func<int> getBindingCallback)
+ {
+ var descriptors = new BufferDescriptor[BitOperations.PopCount((uint)usedMask)];
+
+ for (int i = 0; i < descriptors.Length; i++)
+ {
+ int slot = BitOperations.TrailingZeroCount(usedMask);
+
+ descriptors[i] = new BufferDescriptor(getBindingCallback(), slot);
+
+ if ((writtenMask & (1 << slot)) != 0)
+ {
+ descriptors[i].SetFlag(BufferUsageFlags.Write);
+ }
+
+ usedMask &= ~(1 << slot);
+ }
+
+ return descriptors;
+ }
+
+ public TextureDescriptor[] GetTextureDescriptors()
+ {
+ return _cachedTextureDescriptors ??= GetTextureOrImageDescriptors(_usedTextures, _counts.IncrementTexturesCount);
+ }
+
+ public TextureDescriptor[] GetImageDescriptors()
+ {
+ return _cachedImageDescriptors ??= GetTextureOrImageDescriptors(_usedImages, _counts.IncrementImagesCount);
+ }
+
+ private static TextureDescriptor[] GetTextureOrImageDescriptors(Dictionary<TextureInfo, TextureMeta> dict, Func<int> getBindingCallback)
+ {
+ var descriptors = new TextureDescriptor[dict.Count];
+
+ int i = 0;
+ foreach (var kv in dict.OrderBy(x => x.Key.Indexed).OrderBy(x => x.Key.Handle))
+ {
+ var info = kv.Key;
+ var meta = kv.Value;
+
+ int binding = getBindingCallback();
+
+ descriptors[i] = new TextureDescriptor(binding, meta.Type, info.Format, info.CbufSlot, info.Handle);
+ descriptors[i].SetFlag(meta.UsageFlags);
+ i++;
+ }
+
+ return descriptors;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index 1c15ccf2..74c6a653 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -87,18 +87,16 @@ namespace Ryujinx.Graphics.Shader.Translation
StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(funcs, config);
- GlslProgram program = GlslGenerator.Generate(sInfo, config);
+ string glslCode = GlslGenerator.Generate(sInfo, config);
shaderProgramInfo = new ShaderProgramInfo(
- program.CBufferDescriptors,
- program.SBufferDescriptors,
- program.TextureDescriptors,
- program.ImageDescriptors,
+ config.GetConstantBufferDescriptors(),
+ config.GetStorageBufferDescriptors(),
+ config.GetTextureDescriptors(),
+ config.GetImageDescriptors(),
config.UsedFeatures.HasFlag(FeatureFlags.InstanceId),
config.ClipDistancesWritten);
- string glslCode = program.Code;
-
return new ShaderProgram(config.Stage, glslCode);
}
@@ -112,7 +110,7 @@ namespace Ryujinx.Graphics.Shader.Translation
Block[][] cfg;
ulong maxEndAddress = 0;
- bool hasBindless = false;
+ bool hasBindless;
if ((flags & TranslationFlags.Compute) != 0)
{