diff --git a/src/common/config.cpp b/src/common/config.cpp index 0b5f11200..4a764a4c6 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -52,6 +52,7 @@ static std::string isSideTrophy = "right"; static bool isNullGpu = false; static bool shouldCopyGPUBuffers = false; static bool readbacksEnabled = false; +static bool directMemoryAccessEnabled = false; static bool shouldDumpShaders = false; static bool shouldPatchShaders = true; static u32 vblankDivider = 1; @@ -245,6 +246,10 @@ bool readbacks() { return readbacksEnabled; } +bool directMemoryAccess() { + return directMemoryAccessEnabled; +} + bool dumpShaders() { return shouldDumpShaders; } @@ -353,6 +358,10 @@ void setReadbacks(bool enable) { readbacksEnabled = enable; } +void setDirectMemoryAccess(bool enable) { + directMemoryAccessEnabled = enable; +} + void setDumpShaders(bool enable) { shouldDumpShaders = enable; } @@ -596,6 +605,7 @@ void load(const std::filesystem::path& path) { isNullGpu = toml::find_or(gpu, "nullGpu", false); shouldCopyGPUBuffers = toml::find_or(gpu, "copyGPUBuffers", false); readbacksEnabled = toml::find_or(gpu, "readbacks", false); + directMemoryAccessEnabled = toml::find_or(gpu, "directMemoryAccess", false); shouldDumpShaders = toml::find_or(gpu, "dumpShaders", false); shouldPatchShaders = toml::find_or(gpu, "patchShaders", true); vblankDivider = toml::find_or(gpu, "vblankDivider", 1); @@ -746,6 +756,7 @@ void save(const std::filesystem::path& path) { data["GPU"]["nullGpu"] = isNullGpu; data["GPU"]["copyGPUBuffers"] = shouldCopyGPUBuffers; data["GPU"]["readbacks"] = readbacksEnabled; + data["GPU"]["directMemoryAccess"] = directMemoryAccessEnabled; data["GPU"]["dumpShaders"] = shouldDumpShaders; data["GPU"]["patchShaders"] = shouldPatchShaders; data["GPU"]["vblankDivider"] = vblankDivider; diff --git a/src/common/config.h b/src/common/config.h index 219461e7e..931fa68e2 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -47,6 +47,8 @@ bool copyGPUCmdBuffers(); void setCopyGPUCmdBuffers(bool enable); bool readbacks(); void setReadbacks(bool enable); +bool directMemoryAccess(); +void setDirectMemoryAccess(bool enable); bool dumpShaders(); void setDumpShaders(bool enable); u32 vblankDiv(); diff --git a/src/emulator.cpp b/src/emulator.cpp index d6d523fa0..fbab5929b 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -133,6 +133,7 @@ void Emulator::Run(std::filesystem::path file, const std::vector ar LOG_INFO(Config, "General isNeo: {}", Config::isNeoModeConsole()); LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu()); LOG_INFO(Config, "GPU readbacks: {}", Config::readbacks()); + LOG_INFO(Config, "GPU directMemoryAccess: {}", Config::directMemoryAccess()); LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders()); LOG_INFO(Config, "GPU vblankDivider: {}", Config::vblankDiv()); LOG_INFO(Config, "Vulkan gpuId: {}", Config::getGpuId()); 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 564fb3f80..f3a8c518c 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 @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" +#include "common/config.h" #include "common/logging/log.h" #include "shader_recompiler/backend/spirv/emit_spirv_bounds.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" @@ -167,6 +168,9 @@ using PointerSize = EmitContext::PointerSize; Id EmitReadConst(EmitContext& ctx, IR::Inst* inst, Id addr, Id offset) { const u32 flatbuf_off_dw = inst->Flags(); + if (!Config::directMemoryAccess()) { + return ctx.EmitFlatbufferLoad(ctx.ConstU32(flatbuf_off_dw)); + } // We can only provide a fallback for immediate offsets. if (flatbuf_off_dw == 0) { return ctx.OpFunctionCall(ctx.U32[1], ctx.read_const_dynamic, addr, offset); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 524914ad4..77336c9ec 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -784,19 +784,6 @@ EmitContext::BufferSpv EmitContext::DefineBuffer(bool is_storage, bool is_writte }; void EmitContext::DefineBuffers() { - if (!profile.supports_robust_buffer_access && !info.uses_dma) { - // In case Flatbuf has not already been bound by IR and is needed - // to query buffer sizes, bind it now. - info.buffers.push_back({ - .used_types = IR::Type::U32, - // We can't guarantee that flatbuf will not grow past UBO - // limit if there are a lot of ReadConsts. (We could specialize) - .inline_cbuf = AmdGpu::Buffer::Placeholder(std::numeric_limits::max()), - .buffer_type = BufferType::Flatbuf, - }); - // In the future we may want to read buffer sizes from GPU memory if available. - // info.readconst_types |= Info::ReadConstType::Immediate; - } for (const auto& desc : info.buffers) { const auto buf_sharp = desc.GetSharp(info); const bool is_storage = desc.IsStorage(buf_sharp, profile); @@ -1219,14 +1206,7 @@ Id EmitContext::DefineReadConst(bool dynamic) { if (dynamic) { return u32_zero_value; } else { - const auto& flatbuf_buffer{buffers[flatbuf_index]}; - ASSERT(flatbuf_buffer.binding >= 0 && - flatbuf_buffer.buffer_type == BufferType::Flatbuf); - const auto [flatbuf_buffer_id, flatbuf_pointer_type] = - flatbuf_buffer.Alias(PointerType::U32); - const auto ptr{OpAccessChain(flatbuf_pointer_type, flatbuf_buffer_id, u32_zero_value, - flatbuf_offset)}; - return OpLoad(U32[1], ptr); + return EmitFlatbufferLoad(flatbuf_offset); } }); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index f8c6416e8..28e9099d8 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -180,6 +180,16 @@ public: return OpAccessChain(result_type, shared_mem, index); } + Id EmitFlatbufferLoad(Id flatbuf_offset) { + const auto& flatbuf_buffer{buffers[flatbuf_index]}; + ASSERT(flatbuf_buffer.binding >= 0 && flatbuf_buffer.buffer_type == BufferType::Flatbuf); + const auto [flatbuf_buffer_id, flatbuf_pointer_type] = + flatbuf_buffer.aliases[u32(PointerType::U32)]; + const auto ptr{ + OpAccessChain(flatbuf_pointer_type, flatbuf_buffer_id, u32_zero_value, flatbuf_offset)}; + return OpLoad(U32[1], ptr); + } + Info& info; const RuntimeInfo& runtime_info; const Profile& profile; diff --git a/src/shader_recompiler/ir/passes/ir_passes.h b/src/shader_recompiler/ir/passes/ir_passes.h index 57d36f6df..fdae9d3cf 100644 --- a/src/shader_recompiler/ir/passes/ir_passes.h +++ b/src/shader_recompiler/ir/passes/ir_passes.h @@ -19,7 +19,7 @@ void ConstantPropagationPass(IR::BlockList& program); void FlattenExtendedUserdataPass(IR::Program& program); void ReadLaneEliminationPass(IR::Program& program); void ResourceTrackingPass(IR::Program& program); -void CollectShaderInfoPass(IR::Program& program); +void CollectShaderInfoPass(IR::Program& program, const Profile& profile); void LowerBufferFormatToRaw(IR::Program& program); void LowerFp64ToFp32(IR::Program& program); void RingAccessElimination(const IR::Program& program, const RuntimeInfo& runtime_info); diff --git a/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp b/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp index 472ff7678..a87dceb0a 100644 --- a/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp +++ b/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/config.h" #include "shader_recompiler/ir/program.h" #include "video_core/buffer_cache/buffer_cache.h" @@ -138,7 +139,7 @@ void Visit(Info& info, const IR::Inst& inst) { } } -void CollectShaderInfoPass(IR::Program& program) { +void CollectShaderInfoPass(IR::Program& program, const Profile& profile) { auto& info = program.info; for (IR::Block* const block : program.post_order_blocks) { for (IR::Inst& inst : block->Instructions()) { @@ -146,6 +147,25 @@ void CollectShaderInfoPass(IR::Program& program) { } } + // In case Flatbuf has not already been bound by IR and is needed + // to query buffer sizes, bind it now. + if (!profile.supports_robust_buffer_access && !info.uses_dma) { + info.buffers.push_back({ + .used_types = IR::Type::U32, + // We can't guarantee that flatbuf will not grow past UBO + // limit if there are a lot of ReadConsts. (We could specialize) + .inline_cbuf = AmdGpu::Buffer::Placeholder(std::numeric_limits::max()), + .buffer_type = BufferType::Flatbuf, + }); + // In the future we may want to read buffer sizes from GPU memory if available. + // info.readconst_types |= Info::ReadConstType::Immediate; + } + + if (!Config::directMemoryAccess()) { + info.uses_dma = false; + info.readconst_types = Info::ReadConstType::None; + } + if (info.uses_dma) { info.buffers.push_back({ .used_types = IR::Type::U64, diff --git a/src/shader_recompiler/recompiler.cpp b/src/shader_recompiler/recompiler.cpp index e17fb1c9e..2da9e7b01 100644 --- a/src/shader_recompiler/recompiler.cpp +++ b/src/shader_recompiler/recompiler.cpp @@ -84,7 +84,7 @@ IR::Program TranslateProgram(std::span code, Pools& pools, Info& info Shader::Optimization::IdentityRemovalPass(program.blocks); Shader::Optimization::DeadCodeEliminationPass(program); Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); - Shader::Optimization::CollectShaderInfoPass(program); + Shader::Optimization::CollectShaderInfoPass(program, profile); Shader::IR::DumpProgram(program, info);