| // 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 "flutter/lib/gpu/command_buffer.h" |
| |
| #include "dart_api.h" |
| #include "fml/make_copyable.h" |
| #include "impeller/renderer/command_buffer.h" |
| #include "impeller/renderer/render_pass.h" |
| #include "lib/ui/ui_dart_state.h" |
| #include "tonic/converter/dart_converter.h" |
| |
| namespace flutter { |
| namespace gpu { |
| |
| IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, CommandBuffer); |
| |
| CommandBuffer::CommandBuffer( |
| std::shared_ptr<impeller::CommandBuffer> command_buffer) |
| : command_buffer_(std::move(command_buffer)) {} |
| |
| CommandBuffer::~CommandBuffer() = default; |
| |
| std::shared_ptr<impeller::CommandBuffer> CommandBuffer::GetCommandBuffer() { |
| return command_buffer_; |
| } |
| |
| void CommandBuffer::AddRenderPass( |
| std::shared_ptr<impeller::RenderPass> render_pass) { |
| encodables_.push_back(std::move(render_pass)); |
| } |
| |
| bool CommandBuffer::Submit() { |
| for (auto& encodable : encodables_) { |
| encodable->EncodeCommands(); |
| } |
| return command_buffer_->SubmitCommands(); |
| } |
| |
| bool CommandBuffer::Submit( |
| const impeller::CommandBuffer::CompletionCallback& completion_callback) { |
| for (auto& encodable : encodables_) { |
| encodable->EncodeCommands(); |
| } |
| return command_buffer_->SubmitCommands(completion_callback); |
| } |
| |
| } // namespace gpu |
| } // namespace flutter |
| |
| //---------------------------------------------------------------------------- |
| /// Exports |
| /// |
| |
| bool InternalFlutterGpu_CommandBuffer_Initialize( |
| Dart_Handle wrapper, |
| flutter::gpu::Context* contextWrapper) { |
| auto res = fml::MakeRefCounted<flutter::gpu::CommandBuffer>( |
| contextWrapper->GetContext()->CreateCommandBuffer()); |
| res->AssociateWithDartWrapper(wrapper); |
| |
| return true; |
| } |
| |
| Dart_Handle InternalFlutterGpu_CommandBuffer_Submit( |
| flutter::gpu::CommandBuffer* wrapper, |
| Dart_Handle completion_callback) { |
| if (Dart_IsNull(completion_callback)) { |
| bool success = wrapper->Submit(); |
| if (!success) { |
| return tonic::ToDart("Failed to submit CommandBuffer"); |
| } |
| return Dart_Null(); |
| } |
| |
| if (!Dart_IsClosure(completion_callback)) { |
| return tonic::ToDart("Completion callback must be a function"); |
| } |
| |
| auto dart_state = flutter::UIDartState::Current(); |
| auto& task_runners = dart_state->GetTaskRunners(); |
| |
| auto persistent_completion_callback = |
| std::make_unique<tonic::DartPersistentValue>(dart_state, |
| completion_callback); |
| |
| bool success = wrapper->Submit(fml::MakeCopyable( |
| [callback = std::move(persistent_completion_callback), |
| task_runners](impeller::CommandBuffer::Status status) mutable { |
| bool success = status != impeller::CommandBuffer::Status::kError; |
| |
| auto ui_completion_task = fml::MakeCopyable( |
| [callback = std::move(callback), success]() mutable { |
| auto dart_state = callback->dart_state().lock(); |
| if (!dart_state) { |
| // The root isolate could have died in the meantime. |
| return; |
| } |
| tonic::DartState::Scope scope(dart_state); |
| |
| tonic::DartInvoke(callback->Get(), {tonic::ToDart(success)}); |
| |
| // callback is associated with the Dart isolate and must be |
| // deleted on the UI thread. |
| callback.reset(); |
| }); |
| task_runners.GetUITaskRunner()->PostTask(ui_completion_task); |
| })); |
| if (!success) { |
| return tonic::ToDart("Failed to submit CommandBuffer"); |
| } |
| return Dart_Null(); |
| } |