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

3
假设我每个设备分配都绑定了一个VkBuffer,并使用适当的vkCmdCopyBuffer组合,逐块执行arena的紧凑操作。
假设arena可能包含任意对齐排列的线性和非线性数据。由于在绑定后,VkImage是不可变的,所以紧凑操作将涉及在已移动图像数据的新位置构建和绑定新的VkImage。
在arena进行紧凑操作时,其中没有任何资源被绑定到任何东西,也不能被视为“正在使用”。
实现这并不困难,但我有一个疑虑:
使用vkCmdCopyBuffer移动图像数据(以避免冗余布局转换),然后在新位置构造新的VkImage,是否存在未定义行为(UB)?
我的想法是,实现可能会做一些奇怪的事情,比如依赖于某些内部簿记结构中的绝对设备地址,这使得直到绑定到新对象之前,将图像数据视为POD就是UB。

1
你的最后一段描述了问题。 "图像布局" 包括无损压缩等内容。压缩通常涉及元数据,与像素数据分开存储,告诉如何解释存储在“像素”内存中的字节。在某些实现中,此元数据是 VkImage 内存的一部分,但以非位置独立的方式进行寻址。在其他情况下,它可能存储在其他地方,并通过像素数据的物理地址进行寻址。还有其他问题,例如灵敏度对物理对齐的交错布局,以实现在内存通道/银行上的良好分布。 - Jesse Hall
1个回答

2
好的,让我们系统地看一下这个问题。
首先,您需要找到适合您的图像的目标区域。然后使用 vkCmdCopyBuffer 从源区域复制到目标区域。接下来,您需要为该目标区域创建一个新的 VkImage,并指定其初始布局是什么?
请注意,在 VkCreateImageInfo 中,只有两个有效的 initialLayout 值:未定义或预初始化。而预初始化仅适用于使用线性平铺的图像,因为优化平铺图像没有明确定义的布局。
因此,您无法使用预初始化布局。而使用未定义布局意味着您将在下一个图像转换中使用可能会破坏存在任何数据的内容。现在,未定义的布局可能会在某些实现中工作。对于不关心布局的实现,它可能起作用。如果源图像处于一般布局中,则也可以在实现中使用。
但是,标准没有保证所有这些都可以按预期工作。就标准而言,如果将布局设置为未定义,则数据将无法保留。因此,无论缓冲器/图像别名的问题如何,这都行不通。
您必须在目标位置创建 VkImage,然后使用 vkCmdCopyImage 从源图像复制到目标位置。
还应该注意的是,即使布局问题得到解决,别名规则 告诉我们,从不允许主机访问的内存(即采用优化平铺或非一般/预初始化布局的图像)复制到主机访问的内存会产生未定义的值。因此,即使布局问题不是问题,复制本身也无法实现。至少在理论上如此。

我正在手动跟踪图像布局。我会提供最后已知的布局(或“未定义”),因为数据没有被更改,只是“瞬移”。由于我必须为每个障碍物提供已知的布局,我几乎没有理由相信驱动程序也在做同样的事情(说实话,这个API的一个非常恼人的方面)。除非vkBindImageMemory除了将VkImage与一些内存关联起来(可能覆盖一些元数据)之外,否则我认为只会出现内部树或链接列表的问题... - defube
@defube:这没关系。你无法提供“最后已知布局”,因为Vulkan 不允许initialLayout只能预初始化或未定义。如果您从未定义转换到最后已知的布局,则标准对该内存的内容不做任何保证。因此,您将依赖于未定义的行为。而且,既然您无论如何都必须创建目标VkImage,那么仅进行图像复制有什么不好呢?是要进行多次传输吗? - Nicol Bolas
@defube:顺便说一下,我在官方的Vulkan存储库中添加了一个问题,你可能想要关注一下,看看他们对支持这样的事情有什么说法。 - Nicol Bolas
1
问题在于需要临时空间并进行多个布局转换。碎片整理可能会将图像放置到低地址,仍然重叠其旧位置,而缓冲区复制是保存内容的唯一其他方法,而不需要暂存区域。因此,看起来可移植意味着需要用于碎片整理的临时空间(无论如何也不会经常发生)。我希望“未定义”的图像布局只是意味着“不要触摸它”,然后我会从最后已知的布局转换等等... - defube
1
一种实现的可能性是,每个vkImage可以基于某些原因拥有不同的最优tiling格式。 - ratchet freak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接