diff --git a/common/threads.h b/common/threads.h index 7846c2a3e7f21e63d87fde668ab3b27a8563be00..f9058b17cab269cf589136dea953cbb1e4f0841b 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 d3f000a30f9199cf2e72861ec99a0652bf1356e9..e03bfbe18619bde4e034df76675368954f77e17c 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 78d0bb9e7f241f31c208008e2c6aba18f3a5f740..a624a8a4498027412ad9f6a3567a8c3931ee9551 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 7ee77e06bedc9e095e2f69ed9d3c7bd08bcd8064..a4693b1603dd3561201f9378e98461621ca8ab0a 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 bf7490c254efb243963e8101090dbf6bba4f95ec..0000000000000000000000000000000000000000 --- 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 7e14a65f87da4a85ecec1292e755eb22d36aa205..0000000000000000000000000000000000000000 --- 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 e0ea43f513a5e5909bc2936d7aeac479978e6765..ac22fa0869807e26da91ddb11e567fad8f29cff1 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 3a613a9f91951cbf93723cb7073ce4f960de5562..aeb2687afcb2f58bea90edf4b3aeacd6c9ca8a7a 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 878a0fd28b1d80e506d0e199d27687c3b3426297..00f1f75e075031023f4f38856820279d650c16fd 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 eeafb6e5fb720efda6793b9ca91153cfaa3ff2b8..1f650aa98d30b81a62c5ac7281ea8df1370c7d3a 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 0000000000000000000000000000000000000000..915717aba8aeceff3b2cd9e1983e8d2361b8cbe2 --- /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 0000000000000000000000000000000000000000..2b6ca38b3f5c7368f04b9774434b7d6d35cc6ad3 --- /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 21c37c7a978a92d8a942bb8821adc85dd3003617..0000000000000000000000000000000000000000 --- 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 50dab87b647495d8d8300d4d97411aa66f9f5d4a..0000000000000000000000000000000000000000 --- 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 40985c36cc0bbd4017d9b213d811b7464aeb1494..0000000000000000000000000000000000000000 --- 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 bf54f2d765208b1a379fc56abbcaa990bc667b16..0000000000000000000000000000000000000000 --- 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 2eaccb6c3f9a22c10826064353f965308d00151f..a4ef81291bfa7c175ba2a3123daea67750bf3335 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 f600ce1870b4f9e50048eb3a0320667fb73f1bb8..9d0ddc0c68d3a233543227e36b8ea7807e6de762 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 0000000000000000000000000000000000000000..128e972d3bef17f37b557096dcb2d695db2fdca2 --- /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 0000000000000000000000000000000000000000..fe91a7fe4de3d4b8653e68153bd658697f5b4561 --- /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 0000000000000000000000000000000000000000..45c7f668d21233dd9c147fc58f8200f87f7925de --- /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 0000000000000000000000000000000000000000..dbd04df0fb9067493e2d4aae51e7bc3d2cc181e9 --- /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 0000000000000000000000000000000000000000..a632959c77f2797017474838f567b2521a185123 --- /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 0000000000000000000000000000000000000000..453fe9047bd449a71b1996493d489a2c26e2c2fd --- /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 112ec6389c44a3c130c107aea3a5483e8d904492..e278ed10e039dbf00c75009a8935a05bd152aa29 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 0000000000000000000000000000000000000000..be4a1cea1da3933c45b8bb9807e12f5294cf4f0a --- /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 0000000000000000000000000000000000000000..da467941881c67c59e341703d192a1c94122dbb9 --- /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 7b16fc34667dc3b3046f4d4c425a83b1da95cc35..0077f6f87e451cf3b26a706b093716446ab05ebf 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 e38891234f794c092493f153f656a16c6c804e8a..6e016e78014f4d8750535fb63ee4ef1b0e17acf9 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 2af48ea070a7f2865397df89e70d68363431ca37..b5f3d5dc12eb059541d48b08dd9436a37189ff06 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 93640ec18a1fc00876ab1d8338cd910e94f20742..9d66ad5b37e77761e3777b3262ced7f363816822 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 05a1c89290f46d94a10e90eacec29aba559d4909..39f0e17885bc7c679fba1dc4dec31bf633a6ecb7 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 a62d66aa42a6da87f424ac5625582656cb3333ca..1b2354a342c5593946c062bc3480a734e0c925bb 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 1c6d6748a9eeabf708175e9c1913dbaaf18f3a23..e8a08253bb64a8e0de5a18ca5af15074da1e8d32 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 5b09e006366fcfd4c0880ef1e43dd3939616202f..51416f20fa9fc9d269d1b04228c1f7f14d662542 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 8eea82c8f21b5f83ce68fa8183998efaae077c60..f26670b287068a015a8c861e086e39b5119995e4 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 79b8ae554cbb367bb0cf2b37e994dfd5cd0f7ae2..67ba0345361d85f3ed30c5664374a7e003351769 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 e5808b1607a19a802f71f974f8177c1163ef795b..0471d58da3d6e4161200894822350c2f2b1ea90d 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 df5e7d71dfba44f565da1b0dd8558e4ed6c88bea..f327f121a4ad8dab462290e91df4a7fd8b8ebe5e 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 c320e6896ffe8f45aa1a36f1901dd2796afa7a19..d9665d2d004645538a6359b716a4f5e663406c3d 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 0aaa0d64255f359229801c8ab3bc499b2b9d510a..f21fa15a0b992a5c5c5ac5fc9bd6289bd21bec72 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 c285a3f58dc7d57a8067bceb2cc4242786dd83e3..67148dc0c083b8542a6fee4f3afe2c9f60e06292 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 c42abe802c95ea307b29f18c634af0ec924cfc8e..7bcecd40ccb0046fc4b7ffca3251ff6c1e2c6325 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 aab6df5e844a43f5fc27aaa807132738d0ceb061..20dd342327c781a4bd88d3cfb60116660bb4f5f3 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 90863df3b9e07ecd223c0969acb70365a9dc9dbe..1b7e8fcacac9c0db892fa9985cdd559abd74f865 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 27a988df27a725545dc0931c9855b1c93e79cf58..32eb634c61444a94df559aa3d35bf54d3bc0ef2a 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 1ccea1023a6eb9c61ebd5068e7c8563418d2f91b..c1bdbc158a59a89733feca2c48582d4acbbd8a62 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 bc9de32fcbd37b82688f9cb3ee2e8ef10b354e95..d6dc5e92d201ae5022bf500cf63d570a93b37a40 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 138dd8171f3f5d8214a726c94e11050293688ef7..653e1839c7b341d727719dbeda700909a237bfb7 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 66bb07f4218971106af98d4b84931bd4af3b6972..cedeec474c04a2b5da5ad67d1e456a6f7654fdfc 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 5485104b242f368c846c061384ebfc95023b21e8..447b867b363dd7a47e8187199754ec800a2ecdcc 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 774283e22f21f2c23451e3405c4b982bffd663fa..21c1d4ee81e7945da175be2a65ed85c322988cc8 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 f60cd23c397ad3d5be3d58b0cf0f8fff73962038..6479163b575081e9099a4a41bc0e82ddc92159e1 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 dee5fc5796eaa64c60296e5012717b25d2e54bf5..e3f47f446243457235e25d6996cf34633386d66b 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 1e3dece8ce0a204c858470e8cb3b549bb4ab2adb..822851227dcc28095d9bf8e1560de0a9bbc01123 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 4771487cfb4eb74beaf3cb90de900da6bd0d1dd8..539ceae29e950e1a1fac05e60e2440ddb39c45b6 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 8c0dbded343ead1b72843f828c90c9b92ee2a1f1..ef0fd7604496633e7b7620bd2933091121cfb6e6 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 cdde2b16682219995c8c335ca14f78a3dd04ad78..b97c12d08a527b054600deee08a32b84e4dea898 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 76106c445205a32e9821c72a44e0f8056fc82876..1645781c9951fed2b67dc7f358ce755e4885e3ea 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 c66569be4bcd90925cc5d8a855ecbd27d47df58a..95d43b808795c61adcfe43b377411c727d07d03f 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 0000000000000000000000000000000000000000..1635b64bc79cb9e9e3b454fe883ef3954739cdf9 --- /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 0000000000000000000000000000000000000000..33e7ee53df04dd7da1eba042d05310b07d068207 --- /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 f394412c6957dcea7f08b8bf7e1d2c5a516bad72..ae7e8a1ee317d0c6f601a16b4f6fb010793094a7 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 956cc695f942ff00c6735a0a2fa1b49e7fc4f758..42da82c66c94655d44b3259e3b474d54118449cb 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 1c24eedc8b04e301dbc0add993321be93ce64d7b..8ff1e710af234a7d3f7d58cf93354a22390c73ec 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 2584c2861c761f235e4b72f00de8acf3bf6fd783..39a087ac5f7afadb565741899325a42cd4ac5966 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 039929880e7795545ca30bd6411cf5a8a14ec5e3..b9e68986db63e583f213afbdd72b14a99d15114f 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