diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp index 9319ea007f..ee39ec2a47 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -32,10 +35,10 @@ void GlobalStorageOp(EmitContext& ctx, Register address, bool pointer_based, std std::string_view else_expr = {}) { const size_t num_buffers{ctx.info.storage_buffers_descriptors.size()}; for (size_t index = 0; index < num_buffers; ++index) { - if (!ctx.info.nvn_buffer_used[index]) { + const auto& ssbo{ctx.info.storage_buffers_descriptors[index]}; + if (!ssbo.is_global_fallback) { continue; } - const auto& ssbo{ctx.info.storage_buffers_descriptors[index]}; const u64 ssbo_align_mask{~(ctx.profile.min_ssbo_alignment - 1U)}; ctx.Add("LDC.U64 DC.x,c{}[{}];" // unaligned_ssbo_addr "AND.U64 DC.x,DC.x,{};" // ssbo_addr = unaligned_ssbo_addr & ssbo_align_mask @@ -65,9 +68,10 @@ void GlobalStorageOp(EmitContext& ctx, Register address, bool pointer_based, std if (!else_expr.empty()) { ctx.Add("{}", else_expr); } - const size_t num_used_buffers{ctx.info.nvn_buffer_used.count()}; - for (size_t index = 0; index < num_used_buffers; ++index) { - ctx.Add("ENDIF;"); + for (const auto& ssbo : ctx.info.storage_buffers_descriptors) { + if (ssbo.is_global_fallback) { + ctx.Add("ENDIF;"); + } } } diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index a2df6159fb..4f4d420bd7 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp @@ -633,7 +633,7 @@ std::string EmitContext::DefineGlobalMemoryFunctions() { std::string load_func_128{"uvec4 LoadGlobal128(uint64_t addr){"}; const size_t num_buffers{info.storage_buffers_descriptors.size()}; for (size_t index = 0; index < num_buffers; ++index) { - if (!info.nvn_buffer_used[index]) { + if (!info.storage_buffers_descriptors[index].is_global_fallback) { continue; } define_body(write_func, index, "{0}[uint(addr-{1})>>2]=data;return;}}"); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index b562e82983..c5471a6f71 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -948,12 +948,16 @@ void EmitContext::DefineGlobalMemoryFunctions(const Info& info) { const auto define_body{[&](DefPtr ssbo_member, Id addr, Id element_pointer, u32 shift, auto&& callback) { AddLabel(); + const Id addr_words{OpBitcast(U32[2], addr)}; + const Id addr_low{OpCompositeExtract(U32[1], addr_words, 0U)}; + const Id addr_high{OpCompositeExtract(U32[1], addr_words, 1U)}; + const Id align_mask{Const(~(static_cast(profile.min_ssbo_alignment) - 1U))}; const size_t num_buffers{info.storage_buffers_descriptors.size()}; for (size_t index = 0; index < num_buffers; ++index) { - if (!info.nvn_buffer_used[index]) { + const auto& ssbo{info.storage_buffers_descriptors[index]}; + if (!ssbo.is_global_fallback) { continue; } - const auto& ssbo{info.storage_buffers_descriptors[index]}; const Id ssbo_addr_cbuf_offset{Const(ssbo.cbuf_offset / 8)}; const Id ssbo_size_cbuf_offset{Const(ssbo.cbuf_offset / 4 + 2)}; const Id ssbo_addr_pointer{OpAccessChain( @@ -961,20 +965,23 @@ void EmitContext::DefineGlobalMemoryFunctions(const Info& info) { const Id ssbo_size_pointer{OpAccessChain(uniform_types.U32, cbufs[ssbo.cbuf_index].U32, zero, ssbo_size_cbuf_offset)}; - const u64 ssbo_align_mask{~(profile.min_ssbo_alignment - 1U)}; - const Id unaligned_addr{OpBitcast(U64, OpLoad(U32[2], ssbo_addr_pointer))}; - const Id ssbo_addr{OpBitwiseAnd(U64, unaligned_addr, Constant(U64, ssbo_align_mask))}; - const Id ssbo_size{OpUConvert(U64, OpLoad(U32[1], ssbo_size_pointer))}; - const Id ssbo_end{OpIAdd(U64, ssbo_addr, ssbo_size)}; - const Id cond{OpLogicalAnd(U1, OpUGreaterThanEqual(U1, addr, ssbo_addr), - OpULessThan(U1, addr, ssbo_end))}; + const Id ssbo_addr{OpLoad(U32[2], ssbo_addr_pointer)}; + const Id ssbo_low{ + OpBitwiseAnd(U32[1], OpCompositeExtract(U32[1], ssbo_addr, 0U), align_mask)}; + const Id ssbo_high{OpCompositeExtract(U32[1], ssbo_addr, 1U)}; + const Id ssbo_size{OpLoad(U32[1], ssbo_size_pointer)}; + const Id ssbo_offset{OpISub(U32[1], addr_low, ssbo_low)}; + const Id borrow{ + OpSelect(U32[1], OpULessThan(U1, addr_low, ssbo_low), Const(1U), zero)}; + const Id cond{ + OpLogicalAnd(U1, OpULessThan(U1, ssbo_offset, ssbo_size), + OpIEqual(U1, OpISub(U32[1], addr_high, borrow), ssbo_high))}; const Id then_label{OpLabel()}; const Id else_label{OpLabel()}; OpSelectionMerge(else_label, spv::SelectionControlMask::MaskNone); OpBranchConditional(cond, then_label, else_label); AddLabel(then_label); const Id ssbo_id{ssbos[index].*ssbo_member}; - const Id ssbo_offset{OpUConvert(U32[1], OpISub(U64, addr, ssbo_addr))}; const Id ssbo_index{OpShiftRightLogical(U32[1], ssbo_offset, Const(shift))}; const Id ssbo_pointer{OpAccessChain(element_pointer, ssbo_id, zero, ssbo_index)}; callback(ssbo_pointer); diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index a8517266c0..d1d45d6b33 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp @@ -121,9 +121,12 @@ void AddNVNStorageBuffers(IR::Program& program) { continue; } const u32 offset{base + index * descriptor_size}; - const auto it{std::ranges::find(descs, offset, &StorageBufferDescriptor::cbuf_offset)}; + const auto it{std::ranges::find_if(descs, [&](const StorageBufferDescriptor& desc) { + return desc.cbuf_index == driver_cbuf && desc.cbuf_offset == offset; + })}; if (it != descs.end()) { it->is_written |= program.info.stores_global_memory; + it->is_global_fallback = true; continue; } descs.push_back({ @@ -131,6 +134,7 @@ void AddNVNStorageBuffers(IR::Program& program) { .cbuf_offset = offset, .count = 1, .is_written = program.info.stores_global_memory, + .is_global_fallback = true, }); } } diff --git a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp index f49d54e7ab..ba05295fab 100644 --- a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp +++ b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp @@ -562,6 +562,7 @@ void JoinStorageInfo(Info& base, Info& source) { })}; if (it != descriptors.end()) { it->is_written |= desc.is_written; + it->is_global_fallback |= desc.is_global_fallback; continue; } descriptors.push_back(desc); diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 71309e040e..b8d760a30e 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h @@ -172,6 +172,7 @@ struct StorageBufferDescriptor { u32 cbuf_offset; u32 count; bool is_written; + bool is_global_fallback{}; auto operator<=>(const StorageBufferDescriptor&) const = default; };