Sarek_vulkan.Vulkan_api_hostPinned and registered host memory (specs/vulkan-async-api.md).
Two sources of a host range that a VkBuffer covers:
alloc_pinned: memory the driver allocates (vkAllocateMemory from a HOST_VISIBLE | HOST_COHERENT type, HOST_CACHED when there is one), mapped once for the life of the block. The mapped pointer is the pinned address. No host page reaches the driver, so there is no userptr object and no kernel invalidation callback (the Sarek #503 path), and no extension is needed.register: the pages of a caller's range imported into the driver as device memory (VK_EXT_external_memory_host). The import covers whole pages: the range rounded outwards to the device's minImportedHostPointerAlignment. Opt-in, and refused on AMD drivers (Vulkan_host_import_policy); a device without the extension refuses it.A copy between such a range and a device buffer is one vkCmdCopyBuffer with no staging buffer and no host memcpy: the DMA engine reads or writes the host pages. A copy whose host range lies inside a buffer's range uses it, whether or not it names the allocated or registered bytes exactly.
module Device = Vulkan_api_devicemodule Ffi = Vulkan_api_host_ffitype import = {device : Device.t;base : nativeint;First covered byte: the mapped pointer of a driver allocation, or the first imported byte (a multiple of the alignment).
*)length : int;Covered bytes.
*)buffer : Vulkan_types.vk_buffer;memory : Vulkan_types.vk_device_memory;}One buffer per (device, address). import = None once the device is gone: a registered entry then stays as a tombstone so a late unregister succeeds quietly.
val entries : (int * nativeint, entry) Stdlib.Hashtbl.tLive alloc_pinned blocks. A block is driver memory owned by the device that allocated it: it is unmapped when that device is destroyed, but stays listed until free_pinned, which then succeeds without touching it.
val alignment_of : Device.t -> intval properties_fn_of : Device.t -> Vulkan_api_host_ffi.properties_fnval create_import_buffer : Device.t -> int -> Vulkan_types.vk_bufferval import_requirements :
Device.t ->
Vulkan_types.vk_buffer ->
unit Ctypes.ptr ->
int * intMemory type bits both the buffer and the host pointer allow, and the size the buffer requires.
val allocate_import :
Device.t ->
type_index:int ->
length:int ->
unit Ctypes_static.ptr ->
Vulkan_types.vk_device_memoryval pick_import_type : Device.t -> int -> intImport the pages covering the range from addr of byte_size bytes on device. The buffer's own size requirement must fit the rounded range.
val destroy_import : import -> unitLaunches and copies that name the import have completed (every copy through this module is synchronous), so the objects can go at once.
val release_import : import -> unitval release_entry : entry -> unitval destroy_entry : entry -> unitval find :
Device.t ->
addr:nativeint ->
byte_size:int ->
(Vulkan_types.vk_buffer * int) optionThe buffer and byte offset that address the range from addr of byte_size bytes of host memory on device, when an import covers it.
val check_registrable : Device.t -> unitA registered range is imported as the pages around it; the extension may ask for a coarser granule than a page, and rounding to it would import memory the process may not own.
val register : Device.t -> nativeint -> byte_size:int -> unitval unregister : Device.t -> nativeint -> unitval pinned_memory_type : Device.t -> int -> int optionThe memory type for a pinned block, best first: HOST_VISIBLE | HOST_COHERENT | HOST_CACHED, then without HOST_CACHED, both not DEVICE_LOCAL; only then the DEVICE_LOCAL ones. On a discrete GPU the DEVICE_LOCAL host-visible type is the BAR window onto VRAM, write-combined and read at 0.03 GB/s; a UMA device has only DEVICE_LOCAL types.
val create_pinned_buffer : Device.t -> int -> Vulkan_types.vk_bufferval allocate_mapped_memory :
Device.t ->
Vulkan_types.vk_buffer ->
Vulkan_types.vk_device_memory * nativeintDriver memory for buffer, bound and mapped. The mapping lasts until the memory is freed.
A driver allocation of byte_size bytes, mapped: no host memory crosses to the driver, whatever the device or the import policy.
val alloc_pinned : Device.t -> byte_size:int -> nativeintDriver-allocated, mapped host memory that DMA copies address directly.
val free_pinned : Device.t -> nativeint -> unitReleases the block's buffer and memory, which unmaps it. A block whose device was destroyed has nothing left to release. The table is keyed by address, as core's is: if the address was handed out again after the device was destroyed, a late free of the old block cannot be told from a free of the new one. Free every block before destroying its device.