diff options
| author | 2021-03-09 17:14:57 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:23 -0400 | |
| commit | 3a63fa0477ea8297c80133d35494e1dfdc012f95 (patch) | |
| tree | 3cd8b9be6f91cb1628b0d47513b7adb88df5f7b2 /src/shader_recompiler/backend/spirv | |
| parent | shader: Initial support for textures and TEX (diff) | |
| download | yuzu-3a63fa0477ea8297c80133d35494e1dfdc012f95.tar.gz yuzu-3a63fa0477ea8297c80133d35494e1dfdc012f95.tar.xz yuzu-3a63fa0477ea8297c80133d35494e1dfdc012f95.zip | |
shader: Partial implementation of LDC
Diffstat (limited to 'src/shader_recompiler/backend/spirv')
4 files changed, 124 insertions, 25 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 21900d387..278b26b50 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -104,15 +104,23 @@ void EmitContext::DefineCommonTypes(const Info& info) { | |||
| 104 | 104 | ||
| 105 | U1 = Name(TypeBool(), "u1"); | 105 | U1 = Name(TypeBool(), "u1"); |
| 106 | 106 | ||
| 107 | // TODO: Conditionally define these | ||
| 108 | AddCapability(spv::Capability::Int16); | ||
| 109 | AddCapability(spv::Capability::Int64); | ||
| 110 | U16 = Name(TypeInt(16, false), "u16"); | ||
| 111 | U64 = Name(TypeInt(64, false), "u64"); | ||
| 112 | |||
| 113 | F32.Define(*this, TypeFloat(32), "f32"); | 107 | F32.Define(*this, TypeFloat(32), "f32"); |
| 114 | U32.Define(*this, TypeInt(32, false), "u32"); | 108 | U32.Define(*this, TypeInt(32, false), "u32"); |
| 115 | 109 | ||
| 110 | if (info.uses_int8) { | ||
| 111 | AddCapability(spv::Capability::Int8); | ||
| 112 | U8 = Name(TypeInt(8, false), "u8"); | ||
| 113 | S8 = Name(TypeInt(8, true), "s8"); | ||
| 114 | } | ||
| 115 | if (info.uses_int16) { | ||
| 116 | AddCapability(spv::Capability::Int16); | ||
| 117 | U16 = Name(TypeInt(16, false), "u16"); | ||
| 118 | S16 = Name(TypeInt(16, true), "s16"); | ||
| 119 | } | ||
| 120 | if (info.uses_int64) { | ||
| 121 | AddCapability(spv::Capability::Int64); | ||
| 122 | U64 = Name(TypeInt(64, false), "u64"); | ||
| 123 | } | ||
| 116 | if (info.uses_fp16) { | 124 | if (info.uses_fp16) { |
| 117 | AddCapability(spv::Capability::Float16); | 125 | AddCapability(spv::Capability::Float16); |
| 118 | F16.Define(*this, TypeFloat(16), "f16"); | 126 | F16.Define(*this, TypeFloat(16), "f16"); |
| @@ -151,26 +159,51 @@ void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { | |||
| 151 | if (info.constant_buffer_descriptors.empty()) { | 159 | if (info.constant_buffer_descriptors.empty()) { |
| 152 | return; | 160 | return; |
| 153 | } | 161 | } |
| 154 | const Id array_type{TypeArray(U32[1], Constant(U32[1], 4096))}; | 162 | if (True(info.used_constant_buffer_types & IR::Type::U8)) { |
| 155 | Decorate(array_type, spv::Decoration::ArrayStride, 4U); | 163 | DefineConstantBuffers(info, &UniformDefinitions::U8, binding, U8, 'u', sizeof(u8)); |
| 164 | DefineConstantBuffers(info, &UniformDefinitions::S8, binding, S8, 's', sizeof(s8)); | ||
| 165 | } | ||
| 166 | if (True(info.used_constant_buffer_types & IR::Type::U16)) { | ||
| 167 | DefineConstantBuffers(info, &UniformDefinitions::U16, binding, U16, 'u', sizeof(u16)); | ||
| 168 | DefineConstantBuffers(info, &UniformDefinitions::S16, binding, S16, 's', sizeof(s16)); | ||
| 169 | } | ||
| 170 | if (True(info.used_constant_buffer_types & IR::Type::U32)) { | ||
| 171 | DefineConstantBuffers(info, &UniformDefinitions::U32, binding, U32[1], 'u', sizeof(u32)); | ||
| 172 | } | ||
| 173 | if (True(info.used_constant_buffer_types & IR::Type::F32)) { | ||
| 174 | DefineConstantBuffers(info, &UniformDefinitions::F32, binding, F32[1], 'f', sizeof(f32)); | ||
| 175 | } | ||
| 176 | if (True(info.used_constant_buffer_types & IR::Type::U64)) { | ||
| 177 | DefineConstantBuffers(info, &UniformDefinitions::U64, binding, U64, 'u', sizeof(u64)); | ||
| 178 | } | ||
| 179 | for (const ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) { | ||
| 180 | binding += desc.count; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | void EmitContext::DefineConstantBuffers(const Info& info, Id UniformDefinitions::*member_type, | ||
| 185 | u32 binding, Id type, char type_char, u32 element_size) { | ||
| 186 | const Id array_type{TypeArray(type, Constant(U32[1], 65536U / element_size))}; | ||
| 187 | Decorate(array_type, spv::Decoration::ArrayStride, element_size); | ||
| 156 | 188 | ||
| 157 | const Id struct_type{TypeStruct(array_type)}; | 189 | const Id struct_type{TypeStruct(array_type)}; |
| 158 | Name(struct_type, "cbuf_block"); | 190 | Name(struct_type, fmt::format("cbuf_block_{}{}", type_char, element_size * CHAR_BIT)); |
| 159 | Decorate(struct_type, spv::Decoration::Block); | 191 | Decorate(struct_type, spv::Decoration::Block); |
| 160 | MemberName(struct_type, 0, "data"); | 192 | MemberName(struct_type, 0, "data"); |
| 161 | MemberDecorate(struct_type, 0, spv::Decoration::Offset, 0U); | 193 | MemberDecorate(struct_type, 0, spv::Decoration::Offset, 0U); |
| 162 | 194 | ||
| 163 | const Id uniform_type{TypePointer(spv::StorageClass::Uniform, struct_type)}; | 195 | const Id struct_pointer_type{TypePointer(spv::StorageClass::Uniform, struct_type)}; |
| 164 | uniform_u32 = TypePointer(spv::StorageClass::Uniform, U32[1]); | 196 | const Id uniform_type{TypePointer(spv::StorageClass::Uniform, type)}; |
| 197 | uniform_types.*member_type = uniform_type; | ||
| 165 | 198 | ||
| 166 | u32 index{}; | ||
| 167 | for (const ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) { | 199 | for (const ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) { |
| 168 | const Id id{AddGlobalVariable(uniform_type, spv::StorageClass::Uniform)}; | 200 | const Id id{AddGlobalVariable(struct_pointer_type, spv::StorageClass::Uniform)}; |
| 169 | Decorate(id, spv::Decoration::Binding, binding); | 201 | Decorate(id, spv::Decoration::Binding, binding); |
| 170 | Decorate(id, spv::Decoration::DescriptorSet, 0U); | 202 | Decorate(id, spv::Decoration::DescriptorSet, 0U); |
| 171 | Name(id, fmt::format("c{}", desc.index)); | 203 | Name(id, fmt::format("c{}", desc.index)); |
| 172 | std::fill_n(cbufs.data() + desc.index, desc.count, id); | 204 | for (size_t i = 0; i < desc.count; ++i) { |
| 173 | index += desc.count; | 205 | cbufs[desc.index + i].*member_type = id; |
| 206 | } | ||
| 174 | binding += desc.count; | 207 | binding += desc.count; |
| 175 | } | 208 | } |
| 176 | } | 209 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h index 8b3109eb8..35eca258a 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.h +++ b/src/shader_recompiler/backend/spirv/emit_context.h | |||
| @@ -10,8 +10,8 @@ | |||
| 10 | #include <sirit/sirit.h> | 10 | #include <sirit/sirit.h> |
| 11 | 11 | ||
| 12 | #include "shader_recompiler/frontend/ir/program.h" | 12 | #include "shader_recompiler/frontend/ir/program.h" |
| 13 | #include "shader_recompiler/shader_info.h" | ||
| 14 | #include "shader_recompiler/profile.h" | 13 | #include "shader_recompiler/profile.h" |
| 14 | #include "shader_recompiler/shader_info.h" | ||
| 15 | 15 | ||
| 16 | namespace Shader::Backend::SPIRV { | 16 | namespace Shader::Backend::SPIRV { |
| 17 | 17 | ||
| @@ -34,6 +34,16 @@ struct TextureDefinition { | |||
| 34 | Id type; | 34 | Id type; |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | struct UniformDefinitions { | ||
| 38 | Id U8{}; | ||
| 39 | Id S8{}; | ||
| 40 | Id U16{}; | ||
| 41 | Id S16{}; | ||
| 42 | Id U32{}; | ||
| 43 | Id F32{}; | ||
| 44 | Id U64{}; | ||
| 45 | }; | ||
| 46 | |||
| 37 | class EmitContext final : public Sirit::Module { | 47 | class EmitContext final : public Sirit::Module { |
| 38 | public: | 48 | public: |
| 39 | explicit EmitContext(const Profile& profile, IR::Program& program); | 49 | explicit EmitContext(const Profile& profile, IR::Program& program); |
| @@ -45,7 +55,10 @@ public: | |||
| 45 | 55 | ||
| 46 | Id void_id{}; | 56 | Id void_id{}; |
| 47 | Id U1{}; | 57 | Id U1{}; |
| 58 | Id U8{}; | ||
| 59 | Id S8{}; | ||
| 48 | Id U16{}; | 60 | Id U16{}; |
| 61 | Id S16{}; | ||
| 49 | Id U64{}; | 62 | Id U64{}; |
| 50 | VectorTypes F32; | 63 | VectorTypes F32; |
| 51 | VectorTypes U32; | 64 | VectorTypes U32; |
| @@ -56,10 +69,11 @@ public: | |||
| 56 | Id false_value{}; | 69 | Id false_value{}; |
| 57 | Id u32_zero_value{}; | 70 | Id u32_zero_value{}; |
| 58 | 71 | ||
| 59 | Id uniform_u32{}; | 72 | UniformDefinitions uniform_types; |
| 73 | |||
| 60 | Id storage_u32{}; | 74 | Id storage_u32{}; |
| 61 | 75 | ||
| 62 | std::array<Id, Info::MAX_CBUFS> cbufs{}; | 76 | std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{}; |
| 63 | std::array<Id, Info::MAX_SSBOS> ssbos{}; | 77 | std::array<Id, Info::MAX_SSBOS> ssbos{}; |
| 64 | std::vector<TextureDefinition> textures; | 78 | std::vector<TextureDefinition> textures; |
| 65 | 79 | ||
| @@ -71,6 +85,8 @@ private: | |||
| 71 | void DefineCommonConstants(); | 85 | void DefineCommonConstants(); |
| 72 | void DefineSpecialVariables(const Info& info); | 86 | void DefineSpecialVariables(const Info& info); |
| 73 | void DefineConstantBuffers(const Info& info, u32& binding); | 87 | void DefineConstantBuffers(const Info& info, u32& binding); |
| 88 | void DefineConstantBuffers(const Info& info, Id UniformDefinitions::*member_type, u32 binding, | ||
| 89 | Id type, char type_char, u32 element_size); | ||
| 74 | void DefineStorageBuffers(const Info& info, u32& binding); | 90 | void DefineStorageBuffers(const Info& info, u32& binding); |
| 75 | void DefineTextures(const Info& info, u32& binding); | 91 | void DefineTextures(const Info& info, u32& binding); |
| 76 | void DefineLabels(IR::Program& program); | 92 | void DefineLabels(IR::Program& program); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 69698c478..aafc59bbb 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -34,7 +34,13 @@ void EmitGetPred(EmitContext& ctx); | |||
| 34 | void EmitSetPred(EmitContext& ctx); | 34 | void EmitSetPred(EmitContext& ctx); |
| 35 | void EmitSetGotoVariable(EmitContext& ctx); | 35 | void EmitSetGotoVariable(EmitContext& ctx); |
| 36 | void EmitGetGotoVariable(EmitContext& ctx); | 36 | void EmitGetGotoVariable(EmitContext& ctx); |
| 37 | Id EmitGetCbuf(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | 37 | Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); |
| 38 | Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | ||
| 39 | Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | ||
| 40 | Id EmitGetCbufS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | ||
| 41 | Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | ||
| 42 | Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | ||
| 43 | Id EmitGetCbufU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | ||
| 38 | void EmitGetAttribute(EmitContext& ctx); | 44 | void EmitGetAttribute(EmitContext& ctx); |
| 39 | void EmitSetAttribute(EmitContext& ctx); | 45 | void EmitSetAttribute(EmitContext& ctx); |
| 40 | void EmitGetAttributeIndexed(EmitContext& ctx); | 46 | void EmitGetAttributeIndexed(EmitContext& ctx); |
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 eb9c01c5a..125b58cf7 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 | |||
| @@ -30,17 +30,61 @@ void EmitGetGotoVariable(EmitContext&) { | |||
| 30 | throw NotImplementedException("SPIR-V Instruction"); | 30 | throw NotImplementedException("SPIR-V Instruction"); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | Id EmitGetCbuf(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 33 | static Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, |
| 34 | u32 element_size, const IR::Value& binding, const IR::Value& offset) { | ||
| 34 | if (!binding.IsImmediate()) { | 35 | if (!binding.IsImmediate()) { |
| 35 | throw NotImplementedException("Constant buffer indexing"); | 36 | throw NotImplementedException("Constant buffer indexing"); |
| 36 | } | 37 | } |
| 38 | const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr}; | ||
| 39 | const Id uniform_type{ctx.uniform_types.*member_ptr}; | ||
| 37 | if (!offset.IsImmediate()) { | 40 | if (!offset.IsImmediate()) { |
| 38 | throw NotImplementedException("Variable constant buffer offset"); | 41 | Id index{ctx.Def(offset)}; |
| 42 | if (element_size > 1) { | ||
| 43 | const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))}; | ||
| 44 | const Id shift{ctx.Constant(ctx.U32[1], log2_element_size)}; | ||
| 45 | index = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift); | ||
| 46 | } | ||
| 47 | const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)}; | ||
| 48 | return ctx.OpLoad(result_type, access_chain); | ||
| 39 | } | 49 | } |
| 40 | const Id imm_offset{ctx.Constant(ctx.U32[1], offset.U32() / 4)}; | 50 | if (offset.U32() % element_size != 0) { |
| 41 | const Id cbuf{ctx.cbufs[binding.U32()]}; | 51 | throw NotImplementedException("Unaligned immediate constant buffer load"); |
| 42 | const Id access_chain{ctx.OpAccessChain(ctx.uniform_u32, cbuf, ctx.u32_zero_value, imm_offset)}; | 52 | } |
| 43 | return ctx.OpLoad(ctx.U32[1], access_chain); | 53 | const Id imm_offset{ctx.Constant(ctx.U32[1], offset.U32() / element_size)}; |
| 54 | const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, imm_offset)}; | ||
| 55 | return ctx.OpLoad(result_type, access_chain); | ||
| 56 | } | ||
| 57 | |||
| 58 | Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | ||
| 59 | const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset)}; | ||
| 60 | return ctx.OpUConvert(ctx.U32[1], load); | ||
| 61 | } | ||
| 62 | |||
| 63 | Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | ||
| 64 | const Id load{GetCbuf(ctx, ctx.S8, &UniformDefinitions::S8, sizeof(s8), binding, offset)}; | ||
| 65 | return ctx.OpSConvert(ctx.U32[1], load); | ||
| 66 | } | ||
| 67 | |||
| 68 | Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | ||
| 69 | const Id load{GetCbuf(ctx, ctx.U16, &UniformDefinitions::U16, sizeof(u16), binding, offset)}; | ||
| 70 | return ctx.OpUConvert(ctx.U32[1], load); | ||
| 71 | } | ||
| 72 | |||
| 73 | Id EmitGetCbufS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | ||
| 74 | const Id load{GetCbuf(ctx, ctx.S16, &UniformDefinitions::S16, sizeof(s16), binding, offset)}; | ||
| 75 | return ctx.OpSConvert(ctx.U32[1], load); | ||
| 76 | } | ||
| 77 | |||
| 78 | Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | ||
| 79 | return GetCbuf(ctx, ctx.U32[1], &UniformDefinitions::U32, sizeof(u32), binding, offset); | ||
| 80 | } | ||
| 81 | |||
| 82 | Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | ||
| 83 | return GetCbuf(ctx, ctx.F32[1], &UniformDefinitions::F32, sizeof(f32), binding, offset); | ||
| 84 | } | ||
| 85 | |||
| 86 | Id EmitGetCbufU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | ||
| 87 | return GetCbuf(ctx, ctx.U64, &UniformDefinitions::U64, sizeof(u64), binding, offset); | ||
| 44 | } | 88 | } |
| 45 | 89 | ||
| 46 | void EmitGetAttribute(EmitContext&) { | 90 | void EmitGetAttribute(EmitContext&) { |