Vulkan:使用缓冲区别名实现碎片整理方案

Vulkan: Using buffer aliasing to implement a defragmentation scheme

假设我有一个 VkBuffer 绑定到每个设备分配,并使用 vkCmdCopyBuffer 的适当组合逐块执行竞技场碎片整理。

假设一个竞技场可能包含任何适当排列的线性和非线性数据。由于绑定后 VkImage 的不变性,碎片整理将涉及在已移动的图像数据的新位置构建和绑定新的 VkImage

None 正在碎片整理的区域中的资源绑定到任何东西,或者可以被认为是 "in-use"。

这并不难实现,尽管我有一个顾虑:

使用 vkCmdCopyBuffer 移动图像数据(以避免冗余布局转换),然后在新位置构建新的 VkImage 是不是 UB?

我的想法是,也许一个实现会做一些奇怪的事情,比如依赖一些内部簿记结构中的绝对设备地址,使得它 UB 将图像数据视为 POD,直到绑定到一个新对象。

嗯,系统的来看一下吧

所以你为你的图片找到了一个合适的目标区域。您执行 vkCmdCopyBuffer 从源区域复制到目标区域。现在您为该目标区域创建一个新的 VkImage,您指定的初始布局是...什么?

看,VkCreateImageInfo 中只有两个有效的 initialLayout 值:未定义或预初始化。并且预初始化仅适用于使用线性平铺的图像,因为没有用于最佳平铺图像的明确定义的布局。

所以你不能使用预初始化布局。使用未定义的布局意味着您使用的下一个图像转换可能会破坏那里的任何数据。现在,未定义的布局 可能会在某些实现上起作用 。在不关心布局的实现上,它可能会起作用。如果源图像在一般布局中,它也可能适用于实现。

但是 none 保证 按照标准工作。就标准而言,如果将布局设置为未定义,则不会保留数据。因此,无论 buffer/image 别名问题如何,这都行不通。

您必须在目标位置创建 VkImage,然后使用 vkCmdCopyImage 从源图像复制到目标位置。

还应注意,即使布局问题有效,aliasing rules 告诉我们从非主机可访问内存复制(即:最佳平铺图像或 non-general/preinitialized 布局) 到主机可访问的内存产生未定义的值。所以即使布局问题不是问题,副本本身也不起作用。理论上至少是。