From 89a45a327fb6f7647459ca4d4adeecfd9385d6f7 Mon Sep 17 00:00:00 2001 From: Zephyron Date: Wed, 21 Jan 2026 18:53:59 +1000 Subject: [PATCH] feat(shader): add buffer device address support to shader profile - Add support_buffer_device_address flag to shader Profile - Add global_memory_tracking_failed flag to shader Info - Track global memory instruction coverage in optimization pass - Prepare infrastructure for global memory emulation via BDA --- .../backend/glasm/emit_glasm_memory.cpp | 5 +++-- .../frontend/maxwell/translate_program.cpp | 1 + .../ir_opt/global_memory_to_storage_buffer_pass.cpp | 12 ++++++++++++ src/shader_recompiler/profile.h | 1 + src/shader_recompiler/shader_info.h | 1 + 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp index 9319ea007..c04c7becd 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp @@ -31,10 +31,12 @@ void StorageOp(EmitContext& ctx, const IR::Value& binding, ScalarU32 offset, void GlobalStorageOp(EmitContext& ctx, Register address, bool pointer_based, std::string_view expr, std::string_view else_expr = {}) { const size_t num_buffers{ctx.info.storage_buffers_descriptors.size()}; + size_t buffers_processed{0}; for (size_t index = 0; index < num_buffers; ++index) { if (!ctx.info.nvn_buffer_used[index]) { continue; } + ++buffers_processed; 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 @@ -65,8 +67,7 @@ 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) { + for (size_t index = 0; index < buffers_processed; ++index) { ctx.Add("ENDIF;"); } } diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 321ea625b..9475925d7 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp @@ -110,6 +110,7 @@ void AddNVNStorageBuffers(IR::Program& program) { throw InvalidArgument("Invalid stage {}", program.stage); }()}; auto& descs{program.info.storage_buffers_descriptors}; + for (u32 index = 0; index < num_buffers; ++index) { if (!program.info.nvn_buffer_used[index]) { continue; 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 0cea79945..3addeefd9 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 @@ -522,14 +522,26 @@ void Replace(IR::Block& block, IR::Inst& inst, const IR::U32& storage_index, void GlobalMemoryToStorageBufferPass(IR::Program& program, const HostTranslateInfo& host_info) { StorageInfo info; + size_t total_global_memory_insts{0}; for (IR::Block* const block : program.post_order_blocks) { for (IR::Inst& inst : block->Instructions()) { if (!IsGlobalMemory(inst)) { continue; } + ++total_global_memory_insts; CollectStorageBuffers(*block, inst, info); } } + // Log if some global memory instructions couldn't be tracked + // NOTE: Previously tried enabling all NVN buffers as fallback when tracking failed, + // but this caused crashes due to shader code accessing potentially invalid buffers. + // Now we just log a warning - untracked global memory ops will use default behavior. + const size_t tracked_insts{info.to_replace.size()}; + if (total_global_memory_insts > 0 && tracked_insts < total_global_memory_insts) { + LOG_WARNING(Shader, "Global memory tracking: {} of {} instructions tracked. " + "Untracked ops may cause rendering issues.", + tracked_insts, total_global_memory_insts); + } for (const StorageBufferAddr& storage_buffer : info.set) { program.info.storage_buffers_descriptors.push_back({ .cbuf_index = storage_buffer.index, diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index 90e46bb1b..8a07f5144 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h @@ -34,6 +34,7 @@ struct Profile { bool support_int64_atomics{}; bool support_derivative_control{}; bool support_geometry_shader_passthrough{}; + bool support_buffer_device_address{}; bool support_native_ndc{}; bool support_gl_nv_gpu_shader_5{}; bool support_gl_amd_gpu_shader_half_float{}; diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 858e3eb84..34135f28d 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h @@ -313,6 +313,7 @@ struct Info { bool uses_atomic_s32_max{}; bool uses_int64_bit_atomics{}; bool uses_global_memory{}; + bool global_memory_tracking_failed{}; // True when some global memory ops couldn't be tracked bool uses_atomic_image_u32{}; bool uses_shadow_lod{}; bool uses_rescaling_uniform{};