blob: b2f8fcd6c509844ffbbf1471cc2f0f2d6692d6bf [file] [log] [blame]
// 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::Context> context,
std::shared_ptr<impeller::CommandBuffer> command_buffer)
: context_(std::move(context)),
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 context_->GetCommandQueue()->Submit({command_buffer_}).ok();
}
bool CommandBuffer::Submit(
const impeller::CommandBuffer::CompletionCallback& completion_callback) {
for (auto& encodable : encodables_) {
encodable->EncodeCommands();
}
return context_->GetCommandQueue()
->Submit({command_buffer_}, completion_callback)
.ok();
}
} // 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(),
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();
}