diff options
author | gdkchan <gab.dark.100@gmail.com> | 2023-04-25 19:51:07 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-25 19:51:07 -0300 |
commit | 9f12e50a546b15533778ed0d8290202af91c10a2 (patch) | |
tree | f0e77a7b7c605face5ef29270b4248af2682301a /Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs | |
parent | 097562bc6c227c42f803ce1078fcb4adf06cd20c (diff) |
Refactor attribute handling on the shader generator (#4565)1.1.733
* Refactor attribute handling on the shader generator
* Implement gl_ViewportMask[]
* Add back the Intel FrontFacing bug workaround
* Fix GLSL transform feedback outputs mistmatch with fragment stage
* Shader cache version bump
* Fix geometry shader recognition
* PR feedback
* Delete GetOperandDef and GetOperandUse
* Remove replacements that are no longer needed on GLSL compilation on Vulkan
* Fix incorrect load for per-patch outputs
* Fix build
Diffstat (limited to 'Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs')
-rw-r--r-- | Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs | 380 |
1 files changed, 95 insertions, 285 deletions
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs index fdca5e89..821da477 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs @@ -1,21 +1,19 @@ using Ryujinx.Common; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.Translation; using Spv.Generator; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Numerics; using static Spv.Specification; +using SpvInstruction = Spv.Generator.Instruction; namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { static class Declarations { - // At least 16 attributes are guaranteed by the spec. - public const int MaxAttributes = 16; - private static readonly string[] StagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" }; public static void DeclareParameters(CodeGenContext context, StructuredFunction function) @@ -59,7 +57,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++) { StructuredFunction function = functions[funcIndex]; - Instruction[] locals = new Instruction[function.InArguments.Length]; + SpvInstruction[] locals = new SpvInstruction[function.InArguments.Length]; for (int i = 0; i < function.InArguments.Length; i++) { @@ -105,10 +103,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv DeclareStorageBuffers(context, context.Config.GetStorageBufferDescriptors()); DeclareSamplers(context, context.Config.GetTextureDescriptors()); DeclareImages(context, context.Config.GetImageDescriptors()); - DeclareInputAttributes(context, info, perPatch: false); - DeclareOutputAttributes(context, info, perPatch: false); - DeclareInputAttributes(context, info, perPatch: true); - DeclareOutputAttributes(context, info, perPatch: true); + DeclareInputsAndOutputs(context, info); } private static void DeclareLocalMemory(CodeGenContext context, int size) @@ -121,7 +116,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size); } - private static Instruction DeclareMemory(CodeGenContext context, StorageClass storage, int size) + private static SpvInstruction DeclareMemory(CodeGenContext context, StorageClass storage, int size) { var arrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), size)); var pointerType = context.TypePointer(storage, arrayType); @@ -395,164 +390,104 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv }; } - private static void DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info, bool perPatch) + private static void DeclareInputsAndOutputs(CodeGenContext context, StructuredProgramInfo info) { - bool iaIndexing = context.Config.UsedFeatures.HasFlag(FeatureFlags.IaIndexing); - - if (iaIndexing && !perPatch) + foreach (var ioDefinition in info.IoDefinitions) { - var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4); - attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes)); - - if (context.Config.Stage == ShaderStage.Geometry) - { - attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)context.InputVertices)); - } - - var spvType = context.TypePointer(StorageClass.Input, attrType); - var spvVar = context.Variable(spvType, StorageClass.Input); - - if (context.Config.PassthroughAttributes != 0 && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough()) - { - context.Decorate(spvVar, Decoration.PassthroughNV); - } - - context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0); - - context.AddGlobalVariable(spvVar); - context.InputsArray = spvVar; - } - - var inputs = perPatch ? info.InputsPerPatch : info.Inputs; + var ioVariable = ioDefinition.IoVariable; - foreach (int attr in inputs) - { - if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: false, perPatch)) + // Those are actually from constant buffer, rather than being actual inputs or outputs, + // so we must ignore them here as they are declared as part of the support buffer. + // TODO: Delete this after we represent this properly on the IR (as a constant buffer rather than "input"). + if (ioVariable == IoVariable.FragmentOutputIsBgra || + ioVariable == IoVariable.SupportBlockRenderScale || + ioVariable == IoVariable.SupportBlockViewInverse) { continue; } - bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd; - - if (iaIndexing && isUserAttr && !perPatch) - { - continue; - } + bool isOutput = ioDefinition.StorageKind.IsOutput(); + bool isPerPatch = ioDefinition.StorageKind.IsPerPatch(); PixelImap iq = PixelImap.Unused; if (context.Config.Stage == ShaderStage.Fragment) { - if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd) + if (ioVariable == IoVariable.UserDefined) { - iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType(); + iq = context.Config.ImapTypes[ioDefinition.Location].GetFirstUsedType(); } else { - AttributeInfo attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr: false); - AggregateType elemType = attrInfo.Type & AggregateType.ElementTypeMask; + (_, AggregateType varType) = IoMap.GetSpirvBuiltIn(ioVariable); + AggregateType elemType = varType & AggregateType.ElementTypeMask; - if (attrInfo.IsBuiltin && (elemType == AggregateType.S32 || elemType == AggregateType.U32)) + if (elemType == AggregateType.S32 || elemType == AggregateType.U32) { iq = PixelImap.Constant; } } } - DeclareInputOrOutput(context, attr, perPatch, isOutAttr: false, iq); + DeclareInputOrOutput(context, ioDefinition, isOutput, isPerPatch, iq); } } - private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info, bool perPatch) + private static void DeclareInputOrOutput(CodeGenContext context, IoDefinition ioDefinition, bool isOutput, bool isPerPatch, PixelImap iq = PixelImap.Unused) { - bool oaIndexing = context.Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing); - - if (oaIndexing && !perPatch) - { - var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4); - attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes)); - - if (context.Config.Stage == ShaderStage.TessellationControl) - { - attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive)); - } + IoVariable ioVariable = ioDefinition.IoVariable; + var storageClass = isOutput ? StorageClass.Output : StorageClass.Input; - var spvType = context.TypePointer(StorageClass.Output, attrType); - var spvVar = context.Variable(spvType, StorageClass.Output); + bool isBuiltIn; + BuiltIn builtIn = default; + AggregateType varType; - context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0); - - context.AddGlobalVariable(spvVar); - context.OutputsArray = spvVar; + if (ioVariable == IoVariable.UserDefined) + { + varType = context.Config.GetUserDefinedType(ioDefinition.Location, isOutput); + isBuiltIn = false; } - - var outputs = perPatch ? info.OutputsPerPatch : info.Outputs; - - foreach (int attr in outputs) + else if (ioVariable == IoVariable.FragmentOutputColor) { - if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: true, perPatch)) - { - continue; - } - - bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd; + varType = context.Config.GetFragmentOutputColorType(ioDefinition.Location); + isBuiltIn = false; + } + else + { + (builtIn, varType) = IoMap.GetSpirvBuiltIn(ioVariable); + isBuiltIn = true; - if (oaIndexing && isUserAttr && !perPatch) + if (varType == AggregateType.Invalid) { - continue; + throw new InvalidOperationException($"Unknown variable {ioVariable}."); } - - DeclareOutputAttribute(context, attr, perPatch); } - if (context.Config.Stage == ShaderStage.Vertex) - { - DeclareOutputAttribute(context, AttributeConsts.PositionX, perPatch: false); - } - } - - private static void DeclareOutputAttribute(CodeGenContext context, int attr, bool perPatch) - { - DeclareInputOrOutput(context, attr, perPatch, isOutAttr: true); - } - - public static void DeclareInvocationId(CodeGenContext context) - { - DeclareInputOrOutput(context, AttributeConsts.LaneId, perPatch: false, isOutAttr: false); - } + bool hasComponent = context.Config.HasPerLocationInputOrOutputComponent(ioVariable, ioDefinition.Location, ioDefinition.Component, isOutput); - private static void DeclareInputOrOutput(CodeGenContext context, int attr, bool perPatch, bool isOutAttr, PixelImap iq = PixelImap.Unused) - { - bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd; - if (isUserAttr && context.Config.TransformFeedbackEnabled && !perPatch && - ((isOutAttr && context.Config.LastInVertexPipeline) || - (!isOutAttr && context.Config.Stage == ShaderStage.Fragment))) + if (hasComponent) { - DeclareTransformFeedbackInputOrOutput(context, attr, isOutAttr, iq); - return; + varType &= AggregateType.ElementTypeMask; } - - var dict = perPatch - ? (isOutAttr ? context.OutputsPerPatch : context.InputsPerPatch) - : (isOutAttr ? context.Outputs : context.Inputs); - - var attrInfo = perPatch - ? AttributeInfo.FromPatch(context.Config, attr, isOutAttr) - : AttributeInfo.From(context.Config, attr, isOutAttr); - - if (dict.ContainsKey(attrInfo.BaseValue)) + else if (ioVariable == IoVariable.UserDefined && context.Config.HasTransformFeedbackOutputs(isOutput)) { - return; + varType &= AggregateType.ElementTypeMask; + varType |= context.Config.GetTransformFeedbackOutputComponents(ioDefinition.Location, ioDefinition.Component) switch + { + 2 => AggregateType.Vector2, + 3 => AggregateType.Vector3, + 4 => AggregateType.Vector4, + _ => AggregateType.Invalid + }; } - var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input; - var attrType = context.GetType(attrInfo.Type, attrInfo.Length); + var spvType = context.GetType(varType, IoMap.GetSpirvBuiltInArrayLength(ioVariable)); bool builtInPassthrough = false; - if (AttributeInfo.IsArrayAttributeSpirv(context.Config.Stage, isOutAttr) && !perPatch && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr))) + if (!isPerPatch && IoMap.IsPerVertex(ioVariable, context.Config.Stage, isOutput)) { int arraySize = context.Config.Stage == ShaderStage.Geometry ? context.InputVertices : 32; - attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)arraySize)); + spvType = context.TypeArray(spvType, context.Constant(context.TypeU32(), (LiteralInteger)arraySize)); if (context.Config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough()) { @@ -560,69 +495,64 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv } } - if (context.Config.Stage == ShaderStage.TessellationControl && isOutAttr && !perPatch) + if (context.Config.Stage == ShaderStage.TessellationControl && isOutput && !isPerPatch) { - attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive)); + spvType = context.TypeArray(spvType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive)); } - var spvType = context.TypePointer(storageClass, attrType); - var spvVar = context.Variable(spvType, storageClass); + var spvPointerType = context.TypePointer(storageClass, spvType); + var spvVar = context.Variable(spvPointerType, storageClass); if (builtInPassthrough) { context.Decorate(spvVar, Decoration.PassthroughNV); } - if (attrInfo.IsBuiltin) + if (isBuiltIn) { - if (perPatch) + if (isPerPatch) { context.Decorate(spvVar, Decoration.Patch); } - if (context.Config.GpuAccessor.QueryHostReducedPrecision() && attr == AttributeConsts.PositionX && context.Config.Stage != ShaderStage.Fragment) + if (context.Config.GpuAccessor.QueryHostReducedPrecision() && ioVariable == IoVariable.Position) { context.Decorate(spvVar, Decoration.Invariant); } - context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue)); - - if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr) - { - var tfOutput = context.Info.GetTransformFeedbackOutput(attrInfo.BaseValue); - if (tfOutput.Valid) - { - context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer); - context.Decorate(spvVar, Decoration.XfbStride, (LiteralInteger)tfOutput.Stride); - context.Decorate(spvVar, Decoration.Offset, (LiteralInteger)tfOutput.Offset); - } - } + context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)builtIn); } - else if (perPatch) + else if (isPerPatch) { context.Decorate(spvVar, Decoration.Patch); - int location = context.Config.GetPerPatchAttributeLocation((attr - AttributeConsts.UserAttributePerPatchBase) / 16); + if (ioVariable == IoVariable.UserDefined) + { + int location = context.Config.GetPerPatchAttributeLocation(ioDefinition.Location); - context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location); + context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location); + } } - else if (isUserAttr) + else if (ioVariable == IoVariable.UserDefined) { - int location = (attr - AttributeConsts.UserAttributeBase) / 16; + context.Decorate(spvVar, Decoration.Location, (LiteralInteger)ioDefinition.Location); - context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location); + if (hasComponent) + { + context.Decorate(spvVar, Decoration.Component, (LiteralInteger)ioDefinition.Component); + } - if (!isOutAttr && - !perPatch && - (context.Config.PassthroughAttributes & (1 << location)) != 0 && + if (!isOutput && + !isPerPatch && + (context.Config.PassthroughAttributes & (1 << ioDefinition.Location)) != 0 && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough()) { context.Decorate(spvVar, Decoration.PassthroughNV); } } - else if (attr >= AttributeConsts.FragmentOutputColorBase && attr < AttributeConsts.FragmentOutputColorEnd) + else if (ioVariable == IoVariable.FragmentOutputColor) { - int location = (attr - AttributeConsts.FragmentOutputColorBase) / 16; + int location = ioDefinition.Location; if (context.Config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryDualSourceBlendEnable()) { @@ -646,7 +576,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv } } - if (!isOutAttr) + if (!isOutput) { switch (iq) { @@ -658,143 +588,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv break; } } - - context.AddGlobalVariable(spvVar); - dict.Add(attrInfo.BaseValue, spvVar); - } - - private static void DeclareTransformFeedbackInputOrOutput(CodeGenContext context, int attr, bool isOutAttr, PixelImap iq = PixelImap.Unused) - { - var dict = isOutAttr ? context.Outputs : context.Inputs; - var attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr); - - bool hasComponent = true; - int component = (attr >> 2) & 3; - int components = 1; - var type = attrInfo.Type & AggregateType.ElementTypeMask; - - if (isOutAttr) + else if (context.Config.TryGetTransformFeedbackOutput( + ioVariable, + ioDefinition.Location, + ioDefinition.Component, + out var transformFeedbackOutput)) { - components = context.Info.GetTransformFeedbackOutputComponents(attr); - - if (components > 1) - { - attr &= ~0xf; - type = components switch - { - 2 => AggregateType.Vector2 | AggregateType.FP32, - 3 => AggregateType.Vector3 | AggregateType.FP32, - 4 => AggregateType.Vector4 | AggregateType.FP32, - _ => AggregateType.FP32 - }; - - hasComponent = false; - } - } - - if (dict.ContainsKey(attr)) - { - return; - } - - var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input; - var attrType = context.GetType(type, components); - - if (AttributeInfo.IsArrayAttributeSpirv(context.Config.Stage, isOutAttr) && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr))) - { - int arraySize = context.Config.Stage == ShaderStage.Geometry ? context.InputVertices : 32; - attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)arraySize)); - } - - if (context.Config.Stage == ShaderStage.TessellationControl && isOutAttr) - { - attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive)); - } - - var spvType = context.TypePointer(storageClass, attrType); - var spvVar = context.Variable(spvType, storageClass); - - Debug.Assert(attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd); - int location = (attr - AttributeConsts.UserAttributeBase) / 16; - - context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location); - - if (hasComponent) - { - context.Decorate(spvVar, Decoration.Component, (LiteralInteger)component); - } - - if (isOutAttr) - { - var tfOutput = context.Info.GetTransformFeedbackOutput(attr); - if (tfOutput.Valid) - { - context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer); - context.Decorate(spvVar, Decoration.XfbStride, (LiteralInteger)tfOutput.Stride); - context.Decorate(spvVar, Decoration.Offset, (LiteralInteger)tfOutput.Offset); - } - } - else - { - if ((context.Config.PassthroughAttributes & (1 << location)) != 0 && - context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough()) - { - context.Decorate(spvVar, Decoration.PassthroughNV); - } - - switch (iq) - { - case PixelImap.Constant: - context.Decorate(spvVar, Decoration.Flat); - break; - case PixelImap.ScreenLinear: - context.Decorate(spvVar, Decoration.NoPerspective); - break; - } + context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)transformFeedbackOutput.Buffer); + context.Decorate(spvVar, Decoration.XfbStride, (LiteralInteger)transformFeedbackOutput.Stride); + context.Decorate(spvVar, Decoration.Offset, (LiteralInteger)transformFeedbackOutput.Offset); } context.AddGlobalVariable(spvVar); - dict.Add(attr, spvVar); - } - private static BuiltIn GetBuiltIn(CodeGenContext context, int attr) - { - return attr switch - { - AttributeConsts.TessLevelOuter0 => BuiltIn.TessLevelOuter, - AttributeConsts.TessLevelInner0 => BuiltIn.TessLevelInner, - AttributeConsts.Layer => BuiltIn.Layer, - AttributeConsts.ViewportIndex => BuiltIn.ViewportIndex, - AttributeConsts.PointSize => BuiltIn.PointSize, - AttributeConsts.PositionX => context.Config.Stage == ShaderStage.Fragment ? BuiltIn.FragCoord : BuiltIn.Position, - AttributeConsts.ClipDistance0 => BuiltIn.ClipDistance, - AttributeConsts.PointCoordX => BuiltIn.PointCoord, - AttributeConsts.TessCoordX => BuiltIn.TessCoord, - AttributeConsts.InstanceId => BuiltIn.InstanceId, - AttributeConsts.VertexId => BuiltIn.VertexId, - AttributeConsts.BaseInstance => BuiltIn.BaseInstance, - AttributeConsts.BaseVertex => BuiltIn.BaseVertex, - AttributeConsts.InstanceIndex => BuiltIn.InstanceIndex, - AttributeConsts.VertexIndex => BuiltIn.VertexIndex, - AttributeConsts.DrawIndex => BuiltIn.DrawIndex, - AttributeConsts.FrontFacing => BuiltIn.FrontFacing, - AttributeConsts.FragmentOutputDepth => BuiltIn.FragDepth, - AttributeConsts.ThreadKill => BuiltIn.HelperInvocation, - AttributeConsts.ThreadIdX => BuiltIn.LocalInvocationId, - AttributeConsts.CtaIdX => BuiltIn.WorkgroupId, - AttributeConsts.LaneId => BuiltIn.SubgroupLocalInvocationId, - AttributeConsts.InvocationId => BuiltIn.InvocationId, - AttributeConsts.PrimitiveId => BuiltIn.PrimitiveId, - AttributeConsts.PatchVerticesIn => BuiltIn.PatchVertices, - AttributeConsts.EqMask => BuiltIn.SubgroupEqMask, - AttributeConsts.GeMask => BuiltIn.SubgroupGeMask, - AttributeConsts.GtMask => BuiltIn.SubgroupGtMask, - AttributeConsts.LeMask => BuiltIn.SubgroupLeMask, - AttributeConsts.LtMask => BuiltIn.SubgroupLtMask, - AttributeConsts.SupportBlockViewInverseX => BuiltIn.Position, - AttributeConsts.SupportBlockViewInverseY => BuiltIn.Position, - _ => throw new ArgumentException($"Invalid attribute number 0x{attr:X}.") - }; + var dict = isPerPatch + ? (isOutput ? context.OutputsPerPatch : context.InputsPerPatch) + : (isOutput ? context.Outputs : context.Inputs); + dict.Add(ioDefinition, spvVar); } private static string GetStagePrefix(ShaderStage stage) |