diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index e6234c642038e..e86302daa930e 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -122,6 +122,15 @@ std::shared_ptr ContextGLES::CreateCommandBuffer() const { new CommandBufferGLES(weak_from_this(), reactor_)); } +// |Context| +bool ContextGLES::WaitUntilCommandsCompleted() { + const auto result = reactor_->React(); + if (result) { + reactor_->GetProcTable().Finish(); + } + return result; +} + // |Context| std::shared_ptr ContextGLES::GetWorkQueue() const { return work_queue_; diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index 138843a7fb7a3..7dcfeaf8f249f 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -73,6 +73,9 @@ class ContextGLES final : public Context, // |Context| bool SupportsOffscreenMSAA() const override; + // |Context| + bool WaitUntilCommandsCompleted() override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextGLES); }; diff --git a/impeller/renderer/backend/gles/proc_table_gles.h b/impeller/renderer/backend/gles/proc_table_gles.h index 6fb00e83c4a5a..32b36b69f9a46 100644 --- a/impeller/renderer/backend/gles/proc_table_gles.h +++ b/impeller/renderer/backend/gles/proc_table_gles.h @@ -163,7 +163,8 @@ struct GLProc { PROC(UseProgram); \ PROC(VertexAttribPointer); \ PROC(Viewport); \ - PROC(ReadPixels); + PROC(ReadPixels); \ + 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..b7ad3101305b5 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.h +++ b/impeller/renderer/backend/metal/command_buffer_mtl.h @@ -13,6 +13,8 @@ namespace impeller { class CommandBufferMTL final : public CommandBuffer { public: + using SubmitCallback = std::function)>; + // |CommandBuffer| ~CommandBufferMTL() override; @@ -20,9 +22,11 @@ class CommandBufferMTL final : public CommandBuffer { friend class ContextMTL; id buffer_ = nullptr; + SubmitCallback submit_callback_ = nullptr; CommandBufferMTL(const std::weak_ptr& context, - id queue); + id queue, + SubmitCallback submit_callback); // |CommandBuffer| void SetLabel(const std::string& label) const override; diff --git a/impeller/renderer/backend/metal/command_buffer_mtl.mm b/impeller/renderer/backend/metal/command_buffer_mtl.mm index 2e8a5f7d8a5af..4702bced5ddbf 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/command_buffer_mtl.mm @@ -122,8 +122,11 @@ static bool LogMTLCommandBufferErrorIfPresent(id buffer) { } CommandBufferMTL::CommandBufferMTL(const std::weak_ptr& context, - id queue) - : CommandBuffer(context), buffer_(CreateCommandBuffer(queue)) {} + id queue, + SubmitCallback submit_callback) + : CommandBuffer(context), + buffer_(CreateCommandBuffer(queue)), + submit_callback_(std::move(submit_callback)) {} CommandBufferMTL::~CommandBufferMTL() = default; @@ -164,6 +167,10 @@ static bool LogMTLCommandBufferErrorIfPresent(id buffer) { } [buffer_ commit]; + if (submit_callback_) { + submit_callback_(buffer_); + } + [buffer_ waitUntilScheduled]; buffer_ = nil; return true; diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index 1ba4740d09525..e5430319fd68f 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -39,6 +39,7 @@ class ContextMTL final : public Context, private: id device_ = nullptr; id command_queue_ = nullptr; + id last_submitted_buffer_ = nullptr; std::shared_ptr shader_library_; std::shared_ptr pipeline_library_; std::shared_ptr sampler_library_; @@ -67,6 +68,9 @@ class ContextMTL final : public Context, // |Context| std::shared_ptr CreateCommandBuffer() const override; + // |Context| + bool WaitUntilCommandsCompleted() override; + // |Context| std::shared_ptr GetWorkQueue() const override; diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 379b7cf52fb5f..4e15b4273510b 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -226,14 +226,37 @@ return nullptr; } - auto buffer = std::shared_ptr( - new CommandBufferMTL(weak_from_this(), queue)); + auto weak_this = weak_from_this(); + auto buffer = std::shared_ptr(new CommandBufferMTL( + weak_this, queue, [weak_this](id buffer) { + auto strong_this = weak_this.lock(); + if (strong_this) { + auto& context_mtl = + ContextMTL::Cast(const_cast(*strong_this)); + context_mtl.last_submitted_buffer_ = buffer; + } + })); if (!buffer->IsValid()) { return nullptr; } return buffer; } +// |Context| +bool ContextMTL::WaitUntilCommandsCompleted() { + if (!last_submitted_buffer_) { + return true; + } + + if (last_submitted_buffer_.status == MTLCommandBufferStatusCompleted) { + return true; + } + + [last_submitted_buffer_ waitUntilCompleted]; + last_submitted_buffer_ = nullptr; + return true; +} + std::shared_ptr ContextMTL::GetResourceAllocator() const { return resource_allocator_; } diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index e2002204cd13c..73b8b6679b1f6 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -528,6 +528,15 @@ std::shared_ptr ContextVK::CreateCommandBuffer() const { surface_producer_.get()); } +bool ContextVK::WaitUntilCommandsCompleted() { + auto result = device_->waitIdle(); + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to wait device idle: " << vk::to_string(result); + return false; + } + return true; +} + vk::Instance ContextVK::GetInstance() const { return *instance_; } diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 44806548cd5af..ce5a572deda4e 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -136,6 +136,9 @@ class ContextVK final : public Context, public BackendCast { // |Context| std::shared_ptr CreateCommandBuffer() const override; + // |Context| + bool WaitUntilCommandsCompleted() override; + // |Context| PixelFormat GetColorAttachmentPixelFormat() const override; diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index 8ba839b8612c0..8a53620f92ff4 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -39,6 +39,8 @@ class Context : public std::enable_shared_from_this { virtual std::shared_ptr CreateCommandBuffer() const = 0; + virtual bool WaitUntilCommandsCompleted() = 0; + virtual std::shared_ptr GetWorkQueue() const = 0; //---------------------------------------------------------------------------- diff --git a/impeller/renderer/renderer_unittests.cc b/impeller/renderer/renderer_unittests.cc index cfd3637f9a8c2..179b0f9c5ccb3 100644 --- a/impeller/renderer/renderer_unittests.cc +++ b/impeller/renderer/renderer_unittests.cc @@ -625,6 +625,8 @@ TEST_P(RendererTest, CanBlitTextureToBuffer) { if (!buffer->SubmitCommands()) { return false; } + + context->WaitUntilCommandsCompleted(); } { diff --git a/shell/common/snapshot_controller_impeller.cc b/shell/common/snapshot_controller_impeller.cc index 6e5d65b74769c..1b717ccbffe8b 100644 --- a/shell/common/snapshot_controller_impeller.cc +++ b/shell/common/snapshot_controller_impeller.cc @@ -63,6 +63,7 @@ sk_sp SnapshotControllerImpeller::DoMakeRasterSnapshot( std::shared_ptr image = picture.ToImage(*context, render_target_size); + context->GetContext()->WaitUntilCommandsCompleted(); if (image) { return impeller::DlImageImpeller::Make(image->GetTexture()); }