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/Translation | |
| parent | 097562bc6c227c42f803ce1078fcb4adf06cd20c (diff) | |
Refactor attribute handling on the shader generator (#4565)
* 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/Translation')
12 files changed, 528 insertions, 443 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs index 08efbc9f..683b0d8a 100644 --- a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs +++ b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs @@ -2,104 +2,35 @@ namespace Ryujinx.Graphics.Shader.Translation { static class AttributeConsts { - public const int TessLevelOuter0 = 0x000; - public const int TessLevelOuter1 = 0x004; - public const int TessLevelOuter2 = 0x008; - public const int TessLevelOuter3 = 0x00c; - public const int TessLevelInner0 = 0x010; - public const int TessLevelInner1 = 0x014; - public const int PrimitiveId = 0x060; - public const int Layer = 0x064; - public const int ViewportIndex = 0x068; - public const int PointSize = 0x06c; - public const int PositionX = 0x070; - public const int PositionY = 0x074; - public const int PositionZ = 0x078; - public const int PositionW = 0x07c; - public const int FrontColorDiffuseR = 0x280; - public const int FrontColorDiffuseG = 0x284; - public const int FrontColorDiffuseB = 0x288; - public const int FrontColorDiffuseA = 0x28c; - public const int FrontColorSpecularR = 0x290; - public const int FrontColorSpecularG = 0x294; - public const int FrontColorSpecularB = 0x298; - public const int FrontColorSpecularA = 0x29c; - public const int BackColorDiffuseR = 0x2a0; - public const int BackColorDiffuseG = 0x2a4; - public const int BackColorDiffuseB = 0x2a8; - public const int BackColorDiffuseA = 0x2ac; - public const int BackColorSpecularR = 0x2b0; - public const int BackColorSpecularG = 0x2b4; - public const int BackColorSpecularB = 0x2b8; - public const int BackColorSpecularA = 0x2bc; - public const int ClipDistance0 = 0x2c0; - public const int ClipDistance1 = 0x2c4; - public const int ClipDistance2 = 0x2c8; - public const int ClipDistance3 = 0x2cc; - public const int ClipDistance4 = 0x2d0; - public const int ClipDistance5 = 0x2d4; - public const int ClipDistance6 = 0x2d8; - public const int ClipDistance7 = 0x2dc; - public const int PointCoordX = 0x2e0; - public const int PointCoordY = 0x2e4; - public const int TessCoordX = 0x2f0; - public const int TessCoordY = 0x2f4; - public const int InstanceId = 0x2f8; - public const int VertexId = 0x2fc; - public const int TexCoordCount = 10; - public const int TexCoordBase = 0x300; - public const int TexCoordEnd = TexCoordBase + TexCoordCount * 16; - public const int FrontFacing = 0x3fc; + public const int PrimitiveId = 0x060; + public const int Layer = 0x064; + public const int PositionX = 0x070; + public const int PositionY = 0x074; + public const int FrontColorDiffuseR = 0x280; + public const int BackColorDiffuseR = 0x2a0; + public const int ClipDistance0 = 0x2c0; + public const int ClipDistance1 = 0x2c4; + public const int ClipDistance2 = 0x2c8; + public const int ClipDistance3 = 0x2cc; + public const int ClipDistance4 = 0x2d0; + public const int ClipDistance5 = 0x2d4; + public const int ClipDistance6 = 0x2d8; + public const int ClipDistance7 = 0x2dc; + public const int FogCoord = 0x2e8; + public const int TessCoordX = 0x2f0; + public const int TessCoordY = 0x2f4; + public const int InstanceId = 0x2f8; + public const int VertexId = 0x2fc; + public const int TexCoordCount = 10; + public const int TexCoordBase = 0x300; + public const int TexCoordEnd = TexCoordBase + TexCoordCount * 16; + public const int FrontFacing = 0x3fc; public const int UserAttributesCount = 32; - public const int UserAttributeBase = 0x80; - public const int UserAttributeEnd = UserAttributeBase + UserAttributesCount * 16; + public const int UserAttributeBase = 0x80; + public const int UserAttributeEnd = UserAttributeBase + UserAttributesCount * 16; public const int UserAttributePerPatchBase = 0x18; - public const int UserAttributePerPatchEnd = 0x200; - - public const int LoadOutputMask = 1 << 30; - public const int Mask = 0x3fffffff; - - - // Note: Those attributes are used internally by the translator - // only, they don't exist on Maxwell. - public const int SpecialMask = 0xf << 24; - public const int FragmentOutputDepth = 0x1000000; - public const int FragmentOutputColorBase = 0x1000010; - public const int FragmentOutputColorEnd = FragmentOutputColorBase + 8 * 16; - - public const int FragmentOutputIsBgraBase = 0x1000100; - public const int FragmentOutputIsBgraEnd = FragmentOutputIsBgraBase + 8 * 4; - - public const int SupportBlockViewInverseX = 0x1000200; - public const int SupportBlockViewInverseY = 0x1000204; - - public const int ThreadIdX = 0x2000000; - public const int ThreadIdY = 0x2000004; - public const int ThreadIdZ = 0x2000008; - - public const int CtaIdX = 0x2000010; - public const int CtaIdY = 0x2000014; - public const int CtaIdZ = 0x2000018; - - public const int LaneId = 0x2000020; - - public const int InvocationId = 0x2000024; - public const int PatchVerticesIn = 0x2000028; - - public const int EqMask = 0x2000030; - public const int GeMask = 0x2000034; - public const int GtMask = 0x2000038; - public const int LeMask = 0x200003c; - public const int LtMask = 0x2000040; - - public const int ThreadKill = 0x2000044; - - public const int BaseInstance = 0x2000050; - public const int BaseVertex = 0x2000054; - public const int InstanceIndex = 0x2000058; - public const int VertexIndex = 0x200005c; - public const int DrawIndex = 0x2000060; + public const int UserAttributePerPatchEnd = 0x200; } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs b/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs deleted file mode 100644 index b671429a..00000000 --- a/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Shader.Translation -{ - readonly struct AttributeInfo - { - private static readonly Dictionary<int, AttributeInfo> _builtInAttributes = new Dictionary<int, AttributeInfo>() - { - { AttributeConsts.Layer, new AttributeInfo(AttributeConsts.Layer, 0, 1, AggregateType.S32) }, - { AttributeConsts.ViewportIndex, new AttributeInfo(AttributeConsts.ViewportIndex, 0, 1, AggregateType.S32) }, - { AttributeConsts.PointSize, new AttributeInfo(AttributeConsts.PointSize, 0, 1, AggregateType.FP32) }, - { AttributeConsts.PositionX, new AttributeInfo(AttributeConsts.PositionX, 0, 4, AggregateType.Vector4 | AggregateType.FP32) }, - { AttributeConsts.PositionY, new AttributeInfo(AttributeConsts.PositionX, 1, 4, AggregateType.Vector4 | AggregateType.FP32) }, - { AttributeConsts.PositionZ, new AttributeInfo(AttributeConsts.PositionX, 2, 4, AggregateType.Vector4 | AggregateType.FP32) }, - { AttributeConsts.PositionW, new AttributeInfo(AttributeConsts.PositionX, 3, 4, AggregateType.Vector4 | AggregateType.FP32) }, - { AttributeConsts.ClipDistance0, new AttributeInfo(AttributeConsts.ClipDistance0, 0, 8, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.ClipDistance1, new AttributeInfo(AttributeConsts.ClipDistance0, 1, 8, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.ClipDistance2, new AttributeInfo(AttributeConsts.ClipDistance0, 2, 8, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.ClipDistance3, new AttributeInfo(AttributeConsts.ClipDistance0, 3, 8, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.ClipDistance4, new AttributeInfo(AttributeConsts.ClipDistance0, 4, 8, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.ClipDistance5, new AttributeInfo(AttributeConsts.ClipDistance0, 5, 8, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.ClipDistance6, new AttributeInfo(AttributeConsts.ClipDistance0, 6, 8, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.ClipDistance7, new AttributeInfo(AttributeConsts.ClipDistance0, 7, 8, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.PointCoordX, new AttributeInfo(AttributeConsts.PointCoordX, 0, 2, AggregateType.Vector4 | AggregateType.FP32) }, - { AttributeConsts.PointCoordY, new AttributeInfo(AttributeConsts.PointCoordX, 1, 2, AggregateType.Vector4 | AggregateType.FP32) }, - { AttributeConsts.TessCoordX, new AttributeInfo(AttributeConsts.TessCoordX, 0, 3, AggregateType.Vector4 | AggregateType.FP32) }, - { AttributeConsts.TessCoordY, new AttributeInfo(AttributeConsts.TessCoordX, 1, 3, AggregateType.Vector4 | AggregateType.FP32) }, - { AttributeConsts.InstanceId, new AttributeInfo(AttributeConsts.InstanceId, 0, 1, AggregateType.S32) }, - { AttributeConsts.VertexId, new AttributeInfo(AttributeConsts.VertexId, 0, 1, AggregateType.S32) }, - { AttributeConsts.BaseInstance, new AttributeInfo(AttributeConsts.BaseInstance, 0, 1, AggregateType.S32) }, - { AttributeConsts.BaseVertex, new AttributeInfo(AttributeConsts.BaseVertex, 0, 1, AggregateType.S32) }, - { AttributeConsts.InstanceIndex, new AttributeInfo(AttributeConsts.InstanceIndex, 0, 1, AggregateType.S32) }, - { AttributeConsts.VertexIndex, new AttributeInfo(AttributeConsts.VertexIndex, 0, 1, AggregateType.S32) }, - { AttributeConsts.DrawIndex, new AttributeInfo(AttributeConsts.DrawIndex, 0, 1, AggregateType.S32) }, - { AttributeConsts.FrontFacing, new AttributeInfo(AttributeConsts.FrontFacing, 0, 1, AggregateType.Bool) }, - - // Special. - { AttributeConsts.FragmentOutputDepth, new AttributeInfo(AttributeConsts.FragmentOutputDepth, 0, 1, AggregateType.FP32) }, - { AttributeConsts.ThreadKill, new AttributeInfo(AttributeConsts.ThreadKill, 0, 1, AggregateType.Bool) }, - { AttributeConsts.ThreadIdX, new AttributeInfo(AttributeConsts.ThreadIdX, 0, 3, AggregateType.Vector3 | AggregateType.U32) }, - { AttributeConsts.ThreadIdY, new AttributeInfo(AttributeConsts.ThreadIdX, 1, 3, AggregateType.Vector3 | AggregateType.U32) }, - { AttributeConsts.ThreadIdZ, new AttributeInfo(AttributeConsts.ThreadIdX, 2, 3, AggregateType.Vector3 | AggregateType.U32) }, - { AttributeConsts.CtaIdX, new AttributeInfo(AttributeConsts.CtaIdX, 0, 3, AggregateType.Vector3 | AggregateType.U32) }, - { AttributeConsts.CtaIdY, new AttributeInfo(AttributeConsts.CtaIdX, 1, 3, AggregateType.Vector3 | AggregateType.U32) }, - { AttributeConsts.CtaIdZ, new AttributeInfo(AttributeConsts.CtaIdX, 2, 3, AggregateType.Vector3 | AggregateType.U32) }, - { AttributeConsts.LaneId, new AttributeInfo(AttributeConsts.LaneId, 0, 1, AggregateType.U32) }, - { AttributeConsts.InvocationId, new AttributeInfo(AttributeConsts.InvocationId, 0, 1, AggregateType.S32) }, - { AttributeConsts.PrimitiveId, new AttributeInfo(AttributeConsts.PrimitiveId, 0, 1, AggregateType.S32) }, - { AttributeConsts.PatchVerticesIn, new AttributeInfo(AttributeConsts.PatchVerticesIn, 0, 1, AggregateType.S32) }, - { AttributeConsts.EqMask, new AttributeInfo(AttributeConsts.EqMask, 0, 4, AggregateType.Vector4 | AggregateType.U32) }, - { AttributeConsts.GeMask, new AttributeInfo(AttributeConsts.GeMask, 0, 4, AggregateType.Vector4 | AggregateType.U32) }, - { AttributeConsts.GtMask, new AttributeInfo(AttributeConsts.GtMask, 0, 4, AggregateType.Vector4 | AggregateType.U32) }, - { AttributeConsts.LeMask, new AttributeInfo(AttributeConsts.LeMask, 0, 4, AggregateType.Vector4 | AggregateType.U32) }, - { AttributeConsts.LtMask, new AttributeInfo(AttributeConsts.LtMask, 0, 4, AggregateType.Vector4 | AggregateType.U32) }, - }; - - private static readonly Dictionary<int, AttributeInfo> _builtInAttributesPerPatch = new Dictionary<int, AttributeInfo>() - { - { AttributeConsts.TessLevelOuter0, new AttributeInfo(AttributeConsts.TessLevelOuter0, 0, 4, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.TessLevelOuter1, new AttributeInfo(AttributeConsts.TessLevelOuter0, 1, 4, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.TessLevelOuter2, new AttributeInfo(AttributeConsts.TessLevelOuter0, 2, 4, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.TessLevelOuter3, new AttributeInfo(AttributeConsts.TessLevelOuter0, 3, 4, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.TessLevelInner0, new AttributeInfo(AttributeConsts.TessLevelInner0, 0, 2, AggregateType.Array | AggregateType.FP32) }, - { AttributeConsts.TessLevelInner1, new AttributeInfo(AttributeConsts.TessLevelInner0, 1, 2, AggregateType.Array | AggregateType.FP32) }, - }; - - public int BaseValue { get; } - public int Value { get; } - public int Length { get; } - public AggregateType Type { get; } - public bool IsBuiltin { get; } - public bool IsValid => Type != AggregateType.Invalid; - - public AttributeInfo(int baseValue, int index, int length, AggregateType type, bool isBuiltin = true) - { - BaseValue = baseValue; - Value = baseValue + index * 4; - Length = length; - Type = type; - IsBuiltin = isBuiltin; - } - - public int GetInnermostIndex() - { - return (Value - BaseValue) / 4; - } - - public static bool Validate(ShaderConfig config, int value, bool isOutAttr, bool perPatch) - { - return perPatch ? ValidatePerPatch(config, value, isOutAttr) : Validate(config, value, isOutAttr); - } - - public static bool Validate(ShaderConfig config, int value, bool isOutAttr) - { - if (value == AttributeConsts.ViewportIndex && !config.GpuAccessor.QueryHostSupportsViewportIndex()) - { - return false; - } - - return From(config, value, isOutAttr).IsValid; - } - - public static bool ValidatePerPatch(ShaderConfig config, int value, bool isOutAttr) - { - return FromPatch(config, value, isOutAttr).IsValid; - } - - public static AttributeInfo From(ShaderConfig config, int value, bool isOutAttr) - { - value &= ~3; - - if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd) - { - int location = (value - AttributeConsts.UserAttributeBase) / 16; - - AggregateType elemType; - - if (config.Stage == ShaderStage.Vertex && !isOutAttr) - { - elemType = config.GpuAccessor.QueryAttributeType(location).ToAggregateType(); - } - else - { - elemType = AggregateType.FP32; - } - - return new AttributeInfo(value & ~0xf, (value >> 2) & 3, 4, AggregateType.Vector4 | elemType, false); - } - else if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd) - { - int location = (value - AttributeConsts.FragmentOutputColorBase) / 16; - var elemType = config.GpuAccessor.QueryFragmentOutputType(location) switch - { - AttributeType.Sint => AggregateType.S32, - AttributeType.Uint => AggregateType.U32, - _ => AggregateType.FP32 - }; - - return new AttributeInfo(value & ~0xf, (value >> 2) & 3, 4, AggregateType.Vector4 | elemType, false); - } - else if (value == AttributeConsts.SupportBlockViewInverseX || value == AttributeConsts.SupportBlockViewInverseY) - { - return new AttributeInfo(value, 0, 1, AggregateType.FP32); - } - else if (_builtInAttributes.TryGetValue(value, out AttributeInfo info)) - { - return info; - } - - return new AttributeInfo(value, 0, 0, AggregateType.Invalid); - } - - public static AttributeInfo FromPatch(ShaderConfig config, int value, bool isOutAttr) - { - value &= ~3; - - if (value >= AttributeConsts.UserAttributePerPatchBase && value < AttributeConsts.UserAttributePerPatchEnd) - { - int offset = (value - AttributeConsts.UserAttributePerPatchBase) & 0xf; - return new AttributeInfo(value - offset, offset >> 2, 4, AggregateType.Vector4 | AggregateType.FP32, false); - } - else if (_builtInAttributesPerPatch.TryGetValue(value, out AttributeInfo info)) - { - return info; - } - - return new AttributeInfo(value, 0, 0, AggregateType.Invalid); - } - - public static bool IsArrayBuiltIn(int attr) - { - if (attr <= AttributeConsts.TessLevelInner1 || - attr == AttributeConsts.TessCoordX || - attr == AttributeConsts.TessCoordY) - { - return false; - } - - return (attr & AttributeConsts.SpecialMask) == 0; - } - - public static bool IsArrayAttributeGlsl(ShaderStage stage, bool isOutAttr) - { - if (isOutAttr) - { - return stage == ShaderStage.TessellationControl; - } - else - { - return stage == ShaderStage.TessellationControl || - stage == ShaderStage.TessellationEvaluation || - stage == ShaderStage.Geometry; - } - } - - public static bool IsArrayAttributeSpirv(ShaderStage stage, bool isOutAttr) - { - if (isOutAttr) - { - return false; - } - else - { - return stage == ShaderStage.TessellationControl || - stage == ShaderStage.TessellationEvaluation || - stage == ShaderStage.Geometry; - } - } - } -} diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs index 8f33cced..e81f6425 100644 --- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs +++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs @@ -67,7 +67,7 @@ namespace Ryujinx.Graphics.Shader.Translation (Config.Options.Flags & TranslationFlags.VertexA) == 0) { // Vulkan requires the point size to be always written on the shader if the primitive topology is points. - this.Copy(Attribute(AttributeConsts.PointSize), ConstF(Config.GpuAccessor.QueryPointSize())); + this.Store(StorageKind.Output, IoVariable.PointSize, null, ConstF(Config.GpuAccessor.QueryPointSize())); } } @@ -87,6 +87,15 @@ namespace Ryujinx.Graphics.Shader.Translation return dest; } + public Operand Add(Instruction inst, StorageKind storageKind, Operand dest = null, params Operand[] sources) + { + Operation operation = new Operation(inst, storageKind, dest, sources); + + _operations.Add(operation); + + return dest; + } + public (Operand, Operand) Add(Instruction inst, (Operand, Operand) dest, params Operand[] sources) { Operand[] dests = new[] { dest.Item1, dest.Item2 }; @@ -223,30 +232,35 @@ namespace Ryujinx.Graphics.Shader.Translation { if (Config.GpuAccessor.QueryViewportTransformDisable()) { - Operand x = Attribute(AttributeConsts.PositionX | AttributeConsts.LoadOutputMask); - Operand y = Attribute(AttributeConsts.PositionY | AttributeConsts.LoadOutputMask); - Operand xScale = Attribute(AttributeConsts.SupportBlockViewInverseX); - Operand yScale = Attribute(AttributeConsts.SupportBlockViewInverseY); + Operand x = this.Load(StorageKind.Output, IoVariable.Position, null, Const(0)); + Operand y = this.Load(StorageKind.Output, IoVariable.Position, null, Const(1)); + Operand xScale = this.Load(StorageKind.Input, IoVariable.SupportBlockViewInverse, null, Const(0)); + Operand yScale = this.Load(StorageKind.Input, IoVariable.SupportBlockViewInverse, null, Const(1)); Operand negativeOne = ConstF(-1.0f); - this.Copy(Attribute(AttributeConsts.PositionX), this.FPFusedMultiplyAdd(x, xScale, negativeOne)); - this.Copy(Attribute(AttributeConsts.PositionY), this.FPFusedMultiplyAdd(y, yScale, negativeOne)); + this.Store(StorageKind.Output, IoVariable.Position, null, Const(0), this.FPFusedMultiplyAdd(x, xScale, negativeOne)); + this.Store(StorageKind.Output, IoVariable.Position, null, Const(1), this.FPFusedMultiplyAdd(y, yScale, negativeOne)); } if (Config.Options.TargetApi == TargetApi.Vulkan && Config.GpuAccessor.QueryTransformDepthMinusOneToOne()) { - Operand z = Attribute(AttributeConsts.PositionZ | AttributeConsts.LoadOutputMask); - Operand w = Attribute(AttributeConsts.PositionW | AttributeConsts.LoadOutputMask); + Operand z = this.Load(StorageKind.Output, IoVariable.Position, null, Const(2)); + Operand w = this.Load(StorageKind.Output, IoVariable.Position, null, Const(3)); Operand halfW = this.FPMultiply(w, ConstF(0.5f)); - this.Copy(Attribute(AttributeConsts.PositionZ), this.FPFusedMultiplyAdd(z, ConstF(0.5f), halfW)); + this.Store(StorageKind.Output, IoVariable.Position, null, Const(2), this.FPFusedMultiplyAdd(z, ConstF(0.5f), halfW)); } if (Config.Stage != ShaderStage.Geometry && Config.HasLayerInputAttribute) { Config.SetUsedFeature(FeatureFlags.RtLayer); - this.Copy(Attribute(AttributeConsts.Layer), Attribute(Config.GpLayerInputAttribute | AttributeConsts.LoadOutputMask)); + int attrVecIndex = Config.GpLayerInputAttribute >> 2; + int attrComponentIndex = Config.GpLayerInputAttribute & 3; + + Operand layer = this.Load(StorageKind.Output, IoVariable.UserDefined, null, Const(attrVecIndex), Const(attrComponentIndex)); + + this.Store(StorageKind.Output, IoVariable.Layer, null, layer); } } @@ -255,9 +269,9 @@ namespace Ryujinx.Graphics.Shader.Translation if (Config.GpuAccessor.QueryViewportTransformDisable()) { oldXLocal = Local(); - this.Copy(oldXLocal, Attribute(AttributeConsts.PositionX | AttributeConsts.LoadOutputMask)); + this.Copy(oldXLocal, this.Load(StorageKind.Output, IoVariable.Position, null, Const(0))); oldYLocal = Local(); - this.Copy(oldYLocal, Attribute(AttributeConsts.PositionY | AttributeConsts.LoadOutputMask)); + this.Copy(oldYLocal, this.Load(StorageKind.Output, IoVariable.Position, null, Const(1))); } else { @@ -268,7 +282,7 @@ namespace Ryujinx.Graphics.Shader.Translation if (Config.Options.TargetApi == TargetApi.Vulkan && Config.GpuAccessor.QueryTransformDepthMinusOneToOne()) { oldZLocal = Local(); - this.Copy(oldZLocal, Attribute(AttributeConsts.PositionZ | AttributeConsts.LoadOutputMask)); + this.Copy(oldZLocal, this.Load(StorageKind.Output, IoVariable.Position, null, Const(2))); } else { @@ -293,17 +307,30 @@ namespace Ryujinx.Graphics.Shader.Translation } else if (Config.Stage == ShaderStage.Geometry) { - void WriteOutput(int index, int primIndex) + void WritePositionOutput(int primIndex) + { + Operand x = this.Load(StorageKind.Input, IoVariable.Position, Const(primIndex), Const(0)); + Operand y = this.Load(StorageKind.Input, IoVariable.Position, Const(primIndex), Const(1)); + Operand z = this.Load(StorageKind.Input, IoVariable.Position, Const(primIndex), Const(2)); + Operand w = this.Load(StorageKind.Input, IoVariable.Position, Const(primIndex), Const(3)); + + this.Store(StorageKind.Output, IoVariable.Position, null, Const(0), x); + this.Store(StorageKind.Output, IoVariable.Position, null, Const(1), y); + this.Store(StorageKind.Output, IoVariable.Position, null, Const(2), z); + this.Store(StorageKind.Output, IoVariable.Position, null, Const(3), w); + } + + void WriteUserDefinedOutput(int index, int primIndex) { - Operand x = this.LoadAttribute(Const(index), Const(0), Const(primIndex)); - Operand y = this.LoadAttribute(Const(index + 4), Const(0), Const(primIndex)); - Operand z = this.LoadAttribute(Const(index + 8), Const(0), Const(primIndex)); - Operand w = this.LoadAttribute(Const(index + 12), Const(0), Const(primIndex)); - - this.Copy(Attribute(index), x); - this.Copy(Attribute(index + 4), y); - this.Copy(Attribute(index + 8), z); - this.Copy(Attribute(index + 12), w); + Operand x = this.Load(StorageKind.Input, IoVariable.UserDefined, Const(primIndex), Const(index), Const(0)); + Operand y = this.Load(StorageKind.Input, IoVariable.UserDefined, Const(primIndex), Const(index), Const(1)); + Operand z = this.Load(StorageKind.Input, IoVariable.UserDefined, Const(primIndex), Const(index), Const(2)); + Operand w = this.Load(StorageKind.Input, IoVariable.UserDefined, Const(primIndex), Const(index), Const(3)); + + this.Store(StorageKind.Output, IoVariable.UserDefined, null, Const(index), Const(0), x); + this.Store(StorageKind.Output, IoVariable.UserDefined, null, Const(index), Const(1), y); + this.Store(StorageKind.Output, IoVariable.UserDefined, null, Const(index), Const(2), z); + this.Store(StorageKind.Output, IoVariable.UserDefined, null, Const(index), Const(3), w); } if (Config.GpPassthrough && !Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough()) @@ -312,13 +339,13 @@ namespace Ryujinx.Graphics.Shader.Translation for (int primIndex = 0; primIndex < inputVertices; primIndex++) { - WriteOutput(AttributeConsts.PositionX, primIndex); + WritePositionOutput(primIndex); int passthroughAttributes = Config.PassthroughAttributes; while (passthroughAttributes != 0) { int index = BitOperations.TrailingZeroCount(passthroughAttributes); - WriteOutput(AttributeConsts.UserAttributeBase + index * 16, primIndex); + WriteUserDefinedOutput(index, primIndex); Config.SetOutputUserAttribute(index); passthroughAttributes &= ~(1 << index); } @@ -337,11 +364,9 @@ namespace Ryujinx.Graphics.Shader.Translation if (Config.OmapDepth) { - Operand dest = Attribute(AttributeConsts.FragmentOutputDepth); - Operand src = Register(Config.GetDepthRegister(), RegisterType.Gpr); - this.Copy(dest, src); + this.Store(StorageKind.Output, IoVariable.FragmentOutputDepth, null, src); } AlphaTestOp alphaTestOp = Config.GpuAccessor.QueryAlphaTestCompare(); @@ -390,32 +415,30 @@ namespace Ryujinx.Graphics.Shader.Translation continue; } - int fragmentOutputColorAttr = AttributeConsts.FragmentOutputColorBase + rtIndex * 16; - Operand src = Register(regIndexBase + component, RegisterType.Gpr); // Perform B <-> R swap if needed, for BGRA formats (not supported on OpenGL). if (!supportsBgra && (component == 0 || component == 2)) { - Operand isBgra = Attribute(AttributeConsts.FragmentOutputIsBgraBase + rtIndex * 4); + Operand isBgra = this.Load(StorageKind.Input, IoVariable.FragmentOutputIsBgra, null, Const(rtIndex)); Operand lblIsBgra = Label(); Operand lblEnd = Label(); this.BranchIfTrue(lblIsBgra, isBgra); - this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src); + this.Store(StorageKind.Output, IoVariable.FragmentOutputColor, null, Const(rtIndex), Const(component), src); this.Branch(lblEnd); MarkLabel(lblIsBgra); - this.Copy(Attribute(fragmentOutputColorAttr + (2 - component) * 4), src); + this.Store(StorageKind.Output, IoVariable.FragmentOutputColor, null, Const(rtIndex), Const(2 - component), src); MarkLabel(lblEnd); } else { - this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src); + this.Store(StorageKind.Output, IoVariable.FragmentOutputColor, null, Const(rtIndex), Const(component), src); } } @@ -441,8 +464,11 @@ namespace Ryujinx.Graphics.Shader.Translation // 11 01 01 01 01 00 00 00 Operand ditherMask = Const(unchecked((int)0xfbb99110u)); - Operand x = this.BitwiseAnd(this.FP32ConvertToU32(Attribute(AttributeConsts.PositionX)), Const(1)); - Operand y = this.BitwiseAnd(this.FP32ConvertToU32(Attribute(AttributeConsts.PositionY)), Const(1)); + Operand fragCoordX = this.Load(StorageKind.Input, IoVariable.FragmentCoord, null, Const(0)); + Operand fragCoordY = this.Load(StorageKind.Input, IoVariable.FragmentCoord, null, Const(1)); + + Operand x = this.BitwiseAnd(this.FP32ConvertToU32(fragCoordX), Const(1)); + Operand y = this.BitwiseAnd(this.FP32ConvertToU32(fragCoordY), Const(1)); Operand xy = this.BitwiseOr(x, this.ShiftLeft(y, Const(1))); Operand alpha = Register(3, RegisterType.Gpr); diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs index 1fb60508..93748249 100644 --- a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs +++ b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs @@ -7,54 +7,54 @@ namespace Ryujinx.Graphics.Shader.Translation { static class EmitterContextInsts { - public static Operand AtomicAdd(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c) + public static Operand AtomicAdd(this EmitterContext context, StorageKind storageKind, Operand a, Operand b, Operand c) { - return context.Add(Instruction.AtomicAdd | mr, Local(), a, b, c); + return context.Add(Instruction.AtomicAdd, storageKind, Local(), a, b, c); } - public static Operand AtomicAnd(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c) + public static Operand AtomicAnd(this EmitterContext context, StorageKind storageKind, Operand a, Operand b, Operand c) { - return context.Add(Instruction.AtomicAnd | mr, Local(), a, b, c); + return context.Add(Instruction.AtomicAnd, storageKind, Local(), a, b, c); } - public static Operand AtomicCompareAndSwap(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c, Operand d) + public static Operand AtomicCompareAndSwap(this EmitterContext context, StorageKind storageKind, Operand a, Operand b, Operand c, Operand d) { - return context.Add(Instruction.AtomicCompareAndSwap | mr, Local(), a, b, c, d); + return context.Add(Instruction.AtomicCompareAndSwap, storageKind, Local(), a, b, c, d); } - public static Operand AtomicMaxS32(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c) + public static Operand AtomicMaxS32(this EmitterContext context, StorageKind storageKind, Operand a, Operand b, Operand c) { - return context.Add(Instruction.AtomicMaxS32 | mr, Local(), a, b, c); + return context.Add(Instruction.AtomicMaxS32, storageKind, Local(), a, b, c); } - public static Operand AtomicMaxU32(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c) + public static Operand AtomicMaxU32(this EmitterContext context, StorageKind storageKind, Operand a, Operand b, Operand c) { - return context.Add(Instruction.AtomicMaxU32 | mr, Local(), a, b, c); + return context.Add(Instruction.AtomicMaxU32, storageKind, Local(), a, b, c); } - public static Operand AtomicMinS32(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c) + public static Operand AtomicMinS32(this EmitterContext context, StorageKind storageKind, Operand a, Operand b, Operand c) { - return context.Add(Instruction.AtomicMinS32 | mr, Local(), a, b, c); + return context.Add(Instruction.AtomicMinS32, storageKind, Local(), a, b, c); } - public static Operand AtomicMinU32(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c) + public static Operand AtomicMinU32(this EmitterContext context, StorageKind storageKind, Operand a, Operand b, Operand c) { - return context.Add(Instruction.AtomicMinU32 | mr, Local(), a, b, c); + return context.Add(Instruction.AtomicMinU32, storageKind, Local(), a, b, c); } - public static Operand AtomicOr(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c) + public static Operand AtomicOr(this EmitterContext context, StorageKind storageKind, Operand a, Operand b, Operand c) { - return context.Add(Instruction.AtomicOr | mr, Local(), a, b, c); + return context.Add(Instruction.AtomicOr, storageKind, Local(), a, b, c); } - public static Operand AtomicSwap(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c) + public static Operand AtomicSwap(this EmitterContext context, StorageKind storageKind, Operand a, Operand b, Operand c) { - return context.Add(Instruction.AtomicSwap | mr, Local(), a, b, c); + return context.Add(Instruction.AtomicSwap, storageKind, Local(), a, b, c); } - public static Operand AtomicXor(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c) + public static Operand AtomicXor(this EmitterContext context, StorageKind storageKind, Operand a, Operand b, Operand c) { - return context.Add(Instruction.AtomicXor | mr, Local(), a, b, c); + return context.Add(Instruction.AtomicXor, storageKind, Local(), a, b, c); } public static Operand Ballot(this EmitterContext context, Operand a) @@ -549,9 +549,36 @@ namespace Ryujinx.Graphics.Shader.Translation return context.Add(fpType | Instruction.IsNan, Local(), a); } - public static Operand LoadAttribute(this EmitterContext context, Operand a, Operand b, Operand c) + public static Operand Load(this EmitterContext context, StorageKind storageKind, IoVariable ioVariable, Operand primVertex = null) { - return context.Add(Instruction.LoadAttribute, Local(), a, b, c); + return primVertex != null + ? context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable), primVertex) + : context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable)); + } + + public static Operand Load( + this EmitterContext context, + StorageKind storageKind, + IoVariable ioVariable, + Operand primVertex, + Operand elemIndex) + { + return primVertex != null + ? context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable), primVertex, elemIndex) + : context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable), elemIndex); + } + + public static Operand Load( + this EmitterContext context, + StorageKind storageKind, + IoVariable ioVariable, + Operand primVertex, + Operand arrayIndex, + Operand elemIndex) + { + return primVertex != null + ? context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable), primVertex, arrayIndex, elemIndex) + : context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable), arrayIndex, elemIndex); } public static Operand LoadConstant(this EmitterContext context, Operand a, Operand b) @@ -662,9 +689,43 @@ namespace Ryujinx.Graphics.Shader.Translation return context.Add(Instruction.ShuffleXor, (Local(), Local()), a, b, c); } - public static Operand StoreAttribute(this EmitterContext context, Operand a, Operand b, Operand c) + public static Operand Store( + this EmitterContext context, + StorageKind storageKind, + IoVariable ioVariable, + Operand invocationId, + Operand value) + { + return invocationId != null + ? context.Add(Instruction.Store, storageKind, null, Const((int)ioVariable), invocationId, value) + : context.Add(Instruction.Store, storageKind, null, Const((int)ioVariable), value); + } + + public static Operand Store( + this EmitterContext context, + StorageKind storageKind, + IoVariable ioVariable, + Operand invocationId, + Operand elemIndex, + Operand value) + { + return invocationId != null + ? context.Add(Instruction.Store, storageKind, null, Const((int)ioVariable), invocationId, elemIndex, value) + : context.Add(Instruction.Store, storageKind, null, Const((int)ioVariable), elemIndex, value); + } + + public static Operand Store( + this EmitterContext context, + StorageKind storageKind, + IoVariable ioVariable, + Operand invocationId, + Operand arrayIndex, + Operand elemIndex, + Operand value) { - return context.Add(Instruction.StoreAttribute, null, a, b, c); + return invocationId != null + ? context.Add(Instruction.Store, storageKind, null, Const((int)ioVariable), invocationId, arrayIndex, elemIndex, value) + : context.Add(Instruction.Store, storageKind, null, Const((int)ioVariable), arrayIndex, elemIndex, value); } public static Operand StoreGlobal(this EmitterContext context, Operand a, Operand b, Operand c) diff --git a/Ryujinx.Graphics.Shader/Translation/GlobalMemory.cs b/Ryujinx.Graphics.Shader/Translation/GlobalMemory.cs index 3915c0d5..774a128d 100644 --- a/Ryujinx.Graphics.Shader/Translation/GlobalMemory.cs +++ b/Ryujinx.Graphics.Shader/Translation/GlobalMemory.cs @@ -16,20 +16,15 @@ namespace Ryujinx.Graphics.Shader.Translation public const int UbeDescsSize = StorageDescSize * UbeMaxCount; public const int UbeFirstCbuf = 8; - public static bool UsesGlobalMemory(Instruction inst) + public static bool UsesGlobalMemory(Instruction inst, StorageKind storageKind) { - return (inst.IsAtomic() && IsGlobalMr(inst)) || + return (inst.IsAtomic() && storageKind == StorageKind.GlobalMemory) || inst == Instruction.LoadGlobal || inst == Instruction.StoreGlobal || inst == Instruction.StoreGlobal16 || inst == Instruction.StoreGlobal8; } - private static bool IsGlobalMr(Instruction inst) - { - return (inst & Instruction.MrMask) == Instruction.MrGlobal; - } - public static int GetStorageCbOffset(ShaderStage stage, int slot) { return GetStorageBaseCbOffset(stage) + slot * StorageDescSize; diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs index c280a6d8..2a4070e0 100644 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs +++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs @@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations continue; } - if (UsesGlobalMemory(operation.Inst)) + if (UsesGlobalMemory(operation.Inst, operation.StorageKind)) { Operand source = operation.GetSource(0); @@ -104,9 +104,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations if (isAtomic) { - Instruction inst = (operation.Inst & ~Instruction.MrMask) | Instruction.MrStorage; - - storageOp = new Operation(inst, operation.Dest, sources); + storageOp = new Operation(operation.Inst, StorageKind.StorageBuffer, operation.Dest, sources); } else if (operation.Inst == Instruction.LoadGlobal) { diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs index a2219b36..bae774ee 100644 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs +++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs @@ -170,10 +170,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations return false; } - return x.Type == OperandType.Attribute || - x.Type == OperandType.AttributePerPatch || - x.Type == OperandType.Constant || - x.Type == OperandType.ConstantBuffer; + // TODO: Handle Load operations with the same storage and the same constant parameters. + return x.Type == OperandType.Constant || x.Type == OperandType.ConstantBuffer; } private static bool PropagatePack(Operation packOp) diff --git a/Ryujinx.Graphics.Shader/Translation/Rewriter.cs b/Ryujinx.Graphics.Shader/Translation/Rewriter.cs index 3ec4e49a..91e7ace1 100644 --- a/Ryujinx.Graphics.Shader/Translation/Rewriter.cs +++ b/Ryujinx.Graphics.Shader/Translation/Rewriter.cs @@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Shader.Translation { if (hasConstantBufferDrawParameters) { - if (ReplaceConstantBufferWithDrawParameters(operation)) + if (ReplaceConstantBufferWithDrawParameters(node, operation)) { config.SetUsedFeature(FeatureFlags.DrawParameters); } @@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.Shader.Translation nextNode = node.Next; } - else if (UsesGlobalMemory(operation.Inst)) + else if (UsesGlobalMemory(operation.Inst, operation.StorageKind)) { nextNode = RewriteGlobalAccess(node, config)?.Next ?? nextNode; } @@ -169,9 +169,7 @@ namespace Ryujinx.Graphics.Shader.Translation if (isAtomic) { - Instruction inst = (operation.Inst & ~Instruction.MrMask) | Instruction.MrStorage; - - storageOp = new Operation(inst, operation.Dest, sources); + storageOp = new Operation(operation.Inst, StorageKind.StorageBuffer, operation.Dest, sources); } else if (operation.Inst == Instruction.LoadGlobal) { @@ -708,8 +706,15 @@ namespace Ryujinx.Graphics.Shader.Translation return node; } - private static bool ReplaceConstantBufferWithDrawParameters(Operation operation) + private static bool ReplaceConstantBufferWithDrawParameters(LinkedListNode<INode> node, Operation operation) { + Operand GenerateLoad(IoVariable ioVariable) + { + Operand value = Local(); + node.List.AddBefore(node, new Operation(Instruction.Load, StorageKind.Input, value, Const((int)ioVariable))); + return value; + } + bool modified = false; for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++) @@ -721,15 +726,15 @@ namespace Ryujinx.Graphics.Shader.Translation switch (src.GetCbufOffset()) { case Constants.NvnBaseVertexByteOffset / 4: - operation.SetSource(srcIndex, Attribute(AttributeConsts.BaseVertex)); + operation.SetSource(srcIndex, GenerateLoad(IoVariable.BaseVertex)); modified = true; break; case Constants.NvnBaseInstanceByteOffset / 4: - operation.SetSource(srcIndex, Attribute(AttributeConsts.BaseInstance)); + operation.SetSource(srcIndex, GenerateLoad(IoVariable.BaseInstance)); modified = true; break; case Constants.NvnDrawIndexByteOffset / 4: - operation.SetSource(srcIndex, Attribute(AttributeConsts.DrawIndex)); + operation.SetSource(srcIndex, GenerateLoad(IoVariable.DrawIndex)); modified = true; break; } diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs index 15eb7ed1..22f5a671 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs +++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs @@ -41,6 +41,46 @@ namespace Ryujinx.Graphics.Shader.Translation public bool TransformFeedbackEnabled { get; } + private TransformFeedbackOutput[] _transformFeedbackOutputs; + + readonly struct TransformFeedbackVariable : IEquatable<TransformFeedbackVariable> + { + public IoVariable IoVariable { get; } + public int Location { get; } + public int Component { get; } + + public TransformFeedbackVariable(IoVariable ioVariable, int location = 0, int component = 0) + { + IoVariable = ioVariable; + Location = location; + Component = component; + } + + public override bool Equals(object other) + { + return other is TransformFeedbackVariable tfbVar && Equals(tfbVar); + } + + public bool Equals(TransformFeedbackVariable other) + { + return IoVariable == other.IoVariable && + Location == other.Location && + Component == other.Component; + } + + public override int GetHashCode() + { + return (int)IoVariable | (Location << 8) | (Component << 16); + } + + public override string ToString() + { + return $"{IoVariable}.{Location}.{Component}"; + } + } + + private readonly Dictionary<TransformFeedbackVariable, TransformFeedbackOutput> _transformFeedbackDefinitions; + public int Size { get; private set; } public byte ClipDistancesWritten { get; private set; } @@ -102,6 +142,8 @@ namespace Ryujinx.Graphics.Shader.Translation GpuAccessor = gpuAccessor; Options = options; + _transformFeedbackDefinitions = new Dictionary<TransformFeedbackVariable, TransformFeedbackOutput>(); + AccessibleStorageBuffersMask = (1 << GlobalMemory.StorageMaxCount) - 1; AccessibleConstantBuffersMask = (1 << GlobalMemory.UbeMaxCount) - 1; @@ -147,6 +189,173 @@ namespace Ryujinx.Graphics.Shader.Translation LastInVertexPipeline = header.Stage < ShaderStage.Fragment; } + private void EnsureTransformFeedbackInitialized() + { + if (HasTransformFeedbackOutputs() && _transformFeedbackOutputs == null) + { + TransformFeedbackOutput[] transformFeedbackOutputs = new TransformFeedbackOutput[0xc0]; + ulong vecMap = 0UL; + + for (int tfbIndex = 0; tfbIndex < 4; tfbIndex++) + { + var locations = GpuAccessor.QueryTransformFeedbackVaryingLocations(tfbIndex); + var stride = GpuAccessor.QueryTransformFeedbackStride(tfbIndex); + + for (int i = 0; i < locations.Length; i++) + { + byte wordOffset = locations[i]; + if (wordOffset < 0xc0) + { + transformFeedbackOutputs[wordOffset] = new TransformFeedbackOutput(tfbIndex, i * 4, stride); + vecMap |= 1UL << (wordOffset / 4); + } + } + } + + _transformFeedbackOutputs = transformFeedbackOutputs; + + while (vecMap != 0) + { + int vecIndex = BitOperations.TrailingZeroCount(vecMap); + + for (int subIndex = 0; subIndex < 4; subIndex++) + { + int wordOffset = vecIndex * 4 + subIndex; + int byteOffset = wordOffset * 4; + + if (transformFeedbackOutputs[wordOffset].Valid) + { + IoVariable ioVariable = Instructions.AttributeMap.GetIoVariable(this, byteOffset, out int location); + int component = 0; + + if (HasPerLocationInputOrOutputComponent(ioVariable, location, subIndex, isOutput: true)) + { + component = subIndex; + } + + var transformFeedbackVariable = new TransformFeedbackVariable(ioVariable, location, component); + _transformFeedbackDefinitions.TryAdd(transformFeedbackVariable, transformFeedbackOutputs[wordOffset]); + } + } + + vecMap &= ~(1UL << vecIndex); + } + } + } + + public TransformFeedbackOutput[] GetTransformFeedbackOutputs() + { + EnsureTransformFeedbackInitialized(); + return _transformFeedbackOutputs; + } + + public bool TryGetTransformFeedbackOutput(IoVariable ioVariable, int location, int component, out TransformFeedbackOutput transformFeedbackOutput) + { + EnsureTransformFeedbackInitialized(); + var transformFeedbackVariable = new TransformFeedbackVariable(ioVariable, location, component); + return _transformFeedbackDefinitions.TryGetValue(transformFeedbackVariable, out transformFeedbackOutput); + } + + private bool HasTransformFeedbackOutputs() + { + return TransformFeedbackEnabled && (LastInVertexPipeline || Stage == ShaderStage.Fragment); + } + + public bool HasTransformFeedbackOutputs(bool isOutput) + { + return TransformFeedbackEnabled && ((isOutput && LastInVertexPipeline) || (!isOutput && Stage == ShaderStage.Fragment)); + } + + public bool HasPerLocationInputOrOutput(IoVariable ioVariable, bool isOutput) + { + if (ioVariable == IoVariable.UserDefined) + { + return (!isOutput && !UsedFeatures.HasFlag(FeatureFlags.IaIndexing)) || + (isOutput && !UsedFeatures.HasFlag(FeatureFlags.OaIndexing)); + } + + return ioVariable == IoVariable.FragmentOutputColor; + } + + public bool HasPerLocationInputOrOutputComponent(IoVariable ioVariable, int location, int component, bool isOutput) + { + if (ioVariable != IoVariable.UserDefined || !HasTransformFeedbackOutputs(isOutput)) + { + return false; + } + + return GetTransformFeedbackOutputComponents(location, component) == 1; + } + + public TransformFeedbackOutput GetTransformFeedbackOutput(int wordOffset) + { + EnsureTransformFeedbackInitialized(); + + return _transformFeedbackOutputs[wordOffset]; + } + + public TransformFeedbackOutput GetTransformFeedbackOutput(int location, int component) + { + return GetTransformFeedbackOutput((AttributeConsts.UserAttributeBase / 4) + location * 4 + component); + } + + public int GetTransformFeedbackOutputComponents(int location, int component) + { + EnsureTransformFeedbackInitialized(); + + int baseIndex = (AttributeConsts.UserAttributeBase / 4) + location * 4; + int index = baseIndex + component; + int count = 1; + + for (; count < 4; count++) + { + ref var prev = ref _transformFeedbackOutputs[baseIndex + count - 1]; + ref var curr = ref _transformFeedbackOutputs[baseIndex + count]; + + int prevOffset = prev.Offset; + int currOffset = curr.Offset; + + if (!prev.Valid || !curr.Valid || prevOffset + 4 != currOffset) + { + break; + } + } + + if (baseIndex + count <= index) + { + return 1; + } + + return count; + } + + public AggregateType GetFragmentOutputColorType(int location) + { + return AggregateType.Vector4 | GpuAccessor.QueryFragmentOutputType(location).ToAggregateType(); + } + + public AggregateType GetUserDefinedType(int location, bool isOutput) + { + if ((!isOutput && UsedFeatures.HasFlag(FeatureFlags.IaIndexing)) || + (isOutput && UsedFeatures.HasFlag(FeatureFlags.OaIndexing))) + { + return AggregateType.Array | AggregateType.Vector4 | AggregateType.FP32; + } + + AggregateType type = AggregateType.Vector4; + + if (Stage == ShaderStage.Vertex && !isOutput) + { + type |= GpuAccessor.QueryAttributeType(location).ToAggregateType(); + } + else + { + type |= AggregateType.FP32; + } + + return type; + } + public int GetDepthRegister() { // The depth register is always two registers after the last color output. @@ -184,7 +393,7 @@ namespace Ryujinx.Graphics.Shader.Translation return format; } - private bool FormatSupportsAtomic(TextureFormat format) + private static bool FormatSupportsAtomic(TextureFormat format) { return format == TextureFormat.R32Sint || format == TextureFormat.R32Uint; } diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderIdentifier.cs b/Ryujinx.Graphics.Shader/Translation/ShaderIdentifier.cs index 206718f2..53f1e847 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderIdentifier.cs +++ b/Ryujinx.Graphics.Shader/Translation/ShaderIdentifier.cs @@ -53,40 +53,80 @@ namespace Ryujinx.Graphics.Shader.Translation return false; } - if (operation.Inst == Instruction.StoreAttribute) + if (operation.Inst == Instruction.Store && operation.StorageKind == StorageKind.Output) { - return false; - } - - if (operation.Inst == Instruction.Copy && operation.Dest.Type == OperandType.Attribute) - { - Operand src = operation.GetSource(0); + Operand src = operation.GetSource(operation.SourcesCount - 1); + Operation srcAttributeAsgOp = null; - if (src.Type == OperandType.LocalVariable && src.AsgOp is Operation asgOp && asgOp.Inst == Instruction.LoadAttribute) + if (src.Type == OperandType.LocalVariable && + src.AsgOp is Operation asgOp && + asgOp.Inst == Instruction.Load && + asgOp.StorageKind.IsInputOrOutput()) { - src = Attribute(asgOp.GetSource(0).Value); + if (asgOp.StorageKind != StorageKind.Input) + { + return false; + } + + srcAttributeAsgOp = asgOp; } - if (src.Type == OperandType.Attribute) + if (srcAttributeAsgOp != null) { - if (operation.Dest.Value == AttributeConsts.Layer) + IoVariable dstAttribute = (IoVariable)operation.GetSource(0).Value; + IoVariable srcAttribute = (IoVariable)srcAttributeAsgOp.GetSource(0).Value; + + if (dstAttribute == IoVariable.Layer && srcAttribute == IoVariable.UserDefined) { - if ((src.Value & AttributeConsts.LoadOutputMask) != 0) + if (srcAttributeAsgOp.SourcesCount != 4) { return false; } writesLayer = true; - layerInputAttr = src.Value; + layerInputAttr = srcAttributeAsgOp.GetSource(1).Value * 4 + srcAttributeAsgOp.GetSource(3).Value;; } - else if (src.Value != operation.Dest.Value) + else { - return false; + if (dstAttribute != srcAttribute) + { + return false; + } + + int inputsCount = operation.SourcesCount - 2; + + if (dstAttribute == IoVariable.UserDefined) + { + if (operation.GetSource(1).Value != srcAttributeAsgOp.GetSource(1).Value) + { + return false; + } + + inputsCount--; + } + + for (int i = 0; i < inputsCount; i++) + { + int dstIndex = operation.SourcesCount - 2 - i; + int srcIndex = srcAttributeAsgOp.SourcesCount - 1 - i; + + if ((dstIndex | srcIndex) < 0) + { + return false; + } + + if (operation.GetSource(dstIndex).Type != OperandType.Constant || + srcAttributeAsgOp.GetSource(srcIndex).Type != OperandType.Constant || + operation.GetSource(dstIndex).Value != srcAttributeAsgOp.GetSource(srcIndex).Value) + { + return false; + } + } } } else if (src.Type == OperandType.Constant) { - int dstComponent = (operation.Dest.Value >> 2) & 3; + int dstComponent = operation.GetSource(operation.SourcesCount - 2).Value; float expectedValue = dstComponent == 3 ? 1f : 0f; if (src.AsFloat() != expectedValue) diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs index 6a123045..77d3b568 100644 --- a/Ryujinx.Graphics.Shader/Translation/Translator.cs +++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs @@ -177,7 +177,7 @@ namespace Ryujinx.Graphics.Shader.Translation if (config.Stage == ShaderStage.Vertex) { - InitializeOutput(context, AttributeConsts.PositionX, perPatch: false); + InitializePositionOutput(context); } UInt128 usedAttributes = context.Config.NextInputAttributesComponents; @@ -194,20 +194,23 @@ namespace Ryujinx.Graphics.Shader.Translation continue; } - InitializeOutputComponent(context, AttributeConsts.UserAttributeBase + index * 4, perPatch: false); + InitializeOutputComponent(context, vecIndex, index & 3, perPatch: false); } if (context.Config.NextUsedInputAttributesPerPatch != null) { foreach (int vecIndex in context.Config.NextUsedInputAttributesPerPatch.Order()) { - InitializeOutput(context, AttributeConsts.UserAttributePerPatchBase + vecIndex * 16, perPatch: true); + InitializeOutput(context, vecIndex, perPatch: true); } } if (config.NextUsesFixedFuncAttributes) { - for (int i = 0; i < 4 + AttributeConsts.TexCoordCount; i++) + bool supportsLayerFromVertexOrTess = config.GpuAccessor.QueryHostSupportsLayerVertexTessellation(); + int fixedStartAttr = supportsLayerFromVertexOrTess ? 0 : 1; + + for (int i = fixedStartAttr; i < fixedStartAttr + 5 + AttributeConsts.TexCoordCount; i++) { int index = config.GetFreeUserAttribute(isOutput: true, i); if (index < 0) @@ -215,26 +218,58 @@ namespace Ryujinx.Graphics.Shader.Translation break; } - InitializeOutput(context, AttributeConsts.UserAttributeBase + index * 16, perPatch: false); + InitializeOutput(context, index, perPatch: false); config.SetOutputUserAttributeFixedFunc(index); } } } - private static void InitializeOutput(EmitterContext context, int baseAttr, bool perPatch) + private static void InitializePositionOutput(EmitterContext context) { for (int c = 0; c < 4; c++) { - int attrOffset = baseAttr + c * 4; - InitializeOutputComponent(context, attrOffset, perPatch); + context.Store(StorageKind.Output, IoVariable.Position, null, Const(c), ConstF(c == 3 ? 1f : 0f)); } } - private static void InitializeOutputComponent(EmitterContext context, int attrOffset, bool perPatch) + private static void InitializeOutput(EmitterContext context, int location, bool perPatch) { - int c = (attrOffset >> 2) & 3; - context.Copy(perPatch ? AttributePerPatch(attrOffset) : Attribute(attrOffset), ConstF(c == 3 ? 1f : 0f)); + for (int c = 0; c < 4; c++) + { + InitializeOutputComponent(context, location, c, perPatch); + } + } + + private static void InitializeOutputComponent(EmitterContext context, int location, int c, bool perPatch) + { + StorageKind storageKind = perPatch ? StorageKind.OutputPerPatch : StorageKind.Output; + + if (context.Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing)) + { + Operand invocationId = null; + + if (context.Config.Stage == ShaderStage.TessellationControl && !perPatch) + { + invocationId = context.Load(StorageKind.Input, IoVariable.InvocationId); + } + + int index = location * 4 + c; + + context.Store(storageKind, IoVariable.UserDefined, invocationId, Const(index), ConstF(c == 3 ? 1f : 0f)); + } + else + { + if (context.Config.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)); + } + else + { + context.Store(storageKind, IoVariable.UserDefined, null, Const(location), Const(c), ConstF(c == 3 ? 1f : 0f)); + } + } } private static void EmitOps(EmitterContext context, Block block) diff --git a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs index 856b16b7..4a304f3a 100644 --- a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs +++ b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs @@ -34,15 +34,16 @@ namespace Ryujinx.Graphics.Shader.Translation _config = config; } - private static bool IsUserAttribute(Operand operand) + private static bool IsLoadUserDefined(Operation operation) { - if (operand != null && operand.Type.IsAttribute()) - { - int value = operand.Value & AttributeConsts.Mask; - return value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd; - } + // TODO: Check if sources count match and all sources are constant. + return operation.Inst == Instruction.Load && (IoVariable)operation.GetSource(0).Value == IoVariable.UserDefined; + } - return false; + private static bool IsStoreUserDefined(Operation operation) + { + // TODO: Check if sources count match and all sources are constant. + return operation.Inst == Instruction.Store && (IoVariable)operation.GetSource(0).Value == IoVariable.UserDefined; } private static FunctionCode[] Combine(FunctionCode[] a, FunctionCode[] b, int aStart) @@ -68,9 +69,9 @@ namespace Ryujinx.Graphics.Shader.Translation { Operation operation = a[0].Code[index]; - if (IsUserAttribute(operation.Dest)) + if (IsStoreUserDefined(operation)) { - int tIndex = (operation.Dest.Value - AttributeConsts.UserAttributeBase) / 4; + int tIndex = operation.GetSource(1).Value * 4 + operation.GetSource(2).Value; Operand temp = temps[tIndex]; @@ -82,6 +83,7 @@ namespace Ryujinx.Graphics.Shader.Translation } operation.Dest = temp; + operation.TurnIntoCopy(operation.GetSource(operation.SourcesCount - 1)); } if (operation.Inst == Instruction.Return) @@ -100,18 +102,15 @@ namespace Ryujinx.Graphics.Shader.Translation { Operation operation = b[0].Code[index]; - for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++) + if (IsLoadUserDefined(operation)) { - Operand src = operation.GetSource(srcIndex); + int tIndex = operation.GetSource(1).Value * 4 + operation.GetSource(2).Value; - if (IsUserAttribute(src)) - { - Operand temp = temps[(src.Value - AttributeConsts.UserAttributeBase) / 4]; + Operand temp = temps[tIndex]; - if (temp != null) - { - operation.SetSource(srcIndex, temp); - } + if (temp != null) + { + operation.TurnIntoCopy(temp); } } @@ -209,15 +208,15 @@ namespace Ryujinx.Graphics.Shader.Translation { int attr = AttributeConsts.UserAttributeBase + attrIndex * 16 + c * 4; - Operand value = context.LoadAttribute(Const(attr), Const(0), Const(v)); + Operand value = context.Load(StorageKind.Input, IoVariable.UserDefined, Const(v), Const(attrIndex), Const(c)); if (attr == layerOutputAttr) { - context.Copy(Attribute(AttributeConsts.Layer), value); + context.Store(StorageKind.Output, IoVariable.Layer, null, value); } else { - context.Copy(Attribute(attr), value); + context.Store(StorageKind.Output, IoVariable.UserDefined, null, Const(attrIndex), Const(c), value); config.SetOutputUserAttribute(attrIndex); } @@ -227,11 +226,9 @@ namespace Ryujinx.Graphics.Shader.Translation for (int c = 0; c < 4; c++) { - int attr = AttributeConsts.PositionX + c * 4; - - Operand value = context.LoadAttribute(Const(attr), Const(0), Const(v)); + Operand value = context.Load(StorageKind.Input, IoVariable.Position, Const(v), Const(c)); - context.Copy(Attribute(attr), value); + context.Store(StorageKind.Output, IoVariable.Position, null, Const(c), value); } context.EmitVertex(); |
