使用哪种方式来同步 vkQueueSubmit()? [英] Which way to synchronize vkQueueSubmit() to use?

查看:58
本文介绍了使用哪种方式来同步 vkQueueSubmit()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

void MainWindow::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size)
{
    VkCommandBuffer commandBuffer;
    vkAllocateCommandBuffers(logicalDevice, &allocInfo, &commandBuffer);

    //Start recording
    vkBeginCommandBuffer(commandBuffer, &beginInfo);
    vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
    vkEndCommandBuffer(commandBuffer);

    //Run command buffer
    vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
    //Waiting for completion
    vkQueueWaitIdle(graphicsQueue);

    vkFreeCommandBuffers(logicalDevice, commandPool, 1, &commandBuffer);
}

这个选项不好,因为如果我想多次执行 copyBuffer() 函数,那么所有的缓冲区将被严格地一次复制一个.

This option is bad because if I want to execute the copyBuffer() function several times, then all the buffers will be copied strictly one at a time.

我想为每个函数调用使用一个栅栏,以便多个调用可以并行运行.

I want to use a fence for each function call so that multiple calls can run in parallel.

到目前为止,我只有这样一个解决方案:

So far, I have only such a solution:

void MainWindow::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size)
{
    VkCommandBuffer commandBuffer;
    vkAllocateCommandBuffers(logicalDevice, &allocInfo, &commandBuffer);
    
    //Create fence
    VkFenceCreateInfo fenceInfo{};
    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
    fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;

    VkFence executionCompleteFence = VK_NULL_HANDLE;
    if (vkCreateFence(logicalDevice, &fenceInfo, VK_NULL_HANDLE, &executionCompleteFence) != VK_SUCCESS) {
        throw MakeErrorInfo("Failed to create fence");
    }

    //Start recording
    vkBeginCommandBuffer(commandBuffer, &beginInfo);
    vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);

    vkEndCommandBuffer(commandBuffer);

    //Run command buffer
    vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
    
    vkWaitForFences(logicalDevice, 1, &executionCompleteFence, VK_TRUE, UINT64_MAX);
    vkResetFences(logicalDevice, 1, &executionCompleteFence);

    vkFreeCommandBuffers(logicalDevice, commandPool, 1, &commandBuffer);
    vkDestroyFence(logicalDevice, executionCompleteFence, VK_NULL_HANDLE);
}

这些选项中哪个更好?
第二个选项写对了吗?

Which of these options is better?
Is the second option written correctly?

推荐答案

这两个函数都一样不好.它们都阻止 CPU 做任何事情,直到传输完成.它们都可以用于潜在地将多个 CB 提交到同一帧中的同一队列,但使用不同的提交命令.

Both functions are bad in the same way. They both block the CPU from doing anything until the transfer is done. And they both could be used to potentially submit multiple CBs to the same queue in the same frame, but with different submit commands.

如果您关心性能,那么两者都不是可取的.

Neither is desirable if performance is something you care about.

最终,您需要做的是让您的 copyBuffer 函数不实际执行复制.你应该有一个函数来构建一个命令缓冲区来进行复制.然后将该 CB 存储在稍后与 other 复制 CB 一起提交的位置.或者更好的是,您可以只有一个复制 CB,每个命​​令添加到其中(框架中调用的第一个将创建 CB).

Ultimately, what you need to do is have your copyBuffer function not actually perform the copy. You should have a function which builds a command buffer to do a copy. That CB is then stored in a place to be submitted later with other copying CBs. Or better yet, you can have just one copying CB that each command adds to (the first one called in a frame will create the CB).

在将来的某个时候,在您提交将使用此数据的作品之前,您需要提交传输操作.其工作方式取决于您是否在与将使用它们的工作相同的队列中提交传输操作.

At some point in the future, before you've submitted the work that will use this data, you need to submit the transfer operations. And the way this works depends on if you're submitting the transfer operations on the same queue as the work that will consume them or not.

如果它们在同一个队列中,那么您需要做的就是在批处理末尾的命令缓冲区中设置一个事件,以将传输操作与其接收器同步.如果你想更聪明一点,每个传输操作都可以有自己的事件,接收操作会等待.

If they're on the same queue, then all you need to do is have an event in a command buffer at the end of your batch that synchronizes the transfer operations with their receivers. If you want to be more clever, each transfer operation can have its own event, which the receiving operations will wait on.

在同队列传输中,您还需要确保在与工作的 rest 相同的 vkQueueSubmit 调用中提交传输.或者换一种说法,对于特定帧中的特定队列,您永远不应该多次调用 vkQueueSubmit.

And in same-queue transfers, you also want to make sure that you submit the transfers in the same vkQueueSubmit call as the rest of your work. Or to put it another way, you should never make more than one call to vkQueueSubmit for a particular queue in a particular frame.

如果您要处理单独的队列,那么情况就会发生变化.一点点.如果时间线信号量不是一个选项,您需要在提交接收操作之前提交您的传输工作.这是因为传输批处理需要发出信号量,接收操作将等待.并且不能等待二进制信号量,直到发出信号的操作已提交到队列.

If you're dealing with separate queues, then things change. A bit. If timeline semaphores aren't an option, you'll need to submit your transfer work before you submit the receiving operations. This is because the transfer batch will need to signal a semaphore that the receiving operation will wait on. And a binary semaphore cannot be waited on until the operation that signals it has been submitted to a queue.

但除此之外,其他一切都保持不变.当然,您不需要事件,因为您是通过信号量进行同步的.

But otherwise, everything else stays the same. Of course, you don't need events since you're synchronizing by semaphore.

这篇关于使用哪种方式来同步 vkQueueSubmit()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