C++ 使用哪种方式同步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); }

C++ 使用哪种方式同步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); },c++,synchronization,vulkan,C++,Synchronization,Vulkan,这个选项不好,因为如果我想多次执行copyBuffer()函数,那么所有的缓冲区将严格地一次复制一个 我想为每个函数调用使用一个围栏,以便多个调用可以并行运行 到目前为止,我只有这样一个解决方案: void MainWindow::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) { VkCommandBuffer commandBuffer; vkAllocateCommandBuffer

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

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

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

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);
}
以下哪个选项更好?

第二个选项写得正确吗?

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

第二个稍微好一点
vkQueueWaitIdle
是一种调试和热点外功能。它可能会引发隐藏的第二次提交,以向隐含的围栏发出信号


你不需要重置你随后破坏的围栏。您正在创建一个预签名的,这是一个bug。您还忘了将其传递给
vkQueueSubmit

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

第二个稍微好一点
vkQueueWaitIdle
是一种调试和热点外功能。它可能会引发隐藏的第二次提交,以向隐含的围栏发出信号


你不需要重置你随后破坏的围栏。您正在创建一个预签名的,这是一个bug。此外,您还忘记将其传递给
vkQueueSubmit

这两个函数都有同样的问题。在传输完成之前,它们都会阻止CPU执行任何操作。它们都可以用于潜在地将多个cb提交到同一帧中的同一队列中,但使用不同的提交命令

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

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

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

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

在相同的队列传输中,您还需要确保以与其他工作相同的
vkQueueSubmit
调用提交传输。或者换句话说,对于特定帧中的特定队列,您不应该对
vkQueueSubmit
进行多次调用

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


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

这两个函数在相同的方面都不好。在传输完成之前,它们都会阻止CPU执行任何操作。它们都可以用于潜在地将多个cb提交到同一帧中的同一队列中,但使用不同的提交命令

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

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

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

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

在相同的队列传输中,您还需要确保以与其他工作相同的
vkQueueSubmit
调用提交传输。或者换句话说,对于特定帧中的特定队列,您不应该对
vkQueueSubmit
进行多次调用

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

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

看起来像是错误的副本,包括。。。奇怪的巧合。看起来像是虫子的复制品,包括。。。奇怪的巧合。