Merge pull request 'perf(window): use HOST_CACHED readback staging in SaveFrame (#74)' (#108) from claude/issue-74 into master
This commit is contained in:
commit
d77bd860ba
1 changed files with 38 additions and 2 deletions
|
|
@ -1200,11 +1200,29 @@ void Window::SaveFrame(const std::filesystem::path& path) {
|
|||
|
||||
VkMemoryRequirements memReqs;
|
||||
vkGetBufferMemoryRequirements(Device::device, stagingBuf, &memReqs);
|
||||
|
||||
// Readback path: the CPU *reads* this whole buffer back. The first
|
||||
// HOST_VISIBLE|HOST_COHERENT type is usually write-combined (uncached) on
|
||||
// discrete GPUs, where CPU reads are pathologically slow. Ask for
|
||||
// HOST_CACHED so reads hit the CPU cache, preferring a cached-coherent type
|
||||
// when one exists. HOST_CACHED is near-universal but not spec-guaranteed,
|
||||
// so fall back to any HOST_VISIBLE type (#59) if absent — that path then
|
||||
// relies on the coherency-gated invalidate below. (Deliberately NOT routed
|
||||
// through the upload-strategy helper, which steers toward write-combined
|
||||
// DEVICE_LOCAL|HOST_VISIBLE — the worst type for readback. See issue #89.)
|
||||
std::uint32_t memTypeIndex;
|
||||
try {
|
||||
memTypeIndex = Device::GetMemoryType(memReqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
} catch (const std::runtime_error&) {
|
||||
memTypeIndex = Device::GetMemoryType(memReqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||
}
|
||||
VkMemoryAllocateInfo mai{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = memReqs.size,
|
||||
.memoryTypeIndex = Device::GetMemoryType(memReqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT),
|
||||
.memoryTypeIndex = memTypeIndex,
|
||||
};
|
||||
VkDeviceMemory stagingMem = VK_NULL_HANDLE;
|
||||
Device::CheckVkResult(vkAllocateMemory(Device::device, &mai, nullptr, &stagingMem));
|
||||
|
|
@ -1289,6 +1307,24 @@ void Window::SaveFrame(const std::filesystem::path& path) {
|
|||
// Read back, swizzle BGRA → RGBA if needed, write PNG.
|
||||
void* mapped = nullptr;
|
||||
Device::CheckVkResult(vkMapMemory(Device::device, stagingMem, 0, VK_WHOLE_SIZE, 0, &mapped));
|
||||
|
||||
// If the chosen type is cached-but-not-coherent, the transfer's writes may
|
||||
// not yet be visible to the CPU read; invalidate to pull them in. Gate on
|
||||
// the chosen type's actual coherency (not the requested flags) — a coherent
|
||||
// type needs no invalidate. Whole-range invalidate sidesteps
|
||||
// nonCoherentAtomSize. This is the read-path counterpart of FlushDevice (#60).
|
||||
if (!(Device::memoryProperties.memoryTypes[memTypeIndex].propertyFlags &
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
|
||||
VkMappedMemoryRange invalidateRange{
|
||||
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
|
||||
.memory = stagingMem,
|
||||
.offset = 0,
|
||||
.size = VK_WHOLE_SIZE,
|
||||
};
|
||||
Device::CheckVkResult(
|
||||
vkInvalidateMappedMemoryRanges(Device::device, 1, &invalidateRange));
|
||||
}
|
||||
|
||||
const std::uint8_t* src = static_cast<const std::uint8_t*>(mapped);
|
||||
|
||||
std::vector<std::uint8_t> rgba(static_cast<std::size_t>(width) * height * 4);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue