From 6b13c5b439a54d0bb0139a2e33a2f76707db5fe7 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sat, 7 Dec 2019 18:31:17 -0300
Subject: [PATCH] Support bindless texture gather shader instruction

---
 .../Decoders/IOpCodeTexture.cs                | 23 +++++++++++++++++++
 .../Decoders/IOpCodeTld4.cs                   | 11 +++++++++
 .../Decoders/OpCodeTable.cs                   |  1 +
 .../Decoders/OpCodeTexture.cs                 |  2 +-
 .../Decoders/OpCodeTld4.cs                    |  4 +++-
 .../Decoders/OpCodeTld4B.cs                   | 22 ++++++++++++++++++
 .../Instructions/InstEmitTexture.cs           |  9 +++++++-
 7 files changed, 69 insertions(+), 3 deletions(-)
 create mode 100644 Ryujinx.Graphics.Shader/Decoders/IOpCodeTexture.cs
 create mode 100644 Ryujinx.Graphics.Shader/Decoders/IOpCodeTld4.cs
 create mode 100644 Ryujinx.Graphics.Shader/Decoders/OpCodeTld4B.cs

diff --git a/Ryujinx.Graphics.Shader/Decoders/IOpCodeTexture.cs b/Ryujinx.Graphics.Shader/Decoders/IOpCodeTexture.cs
new file mode 100644
index 0000000000..55d1225aeb
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/IOpCodeTexture.cs
@@ -0,0 +1,23 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeTexture : IOpCode
+    {
+        Register Rd { get; }
+        Register Ra { get; }
+        Register Rb { get; }
+
+        bool IsArray { get; }
+
+        TextureDimensions Dimensions { get; }
+
+        int ComponentMask { get; }
+
+        int Immediate { get; }
+
+        TextureLodMode LodMode { get; }
+
+        bool HasOffset       { get; }
+        bool HasDepthCompare { get; }
+        bool IsMultisample   { get; }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/IOpCodeTld4.cs b/Ryujinx.Graphics.Shader/Decoders/IOpCodeTld4.cs
new file mode 100644
index 0000000000..219d00cbf7
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/IOpCodeTld4.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeTld4 : IOpCodeTexture
+    {
+        TextureGatherOffset Offset { get; }
+
+        int GatherCompIndex { get; }
+
+        bool Bindless { get; }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
index 0837e18589..bdc7ed80c1 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
@@ -184,6 +184,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Set("11011100xx111x", InstEmit.Tld,     typeof(OpCodeTld));
             Set("11011101xx111x", InstEmit.TldB,    typeof(OpCodeTld));
             Set("110010xxxx111x", InstEmit.Tld4,    typeof(OpCodeTld4));
+            Set("1101111011111x", InstEmit.Tld4,    typeof(OpCodeTld4B));
             Set("110111100x1110", InstEmit.Txd,     typeof(OpCodeTxd));
             Set("1101111101001x", InstEmit.Txq,     typeof(OpCodeTex));
             Set("1101111101010x", InstEmit.TxqB,    typeof(OpCodeTex));
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTexture.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTexture.cs
index 7a7e8f46e7..76e95118f7 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTexture.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTexture.cs
@@ -2,7 +2,7 @@ using Ryujinx.Graphics.Shader.Instructions;
 
 namespace Ryujinx.Graphics.Shader.Decoders
 {
-    class OpCodeTexture : OpCode
+    class OpCodeTexture : OpCode, IOpCodeTexture
     {
         public Register Rd { get; }
         public Register Ra { get; }
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTld4.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTld4.cs
index 485edf936b..0ffafbe1a4 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTld4.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTld4.cs
@@ -2,12 +2,14 @@ using Ryujinx.Graphics.Shader.Instructions;
 
 namespace Ryujinx.Graphics.Shader.Decoders
 {
-    class OpCodeTld4 : OpCodeTexture
+    class OpCodeTld4 : OpCodeTexture, IOpCodeTld4
     {
         public TextureGatherOffset Offset { get; }
 
         public int GatherCompIndex { get; }
 
+        public bool Bindless => false;
+
         public OpCodeTld4(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
         {
             HasDepthCompare = opCode.Extract(50);
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTld4B.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTld4B.cs
new file mode 100644
index 0000000000..dc274d1415
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTld4B.cs
@@ -0,0 +1,22 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeTld4B : OpCodeTexture, IOpCodeTld4
+    {
+        public TextureGatherOffset Offset { get; }
+
+        public int GatherCompIndex { get; }
+
+        public bool Bindless => true;
+
+        public OpCodeTld4B(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            HasDepthCompare = opCode.Extract(50);
+
+            Offset = (TextureGatherOffset)opCode.Extract(36, 2);
+
+            GatherCompIndex = opCode.Extract(38, 2);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
index 41ba740e7d..59096869ed 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
@@ -417,7 +417,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
         public static void Tld4(EmitterContext context)
         {
-            OpCodeTld4 op = (OpCodeTld4)context.CurrOp;
+            IOpCodeTld4 op = (IOpCodeTld4)context.CurrOp;
 
             if (op.Rd.IsRZ)
             {
@@ -455,6 +455,13 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
             TextureFlags flags = TextureFlags.Gather;
 
+            if (op.Bindless)
+            {
+                sourcesList.Add(Rb());
+
+                flags |= TextureFlags.Bindless;
+            }
+
             int coordsCount = type.GetDimensions();
 
             for (int index = 0; index < coordsCount; index++)