天天看點

Vulkan Specification(Vulkan規範):第十章 10.2.1

10.2.1. CPU通路裝置記憶體對象

通過

vkAllocateMemory

建立的記憶體對象不能被CPU端直接通路。

建立時帶有

VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT

屬性的記憶體對象被認為是 可映射的 。 記憶體對象必須是可映射的,才能被映射到CPU端。

可調用如下指令可以擷取指向映射到可映射記憶體對象的指針:

VkResult vkMapMemory(
    VkDevice                                    device,
    VkDeviceMemory                              memory,
    VkDeviceSize                                offset,
    VkDeviceSize                                size,
    VkMemoryMapFlags                            flags,
    void**                                      ppData);
           
  • device

     是擁有記憶體對象的邏輯裝置。
  • memory

     是将要被映射的

    VkDeviceMemory

     對象。
  • offset

     是一個從記憶體對象的起始的 從0開始的位元組offset。
  • size

     是需要映射的記憶體區間的大小,或者值為 

    VK_WHOLE_SIZE

    時表示 從 

    offset

     到配置設定的記憶體結尾的全部映射。
  • flags

     被保留。
  • ppData

     指向一個 被傳回的 host-accessible指向 被映射的區間指針。 這個指針 減去 

    offset

     必須被按照 

    VkPhysicalDeviceLimits

    ::

    minMemoryMapAlignment

     對齊。

若調用 

vkMapMemory

對已映射過的記憶體對象再次映射,則是應用程式的錯誤。

注意

vkMapMemory

 will fail if the implementation is unable to allocate an appropriately sized contiguous virtual address range, e.g. due to virtual address space fragmentation or platform limits. In such cases, 

vkMapMemory

 must return VK_ERROR_MEMORY_MAP_FAILED. The application can improve the likelihood of success by reducing the size of the mapped range and/or removing unneeded mappings using 

VkUnmapMemory

.

vkMapMemory

 并不在傳回一個host端可通路的指針之前檢查裝置記憶體目前是否正在使用中。 應用程式必須保證之前送出的任何指令(會向該區間寫入的指令)已經在host端讀取或者寫入完成,且任何之前被送出的指令(從該區間讀取内容的指令) 在host端寫入之前已經完成。 (參看 這裡 擷取更詳細的資訊). 若配置設定裝置記憶體時未帶有 

VK_MEMORY_PROPERTY_HOST_COHERENT_BIT

 标志位,必須提供這些保證,應用程式必須從 區間的起始到最鄰近的多個 

VkPhysicalDeviceLimits

::

nonCoherentAtomSize

聚集在一起,保證從區間的尾部到最鄰近的多個 

VkPhysicalDeviceLimits

::

nonCoherentAtomSize

 聚集在一起。

當一塊區域的裝置記憶體被映射到主機端可通路,應用程式需要負責同步該區間的記憶體通路。

注意

應用程式開發者需要對本章Synchronization and Cache Control 描述的機制相當熟悉, 這對于維持按序通路記憶體來說極其重要。

正确使用

  • memory

     必須未被映射過
  • offset

     必須要被 

    memory

     的大小要小
  • 若 

    size

     不等于 

    VK_WHOLE_SIZE

    , 

    size

     必須大于 
  • 若 

    size

     不等于 

    VK_WHOLE_SIZE

    size

     必須小于等于 

    memory

     減去 

    offset

    的結果的大小
  • memory

     必須在建立時帶有 記憶體類型 

    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT

Valid Usage (Implicit)

  • device

     must be a valid 

    VkDevice

     handle
  • memory

     must be a valid 

    VkDeviceMemory

     handle
  • flags

     must be 
  • ppData

     must be a pointer to a pointer
  • memory

     must have been created, allocated, or retrieved from 

    device

Host Synchronization

  • Host access to 

    memory

     must be externally synchronized

Return Codes

Success

  • VK_SUCCESS

Failure

  • VK_ERROR_OUT_OF_HOST_MEMORY

  • VK_ERROR_OUT_OF_DEVICE_MEMORY

  • VK_ERROR_MEMORY_MAP_FAILED

為了應用程式可以與非一緻性記憶體配置設定一起工作,有兩個指令可以使用: 

vkFlushMappedMemoryRanges

 和 

vkInvalidateMappedMemoryRanges

注意

若建立記憶體對象時帶有

VK_MEMORY_PROPERTY_HOST_COHERENT_BIT

 參數, 

vkFlushMappedMemoryRanges

 和 

vkInvalidateMappedMemoryRanges

 是沒有必要的,且可能會有性能損失。

可調用如下指令來把CPU緩存重新整理到非一緻的記憶體區域中:

VkResult vkFlushMappedMemoryRanges(
    VkDevice                                    device,
    uint32_t                                    memoryRangeCount,
    const VkMappedMemoryRange*                  pMemoryRanges);
           
  • device

     是擁有記憶體對象的邏輯裝置。
  • memoryRangeCount

     是 

    pMemoryRanges

     數組的長度。
  • pMemoryRanges

     是一個指向 

    VkMappedMemoryRange

     類型數組的指針,描述了需要重新整理的記憶體區域。

vkFlushMappedMemoryRanges

 必須用于保證host端寫入到非一緻性記憶體的内容對于 device可見。 隻能在host端寫入到非一緻性記憶體之後,且在會讀取或寫入這些記憶體的指令緩沖區被送出到隊列之前,才可以被調用。

注意

