From a569ac418e232ed631b5a884a1d54aaa619d8341 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Thu, 20 May 2021 21:00:17 -0300
Subject: [PATCH] glasm: Implement patch memory

---
 .../backend/glasm/emit_context.cpp            | 18 +++++++++
 .../glasm/emit_glasm_context_get_set.cpp      | 37 ++++++++++++++++---
 .../backend/glasm/emit_glasm_instructions.h   |  2 +-
 3 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/src/shader_recompiler/backend/glasm/emit_context.cpp b/src/shader_recompiler/backend/glasm/emit_context.cpp
index 7b25fa042..bb68b3d19 100644
--- a/src/shader_recompiler/backend/glasm/emit_context.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_context.cpp
@@ -80,6 +80,24 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
     if (info.uses_invocation_id) {
         Add("ATTRIB primitive_invocation=primitive.invocation;");
     }
+    if (info.stores_tess_level_outer) {
+        Add("OUTPUT result_patch_tessouter[]={{result.patch.tessouter[0..3]}};");
+    }
+    if (info.stores_tess_level_inner) {
+        Add("OUTPUT result_patch_tessinner[]={{result.patch.tessinner[0..1]}};");
+    }
+    for (size_t index = 0; index < info.uses_patches.size(); ++index) {
+        if (!info.uses_patches[index]) {
+            continue;
+        }
+        if (stage == Stage::TessellationEval) {
+            Add("OUTPUT result_patch_attrib{}[]={{result.patch.attrib[{}..{}]}};", index, index,
+                index);
+        } else {
+            Add("ATTRIB primitive_patch_attrib{}[]={{primitive.patch.attrib[{}..{}]}};", index,
+                index, index);
+        }
+    }
     for (size_t index = 0; index < program.info.stores_frag_color.size(); ++index) {
         if (!program.info.stores_frag_color[index]) {
             continue;
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
index d736775c8..c3a2c6b70 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
@@ -136,13 +136,40 @@ void EmitSetAttributeIndexed([[maybe_unused]] EmitContext& ctx, [[maybe_unused]]
     throw NotImplementedException("GLASM instruction");
 }
 
-void EmitGetPatch([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Patch patch) {
-    throw NotImplementedException("GLASM instruction");
+void EmitGetPatch(EmitContext& ctx, IR::Inst& inst, IR::Patch patch) {
+    if (!IR::IsGeneric(patch)) {
+        throw NotImplementedException("Non-generic patch load");
+    }
+    const u32 index{IR::GenericPatchIndex(patch)};
+    const u32 element{IR::GenericPatchElement(patch)};
+    ctx.Add("MOV.F {},result.patch.attrib[{}].{}", inst, index, "xyzw"[element]);
 }
 
-void EmitSetPatch([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Patch patch,
-                  [[maybe_unused]] ScalarF32 value) {
-    throw NotImplementedException("GLASM instruction");
+void EmitSetPatch(EmitContext& ctx, IR::Patch patch, ScalarF32 value) {
+    if (IR::IsGeneric(patch)) {
+        const u32 index{IR::GenericPatchIndex(patch)};
+        const u32 element{IR::GenericPatchElement(patch)};
+        ctx.Add("MOV.F result.patch.attrib[{}].{},{}", index, "xyzw"[element], value);
+        return;
+    }
+    switch (patch) {
+    case IR::Patch::TessellationLodLeft:
+    case IR::Patch::TessellationLodRight:
+    case IR::Patch::TessellationLodTop:
+    case IR::Patch::TessellationLodBottom: {
+        const u32 index{static_cast<u32>(patch) - u32(IR::Patch::TessellationLodLeft)};
+        ctx.Add("MOV.F result.patch.tessouter[{}].x,{};", index, value);
+        break;
+    }
+    case IR::Patch::TessellationLodInteriorU:
+        ctx.Add("MOV.F result.patch.tessinner[0].x,{};", value);
+        break;
+    case IR::Patch::TessellationLodInteriorV:
+        ctx.Add("MOV.F result.patch.tessinner[1].x,{};", value);
+        break;
+    default:
+        throw NotImplementedException("Patch {}", patch);
+    }
 }
 
 void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, ScalarF32 value) {
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
index b0af02235..2eb1eb123 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
@@ -53,7 +53,7 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal
 void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value, ScalarU32 vertex);
 void EmitGetAttributeIndexed(EmitContext& ctx, ScalarU32 offset, ScalarU32 vertex);
 void EmitSetAttributeIndexed(EmitContext& ctx, ScalarU32 offset, ScalarF32 value, ScalarU32 vertex);
-void EmitGetPatch(EmitContext& ctx, IR::Patch patch);
+void EmitGetPatch(EmitContext& ctx, IR::Inst& inst, IR::Patch patch);
 void EmitSetPatch(EmitContext& ctx, IR::Patch patch, ScalarF32 value);
 void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, ScalarF32 value);
 void EmitSetSampleMask(EmitContext& ctx, ScalarS32 value);