From 73b11f390e3dabf42d22af78670c8aa6d8f52cee Mon Sep 17 00:00:00 2001
From: Feng Chen <vonchenplus@gmail.com>
Date: Wed, 1 Sep 2021 00:07:25 +0800
Subject: [PATCH] Add colorfront and txtcoord support

---
 .../backend/spirv/emit_context.cpp            | 14 ++++++++++
 .../backend/spirv/emit_context.h              |  4 +++
 .../spirv/emit_spirv_context_get_set.cpp      | 26 +++++++++++++++++++
 .../frontend/ir/attribute.cpp                 |  8 ++++++
 src/shader_recompiler/frontend/ir/attribute.h |  5 ++++
 5 files changed, 57 insertions(+)

diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index 2d29d8c145..89c75c52d4 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -1201,6 +1201,12 @@ void EmitContext::DefineInputs(const IR::Program& program) {
             }
         }
     }
+    if (loads.AllComponents(IR::Attribute::ColorFrontDiffuseR)) {
+        input_front_color = DefineInput(*this, F32[4], true);
+    }
+    if (loads.AllComponents(IR::Attribute::FixedFncTexture0S)) {
+        input_txt_coord = DefineInput(*this, F32[4], true);
+    }
     if (loads[IR::Attribute::InstanceId]) {
         if (profile.support_vertex_instance_id) {
             instance_id = DefineInput(*this, U32[1], true, spv::BuiltIn::InstanceId);
@@ -1282,6 +1288,9 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
     if (info.stores.AnyComponent(IR::Attribute::PositionX) || stage == Stage::VertexB) {
         output_position = DefineOutput(*this, F32[4], invocations, spv::BuiltIn::Position);
     }
+    if (info.stores.AnyComponent(IR::Attribute::ColorFrontDiffuseR) || stage == Stage::VertexB) {
+        output_front_color = DefineOutput(*this, F32[4], invocations);
+    }
     if (info.stores[IR::Attribute::PointSize] || runtime_info.fixed_state_point_size) {
         if (stage == Stage::Fragment) {
             throw NotImplementedException("Storing PointSize in fragment stage");
@@ -1313,6 +1322,11 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
         viewport_mask = DefineOutput(*this, TypeArray(U32[1], Const(1u)), std::nullopt,
                                      spv::BuiltIn::ViewportMaskNV);
     }
+
+    if (info.stores.AnyComponent(IR::Attribute::FixedFncTexture0S)) {
+        output_txt_coord = DefineOutput(*this, F32[4], invocations);
+    }
+
     for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
         if (info.stores.Generic(index)) {
             DefineGenericOutput(*this, index, invocations);
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index e277bc3580..1023d0ee4d 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -268,10 +268,14 @@ public:
     Id write_global_func_u32x4{};
 
     Id input_position{};
+    Id input_front_color{};
+    Id input_txt_coord{};
     std::array<Id, 32> input_generics{};
 
     Id output_point_size{};
     Id output_position{};
+    Id output_front_color{};
+    Id output_txt_coord;
     std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};
 
     Id output_tess_level_outer{};
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index 14c77f1627..0444bbf8ff 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -74,6 +74,12 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
             return OutputAccessChain(ctx, ctx.output_f32, info.id, index_id);
         }
     }
+    if (attr >= IR::Attribute::FixedFncTexture0S && attr <= IR::Attribute::FixedFncTexture9Q) {
+        const u32 index{IR::TxtCoordAttributeIndex(attr)};
+        const u32 element{IR::TxtCoordAttributeElement(attr)};
+        const Id element_id{ctx.Const(element)};
+        return OutputAccessChain(ctx, ctx.output_f32, ctx.output_txt_coord, element_id);
+    }
     switch (attr) {
     case IR::Attribute::PointSize:
         return ctx.output_point_size;
@@ -85,6 +91,14 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
         const Id element_id{ctx.Const(element)};
         return OutputAccessChain(ctx, ctx.output_f32, ctx.output_position, element_id);
     }
+    case IR::Attribute::ColorFrontDiffuseR:
+    case IR::Attribute::ColorFrontDiffuseG:
+    case IR::Attribute::ColorFrontDiffuseB:
+    case IR::Attribute::ColorFrontDiffuseA: {
+        const u32 element{static_cast<u32>(attr) % 4};
+        const Id element_id{ctx.Const(element)};
+        return OutputAccessChain(ctx, ctx.output_f32, ctx.output_front_color, element_id);
+    }
     case IR::Attribute::ClipDistance0:
     case IR::Attribute::ClipDistance1:
     case IR::Attribute::ClipDistance2:
@@ -307,6 +321,11 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
         const Id value{ctx.OpLoad(type->id, pointer)};
         return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value;
     }
+    if (attr >= IR::Attribute::FixedFncTexture0S && attr <= IR::Attribute::FixedFncTexture9Q) {
+        const u32 index{IR::TxtCoordAttributeIndex(attr)};
+        return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_txt_coord,
+                                                  ctx.Const(element)));
+    }
     switch (attr) {
     case IR::Attribute::PrimitiveId:
         return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id));
@@ -316,6 +335,13 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
     case IR::Attribute::PositionW:
         return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position,
                                                   ctx.Const(element)));
+    case IR::Attribute::ColorFrontDiffuseR:
+    case IR::Attribute::ColorFrontDiffuseG:
+    case IR::Attribute::ColorFrontDiffuseB:
+    case IR::Attribute::ColorFrontDiffuseA: {
+        return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_front_color,
+                                                  ctx.Const(element)));
+    }
     case IR::Attribute::InstanceId:
         if (ctx.profile.support_vertex_instance_id) {
             return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.instance_id));
diff --git a/src/shader_recompiler/frontend/ir/attribute.cpp b/src/shader_recompiler/frontend/ir/attribute.cpp
index 4d0b8b8e5c..dc2bec06db 100644
--- a/src/shader_recompiler/frontend/ir/attribute.cpp
+++ b/src/shader_recompiler/frontend/ir/attribute.cpp
@@ -9,6 +9,14 @@
 
 namespace Shader::IR {
 
+u32 TxtCoordAttributeIndex(Attribute attribute) {
+    return (static_cast<u32>(attribute) - static_cast<u32>(Attribute::FixedFncTexture0S)) / 4u;
+}
+
+u32 TxtCoordAttributeElement(Attribute attribute) {
+    return static_cast<u32>(attribute) % 4;
+}
+
 bool IsGeneric(Attribute attribute) noexcept {
     return attribute >= Attribute::Generic0X && attribute <= Attribute::Generic31X;
 }
diff --git a/src/shader_recompiler/frontend/ir/attribute.h b/src/shader_recompiler/frontend/ir/attribute.h
index ca11994943..6957fb43b9 100644
--- a/src/shader_recompiler/frontend/ir/attribute.h
+++ b/src/shader_recompiler/frontend/ir/attribute.h
@@ -222,8 +222,13 @@ enum class Attribute : u64 {
     FrontFace = 255,
 };
 
+constexpr size_t NUM_TXT_COORD = 10;
 constexpr size_t NUM_GENERICS = 32;
 
+[[nodiscard]] u32 TxtCoordAttributeIndex(Attribute attribute);
+
+[[nodiscard]] u32 TxtCoordAttributeElement(Attribute attribute);
+
 [[nodiscard]] bool IsGeneric(Attribute attribute) noexcept;
 
 [[nodiscard]] u32 GenericAttributeIndex(Attribute attribute);