From 925298d9478f401ae5e5519af2ee8c538c366cbb Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 18 Jul 2017 15:40:18 -0700 Subject: [PATCH] Update the content handler to use the Mozart session API. (#3887) --- common/threads.h | 9 + content_handler/BUILD.gn | 102 ++-- content_handler/app.cc | 11 +- content_handler/app.h | 18 +- content_handler/content_handler_thread.cc | 89 ---- content_handler/content_handler_thread.h | 48 -- content_handler/rasterizer.cc | 28 +- content_handler/rasterizer.h | 6 +- content_handler/runtime_holder.cc | 191 ++++---- content_handler/runtime_holder.h | 21 +- content_handler/session_connection.cc | 74 +++ content_handler/session_connection.h | 58 +++ content_handler/software_rasterizer.cc | 92 ---- content_handler/software_rasterizer.h | 50 -- content_handler/vulkan_native_rasterizer.cc | 90 ---- content_handler/vulkan_native_rasterizer.h | 41 -- content_handler/vulkan_rasterizer.cc | 485 ++------------------ content_handler/vulkan_rasterizer.h | 121 +---- content_handler/vulkan_surface.cc | 340 ++++++++++++++ content_handler/vulkan_surface.h | 91 ++++ content_handler/vulkan_surface_pool.cc | 177 +++++++ content_handler/vulkan_surface_pool.h | 77 ++++ content_handler/vulkan_surface_producer.cc | 138 ++++++ content_handler/vulkan_surface_producer.h | 66 +++ flow/BUILD.gn | 15 +- flow/export_node.cc | 39 ++ flow/export_node.h | 54 +++ flow/layers/backdrop_filter_layer.cc | 11 +- flow/layers/backdrop_filter_layer.h | 1 - flow/layers/child_scene_layer.cc | 54 +-- flow/layers/child_scene_layer.h | 14 +- flow/layers/clip_path_layer.cc | 39 +- flow/layers/clip_path_layer.h | 4 +- flow/layers/clip_rect_layer.cc | 36 +- flow/layers/clip_rect_layer.h | 4 +- flow/layers/clip_rrect_layer.cc | 43 +- flow/layers/clip_rrect_layer.h | 4 +- flow/layers/color_filter_layer.cc | 6 +- flow/layers/color_filter_layer.h | 1 - flow/layers/container_layer.cc | 62 ++- flow/layers/container_layer.h | 23 +- flow/layers/layer.cc | 19 +- flow/layers/layer.h | 28 +- flow/layers/layer_tree.cc | 23 +- flow/layers/layer_tree.h | 13 +- flow/layers/opacity_layer.cc | 26 +- flow/layers/opacity_layer.h | 7 +- flow/layers/physical_model_layer.cc | 95 ++-- flow/layers/physical_model_layer.h | 20 +- flow/layers/picture_layer.cc | 7 +- flow/layers/shader_mask_layer.cc | 6 +- flow/layers/shader_mask_layer.h | 5 +- flow/layers/transform_layer.cc | 34 +- flow/layers/transform_layer.h | 4 +- flow/scene_update_context.cc | 318 +++++++++---- flow/scene_update_context.h | 170 +++++-- lib/ui/BUILD.gn | 2 + lib/ui/compositing.dart | 31 +- lib/ui/compositing/scene_builder.cc | 9 +- lib/ui/compositing/scene_builder.h | 3 +- lib/ui/compositing/scene_host.cc | 44 ++ lib/ui/compositing/scene_host.h | 52 +++ lib/ui/dart_ui.cc | 1 + travis/licenses_golden/licenses_flutter | 56 ++- vulkan/BUILD.gn | 5 +- vulkan/vulkan_proc_table.cc | 25 +- vulkan/vulkan_proc_table.h | 10 +- 67 files changed, 2183 insertions(+), 1663 deletions(-) delete mode 100644 content_handler/content_handler_thread.cc delete mode 100644 content_handler/content_handler_thread.h create mode 100644 content_handler/session_connection.cc create mode 100644 content_handler/session_connection.h delete mode 100644 content_handler/software_rasterizer.cc delete mode 100644 content_handler/software_rasterizer.h delete mode 100644 content_handler/vulkan_native_rasterizer.cc delete mode 100644 content_handler/vulkan_native_rasterizer.h create mode 100644 content_handler/vulkan_surface.cc create mode 100644 content_handler/vulkan_surface.h create mode 100644 content_handler/vulkan_surface_pool.cc create mode 100644 content_handler/vulkan_surface_pool.h create mode 100644 content_handler/vulkan_surface_producer.cc create mode 100644 content_handler/vulkan_surface_producer.h create mode 100644 flow/export_node.cc create mode 100644 flow/export_node.h create mode 100644 lib/ui/compositing/scene_host.cc create mode 100644 lib/ui/compositing/scene_host.h diff --git a/common/threads.h b/common/threads.h index 7846c2a3e..f9058b17c 100644 --- a/common/threads.h +++ b/common/threads.h @@ -7,6 +7,15 @@ #include "lib/ftl/tasks/task_runner.h" +#define ASSERT_IS_PLATFORM_THREAD \ + FTL_DCHECK(::blink::Threads::Platform()->RunsTasksOnCurrentThread()); +#define ASSERT_IS_GPU_THREAD \ + FTL_DCHECK(::blink::Threads::Gpu()->RunsTasksOnCurrentThread()); +#define ASSERT_IS_UI_THREAD \ + FTL_DCHECK(::blink::Threads::UI()->RunsTasksOnCurrentThread()); +#define ASSERT_IS_IO_THREAD \ + FTL_DCHECK(::blink::Threads::IO()->RunsTasksOnCurrentThread()); + namespace blink { class Threads { diff --git a/content_handler/BUILD.gn b/content_handler/BUILD.gn index d3f000a30..e03bfbe18 100644 --- a/content_handler/BUILD.gn +++ b/content_handler/BUILD.gn @@ -6,11 +6,6 @@ assert(is_fuchsia) import("//build/vulkan/config.gni") -declare_args() { - flutter_enable_vulkan = fuchsia_use_vulkan - flutter_use_vulkan_native_surface = false -} - template("flutter_content_handler") { invoker_output_name = invoker.output_name extra_deps = invoker.extra_deps @@ -27,8 +22,6 @@ template("flutter_content_handler") { "app.h", "application_controller_impl.cc", "application_controller_impl.h", - "content_handler_thread.cc", - "content_handler_thread.h", "main.cc", "rasterizer.cc", "rasterizer.h", @@ -36,66 +29,46 @@ template("flutter_content_handler") { "runtime_holder.h", "service_protocol_hooks.cc", "service_protocol_hooks.h", - "software_rasterizer.cc", - "software_rasterizer.h", + "session_connection.cc", + "session_connection.h", + "vulkan_rasterizer.cc", + "vulkan_rasterizer.h", + "vulkan_surface.cc", + "vulkan_surface.h", + "vulkan_surface_pool.cc", + "vulkan_surface_pool.h", + "vulkan_surface_producer.cc", + "vulkan_surface_producer.h", ] deps = [ - "//application/lib/app", - "//application/lib/svc", - "//apps/icu_data/lib", - "//apps/mozart/lib/flutter/sdk_ext", - "//apps/mozart/lib/skia:vmo", - "//apps/mozart/services/buffers", - "//apps/mozart/services/buffers/cpp", - "//apps/mozart/services/composition", - "//apps/mozart/services/input", - "//apps/mozart/services/views", - "//apps/tracing/lib/trace:provider", - - # TODO(abarth): We shouldn't need to depend on libdart_builtin but we fail - # to link otherwise. - "//dart/runtime/bin:libdart_builtin", - "//dart/runtime/vm:libdart_platform", - "//flutter/assets", - "//flutter/common", - "//flutter/flow", - "//flutter/glue", - "//flutter/lib/ui", - "//flutter/runtime", - "//flutter/sky/engine/platform", - "//lib/fidl/dart/sdk_ext", - "//lib/ftl", - "//lib/mtl", - "//lib/tonic/mx", - "//lib/zip", - "//third_party/rapidjson", - "//third_party/skia", - ] - deps += extra_deps - - if (flutter_enable_vulkan) { - defines += [ "FLUTTER_ENABLE_VULKAN=1" ] - - if (flutter_use_vulkan_native_surface) { - defines += [ "FLUTTER_USE_VULKAN_NATIVE_SURFACE=1" ] - sources += [ - "vulkan_native_rasterizer.cc", - "vulkan_native_rasterizer.h", - ] - libs += [ "hid" ] - } else { - sources += [ - "vulkan_rasterizer.cc", - "vulkan_rasterizer.h", - ] - } - - deps += [ - "//flutter/vulkan", - "//magma:vulkan", - ] - } + "//application/lib/app", + "//application/lib/svc", + "//apps/icu_data/lib", + "//apps/mozart/lib/flutter/sdk_ext", + "//apps/mozart/lib/scene:client", + "//apps/mozart/services/input", + "//apps/mozart/services/views", + "//apps/tracing/lib/trace:provider", + "//dart/runtime/bin:libdart_builtin", + "//dart/runtime/vm:libdart_platform", + "//flutter/assets", + "//flutter/common", + "//flutter/flow", + "//flutter/glue", + "//flutter/lib/ui", + "//flutter/runtime", + "//flutter/sky/engine/platform", + "//flutter/vulkan", + "//lib/fidl/dart/sdk_ext", + "//lib/ftl", + "//lib/mtl", + "//lib/tonic/mx", + "//lib/zip", + "//magma:vulkan", + "//third_party/rapidjson", + "//third_party/skia", + ] + extra_deps # The flags below are needed so that Dart's CPU profiler can walk the # C++ stack. @@ -103,6 +76,7 @@ template("flutter_content_handler") { "-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" ] diff --git a/content_handler/app.cc b/content_handler/app.cc index 78d0bb9e7..a624a8a44 100644 --- a/content_handler/app.cc +++ b/content_handler/app.cc @@ -40,11 +40,14 @@ App::App() { tracing::InitializeTracer(context_.get(), {}); - gpu_thread_ = std::make_unique(); - io_thread_ = std::make_unique(); + gpu_thread_ = std::make_unique(); + io_thread_ = std::make_unique(); - FTL_CHECK(gpu_thread_->IsValid()) << "Must be able to create the GPU thread"; - FTL_CHECK(io_thread_->IsValid()) << "Must be able to create the IO thread"; + auto gpu_thread_success = gpu_thread_->Run(); + auto io_thread_success = io_thread_->Run(); + + FTL_CHECK(gpu_thread_success) << "Must be able to create the GPU thread"; + FTL_CHECK(io_thread_success) << "Must be able to create the IO thread"; auto ui_task_runner = mtl::MessageLoop::GetCurrent()->task_runner(); auto gpu_task_runner = gpu_thread_->TaskRunner(); diff --git a/content_handler/app.h b/content_handler/app.h index 7ee77e06b..a4693b160 100644 --- a/content_handler/app.h +++ b/content_handler/app.h @@ -11,9 +11,9 @@ #include "application/lib/app/application_context.h" #include "application/services/application_runner.fidl.h" #include "flutter/content_handler/application_controller_impl.h" -#include "flutter/content_handler/content_handler_thread.h" #include "lib/ftl/macros.h" #include "lib/ftl/synchronization/waitable_event.h" +#include "lib/mtl/threading/thread.h" namespace flutter_runner { @@ -26,10 +26,10 @@ class App : public app::ApplicationRunner { // |app::ApplicationRunner| implementation: - void StartApplication(app::ApplicationPackagePtr application, - app::ApplicationStartupInfoPtr startup_info, - fidl::InterfaceRequest - controller) override; + void StartApplication( + app::ApplicationPackagePtr application, + app::ApplicationStartupInfoPtr startup_info, + fidl::InterfaceRequest controller) override; void Destroy(ApplicationControllerImpl* controller); @@ -43,13 +43,13 @@ class App : public app::ApplicationRunner { private: void WaitForPlatformViewsIdsUIThread( - std::vector* platform_view_ids, - ftl::AutoResetWaitableEvent* latch); + std::vector* platform_view_ids, + ftl::AutoResetWaitableEvent* latch); void UpdateProcessLabel(); std::unique_ptr context_; - std::unique_ptr gpu_thread_; - std::unique_ptr io_thread_; + std::unique_ptr gpu_thread_; + std::unique_ptr io_thread_; fidl::BindingSet runner_bindings_; std::unordered_map> diff --git a/content_handler/content_handler_thread.cc b/content_handler/content_handler_thread.cc deleted file mode 100644 index bf7490c25..000000000 --- a/content_handler/content_handler_thread.cc +++ /dev/null @@ -1,89 +0,0 @@ -// 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 "flutter/content_handler/content_handler_thread.h" - -#include - -#include "lib/ftl/logging.h" -#include "lib/mtl/tasks/incoming_task_queue.h" -#include "lib/mtl/tasks/message_loop.h" - -namespace flutter_runner { - -typedef void (*ThreadEntry)(Thread*); - -static size_t NextPageSizeMultiple(size_t size) { - const size_t page_size = sysconf(_SC_PAGE_SIZE); - FTL_CHECK(page_size != 0); - - size = std::max(size, page_size); - - size_t rem = size % page_size; - - if (rem == 0) { - return size; - } - - return size + page_size - rem; -} - -static bool CreateThread(pthread_t* thread, - ThreadEntry main, - Thread* argument, - size_t stack_size) { - pthread_attr_t thread_attributes; - - if (pthread_attr_init(&thread_attributes) != 0) { - return false; - } - - stack_size = std::max(NextPageSizeMultiple(PTHREAD_STACK_MIN), - NextPageSizeMultiple(stack_size)); - - if (pthread_attr_setstacksize(&thread_attributes, stack_size) != 0) { - return false; - } - - auto result = - pthread_create(thread, &thread_attributes, - reinterpret_cast(main), argument); - - pthread_attr_destroy(&thread_attributes); - - return result == 0; -} - -Thread::Thread() - : task_runner_(ftl::MakeRefCounted()) { - valid_ = CreateThread(&thread_, [](Thread* thread) { thread->Main(); }, this, - 1 << 20); -} - -Thread::~Thread() { - Join(); -} - -bool Thread::IsValid() const { - return valid_; -} - -ftl::RefPtr Thread::TaskRunner() const { - return task_runner_; -} - -void Thread::Main() { - mtl::MessageLoop message_loop(task_runner_); - message_loop.Run(); -} - -bool Thread::Join() { - if (!valid_) { - return false; - } - - return pthread_join(thread_, nullptr) == 0; -} - -} // namespace flutter_runner diff --git a/content_handler/content_handler_thread.h b/content_handler/content_handler_thread.h deleted file mode 100644 index 7e14a65f8..000000000 --- a/content_handler/content_handler_thread.h +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - -#ifndef FLUTTER_CONTENT_HANDLER_CONTENT_HANDLER_THREAD_H_ -#define FLUTTER_CONTENT_HANDLER_CONTENT_HANDLER_THREAD_H_ - -#include - -#include - -#include "lib/ftl/macros.h" -#include "lib/ftl/memory/ref_ptr.h" -#include "lib/ftl/tasks/task_runner.h" - -namespace mtl { -namespace internal { -class IncomingTaskQueue; -} // namespace internal -} // namespace mtl - -namespace flutter_runner { - -class Thread { - public: - Thread(); - - ~Thread(); - - ftl::RefPtr TaskRunner() const; - - bool Join(); - - bool IsValid() const; - - private: - bool valid_; - pthread_t thread_; - ftl::RefPtr task_runner_; - - void Main(); - - FTL_DISALLOW_COPY_AND_ASSIGN(Thread); -}; - -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_CONTENT_HANDLER_THREAD_H_ diff --git a/content_handler/rasterizer.cc b/content_handler/rasterizer.cc index e0ea43f51..ac22fa086 100644 --- a/content_handler/rasterizer.cc +++ b/content_handler/rasterizer.cc @@ -3,41 +3,17 @@ // found in the LICENSE file. #include "flutter/content_handler/rasterizer.h" - -#include "flutter/content_handler/software_rasterizer.h" - -#if FLUTTER_ENABLE_VULKAN -#if FLUTTER_USE_VULKAN_NATIVE_SURFACE -#include "flutter/content_handler/vulkan_native_rasterizer.h" -#else // FLUTTER_USE_VULKAN_NATIVE_SURFACE #include "flutter/content_handler/vulkan_rasterizer.h" -#endif // FLUTTER_USE_VULKAN_NATIVE_SURFACE -#endif // FLUTTER_ENABLE_VULKAN namespace flutter_runner { Rasterizer::~Rasterizer() = default; std::unique_ptr Rasterizer::Create() { -#if FLUTTER_ENABLE_VULKAN -#if FLUTTER_USE_VULKAN_NATIVE_SURFACE - auto vulkan_rasterizer = std::make_unique(); -#else // FLUTTER_USE_VULKAN_NATIVE_SURFACE auto vulkan_rasterizer = std::make_unique(); -#endif // FLUTTER_USE_VULKAN_NATIVE_SURFACE - - if (!vulkan_rasterizer->IsValid()) { - FTL_DLOG(INFO) << "Could not initialize a valid vulkan rasterizer. " - "Attempting to fallback to the software rasterizer."; - return std::make_unique(); - } - - FTL_DLOG(INFO) << "Successfully initialized a valid vulkan rasterizer."; - + FTL_CHECK(vulkan_rasterizer) + << "The vulkan rasterizer must be correctly initialized."; return vulkan_rasterizer; -#else // FLUTTER_ENABLE_VULKAN - return std::make_unique(); -#endif // FLUTTER_ENABLE_VULKAN } } // namespace flutter_runner diff --git a/content_handler/rasterizer.h b/content_handler/rasterizer.h index 3a613a9f9..aeb2687af 100644 --- a/content_handler/rasterizer.h +++ b/content_handler/rasterizer.h @@ -7,10 +7,11 @@ #include -#include "apps/mozart/services/composition/scenes.fidl.h" +#include "apps/mozart/services/scene/session.fidl.h" #include "flutter/flow/layers/layer_tree.h" #include "lib/ftl/functional/closure.h" #include "lib/ftl/macros.h" +#include "magenta/system/ulib/mx/include/mx/eventpair.h" namespace flutter_runner { @@ -20,7 +21,8 @@ class Rasterizer { static std::unique_ptr Create(); - virtual void SetScene(fidl::InterfaceHandle scene) = 0; + virtual void SetSession(fidl::InterfaceHandle session, + mx::eventpair import_token) = 0; virtual void Draw(std::unique_ptr layer_tree, ftl::Closure callback) = 0; diff --git a/content_handler/runtime_holder.cc b/content_handler/runtime_holder.cc index 878a0fd28..00f1f75e0 100644 --- a/content_handler/runtime_holder.cc +++ b/content_handler/runtime_holder.cc @@ -44,13 +44,6 @@ constexpr char kAssetChannel[] = "flutter/assets"; constexpr char kKeyEventChannel[] = "flutter/keyevent"; constexpr char kTextInputChannel[] = "flutter/textinput"; -// Maximum number of frames in flight. -constexpr int kMaxPipelineDepth = 3; - -// When the max pipeline depth is exceeded, drain to this number of frames -// to recover before acknowleding the invalidation and scheduling more frames. -constexpr int kRecoveryPipelineDepth = 1; - blink::PointerData::Change GetChangeFromPointerEventPhase( mozart::PointerEvent::Phase phase) { switch (phase) { @@ -98,10 +91,6 @@ RuntimeHolder::~RuntimeHolder() { ftl::MakeCopyable([rasterizer = std::move(rasterizer_)](){ // Deletes rasterizer. })); - if (deferred_invalidation_callback_) { - // Must be called before being destroyed. - deferred_invalidation_callback_(); - } } void RuntimeHolder::Init( @@ -192,14 +181,23 @@ void RuntimeHolder::CreateView( } } + // Create the view. + mx::eventpair import_token, export_token; + mx_status_t status = mx::eventpair::create(0u, &import_token, &export_token); + if (status != MX_OK) { + FTL_LOG(ERROR) << "Could not create an event pair."; + return; + } mozart::ViewListenerPtr view_listener; - view_listener_binding_.Bind(fidl::GetProxy(&view_listener)); - view_manager_->CreateView(fidl::GetProxy(&view_), - std::move(view_owner_request), - std::move(view_listener), script_uri); - + view_listener_binding_.Bind(view_listener.NewRequest()); + view_manager_->CreateView(view_.NewRequest(), // view + std::move(view_owner_request), // view owner + std::move(view_listener), // view listener + std::move(export_token), // export token + script_uri // diagnostic label + ); app::ServiceProviderPtr view_services; - view_->GetServiceProvider(fidl::GetProxy(&view_services)); + view_->GetServiceProvider(view_services.NewRequest()); // Listen for input events. ConnectToService(view_services.get(), fidl::GetProxy(&input_connection_)); @@ -207,11 +205,20 @@ void RuntimeHolder::CreateView( input_listener_binding_.Bind(GetProxy(&input_listener)); input_connection_->SetEventListener(std::move(input_listener)); - mozart::ScenePtr scene; - view_->CreateScene(fidl::GetProxy(&scene)); + // Setup the session. + mozart2::SessionPtr session; + mozart2::SceneManagerPtr scene_manager; + view_manager_->GetSceneManager(scene_manager.NewRequest()); + scene_manager->CreateSession(session.NewRequest(), + nullptr /* session listener */); blink::Threads::Gpu()->PostTask(ftl::MakeCopyable([ - rasterizer = rasterizer_.get(), scene = std::move(scene) - ]() mutable { rasterizer->SetScene(std::move(scene)); })); + rasterizer = rasterizer_.get(), // + session = session.PassInterfaceHandle(), // + import_token = std::move(import_token) // + ]() mutable { + ASSERT_IS_GPU_THREAD; + rasterizer->SetSession(std::move(session), std::move(import_token)); + })); runtime_ = blink::RuntimeController::Create(this); @@ -259,30 +266,50 @@ std::string RuntimeHolder::DefaultRouteName() { } void RuntimeHolder::ScheduleFrame() { - if (pending_invalidation_ || deferred_invalidation_callback_) - return; - pending_invalidation_ = true; - view_->Invalidate(); + ASSERT_IS_UI_THREAD; + if (!frame_scheduled_) { + frame_scheduled_ = true; + if (!frame_outstanding_) + PostBeginFrame(); + } } void RuntimeHolder::Render(std::unique_ptr layer_tree) { - if (!is_ready_to_draw_) - return; // Only draw once per frame. - is_ready_to_draw_ = false; + if (!frame_outstanding_ || frame_rendering_) { + // TODO(MZ-193): We probably shouldn't be discarding the layer tree here. + // But then, Flutter shouldn't be calling Render() if we didn't call + // BeginFrame(). + return; // Spurious. + } + + frame_rendering_ = true; layer_tree->set_construction_time(ftl::TimePoint::Now() - last_begin_frame_time_); layer_tree->set_frame_size(SkISize::Make(viewport_metrics_.physical_width, viewport_metrics_.physical_height)); - layer_tree->set_scene_version(scene_version_); + // We are on the Platform/UI thread. Post to the GPU thread to render. + ASSERT_IS_PLATFORM_THREAD; blink::Threads::Gpu()->PostTask(ftl::MakeCopyable([ - rasterizer = rasterizer_.get(), layer_tree = std::move(layer_tree), - self = GetWeakPtr() + rasterizer = rasterizer_.get(), // + layer_tree = std::move(layer_tree), // + weak_runtime_holder = GetWeakPtr() // ]() mutable { - rasterizer->Draw(std::move(layer_tree), [self]() { - if (self) - self->OnFrameComplete(); + // On the GPU Thread. + ASSERT_IS_GPU_THREAD; + rasterizer->Draw(std::move(layer_tree), [weak_runtime_holder]() { + // This is on the GPU thread thread. Post to the Platform/UI thread for + // the completion callback. + ASSERT_IS_GPU_THREAD; + blink::Threads::Platform()->PostTask([weak_runtime_holder]() { + // On the Platform/UI thread. + ASSERT_IS_UI_THREAD; + if (weak_runtime_holder) { + weak_runtime_holder->frame_rendering_ = false; + weak_runtime_holder->OnFrameComplete(); + } + }); }); })); } @@ -550,41 +577,27 @@ void RuntimeHolder::OnEvent(mozart::InputEventPtr event, callback(handled); } -void RuntimeHolder::OnInvalidation(mozart::ViewInvalidationPtr invalidation, - const OnInvalidationCallback& callback) { - FTL_DCHECK(invalidation); - pending_invalidation_ = false; +void RuntimeHolder::OnPropertiesChanged( + mozart::ViewPropertiesPtr properties, + const OnPropertiesChangedCallback& callback) { + FTL_DCHECK(properties); - // Apply view property changes. - if (invalidation->properties) { - view_properties_ = std::move(invalidation->properties); - viewport_metrics_.physical_width = - view_properties_->view_layout->size->width; - viewport_metrics_.physical_height = - view_properties_->view_layout->size->height; - viewport_metrics_.device_pixel_ratio = 2.0; - // TODO(abarth): Use view_properties_->display_metrics->device_pixel_ratio - // once that's reasonable. - runtime_->SetViewportMetrics(viewport_metrics_); + // Attempt to read the device pixel ratio. + float pixel_ratio = 1.0; + if (auto& metrics = properties->display_metrics) { + pixel_ratio = metrics->device_pixel_ratio; } - // Remember the scene version for rendering. - scene_version_ = invalidation->scene_version; - - // TODO(jeffbrown): Flow the frame time through the rendering pipeline. - if (outstanding_requests_ >= kMaxPipelineDepth) { - FTL_DCHECK(!deferred_invalidation_callback_); - deferred_invalidation_callback_ = callback; - return; + // Apply view property changes. + if (auto& layout = properties->view_layout) { + viewport_metrics_.physical_width = layout->size->width; + viewport_metrics_.physical_height = layout->size->height; + viewport_metrics_.device_pixel_ratio = pixel_ratio; + runtime_->SetViewportMetrics(viewport_metrics_); } - ++outstanding_requests_; - BeginFrame(); + ScheduleFrame(); - // TODO(jeffbrown): Consider running the callback earlier. - // Note that this may result in the view processing stale view properties - // (such as size) if it prematurely acks the frame but takes too long - // to handle it. callback(); } @@ -645,9 +658,8 @@ void RuntimeHolder::OnAction(mozart::InputMethodAction action) { args.PushBack("TextInputAction.done", allocator); document.SetObject(); - document.AddMember("method", - rapidjson::Value("TextInputClient.performAction"), - allocator); + document.AddMember( + "method", rapidjson::Value("TextInputClient.performAction"), allocator); document.AddMember("args", args, allocator); rapidjson::StringBuffer buffer; @@ -664,39 +676,32 @@ ftl::WeakPtr RuntimeHolder::GetWeakPtr() { return weak_factory_.GetWeakPtr(); } -void RuntimeHolder::BeginFrame() { - FTL_DCHECK(outstanding_requests_ > 0); - FTL_DCHECK(outstanding_requests_ <= kMaxPipelineDepth) - << outstanding_requests_; +void RuntimeHolder::PostBeginFrame() { + blink::Threads::Platform()->PostTask([weak_runtime_holder = GetWeakPtr()]() { + // On the Platform/UI thread. + ASSERT_IS_UI_THREAD; + if (weak_runtime_holder) { + weak_runtime_holder->BeginFrame(); + } + }); +} - FTL_DCHECK(!is_ready_to_draw_); - is_ready_to_draw_ = true; +void RuntimeHolder::BeginFrame() { + ASSERT_IS_UI_THREAD + FTL_DCHECK(frame_scheduled_); + FTL_DCHECK(!frame_outstanding_); + frame_scheduled_ = false; + frame_outstanding_ = true; last_begin_frame_time_ = ftl::TimePoint::Now(); runtime_->BeginFrame(last_begin_frame_time_); - const bool was_ready_to_draw = is_ready_to_draw_; - is_ready_to_draw_ = false; - - // If we were still ready to draw when done with the frame, that means we - // didn't draw anything this frame and we should acknowledge the frame - // ourselves instead of waiting for the rasterizer to acknowledge it. - if (was_ready_to_draw) - OnFrameComplete(); } void RuntimeHolder::OnFrameComplete() { - FTL_DCHECK(outstanding_requests_ > 0); - --outstanding_requests_; - - if (deferred_invalidation_callback_ && - outstanding_requests_ <= kRecoveryPipelineDepth) { - // Schedule frame first to avoid potentially generating a second - // invalidation in case the view manager already has one pending - // awaiting acknowledgement of the deferred invalidation. - OnInvalidationCallback callback = - std::move(deferred_invalidation_callback_); - ScheduleFrame(); - callback(); - } + ASSERT_IS_UI_THREAD + FTL_DCHECK(frame_outstanding_); + frame_outstanding_ = false; + if (frame_scheduled_) + PostBeginFrame(); } } // namespace flutter_runner diff --git a/content_handler/runtime_holder.h b/content_handler/runtime_holder.h index eeafb6e5f..1f650aa98 100644 --- a/content_handler/runtime_holder.h +++ b/content_handler/runtime_holder.h @@ -67,8 +67,9 @@ class RuntimeHolder : public blink::RuntimeDelegate, const OnEventCallback& callback) override; // |mozart::ViewListener| implementation: - void OnInvalidation(mozart::ViewInvalidationPtr invalidation, - const OnInvalidationCallback& callback) override; + void OnPropertiesChanged( + mozart::ViewPropertiesPtr properties, + const OnPropertiesChangedCallback& callback) override; // |mozart::InputMethodEditorClient| implementation: void DidUpdateState(mozart::TextInputStatePtr state, @@ -85,40 +86,32 @@ class RuntimeHolder : public blink::RuntimeDelegate, void InitFidlInternal(); void InitMozartInternal(); + void PostBeginFrame(); void BeginFrame(); void OnFrameComplete(); void Invalidate(); std::unique_ptr context_; fidl::InterfaceRequest outgoing_services_; - std::vector root_bundle_data_; ftl::RefPtr asset_store_; void* dylib_handle_ = nullptr; - std::unique_ptr rasterizer_; std::unique_ptr runtime_; blink::ViewportMetrics viewport_metrics_; - mozart::ViewManagerPtr view_manager_; fidl::Binding view_listener_binding_; fidl::Binding input_listener_binding_; mozart::InputConnectionPtr input_connection_; mozart::ViewPtr view_; - mozart::ViewPropertiesPtr view_properties_; - uint32_t scene_version_ = mozart::kSceneVersionNone; - std::unordered_set down_pointers_; - - bool pending_invalidation_ = false; - OnInvalidationCallback deferred_invalidation_callback_; - bool is_ready_to_draw_ = false; - int outstanding_requests_ = 0; - mozart::InputMethodEditorPtr input_method_editor_; fidl::Binding text_input_binding_; int current_text_input_client_ = 0; ftl::TimePoint last_begin_frame_time_; + bool frame_outstanding_ = false; + bool frame_scheduled_ = false; + bool frame_rendering_ = false; ftl::WeakPtrFactory weak_factory_; diff --git a/content_handler/session_connection.cc b/content_handler/session_connection.cc new file mode 100644 index 000000000..915717aba --- /dev/null +++ b/content_handler/session_connection.cc @@ -0,0 +1,74 @@ +// 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 "flutter/content_handler/session_connection.h" +#include "apps/mozart/lib/scene/session_helpers.h" + +namespace flutter_runner { + +SessionConnection::SessionConnection( + fidl::InterfaceHandle session_handle, + mx::eventpair import_token) + : session_(mozart2::SessionPtr::Create(std::move(session_handle))), + root_node_(&session_), + surface_producer_(std::make_unique(&session_)), + scene_update_context_(&session_, surface_producer_.get()) { + ASSERT_IS_GPU_THREAD; + root_node_.Bind(std::move(import_token)); + session_.set_connection_error_handler( + std::bind(&SessionConnection::OnSessionError, this)); + present_callback_ = + std::bind(&SessionConnection::OnPresent, this, std::placeholders::_1); +} + +SessionConnection::~SessionConnection() { + ASSERT_IS_GPU_THREAD; +} + +void SessionConnection::OnSessionError() { + ASSERT_IS_GPU_THREAD; + // TODO: Not this. + FTL_CHECK(false) << "Session connection was terminated."; +} + +void SessionConnection::Present(flow::CompositorContext::ScopedFrame& frame, + ftl::Closure on_present_callback) { + ASSERT_IS_GPU_THREAD; + FTL_DCHECK(pending_on_present_callback_ == nullptr); + FTL_DCHECK(on_present_callback != nullptr); + pending_on_present_callback_ = on_present_callback; + + // 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. + session_.Present(0, // presentation_time. Placeholder for now. + present_callback_ // callback + ); + + // 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. + EnqueueClearOps(); +} + +void SessionConnection::OnPresent(mozart2::PresentationInfoPtr info) { + ASSERT_IS_GPU_THREAD; + auto callback = pending_on_present_callback_; + pending_on_present_callback_ = nullptr; + callback(); +} + +void SessionConnection::EnqueueClearOps() { + ASSERT_IS_GPU_THREAD; + // 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(mozart::NewDetachChildrenOp(root_node_.id())); +} + +} // namespace flutter_runner diff --git a/content_handler/session_connection.h b/content_handler/session_connection.h new file mode 100644 index 000000000..2b6ca38b3 --- /dev/null +++ b/content_handler/session_connection.h @@ -0,0 +1,58 @@ +// 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. + +#ifndef FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ +#define FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ + +#include "apps/mozart/lib/scene/client/resources.h" +#include "apps/mozart/lib/scene/client/session.h" +#include "flutter/common/threads.h" +#include "flutter/content_handler/vulkan_surface_producer.h" +#include "flutter/flow/compositor_context.h" +#include "flutter/flow/scene_update_context.h" +#include "lib/fidl/cpp/bindings/interface_handle.h" +#include "lib/ftl/macros.h" +#include "magenta/system/ulib/mx/include/mx/eventpair.h" + +namespace flutter_runner { + +class SessionConnection { + public: + SessionConnection(fidl::InterfaceHandle session_handle, + mx::eventpair import_token); + + ~SessionConnection(); + + flow::SceneUpdateContext& scene_update_context() { + return scene_update_context_; + } + + mozart::client::ImportNode& root_node() { + ASSERT_IS_GPU_THREAD; + return root_node_; + } + + void Present(flow::CompositorContext::ScopedFrame& frame, + ftl::Closure on_present_callback); + + private: + mozart::client::Session session_; + mozart::client::ImportNode root_node_; + mozart::client::Session::PresentCallback present_callback_; + ftl::Closure pending_on_present_callback_; + std::unique_ptr surface_producer_; + flow::SceneUpdateContext scene_update_context_; + + void OnSessionError(); + + void EnqueueClearOps(); + + void OnPresent(mozart2::PresentationInfoPtr info); + + FTL_DISALLOW_COPY_AND_ASSIGN(SessionConnection); +}; + +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ diff --git a/content_handler/software_rasterizer.cc b/content_handler/software_rasterizer.cc deleted file mode 100644 index 21c37c7a9..000000000 --- a/content_handler/software_rasterizer.cc +++ /dev/null @@ -1,92 +0,0 @@ -// 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 "flutter/content_handler/software_rasterizer.h" - -#include -#include - -#include "apps/mozart/lib/skia/skia_vmo_surface.h" -#include "lib/ftl/logging.h" -#include "third_party/skia/include/core/SkCanvas.h" - -namespace flutter_runner { - -SoftwareRasterizer::RasterSurfaceProducer::RasterSurfaceProducer() { - buffer_producer_.reset(new mozart::BufferProducer()); -} - -sk_sp SoftwareRasterizer::RasterSurfaceProducer::ProduceSurface( - SkISize size, - mozart::ImagePtr* out_image) { - return mozart::MakeSkSurface(size, buffer_producer_.get(), out_image); -} - -SoftwareRasterizer::SoftwareRasterizer() : compositor_context_(nullptr) {} - -SoftwareRasterizer::~SoftwareRasterizer() = default; - -void SoftwareRasterizer::SetScene(fidl::InterfaceHandle scene) { - scene_.Bind(std::move(scene)); - surface_producer_.reset(new RasterSurfaceProducer()); -} - -void SoftwareRasterizer::Draw(std::unique_ptr layer_tree, - ftl::Closure callback) { - FTL_DCHECK(layer_tree); - if (!scene_) { - callback(); - return; - } - - compositor_context_.engine_time().SetLapTime(layer_tree->construction_time()); - - const SkISize& frame_size = layer_tree->frame_size(); - - auto update = mozart::SceneUpdate::New(); - // TODO(abarth): Support incremental updates. - update->clear_resources = true; - update->clear_nodes = true; - - if (frame_size.isEmpty()) { - update->nodes.insert(mozart::kSceneRootNodeId, mozart::Node::New()); - // Publish the updated scene contents. - // TODO(jeffbrown): We should set the metadata's presentation_time here too. - scene_->Update(std::move(update)); - auto metadata = mozart::SceneMetadata::New(); - metadata->version = layer_tree->scene_version(); - scene_->Publish(std::move(metadata)); - callback(); - return; - } - - flow::CompositorContext::ScopedFrame frame = compositor_context_.AcquireFrame( - nullptr, nullptr, true /* instrumentation enabled */); - - layer_tree->Preroll(frame); - - flow::SceneUpdateContext context(update.get(), surface_producer_.get()); - auto root_node = mozart::Node::New(); - root_node->hit_test_behavior = mozart::HitTestBehavior::New(); - layer_tree->UpdateScene(context, root_node.get()); - update->nodes.insert(mozart::kSceneRootNodeId, std::move(root_node)); - - // Publish the updated scene contents. - // TODO(jeffbrown): We should set the metadata's presentation_time here too. - scene_->Update(std::move(update)); - auto metadata = mozart::SceneMetadata::New(); - metadata->version = layer_tree->scene_version(); - scene_->Publish(std::move(metadata)); - - // Draw the contents of the scene to a surface. - // We do this after publishing to take advantage of pipelining. - // The image buffer's fence is signalled automatically when the surface - // goes out of scope. - context.ExecutePaintTasks(frame); - surface_producer_->Tick(); - - callback(); -} - -} // namespace flutter_runner diff --git a/content_handler/software_rasterizer.h b/content_handler/software_rasterizer.h deleted file mode 100644 index 50dab87b6..000000000 --- a/content_handler/software_rasterizer.h +++ /dev/null @@ -1,50 +0,0 @@ -// 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. - -#ifndef FLUTTER_CONTENT_HANDLER_SOFTWARE_RASTERIZER_H_ -#define FLUTTER_CONTENT_HANDLER_SOFTWARE_RASTERIZER_H_ - -#include - -#include "apps/mozart/services/buffers/cpp/buffer_producer.h" -#include "flutter/content_handler/rasterizer.h" -#include "flutter/flow/compositor_context.h" -#include "lib/ftl/macros.h" - -namespace flutter_runner { - -class SoftwareRasterizer : public Rasterizer { - public: - SoftwareRasterizer(); - - ~SoftwareRasterizer() override; - - void SetScene(fidl::InterfaceHandle scene) override; - - void Draw(std::unique_ptr layer_tree, - ftl::Closure callback) override; - - private: - class RasterSurfaceProducer - : public flow::SceneUpdateContext::SurfaceProducer { - public: - RasterSurfaceProducer(); - sk_sp ProduceSurface(SkISize size, - mozart::ImagePtr* out_image) override; - void Tick() { buffer_producer_->Tick(); } - - private: - std::unique_ptr buffer_producer_; - }; - - mozart::ScenePtr scene_; - std::unique_ptr surface_producer_; - flow::CompositorContext compositor_context_; - - FTL_DISALLOW_COPY_AND_ASSIGN(SoftwareRasterizer); -}; - -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_SOFTWARE_RASTERIZER_H_ diff --git a/content_handler/vulkan_native_rasterizer.cc b/content_handler/vulkan_native_rasterizer.cc deleted file mode 100644 index 40985c36c..000000000 --- a/content_handler/vulkan_native_rasterizer.cc +++ /dev/null @@ -1,90 +0,0 @@ -// 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 "flutter/content_handler/vulkan_native_rasterizer.h" - -#include - -#include "flutter/vulkan/vulkan_native_surface_magma.h" - -namespace flutter_runner { - -VulkanNativeRasterizer::VulkanNativeRasterizer() - : compositor_context_(nullptr) { - auto proc_table = ftl::MakeRefCounted(); - - if (!proc_table->HasAcquiredMandatoryProcAddresses()) { - return; - } - - auto native_surface = std::make_unique(); - - if (!native_surface->IsValid()) { - return; - } - - auto window = std::make_unique( - proc_table, std::move(native_surface)); - - if (!window->IsValid()) { - return; - } - - window_ = std::move(window); -} - -VulkanNativeRasterizer::~VulkanNativeRasterizer() = default; - -bool VulkanNativeRasterizer::IsValid() const { - return window_ == nullptr ? false : window_->IsValid(); -} - -void VulkanNativeRasterizer::SetScene( - fidl::InterfaceHandle scene) { - // TODO: Composition is currently unsupported using the Vulkan backend. -} - -void VulkanNativeRasterizer::Draw(std::unique_ptr layer_tree, - ftl::Closure callback) { - Draw(std::move(layer_tree)); - callback(); -} - -bool VulkanNativeRasterizer::Draw(std::unique_ptr layer_tree) { - if (layer_tree == nullptr) { - FTL_DLOG(INFO) << "Layer tree was not valid."; - return false; - } - - if (!window_->IsValid()) { - FTL_DLOG(INFO) << "Vulkan window was not valid."; - return false; - } - - auto surface = window_->AcquireSurface(); - - if (!surface && surface->getCanvas() != nullptr) { - FTL_DLOG(INFO) << "Could not acquire a vulkan surface."; - return false; - } - - { - auto compositor_frame = compositor_context_.AcquireFrame( - window_->GetSkiaGrContext(), // GrContext* - surface->getCanvas(), // SkCanvas - true // instrumentation - ); - - layer_tree->Raster(compositor_frame); - } - - if (!window_->SwapBuffers()) { - FTL_DLOG(INFO) << "Could not swap buffers successfully."; - return false; - } - - return true; -} - -} // namespace flutter_runner diff --git a/content_handler/vulkan_native_rasterizer.h b/content_handler/vulkan_native_rasterizer.h deleted file mode 100644 index bf54f2d76..000000000 --- a/content_handler/vulkan_native_rasterizer.h +++ /dev/null @@ -1,41 +0,0 @@ -// 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. - -#ifndef FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ -#define FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ - -#include - -#include "flutter/content_handler/rasterizer.h" -#include "flutter/flow/compositor_context.h" -#include "flutter/vulkan/vulkan_window.h" -#include "lib/ftl/macros.h" - -namespace flutter_runner { - -class VulkanNativeRasterizer : public Rasterizer { - public: - VulkanNativeRasterizer(); - - ~VulkanNativeRasterizer() override; - - bool IsValid() const; - - void SetScene(fidl::InterfaceHandle scene) override; - - void Draw(std::unique_ptr layer_tree, - ftl::Closure callback) override; - - private: - std::unique_ptr window_; - flow::CompositorContext compositor_context_; - - bool Draw(std::unique_ptr layer_tree); - - FTL_DISALLOW_COPY_AND_ASSIGN(VulkanNativeRasterizer); -}; - -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ \ No newline at end of file diff --git a/content_handler/vulkan_rasterizer.cc b/content_handler/vulkan_rasterizer.cc index 2eaccb6c3..a4ef81291 100644 --- a/content_handler/vulkan_rasterizer.cc +++ b/content_handler/vulkan_rasterizer.cc @@ -13,22 +13,22 @@ #include #include -#include "lib/ftl/files/unique_fd.h" -#include "third_party/skia/include/gpu/GrContext.h" -#include "third_party/skia/include/gpu/vk/GrVkTypes.h" -#include "third_party/skia/src/gpu/vk/GrVkUtil.h" +#include "flutter/common/threads.h" #include "flutter/glue/trace_event.h" +#include "lib/ftl/files/unique_fd.h" namespace flutter_runner { -namespace { constexpr char kDisplayDriverClass[] = "/dev/class/display"; -static mx_status_t DriverWatcher(int dirfd, int event, const char* fn, void* cookie) { - if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) { - return MX_ERR_STOP; - } - return MX_OK; +static mx_status_t DriverWatcher(int dirfd, + int event, + const char* fn, + void* cookie) { + if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) { + return MX_ERR_STOP; + } + return MX_OK; } bool WaitForFirstDisplayDriver() { @@ -38,481 +38,72 @@ bool WaitForFirstDisplayDriver() { return false; } - mx_status_t status = mxio_watch_directory(fd.get(), DriverWatcher, - mx_deadline_after(MX_SEC(1)), - nullptr); + mx_status_t status = mxio_watch_directory( + fd.get(), DriverWatcher, mx_deadline_after(MX_SEC(1)), nullptr); return status == MX_ERR_STOP; } -} // namespace - -VulkanRasterizer::VulkanSurfaceProducer::VulkanSurfaceProducer() { - valid_ = Initialize(); - if (!valid_) - FTL_LOG(ERROR) << "VulkanSurfaceProducer failed to initialize"; -} - -VulkanRasterizer::VulkanSurfaceProducer::~VulkanSurfaceProducer() { - for (auto& surface_info : pending_surfaces_) - mtl::MessageLoop::GetCurrent()->RemoveHandler( - surface_info.second.handler_key); -} - -std::unique_ptr -VulkanRasterizer::VulkanSurfaceProducer::CreateSurface(uint32_t width, - uint32_t height) { - VkResult vk_result; - - 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{width, 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_result = VK_CALL_LOG_ERROR(vkCreateImage( - backend_context_->fDevice, &image_create_info, nullptr, &vk_image)); - if (vk_result) - return nullptr; - - VkMemoryRequirements memory_reqs; - vkGetImageMemoryRequirements(backend_context_->fDevice, vk_image, - &memory_reqs); - - uint32_t memory_type = 0; - for (; memory_type < 32; memory_type++) { - if ((memory_reqs.memoryTypeBits & (1 << memory_type))) - break; - } - - VkMemoryAllocateInfo alloc_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, - .allocationSize = memory_reqs.size, - .memoryTypeIndex = memory_type, - }; - - VkDeviceMemory vk_memory; - vk_result = VK_CALL_LOG_ERROR(vkAllocateMemory( - backend_context_->fDevice, &alloc_info, NULL, &vk_memory)); - if (vk_result) - return nullptr; - - vk_result = VK_CALL_LOG_ERROR( - vkBindImageMemory(backend_context_->fDevice, vk_image, vk_memory, 0)); - if (vk_result) - return nullptr; - - const GrVkImageInfo image_info = { - .fImage = vk_image, - .fAlloc = {vk_memory, 0, memory_reqs.size, 0}, - .fImageTiling = image_create_info.tiling, - .fImageLayout = image_create_info.initialLayout, - .fFormat = image_create_info.format, - .fLevelCount = image_create_info.mipLevels, - }; - - GrBackendRenderTargetDesc desc; - desc.fWidth = width; - desc.fHeight = height; - desc.fConfig = kSBGRA_8888_GrPixelConfig; - desc.fOrigin = kTopLeft_GrSurfaceOrigin; - desc.fSampleCnt = 0; - desc.fStencilBits = 0; - - desc.fRenderTargetHandle = reinterpret_cast(&image_info); - - SkSurfaceProps props(SkSurfaceProps::InitType::kLegacyFontHost_InitType); - - auto sk_surface = SkSurface::MakeFromBackendRenderTarget(context_.get(), desc, - nullptr, &props); - if (!sk_surface) { - FTL_LOG(ERROR) << "MakeFromBackendRenderTarget Failed"; - return nullptr; - } - - uint32_t vmo_handle; - vk_result = VK_CALL_LOG_ERROR(vkExportDeviceMemoryMAGMA( - backend_context_->fDevice, vk_memory, &vmo_handle)); - if (vk_result) - return nullptr; - - mx::vmo vmo(vmo_handle); - - size_t vmo_size; - vmo.get_size(&vmo_size); - - FTL_DCHECK(vmo_size >= memory_reqs.size); - - mx::eventpair retention_events[2]; - auto mx_status = - mx::eventpair::create(0, &retention_events[0], &retention_events[1]); - if (mx_status) { - FTL_LOG(ERROR) << "Failed to create retention eventpair"; - return nullptr; - } - - if (!sk_surface || sk_surface->getCanvas() == nullptr) { - FTL_LOG(ERROR) << "surface invalid"; - return nullptr; - } - - return std::make_unique(backend_context_, sk_surface, std::move(vmo), - std::move(retention_events[0]), - std::move(retention_events[1]), vk_image, - vk_memory); -} - -sk_sp VulkanRasterizer::VulkanSurfaceProducer::ProduceSurface( - SkISize size, - mozart::ImagePtr* out_image) { - if (size.isEmpty()) { - FTL_LOG(ERROR) << "Attempting to create surface with empty size"; - return nullptr; - } - - // these casts are safe because of the early out on frame_size.isEmpty() - auto width = static_cast(size.width()); - auto height = static_cast(size.height()); - - std::unique_ptr surface; - // try and find a Swapchain with surfaces of the right size - auto it = available_surfaces_.find(MakeSizeKey(width, height)); - if (it == available_surfaces_.end()) { - // No matching Swapchain exists, create a new surfaces - surface = CreateSurface(width, height); - } else { - auto& swapchain = it->second; - if (swapchain.queue.size() == 0) { - // matching Swapchain exists, but does not have any buffers available in - // it - surface = CreateSurface(width, height); - } else { - surface = std::move(swapchain.queue.front()); - swapchain.queue.pop(); - swapchain.tick_count = 0; - - // Need to do some skia foo here to clear all the canvas state from the - // last frame - surface->sk_surface->getCanvas()->restoreToCount(0); - surface->sk_surface->getCanvas()->save(); - surface->sk_surface->getCanvas()->resetMatrix(); - } - } - - if (!surface) { - FTL_LOG(ERROR) << "Failed to produce surface"; - return nullptr; - } - - mx_status_t status; - auto buffer = mozart::Buffer::New(); - status = surface->vmo.duplicate(MX_RIGHT_SAME_RIGHTS, &buffer->vmo); - if (status) { - FTL_LOG(ERROR) << "failed to duplicate vmo"; - return nullptr; - } - - buffer->memory_type = mozart::Buffer::MemoryType::VK_DEVICE_MEMORY; - - mx::eventpair fence_event; - status = mx::eventpair::create(0, &fence_event, &buffer->fence); - if (status) { - FTL_LOG(ERROR) << "failed to create fence eventpair"; - return nullptr; - } - - mtl::MessageLoop::HandlerKey handler_key = - mtl::MessageLoop::GetCurrent()->AddHandler(this, fence_event.get(), - MX_EPAIR_PEER_CLOSED); - - status = surface->remote_retention_event.duplicate(MX_RIGHT_SAME_RIGHTS, - &buffer->retention); - if (status) { - FTL_LOG(ERROR) << "failed to duplicate retention eventpair"; - return nullptr; - } - - auto image = mozart::Image::New(); - image->size = mozart::Size::New(); - image->size->width = width; - image->size->height = height; - image->stride = 4 * width; - image->pixel_format = mozart::Image::PixelFormat::B8G8R8A8; - image->alpha_format = mozart::Image::AlphaFormat::OPAQUE; - image->color_space = mozart::Image::ColorSpace::SRGB; - image->buffer = std::move(buffer); - *out_image = std::move(image); - - auto sk_surface = surface->sk_surface; - PendingSurfaceInfo info; - info.handler_key = handler_key; - info.surface = std::move(surface); - info.production_fence = std::move(fence_event); - outstanding_surfaces_.push_back(std::move(info)); - - return sk_surface; -} - -bool VulkanRasterizer::VulkanSurfaceProducer::FinishFrame() { - mx_status_t status; - - // Finish Rendering - context_->flush(); - VkResult result = - VK_CALL_LOG_ERROR(vkQueueWaitIdle(backend_context_->fQueue)); - if (result) - return false; - - for (auto& info : outstanding_surfaces_) { - // info.surface->sk_surface->prepareForExternalIO(); - // Signal the compositor - status = info.production_fence.signal_peer(0u, MX_EPAIR_SIGNALED); - if (status) { - FTL_LOG(ERROR) << "failed to signal fence event"; - return false; - } - - pending_surfaces_.insert( - std::make_pair(info.production_fence.get(), std::move(info))); - } - outstanding_surfaces_.clear(); - return true; -} - -void VulkanRasterizer::VulkanSurfaceProducer::Tick() { - for (auto it = available_surfaces_.begin(); - it != available_surfaces_.end();) { - auto& swapchain = it->second; - swapchain.tick_count++; - if (swapchain.tick_count > Swapchain::kMaxTickBeforeDiscard) - it = available_surfaces_.erase(it); - else - it++; - } -} - -void VulkanRasterizer::VulkanSurfaceProducer::OnHandleReady( - mx_handle_t handle, - mx_signals_t pending, - uint64_t count) { - FTL_DCHECK(pending & MX_EPAIR_PEER_CLOSED); - - auto it = pending_surfaces_.find(handle); - FTL_DCHECK(it != pending_surfaces_.end()); - - // Add the newly available buffer to the swapchain. - PendingSurfaceInfo& info = it->second; - mtl::MessageLoop::GetCurrent()->RemoveHandler(info.handler_key); - - // try and find a Swapchain with surfaces of the right size - size_key_t key = MakeSizeKey(info.surface->sk_surface->width(), - info.surface->sk_surface->height()); - auto swapchain_it = available_surfaces_.find(key); - if (swapchain_it == available_surfaces_.end()) { - // No matching Swapchain exists, create one - Swapchain swapchain; - if (swapchain.queue.size() + 1 <= Swapchain::kMaxSurfaces) { - swapchain.queue.push(std::move(info.surface)); - } - available_surfaces_.insert(std::make_pair(key, std::move(swapchain))); - } else { - auto& swapchain = swapchain_it->second; - if (swapchain.queue.size() + 1 <= Swapchain::kMaxSurfaces) { - swapchain.queue.push(std::move(info.surface)); - } - } - - pending_surfaces_.erase(it); -} - -bool VulkanRasterizer::VulkanSurfaceProducer::Initialize() { - vk_ = ftl::MakeRefCounted(); - - std::vector extensions = {VK_KHR_SURFACE_EXTENSION_NAME}; - application_ = std::make_unique( - *vk_, "Flutter", std::move(extensions)); - - if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) { - // Make certain the application instance was created and it setup the - // instance proc table entries. - FTL_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. - FTL_LOG(ERROR) << "Device proc addresses have not been setup."; - return false; - } - - if (!vk_->HasAcquiredMandatoryProcAddresses()) { - FTL_LOG(ERROR) << "Failed to acquire mandatory proc addresses"; - return false; - } - - if (!vk_->IsValid()) { - FTL_LOG(ERROR) << "VulkanProcTable invalid"; - return false; - } - - auto interface = vk_->CreateSkiaInterface(); - - if (interface == nullptr || !interface->validate(0)) { - FTL_LOG(ERROR) << "interface invalid"; - return false; - } - - uint32_t skia_features = 0; - if (!logical_device_->GetPhysicalDeviceFeaturesSkia(&skia_features)) { - FTL_LOG(ERROR) << "Failed to get physical device features"; - - return false; - } - - backend_context_ = sk_make_sp(); - 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_.reset(GrContext::Create( - kVulkan_GrBackend, - reinterpret_cast(backend_context_.get()))); - - context_->setResourceCacheLimits(vulkan::kGrCacheMaxCount, - vulkan::kGrCacheMaxByteSize); - - FTL_DLOG(INFO) << "Successfully initialized VulkanRasterizer"; - return true; -} - VulkanRasterizer::VulkanRasterizer() : compositor_context_(nullptr) { valid_ = WaitForFirstDisplayDriver(); - surface_producer_.reset(new VulkanSurfaceProducer()); } VulkanRasterizer::~VulkanRasterizer() = default; bool VulkanRasterizer::IsValid() const { - return valid_ && surface_producer_ && surface_producer_->IsValid(); + return valid_; } -void VulkanRasterizer::SetScene(fidl::InterfaceHandle scene) { - scene_.Bind(std::move(scene)); +void VulkanRasterizer::SetSession( + fidl::InterfaceHandle session, + mx::eventpair import_token) { + ASSERT_IS_GPU_THREAD; + FTL_DCHECK(valid_ && !session_connection_); + session_connection_ = std::make_unique( + std::move(session), std::move(import_token)); } void VulkanRasterizer::Draw(std::unique_ptr layer_tree, ftl::Closure callback) { - Draw(std::move(layer_tree)); - callback(); -} + ASSERT_IS_GPU_THREAD; + FTL_DCHECK(callback != nullptr); -bool VulkanRasterizer::Draw(std::unique_ptr layer_tree) { if (layer_tree == nullptr) { FTL_LOG(ERROR) << "Layer tree was not valid."; - return false; + callback(); + return; } - if (!scene_) { - FTL_LOG(ERROR) << "Scene was not valid."; - return false; + if (!session_connection_) { + FTL_LOG(ERROR) << "Session was not valid."; + callback(); + return; } compositor_context_.engine_time().SetLapTime(layer_tree->construction_time()); - const SkISize& frame_size = layer_tree->frame_size(); - - auto update = mozart::SceneUpdate::New(); - // TODO(abarth): Support incremental updates. - update->clear_resources = true; - update->clear_nodes = true; - - if (frame_size.isEmpty()) { - update->nodes.insert(mozart::kSceneRootNodeId, mozart::Node::New()); - // Publish the updated scene contents. - // TODO(jeffbrown): We should set the metadata's presentation_time here too. - scene_->Update(std::move(update)); - auto metadata = mozart::SceneMetadata::New(); - metadata->version = layer_tree->scene_version(); - scene_->Publish(std::move(metadata)); - FTL_LOG(ERROR) << "Publishing empty node"; - - return false; - } - flow::CompositorContext::ScopedFrame frame = compositor_context_.AcquireFrame( nullptr, nullptr, true /* instrumentation enabled */); { + // Preroll the Flutter layer tree. This allows Flutter to perform pre-paint + // optimizations. TRACE_EVENT0("flutter", "Preroll"); layer_tree->Preroll(frame); - } - flow::SceneUpdateContext context(update.get(), surface_producer_.get()); - auto root_node = mozart::Node::New(); { + // 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"); - root_node->hit_test_behavior = mozart::HitTestBehavior::New(); - layer_tree->UpdateScene(context, root_node.get()); - update->nodes.insert(mozart::kSceneRootNodeId, std::move(root_node)); - - // Publish the updated scene contents. - // TODO(jeffbrown): We should set the metadata's presentation_time here too. - scene_->Update(std::move(update)); - } - - { - TRACE_EVENT0("flutter", "Publish"); - auto metadata = mozart::SceneMetadata::New(); - metadata->version = layer_tree->scene_version(); - scene_->Publish(std::move(metadata)); + layer_tree->UpdateScene(session_connection_->scene_update_context(), + session_connection_->root_node()); } { - TRACE_EVENT0("flutter", "ExecutePaintTasks"); - // Draw the contents of the scene to a surface. - // We do this after publishing to take advantage of pipelining. - context.ExecutePaintTasks(frame); + // Flush all pending session ops. + TRACE_EVENT0("flutter", "SessionPresent"); + session_connection_->Present( + frame, [callback = std::move(callback)]() { callback(); }); } - { - TRACE_EVENT0("flutter", "FinishFrame/Tick"); - if (!surface_producer_->FinishFrame()) { - FTL_LOG(ERROR) << "Failed to Finish Frame"; - return false; - } - surface_producer_->Tick(); - } - - - return true; } } // namespace flutter_runner diff --git a/content_handler/vulkan_rasterizer.h b/content_handler/vulkan_rasterizer.h index f600ce187..9d0ddc0c6 100644 --- a/content_handler/vulkan_rasterizer.h +++ b/content_handler/vulkan_rasterizer.h @@ -6,17 +6,11 @@ #define FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ #include -#include -#include -#include -#include "apps/mozart/services/buffers/cpp/buffer_producer.h" #include "flutter/content_handler/rasterizer.h" +#include "flutter/content_handler/session_connection.h" #include "flutter/flow/compositor_context.h" -#include "flutter/vulkan/vulkan_application.h" -#include "flutter/vulkan/vulkan_device.h" #include "lib/ftl/macros.h" -#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h" namespace flutter_runner { @@ -28,124 +22,17 @@ class VulkanRasterizer : public Rasterizer { bool IsValid() const; - void SetScene(fidl::InterfaceHandle scene) override; + void SetSession(fidl::InterfaceHandle session, + mx::eventpair import_token) override; void Draw(std::unique_ptr layer_tree, ftl::Closure callback) override; private: - class VulkanSurfaceProducer - : public flow::SceneUpdateContext::SurfaceProducer, - private mtl::MessageLoopHandler { - public: - VulkanSurfaceProducer(); - ~VulkanSurfaceProducer() override; - sk_sp ProduceSurface(SkISize size, - mozart::ImagePtr* out_image) override; - - void Tick(); - bool FinishFrame(); - bool IsValid() const { return valid_; } - - private: - // |mtl::MessageLoopHandler| - void OnHandleReady(mx_handle_t handle, - mx_signals_t pending, - uint64_t count) override; - - struct Surface { - sk_sp backend_context; - sk_sp sk_surface; - mx::vmo vmo; - mx::eventpair local_retention_event; - mx::eventpair remote_retention_event; - VkImage vk_image; - VkDeviceMemory vk_memory; - - Surface(sk_sp backend_context, - sk_sp sk_surface, - mx::vmo vmo, - mx::eventpair local_retention_event, - mx::eventpair remote_retention_event, - VkImage vk_image, - VkDeviceMemory vk_memory) - : backend_context(std::move(backend_context)), - sk_surface(std::move(sk_surface)), - vmo(std::move(vmo)), - local_retention_event(std::move(local_retention_event)), - remote_retention_event(std::move(remote_retention_event)), - vk_image(vk_image), - vk_memory(vk_memory) {} - - ~Surface() { - FTL_DCHECK(backend_context); - vkFreeMemory(backend_context->fDevice, vk_memory, NULL); - vkDestroyImage(backend_context->fDevice, vk_image, NULL); - } - }; - - std::unique_ptr CreateSurface(uint32_t width, uint32_t height); - - struct Swapchain { - std::queue> queue; - uint32_t tick_count = 0; - static constexpr uint32_t kMaxSurfaces = 3; - static constexpr uint32_t kMaxTickBeforeDiscard = 3; - }; - - using size_key_t = uint64_t; - static size_key_t MakeSizeKey(uint32_t width, uint32_t height) { - return (static_cast(width) << 32) | - static_cast(height); - } - - // Note: the order here is very important. The proctable bust 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 - ftl::RefPtr vk_; - sk_sp backend_context_; - std::unique_ptr logical_device_; - std::unique_ptr application_; - sk_sp context_; - - // These three containers hold surfaces in various stages of recycling - - // Buffers exist in available_surfaces_ when they are ready to be recycled - // ProduceSurface will look here for an appropriately sized surface before - // creating a new one - // The Swapchain's tick_count is incremented in Tick and decremented when - // a surface is taken from the queue, when the tick count goes above - // kMaxTickBeforeDiscard the Swapchain is discarded. Newly surfaces are - // added to the queue iff there aar less than kMaxSurfaces already in the - // queue - std::unordered_map available_surfaces_; - - struct PendingSurfaceInfo { - mtl::MessageLoop::HandlerKey handler_key; - std::unique_ptr surface; - mx::eventpair production_fence; - }; - // Surfaces produced by ProduceSurface live in outstanding_surfaces_ until - // FinishFrame is called, at which point they are moved to pending_surfaces_ - std::vector outstanding_surfaces_; - // Surfaces exist in pendind surfaces until they are released by the buffer - // consumer - std::unordered_map pending_surfaces_; - bool valid_; - - bool Initialize(); - }; - flow::CompositorContext compositor_context_; - mozart::ScenePtr scene_; - std::unique_ptr surface_producer_; + std::unique_ptr session_connection_; bool valid_; - bool Draw(std::unique_ptr layer_tree); - FTL_DISALLOW_COPY_AND_ASSIGN(VulkanRasterizer); }; diff --git a/content_handler/vulkan_surface.cc b/content_handler/vulkan_surface.cc new file mode 100644 index 000000000..128e972d3 --- /dev/null +++ b/content_handler/vulkan_surface.cc @@ -0,0 +1,340 @@ +// 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 "flutter/content_handler/vulkan_surface.h" +#include "flutter/common/threads.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/gpu/GrContext.h" +#include "third_party/skia/src/gpu/vk/GrVkImage.h" + +namespace flutter_runner { + +VulkanSurface::VulkanSurface(vulkan::VulkanProcTable& p_vk, + sk_sp context, + sk_sp backend_context, + mozart::client::Session* session, + const SkISize& size) + : vk_(p_vk), + backend_context_(std::move(backend_context)), + session_(session) { + ASSERT_IS_GPU_THREAD; + + FTL_DCHECK(session_); + + mx::vmo exported_vmo; + if (!AllocateDeviceMemory(std::move(context), size, exported_vmo)) { + FTL_DLOG(INFO) << "Could not allocate device memory."; + return; + } + + if (!CreateFences()) { + FTL_DLOG(INFO) << "Could not create signal fences."; + return; + } + + if (!PushSessionImageSetupOps(session, std::move(exported_vmo))) { + FTL_DLOG(INFO) << "Could not push session image setup ops."; + return; + } + + event_handler_key_ = mtl::MessageLoop::GetCurrent()->AddHandler( + this, release_event_.get(), MX_USER_SIGNAL_0); + + // Probably not necessary as the events should be in the unsignalled state + // already. + Reset(); + + valid_ = true; +} + +VulkanSurface::~VulkanSurface() { + ASSERT_IS_GPU_THREAD; + if (event_handler_key_ != 0) { + mtl::MessageLoop::GetCurrent()->RemoveHandler(event_handler_key_); + event_handler_key_ = 0; + } +} + +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()); +} + +bool VulkanSurface::CreateFences() { + if (mx::event::create(0, &acquire_event_) != MX_OK) { + return false; + } + + if (mx::event::create(0, &release_event_) != MX_OK) { + return false; + } + + return true; +} + +bool VulkanSurface::AllocateDeviceMemory(sk_sp context, + const SkISize& size, + mx::vmo& exported_vmo) { + if (size.isEmpty()) { + return false; + } + + if (backend_context_ == nullptr) { + return false; + } + + // 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(size.width()), + static_cast(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(vk_.CreateImage(backend_context_->fDevice, + &image_create_info, nullptr, + &vk_image)) != VK_SUCCESS) { + return false; + } + + vk_image_ = {vk_image, [this](VkImage image) { + vk_.DestroyImage(backend_context_->fDevice, image, NULL); + }}; + } + + // Create the memory. + VkMemoryRequirements memory_reqs; + vk_.GetImageMemoryRequirements(backend_context_->fDevice, // + vk_image_, // + &memory_reqs // + ); + + uint32_t memory_type = 0; + for (; memory_type < 32; memory_type++) { + if ((memory_reqs.memoryTypeBits & (1 << memory_type))) { + break; + } + } + + const VkMemoryAllocateInfo alloc_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = nullptr, + .allocationSize = memory_reqs.size, + .memoryTypeIndex = memory_type, + }; + + { + VkDeviceMemory vk_memory = VK_NULL_HANDLE; + if (VK_CALL_LOG_ERROR(vk_.AllocateMemory(backend_context_->fDevice, + &alloc_info, NULL, &vk_memory)) != + VK_SUCCESS) { + return false; + } + + vk_memory_ = {vk_memory, [this](VkDeviceMemory memory) { + vk_.FreeMemory(backend_context_->fDevice, memory, NULL); + }}; + } + + // Bind image memory. + if (VK_CALL_LOG_ERROR(vk_.BindImageMemory( + backend_context_->fDevice, vk_image_, vk_memory_, 0)) != VK_SUCCESS) { + return false; + } + + { + // Acquire the VMO for the device memory. + uint32_t vmo_handle = 0; + if (VK_CALL_LOG_ERROR(vk_.ExportDeviceMemoryMAGMA( + backend_context_->fDevice, vk_memory_, &vmo_handle)) != + VK_SUCCESS) { + return false; + } + exported_vmo.reset(static_cast(vmo_handle)); + } + + // Assert that the VMO size was sufficient. + size_t vmo_size = 0; + if (exported_vmo.get_size(&vmo_size) != MX_OK || + vmo_size < memory_reqs.size) { + return false; + } + + return SetupSkiaSurface(std::move(context), size, image_create_info, + memory_reqs); +} + +bool VulkanSurface::SetupSkiaSurface(sk_sp context, + const SkISize& size, + const VkImageCreateInfo& image_create_info, + const VkMemoryRequirements& memory_reqs) { + if (context == nullptr) { + return false; + } + + const GrVkImageInfo image_info = { + .fImage = vk_image_, + .fAlloc = {vk_memory_, 0, memory_reqs.size, 0}, + .fImageTiling = image_create_info.tiling, + .fImageLayout = image_create_info.initialLayout, + .fFormat = image_create_info.format, + .fLevelCount = image_create_info.mipLevels, + }; + + GrBackendRenderTargetDesc sk_render_target_desc; + sk_render_target_desc.fWidth = size.width(); + sk_render_target_desc.fHeight = size.height(); + sk_render_target_desc.fConfig = kSBGRA_8888_GrPixelConfig; + sk_render_target_desc.fOrigin = kTopLeft_GrSurfaceOrigin; + sk_render_target_desc.fSampleCnt = 0; + sk_render_target_desc.fStencilBits = 0; + sk_render_target_desc.fRenderTargetHandle = + reinterpret_cast(&image_info); + + SkSurfaceProps sk_surface_props( + SkSurfaceProps::InitType::kLegacyFontHost_InitType); + + auto sk_surface = + SkSurface::MakeFromBackendRenderTarget(context.get(), // + sk_render_target_desc, // + nullptr, // + &sk_surface_props // + ); + + if (!sk_surface || sk_surface->getCanvas() == nullptr) { + return false; + } + sk_surface_ = std::move(sk_surface); + + return true; +} + +bool VulkanSurface::PushSessionImageSetupOps(mozart::client::Session* session, + mx::vmo exported_vmo) { + if (sk_surface_ == nullptr) { + return false; + } + + mozart::client::Memory memory(session, std::move(exported_vmo), + mozart2::MemoryType::VK_DEVICE_MEMORY); + + auto image_info = mozart2::ImageInfo::New(); + image_info->width = sk_surface_->width(); + image_info->height = sk_surface_->height(); + image_info->stride = 4 * sk_surface_->width(); + image_info->pixel_format = mozart2::ImageInfo::PixelFormat::BGRA_8; + image_info->color_space = mozart2::ImageInfo::ColorSpace::SRGB; + image_info->tiling = mozart2::ImageInfo::Tiling::LINEAR; + + session_image_ = std::make_unique( + memory, 0 /* memory offset */, std::move(image_info)); + + return session_image_ != nullptr; +} + +mozart::client::Image* VulkanSurface::GetImage() { + ASSERT_IS_GPU_THREAD; + if (!valid_) { + return 0; + } + return session_image_.get(); +} + +sk_sp VulkanSurface::GetSkiaSurface() const { + ASSERT_IS_GPU_THREAD; + return valid_ ? sk_surface_ : nullptr; +} + +size_t VulkanSurface::AdvanceAndGetAge() { + age_++; + return age_; +} + +bool VulkanSurface::FlushSessionAcquireAndReleaseEvents() { + mx::event acquire, release; + + if (acquire_event_.duplicate(MX_RIGHT_SAME_RIGHTS, &acquire) != MX_OK || + release_event_.duplicate(MX_RIGHT_SAME_RIGHTS, &release) != MX_OK) { + return false; + } + + session_->EnqueueAcquireFence(std::move(acquire)); + session_->EnqueueReleaseFence(std::move(release)); + age_ = 0; + return true; +} + +void VulkanSurface::SignalWritesFinished( + std::function on_writes_committed) { + ASSERT_IS_GPU_THREAD; + FTL_DCHECK(on_writes_committed); + + if (!valid_) { + on_writes_committed(); + return; + } + + FTL_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."; + + // Signal the acquire end to the compositor. + if (acquire_event_.signal(0u, MX_USER_SIGNAL_0) != MX_OK) { + on_writes_committed(); + return; + } + + pending_on_writes_committed_ = on_writes_committed; +} + +void VulkanSurface::Reset() { + ASSERT_IS_GPU_THREAD; + + if (acquire_event_.signal(MX_USER_SIGNAL_0, 0u) != MX_OK || + release_event_.signal(MX_USER_SIGNAL_0, 0u) != MX_OK) { + valid_ = false; + FTL_DLOG(ERROR) + << "Could not reset fences. The surface is no longer valid."; + } + + // 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(mx_handle_t handle, + mx_signals_t pending, + uint64_t count) { + ASSERT_IS_GPU_THREAD; + FTL_DCHECK(pending & MX_USER_SIGNAL_0); + FTL_DCHECK(handle == release_event_.get()); + Reset(); +} + +} // namespace flutter_runner diff --git a/content_handler/vulkan_surface.h b/content_handler/vulkan_surface.h new file mode 100644 index 000000000..fe91a7fe4 --- /dev/null +++ b/content_handler/vulkan_surface.h @@ -0,0 +1,91 @@ +// 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 +#include "apps/mozart/lib/scene/client/resources.h" +#include "flutter/flow/scene_update_context.h" +#include "flutter/vulkan/vulkan_handle.h" +#include "flutter/vulkan/vulkan_proc_table.h" +#include "lib/ftl/macros.h" +#include "lib/mtl/tasks/message_loop.h" +#include "lib/mtl/tasks/message_loop_handler.h" +#include "mx/event.h" +#include "mx/vmo.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h" + +namespace flutter_runner { + +class VulkanSurface : public flow::SceneUpdateContext::SurfaceProducerSurface, + public mtl::MessageLoopHandler { + public: + VulkanSurface(vulkan::VulkanProcTable& p_vk, + sk_sp context, + sk_sp backend_context, + mozart::client::Session* session, + const SkISize& size); + + ~VulkanSurface() override; + + size_t AdvanceAndGetAge() override; + + bool FlushSessionAcquireAndReleaseEvents() override; + + bool IsValid() const override; + + 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 on_writes_committed) override; + + // |flow::SceneUpdateContext::SurfaceProducerSurface| + mozart::client::Image* GetImage() override; + + // |flow::SceneUpdateContext::SurfaceProducerSurface| + sk_sp GetSkiaSurface() const override; + + private: + vulkan::VulkanProcTable& vk_; + sk_sp backend_context_; + mozart::client::Session* session_; + vulkan::VulkanHandle vk_image_; + vulkan::VulkanHandle vk_memory_; + sk_sp sk_surface_; + std::unique_ptr session_image_; + mx::event acquire_event_; + mx::event release_event_; + mtl::MessageLoop::HandlerKey event_handler_key_ = 0; + std::function pending_on_writes_committed_; + size_t age_ = 0; + bool valid_ = false; + + // |mtl::MessageLoopHandler| + void OnHandleReady(mx_handle_t handle, + mx_signals_t pending, + uint64_t count) override; + + bool AllocateDeviceMemory(sk_sp context, + const SkISize& size, + mx::vmo& exported_vmo); + + bool SetupSkiaSurface(sk_sp context, + const SkISize& size, + const VkImageCreateInfo& image_create_info, + const VkMemoryRequirements& memory_reqs); + + bool CreateFences(); + + bool PushSessionImageSetupOps(mozart::client::Session* session, + mx::vmo exported_vmo); + + void Reset(); + + FTL_DISALLOW_COPY_AND_ASSIGN(VulkanSurface); +}; + +} // namespace flutter_runner diff --git a/content_handler/vulkan_surface_pool.cc b/content_handler/vulkan_surface_pool.cc new file mode 100644 index 000000000..45c7f668d --- /dev/null +++ b/content_handler/vulkan_surface_pool.cc @@ -0,0 +1,177 @@ +// 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 "flutter/content_handler/vulkan_surface_pool.h" +#include "apps/tracing/lib/trace/event.h" +#include "third_party/skia/include/gpu/GrContext.h" + +namespace flutter_runner { + +VulkanSurfacePool::VulkanSurfacePool(vulkan::VulkanProcTable& p_vk, + sk_sp context, + sk_sp backend_context, + mozart::client::Session* mozart_session) + : vk_(p_vk), + context_(std::move(context)), + backend_context_(std::move(backend_context)), + mozart_session_(mozart_session) {} + +VulkanSurfacePool::~VulkanSurfacePool() {} + +std::unique_ptr +VulkanSurfacePool::AcquireSurface(const SkISize& size) { + auto surface = GetCachedOrCreateSurface(size); + + if (surface == nullptr) { + FTL_DLOG(ERROR) << "Could not acquire surface"; + return nullptr; + } + + if (!surface->FlushSessionAcquireAndReleaseEvents()) { + FTL_DLOG(ERROR) << "Could not flush acquir/release events for buffer."; + return nullptr; + } + + return surface; +} + +std::unique_ptr +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; + FTL_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 + p_surface) { + if (!p_surface) { + return; + } + + uintptr_t surface_key = reinterpret_cast(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 VulkanSurfacePool::CreateSurface( + const SkISize& size) { + auto surface = std::make_unique( + vk_, 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 + 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 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_runner diff --git a/content_handler/vulkan_surface_pool.h b/content_handler/vulkan_surface_pool.h new file mode 100644 index 000000000..dbd04df0f --- /dev/null +++ b/content_handler/vulkan_surface_pool.h @@ -0,0 +1,77 @@ +// 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 +#include +#include "flutter/content_handler/vulkan_surface.h" +#include "lib/ftl/macros.h" + +namespace flutter_runner { + +class VulkanSurfacePool { + public: + static const size_t kMaxSurfacesOfSameSize = 3; + static const size_t kMaxSurfaceAge = 3; + + VulkanSurfacePool(vulkan::VulkanProcTable& vk, + sk_sp context, + sk_sp backend_context, + mozart::client::Session* mozart_session); + + ~VulkanSurfacePool(); + + std::unique_ptr + AcquireSurface(const SkISize& size); + + void SubmitSurface( + std::unique_ptr + surface); + + void AgeAndCollectOldBuffers(); + + private: + using SurfacesSet = std::list< + std::unique_ptr>; + + template + static void HashCombine(size_t& seed, T const& v) { + seed ^= std::hash()(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::VulkanProcTable& vk_; + sk_sp context_; + sk_sp backend_context_; + mozart::client::Session* mozart_session_; + std::unordered_map available_surfaces_; + std::unordered_map< + uintptr_t, + std::unique_ptr> + pending_surfaces_; + size_t trace_surfaces_created_ = 0; + size_t trace_surfaces_reused_ = 0; + + std::unique_ptr + GetCachedOrCreateSurface(const SkISize& size); + + std::unique_ptr CreateSurface(const SkISize& size); + + void RecycleSurface(uintptr_t surface_key); + + void TraceStats(); + + FTL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfacePool); +}; + +} // namespace flutter_runner diff --git a/content_handler/vulkan_surface_producer.cc b/content_handler/vulkan_surface_producer.cc new file mode 100644 index 000000000..a632959c7 --- /dev/null +++ b/content_handler/vulkan_surface_producer.cc @@ -0,0 +1,138 @@ +// 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 "flutter/content_handler/vulkan_surface_producer.h" +#include +#include +#include +#include "third_party/skia/include/gpu/GrContext.h" +#include "third_party/skia/include/gpu/vk/GrVkTypes.h" +#include "third_party/skia/src/gpu/vk/GrVkUtil.h" + +namespace flutter_runner { + +VulkanSurfaceProducer::VulkanSurfaceProducer( + mozart::client::Session* mozart_session) { + valid_ = Initialize(mozart_session); + + FTL_LOG(ERROR) << "Vulkan surface producer initialization: " + << (valid_ ? "Successful" : "Failed"); +} + +VulkanSurfaceProducer::~VulkanSurfaceProducer() = default; + +bool VulkanSurfaceProducer::Initialize( + mozart::client::Session* mozart_session) { + vk_ = ftl::MakeRefCounted(); + + std::vector extensions = {VK_KHR_SURFACE_EXTENSION_NAME}; + application_ = std::make_unique( + *vk_, "FlutterContentHandler", std::move(extensions)); + + if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) { + // Make certain the application instance was created and it setup the + // instance proc table entries. + FTL_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. + FTL_LOG(ERROR) << "Device proc addresses have not been setup."; + return false; + } + + if (!vk_->HasAcquiredMandatoryProcAddresses()) { + FTL_LOG(ERROR) << "Failed to acquire mandatory proc addresses"; + return false; + } + + if (!vk_->IsValid()) { + FTL_LOG(ERROR) << "VulkanProcTable invalid"; + return false; + } + + auto interface = vk_->CreateSkiaInterface(); + + if (interface == nullptr || !interface->validate(0)) { + FTL_LOG(ERROR) << "interface invalid"; + return false; + } + + uint32_t skia_features = 0; + if (!logical_device_->GetPhysicalDeviceFeaturesSkia(&skia_features)) { + FTL_LOG(ERROR) << "Failed to get physical device features"; + + return false; + } + + backend_context_ = sk_make_sp(); + 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_.reset(GrContext::Create( + kVulkan_GrBackend, + reinterpret_cast(backend_context_.get()))); + + context_->setResourceCacheLimits(vulkan::kGrCacheMaxCount, + vulkan::kGrCacheMaxByteSize); + + surface_pool_ = std::make_unique( + *vk_, context_, backend_context_, mozart_session); + + return true; +} + +void VulkanSurfaceProducer::OnSurfacesPresented( + std::vector< + std::unique_ptr> + surfaces) { + // Do a single flush for all canvases derived from the context. + context_->flush(); + + // Do a CPU wait. + // TODO(chinmaygarde): Remove this once we have support for Vulkan semaphores. + VkResult wait_result = + VK_CALL_LOG_ERROR(vk_->QueueWaitIdle(backend_context_->fQueue)); + FTL_DCHECK(wait_result == VK_SUCCESS); + + // Submit surface, this signals acquire events sent along the session. + for (auto& surface : surfaces) { + SubmitSurface(std::move(surface)); + } + + // Buffer management. + surface_pool_->AgeAndCollectOldBuffers(); +} + +std::unique_ptr +VulkanSurfaceProducer::ProduceSurface(const SkISize& size) { + FTL_DCHECK(valid_); + return surface_pool_->AcquireSurface(size); +} + +void VulkanSurfaceProducer::SubmitSurface( + std::unique_ptr surface) { + FTL_DCHECK(valid_ && surface != nullptr); + surface_pool_->SubmitSurface(std::move(surface)); +} + +} // namespace flutter_runner diff --git a/content_handler/vulkan_surface_producer.h b/content_handler/vulkan_surface_producer.h new file mode 100644 index 000000000..453fe9047 --- /dev/null +++ b/content_handler/vulkan_surface_producer.h @@ -0,0 +1,66 @@ +// 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. + +#ifndef FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ +#define FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ + +#include "apps/mozart/lib/scene/client/resources.h" +#include "apps/mozart/lib/scene/client/session.h" +#include "flutter/content_handler/vulkan_surface.h" +#include "flutter/content_handler/vulkan_surface_pool.h" +#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 "lib/ftl/macros.h" +#include "lib/mtl/tasks/message_loop.h" +#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h" + +namespace flutter_runner { + +class VulkanSurfaceProducer : public flow::SceneUpdateContext::SurfaceProducer { + public: + VulkanSurfaceProducer(mozart::client::Session* mozart_session); + + ~VulkanSurfaceProducer(); + + bool IsValid() const { return valid_; } + + // |flow::SceneUpdateContext::SurfaceProducer| + std::unique_ptr + ProduceSurface(const SkISize& size) override; + + // |flow::SceneUpdateContext::SurfaceProducer| + void SubmitSurface( + std::unique_ptr surface) + override; + + void OnSurfacesPresented( + std::vector< + std::unique_ptr> + surfaces); + + private: + // 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. + ftl::RefPtr vk_; + sk_sp backend_context_; + std::unique_ptr logical_device_; + std::unique_ptr application_; + sk_sp context_; + std::unique_ptr surface_pool_; + bool valid_ = false; + + bool Initialize(mozart::client::Session* mozart_session); + + FTL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfaceProducer); +}; + +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 112ec6389..e278ed10e 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -47,8 +47,6 @@ source_set("flow") { "raster_cache.h", "raster_cache_key.cc", "raster_cache_key.h", - "scene_update_context.cc", - "scene_update_context.h", ] deps = [ @@ -62,12 +60,21 @@ source_set("flow") { if (is_fuchsia) { sources += [ + "export_node.cc", + "export_node.h", "layers/child_scene_layer.cc", "layers/child_scene_layer.h", + "scene_update_context.cc", + "scene_update_context.h", ] + + deps += [ + "//apps/mozart/lib/scene:client", + "//apps/mozart/services/scene", + ] + public_deps = [ - "//apps/mozart/lib/skia", - "//apps/mozart/services/composition", + "//magenta/system/ulib/mx", ] } } diff --git a/flow/export_node.cc b/flow/export_node.cc new file mode 100644 index 000000000..be4a1cea1 --- /dev/null +++ b/flow/export_node.cc @@ -0,0 +1,39 @@ +// 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. + +#include "flutter/flow/export_node.h" + +namespace flow { + +ExportNode::ExportNode(uint32_t export_token_handle) + : export_token_(export_token_handle) {} + +ExportNode::~ExportNode() { + // TODO(MZ-190): Ensure the node is properly unregistered on the rasterizer + // thread by attaching it to the update context in some way. +} + +void ExportNode::Bind(SceneUpdateContext& context, + mozart::client::ContainerNode& container, + const SkPoint& offset, + float scale, + bool hit_testable) { + ftl::MutexLocker lock(&mutex_); + + if (export_token_) { + node_.reset(new mozart::client::EntityNode(container.session())); + node_->Export(std::move(export_token_)); + } + + if (node_) { + container.AddChild(*node_); + node_->SetTranslation(offset.x(), offset.y(), 0.f); + node_->SetScale(scale, scale, 1.f); + node_->SetHitTestBehavior(hit_testable + ? mozart2::HitTestBehavior::kDefault + : mozart2::HitTestBehavior::kSuppress); + } +} + +} // namespace flow diff --git a/flow/export_node.h b/flow/export_node.h new file mode 100644 index 000000000..da4679418 --- /dev/null +++ b/flow/export_node.h @@ -0,0 +1,54 @@ +// 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. + +#ifndef FLUTTER_FLOW_EXPORT_NODE_H_ +#define FLUTTER_FLOW_EXPORT_NODE_H_ + +#include + +#include + +#include "apps/mozart/lib/scene/client/resources.h" +#include "flutter/flow/scene_update_context.h" +#include "lib/ftl/build_config.h" +#include "lib/ftl/macros.h" +#include "lib/ftl/memory/ref_counted.h" +#include "lib/ftl/synchronization/mutex.h" +#include "lib/ftl/synchronization/thread_annotations.h" +#include "third_party/skia/include/core/SkPoint.h" + +namespace flow { + +// Represents a node which is being exported from the session. +// This object is created on the UI thread but the entity node it contains +// must be created and destroyed by the rasterizer thread. +// +// Therefore this object is thread-safe. +class ExportNode : public ftl::RefCountedThreadSafe { + public: + ExportNode(uint32_t export_token_handle); + + // Binds the export token to the entity node and adds it as a child of + // the specified container. + void Bind(SceneUpdateContext& context, + mozart::client::ContainerNode& container, + const SkPoint& offset, + float scale, + bool hit_testable); + + private: + ~ExportNode(); + + ftl::Mutex mutex_; + mx::eventpair export_token_ FTL_GUARDED_BY(mutex_); + std::unique_ptr node_ FTL_GUARDED_BY(mutex_); + + FRIEND_MAKE_REF_COUNTED(ExportNode); + FRIEND_REF_COUNTED_THREAD_SAFE(ExportNode); + FTL_DISALLOW_COPY_AND_ASSIGN(ExportNode); +}; + +} // namespace flow + +#endif // FLUTTER_FLOW_EXPORT_NODE_H_ diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index 7b16fc346..0077f6f87 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -8,15 +8,16 @@ namespace flow { -BackdropFilterLayer::BackdropFilterLayer() {} +BackdropFilterLayer::BackdropFilterLayer() = default; -BackdropFilterLayer::~BackdropFilterLayer() {} +BackdropFilterLayer::~BackdropFilterLayer() = default; void BackdropFilterLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "BackdropFilterLayer::Paint"); - Layer::AutoSaveLayer( - context, - SkCanvas::SaveLayerRec{&paint_bounds(), nullptr, filter_.get(), 0}); + FTL_DCHECK(needs_painting()); + + Layer::AutoSaveLayer(context, SkCanvas::SaveLayerRec{&paint_bounds(), nullptr, + filter_.get(), 0}); PaintChildren(context); } diff --git a/flow/layers/backdrop_filter_layer.h b/flow/layers/backdrop_filter_layer.h index e38891234..6e016e780 100644 --- a/flow/layers/backdrop_filter_layer.h +++ b/flow/layers/backdrop_filter_layer.h @@ -16,7 +16,6 @@ class BackdropFilterLayer : public ContainerLayer { void set_filter(sk_sp filter) { filter_ = std::move(filter); } - protected: void Paint(PaintContext& context) override; private: diff --git a/flow/layers/child_scene_layer.cc b/flow/layers/child_scene_layer.cc index 2af48ea07..b5f3d5dc1 100644 --- a/flow/layers/child_scene_layer.cc +++ b/flow/layers/child_scene_layer.cc @@ -4,9 +4,6 @@ #include "flutter/flow/layers/child_scene_layer.h" -#include "apps/mozart/lib/skia/type_converters.h" -#include "apps/mozart/services/composition/nodes.fidl.h" - namespace flow { ChildSceneLayer::ChildSceneLayer() = default; @@ -15,49 +12,30 @@ ChildSceneLayer::~ChildSceneLayer() = default; void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { set_needs_system_composite(true); - transform_.setIdentity(); - transform_.preTranslate(offset_.x(), offset_.y()); - float inverse_device_pixel_ratio = 1.f / device_pixel_ratio_; - transform_.preScale(inverse_device_pixel_ratio, inverse_device_pixel_ratio); - - SkRect bounds = - SkRect::MakeXYWH(offset_.x(), offset_.y(), - physical_size_.width() * inverse_device_pixel_ratio, - physical_size_.height() * inverse_device_pixel_ratio); - set_paint_bounds(bounds); - context->child_paint_bounds = bounds; } void ChildSceneLayer::Paint(PaintContext& context) { - FTL_DCHECK(false) << "Failed to composite child scene."; + FTL_NOTREACHED() << "This layer never needs painting."; } -void ChildSceneLayer::UpdateScene(SceneUpdateContext& context, - mozart::Node* container) { +void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) { FTL_DCHECK(needs_system_composite()); - auto resource = mozart::Resource::New(); - resource->set_scene(mozart::SceneResource::New()); - resource->get_scene()->scene_token = mozart::SceneToken::New(); - resource->get_scene()->scene_token->value = scene_token_; - - auto node = mozart::Node::New(); - if (!hit_testable_) { - node->hit_test_behavior = mozart::HitTestBehavior::New(); - node->hit_test_behavior->visibility = - mozart::HitTestBehavior::Visibility::INVISIBLE; - node->hit_test_behavior->prune = true; + // TODO(MZ-191): Set clip. + // It's worth asking whether all children should be clipped implicitly + // or whether we should leave this up to the Flutter application to decide. + // In some situations, it might be useful to allow children to draw + // outside of their layout bounds. + // + // float inverse_device_pixel_ratio = 1.f / device_pixel_ratio_; + // SkRect bounds = + // SkRect::MakeXYWH(offset_.x(), offset_.y(), + // physical_size_.width() * inverse_device_pixel_ratio, + // physical_size_.height() * inverse_device_pixel_ratio); + if (export_node_) { + context.AddChildScene(export_node_.get(), offset_, device_pixel_ratio_, + hit_testable_); } - node->op = mozart::NodeOp::New(); - node->op->set_scene(mozart::SceneNodeOp::New()); - node->op->get_scene()->scene_resource_id = - context.AddResource(std::move(resource)); - node->content_clip = mozart::RectF::New(); - node->content_clip->width = physical_size_.width(); - node->content_clip->height = physical_size_.height(); - node->content_transform = mozart::Transform::From(transform_); - - context.AddChildNode(container, std::move(node)); } } // namespace flow diff --git a/flow/layers/child_scene_layer.h b/flow/layers/child_scene_layer.h index 93640ec18..9d66ad5b3 100644 --- a/flow/layers/child_scene_layer.h +++ b/flow/layers/child_scene_layer.h @@ -5,8 +5,8 @@ #ifndef FLUTTER_FLOW_LAYERS_CHILD_SCENE_LAYER_H_ #define FLUTTER_FLOW_LAYERS_CHILD_SCENE_LAYER_H_ +#include "flutter/flow/export_node.h" #include "flutter/flow/layers/layer.h" -#include "apps/mozart/services/composition/scenes.fidl.h" namespace flow { @@ -25,22 +25,24 @@ class ChildSceneLayer : public Layer { physical_size_ = physical_size; } - void set_scene_token(uint32_t scene_token) { scene_token_ = scene_token; } + void set_export_node(ftl::RefPtr export_node) { + export_node_ = std::move(export_node); + } void set_hit_testable(bool hit_testable) { hit_testable_ = hit_testable; } void Preroll(PrerollContext* context, const SkMatrix& matrix) override; + void Paint(PaintContext& context) override; - void UpdateScene(SceneUpdateContext& context, - mozart::Node* container) override; + + void UpdateScene(SceneUpdateContext& context) override; private: SkPoint offset_; float device_pixel_ratio_ = 1.0; SkISize physical_size_; - uint32_t scene_token_ = 0; + ftl::RefPtr export_node_; bool hit_testable_ = true; - SkMatrix transform_; FTL_DISALLOW_COPY_AND_ASSIGN(ChildSceneLayer); }; diff --git a/flow/layers/clip_path_layer.cc b/flow/layers/clip_path_layer.cc index 05a1c8929..39f0e1788 100644 --- a/flow/layers/clip_path_layer.cc +++ b/flow/layers/clip_path_layer.cc @@ -5,37 +5,48 @@ #include "flutter/flow/layers/clip_path_layer.h" #if defined(OS_FUCHSIA) -#include "apps/mozart/lib/skia/type_converters.h" // nogncheck -#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck + +#include "apps/mozart/lib/scene/session_helpers.h" // nogncheck + #endif // defined(OS_FUCHSIA) namespace flow { -ClipPathLayer::ClipPathLayer() {} +ClipPathLayer::ClipPathLayer() = default; -ClipPathLayer::~ClipPathLayer() {} +ClipPathLayer::~ClipPathLayer() = default; void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { - PrerollChildren(context, matrix); - if (!context->child_paint_bounds.intersect(clip_path_.getBounds())) - context->child_paint_bounds.setEmpty(); - set_paint_bounds(context->child_paint_bounds); + SkRect child_paint_bounds = SkRect::MakeEmpty(); + PrerollChildren(context, matrix, &child_paint_bounds); + + if (child_paint_bounds.intersect(clip_path_.getBounds())) { + set_paint_bounds(child_paint_bounds); + } } #if defined(OS_FUCHSIA) -void ClipPathLayer::UpdateScene(SceneUpdateContext& context, - mozart::Node* container) { - auto node = mozart::Node::New(); - node->content_clip = mozart::RectF::From(clip_path_.getBounds()); - UpdateSceneChildrenInsideNode(context, container, std::move(node)); +void ClipPathLayer::UpdateScene(SceneUpdateContext& context) { + FTL_DCHECK(needs_system_composite()); + + // TODO(MZ-140): Must be able to specify paths as shapes to nodes. + // Treating the shape as a rectangle for now. + auto bounds = clip_path_.getBounds(); + mozart::client::Rectangle shape(context.session(), // session + bounds.width(), // width + bounds.height() // height + ); + + SceneUpdateContext::Clip clip(context, shape, bounds); + UpdateSceneChildren(context); } #endif // defined(OS_FUCHSIA) void ClipPathLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "ClipPathLayer::Paint"); - FTL_DCHECK(!needs_system_composite()); + FTL_DCHECK(needs_painting()); Layer::AutoSaveLayer save(context, paint_bounds(), nullptr); context.canvas.clipPath(clip_path_, true); diff --git a/flow/layers/clip_path_layer.h b/flow/layers/clip_path_layer.h index a62d66aa4..1b2354a34 100644 --- a/flow/layers/clip_path_layer.h +++ b/flow/layers/clip_path_layer.h @@ -16,13 +16,11 @@ class ClipPathLayer : public ContainerLayer { void set_clip_path(const SkPath& clip_path) { clip_path_ = clip_path; } - protected: void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) override; #if defined(OS_FUCHSIA) - void UpdateScene(SceneUpdateContext& context, - mozart::Node* container) override; + void UpdateScene(SceneUpdateContext& context) override; #endif // defined(OS_FUCHSIA) private: diff --git a/flow/layers/clip_rect_layer.cc b/flow/layers/clip_rect_layer.cc index 1c6d6748a..e8a08253b 100644 --- a/flow/layers/clip_rect_layer.cc +++ b/flow/layers/clip_rect_layer.cc @@ -4,38 +4,40 @@ #include "flutter/flow/layers/clip_rect_layer.h" -#if defined(OS_FUCHSIA) -#include "apps/mozart/lib/skia/type_converters.h" // nogncheck -#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck -#endif // defined(OS_FUCHSIA) - namespace flow { -ClipRectLayer::ClipRectLayer() {} +ClipRectLayer::ClipRectLayer() = default; -ClipRectLayer::~ClipRectLayer() {} +ClipRectLayer::~ClipRectLayer() = default; void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { - PrerollChildren(context, matrix); - if (!context->child_paint_bounds.intersect(clip_rect_)) - context->child_paint_bounds.setEmpty(); - set_paint_bounds(context->child_paint_bounds); + SkRect child_paint_bounds = SkRect::MakeEmpty(); + PrerollChildren(context, matrix, &child_paint_bounds); + + if (child_paint_bounds.intersect(clip_rect_)) { + set_paint_bounds(child_paint_bounds); + } } #if defined(OS_FUCHSIA) -void ClipRectLayer::UpdateScene(SceneUpdateContext& context, - mozart::Node* container) { - auto node = mozart::Node::New(); - node->content_clip = mozart::RectF::From(clip_rect_); - UpdateSceneChildrenInsideNode(context, container, std::move(node)); +void ClipRectLayer::UpdateScene(SceneUpdateContext& context) { + FTL_DCHECK(needs_system_composite()); + + mozart::client::Rectangle shape(context.session(), // session + clip_rect_.width(), // width + clip_rect_.height() // height + ); + + SceneUpdateContext::Clip clip(context, shape, clip_rect_); + UpdateSceneChildren(context); } #endif // defined(OS_FUCHSIA) void ClipRectLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "ClipRectLayer::Paint"); - FTL_DCHECK(!needs_system_composite()); + FTL_DCHECK(needs_painting()); SkAutoCanvasRestore save(&context.canvas, true); context.canvas.clipRect(paint_bounds()); diff --git a/flow/layers/clip_rect_layer.h b/flow/layers/clip_rect_layer.h index 5b09e0063..51416f20f 100644 --- a/flow/layers/clip_rect_layer.h +++ b/flow/layers/clip_rect_layer.h @@ -16,13 +16,11 @@ class ClipRectLayer : public ContainerLayer { void set_clip_rect(const SkRect& clip_rect) { clip_rect_ = clip_rect; } - protected: void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) override; #if defined(OS_FUCHSIA) - void UpdateScene(SceneUpdateContext& context, - mozart::Node* container) override; + void UpdateScene(SceneUpdateContext& context) override; #endif // defined(OS_FUCHSIA) private: diff --git a/flow/layers/clip_rrect_layer.cc b/flow/layers/clip_rrect_layer.cc index 8eea82c8f..f26670b28 100644 --- a/flow/layers/clip_rrect_layer.cc +++ b/flow/layers/clip_rrect_layer.cc @@ -4,38 +4,47 @@ #include "flutter/flow/layers/clip_rrect_layer.h" -#if defined(OS_FUCHSIA) -#include "apps/mozart/lib/skia/type_converters.h" // nogncheck -#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck -#endif // defined(OS_FUCHSIA) - namespace flow { -ClipRRectLayer::ClipRRectLayer() {} +ClipRRectLayer::ClipRRectLayer() = default; -ClipRRectLayer::~ClipRRectLayer() {} +ClipRRectLayer::~ClipRRectLayer() = default; void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { - PrerollChildren(context, matrix); - if (!context->child_paint_bounds.intersect(clip_rrect_.getBounds())) - context->child_paint_bounds.setEmpty(); - set_paint_bounds(context->child_paint_bounds); + SkRect child_paint_bounds = SkRect::MakeEmpty(); + PrerollChildren(context, matrix, &child_paint_bounds); + + if (child_paint_bounds.intersect(clip_rrect_.getBounds())) { + set_paint_bounds(child_paint_bounds); + } } #if defined(OS_FUCHSIA) -void ClipRRectLayer::UpdateScene(SceneUpdateContext& context, - mozart::Node* container) { - auto node = mozart::Node::New(); - node->content_clip = mozart::RectF::From(clip_rrect_.getBounds()); - UpdateSceneChildrenInsideNode(context, container, std::move(node)); +void ClipRRectLayer::UpdateScene(SceneUpdateContext& context) { + FTL_DCHECK(needs_system_composite()); + + // TODO(MZ-137): Need to be able to express the radii as vectors. + mozart::client::RoundedRectangle shape( + context.session(), // session + clip_rrect_.width(), // width + clip_rrect_.height(), // height + clip_rrect_.radii(SkRRect::kUpperLeft_Corner).x(), // top_left_radius + clip_rrect_.radii(SkRRect::kUpperRight_Corner).x(), // top_right_radius + clip_rrect_.radii(SkRRect::kLowerRight_Corner) + .x(), // bottom_right_radius + clip_rrect_.radii(SkRRect::kLowerLeft_Corner).x() // bottom_left_radius + ); + + SceneUpdateContext::Clip clip(context, shape, clip_rrect_.getBounds()); + UpdateSceneChildren(context); } #endif // defined(OS_FUCHSIA) void ClipRRectLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "ClipRRectLayer::Paint"); - FTL_DCHECK(!needs_system_composite()); + FTL_DCHECK(needs_painting()); Layer::AutoSaveLayer save(context, paint_bounds(), nullptr); context.canvas.clipRRect(clip_rrect_, true); diff --git a/flow/layers/clip_rrect_layer.h b/flow/layers/clip_rrect_layer.h index 79b8ae554..67ba03453 100644 --- a/flow/layers/clip_rrect_layer.h +++ b/flow/layers/clip_rrect_layer.h @@ -16,13 +16,11 @@ class ClipRRectLayer : public ContainerLayer { void set_clip_rrect(const SkRRect& clip_rrect) { clip_rrect_ = clip_rrect; } - protected: void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) override; #if defined(OS_FUCHSIA) - void UpdateScene(SceneUpdateContext& context, - mozart::Node* container) override; + void UpdateScene(SceneUpdateContext& context) override; #endif // defined(OS_FUCHSIA) private: diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index e5808b160..0471d58da 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -6,12 +6,14 @@ namespace flow { -ColorFilterLayer::ColorFilterLayer() {} +ColorFilterLayer::ColorFilterLayer() = default; -ColorFilterLayer::~ColorFilterLayer() {} +ColorFilterLayer::~ColorFilterLayer() = default; void ColorFilterLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "ColorFilterLayer::Paint"); + FTL_DCHECK(needs_painting()); + sk_sp color_filter = SkColorFilter::MakeModeFilter(color_, blend_mode_); SkPaint paint; diff --git a/flow/layers/color_filter_layer.h b/flow/layers/color_filter_layer.h index df5e7d71d..f327f121a 100644 --- a/flow/layers/color_filter_layer.h +++ b/flow/layers/color_filter_layer.h @@ -18,7 +18,6 @@ class ColorFilterLayer : public ContainerLayer { void set_blend_mode(SkBlendMode blend_mode) { blend_mode_ = blend_mode; } - protected: void Paint(PaintContext& context) override; private: diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index c320e6896..d9665d2d0 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -6,11 +6,9 @@ namespace flow { -ContainerLayer::ContainerLayer() { - ctm_.setIdentity(); -} +ContainerLayer::ContainerLayer() {} -ContainerLayer::~ContainerLayer() {} +ContainerLayer::~ContainerLayer() = default; void ContainerLayer::Add(std::unique_ptr layer) { layer->set_parent(this); @@ -19,60 +17,52 @@ void ContainerLayer::Add(std::unique_ptr layer) { void ContainerLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "ContainerLayer::Preroll"); - PrerollChildren(context, matrix); - set_paint_bounds(context->child_paint_bounds); + + SkRect child_paint_bounds = SkRect::MakeEmpty(); + PrerollChildren(context, matrix, &child_paint_bounds); + set_paint_bounds(child_paint_bounds); } void ContainerLayer::PrerollChildren(PrerollContext* context, - const SkMatrix& matrix) { - SkRect child_paint_bounds = SkRect::MakeEmpty(); + const SkMatrix& child_matrix, + SkRect* child_paint_bounds) { for (auto& layer : layers_) { PrerollContext child_context = *context; - FTL_DCHECK(child_context.child_paint_bounds.isEmpty()); - layer->Preroll(&child_context, matrix); - if (layer->needs_system_composite()) + layer->Preroll(&child_context, child_matrix); + + if (layer->needs_system_composite()) { set_needs_system_composite(true); - child_paint_bounds.join(child_context.child_paint_bounds); + } + child_paint_bounds->join(layer->paint_bounds()); } - context->child_paint_bounds = child_paint_bounds; - - if (needs_system_composite()) - ctm_ = matrix; } void ContainerLayer::PaintChildren(PaintContext& context) const { - FTL_DCHECK(!needs_system_composite()); + FTL_DCHECK(needs_painting()); + // Intentionally not tracing here as there should be no self-time // and the trace event on this common function has a small overhead. - for (auto& layer : layers_) - layer->Paint(context); + for (auto& layer : layers_) { + if (layer->needs_painting()) { + layer->Paint(context); + } + } } #if defined(OS_FUCHSIA) -void ContainerLayer::UpdateScene(SceneUpdateContext& context, - mozart::Node* container) { - UpdateSceneChildren(context, container); +void ContainerLayer::UpdateScene(SceneUpdateContext& context) { + UpdateSceneChildren(context); } -void ContainerLayer::UpdateSceneChildrenInsideNode(SceneUpdateContext& context, - mozart::Node* container, - mozart::NodePtr node) { +void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context) { FTL_DCHECK(needs_system_composite()); - UpdateSceneChildren(context, node.get()); - context.FinalizeCurrentPaintTaskIfNeeded(node.get(), ctm()); - context.AddChildNode(container, std::move(node)); -} -void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context, - mozart::Node* container) { - FTL_DCHECK(needs_system_composite()); + // Paint all of the layers which need to be drawn into the container. + // These may be flattened down to a containing for (auto& layer : layers_) { if (layer->needs_system_composite()) { - context.FinalizeCurrentPaintTaskIfNeeded(container, ctm()); - layer->UpdateScene(context, container); - } else { - context.AddLayerToCurrentPaintTask(layer.get()); + layer->UpdateScene(context); } } } diff --git a/flow/layers/container_layer.h b/flow/layers/container_layer.h index 0aaa0d642..f21fa15a0 100644 --- a/flow/layers/container_layer.h +++ b/flow/layers/container_layer.h @@ -18,31 +18,26 @@ class ContainerLayer : public Layer { void Add(std::unique_ptr layer); void Preroll(PrerollContext* context, const SkMatrix& matrix) override; - void PrerollChildren(PrerollContext* context, const SkMatrix& matrix); - - void PaintChildren(PaintContext& context) const; #if defined(OS_FUCHSIA) - void UpdateScene(SceneUpdateContext& context, - mozart::Node* container) override; - void UpdateSceneChildrenInsideNode(SceneUpdateContext& context, - mozart::Node* container, - mozart::NodePtr node); - void UpdateSceneChildren(SceneUpdateContext& context, - mozart::Node* container); + void UpdateScene(SceneUpdateContext& context) override; #endif // defined(OS_FUCHSIA) const std::vector>& layers() const { return layers_; } protected: - // Valid only after preroll when needs_system_composite() is true. - const SkMatrix& ctm() const { return ctm_; } + void PrerollChildren(PrerollContext* context, + const SkMatrix& child_matrix, + SkRect* child_paint_bounds); + void PaintChildren(PaintContext& context) const; + +#if defined(OS_FUCHSIA) + void UpdateSceneChildren(SceneUpdateContext& context); +#endif // defined(OS_FUCHSIA) private: std::vector> layers_; - SkMatrix ctm_; - FTL_DISALLOW_COPY_AND_ASSIGN(ContainerLayer); }; diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index c285a3f58..67148dc0c 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -12,33 +12,26 @@ namespace flow { Layer::Layer() : parent_(nullptr), needs_system_composite_(false), - has_paint_bounds_(false), - paint_bounds_() {} + paint_bounds_(SkRect::MakeEmpty()) {} Layer::~Layer() = default; -void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) { - if (!has_paint_bounds()) { - set_paint_bounds(SkRect::MakeEmpty()); - } -} +void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {} #if defined(OS_FUCHSIA) -void Layer::UpdateScene(SceneUpdateContext& context, mozart::Node* container) {} -#endif +void Layer::UpdateScene(SceneUpdateContext& context) {} +#endif // defined(OS_FUCHSIA) Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context, const SkRect& bounds, const SkPaint* paint) - : paint_context_(paint_context), - bounds_(bounds) { + : paint_context_(paint_context), bounds_(bounds) { paint_context_.canvas.saveLayer(bounds_, paint); } Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context, const SkCanvas::SaveLayerRec& layer_rec) - : paint_context_(paint_context), - bounds_(*layer_rec.fBounds) { + : paint_context_(paint_context), bounds_(*layer_rec.fBounds) { paint_context_.canvas.saveLayer(layer_rec); } diff --git a/flow/layers/layer.h b/flow/layers/layer.h index c42abe802..7bcecd40c 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -10,7 +10,6 @@ #include "flutter/flow/instrumentation.h" #include "flutter/flow/raster_cache.h" -#include "flutter/flow/scene_update_context.h" #include "flutter/glue/trace_event.h" #include "lib/ftl/build_config.h" #include "lib/ftl/logging.h" @@ -24,7 +23,16 @@ #include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkRect.h" +#if defined(OS_FUCHSIA) + +#include "apps/mozart/lib/scene/client/resources.h" //nogncheck +#include "apps/mozart/lib/scene/client/session.h" //nogncheck +#include "flutter/flow/scene_update_context.h" //nogncheck + +#endif // defined(OS_FUCHSIA) + namespace flow { + class ContainerLayer; class Layer { @@ -70,8 +78,8 @@ class Layer { virtual void Paint(PaintContext& context) = 0; #if defined(OS_FUCHSIA) - virtual void UpdateScene(SceneUpdateContext& context, - mozart::Node* container); + // Updates the system composited scene. + virtual void UpdateScene(SceneUpdateContext& context); #endif ContainerLayer* parent() const { return parent_; } @@ -83,23 +91,19 @@ class Layer { needs_system_composite_ = value; } - // subclasses should assume this will be true by the time Paint() is called - bool has_paint_bounds() const { return has_paint_bounds_; } - - const SkRect& paint_bounds() const { - FTL_DCHECK(has_paint_bounds_); - return paint_bounds_; - } + const SkRect& paint_bounds() const { return paint_bounds_; } + // This must be set by the time Preroll() returns otherwise the layer will + // be assumed to have empty paint bounds (paints no content). void set_paint_bounds(const SkRect& paint_bounds) { - has_paint_bounds_ = true; paint_bounds_ = paint_bounds; } + bool needs_painting() const { return !paint_bounds_.isEmpty(); } + private: ContainerLayer* parent_; bool needs_system_composite_; - bool has_paint_bounds_; // if false, paint_bounds_ is not valid SkRect paint_bounds_; FTL_DISALLOW_COPY_AND_ASSIGN(Layer); diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index aab6df5e8..20dd34232 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -11,12 +11,11 @@ namespace flow { LayerTree::LayerTree() : frame_size_{}, - scene_version_(0), rasterizer_tracing_threshold_(0), checkerboard_raster_cache_images_(false), checkerboard_offscreen_layers_(false) {} -LayerTree::~LayerTree() {} +LayerTree::~LayerTree() = default; void LayerTree::Raster(CompositorContext::ScopedFrame& frame, bool ignore_raster_cache) { @@ -40,15 +39,21 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame, #if defined(OS_FUCHSIA) void LayerTree::UpdateScene(SceneUpdateContext& context, - mozart::Node* container) { + mozart::client::ContainerNode& container) { TRACE_EVENT0("flutter", "LayerTree::UpdateScene"); + SceneUpdateContext::Frame frame( + context, + SkRRect::MakeRect( + SkRect::MakeIWH(frame_size_.width(), frame_size_.height())), + SK_ColorTRANSPARENT, 0.f, 1.f, 1.f); if (root_layer_->needs_system_composite()) { - root_layer_->UpdateScene(context, container); - } else { - context.AddLayerToCurrentPaintTask(root_layer_.get()); + root_layer_->UpdateScene(context); } - context.FinalizeCurrentPaintTaskIfNeeded(container, SkMatrix::I()); + if (root_layer_->needs_painting()) { + frame.AddPaintedLayer(root_layer_.get()); + } + container.AddChild(frame.entity_node()); } #endif @@ -58,7 +63,9 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame) { frame.context().memory_usage(), checkerboard_offscreen_layers_}; TRACE_EVENT0("flutter", "LayerTree::Paint"); - root_layer_->Paint(context); + + if (root_layer_->needs_painting()) + root_layer_->Paint(context); } } // namespace flow diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index 90863df3b..1b7e8fcac 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -31,10 +31,8 @@ class LayerTree { bool ignore_raster_cache = false); #if defined(OS_FUCHSIA) - // TODO(abarth): Integrate scene updates with the rasterization pass so that - // we can draw on top of child scenes (and so that we can apply clips and - // blending operations to child scene). - void UpdateScene(SceneUpdateContext& context, mozart::Node* container); + void UpdateScene(SceneUpdateContext& context, + mozart::client::ContainerNode& container); #endif void Paint(CompositorContext::ScopedFrame& frame); @@ -49,12 +47,6 @@ class LayerTree { void set_frame_size(const SkISize& frame_size) { frame_size_ = frame_size; } - uint32_t scene_version() const { return scene_version_; } - - void set_scene_version(uint32_t scene_version) { - scene_version_ = scene_version; - } - void set_construction_time(const ftl::TimeDelta& delta) { construction_time_ = delta; } @@ -82,7 +74,6 @@ class LayerTree { private: SkISize frame_size_; // Physical pixels. - uint32_t scene_version_; std::unique_ptr root_layer_; ftl::TimeDelta construction_time_; uint32_t rasterizer_tracing_threshold_; diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index 27a988df2..32eb634c6 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -4,35 +4,15 @@ #include "flutter/flow/layers/opacity_layer.h" -#if defined(OS_FUCHSIA) -#include "apps/mozart/lib/skia/type_converters.h" // nogncheck -#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck -#endif // defined(OS_FUCHSIA) - namespace flow { -OpacityLayer::OpacityLayer() {} - -OpacityLayer::~OpacityLayer() {} - -#if defined(OS_FUCHSIA) - -void OpacityLayer::UpdateScene(SceneUpdateContext& context, - mozart::Node* container) { - auto node = mozart::Node::New(); - node->op = mozart::NodeOp::New(); - node->op->set_layer(mozart::LayerNodeOp::New()); - node->op->get_layer()->layer_rect = mozart::RectF::From(paint_bounds()); - node->op->get_layer()->blend = mozart::Blend::New(); - node->op->get_layer()->blend->alpha = alpha_; - UpdateSceneChildrenInsideNode(context, container, std::move(node)); -} +OpacityLayer::OpacityLayer() = default; -#endif // defined(OS_FUCHSIA) +OpacityLayer::~OpacityLayer() = default; void OpacityLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "OpacityLayer::Paint"); - FTL_DCHECK(!needs_system_composite()); + FTL_DCHECK(needs_painting()); SkPaint paint; paint.setAlpha(alpha_); diff --git a/flow/layers/opacity_layer.h b/flow/layers/opacity_layer.h index 1ccea1023..c1bdbc158 100644 --- a/flow/layers/opacity_layer.h +++ b/flow/layers/opacity_layer.h @@ -16,13 +16,10 @@ class OpacityLayer : public ContainerLayer { void set_alpha(int alpha) { alpha_ = alpha; } - protected: void Paint(PaintContext& context) override; -#if defined(OS_FUCHSIA) - void UpdateScene(SceneUpdateContext& context, - mozart::Node* container) override; -#endif // defined(OS_FUCHSIA) + // TODO(chinmaygarde): Once MZ-139 is addressed, introduce a new node in the + // session scene hierarchy. private: int alpha_; diff --git a/flow/layers/physical_model_layer.cc b/flow/layers/physical_model_layer.cc index bc9de32fc..d6dc5e92d 100644 --- a/flow/layers/physical_model_layer.cc +++ b/flow/layers/physical_model_layer.cc @@ -7,45 +7,63 @@ #include "flutter/flow/paint_utils.h" #include "third_party/skia/include/utils/SkShadowUtils.h" -#if defined(OS_FUCHSIA) -#include "apps/mozart/lib/skia/type_converters.h" // nogncheck -#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck -#endif // defined(OS_FUCHSIA) - namespace flow { -PhysicalModelLayer::PhysicalModelLayer() - : rrect_(SkRRect::MakeEmpty()) {} +PhysicalModelLayer::PhysicalModelLayer() : rrect_(SkRRect::MakeEmpty()) {} -PhysicalModelLayer::~PhysicalModelLayer() {} +PhysicalModelLayer::~PhysicalModelLayer() = default; -void PhysicalModelLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { - PrerollChildren(context, matrix); +void PhysicalModelLayer::Preroll(PrerollContext* context, + const SkMatrix& matrix) { + SkRect child_paint_bounds; + PrerollChildren(context, matrix, &child_paint_bounds); - // Add some margin to the paint bounds to leave space for the shadow. - // The margin is hardcoded to an arbitrary maximum for now because Skia - // doesn't provide a way to calculate it. - SkRect bounds(rrect_.getBounds()); - bounds.outset(20.0, 20.0); - set_paint_bounds(bounds); + if (elevation_ == 0) { + set_paint_bounds(rrect_.getBounds()); + } else { +#if defined(OS_FUCHSIA) + // Let the system compositor draw all shadows for us. + set_needs_system_composite(true); +#else + // Add some margin to the paint bounds to leave space for the shadow. + // The margin is hardcoded to an arbitrary maximum for now because Skia + // doesn't provide a way to calculate it. We fill this whole region + // and clip children to it so we don't need to join the child paint bounds. + SkRect bounds(rrect_.getBounds()); + bounds.outset(20.0, 20.0); + set_paint_bounds(bounds); +#endif // defined(OS_FUCHSIA) + } - context->child_paint_bounds = bounds; +#if defined(OS_FUCHSIA) + if (needs_system_composite()) { + scale_x_ = matrix.getScaleX(); + scale_y_ = matrix.getScaleY(); + } +#endif // defined(OS_FUCHSIA) } #if defined(OS_FUCHSIA) -void PhysicalModelLayer::UpdateScene(SceneUpdateContext& context, - mozart::Node* container) { - context.AddLayerToCurrentPaintTask(this); - auto node = mozart::Node::New(); - node->content_clip = mozart::RectF::From(rrect_.getBounds()); - UpdateSceneChildrenInsideNode(context, container, std::move(node)); +void PhysicalModelLayer::UpdateScene(SceneUpdateContext& context) { + FTL_DCHECK(needs_system_composite()); + + SceneUpdateContext::Frame frame(context, rrect_, color_, elevation_, scale_x_, + scale_y_); + for (auto& layer : layers()) { + if (layer->needs_painting()) { + frame.AddPaintedLayer(layer.get()); + } + } + + UpdateSceneChildren(context); } #endif // defined(OS_FUCHSIA) void PhysicalModelLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "PhysicalModelLayer::Paint"); + FTL_DCHECK(needs_painting()); SkPath path; path.addRRect(rrect_); @@ -55,9 +73,6 @@ void PhysicalModelLayer::Paint(PaintContext& context) { SkColorGetA(color_) != 0xff); } - if (needs_system_composite()) - return; - SkPaint paint; paint.setColor(color_); context.canvas.drawPath(path, paint); @@ -74,22 +89,20 @@ void PhysicalModelLayer::Paint(PaintContext& context) { DrawCheckerboard(&context.canvas, rrect_.getBounds()); } -void PhysicalModelLayer::DrawShadow(SkCanvas* canvas, const SkPath& path, - SkColor color, double elevation, +void PhysicalModelLayer::DrawShadow(SkCanvas* canvas, + const SkPath& path, + SkColor color, + float elevation, bool transparentOccluder) { - SkShadowFlags flags = transparentOccluder ? - SkShadowFlags::kTransparentOccluder_ShadowFlag : - SkShadowFlags::kNone_ShadowFlag; - const SkRect& bounds = path.getBounds(); - SkScalar shadow_x = (bounds.left() + bounds.right()) / 2; - SkScalar shadow_y = bounds.top() - 600.0f; - SkShadowUtils::DrawShadow(canvas, path, - elevation, - SkPoint3::Make(shadow_x, shadow_y, 600.0f), - 800.0f, - 0.039f, 0.25f, - color, - flags); + SkShadowFlags flags = transparentOccluder + ? SkShadowFlags::kTransparentOccluder_ShadowFlag + : SkShadowFlags::kNone_ShadowFlag; + const SkRect& bounds = path.getBounds(); + SkScalar shadow_x = (bounds.left() + bounds.right()) / 2; + SkScalar shadow_y = bounds.top() - 600.0f; + SkShadowUtils::DrawShadow(canvas, path, elevation, + SkPoint3::Make(shadow_x, shadow_y, 600.0f), 800.0f, + 0.039f, 0.25f, color, flags); } } // namespace flow diff --git a/flow/layers/physical_model_layer.h b/flow/layers/physical_model_layer.h index 138dd8171..653e1839c 100644 --- a/flow/layers/physical_model_layer.h +++ b/flow/layers/physical_model_layer.h @@ -15,25 +15,31 @@ class PhysicalModelLayer : public ContainerLayer { ~PhysicalModelLayer() override; void set_rrect(const SkRRect& rrect) { rrect_ = rrect; } - void set_elevation(double elevation) { elevation_ = elevation; } + void set_elevation(float elevation) { elevation_ = elevation; } void set_color(SkColor color) { color_ = color; } - static void DrawShadow(SkCanvas* canvas, const SkPath& path, - SkColor color, double elevation, bool transparentOccluder); + static void DrawShadow(SkCanvas* canvas, + const SkPath& path, + SkColor color, + float elevation, + bool transparentOccluder); - protected: void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) override; #if defined(OS_FUCHSIA) - void UpdateScene(SceneUpdateContext& context, - mozart::Node* container) override; + void UpdateScene(SceneUpdateContext& context) override; #endif // defined(OS_FUCHSIA) private: SkRRect rrect_; - double elevation_; + float elevation_; SkColor color_; + +#if defined(OS_FUCHSIA) + SkScalar scale_x_; + SkScalar scale_y_; +#endif // defined(OS_FUCHSIA) }; } // namespace flow diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index 66bb07f42..cedeec474 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -9,7 +9,7 @@ namespace flow { -PictureLayer::PictureLayer() {} +PictureLayer::PictureLayer() = default; PictureLayer::~PictureLayer() { // The picture may contain references to textures that are associated @@ -29,13 +29,12 @@ void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { SkRect bounds = picture_->cullRect().makeOffset(offset_.x(), offset_.y()); set_paint_bounds(bounds); - context->child_paint_bounds = bounds; } void PictureLayer::Paint(PaintContext& context) { - FTL_DCHECK(picture_); - TRACE_EVENT0("flutter", "PictureLayer::Paint"); + FTL_DCHECK(picture_); + FTL_DCHECK(needs_painting()); SkAutoCanvasRestore save(&context.canvas, true); context.canvas.translate(offset_.x(), offset_.y()); diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index 5485104b2..447b867b3 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -6,12 +6,14 @@ namespace flow { -ShaderMaskLayer::ShaderMaskLayer() {} +ShaderMaskLayer::ShaderMaskLayer() = default; -ShaderMaskLayer::~ShaderMaskLayer() {} +ShaderMaskLayer::~ShaderMaskLayer() = default; void ShaderMaskLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "ShaderMaskLayer::Paint"); + FTL_DCHECK(needs_painting()); + Layer::AutoSaveLayer(context, paint_bounds(), nullptr); PaintChildren(context); diff --git a/flow/layers/shader_mask_layer.h b/flow/layers/shader_mask_layer.h index 774283e22..21c1d4ee8 100644 --- a/flow/layers/shader_mask_layer.h +++ b/flow/layers/shader_mask_layer.h @@ -20,11 +20,8 @@ class ShaderMaskLayer : public ContainerLayer { void set_mask_rect(const SkRect& mask_rect) { mask_rect_ = mask_rect; } - void set_blend_mode(SkBlendMode blend_mode) { - blend_mode_ = blend_mode; - } + void set_blend_mode(SkBlendMode blend_mode) { blend_mode_ = blend_mode; } - protected: void Paint(PaintContext& context) override; private: diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc index f60cd23c3..6479163b5 100644 --- a/flow/layers/transform_layer.cc +++ b/flow/layers/transform_layer.cc @@ -4,39 +4,37 @@ #include "flutter/flow/layers/transform_layer.h" -#if defined(OS_FUCHSIA) -#include "apps/mozart/lib/skia/type_converters.h" // nogncheck -#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck -#endif // defined(OS_FUCHSIA) - namespace flow { -TransformLayer::TransformLayer() {} +TransformLayer::TransformLayer() = default; -TransformLayer::~TransformLayer() {} +TransformLayer::~TransformLayer() = default; void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { - SkMatrix childMatrix; - childMatrix.setConcat(matrix, transform_); - PrerollChildren(context, childMatrix); - transform_.mapRect(&context->child_paint_bounds); - set_paint_bounds(context->child_paint_bounds); + SkMatrix child_matrix; + child_matrix.setConcat(matrix, transform_); + + SkRect child_paint_bounds = SkRect::MakeEmpty(); + PrerollChildren(context, child_matrix, &child_paint_bounds); + + transform_.mapRect(&child_paint_bounds); + set_paint_bounds(child_paint_bounds); } #if defined(OS_FUCHSIA) -void TransformLayer::UpdateScene(SceneUpdateContext& context, - mozart::Node* container) { - auto node = mozart::Node::New(); - node->content_transform = mozart::Transform::From(transform_); - UpdateSceneChildrenInsideNode(context, container, std::move(node)); +void TransformLayer::UpdateScene(SceneUpdateContext& context) { + FTL_DCHECK(needs_system_composite()); + + SceneUpdateContext::Transform transform(context, transform_); + UpdateSceneChildren(context); } #endif // defined(OS_FUCHSIA) void TransformLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "TransformLayer::Paint"); - FTL_DCHECK(!needs_system_composite()); + FTL_DCHECK(needs_painting()); SkAutoCanvasRestore save(&context.canvas, true); context.canvas.concat(transform_); diff --git a/flow/layers/transform_layer.h b/flow/layers/transform_layer.h index dee5fc579..e3f47f446 100644 --- a/flow/layers/transform_layer.h +++ b/flow/layers/transform_layer.h @@ -16,13 +16,11 @@ class TransformLayer : public ContainerLayer { void set_transform(const SkMatrix& transform) { transform_ = transform; } - protected: void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) override; #if defined(OS_FUCHSIA) - void UpdateScene(SceneUpdateContext& context, - mozart::Node* container) override; + void UpdateScene(SceneUpdateContext& context) override; #endif // defined(OS_FUCHSIA) private: diff --git a/flow/scene_update_context.cc b/flow/scene_update_context.cc index 1e3dece8c..822851227 100644 --- a/flow/scene_update_context.cc +++ b/flow/scene_update_context.cc @@ -4,124 +4,272 @@ #include "flutter/flow/scene_update_context.h" -#if defined(OS_FUCHSIA) - -#include "apps/mozart/lib/skia/skia_vmo_surface.h" // nogncheck -#include "apps/mozart/lib/skia/type_converters.h" // nogncheck -#include "apps/mozart/services/composition/scenes.fidl.h" // nogncheck +#include "flutter/flow/export_node.h" #include "flutter/flow/layers/layer.h" +#include "flutter/flow/matrix_decomposition.h" #include "flutter/glue/trace_event.h" namespace flow { -SceneUpdateContext::CurrentPaintTask::CurrentPaintTask() - : bounds(SkRect::MakeEmpty()) {} - -void SceneUpdateContext::CurrentPaintTask::Clear() { - bounds = SkRect::MakeEmpty(); - layers.clear(); -} - -SceneUpdateContext::SceneUpdateContext(mozart::SceneUpdate* update, +SceneUpdateContext::SceneUpdateContext(mozart::client::Session* session, SurfaceProducer* surface_producer) - : update_(update), surface_producer_(surface_producer) {} + : session_(session), surface_producer_(surface_producer) { + FTL_DCHECK(surface_producer_ != nullptr); +} SceneUpdateContext::~SceneUpdateContext() = default; -void SceneUpdateContext::AddLayerToCurrentPaintTask(Layer* layer) { - current_paint_task_.bounds.join(layer->paint_bounds()); - current_paint_task_.layers.push_back(layer); -} +void SceneUpdateContext::AddChildScene(ExportNode* export_node, + SkPoint offset, + float device_pixel_ratio, + bool hit_testable) { + FTL_DCHECK(top_entity_); -void SceneUpdateContext::FinalizeCurrentPaintTaskIfNeeded( - mozart::Node* container, - const SkMatrix& ctm) { - if (mozart::NodePtr node = FinalizeCurrentPaintTask(ctm)) - AddChildNode(container, std::move(node)); + export_node->Bind(*this, top_entity_->entity_node(), offset, + 1.f / device_pixel_ratio, hit_testable); } -mozart::NodePtr SceneUpdateContext::FinalizeCurrentPaintTask( - const SkMatrix& ctm) { - if (current_paint_task_.layers.empty()) - return nullptr; +void SceneUpdateContext::CreateFrame(mozart::client::EntityNode& entity_node, + const SkRRect& rrect, + SkColor color, + SkScalar scale_x, + SkScalar scale_y, + const SkRect& paint_bounds, + std::vector paint_layers) { + // Frames always clip their children. + entity_node.SetClip(0u, true /* clip to self */); - const SkRect& bounds = current_paint_task_.bounds; + // We don't need a shape if the frame is zero size. + if (rrect.isEmpty()) + return; - SkScalar scaleX = ctm.getScaleX(); - SkScalar scaleY = ctm.getScaleY(); + // Add a part which represents the frame's geometry for clipping purposes + // and possibly for its texture. + // TODO(MZ-137): Need to be able to express the radii as vectors. + SkRect shape_bounds = rrect.getBounds(); + mozart::client::RoundedRectangle shape( + session_, // session + rrect.width(), // width + rrect.height(), // height + rrect.radii(SkRRect::kUpperLeft_Corner).x(), // top_left_radius + rrect.radii(SkRRect::kUpperRight_Corner).x(), // top_right_radius + rrect.radii(SkRRect::kLowerRight_Corner).x(), // bottom_right_radius + rrect.radii(SkRRect::kLowerLeft_Corner).x() // bottom_left_radius + ); + mozart::client::ShapeNode shape_node(session_); + shape_node.SetShape(shape); + shape_node.SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(), + shape_bounds.height() * 0.5f + shape_bounds.top(), + 0.f); + entity_node.AddPart(shape_node); - SkISize physical_size = - SkISize::Make(bounds.width() * scaleX, bounds.height() * scaleY); + // Check whether the painted layers will be visible. + if (paint_bounds.isEmpty() || !paint_bounds.intersects(shape_bounds)) + paint_layers.clear(); - if (physical_size.isEmpty()) { - current_paint_task_.Clear(); - return nullptr; + // Check whether a solid color will suffice. + if (paint_layers.empty()) { + SetShapeColor(shape_node, color); + return; + } + + // If the painted area only covers a portion of the frame then we can + // reduce the texture size by drawing just that smaller area. + SkRect inner_bounds = shape_bounds; + inner_bounds.intersect(paint_bounds); + if (inner_bounds != shape_bounds && rrect.contains(inner_bounds)) { + SetShapeColor(shape_node, color); + + mozart::client::Rectangle inner_shape(session_, inner_bounds.width(), + inner_bounds.height()); + mozart::client::ShapeNode inner_node(session_); + inner_node.SetShape(inner_shape); + inner_node.SetTranslation(inner_bounds.width() * 0.5f + inner_bounds.left(), + inner_bounds.height() * 0.5f + inner_bounds.top(), + 0.f); + entity_node.AddPart(inner_node); + SetShapeTextureOrColor(inner_node, color, scale_x, scale_y, inner_bounds, + std::move(paint_layers)); + return; } - mozart::ImagePtr image; - PaintTask task; - task.surface = surface_producer_->ProduceSurface(physical_size, &image); - task.left = bounds.left(); - task.top = bounds.top(); - task.scaleX = scaleX; - task.scaleY = scaleY; - task.layers = std::move(current_paint_task_.layers); - - FTL_DCHECK(task.surface) << "Failed to create surface size=" - << physical_size.width() << "x" - << physical_size.height(); - - paint_tasks_.push_back(task); - - auto resource = mozart::Resource::New(); - resource->set_image(mozart::ImageResource::New()); - resource->get_image()->image = std::move(image); - - auto node = mozart::Node::New(); - node->op = mozart::NodeOp::New(); - node->op->set_image(mozart::ImageNodeOp::New()); - node->op->get_image()->content_rect = mozart::RectF::From(bounds); - node->op->get_image()->image_resource_id = AddResource(std::move(resource)); - - current_paint_task_.Clear(); - return node; + // Apply a texture to the whole shape. + SetShapeTextureOrColor(shape_node, color, scale_x, scale_y, shape_bounds, + std::move(paint_layers)); } -uint32_t SceneUpdateContext::AddResource(mozart::ResourcePtr resource) { - uint32_t resource_id = next_resource_id_++; - update_->resources.insert(resource_id, std::move(resource)); - return resource_id; +void SceneUpdateContext::SetShapeTextureOrColor( + mozart::client::ShapeNode& shape_node, + SkColor color, + SkScalar scale_x, + SkScalar scale_y, + const SkRect& paint_bounds, + std::vector paint_layers) { + mozart::client::Image* image = GenerateImageIfNeeded( + color, scale_x, scale_y, paint_bounds, std::move(paint_layers)); + if (image != nullptr) { + mozart::client::Material material(session_); + material.SetTexture(*image); + shape_node.SetMaterial(material); + return; + } + + SetShapeColor(shape_node, color); } -void SceneUpdateContext::AddChildNode(mozart::Node* container, - mozart::NodePtr child) { - uint32_t node_id = next_node_id_++; - update_->nodes.insert(node_id, std::move(child)); - container->child_node_ids.push_back(node_id); +void SceneUpdateContext::SetShapeColor(mozart::client::ShapeNode& shape_node, + SkColor color) { + if (SkColorGetA(color) == 0) + return; + + mozart::client::Material material(session_); + material.SetColor(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color), + SkColorGetA(color)); + shape_node.SetMaterial(material); } -void SceneUpdateContext::ExecutePaintTasks( - CompositorContext::ScopedFrame& frame) { - TRACE_EVENT0("flutter", "SceneUpdateContext::ExecutePaintTasks"); +mozart::client::Image* SceneUpdateContext::GenerateImageIfNeeded( + SkColor color, + SkScalar scale_x, + SkScalar scale_y, + const SkRect& paint_bounds, + std::vector paint_layers) { + // Bail if there's nothing to paint. + if (paint_layers.empty()) + return nullptr; + + // Bail if the physical bounds are empty after rounding. + SkISize physical_size = SkISize::Make(paint_bounds.width() * scale_x, + paint_bounds.height() * scale_y); + if (physical_size.isEmpty()) + return nullptr; + // Acquire a surface from the surface producer and register the paint tasks. + auto surface = surface_producer_->ProduceSurface(physical_size); + + if (!surface) { + FTL_LOG(ERROR) << "Could not acquire a surface from the surface producer " + "of size: " + << physical_size.width() << "x" << physical_size.height(); + return nullptr; + } + + auto image = surface->GetImage(); + + // Enqueue the paint task. + paint_tasks_.push_back({.surface = std::move(surface), + .left = paint_bounds.left(), + .top = paint_bounds.top(), + .scale_x = scale_x, + .scale_y = scale_y, + .background_color = color, + .layers = std::move(paint_layers)}); + return image; +} + +std::vector> +SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) { + TRACE_EVENT0("flutter", "SceneUpdateContext::ExecutePaintTasks"); + std::vector> surfaces_to_submit; for (auto& task : paint_tasks_) { FTL_DCHECK(task.surface); - SkCanvas* canvas = task.surface->getCanvas(); + SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas(); Layer::PaintContext context = {*canvas, frame.context().frame_time(), frame.context().engine_time(), - frame.context().memory_usage(), - false}; - - canvas->clear(SK_ColorTRANSPARENT); - canvas->scale(task.scaleX, task.scaleY); + frame.context().memory_usage(), false}; + canvas->restoreToCount(1); + canvas->save(); + canvas->clear(task.background_color); + canvas->scale(task.scale_x, task.scale_y); canvas->translate(-task.left, -task.top); - for (Layer* layer : task.layers) + for (Layer* layer : task.layers) { layer->Paint(context); + } + surfaces_to_submit.emplace_back(std::move(task.surface)); } - paint_tasks_.clear(); + return surfaces_to_submit; } -} // namespace flow +SceneUpdateContext::Entity::Entity(SceneUpdateContext& context) + : context_(context), + previous_entity_(context.top_entity_), + entity_node_(context.session()) { + if (previous_entity_) + previous_entity_->entity_node_.AddChild(entity_node_); + context.top_entity_ = this; +} + +SceneUpdateContext::Entity::~Entity() { + FTL_DCHECK(context_.top_entity_ == this); + context_.top_entity_ = previous_entity_; +} + +SceneUpdateContext::Clip::Clip(SceneUpdateContext& context, + mozart::client::Shape& shape, + const SkRect& shape_bounds) + : Entity(context) { + mozart::client::ShapeNode shape_node(context.session()); + shape_node.SetShape(shape); + shape_node.SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(), + shape_bounds.height() * 0.5f + shape_bounds.top(), + 0.f); + + entity_node().AddPart(shape_node); + entity_node().SetClip(0u, true /* clip to self */); +} + +SceneUpdateContext::Clip::~Clip() = default; -#endif // defined(OS_FUCHSIA) +SceneUpdateContext::Transform::Transform(SceneUpdateContext& context, + const SkMatrix& transform) + : Entity(context) { + // TODO(MZ-192): The perspective and shear components in the matrix + // are not handled correctly. + MatrixDecomposition decomposition(transform); + if (decomposition.IsValid()) { + entity_node().SetTranslation(decomposition.translation().x(), // + decomposition.translation().y(), // + decomposition.translation().z() // + ); + entity_node().SetScale(decomposition.scale().x(), // + decomposition.scale().y(), // + decomposition.scale().z() // + ); + entity_node().SetRotation(decomposition.rotation().fData[0], // + decomposition.rotation().fData[1], // + decomposition.rotation().fData[2], // + decomposition.rotation().fData[3] // + ); + } +} + +SceneUpdateContext::Transform::~Transform() = default; + +SceneUpdateContext::Frame::Frame(SceneUpdateContext& context, + const SkRRect& rrect, + SkColor color, + float elevation, + SkScalar scale_x, + SkScalar scale_y) + : Entity(context), + rrect_(rrect), + color_(color), + scale_x_(scale_x), + scale_y_(scale_y), + paint_bounds_(SkRect::MakeEmpty()) { + entity_node().SetTranslation(0.f, 0.f, elevation); +} + +SceneUpdateContext::Frame::~Frame() { + context().CreateFrame(entity_node(), rrect_, color_, scale_x_, scale_y_, + paint_bounds_, std::move(paint_layers_)); +} + +void SceneUpdateContext::Frame::AddPaintedLayer(Layer* layer) { + FTL_DCHECK(layer->needs_painting()); + paint_layers_.push_back(layer); + paint_bounds_.join(layer->paint_bounds()); +} + +} // namespace flow diff --git a/flow/scene_update_context.h b/flow/scene_update_context.h index 4771487cf..539ceae29 100644 --- a/flow/scene_update_context.h +++ b/flow/scene_update_context.h @@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_FLOW_MOZART_SCENE_UPDATE_CONTEXT_H_ -#define FLUTTER_FLOW_MOZART_SCENE_UPDATE_CONTEXT_H_ +#ifndef FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_ +#define FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_ #include #include +#include "apps/mozart/lib/scene/client/resources.h" #include "flutter/flow/compositor_context.h" #include "lib/ftl/build_config.h" #include "lib/ftl/logging.h" @@ -15,82 +16,157 @@ #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkSurface.h" -#if defined(OS_FUCHSIA) -#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck -#include "apps/mozart/services/composition/resources.fidl.h" // nogncheck -#include "apps/mozart/services/images/image.fidl.h" // nogncheck -#endif // defined(OS_FUCHSIA) - -namespace mozart { -class BufferProducer; -class Node; -class SceneUpdate; -} // namespace mozart - namespace flow { -class Layer; -class SceneUpdateContext; -#if defined(OS_FUCHSIA) +class Layer; +class ExportNode; class SceneUpdateContext { public: + class SurfaceProducerSurface { + public: + virtual ~SurfaceProducerSurface() = default; + + virtual size_t AdvanceAndGetAge() = 0; + + virtual bool FlushSessionAcquireAndReleaseEvents() = 0; + + virtual bool IsValid() const = 0; + + virtual SkISize GetSize() const = 0; + + virtual void SignalWritesFinished( + std::function on_writes_committed) = 0; + + virtual mozart::client::Image* GetImage() = 0; + + virtual sk_sp GetSkiaSurface() const = 0; + }; + class SurfaceProducer { public: - virtual ~SurfaceProducer() {} - virtual sk_sp ProduceSurface(SkISize size, - mozart::ImagePtr* out_image) = 0; + virtual std::unique_ptr ProduceSurface( + const SkISize& size) = 0; + + virtual void SubmitSurface( + std::unique_ptr surface) = 0; }; - SceneUpdateContext(mozart::SceneUpdate* update, + SceneUpdateContext(mozart::client::Session* session, SurfaceProducer* surface_producer); + ~SceneUpdateContext(); - mozart::SceneUpdate* update() const { return update_; } + mozart::client::Session* session() { return session_; } - void AddLayerToCurrentPaintTask(Layer* layer); - void FinalizeCurrentPaintTaskIfNeeded(mozart::Node* container, - const SkMatrix& ctm); + class Entity { + public: + Entity(SceneUpdateContext& context); + ~Entity(); - uint32_t AddResource(mozart::ResourcePtr resource); - void AddChildNode(mozart::Node* container, mozart::NodePtr child); + SceneUpdateContext& context() { return context_; } + mozart::client::EntityNode& entity_node() { return entity_node_; } - void ExecutePaintTasks(CompositorContext::ScopedFrame& frame); + private: + SceneUpdateContext& context_; + Entity* const previous_entity_; - private: - mozart::NodePtr FinalizeCurrentPaintTask(const SkMatrix& ctm); + mozart::client::EntityNode entity_node_; + }; - struct CurrentPaintTask { - CurrentPaintTask(); - void Clear(); + class Clip : public Entity { + public: + Clip(SceneUpdateContext& context, + mozart::client::Shape& shape, + const SkRect& shape_bounds); + ~Clip(); + }; - SkRect bounds; - std::vector layers; + class Transform : public Entity { + public: + Transform(SceneUpdateContext& context, const SkMatrix& transform); + ~Transform(); }; + class Frame : public Entity { + public: + Frame(SceneUpdateContext& context, + const SkRRect& rrect, + SkColor color, + float elevation, + SkScalar scale_x, + SkScalar scale_y); + ~Frame(); + + void AddPaintedLayer(Layer* layer); + + private: + const SkRRect& rrect_; + SkColor const color_; + SkScalar const scale_x_; + SkScalar const scale_y_; + + std::vector paint_layers_; + SkRect paint_bounds_; + }; + + void AddChildScene(ExportNode* export_node, + SkPoint offset, + float device_pixel_ratio, + bool hit_testable); + + // TODO(chinmaygarde): This method must submit the surfaces as soon as paint + // tasks are done. However, given that there is no support currently for + // Vulkan semaphores, we need to submit all the surfaces after an explicit + // CPU wait. Once Vulkan semaphores are available, this method must return + // void and the implementation must submit surfaces on its own as soon as the + // specific canvas operations are done. + FTL_WARN_UNUSED_RESULT + std::vector> ExecutePaintTasks( + CompositorContext::ScopedFrame& frame); + + private: struct PaintTask { - sk_sp surface; + std::unique_ptr surface; SkScalar left; SkScalar top; - SkScalar scaleX; - SkScalar scaleY; + SkScalar scale_x; + SkScalar scale_y; + SkColor background_color; std::vector layers; }; - mozart::SceneUpdate* update_; - SurfaceProducer* surface_producer_; + void CreateFrame(mozart::client::EntityNode& entity_node, + const SkRRect& rrect, + SkColor color, + SkScalar scale_x, + SkScalar scale_y, + const SkRect& paint_bounds, + std::vector paint_layers); + void SetShapeTextureOrColor(mozart::client::ShapeNode& shape_node, + SkColor color, + SkScalar scale_x, + SkScalar scale_y, + const SkRect& paint_bounds, + std::vector paint_layers); + void SetShapeColor(mozart::client::ShapeNode& shape_node, SkColor color); + mozart::client::Image* GenerateImageIfNeeded( + SkColor color, + SkScalar scale_x, + SkScalar scale_y, + const SkRect& paint_bounds, + std::vector paint_layers); + + Entity* top_entity_ = nullptr; + + mozart::client::Session* const session_; + SurfaceProducer* const surface_producer_; - CurrentPaintTask current_paint_task_; std::vector paint_tasks_; - uint32_t next_resource_id_ = 1; - uint32_t next_node_id_ = 1; - FTL_DISALLOW_COPY_AND_ASSIGN(SceneUpdateContext); }; -#endif // defined(OS_FUCHSIA) - } // namespace flow -#endif // FLUTTER_FLOW_MOZART_SCENE_UPDATE_CONTEXT_H_ +#endif // FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_ diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 8c0dbded3..ef0fd7604 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -8,6 +8,8 @@ source_set("ui") { "compositing/scene.h", "compositing/scene_builder.cc", "compositing/scene_builder.h", + "compositing/scene_host.cc", + "compositing/scene_host.h", "dart_runtime_hooks.cc", "dart_runtime_hooks.h", "dart_ui.cc", diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index cdde2b166..b97c12d08 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -199,16 +199,12 @@ class SceneBuilder extends NativeFieldWrapperClass2 { /// (Fuchsia-only) Adds a scene rendered by another application to the scene /// for this application. - /// - /// Applications typically obtain scene tokens when embedding other views via - /// the Fuchsia view manager, but this function is agnostic as to the source - /// of scene token. void addChildScene({ Offset offset: Offset.zero, double devicePixelRatio: 1.0, int physicalWidth: 0, int physicalHeight: 0, - int sceneToken, + SceneHost sceneHost, bool hitTestable: true }) { _addChildScene(offset.dx, @@ -216,7 +212,7 @@ class SceneBuilder extends NativeFieldWrapperClass2 { devicePixelRatio, physicalWidth, physicalHeight, - sceneToken, + sceneHost, hitTestable); } void _addChildScene(double dx, @@ -224,7 +220,7 @@ class SceneBuilder extends NativeFieldWrapperClass2 { double devicePixelRatio, int physicalWidth, int physicalHeight, - int sceneToken, + SceneHost sceneHost, bool hitTestable) native "SceneBuilder_addChildScene"; /// Sets a threshold after which additional debugging information should be recorded. @@ -268,3 +264,24 @@ class SceneBuilder extends NativeFieldWrapperClass2 { /// cannot be used further. Scene build() native "SceneBuilder_build"; } + +/// (Fuchsia-only) Hosts content provided by another application. +class SceneHost extends NativeFieldWrapperClass2 { + /// Creates a host for a child scene. + /// + /// The export token is bound to a scene graph node which acts as a container + /// for the child's content. The creator of the scene host is responsible for + /// sending the corresponding import token (the other endpoint of the event pair) + /// to the child. + /// + /// The scene host takes ownership of the provided export token handle. + SceneHost(int export_token_handle) { + _constructor(export_token_handle); + } + void _constructor(int export_token_handle) native "SceneHost_constructor"; + + /// Releases the resources associated with the child scene host. + /// + /// After calling this function, the child scene host cannot be used further. + void dispose() native "SceneHost_dispose"; +} diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 76106c445..1645781c9 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -52,7 +52,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, SceneBuilder); V(SceneBuilder, addChildScene) \ V(SceneBuilder, addPerformanceOverlay) \ V(SceneBuilder, setRasterizerTracingThreshold) \ - V(SceneBuilder, setCheckerboardOffscreenLayers) \ + V(SceneBuilder, setCheckerboardOffscreenLayers) \ V(SceneBuilder, setCheckerboardRasterCacheImages) \ V(SceneBuilder, build) @@ -163,7 +163,8 @@ void SceneBuilder::pushPhysicalModel(const RRect& rrect, if (!cullRect.intersect(rrect.sk_rrect.rect(), m_cullRects.top())) cullRect = SkRect::MakeEmpty(); - std::unique_ptr layer(new flow::PhysicalModelLayer()); + std::unique_ptr layer( + new flow::PhysicalModelLayer()); layer->set_rrect(rrect.sk_rrect); layer->set_elevation(elevation); layer->set_color(color); @@ -221,7 +222,7 @@ void SceneBuilder::addChildScene(double dx, double devicePixelRatio, int physicalWidth, int physicalHeight, - uint32_t sceneToken, + SceneHost* sceneHost, bool hitTestable) { #if defined(OS_FUCHSIA) if (!m_currentLayer) @@ -236,7 +237,7 @@ void SceneBuilder::addChildScene(double dx, layer->set_offset(SkPoint::Make(dx, dy)); layer->set_device_pixel_ratio(devicePixelRatio); layer->set_physical_size(SkISize::Make(physicalWidth, physicalHeight)); - layer->set_scene_token(sceneToken); + layer->set_export_node(sceneHost->exportNode()); layer->set_hit_testable(hitTestable); m_currentLayer->Add(std::move(layer)); #endif diff --git a/lib/ui/compositing/scene_builder.h b/lib/ui/compositing/scene_builder.h index c66569be4..95d43b808 100644 --- a/lib/ui/compositing/scene_builder.h +++ b/lib/ui/compositing/scene_builder.h @@ -11,6 +11,7 @@ #include "flutter/flow/layers/container_layer.h" #include "flutter/lib/ui/compositing/scene.h" +#include "flutter/lib/ui/compositing/scene_host.h" #include "flutter/lib/ui/painting/image_filter.h" #include "flutter/lib/ui/painting/path.h" #include "flutter/lib/ui/painting/picture.h" @@ -61,7 +62,7 @@ class SceneBuilder : public ftl::RefCountedThreadSafe, double devicePixelRatio, int physicalWidth, int physicalHeight, - uint32_t sceneToken, + SceneHost* sceneHost, bool hitTestable); void setRasterizerTracingThreshold(uint32_t frameInterval); diff --git a/lib/ui/compositing/scene_host.cc b/lib/ui/compositing/scene_host.cc new file mode 100644 index 000000000..1635b64bc --- /dev/null +++ b/lib/ui/compositing/scene_host.cc @@ -0,0 +1,44 @@ +// 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 "flutter/lib/ui/compositing/scene_host.h" + +#include "lib/tonic/dart_args.h" +#include "lib/tonic/dart_binding_macros.h" +#include "lib/tonic/dart_library_natives.h" + +namespace blink { + +static void SceneHost_constructor(Dart_NativeArguments args) { + DartCallConstructor(&SceneHost::create, args); +} + +IMPLEMENT_WRAPPERTYPEINFO(ui, SceneHost); + +#define FOR_EACH_BINDING(V) V(SceneHost, dispose) + +FOR_EACH_BINDING(DART_NATIVE_CALLBACK) + +void SceneHost::RegisterNatives(tonic::DartLibraryNatives* natives) { + natives->Register({{"SceneHost_constructor", SceneHost_constructor, 2, true}, + FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); +} + +ftl::RefPtr SceneHost::create(int export_token_handle) { + return ftl::MakeRefCounted(export_token_handle); +} + +SceneHost::SceneHost(int export_token_handle) { +#if defined(OS_FUCHSIA) + export_node_ = ftl::MakeRefCounted(export_token_handle); +#endif +} + +SceneHost::~SceneHost() {} + +void SceneHost::dispose() { + ClearDartWrapper(); +} + +} // namespace blink diff --git a/lib/ui/compositing/scene_host.h b/lib/ui/compositing/scene_host.h new file mode 100644 index 000000000..33e7ee53d --- /dev/null +++ b/lib/ui/compositing/scene_host.h @@ -0,0 +1,52 @@ +// 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. + +#ifndef FLUTTER_LIB_UI_COMPOSITING_SCENE_HOST_H_ +#define FLUTTER_LIB_UI_COMPOSITING_SCENE_HOST_H_ + +#include + +#include "lib/tonic/dart_wrappable.h" + +#if defined(OS_FUCHSIA) +#include "flutter/flow/export_node.h" +#endif + +namespace tonic { +class DartLibraryNatives; +} // namespace tonic + +namespace blink { + +class SceneHost : public ftl::RefCountedThreadSafe, + public tonic::DartWrappable { + DEFINE_WRAPPERTYPEINFO(); + FRIEND_MAKE_REF_COUNTED(SceneHost); + + public: + static ftl::RefPtr create(int export_token_handle); + + ~SceneHost() override; + +#if defined(OS_FUCHSIA) + const ftl::RefPtr& exportNode() const { + return export_node_; + } +#endif + + void dispose(); + + static void RegisterNatives(tonic::DartLibraryNatives* natives); + + private: +#if defined(OS_FUCHSIA) + ftl::RefPtr export_node_; +#endif + + explicit SceneHost(int export_token_handle); +}; + +} // namespace blink + +#endif // FLUTTER_LIB_UI_COMPOSITING_SCENE_HOST_H_ diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index f394412c6..ae7e8a1ee 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -64,6 +64,7 @@ void DartUI::InitForGlobal() { PictureRecorder::RegisterNatives(g_natives); Scene::RegisterNatives(g_natives); SceneBuilder::RegisterNatives(g_natives); + SceneHost::RegisterNatives(g_natives); SemanticsUpdate::RegisterNatives(g_natives); SemanticsUpdateBuilder::RegisterNatives(g_natives); Vertices::RegisterNatives(g_natives); diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index 956cc695f..42da82c66 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -1169,6 +1169,7 @@ FILE: ../../../flutter/content_handler/rasterizer.cc FILE: ../../../flutter/content_handler/rasterizer.h FILE: ../../../flutter/content_handler/runtime_holder.cc FILE: ../../../flutter/content_handler/runtime_holder.h +FILE: ../../../flutter/flow/export_node.cc FILE: ../../../flutter/flow/layers/backdrop_filter_layer.cc FILE: ../../../flutter/flow/layers/backdrop_filter_layer.h FILE: ../../../flutter/flow/layers/child_scene_layer.cc @@ -1353,20 +1354,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: engine -ORIGIN: ../../../flutter/content_handler/content_handler_thread.cc + ../../../LICENSE +ORIGIN: ../../../flutter/content_handler/service_protocol_hooks.cc + ../../../LICENSE TYPE: LicenseType.bsd -FILE: ../../../flutter/content_handler/content_handler_thread.cc -FILE: ../../../flutter/content_handler/content_handler_thread.h FILE: ../../../flutter/content_handler/service_protocol_hooks.cc FILE: ../../../flutter/content_handler/service_protocol_hooks.h -FILE: ../../../flutter/content_handler/software_rasterizer.cc -FILE: ../../../flutter/content_handler/software_rasterizer.h -FILE: ../../../flutter/content_handler/vulkan_native_rasterizer.cc -FILE: ../../../flutter/content_handler/vulkan_native_rasterizer.h +FILE: ../../../flutter/content_handler/session_connection.cc +FILE: ../../../flutter/content_handler/session_connection.h FILE: ../../../flutter/content_handler/vulkan_rasterizer.cc FILE: ../../../flutter/content_handler/vulkan_rasterizer.h +FILE: ../../../flutter/content_handler/vulkan_surface_producer.cc +FILE: ../../../flutter/content_handler/vulkan_surface_producer.h FILE: ../../../flutter/flow/debug_print.cc FILE: ../../../flutter/flow/debug_print.h +FILE: ../../../flutter/flow/export_node.h FILE: ../../../flutter/flow/layers/physical_model_layer.cc FILE: ../../../flutter/flow/layers/physical_model_layer.h FILE: ../../../flutter/flow/matrix_decomposition.cc @@ -1424,6 +1424,8 @@ FILE: ../../../flutter/fml/thread_local_unittests.cc FILE: ../../../flutter/fml/thread_unittests.cc FILE: ../../../flutter/fml/trace_event.cc FILE: ../../../flutter/fml/trace_event.h +FILE: ../../../flutter/lib/ui/compositing/scene_host.cc +FILE: ../../../flutter/lib/ui/compositing/scene_host.h FILE: ../../../flutter/lib/ui/painting/utils.cc FILE: ../../../flutter/lib/ui/painting/vertices.cc FILE: ../../../flutter/lib/ui/painting/vertices.h @@ -1503,6 +1505,44 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== +==================================================================================================== +LIBRARY: engine +ORIGIN: ../../../flutter/content_handler/vulkan_surface.cc + ../../../lib/ftl/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/content_handler/vulkan_surface.cc +FILE: ../../../flutter/content_handler/vulkan_surface.h +FILE: ../../../flutter/content_handler/vulkan_surface_pool.cc +FILE: ../../../flutter/content_handler/vulkan_surface_pool.h +---------------------------------------------------------------------------------------------------- +Copyright 2017 The Fuchsia Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: engine ORIGIN: ../../../flutter/flow/layers/clip_path_layer.cc + ../../../LICENSE @@ -9379,4 +9419,4 @@ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== -Total license count: 208 +Total license count: 209 diff --git a/vulkan/BUILD.gn b/vulkan/BUILD.gn index 1c24eedc8..8ff1e710a 100644 --- a/vulkan/BUILD.gn +++ b/vulkan/BUILD.gn @@ -63,5 +63,8 @@ source_set("vulkan") { "//third_party/skia:gpu", ] - public_configs = [ ":vulkan_config", "//third_party/skia:skia_private" ] + public_configs = [ + ":vulkan_config", + "//third_party/skia:skia_private", + ] } diff --git a/vulkan/vulkan_proc_table.cc b/vulkan/vulkan_proc_table.cc index 2584c2861..39a087ac5 100644 --- a/vulkan/vulkan_proc_table.cc +++ b/vulkan/vulkan_proc_table.cc @@ -74,16 +74,16 @@ bool VulkanProcTable::SetupInstanceProcAddresses( ACQUIRE_PROC(CreateDevice, handle); ACQUIRE_PROC(DestroyDevice, handle); ACQUIRE_PROC(DestroyInstance, handle); + ACQUIRE_PROC(DestroySurfaceKHR, handle); ACQUIRE_PROC(EnumerateDeviceLayerProperties, handle); ACQUIRE_PROC(EnumeratePhysicalDevices, handle); + ACQUIRE_PROC(GetDeviceProcAddr, handle); ACQUIRE_PROC(GetPhysicalDeviceFeatures, handle); ACQUIRE_PROC(GetPhysicalDeviceQueueFamilyProperties, handle); ACQUIRE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR, handle); ACQUIRE_PROC(GetPhysicalDeviceSurfaceFormatsKHR, handle); ACQUIRE_PROC(GetPhysicalDeviceSurfacePresentModesKHR, handle); ACQUIRE_PROC(GetPhysicalDeviceSurfaceSupportKHR, handle); - ACQUIRE_PROC(GetDeviceProcAddr, handle); - ACQUIRE_PROC(DestroySurfaceKHR, handle); #if OS_ANDROID ACQUIRE_PROC(CreateAndroidSurfaceKHR, handle); @@ -92,10 +92,10 @@ bool VulkanProcTable::SetupInstanceProcAddresses( #if OS_FUCHSIA [this, &handle]() -> bool { ACQUIRE_PROC(CreateMagmaSurfaceKHR, handle); + ACQUIRE_PROC(ExportDeviceMemoryMAGMA, handle); ACQUIRE_PROC(GetPhysicalDeviceMagmaPresentationSupportKHR, handle); return true; }(); - #endif // OS_FUCHSIA // The debug report functions are optional. We don't want proc acquisition to @@ -116,28 +116,37 @@ bool VulkanProcTable::SetupInstanceProcAddresses( bool VulkanProcTable::SetupDeviceProcAddresses( const VulkanHandle& handle) { ACQUIRE_PROC(AcquireNextImageKHR, handle); - ACQUIRE_PROC(CreateSwapchainKHR, handle); - ACQUIRE_PROC(DestroySwapchainKHR, handle); - ACQUIRE_PROC(GetSwapchainImagesKHR, handle); - ACQUIRE_PROC(QueuePresentKHR, handle); ACQUIRE_PROC(AllocateCommandBuffers, handle); + ACQUIRE_PROC(AllocateMemory, handle); ACQUIRE_PROC(BeginCommandBuffer, handle); + ACQUIRE_PROC(BindImageMemory, handle); ACQUIRE_PROC(CmdPipelineBarrier, handle); ACQUIRE_PROC(CreateCommandPool, handle); ACQUIRE_PROC(CreateFence, handle); + ACQUIRE_PROC(CreateImage, handle); ACQUIRE_PROC(CreateSemaphore, handle); + ACQUIRE_PROC(CreateSwapchainKHR, handle); ACQUIRE_PROC(DestroyCommandPool, handle); ACQUIRE_PROC(DestroyFence, handle); + ACQUIRE_PROC(DestroyImage, handle); ACQUIRE_PROC(DestroySemaphore, handle); + ACQUIRE_PROC(DestroySwapchainKHR, handle); ACQUIRE_PROC(DeviceWaitIdle, handle); ACQUIRE_PROC(EndCommandBuffer, handle); ACQUIRE_PROC(FreeCommandBuffers, handle); + ACQUIRE_PROC(FreeMemory, handle); ACQUIRE_PROC(GetDeviceQueue, handle); + ACQUIRE_PROC(GetImageMemoryRequirements, handle); + ACQUIRE_PROC(GetSwapchainImagesKHR, handle); + ACQUIRE_PROC(QueuePresentKHR, handle); ACQUIRE_PROC(QueueSubmit, handle); + ACQUIRE_PROC(QueueWaitIdle, handle); ACQUIRE_PROC(ResetCommandBuffer, handle); ACQUIRE_PROC(ResetFences, handle); ACQUIRE_PROC(WaitForFences, handle); - +#if OS_FUCHSIA + ACQUIRE_PROC(ExportDeviceMemoryMAGMA, handle); +#endif // OS_FUCHSIA device_ = {handle, nullptr}; return true; } diff --git a/vulkan/vulkan_proc_table.h b/vulkan/vulkan_proc_table.h index 039929880..b9e68986d 100644 --- a/vulkan/vulkan_proc_table.h +++ b/vulkan/vulkan_proc_table.h @@ -65,12 +65,15 @@ class VulkanProcTable : public ftl::RefCountedThreadSafe { DEFINE_PROC(AcquireNextImageKHR); DEFINE_PROC(AllocateCommandBuffers); + DEFINE_PROC(AllocateMemory); DEFINE_PROC(BeginCommandBuffer); + DEFINE_PROC(BindImageMemory); DEFINE_PROC(CmdPipelineBarrier); DEFINE_PROC(CreateCommandPool); DEFINE_PROC(CreateDebugReportCallbackEXT); DEFINE_PROC(CreateDevice); DEFINE_PROC(CreateFence); + DEFINE_PROC(CreateImage); DEFINE_PROC(CreateInstance); DEFINE_PROC(CreateSemaphore); DEFINE_PROC(CreateSwapchainKHR); @@ -78,6 +81,7 @@ class VulkanProcTable : public ftl::RefCountedThreadSafe { DEFINE_PROC(DestroyDebugReportCallbackEXT); DEFINE_PROC(DestroyDevice); DEFINE_PROC(DestroyFence); + DEFINE_PROC(DestroyImage); DEFINE_PROC(DestroyInstance); DEFINE_PROC(DestroySemaphore); DEFINE_PROC(DestroySurfaceKHR); @@ -89,26 +93,30 @@ class VulkanProcTable : public ftl::RefCountedThreadSafe { DEFINE_PROC(EnumerateInstanceLayerProperties); DEFINE_PROC(EnumeratePhysicalDevices); DEFINE_PROC(FreeCommandBuffers); + DEFINE_PROC(FreeMemory); DEFINE_PROC(GetDeviceProcAddr); DEFINE_PROC(GetDeviceQueue); + DEFINE_PROC(GetImageMemoryRequirements); DEFINE_PROC(GetInstanceProcAddr); DEFINE_PROC(GetPhysicalDeviceFeatures); DEFINE_PROC(GetPhysicalDeviceQueueFamilyProperties); DEFINE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR); DEFINE_PROC(GetPhysicalDeviceSurfaceFormatsKHR); DEFINE_PROC(GetPhysicalDeviceSurfacePresentModesKHR); + DEFINE_PROC(GetPhysicalDeviceSurfaceSupportKHR); DEFINE_PROC(GetSwapchainImagesKHR); DEFINE_PROC(QueuePresentKHR); DEFINE_PROC(QueueSubmit); + DEFINE_PROC(QueueWaitIdle); DEFINE_PROC(ResetCommandBuffer); DEFINE_PROC(ResetFences); DEFINE_PROC(WaitForFences); - DEFINE_PROC(GetPhysicalDeviceSurfaceSupportKHR); #if OS_ANDROID DEFINE_PROC(CreateAndroidSurfaceKHR); #endif // OS_ANDROID #if OS_FUCHSIA DEFINE_PROC(CreateMagmaSurfaceKHR); + DEFINE_PROC(ExportDeviceMemoryMAGMA); DEFINE_PROC(GetPhysicalDeviceMagmaPresentationSupportKHR); #endif // OS_FUCHSIA -- GitLab