未验证 提交 40a37126 编写于 作者: C Chinmay Garde 提交者: GitHub

Remove the content handler for its move to topaz. (#5289)

上级 a262da46
......@@ -30,14 +30,6 @@ group("flutter") {
}
}
if (is_fuchsia) {
public_deps += [
"$flutter_root/content_handler:aot",
"$flutter_root/content_handler:jit",
"$flutter_root/flow",
]
}
# If on the host, compile all unittests targets.
if (current_toolchain == host_toolchain) {
if (is_mac) {
......@@ -70,180 +62,10 @@ config("config") {
include_dirs = [ ".." ]
}
if (is_fuchsia) {
import("//build/package.gni")
package("flutter_aot_runner") {
deps = [
"$flutter_root/content_handler:aot",
]
if (flutter_runtime_mode != "release") {
deps += [
"//third_party/dart/runtime/observatory:embedded_archive_observatory",
]
}
binary = "flutter_aot_runner"
if (flutter_runtime_mode != "release") {
resources = [
{
path = rebase_path(
"$root_gen_dir/observatory/embedded_archive_observatory.tar")
dest = "observatory.tar"
},
]
}
meta = [
{
path = rebase_path("content_handler/meta/sandbox")
dest = "sandbox"
},
]
}
package("flutter2_aot_runner") {
deps = [
"$flutter_root/content_handler:aot",
]
if (flutter_runtime_mode != "release") {
deps += [
"//third_party/dart/runtime/observatory:embedded_archive_observatory",
]
}
binary = "flutter_aot_runner"
if (flutter_runtime_mode != "release") {
resources = [
{
path = rebase_path(
"$root_gen_dir/observatory/embedded_archive_observatory.tar")
dest = "observatory.tar"
},
]
}
meta = [
{
path = rebase_path("content_handler/meta/sandbox")
dest = "sandbox"
},
]
}
package("flutter_jit_runner") {
snapshot_label = "$flutter_root/lib/snapshot:generate_snapshot_bin"
snapshot_gen_dir = get_label_info(snapshot_label, "target_gen_dir")
deps = [
"$flutter_root/content_handler:jit",
snapshot_label,
]
if (flutter_runtime_mode != "release") {
deps += [
"//third_party/dart/runtime/observatory:embedded_archive_observatory",
]
}
binary = "flutter_jit_runner"
resources = [
{
path = rebase_path("$snapshot_gen_dir/vm_isolate_snapshot.bin")
dest = "vm_snapshot_data.bin"
},
{
path = rebase_path("$snapshot_gen_dir/vm_snapshot_instructions.bin")
dest = "vm_snapshot_instructions.bin"
},
{
path = rebase_path("$snapshot_gen_dir/isolate_snapshot.bin")
dest = "isolate_core_snapshot_data.bin"
},
{
path =
rebase_path("$snapshot_gen_dir/isolate_snapshot_instructions.bin")
dest = "isolate_core_snapshot_instructions.bin"
},
]
if (flutter_runtime_mode != "release") {
resources += [
{
path = rebase_path(
"$root_gen_dir/observatory/embedded_archive_observatory.tar")
dest = "observatory.tar"
},
]
}
meta = [
{
path = rebase_path("content_handler/meta/sandbox")
dest = "sandbox"
},
]
}
package("flutter2_jit_runner") {
snapshot_label = "//topaz/runtime/flutter_runner/kernel:kernel_core_snapshot"
snapshot_gen_dir = get_label_info(snapshot_label, "target_gen_dir")
deps = [
"$flutter_root/content_handler:jit",
snapshot_label,
]
if (flutter_runtime_mode != "release") {
deps += [
"//third_party/dart/runtime/observatory:embedded_archive_observatory",
]
}
binary = "flutter_jit_runner"
resources = [
{
path = rebase_path("$snapshot_gen_dir/vm_isolate_snapshot.bin")
dest = "vm_snapshot_data.bin"
},
{
path = rebase_path("$snapshot_gen_dir/vm_snapshot_instructions.bin")
dest = "vm_snapshot_instructions.bin"
},
{
path = rebase_path("$snapshot_gen_dir/isolate_snapshot.bin")
dest = "isolate_core_snapshot_data.bin"
},
{
path =
rebase_path("$snapshot_gen_dir/isolate_snapshot_instructions.bin")
dest = "isolate_core_snapshot_instructions.bin"
},
]
if (flutter_runtime_mode != "release") {
resources += [
{
path = rebase_path(
"$root_gen_dir/observatory/embedded_archive_observatory.tar")
dest = "observatory.tar"
},
]
}
meta = [
{
path = rebase_path("content_handler/meta/sandbox")
dest = "sandbox"
},
]
}
} else {
group("dist") {
testonly = true
group("dist") {
testonly = true
deps = [
"$flutter_root/sky/dist",
]
}
deps = [
"$flutter_root/sky/dist",
]
}
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
assert(is_fuchsia)
import("//build/vulkan/config.gni")
template("flutter_content_handler") {
invoker_output_name = invoker.output_name
extra_deps = invoker.extra_deps
executable(target_name) {
output_name = invoker_output_name
defines = []
libs = []
sources = [
"accessibility_bridge.cc",
"accessibility_bridge.h",
"application.cc",
"application.h",
"application_runner.cc",
"application_runner.h",
"compositor_context.cc",
"compositor_context.h",
"engine.cc",
"engine.h",
"fuchsia_font_manager.cc",
"fuchsia_font_manager.h",
"isolate_configurator.cc",
"isolate_configurator.h",
"main.cc",
"platform_view.cc",
"platform_view.h",
"session_connection.cc",
"session_connection.h",
"surface.cc",
"surface.h",
"task_observers.cc",
"task_observers.h",
"unique_fdio_ns.h",
"vsync_waiter.cc",
"vsync_waiter.h",
"vulkan_surface.cc",
"vulkan_surface.h",
"vulkan_surface_pool.cc",
"vulkan_surface_pool.h",
"vulkan_surface_producer.cc",
"vulkan_surface_producer.h",
]
# The use of these dependencies is temporary and will be moved behind the
# embedder API.
flutter_deps = [
"$flutter_root/assets",
"$flutter_root/common",
"$flutter_root/flow",
"$flutter_root/glue",
"$flutter_root/lib/ui",
"$flutter_root/runtime",
"$flutter_root/third_party/txt",
"$flutter_root/vulkan",
"$flutter_root/fml",
"$flutter_root/shell/common",
"$flutter_root/shell/gpu",
]
deps = [
"//third_party/dart/runtime/bin:libdart_builtin",
"//garnet/public/lib/app/cpp",
"//garnet/public/lib/fonts/fidl",
"//garnet/public/lib/fsl",
"//garnet/public/lib/fxl",
"//garnet/public/lib/icu_data/cpp",
"//garnet/public/lib/svc/cpp",
"//garnet/public/lib/ui/input/fidl",
"//garnet/public/lib/ui/scenic:client",
"//garnet/public/lib/ui/views/fidl:v1",
"//garnet/public/lib/vulkan",
"//garnet/public/lib/zip",
"//peridot/public/lib:fidl",
"//third_party/rapidjson",
"//third_party/skia",
"//topaz/lib/tonic",
"//topaz/public/dart-pkg/fuchsia",
"//topaz/public/lib/ui/flutter/sdk_ext",
"//third_party/skia:gpu",
"//third_party/zlib:minizip",
"//zircon/public/lib/trace-provider",
] + extra_deps + flutter_deps
# The flags below are needed so that Dart's CPU profiler can walk the
# C++ stack.
cflags = [
"-mno-omit-leaf-frame-pointer",
"-fno-omit-frame-pointer",
]
# This flag is needed so that the call to dladdr() in Dart's native symbol
# resolver can report good symbol information for the CPU profiler.
ldflags = [ "-rdynamic" ]
}
}
flutter_content_handler("aot") {
output_name = "flutter_aot_runner"
extra_deps = [
"//third_party/dart/runtime:libdart_precompiled_runtime",
"//third_party/dart/runtime/platform:libdart_platform_precompiled_runtime",
]
}
flutter_content_handler("jit") {
output_name = "flutter_jit_runner"
extra_deps = [
"//third_party/dart/runtime:libdart_jit",
"//third_party/dart/runtime/platform:libdart_platform_jit",
]
}
Flutter Application Runner
==========================
Implements the `component::ApplicationRunner` FIDL interface to launch and run mutliple Flutter applications within the same process.
// Copyright 2017 The Fuchsia 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 "accessibility_bridge.h"
#include <unordered_set>
#include "lib/app/cpp/application_context.h"
#include "third_party/rapidjson/rapidjson/document.h"
#include "third_party/rapidjson/rapidjson/stringbuffer.h"
#include "third_party/rapidjson/rapidjson/writer.h"
namespace flutter {
AccessibilityBridge::AccessibilityBridge(
fidl::InterfaceHandle<modular::ContextWriter> writer)
: writer_(writer.Bind()) {}
AccessibilityBridge::~AccessibilityBridge() = default;
void AccessibilityBridge::UpdateSemantics(
const blink::SemanticsNodeUpdates& update) {
for (const auto& update : update) {
const auto& node = update.second;
semantics_nodes_[node.id] = node;
}
std::vector<int> visited_nodes;
UpdateVisitedForNodeAndChildren(0, &visited_nodes);
EraseUnvisitedNodes(visited_nodes);
// The data sent to the Context Service is a JSON formatted list of labels
// for all on screen widgets.
rapidjson::Document nodes_json(rapidjson::kArrayType);
for (const int node_index : visited_nodes) {
const auto& node = semantics_nodes_[node_index];
if (!node.label.empty()) {
rapidjson::Value value;
value.SetString(node.label.data(), node.label.size());
nodes_json.PushBack(value, nodes_json.GetAllocator());
}
}
if (nodes_json.Size() > 0) {
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
nodes_json.Accept(writer);
writer_->WriteEntityTopic("/inferred/accessibility_text",
buffer.GetString());
}
}
void AccessibilityBridge::UpdateVisitedForNodeAndChildren(
const int id,
std::vector<int>* visited_nodes) {
std::map<int, blink::SemanticsNode>::const_iterator it =
semantics_nodes_.find(id);
if (it == semantics_nodes_.end()) {
return;
}
visited_nodes->push_back(id);
for (const int child : it->second.children) {
UpdateVisitedForNodeAndChildren(child, visited_nodes);
}
}
void AccessibilityBridge::EraseUnvisitedNodes(
const std::vector<int>& visited_nodes) {
const std::unordered_set<int> visited_nodes_lookup(visited_nodes.begin(),
visited_nodes.end());
for (auto it = semantics_nodes_.begin(); it != semantics_nodes_.end();) {
if (visited_nodes_lookup.find((*it).first) == visited_nodes_lookup.end()) {
it = semantics_nodes_.erase(it);
} else {
++it;
}
}
}
} // namespace flutter
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <map>
#include <modular/cpp/fidl.h>
#include "flutter/lib/ui/semantics/semantics_node.h"
#include "lib/fxl/macros.h"
namespace flutter {
// Maintain an up-to-date list of SemanticsNodes on screen, and communicate
// with the Context Service.
class AccessibilityBridge final {
public:
AccessibilityBridge(fidl::InterfaceHandle<modular::ContextWriter> writer);
~AccessibilityBridge();
// Update the internal representation of the semantics nodes, and write the
// semantics to Context Service.
void UpdateSemantics(const blink::SemanticsNodeUpdates& update);
private:
modular::ContextWriterPtr writer_;
std::map<int, blink::SemanticsNode> semantics_nodes_;
// Walk the semantics node tree starting at |id|, and store the id of each
// visited child in |visited_nodes|.
void UpdateVisitedForNodeAndChildren(const int id,
std::vector<int>* visited_nodes);
// Remove any node from |semantics_nodes_| that doesn't have an id in
// |visited_nodes|.
void EraseUnvisitedNodes(const std::vector<int>& visited_nodes);
FXL_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridge);
};
} // namespace flutter
// Copyright 2018 The Fuchsia 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 "application.h"
#include <dlfcn.h>
#include <zircon/dlfcn.h>
#include <sstream>
#include "flutter/shell/common/switches.h"
#include "lib/fsl/vmo/file.h"
#include "lib/fsl/vmo/vector.h"
#include "lib/fxl/command_line.h"
#include "lib/fxl/synchronization/waitable_event.h"
#include "task_observers.h"
namespace flutter {
std::pair<std::unique_ptr<fsl::Thread>, std::unique_ptr<Application>>
Application::Create(
TerminationCallback termination_callback,
component::ApplicationPackage package,
component::ApplicationStartupInfo startup_info,
fidl::InterfaceRequest<component::ApplicationController> controller) {
auto thread = std::make_unique<fsl::Thread>();
std::unique_ptr<Application> application;
fxl::AutoResetWaitableEvent latch;
thread->TaskRunner()->PostTask([&]() mutable {
application.reset(new Application(termination_callback, //
std::move(package), //
std::move(startup_info), //
std::move(controller) //
));
latch.Signal();
});
thread->Run();
latch.Wait();
return {std::move(thread), std::move(application)};
}
static std::string DebugLabelForURL(const std::string& url) {
auto found = url.rfind("/");
if (found == std::string::npos) {
return url;
} else {
return {url, found + 1};
}
}
Application::Application(
TerminationCallback termination_callback,
component::ApplicationPackage,
component::ApplicationStartupInfo startup_info,
fidl::InterfaceRequest<component::ApplicationController>
application_controller_request)
: termination_callback_(termination_callback),
debug_label_(DebugLabelForURL(startup_info.launch_info.url)),
application_controller_(this) {
application_controller_.set_error_handler([this]() { Kill(); });
FXL_DCHECK(fdio_ns_.is_valid());
// ApplicationLaunchInfo::url non-optional.
auto& launch_info = startup_info.launch_info;
// ApplicationLaunchInfo::arguments optional.
if (auto& arguments = launch_info.arguments) {
settings_ = shell::SettingsFromCommandLine(
fxl::CommandLineFromIterators(arguments->begin(), arguments->end()));
}
// TODO: ApplicationLaunchInfo::out.
// TODO: ApplicationLaunchInfo::err.
// ApplicationLaunchInfo::service_request optional.
if (launch_info.directory_request) {
service_provider_bridge_.ServeDirectory(
std::move(launch_info.directory_request));
}
// ApplicationLaunchInfo::flat_namespace optional.
for (size_t i = 0; i < startup_info.flat_namespace.paths->size(); ++i) {
const auto& path = startup_info.flat_namespace.paths->at(i);
if (path == "/svc") {
continue;
}
zx::channel dir = std::move(startup_info.flat_namespace.directories->at(i));
zx_handle_t dir_handle = dir.release();
if (fdio_ns_bind(fdio_ns_.get(), path->data(), dir_handle) != ZX_OK) {
FXL_DLOG(ERROR) << "Could not bind path to namespace: " << path;
zx_handle_close(dir_handle);
}
}
application_directory_.reset(fdio_ns_opendir(fdio_ns_.get()));
FXL_DCHECK(application_directory_.is_valid());
application_assets_directory_.reset(
openat(application_directory_.get(), "pkg/data", O_RDONLY | O_DIRECTORY));
// TODO: ApplicationLaunchInfo::additional_services optional.
// All launch arguments have been read. Perform service binding and
// final settings configuration. The next call will be to create a view
// for this application.
service_provider_bridge_.AddService<views_v1::ViewProvider>(
std::bind(&Application::CreateShellForView, this, std::placeholders::_1));
component::ServiceProviderPtr outgoing_services;
outgoing_services_request_ = outgoing_services.NewRequest();
service_provider_bridge_.set_backend(std::move(outgoing_services));
// Setup the application controller binding.
if (application_controller_request) {
application_controller_.Bind(std::move(application_controller_request));
}
application_context_ =
component::ApplicationContext::CreateFrom(std::move(startup_info));
settings_.vm_snapshot_data_path = "pkg/data/vm_snapshot_data.bin";
settings_.vm_snapshot_instr_path = "pkg/data/vm_snapshot_instructions.bin";
settings_.isolate_snapshot_data_path =
"pkg/data/isolate_core_snapshot_data.bin";
settings_.isolate_snapshot_instr_path =
"pkg/data/isolate_core_snapshot_instructions.bin";
settings_.enable_observatory = true;
settings_.icu_data_path = "";
settings_.assets_dir = application_assets_directory_.get();
settings_.script_snapshot_path = "snapshot_blob.bin";
settings_.application_kernel_asset = "kernel_blob.dill";
settings_.application_kernel_list_asset = "app.dilplist";
settings_.log_tag = debug_label_ + std::string{"(flutter)"};
#ifndef NDEBUG
// Debug mode
settings_.dart_non_checked_mode = false;
#else // NDEBUG
// Release mode
settings_.dart_non_checked_mode = true;
#endif // NDEBUG
settings_.task_observer_add =
std::bind(&CurrentMessageLoopAddAfterTaskObserver, std::placeholders::_1,
std::placeholders::_2);
settings_.task_observer_remove = std::bind(
&CurrentMessageLoopRemoveAfterTaskObserver, std::placeholders::_1);
AttemptVMLaunchWithCurrentSettings(settings_);
}
Application::~Application() = default;
const std::string& Application::GetDebugLabel() const {
return debug_label_;
}
void Application::AttemptVMLaunchWithCurrentSettings(
const blink::Settings& settings) {
if (!blink::DartVM::IsRunningPrecompiledCode()) {
// We will be initializing the VM lazily in this case.
return;
}
fsl::SizedVmo dylib_vmo;
if (!fsl::VmoFromFilenameAt(
application_assets_directory_.get() /* /pkg/data */, "libapp.so",
&dylib_vmo)) {
FXL_LOG(ERROR) << "Dylib containing VM and isolate snapshots does not "
"exist. Will not be able to launch VM.";
return;
}
dlerror();
auto library_handle = dlopen_vmo(dylib_vmo.vmo().get(), RTLD_LAZY);
if (library_handle == nullptr) {
FXL_LOG(ERROR) << "Could not open dylib: " << dlerror();
return;
}
auto lib =
fml::NativeLibrary::CreateWithHandle(library_handle, // library handle
true // close the handle when done
);
auto symbol = [](const char* str) {
return std::string{"_"} + std::string{str};
};
fxl::RefPtr<blink::DartSnapshot> vm_snapshot =
fxl::MakeRefCounted<blink::DartSnapshot>(
blink::DartSnapshotBuffer::CreateWithSymbolInLibrary(
lib, symbol(blink::DartSnapshot::kVMDataSymbol).c_str()),
blink::DartSnapshotBuffer::CreateWithSymbolInLibrary(
lib, symbol(blink::DartSnapshot::kVMInstructionsSymbol).c_str()));
isolate_snapshot_ = fxl::MakeRefCounted<blink::DartSnapshot>(
blink::DartSnapshotBuffer::CreateWithSymbolInLibrary(
lib, symbol(blink::DartSnapshot::kIsolateDataSymbol).c_str()),
blink::DartSnapshotBuffer::CreateWithSymbolInLibrary(
lib,
symbol(blink::DartSnapshot::kIsolateInstructionsSymbol).c_str()));
blink::DartVM::ForProcess(settings_, //
std::move(vm_snapshot), //
isolate_snapshot_ //
);
if (blink::DartVM::ForProcessIfInitialized()) {
FXL_DLOG(INFO) << "VM successfully initialized for AOT mode.";
} else {
FXL_LOG(ERROR) << "VM could not be initialized for AOT mode.";
}
}
// |component::ApplicationController|
void Application::Kill() {
if (last_return_code_.first) {
for (auto wait_callback : wait_callbacks_) {
wait_callback(last_return_code_.second);
}
}
wait_callbacks_.clear();
termination_callback_(this);
// WARNING: Don't do anything past this point as this instance may have been
// collected.
}
// |component::ApplicationController|
void Application::Detach() {
application_controller_.set_error_handler(nullptr);
}
// |component::ApplicationController|
void Application::Wait(WaitCallback callback) {
wait_callbacks_.emplace_back(std::move(callback));
}
// |flutter::Engine::Delegate|
void Application::OnEngineTerminate(const Engine* shell_holder) {
auto found = std::find_if(shell_holders_.begin(), shell_holders_.end(),
[shell_holder](const auto& holder) {
return holder.get() == shell_holder;
});
if (found == shell_holders_.end()) {
return;
}
// We may launch multiple shell in this application. However, we will
// terminate when the last shell goes away. The error code return to the
// application controller will be the last isolate that had an error.
auto return_code = shell_holder->GetEngineReturnCode();
if (return_code.first) {
last_return_code_ = return_code;
}
shell_holders_.erase(found);
if (shell_holders_.size() == 0) {
Kill();
// WARNING: Don't do anything past this point because the delegate may have
// collected this instance via the termination callback.
}
}
void Application::CreateShellForView(
fidl::InterfaceRequest<views_v1::ViewProvider> view_provider_request) {
shells_bindings_.AddBinding(this, std::move(view_provider_request));
}
// |views_v1::ViewProvider|
void Application::CreateView(
fidl::InterfaceRequest<views_v1_token::ViewOwner> view_owner,
fidl::InterfaceRequest<component::ServiceProvider>) {
if (!application_context_) {
FXL_DLOG(ERROR) << "Application context was invalid when attempting to "
"create a shell for a view provider request.";
return;
}
shell_holders_.emplace(std::make_unique<Engine>(
*this, // delegate
debug_label_, // thread label
*application_context_, // application context
settings_, // settings
std::move(isolate_snapshot_), // isolate snapshot
std::move(view_owner), // view owner
std::move(fdio_ns_), // FDIO namespace
std::move(outgoing_services_request_) // outgoing request
));
}
} // namespace flutter
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <array>
#include <memory>
#include <set>
#include <component/cpp/fidl.h>
#include <views_v1/cpp/fidl.h>
#include <views_v1_token/cpp/fidl.h>
#include "engine.h"
#include "flutter/common/settings.h"
#include "lib/app/cpp/application_context.h"
#include "lib/fidl/cpp/binding_set.h"
#include "lib/fidl/cpp/interface_request.h"
#include "lib/fsl/threading/thread.h"
#include "lib/fxl/files/unique_fd.h"
#include "lib/fxl/macros.h"
#include "lib/svc/cpp/service_provider_bridge.h"
#include "unique_fdio_ns.h"
namespace flutter {
// Represents an instance of a Flutter application that contains one of more
// Flutter engine instances.
class Application final : public Engine::Delegate,
public component::ApplicationController,
public views_v1::ViewProvider {
public:
using TerminationCallback = std::function<void(const Application*)>;
// Creates a dedicated thread to run the application and constructions the
// application on it. The application can be accessed only on this thread.
// This is a synchronous operation.
static std::pair<std::unique_ptr<fsl::Thread>, std::unique_ptr<Application>>
Create(TerminationCallback termination_callback,
component::ApplicationPackage package,
component::ApplicationStartupInfo startup_info,
fidl::InterfaceRequest<component::ApplicationController> controller);
// Must be called on the same thread returned from the create call. The thread
// may be collected after.
~Application();
const std::string& GetDebugLabel() const;
private:
blink::Settings settings_;
TerminationCallback termination_callback_;
const std::string debug_label_;
UniqueFDIONS fdio_ns_ = UniqueFDIONSCreate();
fxl::UniqueFD application_directory_;
fxl::UniqueFD application_assets_directory_;
fidl::Binding<component::ApplicationController> application_controller_;
fidl::InterfaceRequest<component::ServiceProvider> outgoing_services_request_;
component::ServiceProviderBridge service_provider_bridge_;
std::unique_ptr<component::ApplicationContext> application_context_;
fidl::BindingSet<views_v1::ViewProvider> shells_bindings_;
fxl::RefPtr<blink::DartSnapshot> isolate_snapshot_;
std::set<std::unique_ptr<Engine>> shell_holders_;
std::vector<WaitCallback> wait_callbacks_;
std::pair<bool, uint32_t> last_return_code_;
Application(
TerminationCallback termination_callback,
component::ApplicationPackage package,
component::ApplicationStartupInfo startup_info,
fidl::InterfaceRequest<component::ApplicationController> controller);
// |component::ApplicationController|
void Kill() override;
// |component::ApplicationController|
void Detach() override;
// |component::ApplicationController|
void Wait(WaitCallback callback) override;
// |views_v1::ViewProvider|
void CreateView(
fidl::InterfaceRequest<views_v1_token::ViewOwner> view_owner,
fidl::InterfaceRequest<component::ServiceProvider> services) override;
// |flutter::Engine::Delegate|
void OnEngineTerminate(const Engine* holder) override;
void CreateShellForView(
fidl::InterfaceRequest<views_v1::ViewProvider> view_provider_request);
void AttemptVMLaunchWithCurrentSettings(const blink::Settings& settings);
FXL_DISALLOW_COPY_AND_ASSIGN(Application);
};
} // namespace flutter
// Copyright 2018 The Fuchsia 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 "application_runner.h"
#include <zircon/types.h>
#include <sstream>
#include <utility>
#include "flutter/lib/ui/text/font_collection.h"
#include "fuchsia_font_manager.h"
#include "lib/fxl/functional/make_copyable.h"
#include "lib/icu_data/cpp/icu_data.h"
#include "third_party/flutter/runtime/dart_vm.h"
#include "third_party/skia/include/core/SkGraphics.h"
namespace flutter {
static void SetProcessName() {
std::stringstream stream;
stream << "io.flutter.runner.";
if (blink::DartVM::IsRunningPrecompiledCode()) {
stream << "aot";
} else {
stream << "jit";
}
const auto name = stream.str();
zx::process::self().set_property(ZX_PROP_NAME, name.c_str(), name.size());
}
static void SetThreadName(const std::string& thread_name) {
zx::thread::self().set_property(ZX_PROP_NAME, thread_name.c_str(),
thread_name.size());
}
ApplicationRunner::ApplicationRunner()
: host_context_(component::ApplicationContext::CreateFromStartupInfo()) {
SkGraphics::Init();
SetupICU();
SetupGlobalFonts();
SetProcessName();
SetThreadName("io.flutter.runner.main");
host_context_->outgoing_services()->AddService<component::ApplicationRunner>(
std::bind(&ApplicationRunner::RegisterApplication, this,
std::placeholders::_1));
}
ApplicationRunner::~ApplicationRunner() {
host_context_->outgoing_services()
->RemoveService<component::ApplicationRunner>();
}
void ApplicationRunner::RegisterApplication(
fidl::InterfaceRequest<component::ApplicationRunner> request) {
active_applications_bindings_.AddBinding(this, std::move(request));
}
void ApplicationRunner::StartApplication(
component::ApplicationPackage package,
component::ApplicationStartupInfo startup_info,
fidl::InterfaceRequest<component::ApplicationController> controller) {
// Notes on application termination: Application typically terminate on the
// thread on which they were created. This usually means the thread was
// specifically created to host the application. But we want to ensure that
// access to the active applications collection is made on the same thread. So
// we capture the runner in the termination callback. There is no risk of
// there being multiple application runner instance in the process at the same
// time. So it is safe to use the raw pointer.
Application::TerminationCallback termination_callback =
[task_runner = fsl::MessageLoop::GetCurrent()->task_runner(), //
application_runner = this //
](const Application* application) {
task_runner->PostTask([application_runner, application]() {
application_runner->OnApplicationTerminate(application);
});
};
auto thread_application_pair =
Application::Create(termination_callback, // termination callback
std::move(package), // application pacakge
std::move(startup_info), // startup info
std::move(controller) // controller request
);
auto key = thread_application_pair.second.get();
active_applications_[key] = std::move(thread_application_pair);
}
void ApplicationRunner::OnApplicationTerminate(const Application* application) {
auto& active_application = active_applications_.at(application);
// Grab the items out of the entry because we will have to rethread the
// destruction.
auto application_to_destroy = std::move(active_application.application);
auto application_destruction_thread = std::move(active_application.thread);
// Delegate the entry.
active_applications_.erase(application);
// Post the task to destroy the application and quit its message loop.
auto runner = application_destruction_thread->TaskRunner();
runner->PostTask(fxl::MakeCopyable(
[instance = std::move(application_to_destroy)]() mutable {
instance.reset();
fsl::MessageLoop::GetCurrent()->PostQuitTask();
}));
// This works because just posted the quit task on the hosted thread.
application_destruction_thread->Join();
}
void ApplicationRunner::SetupICU() {
if (!icu_data::Initialize(host_context_.get())) {
FXL_LOG(ERROR) << "Could not initialize ICU data.";
}
}
void ApplicationRunner::SetupGlobalFonts() {
// Fuchsia does not have per application (shell) fonts. Instead, all fonts
// must be obtained from the font provider.
auto process_font_collection =
blink::FontCollection::ForProcess().GetFontCollection();
// Connect to the system font provider.
fonts::FontProviderSyncPtr sync_font_provider;
host_context_->ConnectToEnvironmentService(sync_font_provider.NewRequest());
// Set the default font manager.
process_font_collection->SetDefaultFontManager(
sk_make_sp<txt::FuchsiaFontManager>(std::move(sync_font_provider)));
}
} // namespace flutter
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <memory>
#include <unordered_map>
#include <component/cpp/fidl.h>
#include "application.h"
#include "lib/app/cpp/application_context.h"
#include "lib/fidl/cpp/binding_set.h"
#include "lib/fsl/tasks/message_loop.h"
#include "lib/fxl/macros.h"
namespace flutter {
// Publishes the |component::ApplicationRunner| service and runs applications on
// their own threads.
class ApplicationRunner final : public component::ApplicationRunner {
public:
ApplicationRunner();
~ApplicationRunner();
private:
struct ActiveApplication {
std::unique_ptr<fsl::Thread> thread;
std::unique_ptr<Application> application;
ActiveApplication(std::pair<std::unique_ptr<fsl::Thread>,
std::unique_ptr<Application>> pair)
: thread(std::move(pair.first)), application(std::move(pair.second)) {}
ActiveApplication() = default;
};
std::unique_ptr<component::ApplicationContext> host_context_;
fidl::BindingSet<component::ApplicationRunner> active_applications_bindings_;
std::unordered_map<const Application*, ActiveApplication>
active_applications_;
// |component::ApplicationRunner|
void StartApplication(component::ApplicationPackage application,
component::ApplicationStartupInfo startup_info,
fidl::InterfaceRequest<component::ApplicationController>
controller) override;
void RegisterApplication(
fidl::InterfaceRequest<component::ApplicationRunner> request);
void UnregisterApplication(const Application* application);
void OnApplicationTerminate(const Application* application);
void SetupICU();
void SetupGlobalFonts();
FXL_DISALLOW_COPY_AND_ASSIGN(ApplicationRunner);
};
} // namespace flutter
// Copyright 2018 The Fuchsia 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 "compositor_context.h"
#include "flutter/flow/layers/layer_tree.h"
#include "flutter/glue/trace_event.h"
namespace flutter {
class ScopedFrame final : public flow::CompositorContext::ScopedFrame {
public:
ScopedFrame(flow::CompositorContext& context,
bool instrumentation_enabled,
SessionConnection& session_connection)
: flow::CompositorContext::ScopedFrame(context,
nullptr,
nullptr,
instrumentation_enabled),
session_connection_(session_connection) {}
private:
SessionConnection& session_connection_;
bool Raster(flow::LayerTree& layer_tree, bool ignore_raster_cache) override {
if (!session_connection_.has_metrics()) {
return true;
}
{
// Preroll the Flutter layer tree. This allows Flutter to perform
// pre-paint optimizations.
TRACE_EVENT0("flutter", "Preroll");
layer_tree.Preroll(*this, true /* ignore raster cache */);
}
{
// Traverse the Flutter layer tree so that the necessary session ops to
// represent the frame are enqueued in the underlying session.
TRACE_EVENT0("flutter", "UpdateScene");
layer_tree.UpdateScene(session_connection_.scene_update_context(),
session_connection_.root_node());
}
{
// Flush all pending session ops.
TRACE_EVENT0("flutter", "SessionPresent");
session_connection_.Present(*this);
}
return true;
}
FXL_DISALLOW_COPY_AND_ASSIGN(ScopedFrame);
};
CompositorContext::CompositorContext(
fidl::InterfaceHandle<ui::Scenic> scenic,
std::string debug_label,
zx::eventpair import_token,
OnMetricsUpdate session_metrics_did_change_callback,
fxl::Closure session_error_callback,
zx_handle_t vsync_event_handle)
: debug_label_(std::move(debug_label)),
session_connection_(std::move(scenic),
debug_label_,
std::move(import_token),
std::move(session_metrics_did_change_callback),
std::move(session_error_callback),
vsync_event_handle) {}
CompositorContext::~CompositorContext() = default;
std::unique_ptr<flow::CompositorContext::ScopedFrame>
CompositorContext::AcquireFrame(GrContext* gr_context,
SkCanvas* canvas,
bool instrumentation_enabled) {
// TODO: The AcquireFrame interface is too broad and must be refactored to get
// rid of the context and canvas arguments as those seem to be only used for
// colorspace correctness purposes on the mobile shells.
return std::make_unique<flutter::ScopedFrame>(*this, //
instrumentation_enabled, //
session_connection_ //
);
}
} // namespace flutter
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <ui/cpp/fidl.h>
#include "flutter/flow/compositor_context.h"
#include "lib/fxl/macros.h"
#include "session_connection.h"
namespace flutter {
// Holds composition specific state and bindings specific to composition on
// Fuchsia.
class CompositorContext final : public flow::CompositorContext {
public:
CompositorContext(fidl::InterfaceHandle<ui::Scenic> scenic,
std::string debug_label,
zx::eventpair import_token,
OnMetricsUpdate session_metrics_did_change_callback,
fxl::Closure session_error_callback,
zx_handle_t vsync_event_handle);
~CompositorContext() override;
private:
const std::string debug_label_;
SessionConnection session_connection_;
// |flow::CompositorContext|
std::unique_ptr<ScopedFrame> AcquireFrame(
GrContext* gr_context,
SkCanvas* canvas,
bool instrumentation_enabled) override;
FXL_DISALLOW_COPY_AND_ASSIGN(CompositorContext);
};
} // namespace flutter
// Copyright 2018 The Fuchsia 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 "engine.h"
#include <sstream>
#include "flutter/common/task_runners.h"
#include "flutter/fml/task_runner.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/run_configuration.h"
#include "lib/fsl/tasks/message_loop.h"
#include "lib/fxl/functional/make_copyable.h"
#include "lib/fxl/synchronization/waitable_event.h"
#include "platform_view.h"
namespace flutter {
static void UpdateNativeThreadLabelNames(const std::string& label,
const blink::TaskRunners& runners) {
auto set_thread_name = [](fxl::RefPtr<fxl::TaskRunner> runner,
std::string prefix, std::string suffix) {
if (!runner) {
return;
}
fml::TaskRunner::RunNowOrPostTask(runner, [name = prefix + suffix]() {
zx::thread::self().set_property(ZX_PROP_NAME, name.c_str(), name.size());
});
};
set_thread_name(runners.GetPlatformTaskRunner(), label, ".platform");
set_thread_name(runners.GetUITaskRunner(), label, ".ui");
set_thread_name(runners.GetGPUTaskRunner(), label, ".gpu");
set_thread_name(runners.GetIOTaskRunner(), label, ".io");
}
Engine::Engine(Delegate& delegate,
std::string thread_label,
component::ApplicationContext& application_context,
blink::Settings settings,
fxl::RefPtr<blink::DartSnapshot> isolate_snapshot,
fidl::InterfaceRequest<views_v1_token::ViewOwner> view_owner,
UniqueFDIONS fdio_ns,
fidl::InterfaceRequest<component::ServiceProvider>
outgoing_services_request)
: delegate_(delegate),
thread_label_(std::move(thread_label)),
settings_(std::move(settings)),
weak_factory_(this) {
if (zx::event::create(0, &vsync_event_) != ZX_OK) {
FXL_DLOG(ERROR) << "Could not create the vsync event.";
return;
}
// Launch the threads that will be used to run the shell. These threads will
// be joined in the destructor.
for (auto& thread : host_threads_) {
thread.Run();
}
views_v1::ViewManagerPtr view_manager;
application_context.ConnectToEnvironmentService(view_manager.NewRequest());
zx::eventpair import_token, export_token;
if (zx::eventpair::create(0u, &import_token, &export_token) != ZX_OK) {
FXL_DLOG(ERROR) << "Could not create event pair.";
return;
}
// Setup the session connection.
fidl::InterfaceHandle<ui::Scenic> scenic;
view_manager->GetScenic(scenic.NewRequest());
// Grab the parent environent services. The platform view may want to access
// some of these services.
fidl::InterfaceHandle<component::ServiceProvider>
parent_environment_service_provider;
application_context.environment()->GetServices(
parent_environment_service_provider.NewRequest());
// We need to manually schedule a frame when the session metrics change.
OnMetricsUpdate on_session_metrics_change_callback = std::bind(
&Engine::OnSessionMetricsDidChange, this, std::placeholders::_1);
// Session errors may occur on the GPU thread, but we must terminate ourselves
// on the platform thread.
fxl::Closure on_session_error_callback =
[runner = fsl::MessageLoop::GetCurrent()->task_runner(),
weak = weak_factory_.GetWeakPtr()]() {
runner->PostTask([weak]() {
if (weak) {
weak->Terminate();
}
});
};
// Grab the accessibilty context writer that can understand the semtics tree
// on the platform view.
fidl::InterfaceHandle<modular::ContextWriter> accessibility_context_writer;
application_context.ConnectToEnvironmentService(
accessibility_context_writer.NewRequest());
// Create the compositor context from the scenic pointer to create the
// rasterizer.
std::unique_ptr<flow::CompositorContext> compositor_context =
std::make_unique<flutter::CompositorContext>(
std::move(scenic), // scenic
thread_label_, // debug label
std::move(import_token), // import token
on_session_metrics_change_callback, // session metrics did change
on_session_error_callback, // session did encounter error
vsync_event_.get() // vsync event handle
);
// Setup the callback that will instantiate the platform view.
shell::Shell::CreateCallback<shell::PlatformView> on_create_platform_view =
fxl::MakeCopyable([debug_label = thread_label_, //
parent_environment_service_provider =
std::move(parent_environment_service_provider), //
view_manager = view_manager.Unbind(), //
view_owner = std::move(view_owner), //
accessibility_context_writer =
std::move(accessibility_context_writer), //
export_token = std::move(export_token), //
vsync_handle = vsync_event_.get() //
](shell::Shell& shell) mutable {
return std::make_unique<flutter::PlatformView>(
shell, // delegate
debug_label, // debug label
shell.GetTaskRunners(), // task runners
std::move(parent_environment_service_provider), // services
std::move(view_manager), // view manager
std::move(view_owner), // view owner
std::move(export_token), // export token
std::move(
accessibility_context_writer), // accessibility context writer
vsync_handle // vsync handle
);
});
// Setup the callback that will instantiate the rasterizer.
shell::Shell::CreateCallback<shell::Rasterizer> on_create_rasterizer =
fxl::MakeCopyable([compositor_context = std::move(compositor_context)](
shell::Shell& shell) mutable {
return std::make_unique<shell::Rasterizer>(
shell.GetTaskRunners(), // task runners
std::move(compositor_context) // compositor context
);
});
// Get the task runners from the managed threads. The current thread will be
// used as the "platform" thread.
blink::TaskRunners task_runners(
thread_label_, // Dart thread labels
fsl::MessageLoop::GetCurrent()->task_runner(), // platform
host_threads_[0].TaskRunner(), // gpu
host_threads_[1].TaskRunner(), // ui
host_threads_[2].TaskRunner() // io
);
UpdateNativeThreadLabelNames(thread_label_, task_runners);
settings_.verbose_logging = true;
settings_.root_isolate_create_callback =
std::bind(&Engine::OnMainIsolateStart, this);
settings_.root_isolate_shutdown_callback =
std::bind([weak = weak_factory_.GetWeakPtr(),
runner = task_runners.GetPlatformTaskRunner()]() {
runner->PostTask([weak = std::move(weak)] {
if (weak) {
weak->OnMainIsolateShutdown();
}
});
});
if (!isolate_snapshot) {
isolate_snapshot =
blink::DartVM::ForProcess(settings_)->GetIsolateSnapshot();
}
shell_ = shell::Shell::Create(
task_runners, // host task runners
settings_, // shell launch settings
std::move(isolate_snapshot), // isolate snapshot
on_create_platform_view, // platform view create callback
on_create_rasterizer // rasterizer create callback
);
if (!shell_) {
FXL_LOG(ERROR) << "Could not launch the shell with settings: "
<< settings_.ToString();
return;
}
// Shell has been created. Before we run the engine, setup the isolate
// configurator.
{
auto view_container =
static_cast<PlatformView*>(shell_->GetPlatformView().get())
->TakeViewContainer();
component::ApplicationEnvironmentPtr application_environment;
application_context.ConnectToEnvironmentService(
application_environment.NewRequest());
isolate_configurator_ = std::make_unique<IsolateConfigurator>(
std::move(fdio_ns), //
std::move(view_container), //
std::move(application_environment), //
std::move(outgoing_services_request) //
);
}
// This platform does not get a separate surface platform view creation
// notification. Fire one eagerly.
shell_->GetPlatformView()->NotifyCreated();
// Launch the engine in the appropriate configuration.
auto run_configuration =
shell::RunConfiguration::InferFromSettings(settings_);
auto on_run_failure = [weak = weak_factory_.GetWeakPtr(), //
runner =
fsl::MessageLoop::GetCurrent()->task_runner() //
]() {
// The engine could have been killed by the caller right after the
// constructor was called but before it could run on the UI thread.
if (weak) {
weak->Terminate();
}
};
shell_->GetTaskRunners().GetUITaskRunner()->PostTask(
fxl::MakeCopyable([engine = shell_->GetEngine(), //
run_configuration = std::move(run_configuration), //
on_run_failure //
]() mutable {
if (!engine) {
return;
}
if (!engine->Run(std::move(run_configuration))) {
on_run_failure();
}
}));
}
Engine::~Engine() {
shell_.reset();
for (const auto& thread : host_threads_) {
thread.TaskRunner()->PostTask(
[]() { fsl::MessageLoop::GetCurrent()->PostQuitTask(); });
}
}
std::pair<bool, uint32_t> Engine::GetEngineReturnCode() const {
std::pair<bool, uint32_t> code(false, 0);
if (!shell_) {
return code;
}
fxl::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
shell_->GetTaskRunners().GetUITaskRunner(),
[&latch, &code, engine = shell_->GetEngine()]() {
if (engine) {
code = engine->GetUIIsolateReturnCode();
}
latch.Signal();
});
latch.Wait();
return code;
}
void Engine::OnMainIsolateStart() {
if (!isolate_configurator_ ||
!isolate_configurator_->ConfigureCurrentIsolate(this)) {
FXL_LOG(ERROR) << "Could not configure some native embedder bindings for a "
"new root isolate.";
}
FXL_DLOG(INFO) << "Main isolate for engine '" << thread_label_
<< "' was started.";
}
void Engine::OnMainIsolateShutdown() {
FXL_DLOG(INFO) << "Main isolate for engine '" << thread_label_
<< "' shutting down.";
Terminate();
}
void Engine::Terminate() {
delegate_.OnEngineTerminate(this);
// Warning. Do not do anything after this point as the delegate may have
// collected this object.
}
void Engine::OnSessionMetricsDidChange(double device_pixel_ratio) {
if (!shell_) {
return;
}
shell_->GetTaskRunners().GetPlatformTaskRunner()->PostTask(
[platform_view = shell_->GetPlatformView(), device_pixel_ratio]() {
if (platform_view) {
reinterpret_cast<flutter::PlatformView*>(platform_view.get())
->UpdateViewportMetrics(device_pixel_ratio);
}
});
}
// |mozart::NativesDelegate|
void Engine::OfferServiceProvider(
fidl::InterfaceHandle<component::ServiceProvider> service_provider,
fidl::VectorPtr<fidl::StringPtr> services) {
if (!shell_) {
return;
}
shell_->GetTaskRunners().GetPlatformTaskRunner()->PostTask(
fxl::MakeCopyable([platform_view = shell_->GetPlatformView(), //
service_provider = std::move(service_provider), //
services = std::move(services) //
]() mutable {
if (platform_view) {
reinterpret_cast<flutter::PlatformView*>(platform_view.get())
->OfferServiceProvider(std::move(service_provider),
std::move(services));
}
}));
}
} // namespace flutter
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <views_v1/cpp/fidl.h>
#include <views_v1_token/cpp/fidl.h>
#include <zx/event.h>
#include "flutter/shell/common/shell.h"
#include "isolate_configurator.h"
#include "lib/app/cpp/application_context.h"
#include "lib/fsl/threading/thread.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/weak_ptr.h"
#include "lib/ui/flutter/sdk_ext/src/natives.h"
namespace flutter {
// Represents an instance of running Flutter engine along with the threads that
// host the same.
class Engine final : public mozart::NativesDelegate {
public:
class Delegate {
public:
virtual void OnEngineTerminate(const Engine* holder) = 0;
};
Engine(Delegate& delegate,
std::string thread_label,
component::ApplicationContext& application_context,
blink::Settings settings,
fxl::RefPtr<blink::DartSnapshot> isolate_snapshot,
fidl::InterfaceRequest<views_v1_token::ViewOwner> view_owner,
UniqueFDIONS fdio_ns,
fidl::InterfaceRequest<component::ServiceProvider>
outgoing_services_request);
~Engine();
// Returns the Dart return code for the root isolate if one is present. This
// call is thread safe and synchronous. This call must be made infrequently.
std::pair<bool, uint32_t> GetEngineReturnCode() const;
private:
Delegate& delegate_;
const std::string thread_label_;
blink::Settings settings_;
std::array<fsl::Thread, 3> host_threads_;
std::unique_ptr<IsolateConfigurator> isolate_configurator_;
std::unique_ptr<shell::Shell> shell_;
zx::event vsync_event_;
fxl::WeakPtrFactory<Engine> weak_factory_;
void OnMainIsolateStart();
void OnMainIsolateShutdown();
void Terminate();
void OnSessionMetricsDidChange(double device_pixel_ratio);
// |mozart::NativesDelegate|
void OfferServiceProvider(
fidl::InterfaceHandle<component::ServiceProvider> service_provider,
fidl::VectorPtr<fidl::StringPtr> services);
FXL_DISALLOW_COPY_AND_ASSIGN(Engine);
};
} // namespace flutter
/*
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fuchsia_font_manager.h"
#include <zx/vmar.h>
#include "lib/fsl/vmo/sized_vmo.h"
#include "lib/fxl/logging.h"
#include "txt/asset_font_style_set.h"
namespace txt {
namespace {
void UnmapMemory(const void* buffer, void* context) {
static_assert(sizeof(void*) == sizeof(uint64_t), "pointers aren't 64-bit");
const uint64_t size = reinterpret_cast<uint64_t>(context);
zx::vmar::root_self().unmap(reinterpret_cast<uintptr_t>(buffer), size);
}
sk_sp<SkData> MakeSkDataFromBuffer(const mem::Buffer& data) {
if (!fsl::SizedVmo::IsSizeValid(data.vmo, data.size) ||
data.size > std::numeric_limits<size_t>::max()) {
return nullptr;
}
uint64_t size = data.size;
uintptr_t buffer = 0;
zx_status_t status = zx::vmar::root_self().map(0, data.vmo, 0, size,
ZX_VM_FLAG_PERM_READ, &buffer);
if (status != ZX_OK)
return nullptr;
return SkData::MakeWithProc(reinterpret_cast<void*>(buffer), size,
UnmapMemory, reinterpret_cast<void*>(size));
}
fonts::FontSlant ToFontSlant(SkFontStyle::Slant slant) {
return (slant == SkFontStyle::kItalic_Slant) ? fonts::FontSlant::ITALIC
: fonts::FontSlant::UPRIGHT;
}
} // anonymous namespace
FuchsiaFontManager::FuchsiaFontManager(fonts::FontProviderSyncPtr provider)
: font_provider_(std::move(provider)) {}
FuchsiaFontManager::~FuchsiaFontManager() = default;
int FuchsiaFontManager::onCountFamilies() const {
FXL_DCHECK(false);
return 0;
}
void FuchsiaFontManager::onGetFamilyName(int index,
SkString* familyName) const {
FXL_DCHECK(false);
}
SkFontStyleSet* FuchsiaFontManager::onCreateStyleSet(int index) const {
FXL_DCHECK(false);
return nullptr;
}
SkFontStyleSet* FuchsiaFontManager::onMatchFamily(
const char family_name[]) const {
sk_sp<SkTypeface> typeface(onMatchFamilyStyle(family_name, SkFontStyle()));
if (!typeface)
return nullptr;
sk_sp<txt::AssetFontStyleSet> font_style_set(
sk_make_sp<txt::AssetFontStyleSet>());
font_style_set->registerTypeface(typeface);
return font_style_set.release();
}
SkTypeface* FuchsiaFontManager::onMatchFamilyStyle(
const char family_name[],
const SkFontStyle& style) const {
fonts::FontRequest request;
request.family = family_name;
request.weight = style.weight();
request.width = style.width();
request.slant = ToFontSlant(style.slant());
fonts::FontResponsePtr response;
if (!font_provider_->GetFont(std::move(request), &response)) {
FXL_DLOG(ERROR) << "Unable to contact the font provider. Did you run "
"Flutter in an environment that has a font manager?";
return nullptr;
}
sk_sp<SkData> data = MakeSkDataFromBuffer(response->data.buffer);
if (!data)
return nullptr;
sk_sp<SkTypeface> typeface =
SkFontMgr::RefDefault()->makeFromData(std::move(data));
return typeface.release();
}
SkTypeface* FuchsiaFontManager::onMatchFamilyStyleCharacter(
const char familyName[],
const SkFontStyle&,
const char* bcp47[],
int bcp47Count,
SkUnichar character) const {
return nullptr;
}
SkTypeface* FuchsiaFontManager::onMatchFaceStyle(const SkTypeface*,
const SkFontStyle&) const {
FXL_DCHECK(false);
return nullptr;
}
sk_sp<SkTypeface> FuchsiaFontManager::onMakeFromData(sk_sp<SkData>,
int ttcIndex) const {
FXL_DCHECK(false);
return nullptr;
}
sk_sp<SkTypeface> FuchsiaFontManager::onMakeFromStreamIndex(
std::unique_ptr<SkStreamAsset>,
int ttcIndex) const {
FXL_DCHECK(false);
return nullptr;
}
sk_sp<SkTypeface> FuchsiaFontManager::onMakeFromStreamArgs(
std::unique_ptr<SkStreamAsset>,
const SkFontArguments&) const {
FXL_DCHECK(false);
return nullptr;
}
sk_sp<SkTypeface> FuchsiaFontManager::onMakeFromFile(const char path[],
int ttcIndex) const {
FXL_DCHECK(false);
return nullptr;
}
sk_sp<SkTypeface> FuchsiaFontManager::onLegacyMakeTypeface(
const char familyName[],
SkFontStyle) const {
FXL_DCHECK(false);
return nullptr;
}
} // namespace txt
/*
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TXT_FUCHSIA_FONT_MANAGER_H_
#define TXT_FUCHSIA_FONT_MANAGER_H_
#include <fonts/cpp/fidl.h>
#include <memory>
#include "lib/fxl/macros.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/ports/SkFontMgr.h"
namespace txt {
class FuchsiaFontManager final : public SkFontMgr {
public:
FuchsiaFontManager(fonts::FontProviderSyncPtr provider);
~FuchsiaFontManager() override;
protected:
// |SkFontMgr|
int onCountFamilies() const override;
// |SkFontMgr|
void onGetFamilyName(int index, SkString* familyName) const override;
// |SkFontMgr|
SkFontStyleSet* onMatchFamily(const char familyName[]) const override;
// |SkFontMgr|
SkFontStyleSet* onCreateStyleSet(int index) const override;
// |SkFontMgr|
SkTypeface* onMatchFamilyStyle(const char familyName[],
const SkFontStyle&) const override;
// |SkFontMgr|
SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
const SkFontStyle&,
const char* bcp47[],
int bcp47Count,
SkUnichar character) const override;
// |SkFontMgr|
SkTypeface* onMatchFaceStyle(const SkTypeface*,
const SkFontStyle&) const override;
// |SkFontMgr|
sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override;
// |SkFontMgr|
sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
int ttcIndex) const override;
// |SkFontMgr|
sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
const SkFontArguments&) const override;
// |SkFontMgr|
sk_sp<SkTypeface> onMakeFromFile(const char path[],
int ttcIndex) const override;
// |SkFontMgr|
sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[],
SkFontStyle) const override;
FXL_DISALLOW_COPY_AND_ASSIGN(FuchsiaFontManager);
private:
mutable fonts::FontProviderSyncPtr font_provider_;
};
} // namespace txt
#endif // TXT_FUCHSIA_FONT_MANAGER_H_
// Copyright 2018 The Fuchsia 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 "isolate_configurator.h"
#include "dart-pkg/fuchsia/sdk_ext/fuchsia.h"
#include "dart-pkg/zircon/sdk_ext/handle.h"
#include "lib/tonic/converter/dart_converter.h"
#include "lib/tonic/dart_state.h"
#include "lib/tonic/logging/dart_error.h"
#include "lib/ui/flutter/sdk_ext/src/natives.h"
#include "third_party/dart/runtime/include/dart_api.h"
namespace flutter {
IsolateConfigurator::IsolateConfigurator(
UniqueFDIONS fdio_ns,
fidl::InterfaceHandle<views_v1::ViewContainer> view_container,
fidl::InterfaceHandle<component::ApplicationEnvironment>
application_environment,
fidl::InterfaceRequest<component::ServiceProvider>
outgoing_services_request)
: fdio_ns_(std::move(fdio_ns)),
view_container_(std::move(view_container)),
application_environment_(std::move(application_environment)),
outgoing_services_request_(std::move(outgoing_services_request)) {}
IsolateConfigurator::~IsolateConfigurator() = default;
bool IsolateConfigurator::ConfigureCurrentIsolate(
mozart::NativesDelegate* natives_delegate) {
if (used_) {
return false;
}
used_ = true;
BindFuchsia();
BindZircon();
BindDartIO();
BindScenic(natives_delegate);
// This is now owned by the Dart bindings. So relinquish our ownership of the
// handle.
(void)fdio_ns_.release();
return true;
}
void IsolateConfigurator::BindFuchsia() {
fuchsia::dart::Initialize(std::move(application_environment_),
std::move(outgoing_services_request_));
}
void IsolateConfigurator::BindZircon() {
// Tell dart:zircon about the FDIO namespace configured for this instance.
Dart_Handle zircon_lib = Dart_LookupLibrary(tonic::ToDart("dart:zircon"));
DART_CHECK_VALID(zircon_lib);
Dart_Handle namespace_type =
Dart_GetType(zircon_lib, tonic::ToDart("_Namespace"), 0, nullptr);
DART_CHECK_VALID(namespace_type);
DART_CHECK_VALID(
Dart_SetField(namespace_type, //
tonic::ToDart("_namespace"), //
tonic::ToDart(reinterpret_cast<intptr_t>(fdio_ns_.get()))));
}
void IsolateConfigurator::BindDartIO() {
// Grab the dart:io lib.
Dart_Handle io_lib = Dart_LookupLibrary(tonic::ToDart("dart:io"));
DART_CHECK_VALID(io_lib);
// Disable dart:io exit()
Dart_Handle embedder_config_type =
Dart_GetType(io_lib, tonic::ToDart("_EmbedderConfig"), 0, nullptr);
DART_CHECK_VALID(embedder_config_type);
DART_CHECK_VALID(Dart_SetField(embedder_config_type,
tonic::ToDart("_mayExit"), Dart_False()));
// Tell dart:io about the FDIO namespace configured for this instance.
Dart_Handle namespace_type =
Dart_GetType(io_lib, tonic::ToDart("_Namespace"), 0, nullptr);
DART_CHECK_VALID(namespace_type);
Dart_Handle namespace_args[] = {
Dart_NewInteger(reinterpret_cast<intptr_t>(fdio_ns_.get())), //
};
DART_CHECK_VALID(namespace_args[0]);
DART_CHECK_VALID(Dart_Invoke(namespace_type, tonic::ToDart("_setupNamespace"),
1, namespace_args));
}
void IsolateConfigurator::BindScenic(
mozart::NativesDelegate* natives_delegate) {
Dart_Handle mozart_internal =
Dart_LookupLibrary(tonic::ToDart("dart:mozart.internal"));
DART_CHECK_VALID(mozart_internal);
DART_CHECK_VALID(Dart_SetNativeResolver(mozart_internal, //
mozart::NativeLookup, //
mozart::NativeSymbol) //
);
DART_CHECK_VALID(Dart_SetField(
mozart_internal, //
tonic::ToDart("_context"), //
tonic::DartConverter<uint64_t>::ToDart(reinterpret_cast<intptr_t>(
static_cast<mozart::NativesDelegate*>(natives_delegate)))));
DART_CHECK_VALID(
Dart_SetField(mozart_internal, //
tonic::ToDart("_viewContainer"), //
tonic::ToDart(zircon::dart::Handle::Create(
view_container_.TakeChannel().release()))));
}
} // namespace flutter
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <component/cpp/fidl.h>
#include <ui/cpp/fidl.h>
#include <views_v1/cpp/fidl.h>
#include "lib/fxl/macros.h"
#include "lib/ui/flutter/sdk_ext/src/natives.h"
#include "unique_fdio_ns.h"
namespace flutter {
// Contains all the information necessary to configure a new root isolate. This
// is a single use item. The lifetime of this object must extend past that of
// the root isolate.
class IsolateConfigurator final {
public:
IsolateConfigurator(
UniqueFDIONS fdio_ns,
fidl::InterfaceHandle<views_v1::ViewContainer> view_container,
fidl::InterfaceHandle<component::ApplicationEnvironment>
application_environment,
fidl::InterfaceRequest<component::ServiceProvider>
outgoing_services_request);
~IsolateConfigurator();
// Can be used only once and only on the UI thread with the newly created
// isolate already current.
bool ConfigureCurrentIsolate(mozart::NativesDelegate* natives_delegate);
private:
bool used_ = false;
UniqueFDIONS fdio_ns_;
fidl::InterfaceHandle<views_v1::ViewContainer> view_container_;
fidl::InterfaceHandle<component::ApplicationEnvironment>
application_environment_;
fidl::InterfaceRequest<component::ServiceProvider> outgoing_services_request_;
void BindFuchsia();
void BindZircon();
void BindDartIO();
void BindScenic(mozart::NativesDelegate* natives_delegate);
FXL_DISALLOW_COPY_AND_ASSIGN(IsolateConfigurator);
};
} // namespace flutter
// Copyright 2018 The Fuchsia 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 <trace-provider/provider.h>
#include <cstdlib>
#include "application_runner.h"
#include "lib/fsl/tasks/message_loop.h"
int main(int argc, char const* argv[]) {
fsl::MessageLoop loop;
trace::TraceProvider provider(loop.async());
FXL_DCHECK(provider.is_valid()) << "Trace provider must be valid.";
FXL_DLOG(INFO) << "Flutter application services initialized.";
flutter::ApplicationRunner runner;
loop.Run();
FXL_DLOG(INFO) << "Flutter application services terminated.";
return EXIT_SUCCESS;
}
{
"features": [
"root-ssl-certificates",
"system-temp",
"vulkan"
]
}
此差异已折叠。
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <map>
#include <set>
#include <input/cpp/fidl.h>
#include <modular/cpp/fidl.h>
#include <views_v1/cpp/fidl.h>
#include <views_v1_token/cpp/fidl.h>
#include "accessibility_bridge.h"
#include "flutter/lib/ui/window/viewport_metrics.h"
#include "flutter/shell/common/platform_view.h"
#include "lib/fidl/cpp/binding.h"
#include "lib/fxl/macros.h"
#include "surface.h"
namespace flutter {
// The per engine component residing on the platform thread is responsible for
// all platform specific integrations.
class PlatformView final : public shell::PlatformView,
public views_v1::ViewListener,
public input::InputMethodEditorClient,
public input::InputListener {
public:
PlatformView(PlatformView::Delegate& delegate,
std::string debug_label,
blink::TaskRunners task_runners,
fidl::InterfaceHandle<component::ServiceProvider>
parent_environment_service_provider,
fidl::InterfaceHandle<views_v1::ViewManager> view_manager,
fidl::InterfaceRequest<views_v1_token::ViewOwner> view_owner,
zx::eventpair export_token,
fidl::InterfaceHandle<modular::ContextWriter>
accessibility_context_writer,
zx_handle_t vsync_event_handle);
~PlatformView();
void UpdateViewportMetrics(double pixel_ratio);
fidl::InterfaceHandle<views_v1::ViewContainer> TakeViewContainer();
void OfferServiceProvider(
fidl::InterfaceHandle<component::ServiceProvider> service_provider,
fidl::VectorPtr<fidl::StringPtr> services);
private:
const std::string debug_label_;
views_v1::ViewManagerPtr view_manager_;
views_v1::ViewPtr view_;
fidl::InterfaceHandle<views_v1::ViewContainer> view_container_;
component::ServiceProviderPtr service_provider_;
fidl::Binding<views_v1::ViewListener> view_listener_;
input::InputConnectionPtr input_connection_;
fidl::Binding<input::InputListener> input_listener_;
int current_text_input_client_ = 0;
fidl::Binding<input::InputMethodEditorClient> ime_client_;
input::InputMethodEditorPtr ime_;
component::ServiceProviderPtr parent_environment_service_provider_;
modular::ClipboardPtr clipboard_;
AccessibilityBridge accessibility_bridge_;
std::unique_ptr<Surface> surface_;
blink::LogicalMetrics metrics_;
std::set<int> down_pointers_;
std::map<
std::string /* channel */,
std::function<void(
fxl::RefPtr<blink::PlatformMessage> /* message */)> /* handler */>
platform_message_handlers_;
zx_handle_t vsync_event_handle_ = 0;
void RegisterPlatformMessageHandlers();
void UpdateViewportMetrics(const views_v1::ViewLayout& layout);
void FlushViewportMetrics();
// |views_v1::ViewListener|
void OnPropertiesChanged(views_v1::ViewProperties properties,
OnPropertiesChangedCallback callback) override;
// |input::InputMethodEditorClient|
void DidUpdateState(input::TextInputState state,
std::unique_ptr<input::InputEvent> event) override;
// |input::InputMethodEditorClient|
void OnAction(input::InputMethodAction action) override;
// |input::InputListener|
void OnEvent(input::InputEvent event, OnEventCallback callback) override;
bool OnHandlePointerEvent(const input::PointerEvent& pointer);
bool OnHandleKeyboardEvent(const input::KeyboardEvent& keyboard);
bool OnHandleFocusEvent(const input::FocusEvent& focus);
// |shell::PlatformView|
std::unique_ptr<shell::VsyncWaiter> CreateVSyncWaiter() override;
// |shell::PlatformView|
std::unique_ptr<shell::Surface> CreateRenderingSurface() override;
// |shell::PlatformView|
void HandlePlatformMessage(
fxl::RefPtr<blink::PlatformMessage> message) override;
// |shell::PlatformView|
void UpdateSemantics(blink::SemanticsNodeUpdates update) override;
// Channel handler for kFlutterPlatformChannel
void HandleFlutterPlatformChannelPlatformMessage(
fxl::RefPtr<blink::PlatformMessage> message);
// Channel handler for kTextInputChannel
void HandleFlutterTextInputChannelPlatformMessage(
fxl::RefPtr<blink::PlatformMessage> message);
FXL_DISALLOW_COPY_AND_ASSIGN(PlatformView);
};
} // namespace flutter
// Copyright 2017 The Chromium 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 "session_connection.h"
#include "lib/fidl/cpp/optional.h"
#include "lib/ui/scenic/fidl_helpers.h"
#include "vsync_waiter.h"
namespace flutter {
SessionConnection::SessionConnection(
fidl::InterfaceHandle<ui::Scenic> scenic_handle,
std::string debug_label,
zx::eventpair import_token,
OnMetricsUpdate session_metrics_did_change_callback,
fxl::Closure session_error_callback,
zx_handle_t vsync_event_handle)
: debug_label_(std::move(debug_label)),
scenic_(scenic_handle.Bind()),
session_(scenic_.get()),
root_node_(&session_),
surface_producer_(std::make_unique<VulkanSurfaceProducer>(&session_)),
scene_update_context_(&session_, surface_producer_.get()),
metrics_changed_callback_(std::move(session_metrics_did_change_callback)),
vsync_event_handle_(vsync_event_handle) {
session_.set_error_handler(std::move(session_error_callback));
session_.set_event_handler(std::bind(&SessionConnection::OnSessionEvents,
this, std::placeholders::_1));
root_node_.Bind(std::move(import_token));
root_node_.SetEventMask(gfx::kMetricsEventMask);
// Signal is initially high inidicating availability of the session.
ToggleSignal(vsync_event_handle_, true);
PresentSession();
}
SessionConnection::~SessionConnection() = default;
void SessionConnection::OnSessionEvents(fidl::VectorPtr<ui::Event> events) {
using Type = gfx::Event::Tag;
for (auto& raw_event : *events) {
if (!raw_event.is_gfx()) {
continue;
}
auto& event = raw_event.gfx();
switch (event.Which()) {
case Type::kMetrics: {
if (event.metrics().node_id == root_node_.id()) {
auto& metrics = event.metrics().metrics;
double device_pixel_ratio = metrics.scale_x;
scene_update_context_.set_metrics(
fidl::MakeOptional(std::move(metrics)));
if (metrics_changed_callback_) {
metrics_changed_callback_(device_pixel_ratio);
}
}
} break;
default:
break;
}
}
}
void SessionConnection::Present(flow::CompositorContext::ScopedFrame& frame) {
// Flush all session ops. Paint tasks have not yet executed but those are
// fenced. The compositor can start processing ops while we finalize paint
// tasks.
PresentSession();
// Execute paint tasks and signal fences.
auto surfaces_to_submit = scene_update_context_.ExecutePaintTasks(frame);
// Tell the surface producer that a present has occurred so it can perform
// book-keeping on buffer caches.
surface_producer_->OnSurfacesPresented(std::move(surfaces_to_submit));
// Prepare for the next frame. These ops won't be processed till the next
// present.
EnqueueClearOps();
}
void SessionConnection::EnqueueClearOps() {
// We are going to be sending down a fresh node hierarchy every frame. So just
// enqueue a detach op on the imported root node.
session_.Enqueue(scenic_lib::NewDetachChildrenCommand(root_node_.id()));
}
void SessionConnection::PresentSession() {
ToggleSignal(vsync_event_handle_, false);
session_.Present(0, // presentation_time. (placeholder).
[handle = vsync_event_handle_](auto) {
ToggleSignal(handle, true);
} // callback
);
}
void SessionConnection::ToggleSignal(zx_handle_t handle, bool set) {
const auto signal = flutter::VsyncWaiter::SessionPresentSignal;
auto status = zx_object_signal(handle, // handle
set ? 0 : signal, // clear mask
set ? signal : 0 // set mask
);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Could not toggle vsync signal: " << set;
}
}
} // namespace flutter
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <zx/eventpair.h>
#include "flutter/flow/compositor_context.h"
#include "flutter/flow/scene_update_context.h"
#include "lib/fidl/cpp/interface_handle.h"
#include "lib/fxl/functional/closure.h"
#include "lib/fxl/macros.h"
#include "lib/ui/scenic/client/resources.h"
#include "lib/ui/scenic/client/session.h"
#include "vulkan_surface_producer.h"
namespace flutter {
using OnMetricsUpdate = std::function<void(double /* device pixel ratio */)>;
// The component residing on the GPU thread that is responsible for
// maintaining the Scenic session connection and presenting node updates.
class SessionConnection final {
public:
SessionConnection(fidl::InterfaceHandle<ui::Scenic> scenic,
std::string debug_label,
zx::eventpair import_token,
OnMetricsUpdate session_metrics_did_change_callback,
fxl::Closure session_error_callback,
zx_handle_t vsync_event_handle);
~SessionConnection();
bool has_metrics() const { return scene_update_context_.has_metrics(); }
const gfx::MetricsPtr& metrics() const {
return scene_update_context_.metrics();
}
flow::SceneUpdateContext& scene_update_context() {
return scene_update_context_;
}
scenic_lib::ImportNode& root_node() { return root_node_; }
void Present(flow::CompositorContext::ScopedFrame& frame);
private:
const std::string debug_label_;
ui::ScenicPtr scenic_;
scenic_lib::Session session_;
scenic_lib::ImportNode root_node_;
std::unique_ptr<VulkanSurfaceProducer> surface_producer_;
flow::SceneUpdateContext scene_update_context_;
OnMetricsUpdate metrics_changed_callback_;
zx_handle_t vsync_event_handle_;
void OnSessionEvents(fidl::VectorPtr<ui::Event> events);
void EnqueueClearOps();
void PresentSession();
static void ToggleSignal(zx_handle_t handle, bool raise);
FXL_DISALLOW_COPY_AND_ASSIGN(SessionConnection);
};
} // namespace flutter
// Copyright 2018 The Fuchsia 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 "surface.h"
#include <fcntl.h>
#include <fdio/watcher.h>
#include <unistd.h>
#include <zircon/device/vfs.h>
#include "lib/fxl/files/unique_fd.h"
namespace flutter {
Surface::Surface(std::string debug_label)
: debug_label_(std::move(debug_label)) {}
Surface::~Surface() = default;
// |shell::Surface|
bool Surface::IsValid() {
return valid_;
}
// |shell::Surface|
std::unique_ptr<shell::SurfaceFrame> Surface::AcquireFrame(
const SkISize& size) {
return std::make_unique<shell::SurfaceFrame>(
nullptr, [](const shell::SurfaceFrame& surface_frame, SkCanvas* canvas) {
return true;
});
}
// |shell::Surface|
GrContext* Surface::GetContext() {
return nullptr;
}
static zx_status_t DriverWatcher(int dirfd,
int event,
const char* fn,
void* cookie) {
if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) {
return ZX_ERR_STOP;
}
return ZX_OK;
}
bool Surface::CanConnectToDisplay() {
constexpr char kGpuDriverClass[] = "/dev/class/gpu";
fxl::UniqueFD fd(open(kGpuDriverClass, O_DIRECTORY | O_RDONLY));
if (fd.get() < 0) {
FXL_DLOG(ERROR) << "Failed to open " << kGpuDriverClass;
return false;
}
zx_status_t status = fdio_watch_directory(
fd.get(), DriverWatcher, zx_deadline_after(ZX_SEC(5)), nullptr);
return status == ZX_ERR_STOP;
}
} // namespace flutter
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include "compositor_context.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/shell/common/surface.h"
#include "lib/fxl/macros.h"
namespace flutter {
// The interface between the Flutter rasterizer and the underlying platform. May
// be constructed on any thread but will be used by the engine only on the GPU
// thread.
class Surface final : public shell::Surface {
public:
Surface(std::string debug_label);
~Surface() override;
private:
const bool valid_ = CanConnectToDisplay();
const std::string debug_label_;
// |shell::Surface|
bool IsValid() override;
// |shell::Surface|
std::unique_ptr<shell::SurfaceFrame> AcquireFrame(
const SkISize& size) override;
// |shell::Surface|
GrContext* GetContext() override;
static bool CanConnectToDisplay();
FXL_DISALLOW_COPY_AND_ASSIGN(Surface);
};
} // namespace flutter
// Copyright 2018 The Fuchsia 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 "task_observers.h"
#include <map>
#include "lib/fsl/tasks/message_loop.h"
namespace flutter {
thread_local std::map<intptr_t, fxl::Closure> tTaskObservers;
static void ExecuteAfterTaskObservers() {
for (const auto& callback : tTaskObservers) {
callback.second();
}
}
void CurrentMessageLoopAddAfterTaskObserver(intptr_t key,
fxl::Closure observer) {
if (!observer) {
return;
}
if (tTaskObservers.size() == 0) {
fsl::MessageLoop::GetCurrent()->SetAfterTaskCallback(
std::bind(&ExecuteAfterTaskObservers));
}
tTaskObservers[key] = observer;
}
void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key) {
tTaskObservers.erase(key);
if (tTaskObservers.size() == 0) {
fsl::MessageLoop::GetCurrent()->ClearAfterTaskCallback();
}
}
} // namespace flutter
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include "lib/fxl/functional/closure.h"
namespace flutter {
void CurrentMessageLoopAddAfterTaskObserver(intptr_t key,
fxl::Closure observer);
void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key);
} // namespace flutter
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include "fdio/namespace.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/memory/unique_object.h"
namespace flutter {
struct UniqueFDIONSTraits {
static fdio_ns_t* InvalidValue() { return nullptr; }
static bool IsValid(fdio_ns_t* ns) { return ns != InvalidValue(); }
static void Free(fdio_ns_t* ns) {
auto status = fdio_ns_destroy(ns);
FXL_DCHECK(status == ZX_OK);
}
};
using UniqueFDIONS = fxl::UniqueObject<fdio_ns_t*, UniqueFDIONSTraits>;
inline UniqueFDIONS UniqueFDIONSCreate() {
fdio_ns_t* ns = nullptr;
if (fdio_ns_create(&ns) == ZX_OK) {
return UniqueFDIONS{ns};
}
return UniqueFDIONS{nullptr};
}
} // namespace flutter
// Copyright 2018 The Fuchsia 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 "third_party/flutter/content_handler/vsync_waiter.h"
#include "lib/fsl/tasks/message_loop.h"
namespace flutter {
VsyncWaiter::VsyncWaiter(std::string debug_label,
zx_handle_t session_present_handle,
blink::TaskRunners task_runners)
: shell::VsyncWaiter(task_runners),
debug_label_(std::move(debug_label)),
session_wait_(session_present_handle, SessionPresentSignal),
phase_(fxl::TimePoint::Now()),
weak_factory_(this) {
auto wait_handler = [&](async_t* async, //
async::Wait* wait, //
zx_status_t status, //
const zx_packet_signal_t* signal //
) {
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Vsync wait failed.";
return;
}
wait->Cancel();
FireCallbackNow();
};
session_wait_.set_handler(wait_handler);
}
VsyncWaiter::~VsyncWaiter() {
session_wait_.Cancel();
}
static constexpr fxl::TimeDelta kFrameInterval =
fxl::TimeDelta::FromSecondsF(1.0 / 60.0);
static fxl::TimePoint SnapToNextPhase(fxl::TimePoint value,
fxl::TimePoint phase,
fxl::TimeDelta interval) {
fxl::TimeDelta offset = (phase - value) % interval;
if (offset != fxl::TimeDelta::Zero()) {
offset = offset + interval;
}
return value + offset;
}
void VsyncWaiter::AwaitVSync() {
fxl::TimePoint now = fxl::TimePoint::Now();
fxl::TimePoint next = SnapToNextPhase(now, phase_, kFrameInterval);
task_runners_.GetUITaskRunner()->PostDelayedTask(
[self = weak_factory_.GetWeakPtr()] {
if (self) {
self->FireCallbackWhenSessionAvailable();
}
},
next - now);
}
void VsyncWaiter::FireCallbackWhenSessionAvailable() {
FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (session_wait_.Begin(fsl::MessageLoop::GetCurrent()->async()) != ZX_OK) {
FXL_LOG(ERROR) << "Could not begin wait for Vsync.";
}
}
void VsyncWaiter::FireCallbackNow() {
FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
auto now = fxl::TimePoint::Now();
// We don't know the display refresh rate on this platform. Since the target
// time is advisory, assume kFrameInterval.
auto next = now + kFrameInterval;
phase_ = now;
FireCallback(now, next);
}
} // namespace flutter
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <lib/async/cpp/wait.h>
#include "flutter/shell/common/vsync_waiter.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/weak_ptr.h"
namespace flutter {
class VsyncWaiter final : public shell::VsyncWaiter {
public:
static constexpr zx_signals_t SessionPresentSignal = ZX_EVENT_SIGNALED;
VsyncWaiter(std::string debug_label,
zx_handle_t session_present_handle,
blink::TaskRunners task_runners);
~VsyncWaiter() override;
private:
const std::string debug_label_;
async::Wait session_wait_;
fxl::TimePoint phase_;
fxl::WeakPtrFactory<VsyncWaiter> weak_factory_;
// |shell::VsyncWaiter|
void AwaitVSync() override;
void FireCallbackWhenSessionAvailable();
void FireCallbackNow();
FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiter);
};
} // namespace flutter
// Copyright 2017 The Fuchsia 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 "vulkan_surface.h"
#include <lib/async/default.h>
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
namespace flutter {
VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider,
sk_sp<GrContext> context,
sk_sp<GrVkBackendContext> backend_context,
scenic_lib::Session* session,
const SkISize& size)
: vulkan_provider_(vulkan_provider),
backend_context_(std::move(backend_context)),
session_(session),
wait_(this) {
FXL_DCHECK(session_);
zx::vmo exported_vmo;
if (!AllocateDeviceMemory(std::move(context), size, exported_vmo)) {
FXL_DLOG(INFO) << "Could not allocate device memory.";
return;
}
if (!CreateFences()) {
FXL_DLOG(INFO) << "Could not create signal fences.";
return;
}
if (!PushSessionImageSetupOps(session, std::move(exported_vmo))) {
FXL_DLOG(INFO) << "Could not push session image setup ops.";
return;
}
wait_.set_object(release_event_.get());
wait_.set_trigger(ZX_EVENT_SIGNALED);
Reset();
valid_ = true;
}
VulkanSurface::~VulkanSurface() {
wait_.Cancel();
wait_.set_object(ZX_HANDLE_INVALID);
}
bool VulkanSurface::IsValid() const {
return valid_;
}
SkISize VulkanSurface::GetSize() const {
if (!valid_) {
return SkISize::Make(0, 0);
}
return SkISize::Make(sk_surface_->width(), sk_surface_->height());
}
vulkan::VulkanHandle<VkSemaphore> VulkanSurface::SemaphoreFromEvent(
const zx::event& event) const {
VkResult result;
VkSemaphore semaphore;
zx::event semaphore_event;
zx_status_t status = event.duplicate(ZX_RIGHT_SAME_RIGHTS, &semaphore_event);
if (status != ZX_OK) {
FXL_DLOG(ERROR) << "failed to duplicate semaphore event";
return vulkan::VulkanHandle<VkSemaphore>();
}
VkSemaphoreCreateInfo create_info = {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
};
result = VK_CALL_LOG_ERROR(vulkan_provider_.vk().CreateSemaphore(
vulkan_provider_.vk_device(), &create_info, nullptr, &semaphore));
if (result != VK_SUCCESS) {
return vulkan::VulkanHandle<VkSemaphore>();
}
VkImportSemaphoreFuchsiaHandleInfoKHR import_info = {
.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FUCHSIA_HANDLE_INFO_KHR,
.pNext = nullptr,
.semaphore = semaphore,
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FUCHSIA_FENCE_BIT_KHR,
.handle = static_cast<uint32_t>(semaphore_event.release())};
result =
VK_CALL_LOG_ERROR(vulkan_provider_.vk().ImportSemaphoreFuchsiaHandleKHR(
vulkan_provider_.vk_device(), &import_info));
if (result != VK_SUCCESS) {
return vulkan::VulkanHandle<VkSemaphore>();
}
return vulkan::VulkanHandle<VkSemaphore>(
semaphore, [&vulkan_provider = vulkan_provider_](VkSemaphore semaphore) {
vulkan_provider.vk().DestroySemaphore(vulkan_provider.vk_device(),
semaphore, nullptr);
});
}
bool VulkanSurface::CreateFences() {
if (zx::event::create(0, &acquire_event_) != ZX_OK) {
return false;
}
acquire_semaphore_ = SemaphoreFromEvent(acquire_event_);
if (!acquire_semaphore_) {
FXL_DLOG(ERROR) << "failed to create acquire semaphore";
return false;
}
if (zx::event::create(0, &release_event_) != ZX_OK) {
return false;
}
command_buffer_fence_ = vulkan_provider_.CreateFence();
return true;
}
bool VulkanSurface::AllocateDeviceMemory(sk_sp<GrContext> context,
const SkISize& size,
zx::vmo& exported_vmo) {
if (size.isEmpty()) {
return false;
}
if (backend_context_ == nullptr) {
return false;
}
const SkColorType color_type = kBGRA_8888_SkColorType;
// Create the image.
const VkImageCreateInfo image_create_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
.imageType = VK_IMAGE_TYPE_2D,
.format = VK_FORMAT_B8G8R8A8_UNORM,
.extent = VkExtent3D{static_cast<uint32_t>(size.width()),
static_cast<uint32_t>(size.height()), 1},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
};
{
VkImage vk_image = VK_NULL_HANDLE;
if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().CreateImage(
vulkan_provider_.vk_device(), &image_create_info, nullptr,
&vk_image)) != VK_SUCCESS) {
return false;
}
vk_image_ = {vk_image,
[& vulkan_provider = vulkan_provider_](VkImage image) {
vulkan_provider.vk().DestroyImage(
vulkan_provider.vk_device(), image, NULL);
}};
}
// Create the memory.
VkMemoryRequirements memory_reqs;
vulkan_provider_.vk().GetImageMemoryRequirements(vulkan_provider_.vk_device(),
vk_image_, &memory_reqs);
uint32_t memory_type = 0;
for (; memory_type < 32; memory_type++) {
if ((memory_reqs.memoryTypeBits & (1 << memory_type))) {
break;
}
}
VkExportMemoryAllocateInfoKHR export_allocate_info = {
.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
.pNext = nullptr,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_FUCHSIA_VMO_BIT_KHR};
const VkMemoryAllocateInfo alloc_info = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = &export_allocate_info,
.allocationSize = memory_reqs.size,
.memoryTypeIndex = memory_type,
};
{
VkDeviceMemory vk_memory = VK_NULL_HANDLE;
if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().AllocateMemory(
vulkan_provider_.vk_device(), &alloc_info, NULL, &vk_memory)) !=
VK_SUCCESS) {
return false;
}
vk_memory_ = {vk_memory, [& vulkan_provider =
vulkan_provider_](VkDeviceMemory memory) {
vulkan_provider.vk().FreeMemory(vulkan_provider.vk_device(),
memory, NULL);
}};
}
// Bind image memory.
if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().BindImageMemory(
vulkan_provider_.vk_device(), vk_image_, vk_memory_, 0)) !=
VK_SUCCESS) {
return false;
}
{
// Acquire the VMO for the device memory.
uint32_t vmo_handle = 0;
VkMemoryGetFuchsiaHandleInfoKHR get_handle_info = {
VK_STRUCTURE_TYPE_MEMORY_GET_FUCHSIA_HANDLE_INFO_KHR, nullptr,
vk_memory_, VK_EXTERNAL_MEMORY_HANDLE_TYPE_FUCHSIA_VMO_BIT_KHR};
if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().GetMemoryFuchsiaHandleKHR(
vulkan_provider_.vk_device(), &get_handle_info, &vmo_handle)) !=
VK_SUCCESS) {
return false;
}
exported_vmo.reset(static_cast<zx_handle_t>(vmo_handle));
}
// Assert that the VMO size was sufficient.
size_t vmo_size = 0;
if (exported_vmo.get_size(&vmo_size) != ZX_OK ||
vmo_size < memory_reqs.size) {
return false;
}
return SetupSkiaSurface(std::move(context), size, color_type,
image_create_info, memory_reqs);
}
bool VulkanSurface::SetupSkiaSurface(sk_sp<GrContext> context,
const SkISize& size,
SkColorType color_type,
const VkImageCreateInfo& image_create_info,
const VkMemoryRequirements& memory_reqs) {
if (context == nullptr) {
return false;
}
const GrVkImageInfo image_info = {
vk_image_, // image
{vk_memory_, 0, memory_reqs.size, 0}, // alloc
image_create_info.tiling, // tiling
image_create_info.initialLayout, // layout
image_create_info.format, // format
image_create_info.mipLevels, // level count
};
GrBackendRenderTarget sk_render_target(size.width(), size.height(), 0,
image_info);
SkSurfaceProps sk_surface_props(
SkSurfaceProps::InitType::kLegacyFontHost_InitType);
auto sk_surface =
SkSurface::MakeFromBackendRenderTarget(context.get(), //
sk_render_target, //
kTopLeft_GrSurfaceOrigin, //
color_type, //
nullptr, //
&sk_surface_props //
);
if (!sk_surface || sk_surface->getCanvas() == nullptr) {
return false;
}
sk_surface_ = std::move(sk_surface);
return true;
}
bool VulkanSurface::PushSessionImageSetupOps(scenic_lib::Session* session,
zx::vmo exported_vmo) {
if (sk_surface_ == nullptr) {
return false;
}
scenic_lib::Memory memory(session, std::move(exported_vmo),
images::MemoryType::VK_DEVICE_MEMORY);
images::ImageInfo image_info;
image_info.width = sk_surface_->width();
image_info.height = sk_surface_->height();
image_info.stride = 4 * sk_surface_->width();
image_info.pixel_format = images::PixelFormat::BGRA_8;
image_info.color_space = images::ColorSpace::SRGB;
image_info.tiling = images::Tiling::LINEAR;
session_image_ = std::make_unique<scenic_lib::Image>(
memory, 0 /* memory offset */, std::move(image_info));
return session_image_ != nullptr;
}
scenic_lib::Image* VulkanSurface::GetImage() {
if (!valid_) {
return 0;
}
return session_image_.get();
}
sk_sp<SkSurface> VulkanSurface::GetSkiaSurface() const {
return valid_ ? sk_surface_ : nullptr;
}
size_t VulkanSurface::AdvanceAndGetAge() {
age_++;
return age_;
}
bool VulkanSurface::FlushSessionAcquireAndReleaseEvents() {
zx::event acquire, release;
if (acquire_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &acquire) != ZX_OK ||
release_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &release) != ZX_OK) {
return false;
}
session_->EnqueueAcquireFence(std::move(acquire));
session_->EnqueueReleaseFence(std::move(release));
age_ = 0;
return true;
}
void VulkanSurface::SignalWritesFinished(
std::function<void(void)> on_writes_committed) {
FXL_DCHECK(on_writes_committed);
if (!valid_) {
on_writes_committed();
return;
}
FXL_CHECK(pending_on_writes_committed_ == nullptr)
<< "Attempted to signal a write on the surface when the previous write "
"has not yet been acknowledged by the compositor.";
pending_on_writes_committed_ = on_writes_committed;
}
void VulkanSurface::Reset() {
if (acquire_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK ||
release_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK) {
valid_ = false;
FXL_DLOG(ERROR)
<< "Could not reset fences. The surface is no longer valid.";
}
VkFence fence = command_buffer_fence_;
if (command_buffer_) {
VK_CALL_LOG_ERROR(vulkan_provider_.vk().WaitForFences(
vulkan_provider_.vk_device(), 1, &fence, VK_TRUE, UINT64_MAX));
command_buffer_.reset();
}
VK_CALL_LOG_ERROR(vulkan_provider_.vk().ResetFences(
vulkan_provider_.vk_device(), 1, &fence));
// Need to make a new acquire semaphore every frame or else validation layers
// get confused about why no one is waiting on it in this VkInstance
acquire_semaphore_.Reset();
acquire_semaphore_ = SemaphoreFromEvent(acquire_event_);
if (!acquire_semaphore_) {
FXL_DLOG(ERROR) << "failed to create acquire semaphore";
}
wait_.Begin(async_get_default());
// It is safe for the caller to collect the surface in the callback.
auto callback = pending_on_writes_committed_;
pending_on_writes_committed_ = nullptr;
if (callback) {
callback();
}
}
void VulkanSurface::OnHandleReady(async_t* async,
async::WaitBase* wait,
zx_status_t status,
const zx_packet_signal_t* signal) {
if (status != ZX_OK)
return;
FXL_DCHECK(signal->observed & ZX_EVENT_SIGNALED);
Reset();
}
} // namespace flutter
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <lib/async/cpp/wait.h>
#include <zx/event.h>
#include <zx/vmo.h>
#include <memory>
#include "flutter/flow/scene_update_context.h"
#include "flutter/vulkan/vulkan_command_buffer.h"
#include "flutter/vulkan/vulkan_handle.h"
#include "flutter/vulkan/vulkan_proc_table.h"
#include "flutter/vulkan/vulkan_provider.h"
#include "lib/fxl/macros.h"
#include "lib/ui/scenic/client/resources.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
namespace flutter {
class VulkanSurface final
: public flow::SceneUpdateContext::SurfaceProducerSurface {
public:
VulkanSurface(vulkan::VulkanProvider& vulkan_provider,
sk_sp<GrContext> context,
sk_sp<GrVkBackendContext> backend_context,
scenic_lib::Session* session,
const SkISize& size);
~VulkanSurface() override;
// |flow::SceneUpdateContext::SurfaceProducerSurface|
size_t AdvanceAndGetAge() override;
// |flow::SceneUpdateContext::SurfaceProducerSurface|
bool FlushSessionAcquireAndReleaseEvents() override;
// |flow::SceneUpdateContext::SurfaceProducerSurface|
bool IsValid() const override;
// |flow::SceneUpdateContext::SurfaceProducerSurface|
SkISize GetSize() const override;
// Note: It is safe for the caller to collect the surface in the
// |on_writes_committed| callback.
void SignalWritesFinished(
std::function<void(void)> on_writes_committed) override;
// |flow::SceneUpdateContext::SurfaceProducerSurface|
scenic_lib::Image* GetImage() override;
// |flow::SceneUpdateContext::SurfaceProducerSurface|
sk_sp<SkSurface> GetSkiaSurface() const override;
const vulkan::VulkanHandle<VkImage>& GetVkImage() { return vk_image_; }
const vulkan::VulkanHandle<VkSemaphore>& GetAcquireVkSemaphore() {
return acquire_semaphore_;
}
vulkan::VulkanCommandBuffer* GetCommandBuffer(
const vulkan::VulkanHandle<VkCommandPool>& pool) {
if (!command_buffer_)
command_buffer_ = std::make_unique<vulkan::VulkanCommandBuffer>(
vulkan_provider_.vk(), vulkan_provider_.vk_device(), pool);
return command_buffer_.get();
}
const vulkan::VulkanHandle<VkFence>& GetCommandBufferFence() {
return command_buffer_fence_;
}
private:
void OnHandleReady(async_t* async,
async::WaitBase* wait,
zx_status_t status,
const zx_packet_signal_t* signal);
bool AllocateDeviceMemory(sk_sp<GrContext> context,
const SkISize& size,
zx::vmo& exported_vmo);
bool SetupSkiaSurface(sk_sp<GrContext> context,
const SkISize& size,
SkColorType color_type,
const VkImageCreateInfo& image_create_info,
const VkMemoryRequirements& memory_reqs);
bool CreateFences();
bool PushSessionImageSetupOps(scenic_lib::Session* session,
zx::vmo exported_vmo);
void Reset();
vulkan::VulkanHandle<VkSemaphore> SemaphoreFromEvent(
const zx::event& event) const;
vulkan::VulkanProvider& vulkan_provider_;
sk_sp<GrVkBackendContext> backend_context_;
scenic_lib::Session* session_;
vulkan::VulkanHandle<VkImage> vk_image_;
vulkan::VulkanHandle<VkDeviceMemory> vk_memory_;
vulkan::VulkanHandle<VkFence> command_buffer_fence_;
sk_sp<SkSurface> sk_surface_;
std::unique_ptr<scenic_lib::Image> session_image_;
zx::event acquire_event_;
vulkan::VulkanHandle<VkSemaphore> acquire_semaphore_;
std::unique_ptr<vulkan::VulkanCommandBuffer> command_buffer_;
zx::event release_event_;
async::WaitMethod<VulkanSurface, &VulkanSurface::OnHandleReady> wait_;
std::function<void()> pending_on_writes_committed_;
size_t age_ = 0;
bool valid_ = false;
FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurface);
};
} // namespace flutter
// Copyright 2017 The Fuchsia 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 "vulkan_surface_pool.h"
#include <trace/event.h>
#include "flutter/glue/trace_event.h"
#include "third_party/skia/include/gpu/GrContext.h"
namespace flutter {
VulkanSurfacePool::VulkanSurfacePool(vulkan::VulkanProvider& vulkan_provider,
sk_sp<GrContext> context,
sk_sp<GrVkBackendContext> backend_context,
scenic_lib::Session* mozart_session)
: vulkan_provider_(vulkan_provider),
context_(std::move(context)),
backend_context_(std::move(backend_context)),
mozart_session_(mozart_session) {}
VulkanSurfacePool::~VulkanSurfacePool() {}
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
VulkanSurfacePool::AcquireSurface(const SkISize& size) {
auto surface = GetCachedOrCreateSurface(size);
if (surface == nullptr) {
FXL_DLOG(ERROR) << "Could not acquire surface";
return nullptr;
}
if (!surface->FlushSessionAcquireAndReleaseEvents()) {
FXL_DLOG(ERROR) << "Could not flush acquire/release events for buffer.";
return nullptr;
}
return surface;
}
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
VulkanSurfacePool::GetCachedOrCreateSurface(const SkISize& size) {
auto found_in_available = available_surfaces_.find(size);
if (found_in_available == available_surfaces_.end()) {
return CreateSurface(size);
}
SurfacesSet& available_surfaces = found_in_available->second;
FXL_DCHECK(available_surfaces.size() > 0);
auto acquired_surface = std::move(available_surfaces.back());
available_surfaces.pop_back();
if (available_surfaces.size() == 0) {
available_surfaces_.erase(found_in_available);
}
if (acquired_surface->IsValid()) {
trace_surfaces_reused_++;
return acquired_surface;
}
// This is only likely to happen if the surface was invalidated between the
// time it was sent into the available buffers cache and accessed now.
// Extremely unlikely.
return CreateSurface(size);
}
void VulkanSurfacePool::SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
p_surface) {
TRACE_EVENT0("flutter", "VulkanSurfacePool::SubmitSurface");
if (!p_surface) {
return;
}
uintptr_t surface_key = reinterpret_cast<uintptr_t>(p_surface.get());
auto insert_iterator =
pending_surfaces_.insert(std::make_pair(surface_key, // key
std::move(p_surface) // value
));
if (insert_iterator.second) {
insert_iterator.first->second->SignalWritesFinished(
std::bind(&VulkanSurfacePool::RecycleSurface, this, surface_key));
}
}
std::unique_ptr<VulkanSurface> VulkanSurfacePool::CreateSurface(
const SkISize& size) {
auto surface = std::make_unique<VulkanSurface>(
vulkan_provider_, context_, backend_context_, mozart_session_, size);
if (!surface->IsValid()) {
return nullptr;
}
trace_surfaces_created_++;
return surface;
}
void VulkanSurfacePool::RecycleSurface(uintptr_t surface_key) {
// Before we do anything, we must clear the surface from the collection of
// pending surfaces.
auto found_in_pending = pending_surfaces_.find(surface_key);
if (found_in_pending == pending_surfaces_.end()) {
return;
}
// Grab a hold of the surface to recycle and clear the entry in the pending
// surfaces collection.
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
surface_to_recycle = std::move(found_in_pending->second);
pending_surfaces_.erase(found_in_pending);
// The surface may have become invalid (for example it the fences could
// not be reset).
if (!surface_to_recycle->IsValid()) {
return;
}
// Recycle the buffer by putting it in the list of available surfaces if the
// maximum size of buffers in the collection is not already present.
auto& available_surfaces = available_surfaces_[surface_to_recycle->GetSize()];
if (available_surfaces.size() < kMaxSurfacesOfSameSize) {
available_surfaces.emplace_back(std::move(surface_to_recycle));
}
}
void VulkanSurfacePool::AgeAndCollectOldBuffers() {
std::vector<SkISize> sizes_to_erase;
for (auto& surface_iterator : available_surfaces_) {
SurfacesSet& old_surfaces = surface_iterator.second;
SurfacesSet new_surfaces;
for (auto& surface : old_surfaces) {
if (surface->AdvanceAndGetAge() < kMaxSurfaceAge) {
new_surfaces.emplace_back(std::move(surface));
}
}
if (new_surfaces.size() == 0) {
sizes_to_erase.emplace_back(surface_iterator.first);
}
old_surfaces.swap(new_surfaces);
}
for (const auto& size : sizes_to_erase) {
available_surfaces_.erase(size);
}
TraceStats();
}
void VulkanSurfacePool::TraceStats() {
// Resources held in cached buffers.
size_t cached_surfaces = 0;
size_t cached_surfaces_bytes = 0;
for (const auto& surfaces : available_surfaces_) {
const auto surface_count = surfaces.second.size();
cached_surfaces += surface_count;
// TODO(chinmaygarde): Assuming for now that all surfaces are 32bpp.
cached_surfaces_bytes +=
(surfaces.first.fWidth * surfaces.first.fHeight * 4 * surface_count);
}
// Resources held by Skia.
int skia_resources = 0;
size_t skia_bytes = 0;
context_->getResourceCacheUsage(&skia_resources, &skia_bytes);
const size_t skia_cache_purgeable =
context_->getResourceCachePurgeableBytes();
TRACE_COUNTER("flutter", "SurfacePool", 0u, //
"CachedCount", cached_surfaces, //
"CachedBytes", cached_surfaces_bytes, //
"Created", trace_surfaces_created_, //
"Reused", trace_surfaces_reused_, //
"PendingInCompositor", pending_surfaces_.size(), //
"SkiaCacheResources", skia_resources, //
"SkiaCacheBytes", skia_bytes, //
"SkiaCachePurgeable", skia_cache_purgeable //
);
// Reset per present/frame stats.
trace_surfaces_created_ = 0;
trace_surfaces_reused_ = 0;
}
} // namespace flutter
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <list>
#include <unordered_map>
#include "lib/fxl/macros.h"
#include "vulkan_surface.h"
namespace flutter {
class VulkanSurfacePool final {
public:
static const size_t kMaxSurfacesOfSameSize = 3;
static const size_t kMaxSurfaceAge = 3;
VulkanSurfacePool(vulkan::VulkanProvider& vulkan_provider,
sk_sp<GrContext> context,
sk_sp<GrVkBackendContext> backend_context,
scenic_lib::Session* mozart_session);
~VulkanSurfacePool();
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
AcquireSurface(const SkISize& size);
void SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
surface);
void AgeAndCollectOldBuffers();
private:
using SurfacesSet = std::list<
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>;
template <class T>
static void HashCombine(size_t& seed, T const& v) {
seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
struct SkISizeHash {
std::size_t operator()(const SkISize& key) const {
size_t seed = 0;
HashCombine(seed, key.fWidth);
HashCombine(seed, key.fHeight);
return seed;
}
};
vulkan::VulkanProvider& vulkan_provider_;
sk_sp<GrContext> context_;
sk_sp<GrVkBackendContext> backend_context_;
scenic_lib::Session* mozart_session_;
std::unordered_map<SkISize, SurfacesSet, SkISizeHash> available_surfaces_;
std::unordered_map<
uintptr_t,
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>
pending_surfaces_;
size_t trace_surfaces_created_ = 0;
size_t trace_surfaces_reused_ = 0;
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
GetCachedOrCreateSurface(const SkISize& size);
std::unique_ptr<VulkanSurface> CreateSurface(const SkISize& size);
void RecycleSurface(uintptr_t surface_key);
void TraceStats();
FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfacePool);
};
} // namespace flutter
// Copyright 2017 The Chromium 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 "vulkan_surface_producer.h"
#include <memory>
#include <string>
#include <vector>
#include "flutter/glue/trace_event.h"
#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/vk/GrVkTypes.h"
namespace flutter {
VulkanSurfaceProducer::VulkanSurfaceProducer(
scenic_lib::Session* mozart_session) {
valid_ = Initialize(mozart_session);
if (valid_) {
FXL_DLOG(INFO)
<< "Flutter engine: Vulkan surface producer initialization: Successful";
} else {
FXL_LOG(ERROR)
<< "Flutter engine: Vulkan surface producer initialization: Failed";
}
}
VulkanSurfaceProducer::~VulkanSurfaceProducer() {
// Make sure queue is idle before we start destroying surfaces
VkResult wait_result =
VK_CALL_LOG_ERROR(vk_->QueueWaitIdle(backend_context_->fQueue));
FXL_DCHECK(wait_result == VK_SUCCESS);
};
bool VulkanSurfaceProducer::Initialize(scenic_lib::Session* mozart_session) {
vk_ = fxl::MakeRefCounted<vulkan::VulkanProcTable>();
std::vector<std::string> extensions = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
};
application_ = std::make_unique<vulkan::VulkanApplication>(
*vk_, "FlutterApplicationRunner", std::move(extensions));
if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) {
// Make certain the application instance was created and it setup the
// instance proc table entries.
FXL_LOG(ERROR) << "Instance proc addresses have not been setup.";
return false;
}
// Create the device.
logical_device_ = application_->AcquireFirstCompatibleLogicalDevice();
if (logical_device_ == nullptr || !logical_device_->IsValid() ||
!vk_->AreDeviceProcsSetup()) {
// Make certain the device was created and it setup the device proc table
// entries.
FXL_LOG(ERROR) << "Device proc addresses have not been setup.";
return false;
}
if (!vk_->HasAcquiredMandatoryProcAddresses()) {
FXL_LOG(ERROR) << "Failed to acquire mandatory proc addresses.";
return false;
}
if (!vk_->IsValid()) {
FXL_LOG(ERROR) << "VulkanProcTable invalid";
return false;
}
auto interface = vk_->CreateSkiaInterface();
if (interface == nullptr || !interface->validate(0)) {
FXL_LOG(ERROR) << "Skia interface invalid.";
return false;
}
uint32_t skia_features = 0;
if (!logical_device_->GetPhysicalDeviceFeaturesSkia(&skia_features)) {
FXL_LOG(ERROR) << "Failed to get physical device features.";
return false;
}
backend_context_ = sk_make_sp<GrVkBackendContext>();
backend_context_->fInstance = application_->GetInstance();
backend_context_->fPhysicalDevice =
logical_device_->GetPhysicalDeviceHandle();
backend_context_->fDevice = logical_device_->GetHandle();
backend_context_->fQueue = logical_device_->GetQueueHandle();
backend_context_->fGraphicsQueueIndex =
logical_device_->GetGraphicsQueueIndex();
backend_context_->fMinAPIVersion = application_->GetAPIVersion();
backend_context_->fFeatures = skia_features;
backend_context_->fInterface.reset(interface.release());
logical_device_->ReleaseDeviceOwnership();
application_->ReleaseInstanceOwnership();
context_ = GrContext::MakeVulkan(backend_context_);
context_->setResourceCacheLimits(vulkan::kGrCacheMaxCount,
vulkan::kGrCacheMaxByteSize);
surface_pool_ = std::make_unique<VulkanSurfacePool>(
*this, context_, backend_context_, mozart_session);
return true;
}
void VulkanSurfaceProducer::OnSurfacesPresented(
std::vector<
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>
surfaces) {
TRACE_EVENT0("flutter", "VulkanSurfaceProducer::OnSurfacesPresented");
// Do a single flush for all canvases derived from the context.
{
TRACE_EVENT0("flutter", "GrContext::flushAndSignalSemaphores");
context_->flush();
}
if (!TransitionSurfacesToExternal(surfaces))
FXL_LOG(ERROR) << "TransitionSurfacesToExternal failed";
// Submit surface
for (auto& surface : surfaces) {
SubmitSurface(std::move(surface));
}
// Buffer management.
surface_pool_->AgeAndCollectOldBuffers();
}
bool VulkanSurfaceProducer::TransitionSurfacesToExternal(
const std::vector<
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>&
surfaces) {
for (auto& surface : surfaces) {
auto vk_surface = static_cast<VulkanSurface*>(surface.get());
vulkan::VulkanCommandBuffer* command_buffer =
vk_surface->GetCommandBuffer(logical_device_->GetCommandPool());
if (!command_buffer->Begin())
return false;
GrBackendRenderTarget backendRT =
vk_surface->GetSkiaSurface()->getBackendRenderTarget(
SkSurface::kFlushRead_BackendHandleAccess);
if (!backendRT.isValid()) {
return false;
}
GrVkImageInfo imageInfo;
if (!backendRT.getVkImageInfo(&imageInfo)) {
return false;
}
VkImageMemoryBarrier image_barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dstAccessMask = 0,
.oldLayout = imageInfo.fImageLayout,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = 0,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR,
.image = vk_surface->GetVkImage(),
.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
if (!command_buffer->InsertPipelineBarrier(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0, // dependencyFlags
0, nullptr, // memory barriers
0, nullptr, // buffer barriers
1, &image_barrier))
return false;
backendRT.setVkImageLayout(image_barrier.newLayout);
if (!command_buffer->End())
return false;
if (!logical_device_->QueueSubmit(
{}, {}, {vk_surface->GetAcquireVkSemaphore()},
{command_buffer->Handle()}, vk_surface->GetCommandBufferFence()))
return false;
}
return true;
}
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
VulkanSurfaceProducer::ProduceSurface(const SkISize& size) {
FXL_DCHECK(valid_);
return surface_pool_->AcquireSurface(size);
}
void VulkanSurfaceProducer::SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface> surface) {
FXL_DCHECK(valid_ && surface != nullptr);
surface_pool_->SubmitSurface(std::move(surface));
}
} // namespace flutter
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include "flutter/flow/scene_update_context.h"
#include "flutter/vulkan/vulkan_application.h"
#include "flutter/vulkan/vulkan_device.h"
#include "flutter/vulkan/vulkan_proc_table.h"
#include "flutter/vulkan/vulkan_provider.h"
#include "lib/fsl/tasks/message_loop.h"
#include "lib/fxl/macros.h"
#include "lib/ui/scenic/client/resources.h"
#include "lib/ui/scenic/client/session.h"
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
#include "vulkan_surface.h"
#include "vulkan_surface_pool.h"
namespace flutter {
class VulkanSurfaceProducer final
: public flow::SceneUpdateContext::SurfaceProducer,
public vulkan::VulkanProvider {
public:
VulkanSurfaceProducer(scenic_lib::Session* mozart_session);
~VulkanSurfaceProducer();
bool IsValid() const { return valid_; }
// |flow::SceneUpdateContext::SurfaceProducer|
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
ProduceSurface(const SkISize& size) override;
// |flow::SceneUpdateContext::SurfaceProducer|
void SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface> surface)
override;
void OnSurfacesPresented(
std::vector<
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>
surfaces);
private:
// VulkanProvider
const vulkan::VulkanProcTable& vk() override { return *vk_.get(); }
const vulkan::VulkanHandle<VkDevice>& vk_device() override {
return logical_device_->GetHandle();
}
bool TransitionSurfacesToExternal(
const std::vector<
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>&
surfaces);
// Note: the order here is very important. The proctable must be destroyed
// last because it contains the function pointers for VkDestroyDevice and
// VkDestroyInstance. The backend context owns the VkDevice and the
// VkInstance, so it must be destroyed after the logical device and the
// application, which own other vulkan objects associated with the device
// and instance.
fxl::RefPtr<vulkan::VulkanProcTable> vk_;
sk_sp<GrVkBackendContext> backend_context_;
std::unique_ptr<vulkan::VulkanDevice> logical_device_;
std::unique_ptr<vulkan::VulkanApplication> application_;
sk_sp<GrContext> context_;
std::unique_ptr<VulkanSurfacePool> surface_pool_;
bool valid_ = false;
bool Initialize(scenic_lib::Session* mozart_session);
FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfaceProducer);
};
} // namespace flutter
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册