Я использую ровно 3 изображения для swapchain и один VkCommandBuffer
(CB) для swapchain изображения. Синхронизация GPU выполняется с двумя семафорами, одна для presentation_finished
и одна для rendering_finished
. Текущий режим VK_PRESENT_MODE_MAILBOX_KHR
(быстрый обзор).
Теперь, когда я запускаю свой пример, не дожидаясь каких-либо CB-ограждений, уровни проверки сообщают об этой ошибке, как только любое swapchain-изображение используется во второй раз:
Вызов
vkBeginCommandBuffer()
активного CB до его завершения. Перед этим вызовом вы должны проверить CB-забор.
На первый взгляд это кажется мне удобным, так как обработка команд из ЦБ может быть просто еще не закончена. Но чем больше я думаю об этом, тем больше я пришел к выводу, что этого не должно быть вообще.
В моем понимании, когда vkAcquireImageKHR
возвращает определенный индекс изображения, он подразумевает, что возвращаемое изображение должно быть завершено рендерингом.
Это потому, что я передаю семафор rendering_finished
на vkQueueSubmit
, который должен быть передан при завершении рендеринга, и vkQueuePresentKHR
, чтобы дождаться, пока он не станет сигналом перед представлением изображения.
В спецификации VkQueuePresentInfoKHR
указано:
pWaitSemaphores
, если не VK_NULL_HANDLE, представляет собой массив объектовVkSemaphore
с элементамиwaitSemaphoreCount
и указывает семафоры, ожидающие до выдачи настоящего запроса
Значение: я никогда не буду представлять изображение, которое не завершило рендеринг, и, следовательно, связанный с ним ЦБ не может быть использован больше, как только изображение будет представлено.
Второй семафор presentation_finished
сигнализируется vkAqcuireImageKHR
и передается в тот же vkQueueSubmit
(для запуска рендеринга). Это означает, что рендеринг любого изображения начнется не раньше, чем разрешено движком презентации.
В заключение: настоящий запрос от vkQueuePresentKHR
не выдается до того, как рендеринг изображения будет завершен, а vkAcquireImageKHR
будет блокироваться до тех пор, пока изображение не будет доступно, и также никогда не вернет полученные изображения.
Что мне не хватает, что делает забор необходимым?
Я включил минимальный пример кода, содержащий только концептуально важные части, чтобы проиллюстрировать проблему.
VkImage[] swapchain_images;
VkCommandBuffer[] command_buffers;
VkSemaphore rendering_finished;
VkSemaphore presentation_finished;
void RenderLoop()
{
/* Acquire an image from the swapchain. Block until one is available.
Signal presentation_finished when we are allowed to render into the image */
int index;
vkAcquireImageKHR(device, swapchain, UINT64_MAX, presentation_finished, nullptr, &index);
/* (...) Frambuffer creation, etc. */
/* Begin CB: The command pool is flagged to reset the command buffer on reuse */
VkCommandBuffer cb = command_buffers[index];
vkBeginCommandBuffer(cb, ...);
/* (...) Trivial rendering of a single color image */
/* End CB */
vkEndCommandBuffer(cb);
/* Queue the rendering and wait for presentation_finished.
When rendering is finished, signal rendering_finished.
The VkSubmitInfo will have these important members set among others:
.pWaitSemaphores = &presentation_finished;
.pSignalSemaphores = &rendering_finished;
*/
vkQueueSubmit(render_queue, &submit_info);
/* Submit the presentation request as soon as the rendering_finished
semaphore gets signalled
The VkPresentInfoKHR will have these important members set among others:
.pWaitSemaphores = &rendering_finished;
*/
vkQueuePresentKHR(present_queue, &present_info);
}
Вставка забора при отправке CB в очередь рендеринга и ожидание его перед использованием этого CB снова, очевидно, устраняет проблему, но, как объяснено, кажется излишним.