[GPU] Double-buffer readback_resolve.

Introduce "fast" readback resolve that reads from previous frame's
resolve buffers, quick swap between buffers each frame to avoid
copies so minimal performance impact and mostly correct bahavior.
Checks if previous frame had a buffer for the current resolve and
falls through to the slow path, which also allows to support
"screenshot" features in the games that do that without stalling
on normal resolve operations.

Re-enabled readback_memexport as separate feature, was previously
bundled with readback_resolve (probably not intentionally) and
ensures destination address is writeable to avoid memory access
related crashes and unnecessary work.

readback_resolve cvar changes from bool to string ternary with
"none", "fast" and "full" options, defaulting to the new "fast"
mode.
This commit is contained in:
Herman S.
2025-10-31 21:20:37 +09:00
committed by Radosław Gliński
parent 93adb2bb95
commit e2c33686cc
8 changed files with 482 additions and 124 deletions

View File

@@ -754,10 +754,21 @@ class VulkanCommandProcessor final : public CommandProcessor {
// Temporary storage for memexport stream constants used in the draw.
std::vector<draw_util::MemExportRange> memexport_ranges_;
// Readback buffer for CPU access to resolved data
VkBuffer readback_buffer_ = VK_NULL_HANDLE;
VkDeviceMemory readback_buffer_memory_ = VK_NULL_HANDLE;
uint32_t readback_buffer_size_ = 0;
// Per-resolve double-buffered readback for delayed sync
struct ReadbackBuffer {
VkBuffer buffers[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE};
VkDeviceMemory memories[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE};
uint32_t sizes[2] = {0, 0};
uint32_t current_index = 0;
uint64_t last_used_frame = 0;
};
// Map: (written_address << 32 | written_length) -> ReadbackBuffer
std::unordered_map<uint64_t, ReadbackBuffer> readback_buffers_;
// Simple single buffer for memexport (always syncs, no double-buffering)
VkBuffer memexport_readback_buffer_ = VK_NULL_HANDLE;
VkDeviceMemory memexport_readback_buffer_memory_ = VK_NULL_HANDLE;
uint32_t memexport_readback_buffer_size_ = 0;
};
} // namespace vulkan