summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/spirv/emit_context.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-04-19 16:33:23 -0300
committerGravatar ameerj2021-07-22 21:51:28 -0400
commit7018e524f5e6217b3259333acc4ea09ad036d331 (patch)
tree58e750b08d48e018accc4de9a05cb483d825904c /src/shader_recompiler/backend/spirv/emit_context.cpp
parentspirv: Fix ViewportMask (diff)
downloadyuzu-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.cpp77
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
766void 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
765void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { 842void 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;