From 9245b426e3d011e768cf3609e44df120e9667daa Mon Sep 17 00:00:00 2001
From: Liam <byteslice@airmail.cc>
Date: Fri, 1 Sep 2023 22:41:01 -0400
Subject: shader_recompiler: fix emulation of 3D textureGrad

---
 .../backend/spirv/emit_spirv_image.cpp             | 35 ++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

(limited to 'src/shader_recompiler/backend/spirv/emit_spirv_image.cpp')

diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index 7d901c04b1..34240b36f7 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -91,6 +91,34 @@ public:
         }
     }
 
+    explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates_1, Id derivates_2,
+                           Id offset, Id lod_clamp) {
+        if (!Sirit::ValidId(derivates_1) || !Sirit::ValidId(derivates_2)) {
+            throw LogicError("Derivates must be present");
+        }
+        boost::container::static_vector<Id, 3> deriv_1_accum{
+            ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 0),
+            ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 2),
+            ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 0),
+        };
+        boost::container::static_vector<Id, 3> deriv_2_accum{
+            ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 1),
+            ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 3),
+            ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 1),
+        };
+        const Id derivates_id1{ctx.OpCompositeConstruct(
+            ctx.F32[3], std::span{deriv_1_accum.data(), deriv_1_accum.size()})};
+        const Id derivates_id2{ctx.OpCompositeConstruct(
+            ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})};
+        Add(spv::ImageOperandsMask::Grad, derivates_id1, derivates_id2);
+        if (Sirit::ValidId(offset)) {
+            Add(spv::ImageOperandsMask::Offset, offset);
+        }
+        if (has_lod_clamp) {
+            Add(spv::ImageOperandsMask::MinLod, lod_clamp);
+        }
+    }
+
     std::span<const Id> Span() const noexcept {
         return std::span{operands.data(), operands.size()};
     }
@@ -524,8 +552,11 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
 Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
                      Id derivates, Id offset, Id lod_clamp) {
     const auto info{inst->Flags<IR::TextureInstInfo>()};
-    const ImageOperands operands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates,
-                                 offset, lod_clamp);
+    const auto operands =
+        info.num_derivates == 3
+            ? ImageOperands(ctx, info.has_lod_clamp != 0, derivates, offset, {}, lod_clamp)
+            : ImageOperands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, offset,
+                            lod_clamp);
     return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
                 &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
                 Texture(ctx, info, index), coords, operands.Mask(), operands.Span());
-- 
cgit v1.2.3-70-g09d2