From fb54c38631439575a327c13531e9d84e4b4af18c Mon Sep 17 00:00:00 2001
From: Kelebek1 <eeeedddccc@hotmail.co.uk>
Date: Sun, 14 Feb 2021 23:21:42 +0000
Subject: [PATCH] Implement texture offset support for TexelFetch and
 TextureGather and add offsets for Tlds

Formatting
---
 .../renderer_vulkan/vk_shader_decompiler.cpp  | 31 ++++++++++++++-----
 src/video_core/shader/decode/memory.cpp       |  1 +
 src/video_core/shader/decode/texture.cpp      | 11 +++++--
 3 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 40e2e0d38..dd6996735 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -1845,13 +1845,21 @@ private:
 
     Expression TextureGather(Operation operation) {
         const auto& meta = std::get<MetaTexture>(operation.GetMeta());
-        UNIMPLEMENTED_IF(!meta.aoffi.empty());
 
         const Id coords = GetCoordinates(operation, Type::Float);
+
+        spv::ImageOperandsMask mask = spv::ImageOperandsMask::MaskNone;
+        std::vector<Id> operands{};
         Id texture{};
+
+        if (!meta.aoffi.empty()) {
+            mask = mask | spv::ImageOperandsMask::Offset;
+            operands.push_back(GetOffsetCoordinates(operation));
+        }
+
         if (meta.sampler.is_shadow) {
             texture = OpImageDrefGather(t_float4, GetTextureSampler(operation), coords,
-                                        AsFloat(Visit(meta.depth_compare)));
+                                        AsFloat(Visit(meta.depth_compare)), mask, operands);
         } else {
             u32 component_value = 0;
             if (meta.component) {
@@ -1860,7 +1868,7 @@ private:
                 component_value = component->GetValue();
             }
             texture = OpImageGather(t_float4, GetTextureSampler(operation), coords,
-                                    Constant(t_uint, component_value));
+                                    Constant(t_uint, component_value), mask, operands);
         }
         return GetTextureElement(operation, texture, Type::Float);
     }
@@ -1928,13 +1936,22 @@ private:
 
         const Id image = GetTextureImage(operation);
         const Id coords = GetCoordinates(operation, Type::Int);
+
+        spv::ImageOperandsMask mask = spv::ImageOperandsMask::MaskNone;
+        std::vector<Id> operands{};
         Id fetch;
+
         if (meta.lod && !meta.sampler.is_buffer) {
-            fetch = OpImageFetch(t_float4, image, coords, spv::ImageOperandsMask::Lod,
-                                 AsInt(Visit(meta.lod)));
-        } else {
-            fetch = OpImageFetch(t_float4, image, coords);
+            mask = mask | spv::ImageOperandsMask::Lod;
+            operands.push_back(AsInt(Visit(meta.lod)));
         }
+
+        if (!meta.aoffi.empty()) {
+            mask = mask | spv::ImageOperandsMask::Offset;
+            operands.push_back(GetOffsetCoordinates(operation));
+        }
+
+        fetch = OpImageFetch(t_float4, image, coords, mask, operands);
         return GetTextureElement(operation, fetch, Type::Float);
     }
 
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp
index 50f4e7d35..7728f600e 100644
--- a/src/video_core/shader/decode/memory.cpp
+++ b/src/video_core/shader/decode/memory.cpp
@@ -330,6 +330,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
         case StoreType::Bits32:
             (this->*set_memory)(bb, GetAddress(0), GetRegister(instr.gpr0));
             break;
+        case StoreType::Unsigned16:
         case StoreType::Signed16: {
             Node address = GetAddress(0);
             Node memory = (this->*get_memory)(address);
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp
index 833fa2a39..43087304d 100644
--- a/src/video_core/shader/decode/texture.cpp
+++ b/src/video_core/shader/decode/texture.cpp
@@ -806,6 +806,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
 
     const std::size_t type_coord_count = GetCoordCount(texture_type);
     const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL;
+    const bool aoffi_enabled = instr.tlds.UsesMiscMode(TextureMiscMode::AOFFI);
 
     // If enabled arrays index is always stored in the gpr8 field
     const u64 array_register = instr.gpr8.Value();
@@ -820,17 +821,23 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
     std::vector<Node> coords;
     for (std::size_t i = 0; i < type_coord_count; ++i) {
         const bool last = (i == (type_coord_count - 1)) && (type_coord_count > 1);
-        coords.push_back(GetRegister(last ? last_coord_register : coord_register + i));
+        coords.push_back(
+            GetRegister(last && !aoffi_enabled ? last_coord_register : coord_register + i));
     }
 
     const Node array = is_array ? GetRegister(array_register) : nullptr;
     // When lod is used always is in gpr20
     const Node lod = lod_enabled ? GetRegister(instr.gpr20) : Immediate(0);
 
+    std::vector<Node> aoffi{};
+    if (aoffi_enabled) {
+        aoffi = GetAoffiCoordinates(GetRegister(instr.gpr20), type_coord_count, false);
+    }
+
     Node4 values;
     for (u32 element = 0; element < values.size(); ++element) {
         auto coords_copy = coords;
-        MetaTexture meta{*sampler, array, {}, {}, {}, {}, {}, lod, {}, element, {}};
+        MetaTexture meta{*sampler, array, {}, aoffi, {}, {}, {}, lod, {}, element, {}};
         values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy));
     }
     return values;