aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Translation
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-04-25 19:51:07 -0300
committerGitHub <noreply@github.com>2023-04-25 19:51:07 -0300
commit9f12e50a546b15533778ed0d8290202af91c10a2 (patch)
treef0e77a7b7c605face5ef29270b4248af2682301a /Ryujinx.Graphics.Shader/Translation
parent097562bc6c227c42f803ce1078fcb4adf06cd20c (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')
-rw-r--r--Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs121
-rw-r--r--Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs210
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContext.cs100
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs109
-rw-r--r--Ryujinx.Graphics.Shader/Translation/GlobalMemory.cs9
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs6
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs6
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Rewriter.cs23
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs211
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderIdentifier.cs72
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Translator.cs57
-rw-r--r--Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs47
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();