aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2020-07-03 20:48:44 -0300
committerGitHub <noreply@github.com>2020-07-04 01:48:44 +0200
commite13154c83d52d9e1c26c55bc5655a5df641e26a9 (patch)
tree302fcc3171027124bec9cc154ef482fd491cf7e9
parent76e5af967a39879187214f0973d226eba126e93f (diff)
Implement shader LEA instruction and improve bindless image load/store (#1355)
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs4
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs3
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs21
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs25
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs45
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs2
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs21
7 files changed, 80 insertions, 41 deletions
diff --git a/Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs b/Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs
index 3bb9bc1f..d902fc86 100644
--- a/Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs
@@ -4,12 +4,12 @@ namespace Ryujinx.Graphics.Shader.Decoders
{
public static bool Extract(this int value, int lsb)
{
- return ((int)(value >> lsb) & 1) != 0;
+ return ((value >> lsb) & 1) != 0;
}
public static int Extract(this int value, int lsb, int length)
{
- return (int)(value >> lsb) & (int)(uint.MaxValue >> (32 - length));
+ return (value >> lsb) & (int)(uint.MaxValue >> (32 - length));
}
public static bool Extract(this long value, int lsb)
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
index be93f137..eef36a95 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
@@ -176,6 +176,9 @@ namespace Ryujinx.Graphics.Shader.Decoders
Set("1110111110010x", InstEmit.Ldc, typeof(OpCodeLdc));
Set("1110111011010x", InstEmit.Ldg, typeof(OpCodeMemory));
Set("1110111101001x", InstEmit.Lds, typeof(OpCodeMemory));
+ Set("010010111101xx", InstEmit.Lea, typeof(OpCodeAluCbuf));
+ Set("0011011x11010x", InstEmit.Lea, typeof(OpCodeAluImm));
+ Set("0101101111010x", InstEmit.Lea, typeof(OpCodeAluReg));
Set("0100110001000x", InstEmit.Lop, typeof(OpCodeLopCbuf));
Set("0011100001000x", InstEmit.Lop, typeof(OpCodeLopImm));
Set("000001xxxxxxxx", InstEmit.Lop, typeof(OpCodeLopImm32));
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
index 7c3d55c4..e55f1f32 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
@@ -384,6 +384,27 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.Copy(Register(op.Predicate0), p1Res);
}
+ public static void Lea(EmitterContext context)
+ {
+ OpCodeAlu op = (OpCodeAlu)context.CurrOp;
+
+ bool negateA = op.RawOpCode.Extract(45);
+
+ int shift = op.RawOpCode.Extract(39, 5);
+
+ Operand srcA = GetSrcA(context);
+ Operand srcB = GetSrcB(context);
+
+ srcA = context.ShiftLeft(srcA, Const(shift));
+ srcA = context.INegate(srcA, negateA);
+
+ Operand res = context.IAdd(srcA, srcB);
+
+ context.Copy(GetDest(context), res);
+
+ // TODO: CC, X
+ }
+
public static void Lop(EmitterContext context)
{
IOpCodeLop op = (IOpCodeLop)context.CurrOp;
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
index 43e5822e..304906d0 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
@@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (!op.IsBindless)
{
- operation.Format = GetTextureFormat(context, handle);
+ operation.Format = context.Config.GetTextureFormat(handle);
}
context.Add(operation);
@@ -228,7 +228,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (!op.IsBindless)
{
- format = GetTextureFormat(context, op.Immediate);
+ format = context.Config.GetTextureFormat(op.Immediate);
}
}
else
@@ -1223,27 +1223,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
};
}
- private static TextureFormat GetTextureFormat(EmitterContext context, int handle)
- {
- // When the formatted load extension is supported, we don't need to
- // specify a format, we can just declare it without a format and the GPU will handle it.
- if (context.Config.GpuAccessor.QuerySupportsImageLoadFormatted())
- {
- return TextureFormat.Unknown;
- }
-
- var format = context.Config.GpuAccessor.QueryTextureFormat(handle);
-
- if (format == TextureFormat.Unknown)
- {
- context.Config.GpuAccessor.Log($"Unknown format for texture {handle}.");
-
- format = TextureFormat.R8G8B8A8Unorm;
- }
-
- return format;
- }
-
private static TextureFormat GetTextureFormat(IntegerSize size)
{
return size switch
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index 9515c349..a26c81c9 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -5,7 +5,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{
class BindlessElimination
{
- public static void RunPass(BasicBlock block)
+ private const int NvnTextureBufferSlot = 2;
+
+ public static void RunPass(BasicBlock block, ShaderConfig config)
{
// We can turn a bindless into regular access by recognizing the pattern
// produced by the compiler for separate texture and sampler.
@@ -24,26 +26,39 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue;
}
- if (!(texOp.GetSource(0).AsgOp is Operation handleCombineOp))
+ if (texOp.Inst == Instruction.TextureSample)
{
- continue;
- }
+ if (!(texOp.GetSource(0).AsgOp is Operation handleCombineOp))
+ {
+ continue;
+ }
- if (handleCombineOp.Inst != Instruction.BitwiseOr)
- {
- continue;
- }
+ if (handleCombineOp.Inst != Instruction.BitwiseOr)
+ {
+ continue;
+ }
- Operand src0 = handleCombineOp.GetSource(0);
- Operand src1 = handleCombineOp.GetSource(1);
+ Operand src0 = handleCombineOp.GetSource(0);
+ Operand src1 = handleCombineOp.GetSource(1);
- if (src0.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != 2 ||
- src1.Type != OperandType.ConstantBuffer || src1.GetCbufSlot() != 2)
- {
- continue;
+ if (src0.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != NvnTextureBufferSlot ||
+ src1.Type != OperandType.ConstantBuffer || src1.GetCbufSlot() != NvnTextureBufferSlot)
+ {
+ continue;
+ }
+
+ texOp.SetHandle(src0.GetCbufOffset() | (src1.GetCbufOffset() << 16));
}
+ else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)
+ {
+ Operand src0 = texOp.GetSource(0);
- texOp.SetHandle(src0.GetCbufOffset() | (src1.GetCbufOffset() << 16));
+ if (src0.Type == OperandType.ConstantBuffer && src0.GetCbufSlot() == NvnTextureBufferSlot)
+ {
+ texOp.SetHandle(src0.GetCbufOffset());
+ texOp.Format = config.GetTextureFormat(texOp.Handle);
+ }
+ }
}
}
}
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
index 10a0e780..286574cf 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
@@ -89,7 +89,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
{
BindlessToIndexed.RunPass(blocks[blkIndex]);
- BindlessElimination.RunPass(blocks[blkIndex]);
+ BindlessElimination.RunPass(blocks[blkIndex], config);
// Try to eliminate any operations that are now unused.
LinkedListNode<INode> node = blocks[blkIndex].Operations.First;
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 9e8329de..8b38afb9 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -68,5 +68,26 @@ namespace Ryujinx.Graphics.Shader.Translation
// The depth register is always two registers after the last color output.
return count + 1;
}
+
+ public TextureFormat GetTextureFormat(int handle)
+ {
+ // When the formatted load extension is supported, we don't need to
+ // specify a format, we can just declare it without a format and the GPU will handle it.
+ if (GpuAccessor.QuerySupportsImageLoadFormatted())
+ {
+ return TextureFormat.Unknown;
+ }
+
+ var format = GpuAccessor.QueryTextureFormat(handle);
+
+ if (format == TextureFormat.Unknown)
+ {
+ GpuAccessor.Log($"Unknown format for texture {handle}.");
+
+ format = TextureFormat.R8G8B8A8Unorm;
+ }
+
+ return format;
+ }
}
} \ No newline at end of file