graphics: skip GPU-clean empty indirect dispatches before shader preparation

Co-authored-by: fxpw <fxpw@outlook.com>
This commit is contained in:
nmzik
2026-10-14 03:36:33 +02:00
parent 9e41d8320a
commit be5915c248
2 changed files with 35 additions and 0 deletions
@@ -22,6 +22,7 @@
#include "graphics/shader/recompiler/ir/passes/ResourceMaterialization.h"
#include "graphics/shader/shader.h"
#include "kernel/eventQueue.h"
#include "kernel/memory.h"
#include "kernel/pthread.h"
#include "libs/errno.h"
@@ -444,6 +445,12 @@ void RenderExecutor::DispatchIndirect(uint64_t submit_id, CommandBuffer& buffer,
static_cast<uint32_t>(args_addr), static_cast<uint32_t>(args_addr >> 32u),
0, mode, buffer.GetShaders().GetCs().cs_regs.data_addr);
Common::LockGuard lock(m_context.GetMutex());
vk::DispatchIndirectCommand args {};
if (!m_context.GetBufferCache().HasGpuDirtyBytes(args_addr, sizeof(args)) &&
LibKernel::Memory::TryReadBacking(args_addr, &args, sizeof(args)) &&
(args.x == 0 || args.y == 0 || args.z == 0)) {
return;
}
const auto& cs_regs = buffer.GetShaders().GetCs();
if (cs_regs.cs_regs.data_addr == 0) {
return;
+28
View File
@@ -10566,6 +10566,34 @@ public:
auto &cache = context.GetBufferCache();
auto &shaders = processor.GetShCtx();
context.MapMemory(base, allocation_size);
// Empty CPU-owned arguments must not inspect the shader, even on a GPU-dirty page.
constexpr auto empty_args = base + allocation_size - case_size;
constexpr auto neighbor = empty_args + 0x100u;
constexpr std::array<std::array<u32, 3>, 3> empty_dimensions{{
{0, 1, 1}, {1, 0, 1}, {1, 1, 0}}};
Require(name, "empty arguments",
LibKernel::Memory::TryWriteBacking(empty_args, empty_dimensions.data(),
sizeof(empty_dimensions)),
"empty indirect arguments could not be written");
shaders.SetCsShader({.data_addr = 1});
for (const bool dirty_neighbor : {false, true}) {
if (dirty_neighbor) {
auto [buffer, offset] = cache.ObtainBuffer(neighbor, sizeof(sentinel), true);
buffer->Fill(offset, sizeof(sentinel), sentinel + 1u);
}
Require(name, "exact argument ownership",
!cache.HasGpuDirtyBytes(empty_args, sizeof(empty_dimensions)) &&
cache.IsRegionGpuModified(empty_args, sizeof(empty_dimensions)) == dirty_neighbor,
"empty arguments did not retain independent byte ownership");
const auto tick = scheduler.CurrentTick();
for (size_t i = 0; i < empty_dimensions.size(); ++i) {
processor.DispatchIndirect(empty_args + i * sizeof(empty_dimensions[0]), 0x41u);
}
Require(name, "empty dispatch avoids readback",
scheduler.CurrentTick() == tick &&
cache.HasGpuDirtyBytes(neighbor, sizeof(sentinel)) == dirty_neighbor,
"empty dispatch submitted work or read back neighboring GPU data");
}
const auto set_buffer = [&](u32 sgpr, uint64_t address, u32 records, u32 stride = 0) {
ShaderBufferResource descriptor{};
descriptor.UpdateAddress48(address);