aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs2
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Constants.cs9
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs36
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs2
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs3
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs1
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs51
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs53
-rw-r--r--Ryujinx.Graphics.Shader/Constants.cs10
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/Decoder.cs53
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/IOpCodeAttribute.cs3
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/OpCodeAl2p.cs24
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/OpCodeAttribute.cs9
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/OpCodeIpa.cs5
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs1
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs83
-rw-r--r--Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs1
-rw-r--r--Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs3
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs9
-rw-r--r--Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs4
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs10
-rw-r--r--Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs12
22 files changed, 298 insertions, 86 deletions
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index e5289bc0..51ae5aa4 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 = 2542;
+ private const ulong ShaderCodeGenVersion = 2546;
// Progress reporting helpers
private volatile int _shaderCount;
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Constants.cs b/Ryujinx.Graphics.Shader/CodeGen/Constants.cs
deleted file mode 100644
index 59e9f145..00000000
--- a/Ryujinx.Graphics.Shader/CodeGen/Constants.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Ryujinx.Graphics.Shader.CodeGen
-{
- static class Constants
- {
- public const int MaxShaderStorageBuffers = 16;
-
- public const int ConstantBufferSize = 0x10000; // In bytes
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 2a93be32..7b26801a 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -402,14 +402,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
private static void DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info)
{
- int usedAttribtes = context.Config.UsedInputAttributes;
- while (usedAttribtes != 0)
+ if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IaIndexing))
{
- int index = BitOperations.TrailingZeroCount(usedAttribtes);
+ string suffix = context.Config.Stage == ShaderStage.Geometry ? "[]" : string.Empty;
- DeclareInputAttribute(context, info, index);
+ context.AppendLine($"layout (location = 0) in vec4 {DefaultNames.IAttributePrefix}{suffix}[{Constants.MaxAttributes}];");
+ }
+ else
+ {
+ int usedAttributes = context.Config.UsedInputAttributes;
+ while (usedAttributes != 0)
+ {
+ int index = BitOperations.TrailingZeroCount(usedAttributes);
+
+ DeclareInputAttribute(context, info, index);
- usedAttribtes &= ~(1 << index);
+ usedAttributes &= ~(1 << index);
+ }
}
}
@@ -448,14 +457,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info)
{
- int usedAttribtes = context.Config.UsedOutputAttributes;
- while (usedAttribtes != 0)
+ if (context.Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing))
{
- int index = BitOperations.TrailingZeroCount(usedAttribtes);
+ context.AppendLine($"layout (location = 0) out vec4 {DefaultNames.OAttributePrefix}[{Constants.MaxAttributes}];");
+ }
+ else
+ {
+ int usedAttributes = context.Config.UsedOutputAttributes;
+ while (usedAttributes != 0)
+ {
+ int index = BitOperations.TrailingZeroCount(usedAttributes);
- DeclareOutputAttribute(context, index);
+ DeclareOutputAttribute(context, index);
- usedAttribtes &= ~(1 << index);
+ usedAttributes &= ~(1 << index);
+ }
}
}
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs
index 6ea700ac..2d6ede0a 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs
@@ -128,7 +128,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
if (assignment.Destination is AstOperand operand && operand.Type == OperandType.Attribute)
{
- dest = OperandManager.GetOutAttributeName(operand, context.Config);
+ dest = OperandManager.GetOutAttributeName(operand.Value, context.Config);
}
else
{
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
index d5cd0f72..41a8b942 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
@@ -161,6 +161,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
case Instruction.PackHalf2x16:
return PackHalf2x16(context, operation);
+ case Instruction.StoreAttribute:
+ return StoreAttribute(context, operation);
+
case Instruction.StoreLocal:
return StoreLocal(context, operation);
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
index f3774a60..a4957658 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
@@ -109,6 +109,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.ShuffleXor, InstType.CallQuaternary, HelperFunctionNames.ShuffleXor);
Add(Instruction.Sine, InstType.CallUnary, "sin");
Add(Instruction.SquareRoot, InstType.CallUnary, "sqrt");
+ Add(Instruction.StoreAttribute, InstType.Special);
Add(Instruction.StoreLocal, InstType.Special);
Add(Instruction.StoreShared, InstType.Special);
Add(Instruction.StoreStorage, InstType.Special);
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index ef3b0bed..a0aec28e 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -137,15 +137,25 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
IAstNode src1 = operation.GetSource(0);
IAstNode src2 = operation.GetSource(1);
+ IAstNode src3 = operation.GetSource(2);
- if (!(src1 is AstOperand attr) || attr.Type != OperandType.Attribute)
+ if (!(src1 is AstOperand baseAttr) || baseAttr.Type != OperandType.Constant)
{
- throw new InvalidOperationException("First source of LoadAttribute must be a attribute.");
+ throw new InvalidOperationException($"First input of {nameof(Instruction.LoadAttribute)} must be a constant operand.");
}
- string indexExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
+ string indexExpr = GetSoureExpr(context, src3, GetSrcVarType(operation.Inst, 2));
- return OperandManager.GetAttributeName(attr, context.Config, isOutAttr: false, indexExpr);
+ if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
+ {
+ return OperandManager.GetAttributeName(baseAttr.Value + (operand.Value << 2), context.Config, isOutAttr: false, indexExpr);
+ }
+ else
+ {
+ string attrExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
+ attrExpr = Enclose(attrExpr, src2, Instruction.ShiftRightS32, isLhs: true);
+ return OperandManager.GetAttributeName(attrExpr, context.Config, isOutAttr: false, indexExpr);
+ }
}
public static string LoadConstant(CodeGenContext context, AstOperation operation)
@@ -154,16 +164,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
IAstNode src2 = operation.GetSource(1);
string offsetExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
-
offsetExpr = Enclose(offsetExpr, src2, Instruction.ShiftRightS32, isLhs: true);
var config = context.Config;
bool indexElement = !config.GpuAccessor.QueryHostHasVectorIndexingBug();
- if (src1 is AstOperand oper && oper.Type == OperandType.Constant)
+ if (src1 is AstOperand operand && operand.Type == OperandType.Constant)
{
bool cbIndexable = config.UsedFeatures.HasFlag(Translation.FeatureFlags.CbIndexing);
- return OperandManager.GetConstantBufferName(oper.Value, offsetExpr, config.Stage, cbIndexable, indexElement);
+ return OperandManager.GetConstantBufferName(operand.Value, offsetExpr, config.Stage, cbIndexable, indexElement);
}
else
{
@@ -250,6 +259,34 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
return $"textureQueryLod({samplerName}, {coordsExpr}){GetMask(texOp.Index)}";
}
+ public static string StoreAttribute(CodeGenContext context, AstOperation operation)
+ {
+ IAstNode src1 = operation.GetSource(0);
+ IAstNode src2 = operation.GetSource(1);
+ IAstNode src3 = operation.GetSource(2);
+
+ if (!(src1 is AstOperand baseAttr) || baseAttr.Type != OperandType.Constant)
+ {
+ throw new InvalidOperationException($"First input of {nameof(Instruction.StoreAttribute)} must be a constant operand.");
+ }
+
+ string attrName;
+
+ if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
+ {
+ attrName = OperandManager.GetAttributeName(baseAttr.Value + (operand.Value << 2), context.Config, isOutAttr: true);
+ }
+ else
+ {
+ string attrExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
+ attrExpr = Enclose(attrExpr, src2, Instruction.ShiftRightS32, isLhs: true);
+ attrName = OperandManager.GetAttributeName(attrExpr, context.Config, isOutAttr: true);
+ }
+
+ string value = GetSoureExpr(context, src3, GetSrcVarType(operation.Inst, 2));
+ return $"{attrName} = {value}";
+ }
+
public static string StoreLocal(CodeGenContext context, AstOperation operation)
{
return StoreLocalOrShared(context, operation, DefaultNames.LocalMemoryName);
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
index 60a471eb..b9f1b4ef 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
@@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return operand.Type switch
{
OperandType.Argument => GetArgumentName(operand.Value),
- OperandType.Attribute => GetAttributeName(operand, config),
+ OperandType.Attribute => GetAttributeName(operand.Value, config),
OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
OperandType.ConstantBuffer => GetConstantBufferName(
operand.CbufSlot,
@@ -142,15 +142,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return GetVec4Indexed(GetUbName(stage, slotExpr) + $"[{offsetExpr} >> 2]", offsetExpr + " & 3", indexElement);
}
- public static string GetOutAttributeName(AstOperand attr, ShaderConfig config)
+ public static string GetOutAttributeName(int value, ShaderConfig config)
{
- return GetAttributeName(attr, config, isOutAttr: true);
+ return GetAttributeName(value, config, isOutAttr: true);
}
- public static string GetAttributeName(AstOperand attr, ShaderConfig config, bool isOutAttr = false, string indexExpr = "0")
+ public static string GetAttributeName(int value, ShaderConfig config, bool isOutAttr = false, string indexExpr = "0")
{
- int value = attr.Value;
-
char swzMask = GetSwizzleMask((value >> 2) & 3);
if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
@@ -161,7 +159,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
? DefaultNames.OAttributePrefix
: DefaultNames.IAttributePrefix;
- if ((config.Options.Flags & TranslationFlags.Feedback) != 0)
+ if (config.UsedFeatures.HasFlag(isOutAttr ? FeatureFlags.OaIndexing : FeatureFlags.IaIndexing))
+ {
+ string name = prefix;
+
+ if (config.Stage == ShaderStage.Geometry && !isOutAttr)
+ {
+ name += $"[{indexExpr}]";
+ }
+
+ return name + $"[{(value >> 4)}]." + swzMask;
+ }
+ else if (config.Options.Flags.HasFlag(TranslationFlags.Feedback))
{
string name = $"{prefix}{(value >> 4)}_{swzMask}";
@@ -231,6 +240,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return isOutAttr ? "// bad_attr0x" + value.ToString("X") : "0.0";
}
+ public static string GetAttributeName(string attrExpr, ShaderConfig config, bool isOutAttr = false, string indexExpr = "0")
+ {
+ string name = isOutAttr
+ ? DefaultNames.OAttributePrefix
+ : DefaultNames.IAttributePrefix;
+
+ if (config.Stage == ShaderStage.Geometry && !isOutAttr)
+ {
+ name += $"[{indexExpr}]";
+ }
+
+ return $"{name}[{attrExpr} >> 2][{attrExpr} & 3]";
+ }
+
public static string GetUbName(ShaderStage stage, int slot, bool cbIndexable)
{
if (cbIndexable)
@@ -314,12 +337,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
if (node is AstOperation operation)
{
- // Load attribute basically just returns the attribute value.
- // Some built-in attributes may have different types, so we need
- // to return the type based on the attribute that is being read.
if (operation.Inst == Instruction.LoadAttribute)
{
- return GetOperandVarType((AstOperand)operation.GetSource(0));
+ // Load attribute basically just returns the attribute value.
+ // Some built-in attributes may have different types, so we need
+ // to return the type based on the attribute that is being read.
+ if (operation.GetSource(0) is AstOperand operand && operand.Type == OperandType.Constant)
+ {
+ if (_builtInAttributes.TryGetValue(operand.Value & ~3, out BuiltInAttribute builtInAttr))
+ {
+ return builtInAttr.Type;
+ }
+ }
+
+ return OperandInfo.GetVarType(OperandType.Attribute);
}
else if (operation.Inst == Instruction.Call)
{
diff --git a/Ryujinx.Graphics.Shader/Constants.cs b/Ryujinx.Graphics.Shader/Constants.cs
new file mode 100644
index 00000000..86af48cf
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Constants.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Graphics.Shader
+{
+ static class Constants
+ {
+ public const int ConstantBufferSize = 0x10000; // In bytes
+
+ public const int MaxAttributes = 16;
+ public const int AllAttributesMask = (int)(uint.MaxValue >> (32 - MaxAttributes));
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
index 12b49d35..c2901eab 100644
--- a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
@@ -282,23 +282,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
// Populate used attributes.
if (op is IOpCodeAttribute opAttr)
{
- for (int elemIndex = 0; elemIndex < opAttr.Count; elemIndex++)
- {
- int attr = opAttr.AttributeOffset + elemIndex * 4;
- if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
- {
- int index = (attr - AttributeConsts.UserAttributeBase) / 16;
-
- if (op.Emitter == InstEmit.Ast)
- {
- config.SetOutputUserAttribute(index);
- }
- else
- {
- config.SetInputUserAttribute(index);
- }
- }
- }
+ SetUserAttributeUses(config, opAttr);
}
block.OpCodes.Add(op);
@@ -310,6 +294,41 @@ namespace Ryujinx.Graphics.Shader.Decoders
block.UpdatePushOps();
}
+ private static void SetUserAttributeUses(ShaderConfig config, IOpCodeAttribute opAttr)
+ {
+ if (opAttr.Indexed)
+ {
+ if (opAttr.Emitter == InstEmit.Ast)
+ {
+ config.SetAllOutputUserAttributes();
+ }
+ else
+ {
+ config.SetAllInputUserAttributes();
+ }
+ }
+ else
+ {
+ for (int elemIndex = 0; elemIndex < opAttr.Count; elemIndex++)
+ {
+ int attr = opAttr.AttributeOffset + elemIndex * 4;
+ if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
+ {
+ int index = (attr - AttributeConsts.UserAttributeBase) / 16;
+
+ if (opAttr.Emitter == InstEmit.Ast)
+ {
+ config.SetOutputUserAttribute(index);
+ }
+ else
+ {
+ config.SetInputUserAttribute(index);
+ }
+ }
+ }
+ }
+ }
+
private static bool IsUnconditionalBranch(OpCode opCode)
{
return IsUnconditional(opCode) && IsControlFlowChange(opCode);
diff --git a/Ryujinx.Graphics.Shader/Decoders/IOpCodeAttribute.cs b/Ryujinx.Graphics.Shader/Decoders/IOpCodeAttribute.cs
index b5b16f1b..2b6835be 100644
--- a/Ryujinx.Graphics.Shader/Decoders/IOpCodeAttribute.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/IOpCodeAttribute.cs
@@ -1,8 +1,9 @@
namespace Ryujinx.Graphics.Shader.Decoders
{
- interface IOpCodeAttribute
+ interface IOpCodeAttribute : IOpCode
{
int AttributeOffset { get; }
int Count { get; }
+ bool Indexed { get; }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeAl2p.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeAl2p.cs
new file mode 100644
index 00000000..d924b393
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeAl2p.cs
@@ -0,0 +1,24 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+ class OpCodeAl2p : OpCode, IOpCodeRd, IOpCodeRa
+ {
+ public Register Rd { get; }
+ public Register Ra { get; }
+ public Register Predicate44 { get; }
+
+ public int Immediate { get; }
+
+ public new static OpCode Create(InstEmitter emitter, ulong address, long opCode) => new OpCodeAl2p(emitter, address, opCode);
+
+ public OpCodeAl2p(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+ {
+ Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr);
+ Ra = new Register(opCode.Extract(8, 8), RegisterType.Gpr);
+ Predicate44 = new Register(opCode.Extract(44, 3), RegisterType.Predicate);
+
+ Immediate = ((int)opCode << 1) >> 21;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeAttribute.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeAttribute.cs
index f9119665..0a24d4c8 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeAttribute.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeAttribute.cs
@@ -4,14 +4,19 @@ namespace Ryujinx.Graphics.Shader.Decoders
{
class OpCodeAttribute : OpCodeAluReg, IOpCodeAttribute
{
- public int AttributeOffset { get; }
- public int Count { get; }
+ public int AttributeOffset { get; }
+ public bool Patch { get; }
+ public int Count { get; }
+
+ public bool Phys => !Patch && AttributeOffset == 0 && !Ra.IsRZ;
+ public bool Indexed => Phys;
public new static OpCode Create(InstEmitter emitter, ulong address, long opCode) => new OpCodeAttribute(emitter, address, opCode);
public OpCodeAttribute(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
{
AttributeOffset = opCode.Extract(20, 10);
+ Patch = opCode.Extract(31);
Count = opCode.Extract(47, 2) + 1;
}
}
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeIpa.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeIpa.cs
index dc4e03e3..d38a1b3a 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeIpa.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeIpa.cs
@@ -7,6 +7,9 @@ namespace Ryujinx.Graphics.Shader.Decoders
public int AttributeOffset { get; }
public int Count => 1;
+ public bool Idx { get; }
+ public bool Indexed => Idx;
+
public InterpolationMode Mode { get; }
public new static OpCode Create(InstEmitter emitter, ulong address, long opCode) => new OpCodeIpa(emitter, address, opCode);
@@ -15,6 +18,8 @@ namespace Ryujinx.Graphics.Shader.Decoders
{
AttributeOffset = opCode.Extract(28, 10);
+ Idx = opCode.Extract(38);
+
Saturate = opCode.Extract(51);
Mode = (InterpolationMode)opCode.Extract(54, 2);
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
index 8b9cb20d..e5bcd7e5 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
@@ -32,6 +32,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
_opCodes = new TableEntry[1 << EncodingBits];
#region Instructions
+ Set("1110111110100x", InstEmit.Al2p, OpCodeAl2p.Create);
Set("1110111111011x", InstEmit.Ald, OpCodeAttribute.Create);
Set("1110111111110x", InstEmit.Ast, OpCodeAttribute.Create);
Set("11101101xxxxxx", InstEmit.Atom, OpCodeAtom.Create);
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
index 7afdbf4e..6744a9e8 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
@@ -15,6 +15,18 @@ namespace Ryujinx.Graphics.Shader.Instructions
Shared
}
+ public static void Al2p(EmitterContext context)
+ {
+ OpCodeAl2p op = (OpCodeAl2p)context.CurrOp;
+
+ if (op.Rd.IsRZ)
+ {
+ return;
+ }
+
+ context.Copy(Register(op.Rd), context.IAdd(Register(op.Ra), Const(op.Immediate)));
+ }
+
public static void Ald(EmitterContext context)
{
OpCodeAttribute op = (OpCodeAttribute)context.CurrOp;
@@ -30,11 +42,31 @@ namespace Ryujinx.Graphics.Shader.Instructions
break;
}
- Operand src = Attribute(op.AttributeOffset + index * 4);
+ if (op.Phys)
+ {
+ Operand userAttrOffset = context.ISubtract(GetSrcA(context), Const(AttributeConsts.UserAttributeBase));
+ Operand userAttrIndex = context.ShiftRightU32(userAttrOffset, Const(2));
+
+ context.Copy(Register(rd), context.LoadAttribute(Const(AttributeConsts.UserAttributeBase), userAttrIndex, primVertex));
+
+ context.Config.SetUsedFeature(FeatureFlags.IaIndexing);
+ }
+ else if (op.Rc.IsRZ)
+ {
+ Operand src = Attribute(op.AttributeOffset + index * 4);
+
+ context.FlagAttributeRead(src.Value);
+
+ context.Copy(Register(rd), src);
+ }
+ else
+ {
+ Operand src = Const(op.AttributeOffset + index * 4);
- context.FlagAttributeRead(src.Value);
+ context.FlagAttributeRead(src.Value);
- context.Copy(Register(rd), context.LoadAttribute(src, primVertex));
+ context.Copy(Register(rd), context.LoadAttribute(src, Const(0), primVertex));
+ }
}
}
@@ -51,11 +83,23 @@ namespace Ryujinx.Graphics.Shader.Instructions
Register rd = new Register(op.Rd.Index + index, RegisterType.Gpr);
- Operand dest = Attribute(op.AttributeOffset + index * 4);
+ if (op.Phys)
+ {
+ Operand userAttrOffset = context.ISubtract(GetSrcA(context), Const(AttributeConsts.UserAttributeBase));
+ Operand userAttrIndex = context.ShiftRightU32(userAttrOffset, Const(2));
+
+ context.StoreAttribute(Const(AttributeConsts.UserAttributeBase), userAttrIndex, Register(rd));
+
+ context.Config.SetUsedFeature(FeatureFlags.OaIndexing);
+ }
+ else
+ {
+ Operand dest = Attribute(op.AttributeOffset + index * 4);
- context.FlagAttributeWritten(dest.Value);
+ context.FlagAttributeWritten(dest.Value);
- context.Copy(dest, Register(rd));
+ context.Copy(dest, Register(rd));
+ }
}
}
@@ -136,16 +180,31 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.FlagAttributeRead(op.AttributeOffset);
- Operand res = Attribute(op.AttributeOffset);
+ Operand res;
- if (op.AttributeOffset >= AttributeConsts.UserAttributeBase &&
- op.AttributeOffset < AttributeConsts.UserAttributeEnd)
+ if (op.Idx)
{
- int index = (op.AttributeOffset - AttributeConsts.UserAttributeBase) >> 4;
+ Operand userAttrOffset = context.ISubtract(GetSrcA(context), Const(AttributeConsts.UserAttributeBase));
+ Operand userAttrIndex = context.ShiftRightU32(userAttrOffset, Const(2));
+
+ res = context.LoadAttribute(Const(AttributeConsts.UserAttributeBase), userAttrIndex, Const(0));
+ res = context.FPMultiply(res, Attribute(AttributeConsts.PositionW));
- if (context.Config.ImapTypes[index].GetFirstUsedType() == PixelImap.Perspective)
+ context.Config.SetUsedFeature(FeatureFlags.IaIndexing);
+ }
+ else
+ {
+ res = Attribute(op.AttributeOffset);
+
+ if (op.AttributeOffset >= AttributeConsts.UserAttributeBase &&
+ op.AttributeOffset < AttributeConsts.UserAttributeEnd)
{
- res = context.FPMultiply(res, Attribute(AttributeConsts.PositionW));
+ int index = (op.AttributeOffset - AttributeConsts.UserAttributeBase) >> 4;
+
+ if (context.Config.ImapTypes[index].GetFirstUsedType() == PixelImap.Perspective)
+ {
+ res = context.FPMultiply(res, Attribute(AttributeConsts.PositionW));
+ }
}
}
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
index 13fd55ec..c1431ebc 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
@@ -108,6 +108,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
ShuffleXor,
Sine,
SquareRoot,
+ StoreAttribute,
StoreGlobal,
StoreLocal,
StoreShared,
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs b/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs
index 88cfe729..33ee26ba 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs
@@ -82,7 +82,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Add(Instruction.ImageLoad, VariableType.F32);
Add(Instruction.ImageStore, VariableType.None);
Add(Instruction.IsNan, VariableType.Bool, VariableType.F32);
- Add(Instruction.LoadAttribute, VariableType.F32, VariableType.S32, VariableType.S32);
+ Add(Instruction.LoadAttribute, VariableType.F32, VariableType.S32, VariableType.S32, VariableType.S32);
Add(Instruction.LoadConstant, VariableType.F32, VariableType.S32, VariableType.S32);
Add(Instruction.LoadGlobal, VariableType.U32, VariableType.S32, VariableType.S32);
Add(Instruction.LoadLocal, VariableType.U32, VariableType.S32);
@@ -115,6 +115,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Add(Instruction.ShuffleXor, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool);
Add(Instruction.Sine, VariableType.Scalar, VariableType.Scalar);
Add(Instruction.SquareRoot, VariableType.Scalar, VariableType.Scalar);
+ Add(Instruction.StoreAttribute, VariableType.None, VariableType.S32, VariableType.S32, VariableType.F32);
Add(Instruction.StoreGlobal, VariableType.None, VariableType.S32, VariableType.S32, VariableType.U32);
Add(Instruction.StoreLocal, VariableType.None, VariableType.S32, VariableType.U32);
Add(Instruction.StoreShared, VariableType.None, VariableType.S32, VariableType.U32);
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
index e5ba04bc..113ece99 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
@@ -511,9 +511,9 @@ namespace Ryujinx.Graphics.Shader.Translation
return context.Add(Instruction.IsNan, Local(), a);
}
- public static Operand LoadAttribute(this EmitterContext context, Operand a, Operand b)
+ public static Operand LoadAttribute(this EmitterContext context, Operand a, Operand b, Operand c)
{
- return context.Add(Instruction.LoadAttribute, Local(), a, b);
+ return context.Add(Instruction.LoadAttribute, Local(), a, b, c);
}
public static Operand LoadConstant(this EmitterContext context, Operand a, Operand b)
@@ -617,6 +617,11 @@ 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)
+ {
+ return context.Add(Instruction.StoreAttribute, null, a, b, c);
+ }
+
public static Operand StoreGlobal(this EmitterContext context, Operand a, Operand b, Operand c)
{
return context.Add(Instruction.StoreGlobal, null, a, b, c);
diff --git a/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs b/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
index b0c48410..1636afd3 100644
--- a/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
+++ b/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
@@ -17,6 +17,8 @@ namespace Ryujinx.Graphics.Shader.Translation
Bindless = 1 << 2,
InstanceId = 1 << 3,
- CbIndexing = 1 << 4
+ CbIndexing = 1 << 4,
+ IaIndexing = 1 << 5,
+ OaIndexing = 1 << 6
}
}
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 02e995f9..f454ceea 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -219,6 +219,16 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
+ public void SetAllInputUserAttributes()
+ {
+ UsedInputAttributes |= Constants.AllAttributesMask;
+ }
+
+ public void SetAllOutputUserAttributes()
+ {
+ UsedOutputAttributes |= Constants.AllAttributesMask;
+ }
+
public void SetClipDistanceWritten(int index)
{
ClipDistancesWritten |= (byte)(1 << index);
diff --git a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
index 47cf0ac8..3c7b3c2b 100644
--- a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
@@ -103,17 +103,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (temp != null)
{
- // TODO: LoadAttribute should accept any integer value as first argument,
- // then we don't need special case here. Right now it expects the first
- // operand to be of type "attribute".
- if ((operation.Inst & Instruction.Mask) == Instruction.LoadAttribute)
- {
- operation.TurnIntoCopy(temp);
- }
- else
- {
- operation.SetSource(srcIndex, temp);
- }
+ operation.SetSource(srcIndex, temp);
}
}
}