Vulkan - 如何证明在不同步的情况下执行两个命令会创建损坏的数据?
Vulkan - how to show that executing two commands without sync creates corrupt data?
我写了一个简单的测试往往会通过并行执行两个复制命令来创建同步问题,所以我可以有办法添加然后同步技术,以熟悉和体验。
不幸的是,似乎有一个隐式同步,因为没有我做的任何同步机制一切正常。
测试执行以下操作:
- (sync) CPU.
用数据更新缓冲区 A
- (异步)将缓冲区 A 复制到 B
- (异步)将缓冲区 B 复制到 C
- 等待设备空闲
- (sync) 通过CPU
读取缓冲区C数据
步骤 (2) 和 (3) 是在没有同步的情况下完成的,所以我认为从 B 到 C 的数据传输将在数据仍在从 A 写入 B 时发生,并且以这种方式在C. 但是读 C 到 CPU 总是显示正确的结果,它总是等于数据写入 A.
将缓冲区大小更改为 1G 没有帮助,它仍然有完美的结果(在这种情况下并不完美:))
硬件:Quadro RTX 5000 with Max-Q Design apiVersion:4202651 驱动程序:1938276352
// Given:
// VkCommandPool cp;
// VkDevice device;
// VkQueue queue;
// VkBuffer bufferA; 1G stage buffer (updated by cpu, has gpu src transfer usage)
// VkBuffer bufferB; 1G buffer (has gpu src and gpu dst transfer usage)
// VkBuffer bufferC; 1G stage buffer (read by cpu, has gpu dst transfer usage)
// create command buffer
VkCommandBufferAllocateInfo cbai = {};
cbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cbai.pNext = 0;
cbai.commandBufferCount = 1;
cbai.level = VkCommandBufferLevel::VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cbai.commandPool = cp;
std::vector<VkCommandBuffer> cbs(1);
vkAllocateCommandBuffers(device, &cbai, cbs.data());
// set copy info
VkCommandBufferBeginInfo cbbi = {};
cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cbbi.pNext = 0;
cbbi.pInheritanceInfo = 0;
VkBufferCopy copyRegion = {};
copyRegion.srcOffset = 0;
copyRegion.dstOffset = 0;
copyRegion.size = 1024 * 1024 * 1024;
// record copy commands
vkBeginCommandBuffer(cbs[0], &cbbi);
vkCmdCopyBuffer(cbs[0], bufferA, bufferB, 1, ©Region);
vkCmdCopyBuffer(cbs[0], bufferB, bufferC, 1, ©Region);
vkEndCommandBuffer(cbs[0]);
// execution of command buffer
VkSubmitInfo si = {};
si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
si.commandBufferCount = 1;
si.pCommandBuffers = cbs.data();
vkQueueSubmit(queue, 1, &si, VK_NULL_HANDLE);
// wait execution finished
vkDeviceWaitIdle(device);
// free command buffers
vkFreeCommandBuffers(device, cp, 1, cbs.data());
未定义行为未定义。您不能编写保证跨实现具有 any 特定行为的任何 UB 代码。包括特别错误的行为。
可能存在隐式同步。或者 GPU 一次只能在该队列上执行一个传输操作。或者是其他东西。关键是代码有UB,但你不能以某种方式使那个UB manifest。
我写了一个简单的测试往往会通过并行执行两个复制命令来创建同步问题,所以我可以有办法添加然后同步技术,以熟悉和体验。 不幸的是,似乎有一个隐式同步,因为没有我做的任何同步机制一切正常。
测试执行以下操作:
- (sync) CPU. 用数据更新缓冲区 A
- (异步)将缓冲区 A 复制到 B
- (异步)将缓冲区 B 复制到 C
- 等待设备空闲
- (sync) 通过CPU 读取缓冲区C数据
步骤 (2) 和 (3) 是在没有同步的情况下完成的,所以我认为从 B 到 C 的数据传输将在数据仍在从 A 写入 B 时发生,并且以这种方式在C. 但是读 C 到 CPU 总是显示正确的结果,它总是等于数据写入 A.
将缓冲区大小更改为 1G 没有帮助,它仍然有完美的结果(在这种情况下并不完美:))
硬件:Quadro RTX 5000 with Max-Q Design apiVersion:4202651 驱动程序:1938276352
// Given:
// VkCommandPool cp;
// VkDevice device;
// VkQueue queue;
// VkBuffer bufferA; 1G stage buffer (updated by cpu, has gpu src transfer usage)
// VkBuffer bufferB; 1G buffer (has gpu src and gpu dst transfer usage)
// VkBuffer bufferC; 1G stage buffer (read by cpu, has gpu dst transfer usage)
// create command buffer
VkCommandBufferAllocateInfo cbai = {};
cbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cbai.pNext = 0;
cbai.commandBufferCount = 1;
cbai.level = VkCommandBufferLevel::VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cbai.commandPool = cp;
std::vector<VkCommandBuffer> cbs(1);
vkAllocateCommandBuffers(device, &cbai, cbs.data());
// set copy info
VkCommandBufferBeginInfo cbbi = {};
cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cbbi.pNext = 0;
cbbi.pInheritanceInfo = 0;
VkBufferCopy copyRegion = {};
copyRegion.srcOffset = 0;
copyRegion.dstOffset = 0;
copyRegion.size = 1024 * 1024 * 1024;
// record copy commands
vkBeginCommandBuffer(cbs[0], &cbbi);
vkCmdCopyBuffer(cbs[0], bufferA, bufferB, 1, ©Region);
vkCmdCopyBuffer(cbs[0], bufferB, bufferC, 1, ©Region);
vkEndCommandBuffer(cbs[0]);
// execution of command buffer
VkSubmitInfo si = {};
si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
si.commandBufferCount = 1;
si.pCommandBuffers = cbs.data();
vkQueueSubmit(queue, 1, &si, VK_NULL_HANDLE);
// wait execution finished
vkDeviceWaitIdle(device);
// free command buffers
vkFreeCommandBuffers(device, cp, 1, cbs.data());
未定义行为未定义。您不能编写保证跨实现具有 any 特定行为的任何 UB 代码。包括特别错误的行为。
可能存在隐式同步。或者 GPU 一次只能在该队列上执行一个传输操作。或者是其他东西。关键是代码有UB,但你不能以某种方式使那个UB manifest。