Vulkan Specification(Vulkan規範):第十章 10.1 主機內存

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(或者pfnReallocation)在遇到 一次爲了直接或者間接調試目的的內存分配失敗時,能導致正在運行的Vulkan實例終止。 在這些情形下,不能假設受影響的VkInstance對象的任何部分將正常工作(甚至是vkDestroyInstance),且應用程序 必須保證通過其他途徑適當的做好清掃工作(比如進程終止)。

如果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 必須: 表現的和以相同參數pUserDatapMemory 等同於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 a VkPipelineCache 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 the VK_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 or VkInstance, the allocator will use an allocation scope of VK_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 pfnAllocationpfnReallocation 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 NULLpfnInternalAllocation 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 or VkInstance 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 for dstCache

    • vkCreateGraphicsPipelines for pPipelineCache

    • vkCreateComputePipelines for pPipelineCache

  • Allocations scoped to a VkDescriptorPool may only be allocated from:

    • any command that takes the pool as a direct argument

    • vkAllocateDescriptorSets for the descriptorPool member of its pAllocateInfo 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 the commandPool member of its pAllocateInfo parameter

    • any vkCmd* command whose commandBuffer was allocated from that VkCommandPool

  • Allocations scoped to any other object may only be allocated in that object’s vkCreate* command.

pfnFree 可能在一下情形中被調用:

  • Allocations scoped to a VkDevice or VkInstance 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 from vkDestroyPipelineCache.

  • 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 whose commandBuffer was allocated from that VkCommandPool

  • 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.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章