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

查看:61
本文介绍了使用哪种方式同步 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 存储在一个位置,以便稍后与 其他 复制 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.

并且在同队列传输中,您还希望确保在相同的 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天全站免登陆