【发布时间】:2022-11-11 16:25:56
【问题描述】:
我正在尝试以渲染始终渲染为纹理的方式设置我的渲染器,然后我只呈现我喜欢的任何纹理,只要它的格式与交换链兼容。这意味着,我需要处理一个渲染场景、ui 等的图形队列(我还没有计算);一个将渲染图像复制到交换链中的传输队列;和一个用于呈现交换链的呈现队列。这是我目前正在尝试解决的用例,但随着渲染器的成熟,我将拥有更多这样的用例(例如计算队列)。
这是我想要实现的伪代码。我也在这里添加了一些我自己的假设:
// wait for fences per frame
waitForFences(fences[currentFrame]);
resetFences(fences[currentFrame]);
// 1. Rendering (queue = Graphics)
commandBuffer.begin();
renderEverything();
commandBuffer.end();
QueueSubmitInfo renderSubmit{};
renderSubmit.commandBuffer = commandBuffer;
// Nothing to wait for
renderSubmit.waitSemaphores = nullptr;
// Signal that rendering is complete
renderSubmit.signalSemaphores = { renderSemaphores[currentFrame] };
// Do not signal the fence yet
queueSubmit(renderSubmit, nullptr);
// 2. Transferring to swapchain (queue = Transfer)
// acquire the image that we want to copy into
// and signal that it is available
swapchain.acquireNextImage(imageAvailableSemaphore[currentFrame]);
commandBuffer.begin();
copyTexture(textureToPresent, swapchain.getAvailableImage());
commandBuffer.end();
QueueSubmitInfo transferSubmit{};
transferSubmit.commandBuffer = commandBuffer;
// Wait for swapchain image to be available
// and rendering to be complete
transferSubmit.waitSemaphores = { renderSemaphores[currentFrame], imageAvailableSemaphore[currentFrame] };
// Signal another semaphore that swapchain
// is ready to be used
transferSubmit.signalSemaphores = { readyForPresenting[currentFrame] };
// Now, signal the fence since this is the end of frame
queueSubmit(transferSubmit, fences[currentFrame]);
// 3. Presenting (queue = Present)
PresentQueueSubmitInfo presentSubmit{};
// Wait until the swapchain is ready to be presented
// Basically, waits until the image is copied to swapchain
presentSubmit.waitSemaphores = { readyForPresenting[currentFrame] };
presentQueueSubmit(presentSubmit);
我的理解是需要栅栏来确保 CPU 等到 GPU 完成将上一个命令缓冲区提交到队列。
在处理多个队列的时候,让CPU只等待帧,用信号量同步不同的队列就够了吗(上面的伪代码就是基于这个)?还是每个队列应该分别等待栅栏?
进入技术细节,如果两个命令缓冲区被提交到同一个队列而没有任何信号量会发生什么?伪代码:
// first submissions
commandBufferOne.begin();
doSomething();
commandBufferOne.end();
SubmitInfo firstSubmit{};
firstSubmit.commandBuffer = commandBufferOne;
queueSubmit(firstSubmit, nullptr);
// second submission
commandBufferTwo.begin();
doSomethingElse();
commandBufferTwo.end();
SubmitInfo secondSubmit{};
secondSubmit.commandBuffer = commandBufferOne;
queueSubmit(secondSubmit, nullptr);
第二次提交会覆盖第一个,还是第一个 FIFO 队列会在第二个之前执行,因为它是第一次提交的?
【问题讨论】:
-
如果 GPU 只有一个队列会发生什么?或者演示引擎不支持复制到交换链图像中?还是没有队列可以呈现,不能执行图形?
-
无论如何,我目前只使用一个队列,因为在我的 GPU 中,一个队列可以进行图形、传输和演示;但是,考虑到规范没有说明应该如何定义队列这一事实,我不确定对各种硬件有什么期望。
-
规范说所有图形队列都可以进行传输(和计算)操作。虽然 GPU 可以控制哪些队列系列可以进行演示,但这并不是真正的问题,因为演示不提供与之同步的栅栏。您只需要确保在提交图形操作后完成呈现即可。
-
我将从这里的规范中完全引用以供将来参考(我完全错过了第一个):“如果一个实现公开了任何支持图形操作的队列族,则至少一个队列族由至少一个物理设备公开实现必须同时支持图形和计算操作。”和“支持传输操作的队列上允许的所有命令也允许支持图形或计算操作的队列上。”