aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlex <78863999+Sssnowyyy@users.noreply.github.com>2026-11-03 01:29:23 -0500
committerGitHub <noreply@github.com>2026-11-03 07:29:23 +0100
commitf50099038ee4c95901821e137471a8ce87bf52a4 (patch)
tree25dc841aa63c9958687a7d28fa84bd7d226598f9 /src
parentad7282cd736ae75b126088d7d6986efebd048c15 (diff)
nx2: fewer render pass splits on tiled GPUs, log failed GPU waits (Pokopia) (#361)
* buffer_cache: don't end the render pass after mapped buffer uploads Every upload set any_buffer_uploaded, and the next draw or dispatch then recorded a transfer-to-shader barrier outside the render pass. On Vulkan the uploads are mapped: each copy either records its own barriers (CopyBuffer with barrier set) or goes to the upload command buffer, which ends with a barrier before the frame's commands run. The extra barrier only ended the render pass. On tiled GPUs every such split writes the attachments out and reads them back. Pokopia's first gameplay scene had ~50 of these splits a frame. Without them, an M3 MacBook Air (MoltenVK, 1x docked) goes from ~35 to ~29.5 ms of GPU time a frame and from 28.5 to 32 fps. OpenGL uploads immediately and keeps the barrier. Assisted-by: Claude Opus 5.5 (profiling, implementation and commit message) * vulkan: log a failed GPU wait before it ends the process When the device is lost, vkWaitSemaphores in MasterSemaphore::Wait returns VK_ERROR_DEVICE_LOST and the exception goes uncaught on the fence thread or the GPU thread, so the process aborts without a line in the log: ReportLoss is only reached from submit and present. A Pokopia crash on macOS left the log ending a second before the abort, with no hint that the GPU was lost. Log the wait's result before rethrowing. On macOS, MoltenVK prints the Metal reason (a GPU hang or page fault) to stderr only. Assisted-by: Claude Opus 5.5 (diagnosis, implementation and commit message)
Diffstat (limited to 'src')
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h7
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.cpp8
2 files changed, 13 insertions, 2 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 40369b16ef..2e0f0d4623 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -2159,7 +2159,12 @@ bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 si
}
const std::span<BufferCopy> copies_span(upload_copies.data(), upload_copies.size());
UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
- any_buffer_uploaded = true;
+ // Mapped uploads carry their own barriers (or run in the upload command buffer, which
+ // ends with one); another barrier here only ended the render pass (~50 times a frame in
+ // Pokopia).
+ if constexpr (!USE_MEMORY_MAPS_FOR_UPLOADS) {
+ any_buffer_uploaded = true;
+ }
return false;
} else {
boost::container::small_vector<BufferCopy, 4> copies;
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
index be5a1144ce..ba364d99a0 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
@@ -104,7 +104,13 @@ void MasterSemaphore::Wait(u64 tick) {
}
// If none of the above is hit, fallback to a regular wait
- while (!semaphore.Wait(tick)) {
+ try {
+ while (!semaphore.Wait(tick)) {
+ }
+ } catch (const vk::Exception& exception) {
+ // The throw ends the process; say why first (a device loss reached nothing else here).
+ LOG_CRITICAL(Render_Vulkan, "Waiting for GPU tick {} failed: {}", tick, exception.what());
+ throw;
}
Refresh();