aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Translation/Optimizations
diff options
context:
space:
mode:
authorgdk <gab.dark.100@gmail.com>2019-10-31 00:29:22 -0300
committerThog <thog@protonmail.com>2020-01-09 02:13:00 +0100
commit278a4c317c0b87add67cc9ebc904afe1db23a031 (patch)
tree452b59bf4aebf45b9086cf1f59e006c089a2cba7 /Ryujinx.Graphics.Shader/Translation/Optimizations
parentd786d8d2b924da7cd116a2eb97d738a9f07b4e43 (diff)
Implement BFI, BRK, FLO, FSWZADD, PBK, SHFL and TXD shader instructions, misc. fixes
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation/Optimizations')
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs19
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs82
2 files changed, 100 insertions, 1 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
index d64579b7..97852ac1 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
@@ -21,6 +21,10 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
EvaluateBinary(operation, (x, y) => x + y);
break;
+ case Instruction.BitCount:
+ EvaluateUnary(operation, (x) => BitCount(x));
+ break;
+
case Instruction.BitwiseAnd:
EvaluateBinary(operation, (x, y) => x & y);
break;
@@ -208,6 +212,21 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return true;
}
+ private static int BitCount(int value)
+ {
+ int count = 0;
+
+ for (int bit = 0; bit < 32; bit++)
+ {
+ if (value.Extract(bit))
+ {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
private static void BitfieldExtractS32(Operation operation)
{
int value = GetBitfieldExtractValue(operation);
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
index d5e57546..22d794a4 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
@@ -1,5 +1,6 @@
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
namespace Ryujinx.Graphics.Shader.Translation.Optimizations
@@ -59,7 +60,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
modified = true;
}
- else if (operation.Inst == Instruction.PackHalf2x16 && PropagatePack(operation))
+ else if ((operation.Inst == Instruction.PackHalf2x16 && PropagatePack(operation)) ||
+ (operation.Inst == Instruction.ShuffleXor && MatchDdxOrDdy(operation)))
{
if (operation.Dest.UseOps.Count == 0)
{
@@ -135,6 +137,84 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return modified;
}
+ public static bool MatchDdxOrDdy(Operation operation)
+ {
+ // It's assumed that "operation.Inst" is ShuffleXor,
+ // that should be checked before calling this method.
+ Debug.Assert(operation.Inst == Instruction.ShuffleXor);
+
+ bool modified = false;
+
+ Operand src2 = operation.GetSource(1);
+ Operand src3 = operation.GetSource(2);
+
+ if (src2.Type != OperandType.Constant || (src2.Value != 1 && src2.Value != 2))
+ {
+ return false;
+ }
+
+ if (src3.Type != OperandType.Constant || src3.Value != 0x1c03)
+ {
+ return false;
+ }
+
+ bool isDdy = src2.Value == 2;
+ bool isDdx = !isDdy;
+
+ // We can replace any use by a FSWZADD with DDX/DDY, when
+ // the following conditions are true:
+ // - The mask should be 0b10100101 for DDY, or 0b10011001 for DDX.
+ // - The first source operand must be the shuffle output.
+ // - The second source operand must be the shuffle first source operand.
+ INode[] uses = operation.Dest.UseOps.ToArray();
+
+ foreach (INode use in uses)
+ {
+ if (!(use is Operation test))
+ {
+ continue;
+ }
+
+ if (!(use is Operation useOp) || useOp.Inst != Instruction.SwizzleAdd)
+ {
+ continue;
+ }
+
+ Operand fswzaddSrc1 = useOp.GetSource(0);
+ Operand fswzaddSrc2 = useOp.GetSource(1);
+ Operand fswzaddSrc3 = useOp.GetSource(2);
+
+ if (fswzaddSrc1 != operation.Dest)
+ {
+ continue;
+ }
+
+ if (fswzaddSrc2 != operation.GetSource(0))
+ {
+ continue;
+ }
+
+ if (fswzaddSrc3.Type != OperandType.Constant)
+ {
+ continue;
+ }
+
+ int mask = fswzaddSrc3.Value;
+
+ if ((isDdx && mask != 0b10011001) ||
+ (isDdy && mask != 0b10100101))
+ {
+ continue;
+ }
+
+ useOp.TurnInto(isDdx ? Instruction.Ddx : Instruction.Ddy, fswzaddSrc2);
+
+ modified = true;
+ }
+
+ return modified;
+ }
+
private static void RemoveNode(BasicBlock block, LinkedListNode<INode> llNode)
{
// Remove a node from the nodes list, and also remove itself