summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/spirv
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-05-23 03:58:11 -0300
committerGravatar ameerj2021-07-22 21:51:29 -0400
commit48a17298d76cd8ed3bf2b53aca1e1ac097693976 (patch)
treef0395bbe074b21c96d8a8bbe2ad9115dcbff92cf /src/shader_recompiler/backend/spirv
parentspirv: Desambiguate descriptor names (diff)
downloadyuzu-48a17298d76cd8ed3bf2b53aca1e1ac097693976.tar.gz
yuzu-48a17298d76cd8ed3bf2b53aca1e1ac097693976.tar.xz
yuzu-48a17298d76cd8ed3bf2b53aca1e1ac097693976.zip
spirv: Support OpenGL uniform buffers and change bindings
Diffstat (limited to 'src/shader_recompiler/backend/spirv')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp102
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h15
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp98
5 files changed, 163 insertions, 56 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index 0459c3925..0eb400223 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -441,8 +441,13 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie
441 } 441 }
442} 442}
443 443
444EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& binding) 444EmitContext::EmitContext(const Profile& profile_, IR::Program& program, Bindings& binding)
445 : Sirit::Module(profile_.supported_spirv), profile{profile_}, stage{program.stage} { 445 : Sirit::Module(profile_.supported_spirv), profile{profile_}, stage{program.stage} {
446 const bool is_unified{profile.unified_descriptor_binding};
447 u32& uniform_binding{is_unified ? binding.unified : binding.uniform_buffer};
448 u32& storage_binding{is_unified ? binding.unified : binding.storage_buffer};
449 u32& texture_binding{is_unified ? binding.unified : binding.texture};
450 u32& image_binding{is_unified ? binding.unified : binding.image};
446 AddCapability(spv::Capability::Shader); 451 AddCapability(spv::Capability::Shader);
447 DefineCommonTypes(program.info); 452 DefineCommonTypes(program.info);
448 DefineCommonConstants(); 453 DefineCommonConstants();
@@ -450,12 +455,12 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin
450 DefineLocalMemory(program); 455 DefineLocalMemory(program);
451 DefineSharedMemory(program); 456 DefineSharedMemory(program);
452 DefineSharedMemoryFunctions(program); 457 DefineSharedMemoryFunctions(program);
453 DefineConstantBuffers(program.info, binding); 458 DefineConstantBuffers(program.info, uniform_binding);
454 DefineStorageBuffers(program.info, binding); 459 DefineStorageBuffers(program.info, storage_binding);
455 DefineTextureBuffers(program.info, binding); 460 DefineTextureBuffers(program.info, texture_binding);
456 DefineImageBuffers(program.info, binding); 461 DefineImageBuffers(program.info, image_binding);
457 DefineTextures(program.info, binding); 462 DefineTextures(program.info, texture_binding);
458 DefineImages(program.info, binding); 463 DefineImages(program.info, image_binding);
459 DefineAttributeMemAccess(program.info); 464 DefineAttributeMemAccess(program.info);
460 DefineGlobalMemoryFunctions(program.info); 465 DefineGlobalMemoryFunctions(program.info);
461 DefineLabels(program); 466 DefineLabels(program);
@@ -489,6 +494,20 @@ Id EmitContext::Def(const IR::Value& value) {
489 } 494 }
490} 495}
491 496
497Id EmitContext::BitOffset8(const IR::Value& offset) {
498 if (offset.IsImmediate()) {
499 return Const((offset.U32() % 4) * 8);
500 }
501 return OpBitwiseAnd(U32[1], OpShiftLeftLogical(U32[1], Def(offset), Const(3u)), Const(24u));
502}
503
504Id EmitContext::BitOffset16(const IR::Value& offset) {
505 if (offset.IsImmediate()) {
506 return Const(((offset.U32() / 2) % 2) * 16);
507 }
508 return OpBitwiseAnd(U32[1], OpShiftLeftLogical(U32[1], Def(offset), Const(3u)), Const(16u));
509}
510
492void EmitContext::DefineCommonTypes(const Info& info) { 511void EmitContext::DefineCommonTypes(const Info& info) {
493 void_id = TypeVoid(); 512 void_id = TypeVoid();
494 513
@@ -496,6 +515,7 @@ void EmitContext::DefineCommonTypes(const Info& info) {
496 515
497 F32.Define(*this, TypeFloat(32), "f32"); 516 F32.Define(*this, TypeFloat(32), "f32");
498 U32.Define(*this, TypeInt(32, false), "u32"); 517 U32.Define(*this, TypeInt(32, false), "u32");
518 S32.Define(*this, TypeInt(32, true), "s32");
499 519
500 private_u32 = Name(TypePointer(spv::StorageClass::Private, U32[1]), "private_u32"); 520 private_u32 = Name(TypePointer(spv::StorageClass::Private, U32[1]), "private_u32");
501 521
@@ -889,28 +909,36 @@ void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
889 if (info.constant_buffer_descriptors.empty()) { 909 if (info.constant_buffer_descriptors.empty()) {
890 return; 910 return;
891 } 911 }
892 if (True(info.used_constant_buffer_types & IR::Type::U8)) { 912 if (profile.support_descriptor_aliasing) {
893 DefineConstBuffers(*this, info, &UniformDefinitions::U8, binding, U8, 'u', sizeof(u8)); 913 if (True(info.used_constant_buffer_types & IR::Type::U8)) {
894 DefineConstBuffers(*this, info, &UniformDefinitions::S8, binding, S8, 's', sizeof(s8)); 914 DefineConstBuffers(*this, info, &UniformDefinitions::U8, binding, U8, 'u', sizeof(u8));
895 } 915 DefineConstBuffers(*this, info, &UniformDefinitions::S8, binding, S8, 's', sizeof(s8));
896 if (True(info.used_constant_buffer_types & IR::Type::U16)) { 916 }
897 DefineConstBuffers(*this, info, &UniformDefinitions::U16, binding, U16, 'u', sizeof(u16)); 917 if (True(info.used_constant_buffer_types & IR::Type::U16)) {
898 DefineConstBuffers(*this, info, &UniformDefinitions::S16, binding, S16, 's', sizeof(s16)); 918 DefineConstBuffers(*this, info, &UniformDefinitions::U16, binding, U16, 'u',
899 } 919 sizeof(u16));
900 if (True(info.used_constant_buffer_types & IR::Type::U32)) { 920 DefineConstBuffers(*this, info, &UniformDefinitions::S16, binding, S16, 's',
901 DefineConstBuffers(*this, info, &UniformDefinitions::U32, binding, U32[1], 'u', 921 sizeof(s16));
902 sizeof(u32)); 922 }
903 } 923 if (True(info.used_constant_buffer_types & IR::Type::U32)) {
904 if (True(info.used_constant_buffer_types & IR::Type::F32)) { 924 DefineConstBuffers(*this, info, &UniformDefinitions::U32, binding, U32[1], 'u',
905 DefineConstBuffers(*this, info, &UniformDefinitions::F32, binding, F32[1], 'f', 925 sizeof(u32));
906 sizeof(f32)); 926 }
907 } 927 if (True(info.used_constant_buffer_types & IR::Type::F32)) {
908 if (True(info.used_constant_buffer_types & IR::Type::U32x2)) { 928 DefineConstBuffers(*this, info, &UniformDefinitions::F32, binding, F32[1], 'f',
909 DefineConstBuffers(*this, info, &UniformDefinitions::U32x2, binding, U32[2], 'u', 929 sizeof(f32));
910 sizeof(u32[2])); 930 }
911 } 931 if (True(info.used_constant_buffer_types & IR::Type::U32x2)) {
912 for (const ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) { 932 DefineConstBuffers(*this, info, &UniformDefinitions::U32x2, binding, U32[2], 'u',
913 binding += desc.count; 933 sizeof(u32[2]));
934 }
935 binding += static_cast<u32>(info.constant_buffer_descriptors.size());
936 } else {
937 DefineConstBuffers(*this, info, &UniformDefinitions::U32x4, binding, U32[4], 'u',
938 sizeof(u32[4]));
939 for (const ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) {
940 binding += desc.count;
941 }
914 } 942 }
915} 943}
916 944
@@ -920,35 +948,37 @@ void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) {
920 } 948 }
921 AddExtension("SPV_KHR_storage_buffer_storage_class"); 949 AddExtension("SPV_KHR_storage_buffer_storage_class");
922 950
923 if (True(info.used_storage_buffer_types & IR::Type::U8)) { 951 const IR::Type used_types{profile.support_descriptor_aliasing ? info.used_storage_buffer_types
952 : IR::Type::U32};
953 if (True(used_types & IR::Type::U8)) {
924 DefineSsbos(*this, storage_types.U8, &StorageDefinitions::U8, info, binding, U8, 954 DefineSsbos(*this, storage_types.U8, &StorageDefinitions::U8, info, binding, U8,
925 sizeof(u8)); 955 sizeof(u8));
926 DefineSsbos(*this, storage_types.S8, &StorageDefinitions::S8, info, binding, S8, 956 DefineSsbos(*this, storage_types.S8, &StorageDefinitions::S8, info, binding, S8,
927 sizeof(u8)); 957 sizeof(u8));
928 } 958 }
929 if (True(info.used_storage_buffer_types & IR::Type::U16)) { 959 if (True(used_types & IR::Type::U16)) {
930 DefineSsbos(*this, storage_types.U16, &StorageDefinitions::U16, info, binding, U16, 960 DefineSsbos(*this, storage_types.U16, &StorageDefinitions::U16, info, binding, U16,
931 sizeof(u16)); 961 sizeof(u16));
932 DefineSsbos(*this, storage_types.S16, &StorageDefinitions::S16, info, binding, S16, 962 DefineSsbos(*this, storage_types.S16, &StorageDefinitions::S16, info, binding, S16,
933 sizeof(u16)); 963 sizeof(u16));
934 } 964 }
935 if (True(info.used_storage_buffer_types & IR::Type::U32)) { 965 if (True(used_types & IR::Type::U32)) {
936 DefineSsbos(*this, storage_types.U32, &StorageDefinitions::U32, info, binding, U32[1], 966 DefineSsbos(*this, storage_types.U32, &StorageDefinitions::U32, info, binding, U32[1],
937 sizeof(u32)); 967 sizeof(u32));
938 } 968 }
939 if (True(info.used_storage_buffer_types & IR::Type::F32)) { 969 if (True(used_types & IR::Type::F32)) {
940 DefineSsbos(*this, storage_types.F32, &StorageDefinitions::F32, info, binding, F32[1], 970 DefineSsbos(*this, storage_types.F32, &StorageDefinitions::F32, info, binding, F32[1],
941 sizeof(f32)); 971 sizeof(f32));
942 } 972 }
943 if (True(info.used_storage_buffer_types & IR::Type::U64)) { 973 if (True(used_types & IR::Type::U64)) {
944 DefineSsbos(*this, storage_types.U64, &StorageDefinitions::U64, info, binding, U64, 974 DefineSsbos(*this, storage_types.U64, &StorageDefinitions::U64, info, binding, U64,
945 sizeof(u64)); 975 sizeof(u64));
946 } 976 }
947 if (True(info.used_storage_buffer_types & IR::Type::U32x2)) { 977 if (True(used_types & IR::Type::U32x2)) {
948 DefineSsbos(*this, storage_types.U32x2, &StorageDefinitions::U32x2, info, binding, U32[2], 978 DefineSsbos(*this, storage_types.U32x2, &StorageDefinitions::U32x2, info, binding, U32[2],
949 sizeof(u32[2])); 979 sizeof(u32[2]));
950 } 980 }
951 if (True(info.used_storage_buffer_types & IR::Type::U32x4)) { 981 if (True(used_types & IR::Type::U32x4)) {
952 DefineSsbos(*this, storage_types.U32x4, &StorageDefinitions::U32x4, info, binding, U32[4], 982 DefineSsbos(*this, storage_types.U32x4, &StorageDefinitions::U32x4, info, binding, U32[4],
953 sizeof(u32[4])); 983 sizeof(u32[4]));
954 } 984 }
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index c52544fb7..baf12c217 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -17,6 +17,14 @@ namespace Shader::Backend::SPIRV {
17 17
18using Sirit::Id; 18using Sirit::Id;
19 19
20struct Bindings {
21 u32 unified{};
22 u32 uniform_buffer{};
23 u32 storage_buffer{};
24 u32 texture{};
25 u32 image{};
26};
27
20class VectorTypes { 28class VectorTypes {
21public: 29public:
22 void Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name); 30 void Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name);
@@ -62,6 +70,7 @@ struct UniformDefinitions {
62 Id U32{}; 70 Id U32{};
63 Id F32{}; 71 Id F32{};
64 Id U32x2{}; 72 Id U32x2{};
73 Id U32x4{};
65}; 74};
66 75
67struct StorageTypeDefinition { 76struct StorageTypeDefinition {
@@ -101,11 +110,14 @@ struct GenericElementInfo {
101 110
102class EmitContext final : public Sirit::Module { 111class EmitContext final : public Sirit::Module {
103public: 112public:
104 explicit EmitContext(const Profile& profile, IR::Program& program, u32& binding); 113 explicit EmitContext(const Profile& profile, IR::Program& program, Bindings& binding);
105 ~EmitContext(); 114 ~EmitContext();
106 115
107 [[nodiscard]] Id Def(const IR::Value& value); 116 [[nodiscard]] Id Def(const IR::Value& value);
108 117
118 [[nodiscard]] Id BitOffset8(const IR::Value& offset);
119 [[nodiscard]] Id BitOffset16(const IR::Value& offset);
120
109 Id Const(u32 value) { 121 Id Const(u32 value) {
110 return Constant(U32[1], value); 122 return Constant(U32[1], value);
111 } 123 }
@@ -139,6 +151,7 @@ public:
139 Id U64{}; 151 Id U64{};
140 VectorTypes F32; 152 VectorTypes F32;
141 VectorTypes U32; 153 VectorTypes U32;
154 VectorTypes S32;
142 VectorTypes F16; 155 VectorTypes F16;
143 VectorTypes F64; 156 VectorTypes F64;
144 157
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index 815b3cd95..0cb075670 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -368,7 +368,7 @@ void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
368} 368}
369} // Anonymous namespace 369} // Anonymous namespace
370 370
371std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, u32& binding) { 371std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, Bindings& binding) {
372 EmitContext ctx{profile, program, binding}; 372 EmitContext ctx{profile, program, binding};
373 const Id main{DefineMain(ctx, program)}; 373 const Id main{DefineMain(ctx, program)};
374 DefineEntryPoint(program, ctx, main); 374 DefineEntryPoint(program, ctx, main);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index c352bbd84..8f6482b7b 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -14,7 +14,7 @@
14namespace Shader::Backend::SPIRV { 14namespace Shader::Backend::SPIRV {
15 15
16[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, 16[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program,
17 u32& binding); 17 Bindings& binding);
18 18
19// Microinstruction emitters 19// Microinstruction emitters
20Id EmitPhi(EmitContext& ctx, IR::Inst* inst); 20Id EmitPhi(EmitContext& ctx, IR::Inst* inst);
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 29da2ef70..ef32184ea 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
@@ -121,7 +121,7 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
121} 121}
122 122
123Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size, 123Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size,
124 const IR::Value& binding, const IR::Value& offset) { 124 const IR::Value& binding, const IR::Value& offset, bool check_alignment = true) {
125 if (!binding.IsImmediate()) { 125 if (!binding.IsImmediate()) {
126 throw NotImplementedException("Constant buffer indexing"); 126 throw NotImplementedException("Constant buffer indexing");
127 } 127 }
@@ -137,13 +137,31 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr,
137 const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)}; 137 const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)};
138 return ctx.OpLoad(result_type, access_chain); 138 return ctx.OpLoad(result_type, access_chain);
139 } 139 }
140 if (offset.U32() % element_size != 0) { 140 if (check_alignment && offset.U32() % element_size != 0) {
141 throw NotImplementedException("Unaligned immediate constant buffer load"); 141 throw NotImplementedException("Unaligned immediate constant buffer load");
142 } 142 }
143 const Id imm_offset{ctx.Const(offset.U32() / element_size)}; 143 const Id imm_offset{ctx.Const(offset.U32() / element_size)};
144 const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, imm_offset)}; 144 const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, imm_offset)};
145 return ctx.OpLoad(result_type, access_chain); 145 return ctx.OpLoad(result_type, access_chain);
146} 146}
147
148Id GetCbufU32x4(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
149 return GetCbuf(ctx, ctx.U32[4], &UniformDefinitions::U32x4, sizeof(u32[4]), binding, offset,
150 false);
151}
152
153Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 index_offset) {
154 if (offset.IsImmediate()) {
155 const u32 element{(offset.U32() / 4) % 4 + index_offset};
156 return ctx.OpCompositeExtract(ctx.U32[1], vector, element);
157 }
158 const Id shift{ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), ctx.Const(2u))};
159 Id element{ctx.OpBitwiseAnd(ctx.U32[1], shift, ctx.Const(3u))};
160 if (index_offset > 0) {
161 element = ctx.OpIAdd(ctx.U32[1], element, ctx.Const(index_offset));
162 }
163 return ctx.OpVectorExtractDynamic(ctx.U32[1], vector, element);
164}
147} // Anonymous namespace 165} // Anonymous namespace
148 166
149void EmitGetRegister(EmitContext&) { 167void EmitGetRegister(EmitContext&) {
@@ -179,40 +197,86 @@ void EmitGetIndirectBranchVariable(EmitContext&) {
179} 197}
180 198
181Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 199Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
182 const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset)}; 200 if (ctx.profile.support_descriptor_aliasing) {
183 return ctx.OpUConvert(ctx.U32[1], load); 201 const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset)};
202 return ctx.OpUConvert(ctx.U32[1], load);
203 } else {
204 const Id vector{GetCbufU32x4(ctx, binding, offset)};
205 const Id element{GetCbufElement(ctx, vector, offset, 0u)};
206 const Id bit_offset{ctx.BitOffset8(offset)};
207 return ctx.OpBitFieldUExtract(ctx.U32[1], element, bit_offset, ctx.Const(8u));
208 }
184} 209}
185 210
186Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 211Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
187 const Id load{GetCbuf(ctx, ctx.S8, &UniformDefinitions::S8, sizeof(s8), binding, offset)}; 212 if (ctx.profile.support_descriptor_aliasing) {
188 return ctx.OpSConvert(ctx.U32[1], load); 213 const Id load{GetCbuf(ctx, ctx.S8, &UniformDefinitions::S8, sizeof(s8), binding, offset)};
214 return ctx.OpSConvert(ctx.U32[1], load);
215 } else {
216 const Id vector{GetCbufU32x4(ctx, binding, offset)};
217 const Id element{GetCbufElement(ctx, vector, offset, 0u)};
218 const Id bit_offset{ctx.BitOffset8(offset)};
219 return ctx.OpBitFieldSExtract(ctx.U32[1], element, bit_offset, ctx.Const(8u));
220 }
189} 221}
190 222
191Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 223Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
192 const Id load{GetCbuf(ctx, ctx.U16, &UniformDefinitions::U16, sizeof(u16), binding, offset)}; 224 if (ctx.profile.support_descriptor_aliasing) {
193 return ctx.OpUConvert(ctx.U32[1], load); 225 const Id load{
226 GetCbuf(ctx, ctx.U16, &UniformDefinitions::U16, sizeof(u16), binding, offset)};
227 return ctx.OpUConvert(ctx.U32[1], load);
228 } else {
229 const Id vector{GetCbufU32x4(ctx, binding, offset)};
230 const Id element{GetCbufElement(ctx, vector, offset, 0u)};
231 const Id bit_offset{ctx.BitOffset16(offset)};
232 return ctx.OpBitFieldUExtract(ctx.U32[1], element, bit_offset, ctx.Const(16u));
233 }
194} 234}
195 235
196Id EmitGetCbufS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 236Id EmitGetCbufS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
197 const Id load{GetCbuf(ctx, ctx.S16, &UniformDefinitions::S16, sizeof(s16), binding, offset)}; 237 if (ctx.profile.support_descriptor_aliasing) {
198 return ctx.OpSConvert(ctx.U32[1], load); 238 const Id load{
239 GetCbuf(ctx, ctx.S16, &UniformDefinitions::S16, sizeof(s16), binding, offset)};
240 return ctx.OpSConvert(ctx.U32[1], load);
241 } else {
242 const Id vector{GetCbufU32x4(ctx, binding, offset)};
243 const Id element{GetCbufElement(ctx, vector, offset, 0u)};
244 const Id bit_offset{ctx.BitOffset16(offset)};
245 return ctx.OpBitFieldSExtract(ctx.U32[1], element, bit_offset, ctx.Const(16u));
246 }
199} 247}
200 248
201Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 249Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
202 return GetCbuf(ctx, ctx.U32[1], &UniformDefinitions::U32, sizeof(u32), binding, offset); 250 if (ctx.profile.support_descriptor_aliasing) {
251 return GetCbuf(ctx, ctx.U32[1], &UniformDefinitions::U32, sizeof(u32), binding, offset);
252 } else {
253 const Id vector{GetCbufU32x4(ctx, binding, offset)};
254 return GetCbufElement(ctx, vector, offset, 0u);
255 }
203} 256}
204 257
205Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 258Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
206 return GetCbuf(ctx, ctx.F32[1], &UniformDefinitions::F32, sizeof(f32), binding, offset); 259 if (ctx.profile.support_descriptor_aliasing) {
260 return GetCbuf(ctx, ctx.F32[1], &UniformDefinitions::F32, sizeof(f32), binding, offset);
261 } else {
262 const Id vector{GetCbufU32x4(ctx, binding, offset)};
263 return ctx.OpBitcast(ctx.F32[1], GetCbufElement(ctx, vector, offset, 0u));
264 }
207} 265}
208 266
209Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 267Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
210 return GetCbuf(ctx, ctx.U32[2], &UniformDefinitions::U32x2, sizeof(u32[2]), binding, offset); 268 if (ctx.profile.support_descriptor_aliasing) {
269 return GetCbuf(ctx, ctx.U32[2], &UniformDefinitions::U32x2, sizeof(u32[2]), binding,
270 offset);
271 } else {
272 const Id vector{GetCbufU32x4(ctx, binding, offset)};
273 return ctx.OpCompositeConstruct(ctx.U32[2], GetCbufElement(ctx, vector, offset, 0u),
274 GetCbufElement(ctx, vector, offset, 1u));
275 }
211} 276}
212 277
213Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { 278Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
214 const u32 element{static_cast<u32>(attr) % 4}; 279 const u32 element{static_cast<u32>(attr) % 4};
215 const auto element_id{[&] { return ctx.Const(element); }};
216 if (IR::IsGeneric(attr)) { 280 if (IR::IsGeneric(attr)) {
217 const u32 index{IR::GenericAttributeIndex(attr)}; 281 const u32 index{IR::GenericAttributeIndex(attr)};
218 const std::optional<AttrInfo> type{AttrTypes(ctx, index)}; 282 const std::optional<AttrInfo> type{AttrTypes(ctx, index)};
@@ -221,7 +285,7 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
221 return ctx.Const(0.0f); 285 return ctx.Const(0.0f);
222 } 286 }
223 const Id generic_id{ctx.input_generics.at(index)}; 287 const Id generic_id{ctx.input_generics.at(index)};
224 const Id pointer{AttrPointer(ctx, type->pointer, vertex, generic_id, element_id())}; 288 const Id pointer{AttrPointer(ctx, type->pointer, vertex, generic_id, ctx.Const(element))};
225 const Id value{ctx.OpLoad(type->id, pointer)}; 289 const Id value{ctx.OpLoad(type->id, pointer)};
226 return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value; 290 return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value;
227 } 291 }
@@ -232,8 +296,8 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
232 case IR::Attribute::PositionY: 296 case IR::Attribute::PositionY:
233 case IR::Attribute::PositionZ: 297 case IR::Attribute::PositionZ:
234 case IR::Attribute::PositionW: 298 case IR::Attribute::PositionW:
235 return ctx.OpLoad( 299 return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position,
236 ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position, element_id())); 300 ctx.Const(element)));
237 case IR::Attribute::InstanceId: 301 case IR::Attribute::InstanceId:
238 if (ctx.profile.support_vertex_instance_id) { 302 if (ctx.profile.support_vertex_instance_id) {
239 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.instance_id)); 303 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.instance_id));