diff --git a/impeller/aiks/aiks_context.cc b/impeller/aiks/aiks_context.cc index fd504cbe03ca3..b220717e7f5f9 100644 --- a/impeller/aiks/aiks_context.cc +++ b/impeller/aiks/aiks_context.cc @@ -36,13 +36,15 @@ const ContentContext& AiksContext::GetContentContext() const { return *content_context_; } -bool AiksContext::Render(const Picture& picture, RenderTarget& render_target) { +bool AiksContext::Render(const Picture& picture, + RenderTarget& render_target, + CommandBuffer::SyncMode sync_mode) { if (!IsValid()) { return false; } if (picture.pass) { - return picture.pass->Render(*content_context_, render_target); + return picture.pass->Render(*content_context_, render_target, sync_mode); } return true; diff --git a/impeller/aiks/aiks_context.h b/impeller/aiks/aiks_context.h index d748f3156fcba..c12c89a2d7416 100644 --- a/impeller/aiks/aiks_context.h +++ b/impeller/aiks/aiks_context.h @@ -8,6 +8,7 @@ #include "flutter/fml/macros.h" #include "impeller/entity/contents/content_context.h" +#include "impeller/renderer/command_buffer.h" #include "impeller/renderer/context.h" #include "impeller/renderer/render_target.h" @@ -28,7 +29,10 @@ class AiksContext { const ContentContext& GetContentContext() const; - bool Render(const Picture& picture, RenderTarget& render_target); + bool Render( + const Picture& picture, + RenderTarget& render_target, + CommandBuffer::SyncMode sync_mode = CommandBuffer::SyncMode::kDontCare); private: std::shared_ptr context_; diff --git a/impeller/aiks/picture.cc b/impeller/aiks/picture.cc index 29737411c0740..6e1ac8c681df3 100644 --- a/impeller/aiks/picture.cc +++ b/impeller/aiks/picture.cc @@ -28,18 +28,21 @@ std::optional Picture::Snapshot(AiksContext& context) { .transform = Matrix::MakeTranslation(coverage.value().origin)}; } -std::shared_ptr Picture::ToImage(AiksContext& context, ISize size) { +std::shared_ptr Picture::ToImage(AiksContext& context, + ISize size, + CommandBuffer::SyncMode sync_mode) { if (size.IsEmpty()) { return nullptr; } - auto texture = RenderToTexture(context, size); + auto texture = RenderToTexture(context, size, std::nullopt, sync_mode); return texture ? std::make_shared(texture) : nullptr; } std::shared_ptr Picture::RenderToTexture( AiksContext& context, ISize size, - std::optional translate) { + std::optional translate, + CommandBuffer::SyncMode sync_mode) { FML_DCHECK(!size.IsEmpty()); pass->IterateAllEntities([&translate](auto& entity) -> bool { @@ -64,7 +67,7 @@ std::shared_ptr Picture::RenderToTexture( return nullptr; } - if (!context.Render(*this, target)) { + if (!context.Render(*this, target, sync_mode)) { VALIDATION_LOG << "Could not render Picture to Texture."; return nullptr; } diff --git a/impeller/aiks/picture.h b/impeller/aiks/picture.h index 7224af3a7b1be..27e1550a73dd9 100644 --- a/impeller/aiks/picture.h +++ b/impeller/aiks/picture.h @@ -21,13 +21,17 @@ struct Picture { std::optional Snapshot(AiksContext& context); - std::shared_ptr ToImage(AiksContext& context, ISize size); + std::shared_ptr ToImage( + AiksContext& context, + ISize size, + CommandBuffer::SyncMode sync_mode = CommandBuffer::SyncMode::kDontCare); private: std::shared_ptr RenderToTexture( AiksContext& context, ISize size, - std::optional translate = std::nullopt); + std::optional translate = std::nullopt, + CommandBuffer::SyncMode sync_mode = CommandBuffer::SyncMode::kDontCare); }; } // namespace impeller diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index b83c8480837ac..0a7fccce78498 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -184,7 +184,8 @@ static RenderTarget CreateRenderTarget(ContentContext& renderer, } bool EntityPass::Render(ContentContext& renderer, - const RenderTarget& render_target) const { + const RenderTarget& render_target, + CommandBuffer::SyncMode sync_mode) const { if (reads_from_pass_texture_ > 0) { auto offscreen_target = CreateRenderTarget(renderer, render_target.GetRenderTargetSize(), true); @@ -214,7 +215,7 @@ bool EntityPass::Render(ContentContext& renderer, if (!render_pass->EncodeCommands()) { return false; } - if (!command_buffer->SubmitCommands()) { + if (!command_buffer->SubmitCommands(sync_mode)) { return false; } @@ -222,7 +223,7 @@ bool EntityPass::Render(ContentContext& renderer, } return OnRender(renderer, render_target.GetRenderTargetSize(), render_target, - Point(), Point(), 0); + Point(), Point(), 0, 0, nullptr, sync_mode); } EntityPass::EntityResult EntityPass::GetEntityForElement( @@ -378,15 +379,15 @@ struct StencilLayer { size_t stencil_depth; }; -bool EntityPass::OnRender( - ContentContext& renderer, - ISize root_pass_size, - const RenderTarget& render_target, - Point position, - Point parent_position, - uint32_t pass_depth, - size_t stencil_depth_floor, - std::shared_ptr backdrop_filter_contents) const { +bool EntityPass::OnRender(ContentContext& renderer, + ISize root_pass_size, + const RenderTarget& render_target, + Point position, + Point parent_position, + uint32_t pass_depth, + size_t stencil_depth_floor, + std::shared_ptr backdrop_filter_contents, + CommandBuffer::SyncMode sync_mode) const { TRACE_EVENT0("impeller", "EntityPass::OnRender"); auto context = renderer.GetContext(); @@ -548,6 +549,12 @@ bool EntityPass::OnRender( } } + if (sync_mode != CommandBuffer::SyncMode::kDontCare) { + FML_DCHECK(reads_from_pass_texture_ == 0); + FML_DCHECK(pass_context.IsActive()); + pass_context.EndPass(sync_mode); + } + return true; } diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index cb7c3b5a47a87..81e583eda4746 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -49,8 +49,10 @@ class EntityPass { EntityPass* GetSuperpass() const; - bool Render(ContentContext& renderer, - const RenderTarget& render_target) const; + bool Render( + ContentContext& renderer, + const RenderTarget& render_target, + CommandBuffer::SyncMode = CommandBuffer::SyncMode::kDontCare) const; void IterateAllEntities(const std::function& iterator); @@ -109,7 +111,8 @@ class EntityPass { Point parent_position, uint32_t pass_depth, size_t stencil_depth_floor = 0, - std::shared_ptr backdrop_filter_contents = nullptr) const; + std::shared_ptr backdrop_filter_contents = nullptr, + CommandBuffer::SyncMode = CommandBuffer::SyncMode::kDontCare) const; std::vector elements_; diff --git a/impeller/entity/inline_pass_context.cc b/impeller/entity/inline_pass_context.cc index 99a1877c95442..75e9f0d4b8949 100644 --- a/impeller/entity/inline_pass_context.cc +++ b/impeller/entity/inline_pass_context.cc @@ -39,7 +39,7 @@ std::shared_ptr InlinePassContext::GetTexture() { return render_target_.GetRenderTargetTexture(); } -bool InlinePassContext::EndPass() { +bool InlinePassContext::EndPass(CommandBuffer::SyncMode sync_mode) { if (!IsActive()) { return true; } @@ -48,7 +48,7 @@ bool InlinePassContext::EndPass() { return false; } - if (!command_buffer_->SubmitCommands()) { + if (!command_buffer_->SubmitCommands(sync_mode)) { return false; } diff --git a/impeller/entity/inline_pass_context.h b/impeller/entity/inline_pass_context.h index ee393bda6c4b2..6bc5c4339e737 100644 --- a/impeller/entity/inline_pass_context.h +++ b/impeller/entity/inline_pass_context.h @@ -4,6 +4,7 @@ #pragma once +#include "impeller/renderer/command_buffer.h" #include "impeller/renderer/context.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" @@ -25,7 +26,8 @@ class InlinePassContext { bool IsValid() const; bool IsActive() const; std::shared_ptr GetTexture(); - bool EndPass(); + bool EndPass( + CommandBuffer::SyncMode sync_mode = CommandBuffer::SyncMode::kDontCare); const RenderTarget& GetRenderTarget() const; uint32_t GetPassCount() const; diff --git a/impeller/renderer/backend/gles/command_buffer_gles.cc b/impeller/renderer/backend/gles/command_buffer_gles.cc index c53c774330399..8686aa0f162fb 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.cc +++ b/impeller/renderer/backend/gles/command_buffer_gles.cc @@ -29,8 +29,22 @@ bool CommandBufferGLES::IsValid() const { } // |CommandBuffer| -bool CommandBufferGLES::OnSubmitCommands(CompletionCallback callback) { +bool CommandBufferGLES::OnSubmitCommands(SyncMode sync_mode, + CompletionCallback callback) { const auto result = reactor_->React(); + if (result) { + const auto& gl = reactor_->GetProcTable(); + switch (sync_mode) { + case CommandBuffer::SyncMode::kWaitUntilScheduled: + gl.Flush(); + break; + case CommandBuffer::SyncMode::kWaitUntilCompleted: + gl.Finish(); + break; + case CommandBuffer::SyncMode::kDontCare: + break; + } + } if (callback) { callback(result ? CommandBuffer::Status::kCompleted : CommandBuffer::Status::kError); diff --git a/impeller/renderer/backend/gles/command_buffer_gles.h b/impeller/renderer/backend/gles/command_buffer_gles.h index 9aef71fa80842..c9f31575842cd 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.h +++ b/impeller/renderer/backend/gles/command_buffer_gles.h @@ -32,7 +32,8 @@ class CommandBufferGLES final : public CommandBuffer { bool IsValid() const override; // |CommandBuffer| - bool OnSubmitCommands(CompletionCallback callback) override; + bool OnSubmitCommands(SyncMode sync_mode, + CompletionCallback callback) override; // |CommandBuffer| std::shared_ptr OnCreateRenderPass(RenderTarget target) override; diff --git a/impeller/renderer/backend/gles/proc_table_gles.h b/impeller/renderer/backend/gles/proc_table_gles.h index 6fb00e83c4a5a..9688ba4f65e53 100644 --- a/impeller/renderer/backend/gles/proc_table_gles.h +++ b/impeller/renderer/backend/gles/proc_table_gles.h @@ -163,7 +163,9 @@ struct GLProc { PROC(UseProgram); \ PROC(VertexAttribPointer); \ PROC(Viewport); \ - PROC(ReadPixels); + PROC(ReadPixels); \ + PROC(Flush); \ + PROC(Finish); #define FOR_EACH_IMPELLER_GLES3_PROC(PROC) PROC(BlitFramebuffer); diff --git a/impeller/renderer/backend/metal/command_buffer_mtl.h b/impeller/renderer/backend/metal/command_buffer_mtl.h index 30dd3f6f5d6a4..895e5eb5058ed 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.h +++ b/impeller/renderer/backend/metal/command_buffer_mtl.h @@ -31,7 +31,8 @@ class CommandBufferMTL final : public CommandBuffer { bool IsValid() const override; // |CommandBuffer| - bool OnSubmitCommands(CompletionCallback callback) override; + bool OnSubmitCommands(SyncMode sync_mode, + CompletionCallback callback) override; // |CommandBuffer| std::shared_ptr OnCreateRenderPass(RenderTarget target) override; diff --git a/impeller/renderer/backend/metal/command_buffer_mtl.mm b/impeller/renderer/backend/metal/command_buffer_mtl.mm index 2e8a5f7d8a5af..79593b96c606f 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/command_buffer_mtl.mm @@ -151,7 +151,8 @@ static bool LogMTLCommandBufferErrorIfPresent(id buffer) { return CommandBufferMTL::Status::kError; } -bool CommandBufferMTL::OnSubmitCommands(CompletionCallback callback) { +bool CommandBufferMTL::OnSubmitCommands(SyncMode sync_mode, + CompletionCallback callback) { if (callback) { [buffer_ addCompletedHandler:^(id buffer) { @@ -162,9 +163,16 @@ static bool LogMTLCommandBufferErrorIfPresent(id buffer) { callback(ToCommitResult(buffer.status)); }]; } - [buffer_ commit]; - [buffer_ waitUntilScheduled]; + + switch (sync_mode) { + case SyncMode::kWaitUntilCompleted: + [buffer_ waitUntilCompleted]; + case SyncMode::kWaitUntilScheduled: + case SyncMode::kDontCare: + [buffer_ waitUntilScheduled]; + } + buffer_ = nil; return true; } diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.cc b/impeller/renderer/backend/vulkan/command_buffer_vk.cc index 6e6096a8412c6..9e6c657232baa 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.cc @@ -59,7 +59,8 @@ bool CommandBufferVK::IsValid() const { return is_valid_; } -bool CommandBufferVK::OnSubmitCommands(CompletionCallback callback) { +bool CommandBufferVK::OnSubmitCommands(SyncMode sync_mode, + CompletionCallback callback) { bool submit = fenced_command_buffer_->Submit(); if (callback) { callback(submit ? CommandBuffer::Status::kCompleted diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.h b/impeller/renderer/backend/vulkan/command_buffer_vk.h index 941c110c6c35e..269592d4dbe91 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.h @@ -43,7 +43,8 @@ class CommandBufferVK final : public CommandBuffer { bool IsValid() const override; // |CommandBuffer| - bool OnSubmitCommands(CompletionCallback callback) override; + bool OnSubmitCommands(SyncMode sync_mode, + CompletionCallback callback) override; // |CommandBuffer| std::shared_ptr OnCreateRenderPass(RenderTarget target) override; diff --git a/impeller/renderer/command_buffer.cc b/impeller/renderer/command_buffer.cc index c5e9c5920d180..0b38d305fc30f 100644 --- a/impeller/renderer/command_buffer.cc +++ b/impeller/renderer/command_buffer.cc @@ -16,7 +16,8 @@ CommandBuffer::CommandBuffer(std::weak_ptr context) CommandBuffer::~CommandBuffer() = default; -bool CommandBuffer::SubmitCommands(const CompletionCallback& callback) { +bool CommandBuffer::SubmitCommands(SyncMode sync_mode, + const CompletionCallback& callback) { TRACE_EVENT0("impeller", "CommandBuffer::SubmitCommands"); if (!IsValid()) { // Already committed or was never valid. Either way, this is caller error. @@ -25,11 +26,15 @@ bool CommandBuffer::SubmitCommands(const CompletionCallback& callback) { } return false; } - return OnSubmitCommands(callback); + return OnSubmitCommands(sync_mode, callback); +} + +bool CommandBuffer::SubmitCommands(const CompletionCallback& callback) { + return SubmitCommands(SyncMode::kDontCare, callback); } -bool CommandBuffer::SubmitCommands() { - return SubmitCommands(nullptr); +bool CommandBuffer::SubmitCommands(SyncMode sync_mode) { + return SubmitCommands(sync_mode, nullptr); } std::shared_ptr CommandBuffer::CreateRenderPass( diff --git a/impeller/renderer/command_buffer.h b/impeller/renderer/command_buffer.h index e043e165c2fd4..641ff5ea71b6d 100644 --- a/impeller/renderer/command_buffer.h +++ b/impeller/renderer/command_buffer.h @@ -45,6 +45,12 @@ class CommandBuffer { kCompleted, }; + enum class SyncMode { + kDontCare, + kWaitUntilScheduled, + kWaitUntilCompleted, + }; + using CompletionCallback = std::function; virtual ~CommandBuffer(); @@ -61,9 +67,12 @@ class CommandBuffer { /// /// @param[in] callback The completion callback. /// + [[nodiscard]] bool SubmitCommands(SyncMode sync_mode, + const CompletionCallback& callback); + [[nodiscard]] bool SubmitCommands(const CompletionCallback& callback); - [[nodiscard]] bool SubmitCommands(); + [[nodiscard]] bool SubmitCommands(SyncMode sync_mode = SyncMode::kDontCare); //---------------------------------------------------------------------------- /// @brief Create a render pass to record render commands into. @@ -100,7 +109,8 @@ class CommandBuffer { virtual std::shared_ptr OnCreateBlitPass() const = 0; - [[nodiscard]] virtual bool OnSubmitCommands(CompletionCallback callback) = 0; + [[nodiscard]] virtual bool OnSubmitCommands(SyncMode sync_mode, + CompletionCallback callback) = 0; virtual std::shared_ptr OnCreateComputePass() const = 0; diff --git a/impeller/renderer/renderer_unittests.cc b/impeller/renderer/renderer_unittests.cc index cfd3637f9a8c2..69284c1956ea7 100644 --- a/impeller/renderer/renderer_unittests.cc +++ b/impeller/renderer/renderer_unittests.cc @@ -622,7 +622,8 @@ TEST_P(RendererTest, CanBlitTextureToBuffer) { pass->EncodeCommands(context->GetResourceAllocator()); - if (!buffer->SubmitCommands()) { + if (!buffer->SubmitCommands( + CommandBuffer::SyncMode::kWaitUntilCompleted)) { return false; } } diff --git a/shell/common/snapshot_controller_impeller.cc b/shell/common/snapshot_controller_impeller.cc index 6e5d65b74769c..d2f75e3fcff76 100644 --- a/shell/common/snapshot_controller_impeller.cc +++ b/shell/common/snapshot_controller_impeller.cc @@ -8,10 +8,11 @@ #include "flutter/flow/surface.h" #include "flutter/fml/trace_event.h" -#include "flutter/impeller/display_list/display_list_dispatcher.h" -#include "flutter/impeller/display_list/display_list_image_impeller.h" -#include "flutter/impeller/geometry/size.h" #include "flutter/shell/common/snapshot_controller.h" +#include "impeller/display_list/display_list_dispatcher.h" +#include "impeller/display_list/display_list_image_impeller.h" +#include "impeller/geometry/size.h" +#include "impeller/renderer/command_buffer.h" namespace flutter { @@ -62,7 +63,8 @@ sk_sp SnapshotControllerImpeller::DoMakeRasterSnapshot( } std::shared_ptr image = - picture.ToImage(*context, render_target_size); + picture.ToImage(*context, render_target_size, + impeller::CommandBuffer::SyncMode::kWaitUntilCompleted); if (image) { return impeller::DlImageImpeller::Make(image->GetTexture()); }