Zero-copy CPU->GPU upload on Vulkan via VK_EXT_external_memory_host. More...
Detailed Description
Zero-copy CPU->GPU upload on Vulkan via VK_EXT_external_memory_host.
QRhi's own texture upload stages every frame through a buffer that VMA is asked for with VMA_MEMORY_USAGE_CPU_TO_GPU (qrhivulkan.cpp). On a discrete GPU that prefers DEVICE_LOCAL|HOST_VISIBLE, i.e. the small (~214-246 MB) host-visible BAR heap. VMA treats a heap that size as "small", so its block size is heapSize/8 and any allocation above half a block becomes a dedicated vkAllocateMemory — and Qt destroys the staging buffer after every upload ("no reuse of staging, this is intentional"). Past that threshold – half a block, i.e. heapSize/16 – each frame therefore pays a fresh BAR allocation, and the effective upload bandwidth collapses.
A capture slot has already been filled by the vendor SDK, so the right answer is not a cheaper copy but no copy: import the slot's own pages as VkDeviceMemory once at setup and let the GPU DMA straight out of them.
Requirements: the imported pointer and the imported length must both be multiples of minImportedHostPointerAlignment (4096 on NVIDIA), which is why slots that want this path must be allocated through alignedSlotAlloc.
Go to the source code of this file.
Classes | |
| struct | score::gfx::interop::VkHostImportedBuffer |
| class | score::gfx::interop::VkHostImportUpload |
Namespaces | |
| namespace | score |
| Base toolkit upon which the software is built. | |
| namespace | score::gfx |
| Graphics rendering pipeline for ossia score. | |
Functions | |
| void * | score::gfx::interop::alignedSlotAlloc (std::size_t bytes, std::size_t alignment) |
| void | score::gfx::interop::alignedSlotFree (void *p) |
| void * | score::gfx::interop::importableAlloc (std::size_t bytes) |
| void | score::gfx::interop::importableFree (void *p) |
| bool | score::gfx::interop::importHostPointerBuffer (QRhi &, void *, std::size_t, unsigned, bool, VkHostImportedBuffer &out) |
| void | score::gfx::interop::releaseHostImportedBuffer (QRhi &rhi, VkHostImportedBuffer &buf) |
| GPU must be done with the buffer (e.g. after QRhi::finish()). | |
Function Documentation
◆ alignedSlotAlloc()
| void * score::gfx::interop::alignedSlotAlloc | ( | std::size_t | bytes, |
| std::size_t | alignment | ||
| ) |
Page-aligned slot storage. Plain new/vector alignment is not enough for VK_EXT_external_memory_host.
◆ importableAlloc()
| void * score::gfx::interop::importableAlloc | ( | std::size_t | bytes | ) |
Storage a graphics API can import directly, as opposed to merely being page-aligned.
On Windows the two are not the same thing: ID3D12Device3::OpenExistingHeapFromAddress rejects _aligned_malloc memory with E_INVALIDARG because it needs the base address of a virtual-memory reservation at the 64 KB system allocation granularity, and a 4 KB-aligned heap pointer lands mid-block. VirtualAlloc gives that; Vulkan's VK_EXT_external_memory_host accepts it too, so one allocator serves both rungs. Elsewhere this is just the page-aligned allocation.
Use for buffers a capture rung may hand to the GPU. Ordinary staging slots should keep alignedSlotAlloc – reserving 64 KB blocks for them would waste address space for no benefit.
◆ importHostPointerBuffer()
| bool score::gfx::interop::importHostPointerBuffer | ( | QRhi & | rhi, |
| void * | host, | ||
| std::size_t | bytes, | ||
| unsigned | bufferUsage, | ||
| bool | requireHostCoherent, | ||
| VkHostImportedBuffer & | out | ||
| ) |
Imports host as the storage of a new VkBuffer with the given VkBufferUsageFlags. host must be VkHostImportUpload::requiredAlignment aligned; the imported length is bytes rounded up to that alignment, so the caller must own that much. With requireHostCoherent, only HOST_COHERENT memory types are accepted (CPU reads then need no vkInvalidateMappedMemoryRanges), preferring HOST_CACHED ones.