diff options
Diffstat (limited to 'src')
12 files changed, 279 insertions, 35 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 002b305dc..eadecb064 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -82,6 +82,28 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) { | |||
| 82 | } | 82 | } |
| 83 | throw InvalidArgument("Invalid attribute type {}", type); | 83 | throw InvalidArgument("Invalid attribute type {}", type); |
| 84 | } | 84 | } |
| 85 | |||
| 86 | struct AttrInfo { | ||
| 87 | Id pointer; | ||
| 88 | Id id; | ||
| 89 | bool needs_cast; | ||
| 90 | }; | ||
| 91 | |||
| 92 | std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) { | ||
| 93 | const AttributeType type{ctx.profile.generic_input_types.at(index)}; | ||
| 94 | switch (type) { | ||
| 95 | case AttributeType::Float: | ||
| 96 | return AttrInfo{ctx.input_f32, ctx.F32[1], false}; | ||
| 97 | case AttributeType::UnsignedInt: | ||
| 98 | return AttrInfo{ctx.input_u32, ctx.U32[1], true}; | ||
| 99 | case AttributeType::SignedInt: | ||
| 100 | return AttrInfo{ctx.input_s32, ctx.TypeInt(32, true), true}; | ||
| 101 | case AttributeType::Disabled: | ||
| 102 | return std::nullopt; | ||
| 103 | } | ||
| 104 | throw InvalidArgument("Invalid attribute type {}", type); | ||
| 105 | } | ||
| 106 | |||
| 85 | } // Anonymous namespace | 107 | } // Anonymous namespace |
| 86 | 108 | ||
| 87 | void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { | 109 | void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { |
| @@ -107,6 +129,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin | |||
| 107 | DefineConstantBuffers(program.info, binding); | 129 | DefineConstantBuffers(program.info, binding); |
| 108 | DefineStorageBuffers(program.info, binding); | 130 | DefineStorageBuffers(program.info, binding); |
| 109 | DefineTextures(program.info, binding); | 131 | DefineTextures(program.info, binding); |
| 132 | DefineAttributeMemAccess(program.info); | ||
| 110 | DefineLabels(program); | 133 | DefineLabels(program); |
| 111 | } | 134 | } |
| 112 | 135 | ||
| @@ -290,6 +313,107 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) { | |||
| 290 | } | 313 | } |
| 291 | } | 314 | } |
| 292 | 315 | ||
| 316 | void EmitContext::DefineAttributeMemAccess(const Info& info) { | ||
| 317 | const auto make_load{[&]() { | ||
| 318 | const Id end_block{OpLabel()}; | ||
| 319 | const Id default_label{OpLabel()}; | ||
| 320 | |||
| 321 | const Id func_type_load{TypeFunction(F32[1], U32[1])}; | ||
| 322 | const Id func{OpFunction(F32[1], spv::FunctionControlMask::MaskNone, func_type_load)}; | ||
| 323 | const Id offset{OpFunctionParameter(U32[1])}; | ||
| 324 | AddLabel(); | ||
| 325 | const Id base_index{OpShiftRightLogical(U32[1], offset, Constant(U32[1], 2U))}; | ||
| 326 | const Id masked_index{OpBitwiseAnd(U32[1], base_index, Constant(U32[1], 3U))}; | ||
| 327 | const Id compare_index{OpShiftRightLogical(U32[1], base_index, Constant(U32[1], 2U))}; | ||
| 328 | std::vector<Sirit::Literal> literals; | ||
| 329 | std::vector<Id> labels; | ||
| 330 | const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2; | ||
| 331 | for (u32 i = 0; i < info.input_generics.size(); i++) { | ||
| 332 | if (!info.input_generics[i].used) { | ||
| 333 | continue; | ||
| 334 | } | ||
| 335 | literals.push_back(base_attribute_value + i); | ||
| 336 | labels.push_back(OpLabel()); | ||
| 337 | } | ||
| 338 | OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); | ||
| 339 | OpSwitch(compare_index, default_label, literals, labels); | ||
| 340 | AddLabel(default_label); | ||
| 341 | OpReturnValue(Constant(F32[1], 0.0f)); | ||
| 342 | size_t label_index = 0; | ||
| 343 | for (u32 i = 0; i < info.input_generics.size(); i++) { | ||
| 344 | if (!info.input_generics[i].used) { | ||
| 345 | continue; | ||
| 346 | } | ||
| 347 | AddLabel(labels[label_index]); | ||
| 348 | const auto type{AttrTypes(*this, i)}; | ||
| 349 | if (!type) { | ||
| 350 | OpReturnValue(Constant(F32[1], 0.0f)); | ||
| 351 | label_index++; | ||
| 352 | continue; | ||
| 353 | } | ||
| 354 | const Id generic_id{input_generics.at(i)}; | ||
| 355 | const Id pointer{OpAccessChain(type->pointer, generic_id, masked_index)}; | ||
| 356 | const Id value{OpLoad(type->id, pointer)}; | ||
| 357 | const Id result{type->needs_cast ? OpBitcast(F32[1], value) : value}; | ||
| 358 | OpReturnValue(result); | ||
| 359 | label_index++; | ||
| 360 | } | ||
| 361 | AddLabel(end_block); | ||
| 362 | OpUnreachable(); | ||
| 363 | OpFunctionEnd(); | ||
| 364 | return func; | ||
| 365 | }}; | ||
| 366 | const auto make_store{[&]() { | ||
| 367 | const Id end_block{OpLabel()}; | ||
| 368 | const Id default_label{OpLabel()}; | ||
| 369 | |||
| 370 | const Id func_type_store{TypeFunction(void_id, U32[1], F32[1])}; | ||
| 371 | const Id func{OpFunction(void_id, spv::FunctionControlMask::MaskNone, func_type_store)}; | ||
| 372 | const Id offset{OpFunctionParameter(U32[1])}; | ||
| 373 | const Id store_value{OpFunctionParameter(F32[1])}; | ||
| 374 | AddLabel(); | ||
| 375 | const Id base_index{OpShiftRightLogical(U32[1], offset, Constant(U32[1], 2U))}; | ||
| 376 | const Id masked_index{OpBitwiseAnd(U32[1], base_index, Constant(U32[1], 3U))}; | ||
| 377 | const Id compare_index{OpShiftRightLogical(U32[1], base_index, Constant(U32[1], 2U))}; | ||
| 378 | std::vector<Sirit::Literal> literals; | ||
| 379 | std::vector<Id> labels; | ||
| 380 | const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2; | ||
| 381 | for (u32 i = 0; i < info.stores_generics.size(); i++) { | ||
| 382 | if (!info.stores_generics[i]) { | ||
| 383 | continue; | ||
| 384 | } | ||
| 385 | literals.push_back(base_attribute_value + i); | ||
| 386 | labels.push_back(OpLabel()); | ||
| 387 | } | ||
| 388 | OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); | ||
| 389 | OpSwitch(compare_index, default_label, literals, labels); | ||
| 390 | AddLabel(default_label); | ||
| 391 | OpReturn(); | ||
| 392 | size_t label_index = 0; | ||
| 393 | for (u32 i = 0; i < info.stores_generics.size(); i++) { | ||
| 394 | if (!info.stores_generics[i]) { | ||
| 395 | continue; | ||
| 396 | } | ||
| 397 | AddLabel(labels[label_index]); | ||
| 398 | const Id generic_id{output_generics.at(i)}; | ||
| 399 | const Id pointer{OpAccessChain(output_f32, generic_id, masked_index)}; | ||
| 400 | OpStore(pointer, store_value); | ||
| 401 | OpReturn(); | ||
| 402 | label_index++; | ||
| 403 | } | ||
| 404 | AddLabel(end_block); | ||
| 405 | OpUnreachable(); | ||
| 406 | OpFunctionEnd(); | ||
| 407 | return func; | ||
| 408 | }}; | ||
| 409 | if (info.loads_indexed_attributes) { | ||
| 410 | indexed_load_func = make_load(); | ||
| 411 | } | ||
| 412 | if (info.stores_indexed_attributes) { | ||
| 413 | indexed_store_func = make_store(); | ||
| 414 | } | ||
| 415 | } | ||
| 416 | |||
| 293 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { | 417 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { |
| 294 | if (info.constant_buffer_descriptors.empty()) { | 418 | if (info.constant_buffer_descriptors.empty()) { |
| 295 | return; | 419 | return; |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h index 03c5a6aba..7a2ac0511 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.h +++ b/src/shader_recompiler/backend/spirv/emit_context.h | |||
| @@ -116,6 +116,9 @@ public: | |||
| 116 | Id fswzadd_lut_a{}; | 116 | Id fswzadd_lut_a{}; |
| 117 | Id fswzadd_lut_b{}; | 117 | Id fswzadd_lut_b{}; |
| 118 | 118 | ||
| 119 | Id indexed_load_func{}; | ||
| 120 | Id indexed_store_func{}; | ||
| 121 | |||
| 119 | Id local_memory{}; | 122 | Id local_memory{}; |
| 120 | 123 | ||
| 121 | Id shared_memory_u8{}; | 124 | Id shared_memory_u8{}; |
| @@ -148,6 +151,7 @@ private: | |||
| 148 | void DefineConstantBuffers(const Info& info, u32& binding); | 151 | void DefineConstantBuffers(const Info& info, u32& binding); |
| 149 | void DefineStorageBuffers(const Info& info, u32& binding); | 152 | void DefineStorageBuffers(const Info& info, u32& binding); |
| 150 | void DefineTextures(const Info& info, u32& binding); | 153 | void DefineTextures(const Info& info, u32& binding); |
| 154 | void DefineAttributeMemAccess(const Info& info); | ||
| 151 | void DefineLabels(IR::Program& program); | 155 | void DefineLabels(IR::Program& program); |
| 152 | 156 | ||
| 153 | void DefineConstantBuffers(const Info& info, Id UniformDefinitions::*member_type, u32 binding, | 157 | void DefineConstantBuffers(const Info& info, Id UniformDefinitions::*member_type, u32 binding, |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 712c5e61f..08460c94e 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -51,8 +51,8 @@ Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& o | |||
| 51 | Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | 51 | Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); |
| 52 | Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr); | 52 | Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr); |
| 53 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value); | 53 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value); |
| 54 | void EmitGetAttributeIndexed(EmitContext& ctx); | 54 | Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset); |
| 55 | void EmitSetAttributeIndexed(EmitContext& ctx); | 55 | void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value); |
| 56 | void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value); | 56 | void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value); |
| 57 | void EmitSetFragDepth(EmitContext& ctx, Id value); | 57 | void EmitSetFragDepth(EmitContext& ctx, Id value); |
| 58 | void EmitGetZFlag(EmitContext& ctx); | 58 | void EmitGetZFlag(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 1bfc60294..a60eca815 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 | |||
| @@ -216,12 +216,12 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value) { | |||
| 216 | ctx.OpStore(*output, value); | 216 | ctx.OpStore(*output, value); |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | void EmitGetAttributeIndexed(EmitContext&) { | 219 | Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset) { |
| 220 | throw NotImplementedException("SPIR-V Instruction"); | 220 | return ctx.OpFunctionCall(ctx.F32[1], ctx.indexed_load_func, offset); |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | void EmitSetAttributeIndexed(EmitContext&) { | 223 | void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value) { |
| 224 | throw NotImplementedException("SPIR-V Instruction"); | 224 | ctx.OpFunctionCall(ctx.void_id, ctx.indexed_store_func, offset, value); |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) { | 227 | void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) { |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index ed1e0dd3b..e4e9b260c 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -307,6 +307,14 @@ void IREmitter::SetAttribute(IR::Attribute attribute, const F32& value) { | |||
| 307 | Inst(Opcode::SetAttribute, attribute, value); | 307 | Inst(Opcode::SetAttribute, attribute, value); |
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | F32 IREmitter::GetAttributeIndexed(IR::U32 phys_address) { | ||
| 311 | return Inst<F32>(Opcode::GetAttributeIndexed, phys_address); | ||
| 312 | } | ||
| 313 | |||
| 314 | void IREmitter::SetAttributeIndexed(IR::U32 phys_address, const F32& value) { | ||
| 315 | Inst(Opcode::SetAttributeIndexed, phys_address, value); | ||
| 316 | } | ||
| 317 | |||
| 310 | void IREmitter::SetFragColor(u32 index, u32 component, const F32& value) { | 318 | void IREmitter::SetFragColor(u32 index, u32 component, const F32& value) { |
| 311 | Inst(Opcode::SetFragColor, Imm32(index), Imm32(component), value); | 319 | Inst(Opcode::SetFragColor, Imm32(index), Imm32(component), value); |
| 312 | } | 320 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 42756af43..afa8bd924 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -76,6 +76,9 @@ public: | |||
| 76 | [[nodiscard]] F32 GetAttribute(IR::Attribute attribute); | 76 | [[nodiscard]] F32 GetAttribute(IR::Attribute attribute); |
| 77 | void SetAttribute(IR::Attribute attribute, const F32& value); | 77 | void SetAttribute(IR::Attribute attribute, const F32& value); |
| 78 | 78 | ||
| 79 | [[nodiscard]] F32 GetAttributeIndexed(IR::U32 phys_address); | ||
| 80 | void SetAttributeIndexed(IR::U32 phys_address, const F32& value); | ||
| 81 | |||
| 79 | void SetFragColor(u32 index, u32 component, const F32& value); | 82 | void SetFragColor(u32 index, u32 component, const F32& value); |
| 80 | void SetFragDepth(const F32& value); | 83 | void SetFragDepth(const F32& value); |
| 81 | 84 | ||
diff --git a/src/shader_recompiler/frontend/maxwell/program.cpp b/src/shader_recompiler/frontend/maxwell/program.cpp index 58caa35a1..aaf2a74a7 100644 --- a/src/shader_recompiler/frontend/maxwell/program.cpp +++ b/src/shader_recompiler/frontend/maxwell/program.cpp | |||
| @@ -87,7 +87,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 87 | Optimization::DeadCodeEliminationPass(program); | 87 | Optimization::DeadCodeEliminationPass(program); |
| 88 | Optimization::IdentityRemovalPass(program); | 88 | Optimization::IdentityRemovalPass(program); |
| 89 | Optimization::VerificationPass(program); | 89 | Optimization::VerificationPass(program); |
| 90 | Optimization::CollectShaderInfoPass(program); | 90 | Optimization::CollectShaderInfoPass(env, program); |
| 91 | CollectInterpolationInfo(env, program); | 91 | CollectInterpolationInfo(env, program); |
| 92 | return program; | 92 | return program; |
| 93 | } | 93 | } |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp index 54bc1e34c..0d248c020 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp | |||
| @@ -31,7 +31,7 @@ enum class SampleMode : u64 { | |||
| 31 | Offset, | 31 | Offset, |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | int NumElements(Size size) { | 34 | u32 NumElements(Size size) { |
| 35 | switch (size) { | 35 | switch (size) { |
| 36 | case Size::B32: | 36 | case Size::B32: |
| 37 | return 1; | 37 | return 1; |
| @@ -65,15 +65,21 @@ void TranslatorVisitor::ALD(u64 insn) { | |||
| 65 | if (ald.patch != 0) { | 65 | if (ald.patch != 0) { |
| 66 | throw NotImplementedException("P"); | 66 | throw NotImplementedException("P"); |
| 67 | } | 67 | } |
| 68 | if (ald.index_reg != IR::Reg::RZ) { | ||
| 69 | throw NotImplementedException("Indexed"); | ||
| 70 | } | ||
| 71 | const u64 offset{ald.absolute_offset.Value()}; | 68 | const u64 offset{ald.absolute_offset.Value()}; |
| 72 | if (offset % 4 != 0) { | 69 | if (offset % 4 != 0) { |
| 73 | throw NotImplementedException("Unaligned absolute offset {}", offset); | 70 | throw NotImplementedException("Unaligned absolute offset {}", offset); |
| 74 | } | 71 | } |
| 75 | const int num_elements{NumElements(ald.size)}; | 72 | const u32 num_elements{NumElements(ald.size)}; |
| 76 | for (int element = 0; element < num_elements; ++element) { | 73 | if (ald.index_reg != IR::Reg::RZ) { |
| 74 | const IR::U32 index_value = X(ald.index_reg); | ||
| 75 | for (u32 element = 0; element < num_elements; ++element) { | ||
| 76 | const IR::U32 final_offset = | ||
| 77 | element == 0 ? index_value : IR::U32{ir.IAdd(index_value, ir.Imm32(element * 4U))}; | ||
| 78 | F(ald.dest_reg + element, ir.GetAttributeIndexed(final_offset)); | ||
| 79 | } | ||
| 80 | return; | ||
| 81 | } | ||
| 82 | for (u32 element = 0; element < num_elements; ++element) { | ||
| 77 | F(ald.dest_reg + element, ir.GetAttribute(IR::Attribute{offset / 4 + element})); | 83 | F(ald.dest_reg + element, ir.GetAttribute(IR::Attribute{offset / 4 + element})); |
| 78 | } | 84 | } |
| 79 | } | 85 | } |
| @@ -103,8 +109,17 @@ void TranslatorVisitor::AST(u64 insn) { | |||
| 103 | if (offset % 4 != 0) { | 109 | if (offset % 4 != 0) { |
| 104 | throw NotImplementedException("Unaligned absolute offset {}", offset); | 110 | throw NotImplementedException("Unaligned absolute offset {}", offset); |
| 105 | } | 111 | } |
| 106 | const int num_elements{NumElements(ast.size)}; | 112 | const u32 num_elements{NumElements(ast.size)}; |
| 107 | for (int element = 0; element < num_elements; ++element) { | 113 | if (ast.index_reg != IR::Reg::RZ) { |
| 114 | const IR::U32 index_value = X(ast.index_reg); | ||
| 115 | for (u32 element = 0; element < num_elements; ++element) { | ||
| 116 | const IR::U32 final_offset = | ||
| 117 | element == 0 ? index_value : IR::U32{ir.IAdd(index_value, ir.Imm32(element * 4U))}; | ||
| 118 | ir.SetAttributeIndexed(final_offset, F(ast.src_reg + element)); | ||
| 119 | } | ||
| 120 | return; | ||
| 121 | } | ||
| 122 | for (u32 element = 0; element < num_elements; ++element) { | ||
| 108 | ir.SetAttribute(IR::Attribute{offset / 4 + element}, F(ast.src_reg + element)); | 123 | ir.SetAttribute(IR::Attribute{offset / 4 + element}, F(ast.src_reg + element)); |
| 109 | } | 124 | } |
| 110 | } | 125 | } |
| @@ -134,12 +149,9 @@ void TranslatorVisitor::IPA(u64 insn) { | |||
| 134 | // gl_FragColor = colors[idx]; | 149 | // gl_FragColor = colors[idx]; |
| 135 | // } | 150 | // } |
| 136 | const bool is_indexed{ipa.idx != 0 && ipa.index_reg != IR::Reg::RZ}; | 151 | const bool is_indexed{ipa.idx != 0 && ipa.index_reg != IR::Reg::RZ}; |
| 137 | if (is_indexed) { | ||
| 138 | throw NotImplementedException("IDX"); | ||
| 139 | } | ||
| 140 | |||
| 141 | const IR::Attribute attribute{ipa.attribute}; | 152 | const IR::Attribute attribute{ipa.attribute}; |
| 142 | IR::F32 value{ir.GetAttribute(attribute)}; | 153 | IR::F32 value{is_indexed ? ir.GetAttributeIndexed(X(ipa.index_reg)) |
| 154 | : ir.GetAttribute(attribute)}; | ||
| 143 | if (IR::IsGeneric(attribute)) { | 155 | if (IR::IsGeneric(attribute)) { |
| 144 | const ProgramHeader& sph{env.SPH()}; | 156 | const ProgramHeader& sph{env.SPH()}; |
| 145 | const u32 attr_index{IR::GenericAttributeIndex(attribute)}; | 157 | const u32 attr_index{IR::GenericAttributeIndex(attribute)}; |
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 0f870535b..dbe9f1f40 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "shader_recompiler/environment.h" | ||
| 5 | #include "shader_recompiler/frontend/ir/microinstruction.h" | 6 | #include "shader_recompiler/frontend/ir/microinstruction.h" |
| 6 | #include "shader_recompiler/frontend/ir/modifiers.h" | 7 | #include "shader_recompiler/frontend/ir/modifiers.h" |
| 7 | #include "shader_recompiler/frontend/ir/program.h" | 8 | #include "shader_recompiler/frontend/ir/program.h" |
| @@ -323,6 +324,12 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 323 | case IR::Opcode::SetAttribute: | 324 | case IR::Opcode::SetAttribute: |
| 324 | SetAttribute(info, inst.Arg(0).Attribute()); | 325 | SetAttribute(info, inst.Arg(0).Attribute()); |
| 325 | break; | 326 | break; |
| 327 | case IR::Opcode::GetAttributeIndexed: | ||
| 328 | info.loads_indexed_attributes = true; | ||
| 329 | break; | ||
| 330 | case IR::Opcode::SetAttributeIndexed: | ||
| 331 | info.stores_indexed_attributes = true; | ||
| 332 | break; | ||
| 326 | case IR::Opcode::SetFragColor: | 333 | case IR::Opcode::SetFragColor: |
| 327 | info.stores_frag_color[inst.Arg(0).U32()] = true; | 334 | info.stores_frag_color[inst.Arg(0).U32()] = true; |
| 328 | break; | 335 | break; |
| @@ -502,15 +509,42 @@ void Visit(Info& info, IR::Inst& inst) { | |||
| 502 | VisitUsages(info, inst); | 509 | VisitUsages(info, inst); |
| 503 | VisitFpModifiers(info, inst); | 510 | VisitFpModifiers(info, inst); |
| 504 | } | 511 | } |
| 512 | |||
| 513 | void GatherInfoFromHeader(Environment& env, Info& info) { | ||
| 514 | auto stage = env.ShaderStage(); | ||
| 515 | if (stage == Stage::Compute) { | ||
| 516 | return; | ||
| 517 | } | ||
| 518 | const auto& header = env.SPH(); | ||
| 519 | if (stage == Stage::Fragment) { | ||
| 520 | for (size_t i = 0; i < info.input_generics.size(); i++) { | ||
| 521 | info.input_generics[i].used = | ||
| 522 | info.input_generics[i].used || header.ps.IsGenericVectorActive(i); | ||
| 523 | } | ||
| 524 | return; | ||
| 525 | } | ||
| 526 | for (size_t i = 0; i < info.input_generics.size(); i++) { | ||
| 527 | info.input_generics[i].used = | ||
| 528 | info.input_generics[i].used || header.vtg.IsInputGenericVectorActive(i); | ||
| 529 | } | ||
| 530 | for (size_t i = 0; i < info.stores_generics.size(); i++) { | ||
| 531 | info.stores_generics[i] = | ||
| 532 | info.stores_generics[i] || header.vtg.IsOutputGenericVectorActive(i); | ||
| 533 | } | ||
| 534 | info.stores_clip_distance = | ||
| 535 | info.stores_clip_distance || header.vtg.omap_systemc.clip_distances != 0; | ||
| 536 | } | ||
| 537 | |||
| 505 | } // Anonymous namespace | 538 | } // Anonymous namespace |
| 506 | 539 | ||
| 507 | void CollectShaderInfoPass(IR::Program& program) { | 540 | void CollectShaderInfoPass(Environment& env, IR::Program& program) { |
| 508 | Info& info{program.info}; | 541 | Info& info{program.info}; |
| 509 | for (IR::Block* const block : program.post_order_blocks) { | 542 | for (IR::Block* const block : program.post_order_blocks) { |
| 510 | for (IR::Inst& inst : block->Instructions()) { | 543 | for (IR::Inst& inst : block->Instructions()) { |
| 511 | Visit(info, inst); | 544 | Visit(info, inst); |
| 512 | } | 545 | } |
| 513 | } | 546 | } |
| 547 | GatherInfoFromHeader(env, info); | ||
| 514 | } | 548 | } |
| 515 | 549 | ||
| 516 | } // namespace Shader::Optimization | 550 | } // namespace Shader::Optimization |
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index 5c1fc166c..186104713 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | namespace Shader::Optimization { | 13 | namespace Shader::Optimization { |
| 14 | 14 | ||
| 15 | void CollectShaderInfoPass(IR::Program& program); | 15 | void CollectShaderInfoPass(Environment& env, IR::Program& program); |
| 16 | void ConstantPropagationPass(IR::Program& program); | 16 | void ConstantPropagationPass(IR::Program& program); |
| 17 | void DeadCodeEliminationPass(IR::Program& program); | 17 | void DeadCodeEliminationPass(IR::Program& program); |
| 18 | void GlobalMemoryToStorageBufferPass(IR::Program& program); | 18 | void GlobalMemoryToStorageBufferPass(IR::Program& program); |
diff --git a/src/shader_recompiler/program_header.h b/src/shader_recompiler/program_header.h index 1544bfa42..ce65fc1a4 100644 --- a/src/shader_recompiler/program_header.h +++ b/src/shader_recompiler/program_header.h | |||
| @@ -68,10 +68,24 @@ struct ProgramHeader { | |||
| 68 | 68 | ||
| 69 | union { | 69 | union { |
| 70 | struct { | 70 | struct { |
| 71 | INSERT_PADDING_BYTES_NOINIT(3); // ImapSystemValuesA | 71 | INSERT_PADDING_BYTES_NOINIT(3); // ImapSystemValuesA |
| 72 | INSERT_PADDING_BYTES_NOINIT(1); // ImapSystemValuesB | 72 | INSERT_PADDING_BYTES_NOINIT(1); // ImapSystemValuesB |
| 73 | INSERT_PADDING_BYTES_NOINIT(16); // ImapGenericVector[32] | 73 | |
| 74 | INSERT_PADDING_BYTES_NOINIT(2); // ImapColor | 74 | union { |
| 75 | BitField<0, 1, u8> x; | ||
| 76 | BitField<1, 1, u8> y; | ||
| 77 | BitField<2, 1, u8> z; | ||
| 78 | BitField<3, 1, u8> w; | ||
| 79 | BitField<4, 1, u8> x2; | ||
| 80 | BitField<5, 1, u8> y2; | ||
| 81 | BitField<6, 1, u8> z2; | ||
| 82 | BitField<7, 1, u8> w2; | ||
| 83 | BitField<0, 4, u8> first; | ||
| 84 | BitField<4, 4, u8> second; | ||
| 85 | u8 raw; | ||
| 86 | } imap_generic_vector[16]; | ||
| 87 | |||
| 88 | INSERT_PADDING_BYTES_NOINIT(2); // ImapColor | ||
| 75 | union { | 89 | union { |
| 76 | BitField<0, 8, u16> clip_distances; | 90 | BitField<0, 8, u16> clip_distances; |
| 77 | BitField<8, 1, u16> point_sprite_s; | 91 | BitField<8, 1, u16> point_sprite_s; |
| @@ -82,15 +96,54 @@ struct ProgramHeader { | |||
| 82 | BitField<14, 1, u16> instance_id; | 96 | BitField<14, 1, u16> instance_id; |
| 83 | BitField<15, 1, u16> vertex_id; | 97 | BitField<15, 1, u16> vertex_id; |
| 84 | }; | 98 | }; |
| 85 | INSERT_PADDING_BYTES_NOINIT(5); // ImapFixedFncTexture[10] | 99 | INSERT_PADDING_BYTES_NOINIT(5); // ImapFixedFncTexture[10] |
| 86 | INSERT_PADDING_BYTES_NOINIT(1); // ImapReserved | 100 | INSERT_PADDING_BYTES_NOINIT(1); // ImapReserved |
| 87 | INSERT_PADDING_BYTES_NOINIT(3); // OmapSystemValuesA | 101 | INSERT_PADDING_BYTES_NOINIT(3); // OmapSystemValuesA |
| 88 | INSERT_PADDING_BYTES_NOINIT(1); // OmapSystemValuesB | 102 | INSERT_PADDING_BYTES_NOINIT(1); // OmapSystemValuesB |
| 89 | INSERT_PADDING_BYTES_NOINIT(16); // OmapGenericVector[32] | 103 | |
| 90 | INSERT_PADDING_BYTES_NOINIT(2); // OmapColor | 104 | union { |
| 91 | INSERT_PADDING_BYTES_NOINIT(2); // OmapSystemValuesC | 105 | BitField<0, 1, u8> x; |
| 92 | INSERT_PADDING_BYTES_NOINIT(5); // OmapFixedFncTexture[10] | 106 | BitField<1, 1, u8> y; |
| 93 | INSERT_PADDING_BYTES_NOINIT(1); // OmapReserved | 107 | BitField<2, 1, u8> z; |
| 108 | BitField<3, 1, u8> w; | ||
| 109 | BitField<4, 1, u8> x2; | ||
| 110 | BitField<5, 1, u8> y2; | ||
| 111 | BitField<6, 1, u8> z2; | ||
| 112 | BitField<7, 1, u8> w2; | ||
| 113 | BitField<0, 4, u8> first; | ||
| 114 | BitField<4, 4, u8> second; | ||
| 115 | u8 raw; | ||
| 116 | } omap_generic_vector[16]; | ||
| 117 | |||
| 118 | INSERT_PADDING_BYTES_NOINIT(2); // OmapColor | ||
| 119 | |||
| 120 | union { | ||
| 121 | BitField<0, 8, u16> clip_distances; | ||
| 122 | BitField<8, 1, u16> point_sprite_s; | ||
| 123 | BitField<9, 1, u16> point_sprite_t; | ||
| 124 | BitField<10, 1, u16> fog_coordinate; | ||
| 125 | BitField<12, 1, u16> tessellation_eval_point_u; | ||
| 126 | BitField<13, 1, u16> tessellation_eval_point_v; | ||
| 127 | BitField<14, 1, u16> instance_id; | ||
| 128 | BitField<15, 1, u16> vertex_id; | ||
| 129 | } omap_systemc; | ||
| 130 | |||
| 131 | INSERT_PADDING_BYTES_NOINIT(5); // OmapFixedFncTexture[10] | ||
| 132 | INSERT_PADDING_BYTES_NOINIT(1); // OmapReserved | ||
| 133 | |||
| 134 | [[nodiscard]] bool IsInputGenericVectorActive(size_t index) const { | ||
| 135 | if ((index & 1) == 0) { | ||
| 136 | return imap_generic_vector[index >> 1].first != 0; | ||
| 137 | } | ||
| 138 | return imap_generic_vector[index >> 1].second != 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | [[nodiscard]] bool IsOutputGenericVectorActive(size_t index) const { | ||
| 142 | if ((index & 1) == 0) { | ||
| 143 | return omap_generic_vector[index >> 1].first != 0; | ||
| 144 | } | ||
| 145 | return omap_generic_vector[index >> 1].second != 0; | ||
| 146 | } | ||
| 94 | } vtg; | 147 | } vtg; |
| 95 | 148 | ||
| 96 | struct { | 149 | struct { |
| @@ -128,6 +181,10 @@ struct ProgramHeader { | |||
| 128 | const auto& vector{imap_generic_vector[attribute]}; | 181 | const auto& vector{imap_generic_vector[attribute]}; |
| 129 | return {vector.x, vector.y, vector.z, vector.w}; | 182 | return {vector.x, vector.y, vector.z, vector.w}; |
| 130 | } | 183 | } |
| 184 | |||
| 185 | [[nodiscard]] bool IsGenericVectorActive(size_t index) const { | ||
| 186 | return imap_generic_vector[index].raw != 0; | ||
| 187 | } | ||
| 131 | } ps; | 188 | } ps; |
| 132 | 189 | ||
| 133 | std::array<u32, 0xf> raw; | 190 | std::array<u32, 0xf> raw; |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 9551a124f..41bb5b9a1 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -76,6 +76,7 @@ struct Info { | |||
| 76 | bool loads_vertex_id{}; | 76 | bool loads_vertex_id{}; |
| 77 | bool loads_front_face{}; | 77 | bool loads_front_face{}; |
| 78 | bool loads_point_coord{}; | 78 | bool loads_point_coord{}; |
| 79 | bool loads_indexed_attributes{}; | ||
| 79 | 80 | ||
| 80 | std::array<bool, 8> stores_frag_color{}; | 81 | std::array<bool, 8> stores_frag_color{}; |
| 81 | bool stores_frag_depth{}; | 82 | bool stores_frag_depth{}; |
| @@ -84,6 +85,7 @@ struct Info { | |||
| 84 | bool stores_point_size{}; | 85 | bool stores_point_size{}; |
| 85 | bool stores_clip_distance{}; | 86 | bool stores_clip_distance{}; |
| 86 | bool stores_viewport_index{}; | 87 | bool stores_viewport_index{}; |
| 88 | bool stores_indexed_attributes{}; | ||
| 87 | 89 | ||
| 88 | bool uses_fp16{}; | 90 | bool uses_fp16{}; |
| 89 | bool uses_fp64{}; | 91 | bool uses_fp64{}; |