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)
-
devicemust be a validVkDevicehandle -
memorymust be a validVkDeviceMemoryhandle -
flagsmust be0 -
ppDatamust be a pointer to a pointer -
memorymust have been created, allocated, or retrieved fromdevice
Host Synchronization
-
Host access to
memorymust 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)
-
devicemust be a validVkDevicehandle -
pMemoryRangesmust be a pointer to an array ofmemoryRangeCountvalidVkMappedMemoryRangestructures -
memoryRangeCountmust 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)
-
devicemust be a validVkDevicehandle -
pMemoryRangesmust be a pointer to an array ofmemoryRangeCountvalidVkMappedMemoryRangestructures -
memoryRangeCountmust 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)
-
sTypemust beVK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE -
pNextmust beNULL -
memorymust be a validVkDeviceMemoryhandle
| 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)
-
devicemust be a validVkDevicehandle -
memorymust be a validVkDeviceMemoryhandle -
memorymust have been created, allocated, or retrieved fromdevice
Host Synchronization
-
Host access to
memorymust be externally synchronized
本文详述了Vulkan API中如何管理设备内存,包括内存对象的映射、访问和同步机制。重点介绍了vkMapMemory、vkFlushMappedMemoryRanges、vkInvalidateMappedMemoryRanges和vkUnmapMemory等关键函数的使用,以及与主机端内存交互时的注意事项。
5397

被折叠的 条评论
为什么被折叠?



