aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader/CodeGen/Spirv
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-06-03 20:12:18 -0300
committerGitHub <noreply@github.com>2023-06-03 20:12:18 -0300
commit21c9ac6240a3db3300143d1d0dd4a1070d4f576f (patch)
tree1d3fbafa1861368efe7cf8c923752cb0b621f717 /src/Ryujinx.Graphics.Shader/CodeGen/Spirv
parent81c9052847f1aa4a70010fefa8e6ee38b5ace612 (diff)
Implement shader storage buffer operations using new Load/Store instructions (#4993)
* Implement storage buffer operations using new Load/Store instruction * Extend GenerateMultiTargetStorageOp to also match access with constant offset, and log and comments * Remove now unused code * Catch more complex cases of global memory usage * Shader cache version bump * Extend global access elimination to work with more shared memory cases * Change alignment requirement from 16 bytes to 8 bytes, handle cases where we need more than 16 storage buffers * Tweak preferencing to catch more cases * Enable CB0 elimination even when host storage buffer alignment is > 16 (for Intel) * Fix storage buffer bindings * Simplify some code * Shader cache version bump * Fix typo * Extend global memory elimination to handle shared memory with multiple possible offsets and local memory
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/CodeGen/Spirv')
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs11
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs74
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs119
3 files changed, 82 insertions, 122 deletions
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
index 7af6d316..c1bfa088 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
public int InputVertices { get; }
public Dictionary<int, Instruction> ConstantBuffers { get; } = new Dictionary<int, Instruction>();
- public Instruction StorageBuffersArray { get; set; }
+ public Dictionary<int, Instruction> StorageBuffers { get; } = new Dictionary<int, Instruction>();
public Instruction LocalMemory { get; set; }
public Instruction SharedMemory { get; set; }
public Dictionary<TextureMeta, SamplerType> SamplersTypes { get; } = new Dictionary<TextureMeta, SamplerType>();
@@ -308,7 +308,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
{
if ((type & AggregateType.Array) != 0)
{
- return TypeArray(GetType(type & ~AggregateType.Array), Constant(TypeU32(), length));
+ if (length > 0)
+ {
+ return TypeArray(GetType(type & ~AggregateType.Array), Constant(TypeU32(), length));
+ }
+ else
+ {
+ return TypeRuntimeArray(GetType(type & ~AggregateType.Array));
+ }
}
else if ((type & AggregateType.ElementCountMask) != 0)
{
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
index 7c242589..eb2db514 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
@@ -5,6 +5,7 @@ using Ryujinx.Graphics.Shader.Translation;
using Spv.Generator;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Numerics;
using static Spv.Specification;
@@ -99,7 +100,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
}
DeclareConstantBuffers(context, context.Config.Properties.ConstantBuffers.Values);
- DeclareStorageBuffers(context, context.Config.GetStorageBufferDescriptors());
+ DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values);
DeclareSamplers(context, context.Config.GetTextureDescriptors());
DeclareImages(context, context.Config.GetImageDescriptors());
DeclareInputsAndOutputs(context, info);
@@ -128,6 +129,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
private static void DeclareConstantBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers)
{
+ DeclareBuffers(context, buffers, isBuffer: false);
+ }
+
+ private static void DeclareStorageBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers)
+ {
+ DeclareBuffers(context, buffers, isBuffer: true);
+ }
+
+ private static void DeclareBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers, bool isBuffer)
+ {
HashSet<SpvInstruction> decoratedTypes = new HashSet<SpvInstruction>();
foreach (BufferDefinition buffer in buffers)
@@ -155,6 +166,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
context.Decorate(structFieldTypes[fieldIndex], Decoration.ArrayStride, (LiteralInteger)fieldSize);
}
+ // Zero lengths are assumed to be a "runtime array" (which does not have a explicit length
+ // specified on the shader, and instead assumes the bound buffer length).
+ // It is only valid as the last struct element.
+
+ Debug.Assert(field.ArrayLength > 0 || fieldIndex == buffer.Type.Fields.Length - 1);
+
offset += fieldSize * field.ArrayLength;
}
else
@@ -163,54 +180,35 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
}
}
- var ubStructType = context.TypeStruct(false, structFieldTypes);
+ var structType = context.TypeStruct(false, structFieldTypes);
- if (decoratedTypes.Add(ubStructType))
+ if (decoratedTypes.Add(structType))
{
- context.Decorate(ubStructType, Decoration.Block);
+ context.Decorate(structType, isBuffer ? Decoration.BufferBlock : Decoration.Block);
for (int fieldIndex = 0; fieldIndex < structFieldOffsets.Length; fieldIndex++)
{
- context.MemberDecorate(ubStructType, fieldIndex, Decoration.Offset, (LiteralInteger)structFieldOffsets[fieldIndex]);
+ context.MemberDecorate(structType, fieldIndex, Decoration.Offset, (LiteralInteger)structFieldOffsets[fieldIndex]);
}
}
- var ubPointerType = context.TypePointer(StorageClass.Uniform, ubStructType);
- var ubVariable = context.Variable(ubPointerType, StorageClass.Uniform);
+ var pointerType = context.TypePointer(StorageClass.Uniform, structType);
+ var variable = context.Variable(pointerType, StorageClass.Uniform);
- context.Name(ubVariable, buffer.Name);
- context.Decorate(ubVariable, Decoration.DescriptorSet, (LiteralInteger)buffer.Set);
- context.Decorate(ubVariable, Decoration.Binding, (LiteralInteger)buffer.Binding);
- context.AddGlobalVariable(ubVariable);
- context.ConstantBuffers.Add(buffer.Binding, ubVariable);
- }
- }
+ context.Name(variable, buffer.Name);
+ context.Decorate(variable, Decoration.DescriptorSet, (LiteralInteger)buffer.Set);
+ context.Decorate(variable, Decoration.Binding, (LiteralInteger)buffer.Binding);
+ context.AddGlobalVariable(variable);
- private static void DeclareStorageBuffers(CodeGenContext context, BufferDescriptor[] descriptors)
- {
- if (descriptors.Length == 0)
- {
- return;
+ if (isBuffer)
+ {
+ context.StorageBuffers.Add(buffer.Binding, variable);
+ }
+ else
+ {
+ context.ConstantBuffers.Add(buffer.Binding, variable);
+ }
}
-
- int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 1 : 0;
- int count = descriptors.Max(x => x.Slot) + 1;
-
- var sbArrayType = context.TypeRuntimeArray(context.TypeU32());
- context.Decorate(sbArrayType, Decoration.ArrayStride, (LiteralInteger)4);
- var sbStructType = context.TypeStruct(true, sbArrayType);
- context.Decorate(sbStructType, Decoration.BufferBlock);
- context.MemberDecorate(sbStructType, 0, Decoration.Offset, (LiteralInteger)0);
- var sbStructArrayType = context.TypeArray(sbStructType, context.Constant(context.TypeU32(), count));
- var sbPointerType = context.TypePointer(StorageClass.Uniform, sbStructArrayType);
- var sbVariable = context.Variable(sbPointerType, StorageClass.Uniform);
-
- context.Name(sbVariable, $"{GetStagePrefix(context.Config.Stage)}_s");
- context.Decorate(sbVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
- context.Decorate(sbVariable, Decoration.Binding, (LiteralInteger)context.Config.FirstStorageBufferBinding);
- context.AddGlobalVariable(sbVariable);
-
- context.StorageBuffersArray = sbVariable;
}
private static void DeclareSamplers(CodeGenContext context, TextureDescriptor[] descriptors)
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
index f088a47f..4be0c62b 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
@@ -99,7 +99,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
Add(Instruction.Load, GenerateLoad);
Add(Instruction.LoadLocal, GenerateLoadLocal);
Add(Instruction.LoadShared, GenerateLoadShared);
- Add(Instruction.LoadStorage, GenerateLoadStorage);
Add(Instruction.Lod, GenerateLod);
Add(Instruction.LogarithmB2, GenerateLogarithmB2);
Add(Instruction.LogicalAnd, GenerateLogicalAnd);
@@ -137,9 +136,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
Add(Instruction.StoreShared, GenerateStoreShared);
Add(Instruction.StoreShared16, GenerateStoreShared16);
Add(Instruction.StoreShared8, GenerateStoreShared8);
- Add(Instruction.StoreStorage, GenerateStoreStorage);
- Add(Instruction.StoreStorage16, GenerateStoreStorage16);
- Add(Instruction.StoreStorage8, GenerateStoreStorage8);
Add(Instruction.Subtract, GenerateSubtract);
Add(Instruction.SwizzleAdd, GenerateSwizzleAdd);
Add(Instruction.TextureSample, GenerateTextureSample);
@@ -889,14 +885,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return new OperationResult(AggregateType.U32, value);
}
- private static OperationResult GenerateLoadStorage(CodeGenContext context, AstOperation operation)
- {
- var elemPointer = GetStorageElemPointer(context, operation);
- var value = context.Load(context.TypeU32(), elemPointer);
-
- return new OperationResult(AggregateType.U32, value);
- }
-
private static OperationResult GenerateLod(CodeGenContext context, AstOperation operation)
{
AstTextureOperation texOp = (AstTextureOperation)operation;
@@ -1307,28 +1295,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return OperationResult.Invalid;
}
- private static OperationResult GenerateStoreStorage(CodeGenContext context, AstOperation operation)
- {
- var elemPointer = GetStorageElemPointer(context, operation);
- context.Store(elemPointer, context.Get(AggregateType.U32, operation.GetSource(2)));
-
- return OperationResult.Invalid;
- }
-
- private static OperationResult GenerateStoreStorage16(CodeGenContext context, AstOperation operation)
- {
- GenerateStoreStorageSmallInt(context, operation, 16);
-
- return OperationResult.Invalid;
- }
-
- private static OperationResult GenerateStoreStorage8(CodeGenContext context, AstOperation operation)
- {
- GenerateStoreStorageSmallInt(context, operation, 8);
-
- return OperationResult.Invalid;
- }
-
private static OperationResult GenerateSubtract(CodeGenContext context, AstOperation operation)
{
return GenerateBinary(context, operation, context.Delegates.FSub, context.Delegates.ISub);
@@ -1849,13 +1815,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
AstOperation operation,
Func<SpvInstruction, SpvInstruction, SpvInstruction, SpvInstruction, SpvInstruction, SpvInstruction> emitU)
{
- var value = context.GetU32(operation.GetSource(2));
+ var value = context.GetU32(operation.GetSource(operation.SourcesCount - 1));
SpvInstruction elemPointer;
if (operation.StorageKind == StorageKind.StorageBuffer)
{
- elemPointer = GetStorageElemPointer(context, operation);
+ elemPointer = GetStoragePointer(context, operation, out _);
}
else if (operation.StorageKind == StorageKind.SharedMemory)
{
@@ -1875,14 +1841,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
private static OperationResult GenerateAtomicMemoryCas(CodeGenContext context, AstOperation operation)
{
- var value0 = context.GetU32(operation.GetSource(2));
- var value1 = context.GetU32(operation.GetSource(3));
+ var value0 = context.GetU32(operation.GetSource(operation.SourcesCount - 2));
+ var value1 = context.GetU32(operation.GetSource(operation.SourcesCount - 1));
SpvInstruction elemPointer;
if (operation.StorageKind == StorageKind.StorageBuffer)
{
- elemPointer = GetStorageElemPointer(context, operation);
+ elemPointer = GetStoragePointer(context, operation, out _);
}
else if (operation.StorageKind == StorageKind.SharedMemory)
{
@@ -1902,16 +1868,32 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
private static OperationResult GenerateLoadOrStore(CodeGenContext context, AstOperation operation, bool isStore)
{
+ SpvInstruction pointer = GetStoragePointer(context, operation, out AggregateType varType);
+
+ if (isStore)
+ {
+ context.Store(pointer, context.Get(varType, operation.GetSource(operation.SourcesCount - 1)));
+ return OperationResult.Invalid;
+ }
+ else
+ {
+ var result = context.Load(context.GetType(varType), pointer);
+ return new OperationResult(varType, result);
+ }
+ }
+
+ private static SpvInstruction GetStoragePointer(CodeGenContext context, AstOperation operation, out AggregateType varType)
+ {
StorageKind storageKind = operation.StorageKind;
StorageClass storageClass;
SpvInstruction baseObj;
- AggregateType varType;
int srcIndex = 0;
switch (storageKind)
{
case StorageKind.ConstantBuffer:
+ case StorageKind.StorageBuffer:
if (!(operation.GetSource(srcIndex++) is AstOperand bindingIndex) || bindingIndex.Type != OperandType.Constant)
{
throw new InvalidOperationException($"First input of {operation.Inst} with {storageKind} storage must be a constant operand.");
@@ -1922,12 +1904,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
throw new InvalidOperationException($"Second input of {operation.Inst} with {storageKind} storage must be a constant operand.");
}
- BufferDefinition buffer = context.Config.Properties.ConstantBuffers[bindingIndex.Value];
+ BufferDefinition buffer = storageKind == StorageKind.ConstantBuffer
+ ? context.Config.Properties.ConstantBuffers[bindingIndex.Value]
+ : context.Config.Properties.StorageBuffers[bindingIndex.Value];
StructureField field = buffer.Type.Fields[fieldIndex.Value];
storageClass = StorageClass.Uniform;
varType = field.Type & AggregateType.ElementTypeMask;
- baseObj = context.ConstantBuffers[bindingIndex.Value];
+ baseObj = storageKind == StorageKind.ConstantBuffer
+ ? context.ConstantBuffers[bindingIndex.Value]
+ : context.StorageBuffers[bindingIndex.Value];
break;
case StorageKind.Input:
@@ -1993,7 +1979,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
throw new InvalidOperationException($"Invalid storage kind {storageKind}.");
}
- int inputsCount = (isStore ? operation.SourcesCount - 1 : operation.SourcesCount) - srcIndex;
+ bool isStoreOrAtomic = operation.Inst == Instruction.Store || operation.Inst.IsAtomic();
+ int inputsCount = (isStoreOrAtomic ? operation.SourcesCount - 1 : operation.SourcesCount) - srcIndex;
+
+ if (operation.Inst == Instruction.AtomicCompareAndSwap)
+ {
+ inputsCount--;
+ }
+
SpvInstruction e0, e1, e2;
SpvInstruction pointer;
@@ -2030,16 +2023,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
break;
}
- if (isStore)
- {
- context.Store(pointer, context.Get(varType, operation.GetSource(srcIndex)));
- return OperationResult.Invalid;
- }
- else
- {
- var result = context.Load(context.GetType(varType), pointer);
- return new OperationResult(varType, result);
- }
+ return pointer;
}
private static SpvInstruction GetScalarInput(CodeGenContext context, IoVariable ioVariable)
@@ -2068,25 +2052,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
GenerateStoreSmallInt(context, elemPointer, bitOffset, value, bitSize);
}
- private static void GenerateStoreStorageSmallInt(CodeGenContext context, AstOperation operation, int bitSize)
- {
- var i0 = context.Get(AggregateType.S32, operation.GetSource(0));
- var offset = context.Get(AggregateType.U32, operation.GetSource(1));
- var value = context.Get(AggregateType.U32, operation.GetSource(2));
-
- var wordOffset = context.ShiftRightLogical(context.TypeU32(), offset, context.Constant(context.TypeU32(), 2));
- var bitOffset = context.BitwiseAnd(context.TypeU32(), offset, context.Constant(context.TypeU32(), 3));
- bitOffset = context.ShiftLeftLogical(context.TypeU32(), bitOffset, context.Constant(context.TypeU32(), 3));
-
- var sbVariable = context.StorageBuffersArray;
-
- var i1 = context.Constant(context.TypeS32(), 0);
-
- var elemPointer = context.AccessChain(context.TypePointer(StorageClass.Uniform, context.TypeU32()), sbVariable, i0, i1, wordOffset);
-
- GenerateStoreSmallInt(context, elemPointer, bitOffset, value, bitSize);
- }
-
private static void GenerateStoreSmallInt(
CodeGenContext context,
SpvInstruction elemPointer,
@@ -2173,16 +2138,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
}
}
- private static SpvInstruction GetStorageElemPointer(CodeGenContext context, AstOperation operation)
- {
- var sbVariable = context.StorageBuffersArray;
- var i0 = context.Get(AggregateType.S32, operation.GetSource(0));
- var i1 = context.Constant(context.TypeS32(), 0);
- var i2 = context.Get(AggregateType.S32, operation.GetSource(1));
-
- return context.AccessChain(context.TypePointer(StorageClass.Uniform, context.TypeU32()), sbVariable, i0, i1, i2);
- }
-
private static OperationResult GenerateUnary(
CodeGenContext context,
AstOperation operation,