diff options
| author | 2021-04-19 16:33:23 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:28 -0400 | |
| commit | 7018e524f5e6217b3259333acc4ea09ad036d331 (patch) | |
| tree | 58e750b08d48e018accc4de9a05cb483d825904c /src/shader_recompiler/backend/spirv/emit_context.cpp | |
| parent | spirv: Fix ViewportMask (diff) | |
| download | yuzu-7018e524f5e6217b3259333acc4ea09ad036d331.tar.gz yuzu-7018e524f5e6217b3259333acc4ea09ad036d331.tar.xz yuzu-7018e524f5e6217b3259333acc4ea09ad036d331.zip | |
shader: Add NVN storage buffer fallbacks
When we can't track the SSBO origin of a global memory instruction,
leave it as a global memory operation and assume these pointers are in
the NVN storage buffer slots, then apply a linear search in the shader's
runtime.
Diffstat (limited to 'src/shader_recompiler/backend/spirv/emit_context.cpp')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_context.cpp | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 2ffa8c453..7f16cb0dc 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -411,6 +411,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin | |||
| 411 | DefineTextures(program.info, binding); | 411 | DefineTextures(program.info, binding); |
| 412 | DefineImages(program.info, binding); | 412 | DefineImages(program.info, binding); |
| 413 | DefineAttributeMemAccess(program.info); | 413 | DefineAttributeMemAccess(program.info); |
| 414 | DefineGlobalMemoryFunctions(program.info); | ||
| 414 | DefineLabels(program); | 415 | DefineLabels(program); |
| 415 | } | 416 | } |
| 416 | 417 | ||
| @@ -762,6 +763,82 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { | |||
| 762 | } | 763 | } |
| 763 | } | 764 | } |
| 764 | 765 | ||
| 766 | void EmitContext::DefineGlobalMemoryFunctions(const Info& info) { | ||
| 767 | if (!info.uses_global_memory) { | ||
| 768 | return; | ||
| 769 | } | ||
| 770 | using DefPtr = Id StorageDefinitions::*; | ||
| 771 | const Id zero{u32_zero_value}; | ||
| 772 | const auto define_body{[&](DefPtr ssbo_member, Id addr, Id element_pointer, u32 shift, | ||
| 773 | auto&& callback) { | ||
| 774 | AddLabel(); | ||
| 775 | const size_t num_buffers{info.storage_buffers_descriptors.size()}; | ||
| 776 | for (size_t index = 0; index < num_buffers; ++index) { | ||
| 777 | const auto& ssbo{info.storage_buffers_descriptors[index]}; | ||
| 778 | const Id ssbo_addr_cbuf_offset{Const(ssbo.cbuf_offset / 8)}; | ||
| 779 | const Id ssbo_size_cbuf_offset{Const(ssbo.cbuf_offset / 4 + 2)}; | ||
| 780 | const Id ssbo_addr_pointer{OpAccessChain( | ||
| 781 | uniform_types.U32x2, cbufs[ssbo.cbuf_index].U32x2, zero, ssbo_addr_cbuf_offset)}; | ||
| 782 | const Id ssbo_size_pointer{OpAccessChain(uniform_types.U32, cbufs[ssbo.cbuf_index].U32, | ||
| 783 | zero, ssbo_size_cbuf_offset)}; | ||
| 784 | |||
| 785 | const Id ssbo_addr{OpBitcast(U64, OpLoad(U32[2], ssbo_addr_pointer))}; | ||
| 786 | const Id ssbo_size{OpUConvert(U64, OpLoad(U32[1], ssbo_size_pointer))}; | ||
| 787 | const Id ssbo_end{OpIAdd(U64, ssbo_addr, ssbo_size)}; | ||
| 788 | const Id cond{OpLogicalAnd(U1, OpUGreaterThanEqual(U1, addr, ssbo_addr), | ||
| 789 | OpULessThan(U1, addr, ssbo_end))}; | ||
| 790 | const Id then_label{OpLabel()}; | ||
| 791 | const Id else_label{OpLabel()}; | ||
| 792 | OpSelectionMerge(else_label, spv::SelectionControlMask::MaskNone); | ||
| 793 | OpBranchConditional(cond, then_label, else_label); | ||
| 794 | AddLabel(then_label); | ||
| 795 | const Id ssbo_id{ssbos[index].*ssbo_member}; | ||
| 796 | const Id ssbo_offset{OpUConvert(U32[1], OpISub(U64, addr, ssbo_addr))}; | ||
| 797 | const Id ssbo_index{OpShiftRightLogical(U32[1], ssbo_offset, Const(shift))}; | ||
| 798 | const Id ssbo_pointer{OpAccessChain(element_pointer, ssbo_id, zero, ssbo_index)}; | ||
| 799 | callback(ssbo_pointer); | ||
| 800 | AddLabel(else_label); | ||
| 801 | } | ||
| 802 | }}; | ||
| 803 | const auto define_load{[&](DefPtr ssbo_member, Id element_pointer, Id type, u32 shift) { | ||
| 804 | const Id function_type{TypeFunction(type, U64)}; | ||
| 805 | const Id func_id{OpFunction(type, spv::FunctionControlMask::MaskNone, function_type)}; | ||
| 806 | const Id addr{OpFunctionParameter(U64)}; | ||
| 807 | define_body(ssbo_member, addr, element_pointer, shift, | ||
| 808 | [&](Id ssbo_pointer) { OpReturnValue(OpLoad(type, ssbo_pointer)); }); | ||
| 809 | OpReturnValue(ConstantNull(type)); | ||
| 810 | OpFunctionEnd(); | ||
| 811 | return func_id; | ||
| 812 | }}; | ||
| 813 | const auto define_write{[&](DefPtr ssbo_member, Id element_pointer, Id type, u32 shift) { | ||
| 814 | const Id function_type{TypeFunction(void_id, U64, type)}; | ||
| 815 | const Id func_id{OpFunction(void_id, spv::FunctionControlMask::MaskNone, function_type)}; | ||
| 816 | const Id addr{OpFunctionParameter(U64)}; | ||
| 817 | const Id data{OpFunctionParameter(type)}; | ||
| 818 | define_body(ssbo_member, addr, element_pointer, shift, [&](Id ssbo_pointer) { | ||
| 819 | OpStore(ssbo_pointer, data); | ||
| 820 | OpReturn(); | ||
| 821 | }); | ||
| 822 | OpReturn(); | ||
| 823 | OpFunctionEnd(); | ||
| 824 | return func_id; | ||
| 825 | }}; | ||
| 826 | const auto define{ | ||
| 827 | [&](DefPtr ssbo_member, const StorageTypeDefinition& type_def, Id type, size_t size) { | ||
| 828 | const Id element_type{type_def.element}; | ||
| 829 | const u32 shift{static_cast<u32>(std::countr_zero(size))}; | ||
| 830 | const Id load_func{define_load(ssbo_member, element_type, type, shift)}; | ||
| 831 | const Id write_func{define_write(ssbo_member, element_type, type, shift)}; | ||
| 832 | return std::make_pair(load_func, write_func); | ||
| 833 | }}; | ||
| 834 | std::tie(load_global_func_u32, write_global_func_u32) = | ||
| 835 | define(&StorageDefinitions::U32, storage_types.U32, U32[1], sizeof(u32)); | ||
| 836 | std::tie(load_global_func_u32x2, write_global_func_u32x2) = | ||
| 837 | define(&StorageDefinitions::U32x2, storage_types.U32x2, U32[2], sizeof(u32[2])); | ||
| 838 | std::tie(load_global_func_u32x4, write_global_func_u32x4) = | ||
| 839 | define(&StorageDefinitions::U32x4, storage_types.U32x4, U32[4], sizeof(u32[4])); | ||
| 840 | } | ||
| 841 | |||
| 765 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { | 842 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { |
| 766 | if (info.constant_buffer_descriptors.empty()) { | 843 | if (info.constant_buffer_descriptors.empty()) { |
| 767 | return; | 844 | return; |