diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs | 313 |
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); } } } |