aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2021-11-08 13:18:46 -0300
committerGitHub <noreply@github.com>2021-11-08 13:18:46 -0300
commit911ea38e939459c652c6e27a28599340a61267dc (patch)
treee0e22a504b67f51625a7c23dd8157bada6841f77
parent3dee712164e635fd3a0d2e9d359a7d11a80bf675 (diff)
Support shader gl_Color, gl_SecondaryColor and gl_TexCoord built-ins (#2817)
* Support shader gl_Color, gl_SecondaryColor and gl_TexCoord built-ins * Shader cache version bump * Fix back color value on fragment shader * Disable IPA multiplication for fixed function attributes and back color selection
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs2
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/Decoder.cs7
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs84
-rw-r--r--Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs73
-rw-r--r--Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs3
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs69
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Translator.cs16
-rw-r--r--Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs4
8 files changed, 220 insertions, 38 deletions
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index 4e1e130c..353c5dfe 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Version of the codegen (to be changed when codegen or guest format change).
/// </summary>
- private const ulong ShaderCodeGenVersion = 2826;
+ private const ulong ShaderCodeGenVersion = 2816;
// Progress reporting helpers
private volatile int _shaderCount;
diff --git a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
index 714aaad3..80d2cb4a 100644
--- a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
@@ -319,6 +319,13 @@ namespace Ryujinx.Graphics.Shader.Decoders
config.SetInputUserAttribute(index, perPatch);
}
}
+
+ if (!isStore &&
+ ((attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.ClipDistance0) ||
+ (attr >= AttributeConsts.TexCoordBase && attr < AttributeConsts.TexCoordEnd)))
+ {
+ config.SetUsedFeature(FeatureFlags.FixedFuncAttr);
+ }
}
}
}
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs
index f82b835c..e2131602 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs
@@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else if (op.SrcB == RegisterConsts.RegisterZeroIndex || op.P)
{
- int offset = op.Imm11 + index * 4;
+ int offset = FixedFuncToUserAttribute(context.Config, op.Imm11 + index * 4, op.O);
context.FlagAttributeRead(offset);
@@ -57,7 +57,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- int offset = op.Imm11 + index * 4;
+ int offset = FixedFuncToUserAttribute(context.Config, op.Imm11 + index * 4, op.O);
context.FlagAttributeRead(offset);
@@ -101,6 +101,13 @@ namespace Ryujinx.Graphics.Shader.Instructions
int offset = op.Imm11 + index * 4;
+ if (!context.Config.IsUsedOutputAttribute(offset))
+ {
+ return;
+ }
+
+ offset = FixedFuncToUserAttribute(context.Config, offset, isOutput: true);
+
context.FlagAttributeWritten(offset);
Operand dest = op.P ? AttributePerPatch(offset) : Attribute(offset);
@@ -118,6 +125,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
Operand res;
+ bool isFixedFunc = false;
+
if (op.Idx)
{
Operand userAttrOffset = context.ISubtract(GetSrcReg(context, op.SrcA), Const(AttributeConsts.UserAttributeBase));
@@ -130,7 +139,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- res = Attribute(op.Imm10);
+ isFixedFunc = TryFixedFuncToUserAttributeIpa(context, op.Imm10, out res);
if (op.Imm10 >= AttributeConsts.UserAttributeBase && op.Imm10 < AttributeConsts.UserAttributeEnd)
{
@@ -143,7 +152,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
- if (op.IpaOp == IpaOp.Multiply)
+ if (op.IpaOp == IpaOp.Multiply && !isFixedFunc)
{
Operand srcB = GetSrcReg(context, op.SrcB);
@@ -204,5 +213,72 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.EndPrimitive();
}
}
+
+ private static bool TryFixedFuncToUserAttributeIpa(EmitterContext context, int attr, out Operand selectedAttr)
+ {
+ if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.BackColorDiffuseR)
+ {
+ // TODO: If two sided rendering is enabled, then this should return
+ // FrontColor if the fragment is front facing, and back color otherwise.
+ int index = (attr - AttributeConsts.FrontColorDiffuseR) >> 4;
+ int userAttrIndex = context.Config.GetFreeUserAttribute(isOutput: false, index);
+ Operand frontAttr = Attribute(AttributeConsts.UserAttributeBase + userAttrIndex * 16 + (attr & 0xf));
+
+ context.Config.SetInputUserAttributeFixedFunc(userAttrIndex);
+
+ selectedAttr = frontAttr;
+ return true;
+ }
+ else if (attr >= AttributeConsts.BackColorDiffuseR && attr < AttributeConsts.ClipDistance0)
+ {
+ selectedAttr = ConstF(((attr >> 2) & 3) == 3 ? 1f : 0f);
+ return true;
+ }
+ else if (attr >= AttributeConsts.TexCoordBase && attr < AttributeConsts.TexCoordEnd)
+ {
+ selectedAttr = Attribute(FixedFuncToUserAttribute(context.Config, attr, AttributeConsts.TexCoordBase, 4, isOutput: false));
+ return true;
+ }
+
+ selectedAttr = Attribute(attr);
+ return false;
+ }
+
+ private static int FixedFuncToUserAttribute(ShaderConfig config, int attr, bool isOutput)
+ {
+ if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.ClipDistance0)
+ {
+ attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.FrontColorDiffuseR, 0, isOutput);
+ }
+ else if (attr >= AttributeConsts.TexCoordBase && attr < AttributeConsts.TexCoordEnd)
+ {
+ attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.TexCoordBase, 4, isOutput);
+ }
+
+ return attr;
+ }
+
+ private static int FixedFuncToUserAttribute(ShaderConfig config, int attr, int baseAttr, int baseIndex, bool isOutput)
+ {
+ int index = (attr - baseAttr) >> 4;
+ int userAttrIndex = config.GetFreeUserAttribute(isOutput, index);
+
+ if ((uint)userAttrIndex < Constants.MaxAttributes)
+ {
+ userAttrIndex += baseIndex;
+ attr = AttributeConsts.UserAttributeBase + userAttrIndex * 16 + (attr & 0xf);
+
+ if (isOutput)
+ {
+ config.SetOutputUserAttributeFixedFunc(userAttrIndex);
+ }
+ else
+ {
+ config.SetInputUserAttributeFixedFunc(userAttrIndex);
+ }
+ }
+
+ return attr;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
index 128013d8..370af009 100644
--- a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
+++ b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
@@ -2,33 +2,52 @@ 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 Layer = 0x064;
- 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 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 FrontFacing = 0x3fc;
+ 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 Layer = 0x064;
+ 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 UserAttributesCount = 32;
public const int UserAttributeBase = 0x80;
diff --git a/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs b/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
index f602ea64..a2363fcb 100644
--- a/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
+++ b/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
@@ -20,6 +20,7 @@ namespace Ryujinx.Graphics.Shader.Translation
RtLayer = 1 << 4,
CbIndexing = 1 << 5,
IaIndexing = 1 << 6,
- OaIndexing = 1 << 7
+ OaIndexing = 1 << 7,
+ FixedFuncAttr = 1 << 8
}
}
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 2314016e..df14a5ed 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -43,11 +43,14 @@ namespace Ryujinx.Graphics.Shader.Translation
private readonly TranslationCounts _counts;
+ public bool NextUsesFixedFuncAttributes { get; private set; }
public int UsedInputAttributes { get; private set; }
- public int UsedInputAttributesPerPatch { get; private set; }
public int UsedOutputAttributes { get; private set; }
+ public int UsedInputAttributesPerPatch { get; private set; }
public int UsedOutputAttributesPerPatch { get; private set; }
public int PassthroughAttributes { get; private set; }
+ private int _nextUsedInputAttributes;
+ private int _thisUsedInputAttributes;
private int _usedConstantBuffers;
private int _usedStorageBuffers;
@@ -224,6 +227,16 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
+ public void SetInputUserAttributeFixedFunc(int index)
+ {
+ UsedInputAttributes |= 1 << index;
+ }
+
+ public void SetOutputUserAttributeFixedFunc(int index)
+ {
+ UsedOutputAttributes |= 1 << index;
+ }
+
public void SetInputUserAttribute(int index, bool perPatch)
{
if (perPatch)
@@ -232,7 +245,10 @@ namespace Ryujinx.Graphics.Shader.Translation
}
else
{
- UsedInputAttributes |= 1 << index;
+ int mask = 1 << index;
+
+ UsedInputAttributes |= mask;
+ _thisUsedInputAttributes |= mask;
}
}
@@ -248,8 +264,16 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
+ public void MergeFromtNextStage(ShaderConfig config)
+ {
+ NextUsesFixedFuncAttributes = config.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr);
+ MergeOutputUserAttributes(config.UsedInputAttributes, config.UsedInputAttributesPerPatch);
+ }
+
public void MergeOutputUserAttributes(int mask, int maskPerPatch)
{
+ _nextUsedInputAttributes = mask;
+
if (GpPassthrough)
{
PassthroughAttributes = mask & ~UsedOutputAttributes;
@@ -261,6 +285,47 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
+ public bool IsUsedOutputAttribute(int attr)
+ {
+ // The check for fixed function attributes on the next stage is conservative,
+ // returning false if the output is just not used by the next stage is also valid.
+ if (NextUsesFixedFuncAttributes &&
+ attr >= AttributeConsts.UserAttributeBase &&
+ attr < AttributeConsts.UserAttributeEnd)
+ {
+ int index = (attr - AttributeConsts.UserAttributeBase) >> 4;
+ return (_nextUsedInputAttributes & (1 << index)) != 0;
+ }
+
+ return true;
+ }
+
+ public int GetFreeUserAttribute(bool isOutput, int index)
+ {
+ int useMask = isOutput ? _nextUsedInputAttributes : _thisUsedInputAttributes;
+ int bit = -1;
+
+ while (useMask != -1)
+ {
+ bit = BitOperations.TrailingZeroCount(~useMask);
+
+ if (bit == 32)
+ {
+ bit = -1;
+ break;
+ }
+ else if (index < 1)
+ {
+ break;
+ }
+
+ useMask |= 1 << bit;
+ index--;
+ }
+
+ return bit;
+ }
+
public void SetAllInputUserAttributes()
{
UsedInputAttributes |= Constants.AllAttributesMask;
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index a658697b..cef25350 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -232,6 +232,22 @@ namespace Ryujinx.Graphics.Shader.Translation
usedAttributesPerPatch &= ~(1 << index);
}
+
+ if (config.NextUsesFixedFuncAttributes)
+ {
+ for (int i = 0; i < 4 + AttributeConsts.TexCoordCount; i++)
+ {
+ int index = config.GetFreeUserAttribute(isOutput: true, i);
+ if (index < 0)
+ {
+ break;
+ }
+
+ InitializeOutput(context, AttributeConsts.UserAttributeBase + index * 16, perPatch: false);
+
+ config.SetOutputUserAttributeFixedFunc(index);
+ }
+ }
}
private static void InitializeOutput(EmitterContext context, int baseAttr, bool perPatch)
diff --git a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
index b19e39af..b4e61cb6 100644
--- a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
@@ -136,9 +136,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
if (nextStage != null)
{
- _config.MergeOutputUserAttributes(
- nextStage._config.UsedInputAttributes,
- nextStage._config.UsedInputAttributesPerPatch);
+ _config.MergeFromtNextStage(nextStage._config);
}
FunctionCode[] code = EmitShader(_program, _config, initializeOutputs: other == null, out _);