From f92921a6d118aa9c6acdb3ecaa3cd61a19fe341e Mon Sep 17 00:00:00 2001 From: gdkchan Date: Thu, 15 Jun 2023 17:31:53 -0300 Subject: Implement Load/Store Local/Shared and Atomic shared using new instructions (#5241) * Implement Load/Store Local/Shared and Atomic shared using new instructions * Remove now unused code * Fix base offset register overwrite * Fix missing storage buffer set index when generating GLSL for Vulkan * Shader cache version bump * Remove more unused code * Some PR feedback --- .../CodeGen/Spirv/CodeGenContext.cs | 5 +- .../CodeGen/Spirv/Declarations.cs | 60 ++----- .../CodeGen/Spirv/Instructions.cs | 176 ++++----------------- 3 files changed, 44 insertions(+), 197 deletions(-) (limited to 'src/Ryujinx.Graphics.Shader/CodeGen/Spirv') diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs index 1f5167e6..a4daaa67 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs @@ -25,8 +25,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv public Dictionary ConstantBuffers { get; } = new Dictionary(); public Dictionary StorageBuffers { get; } = new Dictionary(); - public Instruction LocalMemory { get; set; } - public Instruction SharedMemory { get; set; } + public Dictionary LocalMemories { get; } = new Dictionary(); + public Dictionary SharedMemories { get; } = new Dictionary(); public Dictionary SamplersTypes { get; } = new Dictionary(); public Dictionary Samplers { get; } = new Dictionary(); public Dictionary Images { get; } = new Dictionary(); @@ -35,7 +35,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv public Dictionary InputsPerPatch { get; } = new Dictionary(); public Dictionary OutputsPerPatch { get; } = new Dictionary(); - public Instruction CoordTemp { get; set; } public StructuredFunction CurrentFunction { get; set; } private readonly Dictionary _locals = new Dictionary(); private readonly Dictionary _localForArgs = new Dictionary(); diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs index eb2db514..59acea4f 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs @@ -6,7 +6,6 @@ using Spv.Generator; using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Numerics; using static Spv.Specification; using SpvInstruction = Spv.Generator.Instruction; @@ -44,13 +43,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv context.AddLocalVariable(spvLocal); context.DeclareLocal(local, spvLocal); } - - var ivector2Type = context.TypeVector(context.TypeS32(), 2); - var coordTempPointerType = context.TypePointer(StorageClass.Function, ivector2Type); - var coordTemp = context.Variable(coordTempPointerType, StorageClass.Function); - - context.AddLocalVariable(coordTemp); - context.CoordTemp = coordTemp; } public static void DeclareLocalForArgs(CodeGenContext context, List functions) @@ -77,54 +69,30 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info) { - if (context.Config.Stage == ShaderStage.Compute) - { - int localMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeLocalMemorySize(), 4); - - if (localMemorySize != 0) - { - DeclareLocalMemory(context, localMemorySize); - } - - int sharedMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeSharedMemorySize(), 4); - - if (sharedMemorySize != 0) - { - DeclareSharedMemory(context, sharedMemorySize); - } - } - else if (context.Config.LocalMemorySize != 0) - { - int localMemorySize = BitUtils.DivRoundUp(context.Config.LocalMemorySize, 4); - DeclareLocalMemory(context, localMemorySize); - } - DeclareConstantBuffers(context, context.Config.Properties.ConstantBuffers.Values); DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values); + DeclareMemories(context, context.Config.Properties.LocalMemories, context.LocalMemories, StorageClass.Private); + DeclareMemories(context, context.Config.Properties.SharedMemories, context.SharedMemories, StorageClass.Workgroup); DeclareSamplers(context, context.Config.GetTextureDescriptors()); DeclareImages(context, context.Config.GetImageDescriptors()); DeclareInputsAndOutputs(context, info); } - private static void DeclareLocalMemory(CodeGenContext context, int size) - { - context.LocalMemory = DeclareMemory(context, StorageClass.Private, size); - } - - private static void DeclareSharedMemory(CodeGenContext context, int size) + private static void DeclareMemories( + CodeGenContext context, + IReadOnlyDictionary memories, + Dictionary dict, + StorageClass storage) { - context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size); - } - - private static SpvInstruction DeclareMemory(CodeGenContext context, StorageClass storage, int size) - { - var arrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), size)); - var pointerType = context.TypePointer(storage, arrayType); - var variable = context.Variable(pointerType, storage); + foreach ((int id, MemoryDefinition memory) in memories) + { + var pointerType = context.TypePointer(storage, context.GetType(memory.Type, memory.ArrayLength)); + var variable = context.Variable(pointerType, storage); - context.AddGlobalVariable(variable); + context.AddGlobalVariable(variable); - return variable; + dict.Add(id, variable); + } } private static void DeclareConstantBuffers(CodeGenContext context, IEnumerable buffers) diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs index 6c115752..b451f7a4 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs @@ -97,8 +97,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv Add(Instruction.ImageStore, GenerateImageStore); Add(Instruction.IsNan, GenerateIsNan); Add(Instruction.Load, GenerateLoad); - Add(Instruction.LoadLocal, GenerateLoadLocal); - Add(Instruction.LoadShared, GenerateLoadShared); Add(Instruction.Lod, GenerateLod); Add(Instruction.LogarithmB2, GenerateLogarithmB2); Add(Instruction.LogicalAnd, GenerateLogicalAnd); @@ -132,10 +130,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv Add(Instruction.Sine, GenerateSine); Add(Instruction.SquareRoot, GenerateSquareRoot); Add(Instruction.Store, GenerateStore); - Add(Instruction.StoreLocal, GenerateStoreLocal); - Add(Instruction.StoreShared, GenerateStoreShared); - Add(Instruction.StoreShared16, GenerateStoreShared16); - Add(Instruction.StoreShared8, GenerateStoreShared8); Add(Instruction.Subtract, GenerateSubtract); Add(Instruction.SwizzleAdd, GenerateSwizzleAdd); Add(Instruction.TextureSample, GenerateTextureSample); @@ -871,30 +865,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv return GenerateLoadOrStore(context, operation, isStore: false); } - private static OperationResult GenerateLoadLocal(CodeGenContext context, AstOperation operation) - { - return GenerateLoadLocalOrShared(context, operation, StorageClass.Private, context.LocalMemory); - } - - private static OperationResult GenerateLoadShared(CodeGenContext context, AstOperation operation) - { - return GenerateLoadLocalOrShared(context, operation, StorageClass.Workgroup, context.SharedMemory); - } - - private static OperationResult GenerateLoadLocalOrShared( - CodeGenContext context, - AstOperation operation, - StorageClass storageClass, - SpvInstruction memory) - { - var offset = context.Get(AggregateType.S32, operation.GetSource(0)); - - var elemPointer = context.AccessChain(context.TypePointer(storageClass, context.TypeU32()), memory, offset); - 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; @@ -1268,45 +1238,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv return GenerateLoadOrStore(context, operation, isStore: true); } - private static OperationResult GenerateStoreLocal(CodeGenContext context, AstOperation operation) - { - return GenerateStoreLocalOrShared(context, operation, StorageClass.Private, context.LocalMemory); - } - - private static OperationResult GenerateStoreShared(CodeGenContext context, AstOperation operation) - { - return GenerateStoreLocalOrShared(context, operation, StorageClass.Workgroup, context.SharedMemory); - } - - private static OperationResult GenerateStoreLocalOrShared( - CodeGenContext context, - AstOperation operation, - StorageClass storageClass, - SpvInstruction memory) - { - var offset = context.Get(AggregateType.S32, operation.GetSource(0)); - var value = context.Get(AggregateType.U32, operation.GetSource(1)); - - var elemPointer = context.AccessChain(context.TypePointer(storageClass, context.TypeU32()), memory, offset); - context.Store(elemPointer, value); - - return OperationResult.Invalid; - } - - private static OperationResult GenerateStoreShared16(CodeGenContext context, AstOperation operation) - { - GenerateStoreSharedSmallInt(context, operation, 16); - - return OperationResult.Invalid; - } - - private static OperationResult GenerateStoreShared8(CodeGenContext context, AstOperation operation) - { - GenerateStoreSharedSmallInt(context, operation, 8); - - return OperationResult.Invalid; - } - private static OperationResult GenerateSubtract(CodeGenContext context, AstOperation operation) { return GenerateBinary(context, operation, context.Delegates.FSub, context.Delegates.ISub); @@ -1827,55 +1758,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv AstOperation operation, Func emitU) { - var value = context.GetU32(operation.GetSource(operation.SourcesCount - 1)); + SpvInstruction elemPointer = GetStoragePointer(context, operation, out AggregateType varType); - SpvInstruction elemPointer; - - if (operation.StorageKind == StorageKind.StorageBuffer) - { - elemPointer = GetStoragePointer(context, operation, out _); - } - else if (operation.StorageKind == StorageKind.SharedMemory) - { - var offset = context.GetU32(operation.GetSource(0)); - elemPointer = context.AccessChain(context.TypePointer(StorageClass.Workgroup, context.TypeU32()), context.SharedMemory, offset); - } - else - { - throw new InvalidOperationException($"Invalid storage kind \"{operation.StorageKind}\"."); - } + var value = context.Get(varType, operation.GetSource(operation.SourcesCount - 1)); var one = context.Constant(context.TypeU32(), 1); var zero = context.Constant(context.TypeU32(), 0); - return new OperationResult(AggregateType.U32, emitU(context.TypeU32(), elemPointer, one, zero, value)); + return new OperationResult(varType, emitU(context.GetType(varType), elemPointer, one, zero, value)); } private static OperationResult GenerateAtomicMemoryCas(CodeGenContext context, AstOperation operation) { - var value0 = context.GetU32(operation.GetSource(operation.SourcesCount - 2)); - var value1 = context.GetU32(operation.GetSource(operation.SourcesCount - 1)); + SpvInstruction elemPointer = GetStoragePointer(context, operation, out AggregateType varType); - SpvInstruction elemPointer; - - if (operation.StorageKind == StorageKind.StorageBuffer) - { - elemPointer = GetStoragePointer(context, operation, out _); - } - else if (operation.StorageKind == StorageKind.SharedMemory) - { - var offset = context.GetU32(operation.GetSource(0)); - elemPointer = context.AccessChain(context.TypePointer(StorageClass.Workgroup, context.TypeU32()), context.SharedMemory, offset); - } - else - { - throw new InvalidOperationException($"Invalid storage kind \"{operation.StorageKind}\"."); - } + var value0 = context.Get(varType, operation.GetSource(operation.SourcesCount - 2)); + var value1 = context.Get(varType, operation.GetSource(operation.SourcesCount - 1)); var one = context.Constant(context.TypeU32(), 1); var zero = context.Constant(context.TypeU32(), 0); - return new OperationResult(AggregateType.U32, context.AtomicCompareExchange(context.TypeU32(), elemPointer, one, zero, zero, value1, value0)); + return new OperationResult(varType, context.AtomicCompareExchange(context.GetType(varType), elemPointer, one, zero, zero, value1, value0)); } private static OperationResult GenerateLoadOrStore(CodeGenContext context, AstOperation operation, bool isStore) @@ -1928,6 +1831,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv : context.StorageBuffers[bindingIndex.Value]; break; + case StorageKind.LocalMemory: + case StorageKind.SharedMemory: + if (!(operation.GetSource(srcIndex++) is AstOperand bindingId) || bindingId.Type != OperandType.Constant) + { + throw new InvalidOperationException($"First input of {operation.Inst} with {storageKind} storage must be a constant operand."); + } + + if (storageKind == StorageKind.LocalMemory) + { + storageClass = StorageClass.Private; + varType = context.Config.Properties.LocalMemories[bindingId.Value].Type & AggregateType.ElementTypeMask; + baseObj = context.LocalMemories[bindingId.Value]; + } + else + { + storageClass = StorageClass.Workgroup; + varType = context.Config.Properties.SharedMemories[bindingId.Value].Type & AggregateType.ElementTypeMask; + baseObj = context.SharedMemories[bindingId.Value]; + } + break; + case StorageKind.Input: case StorageKind.InputPerPatch: case StorageKind.Output: @@ -2048,50 +1972,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv return context.Load(context.GetType(varType), context.Inputs[ioDefinition]); } - private static void GenerateStoreSharedSmallInt(CodeGenContext context, AstOperation operation, int bitSize) - { - var offset = context.Get(AggregateType.U32, operation.GetSource(0)); - var value = context.Get(AggregateType.U32, operation.GetSource(1)); - - 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 memory = context.SharedMemory; - - var elemPointer = context.AccessChain(context.TypePointer(StorageClass.Workgroup, context.TypeU32()), memory, wordOffset); - - GenerateStoreSmallInt(context, elemPointer, bitOffset, value, bitSize); - } - - private static void GenerateStoreSmallInt( - CodeGenContext context, - SpvInstruction elemPointer, - SpvInstruction bitOffset, - SpvInstruction value, - int bitSize) - { - var loopStart = context.Label(); - var loopEnd = context.Label(); - - context.Branch(loopStart); - context.AddLabel(loopStart); - - var oldValue = context.Load(context.TypeU32(), elemPointer); - var newValue = context.BitFieldInsert(context.TypeU32(), oldValue, value, bitOffset, context.Constant(context.TypeU32(), bitSize)); - - var one = context.Constant(context.TypeU32(), 1); - var zero = context.Constant(context.TypeU32(), 0); - - var result = context.AtomicCompareExchange(context.TypeU32(), elemPointer, one, zero, zero, newValue, oldValue); - var failed = context.INotEqual(context.TypeBool(), result, oldValue); - - context.LoopMerge(loopEnd, loopStart, LoopControlMask.MaskNone); - context.BranchConditional(failed, loopStart, loopEnd); - - context.AddLabel(loopEnd); - } - private static OperationResult GetZeroOperationResult( CodeGenContext context, AstTextureOperation texOp, -- cgit v1.2.3