summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Liam2022-03-14 19:35:48 -0400
committerGravatar Liam2022-03-14 19:43:32 -0400
commit52895fab674cb160f2559d08c21333f52d6deced (patch)
treef49f9907197d15d15ee5f937a49a095f444e1a49 /src
parentMerge pull request #8008 from ameerj/rescale-offsets-array (diff)
downloadyuzu-52895fab674cb160f2559d08c21333f52d6deced.tar.gz
yuzu-52895fab674cb160f2559d08c21333f52d6deced.tar.xz
yuzu-52895fab674cb160f2559d08c21333f52d6deced.zip
shader: add support for const buffer indirect addressing
Diffstat (limited to 'src')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp51
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp35
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
125Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size, 125Id 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
148Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 179Id 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
32void 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
32void GetPatch(Info& info, IR::Patch patch) { 46void 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 }