aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs')
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs313
1 files changed, 267 insertions, 46 deletions
diff --git a/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
index 40a79c54..39ce92c9 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
@@ -1,8 +1,11 @@
-using Ryujinx.Graphics.Shader.CodeGen.Glsl;
+using Ryujinx.Graphics.Shader.CodeGen;
+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 Ryujinx.Graphics.Shader.Translation.Transforms;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -15,22 +18,47 @@ namespace Ryujinx.Graphics.Shader.Translation
public class TranslatorContext
{
private readonly DecodedProgram _program;
- private readonly ShaderConfig _config;
+ private readonly int _localMemorySize;
public ulong Address { get; }
+ public int Size { get; }
+ public int Cb1DataSize => _program.Cb1DataSize;
- public ShaderStage Stage => _config.Stage;
- public int Size => _config.Size;
- public int Cb1DataSize => _config.Cb1DataSize;
- public bool LayerOutputWritten => _config.LayerOutputWritten;
+ internal bool HasLayerInputAttribute { get; private set; }
+ internal int GpLayerInputAttribute { get; private set; }
- public IGpuAccessor GpuAccessor => _config.GpuAccessor;
+ internal AttributeUsage AttributeUsage => _program.AttributeUsage;
- internal TranslatorContext(ulong address, DecodedProgram program, ShaderConfig config)
+ internal ShaderDefinitions Definitions { get; }
+
+ public ShaderStage Stage => Definitions.Stage;
+
+ internal IGpuAccessor GpuAccessor { get; }
+
+ internal TranslationOptions Options { get; }
+
+ internal FeatureFlags UsedFeatures { get; private set; }
+
+ public bool LayerOutputWritten { get; private set; }
+ public int LayerOutputAttribute { get; private set; }
+
+ internal TranslatorContext(
+ ulong address,
+ int size,
+ int localMemorySize,
+ ShaderDefinitions definitions,
+ IGpuAccessor gpuAccessor,
+ TranslationOptions options,
+ DecodedProgram program)
{
Address = address;
+ Size = size;
_program = program;
- _config = config;
+ _localMemorySize = localMemorySize;
+ Definitions = definitions;
+ GpuAccessor = gpuAccessor;
+ Options = options;
+ UsedFeatures = program.UsedFeatures;
}
private static bool IsLoadUserDefined(Operation operation)
@@ -131,63 +159,259 @@ namespace Ryujinx.Graphics.Shader.Translation
return output;
}
- public void SetNextStage(TranslatorContext nextStage)
+ internal int GetDepthRegister()
+ {
+ // The depth register is always two registers after the last color output.
+ return BitOperations.PopCount((uint)Definitions.OmapTargets) + 1;
+ }
+
+ public void SetLayerOutputAttribute(int attr)
{
- _config.MergeFromtNextStage(nextStage._config);
+ LayerOutputWritten = true;
+ LayerOutputAttribute = attr;
}
public void SetGeometryShaderLayerInputAttribute(int attr)
{
- _config.SetGeometryShaderLayerInputAttribute(attr);
+ UsedFeatures |= FeatureFlags.RtLayer;
+ HasLayerInputAttribute = true;
+ GpLayerInputAttribute = attr;
}
public void SetLastInVertexPipeline()
{
- _config.SetLastInVertexPipeline();
+ Definitions.LastInVertexPipeline = true;
}
- public ShaderProgram Translate(TranslatorContext other = null)
+ public void SetNextStage(TranslatorContext nextStage)
{
- bool usesLocalMemory = _config.UsedFeatures.HasFlag(FeatureFlags.LocalMemory);
+ AttributeUsage.MergeFromtNextStage(
+ Definitions.GpPassthrough,
+ nextStage.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr),
+ nextStage.AttributeUsage);
+
+ // We don't consider geometry shaders using the geometry shader passthrough feature
+ // as being the last because when this feature is used, it can't actually modify any of the outputs,
+ // so the stage that comes before it is the last one that can do modifications.
+ if (nextStage.Definitions.Stage != ShaderStage.Fragment &&
+ (nextStage.Definitions.Stage != ShaderStage.Geometry || !nextStage.Definitions.GpPassthrough))
+ {
+ Definitions.LastInVertexPipeline = false;
+ }
+ }
- _config.ResourceManager.SetCurrentLocalMemory(_config.LocalMemorySize, usesLocalMemory);
+ public ShaderProgram Translate()
+ {
+ ResourceManager resourceManager = CreateResourceManager();
- if (_config.Stage == ShaderStage.Compute)
+ bool usesLocalMemory = _program.UsedFeatures.HasFlag(FeatureFlags.LocalMemory);
+
+ resourceManager.SetCurrentLocalMemory(_localMemorySize, usesLocalMemory);
+
+ if (Stage == ShaderStage.Compute)
{
- bool usesSharedMemory = _config.UsedFeatures.HasFlag(FeatureFlags.SharedMemory);
+ bool usesSharedMemory = _program.UsedFeatures.HasFlag(FeatureFlags.SharedMemory);
- _config.ResourceManager.SetCurrentSharedMemory(GpuAccessor.QueryComputeSharedMemorySize(), usesSharedMemory);
+ resourceManager.SetCurrentSharedMemory(GpuAccessor.QueryComputeSharedMemorySize(), usesSharedMemory);
}
- FunctionCode[] code = EmitShader(_program, _config, initializeOutputs: other == null, out _);
+ FunctionCode[] code = EmitShader(this, resourceManager, _program, initializeOutputs: true, out _);
+
+ return Translate(code, resourceManager, UsedFeatures, _program.ClipDistancesWritten);
+ }
- if (other != null)
+ public ShaderProgram Translate(TranslatorContext other)
+ {
+ ResourceManager resourceManager = CreateResourceManager();
+
+ bool usesLocalMemory = _program.UsedFeatures.HasFlag(FeatureFlags.LocalMemory);
+ resourceManager.SetCurrentLocalMemory(_localMemorySize, usesLocalMemory);
+
+ FunctionCode[] code = EmitShader(this, resourceManager, _program, initializeOutputs: false, out _);
+
+ bool otherUsesLocalMemory = other._program.UsedFeatures.HasFlag(FeatureFlags.LocalMemory);
+ resourceManager.SetCurrentLocalMemory(other._localMemorySize, otherUsesLocalMemory);
+
+ FunctionCode[] otherCode = EmitShader(other, resourceManager, other._program, initializeOutputs: true, out int aStart);
+
+ code = Combine(otherCode, code, aStart);
+
+ return Translate(
+ code,
+ resourceManager,
+ UsedFeatures | other.UsedFeatures,
+ (byte)(_program.ClipDistancesWritten | other._program.ClipDistancesWritten));
+ }
+
+ private ShaderProgram Translate(FunctionCode[] functions, ResourceManager resourceManager, FeatureFlags usedFeatures, byte clipDistancesWritten)
+ {
+ var cfgs = new ControlFlowGraph[functions.Length];
+ var frus = new RegisterUsage.FunctionRegisterUsage[functions.Length];
+
+ for (int i = 0; i < functions.Length; i++)
{
- other._config.MergeOutputUserAttributes(_config.UsedOutputAttributes, Enumerable.Empty<int>());
+ cfgs[i] = ControlFlowGraph.Create(functions[i].Code);
- // We need to share the resource manager since both shaders accesses the same constant buffers.
- other._config.ResourceManager = _config.ResourceManager;
- other._config.ResourceManager.SetCurrentLocalMemory(other._config.LocalMemorySize, other._config.UsedFeatures.HasFlag(FeatureFlags.LocalMemory));
+ if (i != 0)
+ {
+ frus[i] = RegisterUsage.RunPass(cfgs[i]);
+ }
+ }
- FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);
+ List<Function> funcs = new(functions.Length);
- code = Combine(otherCode, code, aStart);
+ for (int i = 0; i < functions.Length; i++)
+ {
+ funcs.Add(null);
+ }
- _config.InheritFrom(other._config);
+ HelperFunctionManager hfm = new(funcs, Definitions.Stage);
+
+ for (int i = 0; i < functions.Length; i++)
+ {
+ 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)
+ {
+ RegisterUsage.FixupCalls(cfg.Blocks, frus);
+
+ Dominance.FindDominators(cfg);
+ Dominance.FindDominanceFrontiers(cfg.Blocks);
+
+ Ssa.Rename(cfg.Blocks);
+
+ TransformContext context = new(
+ hfm,
+ cfg.Blocks,
+ resourceManager,
+ GpuAccessor,
+ Options.TargetLanguage,
+ Definitions.Stage,
+ ref usedFeatures);
+
+ Optimizer.RunPass(context);
+ TransformPasses.RunPass(context);
+ }
+
+ funcs[i] = new Function(cfg.Blocks, $"fun{i}", false, inArgumentsCount, outArgumentsCount);
+ }
+
+ var identification = ShaderIdentifier.Identify(funcs, GpuAccessor, Definitions.Stage, Definitions.InputTopology, out int layerInputAttr);
+
+ return Generate(
+ funcs,
+ AttributeUsage,
+ Definitions,
+ resourceManager,
+ usedFeatures,
+ clipDistancesWritten,
+ identification,
+ layerInputAttr);
+ }
+
+ private ShaderProgram Generate(
+ IReadOnlyList<Function> funcs,
+ AttributeUsage attributeUsage,
+ ShaderDefinitions definitions,
+ ResourceManager resourceManager,
+ FeatureFlags usedFeatures,
+ byte clipDistancesWritten,
+ ShaderIdentification identification = ShaderIdentification.None,
+ int layerInputAttr = 0)
+ {
+ var sInfo = StructuredProgram.MakeStructuredProgram(
+ funcs,
+ attributeUsage,
+ definitions,
+ resourceManager,
+ Options.Flags.HasFlag(TranslationFlags.DebugMode));
+
+ var info = new ShaderProgramInfo(
+ resourceManager.GetConstantBufferDescriptors(),
+ resourceManager.GetStorageBufferDescriptors(),
+ resourceManager.GetTextureDescriptors(),
+ resourceManager.GetImageDescriptors(),
+ identification,
+ layerInputAttr,
+ definitions.Stage,
+ usedFeatures.HasFlag(FeatureFlags.FragCoordXY),
+ usedFeatures.HasFlag(FeatureFlags.InstanceId),
+ usedFeatures.HasFlag(FeatureFlags.DrawParameters),
+ usedFeatures.HasFlag(FeatureFlags.RtLayer),
+ clipDistancesWritten,
+ definitions.OmapTargets);
+
+ var hostCapabilities = new HostCapabilities(
+ GpuAccessor.QueryHostReducedPrecision(),
+ GpuAccessor.QueryHostSupportsFragmentShaderInterlock(),
+ GpuAccessor.QueryHostSupportsFragmentShaderOrderingIntel(),
+ GpuAccessor.QueryHostSupportsGeometryShaderPassthrough(),
+ GpuAccessor.QueryHostSupportsShaderBallot(),
+ GpuAccessor.QueryHostSupportsShaderBarrierDivergence(),
+ GpuAccessor.QueryHostSupportsTextureShadowLod(),
+ GpuAccessor.QueryHostSupportsViewportMask());
+
+ var parameters = new CodeGenParameters(attributeUsage, definitions, resourceManager.Properties, hostCapabilities, GpuAccessor, Options.TargetApi);
+
+ return Options.TargetLanguage switch
+ {
+ TargetLanguage.Glsl => new ShaderProgram(info, TargetLanguage.Glsl, GlslGenerator.Generate(sInfo, parameters)),
+ TargetLanguage.Spirv => new ShaderProgram(info, TargetLanguage.Spirv, SpirvGenerator.Generate(sInfo, parameters)),
+ _ => throw new NotImplementedException(Options.TargetLanguage.ToString()),
+ };
+ }
+
+ private ResourceManager CreateResourceManager()
+ {
+ ResourceManager resourceManager = new(Definitions.Stage, GpuAccessor);
+
+ if (!GpuAccessor.QueryHostSupportsTransformFeedback() && GpuAccessor.QueryTransformFeedbackEnabled())
+ {
+ StructureType tfeInfoStruct = new(new StructureField[]
+ {
+ new StructureField(AggregateType.Array | AggregateType.U32, "base_offset", 4),
+ new StructureField(AggregateType.U32, "vertex_count")
+ });
+
+ BufferDefinition tfeInfoBuffer = new(BufferLayout.Std430, 1, Constants.TfeInfoBinding, "tfe_info", tfeInfoStruct);
+ resourceManager.Properties.AddOrUpdateStorageBuffer(tfeInfoBuffer);
+
+ StructureType tfeDataStruct = new(new StructureField[]
+ {
+ new StructureField(AggregateType.Array | AggregateType.U32, "data", 0)
+ });
+
+ for (int i = 0; i < Constants.TfeBuffersCount; i++)
+ {
+ int binding = Constants.TfeBufferBaseBinding + i;
+ BufferDefinition tfeDataBuffer = new(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
+ resourceManager.Properties.AddOrUpdateStorageBuffer(tfeDataBuffer);
+ }
}
- return Translator.Translate(code, _config);
+ return resourceManager;
}
public ShaderProgram GenerateGeometryPassthrough()
{
- int outputAttributesMask = _config.UsedOutputAttributes;
- int layerOutputAttr = _config.LayerOutputAttribute;
+ int outputAttributesMask = AttributeUsage.UsedOutputAttributes;
+ int layerOutputAttr = LayerOutputAttribute;
OutputTopology outputTopology;
int maxOutputVertices;
- switch (GpuAccessor.QueryPrimitiveTopology())
+ switch (Definitions.InputTopology)
{
case InputTopology.Points:
outputTopology = OutputTopology.PointList;
@@ -204,9 +428,10 @@ namespace Ryujinx.Graphics.Shader.Translation
break;
}
- ShaderConfig config = new(ShaderStage.Geometry, outputTopology, maxOutputVertices, GpuAccessor, _config.Options);
+ var attributeUsage = new AttributeUsage(GpuAccessor);
+ var resourceManager = new ResourceManager(ShaderStage.Geometry, GpuAccessor);
- EmitterContext context = new(default, config, false);
+ var context = new EmitterContext();
for (int v = 0; v < maxOutputVertices; v++)
{
@@ -231,10 +456,7 @@ namespace Ryujinx.Graphics.Shader.Translation
else
{
context.Store(StorageKind.Output, IoVariable.UserDefined, null, Const(attrIndex), Const(c), value);
- config.SetOutputUserAttribute(attrIndex);
}
-
- config.SetInputUserAttribute(attrIndex, c);
}
}
@@ -254,16 +476,15 @@ namespace Ryujinx.Graphics.Shader.Translation
var cfg = ControlFlowGraph.Create(operations);
var function = new Function(cfg.Blocks, "main", false, 0, 0);
- var sInfo = StructuredProgram.MakeStructuredProgram(new[] { function }, config);
-
- var info = config.CreateProgramInfo();
+ var definitions = new ShaderDefinitions(
+ ShaderStage.Geometry,
+ GpuAccessor.QueryGraphicsState(),
+ false,
+ 1,
+ outputTopology,
+ maxOutputVertices);
- 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 Generate(new[] { function }, attributeUsage, definitions, resourceManager, FeatureFlags.RtLayer, 0);
}
}
}