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
並不在返回一個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
必須大於0
-
若
size
不等於VK_WHOLE_SIZE
,size
必須小於等於memory
減去offset
的結果的大小 -
memory
必須在創建時帶有 內存類型VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
Valid Usage (Implicit)
-
device
must be a validVkDevice
handle -
memory
must be a validVkDeviceMemory
handle -
flags
must be0
-
ppData
must be a pointer to a pointer -
memory
must have been created, allocated, or retrieved fromdevice
Host Synchronization
-
Host access to
memory
must be externally synchronized
Return Codes
-
VK_SUCCESS
-
VK_ERROR_OUT_OF_HOST_MEMORY
-
VK_ERROR_OUT_OF_DEVICE_MEMORY
-
VK_ERROR_MEMORY_MAP_FAILED
爲了應用程序可以與非一致性內存分配一起工作,有兩個命令可以使用: 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 validVkDevice
handle -
pMemoryRanges
must be a pointer to an array ofmemoryRangeCount
validVkMappedMemoryRange
structures -
memoryRangeCount
must be greater than0
Return Codes
-
VK_SUCCESS
-
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 validVkDevice
handle -
pMemoryRanges
must be a pointer to an array ofmemoryRangeCount
validVkMappedMemoryRange
structures -
memoryRangeCount
must be greater than0
Return Codes
-
VK_SUCCESS
-
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 beVK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE
-
pNext
must beNULL
-
memory
must be a validVkDeviceMemory
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 validVkDevice
handle -
memory
must be a validVkDeviceMemory
handle -
memory
must have been created, allocated, or retrieved fromdevice
Host Synchronization
-
Host access to
memory
must be externally synchronized