gpt4 book ai didi

c++ - 在 Vulkan 中,每个交换链图像、每个帧或每个命令池是否需要专用的栅栏/信号量?

转载 作者:行者123 更新时间:2023-12-03 20:47:11 31 4
gpt4 key购买 nike

我已经阅读了几篇关于 CPU-GPU(使用栅栏)和 GPU-GPU(使用信号量)同步机制的文章,但仍然无法理解我应该如何实现一个简单的渲染循环。
请看简单的render()下面的功能。如果我猜对了,最低要求是我们确保 vkAcquireNextImageKHR 之间的 GPU-GPU 同步。 , vkQueueSubmitvkQueuePresentKHR通过一组信号量image_availablerendering_finished正如我在下面的示例代码中所做的那样。
然而,这真的省了吗?所有操作都是异步的。那么,“重用”image_available 真的安全吗?在后续调用 render() 中的信号量即使之前调用的信号请求还没有触发?我认为不是,但是另一方面,我们使用相同的队列(不知道图形和表示队列实际上是否相同是否重要)并且队列内的操作应该按顺序使用.. .但如果我做对了,它们可能不会“作为一个整体”被消耗,并且可以重新排序......
第二件事是(同样,除非我遗漏了什么)我显然应该为每个交换链图像使用一个栅栏,以确保对图像的操作对应于 image_index调用render()已完成。但这是否意味着我一定需要做一个

if (vkWaitForFences(device(), 1, &fence[image_index_of_last_call], VK_FALSE, std::numeric_limits<std::uint64_t>::max()) != VK_SUCCESS)
throw std::runtime_error("vkWaitForFences");
vkResetFences(device(), 1, &fence[image_index_of_last_call]);
在我调用 vkAcquireNextImageKHR 之前?那么我需要专门的 image_available吗?和 rendering_finished每个交换链图像的信号量?或者也许每帧?或者也许每个命令缓冲区/池?我真的很困惑...
void render()
{
std::uint32_t image_index;
switch (vkAcquireNextImageKHR(device(), swap_chain().handle(),
std::numeric_limits<std::uint64_t>::max(), m_image_available, VK_NULL_HANDLE, &image_index))
{
case VK_SUBOPTIMAL_KHR:
case VK_SUCCESS:
break;
case VK_ERROR_OUT_OF_DATE_KHR:
on_resized();
return;
default:
throw std::runtime_error("vkAcquireNextImageKHR");
}

static VkPipelineStageFlags constexpr wait_destination_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;

VkSubmitInfo submit_info{};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;

submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &m_image_available;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &m_rendering_finished;

submit_info.pWaitDstStageMask = &wait_destination_stage_mask;

if (vkQueueSubmit(graphics_queue().handle, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS)
throw std::runtime_error("vkQueueSubmit");

VkPresentInfoKHR present_info{};
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;

present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = &m_rendering_finished;

present_info.swapchainCount = 1;
present_info.pSwapchains = &swap_chain().handle();
present_info.pImageIndices = &image_index;

switch (vkQueuePresentKHR(presentation_queue().handle, &present_info))
{
case VK_SUCCESS:
break;
case VK_ERROR_OUT_OF_DATE_KHR:
case VK_SUBOPTIMAL_KHR:
on_resized();
return;
default:
throw std::runtime_error("vkQueuePresentKHR");
}
}
编辑 :正如以下答案中所建议的,假设我们有 k “飞行中的帧”,因此 k上面代码中使用的信号量和栅栏的实例,我将用 m_image_available[i] 表示, m_rendering_finished[i]m_fence[i]对于 i = 0, ..., k - 1 .让 i表示飞行中帧的当前索引,增加 1每次调用 render() 之后, 和 j表示 render() 的调用次数, 从 j = 0 开始.
现在,假设交换链包含三个图像。
  • 如果 j = 0 ,然后 i = 0飞行中的第一帧正在使用交换链图像 0
  • 同理,如果 j = a ,然后 i = aa飞行中的第 1 帧正在使用交换链图像 a , 对于 a= 2, 3
  • 现在,如果 j = 3 ,然后 i = 3 ,但由于交换链图像只有三个图像,所以第四帧正在使用交换链图像0再次。我想知道这是否有问题。我猜不是,因为等待/信号信号量 m_image_available[3]/m_rendering_finished[3] , 用于 vkAcquireNextImageKHR 的调用, vkQueueSubmitvkQueuePresentKHR在这个 render() 的调用中, 专用于飞行中的这个特定帧。
  • 如果我们到达 j = k ,然后 i = 0再次,因为只有 k飞行中的帧。现在我们可能在 render() 的开头等待, 如果调用 vkQueuePresentKHRi = 0 的第一次调用 ( render() )未发出信号m_fence[0]然而。

  • 所以,除了我在上面第三个要点中描述的怀疑之外,唯一剩下的问题是为什么我不应该接受 k尽可能大?我理论上可以想象的是,如果我们以比 GPU 能够消耗的更快的方式向 GPU 提交工作,则使用的队列可能会不断增长并最终溢出(队列中是否存在某种“最大命令“限制?)。

    最佳答案

    If I got it right, the minimal requirement is that we ensure the GPU-GPU synchronization between vkAcquireNextImageKHR, vkQueueSubmit and vkQueuePresentKHR by a single set of semaphores image_available and rendering_finished as I've done in the example code below.


    是的,你没看错。您通过 vkAcquireNextImageKHR 提交了获得要渲染的新图像的愿望。 .演示引擎将发出 m_image_available 的信号。一旦要渲染的图像可用,就可以使用信号量。但是您已经提交了指令。
    接下来,通过 submit_info 向图形队列提交一些命令。 . IE。它们也已经提交给 GPU 并在那里等到 m_image_available信号量接收它的信号。
    此外,一个表示指令被提交给表示引擎,它表达了它需要等到 submit_info 的依赖关系。 - 命令已通过等待 m_rendering_finished 完成信号。
    IE。一切都已提交。如果尚未发出任何信号,则所有内容都将位于某些 GPU 缓冲区中并等待信号。
    现在,如果您的代码直接循环回到 render()功能和重复使用相同的 m_image_availablem_rendering_finished信号量,它只有在你非常幸运的情况下才会起作用,即如果所有信号量在你再次使用它们之前已经发出信号。 vkAcquireNextImageKHR 的规范说明如下:

    If semaphore is not VK_NULL_HANDLE it must not have any uncompleted signal or wait operations pending


    此外,它在 7.4.2. Semaphore Waiting 下显示

    the act of waiting for a binary semaphore also unsignals that semaphore.


    IE。实际上,您需要在 CPU 上等待,直到您确定前面的 vkAcquireNextImageKHR使用相同的 m_image_available信号量已完成。
    是的,你已经猜对了:你需要为传递给 vkQueueSubmit 的东西使用栅栏。 .如果您不在 CPU 上进行同步,您将把更多的工作推给 GPU(这是一个问题),并且您正在重复使用的信号量可能无法及时正确地取消信号(这是一个问题)。
    经常做的是信号量和栅栏成倍增加,例如每个为 3 个,并且这些同步对象集是按顺序使用的,这样可以在 GPU 上并行化更多的工作。 Vulkan Tutorial在其 Rendering and presentation 中很好地描述了这一点章节。这个 lecture中也有动画解释从 7:59 开始.

    关于c++ - 在 Vulkan 中,每个交换链图像、每个帧或每个命令池是否需要专用的栅栏/信号量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65054157/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com