| // 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 |