flutter_flutter/shell/platform/embedder/tests/embedder_config_builder.cc
Chinmay Garde 1c7300ed1e
Account for root surface transformation on the surfaces managed by the external view embedder. (#11384)
The earlier design speculated that embedders could affect the same
transformations on the layers post engine compositor presentation but before
final composition.

However, the linked issue points out that this design is not suitable for use
with hardware overlay planes. When rendering to the same, to affect the
transformation before composition, embedders would have to render to an
off-screen render target and then apply the transformation before presentation.
This patch negates the need for that off-screen render pass.

To be clear, the previous architecture is still fully viable. Embedders still
have full control over layer transformations before composition. This is an
optimization for the hardware overlay planes use-case.

Fixes b/139758641
2019-09-17 15:16:59 -07:00

248 lines
8.7 KiB
C++

// 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/shell/platform/embedder/tests/embedder_config_builder.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace flutter {
namespace testing {
EmbedderConfigBuilder::EmbedderConfigBuilder(
EmbedderTestContext& context,
InitializationPreference preference)
: context_(context) {
project_args_.struct_size = sizeof(project_args_);
project_args_.shutdown_dart_vm_when_done = true;
project_args_.platform_message_callback =
[](const FlutterPlatformMessage* message, void* context) {
reinterpret_cast<EmbedderTestContext*>(context)
->PlatformMessageCallback(message);
};
custom_task_runners_.struct_size = sizeof(FlutterCustomTaskRunners);
opengl_renderer_config_.struct_size = sizeof(FlutterOpenGLRendererConfig);
opengl_renderer_config_.make_current = [](void* context) -> bool {
return reinterpret_cast<EmbedderTestContext*>(context)->GLMakeCurrent();
};
opengl_renderer_config_.clear_current = [](void* context) -> bool {
return reinterpret_cast<EmbedderTestContext*>(context)->GLClearCurrent();
};
opengl_renderer_config_.present = [](void* context) -> bool {
return reinterpret_cast<EmbedderTestContext*>(context)->GLPresent();
};
opengl_renderer_config_.fbo_callback = [](void* context) -> uint32_t {
return reinterpret_cast<EmbedderTestContext*>(context)->GLGetFramebuffer();
};
opengl_renderer_config_.make_resource_current = [](void* context) -> bool {
return reinterpret_cast<EmbedderTestContext*>(context)
->GLMakeResourceCurrent();
};
opengl_renderer_config_.gl_proc_resolver = [](void* context,
const char* name) -> void* {
return reinterpret_cast<EmbedderTestContext*>(context)->GLGetProcAddress(
name);
};
opengl_renderer_config_.fbo_reset_after_present = true;
opengl_renderer_config_.surface_transformation =
[](void* context) -> FlutterTransformation {
return reinterpret_cast<EmbedderTestContext*>(context)
->GetRootSurfaceTransformation();
};
software_renderer_config_.struct_size = sizeof(FlutterSoftwareRendererConfig);
software_renderer_config_.surface_present_callback =
[](void* context, const void* allocation, size_t row_bytes,
size_t height) {
auto image_info =
SkImageInfo::MakeN32Premul(SkISize::Make(row_bytes / 4, height));
SkBitmap bitmap;
if (!bitmap.installPixels(image_info, const_cast<void*>(allocation),
row_bytes)) {
FML_LOG(ERROR) << "Could not copy pixels for the software "
"composition from the engine.";
return false;
}
bitmap.setImmutable();
return reinterpret_cast<EmbedderTestContext*>(context)->SofwarePresent(
SkImage::MakeFromBitmap(bitmap));
};
// The first argument is treated as the executable name. Don't make tests have
// to do this manually.
AddCommandLineArgument("embedder_unittest");
if (preference == InitializationPreference::kInitialize) {
SetAssetsPath();
SetSnapshots();
SetIsolateCreateCallbackHook();
SetSemanticsCallbackHooks();
AddCommandLineArgument("--disable-observatory");
}
}
EmbedderConfigBuilder::~EmbedderConfigBuilder() = default;
FlutterProjectArgs& EmbedderConfigBuilder::GetProjectArgs() {
return project_args_;
}
void EmbedderConfigBuilder::SetSoftwareRendererConfig(SkISize surface_size) {
renderer_config_.type = FlutterRendererType::kSoftware;
renderer_config_.software = software_renderer_config_;
// TODO(chinmaygarde): The compositor still uses a GL surface for operation.
// Once this is no longer the case, don't setup the GL surface when using the
// software renderer config.
context_.SetupOpenGLSurface(surface_size);
}
void EmbedderConfigBuilder::SetOpenGLRendererConfig(SkISize surface_size) {
renderer_config_.type = FlutterRendererType::kOpenGL;
renderer_config_.open_gl = opengl_renderer_config_;
context_.SetupOpenGLSurface(surface_size);
}
void EmbedderConfigBuilder::SetAssetsPath() {
project_args_.assets_path = context_.GetAssetsPath().c_str();
}
void EmbedderConfigBuilder::SetSnapshots() {
if (auto mapping = context_.GetVMSnapshotData()) {
project_args_.vm_snapshot_data = mapping->GetMapping();
project_args_.vm_snapshot_data_size = mapping->GetSize();
}
if (auto mapping = context_.GetVMSnapshotInstructions()) {
project_args_.vm_snapshot_instructions = mapping->GetMapping();
project_args_.vm_snapshot_instructions_size = mapping->GetSize();
}
if (auto mapping = context_.GetIsolateSnapshotData()) {
project_args_.isolate_snapshot_data = mapping->GetMapping();
project_args_.isolate_snapshot_data_size = mapping->GetSize();
}
if (auto mapping = context_.GetIsolateSnapshotInstructions()) {
project_args_.isolate_snapshot_instructions = mapping->GetMapping();
project_args_.isolate_snapshot_instructions_size = mapping->GetSize();
}
}
void EmbedderConfigBuilder::SetIsolateCreateCallbackHook() {
project_args_.root_isolate_create_callback =
EmbedderTestContext::GetIsolateCreateCallbackHook();
}
void EmbedderConfigBuilder::SetSemanticsCallbackHooks() {
project_args_.update_semantics_node_callback =
EmbedderTestContext::GetUpdateSemanticsNodeCallbackHook();
project_args_.update_semantics_custom_action_callback =
EmbedderTestContext::GetUpdateSemanticsCustomActionCallbackHook();
}
void EmbedderConfigBuilder::SetDartEntrypoint(std::string entrypoint) {
if (entrypoint.size() == 0) {
return;
}
dart_entrypoint_ = std::move(entrypoint);
project_args_.custom_dart_entrypoint = dart_entrypoint_.c_str();
}
void EmbedderConfigBuilder::AddCommandLineArgument(std::string arg) {
if (arg.size() == 0) {
return;
}
command_line_arguments_.emplace_back(std::move(arg));
}
void EmbedderConfigBuilder::SetPlatformTaskRunner(
const FlutterTaskRunnerDescription* runner) {
if (runner == nullptr) {
return;
}
custom_task_runners_.platform_task_runner = runner;
project_args_.custom_task_runners = &custom_task_runners_;
}
void EmbedderConfigBuilder::SetPlatformMessageCallback(
std::function<void(const FlutterPlatformMessage*)> callback) {
context_.SetPlatformMessageCallback(callback);
}
void EmbedderConfigBuilder::SetCompositor() {
context_.SetupCompositor();
auto& compositor = context_.GetCompositor();
compositor_.struct_size = sizeof(compositor_);
compositor_.user_data = &compositor;
compositor_.create_backing_store_callback =
[](const FlutterBackingStoreConfig* config, //
FlutterBackingStore* backing_store_out, //
void* user_data //
) {
return reinterpret_cast<EmbedderTestCompositor*>(user_data)
->CreateBackingStore(config, backing_store_out);
};
compositor_.collect_backing_store_callback =
[](const FlutterBackingStore* backing_store, //
void* user_data //
) {
return reinterpret_cast<EmbedderTestCompositor*>(user_data)
->CollectBackingStore(backing_store);
};
compositor_.present_layers_callback = [](const FlutterLayer** layers, //
size_t layers_count, //
void* user_data //
) {
return reinterpret_cast<EmbedderTestCompositor*>(user_data)->Present(
layers, //
layers_count //
);
};
project_args_.compositor = &compositor_;
}
FlutterCompositor& EmbedderConfigBuilder::GetCompositor() {
return compositor_;
}
UniqueEngine EmbedderConfigBuilder::LaunchEngine() const {
FlutterEngine engine = nullptr;
FlutterProjectArgs project_args = project_args_;
std::vector<const char*> args;
args.reserve(command_line_arguments_.size());
for (const auto& arg : command_line_arguments_) {
args.push_back(arg.c_str());
}
if (args.size() > 0) {
project_args.command_line_argv = args.data();
project_args.command_line_argc = args.size();
} else {
// Clear it out in case this is not the first engine launch from the
// embedder config builder.
project_args.command_line_argv = nullptr;
project_args.command_line_argc = 0;
}
auto result = FlutterEngineRun(FLUTTER_ENGINE_VERSION, &renderer_config_,
&project_args, &context_, &engine);
if (result != kSuccess) {
return {};
}
return UniqueEngine{engine};
}
} // namespace testing
} // namespace flutter