在Vulkan中更新顶点缓冲区的最常规正确方法

3
假设在设备内存中有一个顶点缓冲区,在主机上有一个内存一致且可见的分段缓冲区。同样假设使用独立GPU的桌面系统(因此具有单独的内存)。最后,假设帧间同步正确。我看到两种常见的更新顶点缓冲区的方法:
1. 映射+memcpy+取消映射到分段缓冲区,接下来是一个临时(单个命令)命令缓冲区,其中包含一个vkCmdCopyBuffer,将其提交给图形队列并等待队列空闲,然后释放临时命令缓冲区。之后像往常一样将常规帧绘制队列提交给图形队列。这是在https://vulkan-tutorial.com上使用的代码(例如这个 .cpp 文件)。
2. 类似于上述方法,只需使用其他信号量在分段缓冲区复制提交后进行标记,并在常规帧绘制提交中等待,从而跳过“等待空闲”命令。
第二种方法对我来说有点合理,我一再阅读不要在Vulkan中执行任何“等待空闲”操作,因为它会将CPU与GPU同步,但我从未在任何在线教程或示例中看到过它的使用。如果需要相对频繁地更新顶点缓冲区,专家通常会做什么?

1
"Map + memcpy + unmap into the staging buffer" 的意思是将数据从源内存复制到暂存缓冲区,然后再将其映射回目标内存。请注意,在删除内存之前,只有在需要时才取消映射一致的内存。多次映射内存没有任何意义。 - Nicol Bolas
嗯,对于我每帧更新的缓冲区,我实际上已经这样做了(保持映射),但是将所有分段缓冲区都保持映射也是有道理的。 - Blindy
1个回答

5
首先,如果您分配了连续内存,那么几乎肯定是为了从CPU访问它。这需要进行映射。 Vulkan不是OpenGL;没有要求在使用内存之前将其取消映射(而且OpenGL甚至不再有此要求)。
仅当您要删除内存分配本身时,才应该取消映射内存。
其次,如果您想到一个涉及让CPU等待队列或设备空闲的想法,那么您想出了一个不好的想法,并且应该使用另一种思路。唯一应该等待设备空闲的时间是当您想要销毁设备时。
教程代码不应被信任为最佳实践。它通常旨在简单易懂地说明一个概念。简单的Vulkan代码经常妨碍性能(如果您不关心性能,则不应使用Vulkan)。
无论如何,在Vulkan中大多数事情都没有“最普遍正确”的方法。有很多明确不正确的方法,但没有“通常要这样做”的建议。 Vulkan是一种低级别,显式API,其结果是您需要将Vulkan的工具应用于您的特定情况。也许在不同的硬件上进行配置文件。
例如,如果您每帧都生成全新的顶点数据,则最好查看实现是否可以直接从连续内存中读取顶点数据,这样根本不需要缓冲区。是的,读取可能会变慢,但整个过程可能比传输加读取更快。
另一方面,也可能不是这样。它在某些硬件上可能更快,在其他硬件上则更慢。某些硬件可能不允许您使用连续内存来存储任何具有顶点输入用途的缓冲区。即使允许,您可能能够在传输期间执行其他工作,因此GPU在读取传输的数据之前花费最少的时间。而且一些硬件具有一小池设备本地内存,您可以直接从CPU向其中写入;这种内存适用于这些流应用程序。
如果您要进行分段操作,则您的选择主要与您将传输操作提交到哪个队列有关(假设硬件具有多个队列)。这主要涉及您愿意忍受多少延迟。
例如,如果您正在为大型地形系统流式传输数据,则如果需要一两帧才能在GPU上使用顶点数据,则可能没有问题。在这种情况下,您应该寻找备选的仅传输队列,以在其中执行从分段缓冲区到主要内存的复制。如果您这样做,则需要确保后续使用最终结果的命令与该队列同步,这将需要通过信号量完成。

如果你处于需要低延迟的场景,并且传输的数据需要在本帧中使用,则将它们都提交到同一个队列可能更好。您可以使用事件来同步它们,而不是信号量。但是,您还应该努力在传输和渲染操作之间放置某种无关的工作,以便您可以利用一定程度的操作并行性。


1
"教程代码不应该被信任为最佳实践"--虽然我同意你的看法,但我必须从某个地方学习,对吧?我有来自 LunarG 的文档,描述了每个单独的函数和各种帮助理解它们的教程。无论如何,谢谢,我明白了,去掉空闲等待调用并在缓冲区更新提交和渲染命令提交之间使用同步。我将研究一下事件,我还没有听说过,提交调用只使用信号量和栅栏。 - Blindy
@Blindy: "在缓冲区更新提交和渲染命令提交之间使用同步" 我并没有提到"提交"。在单个帧中,您不应该向同一队列提交多次。vkQueueSubmit不是一个快速的函数,因此您应该尽可能地在每次调用时提交尽可能多的工作。 - Nicol Bolas
@Blindy:“只有提交等待信号量和信号量字段”。提交本身不会;提交中的批处理可以对信号量进行信号/等待。您可以提交多个批次。我试图传达的观点是,如果您将传输和渲染命令发送到同一队列,则不应在不同时间“提交”它们。可能要将它们全部一次性提交,也可能分批提交。 - Nicol Bolas
如果我理解正确的话,您是在谈论vkQueueSubmitvkQueuePresentKHR,对吗?我不认为文档中有关于提交与批量提交的区别。 - Blindy
@Blindy:在Vulkan规范的队列提交操作章节中,这一区别在第二段文字中明确表述。 - Nicol Bolas
显示剩余2条评论

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