Vulkan 在内存方面识别出两个不同的概念。有设备可以与之通信的实际物理 RAM 块。然后有方法可以从其中一个 RAM 池中分配内存。
堆代表一块特定的 RAM。 VkMemoryHeap 是描述设备可以与之通信的可用 RAM 堆之一的对象。真正定义特定堆的东西并不多。只有两个:RAM 存储的字节数和存储相对于 Vulkan 设备的位置(本地与非本地)。
内存类型是从特定堆分配内存的特定手段。 VkMemoryType 是描述分配内存的特定方式的对象。对于如何从堆中分配内存,还有更多描述性标志。
举一个更具体的例子,考虑一个带有独立 GPU 的标准 PC 设置。该设备有自己的本地 RAM,但独立 GPU 也可以访问 CPU 内存。因此,Vulkan 设备将有两个堆:其中一个是本地的,另一个是非本地的。
但是,通常会有两个以上的内存类型。您通常有一种表示本地内存的内存类型,它没有VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT 集。这意味着您无法映射内存。您只能通过其他内存类型(或渲染操作或其他)的传输操作来访问它。
但您通常会有两种内存类型,它们都使用相同的非本地堆。它们都是VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,因此允许映射。但是,其中一个可能会设置VK_MEMORY_PROPERTY_HOST_CACHED_BIT 标志,而另一个将设置VK_MEMORY_PROPERTY_HOST_COHERENT_BIT。这允许您选择是否需要缓存 CPU 访问(因此需要显式刷新已修改内存范围)或非缓存 CPU 访问。
虽然它们是两种不同的内存类型,但它们都是从同一个堆中分配的。这就是为什么VkMemoryType 有一个索引,该索引指向分配它的内存的堆。
我唯一不明白的是两个 DEVICE_LOCAL 标志如何交互。
你看过规范吗?它并没有完全隐藏它是如何工作的:
如果propertyFlags 设置了VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT 位,则分配给这种类型的内存对于设备访问来说是最有效的。只会为属于具有VK_MEMORY_HEAP_DEVICE_LOCAL_BIT 集的堆的内存类型设置此属性。
是说如果内存是本地的,那么与该内存对应的所有类型都是本地的,还是说它们可以是本地的?
您似乎试图将错误的含义强加给这些东西。只需看看规范所说的内容,并从表面上看。
PROPERTY_DEVICE_LOCAL 表示将实现最佳设备访问性能的内存类型。这与MEMORY_DEVICE_LOCAL 之间的唯一联系是带有PROPERTY_DEVICE_LOCAL 的内存类型将仅与使用MEMORY_DEVICE_LOCAL 的内存堆相关联。
这是这里唯一相关的意思。
如果您想举例说明内存堆何时是设备本地的,但内存类型却不是,请考虑一个没有自己内存的 GPU。只有一个堆,因此是MEMORY_DEVICE_LOCAL。
但是,以使其主机可见的方式从该池分配内存可能会降低设备访问该内存的性能。因此,for such hardware,同一个堆的主机可见内存类型不会使用PROPERTY_DEVICE_LOCAL。
再一次,other hardware 不会因为使内存主机可见而失去性能。所以它们只有一种内存类型,它具有所有可用的属性。对于英特尔来说,他们的片上 GPU 显然可以访问某种级别的 CPU 缓存。