From d171083d53e106c8c5131522fdc81d51360c562d Mon Sep 17 00:00:00 2001
From: ameerj <52414509+ameerj@users.noreply.github.com>
Date: Wed, 26 May 2021 21:18:17 -0400
Subject: [PATCH] glsl: textures wip

---
 .../backend/glsl/emit_context.cpp             | 54 ++++++++++++--
 .../backend/glsl/emit_context.h               |  8 +++
 .../backend/glsl/emit_glsl.cpp                |  6 +-
 .../glsl/emit_glsl_bitwise_conversion.cpp     |  2 +-
 .../backend/glsl/emit_glsl_image.cpp          | 24 ++++++-
 .../backend/glsl/emit_glsl_instructions.h     | 10 +--
 .../glsl/emit_glsl_not_implemented.cpp        | 27 ++++---
 .../backend/glsl/reg_alloc.cpp                | 72 +++++++------------
 .../backend/glsl/reg_alloc.h                  | 11 +--
 9 files changed, 139 insertions(+), 75 deletions(-)

diff --git a/src/shader_recompiler/backend/glsl/emit_context.cpp b/src/shader_recompiler/backend/glsl/emit_context.cpp
index 8e5983909..de19e0fba 100644
--- a/src/shader_recompiler/backend/glsl/emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_context.cpp
@@ -8,9 +8,21 @@
 #include "shader_recompiler/profile.h"
 
 namespace Shader::Backend::GLSL {
+namespace {
+std::string_view InterpDecorator(Interpolation interp) {
+    switch (interp) {
+    case Interpolation::Smooth:
+        return "";
+    case Interpolation::Flat:
+        return "flat";
+    case Interpolation::NoPerspective:
+        return "noperspective";
+    }
+    throw InvalidArgument("Invalid interpolation {}", interp);
+}
+} // namespace
 
-EmitContext::EmitContext(IR::Program& program, [[maybe_unused]] Bindings& bindings,
-                         const Profile& profile_)
+EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_)
     : info{program.info}, profile{profile_} {
     std::string header = "#version 450\n";
     SetupExtensions(header);
@@ -49,7 +61,8 @@ EmitContext::EmitContext(IR::Program& program, [[maybe_unused]] Bindings& bindin
     for (size_t index = 0; index < info.input_generics.size(); ++index) {
         const auto& generic{info.input_generics[index]};
         if (generic.used) {
-            Add("layout(location={})in vec4 in_attr{};", index, index);
+            Add("layout(location={}) {} in vec4 in_attr{};", index,
+                InterpDecorator(generic.interpolation), index);
         }
     }
     for (size_t index = 0; index < info.stores_frag_color.size(); ++index) {
@@ -66,6 +79,7 @@ EmitContext::EmitContext(IR::Program& program, [[maybe_unused]] Bindings& bindin
     DefineConstantBuffers();
     DefineStorageBuffers();
     DefineHelperFunctions();
+    SetupImages(bindings);
     Add("void main(){{");
 
     if (stage == Stage::VertexA || stage == Stage::VertexB) {
@@ -102,7 +116,7 @@ void EmitContext::DefineConstantBuffers() {
     }
     u32 binding{};
     for (const auto& desc : info.constant_buffer_descriptors) {
-        Add("layout(std140,binding={}) uniform cbuf_{}{{vec4 cbuf{}[{}];}};", binding, binding,
+        Add("layout(std140,binding={}) uniform cbuf_{}{{vec4 cbuf{}[{}];}};", binding, desc.index,
             desc.index, 4 * 1024);
         ++binding;
     }
@@ -164,4 +178,36 @@ void EmitContext::DefineHelperFunctions() {
     }
 }
 
+void EmitContext::SetupImages(Bindings& bindings) {
+    image_buffer_bindings.reserve(info.image_buffer_descriptors.size());
+    for (const auto& desc : info.image_buffer_descriptors) {
+        throw NotImplementedException("image_buffer_descriptors");
+        image_buffer_bindings.push_back(bindings.image);
+        bindings.image += desc.count;
+    }
+    image_bindings.reserve(info.image_descriptors.size());
+    for (const auto& desc : info.image_descriptors) {
+        throw NotImplementedException("image_bindings");
+
+        image_bindings.push_back(bindings.image);
+        bindings.image += desc.count;
+    }
+    texture_buffer_bindings.reserve(info.texture_buffer_descriptors.size());
+    for (const auto& desc : info.texture_buffer_descriptors) {
+        throw NotImplementedException("TextureType::Buffer");
+
+        texture_buffer_bindings.push_back(bindings.texture);
+        bindings.texture += desc.count;
+    }
+    texture_bindings.reserve(info.texture_descriptors.size());
+    for (const auto& desc : info.texture_descriptors) {
+        texture_bindings.push_back(bindings.texture);
+        const auto indices{bindings.texture + desc.count};
+        for (u32 index = bindings.texture; index < indices; ++index) {
+            Add("layout(binding={}) uniform sampler2D tex{};", bindings.texture, index);
+        }
+        bindings.texture += desc.count;
+    }
+}
+
 } // namespace Shader::Backend::GLSL
diff --git a/src/shader_recompiler/backend/glsl/emit_context.h b/src/shader_recompiler/backend/glsl/emit_context.h
index 087eaff6a..1cd051b24 100644
--- a/src/shader_recompiler/backend/glsl/emit_context.h
+++ b/src/shader_recompiler/backend/glsl/emit_context.h
@@ -6,6 +6,8 @@
 
 #include <string>
 #include <utility>
+#include <vector>
+
 #include <fmt/format.h>
 
 #include "shader_recompiler/backend/glsl/reg_alloc.h"
@@ -109,11 +111,17 @@ public:
     std::string_view stage_name = "invalid";
     std::string_view attrib_name = "invalid";
 
+    std::vector<u32> texture_buffer_bindings;
+    std::vector<u32> image_buffer_bindings;
+    std::vector<u32> texture_bindings;
+    std::vector<u32> image_bindings;
+
 private:
     void SetupExtensions(std::string& header);
     void DefineConstantBuffers();
     void DefineStorageBuffers();
     void DefineHelperFunctions();
+    void SetupImages(Bindings& bindings);
 };
 
 } // namespace Shader::Backend::GLSL
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl.cpp b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
index a8e53cf66..35dbe19ec 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
@@ -113,7 +113,7 @@ void PrecolorInst(IR::Inst& phi) {
         if (arg.IsImmediate()) {
             ir.PhiMove(phi, arg);
         } else {
-            ir.PhiMove(phi, IR::Value{&RegAlloc::AliasInst(*arg.Inst())});
+            ir.PhiMove(phi, IR::Value{&*arg.InstRecursive()});
         }
     }
     for (size_t i = 0; i < num_args; ++i) {
@@ -157,7 +157,7 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
             break;
         case IR::AbstractSyntaxNode::Type::Return:
         case IR::AbstractSyntaxNode::Type::Unreachable:
-            ctx.Add("return;\n}}");
+            ctx.Add("return;");
             break;
         case IR::AbstractSyntaxNode::Type::Loop:
         case IR::AbstractSyntaxNode::Type::Repeat:
@@ -175,6 +175,8 @@ std::string EmitGLSL(const Profile& profile, const RuntimeInfo&, IR::Program& pr
     EmitContext ctx{program, bindings, profile};
     Precolor(program);
     EmitCode(ctx, program);
+    ctx.code += "}";
+    fmt::print("\n{}\n", ctx.code);
     return ctx.code;
 }
 
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
index 742f394d4..8512147e2 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
@@ -15,7 +15,7 @@ static void Alias(IR::Inst& inst, const IR::Value& value) {
     if (value.IsImmediate()) {
         return;
     }
-    IR::Inst& value_inst{RegAlloc::AliasInst(*value.Inst())};
+    IR::Inst& value_inst{*value.InstRecursive()};
     value_inst.DestructiveAddUsage(inst.UseCount());
     value_inst.DestructiveRemoveUsage();
     inst.SetDefinition(value_inst.Definition<Id>());
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
index 109938e0e..cc5afc048 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
@@ -6,17 +6,39 @@
 
 #include "shader_recompiler/backend/glsl/emit_context.h"
 #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
+#include "shader_recompiler/frontend/ir/modifiers.h"
 #include "shader_recompiler/frontend/ir/value.h"
 #include "shader_recompiler/profile.h"
 
 namespace Shader::Backend::GLSL {
+namespace {
+std::string Texture(EmitContext& ctx, IR::TextureInstInfo info,
+                    [[maybe_unused]] const IR::Value& index) {
+    if (info.type == TextureType::Buffer) {
+        throw NotImplementedException("TextureType::Buffer");
+    } else {
+        return fmt::format("tex{}", ctx.texture_bindings.at(info.descriptor_index));
+    }
+}
+} // namespace
 
 void EmitImageSampleImplicitLod([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
                                 [[maybe_unused]] const IR::Value& index,
                                 [[maybe_unused]] std::string_view coords,
                                 [[maybe_unused]] std::string_view bias_lc,
                                 [[maybe_unused]] const IR::Value& offset) {
-    throw NotImplementedException("GLSL Instruction");
+    const auto info{inst.Flags<IR::TextureInstInfo>()};
+    if (info.has_bias) {
+        throw NotImplementedException("Bias texture samples");
+    }
+    if (info.has_lod_clamp) {
+        throw NotImplementedException("Lod clamp samples");
+    }
+    if (!offset.IsEmpty()) {
+        throw NotImplementedException("Offset");
+    }
+    const auto texture{Texture(ctx, info, index)};
+    ctx.AddF32x4("{}=texture({},{});", inst, texture, coords);
 }
 
 void EmitImageSampleExplicitLod([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
index 49ab108bb..c9b53bae2 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
@@ -89,11 +89,11 @@ void EmitIsHelperInvocation(EmitContext& ctx);
 void EmitYDirection(EmitContext& ctx);
 void EmitLoadLocal(EmitContext& ctx, std::string_view word_offset);
 void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_view value);
-void EmitUndefU1(EmitContext& ctx);
-void EmitUndefU8(EmitContext& ctx);
-void EmitUndefU16(EmitContext& ctx);
-void EmitUndefU32(EmitContext& ctx);
-void EmitUndefU64(EmitContext& ctx);
+void EmitUndefU1(EmitContext& ctx, IR::Inst& inst);
+void EmitUndefU8(EmitContext& ctx, IR::Inst& inst);
+void EmitUndefU16(EmitContext& ctx, IR::Inst& inst);
+void EmitUndefU32(EmitContext& ctx, IR::Inst& inst);
+void EmitUndefU64(EmitContext& ctx, IR::Inst& inst);
 void EmitLoadGlobalU8(EmitContext& ctx);
 void EmitLoadGlobalS8(EmitContext& ctx);
 void EmitLoadGlobalU16(EmitContext& ctx);
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 14a2edd74..42b1e8764 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
@@ -39,17 +39,26 @@ void EmitReference(EmitContext&) {
 }
 
 void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) {
-    IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())};
+    IR::Inst& phi{*phi_value.InstRecursive()};
+    const auto phi_type{phi.Arg(0).Type()};
     if (!phi.Definition<Id>().is_valid) {
         // The phi node wasn't forward defined
-        ctx.Add("{};", ctx.reg_alloc.Define(phi, phi.Arg(0).Type()));
+        ctx.Add("{};", ctx.reg_alloc.Define(phi, phi_type));
     }
     const auto phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})};
     const auto val_reg{ctx.reg_alloc.Consume(value)};
     if (phi_reg == val_reg) {
         return;
     }
-    ctx.Add("{}={};", phi_reg, val_reg);
+    if (phi_type == value.Type()) {
+        ctx.Add("{}={}; // PHI MOVE", phi_reg, val_reg);
+    } else if (phi_type == IR::Type::U32 && value.Type() == IR::Type::F32) {
+        ctx.Add("{}=floatBitsToUint({}); // CAST PHI MOVE", phi_reg, val_reg);
+    } else {
+        throw NotImplementedException("{} to {} move", phi_type, value.Type());
+        const auto cast{ctx.reg_alloc.GetGlslType(phi_type)};
+        ctx.Add("{}={}({}); // CAST PHI MOVE", phi_reg, cast, val_reg);
+    }
 }
 
 void EmitBranch(EmitContext& ctx, std::string_view label) {
@@ -235,23 +244,23 @@ void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_
     NotImplemented();
 }
 
-void EmitUndefU1(EmitContext& ctx) {
+void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) {
     NotImplemented();
 }
 
-void EmitUndefU8(EmitContext& ctx) {
+void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) {
     NotImplemented();
 }
 
-void EmitUndefU16(EmitContext& ctx) {
+void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) {
     NotImplemented();
 }
 
-void EmitUndefU32(EmitContext& ctx) {
-    NotImplemented();
+void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) {
+    ctx.AddU32("{}=0u;", inst);
 }
 
-void EmitUndefU64(EmitContext& ctx) {
+void EmitUndefU64(EmitContext& ctx, IR::Inst& inst) {
     NotImplemented();
 }
 
diff --git a/src/shader_recompiler/backend/glsl/reg_alloc.cpp b/src/shader_recompiler/backend/glsl/reg_alloc.cpp
index a080d5341..06f1965b5 100644
--- a/src/shader_recompiler/backend/glsl/reg_alloc.cpp
+++ b/src/shader_recompiler/backend/glsl/reg_alloc.cpp
@@ -71,26 +71,17 @@ std::string RegAlloc::Define(IR::Inst& inst) {
 
 std::string RegAlloc::Define(IR::Inst& inst, Type type) {
     const Id id{Alloc()};
-    const auto type_str{GetType(type, id.index)};
+    std::string type_str = "";
+    if (!register_defined[id.index]) {
+        register_defined[id.index] = true;
+        type_str = GetGlslType(type);
+    }
     inst.SetDefinition<Id>(id);
     return type_str + Representation(id);
 }
 
 std::string RegAlloc::Define(IR::Inst& inst, IR::Type type) {
-    switch (type) {
-    case IR::Type::U1:
-        return Define(inst, Type::U1);
-    case IR::Type::U32:
-        return Define(inst, Type::U32);
-    case IR::Type::F32:
-        return Define(inst, Type::F32);
-    case IR::Type::U64:
-        return Define(inst, Type::U64);
-    case IR::Type::F64:
-        return Define(inst, Type::F64);
-    default:
-        throw NotImplementedException("IR type {}", type);
-    }
+    return Define(inst, RegType(type));
 }
 
 std::string RegAlloc::Consume(const IR::Value& value) {
@@ -107,11 +98,24 @@ std::string RegAlloc::Consume(IR::Inst& inst) {
     return Representation(inst.Definition<Id>());
 }
 
-std::string RegAlloc::GetType(Type type, u32 index) {
-    if (register_defined[index]) {
-        return "";
+Type RegAlloc::RegType(IR::Type type) {
+    switch (type) {
+    case IR::Type::U1:
+        return Type::U1;
+    case IR::Type::U32:
+        return Type::U32;
+    case IR::Type::F32:
+        return Type::F32;
+    case IR::Type::U64:
+        return Type::U64;
+    case IR::Type::F64:
+        return Type::F64;
+    default:
+        throw NotImplementedException("IR type {}", type);
     }
-    register_defined[index] = true;
+}
+
+std::string RegAlloc::GetGlslType(Type type) {
     switch (type) {
     case Type::U1:
         return "bool ";
@@ -144,6 +148,10 @@ std::string RegAlloc::GetType(Type type, u32 index) {
     }
 }
 
+std::string RegAlloc::GetGlslType(IR::Type type) {
+    return GetGlslType(RegType(type));
+}
+
 Id RegAlloc::Alloc() {
     if (num_used_registers < NUM_REGS) {
         for (size_t reg = 0; reg < NUM_REGS; ++reg) {
@@ -170,30 +178,4 @@ void RegAlloc::Free(Id id) {
     register_use[id.index] = false;
 }
 
-/*static*/ bool RegAlloc::IsAliased(const IR::Inst& inst) {
-    switch (inst.GetOpcode()) {
-    case IR::Opcode::Identity:
-    case IR::Opcode::BitCastU16F16:
-    case IR::Opcode::BitCastU32F32:
-    case IR::Opcode::BitCastU64F64:
-    case IR::Opcode::BitCastF16U16:
-    case IR::Opcode::BitCastF32U32:
-    case IR::Opcode::BitCastF64U64:
-        return true;
-    default:
-        return false;
-    }
-}
-
-/*static*/ IR::Inst& RegAlloc::AliasInst(IR::Inst& inst) {
-    IR::Inst* it{&inst};
-    while (IsAliased(*it)) {
-        const IR::Value arg{it->Arg(0)};
-        if (arg.IsImmediate()) {
-            break;
-        }
-        it = arg.InstRecursive();
-    }
-    return *it;
-}
 } // namespace Shader::Backend::GLSL
diff --git a/src/shader_recompiler/backend/glsl/reg_alloc.h b/src/shader_recompiler/backend/glsl/reg_alloc.h
index df067d3ad..419d0bde0 100644
--- a/src/shader_recompiler/backend/glsl/reg_alloc.h
+++ b/src/shader_recompiler/backend/glsl/reg_alloc.h
@@ -59,20 +59,15 @@ public:
     std::string Define(IR::Inst& inst, IR::Type type);
 
     std::string Consume(const IR::Value& value);
-
-    /// Returns true if the instruction is expected to be aliased to another
-    static bool IsAliased(const IR::Inst& inst);
-
-    /// Returns the underlying value out of an alias sequence
-    static IR::Inst& AliasInst(IR::Inst& inst);
+    std::string GetGlslType(Type type);
+    std::string GetGlslType(IR::Type type);
 
 private:
     static constexpr size_t NUM_REGS = 4096;
     static constexpr size_t NUM_ELEMENTS = 4;
 
     std::string Consume(IR::Inst& inst);
-    std::string GetType(Type type, u32 index);
-
+    Type RegType(IR::Type type);
     Id Alloc();
     void Free(Id id);