blob: 8bd94893753ee7fda76eea3cd1ec34b2cf429b77 [file] [log] [blame]
// Copyright 2013 The Flutter 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 "impeller/renderer/backend/vulkan/surface_producer_vk.h"
#include <array>
#include <utility>
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/surface_vk.h"
#include "impeller/renderer/backend/vulkan/vk.h"
namespace impeller {
std::unique_ptr<SurfaceProducerVK> SurfaceProducerVK::Create(
const std::weak_ptr<Context>& context,
const SurfaceProducerCreateInfoVK& create_info) {
auto surface_producer =
std::make_unique<SurfaceProducerVK>(context, create_info);
if (!surface_producer->SetupSyncObjects()) {
VALIDATION_LOG << "Failed to setup sync objects.";
return nullptr;
}
return surface_producer;
}
SurfaceProducerVK::SurfaceProducerVK(
std::weak_ptr<Context> context,
const SurfaceProducerCreateInfoVK& create_info)
: context_(std::move(context)), create_info_(create_info) {}
SurfaceProducerVK::~SurfaceProducerVK() = default;
std::unique_ptr<Surface> SurfaceProducerVK::AcquireSurface(
size_t current_frame) {
current_frame = current_frame % kMaxFramesInFlight;
const auto& sync_objects = sync_objects_[current_frame];
auto fence_wait_res = create_info_.device.waitForFences(
{*sync_objects->in_flight_fence}, VK_TRUE, UINT64_MAX);
if (fence_wait_res != vk::Result::eSuccess) {
VALIDATION_LOG << "Failed to wait for fence: "
<< vk::to_string(fence_wait_res);
return nullptr;
}
auto fence_reset_res =
create_info_.device.resetFences({*sync_objects->in_flight_fence});
if (fence_reset_res != vk::Result::eSuccess) {
VALIDATION_LOG << "Failed to reset fence: "
<< vk::to_string(fence_reset_res);
return nullptr;
}
uint32_t image_index;
auto acuire_image_res = create_info_.device.acquireNextImageKHR(
create_info_.swapchain->GetSwapchain(), UINT64_MAX,
*sync_objects->image_available_semaphore, {}, &image_index);
if (acuire_image_res != vk::Result::eSuccess &&
acuire_image_res != vk::Result::eSuboptimalKHR) {
VALIDATION_LOG << "Failed to acquire next image: "
<< vk::to_string(acuire_image_res);
return nullptr;
}
SurfaceVK::SwapCallback swap_callback = [this, current_frame, image_index]() {
return Present(current_frame, image_index);
};
if (auto context = context_.lock()) {
ContextVK* context_vk = reinterpret_cast<ContextVK*>(context.get());
return SurfaceVK::WrapSwapchainImage(
current_frame, create_info_.swapchain->GetSwapchainImage(image_index),
context_vk, std::move(swap_callback));
} else {
return nullptr;
}
}
std::unique_ptr<SurfaceSyncObjectsVK> SurfaceSyncObjectsVK::Create(
vk::Device device) {
auto sync_objects = std::make_unique<SurfaceSyncObjectsVK>();
vk::SemaphoreCreateInfo semaphore_create_info;
{
auto image_avail_res = device.createSemaphoreUnique(semaphore_create_info);
if (image_avail_res.result != vk::Result::eSuccess) {
VALIDATION_LOG << "Failed to create image available semaphore: "
<< vk::to_string(image_avail_res.result);
return nullptr;
}
sync_objects->image_available_semaphore = std::move(image_avail_res.value);
}
{
auto render_finished_res =
device.createSemaphoreUnique(semaphore_create_info);
if (render_finished_res.result != vk::Result::eSuccess) {
VALIDATION_LOG << "Failed to create render finished semaphore: "
<< vk::to_string(render_finished_res.result);
return nullptr;
}
sync_objects->render_finished_semaphore =
std::move(render_finished_res.value);
}
vk::FenceCreateInfo fence_create_info;
fence_create_info.flags = vk::FenceCreateFlagBits::eSignaled;
{
auto fence_res = device.createFenceUnique(fence_create_info);
if (fence_res.result != vk::Result::eSuccess) {
VALIDATION_LOG << "Failed to create fence: "
<< vk::to_string(fence_res.result);
return nullptr;
}
sync_objects->in_flight_fence = std::move(fence_res.value);
}
return sync_objects;
}
bool SurfaceProducerVK::SetupSyncObjects() {
for (size_t i = 0; i < kMaxFramesInFlight; i++) {
auto sync_objects = SurfaceSyncObjectsVK::Create(create_info_.device);
if (!sync_objects) {
return false;
}
sync_objects_[i] = std::move(sync_objects);
}
return true;
}
bool SurfaceProducerVK::Submit(uint32_t frame_num) {
auto& sync_objects = sync_objects_[frame_num];
vk::SubmitInfo submit_info;
std::array<vk::PipelineStageFlags, 1> wait_stages = {
vk::PipelineStageFlagBits::eColorAttachmentOutput};
submit_info.setWaitDstStageMask(wait_stages);
std::array<vk::Semaphore, 1> wait_semaphores = {
*sync_objects->image_available_semaphore};
submit_info.setWaitSemaphores(wait_semaphores);
std::array<vk::Semaphore, 1> signal_semaphores = {
*sync_objects->render_finished_semaphore};
submit_info.setSignalSemaphores(signal_semaphores);
auto graphics_submit_res = create_info_.graphics_queue.submit(
{submit_info}, *sync_objects->in_flight_fence);
if (graphics_submit_res != vk::Result::eSuccess) {
VALIDATION_LOG << "Failed to submit graphics queue: "
<< vk::to_string(graphics_submit_res);
return false;
}
auto idle_wait_res = create_info_.graphics_queue.waitIdle();
if (idle_wait_res != vk::Result::eSuccess) {
VALIDATION_LOG << "Failed to wait for graphics queue idle: "
<< vk::to_string(idle_wait_res);
return false;
}
return true;
}
bool SurfaceProducerVK::Present(size_t frame_num, uint32_t image_index) {
Submit(frame_num);
auto& sync_objects = sync_objects_[frame_num];
vk::PresentInfoKHR present_info;
std::array<vk::Semaphore, 1> signal_semaphores = {
*sync_objects->render_finished_semaphore};
present_info.setWaitSemaphores(signal_semaphores);
std::array<vk::SwapchainKHR, 1> swapchains = {
create_info_.swapchain->GetSwapchain()};
present_info.setSwapchains(swapchains);
std::array<uint32_t, 1> image_indices = {image_index};
present_info.setImageIndices(image_indices);
auto present_res = create_info_.present_queue.presentKHR(present_info);
if ((present_res != vk::Result::eSuccess) &&
(present_res != vk::Result::eSuboptimalKHR)) {
return false;
}
return true;
}
} // namespace impeller