2

https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation

While reading above tutorial, I have found a scenario where multiple items pile up in presentation queue.

The tutorial has a loop that runs bellow codes repeatedly.

   void drawFrame() {
        vkWaitForFences(device, 1, &inFlightFence, VK_TRUE, UINT64_MAX);
        vkResetFences(device, 1, &inFlightFence);

        uint32_t imageIndex;
        vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);

        vkResetCommandBuffer(commandBuffer, /*VkCommandBufferResetFlagBits*/ 0);
        recordCommandBuffer(commandBuffer, imageIndex);

        VkSubmitInfo submitInfo{};
        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;

        VkSemaphore waitSemaphores[] = {imageAvailableSemaphore};
        VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
        submitInfo.waitSemaphoreCount = 1;
        submitInfo.pWaitSemaphores = waitSemaphores;
        submitInfo.pWaitDstStageMask = waitStages;

        submitInfo.commandBufferCount = 1;
        submitInfo.pCommandBuffers = &commandBuffer;

        VkSemaphore signalSemaphores[] = {renderFinishedSemaphore};
        submitInfo.signalSemaphoreCount = 1;
        submitInfo.pSignalSemaphores = signalSemaphores;

        if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFence) != VK_SUCCESS) {
            throw std::runtime_error("failed to submit draw command buffer!");
        }

        VkPresentInfoKHR presentInfo{};
        presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;

        presentInfo.waitSemaphoreCount = 1;
        presentInfo.pWaitSemaphores = signalSemaphores;

        VkSwapchainKHR swapChains[] = {swapChain};
        presentInfo.swapchainCount = 1;
        presentInfo.pSwapchains = swapChains;

        presentInfo.pImageIndices = &imageIndex;

        vkQueuePresentKHR(presentQueue, &presentInfo);

There are two semaphores; One for rendering, another one for presentation.

Similarly, there are two queues for rendering and presentation.

Here is a scenario I found that can happen.

enter image description here

  1. After the first iteration, each queue has one item to process.
  2. At the second iteration, any of the items in the queues are not processed yet. So, it is blocked at vkWaitForFences.
  3. The first item in graphics queue is processed.
    • It signals the blocking fence, and rendering semaphore.
    • The second iteration continues from vkWaitForFences.
    • Graphics queue receives second item. It has total one item.
    • Present queue also receives second item. Present queue has not processed the first item yet, so it has total two item.
  4. Graphics queue process the second item.
    • It signals rendering semaphore again. Rendering semaphore has received two signals without turning off.

Now, present queue will only process one item and do nothing until next iteration. Even in next iterations, if this issue keeps happening, unprocessed items will get piled up in the present queue.

Hence, if processing speed of graphics queue happens to be faster than present queue, there will be a starvation problem.

The tutorial does not explain how this issue can be solved. Is there something in Vulkan that prevents this issue to occur, or have I actually found a flaw in the tutorial code?

tuket
  • 3,232
  • 1
  • 26
  • 41
Donguk Lim
  • 41
  • 2
  • In my opinion, many tutorials fail to provide the practical hint that makes swapchain synchronization much easier: it's not worth having a separate queue for graphics and presentation because there isn't any real HW that requires it (https://stackoverflow.com/questions/61434615/in-vulkan-is-it-beneficial-for-the-graphics-queue-family-to-be-separate-from-th) – tuket Aug 02 '22 at 10:41

1 Answers1

2

vkAcquireNextImageKHR make the image semaphore to get signal when the swap image when the index it returned is presentable. The image with the index returned by vkAcquireNextImageKHR become presentable again, when the item with the index is processed in the present queue.

Hence, if the items in present queue are not processed, vkAcquireNextImageKHR will not signal the image semaphore or block, stopping next rendering.

The number of items that can stay simultaneously in present queue will not grow infinitely, but stops increasing if the number of item is equal to the number of swap images.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Donguk Lim
  • 41
  • 2