aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader/Translation/Translator.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-08-13 22:26:42 -0300
committerGitHub <noreply@github.com>2023-08-13 22:26:42 -0300
commitb423197619dd8d9dda1c255a76105bf30e255dae (patch)
treee3898b3b1672f022b5de4522b51bd21583043996 /src/Ryujinx.Graphics.Shader/Translation/Translator.cs
parent8edfb2bc7b8507d0ef51f0544eb32a65f0bf54a1 (diff)
Delete ShaderConfig and organize shader resources/definitions better (#5509)1.1.985
* Move some properties out of ShaderConfig * Stop using ShaderConfig on backends * Replace ShaderConfig usages on Translator and passes * Move remaining properties out of ShaderConfig and delete ShaderConfig * Remove ResourceManager property from TranslatorContext * Move Rewriter passes to separate transform pass files * Fix TransformPasses.RunPass on cases where a node is removed * Move remaining ClipDistancePrimitivesWritten and UsedFeatures updates to decode stage * Reduce excessive parameter passing a bit by using structs more * Remove binding parameter from ShaderProperties methods since it is redundant * Replace decoder instruction checks with switch statement * Put GLSL on the same plan as SPIR-V for input/output declaration * Stop mutating TranslatorContext state when Translate is called * Pass most of the graphics state using a struct instead of individual query methods * Auto-format * Auto-format * Add backend logging interface * Auto-format * Remove unnecessary use of interpolated strings * Remove more modifications of AttributeUsage after decode * PR feedback * gl_Layer is not supported on compute
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Translation/Translator.cs')
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Translator.cs191
1 files changed, 93 insertions, 98 deletions
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Translator.cs b/src/Ryujinx.Graphics.Shader/Translation/Translator.cs
index 010c80db..b609ac07 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -1,11 +1,6 @@
-using Ryujinx.Graphics.Shader.CodeGen.Glsl;
-using Ryujinx.Graphics.Shader.CodeGen.Spirv;
using Ryujinx.Graphics.Shader.Decoders;
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
-using Ryujinx.Graphics.Shader.StructuredIr;
-using Ryujinx.Graphics.Shader.Translation.Optimizations;
using System;
-using System.Collections.Generic;
using System.Linq;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
@@ -13,6 +8,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
public static class Translator
{
+ private const int ThreadsPerWarp = 32;
private const int HeaderSize = 0x50;
internal readonly struct FunctionCode
@@ -30,111 +26,112 @@ namespace Ryujinx.Graphics.Shader.Translation
return DecodeShader(address, gpuAccessor, options);
}
- internal static ShaderProgram Translate(FunctionCode[] functions, ShaderConfig config)
+ private static TranslatorContext DecodeShader(ulong address, IGpuAccessor gpuAccessor, TranslationOptions options)
{
- var cfgs = new ControlFlowGraph[functions.Length];
- var frus = new RegisterUsage.FunctionRegisterUsage[functions.Length];
+ int localMemorySize;
+ ShaderDefinitions definitions;
+ DecodedProgram program;
- for (int i = 0; i < functions.Length; i++)
+ if (options.Flags.HasFlag(TranslationFlags.Compute))
{
- cfgs[i] = ControlFlowGraph.Create(functions[i].Code);
+ definitions = CreateComputeDefinitions(gpuAccessor);
+ localMemorySize = gpuAccessor.QueryComputeLocalMemorySize();
- if (i != 0)
- {
- frus[i] = RegisterUsage.RunPass(cfgs[i]);
- }
+ program = Decoder.Decode(definitions, gpuAccessor, address);
}
+ else
+ {
+ ShaderHeader header = new(gpuAccessor, address);
- List<Function> funcs = new(functions.Length);
+ definitions = CreateGraphicsDefinitions(gpuAccessor, header);
+ localMemorySize = GetLocalMemorySize(header);
- for (int i = 0; i < functions.Length; i++)
- {
- funcs.Add(null);
+ program = Decoder.Decode(definitions, gpuAccessor, address + HeaderSize);
}
- HelperFunctionManager hfm = new(funcs, config.Stage);
+ ulong maxEndAddress = 0;
- for (int i = 0; i < functions.Length; i++)
+ foreach (DecodedFunction function in program)
{
- var cfg = cfgs[i];
-
- int inArgumentsCount = 0;
- int outArgumentsCount = 0;
-
- if (i != 0)
- {
- var fru = frus[i];
-
- inArgumentsCount = fru.InArguments.Length;
- outArgumentsCount = fru.OutArguments.Length;
- }
-
- if (cfg.Blocks.Length != 0)
+ foreach (Block block in function.Blocks)
{
- RegisterUsage.FixupCalls(cfg.Blocks, frus);
-
- Dominance.FindDominators(cfg);
- Dominance.FindDominanceFrontiers(cfg.Blocks);
-
- Ssa.Rename(cfg.Blocks);
-
- Optimizer.RunPass(hfm, cfg.Blocks, config);
- Rewriter.RunPass(hfm, cfg.Blocks, config);
+ if (maxEndAddress < block.EndAddress)
+ {
+ maxEndAddress = block.EndAddress;
+ }
}
-
- funcs[i] = new Function(cfg.Blocks, $"fun{i}", false, inArgumentsCount, outArgumentsCount);
}
- var identification = ShaderIdentifier.Identify(funcs, config);
-
- var sInfo = StructuredProgram.MakeStructuredProgram(funcs, config);
-
- var info = config.CreateProgramInfo(identification);
+ int size = (int)maxEndAddress + (options.Flags.HasFlag(TranslationFlags.Compute) ? 0 : HeaderSize);
- return config.Options.TargetLanguage switch
- {
- TargetLanguage.Glsl => new ShaderProgram(info, TargetLanguage.Glsl, GlslGenerator.Generate(sInfo, config)),
- TargetLanguage.Spirv => new ShaderProgram(info, TargetLanguage.Spirv, SpirvGenerator.Generate(sInfo, config)),
- _ => throw new NotImplementedException(config.Options.TargetLanguage.ToString()),
- };
+ return new TranslatorContext(address, size, localMemorySize, definitions, gpuAccessor, options, program);
}
- private static TranslatorContext DecodeShader(ulong address, IGpuAccessor gpuAccessor, TranslationOptions options)
+ private static ShaderDefinitions CreateComputeDefinitions(IGpuAccessor gpuAccessor)
{
- ShaderConfig config;
- DecodedProgram program;
- ulong maxEndAddress = 0;
+ return new ShaderDefinitions(
+ ShaderStage.Compute,
+ gpuAccessor.QueryComputeLocalSizeX(),
+ gpuAccessor.QueryComputeLocalSizeY(),
+ gpuAccessor.QueryComputeLocalSizeZ());
+ }
- if (options.Flags.HasFlag(TranslationFlags.Compute))
- {
- config = new ShaderConfig(ShaderStage.Compute, gpuAccessor, options, gpuAccessor.QueryComputeLocalMemorySize());
+ private static ShaderDefinitions CreateGraphicsDefinitions(IGpuAccessor gpuAccessor, ShaderHeader header)
+ {
+ bool transformFeedbackEnabled =
+ gpuAccessor.QueryTransformFeedbackEnabled() &&
+ gpuAccessor.QueryHostSupportsTransformFeedback();
+ TransformFeedbackOutput[] transformFeedbackOutputs = null;
+ ulong transformFeedbackVecMap = 0UL;
- program = Decoder.Decode(config, address);
- }
- else
+ if (transformFeedbackEnabled)
{
- config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, options);
-
- program = Decoder.Decode(config, address + HeaderSize);
- }
+ transformFeedbackOutputs = new TransformFeedbackOutput[0xc0];
- foreach (DecodedFunction function in program)
- {
- foreach (Block block in function.Blocks)
+ for (int tfbIndex = 0; tfbIndex < 4; tfbIndex++)
{
- if (maxEndAddress < block.EndAddress)
+ var locations = gpuAccessor.QueryTransformFeedbackVaryingLocations(tfbIndex);
+ var stride = gpuAccessor.QueryTransformFeedbackStride(tfbIndex);
+
+ for (int i = 0; i < locations.Length; i++)
{
- maxEndAddress = block.EndAddress;
+ byte wordOffset = locations[i];
+ if (wordOffset < 0xc0)
+ {
+ transformFeedbackOutputs[wordOffset] = new TransformFeedbackOutput(tfbIndex, i * 4, stride);
+ transformFeedbackVecMap |= 1UL << (wordOffset / 4);
+ }
}
}
}
- config.SizeAdd((int)maxEndAddress + (options.Flags.HasFlag(TranslationFlags.Compute) ? 0 : HeaderSize));
+ return new ShaderDefinitions(
+ header.Stage,
+ gpuAccessor.QueryGraphicsState(),
+ header.Stage == ShaderStage.Geometry && header.GpPassthrough,
+ header.ThreadsPerInputPrimitive,
+ header.OutputTopology,
+ header.MaxOutputVertexCount,
+ header.ImapTypes,
+ header.OmapTargets,
+ header.OmapSampleMask,
+ header.OmapDepth,
+ transformFeedbackEnabled,
+ transformFeedbackVecMap,
+ transformFeedbackOutputs);
+ }
- return new TranslatorContext(address, program, config);
+ private static int GetLocalMemorySize(ShaderHeader header)
+ {
+ return header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize + (header.ShaderLocalMemoryCrsSize / ThreadsPerWarp);
}
- internal static FunctionCode[] EmitShader(DecodedProgram program, ShaderConfig config, bool initializeOutputs, out int initializationOperations)
+ internal static FunctionCode[] EmitShader(
+ TranslatorContext translatorContext,
+ ResourceManager resourceManager,
+ DecodedProgram program,
+ bool initializeOutputs,
+ out int initializationOperations)
{
initializationOperations = 0;
@@ -149,11 +146,11 @@ namespace Ryujinx.Graphics.Shader.Translation
for (int index = 0; index < functions.Length; index++)
{
- EmitterContext context = new(program, config, index != 0);
+ EmitterContext context = new(translatorContext, resourceManager, program, index != 0);
if (initializeOutputs && index == 0)
{
- EmitOutputsInitialization(context, config);
+ EmitOutputsInitialization(context, translatorContext.AttributeUsage, translatorContext.GpuAccessor, translatorContext.Stage);
initializationOperations = context.OperationsCount;
}
@@ -168,27 +165,27 @@ namespace Ryujinx.Graphics.Shader.Translation
EmitOps(context, block);
}
- functions[index] = new FunctionCode(context.GetOperations());
+ functions[index] = new(context.GetOperations());
}
return functions;
}
- private static void EmitOutputsInitialization(EmitterContext context, ShaderConfig config)
+ private static void EmitOutputsInitialization(EmitterContext context, AttributeUsage attributeUsage, IGpuAccessor gpuAccessor, ShaderStage stage)
{
// Compute has no output attributes, and fragment is the last stage, so we
// don't need to initialize outputs on those stages.
- if (config.Stage == ShaderStage.Compute || config.Stage == ShaderStage.Fragment)
+ if (stage == ShaderStage.Compute || stage == ShaderStage.Fragment)
{
return;
}
- if (config.Stage == ShaderStage.Vertex)
+ if (stage == ShaderStage.Vertex)
{
InitializePositionOutput(context);
}
- UInt128 usedAttributes = context.Config.NextInputAttributesComponents;
+ UInt128 usedAttributes = context.TranslatorContext.AttributeUsage.NextInputAttributesComponents;
while (usedAttributes != UInt128.Zero)
{
int index = (int)UInt128.TrailingZeroCount(usedAttributes);
@@ -197,7 +194,7 @@ namespace Ryujinx.Graphics.Shader.Translation
usedAttributes &= ~(UInt128.One << index);
// We don't need to initialize passthrough attributes.
- if ((context.Config.PassthroughAttributes & (1 << vecIndex)) != 0)
+ if ((context.TranslatorContext.AttributeUsage.PassthroughAttributes & (1 << vecIndex)) != 0)
{
continue;
}
@@ -205,30 +202,28 @@ namespace Ryujinx.Graphics.Shader.Translation
InitializeOutputComponent(context, vecIndex, index & 3, perPatch: false);
}
- if (context.Config.NextUsedInputAttributesPerPatch != null)
+ if (context.TranslatorContext.AttributeUsage.NextUsedInputAttributesPerPatch != null)
{
- foreach (int vecIndex in context.Config.NextUsedInputAttributesPerPatch.Order())
+ foreach (int vecIndex in context.TranslatorContext.AttributeUsage.NextUsedInputAttributesPerPatch.Order())
{
InitializeOutput(context, vecIndex, perPatch: true);
}
}
- if (config.NextUsesFixedFuncAttributes)
+ if (attributeUsage.NextUsesFixedFuncAttributes)
{
- bool supportsLayerFromVertexOrTess = config.GpuAccessor.QueryHostSupportsLayerVertexTessellation();
+ bool supportsLayerFromVertexOrTess = gpuAccessor.QueryHostSupportsLayerVertexTessellation();
int fixedStartAttr = supportsLayerFromVertexOrTess ? 0 : 1;
for (int i = fixedStartAttr; i < fixedStartAttr + 5 + AttributeConsts.TexCoordCount; i++)
{
- int index = config.GetFreeUserAttribute(isOutput: true, i);
+ int index = attributeUsage.GetFreeUserAttribute(isOutput: true, i);
if (index < 0)
{
break;
}
InitializeOutput(context, index, perPatch: false);
-
- config.SetOutputUserAttributeFixedFunc(index);
}
}
}
@@ -253,11 +248,11 @@ namespace Ryujinx.Graphics.Shader.Translation
{
StorageKind storageKind = perPatch ? StorageKind.OutputPerPatch : StorageKind.Output;
- if (context.Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing))
+ if (context.TranslatorContext.Definitions.OaIndexing)
{
Operand invocationId = null;
- if (context.Config.Stage == ShaderStage.TessellationControl && !perPatch)
+ if (context.TranslatorContext.Definitions.Stage == ShaderStage.TessellationControl && !perPatch)
{
invocationId = context.Load(StorageKind.Input, IoVariable.InvocationId);
}
@@ -268,7 +263,7 @@ namespace Ryujinx.Graphics.Shader.Translation
}
else
{
- if (context.Config.Stage == ShaderStage.TessellationControl && !perPatch)
+ if (context.TranslatorContext.Definitions.Stage == ShaderStage.TessellationControl && !perPatch)
{
Operand invocationId = context.Load(StorageKind.Input, IoVariable.InvocationId);
context.Store(storageKind, IoVariable.UserDefined, Const(location), invocationId, Const(c), ConstF(c == 3 ? 1f : 0f));
@@ -286,7 +281,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
InstOp op = block.OpCodes[opIndex];
- if (context.Config.Options.Flags.HasFlag(TranslationFlags.DebugMode))
+ if (context.TranslatorContext.Options.Flags.HasFlag(TranslationFlags.DebugMode))
{
string instName;
@@ -298,7 +293,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
instName = "???";
- context.Config.GpuAccessor.Log($"Invalid instruction at 0x{op.Address:X6} (0x{op.RawOpCode:X16}).");
+ context.TranslatorContext.GpuAccessor.Log($"Invalid instruction at 0x{op.Address:X6} (0x{op.RawOpCode:X16}).");
}
string dbgComment = $"0x{op.Address:X6}: 0x{op.RawOpCode:X16} {instName}";