diff options
| author | 2021-05-23 03:58:11 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:29 -0400 | |
| commit | 48a17298d76cd8ed3bf2b53aca1e1ac097693976 (patch) | |
| tree | f0395bbe074b21c96d8a8bbe2ad9115dcbff92cf /src/shader_recompiler/backend | |
| parent | spirv: Desambiguate descriptor names (diff) | |
| download | yuzu-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')
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 | ||
| 444 | EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& binding) | 444 | EmitContext::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 | ||
| 497 | Id 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 | |||
| 504 | Id 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 | |||
| 492 | void EmitContext::DefineCommonTypes(const Info& info) { | 511 | void 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 | ||
| 18 | using Sirit::Id; | 18 | using Sirit::Id; |
| 19 | 19 | ||
| 20 | struct Bindings { | ||
| 21 | u32 unified{}; | ||
| 22 | u32 uniform_buffer{}; | ||
| 23 | u32 storage_buffer{}; | ||
| 24 | u32 texture{}; | ||
| 25 | u32 image{}; | ||
| 26 | }; | ||
| 27 | |||
| 20 | class VectorTypes { | 28 | class VectorTypes { |
| 21 | public: | 29 | public: |
| 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 | ||
| 67 | struct StorageTypeDefinition { | 76 | struct StorageTypeDefinition { |
| @@ -101,11 +110,14 @@ struct GenericElementInfo { | |||
| 101 | 110 | ||
| 102 | class EmitContext final : public Sirit::Module { | 111 | class EmitContext final : public Sirit::Module { |
| 103 | public: | 112 | public: |
| 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 | ||
| 371 | std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, u32& binding) { | 371 | std::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 @@ | |||
| 14 | namespace Shader::Backend::SPIRV { | 14 | namespace 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 |
| 20 | Id EmitPhi(EmitContext& ctx, IR::Inst* inst); | 20 | Id 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 | ||
| 123 | Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size, | 123 | Id 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 | |||
| 148 | Id 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 | |||
| 153 | Id 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 | ||
| 149 | void EmitGetRegister(EmitContext&) { | 167 | void EmitGetRegister(EmitContext&) { |
| @@ -179,40 +197,86 @@ void EmitGetIndirectBranchVariable(EmitContext&) { | |||
| 179 | } | 197 | } |
| 180 | 198 | ||
| 181 | Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 199 | Id 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 | ||
| 186 | Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 211 | Id 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 | ||
| 191 | Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 223 | Id 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 | ||
| 196 | Id EmitGetCbufS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 236 | Id 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 | ||
| 201 | Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 249 | Id 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 | ||
| 205 | Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 258 | Id 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 | ||
| 209 | Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 267 | Id 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 | ||
| 213 | Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { | 278 | Id 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)); |