diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp | 51 | ||||
| -rw-r--r-- | src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | 35 |
2 files changed, 68 insertions, 18 deletions
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 8ea730c80..1cfe1d49f 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 | |||
| @@ -124,25 +124,56 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | |||
| 124 | 124 | ||
| 125 | Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size, | 125 | Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size, |
| 126 | const IR::Value& binding, const IR::Value& offset) { | 126 | const IR::Value& binding, const IR::Value& offset) { |
| 127 | if (!binding.IsImmediate()) { | 127 | std::array<Id, 2> indexes; |
| 128 | throw NotImplementedException("Constant buffer indexing"); | 128 | |
| 129 | } | ||
| 130 | const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr}; | ||
| 131 | const Id uniform_type{ctx.uniform_types.*member_ptr}; | 129 | const Id uniform_type{ctx.uniform_types.*member_ptr}; |
| 132 | if (!offset.IsImmediate()) { | 130 | if (offset.IsImmediate()) { |
| 131 | // Hardware been proved to read the aligned offset (e.g. LDC.U32 at 6 will read offset 4) | ||
| 132 | const Id imm_offset{ctx.Const(offset.U32() / element_size)}; | ||
| 133 | indexes = {ctx.u32_zero_value, imm_offset}; | ||
| 134 | } else { | ||
| 133 | Id index{ctx.Def(offset)}; | 135 | Id index{ctx.Def(offset)}; |
| 134 | if (element_size > 1) { | 136 | if (element_size > 1) { |
| 135 | const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))}; | 137 | const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))}; |
| 136 | const Id shift{ctx.Const(log2_element_size)}; | 138 | const Id shift{ctx.Const(log2_element_size)}; |
| 137 | index = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift); | 139 | index = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift); |
| 138 | } | 140 | } |
| 139 | const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)}; | 141 | indexes = {ctx.u32_zero_value, index}; |
| 142 | } | ||
| 143 | |||
| 144 | if (binding.IsImmediate()) { | ||
| 145 | const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr}; | ||
| 146 | const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, indexes)}; | ||
| 140 | return ctx.OpLoad(result_type, access_chain); | 147 | return ctx.OpLoad(result_type, access_chain); |
| 148 | } else { | ||
| 149 | const Id index{ctx.Def(binding)}; | ||
| 150 | const Id ptr{ctx.TypePointer(spv::StorageClass::Function, result_type)}; | ||
| 151 | const Id value{ctx.AddLocalVariable(ptr, spv::StorageClass::Function)}; | ||
| 152 | const Id merge_label = ctx.OpLabel(); | ||
| 153 | |||
| 154 | std::array<Id, Info::MAX_CBUFS> buf_labels; | ||
| 155 | std::array<Sirit::Literal, Info::MAX_CBUFS> buf_literals; | ||
| 156 | for (u32 i = 0; i < Info::MAX_CBUFS; i++) { | ||
| 157 | buf_labels[i] = ctx.OpLabel(); | ||
| 158 | buf_literals[i] = Sirit::Literal{i}; | ||
| 159 | } | ||
| 160 | |||
| 161 | ctx.OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone); | ||
| 162 | ctx.OpSwitch(index, buf_labels[0], buf_literals, buf_labels); | ||
| 163 | |||
| 164 | for (u32 i = 0; i < Info::MAX_CBUFS; i++) { | ||
| 165 | ctx.AddLabel(buf_labels[i]); | ||
| 166 | const Id cbuf{ctx.cbufs[i].*member_ptr}; | ||
| 167 | const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, indexes)}; | ||
| 168 | const Id result = ctx.OpLoad(result_type, access_chain); | ||
| 169 | ctx.OpStore(value, result); | ||
| 170 | ctx.OpBranch(merge_label); | ||
| 171 | } | ||
| 172 | |||
| 173 | ctx.AddLabel(merge_label); | ||
| 174 | |||
| 175 | return ctx.OpLoad(result_type, value); | ||
| 141 | } | 176 | } |
| 142 | // Hardware been proved to read the aligned offset (e.g. LDC.U32 at 6 will read offset 4) | ||
| 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)}; | ||
| 145 | return ctx.OpLoad(result_type, access_chain); | ||
| 146 | } | 177 | } |
| 147 | 178 | ||
| 148 | Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 179 | Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
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 bfd2ae650..1a50dd382 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -29,6 +29,20 @@ void AddConstantBufferDescriptor(Info& info, u32 index, u32 count) { | |||
| 29 | }); | 29 | }); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | void AddRegisterIndexedLdc(Info& info) { | ||
| 33 | // The shader can use any possible constant buffer | ||
| 34 | info.constant_buffer_mask = (1 << Info::MAX_CBUFS) - 1; | ||
| 35 | |||
| 36 | auto& cbufs{info.constant_buffer_descriptors}; | ||
| 37 | cbufs.clear(); | ||
| 38 | for (u32 i = 0; i < Info::MAX_CBUFS; i++) { | ||
| 39 | cbufs.push_back(ConstantBufferDescriptor{.index = i, .count = 1}); | ||
| 40 | |||
| 41 | // The shader can use any possible access size | ||
| 42 | info.constant_buffer_used_sizes[i] = 0x10'000; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 32 | void GetPatch(Info& info, IR::Patch patch) { | 46 | void GetPatch(Info& info, IR::Patch patch) { |
| 33 | if (!IR::IsGeneric(patch)) { | 47 | if (!IR::IsGeneric(patch)) { |
| 34 | throw NotImplementedException("Reading non-generic patch {}", patch); | 48 | throw NotImplementedException("Reading non-generic patch {}", patch); |
| @@ -463,10 +477,12 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 463 | case IR::Opcode::GetCbufU32x2: { | 477 | case IR::Opcode::GetCbufU32x2: { |
| 464 | const IR::Value index{inst.Arg(0)}; | 478 | const IR::Value index{inst.Arg(0)}; |
| 465 | const IR::Value offset{inst.Arg(1)}; | 479 | const IR::Value offset{inst.Arg(1)}; |
| 466 | if (!index.IsImmediate()) { | 480 | if (index.IsImmediate()) { |
| 467 | throw NotImplementedException("Constant buffer with non-immediate index"); | 481 | AddConstantBufferDescriptor(info, index.U32(), 1); |
| 482 | } else { | ||
| 483 | AddRegisterIndexedLdc(info); | ||
| 468 | } | 484 | } |
| 469 | AddConstantBufferDescriptor(info, index.U32(), 1); | 485 | |
| 470 | u32 element_size{}; | 486 | u32 element_size{}; |
| 471 | switch (inst.GetOpcode()) { | 487 | switch (inst.GetOpcode()) { |
| 472 | case IR::Opcode::GetCbufU8: | 488 | case IR::Opcode::GetCbufU8: |
| @@ -494,11 +510,14 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 494 | default: | 510 | default: |
| 495 | break; | 511 | break; |
| 496 | } | 512 | } |
| 497 | u32& size{info.constant_buffer_used_sizes[index.U32()]}; | 513 | |
| 498 | if (offset.IsImmediate()) { | 514 | if (index.IsImmediate()) { |
| 499 | size = Common::AlignUp(std::max(size, offset.U32() + element_size), 16u); | 515 | u32& size{info.constant_buffer_used_sizes[index.U32()]}; |
| 500 | } else { | 516 | if (offset.IsImmediate()) { |
| 501 | size = 0x10'000; | 517 | size = Common::AlignUp(std::max(size, offset.U32() + element_size), 16u); |
| 518 | } else { | ||
| 519 | size = 0x10'000; | ||
| 520 | } | ||
| 502 | } | 521 | } |
| 503 | break; | 522 | break; |
| 504 | } | 523 | } |