取消非一緻性記憶體映射并不意味着重新整理被映射的記憶體, 沒有被重新整理的 host端寫入的内容 可能對device不可見。

Valid Usage (Implicit)

  • device

     must be a valid 

    VkDevice

     handle
  • pMemoryRanges

     must be a pointer to an array of 

    memoryRangeCount

     valid 

    VkMappedMemoryRange

     structures
  • memoryRangeCount

     must be greater than 

Return Codes

Success

  • VK_SUCCESS

Failure

  • VK_ERROR_OUT_OF_HOST_MEMORY

  • VK_ERROR_OUT_OF_DEVICE_MEMORY

可調用如下函數從host端cache使 非一緻性記憶體無效:

VkResult vkInvalidateMappedMemoryRanges(
    VkDevice                                    device,
    uint32_t                                    memoryRangeCount,
    const VkMappedMemoryRange*                  pMemoryRanges);
           
  • device

     是擁有記憶體範圍的邏輯裝置。
  • memoryRangeCount

     是 

    pMemoryRanges

     數組的長度。
  • pMemoryRanges

     是一個指針,指向一個 

    VkMappedMemoryRange

     資料結構的數組,描述了需要無效化的記憶體區間。

vkInvalidateMappedMemoryRanges

 must be used to guarantee that device writes to non-coherent memory are visible to the host. It must be called after command buffers that execute and flush (via memory barriers) the device writes have completed, and before the host will read or write any of those locations. If a range of non-coherent memory is written by the host and then invalidated without first being flushed, its contents are undefined.

注意

Mapping non-coherent memory does not implicitly invalidate the mapped memory, and device writes that have not been invalidated must be made visible before the host reads or overwrites them.

Valid Usage (Implicit)

  • device

     must be a valid 

    VkDevice

     handle
  • pMemoryRanges

     must be a pointer to an array of 

    memoryRangeCount

     valid 

    VkMappedMemoryRange

     structures
  • memoryRangeCount

     must be greater than 

Return Codes

Success

  • VK_SUCCESS

Failure

  • VK_ERROR_OUT_OF_HOST_MEMORY

  • VK_ERROR_OUT_OF_DEVICE_MEMORY

VkMappedMemoryRange

 類型資料結構定義如下:

typedef struct VkMappedMemoryRange {
    VkStructureType    sType;
    const void*        pNext;
    VkDeviceMemory     memory;
    VkDeviceSize       offset;
    VkDeviceSize       size;
} VkMappedMemoryRange;
           
  • sType

     是資料結構的類型。
  • pNext

     是 

    NULL

     或者一個指向拓展特定的資料結構的指針。
  • memory

     是這個區間所在的記憶體對象。
  • offset

     是一個從記憶體對象的起始位置開始的,從0開始的偏移量。
  • size

     要麼是區間的大小,要麼是 影響到 從 

    offset

     到目前映射到配置設定的記憶體結束的區間的 

    VK_WHOLE_SIZE

     。

正确使用

  • memory

     目前必須已經被映射了
  • 若 

    size

     和 

    VK_WHOLE_SIZE

     不相等,

    offset

     和 

    size

     必須: 指定已經映射的記憶體 

    memory

     之中的一段區間。
  • 若 

    size

     和 

    VK_WHOLE_SIZE

     相等, 

    offset

     必須: 和已經映射的記憶體的區間完全相同。
  • offset

     必須: 是 

    VkPhysicalDeviceLimits

    ::

    nonCoherentAtomSize

     的倍數
  • 若 

    size

    和 

    VK_WHOLE_SIZE

     不相等,

    size

     必須: 是 

    VkPhysicalDeviceLimits

    ::

    nonCoherentAtomSize

     的倍數。

Valid Usage (Implicit)

  • sType

     must be 

    VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE

  • pNext

     must be 

    NULL

  • memory

     must be a valid 

    VkDeviceMemory

     handle

editing-note

TODO (Tobias) - There’s a circular section reference between this next section and the synchronization section. The information is all covered by both places, but it seems a bit weird to have them reference each other. Not sure how to resolve it.

Host-visible memory types that advertise the 

VK_MEMORY_PROPERTY_HOST_COHERENT_BIT

 property still require memory barriers between host and device in order to be coherent, but do not require additional cache management operations to achieve coherency. For host writes to be seen by subsequent command buffer operations, a pipeline barrier from a source of 

VK_ACCESS_HOST_WRITE_BIT

 and 

VK_PIPELINE_STAGE_HOST_BIT

 to a destination of the relevant device pipeline stages and access types must be performed. Note that such a barrier is performed implicitly upon each command buffer submission, so an explicit barrier is only rarely needed (e.g. if a command buffer waits upon an event signaled by the host, where the host wrote some data after submission). A pipeline barrier is required to make writes visible to subsequent reads on the host.

應用程式若不在需要從host端通路記憶體對象,可調用如下指令來取消映射:

void vkUnmapMemory(
    VkDevice                                    device,
    VkDeviceMemory                              memory);
           
  • device

     是擁有記憶體的邏輯裝置。
  • memory

     是将要被取消映射的記憶體對象。

正确使用

  • memory

     在目前必須被映射過

Valid Usage (Implicit)

  • device

     must be a valid 

    VkDevice

     handle
  • memory

     must be a valid 

    VkDeviceMemory

     handle
  • memory

     must have been created, allocated, or retrieved from 

    device

Host Synchronization

  • Host access to 

    memory

     must be externally synchronized