diff --git a/engine/src/flutter/impeller/display_list/aiks_playground.cc b/engine/src/flutter/impeller/display_list/aiks_playground.cc index 6b2ac34a9f..4bd350c0b4 100644 --- a/engine/src/flutter/impeller/display_list/aiks_playground.cc +++ b/engine/src/flutter/impeller/display_list/aiks_playground.cc @@ -50,14 +50,14 @@ bool AiksPlayground::OpenPlaygroundHere( return Playground::OpenPlaygroundHere( [&renderer, &callback](RenderTarget& render_target) -> bool { - return RenderToOnscreen( + return RenderToTarget( renderer.GetContentContext(), // render_target, // callback(), // SkIRect::MakeWH(render_target.GetRenderTargetSize().width, render_target.GetRenderTargetSize().height), // - /*reset_host_buffer=*/true // - ); + /*reset_host_buffer=*/true, // + /*is_onscreen=*/false); }); } diff --git a/engine/src/flutter/impeller/display_list/canvas.cc b/engine/src/flutter/impeller/display_list/canvas.cc index 04629516ec..0f29cab864 100644 --- a/engine/src/flutter/impeller/display_list/canvas.cc +++ b/engine/src/flutter/impeller/display_list/canvas.cc @@ -43,6 +43,7 @@ #include "impeller/geometry/color.h" #include "impeller/geometry/constants.h" #include "impeller/geometry/path_builder.h" +#include "impeller/renderer/command_buffer.h" namespace impeller { @@ -162,9 +163,11 @@ static std::unique_ptr CreateRenderTarget( Canvas::Canvas(ContentContext& renderer, const RenderTarget& render_target, + bool is_onscreen, bool requires_readback) : renderer_(renderer), render_target_(render_target), + is_onscreen_(is_onscreen), requires_readback_(requires_readback), clip_coverage_stack_(EntityPassClipStack( Rect::MakeSize(render_target.GetRenderTargetSize()))) { @@ -174,10 +177,12 @@ Canvas::Canvas(ContentContext& renderer, Canvas::Canvas(ContentContext& renderer, const RenderTarget& render_target, + bool is_onscreen, bool requires_readback, Rect cull_rect) : renderer_(renderer), render_target_(render_target), + is_onscreen_(is_onscreen), requires_readback_(requires_readback), clip_coverage_stack_(EntityPassClipStack( Rect::MakeSize(render_target.GetRenderTargetSize()))) { @@ -187,10 +192,12 @@ Canvas::Canvas(ContentContext& renderer, Canvas::Canvas(ContentContext& renderer, const RenderTarget& render_target, + bool is_onscreen, bool requires_readback, IRect cull_rect) : renderer_(renderer), render_target_(render_target), + is_onscreen_(is_onscreen), requires_readback_(requires_readback), clip_coverage_stack_(EntityPassClipStack( Rect::MakeSize(render_target.GetRenderTargetSize()))) { @@ -1658,7 +1665,7 @@ std::shared_ptr Canvas::FlipBackdrop(Point global_pass_position, return input_texture; } -bool Canvas::BlitToOnscreen() { +bool Canvas::BlitToOnscreen(bool is_onscreen) { auto command_buffer = renderer_.GetContext()->CreateCommandBuffer(); command_buffer->SetLabel("EntityPass Root Command Buffer"); auto offscreen_target = render_passes_.back() @@ -1675,10 +1682,6 @@ bool Canvas::BlitToOnscreen() { VALIDATION_LOG << "Failed to encode root pass blit command."; return false; } - if (!renderer_.GetContext()->EnqueueCommandBuffer( - std::move(command_buffer))) { - return false; - } } else { auto render_pass = command_buffer->CreateRenderPass(render_target_); render_pass->SetLabel("EntityPass Root Render Pass"); @@ -1704,25 +1707,28 @@ bool Canvas::BlitToOnscreen() { VALIDATION_LOG << "Failed to encode root pass command buffer."; return false; } - if (!renderer_.GetContext()->EnqueueCommandBuffer( - std::move(command_buffer))) { - return false; - } } - return true; + + if (is_onscreen) { + return renderer_.GetContext()->SubmitOnscreen(std::move(command_buffer)); + } else { + return renderer_.GetContext()->EnqueueCommandBuffer( + std::move(command_buffer)); + } } void Canvas::EndReplay() { FML_DCHECK(render_passes_.size() == 1u); render_passes_.back().inline_pass_context->GetRenderPass(); - render_passes_.back().inline_pass_context->EndPass(); + render_passes_.back().inline_pass_context->EndPass( + /*is_onscreen=*/!requires_readback_ && is_onscreen_); backdrop_data_.clear(); // If requires_readback_ was true, then we rendered to an offscreen texture // instead of to the onscreen provided in the render target. Now we need to // draw or blit the offscreen back to the onscreen. if (requires_readback_) { - BlitToOnscreen(); + BlitToOnscreen(/*is_onscreen_=*/is_onscreen_); } if (!renderer_.GetContext()->FlushCommandBuffers()) { diff --git a/engine/src/flutter/impeller/display_list/canvas.h b/engine/src/flutter/impeller/display_list/canvas.h index d92c6d79a8..0b5e76331e 100644 --- a/engine/src/flutter/impeller/display_list/canvas.h +++ b/engine/src/flutter/impeller/display_list/canvas.h @@ -123,15 +123,18 @@ class Canvas { Canvas(ContentContext& renderer, const RenderTarget& render_target, + bool is_onscreen, bool requires_readback); explicit Canvas(ContentContext& renderer, const RenderTarget& render_target, + bool is_onscreen, bool requires_readback, Rect cull_rect); explicit Canvas(ContentContext& renderer, const RenderTarget& render_target, + bool is_onscreen, bool requires_readback, IRect cull_rect); @@ -251,6 +254,7 @@ class Canvas { private: ContentContext& renderer_; RenderTarget render_target_; + const bool is_onscreen_; bool requires_readback_; EntityPassClipStack clip_coverage_stack_; @@ -318,7 +322,7 @@ class Canvas { bool should_remove_texture = false, bool should_use_onscreen = false); - bool BlitToOnscreen(); + bool BlitToOnscreen(bool is_onscreen = false); size_t GetClipHeight() const; diff --git a/engine/src/flutter/impeller/display_list/canvas_unittests.cc b/engine/src/flutter/impeller/display_list/canvas_unittests.cc index 09dad0565d..ee0f8b2e93 100644 --- a/engine/src/flutter/impeller/display_list/canvas_unittests.cc +++ b/engine/src/flutter/impeller/display_list/canvas_unittests.cc @@ -56,10 +56,12 @@ std::unique_ptr CreateTestCanvas( render_target.SetColorAttachment(color0, 0); if (cull_rect.has_value()) { - return std::make_unique(context, render_target, requires_readback, - cull_rect.value()); + return std::make_unique( + context, render_target, /*is_onscreen=*/false, + /*requires_readback=*/requires_readback, cull_rect.value()); } - return std::make_unique(context, render_target, requires_readback); + return std::make_unique(context, render_target, /*is_onscreen=*/false, + /*requires_readback=*/requires_readback); } TEST_P(AiksTest, TransformMultipliesCorrectly) { diff --git a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc index 2059ff11b1..487d2a8551 100644 --- a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc +++ b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc @@ -947,11 +947,13 @@ static bool RequiresReadbackForBlends( CanvasDlDispatcher::CanvasDlDispatcher(ContentContext& renderer, RenderTarget& render_target, + bool is_onscreen, bool has_root_backdrop_filter, flutter::DlBlendMode max_root_blend_mode, IRect cull_rect) : canvas_(renderer, render_target, + is_onscreen, has_root_backdrop_filter || RequiresReadbackForBlends(renderer, max_root_blend_mode), cull_rect), @@ -1270,6 +1272,7 @@ std::shared_ptr DisplayListToTexture( impeller::CanvasDlDispatcher impeller_dispatcher( context.GetContentContext(), // target, // + /*is_onscreen=*/false, // display_list->root_has_backdrop_filter(), // display_list->max_root_blend_mode(), // impeller::IRect::MakeSize(size) // @@ -1288,11 +1291,12 @@ std::shared_ptr DisplayListToTexture( return target.GetRenderTargetTexture(); } -bool RenderToOnscreen(ContentContext& context, - RenderTarget render_target, - const sk_sp& display_list, - SkIRect cull_rect, - bool reset_host_buffer) { +bool RenderToTarget(ContentContext& context, + RenderTarget render_target, + const sk_sp& display_list, + SkIRect cull_rect, + bool reset_host_buffer, + bool is_onscreen) { Rect ip_cull_rect = Rect::MakeLTRB(cull_rect.left(), cull_rect.top(), cull_rect.right(), cull_rect.bottom()); FirstPassDispatcher collector(context, impeller::Matrix(), ip_cull_rect); @@ -1301,6 +1305,7 @@ bool RenderToOnscreen(ContentContext& context, impeller::CanvasDlDispatcher impeller_dispatcher( context, // render_target, // + /*is_onscreen=*/is_onscreen, // display_list->root_has_backdrop_filter(), // display_list->max_root_blend_mode(), // IRect::RoundOut(ip_cull_rect) // diff --git a/engine/src/flutter/impeller/display_list/dl_dispatcher.h b/engine/src/flutter/impeller/display_list/dl_dispatcher.h index ba43f1c15c..8d69eab149 100644 --- a/engine/src/flutter/impeller/display_list/dl_dispatcher.h +++ b/engine/src/flutter/impeller/display_list/dl_dispatcher.h @@ -254,6 +254,7 @@ class CanvasDlDispatcher : public DlDispatcherBase { public: CanvasDlDispatcher(ContentContext& renderer, RenderTarget& render_target, + bool is_onscreen, bool has_root_backdrop_filter, flutter::DlBlendMode max_root_blend_mode, IRect cull_rect); @@ -390,11 +391,15 @@ std::shared_ptr DisplayListToTexture( bool reset_host_buffer = true, bool generate_mips = false); -/// Render the provided display list to the render target. -bool RenderToOnscreen(ContentContext& context, RenderTarget render_target, +/// @brief Render the provided display list to the render target. +/// +/// If [is_onscreen] is true, then the onscreen command buffer will be +/// submitted via Context::SubmitOnscreen. +bool RenderToTarget(ContentContext& context, RenderTarget render_target, const sk_sp& display_list, SkIRect cull_rect, - bool reset_host_buffer); + bool reset_host_buffer, + bool is_onscreen = true); } // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/dl_playground.cc b/engine/src/flutter/impeller/display_list/dl_playground.cc index 9a0561230d..587f270f8e 100644 --- a/engine/src/flutter/impeller/display_list/dl_playground.cc +++ b/engine/src/flutter/impeller/display_list/dl_playground.cc @@ -45,13 +45,14 @@ bool DlPlayground::OpenPlaygroundHere(DisplayListPlaygroundCallback callback) { wireframe = !wireframe; context.GetContentContext().SetWireframe(wireframe); } - return RenderToOnscreen( + return RenderToTarget( context.GetContentContext(), // render_target, // callback(), // SkIRect::MakeWH(render_target.GetRenderTargetSize().width, render_target.GetRenderTargetSize().height), // - /*reset_host_buffer=*/true // + /*reset_host_buffer=*/true, // + /*is_onscreen=*/false // ); }); } diff --git a/engine/src/flutter/impeller/entity/inline_pass_context.cc b/engine/src/flutter/impeller/entity/inline_pass_context.cc index 82d94a614e..e8ea9487cc 100644 --- a/engine/src/flutter/impeller/entity/inline_pass_context.cc +++ b/engine/src/flutter/impeller/entity/inline_pass_context.cc @@ -40,7 +40,7 @@ std::shared_ptr InlinePassContext::GetTexture() { return pass_target_.GetRenderTarget().GetRenderTargetTexture(); } -bool InlinePassContext::EndPass() { +bool InlinePassContext::EndPass(bool is_onscreen) { if (!IsActive()) { return true; } @@ -63,8 +63,12 @@ bool InlinePassContext::EndPass() { } pass_ = nullptr; - return renderer_.GetContext()->EnqueueCommandBuffer( - std::move(command_buffer_)); + if (is_onscreen) { + return renderer_.GetContext()->SubmitOnscreen(std::move(command_buffer_)); + } else { + return renderer_.GetContext()->EnqueueCommandBuffer( + std::move(command_buffer_)); + } } EntityPassTarget& InlinePassContext::GetPassTarget() const { diff --git a/engine/src/flutter/impeller/entity/inline_pass_context.h b/engine/src/flutter/impeller/entity/inline_pass_context.h index d475313057..30acc888a6 100644 --- a/engine/src/flutter/impeller/entity/inline_pass_context.h +++ b/engine/src/flutter/impeller/entity/inline_pass_context.h @@ -27,7 +27,7 @@ class InlinePassContext { std::shared_ptr GetTexture(); - bool EndPass(); + bool EndPass(bool is_onscreen = false); EntityPassTarget& GetPassTarget() const; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc index 027a18726c..e2c42562f0 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc @@ -657,6 +657,10 @@ bool ContextVK::EnqueueCommandBuffer( } bool ContextVK::FlushCommandBuffers() { + if (pending_command_buffers_.empty()) { + return true; + } + if (should_batch_cmd_buffers_) { bool result = GetCommandQueue()->Submit(pending_command_buffers_).ok(); pending_command_buffers_.clear(); @@ -733,4 +737,8 @@ RuntimeStageBackend ContextVK::GetRuntimeStageBackend() const { return RuntimeStageBackend::kVulkan; } +bool ContextVK::SubmitOnscreen(std::shared_ptr cmd_buffer) { + return EnqueueCommandBuffer(std::move(cmd_buffer)); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h index 08ed6569b0..fa3282e9d1 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h @@ -131,6 +131,10 @@ class ContextVK final : public Context, // |Context| const std::shared_ptr& GetCapabilities() const override; + // |Context| + virtual bool SubmitOnscreen( + std::shared_ptr cmd_buffer) override; + const std::shared_ptr& GetYUVConversionLibrary() const; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc index 8dfa1ed472..0b6837a9ac 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc @@ -6,7 +6,6 @@ #include "impeller/core/formats.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" -#include "vulkan/vulkan_enums.hpp" namespace impeller { diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc index 43a68f7dfc..f946cf3571 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -14,7 +14,6 @@ #include "impeller/core/formats.h" #include "impeller/core/texture.h" #include "impeller/core/vertex_buffer.h" -#include "impeller/renderer/backend/vulkan/barrier_vk.h" #include "impeller/renderer/backend/vulkan/command_buffer_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/device_buffer_vk.h" @@ -82,17 +81,19 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( const std::shared_ptr& command_buffer) const { RenderPassBuilderVK builder; - render_target_.IterateAllColorAttachments( - [&](size_t bind_point, const ColorAttachment& attachment) -> bool { - builder.SetColorAttachment( - bind_point, // - attachment.texture->GetTextureDescriptor().format, // - attachment.texture->GetTextureDescriptor().sample_count, // - attachment.load_action, // - attachment.store_action // - ); - return true; - }); + render_target_.IterateAllColorAttachments([&](size_t bind_point, + const ColorAttachment& + attachment) -> bool { + builder.SetColorAttachment( + bind_point, // + attachment.texture->GetTextureDescriptor().format, // + attachment.texture->GetTextureDescriptor().sample_count, // + attachment.load_action, // + attachment.store_action, // + /*current_layout=*/TextureVK::Cast(*attachment.texture).GetLayout() // + ); + return true; + }); if (auto depth = render_target_.GetDepthAttachment(); depth.has_value()) { builder.SetDepthStencilAttachment( @@ -179,6 +180,8 @@ RenderPassVK::RenderPassVK(const std::shared_ptr& context, if (resolve_image_vk_) { TextureVK::Cast(*resolve_image_vk_).SetCachedFramebuffer(framebuffer); TextureVK::Cast(*resolve_image_vk_).SetCachedRenderPass(render_pass_); + TextureVK::Cast(*resolve_image_vk_) + .SetLayoutWithoutEncoding(vk::ImageLayout::eGeneral); } std::array clears; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc index 0783762666..a96e5faf34 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc @@ -129,6 +129,12 @@ bool SurfaceContextVK::FlushCommandBuffers() { return parent_->FlushCommandBuffers(); } +bool SurfaceContextVK::SubmitOnscreen( + std::shared_ptr cmd_buffer) { + swapchain_->AddFinalCommandBuffer(std::move(cmd_buffer)); + return true; +} + RuntimeStageBackend SurfaceContextVK::GetRuntimeStageBackend() const { return parent_->GetRuntimeStageBackend(); } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h index 488dc19f90..c629e65a53 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h @@ -73,6 +73,9 @@ class SurfaceContextVK : public Context, // |Context| RuntimeStageBackend GetRuntimeStageBackend() const override; + // |Context| + bool SubmitOnscreen(std::shared_ptr cmd_buffer) override; + // |Context| void Shutdown() override; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_impl_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_impl_vk.cc index f3b84056e4..721f08da00 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_impl_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_impl_vk.cc @@ -192,6 +192,12 @@ bool AHBSwapchainImplVK::Present( }); } +void AHBSwapchainImplVK::AddFinalCommandBuffer( + std::shared_ptr cmd_buffer) { + FML_DCHECK(!pending_cmd_buffer_); + pending_cmd_buffer_ = std::move(cmd_buffer); +} + std::shared_ptr AHBSwapchainImplVK::SubmitSignalForPresentReady( const std::shared_ptr& texture) const { @@ -204,7 +210,7 @@ AHBSwapchainImplVK::SubmitSignalForPresentReady( return nullptr; } - auto command_buffer = context->CreateCommandBuffer(); + auto command_buffer = pending_cmd_buffer_; if (!command_buffer) { return nullptr; } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_impl_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_impl_vk.h index 1c546fc544..f44e8b15f8 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_impl_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_impl_vk.h @@ -89,6 +89,8 @@ class AHBSwapchainImplVK final /// std::unique_ptr AcquireNextDrawable(); + void AddFinalCommandBuffer(std::shared_ptr cmd_buffer); + private: using AutoSemaSignaler = std::shared_ptr; @@ -102,6 +104,7 @@ class AHBSwapchainImplVK final std::shared_ptr currently_displayed_texture_ IPLR_GUARDED_BY(currently_displayed_texture_mutex_); std::shared_ptr pending_presents_; + std::shared_ptr pending_cmd_buffer_; bool is_valid_ = false; explicit AHBSwapchainImplVK( diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc index ddfdece798..892f73cd0c 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc @@ -66,6 +66,12 @@ vk::Format AHBSwapchainVK::GetSurfaceFormat() const { : vk::Format::eUndefined; } +// |SwapchainVK| +void AHBSwapchainVK::AddFinalCommandBuffer( + std::shared_ptr cmd_buffer) const { + return impl_->AddFinalCommandBuffer(cmd_buffer); +} + // |SwapchainVK| void AHBSwapchainVK::UpdateSurfaceSize(const ISize& size) { if (impl_ && impl_->GetSize() == size) { diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h index ddbcd13a52..7b0dcb42fd 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h @@ -46,6 +46,10 @@ class AHBSwapchainVK final : public SwapchainVK { // |SwapchainVK| void UpdateSurfaceSize(const ISize& size) override; + // |SwapchainVK| + void AddFinalCommandBuffer( + std::shared_ptr cmd_buffer) const override; + private: friend class SwapchainVK; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc index aeebeb38e8..ee6ba61c72 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc @@ -13,11 +13,12 @@ #include "impeller/renderer/backend/vulkan/gpu_tracer_vk.h" #include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h" #include "impeller/renderer/backend/vulkan/swapchain/surface_vk.h" +#include "impeller/renderer/backend/vulkan/texture_vk.h" #include "impeller/renderer/context.h" namespace impeller { -static constexpr size_t kMaxFramesInFlight = 3u; +static constexpr size_t kMaxFramesInFlight = 2u; struct KHRFrameSynchronizerVK { vk::UniqueFence acquire; @@ -25,6 +26,8 @@ struct KHRFrameSynchronizerVK { vk::UniqueSemaphore present_ready; std::shared_ptr final_cmd_buffer; bool is_valid = false; + // Whether the renderer attached an onscreen command buffer to render to. + bool has_onscreen = false; explicit KHRFrameSynchronizerVK(const vk::Device& device) { auto acquire_res = device.createFenceUnique( @@ -378,6 +381,13 @@ KHRSwapchainImplVK::AcquireResult KHRSwapchainImplVK::AcquireNextDrawable() { )}; } +void KHRSwapchainImplVK::AddFinalCommandBuffer( + std::shared_ptr cmd_buffer) { + const auto& sync = synchronizers_[current_frame_]; + sync->final_cmd_buffer = std::move(cmd_buffer); + sync->has_onscreen = true; +} + bool KHRSwapchainImplVK::Present( const std::shared_ptr& image, uint32_t index) { @@ -393,7 +403,10 @@ bool KHRSwapchainImplVK::Present( //---------------------------------------------------------------------------- /// Transition the image to color-attachment-optimal. /// - sync->final_cmd_buffer = context.CreateCommandBuffer(); + if (!sync->has_onscreen) { + sync->final_cmd_buffer = context.CreateCommandBuffer(); + } + sync->has_onscreen = false; if (!sync->final_cmd_buffer) { return false; } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h index 049ab11426..a110f5ed79 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h @@ -7,7 +7,6 @@ #include #include -#include #include "impeller/geometry/size.h" #include "impeller/renderer/backend/vulkan/swapchain/swapchain_transients_vk.h" @@ -63,6 +62,8 @@ class KHRSwapchainImplVK final const ISize& GetSize() const; + void AddFinalCommandBuffer(std::shared_ptr cmd_buffer); + private: std::weak_ptr context_; vk::UniqueSurfaceKHR surface_; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.cc index 0877e5541e..9a1cc0e32e 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.cc @@ -39,6 +39,11 @@ void KHRSwapchainVK::UpdateSurfaceSize(const ISize& size) { size_ = size; } +void KHRSwapchainVK::AddFinalCommandBuffer( + std::shared_ptr cmd_buffer) const { + impl_->AddFinalCommandBuffer(std::move(cmd_buffer)); +} + std::unique_ptr KHRSwapchainVK::AcquireNextDrawable() { if (!IsValid()) { return nullptr; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h index 21acdfd47a..8ac8b75a03 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h @@ -37,6 +37,10 @@ class KHRSwapchainVK final : public SwapchainVK { // |SwapchainVK| void UpdateSurfaceSize(const ISize& size) override; + // |SwapchainVK| + void AddFinalCommandBuffer( + std::shared_ptr cmd_buffer) const override; + private: friend class SwapchainVK; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.h index 5de25d1469..5cff164440 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.h @@ -10,6 +10,7 @@ #include "flutter/fml/build_config.h" #include "impeller/geometry/size.h" #include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/command_buffer.h" #include "impeller/renderer/context.h" #include "impeller/renderer/surface.h" @@ -52,6 +53,9 @@ class SwapchainVK { virtual vk::Format GetSurfaceFormat() const = 0; + virtual void AddFinalCommandBuffer( + std::shared_ptr cmd_buffer) const = 0; + /// @brief Mark the current swapchain configuration as dirty, forcing it to be /// recreated on the next frame. virtual void UpdateSurfaceSize(const ISize& size) = 0; diff --git a/engine/src/flutter/impeller/renderer/context.cc b/engine/src/flutter/impeller/renderer/context.cc index b7922caf21..a741ce1bb9 100644 --- a/engine/src/flutter/impeller/renderer/context.cc +++ b/engine/src/flutter/impeller/renderer/context.cc @@ -37,4 +37,8 @@ bool Context::AddTrackingFence(const std::shared_ptr& texture) const { return false; } +bool Context::SubmitOnscreen(std::shared_ptr cmd_buffer) { + return EnqueueCommandBuffer(std::move(cmd_buffer)); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/context.h b/engine/src/flutter/impeller/renderer/context.h index 71bad51128..8f6cd853dd 100644 --- a/engine/src/flutter/impeller/renderer/context.h +++ b/engine/src/flutter/impeller/renderer/context.h @@ -242,6 +242,9 @@ class Context { /// correct shader types. virtual RuntimeStageBackend GetRuntimeStageBackend() const = 0; + /// @brief Submit the command buffer that renders to the onscreen surface. + virtual bool SubmitOnscreen(std::shared_ptr cmd_buffer); + protected: Context(); diff --git a/engine/src/flutter/impeller/toolkit/interop/surface.cc b/engine/src/flutter/impeller/toolkit/interop/surface.cc index b5e7f72824..3d78e1a949 100644 --- a/engine/src/flutter/impeller/toolkit/interop/surface.cc +++ b/engine/src/flutter/impeller/toolkit/interop/surface.cc @@ -62,8 +62,8 @@ bool Surface::DrawDisplayList(const DisplayList& dl) const { auto skia_cull_rect = SkIRect::MakeWH(cull_rect.GetWidth(), cull_rect.GetHeight()); - auto result = RenderToOnscreen(content_context, render_target, display_list, - skia_cull_rect, /*reset_host_buffer=*/true); + auto result = RenderToTarget(content_context, render_target, display_list, + skia_cull_rect, /*reset_host_buffer=*/true); context_->GetContext()->ResetThreadLocalState(); return result; } diff --git a/engine/src/flutter/shell/gpu/gpu_surface_gl_impeller.cc b/engine/src/flutter/shell/gpu/gpu_surface_gl_impeller.cc index 138709e88d..18938f41ce 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_gl_impeller.cc +++ b/engine/src/flutter/shell/gpu/gpu_surface_gl_impeller.cc @@ -116,11 +116,11 @@ std::unique_ptr GPUSurfaceGLImpeller::AcquireFrame( auto cull_rect = render_target.GetRenderTargetSize(); SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.width, cull_rect.height); - return impeller::RenderToOnscreen(aiks_context->GetContentContext(), // - render_target, // - display_list, // - sk_cull_rect, // - /*reset_host_buffer=*/true // + return impeller::RenderToTarget(aiks_context->GetContentContext(), // + render_target, // + display_list, // + sk_cull_rect, // + /*reset_host_buffer=*/true // ); return true; }; diff --git a/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.mm b/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.mm index b35d509f14..e231f7be81 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.mm +++ b/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.mm @@ -169,11 +169,11 @@ std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLa surface->SetFrameBoundary(surface_frame.submit_info().frame_boundary); const bool reset_host_buffer = surface_frame.submit_info().frame_boundary; - auto render_result = impeller::RenderToOnscreen(aiks_context->GetContentContext(), // - surface->GetRenderTarget(), // - display_list, // - sk_cull_rect, // - /*reset_host_buffer=*/reset_host_buffer // + auto render_result = impeller::RenderToTarget(aiks_context->GetContentContext(), // + surface->GetRenderTarget(), // + display_list, // + sk_cull_rect, // + /*reset_host_buffer=*/reset_host_buffer // ); if (!render_result) { return false; @@ -283,11 +283,11 @@ std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrameFromMTLTextur impeller::IRect cull_rect = surface->coverage(); SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.GetWidth(), cull_rect.GetHeight()); - auto render_result = impeller::RenderToOnscreen(aiks_context->GetContentContext(), // - surface->GetRenderTarget(), // - display_list, // - sk_cull_rect, // - /*reset_host_buffer=*/true // + auto render_result = impeller::RenderToTarget(aiks_context->GetContentContext(), // + surface->GetRenderTarget(), // + display_list, // + sk_cull_rect, // + /*reset_host_buffer=*/true // ); if (!render_result) { FML_LOG(ERROR) << "Failed to render Impeller frame"; diff --git a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc index c0a3fb7344..114861aace 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -115,11 +115,11 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( } SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.width, cull_rect.height); - return impeller::RenderToOnscreen(aiks_context->GetContentContext(), // - render_target, // - display_list, // - sk_cull_rect, // - /*reset_host_buffer=*/true // + return impeller::RenderToTarget(aiks_context->GetContentContext(), // + render_target, // + display_list, // + sk_cull_rect, // + /*reset_host_buffer=*/true // ); }; @@ -212,11 +212,11 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( } SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.width, cull_rect.height); - return impeller::RenderToOnscreen(aiks_context->GetContentContext(), // - render_target, // - display_list, // - sk_cull_rect, // - /*reset_host_buffer=*/true // + return impeller::RenderToTarget(aiks_context->GetContentContext(), // + render_target, // + display_list, // + sk_cull_rect, // + /*reset_host_buffer=*/true // ); }; diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_view.cc b/engine/src/flutter/shell/platform/embedder/embedder_external_view.cc index 99ce249597..3d58ec6667 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_external_view.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_view.cc @@ -133,11 +133,12 @@ bool EmbedderExternalView::Render(const EmbedderRenderTarget& render_target, SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.GetWidth(), cull_rect.GetHeight()); - return impeller::RenderToOnscreen(aiks_context->GetContentContext(), // - *impeller_target, // - display_list, // - sk_cull_rect, // - /*reset_host_buffer=*/true // + return impeller::RenderToTarget(aiks_context->GetContentContext(), // + *impeller_target, // + display_list, // + sk_cull_rect, // + /*reset_host_buffer=*/true, // + /*is_onscreen=*/false // ); } #endif // IMPELLER_SUPPORTS_RENDERING