diff options
Diffstat (limited to 'src')
16 files changed, 405 insertions, 50 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index fa268d38f..755db5dfa 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -88,6 +88,7 @@ add_library(shader_recompiler STATIC | |||
| 88 | frontend/maxwell/translate/impl/integer_shift_right.cpp | 88 | frontend/maxwell/translate/impl/integer_shift_right.cpp |
| 89 | frontend/maxwell/translate/impl/integer_short_multiply_add.cpp | 89 | frontend/maxwell/translate/impl/integer_short_multiply_add.cpp |
| 90 | frontend/maxwell/translate/impl/integer_to_integer_conversion.cpp | 90 | frontend/maxwell/translate/impl/integer_to_integer_conversion.cpp |
| 91 | frontend/maxwell/translate/impl/load_constant.cpp | ||
| 91 | frontend/maxwell/translate/impl/load_effective_address.cpp | 92 | frontend/maxwell/translate/impl/load_effective_address.cpp |
| 92 | frontend/maxwell/translate/impl/load_store_attribute.cpp | 93 | frontend/maxwell/translate/impl/load_store_attribute.cpp |
| 93 | frontend/maxwell/translate/impl/load_store_memory.cpp | 94 | frontend/maxwell/translate/impl/load_store_memory.cpp |
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&) { |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index ae3354c66..33819dd36 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -112,7 +112,27 @@ void IREmitter::SetPred(IR::Pred pred, const U1& value) { | |||
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) { | 114 | U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) { |
| 115 | return Inst<U32>(Opcode::GetCbuf, binding, byte_offset); | 115 | return Inst<U32>(Opcode::GetCbufU32, binding, byte_offset); |
| 116 | } | ||
| 117 | |||
| 118 | UAny IREmitter::GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize, | ||
| 119 | bool is_signed) { | ||
| 120 | switch (bitsize) { | ||
| 121 | case 8: | ||
| 122 | return Inst<U32>(is_signed ? Opcode::GetCbufS8 : Opcode::GetCbufU8, binding, byte_offset); | ||
| 123 | case 16: | ||
| 124 | return Inst<U32>(is_signed ? Opcode::GetCbufS16 : Opcode::GetCbufU16, binding, byte_offset); | ||
| 125 | case 32: | ||
| 126 | return Inst<U32>(Opcode::GetCbufU32, binding, byte_offset); | ||
| 127 | case 64: | ||
| 128 | return Inst<U64>(Opcode::GetCbufU64, binding, byte_offset); | ||
| 129 | default: | ||
| 130 | throw InvalidArgument("Invalid bit size {}", bitsize); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | F32 IREmitter::GetFloatCbuf(const U32& binding, const U32& byte_offset) { | ||
| 135 | return Inst<F32>(Opcode::GetCbufF32, binding, byte_offset); | ||
| 116 | } | 136 | } |
| 117 | 137 | ||
| 118 | U1 IREmitter::GetZFlag() { | 138 | U1 IREmitter::GetZFlag() { |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index cb2a7710a..e4d110540 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -47,6 +47,9 @@ public: | |||
| 47 | void SetGotoVariable(u32 id, const U1& value); | 47 | void SetGotoVariable(u32 id, const U1& value); |
| 48 | 48 | ||
| 49 | [[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset); | 49 | [[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset); |
| 50 | [[nodiscard]] UAny GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize, | ||
| 51 | bool is_signed); | ||
| 52 | [[nodiscard]] F32 GetFloatCbuf(const U32& binding, const U32& byte_offset); | ||
| 50 | 53 | ||
| 51 | [[nodiscard]] U1 GetZFlag(); | 54 | [[nodiscard]] U1 GetZFlag(); |
| 52 | [[nodiscard]] U1 GetSFlag(); | 55 | [[nodiscard]] U1 GetSFlag(); |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index aa011fab1..64bd495ed 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -21,7 +21,13 @@ OPCODE(GetPred, U1, Pred | |||
| 21 | OPCODE(SetPred, Void, Pred, U1, ) | 21 | OPCODE(SetPred, Void, Pred, U1, ) |
| 22 | OPCODE(GetGotoVariable, U1, U32, ) | 22 | OPCODE(GetGotoVariable, U1, U32, ) |
| 23 | OPCODE(SetGotoVariable, Void, U32, U1, ) | 23 | OPCODE(SetGotoVariable, Void, U32, U1, ) |
| 24 | OPCODE(GetCbuf, U32, U32, U32, ) | 24 | OPCODE(GetCbufU8, U32, U32, U32, ) |
| 25 | OPCODE(GetCbufS8, U32, U32, U32, ) | ||
| 26 | OPCODE(GetCbufU16, U32, U32, U32, ) | ||
| 27 | OPCODE(GetCbufS16, U32, U32, U32, ) | ||
| 28 | OPCODE(GetCbufU32, U32, U32, U32, ) | ||
| 29 | OPCODE(GetCbufF32, F32, U32, U32, ) | ||
| 30 | OPCODE(GetCbufU64, U64, U32, U32, ) | ||
| 25 | OPCODE(GetAttribute, U32, Attribute, ) | 31 | OPCODE(GetAttribute, U32, Attribute, ) |
| 26 | OPCODE(SetAttribute, Void, Attribute, U32, ) | 32 | OPCODE(SetAttribute, Void, Attribute, U32, ) |
| 27 | OPCODE(GetAttributeIndexed, U32, U32, ) | 33 | OPCODE(GetAttributeIndexed, U32, U32, ) |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp index a5a0e1a9b..7564aeeb2 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp | |||
| @@ -56,25 +56,32 @@ IR::F32 TranslatorVisitor::GetFloatReg39(u64 insn) { | |||
| 56 | return ir.BitCast<IR::F32>(GetReg39(insn)); | 56 | return ir.BitCast<IR::F32>(GetReg39(insn)); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | IR::U32 TranslatorVisitor::GetCbuf(u64 insn) { | 59 | static std::pair<IR::U32, IR::U32> CbufAddr(u64 insn) { |
| 60 | union { | 60 | union { |
| 61 | u64 raw; | 61 | u64 raw; |
| 62 | BitField<20, 14, s64> offset; | 62 | BitField<20, 14, s64> offset; |
| 63 | BitField<34, 5, u64> binding; | 63 | BitField<34, 5, u64> binding; |
| 64 | } const cbuf{insn}; | 64 | } const cbuf{insn}; |
| 65 | |||
| 65 | if (cbuf.binding >= 18) { | 66 | if (cbuf.binding >= 18) { |
| 66 | throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding); | 67 | throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding); |
| 67 | } | 68 | } |
| 68 | if (cbuf.offset >= 0x10'000 || cbuf.offset < 0) { | 69 | if (cbuf.offset >= 0x10'000 || cbuf.offset < 0) { |
| 69 | throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset); | 70 | throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset); |
| 70 | } | 71 | } |
| 71 | const IR::U32 binding{ir.Imm32(static_cast<u32>(cbuf.binding))}; | 72 | const IR::Value binding{static_cast<u32>(cbuf.binding)}; |
| 72 | const IR::U32 byte_offset{ir.Imm32(static_cast<u32>(cbuf.offset) * 4)}; | 73 | const IR::Value byte_offset{static_cast<u32>(cbuf.offset) * 4}; |
| 74 | return {IR::U32{binding}, IR::U32{byte_offset}}; | ||
| 75 | } | ||
| 76 | |||
| 77 | IR::U32 TranslatorVisitor::GetCbuf(u64 insn) { | ||
| 78 | const auto[binding, byte_offset]{CbufAddr(insn)}; | ||
| 73 | return ir.GetCbuf(binding, byte_offset); | 79 | return ir.GetCbuf(binding, byte_offset); |
| 74 | } | 80 | } |
| 75 | 81 | ||
| 76 | IR::F32 TranslatorVisitor::GetFloatCbuf(u64 insn) { | 82 | IR::F32 TranslatorVisitor::GetFloatCbuf(u64 insn) { |
| 77 | return ir.BitCast<IR::F32>(GetCbuf(insn)); | 83 | const auto[binding, byte_offset]{CbufAddr(insn)}; |
| 84 | return ir.GetFloatCbuf(binding, byte_offset); | ||
| 78 | } | 85 | } |
| 79 | 86 | ||
| 80 | IR::U32 TranslatorVisitor::GetImm20(u64 insn) { | 87 | IR::U32 TranslatorVisitor::GetImm20(u64 insn) { |
| @@ -83,6 +90,7 @@ IR::U32 TranslatorVisitor::GetImm20(u64 insn) { | |||
| 83 | BitField<20, 19, u64> value; | 90 | BitField<20, 19, u64> value; |
| 84 | BitField<56, 1, u64> is_negative; | 91 | BitField<56, 1, u64> is_negative; |
| 85 | } const imm{insn}; | 92 | } const imm{insn}; |
| 93 | |||
| 86 | if (imm.is_negative != 0) { | 94 | if (imm.is_negative != 0) { |
| 87 | const s64 raw{static_cast<s64>(imm.value)}; | 95 | const s64 raw{static_cast<s64>(imm.value)}; |
| 88 | return ir.Imm32(static_cast<s32>(-(1LL << 19) + raw)); | 96 | return ir.Imm32(static_cast<s32>(-(1LL << 19) + raw)); |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_constant.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_constant.cpp new file mode 100644 index 000000000..39becf93c --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_constant.cpp | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/bit_field.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 8 | |||
| 9 | namespace Shader::Maxwell { | ||
| 10 | namespace { | ||
| 11 | enum class Mode : u64 { | ||
| 12 | Default, | ||
| 13 | IL, | ||
| 14 | IS, | ||
| 15 | ISL, | ||
| 16 | }; | ||
| 17 | |||
| 18 | enum class Size : u64 { | ||
| 19 | U8, | ||
| 20 | S8, | ||
| 21 | U16, | ||
| 22 | S16, | ||
| 23 | B32, | ||
| 24 | B64, | ||
| 25 | }; | ||
| 26 | |||
| 27 | std::pair<IR::U32, IR::U32> Slot(IR::IREmitter& ir, Mode mode, const IR::U32& imm_index, | ||
| 28 | const IR::U32& reg, const IR::U32& imm) { | ||
| 29 | switch (mode) { | ||
| 30 | case Mode::Default: | ||
| 31 | return {imm_index, ir.IAdd(reg, imm)}; | ||
| 32 | default: | ||
| 33 | break; | ||
| 34 | } | ||
| 35 | throw NotImplementedException("Mode {}", mode); | ||
| 36 | } | ||
| 37 | } // Anonymous namespace | ||
| 38 | |||
| 39 | void TranslatorVisitor::LDC(u64 insn) { | ||
| 40 | union { | ||
| 41 | u64 raw; | ||
| 42 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 43 | BitField<8, 8, IR::Reg> src_reg; | ||
| 44 | BitField<20, 16, s64> offset; | ||
| 45 | BitField<36, 5, u64> index; | ||
| 46 | BitField<44, 2, Mode> mode; | ||
| 47 | BitField<48, 3, Size> size; | ||
| 48 | } const ldc{insn}; | ||
| 49 | |||
| 50 | const IR::U32 imm_index{ir.Imm32(static_cast<u32>(ldc.index))}; | ||
| 51 | const IR::U32 reg{X(ldc.src_reg)}; | ||
| 52 | const IR::U32 imm{ir.Imm32(static_cast<s32>(ldc.offset))}; | ||
| 53 | const auto [index, offset]{Slot(ir, ldc.mode, imm_index, reg, imm)}; | ||
| 54 | switch (ldc.size) { | ||
| 55 | case Size::U8: | ||
| 56 | X(ldc.dest_reg, ir.GetCbuf(index, offset, 8, false)); | ||
| 57 | break; | ||
| 58 | case Size::S8: | ||
| 59 | X(ldc.dest_reg, ir.GetCbuf(index, offset, 8, true)); | ||
| 60 | break; | ||
| 61 | case Size::U16: | ||
| 62 | X(ldc.dest_reg, ir.GetCbuf(index, offset, 16, false)); | ||
| 63 | break; | ||
| 64 | case Size::S16: | ||
| 65 | X(ldc.dest_reg, ir.GetCbuf(index, offset, 16, true)); | ||
| 66 | break; | ||
| 67 | case Size::B32: | ||
| 68 | X(ldc.dest_reg, ir.GetCbuf(index, offset, 32, false)); | ||
| 69 | break; | ||
| 70 | case Size::B64: { | ||
| 71 | if (!IR::IsAligned(ldc.dest_reg, 2)) { | ||
| 72 | throw NotImplementedException("Unaligned destination register"); | ||
| 73 | } | ||
| 74 | const IR::Value vector{ir.UnpackUint2x32(ir.GetCbuf(index, offset, 64, false))}; | ||
| 75 | for (int i = 0; i < 2; ++i) { | ||
| 76 | X(ldc.dest_reg + i, IR::U32{ir.CompositeExtract(vector, i)}); | ||
| 77 | } | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | default: | ||
| 81 | throw NotImplementedException("Invalid size {}", ldc.size.Value()); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp index ff429c126..5b153acff 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -425,10 +425,6 @@ void TranslatorVisitor::LD(u64) { | |||
| 425 | ThrowNotImplemented(Opcode::LD); | 425 | ThrowNotImplemented(Opcode::LD); |
| 426 | } | 426 | } |
| 427 | 427 | ||
| 428 | void TranslatorVisitor::LDC(u64) { | ||
| 429 | ThrowNotImplemented(Opcode::LDC); | ||
| 430 | } | ||
| 431 | |||
| 432 | void TranslatorVisitor::LDL(u64) { | 428 | void TranslatorVisitor::LDL(u64) { |
| 433 | ThrowNotImplemented(Opcode::LDL); | 429 | ThrowNotImplemented(Opcode::LDL); |
| 434 | } | 430 | } |
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 960beadd4..cdbe85221 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -25,18 +25,13 @@ void AddConstantBufferDescriptor(Info& info, u32 index, u32 count) { | |||
| 25 | 25 | ||
| 26 | void VisitUsages(Info& info, IR::Inst& inst) { | 26 | void VisitUsages(Info& info, IR::Inst& inst) { |
| 27 | switch (inst.Opcode()) { | 27 | switch (inst.Opcode()) { |
| 28 | case IR::Opcode::WorkgroupId: | ||
| 29 | info.uses_workgroup_id = true; | ||
| 30 | break; | ||
| 31 | case IR::Opcode::LocalInvocationId: | ||
| 32 | info.uses_local_invocation_id = true; | ||
| 33 | break; | ||
| 34 | case IR::Opcode::CompositeConstructF16x2: | 28 | case IR::Opcode::CompositeConstructF16x2: |
| 35 | case IR::Opcode::CompositeConstructF16x3: | 29 | case IR::Opcode::CompositeConstructF16x3: |
| 36 | case IR::Opcode::CompositeConstructF16x4: | 30 | case IR::Opcode::CompositeConstructF16x4: |
| 37 | case IR::Opcode::CompositeExtractF16x2: | 31 | case IR::Opcode::CompositeExtractF16x2: |
| 38 | case IR::Opcode::CompositeExtractF16x3: | 32 | case IR::Opcode::CompositeExtractF16x3: |
| 39 | case IR::Opcode::CompositeExtractF16x4: | 33 | case IR::Opcode::CompositeExtractF16x4: |
| 34 | case IR::Opcode::SelectF16: | ||
| 40 | case IR::Opcode::BitCastU16F16: | 35 | case IR::Opcode::BitCastU16F16: |
| 41 | case IR::Opcode::BitCastF16U16: | 36 | case IR::Opcode::BitCastF16U16: |
| 42 | case IR::Opcode::PackFloat2x16: | 37 | case IR::Opcode::PackFloat2x16: |
| @@ -75,13 +70,139 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 75 | case IR::Opcode::FPTrunc64: | 70 | case IR::Opcode::FPTrunc64: |
| 76 | info.uses_fp64 = true; | 71 | info.uses_fp64 = true; |
| 77 | break; | 72 | break; |
| 78 | case IR::Opcode::GetCbuf: | 73 | default: |
| 74 | break; | ||
| 75 | } | ||
| 76 | switch (inst.Opcode()) { | ||
| 77 | case IR::Opcode::GetCbufU8: | ||
| 78 | case IR::Opcode::GetCbufS8: | ||
| 79 | case IR::Opcode::UndefU8: | ||
| 80 | case IR::Opcode::LoadGlobalU8: | ||
| 81 | case IR::Opcode::LoadGlobalS8: | ||
| 82 | case IR::Opcode::WriteGlobalU8: | ||
| 83 | case IR::Opcode::WriteGlobalS8: | ||
| 84 | case IR::Opcode::LoadStorageU8: | ||
| 85 | case IR::Opcode::LoadStorageS8: | ||
| 86 | case IR::Opcode::WriteStorageU8: | ||
| 87 | case IR::Opcode::WriteStorageS8: | ||
| 88 | case IR::Opcode::SelectU8: | ||
| 89 | info.uses_int8 = true; | ||
| 90 | break; | ||
| 91 | default: | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | switch (inst.Opcode()) { | ||
| 95 | case IR::Opcode::GetCbufU16: | ||
| 96 | case IR::Opcode::GetCbufS16: | ||
| 97 | case IR::Opcode::UndefU16: | ||
| 98 | case IR::Opcode::LoadGlobalU16: | ||
| 99 | case IR::Opcode::LoadGlobalS16: | ||
| 100 | case IR::Opcode::WriteGlobalU16: | ||
| 101 | case IR::Opcode::WriteGlobalS16: | ||
| 102 | case IR::Opcode::LoadStorageU16: | ||
| 103 | case IR::Opcode::LoadStorageS16: | ||
| 104 | case IR::Opcode::WriteStorageU16: | ||
| 105 | case IR::Opcode::WriteStorageS16: | ||
| 106 | case IR::Opcode::SelectU16: | ||
| 107 | case IR::Opcode::BitCastU16F16: | ||
| 108 | case IR::Opcode::BitCastF16U16: | ||
| 109 | case IR::Opcode::ConvertS16F16: | ||
| 110 | case IR::Opcode::ConvertS16F32: | ||
| 111 | case IR::Opcode::ConvertS16F64: | ||
| 112 | case IR::Opcode::ConvertU16F16: | ||
| 113 | case IR::Opcode::ConvertU16F32: | ||
| 114 | case IR::Opcode::ConvertU16F64: | ||
| 115 | info.uses_int16 = true; | ||
| 116 | break; | ||
| 117 | default: | ||
| 118 | break; | ||
| 119 | } | ||
| 120 | switch (inst.Opcode()) { | ||
| 121 | case IR::Opcode::GetCbufU64: | ||
| 122 | case IR::Opcode::UndefU64: | ||
| 123 | case IR::Opcode::LoadGlobalU8: | ||
| 124 | case IR::Opcode::LoadGlobalS8: | ||
| 125 | case IR::Opcode::LoadGlobalU16: | ||
| 126 | case IR::Opcode::LoadGlobalS16: | ||
| 127 | case IR::Opcode::LoadGlobal32: | ||
| 128 | case IR::Opcode::LoadGlobal64: | ||
| 129 | case IR::Opcode::LoadGlobal128: | ||
| 130 | case IR::Opcode::WriteGlobalU8: | ||
| 131 | case IR::Opcode::WriteGlobalS8: | ||
| 132 | case IR::Opcode::WriteGlobalU16: | ||
| 133 | case IR::Opcode::WriteGlobalS16: | ||
| 134 | case IR::Opcode::WriteGlobal32: | ||
| 135 | case IR::Opcode::WriteGlobal64: | ||
| 136 | case IR::Opcode::WriteGlobal128: | ||
| 137 | case IR::Opcode::SelectU64: | ||
| 138 | case IR::Opcode::BitCastU64F64: | ||
| 139 | case IR::Opcode::BitCastF64U64: | ||
| 140 | case IR::Opcode::PackUint2x32: | ||
| 141 | case IR::Opcode::UnpackUint2x32: | ||
| 142 | case IR::Opcode::IAdd64: | ||
| 143 | case IR::Opcode::ISub64: | ||
| 144 | case IR::Opcode::INeg64: | ||
| 145 | case IR::Opcode::ShiftLeftLogical64: | ||
| 146 | case IR::Opcode::ShiftRightLogical64: | ||
| 147 | case IR::Opcode::ShiftRightArithmetic64: | ||
| 148 | case IR::Opcode::ConvertS64F16: | ||
| 149 | case IR::Opcode::ConvertS64F32: | ||
| 150 | case IR::Opcode::ConvertS64F64: | ||
| 151 | case IR::Opcode::ConvertU64F16: | ||
| 152 | case IR::Opcode::ConvertU64F32: | ||
| 153 | case IR::Opcode::ConvertU64F64: | ||
| 154 | case IR::Opcode::ConvertU64U32: | ||
| 155 | case IR::Opcode::ConvertU32U64: | ||
| 156 | case IR::Opcode::ConvertF16U64: | ||
| 157 | case IR::Opcode::ConvertF32U64: | ||
| 158 | case IR::Opcode::ConvertF64U64: | ||
| 159 | info.uses_int64 = true; | ||
| 160 | break; | ||
| 161 | default: | ||
| 162 | break; | ||
| 163 | } | ||
| 164 | switch (inst.Opcode()) { | ||
| 165 | case IR::Opcode::WorkgroupId: | ||
| 166 | info.uses_workgroup_id = true; | ||
| 167 | break; | ||
| 168 | case IR::Opcode::LocalInvocationId: | ||
| 169 | info.uses_local_invocation_id = true; | ||
| 170 | break; | ||
| 171 | case IR::Opcode::GetCbufU8: | ||
| 172 | case IR::Opcode::GetCbufS8: | ||
| 173 | case IR::Opcode::GetCbufU16: | ||
| 174 | case IR::Opcode::GetCbufS16: | ||
| 175 | case IR::Opcode::GetCbufU32: | ||
| 176 | case IR::Opcode::GetCbufF32: | ||
| 177 | case IR::Opcode::GetCbufU64: { | ||
| 79 | if (const IR::Value index{inst.Arg(0)}; index.IsImmediate()) { | 178 | if (const IR::Value index{inst.Arg(0)}; index.IsImmediate()) { |
| 80 | AddConstantBufferDescriptor(info, index.U32(), 1); | 179 | AddConstantBufferDescriptor(info, index.U32(), 1); |
| 81 | } else { | 180 | } else { |
| 82 | throw NotImplementedException("Constant buffer with non-immediate index"); | 181 | throw NotImplementedException("Constant buffer with non-immediate index"); |
| 83 | } | 182 | } |
| 183 | switch (inst.Opcode()) { | ||
| 184 | case IR::Opcode::GetCbufU8: | ||
| 185 | case IR::Opcode::GetCbufS8: | ||
| 186 | info.used_constant_buffer_types |= IR::Type::U8; | ||
| 187 | break; | ||
| 188 | case IR::Opcode::GetCbufU16: | ||
| 189 | case IR::Opcode::GetCbufS16: | ||
| 190 | info.used_constant_buffer_types |= IR::Type::U16; | ||
| 191 | break; | ||
| 192 | case IR::Opcode::GetCbufU32: | ||
| 193 | info.used_constant_buffer_types |= IR::Type::U32; | ||
| 194 | break; | ||
| 195 | case IR::Opcode::GetCbufF32: | ||
| 196 | info.used_constant_buffer_types |= IR::Type::F32; | ||
| 197 | break; | ||
| 198 | case IR::Opcode::GetCbufU64: | ||
| 199 | info.used_constant_buffer_types |= IR::Type::U64; | ||
| 200 | break; | ||
| 201 | default: | ||
| 202 | break; | ||
| 203 | } | ||
| 84 | break; | 204 | break; |
| 205 | } | ||
| 85 | case IR::Opcode::BindlessImageSampleImplicitLod: | 206 | case IR::Opcode::BindlessImageSampleImplicitLod: |
| 86 | case IR::Opcode::BindlessImageSampleExplicitLod: | 207 | case IR::Opcode::BindlessImageSampleExplicitLod: |
| 87 | case IR::Opcode::BindlessImageSampleDrefImplicitLod: | 208 | case IR::Opcode::BindlessImageSampleDrefImplicitLod: |
diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp index ae3d5a7d6..7ba9ebe9b 100644 --- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp +++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp | |||
| @@ -193,7 +193,7 @@ void FoldISub32(IR::Inst& inst) { | |||
| 193 | // ISub32 is generally used to subtract two constant buffers, compare and replace this with | 193 | // ISub32 is generally used to subtract two constant buffers, compare and replace this with |
| 194 | // zero if they equal. | 194 | // zero if they equal. |
| 195 | const auto equal_cbuf{[](IR::Inst* a, IR::Inst* b) { | 195 | const auto equal_cbuf{[](IR::Inst* a, IR::Inst* b) { |
| 196 | return a->Opcode() == IR::Opcode::GetCbuf && b->Opcode() == IR::Opcode::GetCbuf && | 196 | return a->Opcode() == IR::Opcode::GetCbufU32 && b->Opcode() == IR::Opcode::GetCbufU32 && |
| 197 | a->Arg(0) == b->Arg(0) && a->Arg(1) == b->Arg(1); | 197 | a->Arg(0) == b->Arg(0) && a->Arg(1) == b->Arg(1); |
| 198 | }}; | 198 | }}; |
| 199 | IR::Inst* op_a{inst.Arg(0).InstRecursive()}; | 199 | IR::Inst* op_a{inst.Arg(0).InstRecursive()}; |
| @@ -207,7 +207,7 @@ void FoldISub32(IR::Inst& inst) { | |||
| 207 | // Canonicalize local variables to simplify the following logic | 207 | // Canonicalize local variables to simplify the following logic |
| 208 | std::swap(op_a, op_b); | 208 | std::swap(op_a, op_b); |
| 209 | } | 209 | } |
| 210 | if (op_b->Opcode() != IR::Opcode::GetCbuf) { | 210 | if (op_b->Opcode() != IR::Opcode::GetCbufU32) { |
| 211 | return; | 211 | return; |
| 212 | } | 212 | } |
| 213 | IR::Inst* const inst_cbuf{op_b}; | 213 | IR::Inst* const inst_cbuf{op_b}; |
| @@ -277,7 +277,7 @@ void FoldLogicalNot(IR::Inst& inst) { | |||
| 277 | } | 277 | } |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | template <typename Dest, typename Source> | 280 | template <IR::Opcode op, typename Dest, typename Source> |
| 281 | void FoldBitCast(IR::Inst& inst, IR::Opcode reverse) { | 281 | void FoldBitCast(IR::Inst& inst, IR::Opcode reverse) { |
| 282 | const IR::Value value{inst.Arg(0)}; | 282 | const IR::Value value{inst.Arg(0)}; |
| 283 | if (value.IsImmediate()) { | 283 | if (value.IsImmediate()) { |
| @@ -285,8 +285,18 @@ void FoldBitCast(IR::Inst& inst, IR::Opcode reverse) { | |||
| 285 | return; | 285 | return; |
| 286 | } | 286 | } |
| 287 | IR::Inst* const arg_inst{value.InstRecursive()}; | 287 | IR::Inst* const arg_inst{value.InstRecursive()}; |
| 288 | if (value.InstRecursive()->Opcode() == reverse) { | 288 | if (arg_inst->Opcode() == reverse) { |
| 289 | inst.ReplaceUsesWith(arg_inst->Arg(0)); | 289 | inst.ReplaceUsesWith(arg_inst->Arg(0)); |
| 290 | return; | ||
| 291 | } | ||
| 292 | if constexpr (op == IR::Opcode::BitCastF32U32) { | ||
| 293 | if (arg_inst->Opcode() == IR::Opcode::GetCbufU32) { | ||
| 294 | // Replace the bitcast with a typed constant buffer read | ||
| 295 | inst.ReplaceOpcode(IR::Opcode::GetCbufF32); | ||
| 296 | inst.SetArg(0, arg_inst->Arg(0)); | ||
| 297 | inst.SetArg(1, arg_inst->Arg(1)); | ||
| 298 | return; | ||
| 299 | } | ||
| 290 | } | 300 | } |
| 291 | } | 301 | } |
| 292 | 302 | ||
| @@ -325,9 +335,9 @@ void ConstantPropagation(IR::Block& block, IR::Inst& inst) { | |||
| 325 | case IR::Opcode::ISub32: | 335 | case IR::Opcode::ISub32: |
| 326 | return FoldISub32(inst); | 336 | return FoldISub32(inst); |
| 327 | case IR::Opcode::BitCastF32U32: | 337 | case IR::Opcode::BitCastF32U32: |
| 328 | return FoldBitCast<f32, u32>(inst, IR::Opcode::BitCastU32F32); | 338 | return FoldBitCast<IR::Opcode::BitCastF32U32, f32, u32>(inst, IR::Opcode::BitCastU32F32); |
| 329 | case IR::Opcode::BitCastU32F32: | 339 | case IR::Opcode::BitCastU32F32: |
| 330 | return FoldBitCast<u32, f32>(inst, IR::Opcode::BitCastF32U32); | 340 | return FoldBitCast<IR::Opcode::BitCastU32F32, u32, f32>(inst, IR::Opcode::BitCastF32U32); |
| 331 | case IR::Opcode::IAdd64: | 341 | case IR::Opcode::IAdd64: |
| 332 | return FoldAdd<u64>(block, inst); | 342 | return FoldAdd<u64>(block, inst); |
| 333 | case IR::Opcode::SelectU32: | 343 | case IR::Opcode::SelectU32: |
diff --git a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp index 2625c0bb2..5d98d278e 100644 --- a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp +++ b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp | |||
| @@ -203,7 +203,7 @@ std::optional<StorageBufferAddr> Track(IR::Block* block, const IR::Value& value, | |||
| 203 | return std::nullopt; | 203 | return std::nullopt; |
| 204 | } | 204 | } |
| 205 | const IR::Inst* const inst{value.InstRecursive()}; | 205 | const IR::Inst* const inst{value.InstRecursive()}; |
| 206 | if (inst->Opcode() == IR::Opcode::GetCbuf) { | 206 | if (inst->Opcode() == IR::Opcode::GetCbufU32) { |
| 207 | const IR::Value index{inst->Arg(0)}; | 207 | const IR::Value index{inst->Arg(0)}; |
| 208 | const IR::Value offset{inst->Arg(1)}; | 208 | const IR::Value offset{inst->Arg(1)}; |
| 209 | if (!index.IsImmediate()) { | 209 | if (!index.IsImmediate()) { |
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index 80e4ad6a9..ec802e02c 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -78,7 +78,7 @@ std::optional<ConstBufferAddr> Track(IR::Block* block, const IR::Value& value, | |||
| 78 | return std::nullopt; | 78 | return std::nullopt; |
| 79 | } | 79 | } |
| 80 | const IR::Inst* const inst{value.InstRecursive()}; | 80 | const IR::Inst* const inst{value.InstRecursive()}; |
| 81 | if (inst->Opcode() == IR::Opcode::GetCbuf) { | 81 | if (inst->Opcode() == IR::Opcode::GetCbufU32) { |
| 82 | const IR::Value index{inst->Arg(0)}; | 82 | const IR::Value index{inst->Arg(0)}; |
| 83 | const IR::Value offset{inst->Arg(1)}; | 83 | const IR::Value offset{inst->Arg(1)}; |
| 84 | if (!index.IsImmediate()) { | 84 | if (!index.IsImmediate()) { |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 103a2f0b4..adc1d9a64 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "shader_recompiler/frontend/ir/type.h" | ||
| 10 | 11 | ||
| 11 | #include <boost/container/small_vector.hpp> | 12 | #include <boost/container/small_vector.hpp> |
| 12 | #include <boost/container/static_vector.hpp> | 13 | #include <boost/container/static_vector.hpp> |
| @@ -61,10 +62,15 @@ struct Info { | |||
| 61 | bool uses_fp16_denorms_preserve{}; | 62 | bool uses_fp16_denorms_preserve{}; |
| 62 | bool uses_fp32_denorms_flush{}; | 63 | bool uses_fp32_denorms_flush{}; |
| 63 | bool uses_fp32_denorms_preserve{}; | 64 | bool uses_fp32_denorms_preserve{}; |
| 65 | bool uses_int8{}; | ||
| 66 | bool uses_int16{}; | ||
| 67 | bool uses_int64{}; | ||
| 64 | bool uses_image_1d{}; | 68 | bool uses_image_1d{}; |
| 65 | bool uses_sampled_1d{}; | 69 | bool uses_sampled_1d{}; |
| 66 | bool uses_sparse_residency{}; | 70 | bool uses_sparse_residency{}; |
| 67 | 71 | ||
| 72 | IR::Type used_constant_buffer_types{}; | ||
| 73 | |||
| 68 | u32 constant_buffer_mask{}; | 74 | u32 constant_buffer_mask{}; |
| 69 | 75 | ||
| 70 | boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> | 76 | boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> |