From c5422041134ed2645e7cd32152e36f9d04c66da3 Mon Sep 17 00:00:00 2001
From: ameerj <52414509+ameerj@users.noreply.github.com>
Date: Mon, 7 Jun 2021 20:39:30 -0400
Subject: [PATCH] glsl: Implement indexed attribute loads

---
 .../backend/glsl/emit_context.cpp             | 42 +++++++++++++++++++
 .../backend/glsl/emit_context.h               |  1 +
 .../glsl/emit_glsl_context_get_set.cpp        | 38 ++++++++---------
 .../backend/glsl/emit_glsl_instructions.h     |  3 +-
 .../glsl/emit_glsl_not_implemented.cpp        |  9 ----
 5 files changed, 64 insertions(+), 29 deletions(-)

diff --git a/src/shader_recompiler/backend/glsl/emit_context.cpp b/src/shader_recompiler/backend/glsl/emit_context.cpp
index d6b3c7aba..ed0955da0 100644
--- a/src/shader_recompiler/backend/glsl/emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_context.cpp
@@ -104,8 +104,22 @@ std::string_view SamplerType(TextureType type, bool is_depth) {
 
 std::string_view ImageType(TextureType type) {
     switch (type) {
+    case TextureType::Color1D:
+        return "uimage1D";
+    case TextureType::ColorArray1D:
+        return "uimage1DArray";
     case TextureType::Color2D:
         return "uimage2D";
+    case TextureType::ColorArray2D:
+        return "uimage2DArray";
+    case TextureType::Color3D:
+        return "uimage3D";
+    case TextureType::ColorCube:
+        return "uimageCube";
+    case TextureType::ColorArrayCube:
+        return "uimageCubeArray";
+    case TextureType::Buffer:
+        return "uimageBuffer";
     default:
         throw NotImplementedException("Image type: {}", type);
     }
@@ -250,6 +264,7 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
         break;
     case Stage::Fragment:
         stage_name = "fs";
+        position_name = "gl_FragCoord";
         break;
     case Stage::Compute:
         stage_name = "cs";
@@ -449,6 +464,33 @@ void EmitContext::DefineHelperFunctions() {
     if (info.uses_global_memory) {
         header += DefineGlobalMemoryFunctions();
     }
+    if (info.loads_indexed_attributes) {
+        const bool is_array{stage == Stage::Geometry};
+        const auto vertex_arg{is_array ? ",uint vertex" : ""};
+        std::string func{
+            fmt::format("float IndexedAttrLoad(int offset{}){{int base_index=offset>>2;uint "
+                        "masked_index=uint(base_index)&3u;switch(base_index>>2){{",
+                        vertex_arg)};
+        if (info.loads_position) {
+            func += fmt::format("case {}:", static_cast<u32>(IR::Attribute::PositionX) >> 2);
+            const auto position_idx{is_array ? "gl_in[vertex]." : ""};
+            func += fmt::format("return {}{}[masked_index];", position_idx, position_name);
+        }
+        const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2;
+        for (u32 i = 0; i < info.input_generics.size(); ++i) {
+            if (!info.input_generics[i].used) {
+                continue;
+            }
+            const auto vertex_idx{is_array ? "[vertex]" : ""};
+            func += fmt::format("case {}:", base_attribute_value + i);
+            func += fmt::format("return in_attr{}{}[masked_index];", i, vertex_idx);
+        }
+        func += "default: return 0.0;}}";
+        header += func;
+    }
+    if (info.stores_indexed_attributes) {
+        // TODO
+    }
 }
 
 std::string EmitContext::DefineGlobalMemoryFunctions() {
diff --git a/src/shader_recompiler/backend/glsl/emit_context.h b/src/shader_recompiler/backend/glsl/emit_context.h
index 9bdca184f..dce99586e 100644
--- a/src/shader_recompiler/backend/glsl/emit_context.h
+++ b/src/shader_recompiler/backend/glsl/emit_context.h
@@ -150,6 +150,7 @@ public:
 
     Stage stage{};
     std::string_view stage_name = "invalid";
+    std::string_view position_name = "gl_Position";
 
     std::vector<u32> texture_buffer_bindings;
     std::vector<u32> image_buffer_bindings;
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
index cfcdd45a2..d09187ea7 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
@@ -206,26 +206,12 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
     case IR::Attribute::PositionX:
     case IR::Attribute::PositionY:
     case IR::Attribute::PositionZ:
-    case IR::Attribute::PositionW:
-        switch (ctx.stage) {
-        case Stage::VertexA:
-        case Stage::VertexB:
-            ctx.AddF32("{}=gl_Position.{};", inst, swizzle);
-            break;
-        case Stage::TessellationEval:
-            ctx.AddF32("{}=gl_TessCoord.{};", inst, swizzle);
-            break;
-        case Stage::TessellationControl:
-        case Stage::Geometry:
-            ctx.AddF32("{}=gl_in[{}].gl_Position.{};", inst, vertex, swizzle);
-            break;
-        case Stage::Fragment:
-            ctx.AddF32("{}=gl_FragCoord.{};", inst, swizzle);
-            break;
-        default:
-            throw NotImplementedException("Get Position for stage {}", ctx.stage);
-        }
+    case IR::Attribute::PositionW: {
+        const bool is_array{IsInputArray(ctx.stage)};
+        const auto input_decorator{is_array ? fmt::format("gl_in[{}].", vertex) : ""};
+        ctx.AddF32("{}={}{}.{};", inst, input_decorator, ctx.position_name, swizzle);
         break;
+    }
     case IR::Attribute::PointSpriteS:
     case IR::Attribute::PointSpriteT:
         ctx.AddF32("{}=gl_PointCoord.{};", inst, swizzle);
@@ -311,6 +297,20 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val
     }
 }
 
+void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, std::string_view offset,
+                             std::string_view vertex) {
+    const bool is_array{ctx.stage == Stage::Geometry};
+    const auto vertex_arg{is_array ? fmt::format(",{}", vertex) : ""};
+    ctx.AddF32("{}=IndexedAttrLoad(int({}){});", inst, offset, vertex_arg);
+}
+
+void EmitSetAttributeIndexed([[maybe_unused]] EmitContext& ctx,
+                             [[maybe_unused]] std::string_view offset,
+                             [[maybe_unused]] std::string_view value,
+                             [[maybe_unused]] std::string_view vertex) {
+    NotImplemented();
+}
+
 void EmitGetPatch(EmitContext& ctx, IR::Inst& inst, IR::Patch patch) {
     if (!IR::IsGeneric(patch)) {
         throw NotImplementedException("Non-generic patch load");
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
index 90dcfcef7..12094139f 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
@@ -72,7 +72,8 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
                       std::string_view vertex);
 void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value,
                       std::string_view vertex);
-void EmitGetAttributeIndexed(EmitContext& ctx, std::string_view offset, std::string_view vertex);
+void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, std::string_view offset,
+                             std::string_view vertex);
 void EmitSetAttributeIndexed(EmitContext& ctx, std::string_view offset, std::string_view value,
                              std::string_view vertex);
 void EmitGetPatch(EmitContext& ctx, IR::Inst& inst, IR::Patch patch);
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
index 37e4b453b..b292db9d4 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
@@ -124,15 +124,6 @@ void EmitGetIndirectBranchVariable(EmitContext& ctx) {
     NotImplemented();
 }
 
-void EmitGetAttributeIndexed(EmitContext& ctx, std::string_view offset, std::string_view vertex) {
-    NotImplemented();
-}
-
-void EmitSetAttributeIndexed(EmitContext& ctx, std::string_view offset, std::string_view value,
-                             std::string_view vertex) {
-    NotImplemented();
-}
-
 void EmitSetSampleMask(EmitContext& ctx, std::string_view value) {
     NotImplemented();
 }