blob: ef25a2e035547006f0930ef0b1d280b080bd7f23 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ui/lib/escher/vk/vulkan_swapchain_helper.h"
#include <chrono>
#include <thread>
#include "src/ui/lib/escher/impl/vulkan_utils.h"
#include "src/ui/lib/escher/util/trace_macros.h"
#include "src/ui/lib/escher/vk/framebuffer.h"
namespace escher {
VulkanSwapchainHelper::VulkanSwapchainHelper(VulkanSwapchain swapchain, vk::Device device,
vk::Queue queue)
: swapchain_(swapchain), device_(device), queue_(queue) {
for (size_t i = 0; i < swapchain_.images.size(); ++i) {
image_available_semaphores_.push_back(Semaphore::New(device_));
render_finished_semaphores_.push_back(Semaphore::New(device_));
}
}
VulkanSwapchainHelper::~VulkanSwapchainHelper() {}
void VulkanSwapchainHelper::DrawFrame(DrawFrameCallback draw_callback) {
auto& image_available_semaphore = image_available_semaphores_[next_semaphore_index_];
auto& render_finished_semaphore = render_finished_semaphores_[next_semaphore_index_];
uint32_t swapchain_index;
{
TRACE_DURATION("gfx", "escher::VulkanSwapchain::Acquire");
auto result = device_.acquireNextImageKHR(swapchain_.swapchain, UINT64_MAX,
image_available_semaphore->vk_semaphore(), nullptr);
if (result.result == vk::Result::eSuboptimalKHR) {
FX_DLOGS(WARNING) << "suboptimal swapchain configuration";
} else if (result.result == vk::Result::eTimeout) {
int retry_count = 0;
int timeout = 2;
while (result.result == vk::Result::eTimeout) {
TRACE_DURATION("gfx", "escher::VulkanSwapchain::Acquire[retry]");
if (retry_count++ > 10) {
FX_LOGS(WARNING) << "failed to acquire next swapchain image"
<< " : Timeout (giving up after 10 tries)";
return;
}
std::chrono::duration<double, std::milli> chrono_timeout(timeout);
std::this_thread::sleep_for(chrono_timeout);
timeout *= 2;
device_.waitIdle();
result = device_.acquireNextImageKHR(swapchain_.swapchain, UINT64_MAX,
image_available_semaphore->vk_semaphore(), nullptr);
}
} else if (result.result != vk::Result::eSuccess) {
FX_LOGS(WARNING) << "failed to acquire next swapchain image"
<< " : " << to_string(result.result);
return;
}
swapchain_index = result.value;
next_semaphore_index_ = (next_semaphore_index_ + 1) % swapchain_.images.size();
}
// Render the scene. The Renderer will wait for acquireNextImageKHR() to
// signal the semaphore.
auto& color_image_out = swapchain_.images[swapchain_index];
draw_callback(color_image_out, image_available_semaphore, render_finished_semaphore);
// When the image is completely rendered, present it.
TRACE_DURATION("gfx", "escher::VulkanSwapchain::Present");
vk::PresentInfoKHR info;
info.waitSemaphoreCount = 1;
auto sema = render_finished_semaphore->vk_semaphore();
info.pWaitSemaphores = &sema;
info.swapchainCount = 1;
info.pSwapchains = &swapchain_.swapchain;
info.pImageIndices = &swapchain_index;
ESCHER_LOG_VK_ERROR(queue_.presentKHR(info), "failed to present rendered image");
}
} // namespace escher