From e453ba69f42057d36559b2c84b6ad9f01eaf4c86 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 26 Jan 2021 03:38:33 -0300 Subject: [PATCH] Add support for shader atomic min/max (S32) (#1948) --- .../CodeGen/Glsl/Declarations.cs | 16 +++++++++++++- .../AtomicMinMaxS32Shared.glsl | 21 +++++++++++++++++++ .../AtomicMinMaxS32Storage.glsl | 21 +++++++++++++++++++ .../HelperFunctions/HelperFunctionNames.cs | 3 +++ .../HelperFunctions/TexelFetchScale_cp.glsl | 6 ++++-- .../HelperFunctions/TexelFetchScale_fp.glsl | 13 ++++++++---- .../CodeGen/Glsl/Instructions/InstGen.cs | 14 ++++++++----- .../Glsl/Instructions/InstGenHelper.cs | 4 ++-- .../Ryujinx.Graphics.Shader.csproj | 2 ++ .../StructuredIr/HelperFunctionsMask.cs | 16 +++++++------- .../StructuredIr/StructuredProgram.cs | 8 +++++++ 11 files changed, 103 insertions(+), 21 deletions(-) create mode 100644 Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Shared.glsl create mode 100644 Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Storage.glsl diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index d43fe6324..a6109a959 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs @@ -157,6 +157,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl } } + if ((info.HelperFunctionsMask & HelperFunctionsMask.AtomicMinMaxS32Shared) != 0) + { + AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Shared.glsl"); + } + + if ((info.HelperFunctionsMask & HelperFunctionsMask.AtomicMinMaxS32Storage) != 0) + { + AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Storage.glsl"); + } + if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighS32) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/MultiplyHighS32.glsl"); @@ -523,7 +533,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl { string code = EmbeddedResources.ReadAllText(filename); - context.AppendLine(code.Replace("\t", CodeGenContext.Tab)); + code = code.Replace("\t", CodeGenContext.Tab); + code = code.Replace("$SHARED_MEM$", DefaultNames.SharedMemoryName); + code = code.Replace("$STORAGE_MEM$", OperandManager.GetShaderStagePrefix(context.Config.Stage) + "_" + DefaultNames.StorageNamePrefix); + + context.AppendLine(code); context.AppendLine(); } } diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Shared.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Shared.glsl new file mode 100644 index 000000000..9f8c641df --- /dev/null +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Shared.glsl @@ -0,0 +1,21 @@ +int Helper_AtomicMaxS32(int offset, int value) +{ + uint oldValue, newValue; + do + { + oldValue = $SHARED_MEM$[offset]; + newValue = uint(max(int(oldValue), value)); + } while (atomicCompSwap($SHARED_MEM$[offset], newValue, oldValue) != oldValue); + return int(oldValue); +} + +int Helper_AtomicMinS32(int offset, int value) +{ + uint oldValue, newValue; + do + { + oldValue = $SHARED_MEM$[offset]; + newValue = uint(min(int(oldValue), value)); + } while (atomicCompSwap($SHARED_MEM$[offset], newValue, oldValue) != oldValue); + return int(oldValue); +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Storage.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Storage.glsl new file mode 100644 index 000000000..fc3af6a73 --- /dev/null +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Storage.glsl @@ -0,0 +1,21 @@ +int Helper_AtomicMaxS32(int index, int offset, int value) +{ + uint oldValue, newValue; + do + { + oldValue = $STORAGE_MEM$[index].data[offset]; + newValue = uint(max(int(oldValue), value)); + } while (atomicCompSwap($STORAGE_MEM$[index].data[offset], newValue, oldValue) != oldValue); + return int(oldValue); +} + +int Helper_AtomicMinS32(int index, int offset, int value) +{ + uint oldValue, newValue; + do + { + oldValue = $STORAGE_MEM$[index].data[offset]; + newValue = uint(min(int(oldValue), value)); + } while (atomicCompSwap($STORAGE_MEM$[index].data[offset], newValue, oldValue) != oldValue); + return int(oldValue); +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/HelperFunctionNames.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/HelperFunctionNames.cs index 21c435475..1ff127bb3 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/HelperFunctionNames.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/HelperFunctionNames.cs @@ -2,6 +2,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl { static class HelperFunctionNames { + public static string AtomicMaxS32 = "Helper_AtomicMaxS32"; + public static string AtomicMinS32 = "Helper_AtomicMinS32"; + public static string MultiplyHighS32 = "Helper_MultiplyHighS32"; public static string MultiplyHighU32 = "Helper_MultiplyHighU32"; diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl index 381566d37..88d18246d 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl @@ -1,6 +1,8 @@ -ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex) { +ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex) +{ float scale = cp_renderScale[samplerIndex]; - if (scale == 1.0) { + if (scale == 1.0) + { return inputVec; } return ivec2(vec2(inputVec) * scale); diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl index 4efaa65af..2e166a4be 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl @@ -1,11 +1,16 @@ -ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex) { +ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex) +{ float scale = fp_renderScale[1 + samplerIndex]; - if (scale == 1.0) { + if (scale == 1.0) + { return inputVec; } - if (scale < 0.0) { // If less than 0, try interpolate between texels by using the screen position. + if (scale < 0.0) // If less than 0, try interpolate between texels by using the screen position. + { return ivec2(vec2(inputVec) * (-scale) + mod(gl_FragCoord.xy, -scale)); - } else { + } + else + { return ivec2(vec2(inputVec) * scale); } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs index 388f0c250..7d0f1aa58 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs @@ -42,13 +42,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions for (int argIndex = 0; argIndex < arity; argIndex++) { + // For shared memory access, the second argument is unused and should be ignored. + // It is there to make both storage and shared access have the same number of arguments. + if (argIndex == 1 && (inst & Instruction.MrMask) == Instruction.MrShared) + { + continue; + } + if (argIndex != 0) { args += ", "; } - VariableType dstType = GetSrcVarType(inst, argIndex); - if (argIndex == 0 && atomic) { Instruction memRegion = inst & Instruction.MrMask; @@ -60,12 +65,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions default: throw new InvalidOperationException($"Invalid memory region \"{memRegion}\"."); } - - // We use the first 2 operands above. - argIndex++; } else { + VariableType dstType = GetSrcVarType(inst, argIndex); + args += GetSoureExpr(context, operation.GetSource(argIndex), dstType); } } diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs index 1b1efe9da..5f5574c31 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs @@ -16,9 +16,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions Add(Instruction.AtomicAdd, InstType.AtomicBinary, "atomicAdd"); Add(Instruction.AtomicAnd, InstType.AtomicBinary, "atomicAnd"); Add(Instruction.AtomicCompareAndSwap, InstType.AtomicTernary, "atomicCompSwap"); - Add(Instruction.AtomicMaxS32, InstType.AtomicBinary, "atomicMax"); + Add(Instruction.AtomicMaxS32, InstType.CallTernary, HelperFunctionNames.AtomicMaxS32); Add(Instruction.AtomicMaxU32, InstType.AtomicBinary, "atomicMax"); - Add(Instruction.AtomicMinS32, InstType.AtomicBinary, "atomicMin"); + Add(Instruction.AtomicMinS32, InstType.CallTernary, HelperFunctionNames.AtomicMinS32); Add(Instruction.AtomicMinU32, InstType.AtomicBinary, "atomicMin"); Add(Instruction.AtomicOr, InstType.AtomicBinary, "atomicOr"); Add(Instruction.AtomicSwap, InstType.AtomicBinary, "atomicExchange"); diff --git a/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj b/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj index 28a031a2f..2fa70c265 100644 --- a/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj +++ b/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj @@ -9,6 +9,8 @@ + + diff --git a/Ryujinx.Graphics.Shader/StructuredIr/HelperFunctionsMask.cs b/Ryujinx.Graphics.Shader/StructuredIr/HelperFunctionsMask.cs index 53367fce1..af462a7f1 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/HelperFunctionsMask.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/HelperFunctionsMask.cs @@ -5,12 +5,14 @@ namespace Ryujinx.Graphics.Shader.StructuredIr [Flags] enum HelperFunctionsMask { - MultiplyHighS32 = 1 << 0, - MultiplyHighU32 = 1 << 1, - Shuffle = 1 << 2, - ShuffleDown = 1 << 3, - ShuffleUp = 1 << 4, - ShuffleXor = 1 << 5, - SwizzleAdd = 1 << 6 + AtomicMinMaxS32Shared = 1 << 0, + AtomicMinMaxS32Storage = 1 << 1, + MultiplyHighS32 = 1 << 2, + MultiplyHighU32 = 1 << 3, + Shuffle = 1 << 4, + ShuffleDown = 1 << 5, + ShuffleUp = 1 << 6, + ShuffleXor = 1 << 7, + SwizzleAdd = 1 << 8 } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs index 733805cde..8c73e698e 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs @@ -244,6 +244,14 @@ namespace Ryujinx.Graphics.Shader.StructuredIr // decide which helper functions are needed on the final generated code. switch (operation.Inst) { + case Instruction.AtomicMaxS32 | Instruction.MrShared: + case Instruction.AtomicMinS32 | Instruction.MrShared: + context.Info.HelperFunctionsMask |= HelperFunctionsMask.AtomicMinMaxS32Shared; + break; + case Instruction.AtomicMaxS32 | Instruction.MrStorage: + case Instruction.AtomicMinS32 | Instruction.MrStorage: + context.Info.HelperFunctionsMask |= HelperFunctionsMask.AtomicMinMaxS32Storage; + break; case Instruction.MultiplyHighS32: context.Info.HelperFunctionsMask |= HelperFunctionsMask.MultiplyHighS32; break;