【问题标题】:How to recreate swapchain after vkAcquireNextImageKHR is VK_SUBOPTIMAL_KHR?vkAcquireNextImageKHR 为 VK_SUBOPTIMAL_KHR 后如何重新创建交换链?
【发布时间】:2022-01-18 21:07:05
【问题描述】:

vulkan tutorial 讨论交换链的重新创建:

如果交换链不是最理想的,您也可以决定[重新创建交换链],但我选择在这种情况下继续进行,因为我们已经获取了图像。

我的问题是:在这种 VK_SUBOPTIMAL_KHR 的情况下,如何重新创建交换链而不继续进行?

要明白我的意思,让我们看一下教程的render function

void drawFrame() {
        vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);

        uint32_t imageIndex;
        VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);

        if (result == VK_ERROR_OUT_OF_DATE_KHR) { 
            recreateSwapChain();
            return;
        /* else if (result == VK_SUBOPTIMAL_KHR) { createSwapchain(); ??? } */
        } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
            throw std::runtime_error("failed to acquire swap chain image!");
        }

        if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) {
            vkWaitForFences(device, 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX);
        }
        imagesInFlight[imageIndex] = inFlightFences[currentFrame];

        VkSubmitInfo submitInfo{};
        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;

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

        submitInfo.commandBufferCount = 1;
        submitInfo.pCommandBuffers = &commandBuffers[imageIndex];

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

        vkResetFences(device, 1, &inFlightFences[currentFrame]);

        if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != 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;

        result = vkQueuePresentKHR(presentQueue, &presentInfo);

        if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
            framebufferResized = false;
            recreateSwapChain();
        } else if (result != VK_SUCCESS) {
            throw std::runtime_error("failed to present swap chain image!");
        }

        currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
    }

麻烦如下:

  1. vkAcquireImageKHR 成功,发出信号量并返回有效的次优图像
  2. 重新创建交换链
  3. 由于VUID-VkPresentInfoKHR-pImageIndices-01430,我们无法使用来自 2 的交换链呈现来自 1 的图像。我们需要再次调用 vkAcquireImageKHR 来获取新图像。
  4. 当我们再次调用 vkAcquireImageKHR 时,信号量处于不允许的信号状态 (VUID-vkAcquireNextImageKHR-semaphore-01286),我们需要“取消信号”。

这里是销毁和重新创建信号量的最佳解决方案吗?

【问题讨论】:

    标签: semaphore vulkan


    【解决方案1】:

    广告 3:如果您在创建新交换链时正确使用 oldSwapchain 参数,则可以使用旧图像(和交换链)。这是我认为教程建议的内容。

    无论如何。我所做的是I paranoidly sanitize that toxic semaphore 是这样的:

    // cleanup dangerous semaphore with signal pending from vkAcquireNextImageKHR (tie it to a specific queue)
    // https://github.com/KhronosGroup/Vulkan-Docs/issues/1059
    void cleanupUnsafeSemaphore( VkQueue queue, VkSemaphore semaphore ){
        const VkPipelineStageFlags psw = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
        VkSubmitInfo submit_info = {};
        submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
        submit_info.waitSemaphoreCount = 1;
        submit_info.pWaitSemaphores = &semaphore;
        submit_info.pWaitDstStageMask;
    
        vkQueueSubmit( queue, 1, &submit_info, VK_NULL_HANDLE );
    }
    

    之后,信号量可以被栅栏或vkQueueWaitIdle正确捕获,然后销毁或重复使用。

    我只是销毁它们,因为新的信号量计数可能会有所不同,而且我并不认为交换链重新创建是一个热点(在这种情况下我也只是使用 vkDeviceWaitIdle)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-18
      • 1970-01-01
      • 2021-06-17
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      相关资源
      最近更新 更多