From 59fead3a47227b513c0ca35090919823f44faecf Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Thu, 17 Jun 2021 20:34:58 -0300
Subject: [PATCH] spirv: Properly handle devices without int8 and int16

---
 .../backend/spirv/emit_context.cpp            | 58 +++++++++++--------
 .../spirv/emit_spirv_context_get_set.cpp      | 54 +++++++++++------
 2 files changed, 70 insertions(+), 42 deletions(-)

diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index 32c21f3b48..4c6501129e 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -911,37 +911,45 @@ void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
     if (info.constant_buffer_descriptors.empty()) {
         return;
     }
-    if (profile.support_descriptor_aliasing) {
-        if (True(info.used_constant_buffer_types & IR::Type::U8)) {
-            DefineConstBuffers(*this, info, &UniformDefinitions::U8, binding, U8, 'u', sizeof(u8));
-            DefineConstBuffers(*this, info, &UniformDefinitions::S8, binding, S8, 's', sizeof(s8));
-        }
-        if (True(info.used_constant_buffer_types & IR::Type::U16)) {
-            DefineConstBuffers(*this, info, &UniformDefinitions::U16, binding, U16, 'u',
-                               sizeof(u16));
-            DefineConstBuffers(*this, info, &UniformDefinitions::S16, binding, S16, 's',
-                               sizeof(s16));
-        }
-        if (True(info.used_constant_buffer_types & IR::Type::U32)) {
-            DefineConstBuffers(*this, info, &UniformDefinitions::U32, binding, U32[1], 'u',
-                               sizeof(u32));
-        }
-        if (True(info.used_constant_buffer_types & IR::Type::F32)) {
-            DefineConstBuffers(*this, info, &UniformDefinitions::F32, binding, F32[1], 'f',
-                               sizeof(f32));
-        }
-        if (True(info.used_constant_buffer_types & IR::Type::U32x2)) {
-            DefineConstBuffers(*this, info, &UniformDefinitions::U32x2, binding, U32[2], 'u',
-                               sizeof(u32[2]));
-        }
-        binding += static_cast<u32>(info.constant_buffer_descriptors.size());
-    } else {
+    IR::Type types{info.used_constant_buffer_types};
+    if (!profile.support_descriptor_aliasing) {
         DefineConstBuffers(*this, info, &UniformDefinitions::U32x4, binding, U32[4], 'u',
                            sizeof(u32[4]));
         for (const ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) {
             binding += desc.count;
         }
     }
+    if (True(types & IR::Type::U8)) {
+        if (profile.support_int8) {
+            DefineConstBuffers(*this, info, &UniformDefinitions::U8, binding, U8, 'u', sizeof(u8));
+            DefineConstBuffers(*this, info, &UniformDefinitions::S8, binding, S8, 's', sizeof(s8));
+        } else {
+            types |= IR::Type::U32;
+        }
+    }
+    if (True(types & IR::Type::U16)) {
+        if (profile.support_int16) {
+            DefineConstBuffers(*this, info, &UniformDefinitions::U16, binding, U16, 'u',
+                               sizeof(u16));
+            DefineConstBuffers(*this, info, &UniformDefinitions::S16, binding, S16, 's',
+                               sizeof(s16));
+        } else {
+            types |= IR::Type::U32;
+        }
+    }
+    if (True(types & IR::Type::U32)) {
+        DefineConstBuffers(*this, info, &UniformDefinitions::U32, binding, U32[1], 'u',
+                           sizeof(u32));
+    }
+    if (True(types & IR::Type::F32)) {
+        DefineConstBuffers(*this, info, &UniformDefinitions::F32, binding, F32[1], 'f',
+                           sizeof(f32));
+    }
+    if (True(types & IR::Type::U32x2)) {
+        DefineConstBuffers(*this, info, &UniformDefinitions::U32x2, binding, U32[2], 'u',
+                           sizeof(u32[2]));
+    }
+    binding += static_cast<u32>(info.constant_buffer_descriptors.size());
 }
 
 void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) {
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 4ac1fbae5c..2e364baecd 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
@@ -144,6 +144,10 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr,
     return ctx.OpLoad(result_type, access_chain);
 }
 
+Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
+    return GetCbuf(ctx, ctx.U32[1], &UniformDefinitions::U32, sizeof(u32), binding, offset);
+}
+
 Id GetCbufU32x4(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
     return GetCbuf(ctx, ctx.U32[4], &UniformDefinitions::U32x4, sizeof(u32[4]), binding, offset);
 }
@@ -203,58 +207,74 @@ void EmitGetLoopSafetyVariable(EmitContext&) {
 }
 
 Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
