diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index e937cc553418e..5799bee67d6fc 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -164,7 +164,8 @@ TEST_P(AiksTest, CanRenderColorFilterWithInvertColorsDrawPaint) { namespace { bool GenerateMipmap(const std::shared_ptr& context, std::shared_ptr texture, - std::string label) { + std::string label, + bool async_submit) { auto buffer = context->CreateCommandBuffer(); if (!buffer) { return false; @@ -174,18 +175,23 @@ bool GenerateMipmap(const std::shared_ptr& context, return false; } pass->GenerateMipmap(std::move(texture), std::move(label)); + if (async_submit) { + return buffer->EncodeAndSubmit(pass, context->GetResourceAllocator()); + } + pass->EncodeCommands(context->GetResourceAllocator()); return buffer->SubmitCommands(); } void CanRenderTiledTexture(AiksTest* aiks_test, Entity::TileMode tile_mode, + bool async_submit = false, Matrix local_matrix = {}) { auto context = aiks_test->GetContext(); ASSERT_TRUE(context); auto texture = aiks_test->CreateTextureForFixture("table_mountain_nx.png", /*enable_mipmapping=*/true); - GenerateMipmap(context, texture, "table_mountain_nx"); + GenerateMipmap(context, texture, "table_mountain_nx", async_submit); Canvas canvas; canvas.Scale(aiks_test->GetContentScale()); canvas.Translate({100.0f, 100.0f, 0}); @@ -232,6 +238,10 @@ TEST_P(AiksTest, CanRenderTiledTextureClamp) { CanRenderTiledTexture(this, Entity::TileMode::kClamp); } +TEST_P(AiksTest, CanRenderTiledTextureClampAsync) { + CanRenderTiledTexture(this, Entity::TileMode::kClamp, /*async_submit=*/true); +} + TEST_P(AiksTest, CanRenderTiledTextureRepeat) { CanRenderTiledTexture(this, Entity::TileMode::kRepeat); } @@ -245,7 +255,7 @@ TEST_P(AiksTest, CanRenderTiledTextureDecal) { } TEST_P(AiksTest, CanRenderTiledTextureClampWithTranslate) { - CanRenderTiledTexture(this, Entity::TileMode::kClamp, + CanRenderTiledTexture(this, Entity::TileMode::kClamp, /*async_submit=*/false, Matrix::MakeTranslation({172.f, 172.f, 0.f})); } diff --git a/impeller/aiks/testing/context_mock.h b/impeller/aiks/testing/context_mock.h index 0b3ed6fe78c1b..59c1ead6cc46a 100644 --- a/impeller/aiks/testing/context_mock.h +++ b/impeller/aiks/testing/context_mock.h @@ -25,11 +25,6 @@ class CommandBufferMock : public CommandBuffer { MOCK_METHOD(void, SetLabel, (const std::string& label), (const, override)); - MOCK_METHOD(bool, - SubmitCommandsAsync, - (std::shared_ptr render_pass), - (override)); - MOCK_METHOD(std::shared_ptr, OnCreateRenderPass, (RenderTarget render_target), diff --git a/impeller/aiks/testing/context_spy.cc b/impeller/aiks/testing/context_spy.cc index f467773f1d7f6..e831719cd3008 100644 --- a/impeller/aiks/testing/context_spy.cc +++ b/impeller/aiks/testing/context_spy.cc @@ -63,12 +63,6 @@ std::shared_ptr ContextSpy::MakeContext( return real_buffer->SetLabel(label); }); - ON_CALL(*spy, SubmitCommandsAsync) - .WillByDefault([real_buffer]( - std::shared_ptr render_pass) { - return real_buffer->SubmitCommandsAsync(std::move(render_pass)); - }); - ON_CALL(*spy, OnCreateRenderPass) .WillByDefault( [real_buffer, shared_this](const RenderTarget& render_target) { diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index ec4725795eb31..8a161db649b6b 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -430,7 +430,7 @@ std::shared_ptr ContentContext::MakeSubpass( return nullptr; } - if (!sub_command_buffer->SubmitCommandsAsync(std::move(sub_renderpass))) { + if (!sub_command_buffer->EncodeAndSubmit(sub_renderpass)) { return nullptr; } diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index b516a276172ee..35a5a739ee89d 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -371,8 +371,8 @@ bool EntityPass::Render(ContentContext& renderer, offscreen_target.GetRenderTarget().GetRenderTargetTexture(), root_render_target.GetRenderTargetTexture()); - if (!blit_pass->EncodeCommands( - renderer.GetContext()->GetResourceAllocator())) { + if (!command_buffer->EncodeAndSubmit( + blit_pass, renderer.GetContext()->GetResourceAllocator())) { VALIDATION_LOG << "Failed to encode root pass blit command."; return false; } @@ -399,15 +399,11 @@ bool EntityPass::Render(ContentContext& renderer, } } - if (!render_pass->EncodeCommands()) { + if (!command_buffer->EncodeAndSubmit(render_pass)) { VALIDATION_LOG << "Failed to encode root pass command buffer."; return false; } } - if (!command_buffer->SubmitCommands()) { - VALIDATION_LOG << "Failed to submit root pass command buffer."; - return false; - } return true; } diff --git a/impeller/entity/inline_pass_context.cc b/impeller/entity/inline_pass_context.cc index c1f9f59649c78..96db4677ce93f 100644 --- a/impeller/entity/inline_pass_context.cc +++ b/impeller/entity/inline_pass_context.cc @@ -54,7 +54,7 @@ bool InlinePassContext::EndPass() { } if (command_buffer_) { - if (!command_buffer_->SubmitCommandsAsync(std::move(pass_))) { + if (!command_buffer_->EncodeAndSubmit(pass_)) { VALIDATION_LOG << "Failed to encode and submit command buffer while ending " "render pass."; diff --git a/impeller/renderer/backend/metal/command_buffer_mtl.h b/impeller/renderer/backend/metal/command_buffer_mtl.h index 9038fa7833dfa..7e167fa2b3a5d 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.h +++ b/impeller/renderer/backend/metal/command_buffer_mtl.h @@ -7,6 +7,7 @@ #include #include "flutter/fml/macros.h" +#include "impeller/core/allocator.h" #include "impeller/renderer/command_buffer.h" namespace impeller { @@ -37,7 +38,11 @@ class CommandBufferMTL final : public CommandBuffer { void OnWaitUntilScheduled() override; // |CommandBuffer| - bool SubmitCommandsAsync(std::shared_ptr render_pass) override; + bool EncodeAndSubmit(const std::shared_ptr& render_pass) override; + + // |CommandBuffer| + bool EncodeAndSubmit(const std::shared_ptr& blit_ass, + const std::shared_ptr& allocator) 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 b3161b74c4e36..7adb44a189225 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/command_buffer_mtl.mm @@ -183,9 +183,9 @@ static bool LogMTLCommandBufferErrorIfPresent(id buffer) { return true; } -bool CommandBufferMTL::SubmitCommandsAsync( - std::shared_ptr render_pass) { - TRACE_EVENT0("impeller", "CommandBufferMTL::SubmitCommandsAsync"); +bool CommandBufferMTL::EncodeAndSubmit( + const std::shared_ptr& render_pass) { + TRACE_EVENT0("impeller", "CommandBufferMTL::EncodeAndSubmit"); if (!IsValid() || !render_pass->IsValid()) { return false; } @@ -239,6 +239,34 @@ static bool LogMTLCommandBufferErrorIfPresent(id buffer) { return true; } +bool CommandBufferMTL::EncodeAndSubmit( + const std::shared_ptr& blit_pass, + const std::shared_ptr& allocator) { + if (!IsValid() || !blit_pass->IsValid()) { + return false; + } + auto context = context_.lock(); + if (!context) { + return false; + } + [buffer_ enqueue]; + auto buffer = buffer_; + buffer_ = nil; + + auto worker_task_runner = ContextMTL::Cast(*context).GetWorkerTaskRunner(); + auto task = fml::MakeCopyable( + [blit_pass, buffer, weak_context = context_, allocator]() { + auto context = weak_context.lock(); + if (!blit_pass->EncodeCommands(allocator)) { + VALIDATION_LOG << "Failed to encode blit pass."; + return; + } + [buffer commit]; + }); + worker_task_runner->PostTask(task); + return true; +} + void CommandBufferMTL::OnWaitUntilScheduled() {} std::shared_ptr CommandBufferMTL::OnCreateRenderPass( diff --git a/impeller/renderer/command_buffer.cc b/impeller/renderer/command_buffer.cc index c0f4a0d50d69a..98b23204604b1 100644 --- a/impeller/renderer/command_buffer.cc +++ b/impeller/renderer/command_buffer.cc @@ -36,11 +36,9 @@ void CommandBuffer::WaitUntilScheduled() { return OnWaitUntilScheduled(); } -bool CommandBuffer::SubmitCommandsAsync( - std::shared_ptr - render_pass // NOLINT(performance-unnecessary-value-param) -) { - TRACE_EVENT0("impeller", "CommandBuffer::SubmitCommandsAsync"); +bool CommandBuffer::EncodeAndSubmit( + const std::shared_ptr& render_pass) { + TRACE_EVENT0("impeller", "CommandBuffer::EncodeAndSubmit"); if (!render_pass->IsValid() || !IsValid()) { return false; } @@ -51,6 +49,20 @@ bool CommandBuffer::SubmitCommandsAsync( return SubmitCommands(nullptr); } +bool CommandBuffer::EncodeAndSubmit( + const std::shared_ptr& blit_pass, + const std::shared_ptr& allocator) { + TRACE_EVENT0("impeller", "CommandBuffer::EncodeAndSubmit"); + if (!blit_pass->IsValid() || !IsValid()) { + return false; + } + if (!blit_pass->EncodeCommands(allocator)) { + return false; + } + + return SubmitCommands(nullptr); +} + std::shared_ptr CommandBuffer::CreateRenderPass( const RenderTarget& render_target) { auto pass = OnCreateRenderPass(render_target); diff --git a/impeller/renderer/command_buffer.h b/impeller/renderer/command_buffer.h index 2614f93d52aaf..61717d2922257 100644 --- a/impeller/renderer/command_buffer.h +++ b/impeller/renderer/command_buffer.h @@ -80,8 +80,20 @@ class CommandBuffer { /// /// A command buffer may only be committed once. /// - [[nodiscard]] virtual bool SubmitCommandsAsync( - std::shared_ptr render_pass); + [[nodiscard]] virtual bool EncodeAndSubmit( + const std::shared_ptr& render_pass); + + //---------------------------------------------------------------------------- + /// @brief Schedule the command encoded by blit passes within this + /// command buffer on the GPU. The enqueing of this buffer is + /// performed immediately but encoding is pushed to a worker + /// thread if possible. + /// + /// A command buffer may only be committed once. + /// + [[nodiscard]] virtual bool EncodeAndSubmit( + const std::shared_ptr& blit_pass, + const std::shared_ptr& allocator); //---------------------------------------------------------------------------- /// @brief Force execution of pending GPU commands.