Repository navigation
Allocate memory that can be shared with another device or API - #318
Open
Jasper-Bekkers wants to merge 2 commits into
Open
Jasper-Bekkers wants to merge 2 commits into
Jasper-Bekkers wants to merge 2 commits into
Conversation
Vulkan can hand memory to another device — or take it from one — through
`VkExportMemoryAllocateInfo` and `VkImportMemory{Win32Handle,Fd}InfoKHR`,
which chain onto `vkAllocateMemory`. That is the one call this crate owns and
does not expose, so callers who need a shared texture have had to allocate
around it: their own `vkAllocateMemory`, their own memory-type search, their
own `VkDeviceMemory` to bind and free, and a second ownership path through
every resource that might hold one.
`Allocator::allocate_external` chains those structs instead, so shared memory
comes back as an ordinary `Allocation` that frees like any other.
Sharing implies a dedicated allocation, since an importer receives the whole
allocation and must not find another resource's data in it — so the entry
point rejects `AllocationScheme::GpuAllocatorManaged` rather than silently
sub-allocating, and the `CpuToGpu` fallback is skipped for it: retrying would
import the same handle twice, and importing a file descriptor consumes it.
`OPAQUE_WIN32` exports get a default security descriptor and `GENERIC_ALL`,
which is what sharing within one process needs. The Win32 export info is
only chained when the handle types include `OPAQUE_WIN32`, as
VUID-VkExportMemoryWin32HandleInfoKHR-handleTypes-00657 requires.
`ImportFd` takes an `OwnedFd`. Only a successful `vkAllocateMemory` hands
the fd to the implementation, so the allocator releases it to the driver
there and closes it on every other path. The caller never has to guess
whether a failed allocation consumed it: a failure after `vkAllocateMemory`
frees memory that already owns the fd, and closing it again would close
whatever reused that fd number.
Opaque imports must use the exporter's exact memory type and allocation
size (VUID-VkMemoryAllocateInfo-allocationSize-01742). The caller provides
both through `requirements`, by narrowing `memory_type_bits` to that one
type.
Pulling the OS handle back out stays with the caller, because
`vkGetMemory{Win32Handle,Fd}KHR` live in device extensions this crate does
not load. `Allocation::memory()` is all they need for it.
Sharing a D3D12 resource only takes `D3D12_HEAP_FLAG_SHARED`, which callers can already pass through `ResourceType::Committed` — but nothing stops them asking for a shared *placed* resource, and that quietly produces something unusable: a placed resource lands on a pool heap created without the flag, and sharing that heap would hand the importer every other resource sitting on it. `ResourceType::Shared` states the intent instead of the mechanism, so the allocator adds the heap flag and commits the resource because it has to, not because the caller remembered to. That mirrors the Vulkan side, where `Allocator::allocate_external` refuses to sub-allocate for the same reason. Turning the handle into something another device can open stays with the caller: `ID3D12Device::CreateSharedHandle` takes the resource, which `Resource::resource()` already hands out.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two allocator entry points for memory that another device or API opens. Breda uses them to share textures between D3D12, Vulkan and an external host (breda#10674).
Allocator::allocate_external(desc, ExternalMemory)chainsVkExportMemoryAllocateInfoorVkImportMemory{Win32Handle,Fd}InfoKHRonto the onevkAllocateMemorythis crate owns. Shared memory comes back as an ordinaryAllocationthat frees like any other, instead of every caller writing its ownvkAllocateMemory, memory-type search and second ownership path.ResourceType::Shared { heap_properties, heap_flags }isCommittedplusD3D12_HEAP_FLAG_SHARED. A shared placed resource would sit on a pool heap created without the flag, and sharing that heap would hand the importer every other resource on it. So "sharing implies committed" lives in the allocator, not in each caller.Rules this enforces
allocate_externalrejectsAllocationScheme::GpuAllocatorManagedwithInvalidAllocationCreateDesc.CpuToGpufallback retry is skipped for external allocations. A retry would import the same handle twice.VkExportMemoryWin32HandleInfoKHR(default security descriptor,GENERIC_ALL) is only chained when the export types containOPAQUE_WIN32(VUID-VkExportMemoryWin32HandleInfoKHR-handleTypes-00657).ExternalMemory::ImportFdtakes anOwnedFd(cfg(all(unix, feature = "std"))). Per spec only a successful import transfers ownership, so the fd is released to the driver right aftervkAllocateMemorysucceeds and closed on every other path. The caller can't double-close it. That includes a failure aftervkAllocateMemory, such as mapping, where the freed memory already owned the fd.ImportWin32leaves the NT handle with the caller, because the import takes its own reference.Caller's responsibility (documented, not enforced)
OPAQUE_FD/OPAQUE_WIN32) must use the exporter's exactmemoryTypeIndexandallocationSize(VUID-VkMemoryAllocateInfo-allocationSize-01742). Pass them throughrequirements.memory_type_bits(narrowed to one bit) andrequirements.size.VkExternalMemory{Image,Buffer}CreateInfo.vkGetMemory{Win32Handle,Fd}KHR,ID3D12Device::CreateSharedHandle) stays with the caller. Those Vulkan entry points live in device extensions this crate doesn't load.Not here
No fence/semaphore export, no queue-family ownership transfer, no dma-buf / DRM modifiers.
Testing
cargo clippy --workspace --all-targets -D warningsis clean forvulkan,std,vulkan,hashbrown,d3d12,stdandvulkan,d3d12,std,visualizeron Windows.--libwithvulkan,stdandvulkan,hashbrownis clean forx86_64-unknown-linux-gnu, which covers theImportFdpath. No runtime test: nothing in this repo creates a second device to import into.This was previously the
external-memorybranch, which sat onash-next(6a68a5b). It is rebased ontomainand usespush_nextfor releasedash0.38.🤖 Generated with Claude Code