-    if (ctx.profile.support_descriptor_aliasing) {
+    if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) {
         const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset)};
         return ctx.OpUConvert(ctx.U32[1], load);
+    }
+    Id element{};
+    if (ctx.profile.support_descriptor_aliasing) {
+        element = GetCbufU32(ctx, binding, offset);
     } else {
         const Id vector{GetCbufU32x4(ctx, binding, offset)};
-        const Id element{GetCbufElement(ctx, vector, offset, 0u)};
-        const Id bit_offset{ctx.BitOffset8(offset)};
-        return ctx.OpBitFieldUExtract(ctx.U32[1], element, bit_offset, ctx.Const(8u));
+        element = GetCbufElement(ctx, vector, offset, 0u);
     }
+    const Id bit_offset{ctx.BitOffset8(offset)};
+    return ctx.OpBitFieldUExtract(ctx.U32[1], element, bit_offset, ctx.Const(8u));
 }
 
 Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
-    if (ctx.profile.support_descriptor_aliasing) {
+    if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) {
         const Id load{GetCbuf(ctx, ctx.S8, &UniformDefinitions::S8, sizeof(s8), binding, offset)};
         return ctx.OpSConvert(ctx.U32[1], load);
+    }
+    Id element{};
+    if (ctx.profile.support_descriptor_aliasing) {
+        element = GetCbufU32(ctx, binding, offset);
     } else {
         const Id vector{GetCbufU32x4(ctx, binding, offset)};
-        const Id element{GetCbufElement(ctx, vector, offset, 0u)};
-        const Id bit_offset{ctx.BitOffset8(offset)};
-        return ctx.OpBitFieldSExtract(ctx.U32[1], element, bit_offset, ctx.Const(8u));
+        element = GetCbufElement(ctx, vector, offset, 0u);
     }
+    const Id bit_offset{ctx.BitOffset8(offset)};
+    return ctx.OpBitFieldSExtract(ctx.U32[1], element, bit_offset, ctx.Const(8u));
 }
 
 Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
-    if (ctx.profile.support_descriptor_aliasing) {
+    if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int16) {
         const Id load{
             GetCbuf(ctx, ctx.U16, &UniformDefinitions::U16, sizeof(u16), binding, offset)};
         return ctx.OpUConvert(ctx.U32[1], load);
+    }
+    Id element{};
+    if (ctx.profile.support_descriptor_aliasing) {
+        element = GetCbufU32(ctx, binding, offset);
     } else {
         const Id vector{GetCbufU32x4(ctx, binding, offset)};
-        const Id element{GetCbufElement(ctx, vector, offset, 0u)};
-        const Id bit_offset{ctx.BitOffset16(offset)};
-        return ctx.OpBitFieldUExtract(ctx.U32[1], element, bit_offset, ctx.Const(16u));
+        element = GetCbufElement(ctx, vector, offset, 0u);
     }
+    const Id bit_offset{ctx.BitOffset16(offset)};
+    return ctx.OpBitFieldUExtract(ctx.U32[1], element, bit_offset, ctx.Const(16u));
 }
 
 Id EmitGetCbufS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
-    if (ctx.profile.support_descriptor_aliasing) {
+    if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int16) {
         const Id load{
             GetCbuf(ctx, ctx.S16, &UniformDefinitions::S16, sizeof(s16), binding, offset)};
         return ctx.OpSConvert(ctx.U32[1], load);
+    }
+    Id element{};
+    if (ctx.profile.support_descriptor_aliasing) {
+        element = GetCbufU32(ctx, binding, offset);
     } else {
         const Id vector{GetCbufU32x4(ctx, binding, offset)};
-        const Id element{GetCbufElement(ctx, vector, offset, 0u)};
-        const Id bit_offset{ctx.BitOffset16(offset)};
-        return ctx.OpBitFieldSExtract(ctx.U32[1], element, bit_offset, ctx.Const(16u));
+        element = GetCbufElement(ctx, vector, offset, 0u);
     }
+    const Id bit_offset{ctx.BitOffset16(offset)};
+    return ctx.OpBitFieldSExtract(ctx.U32[1], element, bit_offset, ctx.Const(16u));
 }
 
 Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
     if (ctx.profile.support_descriptor_aliasing) {
-        return GetCbuf(ctx, ctx.U32[1], &UniformDefinitions::U32, sizeof(u32), binding, offset);
+        return GetCbufU32(ctx, binding, offset);
     } else {
         const Id vector{GetCbufU32x4(ctx, binding, offset)};
         return GetCbufElement(ctx, vector, offset, 0u);