Vulkan 內存分爲兩類: 主機內存 和 設備內存 。
10.1. 主機內存
主機內存是Vulkan實現需要的、設備不可見的內存。 這些內存可以用來存儲軟件內部數據。
Vulkan給應用程序提供了代表Vulkan實現來操作主機內存分配的機會。 如果這個特徵沒有被使用,Vulkan實現將使用自己的內存分配函數。 因爲大多數內存分配都不是在要求高性能代碼區域的,這就不是一個提升性能的特徵了。 相反,在一些嵌入式的平臺上,這還是非常有用的,如爲了調試(e.g. putting a guard page after all host allocations), 或者記錄內存分配。
內存分配器是應用程序通過一個指向VkAllocationCallbacks
類型數據的指針來提供的。
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
是一個指向應用程序定義的函數的指針,當被Vulkan實現調用時,就進行內部內存分配,類型爲PFN_vkInternalAllocationNotification
。 -
pfnInternalFree
是一個指向應用程序定義的函數的指針,當被Vulkan實現調用時,就釋放內部內存,類型爲PFN_vkInternalFreeNotification
。
正確使用
-
pfnAllocation
必須: 是一個有效的用戶自定義的PFN_vkAllocationFunction
類型的函數指針。 -
pfnReallocation
必須: 是一個指向有效的用戶自定義的PFN_vkReallocationFunction
類型的函數指針。 -
pfnFree
必須: 是一個指向有效的用戶自定義的PFN_vkFreeFunction
類型指針。 -
如果
pfnInternalAllocation
或者pfnInternalFree
不爲NULL
,那麼兩個都必須: 是有效的回調函數。
pfnAllocation
定義如下:
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`,且如果Vulkan實現因爲沒有獲取要求的內存而不能正確的繼續處理當前命令時, Vulkan實現必須把這個當作是運行時錯誤,在合適的時候給發生這個狀況的命令產生一個VK_ERROR_OUT_OF_HOST_MEMORY
錯誤, 如Return Codes中所描述。
如果Vulkan實現在沒有獲取到要求分配的內存時能夠繼續正確的處理當前命令,那麼它不能 因這次內存分配失敗而產生VK_ERROR_OUT_OF_HOST_MEMORY
。
pfnReallocation
類型如下:
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
字節的內存,原內存的內容從zero 到 min(original size, new size) - 1 必須: 被保留在新分配的內存中。 如果 size
比原來的內存要大, 附加部分內存的內容是未定義的。 如果滿足這些創建新內存的條件,那麼原來分配的內存應被釋放掉了。
若 pOriginal
是 NULL
, 那麼 pfnReallocation
必須: 表現的和以相同參數(除了pOriginal
)調用PFN_vkAllocationFunction
表現完全相同。
若 size
爲0, 那麼 pfnReallocation
必須: 表現的和以相同參數pUserData
,pMemory
等同於pOriginal
來調用 PFN_vkFreeFunction
完全相同。
若 pOriginal
是 non-NULL
, Vulkan實現必須 必須: 保證 alignment
等於 分配pOriginal
時所用到的alignment
。
若這個函數調用失敗,pOriginal
是 non-NULL
,應用程序不能: 釋放掉原來的內存。
pfnReallocation
必須: 符合PFN_vkAllocationFunction
返回值的規則。
pfnFree
類型定義如下:
typedef void (VKAPI_PTR *PFN_vkFreeFunction)(
void* pUserData,
void* pMemory);
-
pUserData
是由應用程序指定的內存分配器的VkAllocationCallbacks
::pUserData
指定的。 -
pMemory
是需要被釋放的內存。
pMemory
可能: 是 NULL
, 此時回調函數 必須: 謹慎的處理。 若 pMemory
是 non-NULL
, 它必須: 是一個指針,指向 pfnAllocation
或 pfnReallocation
之前分配的內存。 應用程序 應該: 釋放此內存。
pfnInternalAllocation
類型定義如下:
typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)(
void* pUserData,
size_t size,
VkInternalAllocationType allocationType,
VkSystemAllocationScope allocationScope);
-
pUserData
是由應用程序指定的內存分配器的VkAllocationCallbacks
::pUserData
指定的。 -
size
是要求分配的內存字節大小。 -
allocationType
是要求的內存分配的類型。 -
allocationScope
是一個VkSystemAllocationScope
類型的值,指定了內存分配的生命週期,如 這裏所述。
這是一個純粹的查看信息的回調函數。
pfnInternalFree
定義如下:
typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)(
void* pUserData,
size_t size,
VkInternalAllocationType allocationType,
VkSystemAllocationScope allocationScope);
-
pUserData
是由應用程序指定的內存分配器的VkAllocationCallbacks
::pUserData
指定的。 -
size
是要求分配的內存字節大小。 -
allocationType
是要求的內存分配的類型。 -
allocationScope
是一個VkSystemAllocationScope
類型的值,指定了內存分配的生命週期,如 這裏所述。
每一份分配的內存都有 分配存活期 ,定義了它自己的生命週期和所關聯對象。 內存存活期是通過傳遞給VkAllocationCallbacks
中定義的回調函數的allocationScope
參數提供的。 VkSystemAllocationScope
定義的可選的值如下:
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
- The allocation is scoped to the duration of the Vulkan command. -
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
- The allocation is scoped to the lifetime of the Vulkan object that is being created or used. -
VK_SYSTEM_ALLOCATION_SCOPE_CACHE
- The allocation is scoped to the lifetime of aVkPipelineCache
object. -
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE
- The allocation is scoped to the lifetime of the Vulkan device. -
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
- The allocation is scoped to the lifetime of the Vulkan instance.
大多數Vulkan命令操作單個對象,或者創建、操控單一對象。當一份分配的內存使用 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
或 VK_SYSTEM_ALLOCATION_SCOPE_CACHE
時,內存的存活範圍就是被創建或操控的對象。
當Vulkan實現獲取主機端內存時,它將回調應用程序提供的回調函數來使用特定的內存分配器和內存存活範圍:
-
若分配的內存生存週期限定於一個命令之內,內存分配器將使用
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND
。 若創建的、或者被操控的對象有對應的內存分配器,那麼將使用該特定的內存分配器,否則若 父VkDevice
有內存分配器,便使用此內存分配器,否則便使用父VkInstance
擁有的內存分配器。 -
若 If an allocation is associated with an object of type
VkPipelineCache
, the allocator will use theVK_SYSTEM_ALLOCATION_SCOPE_CACHE
allocation scope. The most specific allocator available is used (pipeline cache, else device, else instance). Else, -
If an allocation is scoped to the lifetime of an object, that object is being created or manipulated by the command, and that object’s type is not
VkDevice
orVkInstance
, the allocator will use an allocation scope ofVK_SYSTEM_ALLOCATION_SCOPE_OBJECT
. The most specific allocator available is used (object, else device, else instance). Else, -
If an allocation is scoped to the lifetime of a device, the allocator will use an allocation scope of
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE
. The most specific allocator available is used (device, else instance). Else, -
If the allocation is scoped to the lifetime of an instance and the instance has an allocator, its allocator will be used with an allocation scope of
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
. -
Otherwise an implementation will allocate memory through an alternative mechanism that is unspecified.
從緩存池中分配出來的對象並沒有指定它們對應的內存分配器。 當Vulkan實現爲此對象獲取主機端內存時,內存是由父緩存池的內存分配器獲取的。
不應期待應用程序會負責主機端執行代碼時處理內存分配活動,因爲多平臺上Vulkan實現的負責的安全性問題。 Vulkan實現將在內部分配內存,當這些內存分配或釋放時,調用通知性的回調函數告訴應用程序。 當分配這些可執行的內存時,pfnInternalAllocation
將會被調用。 當釋放這些可執行的內存時,pfnInternalFree
將被調用。 當分配或釋放這些可執行的內存時,Vulkan實現將只調用通知性的回調函數。
傳遞給 pfnInternalAllocation
和pfnInternalFree
函數的allocationType
參數 可能: 是如下值:
typedef enum VkInternalAllocationType {
VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0,
} VkInternalAllocationType;
-
VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE
- 分配的內存是計劃給CPU端使用的。
Vulkan實現在API命令執行期間,只能調用應用程序在當前線程提供的分配函數。 Vulkan實現不應該同時調用這些回調函數。如果需要保持同步,回調函數應該自己實現。提供信息這一類的回調函數也和內存分配函數一樣遵從此限制。
若Vulkan實現傾向於在vkCreate
*命令返回和對應的 vkDestroy
*命令開始之間通過VkAllocationCallbacks
數據結構來進行函數調用,該Vulkan實現必須在vkCreate
*返回之前保存一份內存分配器的copy。 它們依賴的回掉函數和任何數據結構都必須在與之關聯的對象生命週期內都保持有效。
若給vkCreate
*提供一個內存分配器,則必須要給對應的vkDestroy
*命令提供一個兼容匹配的內存分配器。 若用pfnAllocation
or pfnReallocation
分配而來的內存都可以被pfnReallocation
or pfnFree
釋放掉,那麼兩個VkAllocationCallbacks
數據結構必須兼容。 An allocator must not be provided to a vkDestroy
* command if an allocator was not provided to the corresponding vkCreate
* command.
If a non-NULL
allocator is used, the pfnAllocation
, pfnReallocation
and pfnFree
members must be non-NULL
and point to valid implementations of the callbacks. An application can choose to not provide informational callbacks by setting both pfnInternalAllocation
and pfnInternalFree
to NULL
. pfnInternalAllocation
and pfnInternalFree
must either both be NULL
or both be non-NULL
.
If pfnAllocation
or pfnReallocation
fail, the implementation may fail object creation and/or generate an VK_ERROR_OUT_OF_HOST_MEMORY
error, as appropriate.
內存分配回調函數不能調用任何Vulkan命令。
The following sets of rules define when an implementation is permitted to call the allocator callbacks.
pfnAllocation
或者 pfnReallocation
可能在一下情形中被調用:
-
Allocations scoped to a
VkDevice
orVkInstance
may be allocated from any API command. -
Allocations scoped to a command may be allocated from any API command.
-
Allocations scoped to a
VkPipelineCache
may only be allocated from:-
vkCreatePipelineCache
-
vkMergePipelineCaches
fordstCache
-
vkCreateGraphicsPipelines
forpPipelineCache
-
vkCreateComputePipelines
forpPipelineCache
-
-
Allocations scoped to a
VkDescriptorPool
may only be allocated from:-
any command that takes the pool as a direct argument
-
vkAllocateDescriptorSets
for thedescriptorPool
member of itspAllocateInfo
parameter -
vkCreateDescriptorPool
-
-
Allocations scoped to a
VkCommandPool
may only be allocated from:-
any command that takes the pool as a direct argument
-
vkCreateCommandPool
-
vkAllocateCommandBuffers
for thecommandPool
member of itspAllocateInfo
parameter -
any
vkCmd
* command whosecommandBuffer
was allocated from thatVkCommandPool
-
-
Allocations scoped to any other object may only be allocated in that object’s
vkCreate
* command.
pfnFree
可能在一下情形中被調用:
-
Allocations scoped to a
VkDevice
orVkInstance
may be freed from any API command. -
Allocations scoped to a command must be freed by any API command which allocates such memory.
-
Allocations scoped to a
VkPipelineCache
may be freed fromvkDestroyPipelineCache
. -
Allocations scoped to a
VkDescriptorPool
may be freed from-
any command that takes the pool as a direct argument
-
-
Allocations scoped to a
VkCommandPool
may be freed from:-
any command that takes the pool as a direct argument
-
vkResetCommandBuffer
whosecommandBuffer
was allocated from thatVkCommandPool
-
-
Allocations scoped to any other object may be freed in that object’s
vkDestroy
* command. -
Any command that allocates host memory may also free host memory of the same scope.