Vulkan API — урок 30. Пересоздание swap chain

Описанное ранее приложение пусть и успешно рисует треугольник, но не все нюансы оно обрабатывает должным образом. Вполне возможно, что при определенном изменении поверхности окна, она более не будет совместима со swap chain, например при изменении размеров окна. Нам же необходимо отлавливать подобные моменты и создавать swap chain заного.

Создадим новую функцию recreateSwapChain, которая вызывает createSwapChain и все зависимое от оной.

Для начала вызовем vkDeviceWaitIdle, т.к. мы не должны трогать ресурсы, которые могут быть в «работе», о чем говорилось в конце предыдущего урока. Очевидно, что далее мы пересоздадим саму swap chain. Image views так же будут созданы заново, поскольку основаны непосредственно на изображениях swap chain. И render pass, он зависит от формата изображений swap chain. Область просмотра и обрезка определяются при создании конвейера, следовательно графический конвейер должен быть построен заново, но этого можно избежать с помощью динамического состояния для видовых или обрезающих прямоугольников. Наконец фреймбуферы и буферы команд так же напрямую зависят от изображений swap chain.

void recreateSwapChain() {
    vkDeviceWaitIdle(device);

    createSwapChain();
    createImageViews();
    createRenderPass();
    createGraphicsPipeline();
    createFramebuffers();
    createCommandBuffers();
}

Благодаря конструкции VDeleter, большинство функций будет работать исправно при пересоздании, старые объекты подотрутся автоматически. Однако функции createSwapChain и createCommandBuffers потребуют некоторых доработок.

VkSwapchainKHR oldSwapChain = swapChain;
createInfo.oldSwapchain = oldSwapChain;

VkSwapchainKHR newSwapChain;
if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) {
    throw std::runtime_error("failed to create swap chain!");
}

swapChain = newSwapChain;

Нам нужно передать предыдущий swap chain как параметр структуры VkSwapchainCreateInfoKHR, что бы обозначить намерение заменить её. Старая swap chain пока должна оставаться под рукой, пока новая не будет создана, а это значит, что мы не можем записать новый дескриптор непосредственно в swapChain. VDeleter очистит старый объект пред тем, как vkCreateSwapchainKHR будет выполнен. Вариант выхода из сложившейся ситуации – использование временной переменной newSwapChain.

swapChain = newSwapChain;

Эта строка удалит старую swap chain и заменит старый дескриптор на новый.

Проблема с createCommandBuffers заключается в том, что он не освобождает старые буферы команд. Вот два способа решить данную проблему:

  • Вызвать createCommandPool, которая так же будет автоматически освобождать старые буферы команд.
  • Расширить createCommandBuffers, который почистит предыдущие буферы команд.

Т.к. в данном случае пересоздавать пул команд нет нужды, то воспользуемся вторым вариантов.

if (commandBuffers.size() > 0) {
    vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data());
}

commandBuffers.resize(swapChainFramebuffers.size());

Функция createCommandBuffers теперь сначала проверит наличие буферов команд, и при их наличии сразу же все подчистит.

Main Admin

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *