Я пытаюсь синхронизировать этап хоста в моем конвейере, где я в основном редактирую некоторые данные на хосте во время выполнения буфера команд на устройстве. После прочтения спецификации, я думаю, что я делаю правильную синхронизацию, выполнение / зависимости от памяти и операции доступности / видимости, но это не работает ни на NV, ни на AMD. Это вообще возможно? Если так, что я делаю неправильно с точки зрения синхронизации?
В итоге я делаю следующее:
- [D] Буфер устройства (
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
) копируется на видимый и связный хост (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
).
- [D] Первое событие установлено.
- [D] Ожидается второе событие.
- [H] Тем временем хост ожидает первого события.
- [H] После того, как он был установлен, он увеличивает числа в видимом буфере хоста.
- [H] Затем он устанавливает второе событие.
- [D] Затем устройство продолжает копировать видимый буфер хоста обратно в локальный буфер устройства.
Что происходит?
В NV первая часть работает, правильные данные поступают на стороне хоста, но измененные данные никогда не поступают на стороне устройства. На AMD даже первая часть не работает, и я уже не получаю данные на хосте.
Запись в буфер команд:
// ...
VkMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
barrier.srcAccessMask = ...;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vkCmdPipelineBarrier(command_buffer, ..., VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr);
copyWholeBuffer(command_buffer, host_buffer, device_buffer);
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr);
vkCmdSetEvent(command_buffer, device_to_host_sync_event, VK_PIPELINE_STAGE_TRANSFER_BIT);
barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vkCmdWaitEvents(command_buffer, 1, &host_to_device_sync_event, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 1, &barrier, 0, nullptr, 0, nullptr);
copyWholeBuffer(command_buffer, device_buffer, host_buffer);
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = ...;
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, ..., 0, 1, &barrier, 0, nullptr, 0, nullptr);
// ...
Исполнение
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);
while(vkGetEventStatus(device, device_to_host_sync_event) != VK_EVENT_SET)
std::this_thread::sleep_for(std::chrono::microseconds(10));
void* data;
vkMapMemory(device, host_buffer, 0, BUFFER_SIZE, 0, &data);
// read and write parts of the memory
vkUnmapMemory(device, host_buffer);
vkSetEvent(device, host_to_device_sync_event);
vkDeviceWaitIdle(device);
Я загрузил рабочий пример: https://gist.github.com/neXyon/859b2e52bac9a5a56b804d8a9d5fa4a5
Интересные биты начинаются со строки 292! Посмотрите, работает ли он у вас?