首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用哪种方法来同步vkQueueSubmit()?

使用哪种方法来同步vkQueueSubmit()?
EN

Stack Overflow用户
提问于 2021-06-01 21:41:55
回答 2查看 733关注 0票数 1

我有一个函数将数据从一个缓冲区复制到另一个缓冲区,我需要同步它的执行。

我有一个很糟糕的选择:

代码语言:javascript
运行
复制
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()函数,那么所有的缓冲区都将严格地一次复制一次。

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

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

代码语言:javascript
运行
复制
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);
}

这些选项中哪一种更好?

第二个选项写得正确吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-06-02 00:59:04

这两个函数在相同的方面都是坏的。在传输完成之前,它们都阻止CPU执行任何操作。而且,它们都可以用于向同一帧中的同一个队列提交多个CBs,但提交命令不同。

如果性能是你关心的事情,这两种情况都是不可取的。

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

在将来的某个时候,在提交将使用这些数据的工作之前,您需要提交传输操作。它的工作方式取决于您是否在同一队列上提交传输操作,以及是否使用它们。

如果它们在同一个队列上,那么您所需要做的就是在批处理结束时在命令缓冲区中有一个事件,该事件使传输操作与接收方同步。如果您想变得更聪明,每个传输操作都可以有自己的事件,接收操作将等待该事件。

在相同队列的传输中,您还希望确保在与其他工作相同的vkQueueSubmit调用中提交传输。或者换一种说法,对于特定帧中的特定队列,您不应该不止一次地调用vkQueueSubmit

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

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

票数 3
EN

Stack Overflow用户

发布于 2021-06-02 00:11:33

这两个函数在语义上是相同的,并且执行完全相同的阻塞行为。

第二种情况略好一些。vkQueueWaitIdle是一种调试和脱离热点的特性.它可能会招致隐藏的第二次提交,以向隐式围栏发出信号。

你不需要重置栅栏,你随后摧毁无论如何。您正在创建预信号,这是一个bug。你还忘了把它传递给vkQueueSubmit

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67796344

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档