Delete ShaderConfig and organize shader resources/definitions better (#5509)
* 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
This commit is contained in:
parent
8edfb2bc7b
commit
b423197619
68 changed files with 2653 additions and 2407 deletions
|
@ -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()
|
||||
{
|
||||
_config.MergeFromtNextStage(nextStage._config);
|
||||
// The depth register is always two registers after the last color output.
|
||||
return BitOperations.PopCount((uint)Definitions.OmapTargets) + 1;
|
||||
}
|
||||
|
||||
public void SetLayerOutputAttribute(int attr)
|
||||
{
|
||||
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);
|
||||
|
||||
_config.ResourceManager.SetCurrentLocalMemory(_config.LocalMemorySize, usesLocalMemory);
|
||||
|
||||
if (_config.Stage == ShaderStage.Compute)
|
||||
// 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))
|
||||
{
|
||||
bool usesSharedMemory = _config.UsedFeatures.HasFlag(FeatureFlags.SharedMemory);
|
||||
Definitions.LastInVertexPipeline = false;
|
||||
}
|
||||
}
|
||||
|
||||
_config.ResourceManager.SetCurrentSharedMemory(GpuAccessor.QueryComputeSharedMemorySize(), usesSharedMemory);
|
||||
public ShaderProgram Translate()
|
||||
{
|
||||
ResourceManager resourceManager = CreateResourceManager();
|
||||
|
||||
bool usesLocalMemory = _program.UsedFeatures.HasFlag(FeatureFlags.LocalMemory);
|
||||
|
||||
resourceManager.SetCurrentLocalMemory(_localMemorySize, usesLocalMemory);
|
||||
|
||||
if (Stage == ShaderStage.Compute)
|
||||
{
|
||||
bool usesSharedMemory = _program.UsedFeatures.HasFlag(FeatureFlags.SharedMemory);
|
||||
|
||||
resourceManager.SetCurrentSharedMemory(GpuAccessor.QueryComputeSharedMemorySize(), usesSharedMemory);
|
||||
}
|
||||
|
||||
FunctionCode[] code = EmitShader(_program, _config, initializeOutputs: other == null, out _);
|
||||
FunctionCode[] code = EmitShader(this, resourceManager, _program, initializeOutputs: true, out _);
|
||||
|
||||
if (other != null)
|
||||
return Translate(code, resourceManager, UsedFeatures, _program.ClipDistancesWritten);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);
|
||||
|
||||
code = Combine(otherCode, code, aStart);
|
||||
|
||||
_config.InheritFrom(other._config);
|
||||
if (i != 0)
|
||||
{
|
||||
frus[i] = RegisterUsage.RunPass(cfgs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return Translator.Translate(code, _config);
|
||||
List<Function> funcs = new(functions.Length);
|
||||
|
||||
for (int i = 0; i < functions.Length; i++)
|
||||
{
|
||||
funcs.Add(null);
|
||||
}
|
||||
|
||||
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 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 definitions = new ShaderDefinitions(
|
||||
ShaderStage.Geometry,
|
||||
GpuAccessor.QueryGraphicsState(),
|
||||
false,
|
||||
1,
|
||||
outputTopology,
|
||||
maxOutputVertices);
|
||||
|
||||
var info = config.CreateProgramInfo();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue