内存分配
Vulkan 内存分为两种类型:主机内存 和 设备内存。
主机内存
主机内存是 Vulkan 实现所需的,用于非设备可见的存储。
此内存 可能 用于存储 Vulkan 对象的实现表示和状态。 |
Vulkan 为应用程序提供了代表 Vulkan 实现执行主机内存分配的机会。 如果不使用此功能,则实现将执行自己的内存分配。 由于大多数内存分配不在关键路径上,因此这并非旨在作为性能功能。 相反,这 可以 对某些嵌入式系统、调试目的(例如,在所有主机分配后放置一个保护页)或内存分配日志记录很有用。
分配器由应用程序以指向 VkAllocationCallbacks
结构的指针形式提供
// Provided by VK_VERSION_1_0
typedef struct VkAllocationCallbacks {
void* pUserData;
PFN_vkAllocationFunction pfnAllocation;
PFN_vkReallocationFunction pfnReallocation;
PFN_vkFreeFunction pfnFree;
PFN_vkInternalAllocationNotification pfnInternalAllocation;
PFN_vkInternalFreeNotification pfnInternalFree;
} VkAllocationCallbacks;
-
pUserData
是一个值,由回调的实现来解释。 当调用VkAllocationCallbacks
中的任何回调时,Vulkan 实现将此值作为回调的第一个参数传递。 此值 可以 在每次将分配器传递到命令时发生变化,即使同一对象在多个命令中采用分配器也是如此。 -
pfnAllocation
是指向应用程序定义的内存分配函数的 PFN_vkAllocationFunction 指针。 -
pfnReallocation
是指向应用程序定义的内存重新分配函数的 PFN_vkReallocationFunction 指针。 -
pfnFree
是指向应用程序定义的内存释放函数的 PFN_vkFreeFunction 指针。 -
pfnInternalAllocation
是指向应用程序定义的函数的 PFN_vkInternalAllocationNotification 指针,当实现进行内部分配时,将调用该函数。 -
pfnInternalFree
是指向应用程序定义的函数的 PFN_vkInternalFreeNotification 指针,当实现释放内部分配时,将调用该函数。
pfnAllocation
的类型为
// Provided by VK_VERSION_1_0
typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)(
void* pUserData,
size_t size,
size_t alignment,
VkSystemAllocationScope allocationScope);
-
pUserData
是应用程序指定的分配器中 VkAllocationCallbacks::pUserData
指定的值。 -
size
是请求的分配的字节大小。 -
alignment
是请求的分配对齐方式(以字节为单位),并且 必须 是 2 的幂。 -
allocationScope
是一个 VkSystemAllocationScope 值,指定分配生存期的分配范围,如此处所述。
如果 pfnAllocation
无法分配请求的内存,则 必须 返回 NULL
。 如果分配成功,则 必须 返回指向至少包含 size
字节的内存分配的有效指针,并且指针值是 alignment
的倍数。
如果应用程序不遵循这些规则,则 无法 假定 Vulkan 操作正确。 例如, |
如果 pfnAllocation
返回 NULL
,并且如果实现无法在没有请求的分配的情况下继续正确处理当前命令,则必须将其视为运行时错误,并在检测到该情况的命令的适当时间生成 VK_ERROR_OUT_OF_HOST_MEMORY
,如 返回码 中所述。
如果实现能够在没有请求的分配的情况下继续正确处理当前命令,则可以这样做,并且不得因分配失败而生成 VK_ERROR_OUT_OF_HOST_MEMORY
。
pfnReallocation
的类型是
// Provided by VK_VERSION_1_0
typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)(
void* pUserData,
void* pOriginal,
size_t size,
size_t alignment,
VkSystemAllocationScope allocationScope);
-
pUserData
是应用程序指定的分配器中 VkAllocationCallbacks::pUserData
指定的值。 -
pOriginal
必须是NULL
,或者是指向先前由兼容分配器的pfnReallocation
或pfnAllocation
返回的指针。 -
size
是请求的分配的字节大小。 -
alignment
是请求的分配对齐方式(以字节为单位),并且 必须 是 2 的幂。 -
allocationScope
是一个 VkSystemAllocationScope 值,指定分配生存期的分配范围,如此处所述。
如果重新分配成功,pfnReallocation
必须返回具有足够空间容纳 size
字节的分配,并且原始分配中从零字节到 min(原始大小, 新大小) - 1 的内容必须保留在返回的分配中。如果 size
大于旧大小,则额外空间的内容是未定义的。如果满足这些要求涉及创建新的分配,则应释放旧的分配。
如果 pOriginal
为 NULL
,则 pfnReallocation
必须表现得等同于使用相同参数值(不包括 pOriginal
)调用 PFN_vkAllocationFunction。
如果 size
为零,则 pfnReallocation
必须表现得等同于使用相同的 pUserData
参数值且 pMemory
等于 pOriginal
调用 PFN_vkFreeFunction。
如果 pOriginal
不为 NULL
,则实现必须确保 alignment
等于最初分配 pOriginal
时使用的 alignment
。
如果此函数失败且 pOriginal
不为 NULL
,则应用程序不得释放旧的分配。
pfnReallocation
必须遵循与 PFN_vkAllocationFunction
相同的返回值规则。
pfnFree
的类型是
// Provided by VK_VERSION_1_0
typedef void (VKAPI_PTR *PFN_vkFreeFunction)(
void* pUserData,
void* pMemory);
-
pUserData
是应用程序指定的分配器中 VkAllocationCallbacks::pUserData
指定的值。 -
pMemory
是要释放的分配。
pMemory
可以为 NULL
,回调必须安全地处理这种情况。如果 pMemory
不为 NULL
,则它必须是先前由 pfnAllocation
或 pfnReallocation
分配的指针。应用程序应该释放此内存。
pfnInternalAllocation
的类型是
// Provided by VK_VERSION_1_0
typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)(
void* pUserData,
size_t size,
VkInternalAllocationType allocationType,
VkSystemAllocationScope allocationScope);
-
pUserData
是应用程序指定的分配器中 VkAllocationCallbacks::pUserData
指定的值。 -
size
是请求的分配大小。 -
allocationType
是一个 VkInternalAllocationType 值,指定请求的分配类型。 -
allocationScope
是一个 VkSystemAllocationScope 值,指定分配生存期的分配范围,如此处所述。
这是一个纯粹的信息性回调。
pfnInternalFree
的类型是
// Provided by VK_VERSION_1_0
typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)(
void* pUserData,
size_t size,
VkInternalAllocationType allocationType,
VkSystemAllocationScope allocationScope);
-
pUserData
是应用程序指定的分配器中 VkAllocationCallbacks::pUserData
指定的值。 -
size
是请求的分配大小。 -
allocationType
是一个 VkInternalAllocationType 值,指定请求的分配类型。 -
allocationScope
是一个 VkSystemAllocationScope 值,指定分配生存期的分配范围,如此处所述。
每个分配都有一个分配范围,定义其生命周期以及它与哪个对象相关联。传递给 VkAllocationCallbacks 指定的回调函数的 allocationScope
参数的可能值(指示分配范围)是
// Provided by VK_VERSION_1_0
typedef enum VkSystemAllocationScope {
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1,
VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3,
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4,
} VkSystemAllocationScope;
-
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND
指定分配的范围是 Vulkan 命令的持续时间。 -
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
指定分配的范围是正在创建或使用的 Vulkan 对象的生命周期。 -
VK_SYSTEM_ALLOCATION_SCOPE_CACHE
指定分配的范围是VkPipelineCache
或VkValidationCacheEXT
对象的生命周期。 -
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE
指定分配的范围是 Vulkan 设备的生命周期。 -
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
指定分配的范围是 Vulkan 实例的生命周期。
大多数 Vulkan 命令都对单个对象进行操作,或者存在正在创建或操作的唯一对象。当分配使用 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
或 VK_SYSTEM_ALLOCATION_SCOPE_CACHE
的分配范围时,该分配的范围是正在创建或操作的对象。
当实现需要主机内存时,它将使用最可用的特定分配器和分配范围回调应用程序
-
如果分配的范围是命令的持续时间,则分配器将使用
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND
分配范围。使用最可用的特定分配器:如果要创建或操作的对象具有分配器,则将使用该对象的分配器;否则,如果父VkDevice
具有分配器,则将使用该分配器;否则,如果父VkInstance
具有分配器,则将使用该分配器。否则, -
如果分配与
VkValidationCacheEXT
或VkPipelineCache
对象相关联,则分配器将使用VK_SYSTEM_ALLOCATION_SCOPE_CACHE
分配范围。使用最可用的特定分配器(缓存,否则设备,否则实例)。否则, -
如果分配的范围是对象的生命周期,则该对象正在被命令创建或操作,并且该对象的类型不是
VkDevice
或VkInstance
,则分配器将使用VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
的分配范围。使用最可用的特定分配器(对象,否则设备,否则实例)。否则, -
如果分配的范围是设备的生命周期,则分配器将使用
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE
的分配范围。使用最可用的特定分配器(设备,否则实例)。否则, -
如果分配的范围是实例的生命周期,并且该实例具有分配器,则将使用其分配器,其分配范围为
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
。 -
否则,实现将通过未指定的替代机制分配内存。
从池中分配的对象不指定它们自己的分配器。当实现需要此类对象的主机内存时,该内存来自对象的父池的分配器。
由于不同平台之间安全实现的复杂性,应用程序不应处理旨在由主机执行的内存的分配。实现将在内部分配此类内存,并在分配和释放这些内部分配时调用应用程序提供的信息性回调。分配可执行内存后,将调用 pfnInternalAllocation
。释放可执行内存后,将调用 pfnInternalFree
。实现只会为可执行内存的分配和释放调用信息性回调。
pfnInternalAllocation
和 pfnInternalFree
函数的 allocationType
参数可能是以下值之一
// Provided by VK_VERSION_1_0
typedef enum VkInternalAllocationType {
VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0,
} VkInternalAllocationType;
-
VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE
指定分配旨在由主机执行。
在执行 API 命令期间,实现必须仅调用应用程序提供的分配器。实现必须仅从调用发起 API 命令的同一线程调用应用程序提供的分配器。实现应该不同步对任何回调的调用。如果需要同步,回调必须自行提供。信息回调与分配回调受到相同的限制。
如果实现在 vkCreate*
命令返回和对应的 vkDestroy*
命令开始之间的时间内打算通过 VkAllocationCallbacks
结构进行调用,则该实现必须在 vkCreate*
命令返回之前保存分配器的副本。回调函数及其所依赖的任何数据结构,在它们所关联的对象的生命周期内必须保持有效。
如果向 vkCreate*
命令提供了分配器,则必须向对应的 vkDestroy*
命令提供一个兼容的分配器。如果使用每个结构中的 pfnAllocation
或 pfnReallocation
分配的内存可以使用另一个结构中的 pfnReallocation
或 pfnFree
释放,则两个 VkAllocationCallbacks
结构是兼容的。如果没有向对应的 vkCreate*
命令提供分配器,则必须不向 vkDestroy*
命令提供分配器。
如果使用非 NULL
分配器,则 pfnAllocation
、pfnReallocation
和 pfnFree
成员必须为非 NULL
,并指向回调的有效实现。应用程序可以选择不提供信息回调,方法是将 pfnInternalAllocation
和 pfnInternalFree
都设置为 NULL
。pfnInternalAllocation
和 pfnInternalFree
必须要么都为 NULL
,要么都为非 NULL
。
如果 pfnAllocation
或 pfnReallocation
失败,则实现可能会使对象创建失败和/或生成 VK_ERROR_OUT_OF_HOST_MEMORY
错误(如适用)。
分配回调必须不调用任何 Vulkan 命令。
以下规则集定义了实现何时可以调用分配器回调。
pfnAllocation
或 pfnReallocation
可能在以下情况下被调用:
-
作用域为
VkDevice
或VkInstance
的分配可能从任何 API 命令中分配。 -
作用域为命令的分配可能从任何 API 命令中分配。
-
作用域为
VkPipelineCache
的分配可能仅从以下命令中分配:-
vkCreatePipelineCache
-
vkMergePipelineCaches
,针对dstCache
-
vkCreateGraphicsPipelines
,针对pipelineCache
-
vkCreateComputePipelines
,针对pipelineCache
-
-
作用域为
VkValidationCacheEXT
的分配可能仅从以下命令中分配:-
vkCreateValidationCacheEXT
-
vkMergeValidationCachesEXT
,针对dstCache
-
vkCreateShaderModule
,针对 VkShaderModuleValidationCacheCreateInfoEXT 中的validationCache
-
-
作用域为
VkDescriptorPool
的分配可能仅从以下命令中分配:-
任何将池作为直接参数的命令
-
vkAllocateDescriptorSets
,针对其pAllocateInfo
参数的descriptorPool
成员 -
vkCreateDescriptorPool
-
-
作用域为
VkCommandPool
的分配可能仅从以下命令中分配:-
任何将池作为直接参数的命令
-
vkCreateCommandPool
-
vkAllocateCommandBuffers
,针对其pAllocateInfo
参数的commandPool
成员 -
任何
vkCmd*
命令,其commandBuffer
是从该VkCommandPool
分配的
-
-
作用域为任何其他对象的分配可能仅在该对象的
vkCreate*
命令中分配。
pfnFree
或 pfnReallocation
(size
为零)可能在以下情况下被调用:
-
作用域为
VkDevice
或VkInstance
的分配可能从任何 API 命令中释放。 -
作用域为命令的分配必须由分配此类内存的任何 API 命令释放。
-
作用域为
VkPipelineCache
的分配可能从vkDestroyPipelineCache
中释放。 -
作用域为
VkValidationCacheEXT
的分配可能从vkDestroyValidationCacheEXT
中释放。 -
作用域为
VkDescriptorPool
的分配可能从以下命令中释放:-
任何将池作为直接参数的命令
-
-
作用域为
VkCommandPool
的分配可能从以下命令中释放:-
任何将池作为直接参数的命令
-
vkResetCommandBuffer
,其commandBuffer
是从该VkCommandPool
分配的
-
-
作用域为任何其他对象的分配可能在该对象的
vkDestroy*
命令中释放。 -
任何分配主机内存的命令可能也会释放相同作用域的主机内存。
设备内存
设备内存是设备可见的内存 — 例如,图像或缓冲区对象的内容,这些内容可以由设备本地使用。
设备内存属性
物理设备的内存属性描述了可用的内存堆和内存类型。
要查询内存属性,请调用
// Provided by VK_VERSION_1_0
void vkGetPhysicalDeviceMemoryProperties(
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceMemoryProperties* pMemoryProperties);
-
physicalDevice
是要查询的设备的句柄。 -
pMemoryProperties
是指向 VkPhysicalDeviceMemoryProperties 结构的指针,属性将在其中返回。
VkPhysicalDeviceMemoryProperties
结构定义为
// Provided by VK_VERSION_1_0
typedef struct VkPhysicalDeviceMemoryProperties {
uint32_t memoryTypeCount;
VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES];
uint32_t memoryHeapCount;
VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS];
} VkPhysicalDeviceMemoryProperties;
-
memoryTypeCount
是memoryTypes
数组中有效元素的数量。 -
memoryTypes
是VK_MAX_MEMORY_TYPES
个 VkMemoryType 结构的数组,描述了可以用于访问从memoryHeaps
指定的堆分配的内存的内存类型。 -
memoryHeapCount
是memoryHeaps
数组中有效元素的数量。 -
memoryHeaps
是VK_MAX_MEMORY_HEAPS
个 VkMemoryHeap 结构的数组,描述了从中可以分配内存的内存堆。
VkPhysicalDeviceMemoryProperties
结构描述了多个内存堆以及多个可用于访问这些堆中分配的内存的内存类型。 每个堆描述特定大小的内存资源,每个内存类型描述一组可用于给定内存堆的内存属性(例如,主机缓存与非缓存)。 使用特定内存类型的分配将消耗该内存类型堆索引所指示的堆中的资源。 多个内存类型可能共享每个堆,堆和内存类型提供了一种机制,在允许内存与各种不同属性一起使用的同时,也能展示物理内存资源的准确大小。
内存堆的数量由 memoryHeapCount
给出,且小于等于 VK_MAX_MEMORY_HEAPS
。每个堆由 memoryHeaps
数组的元素以 VkMemoryHeap 结构的形式描述。所有内存堆可用的内存类型数量由 memoryTypeCount
给出,且小于等于 VK_MAX_MEMORY_TYPES
。每个内存类型由 memoryTypes
数组的元素以 VkMemoryType 结构的形式描述。
至少一个堆的 VkMemoryHeap::flags
中必须包含 VK_MEMORY_HEAP_DEVICE_LOCAL_BIT
。 如果多个堆都具有相似的性能特征,它们都可以包含 VK_MEMORY_HEAP_DEVICE_LOCAL_BIT
。 在统一内存架构 (UMA) 系统中,通常只有一个内存堆被认为对主机和设备都同样“本地”,并且这样的实现必须将该堆标记为设备本地。
通过 vkGetPhysicalDeviceMemoryProperties 返回的每个内存类型的 propertyFlags
必须设置为以下值之一
-
0
-
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
-
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT
-
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
-
VK_MEMORY_PROPERTY_PROTECTED_BIT
-
VK_MEMORY_PROPERTY_PROTECTED_BIT
|VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
-
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
-
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
-
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
|
VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD
-
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
|
VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
|
VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
|
VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
|
VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV
必须至少有一个内存类型的 propertyFlags
中同时设置了 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
和 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
位。 必须至少有一个内存类型的 propertyFlags
中设置了 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
位。 如果启用了 deviceCoherentMemory
功能,则必须至少有一个内存类型的 propertyFlags
中设置了 VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
位。
对于 memoryTypes
中返回的每对元素 X 和 Y,如果满足以下条件,X 必须放置在比 Y 更低的索引位置:
-
X 的
propertyFlags
成员中返回的位标志集合是 Y 的propertyFlags
成员中返回的位标志集合的严格子集; 或者 -
X 和 Y 的
propertyFlags
成员相等,且 X 属于性能更高的内存堆(以特定于实现的方式确定); 或者 -
Y 的
propertyFlags
成员包含VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
或VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD
,而 X 不包含
如果 X 和 Y 的 使用设备相干或非缓存设备内存类型可能会导致性能损失,而意外使用这些类型是不希望发生的。为了避免这种情况,具有这些属性的内存类型始终显示在列表的末尾; 但在其他方面仍遵循相同的规则。 |
这种排序要求使应用程序能够使用简单的搜索循环来选择所需的内存类型,例如:
// Find a memory in `memoryTypeBitsRequirement` that includes all of `requiredProperties`
int32_t findProperties(const VkPhysicalDeviceMemoryProperties* pMemoryProperties,
uint32_t memoryTypeBitsRequirement,
VkMemoryPropertyFlags requiredProperties) {
const uint32_t memoryCount = pMemoryProperties->memoryTypeCount;
for (uint32_t memoryIndex = 0; memoryIndex < memoryCount; ++memoryIndex) {
const uint32_t memoryTypeBits = (1 << memoryIndex);
const bool isRequiredMemoryType = memoryTypeBitsRequirement & memoryTypeBits;
const VkMemoryPropertyFlags properties =
pMemoryProperties->memoryTypes[memoryIndex].propertyFlags;
const bool hasRequiredProperties =
(properties & requiredProperties) == requiredProperties;
if (isRequiredMemoryType && hasRequiredProperties)
return static_cast<int32_t>(memoryIndex);
}
// failed to find memory type
return -1;
}
// Try to find an optimal memory type, or if it does not exist try fallback memory type
// `device` is the VkDevice
// `image` is the VkImage that requires memory to be bound
// `memoryProperties` properties as returned by vkGetPhysicalDeviceMemoryProperties
// `requiredProperties` are the property flags that must be present
// `optimalProperties` are the property flags that are preferred by the application
VkMemoryRequirements memoryRequirements;
vkGetImageMemoryRequirements(device, image, &memoryRequirements);
int32_t memoryType =
findProperties(&memoryProperties, memoryRequirements.memoryTypeBits, optimalProperties);
if (memoryType == -1) // not found; try fallback properties
memoryType =
findProperties(&memoryProperties, memoryRequirements.memoryTypeBits, requiredProperties);
VK_MAX_MEMORY_TYPES
是描述内存类型的 VkMemoryType 结构数组的长度,如 VkPhysicalDeviceMemoryProperties::memoryTypes
中返回的那样。
#define VK_MAX_MEMORY_TYPES 32U
VK_MAX_MEMORY_HEAPS
是描述内存堆的 VkMemoryHeap 结构数组的长度,如 VkPhysicalDeviceMemoryProperties::memoryHeaps
中返回的那样。
#define VK_MAX_MEMORY_HEAPS 16U
要查询内存属性,请调用
// Provided by VK_VERSION_1_1
void vkGetPhysicalDeviceMemoryProperties2(
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
或等效命令
// Provided by VK_KHR_get_physical_device_properties2
void vkGetPhysicalDeviceMemoryProperties2KHR(
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
-
physicalDevice
是要查询的设备的句柄。 -
pMemoryProperties
是指向 VkPhysicalDeviceMemoryProperties2 结构的指针,其中返回属性。
vkGetPhysicalDeviceMemoryProperties2
的行为类似于 vkGetPhysicalDeviceMemoryProperties,但能够在输出结构的 pNext
链中返回扩展信息。
VkPhysicalDeviceMemoryProperties2
结构定义如下:
// Provided by VK_VERSION_1_1
typedef struct VkPhysicalDeviceMemoryProperties2 {
VkStructureType sType;
void* pNext;
VkPhysicalDeviceMemoryProperties memoryProperties;
} VkPhysicalDeviceMemoryProperties2;
或等效的
// Provided by VK_KHR_get_physical_device_properties2
typedef VkPhysicalDeviceMemoryProperties2 VkPhysicalDeviceMemoryProperties2KHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memoryProperties
是一个 VkPhysicalDeviceMemoryProperties 结构,该结构填充的值与 vkGetPhysicalDeviceMemoryProperties 中的值相同。
VkMemoryHeap
结构定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkMemoryHeap {
VkDeviceSize size;
VkMemoryHeapFlags flags;
} VkMemoryHeap;
-
size
是堆中内存的总大小(以字节为单位)。 -
flags
是 VkMemoryHeapFlagBits 的位掩码,指定堆的属性标志。
在 VkMemoryHeap::flags
中可以设置的位,指示堆的属性标志是
// Provided by VK_VERSION_1_0
typedef enum VkMemoryHeapFlagBits {
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001,
// Provided by VK_VERSION_1_1
VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002,
// Provided by VK_KHR_device_group_creation
VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT,
} VkMemoryHeapFlagBits;
-
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT
指定堆对应于设备本地内存。 设备本地内存可能具有与主机本地内存不同的性能特征,并且可能支持不同的内存属性标志。 -
VK_MEMORY_HEAP_MULTI_INSTANCE_BIT
指定在表示多个物理设备的逻辑设备中,存在每个物理设备实例的堆内存。 默认情况下,从此类堆进行的分配将复制到每个物理设备的堆实例。
// Provided by VK_VERSION_1_0
typedef VkFlags VkMemoryHeapFlags;
VkMemoryHeapFlags
是用于设置零个或多个 VkMemoryHeapFlagBits 的掩码的位掩码类型。
VkMemoryType
结构定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkMemoryType {
VkMemoryPropertyFlags propertyFlags;
uint32_t heapIndex;
} VkMemoryType;
-
heapIndex
描述此内存类型对应的内存堆,且必须小于 VkPhysicalDeviceMemoryProperties 结构中的memoryHeapCount
。 -
propertyFlags
是一个位掩码,表示此内存类型的属性,其值为 VkMemoryPropertyFlagBits 的组合。
在 VkMemoryType::propertyFlags
中 可能 设置的位,表示内存类型的属性,包括:
// Provided by VK_VERSION_1_0
typedef enum VkMemoryPropertyFlagBits {
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002,
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004,
VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008,
VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010,
// Provided by VK_VERSION_1_1
VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020,
// Provided by VK_AMD_device_coherent_memory
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD = 0x00000040,
// Provided by VK_AMD_device_coherent_memory
VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD = 0x00000080,
// Provided by VK_NV_external_memory_rdma
VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV = 0x00000100,
} VkMemoryPropertyFlagBits;
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
位表示使用此类型分配的内存对于设备访问是最有效的。当且仅当内存类型属于设置了VK_MEMORY_HEAP_DEVICE_LOCAL_BIT
的堆时,才会设置此属性。 -
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
位表示可以使用 vkMapMemory 将使用此类型分配的内存映射到主机访问。 -
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
位表示主机缓存管理命令 vkFlushMappedMemoryRanges 和 vkInvalidateMappedMemoryRanges 不需要管理主机上的可用性和可见性。 -
VK_MEMORY_PROPERTY_HOST_CACHED_BIT
位表示使用此类型分配的内存在主机上被缓存。主机访问未缓存的内存比访问缓存的内存慢,但是未缓存的内存始终与主机保持一致性。 -
VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
位表示内存类型只允许设备访问该内存。内存类型 必须 不能同时设置VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
和VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
。此外,对象的后备内存 可能 由实现延迟提供,如延迟分配内存中所述。 -
VK_MEMORY_PROPERTY_PROTECTED_BIT
位表示内存类型只允许设备访问该内存,并且允许受保护的队列操作访问该内存。内存类型 必须 不能设置VK_MEMORY_PROPERTY_PROTECTED_BIT
,并且也不能设置VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
、VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
或VK_MEMORY_PROPERTY_HOST_CACHED_BIT
中的任何一个。 -
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
位表示设备对此内存类型的分配的访问会自动使设备上的可用性和可见性。如果与VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
配对,则主机和设备之间也会自动执行内存域操作。 -
VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD
位表示使用此类型分配的内存不会在设备上缓存。未缓存的设备内存始终与设备保持一致性。 -
VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV
位表示外部设备可以直接访问此内存。
对于任何同时设置了 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
和 VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
的内存,主机或设备的访问也会执行自动的内存域传输操作,这样写入总是自动对主机和设备内存域可用和可见。
设备一致性对于某些调试用例(例如,崩溃分析,其中执行单独的一致性操作可能意味着值无法正确报告)非常有用。但是,设备一致性访问可能比没有设备一致性的等效访问慢,特别是如果它们也是设备未缓存的。特别是对于设备未缓存的内存,在短时间内(例如,在帧内)重复访问相同或相邻的内存位置可能比等效的缓存内存类型慢。因此,除非确实需要,否则通常不建议使用设备一致性或设备未缓存的内存。 |
// Provided by VK_VERSION_1_0
typedef VkFlags VkMemoryPropertyFlags;
VkMemoryPropertyFlags
是一种位掩码类型,用于设置零个或多个 VkMemoryPropertyFlagBits 的掩码。
如果 VkPhysicalDeviceMemoryBudgetPropertiesEXT
结构包含在 VkPhysicalDeviceMemoryProperties2 的 pNext
链中,则会填充当前的内存预算和使用情况。
VkPhysicalDeviceMemoryBudgetPropertiesEXT
结构定义如下:
// Provided by VK_EXT_memory_budget
typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT {
VkStructureType sType;
void* pNext;
VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS];
VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS];
} VkPhysicalDeviceMemoryBudgetPropertiesEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
heapBudget
是一个包含VK_MAX_MEMORY_HEAPS
个VkDeviceSize
值的数组,其中返回内存预算,每个内存堆对应一个元素。堆的预算是对进程在分配 可能 失败或导致性能下降之前可以从该堆分配多少内存的粗略估计。预算包括任何当前已分配的设备内存。 -
heapUsage
是一个包含VK_MAX_MEMORY_HEAPS
个VkDeviceSize
值的数组,其中返回内存使用情况,每个内存堆对应一个元素。堆的使用情况是对进程当前在该堆中使用的内存量的估计。
此结构中返回的值不是不变的。对于大于或等于 VkPhysicalDeviceMemoryProperties::memoryHeapCount
的数组元素,heapBudget
和 heapUsage
值 必须 为零。对于小于 VkPhysicalDeviceMemoryProperties::memoryHeapCount
的数组元素,heapBudget
值 必须 为非零值。对于每个堆,heapBudget
值 必须 小于或等于 VkMemoryHeap::size
。
设备内存对象
Vulkan 设备通过 API 中由 VkDeviceMemory
句柄表示的内存对象来操作设备内存中的数据。
// Provided by VK_VERSION_1_0
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory)
设备内存分配
要分配内存对象,请调用:
// Provided by VK_VERSION_1_0
VkResult vkAllocateMemory(
VkDevice device,
const VkMemoryAllocateInfo* pAllocateInfo,
const VkAllocationCallbacks* pAllocator,
VkDeviceMemory* pMemory);
-
device
是拥有内存的逻辑设备。 -
pAllocateInfo
是指向 VkMemoryAllocateInfo 结构的指针,该结构描述了分配的参数。成功返回的分配 必须 使用请求的参数,实现不允许进行替换。 -
pAllocator
控制主机内存分配,如内存分配章节中所述。 -
pMemory
是指向 VkDeviceMemory 句柄的指针,其中返回有关已分配内存的信息。
vkAllocateMemory
返回的分配保证满足实现的任何对齐要求。例如,如果实现要求图像的对齐为 128 字节,缓冲区的对齐为 64 字节,则通过此机制返回的设备内存将是 128 字节对齐的。这确保应用程序 可以 在同一内存对象中正确地子分配不同类型的对象(可能具有不同的对齐要求)。
分配内存时,其内容是 未定义的,但有以下约束:
-
非保护内存的内容必须不能依赖于受保护内存对象的内容,即使这些内存对象之前已被释放。
一个应用程序分配的内存的内容应该不能依赖于另一个应用程序的受保护内存对象的数据,即使这些内存对象之前已被释放。 |
在 VkDevice 中同时存在的有效内存分配的最大数量可能会受到实现或平台相关的限制。 maxMemoryAllocationCount
特性描述了在遇到这些内部限制之前可以同时存在的分配数量。
由于历史原因,如果超出 |
许多受保护内存的实现涉及复杂的硬件和系统软件支持,并且通常在同时进行的受保护内存分配(来自具有 |
某些平台可能对单个分配的最大大小有限制。例如,某些系统可能无法创建大小大于或等于 4GB 的分配。这种限制取决于实现,如果发生此类失败,则必须返回错误 VK_ERROR_OUT_OF_DEVICE_MEMORY
。此限制在 VkPhysicalDeviceMaintenance3Properties::maxMemoryAllocationSize
中声明。
分配给堆的累积内存大小可能受到指定堆大小的限制。在这种情况下,分配的内存会按设备和每个堆进行跟踪。某些平台允许过度分配到其他堆中。过度分配的行为可以通过 VK_AMD_memory_overallocation_behavior
扩展来指定。
如果启用了 VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT::pageableDeviceLocalMemory
特性,则从 VkMemoryHeap::flags
中包含 VK_MEMORY_HEAP_DEVICE_LOCAL_BIT
的堆中进行的内存分配可能会被透明地移动到主机本地内存,从而允许多个应用程序共享设备本地内存。如果当进行新的分配时,设备本地内存中没有剩余空间,则其他分配可能会被透明地移出以腾出空间。操作系统将根据特定于平台的标准确定要将哪些分配移动到设备本地内存或主机本地内存。为了帮助操作系统做出好的选择,应用程序应该使用 VkMemoryPriorityAllocateInfoEXT 设置适当的内存优先级,并在必要时使用 vkSetDeviceMemoryPriorityEXT 进行调整。优先级较高的分配将首先移动到设备本地内存。
在没有 VK_MEMORY_HEAP_DEVICE_LOCAL_BIT
属性的堆上进行的内存分配,不会被操作系统透明地提升到设备本地内存。
VkMemoryAllocateInfo
结构的定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkMemoryAllocateInfo {
VkStructureType sType;
const void* pNext;
VkDeviceSize allocationSize;
uint32_t memoryTypeIndex;
} VkMemoryAllocateInfo;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
allocationSize
是分配的大小(以字节为单位)。 -
memoryTypeIndex
是一个索引,用于标识 VkPhysicalDeviceMemoryProperties 结构的memoryTypes
数组中的内存类型。
已分配的设备内存对象的内部数据必须包含对实现特定资源的引用,称为内存对象的有效负载。应用程序可以导入和导出该内部数据到设备内存对象以及从设备内存对象中导出,以在 Vulkan 实例和其他兼容 API 之间共享数据。如果 VkMemoryAllocateInfo
结构的 pNext
链包含以下结构之一,则它定义了一个内存导入操作:
-
VkImportMemoryWin32HandleInfoKHR,其中
handleType
值非零。 -
VkImportMemoryFdInfoKHR,其中
handleType
值非零。 -
VkImportMemoryHostPointerInfoEXT,其中
handleType
值非零。 -
VkImportAndroidHardwareBufferInfoANDROID,其中
buffer
值非NULL
。 -
VkImportMemoryZirconHandleInfoFUCHSIA,其中
handleType
值非零。 -
VkImportScreenBufferInfoQNX,其中
buffer
值非NULL
。
如果参数定义了一个导入操作,并且外部句柄类型为 VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT
、VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT
或 VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT
,则 allocationSize
将被忽略。实现 必须 从操作系统查询这些分配的大小。
通过内存导入操作构造的设备内存对象是否持有对其有效负载的引用,取决于用于执行导入的句柄类型的属性,如下面为每个有效的句柄类型定义的那样。导入内存 必须 不修改内存的内容。实现 必须 确保导入内存不会使导入的 Vulkan 实例访问其他 Vulkan 实例中的任何内存或资源,除了与导入的内存对象对应的内存或资源。实现 必须 还确保访问未初始化的导入内存不会使导入的 Vulkan 实例从导出的 Vulkan 实例获取数据,反之亦然。
导出和导入的内存如何隔离取决于实现,但应用程序应注意,这种隔离 可能 会阻止实现将多个可导出的内存对象放置在同一物理或虚拟页面中。因此,应用程序 应该 尽可能避免创建许多小的外部内存对象。 |
导入内存 必须 不会增加系统内的总体堆使用量。但是,它 必须 影响以下每个进程的值:
-
VkPhysicalDeviceLimits::
maxMemoryAllocationCount
-
VkPhysicalDeviceMemoryBudgetPropertiesEXT::
heapUsage
执行内存导入操作时,应用程序有责任确保外部句柄及其关联的有效负载满足所有有效的用法要求。但是,实现 必须 对外部句柄和有效负载执行充分的验证,以确保该操作产生有效的内存对象,该对象在按照其分配参数允许使用时不会导致程序终止、设备丢失、队列停顿或损坏其他资源。如果提供的外部句柄不满足这些要求,则实现 必须 使内存导入操作失败,并返回错误代码 VK_ERROR_INVALID_EXTERNAL_HANDLE
。如果参数定义了一个导出操作,并且外部句柄类型为 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID
,则实现 应该 不严格遵循 memoryTypeIndex
。相反,它们 应该 在内部修改分配,以使用应用程序给定用法所需的内存类型。这是因为对于导出操作,应用程序目前无法在分配之前知道内存类型索引。
如果 pNext
链包含 VkMemoryDedicatedAllocateInfo
结构,则该结构包含内存可以绑定到的唯一缓冲区或图像资源的句柄。
VkMemoryDedicatedAllocateInfo
结构的定义如下
// Provided by VK_VERSION_1_1
typedef struct VkMemoryDedicatedAllocateInfo {
VkStructureType sType;
const void* pNext;
VkImage image;
VkBuffer buffer;
} VkMemoryDedicatedAllocateInfo;
或等效的
// Provided by VK_KHR_dedicated_allocation
typedef VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
image
是 VK_NULL_HANDLE 或此内存将绑定到的图像的句柄。 -
buffer
是 VK_NULL_HANDLE 或此内存将绑定到的缓冲区的句柄。
如果 pNext
链包含 VkDedicatedAllocationMemoryAllocateInfoNV
结构,则该结构包含唯一缓冲区或图像资源的句柄,该内存 可以 绑定到该资源。
VkDedicatedAllocationMemoryAllocateInfoNV
结构定义如下
// Provided by VK_NV_dedicated_allocation
typedef struct VkDedicatedAllocationMemoryAllocateInfoNV {
VkStructureType sType;
const void* pNext;
VkImage image;
VkBuffer buffer;
} VkDedicatedAllocationMemoryAllocateInfoNV;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
image
是 VK_NULL_HANDLE 或此内存将绑定到的图像的句柄。 -
buffer
是 VK_NULL_HANDLE 或此内存将绑定到的缓冲区的句柄。
如果 pNext
链包含一个 VkMemoryPriorityAllocateInfoEXT
结构,则该结构包含内存的优先级。
VkMemoryPriorityAllocateInfoEXT
结构定义如下:
// Provided by VK_EXT_memory_priority
typedef struct VkMemoryPriorityAllocateInfoEXT {
VkStructureType sType;
const void* pNext;
float priority;
} VkMemoryPriorityAllocateInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
priority
是一个介于0
和1
之间的浮点值,表示分配相对于其他内存分配的优先级。值越大,优先级越高。优先级的粒度取决于实现。
当系统内存不足时,具有较高优先级的内存分配可能更可能保留在设备本地内存中。
如果未包含此结构,则相当于 priority
值为 0.5
。
要修改现有内存分配的优先级,请调用
// Provided by VK_EXT_pageable_device_local_memory
void vkSetDeviceMemoryPriorityEXT(
VkDevice device,
VkDeviceMemory memory,
float priority);
-
device
是拥有内存的逻辑设备。 -
memory
是将应用新优先级的 VkDeviceMemory 对象。 -
priority
是一个介于0
和1
之间的浮点值,表示分配相对于其他内存分配的优先级。值越大,优先级越高。优先级的粒度取决于实现。
当系统内存不足时,具有较高优先级的内存分配可能更可能保留在设备本地内存中。
当分配其有效负载可能导出到另一个进程或 Vulkan 实例的内存时,请将一个 VkExportMemoryAllocateInfo 结构添加到 VkMemoryAllocateInfo 结构的 pNext
链中,指定可能导出的句柄类型。
VkExportMemoryAllocateInfo 结构定义如下:
// Provided by VK_VERSION_1_1
typedef struct VkExportMemoryAllocateInfo {
VkStructureType sType;
const void* pNext;
VkExternalMemoryHandleTypeFlags handleTypes;
} VkExportMemoryAllocateInfo;
或等效的
// Provided by VK_KHR_external_memory
typedef VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
handleTypes
是零或 VkExternalMemoryHandleTypeFlagBits 的位掩码,指定应用程序可以从生成的分配中导出的一个或多个内存句柄类型。应用程序可以为同一分配请求多个句柄类型。
当分配可能导出到另一个进程或 Vulkan 实例的内存时,请将一个 VkExportMemoryAllocateInfoNV 结构添加到 VkMemoryAllocateInfo 结构的 pNext
链中,指定可能导出的句柄类型。
VkExportMemoryAllocateInfoNV 结构定义如下:
// Provided by VK_NV_external_memory
typedef struct VkExportMemoryAllocateInfoNV {
VkStructureType sType;
const void* pNext;
VkExternalMemoryHandleTypeFlagsNV handleTypes;
} VkExportMemoryAllocateInfoNV;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
handleTypes
是一个 VkExternalMemoryHandleTypeFlagBitsNV 的位掩码,指定可能导出的一个或多个内存句柄类型。只要它们兼容,如 vkGetPhysicalDeviceExternalImageFormatPropertiesNV 报告的那样,就可以为同一分配请求多个句柄类型。
Win32 外部内存
要指定从内存对象导出的 NT 句柄的附加属性,请将 VkExportMemoryWin32HandleInfoKHR 结构添加到 VkMemoryAllocateInfo 结构的 pNext
链中。VkExportMemoryWin32HandleInfoKHR
结构的定义如下:
// Provided by VK_KHR_external_memory_win32
typedef struct VkExportMemoryWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
const SECURITY_ATTRIBUTES* pAttributes;
DWORD dwAccess;
LPCWSTR name;
} VkExportMemoryWin32HandleInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
pAttributes
是指向 WindowsSECURITY_ATTRIBUTES
结构的指针,该结构指定句柄的安全属性。 -
dwAccess
是一个DWORD
,指定句柄的访问权限。 -
name
是一个以 null 结尾的 UTF-16 字符串,用于关联从创建的内存导出的 NT 句柄引用的负载。
如果 VkExportMemoryAllocateInfo 未包含在同一个 pNext
链中,则忽略此结构。
如果 VkExportMemoryAllocateInfo 包含在 VkMemoryAllocateInfo 的 pNext
链中,且使用 Windows handleType
,但 VkExportMemoryWin32HandleInfoKHR
未包含在 pNext
链中,或者已包含但 pAttributes
设置为 NULL
,则将使用默认安全描述符值,并且应用程序创建的子进程将不会继承该句柄,如 MSDN 文档“同步对象安全性和访问权限”1 中所述。此外,如果该结构不存在,则使用的访问权限取决于句柄类型。
对于以下类型的句柄:
-
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
实现必须确保访问权限允许对内存进行读取和写入访问。
要从 Windows 句柄导入内存,请将 VkImportMemoryWin32HandleInfoKHR 结构添加到 VkMemoryAllocateInfo 结构的 pNext
链中。
VkImportMemoryWin32HandleInfoKHR
结构的定义如下:
// Provided by VK_KHR_external_memory_win32
typedef struct VkImportMemoryWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
VkExternalMemoryHandleTypeFlagBits handleType;
HANDLE handle;
LPCWSTR name;
} VkImportMemoryWin32HandleInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
handleType
是一个 VkExternalMemoryHandleTypeFlagBits 值,指定handle
或name
的类型。 -
handle
是NULL
或要导入的外部句柄。 -
name
是NULL
或一个以 null 结尾的 UTF-16 字符串,用于命名要导入的负载。
从 Windows 句柄导入内存对象负载不会将句柄的所有权转移给 Vulkan 实现。对于定义为 NT 句柄的句柄类型,当不再需要句柄时,应用程序必须使用 CloseHandle
系统调用释放句柄所有权。对于定义为 NT 句柄的句柄类型,导入的内存对象会保持对其负载的引用。
非 NT 句柄导入操作不会向其关联的负载添加引用。如果拥有负载的原始对象被销毁,则共享该负载的所有资源和句柄将变为无效。 |
应用程序可以将相同的负载导入到 Vulkan 的多个实例中,导入到导出该负载的同一实例中,以及多次导入到给定的 Vulkan 实例中。在所有情况下,每个导入操作必须创建一个不同的 VkDeviceMemory
对象。
要导出代表 Vulkan 设备内存对象有效载荷的 Windows 句柄,请调用
// Provided by VK_KHR_external_memory_win32
VkResult vkGetMemoryWin32HandleKHR(
VkDevice device,
const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo,
HANDLE* pHandle);
-
device
是创建要导出的设备内存的逻辑设备。 -
pGetWin32HandleInfo
是指向 VkMemoryGetWin32HandleInfoKHR 结构的指针,该结构包含导出操作的参数。 -
pHandle
将返回代表设备内存对象有效载荷的 Windows 句柄。
对于定义为 NT 句柄的句柄类型,vkGetMemoryWin32HandleKHR
返回的句柄由应用程序拥有,并持有对其有效载荷的引用。为避免资源泄漏,应用程序在不再需要这些句柄时,必须使用 CloseHandle
系统调用释放它们的所有权。
非 NT 句柄类型不会为其关联的有效载荷添加引用。如果拥有有效载荷的原始对象被销毁,则共享该有效载荷的所有资源和句柄都将失效。 |
VkMemoryGetWin32HandleInfoKHR
结构的定义如下:
// Provided by VK_KHR_external_memory_win32
typedef struct VkMemoryGetWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
VkDeviceMemory memory;
VkExternalMemoryHandleTypeFlagBits handleType;
} VkMemoryGetWin32HandleInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memory
是要从中导出句柄的内存对象。 -
handleType
是一个 VkExternalMemoryHandleTypeFlagBits 值,指定请求的句柄类型。
返回的句柄的属性取决于 handleType
的值。有关已定义外部内存句柄类型的属性的说明,请参阅 VkExternalMemoryHandleTypeFlagBits。
与 Vulkan 兼容的 Windows 内存句柄也可能由非 Vulkan API 使用超出本规范范围的方法创建。要确定导入此类句柄时要使用的正确参数,请调用
// Provided by VK_KHR_external_memory_win32
VkResult vkGetMemoryWin32HandlePropertiesKHR(
VkDevice device,
VkExternalMemoryHandleTypeFlagBits handleType,
HANDLE handle,
VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties);
-
device
是将要导入handle
的逻辑设备。 -
handleType
是一个 VkExternalMemoryHandleTypeFlagBits 值,指定handle
的句柄类型。 -
handle
是要导入的句柄。 -
pMemoryWin32HandleProperties
是指向 VkMemoryWin32HandlePropertiesKHR 结构的指针,其中返回handle
的属性。
返回的 VkMemoryWin32HandlePropertiesKHR
结构定义如下:
// Provided by VK_KHR_external_memory_win32
typedef struct VkMemoryWin32HandlePropertiesKHR {
VkStructureType sType;
void* pNext;
uint32_t memoryTypeBits;
} VkMemoryWin32HandlePropertiesKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memoryTypeBits
是一个位掩码,其中为指定的 Windows 句柄可以作为导入的每个内存类型设置一个位。
当 VkExportMemoryAllocateInfoNV::handleTypes
包括 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV
时,将 VkExportMemoryWin32HandleInfoNV
结构添加到 VkExportMemoryAllocateInfoNV 结构的 pNext
链,以指定内存对象外部句柄的安全属性和访问权限。
VkExportMemoryWin32HandleInfoNV
结构的定义如下:
// Provided by VK_NV_external_memory_win32
typedef struct VkExportMemoryWin32HandleInfoNV {
VkStructureType sType;
const void* pNext;
const SECURITY_ATTRIBUTES* pAttributes;
DWORD dwAccess;
} VkExportMemoryWin32HandleInfoNV;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
pAttributes
是指向 WindowsSECURITY_ATTRIBUTES
结构的指针,该结构指定句柄的安全属性。 -
dwAccess
是一个DWORD
,指定句柄的访问权限。
如果此结构不存在,或者如果 pAttributes
为 NULL
,则将使用默认的安全描述符值,并且应用程序创建的子进程将不会继承该句柄,如 MSDN 文档“同步对象安全性和访问权限”1中所述。此外,如果该结构不存在,则访问权限将为
DXGI_SHARED_RESOURCE_READ
| DXGI_SHARED_RESOURCE_WRITE
要导入在同一物理设备上但在当前 Vulkan 实例之外创建的内存,请将 VkImportMemoryWin32HandleInfoNV 结构添加到 VkMemoryAllocateInfo 结构的 pNext
链,指定内存的句柄和类型。
VkImportMemoryWin32HandleInfoNV
结构的定义如下:
// Provided by VK_NV_external_memory_win32
typedef struct VkImportMemoryWin32HandleInfoNV {
VkStructureType sType;
const void* pNext;
VkExternalMemoryHandleTypeFlagsNV handleType;
HANDLE handle;
} VkImportMemoryWin32HandleInfoNV;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
handleType
是0
或一个 VkExternalMemoryHandleTypeFlagBitsNV 值,指定handle
中内存句柄的类型。 -
handle
是指向内存的 WindowsHANDLE
。
如果 handleType
为 0
,则此结构会被它所链入的 VkMemoryAllocateInfo 结构的消费者忽略。
可以在 handleType
中设置的位有:
VkImportMemoryWin32HandleInfoNV::handleType
的可能值,用于指定外部内存句柄的类型,如下所示:
// Provided by VK_NV_external_memory_capabilities
typedef enum VkExternalMemoryHandleTypeFlagBitsNV {
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008,
} VkExternalMemoryHandleTypeFlagBitsNV;
-
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV
指定一个由 vkGetMemoryWin32HandleNV 返回的内存句柄。 -
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV
指定一个由 vkGetMemoryWin32HandleNV 返回的内存句柄,或者使用DuplicateHandle()
从此类句柄复制而来的句柄。 -
VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV
指定一个由IDXGIResource1::CreateSharedHandle
返回的有效 NT 内存句柄,或者使用DuplicateHandle()
从此类句柄复制而来的句柄。 -
VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV
指定一个由IDXGIResource::GetSharedHandle()
返回的内存句柄。
// Provided by VK_NV_external_memory_capabilities
typedef VkFlags VkExternalMemoryHandleTypeFlagsNV;
VkExternalMemoryHandleTypeFlagsNV
是一个位掩码类型,用于设置零个或多个 VkExternalMemoryHandleTypeFlagBitsNV 的掩码。
要检索使用 VkExportMemoryAllocateInfoNV::handleTypes
设置(包含 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV
或 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV
)创建的设备内存对象对应的句柄,请调用:
// Provided by VK_NV_external_memory_win32
VkResult vkGetMemoryWin32HandleNV(
VkDevice device,
VkDeviceMemory memory,
VkExternalMemoryHandleTypeFlagsNV handleType,
HANDLE* pHandle);
-
device
是拥有内存的逻辑设备。 -
memory
是 VkDeviceMemory 对象。 -
handleType
是 VkExternalMemoryHandleTypeFlagBitsNV 的位掩码,其中包含指定所请求句柄类型的单个位。 -
handle
是指向 WindowsHANDLE
的指针,句柄将在其中返回。
文件描述符外部内存
要从 POSIX 文件描述符句柄导入内存,请将 VkImportMemoryFdInfoKHR 结构添加到 VkMemoryAllocateInfo 结构的 pNext
链中。VkImportMemoryFdInfoKHR
结构的定义如下:
// Provided by VK_KHR_external_memory_fd
typedef struct VkImportMemoryFdInfoKHR {
VkStructureType sType;
const void* pNext;
VkExternalMemoryHandleTypeFlagBits handleType;
int fd;
} VkImportMemoryFdInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
handleType
是 VkExternalMemoryHandleTypeFlagBits 值,用于指定fd
的句柄类型。 -
fd
是要导入的外部句柄。
从文件描述符导入内存会将文件描述符的所有权从应用程序转移到 Vulkan 实现。成功导入后,应用程序不得对文件描述符执行任何操作。导入的内存对象持有对其有效负载的引用。
应用程序可以将相同的负载导入到 Vulkan 的多个实例中,导入到导出该负载的同一实例中,以及多次导入到给定的 Vulkan 实例中。在所有情况下,每个导入操作必须创建一个不同的 VkDeviceMemory
对象。
要导出引用 Vulkan 设备内存对象有效负载的 POSIX 文件描述符,请调用:
// Provided by VK_KHR_external_memory_fd
VkResult vkGetMemoryFdKHR(
VkDevice device,
const VkMemoryGetFdInfoKHR* pGetFdInfo,
int* pFd);
-
device
是创建要导出的设备内存的逻辑设备。 -
pGetFdInfo
是指向 VkMemoryGetFdInfoKHR 结构的指针,该结构包含导出操作的参数。 -
pFd
将返回引用设备内存对象有效负载的文件描述符。
对 vkGetMemoryFdKHR
的每次调用必须创建一个新的文件描述符,该描述符持有对内存对象有效负载的引用,并将文件描述符的所有权转移给应用程序。为避免泄漏资源,应用程序在不再需要文件描述符时,必须使用 close
系统调用释放其所有权,或者通过从中导入 Vulkan 内存对象来释放其所有权。在操作系统支持的情况下,实现必须设置文件描述符,使其在发出 execve
系统调用时自动关闭。
VkMemoryGetFdInfoKHR
结构定义如下:
// Provided by VK_KHR_external_memory_fd
typedef struct VkMemoryGetFdInfoKHR {
VkStructureType sType;
const void* pNext;
VkDeviceMemory memory;
VkExternalMemoryHandleTypeFlagBits handleType;
} VkMemoryGetFdInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memory
是要从中导出句柄的内存对象。 -
handleType
是一个 VkExternalMemoryHandleTypeFlagBits 值,指定请求的句柄类型。
导出的文件描述符的属性取决于 handleType
的值。有关定义的外部内存句柄类型的属性说明,请参阅VkExternalMemoryHandleTypeFlagBits。
导出的文件大小可能大于 VkMemoryAllocateInfo:: |
与 Vulkan 兼容的 POSIX 文件描述符内存句柄可以通过本规范范围之外的方法,由非 Vulkan API 创建。要确定导入此类句柄时使用的正确参数,请调用
// Provided by VK_KHR_external_memory_fd
VkResult vkGetMemoryFdPropertiesKHR(
VkDevice device,
VkExternalMemoryHandleTypeFlagBits handleType,
int fd,
VkMemoryFdPropertiesKHR* pMemoryFdProperties);
-
device
是将要导入fd
的逻辑设备。 -
handleType
是一个 VkExternalMemoryHandleTypeFlagBits 值,指定句柄fd
的类型。 -
fd
是将被导入的句柄。 -
pMemoryFdProperties
是指向 VkMemoryFdPropertiesKHR 结构的指针,该结构返回句柄fd
的属性。
返回的 VkMemoryFdPropertiesKHR
结构定义如下
// Provided by VK_KHR_external_memory_fd
typedef struct VkMemoryFdPropertiesKHR {
VkStructureType sType;
void* pNext;
uint32_t memoryTypeBits;
} VkMemoryFdPropertiesKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memoryTypeBits
是一个位掩码,其中为指定文件描述符可以导入的每个内存类型设置一个位。
主机外部内存
要从主机指针导入内存,请将 VkImportMemoryHostPointerInfoEXT 结构添加到 VkMemoryAllocateInfo 结构的 pNext
链中。 VkImportMemoryHostPointerInfoEXT
结构定义如下
// Provided by VK_EXT_external_memory_host
typedef struct VkImportMemoryHostPointerInfoEXT {
VkStructureType sType;
const void* pNext;
VkExternalMemoryHandleTypeFlagBits handleType;
void* pHostPointer;
} VkImportMemoryHostPointerInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
handleType
是一个 VkExternalMemoryHandleTypeFlagBits 值,指定句柄类型。 -
pHostPointer
是要从中导入的主机指针。
从主机指针导入内存会在主机和 Vulkan 实现之间共享内存的所有权。应用程序可以继续通过主机指针访问内存,但应用程序有责任按照设备内存对象的主机访问中定义的那样,同步设备和非设备对有效负载的访问。
应用程序可以将相同的有效负载导入到 Vulkan 的多个实例中,以及多次导入到给定的 Vulkan 实例中。但是,由于平台限制,实现可能无法将相同的有效负载多次导入到给定的物理设备中。
由于超出本规范范围的其他特定于平台的限制,从特定主机指针导入内存可能不可行,在这种情况下,实现必须使用错误代码 VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR
来使内存导入操作失败。
从主机指针导入的设备内存对象是否持有对其有效负载的引用是未定义的。因此,应用程序必须确保导入的内存范围在导入的内存对象的生命周期内保持有效和可访问。
实现可以支持为非主机可见的内存类型导入主机指针。在这种情况下,在成功调用 vkAllocateMemory 之后,在 VkDeviceMemory 被销毁之前,应用程序必须不访问从 pHostPointer
导入的内存范围。导入时主机内存的内容变为未定义的,并且在 VkDeviceMemory 被销毁后保持未定义。当 VkDeviceMemory 句柄有效时,应用程序还必须不访问映射到与 pHostPointer
相同物理内存但映射到不同主机指针的主机内存。在通用操作系统上运行的实现应该不支持为非主机可见的内存类型导入主机指针。
使用主机指针来支持非主机可见的分配是一种特定于平台的用例,除非平台指示,否则应用程序不应尝试这样做。 |
要确定导入主机指针时要使用的正确参数,请调用
// Provided by VK_EXT_external_memory_host
VkResult vkGetMemoryHostPointerPropertiesEXT(
VkDevice device,
VkExternalMemoryHandleTypeFlagBits handleType,
const void* pHostPointer,
VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties);
-
device
是将要导入pHostPointer
的逻辑设备。 -
handleType
是一个 VkExternalMemoryHandleTypeFlagBits 值,指定pHostPointer
句柄的类型。 -
pHostPointer
是要从中导入的主机指针。 -
pMemoryHostPointerProperties
是指向 VkMemoryHostPointerPropertiesEXT 结构的指针,该结构返回主机指针属性。
VkMemoryHostPointerPropertiesEXT
结构定义如下
// Provided by VK_EXT_external_memory_host
typedef struct VkMemoryHostPointerPropertiesEXT {
VkStructureType sType;
void* pNext;
uint32_t memoryTypeBits;
} VkMemoryHostPointerPropertiesEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memoryTypeBits
是一个位掩码,其中为每个指定主机指针 可以 作为导入的内存类型设置一个位。
memoryTypeBits
返回的值 应该仅包含标识主机可见的内存类型的位。实现 可能 包含标识非主机可见的内存类型的位。此类类型的导入指针的行为由 VkImportMemoryHostPointerInfoEXT 定义。
Android 硬件缓冲区外部内存
要从 Android 硬件缓冲区导入当前 Vulkan 实例外部创建的内存,请将 VkImportAndroidHardwareBufferInfoANDROID
结构添加到 VkMemoryAllocateInfo 结构的 pNext
链。VkImportAndroidHardwareBufferInfoANDROID
结构定义如下
// Provided by VK_ANDROID_external_memory_android_hardware_buffer
typedef struct VkImportAndroidHardwareBufferInfoANDROID {
VkStructureType sType;
const void* pNext;
struct AHardwareBuffer* buffer;
} VkImportAndroidHardwareBufferInfoANDROID;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
buffer
是要导入的 Android 硬件缓冲区。
如果 vkAllocateMemory 命令成功,则实现 必须 获取对导入的硬件缓冲区的引用,该引用 必须 在释放设备内存对象时释放。如果命令失败,则实现 必须 不保留引用。
要导出引用 Vulkan 设备内存对象有效负载的 Android 硬件缓冲区,请调用
// Provided by VK_ANDROID_external_memory_android_hardware_buffer
VkResult vkGetMemoryAndroidHardwareBufferANDROID(
VkDevice device,
const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo,
struct AHardwareBuffer** pBuffer);
-
device
是创建要导出的设备内存的逻辑设备。 -
pInfo
是指向 VkMemoryGetAndroidHardwareBufferInfoANDROID 结构的指针,该结构包含导出操作的参数。 -
pBuffer
将返回一个 Android 硬件缓冲区,该缓冲区引用设备内存对象的有效负载。
每次调用 vkGetMemoryAndroidHardwareBufferANDROID
必须 返回一个 Android 硬件缓冲区,该缓冲区除了 VkDeviceMemory 持有的引用外,还获得了一个新的引用。为避免资源泄漏,当不再需要引用时,应用程序 必须 通过调用 AHardwareBuffer_release
来释放引用。当在 VkMemoryGetAndroidHardwareBufferInfoANDROID::memory
中使用相同的句柄调用时,vkGetMemoryAndroidHardwareBufferANDROID
必须 返回相同的 Android 硬件缓冲区对象。如果设备内存是通过导入 Android 硬件缓冲区创建的,则 vkGetMemoryAndroidHardwareBufferANDROID
必须 返回相同的 Android 硬件缓冲区对象。
VkMemoryGetAndroidHardwareBufferInfoANDROID
结构定义如下
// Provided by VK_ANDROID_external_memory_android_hardware_buffer
typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID {
VkStructureType sType;
const void* pNext;
VkDeviceMemory memory;
} VkMemoryGetAndroidHardwareBufferInfoANDROID;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memory
是内存对象,Android 硬件缓冲区将从该对象导出。
要确定导入 Android 硬件缓冲区时要使用的内存参数,请调用
// Provided by VK_ANDROID_external_memory_android_hardware_buffer
VkResult vkGetAndroidHardwareBufferPropertiesANDROID(
VkDevice device,
const struct AHardwareBuffer* buffer,
VkAndroidHardwareBufferPropertiesANDROID* pProperties);
-
device
是将导入buffer
的逻辑设备。 -
buffer
是要导入的 Android 硬件缓冲区。 -
pProperties
是指向 VkAndroidHardwareBufferPropertiesANDROID 结构的指针,其中返回buffer
的属性。
返回的 VkAndroidHardwareBufferPropertiesANDROID
结构定义如下
// Provided by VK_ANDROID_external_memory_android_hardware_buffer
typedef struct VkAndroidHardwareBufferPropertiesANDROID {
VkStructureType sType;
void* pNext;
VkDeviceSize allocationSize;
uint32_t memoryTypeBits;
} VkAndroidHardwareBufferPropertiesANDROID;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
allocationSize
是外部内存的大小 -
memoryTypeBits
是一个位掩码,其中为每个指定的 Android 硬件缓冲区 可以导入的内存类型设置一个位。
要获取 Android 硬件缓冲区的格式属性,请在传递给 vkGetAndroidHardwareBufferPropertiesANDROID 的 VkAndroidHardwareBufferPropertiesANDROID 结构的 pNext
链中包含 VkAndroidHardwareBufferFormatPropertiesANDROID
结构。此结构的定义如下
// Provided by VK_ANDROID_external_memory_android_hardware_buffer
typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID {
VkStructureType sType;
void* pNext;
VkFormat format;
uint64_t externalFormat;
VkFormatFeatureFlags formatFeatures;
VkComponentMapping samplerYcbcrConversionComponents;
VkSamplerYcbcrModelConversion suggestedYcbcrModel;
VkSamplerYcbcrRange suggestedYcbcrRange;
VkChromaLocation suggestedXChromaOffset;
VkChromaLocation suggestedYChromaOffset;
} VkAndroidHardwareBufferFormatPropertiesANDROID;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
format
是与 Android 硬件缓冲区的格式对应的 Vulkan 格式,如果没有等效的 Vulkan 格式,则为VK_FORMAT_UNDEFINED
。 -
externalFormat
是用于 VkExternalFormatANDROID 的实现定义的外部格式标识符。它必须不为零。 -
formatFeatures
描述了当与从buffer
导入的内存绑定的图像一起使用时,此外部格式的功能。 -
samplerYcbcrConversionComponents
是在 VkSamplerYcbcrConversionCreateInfo 中 应该 使用的组件混合。 -
suggestedYcbcrModel
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的颜色模型。 -
suggestedYcbcrRange
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的数值范围。 -
suggestedXChromaOffset
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的 X 色度偏移。 -
suggestedYChromaOffset
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的 Y 色度偏移。
如果 Android 硬件缓冲区的格式在格式等效表中列出,则 format
必须具有表中列出的等效 Vulkan 格式。 否则,format
可以为 VK_FORMAT_UNDEFINED
,表示 Android 硬件缓冲区只能与外部格式一起使用。
formatFeatures
成员 必须包括 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
和 VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT
或 VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT
中的至少一个,并且 应该包括 VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT
和 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT
。
|
具有相同外部格式的 Android 硬件缓冲区必须在 formatFeatures
中对 VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT
、VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT
、VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT
、VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT
、VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT
和 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT
具有相同的支持。具有相同外部格式的 Android 硬件缓冲区之间的其他格式特性可能不同。这允许应用程序对具有相同外部格式的任何 Android 硬件缓冲区使用相同的 VkSamplerYcbcrConversion 对象(以及从中创建的采样器和管线)。
如果 format
不是 VK_FORMAT_UNDEFINED
,则 samplerYcbcrConversionComponents
的值在用作具有该格式的 VkSamplerYcbcrConversionCreateInfo 的 components
成员时必须有效。如果 format
是 VK_FORMAT_UNDEFINED
,则 samplerYcbcrConversionComponents
的所有成员必须是 标识置换。
实现可能并非始终能够确定图像内容的颜色模型、数值范围或色度偏移,因此 VkAndroidHardwareBufferFormatPropertiesANDROID
中的值仅为建议值。应用程序应该将这些值视为在没有通过其他方式获得的更可靠信息时使用的合理默认值。如果底层物理设备也可以通过具有 GL_OES_EGL_image_external
扩展的 OpenGL ES 使用,则该实现应该建议产生与通过使用等效采样器参数在 OpenGL ES 中通过 samplerExternalOES
对同一外部图像进行采样所获得的类似采样值的值。
由于 |
Android 硬件缓冲区的格式属性可以通过在传递给 vkGetAndroidHardwareBufferPropertiesANDROID 的 VkAndroidHardwareBufferPropertiesANDROID 结构的 pNext
链中包含一个 VkAndroidHardwareBufferFormatProperties2ANDROID
结构来获取。此结构定义为
// Provided by VK_ANDROID_external_memory_android_hardware_buffer with VK_KHR_format_feature_flags2 or VK_VERSION_1_3
typedef struct VkAndroidHardwareBufferFormatProperties2ANDROID {
VkStructureType sType;
void* pNext;
VkFormat format;
uint64_t externalFormat;
VkFormatFeatureFlags2 formatFeatures;
VkComponentMapping samplerYcbcrConversionComponents;
VkSamplerYcbcrModelConversion suggestedYcbcrModel;
VkSamplerYcbcrRange suggestedYcbcrRange;
VkChromaLocation suggestedXChromaOffset;
VkChromaLocation suggestedYChromaOffset;
} VkAndroidHardwareBufferFormatProperties2ANDROID;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
format
是与 Android 硬件缓冲区的格式对应的 Vulkan 格式,如果没有等效的 Vulkan 格式,则为VK_FORMAT_UNDEFINED
。 -
externalFormat
是用于 VkExternalFormatANDROID 的实现定义的外部格式标识符。它必须不为零。 -
formatFeatures
描述了当与从buffer
导入的内存绑定的图像一起使用时,此外部格式的功能。 -
samplerYcbcrConversionComponents
是在 VkSamplerYcbcrConversionCreateInfo 中 应该 使用的组件混合。 -
suggestedYcbcrModel
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的颜色模型。 -
suggestedYcbcrRange
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的数值范围。 -
suggestedXChromaOffset
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的 X 色度偏移。 -
suggestedYChromaOffset
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的 Y 色度偏移。
formatFeatures
中报告的位必须包括 VkAndroidHardwareBufferFormatPropertiesANDROID
::formatFeatures
的相应字段中报告的位。
// Provided by VK_ANDROID_external_format_resolve
typedef struct VkAndroidHardwareBufferFormatResolvePropertiesANDROID {
VkStructureType sType;
void* pNext;
VkFormat colorAttachmentFormat;
} VkAndroidHardwareBufferFormatResolvePropertiesANDROID;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
colorAttachmentFormat
是一个 VkFormat,指定当解析为指定的外部格式时,用于颜色附件图像的颜色附件图像的格式。如果实现支持指定外部格式的外部格式解析,则此值将是一种颜色格式,支持 VkFormatProperties::optimalTilingFeatures
中的VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT
,由 vkGetPhysicalDeviceFormatProperties 返回,且format
等于colorAttachmentFormat
。如果不支持外部格式解析,则此值将为VK_FORMAT_UNDEFINED
。
使用 GRALLOC_USAGE_HW_RENDER
标志创建的任何 Android 硬件缓冲区必须以某种方式在 Vulkan 中可渲染,要么
-
VkAndroidHardwareBufferFormatPropertiesANDROID::
format
必须是一种支持 VkFormatProperties::optimalTilingFeatures
中的VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT
或VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
的格式;或者 -
colorAttachmentFormat
必须是一种支持 VkFormatProperties::optimalTilingFeatures
中的VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT
的格式。
远程设备外部内存
要导出表示远程设备可访问的 Vulkan 设备内存对象负载的地址,请调用
// Provided by VK_NV_external_memory_rdma
VkResult vkGetMemoryRemoteAddressNV(
VkDevice device,
const VkMemoryGetRemoteAddressInfoNV* pMemoryGetRemoteAddressInfo,
VkRemoteAddressNV* pAddress);
-
device
是创建要导出的设备内存的逻辑设备。 -
pMemoryGetRemoteAddressInfo
是指向 VkMemoryGetRemoteAddressInfoNV 结构的指针,该结构包含导出操作的参数。 -
pAddress
是指向VkRemoteAddressNV
值的指针,在该值中返回表示设备内存对象负载的地址。
所涉及设备的内核模式驱动程序之间可能需要更多通信。此信息不在此文档的范围之内,应从设备供应商处请求。
VkMemoryGetRemoteAddressInfoNV
结构定义为
// Provided by VK_NV_external_memory_rdma
typedef struct VkMemoryGetRemoteAddressInfoNV {
VkStructureType sType;
const void* pNext;
VkDeviceMemory memory;
VkExternalMemoryHandleTypeFlagBits handleType;
} VkMemoryGetRemoteAddressInfoNV;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memory
是从中导出远程可访问地址的内存对象。 -
handleType
是请求的句柄类型。
VkRemoteAddressNV
表示远程设备可访问的内存对象的地址,如在 vkGetMemoryRemoteAddressNV::pAddress
中返回。
// Provided by VK_NV_external_memory_rdma
typedef void* VkRemoteAddressNV;
Fuchsia 外部内存
在 Fuchsia 上,当分配可能从其他设备、进程或 Vulkan 实例导入的内存时,将 VkImportMemoryZirconHandleInfoFUCHSIA 结构添加到 VkMemoryAllocateInfo 结构的 pNext
链中。
Fuchsia 上的外部内存使用 zx_handle_t
类型的 VMO 句柄进行导入和导出。外部内存的 VMO 句柄通常从 Fuchsia 的 Sysmem 服务或诸如 zx_vmo_create
() 等系统调用中获取。导入的 VMO 句柄也可以通过从另一个 Vulkan 实例导出它们来获得,如导出 Fuchsia 设备内存中所述。
将 VMO 句柄导入到 Vulkan 实例会将句柄的所有权从应用程序转移到该实例。应用程序在成功导入后必须不对该句柄执行任何操作。
应用程序可以将相同的底层内存导入到 Vulkan 的多个实例中,从导出它的同一个实例导入,以及多次导入到给定的 Vulkan 实例中。在所有情况下,每次导入操作必须创建一个不同的 VkDeviceMemory
对象。
导入 Fuchsia 外部内存
VkImportMemoryZirconHandleInfoFUCHSIA
结构定义如下
// Provided by VK_FUCHSIA_external_memory
typedef struct VkImportMemoryZirconHandleInfoFUCHSIA {
VkStructureType sType;
const void* pNext;
VkExternalMemoryHandleTypeFlagBits handleType;
zx_handle_t handle;
} VkImportMemoryZirconHandleInfoFUCHSIA;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
handleType
是一个 VkExternalMemoryHandleTypeFlagBits 值,指定handle
的类型。 -
handle
是一个指向外部内存的zx_handle_t
(Zircon) 句柄。
要获取 VkMemoryAllocateInfo 结构的 memoryTypeIndex,请调用 vkGetMemoryZirconHandlePropertiesFUCHSIA
// Provided by VK_FUCHSIA_external_memory
VkResult vkGetMemoryZirconHandlePropertiesFUCHSIA(
VkDevice device,
VkExternalMemoryHandleTypeFlagBits handleType,
zx_handle_t zirconHandle,
VkMemoryZirconHandlePropertiesFUCHSIA* pMemoryZirconHandleProperties);
-
device
是 VkDevice。 -
handleType
是一个 VkExternalMemoryHandleTypeFlagBits 值,指定zirconHandle
的类型 -
zirconHandle
是一个指向外部资源的zx_handle_t
(Zircon) 句柄。 -
pMemoryZirconHandleProperties
是一个指向 VkMemoryZirconHandlePropertiesFUCHSIA 结构的指针,结果将存储在该结构中。
VkMemoryZirconHandlePropertiesFUCHSIA
结构定义如下
// Provided by VK_FUCHSIA_external_memory
typedef struct VkMemoryZirconHandlePropertiesFUCHSIA {
VkStructureType sType;
void* pNext;
uint32_t memoryTypeBits;
} VkMemoryZirconHandlePropertiesFUCHSIA;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memoryTypeBits
是一个位掩码,其中包含为指定句柄可以导入的每个内存类型设置的位。
在 vkGetMemoryZirconHandlePropertiesFUCHSIA 成功填充 pMemoryZirconHandleProperties
后,将 VkMemoryAllocateInfo 的 memoryTypeIndex 字段分配给 VkMemoryZirconHandlePropertiesFUCHSIA 的 memoryTypeBits 字段中设置了位的内存类型。
导出 Fuchsia 设备内存
与导入类似,从 Vulkan 导出 VMO 句柄会将句柄的所有权从 Vulkan 实例转移到应用程序。应用程序负责在使用完毕后使用 zx_handle_close
() 关闭句柄。
要将设备内存导出为可由另一个实例、设备或进程使用的 Zircon 句柄,请使用以下命令检索 VkDeviceMemory 的句柄
// Provided by VK_FUCHSIA_external_memory
VkResult vkGetMemoryZirconHandleFUCHSIA(
VkDevice device,
const VkMemoryGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo,
zx_handle_t* pZirconHandle);
-
device
是 VkDevice。 -
pGetZirconHandleInfo
是指向 VkMemoryGetZirconHandleInfoFUCHSIA 结构的指针。 -
pZirconHandle
是一个指向zx_handle_t
的指针,其中保存生成的 Zircon 句柄。
VkMemoryGetZirconHandleInfoFUCHSIA
定义如下
// Provided by VK_FUCHSIA_external_memory
typedef struct VkMemoryGetZirconHandleInfoFUCHSIA {
VkStructureType sType;
const void* pNext;
VkDeviceMemory memory;
VkExternalMemoryHandleTypeFlagBits handleType;
} VkMemoryGetZirconHandleInfoFUCHSIA;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memory
是正在导出的 VkDeviceMemory。 -
handleType
是一个 VkExternalMemoryHandleTypeFlagBits 值,指定 vkGetMemoryZirconHandleFUCHSIA::pZirconHandle
指向的句柄的类型。
现在已经获得了 pZirconHandle
的结果,可以使用 vkGetMemoryZirconHandlePropertiesFUCHSIA 获取句柄的内存属性,如上所述,将解引用后检索到的 pZirconHandle
替换为 zirconHandle
参数。
Metal 对象
在 Apple 设备平台上,基于 Metal 构建的 Vulkan 实现,并实现了 VK_EXT_metal_objects
扩展,支持导入和导出与特定 Vulkan 对象关联的底层 Metal 对象的功能。
可以使用 vkExportMetalObjectsEXT 命令的 VkExportMetalObjectsInfoEXT 参数的 pNext
链,从这些 Vulkan 对象中导出与某些 Vulkan 对象关联的底层 Metal 对象。
通过在 vkAllocateMemory 命令的 VkMemoryAllocateInfo 结构的 pNext
链中包含 VkImportMetalBufferInfoEXT 结构,可以将 VkDeviceMemory 对象分配到现有的 MTLBuffer
对象上。
通过在 vkCreateImage 命令的 VkImageCreateInfo 结构的 pNext
链中包含 VkImportMetalIOSurfaceInfoEXT 或 VkImportMetalTextureInfoEXT 结构,可以在现有的 IOSurface
对象或一个或多个现有的 Metal MTLTexture
对象上创建新的 VkImage 对象。
要从 Vulkan 对象导出 Metal 对象,应用程序**必须**首先在创建 Vulkan 对象时通过在相应的 Vulkan 对象创建命令的 VkInstanceCreateInfo、VkMemoryAllocateInfo、VkImageCreateInfo、VkImageViewCreateInfo、VkBufferViewCreateInfo、VkSemaphoreCreateInfo 或 VkEventCreateInfo 的 pNext
链中包含一个或多个 VkExportMetalObjectCreateInfoEXT 结构,来表明导出意图。
VkExportMetalObjectCreateInfoEXT
结构定义如下:
// Provided by VK_EXT_metal_objects
typedef struct VkExportMetalObjectCreateInfoEXT {
VkStructureType sType;
const void* pNext;
VkExportMetalObjectTypeFlagBitsEXT exportObjectType;
} VkExportMetalObjectCreateInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
exportObjectType
是一个 VkExportMetalObjectTypeFlagBitsEXT,指示应用程序可能请求从 Vulkan 对象导出的 Metal 对象的类型。
指示可能从相应 Vulkan 对象导出的 Metal 对象类型的位如下:
// Provided by VK_EXT_metal_objects
typedef enum VkExportMetalObjectTypeFlagBitsEXT {
VK_EXPORT_METAL_OBJECT_TYPE_METAL_DEVICE_BIT_EXT = 0x00000001,
VK_EXPORT_METAL_OBJECT_TYPE_METAL_COMMAND_QUEUE_BIT_EXT = 0x00000002,
VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT = 0x00000004,
VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT = 0x00000008,
VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT = 0x00000010,
VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT = 0x00000020,
} VkExportMetalObjectTypeFlagBitsEXT;
-
VK_EXPORT_METAL_OBJECT_TYPE_METAL_DEVICE_BIT_EXT
指定可以导出 MetalMTLDevice
。 -
VK_EXPORT_METAL_OBJECT_TYPE_METAL_COMMAND_QUEUE_BIT_EXT
指定可以导出 MetalMTLCommandQueue
。 -
VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT
指定可以导出 MetalMTLBuffer
。 -
VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT
指定可以导出 MetalMTLTexture
。 -
VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT
指定可以导出 MetalIOSurface
。 -
VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT
指定可以导出 MetalMTLSharedEvent
。
// Provided by VK_EXT_metal_objects
typedef VkFlags VkExportMetalObjectTypeFlagsEXT;
VkExportMetalObjectTypeFlagsEXT
是一个位掩码类型,用于设置零个或多个 VkExportMetalObjectTypeFlagBitsEXT 的掩码。
要导出 Vulkan 对象下的 Metal 对象,请调用
// Provided by VK_EXT_metal_objects
void vkExportMetalObjectsEXT(
VkDevice device,
VkExportMetalObjectsInfoEXT* pMetalObjectsInfo);
-
device
是创建 Vulkan 对象的设备。 -
pMetalObjectsInfo
是指向 VkExportMetalObjectsInfoEXT 结构的指针,该结构的pNext
链包含多个结构,每个结构标识一个 Vulkan 对象,并提供一个指针,通过该指针返回 Metal 对象。
VkExportMetalObjectsInfoEXT
结构定义如下:
// Provided by VK_EXT_metal_objects
typedef struct VkExportMetalObjectsInfoEXT {
VkStructureType sType;
const void* pNext;
} VkExportMetalObjectsInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。
要导出与 VkDevice 对象关联的 VkPhysicalDevice 对应的 Metal MTLDevice
对象,请在 vkExportMetalObjectsEXT 调用的 pMetalObjectsInfo
参数的 pNext
链中包含 VkExportMetalDeviceInfoEXT
结构。
VkExportMetalDeviceInfoEXT
结构定义如下:
// Provided by VK_EXT_metal_objects
typedef struct VkExportMetalDeviceInfoEXT {
VkStructureType sType;
const void* pNext;
MTLDevice_id mtlDevice;
} VkExportMetalDeviceInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
mtlDevice
是与调用中标识的 VkDevice 对象关联的 VkPhysicalDevice 对应的 Metalid<MTLDevice>
对象。实现将在该成员中返回MTLDevice
,如果找不到与 VkPhysicalDevice 对象对应的MTLDevice
,则返回NULL
。
类型 id<MTLDevice>
在 Apple 的 Metal 框架中定义,但为了避免不必要的编译时依赖,Vulkan 头文件中提供了 MTLDevice_id
的不完整类型定义。
// Provided by VK_EXT_metal_objects
#ifdef __OBJC__
@protocol MTLDevice;
typedef __unsafe_unretained id<MTLDevice> MTLDevice_id;
#else
typedef void* MTLDevice_id;
#endif
要导出 VkQueue 对象对应的 Metal MTLCommandQueue
对象,请在 vkExportMetalObjectsEXT 调用的 pMetalObjectsInfo
参数的 pNext
链中包含 VkExportMetalCommandQueueInfoEXT
结构。
VkExportMetalCommandQueueInfoEXT
结构定义如下:
// Provided by VK_EXT_metal_objects
typedef struct VkExportMetalCommandQueueInfoEXT {
VkStructureType sType;
const void* pNext;
VkQueue queue;
MTLCommandQueue_id mtlCommandQueue;
} VkExportMetalCommandQueueInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
queue
是一个 VkQueue。 -
mtlCommandQueue
是queue
中 VkQueue 对象对应的 Metalid<MTLCommandQueue>
对象。实现将在该成员中返回MTLCommandQueue
,如果找不到与 VkQueue 对象对应的MTLCommandQueue
,则返回NULL
。
类型 id<MTLCommandQueue>
在 Apple 的 Metal 框架中定义,但为了避免不必要的编译时依赖,Vulkan 头文件中提供了 MTLCommandQueue_id
的不完整类型定义。
// Provided by VK_EXT_metal_objects
#ifdef __OBJC__
@protocol MTLCommandQueue;
typedef __unsafe_unretained id<MTLCommandQueue> MTLCommandQueue_id;
#else
typedef void* MTLCommandQueue_id;
#endif
要导出 VkDeviceMemory 对象对应的 Metal MTLBuffer
对象,请在 vkExportMetalObjectsEXT 调用的 pMetalObjectsInfo
参数的 pNext
链中包含 VkExportMetalBufferInfoEXT
结构。
VkExportMetalBufferInfoEXT
结构定义如下:
// Provided by VK_EXT_metal_objects
typedef struct VkExportMetalBufferInfoEXT {
VkStructureType sType;
const void* pNext;
VkDeviceMemory memory;
MTLBuffer_id mtlBuffer;
} VkExportMetalBufferInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memory
是一个 VkDeviceMemory。 -
mtlBuffer
是memory
中 VkDeviceMemory 对象对应的 Metalid<MTLBuffer>
对象。实现将在该成员中返回MTLBuffer
,如果找不到与 VkDeviceMemory 对象对应的MTLBuffer
,则返回NULL
。
要导入 Metal MTLBuffer
对象以作为 VkDeviceMemory 对象的基础,请在 vkAllocateMemory 命令中 VkMemoryAllocateInfo 结构的 pNext
链中包含 VkImportMetalBufferInfoEXT
结构。
VkImportMetalBufferInfoEXT
结构定义如下:
// Provided by VK_EXT_metal_objects
typedef struct VkImportMetalBufferInfoEXT {
VkStructureType sType;
const void* pNext;
MTLBuffer_id mtlBuffer;
} VkImportMetalBufferInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
mtlBuffer
是作为 VkDeviceMemory 基础的 Metalid<MTLBuffer>
对象。
应用程序必须确保 id<MTLBuffer>
对象的配置与 VkDeviceMemory 的配置兼容。否则会导致未定义的行为。
类型 id<MTLBuffer>
在 Apple 的 Metal 框架中定义,但为了避免不必要的编译时依赖,Vulkan 头文件中提供了 MTLBuffer_id
的不完整类型定义。
// Provided by VK_EXT_metal_objects
#ifdef __OBJC__
@protocol MTLBuffer;
typedef __unsafe_unretained id<MTLBuffer> MTLBuffer_id;
#else
typedef void* MTLBuffer_id;
#endif
要导出 VkImage、VkImageView 或 VkBufferView 对象对应的 Metal MTLTexture
对象,请在 vkExportMetalObjectsEXT 调用的 pMetalObjectsInfo
参数的 pNext
链中包含 VkExportMetalTextureInfoEXT
结构。
VkExportMetalTextureInfoEXT
结构定义如下:
// Provided by VK_EXT_metal_objects
typedef struct VkExportMetalTextureInfoEXT {
VkStructureType sType;
const void* pNext;
VkImage image;
VkImageView imageView;
VkBufferView bufferView;
VkImageAspectFlagBits plane;
MTLTexture_id mtlTexture;
} VkExportMetalTextureInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
image
是 VK_NULL_HANDLE 或 VkImage。 -
imageView
是 VK_NULL_HANDLE 或 VkImageView。 -
bufferView
是 VK_NULL_HANDLE 或 VkBufferView。 -
plane
指定多平面 VkImage 或 VkImageView 的平面。 -
mtlTexture
是image
、imageView
或bufferView
中 VkImage、VkImageView 或 VkBufferView 对象分别在aspectMask
中指示的平面上对应的 Metalid<MTLTexture>
对象。实现将在该成员中返回MTLTexture
,如果在aspectMask
中指示的平面上,找不到与 VkImage、VkImageView 或 VkBufferView 对象对应的MTLTexture
,则返回NULL
。
要将一个或多个现有的 Metal MTLTexture
对象导入到一个 VkImage 对象之下,请在 vkCreateImage 命令的 VkImageCreateInfo 结构的 pNext
链中包含一个或多个 VkImportMetalTextureInfoEXT
结构。
VkImportMetalTextureInfoEXT
结构定义如下:
// Provided by VK_EXT_metal_objects
typedef struct VkImportMetalTextureInfoEXT {
VkStructureType sType;
const void* pNext;
VkImageAspectFlagBits plane;
MTLTexture_id mtlTexture;
} VkImportMetalTextureInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
plane
指定 VkImage 的平面,id<MTLTexture>
对象应附加到该平面。 -
mtlTexture
是要作为 VkImage 平面基础的 Metalid<MTLTexture>
对象。
类型 id<MTLTexture>
在 Apple 的 Metal 框架中定义,但是为了删除不必要的编译时依赖项,在 Vulkan 头文件中提供了 MTLTexture_id
的不完整类型定义
// Provided by VK_EXT_metal_objects
#ifdef __OBJC__
@protocol MTLTexture;
typedef __unsafe_unretained id<MTLTexture> MTLTexture_id;
#else
typedef void* MTLTexture_id;
#endif
要导出作为 VkImage 对象基础的 Metal IOSurfaceRef
对象,请在 vkExportMetalObjectsEXT 调用的 pMetalObjectsInfo
参数的 pNext
链中包含 VkExportMetalIOSurfaceInfoEXT
结构。
VkExportMetalIOSurfaceInfoEXT
结构定义如下:
// Provided by VK_EXT_metal_objects
typedef struct VkExportMetalIOSurfaceInfoEXT {
VkStructureType sType;
const void* pNext;
VkImage image;
IOSurfaceRef ioSurface;
} VkExportMetalIOSurfaceInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
image
是一个 VkImage。 -
ioSurface
是image
中作为 VkImage 对象基础的 MetalIOSurfaceRef
对象。 如果在 VkImage 对象下找不到IOSurfaceRef
,则实现将在此成员中返回IOSurfaceRef
,否则将返回NULL
。
要导入或创建作为 VkImage 对象基础的 Metal IOSurfaceRef
对象,请在 vkCreateImage 命令的 VkImageCreateInfo 结构的 pNext
链中包含 VkImportMetalIOSurfaceInfoEXT
结构。
VkImportMetalIOSurfaceInfoEXT
结构定义如下:
// Provided by VK_EXT_metal_objects
typedef struct VkImportMetalIOSurfaceInfoEXT {
VkStructureType sType;
const void* pNext;
IOSurfaceRef ioSurface;
} VkImportMetalIOSurfaceInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
ioSurface
是 VK_NULL_HANDLE 或要作为 VkImage 基础的 MetalIOSurfaceRef
对象。
如果 ioSurface
不是 VK_NULL_HANDLE,它将被用来作为 VkImage 的基础。如果 ioSurface
是 VK_NULL_HANDLE,则实现将创建一个新的 IOSurface
来作为 VkImage 的基础。
如果提供了,应用程序必须确保 IOSurfaceRef
对象的配置与 VkImage 的配置兼容。否则会导致未定义的行为。
类型 IOSurfaceRef
在 Apple 的 CoreGraphics 框架中定义,但是为了删除不必要的编译时依赖项,在 Vulkan 头文件中提供了 IOSurfaceRef
的不完整类型定义。
// Provided by VK_EXT_metal_objects
typedef struct __IOSurface* IOSurfaceRef;
要导出作为 VkSemaphore 或 VkEvent 对象基础的 Metal MTLSharedEvent
对象,请在 vkExportMetalObjectsEXT 调用的 pMetalObjectsInfo
参数的 pNext
链中包含 VkExportMetalSharedEventInfoEXT
结构。
VkExportMetalSharedEventInfoEXT
结构定义如下:
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
semaphore
是 VK_NULL_HANDLE 或一个 VkSemaphore。 -
event
是 VK_NULL_HANDLE 或一个 VkEvent。 -
mtlSharedEvent
是semaphore
或event
中作为 VkSemaphore 或 VkEvent 对象基础的 Metalid<MTLSharedEvent>
对象。 如果在 VkSemaphore 或 VkEvent 对象下找不到MTLSharedEvent
,则实现将在此成员中返回MTLSharedEvent
,否则将返回NULL
。
要将 Metal id<MTLSharedEvent>
对象导入以作为 VkSemaphore 或 VkEvent 对象的基础,请在 VkSemaphoreCreateInfo 或 VkEventCreateInfo 结构的 pNext
链中包含一个 VkImportMetalSharedEventInfoEXT
结构,并分别在 vkCreateSemaphore 或 vkCreateEvent 命令中使用。
VkImportMetalSharedEventInfoEXT
结构定义如下:
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
mtlSharedEvent
是 Metal 的id<MTLSharedEvent>
对象,它将作为 VkSemaphore 或 VkEvent 的基础。
如果 VkSemaphoreCreateInfo 结构的 pNext
链同时包含 VkImportMetalSharedEventInfoEXT
和 VkSemaphoreTypeCreateInfo,则导入的 id<MTLSharedEvent>
对象的 signaledValue
属性将被设置为 VkSemaphoreTypeCreateInfo::initialValue
。
类型 id<MTLSharedEvent>
在 Apple 的 Metal 框架中定义,但为了消除不必要的编译时依赖,Vulkan 头部文件中提供了 MTLSharedEvent_id
的不完整类型定义。
QNX 屏幕缓冲区外部内存
要从 QNX 屏幕缓冲区导入在当前 Vulkan 实例外部创建的内存,请将 VkImportScreenBufferInfoQNX
结构添加到 VkMemoryAllocateInfo 结构的 pNext
链中。VkImportScreenBufferInfoQNX
结构定义如下:
// Provided by VK_QNX_external_memory_screen_buffer
typedef struct VkImportScreenBufferInfoQNX {
VkStructureType sType;
const void* pNext;
struct _screen_buffer* buffer;
} VkImportScreenBufferInfoQNX;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
buffer
是指向struct
_screen_buffer
的指针,即要导入的 QNX 屏幕缓冲区。
实现 可能 不会获取对导入的屏幕缓冲区的引用。因此,应用程序 必须 确保 buffer
引用的对象在它导入的设备内存被使用期间保持有效。
要确定导入 QNX 屏幕缓冲区时要使用的内存参数,请调用
// Provided by VK_QNX_external_memory_screen_buffer
VkResult vkGetScreenBufferPropertiesQNX(
VkDevice device,
const struct _screen_buffer* buffer,
VkScreenBufferPropertiesQNX* pProperties);
-
device
是将导入buffer
的逻辑设备。 -
buffer
是要导入的 QNX 屏幕缓冲区。 -
pProperties
是指向 VkScreenBufferPropertiesQNX 结构的指针,该结构返回buffer
的属性。
返回的 VkScreenBufferPropertiesQNX
结构定义如下:
// Provided by VK_QNX_external_memory_screen_buffer
typedef struct VkScreenBufferPropertiesQNX {
VkStructureType sType;
void* pNext;
VkDeviceSize allocationSize;
uint32_t memoryTypeBits;
} VkScreenBufferPropertiesQNX;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
allocationSize
是外部内存的大小。 -
memoryTypeBits
是一个位掩码,其中为每个指定的屏幕缓冲区 可以 导入为的内存类型设置一位。
要获取 QNX 屏幕缓冲区的格式属性,请在传递给 vkGetScreenBufferPropertiesQNX 的 VkScreenBufferPropertiesQNX 结构的 pNext
链中包含一个 VkScreenBufferFormatPropertiesQNX
结构。此结构定义如下:
// Provided by VK_QNX_external_memory_screen_buffer
typedef struct VkScreenBufferFormatPropertiesQNX {
VkStructureType sType;
void* pNext;
VkFormat format;
uint64_t externalFormat;
uint64_t screenUsage;
VkFormatFeatureFlags formatFeatures;
VkComponentMapping samplerYcbcrConversionComponents;
VkSamplerYcbcrModelConversion suggestedYcbcrModel;
VkSamplerYcbcrRange suggestedYcbcrRange;
VkChromaLocation suggestedXChromaOffset;
VkChromaLocation suggestedYChromaOffset;
} VkScreenBufferFormatPropertiesQNX;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
format
是对应于屏幕缓冲区格式的 Vulkan 格式,如果不存在等效的 Vulkan 格式,则为VK_FORMAT_UNDEFINED
。 -
externalFormat
是一个实现定义的外部格式标识符,用于 VkExternalFormatQNX。它 必须 非零。 -
screenUsage
是 QNX 屏幕缓冲区的实现定义的外部使用标识符。 -
formatFeatures
描述了当与从buffer
导入的内存绑定的图像一起使用时,此外部格式的功能。 -
samplerYcbcrConversionComponents
是在 VkSamplerYcbcrConversionCreateInfo 中 应该 使用的组件混合。 -
suggestedYcbcrModel
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的颜色模型。 -
suggestedYcbcrRange
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的数值范围。 -
suggestedXChromaOffset
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的 X 色度偏移。 -
suggestedYChromaOffset
是建议在 VkSamplerYcbcrConversionCreateInfo 中使用的 Y 色度偏移。
如果 QNX 屏幕缓冲区具有 QNX 屏幕格式等效表中列出的格式之一,则 format
必须具有表中列出的等效 Vulkan 格式。否则,format
可以为 VK_FORMAT_UNDEFINED
,表示 QNX 屏幕缓冲区 只能 与外部格式一起使用。formatFeatures
成员 必须 包含 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
,并且 应该 包含 VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT
和 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT
。
设备组内存分配
如果 VkMemoryAllocateInfo 的 pNext
链中包含 VkMemoryAllocateFlagsInfo
结构,则该结构包含控制将分配多少内存实例的标志和设备掩码。
VkMemoryAllocateFlagsInfo
结构定义如下:
// Provided by VK_VERSION_1_1
typedef struct VkMemoryAllocateFlagsInfo {
VkStructureType sType;
const void* pNext;
VkMemoryAllocateFlags flags;
uint32_t deviceMask;
} VkMemoryAllocateFlagsInfo;
或等效的
// Provided by VK_KHR_device_group
typedef VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
flags
是控制分配的 VkMemoryAllocateFlagBits 的位掩码。 -
deviceMask
是逻辑设备中物理设备的掩码,指示如果flags
中设置了VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT
,则 必须 在掩码中的每个设备上分配内存。
如果未设置 VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT
,则分配的实例数量取决于内存堆中是否设置了 VK_MEMORY_HEAP_MULTI_INSTANCE_BIT
。如果设置了 VK_MEMORY_HEAP_MULTI_INSTANCE_BIT
,则会为逻辑设备中的每个物理设备分配内存(如同 deviceMask
为所有设备索引设置了位)。如果未设置 VK_MEMORY_HEAP_MULTI_INSTANCE_BIT
,则会分配单个内存实例(如同 deviceMask
设置为 1)。
在某些实现中,即使 deviceMask
排除了一些设备,从多实例堆分配的内存可能会消耗所有物理设备上的内存。如果 VkPhysicalDeviceGroupProperties::subsetAllocation
为 VK_TRUE
,则仅为设备掩码中的设备消耗内存。
实际上,多实例堆上的大多数分配将在所有物理设备上进行分配。单播分配支持是少数分配的可选优化。 |
可以在 VkMemoryAllocateFlagsInfo::flags
中设置的用于控制设备内存分配的位有:
// Provided by VK_VERSION_1_1
typedef enum VkMemoryAllocateFlagBits {
VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001,
// Provided by VK_VERSION_1_2
VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT = 0x00000002,
// Provided by VK_VERSION_1_2
VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000004,
// Provided by VK_KHR_device_group
VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT,
// Provided by VK_KHR_buffer_device_address
VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT,
// Provided by VK_KHR_buffer_device_address
VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT,
} VkMemoryAllocateFlagBits;
或等效的
// Provided by VK_KHR_device_group
typedef VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR;
-
VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT
指定将为 VkMemoryAllocateFlagsInfo::deviceMask
中的设备分配内存。 -
VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT
指定内存可以附加到使用usage
中设置的VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
位创建的缓冲区对象,并且可以通过 vkGetDeviceMemoryOpaqueCaptureAddress 使用内存句柄来检索不透明地址。 -
VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT
指定内存的地址可以被保存并在后续运行中重复使用(例如,用于跟踪捕获和重放),有关更多详细信息,请参见 VkBufferOpaqueCaptureAddressCreateInfo。
// Provided by VK_VERSION_1_1
typedef VkFlags VkMemoryAllocateFlags;
或等效的
// Provided by VK_KHR_device_group
typedef VkMemoryAllocateFlags VkMemoryAllocateFlagsKHR;
VkMemoryAllocateFlags
是一个位掩码类型,用于设置零个或多个 VkMemoryAllocateFlagBits 的掩码。
不透明捕获地址分配
要为内存分配请求特定的设备地址,请将 VkMemoryOpaqueCaptureAddressAllocateInfo 结构添加到 VkMemoryAllocateInfo 结构的 pNext
链中。VkMemoryOpaqueCaptureAddressAllocateInfo
结构的定义如下:
// Provided by VK_VERSION_1_2
typedef struct VkMemoryOpaqueCaptureAddressAllocateInfo {
VkStructureType sType;
const void* pNext;
uint64_t opaqueCaptureAddress;
} VkMemoryOpaqueCaptureAddressAllocateInfo;
或等效的
// Provided by VK_KHR_buffer_device_address
typedef VkMemoryOpaqueCaptureAddressAllocateInfo VkMemoryOpaqueCaptureAddressAllocateInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
opaqueCaptureAddress
是为内存分配请求的不透明捕获地址。
如果 opaqueCaptureAddress
为零,则不请求特定地址。
如果 opaqueCaptureAddress
不为零,则它应该是从同一实现上以相同方式创建的内存分配的 vkGetDeviceMemoryOpaqueCaptureAddress 中检索的地址。
在大多数情况下,非零 但是,这不是严格的要求,因为跟踪捕获/重放工具可能需要调整导入内存的内存分配参数。 |
如果此结构不存在,则如同 opaqueCaptureAddress
为零。
释放设备内存
要释放内存对象,请调用
// Provided by VK_VERSION_1_0
void vkFreeMemory(
VkDevice device,
VkDeviceMemory memory,
const VkAllocationCallbacks* pAllocator);
-
device
是拥有内存的逻辑设备。 -
memory
是要释放的 VkDeviceMemory 对象。 -
pAllocator
控制主机内存分配,如内存分配章节中所述。
在释放内存对象之前,应用程序必须确保设备不再使用该内存对象,例如,在挂起状态下的命令缓冲区中。内存可以在仍然绑定到资源时释放,但这些资源之后必须不再使用。释放内存对象会释放它对其有效负载所持有的引用(如果有)。如果仍然有任何绑定的图像或缓冲区,则内存对象的有效负载可能不会立即被实现释放,但必须在所有绑定的图像和缓冲区都被销毁时释放。一旦释放了对有效负载的所有引用,它就会返回到从中分配的堆。
内存对象如何绑定到图像和缓冲区在 资源内存关联 部分中有详细描述。
如果在释放时内存对象被映射,则它会被隐式取消映射。
如下文所述,当内存对象被取消映射时,主机写入不会被隐式刷新,但实现必须保证未刷新的写入不会影响任何其他内存。 |
主机对设备内存对象的访问
使用 vkAllocateMemory 创建的内存对象不能直接被主机访问。
使用内存属性 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
创建的内存对象被认为是可映射的。内存对象必须是可映射的,才能成功地在主机上映射。
要检索可映射内存对象区域的主机虚拟地址指针,请调用
// Provided by VK_VERSION_1_0
VkResult vkMapMemory(
VkDevice device,
VkDeviceMemory memory,
VkDeviceSize offset,
VkDeviceSize size,
VkMemoryMapFlags flags,
void** ppData);
-
device
是拥有内存的逻辑设备。 -
memory
是要映射的 VkDeviceMemory 对象。 -
offset
是从内存对象开始的基于零的字节偏移量。 -
size
是要映射的内存范围的大小,或者VK_WHOLE_SIZE
表示从offset
映射到分配的末尾。 -
flags
是 VkMemoryMapFlagBits 的位掩码,指定内存映射操作的其他参数。 -
ppData
是指向void*
变量的指针,在该变量中返回指向映射范围开始位置的主机可访问指针。返回的指针的值减去offset
必须与 VkPhysicalDeviceLimits::minMemoryMapAlignment
对齐。
在成功调用 vkMapMemory
后,内存对象 memory
被认为当前是主机映射的。
在已经是主机映射的内存对象上调用 |
如果实现无法分配适当大小的连续虚拟地址范围(例如,由于虚拟地址空间碎片或平台限制),则 |
vkMapMemory
不会检查设备内存是否在返回主机可访问指针之前正在使用。应用程序必须保证在主机从该范围读取或写入之前,任何先前提交的写入此范围的命令都已完成;并且在主机写入该区域之前,任何先前提交的从该范围读取的命令都已完成(有关满足此类保证的详细信息,请参见 此处)。如果设备内存是在未设置 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
的情况下分配的,则必须为扩展范围做出这些保证:应用程序必须将范围的起始位置向下舍入到 VkPhysicalDeviceLimits::nonCoherentAtomSize
的最接近的倍数,并将范围的结束位置向上舍入到 VkPhysicalDeviceLimits::nonCoherentAtomSize
的最接近的倍数。
当一段设备内存被主机映射时,应用程序负责同步该内存范围的设备和主机访问。
应用程序开发人员务必仔细熟悉同步和缓存控制章节中描述的所有机制,因为它们对于维护内存访问顺序至关重要。 |
调用 vkMapMemory
相当于调用带有空 pNext
链的 vkMapMemory2。
可以在 vkMapMemory::flags
和 VkMemoryMapInfo::flags
中设置的位,指定内存映射的附加属性,包括
// Provided by VK_VERSION_1_0
typedef enum VkMemoryMapFlagBits {
// Provided by VK_EXT_map_memory_placed
VK_MEMORY_MAP_PLACED_BIT_EXT = 0x00000001,
} VkMemoryMapFlagBits;
-
VK_MEMORY_MAP_PLACED_BIT_EXT
请求实现将内存映射放置在应用程序通过 VkMemoryMapPlacedInfoEXT::pPlacedAddress
指定的虚拟地址处,替换该地址处的任何现有映射。此标志必须不与 vkMapMemory 一起使用,因为没有办法指定放置地址。
// Provided by VK_VERSION_1_0
typedef VkFlags VkMemoryMapFlags;
VkMemoryMapFlags
是一种位掩码类型,用于设置零个或多个 VkMemoryMapFlagBits 的掩码。
或者,要检索可映射内存对象区域的主机虚拟地址指针,请调用
// Provided by VK_VERSION_1_4
VkResult vkMapMemory2(
VkDevice device,
const VkMemoryMapInfo* pMemoryMapInfo,
void** ppData);
或等效命令
// Provided by VK_KHR_map_memory2
VkResult vkMapMemory2KHR(
VkDevice device,
const VkMemoryMapInfo* pMemoryMapInfo,
void** ppData);
-
device
是拥有内存的逻辑设备。 -
pMemoryMapInfo
是指向 VkMemoryMapInfo 结构的指针,该结构描述了映射的参数。 -
ppData
是指向void *
变量的指针,该变量中返回指向映射范围起点的可主机访问指针。此指针减去 VkMemoryMapInfo::offset
的结果必须至少与 VkPhysicalDeviceLimits::minMemoryMapAlignment
对齐。
此函数的行为与 vkMapMemory 完全相同,只是它通过可扩展的结构指针而不是直接作为函数参数获取其参数。
VkMemoryMapInfo
结构的定义如下:
// Provided by VK_VERSION_1_4
typedef struct VkMemoryMapInfo {
VkStructureType sType;
const void* pNext;
VkMemoryMapFlags flags;
VkDeviceMemory memory;
VkDeviceSize offset;
VkDeviceSize size;
} VkMemoryMapInfo;
或等效的
// Provided by VK_KHR_map_memory2
typedef VkMemoryMapInfo VkMemoryMapInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
flags
是 VkMemoryMapFlagBits 的位掩码,指定内存映射操作的其他参数。 -
memory
是要映射的 VkDeviceMemory 对象。 -
offset
是从内存对象开始的基于零的字节偏移量。 -
size
是要映射的内存范围的大小,或者VK_WHOLE_SIZE
表示从offset
映射到分配的末尾。
如果 VkMemoryMapInfo
::flags
中设置了 VK_MEMORY_MAP_PLACED_BIT_EXT
,并且 VkMemoryMapInfo 的 pNext
链包含一个 VkMemoryMapPlacedInfoEXT
结构体,则该结构体指定了内存映射的放置地址。实现将在指定的地址放置内存映射,替换指定内存范围内的任何现有映射。以这种方式替换内存映射不会隐式取消映射 Vulkan 内存对象。相反,应用程序必须确保没有其他 Vulkan 内存对象映射在指定的虚拟地址范围内的任何位置。如果成功,ppData
将设置为与 VkMemoryMapPlacedInfoEXT
::pPlacedAddress
相同的值,并且 vkMapMemory2
将返回 VK_SUCCESS
。如果由于任何原因无法将映射放置在请求的地址,则内存对象将保持未映射状态,并且 vkMapMemory2
将返回 VK_ERROR_MEMORY_MAP_FAILED
。
VkMemoryMapPlacedInfoEXT
结构体定义如下:
// Provided by VK_EXT_map_memory_placed
typedef struct VkMemoryMapPlacedInfoEXT {
VkStructureType sType;
const void* pNext;
void* pPlacedAddress;
} VkMemoryMapPlacedInfoEXT;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
pPlacedAddress
是放置地址的虚拟地址。如果VkMemoryMapInfo
::flags
不包含VK_MEMORY_MAP_PLACED_BIT_EXT
,则此值将被忽略。
提供了两个命令,以使应用程序能够处理非一致性内存分配:vkFlushMappedMemoryRanges
和 vkInvalidateMappedMemoryRanges
。
虽然从 |
在成功调用 vkMapMemory
或 vkMapMemory2
后,内存对象 memory
被认为是当前主机映射的。
要刷新主机缓存中非一致性内存的范围,请调用
// Provided by VK_VERSION_1_0
VkResult vkFlushMappedMemoryRanges(
VkDevice device,
uint32_t memoryRangeCount,
const VkMappedMemoryRange* pMemoryRanges);
-
device
是拥有内存范围的逻辑设备。 -
memoryRangeCount
是pMemoryRanges
数组的长度。 -
pMemoryRanges
是一个指向 VkMappedMemoryRange 结构体数组的指针,这些结构体描述了需要刷新的内存范围。
vkFlushMappedMemoryRanges
保证了主机对 pMemoryRanges
描述的内存范围的写入对主机内存域可用,这样它们可以通过使用 VK_ACCESS_HOST_WRITE_BIT
访问类型的 内存域操作,对设备内存域可用。
第一个同步范围包括所有在其之前发生的主机操作,这些操作由主机内存模型定义。
注意
某些系统允许不直接与主机内存模型集成的写入;这些写入必须由应用程序手动同步。一个例子是 x86 上的非临时存储指令;为了确保这些操作发生在提交之前,应用程序应该调用 |
第二个同步范围为空。
第一个访问范围包括对指定内存范围的主机写入。
注意
当主机对内存位置的写入以这种方式可用时,内存位置所在的每个完整对齐的 |
第二个访问范围为空。
取消映射非一致性内存不会隐式刷新主机映射的内存,并且未刷新的主机写入可能永远对设备不可见。但是,实现必须确保未刷新的写入不会对任何其他内存可见。
上述保证避免了以下场景中潜在的内存损坏:在将内存对象取消映射(或释放)之前,主机对映射的内存对象的写入尚未刷新,并且该虚拟地址范围随后被重新用于不同的映射(或内存分配)。 |
要使主机缓存中的非一致性内存范围失效,请调用
// Provided by VK_VERSION_1_0
VkResult vkInvalidateMappedMemoryRanges(
VkDevice device,
uint32_t memoryRangeCount,
const VkMappedMemoryRange* pMemoryRanges);
-
device
是拥有内存范围的逻辑设备。 -
memoryRangeCount
是pMemoryRanges
数组的长度。 -
pMemoryRanges
是一个指向 VkMappedMemoryRange 结构体数组的指针,这些结构体描述了需要失效的内存范围。
vkInvalidateMappedMemoryRanges
保证了设备对 pMemoryRanges
描述的内存范围的写入,这些写入已使用 VK_ACCESS_HOST_WRITE_BIT
和 VK_ACCESS_HOST_READ_BIT
访问类型对主机内存域可用,并且对主机可见。如果主机写入并失效了非一致性内存范围,但没有先刷新,则其内容是未定义的。
第一个同步范围包括所有在其之前发生的主机操作,这些操作由主机内存模型定义。
注意
此函数不直接与设备操作同步 - 必须预先执行其他依赖于设备操作的主机同步操作,例如vkWaitForFences。因此,对于任何要对主机可见的非一致性设备写入,都必须存在以下依赖链:
|
第二个同步范围包括所有在其之后发生的主机操作,这些操作由主机内存模型定义。
第一个访问范围为空。
第二个访问范围包括对指定内存范围的主机读取。
注意
当设备对内存位置的写入以这种方式对主机可见时,内存位置所在的每个完整对齐的 |
映射非一致性内存不会隐式地使该内存失效。 |
VkMappedMemoryRange
结构体定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkMappedMemoryRange {
VkStructureType sType;
const void* pNext;
VkDeviceMemory memory;
VkDeviceSize offset;
VkDeviceSize size;
} VkMappedMemoryRange;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memory
是此范围所属的内存对象。 -
offset
是从内存对象开头开始的基于零的字节偏移量。 -
size
是范围的大小,或者如果需要影响从offset
到当前分配映射结尾的范围,则为VK_WHOLE_SIZE
。
要取消内存对象的映射,一旦应用程序不再需要对其进行主机访问,请调用
// Provided by VK_VERSION_1_0
void vkUnmapMemory(
VkDevice device,
VkDeviceMemory memory);
-
device
是拥有内存的逻辑设备。 -
memory
是要取消映射的内存对象。
调用 vkUnmapMemory
等效于调用 vkUnmapMemory2,其中 pNext
链为空,flags
设置为零。
或者,要取消内存对象的映射,一旦应用程序不再需要对其进行主机访问,请调用
// Provided by VK_VERSION_1_4
VkResult vkUnmapMemory2(
VkDevice device,
const VkMemoryUnmapInfo* pMemoryUnmapInfo);
或等效命令
// Provided by VK_KHR_map_memory2
VkResult vkUnmapMemory2KHR(
VkDevice device,
const VkMemoryUnmapInfo* pMemoryUnmapInfo);
-
device
是拥有内存的逻辑设备。 -
pMemoryUnmapInfo
是指向 VkMemoryUnmapInfo 结构的指针,该结构描述取消映射的参数。
此函数的行为与 vkUnmapMemory 完全相同,只是它通过可扩展结构指针而不是直接作为函数参数获取参数。
VkMemoryUnmapInfo
结构定义如下
// Provided by VK_VERSION_1_4
typedef struct VkMemoryUnmapInfo {
VkStructureType sType;
const void* pNext;
VkMemoryUnmapFlags flags;
VkDeviceMemory memory;
} VkMemoryUnmapInfo;
或等效的
// Provided by VK_KHR_map_memory2
typedef VkMemoryUnmapInfo VkMemoryUnmapInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
flags
是 VkMemoryUnmapFlagBits 的位掩码,用于指定内存映射操作的附加参数。 -
memory
是要取消映射的 VkDeviceMemory 对象。
可以在 VkMemoryUnmapInfo::flags
中设置的位,用于指定内存取消映射的附加属性,包括
// Provided by VK_VERSION_1_4
typedef enum VkMemoryUnmapFlagBits {
// Provided by VK_EXT_map_memory_placed
VK_MEMORY_UNMAP_RESERVE_BIT_EXT = 0x00000001,
} VkMemoryUnmapFlagBits;
或等效的
// Provided by VK_KHR_map_memory2
typedef VkMemoryUnmapFlagBits VkMemoryUnmapFlagBitsKHR;
-
VK_MEMORY_UNMAP_RESERVE_BIT_EXT
请求当前由内存映射占用的虚拟地址范围在 vkUnmapMemory2 调用完成后仍保持保留。未来的系统内存映射操作或对 vkMapMemory 或 vkMapMemory2 的调用将不会返回该范围内的地址,除非客户端之后取消保留该范围,或者通过使用VK_MEMORY_MAP_PLACED_BIT_EXT
调用 vkMapMemory2 或执行等效的系统内存映射将映射显式放置在该范围内。当设置了VK_MEMORY_UNMAP_RESERVE_BIT_EXT
时,内存取消映射操作可能会失败,在这种情况下,内存对象将保持主机映射状态,并且 vkUnmapMemory2 将返回VK_ERROR_MEMORY_MAP_FAILED
。
// Provided by VK_VERSION_1_4
typedef VkFlags VkMemoryUnmapFlags;
或等效的
// Provided by VK_KHR_map_memory2
typedef VkMemoryUnmapFlags VkMemoryUnmapFlagsKHR;
VkMemoryUnmapFlags
是一个位掩码类型,用于设置零个或多个 VkMemoryUnmapFlagBits 的掩码。
延迟分配的内存
如果内存对象是从设置了 VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
位的堆中分配的,则该对象的后备内存可能由实现延迟提供。内存的实际提交大小最初可能小至零(或大至请求的大小),并且随着需要额外的内存而单调递增。
仅允许将设置了此标志的内存类型绑定到使用标志包含 VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
的 VkImage
。
对渲染过程实例完成后不需要的帧缓冲区附件使用延迟分配的内存对象可能允许某些实现从不为此类附件分配内存。 |
要确定当前为内存对象提交的延迟分配内存量,请调用
// Provided by VK_VERSION_1_0
void vkGetDeviceMemoryCommitment(
VkDevice device,
VkDeviceMemory memory,
VkDeviceSize* pCommittedMemoryInBytes);
-
device
是拥有内存的逻辑设备。 -
memory
是正在查询的内存对象。 -
pCommittedMemoryInBytes
是指向VkDeviceSize
值的指针,成功时,其中返回当前提交的字节数。
实现可能随时更新提交,并且此查询返回的值可能已过时。
实现保证从内存对象创建时使用的内存类型指示的 heapIndex
中分配任何提交的内存。
受保护的内存
受保护的内存将设备内存划分为受保护的设备内存和未受保护的设备内存。
受保护的内存添加了以下概念:
-
内存
-
未受保护的设备内存,设备可以看到它,主机可以看到它
-
受保护的设备内存,设备可以看到它,但主机不得看到它。
-
-
资源
-
未受保护的图像和未受保护的缓冲区,未受保护的内存可以绑定到这些图像和缓冲区。
-
受保护的图像和受保护的缓冲区,受保护的内存可以绑定到这些对象。
-
-
命令缓冲区
-
非受保护的命令缓冲区,可以将其提交到设备队列以执行非受保护的队列操作。
-
受保护的命令缓冲区,可以将其提交到支持受保护功能的设备队列以执行受保护的队列操作。
-
-
设备队列
-
非受保护的设备队列,非受保护的命令缓冲区可以提交到这些队列。
-
支持受保护功能的设备队列,非受保护的命令缓冲区或受保护的命令缓冲区可以提交到这些队列。
-
-
队列提交
-
非受保护的队列提交,通过这种方式可以提交非受保护的命令缓冲区。
-
受保护的队列提交,通过这种方式可以提交受保护的命令缓冲区。
-
-
队列操作
-
非受保护的队列操作
-
受保护的队列操作
-
当启用 |
受保护内存访问规则
如果VkPhysicalDeviceProtectedMemoryProperties::protectedNoFault
为 VK_FALSE
,则应用程序必须不执行以下任何操作
-
在受保护的队列操作中写入非受保护的内存。
-
在受保护的队列操作中访问受保护的内存,除非是在帧缓冲区空间管线阶段、计算着色器阶段或传输阶段。
-
在受保护的队列操作中执行查询。
如果VkPhysicalDeviceProtectedMemoryProperties::protectedNoFault
为 VK_TRUE
,则这些操作是有效的,但读取操作将返回未定义的值,写入操作将被丢弃或存储未定义的值。
此外,间接操作必须不在受保护的队列操作中执行。
无论这些操作是否有效,或者是否执行了任何其他无效用法,实现必须保证
-
受保护的设备内存必须永远对主机不可见。
-
写入非受保护的设备内存的值必须不是来自受保护内存的值的函数。
外部内存句柄类型
Android 硬件缓冲区
Android 的 NDK 定义了 AHardwareBuffer
对象,这些对象表示可在进程之间共享的设备内存,并且可以被各种媒体 API 和用于实现这些 API 的硬件访问。这些 Android 硬件缓冲区对象可以被导入到 VkDeviceMemory 对象中,以便通过 Vulkan 访问,或者从 Vulkan 导出。如果 VkImage 或 VkBuffer 是使用 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID
创建的,则可以将其绑定到导入或导出的 VkDeviceMemory 对象。
为了消除不必要的编译时依赖,Vulkan 头部提供了一个不完整的 AHardwareBuffer
类型定义。
// Provided by VK_ANDROID_external_memory_android_hardware_buffer
struct AHardwareBuffer;
实际的 AHardwareBuffer
类型定义在 Android NDK 头部中。
可以使用 |
Android 硬件缓冲区对象使用 Android NDK 函数进行引用计数,这超出了本规范的范围。从 Android 硬件缓冲区导入的或者可以导出到 Android 硬件缓冲区的 VkDeviceMemory 必须获取其 AHardwareBuffer
对象的引用,并且必须在释放设备内存时释放此引用。在 Vulkan 命令的主机执行期间(该命令以 Android 硬件缓冲区作为参数,包括通过 pNext
链的间接参数),应用程序必须不将 Android 硬件缓冲区的引用计数减至零。
可以使用 NDK 函数映射和取消映射 Android 硬件缓冲区以进行 CPU 访问。这些锁定和解锁 API 被认为获取和释放了 Android 硬件缓冲区的所有权,应用程序必须遵循 外部资源共享 中描述的规则,以在 Vulkan 实例和这些原生 API 之间传输所有权。
Android 硬件缓冲区可以与同一设备上的外部 API 和 Vulkan 实例以及与外部设备共享。在传输 Android 硬件缓冲区的所有权时,队列族所有权转移中描述的外部和外部特殊队列族并不相同。所有生成或使用 Android 硬件缓冲区的 API 都被认为使用外部设备,但具有匹配的设备和驱动程序 UUID 的 OpenGL ES 上下文和 Vulkan 逻辑设备除外。当 Android 硬件缓冲区的用法仅允许在同一物理设备上使用时,实现可能将与外部队列族之间的传输视为与外部队列族之间的传输。
Android 硬件缓冲区的最佳用法
Vulkan 缓冲区和图像用法标志与 Android 硬件缓冲区用法标志不完全对应。当使用非 Vulkan API 分配 Android 硬件缓冲区时,如果包含任何 AHARDWAREBUFFER_USAGE_GPU_*
用法位,则默认情况下,分配器必须以这样一种方式分配内存,使其支持用法等效表中没有 Android 硬件缓冲区等效项的 Vulkan 用法和创建标志。
可以将 VkAndroidHardwareBufferUsageANDROID 结构包含在传递给 vkGetPhysicalDeviceImageFormatProperties2 的 VkImageFormatProperties2 结构的 pNext
链中,以获取特定 Vulkan 资源创建参数的最佳 Android 硬件缓冲区用法标志。这些命令返回的一些用法标志是基于输入参数必需的,但也可能返回其他供应商特定的用法标志 (AHARDWAREBUFFER_USAGE_VENDOR_*
)。任何使用这些供应商特定的用法标志分配并导入到 Vulkan 的 Android 硬件缓冲区必须仅绑定到使用参数创建的资源,这些参数是用于获取 Android 硬件缓冲区用法的参数的子集,因为内存可能以不兼容其他参数的方式分配。如果一个 Android 硬件缓冲区在推荐的用法之外,还成功地分配了额外的非供应商特定的用法标志,那么它必须支持以与仅使用推荐的用法分配的 Android 硬件缓冲区相同的方式使用,以及以额外的用法指示的方式使用。
Android 硬件缓冲区外部格式
Android 硬件缓冲区可能使用特定于实现的格式、布局、颜色模型等表示图像,这些格式、布局、颜色模型等没有 Vulkan 等效项。这种外部格式通常被外部图像源(如视频解码器或摄像头)使用。Vulkan 可以导入具有外部格式的 Android 硬件缓冲区,但由于图像内容可能采用专有表示形式,因此具有外部格式的图像必须具有最佳平铺,并且它们的使用受到限制。具有外部格式的图像必须仅使用启用了 Y′CBCR 转换的采样器进行采样。
将由 Android 硬件缓冲区支持的图像可以通过将 VkImageCreateInfo::format
设置为 VK_FORMAT_UNDEFINED
,并在 pNext
链中包含 VkExternalFormatANDROID 结构来使用外部格式。即使 Android 硬件缓冲区具有 等效 Vulkan 格式的格式,也可以使用外部格式创建图像,以便一致地处理可能使用这两种格式的图像源。但是,所有使用外部格式创建的图像都必须遵守与外部格式相关的有效使用要求,即使 Android 硬件缓冲区的格式具有 Vulkan 等效项。Android 硬件缓冲区的外部格式可以通过将 VkAndroidHardwareBufferFormatPropertiesANDROID 结构传递给 vkGetAndroidHardwareBufferPropertiesANDROID 来获得。
Android 硬件缓冲区图像资源
Android 硬件缓冲区具有固有的宽度、高度、格式和使用属性,因此绑定到从 Android 硬件缓冲区导入的内存的 Vulkan 图像必须使用专用分配:对于使用包含 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID
的 VkExternalMemoryImageCreateInfo::handleTypes
创建的图像,VkMemoryDedicatedRequirements
::requiresDedicatedAllocation
必须为 VK_TRUE
。在创建将绑定到导入的 Android 硬件缓冲区的图像时,图像创建参数必须等效于 VkMemoryAllocateInfo 的有效使用所描述的 AHardwareBuffer
属性。类似地,为专用图像分配的设备内存必须在绑定到该图像之前,才能导出到 Android 硬件缓冲区,并且实现必须返回一个属性从该图像导出的 Android 硬件缓冲区
-
AHardwareBuffer_Desc
的width
和height
成员必须分别与 VkImageCreateInfo::extent
的width
和height
成员相同。 -
AHardwareBuffer_Desc
的layers
成员必须与 VkImageCreateInfo 的arrayLayers
成员相同。 -
AHardwareBuffer_Desc
的format
成员必须等效于 VkImageCreateInfo::format
,如 AHardwareBuffer 格式等效性所定义。 -
AHardwareBuffer_Desc
的usage
成员必须包含与 VkImageCreateInfo::usage
和 VkImageCreateInfo::flags
中包含的位对应的位,其中根据 AHardwareBuffer 使用等效性存在这种对应关系。它可能还包括其他使用位,包括特定于供应商的使用。供应商使用位的存在可能导致 Android 硬件缓冲区只能以图像创建参数指示的方式使用,即使在 Vulkan 之外使用时也是如此,类似于使用 VkAndroidHardwareBufferUsageANDROID 中返回的使用分配 Android 硬件缓冲区一样。
对于具有 Android 硬件缓冲区外部句柄类型的图像,实现可能支持比非外部图像更少的图像创建参数组合。可以通过将 VkExternalImageFormatProperties 传递给 vkGetPhysicalDeviceImageFormatProperties2,并将 handleType
设置为 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID
来确定对给定参数集的支持。任何在 Vulkan 之外成功分配的,且使用包括 AHARDWAREBUFFER_USAGE_GPU_*
的 Android 硬件缓冲区,当使用等效的 Vulkan 图像参数时必须支持。如果支持导入给定的图像参数选择,则它们也可以用于创建将导出到 Android 硬件缓冲区的图像和内存。
AHardwareBuffer 格式 | Vulkan 格式 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AHardwareBuffer 使用 | Vulkan 使用或创建标志 |
---|---|
无 |
|
无 |
|
|
|
|
|
|
|
|
|
|
|
|
无 2 |
|
|
无 |
|
无 |
|
|
|
- 1
-
Vulkan 不区分
AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM
和AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM
:它们都表现为VK_FORMAT_R8G8B8A8_UNORM
。在外部实体写入AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM
Android 硬件缓冲区后,Vulkan 从 X/A 分量读取的值是未定义的。为了模拟采样或混合期间 X 分量的传统行为,应用程序应该在图像视图分量映射中使用VK_COMPONENT_SWIZZLE_ONE
,并在颜色混合因子中使用VK_BLEND_FACTOR_ONE
。当从此类图像复制到另一个图像或缓冲区时,无法避免复制这些未定义的值。 - 2
-
AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE
标志不对应于 Vulkan 图像使用或创建标志。相反,它的存在表示 Android 硬件缓冲区包含完整的 mipmap 链,它的不存在表示 Android 硬件缓冲区仅包含单个 mip 级别。 - 3
-
只有对格式有效的图像使用才是有效的。获取一个具有
AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM
格式和AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER
使用的 Android 硬件缓冲区,并尝试创建具有VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
的图像是无效的。 - 4
-
与
BLOB
以外的硬件缓冲区格式结合使用。
当将 |
Android 硬件缓冲区资源
格式为 AHARDWAREBUFFER_FORMAT_BLOB
且用法包含 AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER
的 Android 硬件缓冲区可以用作 VkBuffer 对象的后备存储。此类 Android 硬件缓冲区的字节大小由其 width
指定;height
和 layers
均为 1
。
与图像不同,由 Android 硬件缓冲区支持的缓冲区资源不需要专用分配。
导出的 AHardwareBuffer
对象如果没有专用图像,则必须具有 AHARDWAREBUFFER_FORMAT_BLOB
格式,用法必须包含 AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER
,width
必须等于设备内存分配大小,height
和 layers
必须为 1
。
QNX 屏幕缓冲区
QNX SDP 定义了 _screen_buffer
对象,该对象表示 QNX 屏幕图形子系统可以直接在其窗口系统 API 中使用的缓冲区。更具体地说,屏幕缓冲区是存储像素数据的内存区域。它可以附加到屏幕窗口、流或像素图。这些 QNX 屏幕缓冲区对象可以导入到 VkDeviceMemory 对象中,以便通过 Vulkan 访问。如果 VkImage 或 VkBuffer 是使用 VK_EXTERNAL_MEMORY_HANDLE_TYPE_SCREEN_BUFFER_BIT_QNX
创建的,则可以将其绑定到导入的 VkDeviceMemory 对象。
struct
_screen_buffer
是强类型的,因此命名句柄类型是多余的。struct
_screen_buffer
图像的内部布局以及大小可能取决于本地用法标志,这些标志没有相应的 Vulkan 对等项。
QNX 屏幕缓冲区有效性
QNX SDP 中屏幕的设计使得难以从屏幕外部确定对象的有效性。因此,应用程序必须确保在各种 Vulkan 接口中提供的 QNX 屏幕缓冲区对象是使用 QNX 屏幕 API 显式创建的。有关更多信息,请参阅 QNX SDP 文档。
从 QNX 屏幕缓冲区导入的 VkDeviceMemory 无法获取对其 _screen_buffer
对象的引用。因此,在主机执行 Vulkan 命令时,如果 Vulkan 命令将 QNX 屏幕缓冲区作为参数(包括通过 pNext
链的间接参数),应用程序必须确保 QNX 屏幕缓冲区资源保持有效。
通常,为了使 _screen_buffer
对象在 Vulkan 实现中有效使用,该缓冲区对象应该具有 _screen_buffer
::SCREEN_PROPERTY_USAGE
,其中至少包含以下之一:SCREEN_USAGE_VULKAN
、SCREEN_USAGE_OPENGL_ES2
、SCREEN_USAGE_OPENGL_ES3
或 SCREEN_USAGE_NATIVE
。所需的具体屏幕原生用法标志取决于 Vulkan 实现,QNX 屏幕本身不一定会强制执行这些要求。请注意,屏幕原生用法标志与 Vulkan 规范中的用法标志无关。
QNX 屏幕缓冲区外部格式
QNX 屏幕缓冲区可以使用特定于实现的格式、布局、颜色模型等表示图像,这些格式、布局、颜色模型等没有 Vulkan 等效项。此类外部格式通常由外部图像源(如视频解码器或摄像头)使用。Vulkan 可以导入具有外部格式的 QNX 屏幕缓冲区,但由于图像内容采用无法发现且可能专有的表示形式,因此具有外部格式的图像必须仅用作采样图像,必须仅使用启用了 Y′CBCR 转换的采样器进行采样,并且必须具有最佳平铺。
将由 QNX 屏幕缓冲区支持的图像可以通过将 VkImageCreateInfo::format
设置为 VK_FORMAT_UNDEFINED
并将 VkExternalFormatQNX 结构包含在 pNext
链中来使用外部格式。即使 QNX 屏幕缓冲区的格式具有 等效的 Vulkan 格式,也可以创建具有外部格式的图像,以实现对可能使用任一类别格式的源的图像的一致处理。QNX 屏幕缓冲区的外部格式可以通过将 VkScreenBufferFormatPropertiesQNX 结构传递给 vkGetScreenBufferPropertiesQNX 来获取。
QNX 屏幕缓冲区图像资源
QNX 屏幕缓冲区具有内在的宽度、高度、格式和用法属性,因此绑定到从 QNX 屏幕缓冲区导入的内存的 Vulkan 图像必须使用专用分配:对于使用包含 VK_EXTERNAL_MEMORY_HANDLE_TYPE_SCREEN_BUFFER_BIT_QNX
的 VkExternalMemoryImageCreateInfo::handleTypes
创建的图像,VkMemoryDedicatedRequirements
::requiresDedicatedAllocation
必须为 VK_TRUE
。创建将绑定到导入的 QNX 屏幕缓冲区的图像时,图像创建参数必须等效于 VkMemoryAllocateInfo 的有效用法中所述的 _screen_buffer
属性。
QNX 屏幕格式 | Vulkan 格式 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- 1
-
Vulkan 不区分
SCREEN_FORMAT_RGBA8888
和SCREEN_FORMAT_RGBX8888
:它们的行为都类似于VK_FORMAT_R8G8B8A8_UNORM
。在外部实体写入SCREEN_FORMAT_RGBX8888
QNX 屏幕缓冲区后,Vulkan 从 X/A 组件读取的值是未定义的。为了在采样或混合过程中模拟 X 组件的传统行为,应用程序应该在图像视图组件映射中使用VK_COMPONENT_SWIZZLE_ONE
,在颜色混合因子中使用VK_BLEND_FACTOR_ONE
。从这样的图像复制到另一个图像或缓冲区时,无法避免复制这些未定义的值。相同的行为适用于以下几对:SCREEN_FORMAT_BGRA8888
和SCREEN_FORMAT_BGRX8888
、SCREEN_FORMAT_RGBA1010102
和SCREEN_FORMAT_RGBX1010102
、SCREEN_FORMAT_BGRA1010102
和SCREEN_FORMAT_BGRX1010102
、SCREEN_FORMAT_RGBA5551
和SCREEN_FORMAT_RGBX5551
对等内存功能
对等内存是为给定的物理设备分配的内存,然后绑定到资源,并由逻辑设备中表示多个物理设备的不同物理设备访问。设备可能不支持某些读取和写入对等内存的方式。
要确定如何访问对等内存,请调用
// Provided by VK_VERSION_1_1
void vkGetDeviceGroupPeerMemoryFeatures(
VkDevice device,
uint32_t heapIndex,
uint32_t localDeviceIndex,
uint32_t remoteDeviceIndex,
VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
或等效命令
// Provided by VK_KHR_device_group
void vkGetDeviceGroupPeerMemoryFeaturesKHR(
VkDevice device,
uint32_t heapIndex,
uint32_t localDeviceIndex,
uint32_t remoteDeviceIndex,
VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
-
device
是拥有内存的逻辑设备。 -
heapIndex
是内存堆的索引,从中分配内存。 -
localDeviceIndex
是执行内存访问的物理设备的设备索引。 -
remoteDeviceIndex
是为之分配内存的物理设备的设备索引。 -
pPeerMemoryFeatures
是指向 VkPeerMemoryFeatureFlags 位掩码的指针,该位掩码指示对于堆、本地和远程设备的组合支持哪些类型的内存访问。
在 vkGetDeviceGroupPeerMemoryFeatures::pPeerMemoryFeatures
中可能设置的位,指示支持的对等内存特性,是
// Provided by VK_VERSION_1_1
typedef enum VkPeerMemoryFeatureFlagBits {
VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001,
VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002,
VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004,
VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008,
// Provided by VK_KHR_device_group
VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT,
// Provided by VK_KHR_device_group
VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT,
// Provided by VK_KHR_device_group
VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT,
// Provided by VK_KHR_device_group
VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT,
} VkPeerMemoryFeatureFlagBits;
或等效的
// Provided by VK_KHR_device_group
typedef VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR;
-
VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT
指定内存可以作为任何vkCmdCopy*
命令的源进行访问。 -
VK_PEER_MEMORY_FEATURE_COPY_DST_BIT
指定内存可以作为任何vkCmdCopy*
命令的目标进行访问。 -
VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT
指定内存可以作为任何内存访问类型进行读取。 -
VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT
指定内存可以作为任何内存访问类型进行写入。着色器原子操作被认为是写入。
内存堆的对等内存特性也适用于在图像布局转换期间可能执行的任何访问。 |
对于所有主机本地堆和至少一个设备本地内存堆,必须支持VK_PEER_MEMORY_FEATURE_COPY_DST_BIT
。
如果设备不支持对等内存特性,只要实际只访问本地绑定,使用包含本地和对等内存绑定的资源以及相应的访问类型仍然有效。 例如,执行分帧渲染的应用程序会使用包含本地和对等内存绑定的帧缓冲区附件,但会裁剪渲染以仅更新本地内存。
// Provided by VK_VERSION_1_1
typedef VkFlags VkPeerMemoryFeatureFlags;
或等效的
// Provided by VK_KHR_device_group
typedef VkPeerMemoryFeatureFlags VkPeerMemoryFeatureFlagsKHR;
VkPeerMemoryFeatureFlags
是一种位掩码类型,用于设置零个或多个 VkPeerMemoryFeatureFlagBits 的掩码。
不透明捕获地址查询
要从内存对象查询 64 位不透明捕获地址值,请调用
// Provided by VK_VERSION_1_2
uint64_t vkGetDeviceMemoryOpaqueCaptureAddress(
VkDevice device,
const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo);
或等效命令
// Provided by VK_KHR_buffer_device_address
uint64_t vkGetDeviceMemoryOpaqueCaptureAddressKHR(
VkDevice device,
const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo);
-
device
是分配内存对象的逻辑设备。 -
pInfo
是指向 VkDeviceMemoryOpaqueCaptureAddressInfo 结构的指针,该结构指定要检索地址的内存对象。
64 位返回值是一个不透明地址,表示 pInfo->memory
的起始位置。
如果内存对象使用非零值的 VkMemoryOpaqueCaptureAddressAllocateInfo::opaqueCaptureAddress
分配,则返回值必须是相同的地址。
这些不透明地址的预期用途仅供跟踪捕获/重放工具在跟踪中存储这些地址,并在重放期间随后指定它们。 |
VkDeviceMemoryOpaqueCaptureAddressInfo
结构的定义如下
// Provided by VK_VERSION_1_2
typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo {
VkStructureType sType;
const void* pNext;
VkDeviceMemory memory;
} VkDeviceMemoryOpaqueCaptureAddressInfo;
或等效的
// Provided by VK_KHR_buffer_device_address
typedef VkDeviceMemoryOpaqueCaptureAddressInfo VkDeviceMemoryOpaqueCaptureAddressInfoKHR;
-
sType
是标识此结构的 VkStructureType 值。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
memory
指定正在查询地址的内存。