diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index a98cab24c4da3..b75d53306c93d 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -844,6 +844,8 @@ ORIGIN: ../../../flutter/flow/raster_cache_util.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/rtree.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/rtree.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/skia_gpu_object.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/flow/studio.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/flow/studio.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/surface.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/surface.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/surface_frame.cc + ../../../flutter/LICENSE @@ -2241,6 +2243,20 @@ ORIGIN: ../../../flutter/shell/common/vsync_waiter_fallback.cc + ../../../flutte ORIGIN: ../../../flutter/shell/common/vsync_waiter_fallback.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/vsync_waiters_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/vsync_waiters_test.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_gl_impeller.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_gl_impeller.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_gl_skia.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_gl_skia.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_metal_impeller.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_metal_impeller.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_metal_skia.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_metal_skia.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_software.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_software.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_vulkan.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_vulkan.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_vulkan_impeller.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/gpu/gpu_studio_vulkan_impeller.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/gpu/gpu_surface_gl_impeller.cc + ../../../flutter/LICENSE @@ -2805,6 +2821,15 @@ ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target.h + ../. ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target_cache.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target_cache.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_struct_macros.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_studio.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_studio_gl.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_studio_gl.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_studio_metal.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_studio_metal.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_studio_software.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_studio_software.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_studio_vulkan.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_studio_vulkan.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_gl.cc + ../../../flutter/LICENSE @@ -2933,6 +2958,8 @@ ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/software_surface.cc + .. ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/software_surface.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/software_surface_producer.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/software_surface_producer.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/studio.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/studio.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/surface.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/surface.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/surface_producer.h + ../../../flutter/LICENSE @@ -3513,6 +3540,8 @@ FILE: ../../../flutter/flow/raster_cache_util.h FILE: ../../../flutter/flow/rtree.cc FILE: ../../../flutter/flow/rtree.h FILE: ../../../flutter/flow/skia_gpu_object.h +FILE: ../../../flutter/flow/studio.cc +FILE: ../../../flutter/flow/studio.h FILE: ../../../flutter/flow/surface.cc FILE: ../../../flutter/flow/surface.h FILE: ../../../flutter/flow/surface_frame.cc @@ -4912,6 +4941,20 @@ FILE: ../../../flutter/shell/common/vsync_waiter_fallback.cc FILE: ../../../flutter/shell/common/vsync_waiter_fallback.h FILE: ../../../flutter/shell/common/vsync_waiters_test.cc FILE: ../../../flutter/shell/common/vsync_waiters_test.h +FILE: ../../../flutter/shell/gpu/gpu_studio_gl_impeller.cc +FILE: ../../../flutter/shell/gpu/gpu_studio_gl_impeller.h +FILE: ../../../flutter/shell/gpu/gpu_studio_gl_skia.cc +FILE: ../../../flutter/shell/gpu/gpu_studio_gl_skia.h +FILE: ../../../flutter/shell/gpu/gpu_studio_metal_impeller.h +FILE: ../../../flutter/shell/gpu/gpu_studio_metal_impeller.mm +FILE: ../../../flutter/shell/gpu/gpu_studio_metal_skia.h +FILE: ../../../flutter/shell/gpu/gpu_studio_metal_skia.mm +FILE: ../../../flutter/shell/gpu/gpu_studio_software.cc +FILE: ../../../flutter/shell/gpu/gpu_studio_software.h +FILE: ../../../flutter/shell/gpu/gpu_studio_vulkan.cc +FILE: ../../../flutter/shell/gpu/gpu_studio_vulkan.h +FILE: ../../../flutter/shell/gpu/gpu_studio_vulkan_impeller.cc +FILE: ../../../flutter/shell/gpu/gpu_studio_vulkan_impeller.h FILE: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.cc FILE: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.h FILE: ../../../flutter/shell/gpu/gpu_surface_gl_impeller.cc @@ -5490,6 +5533,15 @@ FILE: ../../../flutter/shell/platform/embedder/embedder_render_target.h FILE: ../../../flutter/shell/platform/embedder/embedder_render_target_cache.cc FILE: ../../../flutter/shell/platform/embedder/embedder_render_target_cache.h FILE: ../../../flutter/shell/platform/embedder/embedder_struct_macros.h +FILE: ../../../flutter/shell/platform/embedder/embedder_studio.h +FILE: ../../../flutter/shell/platform/embedder/embedder_studio_gl.cc +FILE: ../../../flutter/shell/platform/embedder/embedder_studio_gl.h +FILE: ../../../flutter/shell/platform/embedder/embedder_studio_metal.h +FILE: ../../../flutter/shell/platform/embedder/embedder_studio_metal.mm +FILE: ../../../flutter/shell/platform/embedder/embedder_studio_software.cc +FILE: ../../../flutter/shell/platform/embedder/embedder_studio_software.h +FILE: ../../../flutter/shell/platform/embedder/embedder_studio_vulkan.cc +FILE: ../../../flutter/shell/platform/embedder/embedder_studio_vulkan.h FILE: ../../../flutter/shell/platform/embedder/embedder_surface.cc FILE: ../../../flutter/shell/platform/embedder/embedder_surface.h FILE: ../../../flutter/shell/platform/embedder/embedder_surface_gl.cc @@ -5621,6 +5673,8 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/software_surface.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/software_surface.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/software_surface_producer.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/software_surface_producer.h +FILE: ../../../flutter/shell/platform/fuchsia/flutter/studio.cc +FILE: ../../../flutter/shell/platform/fuchsia/flutter/studio.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/surface.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/surface.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/surface_producer.h diff --git a/flow/BUILD.gn b/flow/BUILD.gn index efda895393f26..7c6b63e9e02f0 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -78,6 +78,8 @@ source_set("flow") { "rtree.cc", "rtree.h", "skia_gpu_object.h", + "studio.cc", + "studio.h", "surface.cc", "surface.h", "surface_frame.cc", diff --git a/flow/embedded_views.cc b/flow/embedded_views.cc index b76c9730af903..406f3c476aa07 100644 --- a/flow/embedded_views.cc +++ b/flow/embedded_views.cc @@ -110,10 +110,6 @@ const std::vector>::const_iterator MutatorsStack::End() return vector_.end(); }; -bool ExternalViewEmbedder::SupportsDynamicThreadMerging() { - return false; -} - void ExternalViewEmbedder::Teardown() {} } // namespace flutter diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 4162e79a15af6..f382c161c6451 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -432,13 +432,6 @@ class ExternalViewEmbedder { bool should_resubmit_frame, fml::RefPtr raster_thread_merger) {} - // Whether the embedder should support dynamic thread merging. - // - // Returning `true` results a |RasterThreadMerger| instance to be created. - // * See also |BegineFrame| and |EndFrame| for getting the - // |RasterThreadMerger| instance. - virtual bool SupportsDynamicThreadMerging(); - // Called when the rasterizer is being torn down. // This method provides a way to release resources associated with the current // embedder. diff --git a/flow/studio.cc b/flow/studio.cc new file mode 100644 index 0000000000000..0b38e3008a93b --- /dev/null +++ b/flow/studio.cc @@ -0,0 +1,33 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/flow/studio.h" + +namespace flutter { + +Studio::Studio() = default; + +Studio::~Studio() = default; + +std::unique_ptr Studio::MakeRenderContextCurrent() { + return std::make_unique(true); +} + +bool Studio::ClearRenderContext() { + return false; +} + +bool Studio::AllowsDrawingWhenGpuDisabled() const { + return true; +} + +bool Studio::EnableRasterCache() const { + return true; +} + +std::shared_ptr Studio::GetAiksContext() const { + return nullptr; +} + +} // namespace flutter diff --git a/flow/studio.h b/flow/studio.h new file mode 100644 index 0000000000000..4bd1823d7b60b --- /dev/null +++ b/flow/studio.h @@ -0,0 +1,47 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_FLOW_STUDIO_H_ +#define FLUTTER_FLOW_STUDIO_H_ + +#include + +#include "flutter/common/graphics/gl_context_switch.h" +#include "flutter/fml/macros.h" + +class GrDirectContext; + +namespace impeller { +class AiksContext; +} // namespace impeller + +namespace flutter { + +class Studio { + public: + Studio(); + + virtual ~Studio(); + + virtual bool IsValid() = 0; + + virtual GrDirectContext* GetContext() = 0; + + virtual std::unique_ptr MakeRenderContextCurrent(); + + virtual bool ClearRenderContext(); + + virtual bool AllowsDrawingWhenGpuDisabled() const; + + virtual bool EnableRasterCache() const; + + virtual std::shared_ptr GetAiksContext() const; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(Studio); +}; + +} // namespace flutter + +#endif // FLUTTER_FLOW_STUDIO_H_ diff --git a/flow/surface.cc b/flow/surface.cc index 795d74780d8fc..4461ce3888860 100644 --- a/flow/surface.cc +++ b/flow/surface.cc @@ -10,26 +10,6 @@ Surface::Surface() = default; Surface::~Surface() = default; -std::unique_ptr Surface::MakeRenderContextCurrent() { - return std::make_unique(true); -} - -bool Surface::ClearRenderContext() { - return false; -} - -bool Surface::AllowsDrawingWhenGpuDisabled() const { - return true; -} - -bool Surface::EnableRasterCache() const { - return true; -} - -std::shared_ptr Surface::GetAiksContext() const { - return nullptr; -} - Surface::SurfaceData Surface::GetSurfaceData() const { return {}; } diff --git a/flow/surface.h b/flow/surface.h index f824e0eb9bd8e..4699bc61b4d6d 100644 --- a/flow/surface.h +++ b/flow/surface.h @@ -39,18 +39,6 @@ class Surface { virtual SkMatrix GetRootTransformation() const = 0; - virtual GrDirectContext* GetContext() = 0; - - virtual std::unique_ptr MakeRenderContextCurrent(); - - virtual bool ClearRenderContext(); - - virtual bool AllowsDrawingWhenGpuDisabled() const; - - virtual bool EnableRasterCache() const; - - virtual std::shared_ptr GetAiksContext() const; - /// Capture the `SurfaceData` currently present in the surface. /// /// Not guaranteed to work on all setups and not intended to be used in diff --git a/lib/ui/compositing/scene_builder_unittests.cc b/lib/ui/compositing/scene_builder_unittests.cc index 702d83bf61417..d83e15350d64c 100644 --- a/lib/ui/compositing/scene_builder_unittests.cc +++ b/lib/ui/compositing/scene_builder_unittests.cc @@ -82,7 +82,7 @@ TEST_F(ShellTest, SceneBuilderBuildAndSceneDisposeReleasesLayerStack) { AddNativeCallback("ValidateSceneHasNoLayers", CREATE_NATIVE_ENTRY(validate_scene_has_no_layers)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -141,7 +141,7 @@ TEST_F(ShellTest, EngineLayerDisposeReleasesReference) { AddNativeCallback("ValidateEngineLayerDispose", CREATE_NATIVE_ENTRY(validate_engine_layer_dispose)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index 77b126d797346..1971605b475e1 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -99,7 +99,7 @@ typedef CanvasPath Path; V(PlatformConfigurationNativeApi::ImplicitViewEnabled, 0) \ V(PlatformConfigurationNativeApi::DefaultRouteName, 0) \ V(PlatformConfigurationNativeApi::ScheduleFrame, 0) \ - V(PlatformConfigurationNativeApi::Render, 1) \ + V(PlatformConfigurationNativeApi::Render, 2) \ V(PlatformConfigurationNativeApi::UpdateSemantics, 1) \ V(PlatformConfigurationNativeApi::SetNeedsReportTimings, 1) \ V(PlatformConfigurationNativeApi::SetIsolateDebugName, 1) \ diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index c391d273e1e59..7602df1846410 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -4,6 +4,20 @@ part of dart.ui; +@pragma('vm:entry-point') +void _addView( + Object id, +) { + PlatformDispatcher.instance._addView(id); +} + +@pragma('vm:entry-point') +void _removeView( + Object id, +) { + PlatformDispatcher.instance._removeView(id); +} + @pragma('vm:entry-point') void _updateDisplays( List ids, @@ -30,6 +44,11 @@ void _updateDisplays( PlatformDispatcher.instance._updateDisplays(displays); } +@pragma('vm:entry-point') +void _sendViewConfigurations(List viewIds) { + PlatformDispatcher.instance._onSentViewConfigurations(viewIds); +} + @pragma('vm:entry-point') void _updateWindowMetrics( int id, diff --git a/lib/ui/hooks_unittests.cc b/lib/ui/hooks_unittests.cc index 8fc69f42dcd7d..c386c462f9487 100644 --- a/lib/ui/hooks_unittests.cc +++ b/lib/ui/hooks_unittests.cc @@ -35,7 +35,7 @@ TEST_F(HooksTest, HooksUnitTests) { auto message_latch = std::make_shared(); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto call_hook = [](Dart_NativeArguments args) { diff --git a/lib/ui/painting/image_dispose_unittests.cc b/lib/ui/painting/image_dispose_unittests.cc index 0f8bb6d027062..2d1a648bdf6bc 100644 --- a/lib/ui/painting/image_dispose_unittests.cc +++ b/lib/ui/painting/image_dispose_unittests.cc @@ -69,7 +69,7 @@ TEST_F(ImageDisposeTest, ImageReleasedAfterFrameAndDisposePictureAndLayer) { CREATE_NATIVE_ENTRY(native_capture_image_and_picture)); AddNativeCallback("Finish", CREATE_NATIVE_ENTRY(native_finish)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); diff --git a/lib/ui/painting/image_encoding_unittests.cc b/lib/ui/painting/image_encoding_unittests.cc index 8a111167fc64d..833dfc11856f8 100644 --- a/lib/ui/painting/image_encoding_unittests.cc +++ b/lib/ui/painting/image_encoding_unittests.cc @@ -106,7 +106,7 @@ TEST_F(ShellTest, EncodeImageGivesExternalTypedData) { AddNativeCallback("ValidateExternal", CREATE_NATIVE_ENTRY(nativeValidateExternal)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -170,7 +170,7 @@ TEST_F(ShellTest, EncodeImageAccessesSyncSwitch) { AddNativeCallback("EncodeImage", CREATE_NATIVE_ENTRY(native_encode_image)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); diff --git a/lib/ui/painting/paint_unittests.cc b/lib/ui/painting/paint_unittests.cc index 1324568cb2347..1986cc8d78701 100644 --- a/lib/ui/painting/paint_unittests.cc +++ b/lib/ui/painting/paint_unittests.cc @@ -36,7 +36,7 @@ TEST_F(ShellTest, ConvertPaintToDlPaint) { AddNativeCallback("ConvertPaintToDlPaint", CREATE_NATIVE_ENTRY(nativeToDlPaint)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); diff --git a/lib/ui/painting/path_unittests.cc b/lib/ui/painting/path_unittests.cc index f02b72ff5a511..e9f39b3ba73c8 100644 --- a/lib/ui/painting/path_unittests.cc +++ b/lib/ui/painting/path_unittests.cc @@ -50,7 +50,7 @@ TEST_F(ShellTest, PathVolatilityOldPathsBecomeNonVolatile) { AddNativeCallback("ValidatePath", CREATE_NATIVE_ENTRY(native_validate_path)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -108,7 +108,7 @@ TEST_F(ShellTest, PathVolatilityGCRemovesPathFromTracker) { AddNativeCallback("ValidatePath", CREATE_NATIVE_ENTRY(native_validate_path)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -164,7 +164,7 @@ TEST_F(ShellTest, DeterministicRenderingDisablesPathVolatility) { AddNativeCallback("ValidatePath", CREATE_NATIVE_ENTRY(native_validate_path)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); diff --git a/lib/ui/painting/single_frame_codec_unittests.cc b/lib/ui/painting/single_frame_codec_unittests.cc index d9a76af262ed5..2cbb2254442a4 100644 --- a/lib/ui/painting/single_frame_codec_unittests.cc +++ b/lib/ui/painting/single_frame_codec_unittests.cc @@ -41,7 +41,7 @@ TEST_F(ShellTest, SingleFrameCodecAccuratelyReportsSize) { AddNativeCallback("ValidateCodec", CREATE_NATIVE_ENTRY(validate_codec)); AddNativeCallback("Finish", CREATE_NATIVE_ENTRY(finish)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index 1d479391984b3..9ee545d4c1f62 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -61,6 +61,8 @@ typedef ErrorCallback = bool Function(Object exception, StackTrace stackTrace); // A gesture setting value that indicates it has not been set by the engine. const double _kUnsetGestureSetting = -1.0; +const int _kImplicitViewId = 0; + // A message channel to receive KeyData from the platform. // // See embedder.cc::kFlutterKeyDataChannel for more information. @@ -111,6 +113,12 @@ class PlatformDispatcher { /// these. Use [instance] to access the singleton. PlatformDispatcher._() { _setNeedsReportTimings = _nativeSetNeedsReportTimings; + // TODO(dkwingsmt): Can not call _implicitViewEnabled here because + // the Dart state has not finished initialization. + // if (_implicitViewEnabled()) { + // print('PlatformDispatcher ctor 2'); + // _implicitView = FlutterView._(_kImplicitViewId, this); + // } } /// The [PlatformDispatcher] singleton. @@ -173,6 +181,10 @@ class PlatformDispatcher { /// the application. /// /// If any of their configurations change, [onMetricsChanged] will be called. + /// + /// If implicit view is enabled but the implicit view is currently closed, + /// this list will not include the implicit view, but [implicitView] will + /// still be a non-null value. Iterable get views => _views.values; final Map _views = {}; @@ -203,12 +215,23 @@ class PlatformDispatcher { /// the application is shut down (although the engine may replace or remove /// the underlying backing surface of the view at its discretion). /// + /// If the implicit view is currently closed, [views] will not include this + /// value, but this property is still non-null, and single-view apps that + /// render into this property will still be able to do so, resulting in a + /// no-op. + /// /// See also: /// /// * [View.of], for accessing the current view. /// * [PlatformDispatcher.views] for a list of all [FlutterView]s provided /// by the platform. - FlutterView? get implicitView => _implicitViewEnabled() ? _views[0] : null; + FlutterView? get implicitView { + if (_implicitView == null && _implicitViewEnabled()) { + _implicitView = FlutterView._(_kImplicitViewId, this); + } + return _implicitView; + } + FlutterView? _implicitView; @Native(symbol: 'PlatformConfigurationNativeApi::ImplicitViewEnabled') external static bool _implicitViewEnabled(); @@ -239,6 +262,31 @@ class PlatformDispatcher { _onMetricsChangedZone = Zone.current; } + FlutterView _createView(Object id) { + if (id == _kImplicitViewId) { + assert(_implicitViewEnabled()); + return implicitView!; + } + return FlutterView._(id as int, this); + } + + void _addView(Object id) { + assert(!_views.containsKey(id)); + _views[id as int] = _createView(id); + _viewConfigurations[id] = const _ViewConfiguration(); + } + + void _removeView(Object id) { + assert(!_views.containsKey(id)); + // TODO(dkwingsmt): Reset _implicitView? + _views.remove(id); + _viewConfigurations.remove(id); + } + + void _onSentViewConfigurations(List viewIds) { + viewIds.forEach(_addView); + } + // Called from the engine, via hooks.dart. // // Updates the available displays. @@ -278,9 +326,7 @@ class PlatformDispatcher { ) { final _ViewConfiguration previousConfiguration = _viewConfigurations[id] ?? const _ViewConfiguration(); - if (!_views.containsKey(id)) { - _views[id] = FlutterView._(id, this); - } + _views.putIfAbsent(id, () => _createView(id)); _viewConfigurations[id] = previousConfiguration.copyWith( view: _views[id], devicePixelRatio: devicePixelRatio, diff --git a/lib/ui/semantics/semantics_update_builder_unittests.cc b/lib/ui/semantics/semantics_update_builder_unittests.cc index 004d7f8f78296..197314fbd3160 100644 --- a/lib/ui/semantics/semantics_update_builder_unittests.cc +++ b/lib/ui/semantics/semantics_update_builder_unittests.cc @@ -74,7 +74,7 @@ TEST_F(SemanticsUpdateBuilderTest, CanHandleAttributedStrings) { AddNativeCallback("SemanticsUpdate", CREATE_NATIVE_ENTRY(nativeSemanticsUpdate)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 0b0e43d570334..acf0006470ab7 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -331,10 +331,12 @@ class FlutterView { /// scheduling of frames. /// * [RendererBinding], the Flutter framework class which manages layout and /// painting. - void render(Scene scene) => _render(scene as _NativeScene); + void render(Scene scene) { + _render(viewId as int, scene as _NativeScene); + } - @Native)>(symbol: 'PlatformConfigurationNativeApi::Render') - external static void _render(_NativeScene scene); + @Native)>(symbol: 'PlatformConfigurationNativeApi::Render') + external static void _render(int viewId, _NativeScene scene); /// Change the retained semantics data about this [FlutterView]. /// diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc index b1cd11fad30e7..6e13259ba33c0 100644 --- a/lib/ui/window/platform_configuration.cc +++ b/lib/ui/window/platform_configuration.cc @@ -22,7 +22,7 @@ namespace flutter { namespace { -constexpr int kImplicitViewId = 0; +constexpr int64_t kFlutterDefaultViewId = 0ll; Dart_Handle ToByteData(const fml::Mapping& buffer) { return tonic::DartByteData::Create(buffer.GetMapping(), buffer.GetSize()); @@ -34,7 +34,11 @@ PlatformConfigurationClient::~PlatformConfigurationClient() {} PlatformConfiguration::PlatformConfiguration( PlatformConfigurationClient* client) - : client_(client) {} + : client_(client) { + if (client_->ImplicitViewEnabled()) { + AddView(kFlutterDefaultViewId); + } +} PlatformConfiguration::~PlatformConfiguration() {} @@ -43,6 +47,10 @@ void PlatformConfiguration::DidCreateIsolate() { on_error_.Set(tonic::DartState::Current(), Dart_GetField(library, tonic::ToDart("_onError"))); + add_view_.Set(tonic::DartState::Current(), + Dart_GetField(library, tonic::ToDart("_addView"))); + remove_view_.Set(tonic::DartState::Current(), + Dart_GetField(library, tonic::ToDart("_removeView"))); update_displays_.Set( tonic::DartState::Current(), Dart_GetField(library, tonic::ToDart("_updateDisplays"))); @@ -76,12 +84,56 @@ void PlatformConfiguration::DidCreateIsolate() { report_timings_.Set(tonic::DartState::Current(), Dart_GetField(library, tonic::ToDart("_reportTimings"))); - // TODO(loicsharma): This should only be created if the embedder enables the - // implicit view. - // See: https://github.com/flutter/flutter/issues/120306 - windows_.emplace(kImplicitViewId, - std::make_unique( - kImplicitViewId, ViewportMetrics{1.0, 0.0, 0.0, -1, 0})); + library_.Set(tonic::DartState::Current(), + Dart_LookupLibrary(tonic::ToDart("dart:ui"))); + + SendViewConfigurations(); +} + +void PlatformConfiguration::SendViewConfigurations() { + std::shared_ptr dart_state = library_.dart_state().lock(); + FML_DCHECK(dart_state); + tonic::DartState::Scope scope(dart_state); + + // TODO(dkwingsmt): send all of ViewportMetrics + std::vector view_ids; + for (const auto& [view_id, window] : windows_) { + view_ids.push_back(view_id); + } + + tonic::CheckAndHandleError(tonic::DartInvokeField( + library_.value(), "_sendViewConfigurations", {tonic::ToDart(view_ids)})); +} + +void PlatformConfiguration::AddView(int64_t view_id) { + // TODO(dkwingsmt): How do I access the current dart state after + // DidCreateIsolate? + windows_.emplace( + view_id, std::make_unique(library_, view_id, + ViewportMetrics{1.0, 0.0, 0.0, -1, 0})); + std::shared_ptr dart_state = add_view_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + tonic::CheckAndHandleError( + tonic::DartInvoke(add_view_.Get(), { + tonic::ToDart(view_id), + })); +} + +void PlatformConfiguration::RemoveView(int64_t view_id) { + windows_.erase(view_id); + std::shared_ptr dart_state = + remove_view_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + tonic::CheckAndHandleError( + tonic::DartInvoke(remove_view_.Get(), { + tonic::ToDart(view_id), + })); } void PlatformConfiguration::UpdateDisplays( @@ -337,9 +389,10 @@ void PlatformConfiguration::CompletePlatformMessageResponse( response->Complete(std::make_unique(std::move(data))); } -void PlatformConfigurationNativeApi::Render(Scene* scene) { +void PlatformConfigurationNativeApi::Render(int64_t view_id, Scene* scene) { UIDartState::ThrowIfUIOperationsProhibited(); - UIDartState::Current()->platform_configuration()->client()->Render(scene); + UIDartState::Current()->platform_configuration()->client()->Render(view_id, + scene); } void PlatformConfigurationNativeApi::SetNeedsReportTimings(bool value) { diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index c03f38194bf50..083a62d1d5fff 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -79,7 +79,7 @@ class PlatformConfigurationClient { /// @brief Updates the client's rendering on the GPU with the newly /// provided Scene. /// - virtual void Render(Scene* scene) = 0; + virtual void Render(int64_t view_id, Scene* scene) = 0; //-------------------------------------------------------------------------- /// @brief Receives an updated semantics tree from the Framework. @@ -268,6 +268,10 @@ class PlatformConfiguration final { /// void DidCreateIsolate(); + void AddView(int64_t view_id); + + void RemoveView(int64_t view_id); + //---------------------------------------------------------------------------- /// @brief Update the specified display data in the framework. /// @@ -415,7 +419,14 @@ class PlatformConfiguration final { /// /// @return a pointer to the Window. /// - Window* get_window(int window_id) { return windows_[window_id].get(); } + Window* get_window(int window_id) { + auto found = windows_.find(window_id); + if (found != windows_.end()) { + return found->second.get(); + } else { + return nullptr; + } + } //---------------------------------------------------------------------------- /// @brief Responds to a previous platform message to the engine from the @@ -442,6 +453,8 @@ class PlatformConfiguration final { private: PlatformConfigurationClient* client_; tonic::DartPersistentValue on_error_; + tonic::DartPersistentValue add_view_; + tonic::DartPersistentValue remove_view_; tonic::DartPersistentValue update_displays_; tonic::DartPersistentValue update_locales_; tonic::DartPersistentValue update_user_settings_data_; @@ -455,12 +468,20 @@ class PlatformConfiguration final { tonic::DartPersistentValue draw_frame_; tonic::DartPersistentValue report_timings_; + tonic::DartPersistentValue library_; + + // All *actual* views that the app has. + // + // This means that, if implicit view is enabled but the implicit view is + // currently closed, `windows_` will not have an entry for ID 0. std::unordered_map> windows_; // ID starts at 1 because an ID of 0 indicates that no response is expected. int next_response_id_ = 1; std::unordered_map> pending_responses_; + + void SendViewConfigurations(); }; //---------------------------------------------------------------------------- @@ -495,7 +516,7 @@ class PlatformConfigurationNativeApi { static void ScheduleFrame(); - static void Render(Scene* scene); + static void Render(int64_t view_id, Scene* scene); static void UpdateSemantics(SemanticsUpdate* update); diff --git a/lib/ui/window/platform_configuration_unittests.cc b/lib/ui/window/platform_configuration_unittests.cc index e89a5cc7d381c..64648093b7d75 100644 --- a/lib/ui/window/platform_configuration_unittests.cc +++ b/lib/ui/window/platform_configuration_unittests.cc @@ -49,7 +49,7 @@ TEST_F(ShellTest, PlatformConfigurationInitialization) { AddNativeCallback("ValidateConfiguration", CREATE_NATIVE_ENTRY(nativeValidateConfiguration)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto run_configuration = RunConfiguration::InferFromSettings(settings); @@ -99,7 +99,7 @@ TEST_F(ShellTest, PlatformConfigurationWindowMetricsUpdate) { AddNativeCallback("ValidateConfiguration", CREATE_NATIVE_ENTRY(nativeValidateConfiguration)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto run_configuration = RunConfiguration::InferFromSettings(settings); @@ -137,7 +137,7 @@ TEST_F(ShellTest, PlatformConfigurationOnErrorHandlesError) { CreateNewThread() // io ); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto run_configuration = RunConfiguration::InferFromSettings(settings); @@ -187,7 +187,7 @@ TEST_F(ShellTest, PlatformConfigurationOnErrorDoesNotHandleError) { CreateNewThread() // io ); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto run_configuration = RunConfiguration::InferFromSettings(settings); @@ -238,7 +238,7 @@ TEST_F(ShellTest, PlatformConfigurationOnErrorThrows) { CreateNewThread() // io ); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto run_configuration = RunConfiguration::InferFromSettings(settings); @@ -286,7 +286,7 @@ TEST_F(ShellTest, PlatformConfigurationSetDartPerformanceMode) { CreateNewThread() // io ); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto run_configuration = RunConfiguration::InferFromSettings(settings); diff --git a/lib/ui/window/platform_message_response_dart_port_unittests.cc b/lib/ui/window/platform_message_response_dart_port_unittests.cc index 7dda83049d926..32422be053bfc 100644 --- a/lib/ui/window/platform_message_response_dart_port_unittests.cc +++ b/lib/ui/window/platform_message_response_dart_port_unittests.cc @@ -53,7 +53,7 @@ TEST_F(ShellTest, PlatformMessageResponseDartPort) { Settings settings = CreateSettingsForFixture(); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); diff --git a/lib/ui/window/platform_message_response_dart_unittests.cc b/lib/ui/window/platform_message_response_dart_unittests.cc index a9a29198bcf4d..d2f0863719c94 100644 --- a/lib/ui/window/platform_message_response_dart_unittests.cc +++ b/lib/ui/window/platform_message_response_dart_unittests.cc @@ -52,7 +52,7 @@ TEST_F(ShellTest, PlatformMessageResponseDart) { Settings settings = CreateSettingsForFixture(); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc index f3866f2ebc56a..45c8c2693190d 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -13,11 +13,12 @@ namespace flutter { -Window::Window(int64_t window_id, ViewportMetrics metrics) - : window_id_(window_id), viewport_metrics_(std::move(metrics)) { - library_.Set(tonic::DartState::Current(), - Dart_LookupLibrary(tonic::ToDart("dart:ui"))); -} +Window::Window(tonic::DartPersistentValue& library, + int64_t window_id, + ViewportMetrics metrics) + : library_(library), + window_id_(window_id), + viewport_metrics_(std::move(metrics)) {} Window::~Window() {} diff --git a/lib/ui/window/window.h b/lib/ui/window/window.h index 95153f6559b7b..67ef8198fe800 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -20,7 +20,9 @@ namespace flutter { class Window final { public: - Window(int64_t window_id, ViewportMetrics metrics); + Window(tonic::DartPersistentValue& library, + int64_t window_id, + ViewportMetrics metrics); ~Window(); @@ -31,7 +33,7 @@ class Window final { void UpdateWindowMetrics(const ViewportMetrics& metrics); private: - tonic::DartPersistentValue library_; + tonic::DartPersistentValue& library_; int64_t window_id_; ViewportMetrics viewport_metrics_; }; diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 5ffd02d099139..68d9d6cf2f45e 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -20,7 +20,7 @@ namespace flutter { -const uint64_t kFlutterDefaultViewId = 0llu; +constexpr uint64_t kFlutterDefaultViewId = 0ll; RuntimeController::RuntimeController(RuntimeDelegate& p_client, const TaskRunners& task_runners) @@ -115,7 +115,10 @@ std::unique_ptr RuntimeController::Clone() const { } bool RuntimeController::FlushRuntimeStateToIsolate() { - return SetViewportMetrics(platform_data_.viewport_metrics) && + // TODO(dkwingsmt): Needs a view ID here (or platform_data should probably + // have multiple view metrics). + return SetViewportMetrics(kFlutterDefaultViewId, + platform_data_.viewport_metrics) && SetLocales(platform_data_.locale_data) && SetSemanticsEnabled(platform_data_.semantics_enabled) && SetAccessibilityFeatures( @@ -125,13 +128,35 @@ bool RuntimeController::FlushRuntimeStateToIsolate() { SetDisplays(platform_data_.displays); } -bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { +bool RuntimeController::AddView(int64_t view_id) { + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->AddView(view_id); + return true; + } + + return false; +} + +bool RuntimeController::RemoveView(int64_t view_id) { + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->RemoveView(view_id); + return true; + } + + return false; +} + +bool RuntimeController::SetViewportMetrics(int64_t view_id, + const ViewportMetrics& metrics) { TRACE_EVENT0("flutter", "SetViewportMetrics"); platform_data_.viewport_metrics = metrics; if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { - platform_configuration->get_window(0)->UpdateWindowMetrics(metrics); - return true; + Window* window = platform_configuration->get_window(view_id); + if (window) { + window->UpdateWindowMetrics(metrics); + return true; + } } return false; @@ -318,16 +343,15 @@ void RuntimeController::ScheduleFrame() { } // |PlatformConfigurationClient| -void RuntimeController::Render(Scene* scene) { - // TODO(dkwingsmt): Currently only supports a single window. - int64_t view_id = kFlutterDefaultViewId; +void RuntimeController::Render(int64_t view_id, Scene* scene) { auto window = UIDartState::Current()->platform_configuration()->get_window(view_id); if (window == nullptr) { return; } const auto& viewport_metrics = window->viewport_metrics(); - client_.Render(scene->takeLayerTree(viewport_metrics.physical_width, + client_.Render(view_id, + scene->takeLayerTree(viewport_metrics.physical_width, viewport_metrics.physical_height), viewport_metrics.device_pixel_ratio); } diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index 1df085262f605..e7ea2500257e6 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -163,6 +163,10 @@ class RuntimeController : public PlatformConfigurationClient { /// std::unique_ptr Clone() const; + bool AddView(int64_t view_id); + + bool RemoveView(int64_t view_id); + //---------------------------------------------------------------------------- /// @brief Forward the specified viewport metrics to the running isolate. /// If the isolate is not running, these metrics will be saved and @@ -172,7 +176,7 @@ class RuntimeController : public PlatformConfigurationClient { /// /// @return If the window metrics were forwarded to the running isolate. /// - bool SetViewportMetrics(const ViewportMetrics& metrics); + bool SetViewportMetrics(int64_t view_id, const ViewportMetrics& metrics); //---------------------------------------------------------------------------- /// @brief Forward the specified display metrics to the running isolate. @@ -630,7 +634,7 @@ class RuntimeController : public PlatformConfigurationClient { void ScheduleFrame() override; // |PlatformConfigurationClient| - void Render(Scene* scene) override; + void Render(int64_t view_id, Scene* scene) override; // |PlatformConfigurationClient| void UpdateSemantics(SemanticsUpdate* update) override; diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h index 18e4dbfdfd31c..0b0e7e8ae299d 100644 --- a/runtime/runtime_delegate.h +++ b/runtime/runtime_delegate.h @@ -27,7 +27,8 @@ class RuntimeDelegate { virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0; - virtual void Render(std::unique_ptr layer_tree, + virtual void Render(int64_t view_id, + std::unique_ptr layer_tree, float device_pixel_ratio) = 0; virtual void UpdateSemantics(SemanticsNodeUpdates update, diff --git a/shell/common/animator.cc b/shell/common/animator.cc index bb4c131cdff68..eff861b9bedcf 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -128,7 +128,8 @@ void Animator::BeginFrame( } } -void Animator::Render(std::unique_ptr layer_tree, +void Animator::Render(int64_t view_id, + std::unique_ptr layer_tree, float device_pixel_ratio) { has_rendered_ = true; last_layer_tree_size_ = layer_tree->frame_size(); @@ -149,7 +150,7 @@ void Animator::Render(std::unique_ptr layer_tree, frame_timings_recorder_->GetVsyncTargetTime()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), std::move(frame_timings_recorder_), + view_id, std::move(layer_tree), std::move(frame_timings_recorder_), device_pixel_ratio); // Commit the pending continuation. PipelineProduceResult result = diff --git a/shell/common/animator.h b/shell/common/animator.h index 4e6295957bdcc..54de1e21b041a 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -54,7 +54,8 @@ class Animator final { void RequestFrame(bool regenerate_layer_tree = true); - void Render(std::unique_ptr layer_tree, + void Render(int64_t view_id, + std::unique_ptr layer_tree, float device_pixel_ratio); const std::weak_ptr GetVsyncWaiter() const; diff --git a/shell/common/animator_unittests.cc b/shell/common/animator_unittests.cc index cf20635b14203..130f344ca40de 100644 --- a/shell/common/animator_unittests.cc +++ b/shell/common/animator_unittests.cc @@ -23,6 +23,8 @@ namespace flutter { namespace testing { +constexpr int64_t kDefaultViewId = 0; + class FakeAnimatorDelegate : public Animator::Delegate { public: MOCK_METHOD2(OnAnimatorBeginFrame, @@ -83,7 +85,7 @@ TEST_F(ShellTest, VSyncTargetTime) { shell, shell.GetTaskRunners(), vsync_clock, create_vsync_waiter, ShellTestPlatformView::BackendType::kDefaultBackend, nullptr, shell.GetConcurrentWorkerTaskRunner(), - shell.GetIsGpuDisabledSyncSwitch()); + shell.GetIsGpuDisabledSyncSwitch(), false); }, [](Shell& shell) { return std::make_unique(shell); }); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); @@ -159,7 +161,7 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyIdleBeforeRender) { ASSERT_FALSE(delegate.notify_idle_called_); auto layer_tree = std::make_unique(LayerTree::Config(), SkISize::Make(600, 800)); - animator->Render(std::move(layer_tree), 1.0); + animator->Render(kDefaultViewId, std::move(layer_tree), 1.0); task_runners.GetPlatformTaskRunner()->PostTask(flush_vsync_task); }, // See kNotifyIdleTaskWaitTime in animator.cc. @@ -242,7 +244,7 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyDelegateIfPipelineIsNotEmpty) { PostTaskSync(task_runners.GetUITaskRunner(), [&] { auto layer_tree = std::make_unique(LayerTree::Config(), SkISize::Make(600, 800)); - animator->Render(std::move(layer_tree), 1.0); + animator->Render(kDefaultViewId, std::move(layer_tree), 1.0); }); } diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 2c0b22d1863f8..198ae96d206c9 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -292,8 +292,17 @@ tonic::DartErrorHandleType Engine::GetUIIsolateLastError() { return runtime_controller_->GetLastError(); } -void Engine::SetViewportMetrics(const ViewportMetrics& metrics) { - runtime_controller_->SetViewportMetrics(metrics); +void Engine::AddView(int64_t view_id) { + runtime_controller_->AddView(view_id); +} + +void Engine::RemoveView(int64_t view_id) { + runtime_controller_->RemoveView(view_id); +} + +void Engine::SetViewportMetrics(int64_t view_id, + const ViewportMetrics& metrics) { + runtime_controller_->SetViewportMetrics(view_id, metrics); ScheduleFrame(); } @@ -456,7 +465,8 @@ void Engine::ScheduleFrame(bool regenerate_layer_tree) { animator_->RequestFrame(regenerate_layer_tree); } -void Engine::Render(std::unique_ptr layer_tree, +void Engine::Render(int64_t view_id, + std::unique_ptr layer_tree, float device_pixel_ratio) { if (!layer_tree) { return; @@ -467,7 +477,7 @@ void Engine::Render(std::unique_ptr layer_tree, return; } - animator_->Render(std::move(layer_tree), device_pixel_ratio); + animator_->Render(view_id, std::move(layer_tree), device_pixel_ratio); } void Engine::UpdateSemantics(SemanticsNodeUpdates update, diff --git a/shell/common/engine.h b/shell/common/engine.h index 1890589729b04..5ae5931501cb8 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -676,6 +676,10 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { /// std::optional GetUIIsolateReturnCode(); + void AddView(int64_t view_id); + + void RemoveView(int64_t view_id); + //---------------------------------------------------------------------------- /// @brief Updates the viewport metrics for the currently running Flutter /// application. The viewport metrics detail the size of the @@ -686,7 +690,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { /// /// @param[in] metrics The metrics /// - void SetViewportMetrics(const ViewportMetrics& metrics); + void SetViewportMetrics(int64_t view_id, const ViewportMetrics& metrics); //---------------------------------------------------------------------------- /// @brief Updates the display metrics for the currently running Flutter @@ -906,7 +910,8 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { std::string DefaultRouteName() override; // |RuntimeDelegate| - void Render(std::unique_ptr layer_tree, + void Render(int64_t view_id, + std::unique_ptr layer_tree, float device_pixel_ratio) override; // |RuntimeDelegate| diff --git a/shell/common/engine_unittests.cc b/shell/common/engine_unittests.cc index 5011f266557c8..d551337fd4b17 100644 --- a/shell/common/engine_unittests.cc +++ b/shell/common/engine_unittests.cc @@ -21,6 +21,8 @@ namespace flutter { namespace { +constexpr int64_t kDefaultViewId = 0ll; + class MockDelegate : public Engine::Delegate { public: MOCK_METHOD2(OnEngineUpdateSemantics, @@ -51,7 +53,8 @@ class MockRuntimeDelegate : public RuntimeDelegate { MOCK_METHOD0(ImplicitViewEnabled, bool()); MOCK_METHOD0(DefaultRouteName, std::string()); MOCK_METHOD1(ScheduleFrame, void(bool)); - MOCK_METHOD2(Render, void(std::unique_ptr, float)); + MOCK_METHOD3(Render, + void(int64_t, std::unique_ptr, float)); MOCK_METHOD2(UpdateSemantics, void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates)); MOCK_METHOD1(HandlePlatformMessage, void(std::unique_ptr)); @@ -330,7 +333,8 @@ TEST_F(EngineTest, SpawnResetsViewportMetrics) { const double kViewHeight = 1024; old_viewport_metrics.physical_width = kViewWidth; old_viewport_metrics.physical_height = kViewHeight; - mock_runtime_controller->SetViewportMetrics(old_viewport_metrics); + mock_runtime_controller->SetViewportMetrics(kDefaultViewId, + old_viewport_metrics); auto engine = std::make_unique( /*delegate=*/delegate_, /*dispatcher_maker=*/dispatcher_maker_, diff --git a/shell/common/input_events_unittests.cc b/shell/common/input_events_unittests.cc index 3f117c006c65f..f84cddbfbe5d2 100644 --- a/shell/common/input_events_unittests.cc +++ b/shell/common/input_events_unittests.cc @@ -54,7 +54,10 @@ static void TestSimulatedInputEvents( bool restart_engine = false) { ///// Begin constructing shell /////////////////////////////////////////////// auto settings = fixture->CreateSettingsForFixture(); - std::unique_ptr shell = fixture->CreateShell(settings, true); + std::unique_ptr shell = fixture->CreateShell({ + .settings = settings, + .simulate_vsync = true, + }); auto configuration = RunConfiguration::InferFromSettings(settings); configuration.SetEntrypoint("onPointerDataPacketMain"); @@ -300,7 +303,10 @@ TEST_F(ShellTest, HandlesActualIphoneXsInputEvents) { TEST_F(ShellTest, CanCorrectlyPipePointerPacket) { // Sets up shell with test fixture. auto settings = CreateSettingsForFixture(); - std::unique_ptr shell = CreateShell(settings, true); + std::unique_ptr shell = CreateShell({ + .settings = settings, + .simulate_vsync = true, + }); auto configuration = RunConfiguration::InferFromSettings(settings); configuration.SetEntrypoint("onPointerDataPacketMain"); @@ -361,7 +367,10 @@ TEST_F(ShellTest, CanCorrectlyPipePointerPacket) { TEST_F(ShellTest, CanCorrectlySynthesizePointerPacket) { // Sets up shell with test fixture. auto settings = CreateSettingsForFixture(); - std::unique_ptr shell = CreateShell(settings, true); + std::unique_ptr shell = CreateShell({ + .settings = settings, + .simulate_vsync = true, + }); auto configuration = RunConfiguration::InferFromSettings(settings); configuration.SetEntrypoint("onPointerDataPacketMain"); diff --git a/shell/common/pipeline.h b/shell/common/pipeline.h index 00e67d1a4261f..aaea57a32ee54 100644 --- a/shell/common/pipeline.h +++ b/shell/common/pipeline.h @@ -252,12 +252,15 @@ class Pipeline { }; struct LayerTreeItem { - LayerTreeItem(std::unique_ptr layer_tree, + LayerTreeItem(int64_t view_id, + std::unique_ptr layer_tree, std::unique_ptr frame_timings_recorder, float device_pixel_ratio) - : layer_tree(std::move(layer_tree)), + : view_id(view_id), + layer_tree(std::move(layer_tree)), frame_timings_recorder(std::move(frame_timings_recorder)), device_pixel_ratio(device_pixel_ratio) {} + int64_t view_id; std::unique_ptr layer_tree; std::unique_ptr frame_timings_recorder; float device_pixel_ratio; diff --git a/shell/common/platform_view.cc b/shell/common/platform_view.cc index 7cb0b091d5bcd..e5d52d82ebe30 100644 --- a/shell/common/platform_view.cc +++ b/shell/common/platform_view.cc @@ -51,35 +51,51 @@ void PlatformView::SetAccessibilityFeatures(int32_t flags) { delegate_.OnPlatformViewSetAccessibilityFeatures(flags); } -void PlatformView::SetViewportMetrics(const ViewportMetrics& metrics) { - delegate_.OnPlatformViewSetViewportMetrics(metrics); +void PlatformView::SetViewportMetrics(int64_t view_id, + const ViewportMetrics& metrics) { + delegate_.OnPlatformViewSetViewportMetrics(view_id, metrics); } void PlatformView::NotifyCreated() { - std::unique_ptr surface; + delegate_.OnPlatformViewCreated(); +} + +void PlatformView::NotifyDestroyed() { + delegate_.OnPlatformViewDestroyed(); +} + +std::unique_ptr PlatformView::CreateStudio() { + std::unique_ptr studio; // Threading: We want to use the platform view on the non-platform thread. // Using the weak pointer is illegal. But, we are going to introduce a latch - // so that the platform view is not collected till the surface is obtained. + // so that the platform view is not collected till the studio and the surface + // are obtained. auto* platform_view = this; fml::ManualResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask( - task_runners_.GetRasterTaskRunner(), [platform_view, &surface, &latch]() { - surface = platform_view->CreateRenderingSurface(); - if (surface && !surface->IsValid()) { - surface.reset(); + task_runners_.GetRasterTaskRunner(), [platform_view, &studio, &latch]() { + studio = platform_view->CreateRenderingStudio(); + if (!studio || !studio->IsValid()) { + studio.reset(); } latch.Signal(); }); latch.Wait(); - if (!surface) { - FML_LOG(ERROR) << "Failed to create platform view rendering surface"; - return; + if (!studio) { + FML_LOG(ERROR) << "Failed to create platform view rendering studio"; + return nullptr; } - delegate_.OnPlatformViewCreated(std::move(surface)); + return studio; } -void PlatformView::NotifyDestroyed() { - delegate_.OnPlatformViewDestroyed(); +std::unique_ptr PlatformView::CreateSurface(int64_t view_id) { + FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread()); + auto surface = CreateRenderingSurface(view_id); + if (!surface) { + FML_LOG(ERROR) << "Failed to create platform view rendering surface"; + return nullptr; + } + return surface; } void PlatformView::ScheduleFrame() { @@ -134,11 +150,19 @@ void PlatformView::MarkTextureFrameAvailable(int64_t texture_id) { delegate_.OnPlatformViewMarkTextureFrameAvailable(texture_id); } -std::unique_ptr PlatformView::CreateRenderingSurface() { +std::unique_ptr PlatformView::CreateRenderingStudio() { + // We have a default implementation because tests create a platform view but + // never a rendering studio. + FML_DCHECK(false) << "This platform does not provide a rendering studio but " + "it was notified of rendering studio creation."; + return nullptr; +} + +std::unique_ptr PlatformView::CreateRenderingSurface(int64_t view_id) { // We have a default implementation because tests create a platform view but // never a rendering surface. FML_DCHECK(false) << "This platform does not provide a rendering surface but " - "it was notified of surface rendering surface creation."; + "it was notified of rendering surface creation."; return nullptr; } @@ -149,6 +173,10 @@ PlatformView::CreateExternalViewEmbedder() { return nullptr; } +bool PlatformView::SupportsDynamicThreadMerging() { + return false; +} + void PlatformView::SetNextFrameCallback(const fml::closure& closure) { if (!closure) { return; diff --git a/shell/common/platform_view.h b/shell/common/platform_view.h index 9ec848e34568d..5c85107b547e4 100644 --- a/shell/common/platform_view.h +++ b/shell/common/platform_view.h @@ -11,6 +11,7 @@ #include "flutter/common/graphics/texture.h" #include "flutter/common/task_runners.h" #include "flutter/flow/embedded_views.h" +#include "flutter/flow/studio.h" #include "flutter/flow/surface.h" #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" @@ -60,15 +61,10 @@ class PlatformView { public: using KeyDataResponse = std::function; //-------------------------------------------------------------------------- - /// @brief Notifies the delegate that the platform view was created - /// with the given render surface. This surface is platform - /// (iOS, Android) and client-rendering API (OpenGL, Software, - /// Metal, Vulkan) specific. This is usually a sign to the - /// rasterizer to set up and begin rendering to that surface. + /// @brief Notifies the delegate that the platform view was created. + /// This is usually a sign to the rasterizer to set up. /// - /// @param[in] surface The surface - /// - virtual void OnPlatformViewCreated(std::unique_ptr surface) = 0; + virtual void OnPlatformViewCreated() = 0; //-------------------------------------------------------------------------- /// @brief Notifies the delegate that the platform view was destroyed. @@ -112,6 +108,7 @@ class PlatformView { /// @param[in] metrics The updated viewport metrics. /// virtual void OnPlatformViewSetViewportMetrics( + int64_t view_id, const ViewportMetrics& metrics) = 0; //-------------------------------------------------------------------------- @@ -474,7 +471,7 @@ class PlatformView { /// /// @param[in] metrics The updated viewport metrics. /// - void SetViewportMetrics(const ViewportMetrics& metrics); + void SetViewportMetrics(int64_t view_id, const ViewportMetrics& metrics); //---------------------------------------------------------------------------- /// @brief Used by embedders to notify the shell that a platform view @@ -498,6 +495,9 @@ class PlatformView { /// virtual void NotifyDestroyed(); + std::unique_ptr CreateStudio(); + std::unique_ptr CreateSurface(int64_t view_id); + //---------------------------------------------------------------------------- /// @brief Used by embedders to schedule a frame. In response to this /// call, the framework may need to start generating a new frame. @@ -683,8 +683,19 @@ class PlatformView { ComputePlatformResolvedLocales( const std::vector& supported_locale_data); + /// @brief Returns the external view embedder for the implicit view. + /// Those of non-implicit views should be set by + /// Shell::AddRenderSurface. virtual std::shared_ptr CreateExternalViewEmbedder(); + /// Whether the embedder should support dynamic thread merging. + /// + /// Returning `true` results a |RasterThreadMerger| instance to be created by + /// |Rasterizer|. + /// * See also |BegineFrame| and |EndFrame| of |ExternalViewEmbedder| for + /// getting the |RasterThreadMerger| instance. + virtual bool SupportsDynamicThreadMerging(); + //-------------------------------------------------------------------------- /// @brief Invoked when the dart VM requests that a deferred library /// be loaded. Notifies the engine that the deferred library @@ -832,8 +843,10 @@ class PlatformView { const Settings& GetSettings() const; protected: - // This is the only method called on the raster task runner. - virtual std::unique_ptr CreateRenderingSurface(); + virtual std::unique_ptr CreateRenderingStudio(); + + // This is called on the raster task runner. + virtual std::unique_ptr CreateRenderingSurface(int64_t view_id); PlatformView::Delegate& delegate_; const TaskRunners task_runners_; diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 2136c60cdd44e..10355cbb8ebc5 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -44,6 +44,7 @@ Rasterizer::Rasterizer(Delegate& delegate, user_override_resource_cache_bytes_(false), snapshot_controller_( SnapshotController::Make(*this, delegate.GetSettings())), + requires_view_embedder_(false), weak_factory_(this) { FML_DCHECK(compositor_context_); } @@ -64,22 +65,21 @@ void Rasterizer::SetImpellerContext( impeller_context_ = std::move(impeller_context); } -void Rasterizer::Setup(std::unique_ptr surface) { - surface_ = std::move(surface); +void Rasterizer::Setup(std::unique_ptr studio, + bool support_thread_merging) { + studio_ = std::move(studio); if (max_cache_bytes_.has_value()) { SetResourceCacheMaxBytes(max_cache_bytes_.value(), user_override_resource_cache_bytes_); } - auto context_switch = surface_->MakeRenderContextCurrent(); + auto context_switch = studio_->MakeRenderContextCurrent(); if (context_switch->GetResult()) { compositor_context_->OnGrContextCreated(); } - if (external_view_embedder_ && - external_view_embedder_->SupportsDynamicThreadMerging() && - !raster_thread_merger_) { + if (support_thread_merging && !raster_thread_merger_) { const auto platform_id = delegate_.GetTaskRunners().GetPlatformTaskRunner()->GetTaskQueueId(); const auto gpu_id = @@ -90,32 +90,32 @@ void Rasterizer::Setup(std::unique_ptr surface) { if (raster_thread_merger_) { raster_thread_merger_->SetMergeUnmergeCallback([=]() { // Clear the GL context after the thread configuration has changed. - if (surface_) { - surface_->ClearRenderContext(); + if (studio_) { + studio_->ClearRenderContext(); } }); } } void Rasterizer::TeardownExternalViewEmbedder() { - if (external_view_embedder_) { - external_view_embedder_->Teardown(); + for (auto& surface_record : surfaces_) { + surface_record.second.view_embedder->Teardown(); + surface_record.second.view_embedder = nullptr; } } void Rasterizer::Teardown() { - if (surface_) { - auto context_switch = surface_->MakeRenderContextCurrent(); + if (studio_) { + auto context_switch = studio_->MakeRenderContextCurrent(); if (context_switch->GetResult()) { compositor_context_->OnGrContextDestroyed(); - if (auto* context = surface_->GetContext()) { + if (auto* context = studio_->GetContext()) { context->purgeUnlockedResources(/*scratchResourcesOnly=*/false); } } - surface_.reset(); + studio_.reset(); } - - last_layer_tree_.reset(); + surfaces_.clear(); if (raster_thread_merger_.get() != nullptr && raster_thread_merger_.get()->IsMerged()) { @@ -138,51 +138,109 @@ void Rasterizer::DisableThreadMergerIfNeeded() { } void Rasterizer::NotifyLowMemoryWarning() const { - if (!surface_) { + if (!studio_) { FML_DLOG(INFO) << "Rasterizer::NotifyLowMemoryWarning called with no surface."; return; } - auto context = surface_->GetContext(); + auto context = studio_->GetContext(); if (!context) { FML_DLOG(INFO) << "Rasterizer::NotifyLowMemoryWarning called with no GrContext."; return; } - auto context_switch = surface_->MakeRenderContextCurrent(); + auto context_switch = studio_->MakeRenderContextCurrent(); if (!context_switch->GetResult()) { return; } context->performDeferredCleanup(std::chrono::milliseconds(0)); } +void Rasterizer::AddSurface( + int64_t view_id, + std::unique_ptr surface, + std::shared_ptr view_embedder) { + // Only allows having no view embedders if there is one surface and there has + // never been an view embedder. + if (!requires_view_embedder_) { + if (view_embedder || !surfaces_.empty()) { + requires_view_embedder_ = true; + } + } + if (requires_view_embedder_) { + FML_DCHECK(view_embedder); + } + bool insertion_happened = + surfaces_ + .try_emplace(/* map key=*/view_id, /*constructor args:*/ view_id, + view_embedder, std::move(surface)) + .second; + if (!insertion_happened) { + FML_DLOG(INFO) << "Rasterizer::AddSurface called with an existing view ID " + << view_id << "."; + } +} + +void Rasterizer::RemoveSurface(int64_t view_id) { + surfaces_.erase(view_id); +} + std::shared_ptr Rasterizer::GetTextureRegistry() { return compositor_context_->texture_registry(); } GrDirectContext* Rasterizer::GetGrContext() { - return surface_ ? surface_->GetContext() : nullptr; + return studio_ ? studio_->GetContext() : nullptr; } -flutter::LayerTree* Rasterizer::GetLastLayerTree() { - return last_layer_tree_.get(); +bool Rasterizer::HasLastLayerTree() const { + // TODO(dkwingsmt): This method is only available in unittests now + for (auto& record_pair : surfaces_) { + auto& layer_tree = record_pair.second.last_tree; + if (layer_tree) { + return true; + } + } + return false; } -void Rasterizer::DrawLastLayerTree( - std::unique_ptr frame_timings_recorder) { - if (!last_layer_tree_ || !surface_) { - return; +int Rasterizer::DrawLastLayerTree( + std::unique_ptr frame_timings_recorder, + bool enable_leaf_layer_tracing) { + if (!studio_) { + return 0; + } + int success_count = 0; + bool should_resubmit_frame = false; + for (auto& [view_id, surface_record] : surfaces_) { + Surface* surface = surface_record.surface.get(); + auto view_embedder = surface_record.view_embedder; + flutter::LayerTree* layer_tree = surface_record.last_tree.get(); + float device_pixel_ratio = surface_record.last_pixel_ratio; + if (!surface || !layer_tree) { + continue; + } + if (enable_leaf_layer_tracing) { + layer_tree->enable_leaf_layer_tracing(true); + } + RasterStatus raster_status = + DrawToSurface(*frame_timings_recorder, layer_tree, device_pixel_ratio, + &surface_record); + if (enable_leaf_layer_tracing) { + layer_tree->enable_leaf_layer_tracing(false); + } + should_resubmit_frame = + should_resubmit_frame || ShouldResubmitFrame(raster_status); + success_count += 1; + + // EndFrame should perform cleanups for the external_view_embedder. + if (view_embedder && view_embedder->GetUsedThisFrame()) { + view_embedder->SetUsedThisFrame(false); + view_embedder->EndFrame(should_resubmit_frame, raster_thread_merger_); + } } - RasterStatus raster_status = DrawToSurface( - *frame_timings_recorder, *last_layer_tree_, last_device_pixel_ratio_); - // EndFrame should perform cleanups for the external_view_embedder. - if (external_view_embedder_ && external_view_embedder_->GetUsedThisFrame()) { - bool should_resubmit_frame = ShouldResubmitFrame(raster_status); - external_view_embedder_->SetUsedThisFrame(false); - external_view_embedder_->EndFrame(should_resubmit_frame, - raster_thread_merger_); - } + return success_count; } RasterStatus Rasterizer::Draw( @@ -198,18 +256,21 @@ RasterStatus Rasterizer::Draw( .GetRasterTaskRunner() ->RunsTasksOnCurrentThread()); - RasterStatus raster_status = RasterStatus::kFailed; + DoDrawResult draw_result; LayerTreePipeline::Consumer consumer = - [&](std::unique_ptr item) { + [this, &draw_result, + &discard_callback](std::unique_ptr item) { std::unique_ptr layer_tree = std::move(item->layer_tree); std::unique_ptr frame_timings_recorder = std::move(item->frame_timings_recorder); float device_pixel_ratio = item->device_pixel_ratio; - if (discard_callback(*layer_tree.get())) { - raster_status = RasterStatus::kDiscarded; + int64_t view_id = item->view_id; + draw_result.view_id = view_id; + if (discard_callback(view_id, *layer_tree.get())) { + draw_result.raster_status = RasterStatus::kDiscarded; } else { - raster_status = DoDraw(std::move(frame_timings_recorder), - std::move(layer_tree), device_pixel_ratio); + draw_result = DoDraw(view_id, std::move(frame_timings_recorder), + std::move(layer_tree), device_pixel_ratio); } }; @@ -220,26 +281,25 @@ RasterStatus Rasterizer::Draw( // if the raster status is to resubmit the frame, we push the frame to the // front of the queue and also change the consume status to more available. - bool should_resubmit_frame = ShouldResubmitFrame(raster_status); + bool should_resubmit_frame = ShouldResubmitFrame(draw_result.raster_status); if (should_resubmit_frame) { - auto resubmitted_layer_tree_item = std::make_unique( - std::move(resubmitted_layer_tree_), std::move(resubmitted_recorder_), - resubmitted_pixel_ratio_); auto front_continuation = pipeline->ProduceIfEmpty(); - PipelineProduceResult result = - front_continuation.Complete(std::move(resubmitted_layer_tree_item)); - if (result.success) { + PipelineProduceResult pipeline_result = front_continuation.Complete( + std::move(draw_result.resubmitted_layer_tree_item)); + if (pipeline_result.success) { consume_result = PipelineConsumeResult::MoreAvailable; } - } else if (raster_status == RasterStatus::kEnqueuePipeline) { + } else if (draw_result.raster_status == RasterStatus::kEnqueuePipeline) { consume_result = PipelineConsumeResult::MoreAvailable; } // EndFrame should perform cleanups for the external_view_embedder. - if (external_view_embedder_ && external_view_embedder_->GetUsedThisFrame()) { - external_view_embedder_->SetUsedThisFrame(false); - external_view_embedder_->EndFrame(should_resubmit_frame, - raster_thread_merger_); + auto surface_record = surfaces_.find(draw_result.view_id); + FML_DCHECK(surface_record != surfaces_.end()); + auto view_embedder = surface_record->second.view_embedder; + if (view_embedder && view_embedder->GetUsedThisFrame()) { + view_embedder->SetUsedThisFrame(false); + view_embedder->EndFrame(should_resubmit_frame, raster_thread_merger_); } // Consume as many pipeline items as possible. But yield the event loop @@ -260,7 +320,7 @@ RasterStatus Rasterizer::Draw( break; } - return raster_status; + return draw_result.raster_status; } bool Rasterizer::ShouldResubmitFrame(const RasterStatus& raster_status) { @@ -313,9 +373,9 @@ std::unique_ptr Rasterizer::MakeSkiaGpuImage( result = MakeBitmapImage(display_list, image_info); }) .SetIfFalse([&result, &image_info, &display_list, - surface = surface_.get(), + studio = studio_.get(), gpu_image_behavior = gpu_image_behavior_] { - if (!surface || + if (!studio || gpu_image_behavior == MakeGpuImageBehavior::kBitmap) { // TODO(dnfield): This isn't safe if display_list contains any GPU // resources like an SkImage_gpu. @@ -323,13 +383,13 @@ std::unique_ptr Rasterizer::MakeSkiaGpuImage( return; } - auto context_switch = surface->MakeRenderContextCurrent(); + auto context_switch = studio->MakeRenderContextCurrent(); if (!context_switch->GetResult()) { result = MakeBitmapImage(display_list, image_info); return; } - auto* context = surface->GetContext(); + auto* context = studio->GetContext(); if (!context) { result = MakeBitmapImage(display_list, image_info); return; @@ -381,7 +441,8 @@ fml::Milliseconds Rasterizer::GetFrameBudget() const { return delegate_.GetFrameBudget(); }; -RasterStatus Rasterizer::DoDraw( +Rasterizer::DoDrawResult Rasterizer::DoDraw( + int64_t view_id, std::unique_ptr frame_timings_recorder, std::unique_ptr layer_tree, float device_pixel_ratio) { @@ -390,33 +451,42 @@ RasterStatus Rasterizer::DoDraw( FML_DCHECK(delegate_.GetTaskRunners() .GetRasterTaskRunner() ->RunsTasksOnCurrentThread()); + SurfaceRecord* surface_record = GetSurface(view_id); - if (!layer_tree || !surface_) { - return RasterStatus::kFailed; + if (!layer_tree || !surface_record) { + return DoDrawResult{ + .raster_status = RasterStatus::kFailed, + }; } PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess(); persistent_cache->ResetStoredNewShaders(); RasterStatus raster_status = - DrawToSurface(*frame_timings_recorder, *layer_tree, device_pixel_ratio); + DrawToSurface(*frame_timings_recorder, layer_tree.get(), + device_pixel_ratio, surface_record); if (raster_status == RasterStatus::kSuccess) { - last_layer_tree_ = std::move(layer_tree); - last_device_pixel_ratio_ = device_pixel_ratio; + surface_record->last_tree = std::move(layer_tree); + surface_record->last_pixel_ratio = device_pixel_ratio; } else if (ShouldResubmitFrame(raster_status)) { - resubmitted_pixel_ratio_ = device_pixel_ratio; - resubmitted_layer_tree_ = std::move(layer_tree); - resubmitted_recorder_ = frame_timings_recorder->CloneUntil( - FrameTimingsRecorder::State::kBuildEnd); - return raster_status; + return DoDrawResult{ + .raster_status = raster_status, + .resubmitted_layer_tree_item = std::make_unique( + view_id, std::move(layer_tree), + frame_timings_recorder->CloneUntil( + FrameTimingsRecorder::State::kBuildEnd), + device_pixel_ratio), + }; } else if (raster_status == RasterStatus::kDiscarded) { - return raster_status; + return DoDrawResult{ + .raster_status = raster_status, + }; } if (persistent_cache->IsDumpingSkp() && persistent_cache->StoredNewShaders()) { - auto screenshot = - ScreenshotLastLayerTree(ScreenshotType::SkiaPicture, false); + auto screenshot = ScreenshotLayerTree(ScreenshotType::SkiaPicture, false, + *surface_record); persistent_cache->DumpSkp(*screenshot.data); } @@ -478,31 +548,37 @@ RasterStatus Rasterizer::DoDraw( if (raster_thread_merger_) { if (raster_thread_merger_->DecrementLease() == fml::RasterThreadStatus::kUnmergedNow) { - return RasterStatus::kEnqueuePipeline; + return DoDrawResult{ + .raster_status = RasterStatus::kEnqueuePipeline, + }; } } - return raster_status; + return DoDrawResult{ + .raster_status = raster_status, + }; } RasterStatus Rasterizer::DrawToSurface( FrameTimingsRecorder& frame_timings_recorder, - flutter::LayerTree& layer_tree, - float device_pixel_ratio) { + flutter::LayerTree* layer_tree, + float device_pixel_ratio, + SurfaceRecord* surface_record) { TRACE_EVENT0("flutter", "Rasterizer::DrawToSurface"); - FML_DCHECK(surface_); + FML_DCHECK(surface_record); RasterStatus raster_status; - if (surface_->AllowsDrawingWhenGpuDisabled()) { + if (studio_->AllowsDrawingWhenGpuDisabled()) { raster_status = DrawToSurfaceUnsafe(frame_timings_recorder, layer_tree, - device_pixel_ratio); + device_pixel_ratio, surface_record); } else { delegate_.GetIsGpuDisabledSyncSwitch()->Execute( fml::SyncSwitch::Handlers() .SetIfTrue([&] { raster_status = RasterStatus::kDiscarded; }) .SetIfFalse([&] { - raster_status = DrawToSurfaceUnsafe( - frame_timings_recorder, layer_tree, device_pixel_ratio); + raster_status = + DrawToSurfaceUnsafe(frame_timings_recorder, layer_tree, + device_pixel_ratio, surface_record); })); } @@ -514,21 +590,23 @@ RasterStatus Rasterizer::DrawToSurface( /// \see Rasterizer::DrawToSurface RasterStatus Rasterizer::DrawToSurfaceUnsafe( FrameTimingsRecorder& frame_timings_recorder, - flutter::LayerTree& layer_tree, - float device_pixel_ratio) { - FML_DCHECK(surface_); + flutter::LayerTree* layer_tree, + float device_pixel_ratio, + SurfaceRecord* surface_record) { + Surface* surface = surface_record->surface.get(); + auto view_embedder = surface_record->view_embedder; + FML_DCHECK(surface); compositor_context_->ui_time().SetLapTime( frame_timings_recorder.GetBuildDuration()); DlCanvas* embedder_root_canvas = nullptr; - if (external_view_embedder_) { - FML_DCHECK(!external_view_embedder_->GetUsedThisFrame()); - external_view_embedder_->SetUsedThisFrame(true); - external_view_embedder_->BeginFrame( - layer_tree.frame_size(), surface_->GetContext(), device_pixel_ratio, - raster_thread_merger_); - embedder_root_canvas = external_view_embedder_->GetRootCanvas(); + if (view_embedder) { + FML_DCHECK(!view_embedder->GetUsedThisFrame()); + view_embedder->SetUsedThisFrame(true); + view_embedder->BeginFrame(layer_tree->frame_size(), studio_->GetContext(), + device_pixel_ratio, raster_thread_merger_); + embedder_root_canvas = view_embedder->GetRootCanvas(); } frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now()); @@ -537,7 +615,7 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe( // // Deleting a surface also clears the GL context. Therefore, acquire the // frame after calling `BeginFrame` as this operation resets the GL context. - auto frame = surface_->AcquireFrame(layer_tree.frame_size()); + auto frame = surface->AcquireFrame(layer_tree->frame_size()); if (frame == nullptr) { frame_timings_recorder.RecordRasterEnd( &compositor_context_->raster_cache()); @@ -548,22 +626,22 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe( // root surface transformation is set by the embedder instead of // having to apply it here. SkMatrix root_surface_transformation = - embedder_root_canvas ? SkMatrix{} : surface_->GetRootTransformation(); + embedder_root_canvas ? SkMatrix{} : surface->GetRootTransformation(); auto root_surface_canvas = embedder_root_canvas ? embedder_root_canvas : frame->Canvas(); auto compositor_frame = compositor_context_->AcquireFrame( - surface_->GetContext(), // skia GrContext - root_surface_canvas, // root surface canvas - external_view_embedder_.get(), // external view embedder - root_surface_transformation, // root surface transformation - true, // instrumentation enabled + studio_->GetContext(), // skia GrContext + root_surface_canvas, // root surface canvas + view_embedder.get(), // external view embedder + root_surface_transformation, // root surface transformation + true, // instrumentation enabled frame->framebuffer_info() .supports_readback, // surface supports pixel reads raster_thread_merger_, // thread merger frame->GetDisplayListBuilder().get(), // display list builder - surface_->GetAiksContext().get() // aiks context + studio_->GetAiksContext().get() // aiks context ); if (compositor_frame) { compositor_context_->raster_cache().BeginFrame(); @@ -572,19 +650,19 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe( // when leaf layer tracing is enabled we wish to repaint the whole frame // for accurate performance metrics. if (frame->framebuffer_info().supports_partial_repaint && - !layer_tree.is_leaf_layer_tracing_enabled()) { - // Disable partial repaint if external_view_embedder_ SubmitFrame is + !layer_tree->is_leaf_layer_tracing_enabled()) { + // Disable partial repaint if view_embedder SubmitFrame is // involved - ExternalViewEmbedder unconditionally clears the entire // surface and also partial repaint with platform view present is // something that still need to be figured out. bool force_full_repaint = - external_view_embedder_ && + view_embedder && (!raster_thread_merger_ || raster_thread_merger_->IsMerged()); damage = std::make_unique(); auto existing_damage = frame->framebuffer_info().existing_damage; if (existing_damage.has_value() && !force_full_repaint) { - damage->SetPreviousLayerTree(last_layer_tree_.get()); + damage->SetPreviousLayerTree(surface_record->last_tree.get()); damage->AddAdditionalDamage(existing_damage.value()); damage->SetClipAlignment( frame->framebuffer_info().horizontal_clip_alignment, @@ -593,13 +671,13 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe( } bool ignore_raster_cache = true; - if (surface_->EnableRasterCache() && - !layer_tree.is_leaf_layer_tracing_enabled()) { + if (studio_->EnableRasterCache() && + !layer_tree->is_leaf_layer_tracing_enabled()) { ignore_raster_cache = false; } RasterStatus raster_status = - compositor_frame->Raster(layer_tree, // layer tree + compositor_frame->Raster(*layer_tree, // layer tree ignore_raster_cache, // ignore raster cache damage.get() // frame damage ); @@ -624,11 +702,10 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe( frame->set_submit_info(submit_info); - if (external_view_embedder_ && + if (view_embedder && (!raster_thread_merger_ || raster_thread_merger_->IsMerged())) { FML_DCHECK(!frame->IsSubmitted()); - external_view_embedder_->SubmitFrame(surface_->GetContext(), - std::move(frame)); + view_embedder->SubmitFrame(studio_->GetContext(), std::move(frame)); } else { frame->Submit(); } @@ -643,8 +720,8 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe( &compositor_context_->raster_cache()); FireNextFrameCallbackIfPresent(); - if (surface_->GetContext()) { - surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration); + if (studio_->GetContext()) { + studio_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration); } return raster_status; @@ -711,7 +788,7 @@ sk_sp Rasterizer::ScreenshotLayerTreeAsImage( // render context is GL. frame->Raster() pops the gl context in platforms // that gl context switching are used. (For example, older iOS that uses GL) // We reset the GL context using the context switch. - auto context_switch = surface_->MakeRenderContextCurrent(); + auto context_switch = studio_->MakeRenderContextCurrent(); if (!context_switch->GetResult()) { FML_LOG(ERROR) << "Screenshot: unable to make image screenshot"; return nullptr; @@ -738,17 +815,27 @@ sk_sp Rasterizer::ScreenshotLayerTreeAsImage( Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree( Rasterizer::ScreenshotType type, bool base64_encode) { - auto* layer_tree = GetLastLayerTree(); - if (layer_tree == nullptr) { + // TODO(dkwingsmt): Probably screenshot all layer trees and put them together + // instead of just the first one. + SurfaceRecord* surface_record = GetFirstSurface(); + if (surface_record == nullptr || surface_record->last_tree == nullptr) { FML_LOG(ERROR) << "Last layer tree was null when screenshotting."; return {}; } + return ScreenshotLayerTree(type, base64_encode, *surface_record); +} + +Rasterizer::Screenshot Rasterizer::ScreenshotLayerTree( + ScreenshotType type, + bool base64_encode, + SurfaceRecord& surface_record) { + auto& surface = surface_record.surface; + auto* layer_tree = surface_record.last_tree.get(); sk_sp data = nullptr; std::string format; - GrDirectContext* surface_context = - surface_ ? surface_->GetContext() : nullptr; + GrDirectContext* surface_context = studio_ ? studio_->GetContext() : nullptr; switch (type) { case ScreenshotType::SkiaPicture: @@ -766,7 +853,7 @@ Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree( surface_context, true); break; case ScreenshotType::SurfaceData: { - Surface::SurfaceData surface_data = surface_->GetSurfaceData(); + Surface::SurfaceData surface_data = surface->GetSurfaceData(); format = surface_data.pixel_format; data = surface_data.data; break; @@ -792,11 +879,6 @@ void Rasterizer::SetNextFrameCallback(const fml::closure& callback) { next_frame_callback_ = callback; } -void Rasterizer::SetExternalViewEmbedder( - const std::shared_ptr& view_embedder) { - external_view_embedder_ = view_embedder; -} - void Rasterizer::SetSnapshotSurfaceProducer( std::unique_ptr producer) { snapshot_surface_producer_ = std::move(producer); @@ -826,13 +908,13 @@ void Rasterizer::SetResourceCacheMaxBytes(size_t max_bytes, bool from_user) { } max_cache_bytes_ = max_bytes; - if (!surface_) { + if (!studio_) { return; } - GrDirectContext* context = surface_->GetContext(); + GrDirectContext* context = studio_->GetContext(); if (context) { - auto context_switch = surface_->MakeRenderContextCurrent(); + auto context_switch = studio_->MakeRenderContextCurrent(); if (!context_switch->GetResult()) { return; } @@ -842,10 +924,10 @@ void Rasterizer::SetResourceCacheMaxBytes(size_t max_bytes, bool from_user) { } std::optional Rasterizer::GetResourceCacheMaxBytes() const { - if (!surface_) { + if (!studio_) { return std::nullopt; } - GrDirectContext* context = surface_->GetContext(); + GrDirectContext* context = studio_->GetContext(); if (context) { return context->getResourceCacheLimit(); } diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index b17242342c084..20a7db54ee0ac 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -7,6 +7,7 @@ #include #include +#include #include "flutter/common/settings.h" #include "flutter/common/task_runners.h" @@ -15,6 +16,7 @@ #include "flutter/flow/embedded_views.h" #include "flutter/flow/frame_timings.h" #include "flutter/flow/layers/layer_tree.h" +#include "flutter/flow/studio.h" #include "flutter/flow/surface.h" #include "flutter/fml/closure.h" #include "flutter/fml/memory/weak_ptr.h" @@ -155,21 +157,21 @@ class Rasterizer final : public SnapshotDelegate, void SetImpellerContext(std::weak_ptr impeller_context); //---------------------------------------------------------------------------- - /// @brief Rasterizers may be created well before an on-screen surface is + /// @brief Rasterizers may be created well before an on-screen studio is /// available for rendering. Shells usually create a rasterizer in - /// their constructors. Once an on-screen surface is available + /// their constructors. Once an on-screen studio is available /// however, one may be provided to the rasterizer using this - /// call. No rendering may occur before this call. The surface is + /// call. No rendering may occur before this call. The studio is /// held till the balancing call to `Rasterizer::Teardown` is - /// made. Calling a setup before tearing down the previous surface + /// made. Calling a setup before tearing down the studio /// (if this is not the first time the surface has been set up) is /// user error. /// /// @see `Rasterizer::Teardown` /// - /// @param[in] surface The on-screen render surface. + /// @param[in] studio The on-screen render studio. /// - void Setup(std::unique_ptr surface); + void Setup(std::unique_ptr studio, bool support_thread_merging); //---------------------------------------------------------------------------- /// @brief Releases the previously set up on-screen render surface and @@ -205,42 +207,47 @@ class Rasterizer final : public SnapshotDelegate, fml::TaskRunnerAffineWeakPtr GetSnapshotDelegate() const; //---------------------------------------------------------------------------- - /// @brief Sometimes, it may be necessary to render the same frame again - /// without having to wait for the framework to build a whole new - /// layer tree describing the same contents. One such case is when - /// external textures (video or camera streams for example) are - /// updated in an otherwise static layer tree. To support this use - /// case, the rasterizer holds onto the last rendered layer tree. + /// @brief Add a surface, implicit or not. + void AddSurface(int64_t view_id, + std::unique_ptr surface, + std::shared_ptr view_embedder); + + void RemoveSurface(int64_t view_id); + + //---------------------------------------------------------------------------- /// /// @bug https://github.com/flutter/flutter/issues/33939 /// /// @return A pointer to the last layer or `nullptr` if this rasterizer /// has never rendered a frame. /// - flutter::LayerTree* GetLastLayerTree(); + bool HasLastLayerTree() const; //---------------------------------------------------------------------------- - /// @brief Draws a last layer tree to the render surface. This may seem - /// entirely redundant at first glance. After all, on surface loss - /// and re-acquisition, the framework generates a new layer tree. - /// Otherwise, why render the same contents to the screen again? - /// This is used as an optimization in cases where there are - /// external textures (video or camera streams for example) in + /// @brief Draws to all render surfaces their last layer trees. This may + /// seem entirely redundant at first glance. After all, on surface + /// loss and re-acquisition, the framework generates a new layer + /// tree. Otherwise, why render the same contents to the screen + /// again? This is used as an optimization in cases where there + /// are external textures (video or camera streams for example) in /// referenced in the layer tree. These textures may be updated at /// a cadence different from that of the Flutter application. /// Flutter can re-render the layer tree with just the updated /// textures instead of waiting for the framework to do the work /// to generate the layer tree describing the same contents. /// - void DrawLastLayerTree( - std::unique_ptr frame_timings_recorder); + /// @return The number of surfaces that are drawn this way. + int DrawLastLayerTree( + std::unique_ptr frame_timings_recorder, + bool enable_leaf_layer_tracing = false); // |SnapshotDelegate| GrDirectContext* GetGrContext() override; std::shared_ptr GetTextureRegistry() override; - using LayerTreeDiscardCallback = std::function; + using LayerTreeDiscardCallback = + std::function; //---------------------------------------------------------------------------- /// @brief Takes the next item from the layer tree pipeline and executes @@ -397,16 +404,6 @@ class Rasterizer final : public SnapshotDelegate, /// void SetNextFrameCallback(const fml::closure& callback); - //---------------------------------------------------------------------------- - /// @brief Set the External View Embedder. This is done on shell - /// initialization. This is non-null on platforms that support - /// embedding externally composited views. - /// - /// @param[in] view_embedder The external view embedder object. - /// - void SetExternalViewEmbedder( - const std::shared_ptr& view_embedder); - //---------------------------------------------------------------------------- /// @brief Set the snapshot surface producer. This is done on shell /// initialization. This is non-null on platforms that support taking @@ -500,6 +497,56 @@ class Rasterizer final : public SnapshotDelegate, void DisableThreadMergerIfNeeded(); private: + // The result of `DoDraw`. + // + // Normally `DoDraw` returns simply a raster status. However, sometimes we + // need to attempt to rasterize the layer tree again. This happens when + // layer_tree has not successfully rasterized due to changes in the thread + // configuration, in which case the resubmitted task will be inserted to the + // front of the pipeline. + struct DoDrawResult { + RasterStatus raster_status = RasterStatus::kFailed; + int64_t view_id; + std::unique_ptr resubmitted_layer_tree_item; + }; + + struct SurfaceRecord { + SurfaceRecord(int64_t view_id, + std::shared_ptr view_embedder, + std::unique_ptr surface) + : view_id(view_id), + view_embedder(std::move(view_embedder)), + surface(std::move(surface)) {} + + int64_t view_id; + std::shared_ptr view_embedder; + std::unique_ptr surface; + + // This is the information for the last successfully drawing. + // + // Sometimes, it may be necessary to render the same frame again without + // having to wait for the framework to build a whole new layer tree + // describing the same contents. One such case is when external textures + // (video or camera streams for example) are updated in an otherwise static + // layer tree. To support this use case, the rasterizer holds onto the last + // rendered layer tree. + std::shared_ptr last_tree; + float last_pixel_ratio; + }; + + SurfaceRecord* GetSurface(int64_t view_id) { + auto found_surface = surfaces_.find(view_id); + if (found_surface == surfaces_.end()) { + return nullptr; + } + return &found_surface->second; + } + + SurfaceRecord* GetFirstSurface() { + // TODO(dkwingsmt) + return GetSurface(0ll); + } + // |SnapshotDelegate| std::unique_ptr MakeSkiaGpuImage( sk_sp display_list, @@ -519,15 +566,13 @@ class Rasterizer final : public SnapshotDelegate, fml::Milliseconds GetFrameBudget() const override; // |SnapshotController::Delegate| - const std::unique_ptr& GetSurface() const override { - return surface_; - } + Studio* GetStudio() const override { return studio_.get(); } // |SnapshotController::Delegate| std::shared_ptr GetAiksContext() const override { #if IMPELLER_SUPPORTS_RENDERING - if (surface_) { - return surface_->GetAiksContext(); + if (studio_) { + return studio_->GetAiksContext(); } if (auto context = impeller_context_.lock()) { return std::make_shared(context); @@ -554,45 +599,50 @@ class Rasterizer final : public SnapshotDelegate, GrDirectContext* surface_context, bool compressed); - RasterStatus DoDraw( + DoDrawResult DoDraw( + int64_t view_id, std::unique_ptr frame_timings_recorder, std::unique_ptr layer_tree, float device_pixel_ratio); RasterStatus DrawToSurface(FrameTimingsRecorder& frame_timings_recorder, - flutter::LayerTree& layer_tree, - float device_pixel_ratio); + flutter::LayerTree* layer_tree, + float device_pixel_ratio, + SurfaceRecord* surface_record); RasterStatus DrawToSurfaceUnsafe(FrameTimingsRecorder& frame_timings_recorder, - flutter::LayerTree& layer_tree, - float device_pixel_ratio); + flutter::LayerTree* layer_tree, + float device_pixel_ratio, + SurfaceRecord* surface_record); + + Screenshot ScreenshotLayerTree(ScreenshotType type, + bool base64_encode, + SurfaceRecord& surface_record); void FireNextFrameCallbackIfPresent(); - static bool NoDiscard(const flutter::LayerTree& layer_tree) { return false; } + static bool NoDiscard(int64_t view_id, const flutter::LayerTree& layer_tree) { + return false; + } static bool ShouldResubmitFrame(const RasterStatus& raster_status); Delegate& delegate_; MakeGpuImageBehavior gpu_image_behavior_; std::weak_ptr impeller_context_; - std::unique_ptr surface_; + std::unique_ptr studio_; + std::unordered_map surfaces_; std::unique_ptr snapshot_surface_producer_; std::unique_ptr compositor_context_; - // This is the last successfully rasterized layer tree. - std::unique_ptr last_layer_tree_; - float last_device_pixel_ratio_; - // Set when we need attempt to rasterize the layer tree again. This layer_tree - // has not successfully rasterized. This can happen due to the change in the - // thread configuration. This will be inserted to the front of the pipeline. - std::unique_ptr resubmitted_layer_tree_; - std::unique_ptr resubmitted_recorder_; - float resubmitted_pixel_ratio_; fml::closure next_frame_callback_; bool user_override_resource_cache_bytes_; std::optional max_cache_bytes_; fml::RefPtr raster_thread_merger_; - std::shared_ptr external_view_embedder_; std::unique_ptr snapshot_controller_; + // The Rasterizer allows having no view embedder, but only in a legacy mode + // where there is only one surface (the implicit surface), and no view + // embedder is provided ever. In other cases, the Rasterizer should always + // have a view embedder. + bool requires_view_embedder_; // WeakPtrFactory must be the last member. fml::TaskRunnerAffineWeakPtrFactory weak_factory_; diff --git a/shell/common/rasterizer_unittests.cc b/shell/common/rasterizer_unittests.cc index 53de96c86bd4e..be6d69804c414 100644 --- a/shell/common/rasterizer_unittests.cc +++ b/shell/common/rasterizer_unittests.cc @@ -29,6 +29,8 @@ using testing::ReturnRef; namespace flutter { namespace { + +constexpr int64_t kDefaultViewId = 0; constexpr float kDevicePixelRatio = 2.0f; class MockDelegate : public Rasterizer::Delegate { @@ -41,10 +43,18 @@ class MockDelegate : public Rasterizer::Delegate { const fml::RefPtr()); MOCK_CONST_METHOD0(GetIsGpuDisabledSyncSwitch, std::shared_ptr()); - MOCK_METHOD0(CreateSnapshotSurface, std::unique_ptr()); MOCK_CONST_METHOD0(GetSettings, const Settings&()); }; +class MockStudio : public Studio { + public: + MOCK_METHOD0(IsValid, bool()); + MOCK_METHOD0(GetContext, GrDirectContext*()); + MOCK_METHOD0(MakeRenderContextCurrent, std::unique_ptr()); + MOCK_METHOD0(ClearRenderContext, bool()); + MOCK_CONST_METHOD0(AllowsDrawingWhenGpuDisabled, bool()); +}; + class MockSurface : public Surface { public: MOCK_METHOD0(IsValid, bool()); @@ -80,7 +90,6 @@ class MockExternalViewEmbedder : public ExternalViewEmbedder { MOCK_METHOD2(EndFrame, void(bool should_resubmit_frame, fml::RefPtr raster_thread_merger)); - MOCK_METHOD0(SupportsDynamicThreadMerging, bool()); }; } // namespace @@ -121,10 +130,12 @@ TEST(RasterizerTest, drawEmptyPipeline) { ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings)); ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), nullptr); fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); @@ -152,11 +163,11 @@ TEST(RasterizerTest, .WillRepeatedly(ReturnRef(task_runners)); EXPECT_CALL(delegate, OnFrameRasterized(_)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); std::shared_ptr> external_view_embedder = std::make_shared>(); - rasterizer->SetExternalViewEmbedder(external_view_embedder); SurfaceFrame::FramebufferInfo framebuffer_info; framebuffer_info.supports_readback = true; @@ -165,10 +176,10 @@ TEST(RasterizerTest, /*surface=*/nullptr, framebuffer_info, /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); + EXPECT_CALL(*studio, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); EXPECT_CALL(*surface, AcquireFrame(SkISize())) .WillOnce(Return(ByMove(std::move(surface_frame)))); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); EXPECT_CALL(*external_view_embedder, @@ -185,7 +196,9 @@ TEST(RasterizerTest, nullptr))) .Times(1); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), + external_view_embedder); fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); @@ -193,12 +206,12 @@ TEST(RasterizerTest, std::make_unique(/*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), + kDefaultViewId, std::move(layer_tree), CreateFinishedBuildRecorder(), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; rasterizer->Draw(pipeline, no_discard); latch.Signal(); }); @@ -224,22 +237,20 @@ TEST( .WillRepeatedly(ReturnRef(task_runners)); EXPECT_CALL(delegate, OnFrameRasterized(_)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); std::shared_ptr> external_view_embedder = std::make_shared>(); - rasterizer->SetExternalViewEmbedder(external_view_embedder); - EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging) - .WillRepeatedly(Return(true)); SurfaceFrame::FramebufferInfo framebuffer_info; framebuffer_info.supports_readback = true; auto surface_frame = std::make_unique( /*surface=*/nullptr, framebuffer_info, /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); + EXPECT_CALL(*studio, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); EXPECT_CALL(*surface, AcquireFrame(SkISize())) .WillOnce(Return(ByMove(std::move(surface_frame)))); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); EXPECT_CALL(*external_view_embedder, @@ -252,19 +263,21 @@ TEST( /*raster_thread_merger=*/_)) .Times(1); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), /*support_thread_merging=*/true); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), + external_view_embedder); fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); auto layer_tree = std::make_unique( /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), + kDefaultViewId, std::move(layer_tree), CreateFinishedBuildRecorder(), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; rasterizer->Draw(pipeline, no_discard); latch.Signal(); }); @@ -294,11 +307,11 @@ TEST( EXPECT_CALL(delegate, OnFrameRasterized(_)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); std::shared_ptr> external_view_embedder = std::make_shared>(); - rasterizer->SetExternalViewEmbedder(external_view_embedder); SurfaceFrame::FramebufferInfo framebuffer_info; framebuffer_info.supports_readback = true; @@ -307,13 +320,11 @@ TEST( /*surface=*/nullptr, framebuffer_info, /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); + EXPECT_CALL(*studio, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); EXPECT_CALL(*surface, AcquireFrame(SkISize())) .WillOnce(Return(ByMove(std::move(surface_frame)))); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); - EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging) - .WillRepeatedly(Return(true)); EXPECT_CALL(*external_view_embedder, BeginFrame(/*frame_size=*/SkISize(), /*context=*/nullptr, @@ -325,17 +336,20 @@ TEST( /*raster_thread_merger=*/_)) .Times(1); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), /*support_thread_merging=*/true); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), + external_view_embedder); auto pipeline = std::make_shared(/*depth=*/10); auto layer_tree = std::make_unique(/*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), kDevicePixelRatio); + kDefaultViewId, std::move(layer_tree), CreateFinishedBuildRecorder(), + kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; rasterizer->Draw(pipeline, no_discard); } @@ -361,11 +375,11 @@ TEST(RasterizerTest, EXPECT_CALL(delegate, OnFrameRasterized(_)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); std::shared_ptr> external_view_embedder = std::make_shared>(); - rasterizer->SetExternalViewEmbedder(external_view_embedder); SurfaceFrame::FramebufferInfo framebuffer_info; framebuffer_info.supports_readback = true; @@ -378,16 +392,14 @@ TEST(RasterizerTest, /*surface=*/nullptr, framebuffer_info, /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()) + EXPECT_CALL(*studio, AllowsDrawingWhenGpuDisabled()) .WillRepeatedly(Return(true)); // Prepare two frames for Draw() and DrawLastLayerTree(). EXPECT_CALL(*surface, AcquireFrame(SkISize())) .WillOnce(Return(ByMove(std::move(surface_frame1)))) .WillOnce(Return(ByMove(std::move(surface_frame2)))); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); - EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging) - .WillRepeatedly(Return(true)); EXPECT_CALL(*external_view_embedder, BeginFrame(/*frame_size=*/SkISize(), /*context=*/nullptr, @@ -399,17 +411,20 @@ TEST(RasterizerTest, /*raster_thread_merger=*/_)) .Times(2); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), /*support_thread_merging=*/true); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), + external_view_embedder); auto pipeline = std::make_shared(/*depth=*/10); auto layer_tree = std::make_unique(/*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), kDevicePixelRatio); + kDefaultViewId, std::move(layer_tree), CreateFinishedBuildRecorder(), + kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; // The Draw() will respectively call BeginFrame(), SubmitFrame() and // EndFrame() one time. @@ -420,52 +435,6 @@ TEST(RasterizerTest, rasterizer->DrawLastLayerTree(CreateFinishedBuildRecorder()); } -TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) { - std::string test_name = - ::testing::UnitTest::GetInstance()->current_test_info()->name(); - ThreadHost thread_host("io.flutter.test." + test_name + ".", - ThreadHost::Type::Platform | ThreadHost::Type::RASTER | - ThreadHost::Type::IO | ThreadHost::Type::UI); - TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), - thread_host.raster_thread->GetTaskRunner(), - thread_host.ui_thread->GetTaskRunner(), - thread_host.io_thread->GetTaskRunner()); - NiceMock delegate; - Settings settings; - ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings)); - EXPECT_CALL(delegate, GetTaskRunners()) - .WillRepeatedly(ReturnRef(task_runners)); - auto rasterizer = std::make_unique(delegate); - - std::shared_ptr> external_view_embedder = - std::make_shared>(); - rasterizer->SetExternalViewEmbedder(external_view_embedder); - - EXPECT_CALL( - *external_view_embedder, - EndFrame(/*should_resubmit_frame=*/false, - /*raster_thread_merger=*/fml::RefPtr( - nullptr))) - .Times(0); - - fml::AutoResetWaitableEvent latch; - thread_host.raster_thread->GetTaskRunner()->PostTask([&] { - auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique( - /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); - auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), - kDevicePixelRatio); - PipelineProduceResult result = - pipeline->Produce().Complete(std::move(layer_tree_item)); - EXPECT_TRUE(result.success); - auto no_discard = [](LayerTree&) { return false; }; - rasterizer->Draw(pipeline, no_discard); - latch.Signal(); - }); - latch.Wait(); -} - TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNotUsedThisFrame) { std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name(); @@ -483,14 +452,16 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNotUsedThisFrame) { .WillRepeatedly(ReturnRef(task_runners)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); std::shared_ptr> external_view_embedder = std::make_shared>(); - rasterizer->SetExternalViewEmbedder(external_view_embedder); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), + external_view_embedder); EXPECT_CALL(*external_view_embedder, BeginFrame(/*frame_size=*/SkISize(), /*context=*/nullptr, @@ -510,13 +481,13 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNotUsedThisFrame) { auto layer_tree = std::make_unique( /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), + kDefaultViewId, std::move(layer_tree), CreateFinishedBuildRecorder(), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); // Always discard the layer tree. - auto discard_callback = [](LayerTree&) { return true; }; + auto discard_callback = [](int64_t, LayerTree&) { return true; }; RasterStatus status = rasterizer->Draw(pipeline, discard_callback); EXPECT_EQ(status, RasterStatus::kDiscarded); latch.Signal(); @@ -541,14 +512,16 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenPipelineIsEmpty) { .WillRepeatedly(ReturnRef(task_runners)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); std::shared_ptr> external_view_embedder = std::make_shared>(); - rasterizer->SetExternalViewEmbedder(external_view_embedder); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), + external_view_embedder); EXPECT_CALL( *external_view_embedder, @@ -560,7 +533,7 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenPipelineIsEmpty) { fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; RasterStatus status = rasterizer->Draw(pipeline, no_discard); EXPECT_EQ(status, RasterStatus::kFailed); latch.Signal(); @@ -587,6 +560,7 @@ TEST(RasterizerTest, EXPECT_CALL(delegate, OnFrameRasterized(_)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); auto is_gpu_disabled_sync_switch = std::make_shared(false); @@ -597,28 +571,29 @@ TEST(RasterizerTest, /*surface=*/nullptr, /*framebuffer_info=*/framebuffer_info, /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); + EXPECT_CALL(*studio, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); ON_CALL(delegate, GetIsGpuDisabledSyncSwitch()) .WillByDefault(Return(is_gpu_disabled_sync_switch)); EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()).Times(0); EXPECT_CALL(*surface, AcquireFrame(SkISize())) .WillOnce(Return(ByMove(std::move(surface_frame)))); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), nullptr); fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); auto layer_tree = std::make_unique( /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), + kDefaultViewId, std::move(layer_tree), CreateFinishedBuildRecorder(), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; rasterizer->Draw(pipeline, no_discard); latch.Signal(); }); @@ -644,6 +619,7 @@ TEST( .WillRepeatedly(ReturnRef(task_runners)); EXPECT_CALL(delegate, OnFrameRasterized(_)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); auto is_gpu_disabled_sync_switch = std::make_shared(true); @@ -655,28 +631,29 @@ TEST( /*surface=*/nullptr, /*framebuffer_info=*/framebuffer_info, /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); + EXPECT_CALL(*studio, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); ON_CALL(delegate, GetIsGpuDisabledSyncSwitch()) .WillByDefault(Return(is_gpu_disabled_sync_switch)); EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()).Times(0); EXPECT_CALL(*surface, AcquireFrame(SkISize())) .WillOnce(Return(ByMove(std::move(surface_frame)))); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), nullptr); fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); auto layer_tree = std::make_unique( /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), + kDefaultViewId, std::move(layer_tree), CreateFinishedBuildRecorder(), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; RasterStatus status = rasterizer->Draw(pipeline, no_discard); EXPECT_EQ(status, RasterStatus::kSuccess); latch.Signal(); @@ -703,6 +680,7 @@ TEST( .WillRepeatedly(ReturnRef(task_runners)); EXPECT_CALL(delegate, OnFrameRasterized(_)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); auto is_gpu_disabled_sync_switch = std::make_shared(false); @@ -714,27 +692,28 @@ TEST( /*surface=*/nullptr, /*framebuffer_info=*/framebuffer_info, /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(false)); + EXPECT_CALL(*studio, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(false)); EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()) .WillOnce(Return(is_gpu_disabled_sync_switch)); EXPECT_CALL(*surface, AcquireFrame(SkISize())) .WillOnce(Return(ByMove(std::move(surface_frame)))); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), nullptr); fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); auto layer_tree = std::make_unique( /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), + kDefaultViewId, std::move(layer_tree), CreateFinishedBuildRecorder(), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; RasterStatus status = rasterizer->Draw(pipeline, no_discard); EXPECT_EQ(status, RasterStatus::kSuccess); latch.Signal(); @@ -761,6 +740,7 @@ TEST( .WillRepeatedly(ReturnRef(task_runners)); EXPECT_CALL(delegate, OnFrameRasterized(_)).Times(0); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); auto is_gpu_disabled_sync_switch = std::make_shared(true); @@ -772,26 +752,27 @@ TEST( /*surface=*/nullptr, /*framebuffer_info=*/framebuffer_info, /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(false)); + EXPECT_CALL(*studio, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(false)); EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()) .WillOnce(Return(is_gpu_disabled_sync_switch)); EXPECT_CALL(*surface, AcquireFrame(SkISize())).Times(0); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), nullptr); fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); auto layer_tree = std::make_unique( /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), + kDefaultViewId, std::move(layer_tree), CreateFinishedBuildRecorder(), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; RasterStatus status = rasterizer->Draw(pipeline, no_discard); EXPECT_EQ(status, RasterStatus::kDiscarded); latch.Signal(); @@ -825,6 +806,7 @@ TEST( }); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); auto is_gpu_disabled_sync_switch = std::make_shared(false); @@ -833,21 +815,22 @@ TEST( ON_CALL(*surface, AcquireFrame(SkISize())) .WillByDefault(::testing::Invoke([] { return nullptr; })); EXPECT_CALL(*surface, AcquireFrame(SkISize())); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillOnce(Return(ByMove(std::make_unique(true)))); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), nullptr); fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); auto layer_tree = std::make_unique( /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(), + kDefaultViewId, std::move(layer_tree), CreateFinishedBuildRecorder(), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; RasterStatus status = rasterizer->Draw(pipeline, no_discard); EXPECT_EQ(status, RasterStatus::kFailed); latch.Signal(); @@ -879,8 +862,9 @@ TEST(RasterizerTest, }); latch.Wait(); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); - EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()) + EXPECT_CALL(*studio, AllowsDrawingWhenGpuDisabled()) .WillRepeatedly(Return(true)); ON_CALL(*surface, AcquireFrame(SkISize())) .WillByDefault(::testing::Invoke([] { @@ -892,7 +876,7 @@ TEST(RasterizerTest, [](const SurfaceFrame& frame, DlCanvas*) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); })); - ON_CALL(*surface, MakeRenderContextCurrent()) + ON_CALL(*studio, MakeRenderContextCurrent()) .WillByDefault(::testing::Invoke( [] { return std::make_unique(true); })); @@ -915,20 +899,21 @@ TEST(RasterizerTest, }); thread_host.raster_thread->GetTaskRunner()->PostTask([&] { - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), nullptr); auto pipeline = std::make_shared(/*depth=*/10); for (int i = 0; i < 2; i++) { auto layer_tree = std::make_unique( /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i]), - kDevicePixelRatio); + kDefaultViewId, std::move(layer_tree), + CreateFinishedBuildRecorder(timestamps[i]), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); EXPECT_EQ(result.is_first_item, i == 0); } - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; // Although we only call 'Rasterizer::Draw' once, it will be called twice // finally because there are two items in the pipeline. rasterizer->Draw(pipeline, no_discard); @@ -959,17 +944,19 @@ TEST(RasterizerTest, TeardownFreesResourceCache) { .WillRepeatedly(ReturnRef(task_runners)); auto rasterizer = std::make_unique(delegate); + auto studio = std::make_unique>(); auto surface = std::make_unique>(); auto context = GrDirectContext::MakeMock(nullptr); context->setResourceCacheLimit(0); - EXPECT_CALL(*surface, MakeRenderContextCurrent()) + EXPECT_CALL(*studio, MakeRenderContextCurrent()) .WillRepeatedly([]() -> std::unique_ptr { return std::make_unique(true); }); - EXPECT_CALL(*surface, GetContext()).WillRepeatedly(Return(context.get())); + EXPECT_CALL(*studio, GetContext()).WillRepeatedly(Return(context.get())); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), nullptr); EXPECT_EQ(context->getResourceCacheLimit(), 0ul); rasterizer->SetResourceCacheMaxBytes(10000000, false); @@ -1060,8 +1047,9 @@ TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) { int frames_submitted = 0; fml::CountDownLatch submit_latch(2); + auto studio = std::make_unique>(); auto surface = std::make_unique(); - ON_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillByDefault(Return(true)); + ON_CALL(*studio, AllowsDrawingWhenGpuDisabled()).WillByDefault(Return(true)); ON_CALL(*surface, AcquireFrame(SkISize())) .WillByDefault(::testing::Invoke([&] { SurfaceFrame::FramebufferInfo framebuffer_info; @@ -1081,25 +1069,26 @@ TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) { /*frame_size=*/SkISize::Make(800, 600)); })); - ON_CALL(*surface, MakeRenderContextCurrent()) + ON_CALL(*studio, MakeRenderContextCurrent()) .WillByDefault(::testing::Invoke( [] { return std::make_unique(true); })); thread_host.raster_thread->GetTaskRunner()->PostTask([&] { - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), nullptr); auto pipeline = std::make_shared(/*depth=*/10); for (int i = 0; i < 2; i++) { auto layer_tree = std::make_unique( /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i]), - kDevicePixelRatio); + kDefaultViewId, std::move(layer_tree), + CreateFinishedBuildRecorder(timestamps[i]), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); EXPECT_EQ(result.is_first_item, i == 0); } - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; // Although we only call 'Rasterizer::Draw' once, it will be called twice // finally because there are two items in the pipeline. rasterizer->Draw(pipeline, no_discard); @@ -1143,8 +1132,9 @@ TEST(RasterizerTest, presentationTimeNotSetWhenVsyncTargetInPast) { const auto first_timestamp = fml::TimePoint::Now() - millis_16; fml::CountDownLatch submit_latch(1); + auto studio = std::make_unique>(); auto surface = std::make_unique(); - ON_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillByDefault(Return(true)); + ON_CALL(*studio, AllowsDrawingWhenGpuDisabled()).WillByDefault(Return(true)); ON_CALL(*surface, AcquireFrame(SkISize())) .WillByDefault(::testing::Invoke([&] { SurfaceFrame::FramebufferInfo framebuffer_info; @@ -1162,23 +1152,24 @@ TEST(RasterizerTest, presentationTimeNotSetWhenVsyncTargetInPast) { /*frame_size=*/SkISize::Make(800, 600)); })); - ON_CALL(*surface, MakeRenderContextCurrent()) + ON_CALL(*studio, MakeRenderContextCurrent()) .WillByDefault(::testing::Invoke( [] { return std::make_unique(true); })); thread_host.raster_thread->GetTaskRunner()->PostTask([&] { - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), false); + rasterizer->AddSurface(kDefaultViewId, std::move(surface), nullptr); auto pipeline = std::make_shared(/*depth=*/10); auto layer_tree = std::make_unique( /*config=*/LayerTree::Config(), /*frame_size=*/SkISize()); auto layer_tree_item = std::make_unique( - std::move(layer_tree), CreateFinishedBuildRecorder(first_timestamp), - kDevicePixelRatio); + kDefaultViewId, std::move(layer_tree), + CreateFinishedBuildRecorder(first_timestamp), kDevicePixelRatio); PipelineProduceResult result = pipeline->Produce().Complete(std::move(layer_tree_item)); EXPECT_TRUE(result.success); EXPECT_EQ(result.is_first_item, true); - auto no_discard = [](LayerTree&) { return false; }; + auto no_discard = [](int64_t, LayerTree&) { return false; }; rasterizer->Draw(pipeline, no_discard); }); diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 7487147f57783..3f2b1d32e8985 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -702,8 +702,6 @@ bool Shell::Setup(std::unique_ptr platform_view, io_manager_ = io_manager; // Set the external view embedder for the rasterizer. - auto view_embedder = platform_view_->CreateExternalViewEmbedder(); - rasterizer_->SetExternalViewEmbedder(view_embedder); rasterizer_->SetSnapshotSurfaceProducer( platform_view_->CreateSnapshotSurfaceProducer()); @@ -775,12 +773,21 @@ DartVM* Shell::GetDartVM() { return &vm_; } +constexpr int64_t kFlutterDefaultViewId = 0ll; + // |PlatformView::Delegate| -void Shell::OnPlatformViewCreated(std::unique_ptr surface) { +void Shell::OnPlatformViewCreated() { TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated"); FML_DCHECK(is_setup_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + std::unique_ptr studio = platform_view_->CreateStudio(); + if (studio == nullptr) { + // TODO(dkwingsmt): This case is observed in windows unit tests. Anyway, + // we're probably not creating the surface in this callback eventually. + return; + } + // Prevent any request to change the thread configuration for raster and // platform queues while the platform view is being created. // @@ -806,15 +813,23 @@ void Shell::OnPlatformViewCreated(std::unique_ptr surface) { !task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread(); fml::AutoResetWaitableEvent latch; - auto raster_task = - fml::MakeCopyable([&waiting_for_first_frame = waiting_for_first_frame_, - rasterizer = rasterizer_->GetWeakPtr(), // - surface = std::move(surface)]() mutable { + auto raster_task = fml::MakeCopyable( + [&waiting_for_first_frame = waiting_for_first_frame_, // + rasterizer = rasterizer_->GetWeakPtr(), // + platform_view = platform_view_.get(), // + studio = std::move(studio) // + ]() mutable { + std::unique_ptr surface = + platform_view->CreateSurface(kFlutterDefaultViewId); + auto view_embedder = platform_view->CreateExternalViewEmbedder(); if (rasterizer) { // Enables the thread merger which may be used by the external view // embedder. rasterizer->EnableThreadMergerIfNeeded(); - rasterizer->Setup(std::move(surface)); + rasterizer->Setup(std::move(studio), + platform_view->SupportsDynamicThreadMerging()); + rasterizer->AddSurface(kFlutterDefaultViewId, std::move(surface), + view_embedder); } waiting_for_first_frame.store(true); @@ -954,7 +969,8 @@ void Shell::OnPlatformViewScheduleFrame() { } // |PlatformView::Delegate| -void Shell::OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) { +void Shell::OnPlatformViewSetViewportMetrics(int64_t view_id, + const ViewportMetrics& metrics) { FML_DCHECK(is_setup_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); @@ -978,15 +994,15 @@ void Shell::OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) { }); task_runners_.GetUITaskRunner()->PostTask( - [engine = engine_->GetWeakPtr(), metrics]() { + [engine = engine_->GetWeakPtr(), metrics, view_id]() { if (engine) { - engine->SetViewportMetrics(metrics); + engine->SetViewportMetrics(view_id, metrics); } }); { std::scoped_lock lock(resize_mutex_); - expected_frame_size_ = + expected_frame_sizes_[view_id] = SkISize::Make(metrics.physical_width, metrics.physical_height); device_pixel_ratio_ = metrics.device_pixel_ratio; } @@ -1193,10 +1209,11 @@ void Shell::OnAnimatorUpdateLatestFrameTargetTime( void Shell::OnAnimatorDraw(std::shared_ptr pipeline) { FML_DCHECK(is_setup_); - auto discard_callback = [this](flutter::LayerTree& tree) { + auto discard_callback = [this](int64_t view_id, flutter::LayerTree& tree) { std::scoped_lock lock(resize_mutex_); - return !expected_frame_size_.isEmpty() && - tree.frame_size() != expected_frame_size_; + auto expected_frame_size = ExpectedFrameSize(view_id); + return !expected_frame_size.isEmpty() && + tree.frame_size() != expected_frame_size; }; task_runners_.GetRasterTaskRunner()->PostTask(fml::MakeCopyable( @@ -1918,24 +1935,24 @@ bool Shell::OnServiceProtocolRenderFrameWithRasterStats( rapidjson::Document* response) { FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread()); - if (auto last_layer_tree = rasterizer_->GetLastLayerTree()) { + // When rendering the last layer tree, we do not need to build a frame, + // invariants in FrameTimingRecorder enforce that raster timings can not be + // set before build-end. + auto frame_timings_recorder = std::make_unique(); + const auto now = fml::TimePoint::Now(); + frame_timings_recorder->RecordVsync(now, now); + frame_timings_recorder->RecordBuildStart(now); + frame_timings_recorder->RecordBuildEnd(now); + + int success_count = + rasterizer_->DrawLastLayerTree(std::move(frame_timings_recorder), + /* enable_leaf_layer_tracing=*/true); + + if (success_count > 0) { auto& allocator = response->GetAllocator(); response->SetObject(); response->AddMember("type", "RenderFrameWithRasterStats", allocator); - // When rendering the last layer tree, we do not need to build a frame, - // invariants in FrameTimingRecorder enforce that raster timings can not be - // set before build-end. - auto frame_timings_recorder = std::make_unique(); - const auto now = fml::TimePoint::Now(); - frame_timings_recorder->RecordVsync(now, now); - frame_timings_recorder->RecordBuildStart(now); - frame_timings_recorder->RecordBuildEnd(now); - - last_layer_tree->enable_leaf_layer_tracing(true); - rasterizer_->DrawLastLayerTree(std::move(frame_timings_recorder)); - last_layer_tree->enable_leaf_layer_tracing(false); - rapidjson::Value snapshots; snapshots.SetArray(); @@ -1949,7 +1966,8 @@ bool Shell::OnServiceProtocolRenderFrameWithRasterStats( response->AddMember("snapshots", snapshots, allocator); - const auto& frame_size = expected_frame_size_; + // TODO(dkwingsmt) + const auto& frame_size = ExpectedFrameSize(kFlutterDefaultViewId); response->AddMember("frame_width", frame_size.width(), allocator); response->AddMember("frame_height", frame_size.height(), allocator); @@ -2005,6 +2023,65 @@ bool Shell::OnServiceProtocolReloadAssetFonts( return true; } +void Shell::AddRenderSurface( + int64_t view_id, + std::unique_ptr external_view_embedder) { + TRACE_EVENT0("flutter", "Shell::AddRenderSurface"); + FML_DCHECK(is_setup_); + FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + if (view_id == kFlutterDefaultViewId) { + return; + } + if (!engine_) { + return; + } + task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr(), // + view_id // + ] { engine->AddView(view_id); }); + + // TODO(dkwingsmt): platform_view_ is captured illegally here. + // We need some mechanism from it being collected. + task_runners_.GetRasterTaskRunner()->PostTask(fml::MakeCopyable( + [platform_view = platform_view_.get(), // + rasterizer = rasterizer_->GetWeakPtr(), // + view_embedder_ptr = external_view_embedder.release(), // + view_id // + ]() mutable { + if (platform_view && rasterizer) { + std::shared_ptr view_embedder( + view_embedder_ptr); + std::unique_ptr surface = + platform_view->CreateSurface(view_id); + if (surface) { + rasterizer->AddSurface(view_id, std::move(surface), view_embedder); + } + } + })); +} + +void Shell::RemoveRenderSurface(int64_t view_id) { + TRACE_EVENT0("flutter", "Shell::RemoveRenderSurface"); + FML_DCHECK(is_setup_); + FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + + fml::AutoResetWaitableEvent latch; + // platform_view_->RemoveSurface(view_id); + task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr(), // + view_id // + ] { engine->RemoveView(view_id); }); + task_runners_.GetRasterTaskRunner()->PostTask( + [&latch, // + rasterizer = rasterizer_->GetWeakPtr(), // + view_id // + ]() mutable { + if (rasterizer) { + rasterizer->RemoveSurface(view_id); + } + latch.Signal(); + }); + latch.Wait(); +} + Rasterizer::Screenshot Shell::Screenshot( Rasterizer::ScreenshotType screenshot_type, bool base64_encode) { @@ -2145,4 +2222,12 @@ Shell::GetConcurrentWorkerTaskRunner() const { return vm_->GetConcurrentWorkerTaskRunner(); } +SkISize Shell::ExpectedFrameSize(int64_t view_id) { + auto found = expected_frame_sizes_.find(view_id); + if (found == expected_frame_sizes_.end()) { + return SkISize::MakeEmpty(); + } + return found->second; +} + } // namespace flutter diff --git a/shell/common/shell.h b/shell/common/shell.h index 6f6360625f412..1f5b1d2974630 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -298,6 +298,15 @@ class Shell final : public PlatformView::Delegate, /// bool IsSetup() const; + /// @brief Add a non-implicit render surface. The implicit render surface + /// is created in OnPlatformViewCreated. + /// @param view_id + /// @param external_view_embedder Must not be null. + void AddRenderSurface( + int64_t view_id, + std::unique_ptr external_view_embedder); + void RemoveRenderSurface(int64_t view_id); + //---------------------------------------------------------------------------- /// @brief Captures a screenshot and optionally Base64 encodes the data /// of the last layer tree rendered by the rasterizer in this @@ -473,7 +482,7 @@ class Shell final : public PlatformView::Delegate, std::mutex resize_mutex_; // used to discard wrong size layer tree produced during interactive resizing - SkISize expected_frame_size_ = SkISize::MakeEmpty(); + std::unordered_map expected_frame_sizes_; // Used to communicate the right frame bounds via service protocol. double device_pixel_ratio_ = 0.0; @@ -528,7 +537,7 @@ class Shell final : public PlatformView::Delegate, void ReportTimings(); // |PlatformView::Delegate| - void OnPlatformViewCreated(std::unique_ptr surface) override; + void OnPlatformViewCreated() override; // |PlatformView::Delegate| void OnPlatformViewDestroyed() override; @@ -538,6 +547,7 @@ class Shell final : public PlatformView::Delegate, // |PlatformView::Delegate| void OnPlatformViewSetViewportMetrics( + int64_t view_id, const ViewportMetrics& metrics) override; // |PlatformView::Delegate| @@ -734,6 +744,8 @@ class Shell final : public PlatformView::Delegate, // directory. std::unique_ptr RestoreOriginalAssetResolver(); + SkISize ExpectedFrameSize(int64_t view_id); + // For accessing the Shell via the raster thread, necessary for various // rasterizer callbacks. std::unique_ptr> weak_factory_gpu_; diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index 8be076930b11b..e5d06e119aeb0 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -20,6 +20,8 @@ namespace flutter { namespace testing { +constexpr int64_t kDefaultViewId = 0; + ShellTest::ShellTest() : thread_host_("io.flutter.test." + GetCurrentTestName() + ".", ThreadHost::Type::Platform | ThreadHost::Type::IO | @@ -139,7 +141,7 @@ void ShellTest::SetViewportMetrics(Shell* shell, double width, double height) { shell->GetTaskRunners().GetUITaskRunner()->PostTask( [&latch, engine = shell->weak_engine_, viewport_metrics]() { if (engine) { - engine->SetViewportMetrics(viewport_metrics); + engine->SetViewportMetrics(kDefaultViewId, viewport_metrics); const auto frame_begin_time = fml::TimePoint::Now(); const auto frame_end_time = frame_begin_time + fml::TimeDelta::FromSecondsF(1.0 / 60.0); @@ -181,7 +183,7 @@ void ShellTest::PumpOneFrame(Shell* shell, fml::AutoResetWaitableEvent latch; shell->GetTaskRunners().GetUITaskRunner()->PostTask( [&latch, engine = shell->weak_engine_, viewport_metrics]() { - engine->SetViewportMetrics(viewport_metrics); + engine->SetViewportMetrics(kDefaultViewId, viewport_metrics); const auto frame_begin_time = fml::TimePoint::Now(); const auto frame_end_time = frame_begin_time + fml::TimeDelta::FromSecondsF(1.0 / 60.0); @@ -210,7 +212,8 @@ void ShellTest::PumpOneFrame(Shell* shell, if (builder) { builder(root_layer); } - runtime_delegate->Render(std::move(layer_tree), device_pixel_ratio); + runtime_delegate->Render(kDefaultViewId, std::move(layer_tree), + device_pixel_ratio); latch.Signal(); }); latch.Wait(); @@ -321,23 +324,21 @@ fml::TimePoint ShellTest::GetLatestFrameTargetTime(Shell* shell) const { } std::unique_ptr ShellTest::CreateShell(const Settings& settings, - bool simulate_vsync) { - return CreateShell(settings, GetTaskRunnersForFixture(), simulate_vsync); + const TaskRunners* task_runners) { + return CreateShell({ + .settings = settings, + .task_runners = task_runners, + }); } -std::unique_ptr ShellTest::CreateShell( - const Settings& settings, - TaskRunners task_runners, - bool simulate_vsync, - const std::shared_ptr& - shell_test_external_view_embedder, - bool is_gpu_disabled, - ShellTestPlatformView::BackendType rendering_backend, - Shell::CreateCallback platform_view_create_callback) { +std::unique_ptr ShellTest::CreateShell(const Config& config) { const auto vsync_clock = std::make_shared(); + TaskRunners task_runners = config.task_runners != nullptr + ? *config.task_runners + : GetTaskRunnersForFixture(); CreateVsyncWaiter create_vsync_waiter = [&]() { - if (simulate_vsync) { + if (config.simulate_vsync) { return static_cast>( std::make_unique(task_runners, vsync_clock)); } else { @@ -346,23 +347,28 @@ std::unique_ptr ShellTest::CreateShell( } }; + Shell::CreateCallback platform_view_create_callback = + std::move(config.platform_view_create_callback); if (!platform_view_create_callback) { - platform_view_create_callback = [vsync_clock, // - &create_vsync_waiter, // - shell_test_external_view_embedder, // - rendering_backend // - ](Shell& shell) { - return ShellTestPlatformView::Create( - shell, // - shell.GetTaskRunners(), // - vsync_clock, // - create_vsync_waiter, // - rendering_backend, // - shell_test_external_view_embedder, // - shell.GetConcurrentWorkerTaskRunner(), // - shell.GetIsGpuDisabledSyncSwitch() // - ); - }; + platform_view_create_callback = + [vsync_clock, // + &create_vsync_waiter, // + shell_test_external_view_embedder = + config.shell_test_external_view_embedder, // + rendering_backend = config.rendering_backend, // + support_thread_merging = config.support_thread_merging](Shell& shell) { + return ShellTestPlatformView::Create( + shell, // + shell.GetTaskRunners(), // + vsync_clock, // + create_vsync_waiter, // + rendering_backend, // + shell_test_external_view_embedder, // + shell.GetConcurrentWorkerTaskRunner(), // + shell.GetIsGpuDisabledSyncSwitch(), // + support_thread_merging // + ); + }; } Shell::CreateCallback rasterizer_create_callback = @@ -370,10 +376,10 @@ std::unique_ptr ShellTest::CreateShell( return Shell::Create(flutter::PlatformData(), // task_runners, // - settings, // + config.settings, // platform_view_create_callback, // rasterizer_create_callback, // - is_gpu_disabled // + config.is_gpu_disabled // ); } diff --git a/shell/common/shell_test.h b/shell/common/shell_test.h index b9e95cc590e8b..158a245474e2c 100644 --- a/shell/common/shell_test.h +++ b/shell/common/shell_test.h @@ -31,22 +31,32 @@ namespace testing { class ShellTest : public FixtureTest { public: + struct Config { + // Required. + const Settings& settings; + // Defaults to &GetTaskRunnersForFixture(). + const TaskRunners* task_runners; + // Defaults to false. + bool simulate_vsync; + // Defaults to nullptr. + std::shared_ptr + shell_test_external_view_embedder; + // Defaults to false. + bool is_gpu_disabled; + // Defaults to kDefaultBackend. + ShellTestPlatformView::BackendType rendering_backend; + // Defaults to calling ShellTestPlatformView::Create with the provided + // arguments. + Shell::CreateCallback platform_view_create_callback; + bool support_thread_merging; + }; + ShellTest(); Settings CreateSettingsForFixture() override; std::unique_ptr CreateShell(const Settings& settings, - bool simulate_vsync = false); - std::unique_ptr CreateShell( - const Settings& settings, - TaskRunners task_runners, - bool simulate_vsync = false, - const std::shared_ptr& - shell_test_external_view_embedder = nullptr, - bool is_gpu_disabled = false, - ShellTestPlatformView::BackendType rendering_backend = - ShellTestPlatformView::BackendType::kDefaultBackend, - Shell::CreateCallback platform_view_create_callback = - nullptr); + const TaskRunners* task_runners = nullptr); + std::unique_ptr CreateShell(const Config& config); void DestroyShell(std::unique_ptr shell); void DestroyShell(std::unique_ptr shell, const TaskRunners& task_runners); diff --git a/shell/common/shell_test_external_view_embedder.cc b/shell/common/shell_test_external_view_embedder.cc index 2536bb62ac6a2..9484c9a607c18 100644 --- a/shell/common/shell_test_external_view_embedder.cc +++ b/shell/common/shell_test_external_view_embedder.cc @@ -8,11 +8,9 @@ namespace flutter { ShellTestExternalViewEmbedder::ShellTestExternalViewEmbedder( const EndFrameCallBack& end_frame_call_back, - PostPrerollResult post_preroll_result, - bool support_thread_merging) + PostPrerollResult post_preroll_result) : end_frame_call_back_(end_frame_call_back), post_preroll_result_(post_preroll_result), - support_thread_merging_(support_thread_merging), submitted_frame_count_(0) {} void ShellTestExternalViewEmbedder::UpdatePostPrerollResult( @@ -117,8 +115,4 @@ DlCanvas* ShellTestExternalViewEmbedder::GetRootCanvas() { return nullptr; } -bool ShellTestExternalViewEmbedder::SupportsDynamicThreadMerging() { - return support_thread_merging_; -} - } // namespace flutter diff --git a/shell/common/shell_test_external_view_embedder.h b/shell/common/shell_test_external_view_embedder.h index 204472d5bc050..414d3ff2f2f2e 100644 --- a/shell/common/shell_test_external_view_embedder.h +++ b/shell/common/shell_test_external_view_embedder.h @@ -20,8 +20,7 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { std::function)>; ShellTestExternalViewEmbedder(const EndFrameCallBack& end_frame_call_back, - PostPrerollResult post_preroll_result, - bool support_thread_merging); + PostPrerollResult post_preroll_result); ~ShellTestExternalViewEmbedder() = default; @@ -85,14 +84,10 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| DlCanvas* GetRootCanvas() override; - // |ExternalViewEmbedder| - bool SupportsDynamicThreadMerging() override; - const EndFrameCallBack end_frame_call_back_; PostPrerollResult post_preroll_result_; - bool support_thread_merging_; SkISize frame_size_; std::map> slices_; std::map mutators_stacks_; diff --git a/shell/common/shell_test_platform_view.cc b/shell/common/shell_test_platform_view.cc index a683d372d8d0a..9ccdd0e912124 100644 --- a/shell/common/shell_test_platform_view.cc +++ b/shell/common/shell_test_platform_view.cc @@ -26,7 +26,8 @@ std::unique_ptr ShellTestPlatformView::Create( const std::shared_ptr& shell_test_external_view_embedder, const std::shared_ptr& worker_task_runner, - const std::shared_ptr& is_gpu_disabled_sync_switch) { + const std::shared_ptr& is_gpu_disabled_sync_switch, + bool support_thread_merging) { // TODO(gw280): https://github.com/flutter/flutter/issues/50298 // Make this fully runtime configurable switch (backend) { @@ -35,20 +36,20 @@ std::unique_ptr ShellTestPlatformView::Create( case BackendType::kGLBackend: return std::make_unique( delegate, task_runners, vsync_clock, create_vsync_waiter, - shell_test_external_view_embedder); + shell_test_external_view_embedder, support_thread_merging); #endif // SHELL_ENABLE_GL #ifdef SHELL_ENABLE_VULKAN case BackendType::kVulkanBackend: return std::make_unique( delegate, task_runners, vsync_clock, create_vsync_waiter, - shell_test_external_view_embedder); + shell_test_external_view_embedder, support_thread_merging); #endif // SHELL_ENABLE_VULKAN #ifdef SHELL_ENABLE_METAL case BackendType::kMetalBackend: return std::make_unique( delegate, task_runners, vsync_clock, create_vsync_waiter, shell_test_external_view_embedder, worker_task_runner, - is_gpu_disabled_sync_switch); + is_gpu_disabled_sync_switch, support_thread_merging); #endif // SHELL_ENABLE_METAL default: diff --git a/shell/common/shell_test_platform_view.h b/shell/common/shell_test_platform_view.h index ebb96c87dd23e..8b46417af9505 100644 --- a/shell/common/shell_test_platform_view.h +++ b/shell/common/shell_test_platform_view.h @@ -15,10 +15,10 @@ namespace testing { class ShellTestPlatformView : public PlatformView { public: enum class BackendType { + kDefaultBackend = 0, // Default value kGLBackend, kVulkanBackend, kMetalBackend, - kDefaultBackend, }; static std::unique_ptr Create( @@ -30,8 +30,8 @@ class ShellTestPlatformView : public PlatformView { const std::shared_ptr& shell_test_external_view_embedder, const std::shared_ptr& worker_task_runner, - const std::shared_ptr& - is_gpu_disabled_sync_switch); + const std::shared_ptr& is_gpu_disabled_sync_switch, + bool support_thread_merging); virtual void SimulateVSync() = 0; diff --git a/shell/common/shell_test_platform_view_gl.cc b/shell/common/shell_test_platform_view_gl.cc index 98323108fac44..6ba0d60fbcfff 100644 --- a/shell/common/shell_test_platform_view_gl.cc +++ b/shell/common/shell_test_platform_view_gl.cc @@ -6,6 +6,7 @@ #include +#include "flutter/shell/gpu/gpu_studio_gl_skia.h" #include "flutter/shell/gpu/gpu_surface_gl_skia.h" namespace flutter { @@ -17,13 +18,15 @@ ShellTestPlatformViewGL::ShellTestPlatformViewGL( std::shared_ptr vsync_clock, CreateVsyncWaiter create_vsync_waiter, std::shared_ptr - shell_test_external_view_embedder) + shell_test_external_view_embedder, + bool support_thread_merging) : ShellTestPlatformView(delegate, task_runners), gl_surface_(SkISize::Make(800, 600)), create_vsync_waiter_(std::move(create_vsync_waiter)), vsync_clock_(std::move(vsync_clock)), shell_test_external_view_embedder_( - std::move(shell_test_external_view_embedder)) {} + std::move(shell_test_external_view_embedder)), + support_thread_merging_(support_thread_merging) {} ShellTestPlatformViewGL::~ShellTestPlatformViewGL() = default; @@ -37,8 +40,20 @@ void ShellTestPlatformViewGL::SimulateVSync() { } // |PlatformView| -std::unique_ptr ShellTestPlatformViewGL::CreateRenderingSurface() { - return std::make_unique(this, true); +std::unique_ptr ShellTestPlatformViewGL::CreateRenderingStudio() { + if (main_context_ == nullptr) { + main_context_ = GPUStudioGLSkia::MakeGLContext(this); + } + return std::make_unique(main_context_, this); +} + +// |PlatformView| +std::unique_ptr ShellTestPlatformViewGL::CreateRenderingSurface( + int64_t view_id) { + if (main_context_ == nullptr) { + main_context_ = GPUStudioGLSkia::MakeGLContext(this); + } + return std::make_unique(main_context_, this, true); } // |PlatformView| @@ -47,6 +62,11 @@ ShellTestPlatformViewGL::CreateExternalViewEmbedder() { return shell_test_external_view_embedder_; } +// |PlatformView| +bool ShellTestPlatformViewGL::SupportsDynamicThreadMerging() { + return support_thread_merging_; +} + // |PlatformView| PointerDataDispatcherMaker ShellTestPlatformViewGL::GetDispatcherMaker() { return [](DefaultPointerDataDispatcher::Delegate& delegate) { diff --git a/shell/common/shell_test_platform_view_gl.h b/shell/common/shell_test_platform_view_gl.h index 4dca801da3c34..ed4c489579b0d 100644 --- a/shell/common/shell_test_platform_view_gl.h +++ b/shell/common/shell_test_platform_view_gl.h @@ -21,7 +21,8 @@ class ShellTestPlatformViewGL : public ShellTestPlatformView, std::shared_ptr vsync_clock, CreateVsyncWaiter create_vsync_waiter, std::shared_ptr - shell_test_external_view_embedder); + shell_test_external_view_embedder, + bool support_thread_merging); // |ShellTestPlatformView| virtual ~ShellTestPlatformViewGL() override; @@ -39,12 +40,22 @@ class ShellTestPlatformViewGL : public ShellTestPlatformView, std::shared_ptr shell_test_external_view_embedder_; + sk_sp main_context_; + + bool support_thread_merging_; + + // |PlatformView| + std::unique_ptr CreateRenderingStudio() override; + // |PlatformView| - std::unique_ptr CreateRenderingSurface() override; + std::unique_ptr CreateRenderingSurface(int64_t view_id) override; // |PlatformView| std::shared_ptr CreateExternalViewEmbedder() override; + // |PlatformView| + bool SupportsDynamicThreadMerging() override; + // |PlatformView| std::unique_ptr CreateVSyncWaiter() override; diff --git a/shell/common/shell_test_platform_view_metal.h b/shell/common/shell_test_platform_view_metal.h index a20b9c5f3f929..e27cb965ce7c5 100644 --- a/shell/common/shell_test_platform_view_metal.h +++ b/shell/common/shell_test_platform_view_metal.h @@ -25,18 +25,20 @@ class ShellTestPlatformViewMetal final : public ShellTestPlatformView, std::shared_ptr shell_test_external_view_embedder, const std::shared_ptr& worker_task_runner, - const std::shared_ptr& - is_gpu_disabled_sync_switch); + const std::shared_ptr& is_gpu_disabled_sync_switch, + bool support_thread_merging); // |ShellTestPlatformView| virtual ~ShellTestPlatformViewMetal() override; private: const std::unique_ptr metal_context_; + std::shared_ptr sksl_precompiler_; const CreateVsyncWaiter create_vsync_waiter_; const std::shared_ptr vsync_clock_; const std::shared_ptr shell_test_external_view_embedder_; + bool support_thread_merging_; // |ShellTestPlatformView| virtual void SimulateVSync() override; @@ -47,11 +49,17 @@ class ShellTestPlatformViewMetal final : public ShellTestPlatformView, // |PlatformView| std::shared_ptr CreateExternalViewEmbedder() override; + // |PlatformView| + bool SupportsDynamicThreadMerging() override; + // |PlatformView| PointerDataDispatcherMaker GetDispatcherMaker() override; // |PlatformView| - std::unique_ptr CreateRenderingSurface() override; + std::unique_ptr CreateRenderingStudio() override; + + // |PlatformView| + std::unique_ptr CreateRenderingSurface(int64_t view_id) override; // |PlatformView| std::shared_ptr GetImpellerContext() const override; diff --git a/shell/common/shell_test_platform_view_metal.mm b/shell/common/shell_test_platform_view_metal.mm index 598ecd5f87557..e73162043a9ae 100644 --- a/shell/common/shell_test_platform_view_metal.mm +++ b/shell/common/shell_test_platform_view_metal.mm @@ -9,6 +9,8 @@ #include #include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/shell/gpu/gpu_studio_metal_impeller.h" +#include "flutter/shell/gpu/gpu_studio_metal_skia.h" #include "flutter/shell/gpu/gpu_surface_metal_impeller.h" #include "flutter/shell/gpu/gpu_surface_metal_skia.h" #include "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h" @@ -75,7 +77,8 @@ GPUMTLTextureInfo offscreen_texture_info() const { CreateVsyncWaiter create_vsync_waiter, std::shared_ptr shell_test_external_view_embedder, const std::shared_ptr& worker_task_runner, - const std::shared_ptr& is_gpu_disabled_sync_switch) + const std::shared_ptr& is_gpu_disabled_sync_switch, + bool support_thread_merging) : ShellTestPlatformView(delegate, task_runners), GPUSurfaceMetalDelegate(MTLRenderTargetType::kMTLTexture), metal_context_(std::make_unique(GetSettings().enable_impeller, @@ -83,7 +86,9 @@ GPUMTLTextureInfo offscreen_texture_info() const { is_gpu_disabled_sync_switch)), create_vsync_waiter_(std::move(create_vsync_waiter)), vsync_clock_(std::move(vsync_clock)), - shell_test_external_view_embedder_(std::move(shell_test_external_view_embedder)) { + shell_test_external_view_embedder_(std::move(shell_test_external_view_embedder)), + support_thread_merging_(support_thread_merging) { + sksl_precompiler_ = std::make_shared(); if (GetSettings().enable_impeller) { FML_CHECK([metal_context_->impeller_context() context] != nil); } else { @@ -107,6 +112,11 @@ GPUMTLTextureInfo offscreen_texture_info() const { return shell_test_external_view_embedder_; } +// |PlatformView| +bool ShellTestPlatformViewMetal::SupportsDynamicThreadMerging() { + return support_thread_merging_; +} + // |PlatformView| PointerDataDispatcherMaker ShellTestPlatformViewMetal::GetDispatcherMaker() { return [](DefaultPointerDataDispatcher::Delegate& delegate) { @@ -115,13 +125,23 @@ GPUMTLTextureInfo offscreen_texture_info() const { } // |PlatformView| -std::unique_ptr ShellTestPlatformViewMetal::CreateRenderingSurface() { +std::unique_ptr ShellTestPlatformViewMetal::CreateRenderingStudio() { + if (GetSettings().enable_impeller) { + return std::make_unique(this, + [metal_context_->impeller_context() context]); + } + return std::make_unique(this, [metal_context_->context() mainContext], + sksl_precompiler_); +} + +// |PlatformView| +std::unique_ptr ShellTestPlatformViewMetal::CreateRenderingSurface(int64_t view_id) { if (GetSettings().enable_impeller) { return std::make_unique(this, [metal_context_->impeller_context() context]); } return std::make_unique(this, [metal_context_->context() mainContext], - MsaaSampleCount::kNone); + MsaaSampleCount::kNone, sksl_precompiler_); } // |PlatformView| diff --git a/shell/common/shell_test_platform_view_vulkan.cc b/shell/common/shell_test_platform_view_vulkan.cc index 38170118e2072..2ae1a935aa7df 100644 --- a/shell/common/shell_test_platform_view_vulkan.cc +++ b/shell/common/shell_test_platform_view_vulkan.cc @@ -9,6 +9,7 @@ #include "flutter/common/graphics/persistent_cache.h" #include "flutter/flutter_vma/flutter_skia_vma.h" #include "flutter/shell/common/context_options.h" +#include "flutter/shell/gpu/gpu_studio_vulkan.h" #include "flutter/vulkan/vulkan_skia_proc_table.h" #include "flutter/vulkan/vulkan_utilities.h" @@ -34,13 +35,15 @@ ShellTestPlatformViewVulkan::ShellTestPlatformViewVulkan( std::shared_ptr vsync_clock, CreateVsyncWaiter create_vsync_waiter, std::shared_ptr - shell_test_external_view_embedder) + shell_test_external_view_embedder, + bool support_thread_merging) : ShellTestPlatformView(delegate, task_runners), create_vsync_waiter_(std::move(create_vsync_waiter)), vsync_clock_(std::move(vsync_clock)), proc_table_(fml::MakeRefCounted(VULKAN_SO_PATH)), shell_test_external_view_embedder_( - std::move(shell_test_external_view_embedder)) {} + std::move(shell_test_external_view_embedder)), + support_thread_merging_(support_thread_merging) {} ShellTestPlatformViewVulkan::~ShellTestPlatformViewVulkan() = default; @@ -53,8 +56,20 @@ void ShellTestPlatformViewVulkan::SimulateVSync() { } // |PlatformView| -std::unique_ptr ShellTestPlatformViewVulkan::CreateRenderingSurface() { - return std::make_unique(proc_table_, +std::unique_ptr ShellTestPlatformViewVulkan::CreateRenderingStudio() { + if (!offscreen_context_) { + offscreen_context_ = std::make_shared(proc_table_); + } + return std::make_unique(offscreen_context_); +} + +// |PlatformView| +std::unique_ptr ShellTestPlatformViewVulkan::CreateRenderingSurface( + int64_t view_id) { + if (!offscreen_context_) { + offscreen_context_ = std::make_shared(proc_table_); + } + return std::make_unique(offscreen_context_, shell_test_external_view_embedder_); } @@ -64,6 +79,11 @@ ShellTestPlatformViewVulkan::CreateExternalViewEmbedder() { return shell_test_external_view_embedder_; } +// |PlatformView| +bool ShellTestPlatformViewVulkan::SupportsDynamicThreadMerging() { + return support_thread_merging_; +} + // |PlatformView| PointerDataDispatcherMaker ShellTestPlatformViewVulkan::GetDispatcherMaker() { return [](DefaultPointerDataDispatcher::Delegate& delegate) { @@ -75,14 +95,9 @@ PointerDataDispatcherMaker ShellTestPlatformViewVulkan::GetDispatcherMaker() { // shell_test. // We need to merge this functionality back into //vulkan. // https://github.com/flutter/flutter/issues/51132 -ShellTestPlatformViewVulkan::OffScreenSurface::OffScreenSurface( - fml::RefPtr vk, - std::shared_ptr - shell_test_external_view_embedder) - : valid_(false), - vk_(std::move(vk)), - shell_test_external_view_embedder_( - std::move(shell_test_external_view_embedder)) { +ShellTestPlatformViewVulkan::OffScreenContext::OffScreenContext( + fml::RefPtr vk) + : vk_(std::move(vk)) { if (!vk_ || !vk_->HasAcquiredMandatoryProcAddresses()) { FML_DLOG(ERROR) << "Proc table has not acquired mandatory proc addresses."; return; @@ -124,13 +139,12 @@ ShellTestPlatformViewVulkan::OffScreenSurface::OffScreenSurface( // Create the Skia GrContext. if (!CreateSkiaGrContext()) { FML_DLOG(ERROR) << "Could not create Skia context."; - return; } - - valid_ = true; } -bool ShellTestPlatformViewVulkan::OffScreenSurface::CreateSkiaGrContext() { +ShellTestPlatformViewVulkan::OffScreenContext::~OffScreenContext() {} + +bool ShellTestPlatformViewVulkan::OffScreenContext::CreateSkiaGrContext() { GrVkBackendContext backend_context; if (!CreateSkiaBackendContext(&backend_context)) { @@ -156,7 +170,7 @@ bool ShellTestPlatformViewVulkan::OffScreenSurface::CreateSkiaGrContext() { return true; } -bool ShellTestPlatformViewVulkan::OffScreenSurface::CreateSkiaBackendContext( +bool ShellTestPlatformViewVulkan::OffScreenContext::CreateSkiaBackendContext( GrVkBackendContext* context) { auto getProc = CreateSkiaGetProc(vk_); @@ -186,10 +200,18 @@ bool ShellTestPlatformViewVulkan::OffScreenSurface::CreateSkiaBackendContext( return true; } +ShellTestPlatformViewVulkan::OffScreenSurface::OffScreenSurface( + const std::shared_ptr& offscreen_context, + std::shared_ptr + shell_test_external_view_embedder) + : shell_test_external_view_embedder_( + std::move(shell_test_external_view_embedder)), + offscreen_context_(offscreen_context) {} + ShellTestPlatformViewVulkan::OffScreenSurface::~OffScreenSurface() {} bool ShellTestPlatformViewVulkan::OffScreenSurface::IsValid() { - return valid_; + return GetContext(); } std::unique_ptr @@ -197,7 +219,7 @@ ShellTestPlatformViewVulkan::OffScreenSurface::AcquireFrame( const SkISize& size) { auto image_info = SkImageInfo::Make(size, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kOpaque_SkAlphaType); - auto surface = SkSurfaces::RenderTarget(context_.get(), skgpu::Budgeted::kNo, + auto surface = SkSurfaces::RenderTarget(GetContext(), skgpu::Budgeted::kNo, image_info, 0, nullptr); SurfaceFrame::SubmitCallback callback = [](const SurfaceFrame&, DlCanvas* canvas) -> bool { @@ -214,7 +236,7 @@ ShellTestPlatformViewVulkan::OffScreenSurface::AcquireFrame( } GrDirectContext* ShellTestPlatformViewVulkan::OffScreenSurface::GetContext() { - return context_.get(); + return offscreen_context_->GetContext().get(); } SkMatrix ShellTestPlatformViewVulkan::OffScreenSurface::GetRootTransformation() diff --git a/shell/common/shell_test_platform_view_vulkan.h b/shell/common/shell_test_platform_view_vulkan.h index 718f7fe6dec06..97b54c47d5e36 100644 --- a/shell/common/shell_test_platform_view_vulkan.h +++ b/shell/common/shell_test_platform_view_vulkan.h @@ -22,16 +22,63 @@ class ShellTestPlatformViewVulkan : public ShellTestPlatformView { std::shared_ptr vsync_clock, CreateVsyncWaiter create_vsync_waiter, std::shared_ptr - shell_test_external_view_embedder); + shell_test_external_view_embedder, + bool support_thread_merging); ~ShellTestPlatformViewVulkan() override; void SimulateVSync() override; private: + class OffScreenContext { + public: + OffScreenContext(fml::RefPtr vk); + + ~OffScreenContext(); + + sk_sp GetContext() { return context_; } + + private: + fml::RefPtr vk_; + std::unique_ptr application_; + std::unique_ptr logical_device_; + sk_sp memory_allocator_; + sk_sp context_; + + bool CreateSkiaGrContext(); + bool CreateSkiaBackendContext(GrVkBackendContext* context); + + FML_DISALLOW_COPY_AND_ASSIGN(OffScreenContext); + }; + + class OffScreenStudio : public flutter::Studio { + public: + //------------------------------------------------------------------------------ + /// @brief Create a GPUStudioVulkan while letting it reuse an existing + /// GrDirectContext. + /// + OffScreenStudio(const std::shared_ptr& offscreen_context) + : offscreen_context_(offscreen_context) {} + + ~OffScreenStudio() override = default; + + // |Studio| + bool IsValid() override { return GetContext(); } + + // |Studio| + GrDirectContext* GetContext() override { + return offscreen_context_->GetContext().get(); + } + + private: + std::shared_ptr offscreen_context_; + + FML_DISALLOW_COPY_AND_ASSIGN(OffScreenStudio); + }; + class OffScreenSurface : public flutter::Surface { public: - OffScreenSurface(fml::RefPtr vk, + OffScreenSurface(const std::shared_ptr& offscreen_context, std::shared_ptr shell_test_external_view_embedder); @@ -43,23 +90,15 @@ class ShellTestPlatformViewVulkan : public ShellTestPlatformView { // |Surface| std::unique_ptr AcquireFrame(const SkISize& size) override; - SkMatrix GetRootTransformation() const override; - // |Surface| - GrDirectContext* GetContext() override; + SkMatrix GetRootTransformation() const override; private: - bool valid_; - fml::RefPtr vk_; + GrDirectContext* GetContext(); + std::shared_ptr shell_test_external_view_embedder_; - std::unique_ptr application_; - std::unique_ptr logical_device_; - sk_sp memory_allocator_; - sk_sp context_; - - bool CreateSkiaGrContext(); - bool CreateSkiaBackendContext(GrVkBackendContext* context); + std::shared_ptr offscreen_context_; FML_DISALLOW_COPY_AND_ASSIGN(OffScreenSurface); }; @@ -73,12 +112,22 @@ class ShellTestPlatformViewVulkan : public ShellTestPlatformView { std::shared_ptr shell_test_external_view_embedder_; + std::shared_ptr offscreen_context_; + + bool support_thread_merging_; + + // |PlatformView| + std::unique_ptr CreateRenderingStudio() override; + // |PlatformView| - std::unique_ptr CreateRenderingSurface() override; + std::unique_ptr CreateRenderingSurface(int64_t view_id) override; // |PlatformView| std::shared_ptr CreateExternalViewEmbedder() override; + // |PlatformView| + bool SupportsDynamicThreadMerging() override; + // |PlatformView| std::unique_ptr CreateVSyncWaiter() override; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 2edc3b173d82b..42b4c8ec5ee7b 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -57,12 +57,14 @@ namespace flutter { namespace testing { +constexpr int64_t kDefaultViewId = 0ll; + using ::testing::_; using ::testing::Return; namespace { class MockPlatformViewDelegate : public PlatformView::Delegate { - MOCK_METHOD1(OnPlatformViewCreated, void(std::unique_ptr surface)); + MOCK_METHOD0(OnPlatformViewCreated, void()); MOCK_METHOD0(OnPlatformViewDestroyed, void()); @@ -71,8 +73,8 @@ class MockPlatformViewDelegate : public PlatformView::Delegate { MOCK_METHOD1(OnPlatformViewSetNextFrameCallback, void(const fml::closure& closure)); - MOCK_METHOD1(OnPlatformViewSetViewportMetrics, - void(const ViewportMetrics& metrics)); + MOCK_METHOD2(OnPlatformViewSetViewportMetrics, + void(int64_t view_id, const ViewportMetrics& metrics)); MOCK_METHOD1(OnPlatformViewDispatchPlatformMessage, void(std::unique_ptr message)); @@ -117,15 +119,10 @@ class MockPlatformViewDelegate : public PlatformView::Delegate { AssetResolver::AssetResolverType type)); }; -class MockSurface : public Surface { +class MockStudio : public Studio { public: MOCK_METHOD0(IsValid, bool()); - MOCK_METHOD1(AcquireFrame, - std::unique_ptr(const SkISize& size)); - - MOCK_CONST_METHOD0(GetRootTransformation, SkMatrix()); - MOCK_METHOD0(GetContext, GrDirectContext*()); MOCK_METHOD0(MakeRenderContextCurrent, std::unique_ptr()); @@ -133,12 +130,25 @@ class MockSurface : public Surface { MOCK_METHOD0(ClearRenderContext, bool()); }; +class MockSurface : public Surface { + public: + MOCK_METHOD0(IsValid, bool()); + + MOCK_METHOD0(GetContext, GrDirectContext*()); + + MOCK_METHOD1(AcquireFrame, + std::unique_ptr(const SkISize& size)); + + MOCK_CONST_METHOD0(GetRootTransformation, SkMatrix()); +}; + class MockPlatformView : public PlatformView { public: MockPlatformView(MockPlatformViewDelegate& delegate, const TaskRunners& task_runners) : PlatformView(delegate, task_runners) {} - MOCK_METHOD0(CreateRenderingSurface, std::unique_ptr()); + MOCK_METHOD0(CreateRenderingStudio, std::unique_ptr()); + MOCK_METHOD1(CreateRenderingSurface, std::unique_ptr(int64_t)); MOCK_CONST_METHOD0(GetPlatformMessageHandler, std::shared_ptr()); }; @@ -147,7 +157,8 @@ class TestPlatformView : public PlatformView { public: TestPlatformView(Shell& shell, const TaskRunners& task_runners) : PlatformView(shell, task_runners) {} - MOCK_METHOD0(CreateRenderingSurface, std::unique_ptr()); + MOCK_METHOD0(CreateRenderingStudio, std::unique_ptr()); + MOCK_METHOD1(CreateRenderingSurface, std::unique_ptr(int64_t)); }; class MockPlatformMessageHandler : public PlatformMessageHandler { @@ -265,7 +276,7 @@ static bool RasterizerHasLayerTree(Shell* shell) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetRasterTaskRunner(), [shell, &latch, &has_layer_tree]() { - has_layer_tree = shell->GetRasterizer()->GetLastLayerTree() != nullptr; + has_layer_tree = shell->GetRasterizer()->HasLastLayerTree(); latch.Signal(); }); latch.Wait(); @@ -330,7 +341,7 @@ TEST_F(ShellTest, InitializeWithInvalidThreads) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); Settings settings = CreateSettingsForFixture(); TaskRunners task_runners("test", nullptr, nullptr, nullptr, nullptr); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_FALSE(shell); ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } @@ -348,7 +359,7 @@ TEST_F(ShellTest, InitializeWithDifferentThreads) { thread_host.raster_thread->GetTaskRunner(), thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner()); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(ValidateShell(shell.get())); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); DestroyShell(std::move(shell), task_runners); @@ -363,7 +374,7 @@ TEST_F(ShellTest, InitializeWithSingleThread) { auto task_runner = thread_host.platform_thread->GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); DestroyShell(std::move(shell), task_runners); @@ -377,7 +388,7 @@ TEST_F(ShellTest, InitializeWithSingleThreadWhichIsTheCallingThread) { auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(ValidateShell(shell.get())); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); DestroyShell(std::move(shell), task_runners); @@ -409,9 +420,11 @@ TEST_F(ShellTest, return static_cast>( std::make_unique(task_runners)); }, - ShellTestPlatformView::BackendType::kDefaultBackend, nullptr, + ShellTestPlatformView::BackendType::kDefaultBackend, + /*external_view_embedder=*/nullptr, shell.GetConcurrentWorkerTaskRunner(), - shell.GetIsGpuDisabledSyncSwitch()); + shell.GetIsGpuDisabledSyncSwitch(), + /*support_thread_merging=*/false); }, [](Shell& shell) { return std::make_unique(shell); }); ASSERT_TRUE(ValidateShell(shell.get())); @@ -428,9 +441,11 @@ TEST_F(ShellTest, InitializeWithDisabledGpu) { auto task_runner = thread_host.platform_thread->GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - auto shell = CreateShell(settings, task_runners, /*simulate_vsync=*/false, - /*shell_test_external_view_embedder=*/nullptr, - /*is_gpu_disabled=*/true); + auto shell = CreateShell({ + .settings = settings, + .task_runners = &task_runners, + .is_gpu_disabled = true, + }); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); @@ -456,7 +471,7 @@ TEST_F(ShellTest, InitializeWithGPUAndPlatformThreadsTheSame) { thread_host.ui_thread->GetTaskRunner(), // ui thread_host.io_thread->GetTaskRunner() // io ); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); DestroyShell(std::move(shell), task_runners); @@ -793,9 +808,11 @@ TEST_F(ShellTest, ExternalEmbedderNoThreadMerger) { end_frame_latch.Signal(); }; auto external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kResubmitFrame, false); - auto shell = CreateShell(settings, GetTaskRunnersForFixture(), false, - external_view_embedder); + end_frame_callback, PostPrerollResult::kResubmitFrame); + auto shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -850,9 +867,11 @@ TEST_F(ShellTest, PushBackdropFilterToVisitedPlatformViews) { }; external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kResubmitFrame, false); - auto shell = CreateShell(settings, GetTaskRunnersForFixture(), false, - external_view_embedder); + end_frame_callback, PostPrerollResult::kResubmitFrame); + auto shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -919,9 +938,12 @@ TEST_F(ShellTest, end_frame_latch.Signal(); }; auto external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kResubmitFrame, true); - auto shell = CreateShell(settings, GetTaskRunnersForFixture(), false, - external_view_embedder); + end_frame_callback, PostPrerollResult::kResubmitFrame); + auto shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + .support_thread_merging = true, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -959,10 +981,13 @@ TEST_F(ShellTest, OnPlatformViewDestroyDisablesThreadMerger) { raster_thread_merger = std::move(thread_merger); }; auto external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kSuccess, true); + end_frame_callback, PostPrerollResult::kSuccess); - auto shell = CreateShell(settings, GetTaskRunnersForFixture(), false, - external_view_embedder); + auto shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + .support_thread_merging = true, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1019,12 +1044,15 @@ TEST_F(ShellTest, OnPlatformViewDestroyAfterMergingThreads) { end_frame_latch.Signal(); }; external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kSuccess, true); + end_frame_callback, PostPrerollResult::kSuccess); // Set resubmit once to trigger thread merging. external_view_embedder->UpdatePostPrerollResult( PostPrerollResult::kResubmitFrame); - auto shell = CreateShell(settings, GetTaskRunnersForFixture(), false, - external_view_embedder); + auto shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + .support_thread_merging = true, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1085,10 +1113,13 @@ TEST_F(ShellTest, OnPlatformViewDestroyWhenThreadsAreMerging) { // can later check if the rasterizer is tore down using // |ValidateDestroyPlatformView| auto external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kSuccess, true); + end_frame_callback, PostPrerollResult::kSuccess); - auto shell = CreateShell(settings, GetTaskRunnersForFixture(), false, - external_view_embedder); + auto shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + .support_thread_merging = true, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1149,9 +1180,12 @@ TEST_F(ShellTest, end_frame_latch.Signal(); }; auto external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kSuccess, true); - auto shell = CreateShell(settings, GetTaskRunnersForFixture(), false, - external_view_embedder); + end_frame_callback, PostPrerollResult::kSuccess); + auto shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + .support_thread_merging = true, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1189,8 +1223,7 @@ TEST_F(ShellTest, TEST_F(ShellTest, OnPlatformViewDestroyWithoutRasterThreadMerger) { auto settings = CreateSettingsForFixture(); - auto shell = - CreateShell(settings, GetTaskRunnersForFixture(), false, nullptr); + auto shell = CreateShell(settings); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1239,7 +1272,7 @@ TEST_F(ShellTest, OnPlatformViewDestroyWithStaticThreadMerging) { end_frame_latch.Signal(); }; auto external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kSuccess, true); + end_frame_callback, PostPrerollResult::kSuccess); ThreadHost thread_host( "io.flutter.test." + GetCurrentTestName() + ".", ThreadHost::Type::Platform | ThreadHost::Type::IO | ThreadHost::Type::UI); @@ -1250,8 +1283,12 @@ TEST_F(ShellTest, OnPlatformViewDestroyWithStaticThreadMerging) { thread_host.ui_thread->GetTaskRunner(), // ui thread_host.io_thread->GetTaskRunner() // io ); - auto shell = - CreateShell(settings, task_runners, false, external_view_embedder); + auto shell = CreateShell({ + .settings = settings, + .task_runners = &task_runners, + .shell_test_external_view_embedder = external_view_embedder, + .support_thread_merging = true, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1290,9 +1327,12 @@ TEST_F(ShellTest, GetUsedThisFrameShouldBeSetBeforeEndFrame) { end_frame_latch.Signal(); }; external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kSuccess, true); - auto shell = CreateShell(settings, GetTaskRunnersForFixture(), false, - external_view_embedder); + end_frame_callback, PostPrerollResult::kSuccess); + auto shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + .support_thread_merging = true, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1340,10 +1380,13 @@ TEST_F(ShellTest, DISABLED_SkipAndSubmitFrame) { end_frame_latch.Signal(); }; external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kSkipAndRetryFrame, true); + end_frame_callback, PostPrerollResult::kSkipAndRetryFrame); - auto shell = CreateShell(settings, GetTaskRunnersForFixture(), false, - external_view_embedder); + auto shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + .support_thread_merging = true, + }); PlatformViewNotifyCreated(shell.get()); @@ -1507,7 +1550,7 @@ TEST_F(ShellTest, WaitForFirstFrameInlined) { auto task_runner = CreateNewThread(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1553,30 +1596,32 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { Shell::CreateCallback platform_view_create_callback = [task_runners, main_context](flutter::Shell& shell) { auto result = std::make_unique(shell, task_runners); - ON_CALL(*result, CreateRenderingSurface()) - .WillByDefault(::testing::Invoke([main_context] { + ON_CALL(*result, CreateRenderingSurface(0ll)) + .WillByDefault(::testing::Invoke([] { auto surface = std::make_unique(); - ON_CALL(*surface, GetContext()) - .WillByDefault(Return(main_context.get())); ON_CALL(*surface, IsValid()).WillByDefault(Return(true)); - ON_CALL(*surface, MakeRenderContextCurrent()) + return surface; + })); + ON_CALL(*result, CreateRenderingStudio()) + .WillByDefault(::testing::Invoke([main_context] { + auto studio = std::make_unique(); + ON_CALL(*studio, GetContext()) + .WillByDefault(Return(main_context.get())); + ON_CALL(*studio, IsValid()).WillByDefault(Return(true)); + ON_CALL(*studio, MakeRenderContextCurrent()) .WillByDefault(::testing::Invoke([] { return std::make_unique(true); })); - return surface; + return studio; })); return result; }; - auto shell = CreateShell( - /*settings=*/settings, - /*task_runners=*/task_runners, - /*simulate_vsync=*/false, - /*shell_test_external_view_embedder=*/nullptr, - /*is_gpu_disabled=*/false, - /*rendering_backend=*/ - ShellTestPlatformView::BackendType::kDefaultBackend, - /*platform_view_create_callback=*/platform_view_create_callback); + auto shell = CreateShell({ + .settings = settings, + .task_runners = &task_runners, + .platform_view_create_callback = platform_view_create_callback, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1586,7 +1631,8 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { RunEngine(shell.get(), std::move(configuration)); PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 100, 100, 22, 0}); + shell->GetPlatformView()->SetViewportMetrics(kDefaultViewId, + {1.0, 100, 100, 22, 0}); }); // first cache bytes @@ -1615,7 +1661,7 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { PostSync(second_shell->GetTaskRunners().GetPlatformTaskRunner(), [&second_shell]() { second_shell->GetPlatformView()->SetViewportMetrics( - {1.0, 100, 100, 22, 0}); + kDefaultViewId, {1.0, 100, 100, 22, 0}); }); // first cache bytes + second cache bytes EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), @@ -1624,7 +1670,7 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { PostSync(second_shell->GetTaskRunners().GetPlatformTaskRunner(), [&second_shell]() { second_shell->GetPlatformView()->SetViewportMetrics( - {1.0, 100, 300, 22, 0}); + kDefaultViewId, {1.0, 100, 300, 22, 0}); }); // first cache bytes + second cache bytes EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), @@ -1635,7 +1681,7 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { PostSync(third_shell->GetTaskRunners().GetPlatformTaskRunner(), [&third_shell]() { third_shell->GetPlatformView()->SetViewportMetrics( - {1.0, 400, 100, 22, 0}); + kDefaultViewId, {1.0, 400, 100, 22, 0}); }); // first cache bytes + second cache bytes + third cache bytes EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), @@ -1644,7 +1690,7 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { PostSync(third_shell->GetTaskRunners().GetPlatformTaskRunner(), [&third_shell]() { third_shell->GetPlatformView()->SetViewportMetrics( - {1.0, 800, 100, 22, 0}); + kDefaultViewId, {1.0, 800, 100, 22, 0}); }); // max bytes threshold EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), @@ -1657,7 +1703,7 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { PostSync(second_shell->GetTaskRunners().GetPlatformTaskRunner(), [&second_shell]() { second_shell->GetPlatformView()->SetViewportMetrics( - {1.0, 100, 100, 22, 0}); + kDefaultViewId, {1.0, 100, 100, 22, 0}); }); // first cache bytes + second cache bytes EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), @@ -1672,7 +1718,7 @@ TEST_F(ShellTest, SetResourceCacheSize) { auto task_runner = CreateNewThread(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1701,7 +1747,8 @@ TEST_F(ShellTest, SetResourceCacheSize) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200, 22, 0}); + shell->GetPlatformView()->SetViewportMetrics(kDefaultViewId, + {1.0, 400, 200, 22, 0}); }); PumpOneFrame(shell.get()); @@ -1721,7 +1768,8 @@ TEST_F(ShellTest, SetResourceCacheSize) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 800, 400, 22, 0}); + shell->GetPlatformView()->SetViewportMetrics(kDefaultViewId, + {1.0, 800, 400, 22, 0}); }); PumpOneFrame(shell.get()); @@ -1734,11 +1782,12 @@ TEST_F(ShellTest, SetResourceCacheSizeEarly) { auto task_runner = CreateNewThread(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200, 22, 0}); + shell->GetPlatformView()->SetViewportMetrics(kDefaultViewId, + {1.0, 400, 200, 22, 0}); }); PumpOneFrame(shell.get()); @@ -1761,11 +1810,12 @@ TEST_F(ShellTest, SetResourceCacheSizeNotifiesDart) { auto task_runner = CreateNewThread(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200, 22, 0}); + shell->GetPlatformView()->SetViewportMetrics(kDefaultViewId, + {1.0, 400, 200, 22, 0}); }); PumpOneFrame(shell.get()); @@ -1800,7 +1850,7 @@ TEST_F(ShellTest, CanCreateImagefromDecompressedBytes) { TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -1869,7 +1919,7 @@ TEST_F(ShellTest, TextureFrameMarkedAvailableAndUnregister) { auto task_runner = CreateNewThread(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(ValidateShell(shell.get())); PlatformViewNotifyCreated(shell.get()); @@ -1923,7 +1973,7 @@ TEST_F(ShellTest, IsolateCanAccessPersistentIsolateData) { message_latch.Signal(); })); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -1950,7 +2000,7 @@ TEST_F(ShellTest, CanScheduleFrameFromPlatform) { CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { check_latch.Signal(); })); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -1984,7 +2034,7 @@ TEST_F(ShellTest, SecondaryVsyncCallbackShouldBeCalledAfterVsyncCallback) { is_on_begin_frame_called = true; count_down_latch.CountDown(); })); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -2334,7 +2384,7 @@ TEST_F(ShellTest, RasterizerScreenshot) { auto task_runner = CreateNewThread(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(ValidateShell(shell.get())); PlatformViewNotifyCreated(shell.get()); @@ -2364,7 +2414,7 @@ TEST_F(ShellTest, RasterizerMakeRasterSnapshot) { auto task_runner = CreateNewThread(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); ASSERT_TRUE(ValidateShell(shell.get())); PlatformViewNotifyCreated(shell.get()); @@ -2617,9 +2667,11 @@ TEST_F(ShellTest, DISABLED_DiscardLayerTreeOnResize) { end_frame_latch.Signal(); }; auto external_view_embedder = std::make_shared( - std::move(end_frame_callback), PostPrerollResult::kSuccess, false); - std::unique_ptr shell = CreateShell( - settings, GetTaskRunnersForFixture(), false, external_view_embedder); + std::move(end_frame_callback), PostPrerollResult::kSuccess); + std::unique_ptr shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -2628,6 +2680,7 @@ TEST_F(ShellTest, DISABLED_DiscardLayerTreeOnResize) { shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell, &expected_size]() { shell->GetPlatformView()->SetViewportMetrics( + kDefaultViewId, {1.0, static_cast(expected_size.width()), static_cast(expected_size.height()), 22, 0}); }); @@ -2689,10 +2742,12 @@ TEST_F(ShellTest, DISABLED_DiscardResubmittedLayerTreeOnResize) { }; external_view_embedder = std::make_shared( - std::move(end_frame_callback), PostPrerollResult::kResubmitFrame, true); + std::move(end_frame_callback), PostPrerollResult::kResubmitFrame); - std::unique_ptr shell = CreateShell( - settings, GetTaskRunnersForFixture(), false, external_view_embedder); + std::unique_ptr shell = CreateShell({ + .settings = settings, + .shell_test_external_view_embedder = external_view_embedder, + }); // Create the surface needed by rasterizer PlatformViewNotifyCreated(shell.get()); @@ -2701,8 +2756,8 @@ TEST_F(ShellTest, DISABLED_DiscardResubmittedLayerTreeOnResize) { shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell, &origin_size]() { shell->GetPlatformView()->SetViewportMetrics( - {1.0, static_cast(origin_size.width()), - static_cast(origin_size.height()), 22, 0}); + kDefaultViewId, {1.0, static_cast(origin_size.width()), + static_cast(origin_size.height()), 22, 0}); }); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -2720,8 +2775,8 @@ TEST_F(ShellTest, DISABLED_DiscardResubmittedLayerTreeOnResize) { shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell, &new_size, &resize_latch]() { shell->GetPlatformView()->SetViewportMetrics( - {1.0, static_cast(new_size.width()), - static_cast(new_size.height()), 22, 0}); + kDefaultViewId, {1.0, static_cast(new_size.width()), + static_cast(new_size.height()), 22, 0}); resize_latch.Signal(); }); @@ -2776,7 +2831,7 @@ TEST_F(ShellTest, IgnoresInvalidMetrics) { AddNativeCallback("ReportMetrics", CREATE_NATIVE_ENTRY(native_report_device_pixel_ratio)); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); auto configuration = RunConfiguration::InferFromSettings(settings); configuration.SetEntrypoint("reportMetrics"); @@ -2784,14 +2839,17 @@ TEST_F(ShellTest, IgnoresInvalidMetrics) { RunEngine(shell.get(), std::move(configuration)); task_runner->PostTask([&]() { - shell->GetPlatformView()->SetViewportMetrics({0.0, 400, 200, 22, 0}); + shell->GetPlatformView()->SetViewportMetrics(kDefaultViewId, + {0.0, 400, 200, 22, 0}); task_runner->PostTask([&]() { - shell->GetPlatformView()->SetViewportMetrics({0.8, 0.0, 200, 22, 0}); + shell->GetPlatformView()->SetViewportMetrics(kDefaultViewId, + {0.8, 0.0, 200, 22, 0}); task_runner->PostTask([&]() { - shell->GetPlatformView()->SetViewportMetrics({0.8, 400, 0.0, 22, 0}); + shell->GetPlatformView()->SetViewportMetrics(kDefaultViewId, + {0.8, 400, 0.0, 22, 0}); task_runner->PostTask([&]() { shell->GetPlatformView()->SetViewportMetrics( - {0.8, 400, 200.0, 22, 0}); + kDefaultViewId, {0.8, 400, 200.0, 22, 0}); }); }); }); @@ -2803,7 +2861,8 @@ TEST_F(ShellTest, IgnoresInvalidMetrics) { latch.Reset(); task_runner->PostTask([&]() { - shell->GetPlatformView()->SetViewportMetrics({1.2, 600, 300, 22, 0}); + shell->GetPlatformView()->SetViewportMetrics(kDefaultViewId, + {1.2, 600, 300, 22, 0}); }); latch.Wait(); ASSERT_EQ(last_device_pixel_ratio, 1.2); @@ -3063,9 +3122,12 @@ TEST_F(ShellTest, Spawn) { [&platform_view_delegate](Shell& shell) { auto result = std::make_unique( platform_view_delegate, shell.GetTaskRunners()); - ON_CALL(*result, CreateRenderingSurface()) + ON_CALL(*result, CreateRenderingSurface(0ll)) .WillByDefault(::testing::Invoke( [] { return std::make_unique(); })); + ON_CALL(*result, CreateRenderingStudio()) + .WillByDefault(::testing::Invoke( + [] { return std::make_unique(); })); return result; }, [](Shell& shell) { return std::make_unique(shell); }); @@ -3175,9 +3237,12 @@ TEST_F(ShellTest, SpawnWithDartEntrypointArgs) { [&platform_view_delegate](Shell& shell) { auto result = std::make_unique( platform_view_delegate, shell.GetTaskRunners()); - ON_CALL(*result, CreateRenderingSurface()) + ON_CALL(*result, CreateRenderingSurface(0ll)) .WillByDefault(::testing::Invoke( [] { return std::make_unique(); })); + ON_CALL(*result, CreateRenderingStudio()) + .WillByDefault(::testing::Invoke( + [] { return std::make_unique(); })); return result; }, [](Shell& shell) { return std::make_unique(shell); }); @@ -3238,9 +3303,12 @@ TEST_F(ShellTest, IOManagerIsSharedBetweenParentAndSpawnedShell) { [&platform_view_delegate](Shell& shell) { auto result = std::make_unique( platform_view_delegate, shell.GetTaskRunners()); - ON_CALL(*result, CreateRenderingSurface()) + ON_CALL(*result, CreateRenderingSurface(0ll)) .WillByDefault(::testing::Invoke( [] { return std::make_unique(); })); + ON_CALL(*result, CreateRenderingStudio()) + .WillByDefault(::testing::Invoke( + [] { return std::make_unique(); })); return result; }, [](Shell& shell) { return std::make_unique(shell); }); @@ -3292,9 +3360,12 @@ TEST_F(ShellTest, IOManagerInSpawnedShellIsNotNullAfterParentShellDestroyed) { [&platform_view_delegate](Shell& shell) { auto result = std::make_unique( platform_view_delegate, shell.GetTaskRunners()); - ON_CALL(*result, CreateRenderingSurface()) + ON_CALL(*result, CreateRenderingSurface(0ll)) .WillByDefault(::testing::Invoke( [] { return std::make_unique(); })); + ON_CALL(*result, CreateRenderingStudio()) + .WillByDefault(::testing::Invoke( + [] { return std::make_unique(); })); return result; }, [](Shell& shell) { return std::make_unique(shell); }); @@ -3340,9 +3411,12 @@ TEST_F(ShellTest, ImageGeneratorRegistryNotNullAfterParentShellDestroyed) { [&platform_view_delegate](Shell& shell) { auto result = std::make_unique( platform_view_delegate, shell.GetTaskRunners()); - ON_CALL(*result, CreateRenderingSurface()) + ON_CALL(*result, CreateRenderingSurface(0ll)) .WillByDefault(::testing::Invoke( [] { return std::make_unique(); })); + ON_CALL(*result, CreateRenderingStudio()) + .WillByDefault(::testing::Invoke( + [] { return std::make_unique(); })); return result; }, [](Shell& shell) { return std::make_unique(shell); }); @@ -3377,7 +3451,7 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeReplaces) { auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); @@ -3422,7 +3496,7 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeAppends) { auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); @@ -3463,7 +3537,7 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeNull) { auto task_runner = thread_host.platform_thread->GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); @@ -3500,7 +3574,7 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeDoesNotReplaceMismatchType) { auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); @@ -3545,14 +3619,10 @@ TEST_F(ShellTest, CanCreateShellsWithGLBackend) { GTEST_SKIP(); #endif // !SHELL_ENABLE_GL auto settings = CreateSettingsForFixture(); - std::unique_ptr shell = - CreateShell(settings, // - GetTaskRunnersForFixture(), // - false, // - nullptr, // - false, // - ShellTestPlatformView::BackendType::kGLBackend // - ); + std::unique_ptr shell = CreateShell({ + .settings = settings, + .rendering_backend = ShellTestPlatformView::BackendType::kGLBackend, + }); ASSERT_NE(shell, nullptr); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -3569,14 +3639,10 @@ TEST_F(ShellTest, CanCreateShellsWithVulkanBackend) { GTEST_SKIP(); #endif // !SHELL_ENABLE_VULKAN auto settings = CreateSettingsForFixture(); - std::unique_ptr shell = - CreateShell(settings, // - GetTaskRunnersForFixture(), // - false, // - nullptr, // - false, // - ShellTestPlatformView::BackendType::kVulkanBackend // - ); + std::unique_ptr shell = CreateShell({ + .settings = settings, + .rendering_backend = ShellTestPlatformView::BackendType::kVulkanBackend, + }); ASSERT_NE(shell, nullptr); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -3593,14 +3659,10 @@ TEST_F(ShellTest, CanCreateShellsWithMetalBackend) { GTEST_SKIP(); #endif // !SHELL_ENABLE_METAL auto settings = CreateSettingsForFixture(); - std::unique_ptr shell = - CreateShell(settings, // - GetTaskRunnersForFixture(), // - false, // - nullptr, // - false, // - ShellTestPlatformView::BackendType::kMetalBackend // - ); + std::unique_ptr shell = CreateShell({ + .settings = settings, + .rendering_backend = ShellTestPlatformView::BackendType::kMetalBackend, + }); ASSERT_NE(shell, nullptr); ASSERT_TRUE(shell->IsSetup()); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -3764,15 +3826,11 @@ TEST_F(ShellTest, UsesPlatformMessageHandler) { .WillOnce(Return(platform_message_handler)); return result; }; - auto shell = CreateShell( - /*settings=*/settings, - /*task_runners=*/task_runners, - /*simulate_vsync=*/false, - /*shell_test_external_view_embedder=*/nullptr, - /*is_gpu_disabled=*/false, - /*rendering_backend=*/ - ShellTestPlatformView::BackendType::kDefaultBackend, - /*platform_view_create_callback=*/platform_view_create_callback); + auto shell = CreateShell({ + .settings = settings, + .task_runners = &task_runners, + .platform_view_create_callback = platform_view_create_callback, + }); EXPECT_EQ(platform_message_handler, shell->GetPlatformMessageHandler()); PostSync(task_runners.GetUITaskRunner(), [&shell]() { @@ -3838,9 +3896,12 @@ TEST_F(ShellTest, SpawnWorksWithOnError) { auto result = std::make_unique<::testing::NiceMock>( platform_view_delegate, shell.GetTaskRunners()); - ON_CALL(*result, CreateRenderingSurface()) + ON_CALL(*result, CreateRenderingSurface(0ll)) + .WillByDefault(::testing::Invoke( + [] { return std::make_unique(); })); + ON_CALL(*result, CreateRenderingStudio()) .WillByDefault(::testing::Invoke([] { - return std::make_unique<::testing::NiceMock>(); + return std::make_unique<::testing::NiceMock>(); })); return result; }, @@ -3864,7 +3925,7 @@ TEST_F(ShellTest, ImmutableBufferLoadsAssetOnBackgroundThread) { auto task_runner = CreateNewThread(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - std::unique_ptr shell = CreateShell(settings, task_runners); + std::unique_ptr shell = CreateShell(settings, &task_runners); fml::CountDownLatch latch(1); AddNativeCallback("NotifyNative", @@ -3898,14 +3959,10 @@ TEST_F(ShellTest, PictureToImageSync) { GTEST_SKIP(); #endif // !SHELL_ENABLE_GL auto settings = CreateSettingsForFixture(); - std::unique_ptr shell = - CreateShell(settings, // - GetTaskRunnersForFixture(), // - false, // - nullptr, // - false, // - ShellTestPlatformView::BackendType::kGLBackend // - ); + std::unique_ptr shell = CreateShell({ + .settings = settings, + .rendering_backend = ShellTestPlatformView::BackendType::kGLBackend, + }); AddNativeCallback("NativeOnBeforeToImageSync", CREATE_NATIVE_ENTRY([&](auto args) { @@ -3941,14 +3998,10 @@ TEST_F(ShellTest, PictureToImageSyncImpellerNoSurface) { #endif // !SHELL_ENABLE_METAL auto settings = CreateSettingsForFixture(); settings.enable_impeller = true; - std::unique_ptr shell = - CreateShell(settings, // - GetTaskRunnersForFixture(), // - false, // - nullptr, // - false, // - ShellTestPlatformView::BackendType::kMetalBackend // - ); + std::unique_ptr shell = CreateShell({ + .settings = settings, + .rendering_backend = ShellTestPlatformView::BackendType::kMetalBackend, + }); AddNativeCallback("NativeOnBeforeToImageSync", CREATE_NATIVE_ENTRY([&](auto args) { @@ -3993,14 +4046,11 @@ TEST_F(ShellTest, PictureToImageSyncWithTrampledContext) { task_runner); auto settings = CreateSettingsForFixture(); - std::unique_ptr shell = - CreateShell(settings, // - task_runners, // - false, // - nullptr, // - false, // - ShellTestPlatformView::BackendType::kGLBackend // - ); + std::unique_ptr shell = CreateShell({ + .settings = settings, + .task_runners = &task_runners, + .rendering_backend = ShellTestPlatformView::BackendType::kGLBackend, + }); AddNativeCallback( "NativeOnBeforeToImageSync", CREATE_NATIVE_ENTRY([&](auto args) { @@ -4035,8 +4085,7 @@ TEST_F(ShellTest, PictureToImageSyncWithTrampledContext) { TEST_F(ShellTest, PluginUtilitiesCallbackHandleErrorHandling) { auto settings = CreateSettingsForFixture(); - std::unique_ptr shell = - CreateShell(settings, GetTaskRunnersForFixture()); + std::unique_ptr shell = CreateShell(settings); fml::AutoResetWaitableEvent latch; bool test_passed; @@ -4074,7 +4123,7 @@ TEST_F(ShellTest, NotifyIdleRejectsPastAndNearFuture) { thread_host.raster_thread->GetTaskRunner(), thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner()); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); @@ -4119,7 +4168,7 @@ TEST_F(ShellTest, NotifyIdleNotCalledInLatencyMode) { thread_host.raster_thread->GetTaskRunner(), thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner()); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); @@ -4162,7 +4211,7 @@ TEST_F(ShellTest, NotifyDestroyed) { thread_host.raster_thread->GetTaskRunner(), thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner()); - auto shell = CreateShell(settings, task_runners); + auto shell = CreateShell(settings, &task_runners); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); diff --git a/shell/common/snapshot_controller.h b/shell/common/snapshot_controller.h index c402c3ec709fa..e8a6408160b7d 100644 --- a/shell/common/snapshot_controller.h +++ b/shell/common/snapshot_controller.h @@ -7,6 +7,7 @@ #include "flutter/common/settings.h" #include "flutter/display_list/image/dl_image.h" +#include "flutter/flow/studio.h" #include "flutter/flow/surface.h" #include "flutter/fml/synchronization/sync_switch.h" #include "flutter/lib/ui/snapshot_delegate.h" @@ -23,7 +24,7 @@ class SnapshotController { class Delegate { public: virtual ~Delegate() = default; - virtual const std::unique_ptr& GetSurface() const = 0; + virtual Studio* GetStudio() const = 0; virtual std::shared_ptr GetAiksContext() const = 0; virtual const std::unique_ptr& GetSnapshotSurfaceProducer() const = 0; diff --git a/shell/common/snapshot_controller_skia.cc b/shell/common/snapshot_controller_skia.cc index d39a9003050d4..09213854a10c8 100644 --- a/shell/common/snapshot_controller_skia.cc +++ b/shell/common/snapshot_controller_skia.cc @@ -54,20 +54,20 @@ sk_sp SnapshotControllerSkia::DoMakeRasterSnapshot( SkImageInfo image_info = SkImageInfo::MakeN32Premul( size.width(), size.height(), SkColorSpace::MakeSRGB()); - std::unique_ptr pbuffer_surface; - Surface* snapshot_surface = nullptr; + std::unique_ptr pbuffer_studio; + Studio* snapshot_studio = nullptr; auto& delegate = GetDelegate(); - if (delegate.GetSurface() && delegate.GetSurface()->GetContext()) { - snapshot_surface = delegate.GetSurface().get(); + if (delegate.GetStudio() && delegate.GetStudio()->GetContext()) { + snapshot_studio = delegate.GetStudio(); } else if (delegate.GetSnapshotSurfaceProducer()) { - pbuffer_surface = - delegate.GetSnapshotSurfaceProducer()->CreateSnapshotSurface(); - if (pbuffer_surface && pbuffer_surface->GetContext()) { - snapshot_surface = pbuffer_surface.get(); + pbuffer_studio = + delegate.GetSnapshotSurfaceProducer()->CreateSnapshotStudio(); + if (pbuffer_studio && pbuffer_studio->GetContext()) { + snapshot_studio = pbuffer_studio.get(); } } - if (!snapshot_surface) { + if (!snapshot_studio) { // Raster surface is fine if there is no on screen surface. This might // happen in case of software rendering. sk_sp sk_surface = SkSurfaces::Raster(image_info); @@ -80,14 +80,13 @@ sk_sp SnapshotControllerSkia::DoMakeRasterSnapshot( result = DrawSnapshot(surface, draw_callback); }) .SetIfFalse([&] { - FML_DCHECK(snapshot_surface); - auto context_switch = - snapshot_surface->MakeRenderContextCurrent(); + FML_DCHECK(snapshot_studio); + auto context_switch = snapshot_studio->MakeRenderContextCurrent(); if (!context_switch->GetResult()) { return; } - GrRecordingContext* context = snapshot_surface->GetContext(); + GrRecordingContext* context = snapshot_studio->GetContext(); auto max_size = context->maxRenderTargetSize(); double scale_factor = std::min( 1.0, static_cast(max_size) / @@ -139,8 +138,8 @@ sk_sp SnapshotControllerSkia::ConvertToRasterImage( // If the rasterizer does not have a surface with a GrContext, then it will // be unable to render a cross-context SkImage. The caller will need to // create the raster image on the IO thread. - if (GetDelegate().GetSurface() == nullptr || - GetDelegate().GetSurface()->GetContext() == nullptr) { + if (GetDelegate().GetStudio() == nullptr || + GetDelegate().GetStudio()->GetContext() == nullptr) { return nullptr; } diff --git a/shell/common/snapshot_surface_producer.h b/shell/common/snapshot_surface_producer.h index ae505109beda8..9a00259b6e89e 100644 --- a/shell/common/snapshot_surface_producer.h +++ b/shell/common/snapshot_surface_producer.h @@ -7,7 +7,7 @@ #include -#include "flutter/flow/surface.h" +#include "flutter/flow/studio.h" namespace flutter { @@ -15,7 +15,7 @@ class SnapshotSurfaceProducer { public: virtual ~SnapshotSurfaceProducer() = default; - virtual std::unique_ptr CreateSnapshotSurface() = 0; + virtual std::unique_ptr CreateSnapshotStudio() = 0; }; } // namespace flutter diff --git a/shell/gpu/BUILD.gn b/shell/gpu/BUILD.gn index 5e5c1cce53a6c..ec7b2a25b3530 100644 --- a/shell/gpu/BUILD.gn +++ b/shell/gpu/BUILD.gn @@ -17,6 +17,8 @@ gpu_common_deps = [ source_set("gpu_surface_software") { sources = [ + "gpu_studio_software.cc", + "gpu_studio_software.h", "gpu_surface_software.cc", "gpu_surface_software.h", "gpu_surface_software_delegate.cc", @@ -28,6 +30,8 @@ source_set("gpu_surface_software") { source_set("gpu_surface_gl") { sources = [ + "gpu_studio_gl_skia.cc", + "gpu_studio_gl_skia.h", "gpu_surface_gl_delegate.cc", "gpu_surface_gl_delegate.h", "gpu_surface_gl_skia.cc", @@ -38,6 +42,8 @@ source_set("gpu_surface_gl") { if (impeller_enable_opengles) { sources += [ + "gpu_studio_gl_impeller.cc", + "gpu_studio_gl_impeller.h", "gpu_surface_gl_impeller.cc", "gpu_surface_gl_impeller.h", ] @@ -48,6 +54,8 @@ source_set("gpu_surface_gl") { source_set("gpu_surface_vulkan") { sources = [ + "gpu_studio_vulkan.cc", + "gpu_studio_vulkan.h", "gpu_surface_vulkan.cc", "gpu_surface_vulkan.h", "gpu_surface_vulkan_delegate.cc", @@ -61,6 +69,8 @@ source_set("gpu_surface_vulkan") { if (impeller_enable_vulkan) { sources += [ + "gpu_studio_vulkan_impeller.cc", + "gpu_studio_vulkan_impeller.h", "gpu_surface_vulkan_impeller.cc", "gpu_surface_vulkan_impeller.h", ] @@ -71,6 +81,8 @@ source_set("gpu_surface_vulkan") { source_set("gpu_surface_metal") { sources = [ + "gpu_studio_metal_skia.h", + "gpu_studio_metal_skia.mm", "gpu_surface_metal_delegate.cc", "gpu_surface_metal_delegate.h", "gpu_surface_metal_skia.h", @@ -81,6 +93,8 @@ source_set("gpu_surface_metal") { if (impeller_enable_metal) { sources += [ + "gpu_studio_metal_impeller.h", + "gpu_studio_metal_impeller.mm", "gpu_surface_metal_impeller.h", "gpu_surface_metal_impeller.mm", ] diff --git a/shell/gpu/gpu_studio_gl_impeller.cc b/shell/gpu/gpu_studio_gl_impeller.cc new file mode 100644 index 0000000000000..1ce359d28f92f --- /dev/null +++ b/shell/gpu/gpu_studio_gl_impeller.cc @@ -0,0 +1,81 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/gpu/gpu_studio_gl_impeller.h" + +#include "flutter/fml/make_copyable.h" +#include "flutter/impeller/display_list/dl_dispatcher.h" +#include "flutter/impeller/renderer/backend/gles/surface_gles.h" +#include "flutter/impeller/renderer/renderer.h" + +namespace flutter { + +GPUStudioGLImpeller::GPUStudioGLImpeller( + GPUSurfaceGLDelegate* delegate, + const std::shared_ptr& context) { + if (delegate == nullptr) { + return; + } + + if (!context || !context->IsValid()) { + return; + } + + auto renderer = std::make_shared(context); + if (!renderer->IsValid()) { + return; + } + + auto aiks_context = std::make_shared(context); + + if (!aiks_context->IsValid()) { + return; + } + + delegate_ = delegate; + aiks_context_ = std::move(aiks_context); + is_valid_ = true; +} + +// |Studio| +GPUStudioGLImpeller::~GPUStudioGLImpeller() = default; + +// |Studio| +bool GPUStudioGLImpeller::IsValid() { + return is_valid_; +} + +// |Studio| +GrDirectContext* GPUStudioGLImpeller::GetContext() { + // Impeller != Skia. + return nullptr; +} + +// |Studio| +std::unique_ptr +GPUStudioGLImpeller::MakeRenderContextCurrent() { + return delegate_->GLContextMakeCurrent(); +} + +// |Studio| +bool GPUStudioGLImpeller::ClearRenderContext() { + return delegate_->GLContextClearCurrent(); +} + +bool GPUStudioGLImpeller::AllowsDrawingWhenGpuDisabled() const { + return delegate_->AllowsDrawingWhenGpuDisabled(); +} + +// |Studio| +bool GPUStudioGLImpeller::EnableRasterCache() const { + return false; +} + +// |Studio| +std::shared_ptr GPUStudioGLImpeller::GetAiksContext() + const { + return aiks_context_; +} + +} // namespace flutter diff --git a/shell/gpu/gpu_studio_gl_impeller.h b/shell/gpu/gpu_studio_gl_impeller.h new file mode 100644 index 0000000000000..764a3c70d917f --- /dev/null +++ b/shell/gpu/gpu_studio_gl_impeller.h @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SHELL_GPU_GPU_STUDIO_GL_IMPELLER_H_ +#define SHELL_GPU_GPU_STUDIO_GL_IMPELLER_H_ + +#include "flutter/common/graphics/gl_context_switch.h" +#include "flutter/flow/studio.h" +#include "flutter/flow/surface.h" +#include "flutter/fml/macros.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/impeller/aiks/aiks_context.h" +#include "flutter/impeller/renderer/context.h" +#include "flutter/shell/gpu/gpu_surface_gl_delegate.h" + +namespace flutter { + +class GPUStudioGLImpeller final : public Studio { + public: + explicit GPUStudioGLImpeller( + GPUSurfaceGLDelegate* delegate, + const std::shared_ptr& context); + + // |Studio| + ~GPUStudioGLImpeller() override; + + // |Studio| + bool IsValid() override; + + private: + GPUSurfaceGLDelegate* delegate_ = nullptr; + std::shared_ptr aiks_context_; + bool is_valid_ = false; + + // |Studio| + GrDirectContext* GetContext() override; + + // |Studio| + std::unique_ptr MakeRenderContextCurrent() override; + + // |Studio| + bool ClearRenderContext() override; + + // |Studio| + bool AllowsDrawingWhenGpuDisabled() const override; + + // |Studio| + bool EnableRasterCache() const override; + + // |Studio| + std::shared_ptr GetAiksContext() const override; + + FML_DISALLOW_COPY_AND_ASSIGN(GPUStudioGLImpeller); +}; + +} // namespace flutter + +#endif // SHELL_GPU_GPU_STUDIO_GL_IMPELLER_H_ diff --git a/shell/gpu/gpu_studio_gl_skia.cc b/shell/gpu/gpu_studio_gl_skia.cc new file mode 100644 index 0000000000000..60ae52e808c91 --- /dev/null +++ b/shell/gpu/gpu_studio_gl_skia.cc @@ -0,0 +1,111 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/gpu/gpu_studio_gl_skia.h" + +#include "flutter/common/graphics/persistent_cache.h" +#include "flutter/fml/base32.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/size.h" +#include "flutter/fml/trace_event.h" +#include "flutter/shell/common/context_options.h" +#include "flutter/shell/gpu/gpu_surface_gl_delegate.h" +#include "third_party/skia/include/core/SkAlphaType.h" +#include "third_party/skia/include/core/SkColorFilter.h" +#include "third_party/skia/include/core/SkColorSpace.h" +#include "third_party/skia/include/core/SkColorType.h" +#include "third_party/skia/include/gpu/GrContextOptions.h" + +namespace flutter { + +// Default maximum number of bytes of GPU memory of budgeted resources in the +// cache. +// The shell will dynamically increase or decrease this cache based on the +// viewport size, unless a user has specifically requested a size on the Skia +// system channel. +static const size_t kGrCacheMaxByteSize = 24 * (1 << 20); + +sk_sp GPUStudioGLSkia::MakeGLContext( + GPUSurfaceGLDelegate* delegate) { + auto context_switch = delegate->GLContextMakeCurrent(); + if (!context_switch->GetResult()) { + FML_LOG(ERROR) + << "Could not make the context current to set up the Gr context."; + return nullptr; + } + + const auto options = + MakeDefaultContextOptions(ContextType::kRender, GrBackendApi::kOpenGL); + + auto context = GrDirectContext::MakeGL(delegate->GetGLInterface(), options); + + if (!context) { + FML_LOG(ERROR) << "Failed to set up Skia Gr context."; + return nullptr; + } + + context->setResourceCacheLimit(kGrCacheMaxByteSize); + + PersistentCache::GetCacheForProcess()->PrecompileKnownSkSLs(context.get()); + + return context; +} + +GPUStudioGLSkia::GPUStudioGLSkia(const sk_sp& gr_context, + GPUSurfaceGLDelegate* delegate) + : delegate_(delegate), context_(gr_context) { + auto context_switch = delegate_->GLContextMakeCurrent(); + if (!context_switch->GetResult()) { + FML_LOG(ERROR) + << "Could not make the context current to set up the Gr context."; + return; + } + + delegate_->GLContextClearCurrent(); + + valid_ = gr_context != nullptr; +} + +GPUStudioGLSkia::~GPUStudioGLSkia() { + if (!valid_) { + return; + } + auto context_switch = delegate_->GLContextMakeCurrent(); + if (!context_switch->GetResult()) { + FML_LOG(ERROR) << "Could not make the context current to destroy the " + "GrDirectContext resources."; + return; + } + + context_ = nullptr; + + delegate_->GLContextClearCurrent(); +} + +// |Studio| +bool GPUStudioGLSkia::IsValid() { + return valid_; +} + +// |Studio| +GrDirectContext* GPUStudioGLSkia::GetContext() { + return context_.get(); +} + +// |Studio| +std::unique_ptr GPUStudioGLSkia::MakeRenderContextCurrent() { + return delegate_->GLContextMakeCurrent(); +} + +// |Studio| +bool GPUStudioGLSkia::ClearRenderContext() { + return delegate_->GLContextClearCurrent(); +} + +// |Studio| +bool GPUStudioGLSkia::AllowsDrawingWhenGpuDisabled() const { + return delegate_->AllowsDrawingWhenGpuDisabled(); +} + +} // namespace flutter diff --git a/shell/gpu/gpu_studio_gl_skia.h b/shell/gpu/gpu_studio_gl_skia.h new file mode 100644 index 0000000000000..2744e4e794404 --- /dev/null +++ b/shell/gpu/gpu_studio_gl_skia.h @@ -0,0 +1,58 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SHELL_GPU_GPU_STUDIO_GL_SKIA_H_ +#define SHELL_GPU_GPU_STUDIO_GL_SKIA_H_ + +#include +#include + +#include "flutter/common/graphics/gl_context_switch.h" +#include "flutter/flow/embedded_views.h" +#include "flutter/flow/studio.h" +#include "flutter/flow/surface.h" +#include "flutter/fml/macros.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/shell/gpu/gpu_surface_gl_delegate.h" + +#include "third_party/skia/include/gpu/GrDirectContext.h" + +namespace flutter { + +class GPUStudioGLSkia : public Studio { + public: + static sk_sp MakeGLContext(GPUSurfaceGLDelegate* delegate); + + GPUStudioGLSkia(const sk_sp& gr_context, + GPUSurfaceGLDelegate* delegate); + + // |Studio| + ~GPUStudioGLSkia() override; + + // |Studio| + bool IsValid() override; + + // |Studio| + GrDirectContext* GetContext() override; + + // |Studio| + std::unique_ptr MakeRenderContextCurrent() override; + + // |Studio| + bool ClearRenderContext() override; + + // |Studio| + bool AllowsDrawingWhenGpuDisabled() const override; + + private: + GPUSurfaceGLDelegate* delegate_; + sk_sp context_; + bool valid_ = false; + + FML_DISALLOW_COPY_AND_ASSIGN(GPUStudioGLSkia); +}; + +} // namespace flutter + +#endif // SHELL_GPU_GPU_STUDIO_GL_SKIA_H_ diff --git a/shell/gpu/gpu_studio_metal_impeller.h b/shell/gpu/gpu_studio_metal_impeller.h new file mode 100644 index 0000000000000..bea50ec6f44c9 --- /dev/null +++ b/shell/gpu/gpu_studio_metal_impeller.h @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_GPU_GPU_STUDIO_METAL_IMPELLER_H_ +#define FLUTTER_SHELL_GPU_GPU_STUDIO_METAL_IMPELLER_H_ + +#ifndef QUARTSCORE_CAMETALLAYER_H +#define QUARTSCORE_CAMETALLAYER_H +#include +#endif + +#include "flutter/flow/studio.h" +#include "flutter/flow/surface.h" +#include "flutter/fml/macros.h" +#include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/impeller/aiks/aiks_context.h" +#include "flutter/impeller/renderer/renderer.h" +#include "flutter/shell/gpu/gpu_surface_metal_delegate.h" + +namespace flutter { + +class SK_API_AVAILABLE_CA_METAL_LAYER GPUStudioMetalImpeller : public Studio { + public: + GPUStudioMetalImpeller(GPUSurfaceMetalDelegate* delegate, + const std::shared_ptr& context); + + // |Studio| + ~GPUStudioMetalImpeller(); + + // |Studio| + bool IsValid() override; + + private: + const GPUSurfaceMetalDelegate* delegate_; + std::shared_ptr impeller_renderer_; + std::shared_ptr aiks_context_; + + // |Studio| + GrDirectContext* GetContext() override; + + // |Studio| + std::unique_ptr MakeRenderContextCurrent() override; + + // |Studio| + bool AllowsDrawingWhenGpuDisabled() const override; + + // |Studio| + bool EnableRasterCache() const override; + + // |Studio| + std::shared_ptr GetAiksContext() const override; + + FML_DISALLOW_COPY_AND_ASSIGN(GPUStudioMetalImpeller); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_GPU_GPU_STUDIO_METAL_IMPELLER_H_ diff --git a/shell/gpu/gpu_studio_metal_impeller.mm b/shell/gpu/gpu_studio_metal_impeller.mm new file mode 100644 index 0000000000000..4a9c140c0ca48 --- /dev/null +++ b/shell/gpu/gpu_studio_metal_impeller.mm @@ -0,0 +1,70 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/gpu/gpu_studio_metal_impeller.h" + +#import +#import + +#include "flutter/common/settings.h" +#include "flutter/fml/make_copyable.h" +#include "flutter/fml/mapping.h" +#include "flutter/fml/trace_event.h" +#include "flutter/impeller/display_list/dl_dispatcher.h" +#include "flutter/impeller/renderer/backend/metal/surface_mtl.h" + +static_assert(!__has_feature(objc_arc), "ARC must be disabled."); + +namespace flutter { + +static std::shared_ptr CreateImpellerRenderer( + std::shared_ptr context) { + auto renderer = std::make_shared(std::move(context)); + if (!renderer->IsValid()) { + FML_LOG(ERROR) << "Could not create valid Impeller Renderer."; + return nullptr; + } + return renderer; +} + +GPUStudioMetalImpeller::GPUStudioMetalImpeller(GPUSurfaceMetalDelegate* delegate, + const std::shared_ptr& context) + : delegate_(delegate), + impeller_renderer_(CreateImpellerRenderer(context)), + aiks_context_( + std::make_shared(impeller_renderer_ ? context : nullptr)) {} + +GPUStudioMetalImpeller::~GPUStudioMetalImpeller() = default; + +// |Studio| +bool GPUStudioMetalImpeller::IsValid() { + return !!aiks_context_; +} + +// |Studio| +GrDirectContext* GPUStudioMetalImpeller::GetContext() { + return nullptr; +} + +// |Studio| +std::unique_ptr GPUStudioMetalImpeller::MakeRenderContextCurrent() { + // This backend has no such concept. + return std::make_unique(true); +} + +bool GPUStudioMetalImpeller::AllowsDrawingWhenGpuDisabled() const { + return delegate_->AllowsDrawingWhenGpuDisabled(); +} + +// |Studio| +bool GPUStudioMetalImpeller::EnableRasterCache() const { + return false; +} + +// |Studio| +std::shared_ptr GPUStudioMetalImpeller::GetAiksContext() const { + return aiks_context_; +} + +} // namespace flutter diff --git a/shell/gpu/gpu_studio_metal_skia.h b/shell/gpu/gpu_studio_metal_skia.h new file mode 100644 index 0000000000000..08d83ace65439 --- /dev/null +++ b/shell/gpu/gpu_studio_metal_skia.h @@ -0,0 +1,51 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_GPU_GPU_STUDIO_METAL_H_ +#define FLUTTER_SHELL_GPU_GPU_STUDIO_METAL_H_ + +#include "flutter/common/graphics/msaa_sample_count.h" +#include "flutter/flow/studio.h" +#include "flutter/flow/surface.h" +#include "flutter/fml/macros.h" +#include "flutter/shell/gpu/gpu_surface_metal_delegate.h" +#include "third_party/skia/include/gpu/GrDirectContext.h" + +namespace flutter { + +class SK_API_AVAILABLE_CA_METAL_LAYER GPUStudioMetalSkia : public Studio { + public: + GPUStudioMetalSkia(GPUSurfaceMetalDelegate* delegate, + sk_sp context, + std::shared_ptr + sksl_precompiler); + + // |Studio| + ~GPUStudioMetalSkia(); + + // |Studio| + bool IsValid() override; + + private: + const GPUSurfaceMetalDelegate* delegate_; + sk_sp context_; + std::shared_ptr sksl_precompiler_; + + // |Studio| + GrDirectContext* GetContext() override; + + // |Studio| + std::unique_ptr MakeRenderContextCurrent() override; + + // |Studio| + bool AllowsDrawingWhenGpuDisabled() const override; + + void PrecompileKnownSkSLsIfNecessary(); + + FML_DISALLOW_COPY_AND_ASSIGN(GPUStudioMetalSkia); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_GPU_GPU_STUDIO_METAL_H_ diff --git a/shell/gpu/gpu_studio_metal_skia.mm b/shell/gpu/gpu_studio_metal_skia.mm new file mode 100644 index 0000000000000..61eaa1ebcbce9 --- /dev/null +++ b/shell/gpu/gpu_studio_metal_skia.mm @@ -0,0 +1,64 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/gpu/gpu_studio_metal_skia.h" + +#import +#import + +#include + +#include "flutter/fml/make_copyable.h" +#include "flutter/fml/platform/darwin/cf_utils.h" +#include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/fml/trace_event.h" +#include "flutter/shell/gpu/gpu_surface_metal_delegate.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkColorSpace.h" +#include "third_party/skia/include/core/SkColorType.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/core/SkRect.h" +#include "third_party/skia/include/core/SkRefCnt.h" +#include "third_party/skia/include/core/SkSize.h" +#include "third_party/skia/include/ports/SkCFObject.h" + +static_assert(!__has_feature(objc_arc), "ARC must be disabled."); + +namespace flutter { + +GPUStudioMetalSkia::GPUStudioMetalSkia( + GPUSurfaceMetalDelegate* delegate, + sk_sp context, + std::shared_ptr sksl_precompiler) + : delegate_(delegate), + context_(std::move(context)), + sksl_precompiler_(std::move(sksl_precompiler)) {} + +GPUStudioMetalSkia::~GPUStudioMetalSkia() = default; + +// |Studio| +bool GPUStudioMetalSkia::IsValid() { + return context_ != nullptr; +} + +// |Studio| +GrDirectContext* GPUStudioMetalSkia::GetContext() { + return context_.get(); +} + +// |Studio| +std::unique_ptr GPUStudioMetalSkia::MakeRenderContextCurrent() { + // A context may either be necessary to render to the surface or to snapshot an offscreen + // surface. Either way, SkSL precompilation must be attempted. + sksl_precompiler_->PrecompileKnownSkSLsIfNecessary(GetContext()); + + // This backend has no such concept. + return std::make_unique(true); +} + +bool GPUStudioMetalSkia::AllowsDrawingWhenGpuDisabled() const { + return delegate_->AllowsDrawingWhenGpuDisabled(); +} + +} // namespace flutter diff --git a/shell/gpu/gpu_studio_software.cc b/shell/gpu/gpu_studio_software.cc new file mode 100644 index 0000000000000..be46c443b22f8 --- /dev/null +++ b/shell/gpu/gpu_studio_software.cc @@ -0,0 +1,29 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/gpu/gpu_studio_software.h" + +#include + +#include "flutter/fml/logging.h" + +namespace flutter { + +GPUStudioSoftware::GPUStudioSoftware(GPUSurfaceSoftwareDelegate* delegate) + : delegate_(delegate) {} + +GPUStudioSoftware::~GPUStudioSoftware() = default; + +// |Studio| +bool GPUStudioSoftware::IsValid() { + return delegate_ != nullptr; +} + +// |Studio| +GrDirectContext* GPUStudioSoftware::GetContext() { + // There is no GrContext associated with a software surface. + return nullptr; +} + +} // namespace flutter diff --git a/shell/gpu/gpu_studio_software.h b/shell/gpu/gpu_studio_software.h new file mode 100644 index 0000000000000..f953b66c2fa9b --- /dev/null +++ b/shell/gpu/gpu_studio_software.h @@ -0,0 +1,36 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_GPU_GPU_STUDIO_SOFTWARE_H_ +#define FLUTTER_SHELL_GPU_GPU_STUDIO_SOFTWARE_H_ + +#include "flutter/flow/studio.h" +#include "flutter/flow/surface.h" +#include "flutter/fml/macros.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/shell/gpu/gpu_surface_software_delegate.h" + +namespace flutter { + +class GPUStudioSoftware : public Studio { + public: + GPUStudioSoftware(GPUSurfaceSoftwareDelegate* delegate); + + ~GPUStudioSoftware() override; + + // |Studio| + bool IsValid() override; + + // |Studio| + GrDirectContext* GetContext() override; + + private: + GPUSurfaceSoftwareDelegate* delegate_; + + FML_DISALLOW_COPY_AND_ASSIGN(GPUStudioSoftware); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_GPU_GPU_STUDIO_SOFTWARE_H_ diff --git a/shell/gpu/gpu_studio_vulkan.cc b/shell/gpu/gpu_studio_vulkan.cc new file mode 100644 index 0000000000000..90453b9f4bd22 --- /dev/null +++ b/shell/gpu/gpu_studio_vulkan.cc @@ -0,0 +1,42 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/gpu/gpu_studio_vulkan.h" + +#include "flutter/fml/logging.h" +#include "flutter/fml/trace_event.h" + +#include "third_party/skia/include/core/SkColorSpace.h" +#include "third_party/skia/include/core/SkSize.h" +#include "vulkan/vulkan_core.h" + +namespace flutter { + +GPUStudioVulkan::GPUStudioVulkan(const sk_sp& skia_context) + : skia_context_(skia_context) {} + +GPUStudioVulkan::~GPUStudioVulkan() = default; + +bool GPUStudioVulkan::IsValid() { + return skia_context_ != nullptr; +} + +GrDirectContext* GPUStudioVulkan::GetContext() { + return skia_context_.get(); +} + +SkColorType GPUStudioVulkan::ColorTypeFromFormat(const VkFormat format) { + switch (format) { + case VK_FORMAT_R8G8B8A8_UNORM: + case VK_FORMAT_R8G8B8A8_SRGB: + return SkColorType::kRGBA_8888_SkColorType; + case VK_FORMAT_B8G8R8A8_UNORM: + case VK_FORMAT_B8G8R8A8_SRGB: + return SkColorType::kBGRA_8888_SkColorType; + default: + return SkColorType::kUnknown_SkColorType; + } +} + +} // namespace flutter diff --git a/shell/gpu/gpu_studio_vulkan.h b/shell/gpu/gpu_studio_vulkan.h new file mode 100644 index 0000000000000..294a2572ac247 --- /dev/null +++ b/shell/gpu/gpu_studio_vulkan.h @@ -0,0 +1,53 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SHELL_GPU_GPU_STUDIO_VULKAN_H_ +#define SHELL_GPU_GPU_STUDIO_VULKAN_H_ + +#include + +#include "flutter/flow/studio.h" +#include "flutter/flow/surface.h" +#include "flutter/fml/macros.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h" +#include "flutter/vulkan/vulkan_backbuffer.h" +#include "flutter/vulkan/vulkan_native_surface.h" +#include "flutter/vulkan/vulkan_window.h" + +#include "third_party/skia/include/core/SkRefCnt.h" + +namespace flutter { + +//------------------------------------------------------------------------------ +/// @brief A GPU surface backed by VkImages provided by a +/// GPUSurfaceVulkanDelegate. +/// +class GPUStudioVulkan : public Studio { + public: + //------------------------------------------------------------------------------ + /// @brief Create a GPUStudioVulkan while letting it reuse an existing + /// GrDirectContext. + /// + GPUStudioVulkan(const sk_sp& context); + + ~GPUStudioVulkan() override; + + // |Studio| + bool IsValid() override; + + // |Studio| + GrDirectContext* GetContext() override; + + static SkColorType ColorTypeFromFormat(const VkFormat format); + + private: + sk_sp skia_context_; + + FML_DISALLOW_COPY_AND_ASSIGN(GPUStudioVulkan); +}; + +} // namespace flutter + +#endif // SHELL_GPU_GPU_STUDIO_VULKAN_H_ diff --git a/shell/gpu/gpu_studio_vulkan_impeller.cc b/shell/gpu/gpu_studio_vulkan_impeller.cc new file mode 100644 index 0000000000000..7dc5d69d15f7a --- /dev/null +++ b/shell/gpu/gpu_studio_vulkan_impeller.cc @@ -0,0 +1,62 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/gpu/gpu_studio_vulkan_impeller.h" + +#include "flutter/fml/make_copyable.h" +#include "flutter/impeller/display_list/dl_dispatcher.h" +#include "flutter/impeller/renderer/renderer.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" + +namespace flutter { + +GPUStudioVulkanImpeller::GPUStudioVulkanImpeller( + std::shared_ptr context) { + if (!context || !context->IsValid()) { + return; + } + + auto aiks_context = std::make_shared(context); + if (!aiks_context->IsValid()) { + return; + } + + impeller_context_ = std::move(context); + aiks_context_ = std::move(aiks_context); + is_valid_ = true; +} + +// |Studio| +GPUStudioVulkanImpeller::~GPUStudioVulkanImpeller() = default; + +// |Studio| +bool GPUStudioVulkanImpeller::IsValid() { + return is_valid_; +} + +// |Studio| +GrDirectContext* GPUStudioVulkanImpeller::GetContext() { + // Impeller != Skia. + return nullptr; +} + +// |Studio| +std::unique_ptr +GPUStudioVulkanImpeller::MakeRenderContextCurrent() { + // This backend has no such concept. + return std::make_unique(true); +} + +// |Studio| +bool GPUStudioVulkanImpeller::EnableRasterCache() const { + return false; +} + +// |Studio| +std::shared_ptr GPUStudioVulkanImpeller::GetAiksContext() + const { + return aiks_context_; +} + +} // namespace flutter diff --git a/shell/gpu/gpu_studio_vulkan_impeller.h b/shell/gpu/gpu_studio_vulkan_impeller.h new file mode 100644 index 0000000000000..9c2be075a9a13 --- /dev/null +++ b/shell/gpu/gpu_studio_vulkan_impeller.h @@ -0,0 +1,48 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "flutter/common/graphics/gl_context_switch.h" +#include "flutter/flow/studio.h" +#include "flutter/flow/surface.h" +#include "flutter/fml/macros.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/impeller/aiks/aiks_context.h" +#include "flutter/impeller/renderer/context.h" +#include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h" + +namespace flutter { + +class GPUStudioVulkanImpeller final : public Studio { + public: + explicit GPUStudioVulkanImpeller(std::shared_ptr context); + + // |Studio| + ~GPUStudioVulkanImpeller() override; + + // |Studio| + bool IsValid() override; + + private: + std::shared_ptr impeller_context_; + std::shared_ptr aiks_context_; + bool is_valid_ = false; + + // |Studio| + GrDirectContext* GetContext() override; + + // |Studio| + std::unique_ptr MakeRenderContextCurrent() override; + + // |Studio| + bool EnableRasterCache() const override; + + // |Studio| + std::shared_ptr GetAiksContext() const override; + + FML_DISALLOW_COPY_AND_ASSIGN(GPUStudioVulkanImpeller); +}; + +} // namespace flutter diff --git a/shell/gpu/gpu_surface_gl_impeller.cc b/shell/gpu/gpu_surface_gl_impeller.cc index a6960717d3297..07633148e1f8b 100644 --- a/shell/gpu/gpu_surface_gl_impeller.cc +++ b/shell/gpu/gpu_surface_gl_impeller.cc @@ -133,36 +133,4 @@ SkMatrix GPUSurfaceGLImpeller::GetRootTransformation() const { return {}; } -// |Surface| -GrDirectContext* GPUSurfaceGLImpeller::GetContext() { - // Impeller != Skia. - return nullptr; -} - -// |Surface| -std::unique_ptr -GPUSurfaceGLImpeller::MakeRenderContextCurrent() { - return delegate_->GLContextMakeCurrent(); -} - -// |Surface| -bool GPUSurfaceGLImpeller::ClearRenderContext() { - return delegate_->GLContextClearCurrent(); -} - -bool GPUSurfaceGLImpeller::AllowsDrawingWhenGpuDisabled() const { - return delegate_->AllowsDrawingWhenGpuDisabled(); -} - -// |Surface| -bool GPUSurfaceGLImpeller::EnableRasterCache() const { - return false; -} - -// |Surface| -std::shared_ptr GPUSurfaceGLImpeller::GetAiksContext() - const { - return aiks_context_; -} - } // namespace flutter diff --git a/shell/gpu/gpu_surface_gl_impeller.h b/shell/gpu/gpu_surface_gl_impeller.h index 048c8570e1140..9e054291391fc 100644 --- a/shell/gpu/gpu_surface_gl_impeller.h +++ b/shell/gpu/gpu_surface_gl_impeller.h @@ -40,24 +40,6 @@ class GPUSurfaceGLImpeller final : public Surface { // |Surface| SkMatrix GetRootTransformation() const override; - // |Surface| - GrDirectContext* GetContext() override; - - // |Surface| - std::unique_ptr MakeRenderContextCurrent() override; - - // |Surface| - bool ClearRenderContext() override; - - // |Surface| - bool AllowsDrawingWhenGpuDisabled() const override; - - // |Surface| - bool EnableRasterCache() const override; - - // |Surface| - std::shared_ptr GetAiksContext() const override; - FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceGLImpeller); }; diff --git a/shell/gpu/gpu_surface_gl_skia.cc b/shell/gpu/gpu_surface_gl_skia.cc index 8285145b4efd3..d3a9a166e2241 100644 --- a/shell/gpu/gpu_surface_gl_skia.cc +++ b/shell/gpu/gpu_surface_gl_skia.cc @@ -4,7 +4,6 @@ #include "flutter/shell/gpu/gpu_surface_gl_skia.h" -#include "flutter/common/graphics/persistent_cache.h" #include "flutter/fml/base32.h" #include "flutter/fml/logging.h" #include "flutter/fml/size.h" @@ -30,45 +29,6 @@ namespace flutter { -// Default maximum number of bytes of GPU memory of budgeted resources in the -// cache. -// The shell will dynamically increase or decrease this cache based on the -// viewport size, unless a user has specifically requested a size on the Skia -// system channel. -static const size_t kGrCacheMaxByteSize = 24 * (1 << 20); - -sk_sp GPUSurfaceGLSkia::MakeGLContext( - GPUSurfaceGLDelegate* delegate) { - auto context_switch = delegate->GLContextMakeCurrent(); - if (!context_switch->GetResult()) { - FML_LOG(ERROR) - << "Could not make the context current to set up the Gr context."; - return nullptr; - } - - const auto options = - MakeDefaultContextOptions(ContextType::kRender, GrBackendApi::kOpenGL); - - auto context = GrDirectContext::MakeGL(delegate->GetGLInterface(), options); - - if (!context) { - FML_LOG(ERROR) << "Failed to set up Skia Gr context."; - return nullptr; - } - - context->setResourceCacheLimit(kGrCacheMaxByteSize); - - PersistentCache::GetCacheForProcess()->PrecompileKnownSkSLs(context.get()); - - return context; -} - -GPUSurfaceGLSkia::GPUSurfaceGLSkia(GPUSurfaceGLDelegate* delegate, - bool render_to_surface) - : GPUSurfaceGLSkia(MakeGLContext(delegate), delegate, render_to_surface) { - context_owner_ = true; -} - GPUSurfaceGLSkia::GPUSurfaceGLSkia(const sk_sp& gr_context, GPUSurfaceGLDelegate* delegate, bool render_to_surface) @@ -102,9 +62,6 @@ GPUSurfaceGLSkia::~GPUSurfaceGLSkia() { onscreen_surface_ = nullptr; fbo_id_ = 0; - if (context_owner_) { - context_->releaseResourcesAndAbandonContext(); - } context_ = nullptr; delegate_->GLContextClearCurrent(); @@ -326,24 +283,4 @@ sk_sp GPUSurfaceGLSkia::AcquireRenderSurface( return onscreen_surface_; } -// |Surface| -GrDirectContext* GPUSurfaceGLSkia::GetContext() { - return context_.get(); -} - -// |Surface| -std::unique_ptr GPUSurfaceGLSkia::MakeRenderContextCurrent() { - return delegate_->GLContextMakeCurrent(); -} - -// |Surface| -bool GPUSurfaceGLSkia::ClearRenderContext() { - return delegate_->GLContextClearCurrent(); -} - -// |Surface| -bool GPUSurfaceGLSkia::AllowsDrawingWhenGpuDisabled() const { - return delegate_->AllowsDrawingWhenGpuDisabled(); -} - } // namespace flutter diff --git a/shell/gpu/gpu_surface_gl_skia.h b/shell/gpu/gpu_surface_gl_skia.h index 6aef2096f94df..42cb592f9ccd0 100644 --- a/shell/gpu/gpu_surface_gl_skia.h +++ b/shell/gpu/gpu_surface_gl_skia.h @@ -22,11 +22,6 @@ namespace flutter { class GPUSurfaceGLSkia : public Surface { public: - static sk_sp MakeGLContext(GPUSurfaceGLDelegate* delegate); - - GPUSurfaceGLSkia(GPUSurfaceGLDelegate* delegate, bool render_to_surface); - - // Creates a new GL surface reusing an existing GrDirectContext. GPUSurfaceGLSkia(const sk_sp& gr_context, GPUSurfaceGLDelegate* delegate, bool render_to_surface); @@ -43,18 +38,6 @@ class GPUSurfaceGLSkia : public Surface { // |Surface| SkMatrix GetRootTransformation() const override; - // |Surface| - GrDirectContext* GetContext() override; - - // |Surface| - std::unique_ptr MakeRenderContextCurrent() override; - - // |Surface| - bool ClearRenderContext() override; - - // |Surface| - bool AllowsDrawingWhenGpuDisabled() const override; - private: bool CreateOrUpdateSurfaces(const SkISize& size); @@ -73,7 +56,6 @@ class GPUSurfaceGLSkia : public Surface { // still have an option of overriding this damage with their own in // `GLContextFrameBufferInfo`. std::optional existing_damage_ = std::nullopt; - bool context_owner_ = false; // TODO(38466): Refactor GPU surface APIs take into account the fact that an // external view embedder may want to render to the root surface. This is a // hack to make avoid allocating resources for the root surface when an diff --git a/shell/gpu/gpu_surface_metal_delegate.cc b/shell/gpu/gpu_surface_metal_delegate.cc index 7a22d8de88a89..8b1fd17a3cab3 100644 --- a/shell/gpu/gpu_surface_metal_delegate.cc +++ b/shell/gpu/gpu_surface_metal_delegate.cc @@ -4,6 +4,8 @@ #include "flutter/shell/gpu/gpu_surface_metal_delegate.h" +#include "flutter/common/graphics/persistent_cache.h" + namespace flutter { GPUSurfaceMetalDelegate::GPUSurfaceMetalDelegate( @@ -20,4 +22,17 @@ bool GPUSurfaceMetalDelegate::AllowsDrawingWhenGpuDisabled() const { return true; } +GPUSurfaceMetalDelegate::SkSLPrecompiler::SkSLPrecompiler() {} + +void GPUSurfaceMetalDelegate::SkSLPrecompiler::PrecompileKnownSkSLsIfNecessary( + GrDirectContext* current_context) { + if (current_context == precompiled_sksl_context_) { + // Known SkSLs have already been prepared in this context. + return; + } + precompiled_sksl_context_ = current_context; + flutter::PersistentCache::GetCacheForProcess()->PrecompileKnownSkSLs( + precompiled_sksl_context_); +} + } // namespace flutter diff --git a/shell/gpu/gpu_surface_metal_delegate.h b/shell/gpu/gpu_surface_metal_delegate.h index a5dadedd9a429..1482da72f00c3 100644 --- a/shell/gpu/gpu_surface_metal_delegate.h +++ b/shell/gpu/gpu_surface_metal_delegate.h @@ -51,6 +51,17 @@ enum class MTLRenderTargetType { kMTLTexture, kCAMetalLayer }; /// class GPUSurfaceMetalDelegate { public: + class SkSLPrecompiler { + public: + SkSLPrecompiler(); + void PrecompileKnownSkSLsIfNecessary(GrDirectContext* current_context); + + private: + GrDirectContext* precompiled_sksl_context_; + + FML_DISALLOW_COPY_AND_ASSIGN(SkSLPrecompiler); + }; + //------------------------------------------------------------------------------ /// @brief Construct a new GPUSurfaceMetalDelegate object with the specified /// render_target type. diff --git a/shell/gpu/gpu_surface_metal_impeller.h b/shell/gpu/gpu_surface_metal_impeller.h index 3b139c1890384..ece62e423f5be 100644 --- a/shell/gpu/gpu_surface_metal_impeller.h +++ b/shell/gpu/gpu_surface_metal_impeller.h @@ -5,7 +5,10 @@ #ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_IMPELLER_H_ #define FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_IMPELLER_H_ +#ifndef QUARTSCORE_CAMETALLAYER_H +#define QUARTSCORE_CAMETALLAYER_H #include +#endif #include "flutter/flow/surface.h" #include "flutter/fml/macros.h" @@ -46,21 +49,6 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetalImpeller : public Surface { // |Surface| SkMatrix GetRootTransformation() const override; - // |Surface| - GrDirectContext* GetContext() override; - - // |Surface| - std::unique_ptr MakeRenderContextCurrent() override; - - // |Surface| - bool AllowsDrawingWhenGpuDisabled() const override; - - // |Surface| - bool EnableRasterCache() const override; - - // |Surface| - std::shared_ptr GetAiksContext() const override; - FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceMetalImpeller); }; diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index 94f77a1ec192f..55ab6a9d662bc 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -162,31 +162,6 @@ return {}; } -// |Surface| -GrDirectContext* GPUSurfaceMetalImpeller::GetContext() { - return nullptr; -} - -// |Surface| -std::unique_ptr GPUSurfaceMetalImpeller::MakeRenderContextCurrent() { - // This backend has no such concept. - return std::make_unique(true); -} - -bool GPUSurfaceMetalImpeller::AllowsDrawingWhenGpuDisabled() const { - return delegate_->AllowsDrawingWhenGpuDisabled(); -} - -// |Surface| -bool GPUSurfaceMetalImpeller::EnableRasterCache() const { - return false; -} - -// |Surface| -std::shared_ptr GPUSurfaceMetalImpeller::GetAiksContext() const { - return aiks_context_; -} - Surface::SurfaceData GPUSurfaceMetalImpeller::GetSurfaceData() const { if (!(last_drawable_ && [last_drawable_ conformsToProtocol:@protocol(CAMetalDrawable)])) { return {}; diff --git a/shell/gpu/gpu_surface_metal_skia.h b/shell/gpu/gpu_surface_metal_skia.h index bd7d6a35135f3..49747c4e7b280 100644 --- a/shell/gpu/gpu_surface_metal_skia.h +++ b/shell/gpu/gpu_surface_metal_skia.h @@ -18,6 +18,8 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetalSkia : public Surface { GPUSurfaceMetalSkia(GPUSurfaceMetalDelegate* delegate, sk_sp context, MsaaSampleCount msaa_samples, + std::shared_ptr + sksl_precompiler, bool render_to_surface = true); // |Surface| @@ -30,8 +32,8 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetalSkia : public Surface { const GPUSurfaceMetalDelegate* delegate_; const MTLRenderTargetType render_target_type_; sk_sp context_; - GrDirectContext* precompiled_sksl_context_ = nullptr; MsaaSampleCount msaa_samples_ = MsaaSampleCount::kNone; + std::shared_ptr sksl_precompiler_; // TODO(38466): Refactor GPU surface APIs take into account the fact that an // external view embedder may want to render to the root surface. This is a // hack to make avoid allocating resources for the root surface when an @@ -50,14 +52,6 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetalSkia : public Surface { SkMatrix GetRootTransformation() const override; // |Surface| - GrDirectContext* GetContext() override; - - // |Surface| - std::unique_ptr MakeRenderContextCurrent() override; - - // |Surface| - bool AllowsDrawingWhenGpuDisabled() const override; - std::unique_ptr AcquireFrameFromCAMetalLayer( const SkISize& frame_info); diff --git a/shell/gpu/gpu_surface_metal_skia.mm b/shell/gpu/gpu_surface_metal_skia.mm index ed884151d0ab7..1f2fffd974949 100644 --- a/shell/gpu/gpu_surface_metal_skia.mm +++ b/shell/gpu/gpu_surface_metal_skia.mm @@ -9,7 +9,6 @@ #include -#include "flutter/common/graphics/persistent_cache.h" #include "flutter/fml/make_copyable.h" #include "flutter/fml/platform/darwin/cf_utils.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" @@ -51,14 +50,17 @@ } } // namespace -GPUSurfaceMetalSkia::GPUSurfaceMetalSkia(GPUSurfaceMetalDelegate* delegate, - sk_sp context, - MsaaSampleCount msaa_samples, - bool render_to_surface) +GPUSurfaceMetalSkia::GPUSurfaceMetalSkia( + GPUSurfaceMetalDelegate* delegate, + sk_sp context, + MsaaSampleCount msaa_samples, + std::shared_ptr sksl_precompiler, + bool render_to_surface) : delegate_(delegate), render_target_type_(delegate->GetRenderTargetType()), context_(std::move(context)), msaa_samples_(msaa_samples), + sksl_precompiler_(std::move(sksl_precompiler)), render_to_surface_(render_to_surface) { // If this preference is explicitly set, we allow for disabling partial repaint. NSNumber* disablePartialRepaint = @@ -75,16 +77,6 @@ return context_ != nullptr; } -void GPUSurfaceMetalSkia::PrecompileKnownSkSLsIfNecessary() { - auto* current_context = GetContext(); - if (current_context == precompiled_sksl_context_) { - // Known SkSLs have already been prepared in this context. - return; - } - precompiled_sksl_context_ = current_context; - flutter::PersistentCache::GetCacheForProcess()->PrecompileKnownSkSLs(precompiled_sksl_context_); -} - // |Surface| std::unique_ptr GPUSurfaceMetalSkia::AcquireFrame(const SkISize& frame_size) { if (!IsValid()) { @@ -103,7 +95,7 @@ [](const SurfaceFrame& surface_frame, DlCanvas* canvas) { return true; }, frame_size); } - PrecompileKnownSkSLsIfNecessary(); + sksl_precompiler_->PrecompileKnownSkSLsIfNecessary(context_.get()); switch (render_target_type_) { case MTLRenderTargetType::kCAMetalLayer: @@ -248,23 +240,4 @@ return {}; } -// |Surface| -GrDirectContext* GPUSurfaceMetalSkia::GetContext() { - return context_.get(); -} - -// |Surface| -std::unique_ptr GPUSurfaceMetalSkia::MakeRenderContextCurrent() { - // A context may either be necessary to render to the surface or to snapshot an offscreen - // surface. Either way, SkSL precompilation must be attempted. - PrecompileKnownSkSLsIfNecessary(); - - // This backend has no such concept. - return std::make_unique(true); -} - -bool GPUSurfaceMetalSkia::AllowsDrawingWhenGpuDisabled() const { - return delegate_->AllowsDrawingWhenGpuDisabled(); -} - } // namespace flutter diff --git a/shell/gpu/gpu_surface_software.cc b/shell/gpu/gpu_surface_software.cc index efb905ba24ecb..2d9902794043c 100644 --- a/shell/gpu/gpu_surface_software.cc +++ b/shell/gpu/gpu_surface_software.cc @@ -90,10 +90,4 @@ SkMatrix GPUSurfaceSoftware::GetRootTransformation() const { return matrix; } -// |Surface| -GrDirectContext* GPUSurfaceSoftware::GetContext() { - // There is no GrContext associated with a software surface. - return nullptr; -} - } // namespace flutter diff --git a/shell/gpu/gpu_surface_software.h b/shell/gpu/gpu_surface_software.h index 18bc8d5b41446..abec2eb4b9460 100644 --- a/shell/gpu/gpu_surface_software.h +++ b/shell/gpu/gpu_surface_software.h @@ -28,9 +28,6 @@ class GPUSurfaceSoftware : public Surface { // |Surface| SkMatrix GetRootTransformation() const override; - // |Surface| - GrDirectContext* GetContext() override; - private: GPUSurfaceSoftwareDelegate* delegate_; // TODO(38466): Refactor GPU surface APIs take into account the fact that an diff --git a/shell/gpu/gpu_surface_vulkan.cc b/shell/gpu/gpu_surface_vulkan.cc index 2329e74bd7927..b7d32f64a65d7 100644 --- a/shell/gpu/gpu_surface_vulkan.cc +++ b/shell/gpu/gpu_surface_vulkan.cc @@ -95,10 +95,6 @@ SkMatrix GPUSurfaceVulkan::GetRootTransformation() const { return matrix; } -GrDirectContext* GPUSurfaceVulkan::GetContext() { - return skia_context_.get(); -} - sk_sp GPUSurfaceVulkan::CreateSurfaceFromVulkanImage( const VkImage image, const VkFormat format, diff --git a/shell/gpu/gpu_surface_vulkan.h b/shell/gpu/gpu_surface_vulkan.h index c198f7c60e8f4..13bc39fcd33da 100644 --- a/shell/gpu/gpu_surface_vulkan.h +++ b/shell/gpu/gpu_surface_vulkan.h @@ -45,9 +45,6 @@ class GPUSurfaceVulkan : public Surface { // |Surface| SkMatrix GetRootTransformation() const override; - // |Surface| - GrDirectContext* GetContext() override; - static SkColorType ColorTypeFromFormat(const VkFormat format); private: diff --git a/shell/gpu/gpu_surface_vulkan_impeller.cc b/shell/gpu/gpu_surface_vulkan_impeller.cc index b5848cc4c6637..9d4cab79bb3fc 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -103,28 +103,4 @@ SkMatrix GPUSurfaceVulkanImpeller::GetRootTransformation() const { return {}; } -// |Surface| -GrDirectContext* GPUSurfaceVulkanImpeller::GetContext() { - // Impeller != Skia. - return nullptr; -} - -// |Surface| -std::unique_ptr -GPUSurfaceVulkanImpeller::MakeRenderContextCurrent() { - // This backend has no such concept. - return std::make_unique(true); -} - -// |Surface| -bool GPUSurfaceVulkanImpeller::EnableRasterCache() const { - return false; -} - -// |Surface| -std::shared_ptr -GPUSurfaceVulkanImpeller::GetAiksContext() const { - return aiks_context_; -} - } // namespace flutter diff --git a/shell/gpu/gpu_surface_vulkan_impeller.h b/shell/gpu/gpu_surface_vulkan_impeller.h index 7eca3ecd17f43..d0b4787fd7924 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.h +++ b/shell/gpu/gpu_surface_vulkan_impeller.h @@ -37,18 +37,6 @@ class GPUSurfaceVulkanImpeller final : public Surface { // |Surface| SkMatrix GetRootTransformation() const override; - // |Surface| - GrDirectContext* GetContext() override; - - // |Surface| - std::unique_ptr MakeRenderContextCurrent() override; - - // |Surface| - bool EnableRasterCache() const override; - - // |Surface| - std::shared_ptr GetAiksContext() const override; - FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceVulkanImpeller); }; diff --git a/shell/platform/android/android_context_gl_unittests.cc b/shell/platform/android/android_context_gl_unittests.cc index 500ec7e74c313..f81ea854659ba 100644 --- a/shell/platform/android/android_context_gl_unittests.cc +++ b/shell/platform/android/android_context_gl_unittests.cc @@ -88,7 +88,7 @@ TEST(AndroidSurfaceGL, CreateSnapshopSurfaceWhenOnscreenSurfaceIsNotNull) { android_surface->SetNativeWindow(window); auto onscreen_surface = android_surface->GetOnscreenSurface(); EXPECT_NE(onscreen_surface, nullptr); - android_surface->CreateSnapshotSurface(); + android_surface->CreateSnapshotStudio(); EXPECT_EQ(onscreen_surface, android_surface->GetOnscreenSurface()); } @@ -111,7 +111,7 @@ TEST(AndroidSurfaceGL, CreateSnapshopSurfaceWhenOnscreenSurfaceIsNull) { auto android_surface = std::make_unique(android_context); EXPECT_EQ(android_surface->GetOnscreenSurface(), nullptr); - android_surface->CreateSnapshotSurface(); + android_surface->CreateSnapshotStudio(); EXPECT_NE(android_surface->GetOnscreenSurface(), nullptr); } diff --git a/shell/platform/android/android_surface_gl_impeller.cc b/shell/platform/android/android_surface_gl_impeller.cc index 662541ab64b55..646a53ab0f7a3 100644 --- a/shell/platform/android/android_surface_gl_impeller.cc +++ b/shell/platform/android/android_surface_gl_impeller.cc @@ -6,6 +6,7 @@ #include "flutter/fml/logging.h" #include "flutter/impeller/toolkit/egl/surface.h" +#include "flutter/shell/gpu/gpu_studio_gl_impeller.h" #include "flutter/shell/gpu/gpu_surface_gl_impeller.h" namespace flutter { @@ -32,6 +33,19 @@ bool AndroidSurfaceGLImpeller::IsValid() const { return is_valid_; } +// |AndroidSurface| +std::unique_ptr AndroidSurfaceGLImpeller::CreateGPUStudio( + GrDirectContext* gr_context) { + auto studio = std::make_unique( + this, // delegate + android_context_->GetImpellerContext() // context + ); + if (!studio->IsValid()) { + return nullptr; + } + return studio; +} + // |AndroidSurface| std::unique_ptr AndroidSurfaceGLImpeller::CreateGPUSurface( GrDirectContext* gr_context) { @@ -79,7 +93,7 @@ bool AndroidSurfaceGLImpeller::SetNativeWindow( } // |AndroidSurface| -std::unique_ptr AndroidSurfaceGLImpeller::CreateSnapshotSurface() { +std::unique_ptr AndroidSurfaceGLImpeller::CreateSnapshotStudio() { FML_UNREACHABLE(); } diff --git a/shell/platform/android/android_surface_gl_impeller.h b/shell/platform/android/android_surface_gl_impeller.h index 3066a8552ee25..77e38aae38a0e 100644 --- a/shell/platform/android/android_surface_gl_impeller.h +++ b/shell/platform/android/android_surface_gl_impeller.h @@ -26,6 +26,9 @@ class AndroidSurfaceGLImpeller final : public GPUSurfaceGLDelegate, // |AndroidSurface| bool IsValid() const override; + // |AndroidSurface| + std::unique_ptr CreateGPUStudio(GrDirectContext* gr_context) override; + // |AndroidSurface| std::unique_ptr CreateGPUSurface( GrDirectContext* gr_context) override; @@ -46,7 +49,7 @@ class AndroidSurfaceGLImpeller final : public GPUSurfaceGLDelegate, bool SetNativeWindow(fml::RefPtr window) override; // |AndroidSurface| - std::unique_ptr CreateSnapshotSurface() override; + std::unique_ptr CreateSnapshotStudio() override; // |AndroidSurface| std::shared_ptr GetImpellerContext() override; diff --git a/shell/platform/android/android_surface_gl_skia.cc b/shell/platform/android/android_surface_gl_skia.cc index d6ec0c3cf3d96..abd44d205345a 100644 --- a/shell/platform/android/android_surface_gl_skia.cc +++ b/shell/platform/android/android_surface_gl_skia.cc @@ -9,6 +9,8 @@ #include "flutter/fml/logging.h" #include "flutter/fml/memory/ref_ptr.h" +#include "flutter/shell/gpu/gpu_studio_gl_skia.h" +#include "flutter/shell/gpu/gpu_surface_gl_skia.h" #include "flutter/shell/platform/android/android_egl_surface.h" #include "flutter/shell/platform/android/android_shell_holder.h" @@ -47,20 +49,36 @@ bool AndroidSurfaceGLSkia::IsValid() const { return offscreen_surface_ && android_context_->IsValid(); } -std::unique_ptr AndroidSurfaceGLSkia::CreateGPUSurface( +sk_sp AndroidSurfaceGLSkia::UseExistingMainContextOrCreate( GrDirectContext* gr_context) { if (gr_context) { - return std::make_unique(sk_ref_sp(gr_context), this, - true); + return sk_ref_sp(gr_context); } else { sk_sp main_skia_context = android_context_->GetMainSkiaContext(); if (!main_skia_context) { - main_skia_context = GPUSurfaceGLSkia::MakeGLContext(this); + main_skia_context = GPUStudioGLSkia::MakeGLContext(this); android_context_->SetMainSkiaContext(main_skia_context); } - return std::make_unique(main_skia_context, this, true); + FML_DCHECK(android_context_->GetMainSkiaContext() == main_skia_context); + return main_skia_context; + } +} + +std::unique_ptr AndroidSurfaceGLSkia::CreateGPUStudio( + GrDirectContext* gr_context) { + auto studio = std::make_unique( + UseExistingMainContextOrCreate(gr_context), this); + if (!studio->IsValid()) { + return nullptr; } + return studio; +} + +std::unique_ptr AndroidSurfaceGLSkia::CreateGPUSurface( + GrDirectContext* gr_context) { + return std::make_unique( + UseExistingMainContextOrCreate(gr_context), this, true); } bool AndroidSurfaceGLSkia::OnScreenSurfaceResize(const SkISize& size) { @@ -204,18 +222,18 @@ sk_sp AndroidSurfaceGLSkia::GetGLInterface() const { return GPUSurfaceGLDelegate::GetGLInterface(); } -std::unique_ptr AndroidSurfaceGLSkia::CreateSnapshotSurface() { +std::unique_ptr AndroidSurfaceGLSkia::CreateSnapshotStudio() { if (!onscreen_surface_ || !onscreen_surface_->IsValid()) { onscreen_surface_ = android_context_->CreatePbufferSurface(); } sk_sp main_skia_context = android_context_->GetMainSkiaContext(); if (!main_skia_context) { - main_skia_context = GPUSurfaceGLSkia::MakeGLContext(this); + main_skia_context = GPUStudioGLSkia::MakeGLContext(this); android_context_->SetMainSkiaContext(main_skia_context); } - return std::make_unique(main_skia_context, this, true); + return std::make_unique(main_skia_context, this); } } // namespace flutter diff --git a/shell/platform/android/android_surface_gl_skia.h b/shell/platform/android/android_surface_gl_skia.h index 1c35692dc3a0e..98a6d84346f95 100644 --- a/shell/platform/android/android_surface_gl_skia.h +++ b/shell/platform/android/android_surface_gl_skia.h @@ -29,6 +29,9 @@ class AndroidSurfaceGLSkia final : public GPUSurfaceGLDelegate, // |AndroidSurface| bool IsValid() const override; + // |AndroidSurface| + std::unique_ptr CreateGPUStudio(GrDirectContext* gr_context) override; + // |AndroidSurface| std::unique_ptr CreateGPUSurface( GrDirectContext* gr_context) override; @@ -49,7 +52,7 @@ class AndroidSurfaceGLSkia final : public GPUSurfaceGLDelegate, bool SetNativeWindow(fml::RefPtr window) override; // |AndroidSurface| - virtual std::unique_ptr CreateSnapshotSurface() override; + virtual std::unique_ptr CreateSnapshotStudio() override; // |GPUSurfaceGLDelegate| std::unique_ptr GLContextMakeCurrent() override; @@ -86,6 +89,9 @@ class AndroidSurfaceGLSkia final : public GPUSurfaceGLDelegate, std::unique_ptr onscreen_surface_; std::unique_ptr offscreen_surface_; + sk_sp UseExistingMainContextOrCreate( + GrDirectContext* gr_context); + FML_DISALLOW_COPY_AND_ASSIGN(AndroidSurfaceGLSkia); }; diff --git a/shell/platform/android/android_surface_software.cc b/shell/platform/android/android_surface_software.cc index db5881c684b88..8ced9c3253d65 100644 --- a/shell/platform/android/android_surface_software.cc +++ b/shell/platform/android/android_surface_software.cc @@ -11,6 +11,8 @@ #include "flutter/fml/platform/android/jni_weak_ref.h" #include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/fml/trace_event.h" +#include "flutter/shell/gpu/gpu_studio_software.h" +#include "flutter/shell/gpu/gpu_surface_software.h" #include "flutter/shell/platform/android/android_shell_holder.h" #include "flutter/shell/platform/android/jni/platform_view_android_jni.h" @@ -60,6 +62,21 @@ bool AndroidSurfaceSoftware::ResourceContextClearCurrent() { return false; } +std::unique_ptr AndroidSurfaceSoftware::CreateGPUStudio( + GrDirectContext* gr_context) { + if (!IsValid()) { + return nullptr; + } + + auto studio = std::make_unique(this); + + if (!studio->IsValid()) { + return nullptr; + } + + return studio; +} + std::unique_ptr AndroidSurfaceSoftware::CreateGPUSurface( // The software AndroidSurface neither uses any passed in Skia context // nor does it interact with the AndroidContext's raster Skia context. diff --git a/shell/platform/android/android_surface_software.h b/shell/platform/android/android_surface_software.h index 1b7083aa7dda1..3a520ff48fdee 100644 --- a/shell/platform/android/android_surface_software.h +++ b/shell/platform/android/android_surface_software.h @@ -32,6 +32,9 @@ class AndroidSurfaceSoftware final : public AndroidSurface, // |AndroidSurface| bool ResourceContextClearCurrent() override; + // |AndroidSurface| + std::unique_ptr CreateGPUStudio(GrDirectContext* gr_context) override; + // |AndroidSurface| std::unique_ptr CreateGPUSurface( GrDirectContext* gr_context) override; diff --git a/shell/platform/android/android_surface_vulkan_impeller.cc b/shell/platform/android/android_surface_vulkan_impeller.cc index e5d2416af90bb..76dbcfad08d67 100644 --- a/shell/platform/android/android_surface_vulkan_impeller.cc +++ b/shell/platform/android/android_surface_vulkan_impeller.cc @@ -11,6 +11,7 @@ #include "flutter/fml/logging.h" #include "flutter/fml/memory/ref_ptr.h" #include "flutter/impeller/renderer/backend/vulkan/context_vk.h" +#include "flutter/shell/gpu/gpu_studio_vulkan_impeller.h" #include "flutter/shell/gpu/gpu_surface_vulkan_impeller.h" #include "flutter/vulkan/vulkan_native_surface_android.h" @@ -32,6 +33,23 @@ void AndroidSurfaceVulkanImpeller::TeardownOnScreenContext() { // Nothing to do. } +std::unique_ptr AndroidSurfaceVulkanImpeller::CreateGPUStudio( + GrDirectContext* gr_context) { + if (!IsValid()) { + return nullptr; + } + + std::unique_ptr studio = + std::make_unique( + android_context_->GetImpellerContext()); + + if (!studio->IsValid()) { + return nullptr; + } + + return studio; +} + std::unique_ptr AndroidSurfaceVulkanImpeller::CreateGPUSurface( GrDirectContext* gr_context) { if (!IsValid()) { diff --git a/shell/platform/android/android_surface_vulkan_impeller.h b/shell/platform/android/android_surface_vulkan_impeller.h index 548a0a5a4cf69..6b36106bae826 100644 --- a/shell/platform/android/android_surface_vulkan_impeller.h +++ b/shell/platform/android/android_surface_vulkan_impeller.h @@ -23,6 +23,9 @@ class AndroidSurfaceVulkanImpeller : public AndroidSurface { // |AndroidSurface| bool IsValid() const override; + // |AndroidSurface| + std::unique_ptr CreateGPUStudio(GrDirectContext* gr_context) override; + // |AndroidSurface| std::unique_ptr CreateGPUSurface( GrDirectContext* gr_context) override; diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.cc b/shell/platform/android/external_view_embedder/external_view_embedder.cc index f1d8af9f6a710..d2c6bc971d755 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder.cc @@ -293,11 +293,6 @@ void AndroidExternalViewEmbedder::EndFrame( } } -// |ExternalViewEmbedder| -bool AndroidExternalViewEmbedder::SupportsDynamicThreadMerging() { - return true; -} - // |ExternalViewEmbedder| void AndroidExternalViewEmbedder::Teardown() { DestroySurfaces(); diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.h b/shell/platform/android/external_view_embedder/external_view_embedder.h index 03bae5ecb8e1a..15a96fc2c8424 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.h +++ b/shell/platform/android/external_view_embedder/external_view_embedder.h @@ -70,8 +70,6 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { bool should_resubmit_frame, fml::RefPtr raster_thread_merger) override; - bool SupportsDynamicThreadMerging() override; - void Teardown() override; // Gets the rect based on the device pixel ratio of a platform view displayed diff --git a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc index 3c08eef409281..523c48e3b7d77 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc @@ -55,13 +55,6 @@ class SurfaceMock : public Surface { (override)); MOCK_METHOD(SkMatrix, GetRootTransformation, (), (const, override)); - - MOCK_METHOD(GrDirectContext*, GetContext, (), (override)); - - MOCK_METHOD(std::unique_ptr, - MakeRenderContextCurrent, - (), - (override)); }; fml::RefPtr GetThreadMergerFromPlatformThread( @@ -926,13 +919,15 @@ TEST(AndroidExternalViewEmbedder, DoesNotDestroyOverlayLayersOnSizeChange) { GetThreadMergerFromRasterThread(&platform_thread)); } -TEST(AndroidExternalViewEmbedder, SupportsDynamicThreadMerging) { - auto jni_mock = std::make_shared(); - auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); - auto embedder = std::make_unique( - android_context, jni_mock, nullptr, GetTaskRunnersForFixture()); - ASSERT_TRUE(embedder->SupportsDynamicThreadMerging()); -} +// TODO(dkwingsmt): Migrate to a unit test for PlatformViewAndroid, which +// however doesn't have unit tests at all... +// TEST(AndroidExternalViewEmbedder, SupportsDynamicThreadMerging) { +// auto jni_mock = std::make_shared(); +// auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); +// auto embedder = std::make_unique( +// android_context, jni_mock, nullptr, GetTaskRunnersForFixture()); +// ASSERT_TRUE(embedder->SupportsDynamicThreadMerging()); +// } TEST(AndroidExternalViewEmbedder, DisableThreadMerger) { auto jni_mock = std::make_shared(); diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index b89c23a368d27..fd680263a652a 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -295,7 +295,17 @@ std::unique_ptr PlatformViewAndroid::CreateVSyncWaiter() { } // |PlatformView| -std::unique_ptr PlatformViewAndroid::CreateRenderingSurface() { +std::unique_ptr PlatformViewAndroid::CreateRenderingStudio() { + if (!android_surface_) { + return nullptr; + } + return android_surface_->CreateGPUStudio( + android_context_->GetMainSkiaContext().get()); +} + +// |PlatformView| +std::unique_ptr PlatformViewAndroid::CreateRenderingSurface( + int64_t view_id) { if (!android_surface_) { return nullptr; } @@ -310,6 +320,11 @@ PlatformViewAndroid::CreateExternalViewEmbedder() { *android_context_, jni_facade_, surface_factory_, task_runners_); } +// |PlatformView| +bool PlatformViewAndroid::SupportsDynamicThreadMerging() { + return true; +} + // |PlatformView| std::unique_ptr PlatformViewAndroid::CreateSnapshotSurfaceProducer() { diff --git a/shell/platform/android/platform_view_android.h b/shell/platform/android/platform_view_android.h index 300f3ab9b6c13..25c5786dc71b2 100644 --- a/shell/platform/android/platform_view_android.h +++ b/shell/platform/android/platform_view_android.h @@ -143,11 +143,17 @@ class PlatformViewAndroid final : public PlatformView { std::unique_ptr CreateVSyncWaiter() override; // |PlatformView| - std::unique_ptr CreateRenderingSurface() override; + std::unique_ptr CreateRenderingStudio() override; + + // |PlatformView| + std::unique_ptr CreateRenderingSurface(int64_t view_id) override; // |PlatformView| std::shared_ptr CreateExternalViewEmbedder() override; + // |PlatformView| + bool SupportsDynamicThreadMerging() override; + // |PlatformView| std::unique_ptr CreateSnapshotSurfaceProducer() override; diff --git a/shell/platform/android/platform_view_android_jni_impl.cc b/shell/platform/android/platform_view_android_jni_impl.cc index c4580bc0562d7..05637727521f8 100644 --- a/shell/platform/android/platform_view_android_jni_impl.cc +++ b/shell/platform/android/platform_view_android_jni_impl.cc @@ -37,6 +37,8 @@ namespace flutter { +static constexpr int64_t kFlutterDefaultViewId = 0ll; + static fml::jni::ScopedJavaGlobalRef* g_flutter_callback_info_class = nullptr; @@ -338,7 +340,8 @@ static void SetViewportMetrics(JNIEnv* env, 0, // Display ID }; - ANDROID_SHELL_HOLDER->GetPlatformView()->SetViewportMetrics(metrics); + ANDROID_SHELL_HOLDER->GetPlatformView()->SetViewportMetrics( + kFlutterDefaultViewId, metrics); } static void UpdateDisplayMetrics(JNIEnv* env, diff --git a/shell/platform/android/surface/android_surface.cc b/shell/platform/android/surface/android_surface.cc index e301491b5fce0..5a4708629ed63 100644 --- a/shell/platform/android/surface/android_surface.cc +++ b/shell/platform/android/surface/android_surface.cc @@ -11,7 +11,7 @@ AndroidSurface::AndroidSurface() = default; AndroidSurface::~AndroidSurface() = default; -std::unique_ptr AndroidSurface::CreateSnapshotSurface() { +std::unique_ptr AndroidSurface::CreateSnapshotStudio() { return nullptr; } diff --git a/shell/platform/android/surface/android_surface.h b/shell/platform/android/surface/android_surface.h index 7eae6c68e7d71..e726fa3e96113 100644 --- a/shell/platform/android/surface/android_surface.h +++ b/shell/platform/android/surface/android_surface.h @@ -7,6 +7,7 @@ #include #include "flutter/flow/embedded_views.h" +#include "flutter/flow/studio.h" #include "flutter/flow/surface.h" #include "flutter/fml/macros.h" #include "flutter/shell/platform/android/context/android_context.h" @@ -30,6 +31,9 @@ class AndroidSurface { virtual void TeardownOnScreenContext() = 0; + virtual std::unique_ptr CreateGPUStudio( + GrDirectContext* gr_context = nullptr) = 0; + virtual std::unique_ptr CreateGPUSurface( GrDirectContext* gr_context = nullptr) = 0; @@ -41,7 +45,7 @@ class AndroidSurface { virtual bool SetNativeWindow(fml::RefPtr window) = 0; - virtual std::unique_ptr CreateSnapshotSurface(); + virtual std::unique_ptr CreateSnapshotStudio(); virtual std::shared_ptr GetImpellerContext(); diff --git a/shell/platform/android/surface/android_surface_mock.h b/shell/platform/android/surface/android_surface_mock.h index 411816698cb74..a4eb52390ac2d 100644 --- a/shell/platform/android/surface/android_surface_mock.h +++ b/shell/platform/android/surface/android_surface_mock.h @@ -22,6 +22,11 @@ class AndroidSurfaceMock final : public GPUSurfaceGLDelegate, MOCK_METHOD(void, TeardownOnScreenContext, (), (override)); + MOCK_METHOD(std::unique_ptr, + CreateGPUStudio, + (GrDirectContext * gr_context), + (override)); + MOCK_METHOD(std::unique_ptr, CreateGPUSurface, (GrDirectContext * gr_context), diff --git a/shell/platform/android/surface/snapshot_surface_producer.cc b/shell/platform/android/surface/snapshot_surface_producer.cc index 3ca4c37f3ce6a..500db668e3570 100644 --- a/shell/platform/android/surface/snapshot_surface_producer.cc +++ b/shell/platform/android/surface/snapshot_surface_producer.cc @@ -10,9 +10,8 @@ AndroidSnapshotSurfaceProducer::AndroidSnapshotSurfaceProducer( AndroidSurface& android_surface) : android_surface_(android_surface) {} -std::unique_ptr -AndroidSnapshotSurfaceProducer::CreateSnapshotSurface() { - return android_surface_.CreateSnapshotSurface(); +std::unique_ptr AndroidSnapshotSurfaceProducer::CreateSnapshotStudio() { + return android_surface_.CreateSnapshotStudio(); } } // namespace flutter diff --git a/shell/platform/android/surface/snapshot_surface_producer.h b/shell/platform/android/surface/snapshot_surface_producer.h index 5ec8c68b2f457..4c7a9acee49d9 100644 --- a/shell/platform/android/surface/snapshot_surface_producer.h +++ b/shell/platform/android/surface/snapshot_surface_producer.h @@ -5,7 +5,6 @@ #ifndef SHELL_PLATFORM_ANDROID_SURFACE_SNAPSHOT_SURFACE_PRODUCER_H_ #define SHELL_PLATFORM_ANDROID_SURFACE_SNAPSHOT_SURFACE_PRODUCER_H_ -#include "flutter/flow/surface.h" #include "flutter/shell/common/snapshot_surface_producer.h" #include "flutter/shell/platform/android/surface/android_surface.h" @@ -16,7 +15,7 @@ class AndroidSnapshotSurfaceProducer : public SnapshotSurfaceProducer { explicit AndroidSnapshotSurfaceProducer(AndroidSurface& android_surface); // |SnapshotSurfaceProducer| - std::unique_ptr CreateSnapshotSurface() override; + std::unique_ptr CreateSnapshotStudio() override; private: AndroidSurface& android_surface_; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index d8adc04c78abd..eec732332901d 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -38,6 +38,8 @@ #import "flutter/shell/platform/darwin/ios/rendering_api_selection.h" #include "flutter/shell/profiling/sampling_profiler.h" +static constexpr int64_t kFlutterDefaultViewId = 0ll; + /// Inheriting ThreadConfigurer and use iOS platform thread API to configure the thread priorities /// Using iOS platform thread API to configure thread priority static void IOSPlatformThreadConfigSetter(const fml::Thread::ThreadConfig& config) { @@ -308,7 +310,7 @@ - (void)updateViewportMetrics:(flutter::ViewportMetrics)viewportMetrics { if (!self.platformView) { return; } - self.platformView->SetViewportMetrics(viewportMetrics); + self.platformView->SetViewportMetrics(kFlutterDefaultViewId, viewportMetrics); } - (void)dispatchPointerDataPacket:(std::unique_ptr)packet { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm index e4341a065c2af..0305875670f70 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm @@ -20,11 +20,11 @@ class FakeDelegate : public PlatformView::Delegate { public: - void OnPlatformViewCreated(std::unique_ptr surface) override {} + void OnPlatformViewCreated() override {} void OnPlatformViewDestroyed() override {} void OnPlatformViewScheduleFrame() override {} void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) override {} - void OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) override {} + void OnPlatformViewSetViewportMetrics(int64_t view_id, const ViewportMetrics& metrics) override {} const flutter::Settings& OnPlatformViewGetSettings() const override { return settings_; } void OnPlatformViewDispatchPlatformMessage(std::unique_ptr message) override {} void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr packet) override { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 75f62214897d9..4ce072477d475 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -15,6 +15,9 @@ #import "flutter/shell/platform/darwin/ios/platform_view_ios.h" FLUTTER_ASSERT_NOT_ARC + +constexpr int64_t kDefaultViewId = 0ll; + @class FlutterPlatformViewsTestMockPlatformView; static FlutterPlatformViewsTestMockPlatformView* gMockPlatformView = nil; const float kFloatCompareEpsilon = 0.001; @@ -89,11 +92,11 @@ @implementation FlutterPlatformViewsTestMockFlutterPlatformFactory namespace flutter { namespace { class FlutterPlatformViewsTestMockPlatformViewDelegate : public PlatformView::Delegate { - void OnPlatformViewCreated(std::unique_ptr surface) override {} + void OnPlatformViewCreated() override {} void OnPlatformViewDestroyed() override {} void OnPlatformViewScheduleFrame() override {} void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) override {} - void OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) override {} + void OnPlatformViewSetViewportMetrics(int64_t view_id, const ViewportMetrics& metrics) override {} const flutter::Settings& OnPlatformViewGetSettings() const override { return settings_; } void OnPlatformViewDispatchPlatformMessage(std::unique_ptr message) override {} void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr packet) override { diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm index 40995c9111284..987d72e687be4 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm @@ -73,11 +73,11 @@ @implementation MockFlutterPlatformFactory namespace flutter { namespace { class MockDelegate : public PlatformView::Delegate { - void OnPlatformViewCreated(std::unique_ptr surface) override {} + void OnPlatformViewCreated() override {} void OnPlatformViewDestroyed() override {} void OnPlatformViewScheduleFrame() override {} void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) override {} - void OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) override {} + void OnPlatformViewSetViewportMetrics(int64_t view_id, const ViewportMetrics& metrics) override {} const flutter::Settings& OnPlatformViewGetSettings() const override { return settings_; } void OnPlatformViewDispatchPlatformMessage(std::unique_ptr message) override {} void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr packet) override { diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.h b/shell/platform/darwin/ios/ios_external_view_embedder.h index 3893ccec0c1ab..b785d18103faf 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.h +++ b/shell/platform/darwin/ios/ios_external_view_embedder.h @@ -58,9 +58,6 @@ class IOSExternalViewEmbedder : public ExternalViewEmbedder { bool should_resubmit_frame, fml::RefPtr raster_thread_merger) override; - // |ExternalViewEmbedder| - bool SupportsDynamicThreadMerging() override; - // |ExternalViewEmbedder| void PushFilterToVisitedPlatformViews( std::shared_ptr filter, diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.mm b/shell/platform/darwin/ios/ios_external_view_embedder.mm index 4e28b6cfcca82..8aded863ae4ab 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.mm +++ b/shell/platform/darwin/ios/ios_external_view_embedder.mm @@ -81,11 +81,6 @@ platform_views_controller_->EndFrame(should_resubmit_frame, raster_thread_merger); } -// |ExternalViewEmbedder| -bool IOSExternalViewEmbedder::SupportsDynamicThreadMerging() { - return true; -} - // |ExternalViewEmbedder| void IOSExternalViewEmbedder::PushFilterToVisitedPlatformViews( std::shared_ptr filter, diff --git a/shell/platform/darwin/ios/ios_surface.h b/shell/platform/darwin/ios/ios_surface.h index 78394f25781c6..c93eb886f5a25 100644 --- a/shell/platform/darwin/ios/ios_surface.h +++ b/shell/platform/darwin/ios/ios_surface.h @@ -10,6 +10,7 @@ #include #include "flutter/flow/embedded_views.h" +#include "flutter/flow/studio.h" #include "flutter/flow/surface.h" #include "flutter/fml/macros.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" @@ -35,6 +36,8 @@ class IOSSurface { virtual void UpdateStorageSizeIfNecessary() = 0; + virtual std::unique_ptr CreateGPUStudio(GrDirectContext* gr_context = nullptr) = 0; + // Creates a GPU surface. If no GrDirectContext is supplied and the rendering mode // supports one, a new one will be created; otherwise, the software backend // will be used. diff --git a/shell/platform/darwin/ios/ios_surface_metal_impeller.h b/shell/platform/darwin/ios/ios_surface_metal_impeller.h index 6c3615318a9ca..9f29a9cc68dc3 100644 --- a/shell/platform/darwin/ios/ios_surface_metal_impeller.h +++ b/shell/platform/darwin/ios/ios_surface_metal_impeller.h @@ -38,6 +38,9 @@ class SK_API_AVAILABLE_CA_METAL_LAYER IOSSurfaceMetalImpeller final // |IOSSurface| void UpdateStorageSizeIfNecessary() override; + // |IOSSurface| + std::unique_ptr CreateGPUStudio(GrDirectContext* gr_context) override; + // |IOSSurface| std::unique_ptr CreateGPUSurface(GrDirectContext* gr_context) override; diff --git a/shell/platform/darwin/ios/ios_surface_metal_impeller.mm b/shell/platform/darwin/ios/ios_surface_metal_impeller.mm index b025f4de59cb4..ee429fd4ffa2a 100644 --- a/shell/platform/darwin/ios/ios_surface_metal_impeller.mm +++ b/shell/platform/darwin/ios/ios_surface_metal_impeller.mm @@ -6,6 +6,7 @@ #include "flutter/impeller/renderer/backend/metal/formats_mtl.h" #include "flutter/impeller/renderer/context.h" +#include "flutter/shell/gpu/gpu_studio_metal_impeller.h" #include "flutter/shell/gpu/gpu_surface_metal_impeller.h" namespace flutter { @@ -35,6 +36,15 @@ // Nothing to do. } +// |IOSSurface| +std::unique_ptr IOSSurfaceMetalImpeller::CreateGPUStudio(GrDirectContext*) { + impeller_context_->UpdateOffscreenLayerPixelFormat( + impeller::FromMTLPixelFormat(layer_.get().pixelFormat)); + return std::make_unique(this, // + impeller_context_ // + ); +} + // |IOSSurface| std::unique_ptr IOSSurfaceMetalImpeller::CreateGPUSurface(GrDirectContext*) { impeller_context_->UpdateOffscreenLayerPixelFormat( diff --git a/shell/platform/darwin/ios/ios_surface_metal_skia.h b/shell/platform/darwin/ios/ios_surface_metal_skia.h index efd174b07e09d..43f6dd1268ae9 100644 --- a/shell/platform/darwin/ios/ios_surface_metal_skia.h +++ b/shell/platform/darwin/ios/ios_surface_metal_skia.h @@ -28,6 +28,7 @@ class SK_API_AVAILABLE_CA_METAL_LAYER IOSSurfaceMetalSkia final : public IOSSurf id device_; id command_queue_; bool is_valid_ = false; + std::shared_ptr sksl_precompiler_; // |IOSSurface| bool IsValid() const override; @@ -35,6 +36,9 @@ class SK_API_AVAILABLE_CA_METAL_LAYER IOSSurfaceMetalSkia final : public IOSSurf // |IOSSurface| void UpdateStorageSizeIfNecessary() override; + // |IOSSurface| + std::unique_ptr CreateGPUStudio(GrDirectContext* gr_context = nullptr) override; + // |IOSSurface| std::unique_ptr CreateGPUSurface(GrDirectContext* gr_context) override; diff --git a/shell/platform/darwin/ios/ios_surface_metal_skia.mm b/shell/platform/darwin/ios/ios_surface_metal_skia.mm index d010c181daa9b..2c45d4de60f16 100644 --- a/shell/platform/darwin/ios/ios_surface_metal_skia.mm +++ b/shell/platform/darwin/ios/ios_surface_metal_skia.mm @@ -4,6 +4,7 @@ #import "flutter/shell/platform/darwin/ios/ios_surface_metal_skia.h" +#include "flutter/shell/gpu/gpu_studio_metal_skia.h" #include "flutter/shell/gpu/gpu_surface_metal_delegate.h" #include "flutter/shell/gpu/gpu_surface_metal_skia.h" #include "flutter/shell/platform/darwin/ios/ios_context_metal_skia.h" @@ -24,6 +25,7 @@ auto darwin_context = metal_context->GetDarwinContext().get(); command_queue_ = darwin_context.commandQueue; device_ = darwin_context.device; + sksl_precompiler_ = std::make_shared(); } // |IOSSurface| @@ -39,13 +41,21 @@ // Nothing to do. } +// |IOSSurface| +std::unique_ptr IOSSurfaceMetalSkia::CreateGPUStudio(GrDirectContext* context) { + FML_DCHECK(context); + return std::make_unique(this, // delegate + sk_ref_sp(context), // context + sksl_precompiler_); +} + // |IOSSurface| std::unique_ptr IOSSurfaceMetalSkia::CreateGPUSurface(GrDirectContext* context) { FML_DCHECK(context); - return std::make_unique(this, // delegate - sk_ref_sp(context), // context - GetContext()->GetMsaaSampleCount() // sample count - ); + return std::make_unique(this, // delegate + sk_ref_sp(context), // context + GetContext()->GetMsaaSampleCount(), // sample count + sksl_precompiler_); } // |GPUSurfaceMetalDelegate| diff --git a/shell/platform/darwin/ios/ios_surface_software.h b/shell/platform/darwin/ios/ios_surface_software.h index e1ed6b69518c0..e0529df886bf1 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -31,6 +31,9 @@ class IOSSurfaceSoftware final : public IOSSurface, public GPUSurfaceSoftwareDel // |IOSSurface| void UpdateStorageSizeIfNecessary() override; + // |IOSSurface| + std::unique_ptr CreateGPUStudio(GrDirectContext* gr_context = nullptr) override; + // |IOSSurface| std::unique_ptr CreateGPUSurface(GrDirectContext* gr_context = nullptr) override; diff --git a/shell/platform/darwin/ios/ios_surface_software.mm b/shell/platform/darwin/ios/ios_surface_software.mm index 736d8dc488127..727cd2b978b00 100644 --- a/shell/platform/darwin/ios/ios_surface_software.mm +++ b/shell/platform/darwin/ios/ios_surface_software.mm @@ -11,6 +11,8 @@ #include "flutter/fml/logging.h" #include "flutter/fml/platform/darwin/cf_utils.h" #include "flutter/fml/trace_event.h" +#include "flutter/shell/gpu/gpu_studio_software.h" +#include "flutter/shell/gpu/gpu_surface_software.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/utils/mac/SkCGUtils.h" @@ -34,6 +36,20 @@ // Android oddities. } +std::unique_ptr IOSSurfaceSoftware::CreateGPUStudio(GrDirectContext* gr_context) { + if (!IsValid()) { + return nullptr; + } + + auto studio = std::make_unique(this); + + if (!studio->IsValid()) { + return nullptr; + } + + return studio; +} + std::unique_ptr IOSSurfaceSoftware::CreateGPUSurface(GrDirectContext* gr_context) { if (!IsValid()) { return nullptr; diff --git a/shell/platform/darwin/ios/platform_message_handler_ios_test.mm b/shell/platform/darwin/ios/platform_message_handler_ios_test.mm index f1af3bef93ab0..92164577651af 100644 --- a/shell/platform/darwin/ios/platform_message_handler_ios_test.mm +++ b/shell/platform/darwin/ios/platform_message_handler_ios_test.mm @@ -44,8 +44,8 @@ @interface PlatformMessageHandlerIosTest : XCTestCase @implementation PlatformMessageHandlerIosTest - (void)testCreate { - flutter::TaskRunners task_runners("test", GetCurrentTaskRunner(), CreateNewThread("raster"), - CreateNewThread("ui"), CreateNewThread("io")); + TaskRunners task_runners("test", GetCurrentTaskRunner(), CreateNewThread("raster"), + CreateNewThread("ui"), CreateNewThread("io")); auto handler = std::make_unique(task_runners.GetPlatformTaskRunner()); XCTAssertTrue(handler); } diff --git a/shell/platform/darwin/ios/platform_view_ios.h b/shell/platform/darwin/ios/platform_view_ios.h index fa48ce8ee309b..510d51deba038 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -151,11 +151,17 @@ class PlatformViewIOS final : public PlatformView { void HandlePlatformMessage(std::unique_ptr message) override; // |PlatformView| - std::unique_ptr CreateRenderingSurface() override; + std::unique_ptr CreateRenderingStudio() override; + + // |PlatformView| + std::unique_ptr CreateRenderingSurface(int64_t view_id) override; // |PlatformView| std::shared_ptr CreateExternalViewEmbedder() override; + // |PlatformView| + bool SupportsDynamicThreadMerging() override; + // |PlatformView| sk_sp CreateResourceContext() const override; diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm index 61095c81d71a9..2bcef0a1b5677 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -142,7 +142,19 @@ new PlatformMessageHandlerIos(task_runners.GetPlatformTaskRunner())) {} } // |PlatformView| -std::unique_ptr PlatformViewIOS::CreateRenderingSurface() { +std::unique_ptr PlatformViewIOS::CreateRenderingStudio() { + FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread()); + std::lock_guard guard(ios_surface_mutex_); + if (!ios_surface_) { + FML_DLOG(INFO) << "Could not CreateRenderingSurface, this PlatformViewIOS " + "has no ViewController."; + return nullptr; + } + return ios_surface_->CreateGPUStudio(ios_context_->GetMainContext().get()); +} + +// |PlatformView| +std::unique_ptr PlatformViewIOS::CreateRenderingSurface(int64_t view_id) { FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread()); std::lock_guard guard(ios_surface_mutex_); if (!ios_surface_) { @@ -158,6 +170,11 @@ new PlatformMessageHandlerIos(task_runners.GetPlatformTaskRunner())) {} return std::make_shared(platform_views_controller_, ios_context_); } +// |PlatformView| +bool PlatformViewIOS::SupportsDynamicThreadMerging() { + return true; +} + // |PlatformView| sk_sp PlatformViewIOS::CreateResourceContext() const { return ios_context_->CreateResourceContext(); diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h index ce22bb9f54916..fd96194b94ad1 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h @@ -27,8 +27,9 @@ class FlutterCompositor { // The view_provider is used to query FlutterViews from view IDs, // which are used for presenting and creating backing stores. // It must not be null, and is typically FlutterViewEngineProvider. - explicit FlutterCompositor(id view_provider, - FlutterPlatformViewController* platform_views_controller); + FlutterCompositor(id view_provider, + int64_t view_id, + FlutterPlatformViewController* platform_views_controller); ~FlutterCompositor() = default; @@ -47,9 +48,9 @@ class FlutterCompositor { bool CreateBackingStore(const FlutterBackingStoreConfig* config, FlutterBackingStore* backing_store_out); - // Presents the FlutterLayers by updating the FlutterView specified by - // `view_id` using the layer content. Sets frame_started_ to false. - bool Present(FlutterViewId view_id, const FlutterLayer** layers, size_t layers_count); + // Presents the FlutterLayers by updating the FlutterView. Sets frame_started_ + // to false. + bool Present(const FlutterLayer** layers, size_t layers_count); private: void PresentPlatformViews(FlutterView* default_base_view, @@ -63,8 +64,8 @@ class FlutterCompositor { const FlutterLayer* layer, size_t layer_position); - // Where the compositor can query FlutterViews. Must not be null. id const view_provider_; + int64_t view_id_; // The controller used to manage creation and deletion of platform views. const FlutterPlatformViewController* platform_view_controller_; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm index 3da1c44edf0c4..38e4219aa67cb 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm @@ -10,19 +10,18 @@ namespace flutter { FlutterCompositor::FlutterCompositor(id view_provider, + int64_t view_id, FlutterPlatformViewController* platform_view_controller) : view_provider_(view_provider), + view_id_(view_id), platform_view_controller_(platform_view_controller), mutator_views_([NSMapTable strongToStrongObjectsMapTable]) { - FML_CHECK(view_provider != nullptr) << "view_provider cannot be nullptr"; + FML_CHECK(view_provider_ != nullptr) << "view provider cannot be nullptr"; } bool FlutterCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config, FlutterBackingStore* backing_store_out) { - // TODO(dkwingsmt): This class only supports single-view for now. As more - // classes are gradually converted to multi-view, it should get the view ID - // from somewhere. - FlutterView* view = [view_provider_ viewForId:kFlutterDefaultViewId]; + FlutterView* view = [view_provider_ viewForId:view_id_]; if (!view) { return false; } @@ -37,10 +36,8 @@ return true; } -bool FlutterCompositor::Present(FlutterViewId view_id, - const FlutterLayer** layers, - size_t layers_count) { - FlutterView* view = [view_provider_ viewForId:view_id]; +bool FlutterCompositor::Present(const FlutterLayer** layers, size_t layers_count) { + FlutterView* view = [view_provider_ viewForId:view_id_]; if (!view) { return false; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm index f7ac37e01be68..60d82d065591e 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm @@ -87,7 +87,7 @@ - (nullable FlutterView*)viewForId:(FlutterViewId)viewId { TEST(FlutterCompositorTest, TestCreate) { std::unique_ptr macos_compositor = - std::make_unique(MockViewProvider(), + std::make_unique(MockViewProvider(), kFlutterDefaultViewId, /*platform_view_controller*/ nullptr); FlutterBackingStore backing_store; @@ -95,7 +95,7 @@ - (nullable FlutterView*)viewForId:(FlutterViewId)viewId { config.struct_size = sizeof(FlutterBackingStoreConfig); config.size.width = 800; config.size.height = 600; - macos_compositor->CreateBackingStore(&config, &backing_store); + ASSERT_TRUE(macos_compositor->CreateBackingStore(&config, &backing_store)); ASSERT_EQ(backing_store.type, kFlutterBackingStoreTypeMetal); ASSERT_NE(backing_store.metal.texture.texture, nil); @@ -112,7 +112,7 @@ - (nullable FlutterView*)viewForId:(FlutterViewId)viewId { }; std::unique_ptr macos_compositor = - std::make_unique(MockViewProvider(onPresent), + std::make_unique(MockViewProvider(onPresent), kFlutterDefaultViewId, /*platform_view_controller*/ nullptr); FlutterBackingStore backing_store; @@ -131,7 +131,7 @@ - (nullable FlutterView*)viewForId:(FlutterViewId)viewId { }}; const FlutterLayer* layers_ptr = layers; - macos_compositor->Present(kFlutterDefaultViewId, &layers_ptr, 1); + macos_compositor->Present(&layers_ptr, 1); ASSERT_EQ(presentedSurfaces.count, 1ul); } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 2be2f6b70af8f..c382a99bcc8a2 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -47,6 +47,36 @@ static FlutterLocale FlutterLocaleFromNSLocale(NSLocale* locale) { @"NSApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification"; static NSString* const kEnhancedUserInterfaceKey = @"AXEnhancedUserInterface"; +static FlutterCompositor createFlutterCompositorFor(flutter::FlutterCompositor* macOSCompositor) { + FlutterCompositor compositor; + compositor = {}; + compositor.struct_size = sizeof(FlutterCompositor); + compositor.user_data = macOSCompositor; + + compositor.create_backing_store_callback = [](const FlutterBackingStoreConfig* config, // + FlutterBackingStore* backing_store_out, // + void* user_data // + ) { + return reinterpret_cast(user_data)->CreateBackingStore( + config, backing_store_out); + }; + + compositor.collect_backing_store_callback = [](const FlutterBackingStore* backing_store, // + void* user_data // + ) { return true; }; + + compositor.present_layers_callback = [](const FlutterLayer** layers, // + size_t layers_count, // + void* user_data // + ) { + return reinterpret_cast(user_data)->Present(layers, layers_count); + }; + + compositor.avoid_backing_store_cache = true; + + return compositor; +} + /// Clipboard plain text format. constexpr char kTextPlainFormat[] = "text/plain"; @@ -77,6 +107,44 @@ - (instancetype)initWithConnection:(NSNumber*)connection #pragma mark - +@interface FlutterEngineViewRecord : NSObject + +- (nullable instancetype)initWithViewController:(nonnull FlutterViewController*)controller + macOSCompositor: + (std::shared_ptr)macOSCompositor + compositor:(FlutterCompositor)compositor; + +@property(nonatomic, weak) FlutterViewController* controller; + +@end + +@implementation FlutterEngineViewRecord { + __weak FlutterViewController* _controller; + + // _macOSCompositor is created when the engine is created and its destruction is handled by ARC + // when the engine is destroyed. + std::shared_ptr _macOSCompositor; + + // FlutterCompositor is copied and used in embedder.cc. + FlutterCompositor _compositor; +} + +@synthesize controller = _controller; + +- (instancetype)initWithViewController:(FlutterViewController*)controller + macOSCompositor:(std::shared_ptr)macOSCompositor + compositor:(FlutterCompositor)compositor { + self = [super init]; + NSAssert(self, @"Super init cannot be nil"); + _controller = controller; + _macOSCompositor = macOSCompositor; + _compositor = compositor; + return self; +} +@end + +#pragma mark - + /** * Private interface declaration for FlutterEngine. */ @@ -361,17 +429,15 @@ @implementation FlutterEngine { // Pointer to the Dart AOT snapshot and instruction data. _FlutterEngineAOTData* _aotData; + // The information of all views attached to this engine mapped from IDs. + NSMutableDictionary* _viewRecords; + // _macOSCompositor is created when the engine is created and its destruction is handled by ARC // when the engine is destroyed. - std::unique_ptr _macOSCompositor; - - // The information of all views attached to this engine mapped from IDs. - // - // It can't use NSDictionary, because the values need to be weak references. - NSMapTable* _viewControllers; + std::shared_ptr _implicitMacOSCompositor; // FlutterCompositor is copied and used in embedder.cc. - FlutterCompositor _compositor; + FlutterCompositor _implicitCompositor; // Method channel for platform view functions. These functions include creating, disposing and // mutating a platform view. @@ -429,7 +495,7 @@ - (instancetype)initWithName:(NSString*)labelPrefix _embedderAPI.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&_embedderAPI); - _viewControllers = [NSMapTable weakToWeakObjectsMapTable]; + _viewRecords = [NSMutableDictionary dictionary]; _renderer = [[FlutterRenderer alloc] initWithFlutterEngine:self]; NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter]; @@ -447,6 +513,11 @@ - (instancetype)initWithName:(NSString*)labelPrefix reinterpret_cast([[NSApplication sharedApplication] delegate]); [appDelegate addApplicationLifecycleDelegate:self]; + _implicitMacOSCompositor = std::make_shared( + [[FlutterViewEngineProvider alloc] initWithEngine:self], kFlutterDefaultViewId, + _platformViewController); + _implicitCompositor = createFlutterCompositorFor(_implicitMacOSCompositor.get()); + return self; } @@ -471,7 +542,7 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { return NO; } - if (!_allowHeadlessExecution && [_viewControllers count] == 0) { + if (!_allowHeadlessExecution && [_viewRecords count] == 0) { NSLog(@"Attempted to run an engine with no view controller without headless mode enabled."); return NO; } @@ -542,7 +613,7 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { flutterArguments.aot_data = _aotData; } - flutterArguments.compositor = [self createFlutterCompositor]; + flutterArguments.compositor = &_implicitCompositor; flutterArguments.on_pre_engine_restart_callback = [](void* user_data) { FlutterEngine* engine = (__bridge FlutterEngine*)user_data; @@ -566,10 +637,8 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { [self sendUserLocales]; // Update window metric for all view controllers. - NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; - FlutterViewController* nextViewController; - while ((nextViewController = [viewControllerEnumerator nextObject])) { - [self updateWindowMetricsForViewController:nextViewController]; + for (id viewId in _viewRecords) { + [self updateWindowMetricsForViewController:_viewRecords[viewId].controller]; } [self updateDisplayConfig]; @@ -609,41 +678,52 @@ - (void)registerViewController:(FlutterViewController*)controller forId:(Flutter NSAssert(controller != nil, @"The controller must not be nil."); NSAssert(![controller attached], @"The incoming view controller is already attached to an engine."); - NSAssert([_viewControllers objectForKey:@(viewId)] == nil, @"The requested view ID is occupied."); + NSAssert(_viewRecords[@(viewId)] == nil, @"The requested view ID is occupied."); [controller setUpWithEngine:self viewId:viewId threadSynchronizer:_threadSynchronizer]; NSAssert(controller.viewId == viewId, @"Failed to assign view ID."); - [_viewControllers setObject:controller forKey:@(viewId)]; + const bool isImplicitView = viewId == kFlutterDefaultViewId; + auto macOSCompositor = isImplicitView + ? _implicitMacOSCompositor + : std::make_shared( + [[FlutterViewEngineProvider alloc] initWithEngine:self], viewId, + _platformViewController); + FlutterCompositor compositor = + isImplicitView ? _implicitCompositor : createFlutterCompositorFor(macOSCompositor.get()); + NSAssert(macOSCompositor, @"No macOSCompositor"); + NSAssert(compositor.create_backing_store_callback, @"Invalid compositor"); + _viewRecords[@(viewId)] = [[FlutterEngineViewRecord alloc] initWithViewController:controller + macOSCompositor:macOSCompositor + compositor:compositor]; } - (void)deregisterViewControllerForId:(FlutterViewId)viewId { - FlutterViewController* oldController = [self viewControllerForId:viewId]; - if (oldController != nil) { - [oldController detachFromEngine]; - [_viewControllers removeObjectForKey:@(viewId)]; + FlutterEngineViewRecord* oldRecord = _viewRecords[@(viewId)]; + if (oldRecord.controller != nil) { + [oldRecord.controller detachFromEngine]; } + [_viewRecords removeObjectForKey:@(viewId)]; } - (void)shutDownIfNeeded { - if ([_viewControllers count] == 0 && !_allowHeadlessExecution) { + if ([_viewRecords count] == 0 && !_allowHeadlessExecution) { [self shutDownEngine]; } } - (FlutterViewController*)viewControllerForId:(FlutterViewId)viewId { - FlutterViewController* controller = [_viewControllers objectForKey:@(viewId)]; - NSAssert(controller == nil || controller.viewId == viewId, + FlutterEngineViewRecord* viewRecord = _viewRecords[@(viewId)]; + NSAssert(viewRecord == nil || viewRecord.controller.viewId == viewId, @"The stored controller has unexpected view ID."); - return controller; + return viewRecord.controller; } - (void)setViewController:(FlutterViewController*)controller { - FlutterViewController* currentController = - [_viewControllers objectForKey:@(kFlutterDefaultViewId)]; - if (currentController == controller) { + FlutterEngineViewRecord* currentViewRecord = _viewRecords[@(kFlutterDefaultViewId)]; + if (currentViewRecord.controller == controller) { // From nil to nil, or from non-nil to the same controller. return; } - if (currentController == nil && controller != nil) { + if (currentViewRecord == nil && controller != nil) { // From nil to non-nil. NSAssert(controller.engine == nil, @"Failed to set view controller to the engine: " @@ -652,9 +732,10 @@ - (void)setViewController:(FlutterViewController*)controller { @"you should use FlutterViewController#init(engine:, nibName, bundle:) instead.", controller.engine); [self registerViewController:controller forId:kFlutterDefaultViewId]; - } else if (currentController != nil && controller == nil) { - NSAssert(currentController.viewId == kFlutterDefaultViewId, - @"The default controller has an unexpected ID %llu", currentController.viewId); + } else if (currentViewRecord != nil && controller == nil) { + NSAssert(currentViewRecord.controller.viewId == kFlutterDefaultViewId, + @"The default controller has an unexpected ID %llu", + currentViewRecord.controller.viewId); // From non-nil to nil. [self deregisterViewControllerForId:kFlutterDefaultViewId]; [self shutDownIfNeeded]; @@ -665,7 +746,7 @@ - (void)setViewController:(FlutterViewController*)controller { @"The engine already has a default view controller %@. " @"If you wanted to make the default view render in a different window, " @"you should attach the current view controller to the window instead.", - [_viewControllers objectForKey:@(kFlutterDefaultViewId)]); + currentViewRecord.controller); } } @@ -673,42 +754,6 @@ - (FlutterViewController*)viewController { return [self viewControllerForId:kFlutterDefaultViewId]; } -- (FlutterCompositor*)createFlutterCompositor { - _macOSCompositor = std::make_unique( - [[FlutterViewEngineProvider alloc] initWithEngine:self], _platformViewController); - - _compositor = {}; - _compositor.struct_size = sizeof(FlutterCompositor); - _compositor.user_data = _macOSCompositor.get(); - - _compositor.create_backing_store_callback = [](const FlutterBackingStoreConfig* config, // - FlutterBackingStore* backing_store_out, // - void* user_data // - ) { - return reinterpret_cast(user_data)->CreateBackingStore( - config, backing_store_out); - }; - - _compositor.collect_backing_store_callback = [](const FlutterBackingStore* backing_store, // - void* user_data // - ) { return true; }; - - _compositor.present_layers_callback = [](const FlutterLayer** layers, // - size_t layers_count, // - void* user_data // - ) { - // TODO(dkwingsmt): This callback only supports single-view, therefore it - // only operates on the default view. To support multi-view, we need a new - // callback that also receives a view ID. - return reinterpret_cast(user_data)->Present(kFlutterDefaultViewId, - layers, layers_count); - }; - - _compositor.avoid_backing_store_cache = true; - - return &_compositor; -} - - (id)binaryMessenger { // TODO(stuartmorgan): Switch to FlutterBinaryMessengerRelay to avoid plugins // keeping the engine alive. @@ -805,12 +850,6 @@ - (nonnull NSString*)executableName { } - (void)updateWindowMetricsForViewController:(FlutterViewController*)viewController { - if (viewController.viewId != kFlutterDefaultViewId) { - // TODO(dkwingsmt): The embedder API only supports single-view for now. As - // embedder APIs are converted to multi-view, this method should support any - // views. - return; - } if (!_engine || !viewController || !viewController.viewLoaded) { return; } @@ -830,7 +869,7 @@ - (void)updateWindowMetricsForViewController:(FlutterViewController*)viewControl .top = static_cast(scaledBounds.origin.y), .display_id = static_cast(displayId), }; - _embedderAPI.SendWindowMetricsEvent(_engine, &windowMetricsEvent); + _embedderAPI.SendWindowMetricsEvent(_engine, viewController.viewId, &windowMetricsEvent); } - (void)sendPointerEvent:(const FlutterPointerEvent&)event { @@ -850,10 +889,8 @@ - (void)setSemanticsEnabled:(BOOL)enabled { _semanticsEnabled = enabled; // Update all view controllers' bridges. - NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; - FlutterViewController* nextViewController; - while ((nextViewController = [viewControllerEnumerator nextObject])) { - [nextViewController notifySemanticsEnabledChanged]; + for (id viewId in _viewRecords) { + [_viewRecords[viewId].controller notifySemanticsEnabledChanged]; } _embedderAPI.UpdateSemanticsEnabled(_engine, _semanticsEnabled); @@ -934,10 +971,8 @@ - (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message { } - (void)engineCallbackOnPreEngineRestart { - NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; - FlutterViewController* nextViewController; - while ((nextViewController = [viewControllerEnumerator nextObject])) { - [nextViewController onPreEngineRestart]; + for (id viewId in _viewRecords) { + [_viewRecords[viewId].controller onPreEngineRestart]; } } @@ -1034,19 +1069,15 @@ - (void)applicationWillTerminate:(NSNotification*)notification { - (void)windowDidChangeScreen:(NSNotification*)notification { // Update window metric for all view controllers since the display_id has // changed. - NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; - FlutterViewController* nextViewController; - while ((nextViewController = [viewControllerEnumerator nextObject])) { - [self updateWindowMetricsForViewController:nextViewController]; + for (id viewId in _viewRecords) { + [self updateWindowMetricsForViewController:_viewRecords[viewId].controller]; } } - (void)onAccessibilityStatusChanged:(NSNotification*)notification { BOOL enabled = [notification.userInfo[kEnhancedUserInterfaceKey] boolValue]; - NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; - FlutterViewController* nextViewController; - while ((nextViewController = [viewControllerEnumerator nextObject])) { - [nextViewController onAccessibilityStatusChanged:enabled]; + for (id viewId in _viewRecords) { + [_viewRecords[viewId].controller onAccessibilityStatusChanged:enabled]; } self.semanticsEnabled = enabled; @@ -1338,7 +1369,7 @@ - (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)t // Getter used by test harness, only exposed through the FlutterEngine(Test) category - (flutter::FlutterCompositor*)macOSCompositor { - return _macOSCompositor.get(); + return _implicitMacOSCompositor.get(); } @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm index 60e8bc363f8df..10abab8a52a94 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm @@ -15,6 +15,7 @@ #include "flutter/shell/platform/common/accessibility_bridge.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h" #import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h" #include "flutter/shell/platform/embedder/embedder.h" diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h index 71fe5481cf72b..947c54d7a2ce1 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h @@ -11,7 +11,6 @@ #include "flutter/shell/platform/common/app_lifecycle_state.h" #import "flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMac.h" -#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h" @@ -110,6 +109,8 @@ typedef NS_ENUM(NSInteger, FlutterAppExitResponse) { */ @property(nonatomic, readonly) FlutterEngineTerminationHandler* terminationHandler; +@property(nonatomic, readonly) FlutterThreadSynchronizer* synchronizer; + /** * Attach a view controller to the engine as its default controller. * diff --git a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm index 63c4df7d5eec0..1f85589db9d98 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm @@ -36,6 +36,8 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine, @implementation FlutterRenderer { FlutterDarwinContextMetalSkia* _darwinMetalContext; + + NSMutableDictionary* _texture_to_view; } - (instancetype)initWithFlutterEngine:(nonnull FlutterEngine*)flutterEngine { @@ -55,6 +57,7 @@ - (instancetype)initWithFlutterEngine:(nonnull FlutterEngine*)flutterEngine { _darwinMetalContext = [[FlutterDarwinContextMetalSkia alloc] initWithMTLDevice:_device commandQueue:_commandQueue]; + _texture_to_view = [NSMutableDictionary dictionary]; } return self; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterView.mm b/shell/platform/darwin/macos/framework/Source/FlutterView.mm index 89bbdb9153828..caccecdff79e5 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterView.mm @@ -12,8 +12,8 @@ @interface FlutterView () { int64_t _viewId; __weak id _reshapeListener; - FlutterThreadSynchronizer* _threadSynchronizer; FlutterSurfaceManager* _surfaceManager; + FlutterThreadSynchronizer* _threadSynchronizer; } @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index 5129ef4ebe0f0..cae4ebe4107ed 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -486,6 +486,10 @@ - (void)viewWillAppear { [self listenForMetaModifiedKeyUpEvents]; } +- (void)viewDidAppear { + [_engine updateWindowMetricsForViewController:self]; +} + - (void)viewWillDisappear { // Per Apple's documentation, it is discouraged to call removeMonitor: in dealloc, and it's // recommended to be called earlier in the lifecycle. diff --git a/shell/platform/embedder/BUILD.gn b/shell/platform/embedder/BUILD.gn index 9c827ac38bd3c..4ab53a130873a 100644 --- a/shell/platform/embedder/BUILD.gn +++ b/shell/platform/embedder/BUILD.gn @@ -76,6 +76,9 @@ template("embedder_source_set") { "embedder_render_target_cache.cc", "embedder_render_target_cache.h", "embedder_struct_macros.h", + "embedder_studio.h", + "embedder_studio_software.cc", + "embedder_studio_software.h", "embedder_surface.cc", "embedder_surface.h", "embedder_surface_software.cc", @@ -95,6 +98,8 @@ template("embedder_source_set") { sources += [ "embedder_external_texture_gl.cc", "embedder_external_texture_gl.h", + "embedder_studio_gl.cc", + "embedder_studio_gl.h", "embedder_surface_gl.cc", "embedder_surface_gl.h", ] @@ -120,6 +125,8 @@ template("embedder_source_set") { sources += [ "embedder_external_texture_metal.h", "embedder_external_texture_metal.mm", + "embedder_studio_metal.h", + "embedder_studio_metal.mm", "embedder_surface_metal.h", "embedder_surface_metal.mm", ] @@ -132,6 +139,8 @@ template("embedder_source_set") { if (embedder_enable_vulkan) { sources += [ + "embedder_studio_vulkan.cc", + "embedder_studio_vulkan.h", "embedder_surface_vulkan.cc", "embedder_surface_vulkan.h", ] diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 17df21bf1f6a2..162e1354cf807 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -56,6 +56,7 @@ extern const intptr_t kPlatformStrongDillSize; #include "flutter/shell/platform/embedder/embedder_platform_message_response.h" #include "flutter/shell/platform/embedder/embedder_render_target.h" #include "flutter/shell/platform/embedder/embedder_struct_macros.h" +#include "flutter/shell/platform/embedder/embedder_studio_software.h" #include "flutter/shell/platform/embedder/embedder_task_runner.h" #include "flutter/shell/platform/embedder/embedder_thread_host.h" #include "flutter/shell/platform/embedder/pixel_formats.h" @@ -65,13 +66,18 @@ extern const intptr_t kPlatformStrongDillSize; #ifdef SHELL_ENABLE_GL #include "flutter/shell/platform/embedder/embedder_external_texture_gl.h" +#include "flutter/shell/platform/embedder/embedder_studio_gl.h" #endif #ifdef SHELL_ENABLE_METAL -#include "flutter/shell/platform/embedder/embedder_surface_metal.h" +#include "flutter/shell/platform/embedder/embedder_studio_metal.h" #include "third_party/skia/include/ports/SkCFObject.h" #endif +#ifdef SHELL_ENABLE_VULKAN +#include "flutter/shell/platform/embedder/embedder_studio_vulkan.h" +#endif + const int32_t kFlutterSemanticsNodeIdBatchEnd = -1; const int32_t kFlutterSemanticsCustomActionIdBatchEnd = -1; @@ -418,7 +424,7 @@ InferOpenGLPlatformViewCreationCallback( bool fbo_reset_after_present = SAFE_ACCESS(open_gl_config, fbo_reset_after_present, false); - flutter::EmbedderSurfaceGL::GLDispatchTable gl_dispatch_table = { + flutter::EmbedderStudioGL::GLDispatchTable gl_dispatch_table = { gl_make_current, // gl_make_current_callback gl_clear_current, // gl_clear_current_callback gl_present, // gl_present_callback @@ -429,19 +435,21 @@ InferOpenGLPlatformViewCreationCallback( gl_populate_existing_damage, // gl_populate_existing_damage }; - return fml::MakeCopyable( - [gl_dispatch_table, fbo_reset_after_present, platform_dispatch_table, - external_view_embedder = - std::move(external_view_embedder)](flutter::Shell& shell) mutable { - return std::make_unique( - shell, // delegate - shell.GetTaskRunners(), // task runners - gl_dispatch_table, // embedder GL dispatch table - fbo_reset_after_present, // fbo reset after present - platform_dispatch_table, // embedder platform dispatch table - std::move(external_view_embedder) // external view embedder - ); - }); + std::shared_ptr shared_view_embedder = + std::move(external_view_embedder); + + return fml::MakeCopyable([gl_dispatch_table, fbo_reset_after_present, + platform_dispatch_table, shared_view_embedder]( + flutter::Shell& shell) mutable { + return std::make_unique( + shell, // delegate + shell.GetTaskRunners(), // task runners + std::make_unique( + gl_dispatch_table, fbo_reset_after_present, shared_view_embedder), + platform_dispatch_table, // embedder platform dispatch table + shared_view_embedder // external view embedder + ); + }); #else return nullptr; #endif @@ -488,32 +496,29 @@ InferMetalPlatformViewCreationCallback( return texture_info; }; - flutter::EmbedderSurfaceMetal::MetalDispatchTable metal_dispatch_table = { + flutter::EmbedderStudioMetal::MetalDispatchTable metal_dispatch_table = { .present = metal_present, .get_texture = metal_get_texture, }; - std::shared_ptr view_embedder = + std::shared_ptr shared_view_embedder = std::move(external_view_embedder); - std::unique_ptr embedder_surface = - std::make_unique( - const_cast(config->metal.device), - const_cast( - config->metal.present_command_queue), - metal_dispatch_table, view_embedder); - // The static leak checker gets confused by the use of fml::MakeCopyable. // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) return fml::MakeCopyable( - [embedder_surface = std::move(embedder_surface), platform_dispatch_table, - external_view_embedder = view_embedder](flutter::Shell& shell) mutable { + [config, metal_dispatch_table, platform_dispatch_table, + shared_view_embedder](flutter::Shell& shell) mutable { return std::make_unique( - shell, // delegate - shell.GetTaskRunners(), // task runners - std::move(embedder_surface), // embedder surface - platform_dispatch_table, // platform dispatch table - std::move(external_view_embedder) // external view embedder + shell, // delegate + shell.GetTaskRunners(), // task runners + std::make_unique( + const_cast(config->metal.device), + const_cast( + config->metal.present_command_queue), + metal_dispatch_table, shared_view_embedder), + platform_dispatch_table, // platform dispatch table + shared_view_embedder // external view embedder ); }); #else @@ -568,39 +573,35 @@ InferVulkanPlatformViewCreationCallback( auto proc_addr = vulkan_get_instance_proc_address(vk_instance, "vkGetInstanceProcAddr"); - flutter::EmbedderSurfaceVulkan::VulkanDispatchTable vulkan_dispatch_table = { + flutter::EmbedderStudioVulkan::VulkanDispatchTable vulkan_dispatch_table = { .get_instance_proc_address = reinterpret_cast(proc_addr), .get_next_image = vulkan_get_next_image, .present_image = vulkan_present_image_callback, }; - std::shared_ptr view_embedder = + std::shared_ptr shared_view_embedder = std::move(external_view_embedder); - std::unique_ptr embedder_surface = - std::make_unique( - config->vulkan.version, vk_instance, - config->vulkan.enabled_instance_extension_count, - config->vulkan.enabled_instance_extensions, - config->vulkan.enabled_device_extension_count, - config->vulkan.enabled_device_extensions, - static_cast(config->vulkan.physical_device), - static_cast(config->vulkan.device), - config->vulkan.queue_family_index, - static_cast(config->vulkan.queue), vulkan_dispatch_table, - view_embedder); - return fml::MakeCopyable( - [embedder_surface = std::move(embedder_surface), platform_dispatch_table, - external_view_embedder = - std::move(view_embedder)](flutter::Shell& shell) mutable { + [config, vulkan_dispatch_table, vk_instance, platform_dispatch_table, + shared_view_embedder](flutter::Shell& shell) mutable { return std::make_unique( - shell, // delegate - shell.GetTaskRunners(), // task runners - std::move(embedder_surface), // embedder surface - platform_dispatch_table, // platform dispatch table - std::move(external_view_embedder) // external view embedder + shell, // delegate + shell.GetTaskRunners(), // task runners + std::make_unique( + config->vulkan.version, vk_instance, + config->vulkan.enabled_instance_extension_count, + config->vulkan.enabled_instance_extensions, + config->vulkan.enabled_device_extension_count, + config->vulkan.enabled_device_extensions, + static_cast(config->vulkan.physical_device), + static_cast(config->vulkan.device), + config->vulkan.queue_family_index, + static_cast(config->vulkan.queue), + vulkan_dispatch_table, shared_view_embedder), + platform_dispatch_table, // platform dispatch table + shared_view_embedder // external view embedder ); }); #else @@ -626,21 +627,24 @@ InferSoftwarePlatformViewCreationCallback( return ptr(user_data, allocation, row_bytes, height); }; - flutter::EmbedderSurfaceSoftware::SoftwareDispatchTable + flutter::EmbedderStudioSoftware::SoftwareDispatchTable software_dispatch_table = { software_present_backing_store, // required }; + std::shared_ptr shared_view_embedder = + std::move(external_view_embedder); + return fml::MakeCopyable( [software_dispatch_table, platform_dispatch_table, - external_view_embedder = - std::move(external_view_embedder)](flutter::Shell& shell) mutable { + shared_view_embedder](flutter::Shell& shell) mutable { return std::make_unique( - shell, // delegate - shell.GetTaskRunners(), // task runners - software_dispatch_table, // software dispatch table - platform_dispatch_table, // platform dispatch table - std::move(external_view_embedder) // external view embedder + shell, // delegate + shell.GetTaskRunners(), // task runners + std::make_unique( + software_dispatch_table, shared_view_embedder), + platform_dispatch_table, // platform dispatch table + shared_view_embedder // external view embedder ); }); } @@ -2045,8 +2049,30 @@ FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine) return kSuccess; } +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineAddRenderSurface( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FlutterRenderSurfaceConfig* config) { + if (engine == nullptr) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid."); + } + auto external_view_embedder_result = + InferExternalViewEmbedderFromArgs(config->compositor); + if (external_view_embedder_result.second) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, + "Compositor arguments were invalid."); + } + flutter::EmbedderEngine* embedder_engine = + reinterpret_cast(engine); + embedder_engine->GetShell().AddRenderSurface( + config->view_id, std::move(external_view_embedder_result.first)); + + return kSuccess; +} + FlutterEngineResult FlutterEngineSendWindowMetricsEvent( FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t view_id, const FlutterWindowMetricsEvent* flutter_metrics) { if (engine == nullptr || flutter_metrics == nullptr) { return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid."); @@ -2092,7 +2118,7 @@ FlutterEngineResult FlutterEngineSendWindowMetricsEvent( } return reinterpret_cast(engine)->SetViewportMetrics( - metrics) + view_id, metrics) ? kSuccess : LOG_EMBEDDER_ERROR(kInvalidArguments, "Viewport metrics were invalid."); @@ -3081,6 +3107,7 @@ FlutterEngineResult FlutterEngineGetProcAddresses( SET_PROC(Initialize, FlutterEngineInitialize); SET_PROC(Deinitialize, FlutterEngineDeinitialize); SET_PROC(RunInitialized, FlutterEngineRunInitialized); + SET_PROC(AddRenderSurface, FlutterEngineAddRenderSurface); SET_PROC(SendWindowMetricsEvent, FlutterEngineSendWindowMetricsEvent); SET_PROC(SendPointerEvent, FlutterEngineSendPointerEvent); SET_PROC(SendKeyEvent, FlutterEngineSendKeyEvent); diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index f1197403b73e4..1abc1011ccbe4 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -1605,10 +1605,10 @@ typedef bool (*FlutterLayersPresentCallback)(const FlutterLayer** layers, typedef struct { /// This size of this struct. Must be sizeof(FlutterCompositor). size_t struct_size; - /// A baton that in not interpreted by the engine in any way. If it passed + /// A baton that in not interpreted by the engine in any way. It is passed /// back to the embedder in `FlutterCompositor.create_backing_store_callback`, /// `FlutterCompositor.collect_backing_store_callback` and - /// `FlutterCompositor.present_layers_callback` + /// `FlutterCompositor.present_layers_callback`. void* user_data; /// A callback invoked by the engine to obtain a backing store for a specific /// `FlutterLayer`. @@ -1628,6 +1628,11 @@ typedef struct { bool avoid_backing_store_cache; } FlutterCompositor; +typedef struct { + int64_t view_id; + FlutterCompositor* compositor; +} FlutterRenderSurfaceConfig; + typedef struct { /// This size of this struct. Must be sizeof(FlutterLocale). size_t struct_size; @@ -2258,9 +2263,20 @@ FLUTTER_EXPORT FlutterEngineResult FlutterEngineRunInitialized( FLUTTER_API_SYMBOL(FlutterEngine) engine); +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineAddRenderSurface( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FlutterRenderSurfaceConfig* config); + +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineRemoveRenderSurface( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t view_id); + FLUTTER_EXPORT FlutterEngineResult FlutterEngineSendWindowMetricsEvent( FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t view_id, const FlutterWindowMetricsEvent* event); FLUTTER_EXPORT @@ -2832,8 +2848,15 @@ typedef FlutterEngineResult (*FlutterEngineDeinitializeFnPtr)( FLUTTER_API_SYMBOL(FlutterEngine) engine); typedef FlutterEngineResult (*FlutterEngineRunInitializedFnPtr)( FLUTTER_API_SYMBOL(FlutterEngine) engine); +typedef FlutterEngineResult (*FlutterEngineAddRenderSurfaceFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FlutterRenderSurfaceConfig* config); +typedef FlutterEngineResult (*FlutterEngineRemoveRenderSurfaceFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t view_id); typedef FlutterEngineResult (*FlutterEngineSendWindowMetricsEventFnPtr)( FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t view_id, const FlutterWindowMetricsEvent* event); typedef FlutterEngineResult (*FlutterEngineSendPointerEventFnPtr)( FLUTTER_API_SYMBOL(FlutterEngine) engine, @@ -2941,6 +2964,7 @@ typedef struct { FlutterEngineInitializeFnPtr Initialize; FlutterEngineDeinitializeFnPtr Deinitialize; FlutterEngineRunInitializedFnPtr RunInitialized; + FlutterEngineAddRenderSurfaceFnPtr AddRenderSurface; FlutterEngineSendWindowMetricsEventFnPtr SendWindowMetricsEvent; FlutterEngineSendPointerEventFnPtr SendPointerEvent; FlutterEngineSendKeyEventFnPtr SendKeyEvent; diff --git a/shell/platform/embedder/embedder_engine.cc b/shell/platform/embedder/embedder_engine.cc index cc4da738f72fc..b34da8a287f4e 100644 --- a/shell/platform/embedder/embedder_engine.cc +++ b/shell/platform/embedder/embedder_engine.cc @@ -100,6 +100,7 @@ bool EmbedderEngine::NotifyDestroyed() { } bool EmbedderEngine::SetViewportMetrics( + int64_t view_id, const flutter::ViewportMetrics& metrics) { if (!IsValid()) { return false; @@ -109,7 +110,7 @@ bool EmbedderEngine::SetViewportMetrics( if (!platform_view) { return false; } - platform_view->SetViewportMetrics(metrics); + platform_view->SetViewportMetrics(view_id, metrics); return true; } diff --git a/shell/platform/embedder/embedder_engine.h b/shell/platform/embedder/embedder_engine.h index 60d33ba76e652..a587eeb3eaa74 100644 --- a/shell/platform/embedder/embedder_engine.h +++ b/shell/platform/embedder/embedder_engine.h @@ -48,7 +48,8 @@ class EmbedderEngine { bool IsValid() const; - bool SetViewportMetrics(const flutter::ViewportMetrics& metrics); + bool SetViewportMetrics(int64_t view_id, + const flutter::ViewportMetrics& metrics); bool DispatchPointerDataPacket( std::unique_ptr packet); diff --git a/shell/platform/embedder/embedder_studio.h b/shell/platform/embedder/embedder_studio.h new file mode 100644 index 0000000000000..2ebfa51eb36ae --- /dev/null +++ b/shell/platform/embedder/embedder_studio.h @@ -0,0 +1,36 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_H_ + +#include + +#include "flutter/flow/studio.h" +#include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" +#include "flutter/shell/platform/embedder/embedder_surface.h" + +namespace flutter { + +class EmbedderStudio { + public: + EmbedderStudio() {} + + virtual ~EmbedderStudio() = default; + + virtual bool IsValid() const = 0; + + virtual std::unique_ptr CreateGPUStudio() = 0; + + virtual std::unique_ptr CreateSurface() = 0; + + virtual sk_sp CreateResourceContext() const = 0; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderStudio); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_H_ diff --git a/shell/platform/embedder/embedder_studio_gl.cc b/shell/platform/embedder/embedder_studio_gl.cc new file mode 100644 index 0000000000000..36885f9400866 --- /dev/null +++ b/shell/platform/embedder/embedder_studio_gl.cc @@ -0,0 +1,155 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/embedder/embedder_studio_gl.h" + +#include + +#include "flutter/shell/common/shell_io_manager.h" +#include "flutter/shell/gpu/gpu_studio_gl_skia.h" +#include "flutter/shell/platform/embedder/embedder_surface_gl.h" + +namespace flutter { + +EmbedderStudioGL::EmbedderStudioGL( + GLDispatchTable gl_dispatch_table, + bool fbo_reset_after_present, + std::shared_ptr external_view_embedder) + : gl_dispatch_table_(std::move(gl_dispatch_table)), + fbo_reset_after_present_(fbo_reset_after_present), + external_view_embedder_(std::move(external_view_embedder)) { + // Make sure all required members of the dispatch table are checked. + if (!gl_dispatch_table_.gl_make_current_callback || + !gl_dispatch_table_.gl_clear_current_callback || + !gl_dispatch_table_.gl_present_callback || + !gl_dispatch_table_.gl_fbo_callback || + !gl_dispatch_table_.gl_populate_existing_damage) { + return; + } + + valid_ = true; +} + +EmbedderStudioGL::~EmbedderStudioGL() { + if (main_context_ != nullptr) { + main_context_->releaseResourcesAndAbandonContext(); + } +} + +// |EmbedderStudio| +bool EmbedderStudioGL::IsValid() const { + return valid_; +} + +// |GPUSurfaceGLDelegate| +std::unique_ptr EmbedderStudioGL::GLContextMakeCurrent() { + return std::make_unique( + gl_dispatch_table_.gl_make_current_callback()); +} + +// |GPUSurfaceGLDelegate| +bool EmbedderStudioGL::GLContextClearCurrent() { + return gl_dispatch_table_.gl_clear_current_callback(); +} + +// |GPUSurfaceGLDelegate| +bool EmbedderStudioGL::GLContextPresent(const GLPresentInfo& present_info) { + // Pass the present information to the embedder present callback. + return gl_dispatch_table_.gl_present_callback(present_info); +} + +// |GPUSurfaceGLDelegate| +GLFBOInfo EmbedderStudioGL::GLContextFBO(GLFrameInfo frame_info) const { + // Get the FBO ID using the gl_fbo_callback and then get exiting damage by + // passing that ID to the gl_populate_existing_damage. + return gl_dispatch_table_.gl_populate_existing_damage( + gl_dispatch_table_.gl_fbo_callback(frame_info)); +} + +// |GPUSurfaceGLDelegate| +bool EmbedderStudioGL::GLContextFBOResetAfterPresent() const { + return fbo_reset_after_present_; +} + +// |GPUSurfaceGLDelegate| +SkMatrix EmbedderStudioGL::GLContextSurfaceTransformation() const { + auto callback = gl_dispatch_table_.gl_surface_transformation_callback; + if (!callback) { + SkMatrix matrix; + matrix.setIdentity(); + return matrix; + } + return callback(); +} + +// |GPUSurfaceGLDelegate| +EmbedderStudioGL::GLProcResolver EmbedderStudioGL::GetGLProcResolver() const { + return gl_dispatch_table_.gl_proc_resolver; +} + +// |GPUSurfaceGLDelegate| +SurfaceFrame::FramebufferInfo EmbedderStudioGL::GLContextFramebufferInfo() + const { + // Enable partial repaint by default on the embedders. + auto info = SurfaceFrame::FramebufferInfo{}; + info.supports_readback = true; + info.supports_partial_repaint = + gl_dispatch_table_.gl_populate_existing_damage != nullptr; + return info; +} + +// |EmbedderStudio| +std::unique_ptr EmbedderStudioGL::CreateGPUStudio() { + if (!IsValid()) { + return nullptr; + } + auto studio = std::make_unique(MainContext(), this); + if (!studio->IsValid()) { + return nullptr; + } + + return studio; +} + +// |EmbedderStudio| +std::unique_ptr EmbedderStudioGL::CreateSurface() { + const bool render_to_surface = !external_view_embedder_; + return std::make_unique( + MainContext(), + this, // GPU surface GL delegate + render_to_surface // render to surface + ); +} + +// |EmbedderStudio| +sk_sp EmbedderStudioGL::CreateResourceContext() const { + auto callback = gl_dispatch_table_.gl_make_resource_current_callback; + if (callback && callback()) { + if (auto context = ShellIOManager::CreateCompatibleResourceLoadingContext( + GrBackend::kOpenGL_GrBackend, GetGLInterface())) { + return context; + } else { + FML_LOG(ERROR) + << "Internal error: Resource context available but could not create " + "a compatible Skia context."; + return nullptr; + } + } + + // The callback was not available or failed. + FML_LOG(ERROR) + << "Could not create a resource context for async texture uploads. " + "Expect degraded performance. Set a valid make_resource_current " + "callback on FlutterOpenGLRendererConfig."; + return nullptr; +} + +sk_sp EmbedderStudioGL::MainContext() { + if (!main_context_) { + main_context_ = GPUStudioGLSkia::MakeGLContext(this); + } + return main_context_; +} + +} // namespace flutter diff --git a/shell/platform/embedder/embedder_studio_gl.h b/shell/platform/embedder/embedder_studio_gl.h new file mode 100644 index 0000000000000..74b0620b80776 --- /dev/null +++ b/shell/platform/embedder/embedder_studio_gl.h @@ -0,0 +1,88 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_GL_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_GL_H_ + +#include "flutter/fml/macros.h" +#include "flutter/shell/gpu/gpu_surface_gl_skia.h" +#include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" +#include "flutter/shell/platform/embedder/embedder_studio.h" + +namespace flutter { + +class EmbedderStudioGL final : public EmbedderStudio, + public GPUSurfaceGLDelegate { + public: + struct GLDispatchTable { + std::function gl_make_current_callback; // required + std::function gl_clear_current_callback; // required + std::function gl_present_callback; // required + std::function gl_fbo_callback; // required + std::function gl_make_resource_current_callback; // optional + std::function + gl_surface_transformation_callback; // optional + std::function gl_proc_resolver; // optional + std::function gl_populate_existing_damage; // required + }; + + EmbedderStudioGL( + GLDispatchTable gl_dispatch_table, + bool fbo_reset_after_present, + std::shared_ptr external_view_embedder); + + ~EmbedderStudioGL() override; + + // |EmbedderStudio| + bool IsValid() const override; + + // |EmbedderStudio| + std::unique_ptr CreateGPUStudio() override; + + // |EmbedderStudio| + std::unique_ptr CreateSurface() override; + + // |EmbedderStudio| + sk_sp CreateResourceContext() const override; + + // |GPUSurfaceGLDelegate| + std::unique_ptr GLContextMakeCurrent() override; + + // |GPUSurfaceGLDelegate| + bool GLContextClearCurrent() override; + + // |GPUSurfaceGLDelegate| + bool GLContextPresent(const GLPresentInfo& present_info) override; + + // |GPUSurfaceGLDelegate| + GLFBOInfo GLContextFBO(GLFrameInfo frame_info) const override; + + // |GPUSurfaceGLDelegate| + bool GLContextFBOResetAfterPresent() const override; + + // |GPUSurfaceGLDelegate| + SkMatrix GLContextSurfaceTransformation() const override; + + // |GPUSurfaceGLDelegate| + GLProcResolver GetGLProcResolver() const override; + + // |GPUSurfaceGLDelegate| + SurfaceFrame::FramebufferInfo GLContextFramebufferInfo() const override; + + private: + bool valid_ = false; + GLDispatchTable gl_dispatch_table_; + bool fbo_reset_after_present_; + sk_sp main_context_; + + std::shared_ptr external_view_embedder_; + + sk_sp MainContext(); + + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderStudioGL); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_GL_H_ diff --git a/shell/platform/embedder/embedder_studio_metal.h b/shell/platform/embedder/embedder_studio_metal.h new file mode 100644 index 0000000000000..6c7d9e6e838fe --- /dev/null +++ b/shell/platform/embedder/embedder_studio_metal.h @@ -0,0 +1,74 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_METAL_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_METAL_H_ + +#include "flutter/fml/macros.h" +#include "flutter/shell/gpu/gpu_surface_metal_delegate.h" +#include "flutter/shell/gpu/gpu_surface_metal_skia.h" +#include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" +#include "flutter/shell/platform/embedder/embedder_studio.h" + +#include "third_party/skia/include/core/SkSurface.h" + +namespace flutter { + +class EmbedderStudioMetal final : public EmbedderStudio, + public GPUSurfaceMetalDelegate { + public: + struct MetalDispatchTable { + std::function present; // required + std::function + get_texture; // required + }; + + EmbedderStudioMetal( + GPUMTLDeviceHandle device, + GPUMTLCommandQueueHandle command_queue, + MetalDispatchTable dispatch_table, + std::shared_ptr external_view_embedder); + + ~EmbedderStudioMetal() override; + + // |EmbedderStudio| + bool IsValid() const override; + + // |EmbedderStudio| + std::unique_ptr CreateGPUStudio() override; + + // |EmbedderStudio| + std::unique_ptr CreateSurface() override; + + // |EmbedderStudio| + sk_sp CreateResourceContext() const override; + + // |GPUSurfaceMetalDelegate| + GPUCAMetalLayerHandle GetCAMetalLayer( + const SkISize& frame_size) const override; + + // |GPUSurfaceMetalDelegate| + bool PresentDrawable(GrMTLHandle drawable) const override; + + // |GPUSurfaceMetalDelegate| + GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_size) const override; + + // |GPUSurfaceMetalDelegate| + bool PresentTexture(GPUMTLTextureInfo texture) const override; + + private: + bool valid_ = false; + MetalDispatchTable metal_dispatch_table_; + std::shared_ptr external_view_embedder_; + sk_sp surface_; + sk_sp main_context_; + sk_sp resource_context_; + std::shared_ptr sksl_precompiler_; + + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderStudioMetal); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_METAL_H_ diff --git a/shell/platform/embedder/embedder_studio_metal.mm b/shell/platform/embedder/embedder_studio_metal.mm new file mode 100644 index 0000000000000..6a7f3fb267815 --- /dev/null +++ b/shell/platform/embedder/embedder_studio_metal.mm @@ -0,0 +1,95 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/embedder/embedder_studio_metal.h" + +#include + +#include "flutter/fml/logging.h" +#include "flutter/shell/gpu/gpu_studio_metal_skia.h" +#include "flutter/shell/gpu/gpu_surface_metal_delegate.h" +#import "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.h" +#include "flutter/shell/platform/embedder/embedder_surface_metal.h" +#include "third_party/skia/include/gpu/GrDirectContext.h" + +FLUTTER_ASSERT_NOT_ARC +namespace flutter { + +EmbedderStudioMetal::EmbedderStudioMetal( + GPUMTLDeviceHandle device, + GPUMTLCommandQueueHandle command_queue, + MetalDispatchTable metal_dispatch_table, + std::shared_ptr external_view_embedder) + : GPUSurfaceMetalDelegate(MTLRenderTargetType::kMTLTexture), + metal_dispatch_table_(std::move(metal_dispatch_table)), + external_view_embedder_(std::move(external_view_embedder)) { + main_context_ = + [FlutterDarwinContextMetalSkia createGrContext:(id)device + commandQueue:(id)command_queue]; + resource_context_ = + [FlutterDarwinContextMetalSkia createGrContext:(id)device + commandQueue:(id)command_queue]; + sksl_precompiler_ = std::make_shared(); + valid_ = main_context_ && resource_context_; +} + +EmbedderStudioMetal::~EmbedderStudioMetal() = default; + +bool EmbedderStudioMetal::IsValid() const { + return valid_; +} + +std::unique_ptr EmbedderStudioMetal::CreateGPUStudio() API_AVAILABLE(ios(13.0)) { + if (@available(iOS 13.0, *)) { + } else { + return nullptr; + } + if (!IsValid()) { + return nullptr; + } + + auto studio = std::make_unique(this, main_context_, sksl_precompiler_); + + if (!studio->IsValid()) { + return nullptr; + } + + return studio; +} + +std::unique_ptr EmbedderStudioMetal::CreateSurface() { + if (!IsValid()) { + return nullptr; + } + const bool render_to_surface = !external_view_embedder_; + return std::make_unique(main_context_, + this, // GPU surface GL delegate + sksl_precompiler_, + render_to_surface // render to surface + ); +} + +sk_sp EmbedderStudioMetal::CreateResourceContext() const { + return resource_context_; +} + +GPUCAMetalLayerHandle EmbedderStudioMetal::GetCAMetalLayer(const SkISize& frame_info) const { + FML_CHECK(false) << "Only rendering to MTLTexture is supported."; + return nullptr; +} + +bool EmbedderStudioMetal::PresentDrawable(GrMTLHandle drawable) const { + FML_CHECK(false) << "Only rendering to MTLTexture is supported."; + return false; +} + +GPUMTLTextureInfo EmbedderStudioMetal::GetMTLTexture(const SkISize& frame_info) const { + return metal_dispatch_table_.get_texture(frame_info); +} + +bool EmbedderStudioMetal::PresentTexture(GPUMTLTextureInfo texture) const { + return metal_dispatch_table_.present(texture); +} + +} // namespace flutter diff --git a/shell/platform/embedder/embedder_studio_software.cc b/shell/platform/embedder/embedder_studio_software.cc new file mode 100644 index 0000000000000..ece206c5c3156 --- /dev/null +++ b/shell/platform/embedder/embedder_studio_software.cc @@ -0,0 +1,133 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/embedder/embedder_studio_software.h" + +#include + +#include "flutter/fml/trace_event.h" + +#include "flutter/shell/gpu/gpu_studio_software.h" +#include "flutter/shell/platform/embedder/embedder_studio_software.h" +#include "flutter/shell/platform/embedder/embedder_surface_software.h" +#include "third_party/skia/include/core/SkColorSpace.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/gpu/GrDirectContext.h" + +namespace flutter { + +EmbedderStudioSoftware::EmbedderStudioSoftware( + SoftwareDispatchTable software_dispatch_table, + std::shared_ptr external_view_embedder) + : software_dispatch_table_(std::move(software_dispatch_table)), + external_view_embedder_(std::move(external_view_embedder)) { + if (!software_dispatch_table_.software_present_backing_store) { + return; + } + valid_ = true; +} + +EmbedderStudioSoftware::~EmbedderStudioSoftware() = default; + +// |EmbedderStudio| +bool EmbedderStudioSoftware::IsValid() const { + return valid_; +} + +// |EmbedderStudio| +std::unique_ptr EmbedderStudioSoftware::CreateGPUStudio() { + if (!IsValid()) { + return nullptr; + } + auto studio = std::make_unique(this); + + if (!studio->IsValid()) { + return nullptr; + } + + return studio; +} + +// |EmbedderStudio| +std::unique_ptr EmbedderStudioSoftware::CreateSurface() { + if (!IsValid()) { + return nullptr; + } + const bool render_to_surface = !external_view_embedder_; + auto surface = + std::make_unique(this, render_to_surface); + + if (!surface->IsValid()) { + return nullptr; + } + + return surface; +} + +// |EmbedderStudio| +sk_sp EmbedderStudioSoftware::CreateResourceContext() const { + return nullptr; +} + +// |GPUSurfaceSoftwareDelegate| +sk_sp EmbedderStudioSoftware::AcquireBackingStore( + const SkISize& size) { + TRACE_EVENT0("flutter", "EmbedderStudioSoftware::AcquireBackingStore"); + if (!IsValid()) { + FML_LOG(ERROR) + << "Could not acquire backing store for the software surface."; + return nullptr; + } + + if (sk_surface_ != nullptr && + SkISize::Make(sk_surface_->width(), sk_surface_->height()) == size) { + // The old and new surface sizes are the same. Nothing to do here. + return sk_surface_; + } + + SkImageInfo info = SkImageInfo::MakeN32( + size.fWidth, size.fHeight, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()); + sk_surface_ = SkSurfaces::Raster(info, nullptr); + + if (sk_surface_ == nullptr) { + FML_LOG(ERROR) << "Could not create backing store for software rendering."; + return nullptr; + } + + return sk_surface_; +} + +// |GPUSurfaceSoftwareDelegate| +bool EmbedderStudioSoftware::PresentBackingStore( + sk_sp backing_store) { + if (!IsValid()) { + FML_LOG(ERROR) << "Tried to present an invalid software surface."; + return false; + } + + SkPixmap pixmap; + if (!backing_store->peekPixels(&pixmap)) { + FML_LOG(ERROR) << "Could not peek the pixels of the backing store."; + return false; + } + + // Some basic sanity checking. + uint64_t expected_pixmap_data_size = pixmap.width() * pixmap.height() * 4; + + const size_t pixmap_size = pixmap.computeByteSize(); + + if (expected_pixmap_data_size != pixmap_size) { + FML_LOG(ERROR) << "Software backing store had unexpected size."; + return false; + } + + return software_dispatch_table_.software_present_backing_store( + pixmap.addr(), // + pixmap.rowBytes(), // + pixmap.height() // + ); +} + +} // namespace flutter diff --git a/shell/platform/embedder/embedder_studio_software.h b/shell/platform/embedder/embedder_studio_software.h new file mode 100644 index 0000000000000..0ab0e2977fd5e --- /dev/null +++ b/shell/platform/embedder/embedder_studio_software.h @@ -0,0 +1,60 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_SOFTWARE_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_SOFTWARE_H_ + +#include "flutter/fml/macros.h" +#include "flutter/shell/gpu/gpu_surface_software.h" +#include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" +#include "flutter/shell/platform/embedder/embedder_studio.h" + +#include "third_party/skia/include/core/SkSurface.h" + +namespace flutter { + +class EmbedderStudioSoftware final : public EmbedderStudio, + public GPUSurfaceSoftwareDelegate { + public: + struct SoftwareDispatchTable { + std::function + software_present_backing_store; // required + }; + + EmbedderStudioSoftware( + SoftwareDispatchTable software_dispatch_table, + std::shared_ptr external_view_embedder); + + ~EmbedderStudioSoftware() override; + + // |EmbedderStudio| + bool IsValid() const override; + + // |EmbedderStudio| + std::unique_ptr CreateGPUStudio() override; + + // |EmbedderStudio| + std::unique_ptr CreateSurface() override; + + // |EmbedderStudio| + sk_sp CreateResourceContext() const override; + + // |GPUSurfaceSoftwareDelegate| + sk_sp AcquireBackingStore(const SkISize& size) override; + + // |GPUSurfaceSoftwareDelegate| + bool PresentBackingStore(sk_sp backing_store) override; + + private: + bool valid_ = false; + SoftwareDispatchTable software_dispatch_table_; + sk_sp sk_surface_; + std::shared_ptr external_view_embedder_; + + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderStudioSoftware); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_SOFTWARE_H_ diff --git a/shell/platform/embedder/embedder_studio_vulkan.cc b/shell/platform/embedder/embedder_studio_vulkan.cc new file mode 100644 index 0000000000000..1a03b103a7220 --- /dev/null +++ b/shell/platform/embedder/embedder_studio_vulkan.cc @@ -0,0 +1,193 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/embedder/embedder_studio_vulkan.h" + +#include + +#include "flutter/flutter_vma/flutter_skia_vma.h" +#include "flutter/shell/common/shell_io_manager.h" +#include "flutter/shell/gpu/gpu_studio_vulkan.h" +#include "flutter/shell/gpu/gpu_surface_vulkan.h" +#include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h" +#include "flutter/shell/platform/embedder/embedder_surface_vulkan.h" +#include "flutter/vulkan/vulkan_skia_proc_table.h" +#include "include/gpu/GrDirectContext.h" +#include "include/gpu/vk/GrVkBackendContext.h" +#include "include/gpu/vk/GrVkExtensions.h" + +namespace flutter { + +EmbedderStudioVulkan::EmbedderStudioVulkan( + uint32_t version, + VkInstance instance, + size_t instance_extension_count, + const char** instance_extensions, + size_t device_extension_count, + const char** device_extensions, + VkPhysicalDevice physical_device, + VkDevice device, + uint32_t queue_family_index, + VkQueue queue, + const VulkanDispatchTable& vulkan_dispatch_table, + std::shared_ptr external_view_embedder) + : vk_(fml::MakeRefCounted( + vulkan_dispatch_table.get_instance_proc_address)), + device_(*vk_, + vulkan::VulkanHandle{physical_device}, + vulkan::VulkanHandle{device}, + queue_family_index, + vulkan::VulkanHandle{queue}), + vulkan_dispatch_table_(vulkan_dispatch_table), + external_view_embedder_(std::move(external_view_embedder)) { + // Make sure all required members of the dispatch table are checked. + if (!vulkan_dispatch_table_.get_instance_proc_address || + !vulkan_dispatch_table_.get_next_image || + !vulkan_dispatch_table_.present_image) { + return; + } + + bool success = vk_->SetupInstanceProcAddresses( + vulkan::VulkanHandle{instance}); + if (!success) { + FML_LOG(ERROR) << "Could not setup instance proc addresses."; + return; + } + success = + vk_->SetupDeviceProcAddresses(vulkan::VulkanHandle{device}); + if (!success) { + FML_LOG(ERROR) << "Could not setup device proc addresses."; + return; + } + if (!vk_->IsValid()) { + FML_LOG(ERROR) << "VulkanProcTable invalid."; + return; + } + + main_context_ = CreateGrContext(instance, version, instance_extension_count, + instance_extensions, device_extension_count, + device_extensions, ContextType::kRender); + // TODO(96954): Add a second (optional) queue+family index to the Embedder API + // to allow embedders to specify a dedicated transfer queue for + // use by the resource context. Queue families with graphics + // capability can always be used for memory transferring, but it + // would be advantageous to use a dedicated transter queue here. + resource_context_ = CreateGrContext( + instance, version, instance_extension_count, instance_extensions, + device_extension_count, device_extensions, ContextType::kResource); + + valid_ = main_context_ && resource_context_; +} + +EmbedderStudioVulkan::~EmbedderStudioVulkan() { + if (main_context_) { + main_context_->releaseResourcesAndAbandonContext(); + } + if (resource_context_) { + resource_context_->releaseResourcesAndAbandonContext(); + } +} + +// |GPUSurfaceVulkanDelegate| +const vulkan::VulkanProcTable& EmbedderStudioVulkan::vk() { + return *vk_; +} + +// |GPUSurfaceVulkanDelegate| +FlutterVulkanImage EmbedderStudioVulkan::AcquireImage(const SkISize& size) { + return vulkan_dispatch_table_.get_next_image(size); +} + +// |GPUSurfaceVulkanDelegate| +bool EmbedderStudioVulkan::PresentImage(VkImage image, VkFormat format) { + return vulkan_dispatch_table_.present_image(image, format); +} + +// |EmbedderStudio| +bool EmbedderStudioVulkan::IsValid() const { + return valid_; +} + +// |EmbedderStudio| +std::unique_ptr EmbedderStudioVulkan::CreateGPUStudio() { + if (!IsValid()) { + return nullptr; + } + auto studio = std::make_unique(main_context_); + + if (!studio->IsValid()) { + return nullptr; + } + + return studio; +} + +// |EmbedderStudio| +std::unique_ptr EmbedderStudioVulkan::CreateSurface() { + const bool render_to_surface = !external_view_embedder_; + return std::make_unique(this, main_context_, + render_to_surface); +} + +// |EmbedderStudio| +sk_sp EmbedderStudioVulkan::CreateResourceContext() const { + return resource_context_; +} + +sk_sp EmbedderStudioVulkan::CreateGrContext( + VkInstance instance, + uint32_t version, + size_t instance_extension_count, + const char** instance_extensions, + size_t device_extension_count, + const char** device_extensions, + ContextType context_type) const { + uint32_t skia_features = 0; + if (!device_.GetPhysicalDeviceFeaturesSkia(&skia_features)) { + FML_LOG(ERROR) << "Failed to get physical device features."; + + return nullptr; + } + + auto get_proc = CreateSkiaGetProc(vk_); + if (get_proc == nullptr) { + FML_LOG(ERROR) << "Failed to create Vulkan getProc for Skia."; + return nullptr; + } + + GrVkExtensions extensions; + + GrVkBackendContext backend_context = {}; + backend_context.fInstance = instance; + backend_context.fPhysicalDevice = device_.GetPhysicalDeviceHandle(); + backend_context.fDevice = device_.GetHandle(); + backend_context.fQueue = device_.GetQueueHandle(); + backend_context.fGraphicsQueueIndex = device_.GetGraphicsQueueIndex(); + backend_context.fMinAPIVersion = version; + backend_context.fMaxAPIVersion = version; + backend_context.fFeatures = skia_features; + backend_context.fVkExtensions = &extensions; + backend_context.fGetProc = get_proc; + backend_context.fOwnsInstanceAndDevice = false; + + uint32_t vulkan_api_version = version; + sk_sp allocator = + flutter::FlutterSkiaVulkanMemoryAllocator::Make( + vulkan_api_version, instance, device_.GetPhysicalDeviceHandle(), + device_.GetHandle(), vk_, true); + + backend_context.fMemoryAllocator = allocator; + + extensions.init(backend_context.fGetProc, backend_context.fInstance, + backend_context.fPhysicalDevice, instance_extension_count, + instance_extensions, device_extension_count, + device_extensions); + + GrContextOptions options = + MakeDefaultContextOptions(context_type, GrBackendApi::kVulkan); + options.fReduceOpsTaskSplitting = GrContextOptions::Enable::kNo; + return GrDirectContext::MakeVulkan(backend_context, options); +} + +} // namespace flutter diff --git a/shell/platform/embedder/embedder_studio_vulkan.h b/shell/platform/embedder/embedder_studio_vulkan.h new file mode 100644 index 0000000000000..bfd5af3ed5122 --- /dev/null +++ b/shell/platform/embedder/embedder_studio_vulkan.h @@ -0,0 +1,91 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_VULKAN_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_VULKAN_H_ + +#include "flutter/fml/macros.h" +#include "flutter/shell/common/context_options.h" +#include "flutter/shell/gpu/gpu_surface_vulkan.h" +#include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h" +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" +#include "flutter/shell/platform/embedder/embedder_studio.h" +#include "flutter/vulkan/procs/vulkan_proc_table.h" + +namespace flutter { + +class EmbedderStudioVulkan final : public EmbedderStudio, + public GPUSurfaceVulkanDelegate { + public: + struct VulkanDispatchTable { + PFN_vkGetInstanceProcAddr get_instance_proc_address; // required + std::function + get_next_image; // required + std::function + present_image; // required + }; + + EmbedderStudioVulkan( + uint32_t version, + VkInstance instance, + size_t instance_extension_count, + const char** instance_extensions, + size_t device_extension_count, + const char** device_extensions, + VkPhysicalDevice physical_device, + VkDevice device, + uint32_t queue_family_index, + VkQueue queue, + const VulkanDispatchTable& vulkan_dispatch_table, + std::shared_ptr external_view_embedder); + + ~EmbedderStudioVulkan() override; + + // |GPUSurfaceVulkanDelegate| + const vulkan::VulkanProcTable& vk() override; + + // |GPUSurfaceVulkanDelegate| + FlutterVulkanImage AcquireImage(const SkISize& size) override; + + // |GPUSurfaceVulkanDelegate| + bool PresentImage(VkImage image, VkFormat format) override; + + // |EmbedderStudio| + bool IsValid() const override; + + // |EmbedderStudio| + std::unique_ptr CreateGPUStudio() override; + + // |EmbedderStudio| + std::unique_ptr CreateSurface() override; + + // |EmbedderStudio| + sk_sp CreateResourceContext() const override; + + private: + bool valid_ = false; + fml::RefPtr vk_; + vulkan::VulkanDevice device_; + VulkanDispatchTable vulkan_dispatch_table_; + std::shared_ptr external_view_embedder_; + sk_sp main_context_; + sk_sp resource_context_; + + sk_sp CreateGrContext(VkInstance instance, + uint32_t version, + size_t instance_extension_count, + const char** instance_extensions, + size_t device_extension_count, + const char** device_extensions, + ContextType context_type) const; + + void* GetInstanceProcAddress(VkInstance instance, const char* proc_name); + + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderStudioVulkan); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_STUDIO_VULKAN_H_ diff --git a/shell/platform/embedder/embedder_surface.h b/shell/platform/embedder/embedder_surface.h index ed8dbff74b8d0..aae2e5d27585b 100644 --- a/shell/platform/embedder/embedder_surface.h +++ b/shell/platform/embedder/embedder_surface.h @@ -21,8 +21,6 @@ class EmbedderSurface { virtual std::unique_ptr CreateGPUSurface() = 0; - virtual sk_sp CreateResourceContext() const = 0; - private: FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurface); }; diff --git a/shell/platform/embedder/embedder_surface_gl.cc b/shell/platform/embedder/embedder_surface_gl.cc index 44b1fddf808fb..3fb102ded3692 100644 --- a/shell/platform/embedder/embedder_surface_gl.cc +++ b/shell/platform/embedder/embedder_surface_gl.cc @@ -7,122 +7,34 @@ #include #include "flutter/shell/common/shell_io_manager.h" +#include "flutter/shell/platform/embedder/embedder_studio_gl.h" namespace flutter { -EmbedderSurfaceGL::EmbedderSurfaceGL( - GLDispatchTable gl_dispatch_table, - bool fbo_reset_after_present, - std::shared_ptr external_view_embedder) - : gl_dispatch_table_(std::move(gl_dispatch_table)), - fbo_reset_after_present_(fbo_reset_after_present), - external_view_embedder_(std::move(external_view_embedder)) { - // Make sure all required members of the dispatch table are checked. - if (!gl_dispatch_table_.gl_make_current_callback || - !gl_dispatch_table_.gl_clear_current_callback || - !gl_dispatch_table_.gl_present_callback || - !gl_dispatch_table_.gl_fbo_callback || - !gl_dispatch_table_.gl_populate_existing_damage) { - return; - } - - valid_ = true; -} +EmbedderSurfaceGL::EmbedderSurfaceGL(sk_sp main_context, + EmbedderStudioGL* studio, + bool render_to_surface) + : main_context_(std::move(main_context)), + studio_(studio), + render_to_surface_(render_to_surface) {} -EmbedderSurfaceGL::~EmbedderSurfaceGL() = default; +EmbedderSurfaceGL::~EmbedderSurfaceGL() {} // |EmbedderSurface| bool EmbedderSurfaceGL::IsValid() const { - return valid_; -} - -// |GPUSurfaceGLDelegate| -std::unique_ptr EmbedderSurfaceGL::GLContextMakeCurrent() { - return std::make_unique( - gl_dispatch_table_.gl_make_current_callback()); -} - -// |GPUSurfaceGLDelegate| -bool EmbedderSurfaceGL::GLContextClearCurrent() { - return gl_dispatch_table_.gl_clear_current_callback(); -} - -// |GPUSurfaceGLDelegate| -bool EmbedderSurfaceGL::GLContextPresent(const GLPresentInfo& present_info) { - // Pass the present information to the embedder present callback. - return gl_dispatch_table_.gl_present_callback(present_info); -} - -// |GPUSurfaceGLDelegate| -GLFBOInfo EmbedderSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const { - // Get the FBO ID using the gl_fbo_callback and then get exiting damage by - // passing that ID to the gl_populate_existing_damage. - return gl_dispatch_table_.gl_populate_existing_damage( - gl_dispatch_table_.gl_fbo_callback(frame_info)); -} - -// |GPUSurfaceGLDelegate| -bool EmbedderSurfaceGL::GLContextFBOResetAfterPresent() const { - return fbo_reset_after_present_; -} - -// |GPUSurfaceGLDelegate| -SkMatrix EmbedderSurfaceGL::GLContextSurfaceTransformation() const { - auto callback = gl_dispatch_table_.gl_surface_transformation_callback; - if (!callback) { - SkMatrix matrix; - matrix.setIdentity(); - return matrix; - } - return callback(); -} - -// |GPUSurfaceGLDelegate| -EmbedderSurfaceGL::GLProcResolver EmbedderSurfaceGL::GetGLProcResolver() const { - return gl_dispatch_table_.gl_proc_resolver; -} - -// |GPUSurfaceGLDelegate| -SurfaceFrame::FramebufferInfo EmbedderSurfaceGL::GLContextFramebufferInfo() - const { - // Enable partial repaint by default on the embedders. - auto info = SurfaceFrame::FramebufferInfo{}; - info.supports_readback = true; - info.supports_partial_repaint = - gl_dispatch_table_.gl_populate_existing_damage != nullptr; - return info; + return studio_->IsValid(); } // |EmbedderSurface| std::unique_ptr EmbedderSurfaceGL::CreateGPUSurface() { - const bool render_to_surface = !external_view_embedder_; + if (!IsValid()) { + return nullptr; + } return std::make_unique( - this, // GPU surface GL delegate - render_to_surface // render to surface + main_context_, + studio_, // GPU surface GL delegate + render_to_surface_ // render to surface ); } -// |EmbedderSurface| -sk_sp EmbedderSurfaceGL::CreateResourceContext() const { - auto callback = gl_dispatch_table_.gl_make_resource_current_callback; - if (callback && callback()) { - if (auto context = ShellIOManager::CreateCompatibleResourceLoadingContext( - GrBackend::kOpenGL_GrBackend, GetGLInterface())) { - return context; - } else { - FML_LOG(ERROR) - << "Internal error: Resource context available but could not create " - "a compatible Skia context."; - return nullptr; - } - } - - // The callback was not available or failed. - FML_LOG(ERROR) - << "Could not create a resource context for async texture uploads. " - "Expect degraded performance. Set a valid make_resource_current " - "callback on FlutterOpenGLRendererConfig."; - return nullptr; -} - } // namespace flutter diff --git a/shell/platform/embedder/embedder_surface_gl.h b/shell/platform/embedder/embedder_surface_gl.h index 695aeea84b860..f9ed3a2fd5b22 100644 --- a/shell/platform/embedder/embedder_surface_gl.h +++ b/shell/platform/embedder/embedder_surface_gl.h @@ -8,71 +8,29 @@ #include "flutter/fml/macros.h" #include "flutter/shell/gpu/gpu_surface_gl_skia.h" #include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" +#include "flutter/shell/platform/embedder/embedder_studio_gl.h" #include "flutter/shell/platform/embedder/embedder_surface.h" namespace flutter { -class EmbedderSurfaceGL final : public EmbedderSurface, - public GPUSurfaceGLDelegate { +class EmbedderSurfaceGL final : public EmbedderSurface { public: - struct GLDispatchTable { - std::function gl_make_current_callback; // required - std::function gl_clear_current_callback; // required - std::function gl_present_callback; // required - std::function gl_fbo_callback; // required - std::function gl_make_resource_current_callback; // optional - std::function - gl_surface_transformation_callback; // optional - std::function gl_proc_resolver; // optional - std::function gl_populate_existing_damage; // required - }; - - EmbedderSurfaceGL( - GLDispatchTable gl_dispatch_table, - bool fbo_reset_after_present, - std::shared_ptr external_view_embedder); + EmbedderSurfaceGL(sk_sp main_context, + EmbedderStudioGL* studio, + bool render_to_surface); ~EmbedderSurfaceGL() override; - private: - bool valid_ = false; - GLDispatchTable gl_dispatch_table_; - bool fbo_reset_after_present_; - - std::shared_ptr external_view_embedder_; - // |EmbedderSurface| bool IsValid() const override; - // |EmbedderSurface| - std::unique_ptr CreateGPUSurface() override; + private: + sk_sp main_context_; + EmbedderStudioGL* studio_; + bool render_to_surface_; // |EmbedderSurface| - sk_sp CreateResourceContext() const override; - - // |GPUSurfaceGLDelegate| - std::unique_ptr GLContextMakeCurrent() override; - - // |GPUSurfaceGLDelegate| - bool GLContextClearCurrent() override; - - // |GPUSurfaceGLDelegate| - bool GLContextPresent(const GLPresentInfo& present_info) override; - - // |GPUSurfaceGLDelegate| - GLFBOInfo GLContextFBO(GLFrameInfo frame_info) const override; - - // |GPUSurfaceGLDelegate| - bool GLContextFBOResetAfterPresent() const override; - - // |GPUSurfaceGLDelegate| - SkMatrix GLContextSurfaceTransformation() const override; - - // |GPUSurfaceGLDelegate| - GLProcResolver GetGLProcResolver() const override; - - // |GPUSurfaceGLDelegate| - SurfaceFrame::FramebufferInfo GLContextFramebufferInfo() const override; + std::unique_ptr CreateGPUSurface() override; FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurfaceGL); }; diff --git a/shell/platform/embedder/embedder_surface_metal.h b/shell/platform/embedder/embedder_surface_metal.h index d835218103e02..168b3d7093cdc 100644 --- a/shell/platform/embedder/embedder_surface_metal.h +++ b/shell/platform/embedder/embedder_surface_metal.h @@ -9,58 +9,34 @@ #include "flutter/shell/gpu/gpu_surface_metal_delegate.h" #include "flutter/shell/gpu/gpu_surface_metal_skia.h" #include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" +#include "flutter/shell/platform/embedder/embedder_studio_metal.h" #include "flutter/shell/platform/embedder/embedder_surface.h" #include "third_party/skia/include/core/SkSurface.h" namespace flutter { -class EmbedderSurfaceMetal final : public EmbedderSurface, - public GPUSurfaceMetalDelegate { +class EmbedderSurfaceMetal final : public EmbedderSurface { public: - struct MetalDispatchTable { - std::function present; // required - std::function - get_texture; // required - }; - - EmbedderSurfaceMetal( - GPUMTLDeviceHandle device, - GPUMTLCommandQueueHandle command_queue, - MetalDispatchTable dispatch_table, - std::shared_ptr external_view_embedder); + EmbedderSurfaceMetal(sk_sp main_context, + EmbedderStudioMetal* studio, + std::shared_ptr + sksl_precompiler, + bool render_to_surface); ~EmbedderSurfaceMetal() override; - private: - bool valid_ = false; - MetalDispatchTable metal_dispatch_table_; - std::shared_ptr external_view_embedder_; - sk_sp surface_; - sk_sp main_context_; - sk_sp resource_context_; - // |EmbedderSurface| bool IsValid() const override; - // |EmbedderSurface| - std::unique_ptr CreateGPUSurface() override; + private: + sk_sp main_context_; + EmbedderStudioMetal* studio_; + std::shared_ptr sksl_precompiler_; + bool render_to_surface_; // |EmbedderSurface| - sk_sp CreateResourceContext() const override; - - // |GPUSurfaceMetalDelegate| - GPUCAMetalLayerHandle GetCAMetalLayer( - const SkISize& frame_size) const override; - - // |GPUSurfaceMetalDelegate| - bool PresentDrawable(GrMTLHandle drawable) const override; - - // |GPUSurfaceMetalDelegate| - GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_size) const override; - - // |GPUSurfaceMetalDelegate| - bool PresentTexture(GPUMTLTextureInfo texture) const override; + std::unique_ptr CreateGPUSurface() override; FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurfaceMetal); }; diff --git a/shell/platform/embedder/embedder_surface_metal.mm b/shell/platform/embedder/embedder_surface_metal.mm index b7582d01b5c2c..1c164013d92c0 100644 --- a/shell/platform/embedder/embedder_surface_metal.mm +++ b/shell/platform/embedder/embedder_surface_metal.mm @@ -9,32 +9,26 @@ #include "flutter/fml/logging.h" #include "flutter/shell/gpu/gpu_surface_metal_delegate.h" #import "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.h" +#include "flutter/shell/platform/embedder/embedder_studio_metal.h" #include "third_party/skia/include/gpu/GrDirectContext.h" FLUTTER_ASSERT_NOT_ARC namespace flutter { EmbedderSurfaceMetal::EmbedderSurfaceMetal( - GPUMTLDeviceHandle device, - GPUMTLCommandQueueHandle command_queue, - MetalDispatchTable metal_dispatch_table, - std::shared_ptr external_view_embedder) - : GPUSurfaceMetalDelegate(MTLRenderTargetType::kMTLTexture), - metal_dispatch_table_(std::move(metal_dispatch_table)), - external_view_embedder_(std::move(external_view_embedder)) { - main_context_ = - [FlutterDarwinContextMetalSkia createGrContext:(id)device - commandQueue:(id)command_queue]; - resource_context_ = - [FlutterDarwinContextMetalSkia createGrContext:(id)device - commandQueue:(id)command_queue]; - valid_ = main_context_ && resource_context_; -} + sk_sp main_context, + EmbedderStudioMetal* studio, + std::shared_ptr sksl_precompiler, + bool render_to_surface) + : main_context_(std::move(main_context)), + studio_(studio), + sksl_precompiler_(std::move(sksl_precompiler)), + render_to_surface_(render_to_surface) {} EmbedderSurfaceMetal::~EmbedderSurfaceMetal() = default; bool EmbedderSurfaceMetal::IsValid() const { - return valid_; + return studio_->IsValid(); } std::unique_ptr EmbedderSurfaceMetal::CreateGPUSurface() API_AVAILABLE(ios(13.0)) { @@ -46,9 +40,8 @@ return nullptr; } - const bool render_to_surface = !external_view_embedder_; - auto surface = std::make_unique(this, main_context_, MsaaSampleCount::kNone, - render_to_surface); + auto surface = std::make_unique( + studio_, main_context_, MsaaSampleCount::kNone, sksl_precompiler_, render_to_surface_); if (!surface->IsValid()) { return nullptr; @@ -57,26 +50,4 @@ return surface; } -sk_sp EmbedderSurfaceMetal::CreateResourceContext() const { - return resource_context_; -} - -GPUCAMetalLayerHandle EmbedderSurfaceMetal::GetCAMetalLayer(const SkISize& frame_info) const { - FML_CHECK(false) << "Only rendering to MTLTexture is supported."; - return nullptr; -} - -bool EmbedderSurfaceMetal::PresentDrawable(GrMTLHandle drawable) const { - FML_CHECK(false) << "Only rendering to MTLTexture is supported."; - return false; -} - -GPUMTLTextureInfo EmbedderSurfaceMetal::GetMTLTexture(const SkISize& frame_info) const { - return metal_dispatch_table_.get_texture(frame_info); -} - -bool EmbedderSurfaceMetal::PresentTexture(GPUMTLTextureInfo texture) const { - return metal_dispatch_table_.present(texture); -} - } // namespace flutter diff --git a/shell/platform/embedder/embedder_surface_software.cc b/shell/platform/embedder/embedder_surface_software.cc index 7f6d445aa054c..8e270bbf4a7ba 100644 --- a/shell/platform/embedder/embedder_surface_software.cc +++ b/shell/platform/embedder/embedder_surface_software.cc @@ -15,22 +15,15 @@ namespace flutter { -EmbedderSurfaceSoftware::EmbedderSurfaceSoftware( - SoftwareDispatchTable software_dispatch_table, - std::shared_ptr external_view_embedder) - : software_dispatch_table_(std::move(software_dispatch_table)), - external_view_embedder_(std::move(external_view_embedder)) { - if (!software_dispatch_table_.software_present_backing_store) { - return; - } - valid_ = true; -} +EmbedderSurfaceSoftware::EmbedderSurfaceSoftware(EmbedderStudioSoftware* studio, + bool render_to_surface) + : studio_(studio), render_to_surface_(render_to_surface) {} EmbedderSurfaceSoftware::~EmbedderSurfaceSoftware() = default; // |EmbedderSurface| bool EmbedderSurfaceSoftware::IsValid() const { - return valid_; + return true; } // |EmbedderSurface| @@ -38,8 +31,8 @@ std::unique_ptr EmbedderSurfaceSoftware::CreateGPUSurface() { if (!IsValid()) { return nullptr; } - const bool render_to_surface = !external_view_embedder_; - auto surface = std::make_unique(this, render_to_surface); + auto surface = + std::make_unique(studio_, render_to_surface_); if (!surface->IsValid()) { return nullptr; @@ -48,68 +41,4 @@ std::unique_ptr EmbedderSurfaceSoftware::CreateGPUSurface() { return surface; } -// |EmbedderSurface| -sk_sp EmbedderSurfaceSoftware::CreateResourceContext() const { - return nullptr; -} - -// |GPUSurfaceSoftwareDelegate| -sk_sp EmbedderSurfaceSoftware::AcquireBackingStore( - const SkISize& size) { - TRACE_EVENT0("flutter", "EmbedderSurfaceSoftware::AcquireBackingStore"); - if (!IsValid()) { - FML_LOG(ERROR) - << "Could not acquire backing store for the software surface."; - return nullptr; - } - - if (sk_surface_ != nullptr && - SkISize::Make(sk_surface_->width(), sk_surface_->height()) == size) { - // The old and new surface sizes are the same. Nothing to do here. - return sk_surface_; - } - - SkImageInfo info = SkImageInfo::MakeN32( - size.fWidth, size.fHeight, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()); - sk_surface_ = SkSurfaces::Raster(info, nullptr); - - if (sk_surface_ == nullptr) { - FML_LOG(ERROR) << "Could not create backing store for software rendering."; - return nullptr; - } - - return sk_surface_; -} - -// |GPUSurfaceSoftwareDelegate| -bool EmbedderSurfaceSoftware::PresentBackingStore( - sk_sp backing_store) { - if (!IsValid()) { - FML_LOG(ERROR) << "Tried to present an invalid software surface."; - return false; - } - - SkPixmap pixmap; - if (!backing_store->peekPixels(&pixmap)) { - FML_LOG(ERROR) << "Could not peek the pixels of the backing store."; - return false; - } - - // Some basic sanity checking. - uint64_t expected_pixmap_data_size = pixmap.width() * pixmap.height() * 4; - - const size_t pixmap_size = pixmap.computeByteSize(); - - if (expected_pixmap_data_size != pixmap_size) { - FML_LOG(ERROR) << "Software backing store had unexpected size."; - return false; - } - - return software_dispatch_table_.software_present_backing_store( - pixmap.addr(), // - pixmap.rowBytes(), // - pixmap.height() // - ); -} - } // namespace flutter diff --git a/shell/platform/embedder/embedder_surface_software.h b/shell/platform/embedder/embedder_surface_software.h index 5d52e63d76528..858afc4c9eb86 100644 --- a/shell/platform/embedder/embedder_surface_software.h +++ b/shell/platform/embedder/embedder_surface_software.h @@ -8,46 +8,29 @@ #include "flutter/fml/macros.h" #include "flutter/shell/gpu/gpu_surface_software.h" #include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" +#include "flutter/shell/platform/embedder/embedder_studio_software.h" #include "flutter/shell/platform/embedder/embedder_surface.h" #include "third_party/skia/include/core/SkSurface.h" namespace flutter { -class EmbedderSurfaceSoftware final : public EmbedderSurface, - public GPUSurfaceSoftwareDelegate { +class EmbedderSurfaceSoftware final : public EmbedderSurface { public: - struct SoftwareDispatchTable { - std::function - software_present_backing_store; // required - }; - - EmbedderSurfaceSoftware( - SoftwareDispatchTable software_dispatch_table, - std::shared_ptr external_view_embedder); + EmbedderSurfaceSoftware(EmbedderStudioSoftware* studio, + bool render_to_surface); ~EmbedderSurfaceSoftware() override; - private: - bool valid_ = false; - SoftwareDispatchTable software_dispatch_table_; - sk_sp sk_surface_; - std::shared_ptr external_view_embedder_; - // |EmbedderSurface| bool IsValid() const override; - // |EmbedderSurface| - std::unique_ptr CreateGPUSurface() override; + private: + EmbedderStudioSoftware* studio_; + bool render_to_surface_; // |EmbedderSurface| - sk_sp CreateResourceContext() const override; - - // |GPUSurfaceSoftwareDelegate| - sk_sp AcquireBackingStore(const SkISize& size) override; - - // |GPUSurfaceSoftwareDelegate| - bool PresentBackingStore(sk_sp backing_store) override; + std::unique_ptr CreateGPUSurface() override; FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurfaceSoftware); }; diff --git a/shell/platform/embedder/embedder_surface_vulkan.cc b/shell/platform/embedder/embedder_surface_vulkan.cc index d7191770025de..0f80a7786d511 100644 --- a/shell/platform/embedder/embedder_surface_vulkan.cc +++ b/shell/platform/embedder/embedder_surface_vulkan.cc @@ -18,160 +18,24 @@ namespace flutter { EmbedderSurfaceVulkan::EmbedderSurfaceVulkan( - uint32_t version, - VkInstance instance, - size_t instance_extension_count, - const char** instance_extensions, - size_t device_extension_count, - const char** device_extensions, - VkPhysicalDevice physical_device, - VkDevice device, - uint32_t queue_family_index, - VkQueue queue, - const VulkanDispatchTable& vulkan_dispatch_table, - std::shared_ptr external_view_embedder) - : vk_(fml::MakeRefCounted( - vulkan_dispatch_table.get_instance_proc_address)), - device_(*vk_, - vulkan::VulkanHandle{physical_device}, - vulkan::VulkanHandle{device}, - queue_family_index, - vulkan::VulkanHandle{queue}), - vulkan_dispatch_table_(vulkan_dispatch_table), - external_view_embedder_(std::move(external_view_embedder)) { - // Make sure all required members of the dispatch table are checked. - if (!vulkan_dispatch_table_.get_instance_proc_address || - !vulkan_dispatch_table_.get_next_image || - !vulkan_dispatch_table_.present_image) { - return; - } + EmbedderStudioVulkan* studio, + sk_sp main_context, + bool render_to_surface) + : main_context_(std::move(main_context)), + studio_(studio), + render_to_surface_(render_to_surface) {} - bool success = vk_->SetupInstanceProcAddresses( - vulkan::VulkanHandle{instance}); - if (!success) { - FML_LOG(ERROR) << "Could not setup instance proc addresses."; - return; - } - success = - vk_->SetupDeviceProcAddresses(vulkan::VulkanHandle{device}); - if (!success) { - FML_LOG(ERROR) << "Could not setup device proc addresses."; - return; - } - if (!vk_->IsValid()) { - FML_LOG(ERROR) << "VulkanProcTable invalid."; - return; - } - - main_context_ = CreateGrContext(instance, version, instance_extension_count, - instance_extensions, device_extension_count, - device_extensions, ContextType::kRender); - // TODO(96954): Add a second (optional) queue+family index to the Embedder API - // to allow embedders to specify a dedicated transfer queue for - // use by the resource context. Queue families with graphics - // capability can always be used for memory transferring, but it - // would be advantageous to use a dedicated transter queue here. - resource_context_ = CreateGrContext( - instance, version, instance_extension_count, instance_extensions, - device_extension_count, device_extensions, ContextType::kResource); - - valid_ = main_context_ && resource_context_; -} - -EmbedderSurfaceVulkan::~EmbedderSurfaceVulkan() { - if (main_context_) { - main_context_->releaseResourcesAndAbandonContext(); - } - if (resource_context_) { - resource_context_->releaseResourcesAndAbandonContext(); - } -} - -// |GPUSurfaceVulkanDelegate| -const vulkan::VulkanProcTable& EmbedderSurfaceVulkan::vk() { - return *vk_; -} - -// |GPUSurfaceVulkanDelegate| -FlutterVulkanImage EmbedderSurfaceVulkan::AcquireImage(const SkISize& size) { - return vulkan_dispatch_table_.get_next_image(size); -} - -// |GPUSurfaceVulkanDelegate| -bool EmbedderSurfaceVulkan::PresentImage(VkImage image, VkFormat format) { - return vulkan_dispatch_table_.present_image(image, format); -} +EmbedderSurfaceVulkan::~EmbedderSurfaceVulkan() {} // |EmbedderSurface| bool EmbedderSurfaceVulkan::IsValid() const { - return valid_; + return studio_->IsValid(); } // |EmbedderSurface| std::unique_ptr EmbedderSurfaceVulkan::CreateGPUSurface() { - const bool render_to_surface = !external_view_embedder_; - return std::make_unique(this, main_context_, - render_to_surface); -} - -// |EmbedderSurface| -sk_sp EmbedderSurfaceVulkan::CreateResourceContext() const { - return resource_context_; -} - -sk_sp EmbedderSurfaceVulkan::CreateGrContext( - VkInstance instance, - uint32_t version, - size_t instance_extension_count, - const char** instance_extensions, - size_t device_extension_count, - const char** device_extensions, - ContextType context_type) const { - uint32_t skia_features = 0; - if (!device_.GetPhysicalDeviceFeaturesSkia(&skia_features)) { - FML_LOG(ERROR) << "Failed to get physical device features."; - - return nullptr; - } - - auto get_proc = CreateSkiaGetProc(vk_); - if (get_proc == nullptr) { - FML_LOG(ERROR) << "Failed to create Vulkan getProc for Skia."; - return nullptr; - } - - GrVkExtensions extensions; - - GrVkBackendContext backend_context = {}; - backend_context.fInstance = instance; - backend_context.fPhysicalDevice = device_.GetPhysicalDeviceHandle(); - backend_context.fDevice = device_.GetHandle(); - backend_context.fQueue = device_.GetQueueHandle(); - backend_context.fGraphicsQueueIndex = device_.GetGraphicsQueueIndex(); - backend_context.fMinAPIVersion = version; - backend_context.fMaxAPIVersion = version; - backend_context.fFeatures = skia_features; - backend_context.fVkExtensions = &extensions; - backend_context.fGetProc = get_proc; - backend_context.fOwnsInstanceAndDevice = false; - - uint32_t vulkan_api_version = version; - sk_sp allocator = - flutter::FlutterSkiaVulkanMemoryAllocator::Make( - vulkan_api_version, instance, device_.GetPhysicalDeviceHandle(), - device_.GetHandle(), vk_, true); - - backend_context.fMemoryAllocator = allocator; - - extensions.init(backend_context.fGetProc, backend_context.fInstance, - backend_context.fPhysicalDevice, instance_extension_count, - instance_extensions, device_extension_count, - device_extensions); - - GrContextOptions options = - MakeDefaultContextOptions(context_type, GrBackendApi::kVulkan); - options.fReduceOpsTaskSplitting = GrContextOptions::Enable::kNo; - return GrDirectContext::MakeVulkan(backend_context, options); + return std::make_unique(studio_, main_context_, + render_to_surface_); } } // namespace flutter diff --git a/shell/platform/embedder/embedder_surface_vulkan.h b/shell/platform/embedder/embedder_surface_vulkan.h index 0e972d3723b74..df25d52c8a5fd 100644 --- a/shell/platform/embedder/embedder_surface_vulkan.h +++ b/shell/platform/embedder/embedder_surface_vulkan.h @@ -11,65 +11,31 @@ #include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" +#include "flutter/shell/platform/embedder/embedder_studio_vulkan.h" #include "flutter/shell/platform/embedder/embedder_surface.h" #include "flutter/vulkan/procs/vulkan_proc_table.h" namespace flutter { -class EmbedderSurfaceVulkan final : public EmbedderSurface, - public GPUSurfaceVulkanDelegate { +class EmbedderSurfaceVulkan final : public EmbedderSurface { public: - struct VulkanDispatchTable { - PFN_vkGetInstanceProcAddr get_instance_proc_address; // required - std::function - get_next_image; // required - std::function - present_image; // required - }; - - EmbedderSurfaceVulkan( - uint32_t version, - VkInstance instance, - size_t instance_extension_count, - const char** instance_extensions, - size_t device_extension_count, - const char** device_extensions, - VkPhysicalDevice physical_device, - VkDevice device, - uint32_t queue_family_index, - VkQueue queue, - const VulkanDispatchTable& vulkan_dispatch_table, - std::shared_ptr external_view_embedder); + EmbedderSurfaceVulkan(EmbedderStudioVulkan* studio, + sk_sp main_context, + bool render_to_surface); ~EmbedderSurfaceVulkan() override; - // |GPUSurfaceVulkanDelegate| - const vulkan::VulkanProcTable& vk() override; - - // |GPUSurfaceVulkanDelegate| - FlutterVulkanImage AcquireImage(const SkISize& size) override; - - // |GPUSurfaceVulkanDelegate| - bool PresentImage(VkImage image, VkFormat format) override; + // |EmbedderSurface| + bool IsValid() const override; private: - bool valid_ = false; - fml::RefPtr vk_; - vulkan::VulkanDevice device_; - VulkanDispatchTable vulkan_dispatch_table_; - std::shared_ptr external_view_embedder_; sk_sp main_context_; - sk_sp resource_context_; - - // |EmbedderSurface| - bool IsValid() const override; + EmbedderStudioVulkan* studio_; + bool render_to_surface_; // |EmbedderSurface| std::unique_ptr CreateGPUSurface() override; - // |EmbedderSurface| - sk_sp CreateResourceContext() const override; - sk_sp CreateGrContext(VkInstance instance, uint32_t version, size_t instance_extension_count, diff --git a/shell/platform/embedder/platform_view_embedder.cc b/shell/platform/embedder/platform_view_embedder.cc index 1cedc22810a50..5714af00d8430 100644 --- a/shell/platform/embedder/platform_view_embedder.cc +++ b/shell/platform/embedder/platform_view_embedder.cc @@ -48,72 +48,17 @@ class PlatformViewEmbedder::EmbedderPlatformMessageHandler PlatformViewEmbedder::PlatformViewEmbedder( PlatformView::Delegate& delegate, const flutter::TaskRunners& task_runners, - const EmbedderSurfaceSoftware::SoftwareDispatchTable& - software_dispatch_table, + std::unique_ptr embedder_studio, PlatformDispatchTable platform_dispatch_table, std::shared_ptr external_view_embedder) : PlatformView(delegate, task_runners), external_view_embedder_(std::move(external_view_embedder)), - embedder_surface_( - std::make_unique(software_dispatch_table, - external_view_embedder_)), + embedder_studio_(std::move(embedder_studio)), platform_message_handler_(new EmbedderPlatformMessageHandler( GetWeakPtr(), task_runners.GetPlatformTaskRunner())), platform_dispatch_table_(std::move(platform_dispatch_table)) {} -#ifdef SHELL_ENABLE_GL -PlatformViewEmbedder::PlatformViewEmbedder( - PlatformView::Delegate& delegate, - const flutter::TaskRunners& task_runners, - const EmbedderSurfaceGL::GLDispatchTable& gl_dispatch_table, - bool fbo_reset_after_present, - PlatformDispatchTable platform_dispatch_table, - std::shared_ptr external_view_embedder) - : PlatformView(delegate, task_runners), - external_view_embedder_(std::move(external_view_embedder)), - embedder_surface_( - std::make_unique(gl_dispatch_table, - fbo_reset_after_present, - external_view_embedder_)), - platform_message_handler_(new EmbedderPlatformMessageHandler( - GetWeakPtr(), - task_runners.GetPlatformTaskRunner())), - platform_dispatch_table_(std::move(platform_dispatch_table)) {} -#endif - -#ifdef SHELL_ENABLE_METAL -PlatformViewEmbedder::PlatformViewEmbedder( - PlatformView::Delegate& delegate, - const flutter::TaskRunners& task_runners, - std::unique_ptr embedder_surface, - PlatformDispatchTable platform_dispatch_table, - std::shared_ptr external_view_embedder) - : PlatformView(delegate, task_runners), - external_view_embedder_(std::move(external_view_embedder)), - embedder_surface_(std::move(embedder_surface)), - platform_message_handler_(new EmbedderPlatformMessageHandler( - GetWeakPtr(), - task_runners.GetPlatformTaskRunner())), - platform_dispatch_table_(std::move(platform_dispatch_table)) {} -#endif - -#ifdef SHELL_ENABLE_VULKAN -PlatformViewEmbedder::PlatformViewEmbedder( - PlatformView::Delegate& delegate, - const flutter::TaskRunners& task_runners, - std::unique_ptr embedder_surface, - PlatformDispatchTable platform_dispatch_table, - std::shared_ptr external_view_embedder) - : PlatformView(delegate, task_runners), - external_view_embedder_(std::move(external_view_embedder)), - embedder_surface_(std::move(embedder_surface)), - platform_message_handler_(new EmbedderPlatformMessageHandler( - GetWeakPtr(), - task_runners.GetPlatformTaskRunner())), - platform_dispatch_table_(std::move(platform_dispatch_table)) {} -#endif - PlatformViewEmbedder::~PlatformViewEmbedder() = default; void PlatformViewEmbedder::UpdateSemantics( @@ -143,12 +88,21 @@ void PlatformViewEmbedder::HandlePlatformMessage( } // |PlatformView| -std::unique_ptr PlatformViewEmbedder::CreateRenderingSurface() { - if (embedder_surface_ == nullptr) { - FML_LOG(ERROR) << "Embedder surface was null."; +std::unique_ptr PlatformViewEmbedder::CreateRenderingStudio() { + return embedder_studio_->CreateGPUStudio(); +} + +// |PlatformView| +std::unique_ptr PlatformViewEmbedder::CreateRenderingSurface( + int64_t view_id) { + auto found_iter = embedder_surfaces_.find(view_id); + if (found_iter != embedder_surfaces_.end()) { + FML_LOG(ERROR) << "Embedder surface " << view_id << " already exists."; return nullptr; } - return embedder_surface_->CreateGPUSurface(); + auto& embedder_surface = embedder_surfaces_[view_id] = + embedder_studio_->CreateSurface(); + return embedder_surface->CreateGPUSurface(); } // |PlatformView| @@ -159,11 +113,7 @@ PlatformViewEmbedder::CreateExternalViewEmbedder() { // |PlatformView| sk_sp PlatformViewEmbedder::CreateResourceContext() const { - if (embedder_surface_ == nullptr) { - FML_LOG(ERROR) << "Embedder surface was null."; - return nullptr; - } - return embedder_surface_->CreateResourceContext(); + return embedder_studio_->CreateResourceContext(); } // |PlatformView| diff --git a/shell/platform/embedder/platform_view_embedder.h b/shell/platform/embedder/platform_view_embedder.h index 20f4dc139875b..9766f6bf8a8a6 100644 --- a/shell/platform/embedder/platform_view_embedder.h +++ b/shell/platform/embedder/platform_view_embedder.h @@ -6,27 +6,16 @@ #define FLUTTER_SHELL_PLATFORM_EMBEDDER_PLATFORM_VIEW_EMBEDDER_H_ #include +#include #include "flow/embedded_views.h" #include "flutter/fml/macros.h" #include "flutter/shell/common/platform_view.h" #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/embedder/embedder_studio.h" #include "flutter/shell/platform/embedder/embedder_surface.h" -#include "flutter/shell/platform/embedder/embedder_surface_software.h" #include "flutter/shell/platform/embedder/vsync_waiter_embedder.h" -#ifdef SHELL_ENABLE_GL -#include "flutter/shell/platform/embedder/embedder_surface_gl.h" -#endif - -#ifdef SHELL_ENABLE_METAL -#include "flutter/shell/platform/embedder/embedder_surface_metal.h" -#endif - -#ifdef SHELL_ENABLE_VULKAN -#include "flutter/shell/platform/embedder/embedder_surface_vulkan.h" -#endif - namespace flutter { class PlatformViewEmbedder final : public PlatformView { @@ -51,45 +40,12 @@ class PlatformViewEmbedder final : public PlatformView { OnPreEngineRestartCallback on_pre_engine_restart_callback; // optional }; - // Create a platform view that sets up a software rasterizer. - PlatformViewEmbedder( - PlatformView::Delegate& delegate, - const flutter::TaskRunners& task_runners, - const EmbedderSurfaceSoftware::SoftwareDispatchTable& - software_dispatch_table, - PlatformDispatchTable platform_dispatch_table, - std::shared_ptr external_view_embedder); - -#ifdef SHELL_ENABLE_GL - // Creates a platform view that sets up an OpenGL rasterizer. PlatformViewEmbedder( PlatformView::Delegate& delegate, const flutter::TaskRunners& task_runners, - const EmbedderSurfaceGL::GLDispatchTable& gl_dispatch_table, - bool fbo_reset_after_present, + std::unique_ptr embedder_studio, PlatformDispatchTable platform_dispatch_table, std::shared_ptr external_view_embedder); -#endif - -#ifdef SHELL_ENABLE_METAL - // Creates a platform view that sets up an metal rasterizer. - PlatformViewEmbedder( - PlatformView::Delegate& delegate, - const flutter::TaskRunners& task_runners, - std::unique_ptr embedder_surface, - PlatformDispatchTable platform_dispatch_table, - std::shared_ptr external_view_embedder); -#endif - -#ifdef SHELL_ENABLE_VULKAN - // Creates a platform view that sets up an Vulkan rasterizer. - PlatformViewEmbedder( - PlatformView::Delegate& delegate, - const flutter::TaskRunners& task_runners, - std::unique_ptr embedder_surface, - PlatformDispatchTable platform_dispatch_table, - std::shared_ptr external_view_embedder); -#endif ~PlatformViewEmbedder() override; @@ -108,12 +64,17 @@ class PlatformViewEmbedder final : public PlatformView { private: class EmbedderPlatformMessageHandler; std::shared_ptr external_view_embedder_; - std::unique_ptr embedder_surface_; + std::unique_ptr embedder_studio_; + std::unordered_map> + embedder_surfaces_; std::shared_ptr platform_message_handler_; PlatformDispatchTable platform_dispatch_table_; // |PlatformView| - std::unique_ptr CreateRenderingSurface() override; + std::unique_ptr CreateRenderingStudio() override; + + // |PlatformView| + std::unique_ptr CreateRenderingSurface(int64_t view_id) override; // |PlatformView| std::shared_ptr CreateExternalViewEmbedder() override; diff --git a/shell/platform/embedder/platform_view_embedder_unittests.cc b/shell/platform/embedder/platform_view_embedder_unittests.cc index 3e795f1fb530f..b04365c0d6967 100644 --- a/shell/platform/embedder/platform_view_embedder_unittests.cc +++ b/shell/platform/embedder/platform_view_embedder_unittests.cc @@ -5,6 +5,7 @@ #include "flutter/shell/platform/embedder/platform_view_embedder.h" #include "flutter/shell/common/thread_host.h" +#include "flutter/shell/platform/embedder/embedder_studio.h" #include "flutter/testing/testing.h" #include "gmock/gmock.h" @@ -16,13 +17,13 @@ namespace flutter { namespace testing { namespace { class MockDelegate : public PlatformView::Delegate { - MOCK_METHOD1(OnPlatformViewCreated, void(std::unique_ptr)); + MOCK_METHOD0(OnPlatformViewCreated, void()); MOCK_METHOD0(OnPlatformViewDestroyed, void()); MOCK_METHOD0(OnPlatformViewScheduleFrame, void()); MOCK_METHOD1(OnPlatformViewSetNextFrameCallback, void(const fml::closure& closure)); - MOCK_METHOD1(OnPlatformViewSetViewportMetrics, - void(const ViewportMetrics& metrics)); + MOCK_METHOD2(OnPlatformViewSetViewportMetrics, + void(int64_t view_id, const ViewportMetrics& metrics)); MOCK_METHOD1(OnPlatformViewDispatchPlatformMessage, void(std::unique_ptr message)); MOCK_METHOD1(OnPlatformViewDispatchPointerDataPacket, @@ -57,6 +58,14 @@ class MockResponse : public PlatformMessageResponse { MOCK_METHOD1(Complete, void(std::unique_ptr data)); MOCK_METHOD0(CompleteEmpty, void()); }; + +class MockStudio : public EmbedderStudio { + public: + MOCK_CONST_METHOD0(IsValid, bool()); + MOCK_METHOD0(CreateGPUStudio, std::unique_ptr()); + MOCK_METHOD0(CreateSurface, std::unique_ptr()); + MOCK_CONST_METHOD0(CreateResourceContext, sk_sp()); +}; } // namespace TEST(PlatformViewEmbedderTest, HasPlatformMessageHandler) { @@ -68,11 +77,10 @@ TEST(PlatformViewEmbedderTest, HasPlatformMessageHandler) { fml::AutoResetWaitableEvent latch; task_runners.GetPlatformTaskRunner()->PostTask([&latch, task_runners] { MockDelegate delegate; - EmbedderSurfaceSoftware::SoftwareDispatchTable software_dispatch_table; PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table; std::shared_ptr external_view_embedder; auto embedder = std::make_unique( - delegate, task_runners, software_dispatch_table, + delegate, task_runners, std::make_unique(), platform_dispatch_table, external_view_embedder); ASSERT_TRUE(embedder->GetPlatformMessageHandler()); @@ -91,27 +99,26 @@ TEST(PlatformViewEmbedderTest, Dispatches) { std::unique_ptr embedder; { fml::AutoResetWaitableEvent latch; - task_runners.GetPlatformTaskRunner()->PostTask([&latch, task_runners, - &did_call, &embedder] { - MockDelegate delegate; - EmbedderSurfaceSoftware::SoftwareDispatchTable software_dispatch_table; - PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table; - platform_dispatch_table.platform_message_response_callback = - [&did_call](std::unique_ptr message) { - did_call = true; - }; - std::shared_ptr external_view_embedder; - embedder = std::make_unique( - delegate, task_runners, software_dispatch_table, - platform_dispatch_table, external_view_embedder); - auto platform_message_handler = embedder->GetPlatformMessageHandler(); - fml::RefPtr response = - fml::MakeRefCounted(); - std::unique_ptr message = - std::make_unique("foo", response); - platform_message_handler->HandlePlatformMessage(std::move(message)); - latch.Signal(); - }); + task_runners.GetPlatformTaskRunner()->PostTask( + [&latch, task_runners, &did_call, &embedder] { + MockDelegate delegate; + PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table; + platform_dispatch_table.platform_message_response_callback = + [&did_call](std::unique_ptr message) { + did_call = true; + }; + std::shared_ptr external_view_embedder; + embedder = std::make_unique( + delegate, task_runners, std::make_unique(), + platform_dispatch_table, external_view_embedder); + auto platform_message_handler = embedder->GetPlatformMessageHandler(); + fml::RefPtr response = + fml::MakeRefCounted(); + std::unique_ptr message = + std::make_unique("foo", response); + platform_message_handler->HandlePlatformMessage(std::move(message)); + latch.Signal(); + }); latch.Wait(); } { @@ -135,28 +142,27 @@ TEST(PlatformViewEmbedderTest, DeletionDisabledDispatch) { bool did_call = false; { fml::AutoResetWaitableEvent latch; - task_runners.GetPlatformTaskRunner()->PostTask([&latch, task_runners, - &did_call] { - MockDelegate delegate; - EmbedderSurfaceSoftware::SoftwareDispatchTable software_dispatch_table; - PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table; - platform_dispatch_table.platform_message_response_callback = - [&did_call](std::unique_ptr message) { - did_call = true; - }; - std::shared_ptr external_view_embedder; - auto embedder = std::make_unique( - delegate, task_runners, software_dispatch_table, - platform_dispatch_table, external_view_embedder); - auto platform_message_handler = embedder->GetPlatformMessageHandler(); - fml::RefPtr response = - fml::MakeRefCounted(); - std::unique_ptr message = - std::make_unique("foo", response); - platform_message_handler->HandlePlatformMessage(std::move(message)); - embedder.reset(); - latch.Signal(); - }); + task_runners.GetPlatformTaskRunner()->PostTask( + [&latch, task_runners, &did_call] { + MockDelegate delegate; + PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table; + platform_dispatch_table.platform_message_response_callback = + [&did_call](std::unique_ptr message) { + did_call = true; + }; + std::shared_ptr external_view_embedder; + auto embedder = std::make_unique( + delegate, task_runners, std::make_unique(), + platform_dispatch_table, external_view_embedder); + auto platform_message_handler = embedder->GetPlatformMessageHandler(); + fml::RefPtr response = + fml::MakeRefCounted(); + std::unique_ptr message = + std::make_unique("foo", response); + platform_message_handler->HandlePlatformMessage(std::move(message)); + embedder.reset(); + latch.Signal(); + }); latch.Wait(); } { diff --git a/shell/platform/embedder/tests/embedder_gl_unittests.cc b/shell/platform/embedder/tests/embedder_gl_unittests.cc index 41ed0381c1696..1cea5fe25fa50 100644 --- a/shell/platform/embedder/tests/embedder_gl_unittests.cc +++ b/shell/platform/embedder/tests/embedder_gl_unittests.cc @@ -43,6 +43,8 @@ namespace flutter { namespace testing { +static constexpr int64_t kDefaultViewId = 0ll; + using EmbedderTest = testing::EmbedderTest; TEST_F(EmbedderTest, CanGetVulkanEmbedderContext) { @@ -161,8 +163,9 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -254,8 +257,9 @@ TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); setup.Wait(); @@ -326,8 +330,9 @@ TEST_F(EmbedderTest, RasterCacheEnabled) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); setup.Wait(); @@ -427,8 +432,9 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -519,8 +525,9 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -684,8 +691,9 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -804,7 +812,8 @@ TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, + &event), kSuccess); ASSERT_TRUE(engine.is_valid()); sync_latch.Signal(); @@ -878,8 +887,9 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithRootLayerOnly) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -988,8 +998,9 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithPlatformLayerOnBottom) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -1169,8 +1180,9 @@ TEST_F(EmbedderTest, event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -1198,8 +1210,9 @@ TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositor) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(ImageMatchesFixture("scene_without_custom_compositor.png", rendered_scene)); @@ -1231,8 +1244,9 @@ TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositorWithTransformation) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(ImageMatchesFixture( "scene_without_custom_compositor_with_xform.png", rendered_scene)); @@ -1258,8 +1272,9 @@ TEST_P(EmbedderTestMultiBackend, CanRenderGradientWithoutCompositor) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(ImageMatchesFixture( FixtureNameForBackend(backend, "gradient.png"), rendered_scene)); @@ -1292,8 +1307,9 @@ TEST_F(EmbedderTest, CanRenderGradientWithoutCompositorWithXform) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene)); } @@ -1320,8 +1336,9 @@ TEST_P(EmbedderTestMultiBackend, CanRenderGradientWithCompositor) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(ImageMatchesFixture( FixtureNameForBackend(backend, "gradient.png"), rendered_scene)); @@ -1358,8 +1375,9 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorWithXform) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene)); } @@ -1462,8 +1480,9 @@ TEST_P(EmbedderTestMultiBackend, event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(ImageMatchesFixture( FixtureNameForBackend(backend, "gradient.png"), rendered_scene)); @@ -1577,8 +1596,9 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene)); } @@ -1680,8 +1700,9 @@ TEST_F(EmbedderTest, VerifyB141980393) { event.width = flutter_application_rect.width(); event.height = flutter_application_rect.height(); event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -1725,8 +1746,9 @@ TEST_F(EmbedderTest, CanCreateEmbedderWithCustomRenderTaskRunner) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); task_latch.Wait(); ASSERT_TRUE(task_executed); ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess); @@ -1786,7 +1808,8 @@ TEST_P(EmbedderTestMultiBackend, event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, + &event), kSuccess); }); @@ -1895,8 +1918,9 @@ TEST_P(EmbedderTestMultiBackend, event.width = 400 * 2.0; event.height = 300 * 2.0; event.pixel_ratio = 2.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -1991,8 +2015,9 @@ TEST_F( event.width = 400 * 2.0; event.height = 300 * 2.0; event.pixel_ratio = 2.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -2025,8 +2050,9 @@ TEST_F(EmbedderTest, event.width = 1024; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); constexpr size_t frames_expected = 10; @@ -2065,8 +2091,9 @@ TEST_F(EmbedderTest, event.width = 1024; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); constexpr size_t frames_expected = 10; @@ -2172,8 +2199,9 @@ TEST_P(EmbedderTestMultiBackend, PlatformViewMutatorsAreValid) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -2268,8 +2296,9 @@ TEST_F(EmbedderTest, PlatformViewMutatorsAreValidWithPixelRatio) { event.width = 800; event.height = 600; event.pixel_ratio = 2.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -2371,8 +2400,9 @@ TEST_F(EmbedderTest, event.width = 800; event.height = 600; event.pixel_ratio = 2.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -2399,8 +2429,9 @@ TEST_F(EmbedderTest, EmptySceneIsAcceptable) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); } @@ -2427,8 +2458,9 @@ TEST_F(EmbedderTest, SceneWithNoRootContainerIsAcceptable) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); } @@ -2462,8 +2494,9 @@ TEST_F(EmbedderTest, ArcEndCapsAreDrawnCorrectly) { event.width = 800; event.height = 1024; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(ImageMatchesFixture("arc_end_caps.png", scene_image)); } @@ -2541,8 +2574,9 @@ TEST_F(EmbedderTest, ClipsAreCorrectlyCalculated) { event.width = 400; event.height = 300; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); } @@ -2625,8 +2659,9 @@ TEST_F(EmbedderTest, ComplexClipsAreCorrectlyCalculated) { event.width = 1024; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); } @@ -2855,8 +2890,9 @@ TEST_F(EmbedderTest, CompositorCanPostZeroLayersForPresentation) { event.width = 300; event.height = 200; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -2918,8 +2954,9 @@ TEST_F(EmbedderTest, CompositorCanPostOnlyPlatformViews) { event.width = 300; event.height = 200; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -2957,8 +2994,9 @@ TEST_F(EmbedderTest, CompositorRenderTargetsAreRecycled) { event.width = 300; event.height = 200; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 10u); @@ -3034,8 +3072,9 @@ TEST_F(EmbedderTest, CompositorRenderTargetsAreInStableOrder) { event.width = 300; event.height = 200; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); } @@ -3060,8 +3099,9 @@ TEST_F(EmbedderTest, FrameInfoContainsValidWidthAndHeight) { event.width = 1024; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); static fml::CountDownLatch frame_latch(10); @@ -3191,8 +3231,9 @@ TEST_F(EmbedderTest, PresentInfoContainsValidFBOId) { event.width = 1024; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); static fml::CountDownLatch frame_latch(10); @@ -3265,8 +3306,9 @@ TEST_F(EmbedderTest, event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); // Because it's the same as the first frame, the second frame damage should // be empty but, because there was a full existing buffer damage, the buffer @@ -3287,8 +3329,9 @@ TEST_F(EmbedderTest, ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600); }); - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); } TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) { @@ -3341,8 +3384,9 @@ TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); // Because it's the same as the first frame, the second frame should not be // rerendered assuming there is no existing damage. @@ -3362,8 +3406,9 @@ TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) { ASSERT_EQ(present_info.buffer_damage.damage->bottom, 0); }); - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); } TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) { @@ -3416,8 +3461,9 @@ TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); // Because it's the same as the first frame, the second frame damage should be // empty but, because there was a partial existing damage, the buffer damage @@ -3438,8 +3484,9 @@ TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) { ASSERT_EQ(present_info.buffer_damage.damage->bottom, 300); }); - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); } TEST_F(EmbedderTest, PopulateExistingDamageReceivesValidID) { @@ -3473,8 +3520,9 @@ TEST_F(EmbedderTest, PopulateExistingDamageReceivesValidID) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); } TEST_F(EmbedderTest, PopulateExistingDamageReceivesInvalidID) { @@ -3519,8 +3567,9 @@ TEST_F(EmbedderTest, PopulateExistingDamageReceivesInvalidID) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); } TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithDisplayId) { @@ -3559,8 +3608,9 @@ TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithDisplayId) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); } @@ -3601,8 +3651,9 @@ TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithoutDisplayId) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); } @@ -3650,8 +3701,9 @@ TEST_F(EmbedderTest, SetValidMultiDisplayConfiguration) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); } @@ -3696,8 +3748,9 @@ TEST_F(EmbedderTest, MultipleDisplaysWithSingleDisplayTrueIsInvalid) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); } @@ -3742,8 +3795,9 @@ TEST_F(EmbedderTest, MultipleDisplaysWithSameDisplayIdIsInvalid) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); } @@ -3783,8 +3837,9 @@ TEST_F(EmbedderTest, CompositorRenderTargetsNotRecycledWhenAvoidsCacheSet) { event.width = 300; event.height = 200; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); @@ -3945,8 +4000,9 @@ TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLTexture) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); } @@ -4008,8 +4064,9 @@ TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLFramebuffer) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); } diff --git a/shell/platform/embedder/tests/embedder_metal_unittests.mm b/shell/platform/embedder/tests/embedder_metal_unittests.mm index 78f7b82ed2fbf..2991dbae2835f 100644 --- a/shell/platform/embedder/tests/embedder_metal_unittests.mm +++ b/shell/platform/embedder/tests/embedder_metal_unittests.mm @@ -30,6 +30,8 @@ namespace flutter { namespace testing { +constexpr int64_t kDefaultViewId = 0ll; + using EmbedderTest = testing::EmbedderTest; TEST_F(EmbedderTest, CanRenderGradientWithMetal) { @@ -51,7 +53,7 @@ event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), kSuccess); + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), kSuccess); // TODO (https://github.com/flutter/flutter/issues/73590): re-enable once // we are able to figure out why this fails on the bots. @@ -120,7 +122,7 @@ GrBackendTexture backend_texture(texture_size.width(), texture_size.height(), Gr event.width = texture_size.width(); event.height = texture_size.height(); event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), kSuccess); + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), kSuccess); ASSERT_TRUE(ImageMatchesFixture("external_texture_metal.png", rendered_scene)); } @@ -202,7 +204,7 @@ GrBackendTexture backend_texture(texture_size.width(), texture_size.height(), Gr event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), kSuccess); + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -227,7 +229,7 @@ GrBackendTexture backend_texture(texture_size.width(), texture_size.height(), Gr event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), kSuccess); + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), kSuccess); ASSERT_TRUE(ImageMatchesFixture("scene_without_custom_compositor.png", rendered_scene)); } @@ -275,7 +277,7 @@ GrBackendTexture backend_texture(texture_size.width(), texture_size.height(), Gr event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), kSuccess); + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), kSuccess); ASSERT_TRUE(engine.is_valid()); collect_context->latch.Wait(); @@ -429,7 +431,7 @@ GrBackendTexture backend_texture(texture_size.width(), texture_size.height(), Gr event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), kSuccess); + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -487,7 +489,7 @@ void Collect() { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), kSuccess); + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); } diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index 33af2a2e122be..eb88e4639292c 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -52,6 +52,8 @@ static uint64_t NanosFromEpoch(int millis_from_now) { namespace flutter { namespace testing { +static constexpr int64_t kDefaultViewId = 0ll; + using EmbedderTest = testing::EmbedderTest; TEST(EmbedderTestNoFixture, MustNotRunWithInvalidArgs) { @@ -805,8 +807,9 @@ TEST_F(EmbedderTest, event.physical_view_inset_right = 0.0; event.physical_view_inset_bottom = 0.0; event.physical_view_inset_left = 0.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -921,8 +924,9 @@ TEST_F(EmbedderTest, NoLayerCreatedForTransparentOverlayOnTopOfPlatformLayer) { event.physical_view_inset_right = 0.0; event.physical_view_inset_bottom = 0.0; event.physical_view_inset_left = 0.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -1043,8 +1047,9 @@ TEST_F(EmbedderTest, NoLayerCreatedForNoOverlayOnTopOfPlatformLayer) { event.physical_view_inset_right = 0.0; event.physical_view_inset_bottom = 0.0; event.physical_view_inset_left = 0.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -1114,8 +1119,9 @@ TEST_F(EmbedderTest, CanDeinitializeAnEngine) { event.physical_view_inset_right = 0.0; event.physical_view_inset_bottom = 0.0; event.physical_view_inset_left = 0.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kInvalidArguments); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kInvalidArguments); engine.reset(); } @@ -1319,8 +1325,9 @@ TEST_F(EmbedderTest, VerifyB143464703WithSoftwareBackend) { event.physical_view_inset_right = 0.0; event.physical_view_inset_bottom = 0.0; event.physical_view_inset_left = 0.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); ASSERT_TRUE(engine.is_valid()); // wait for scene to be rendered. @@ -1811,8 +1818,9 @@ TEST_F(EmbedderTest, InvalidFlutterWindowMetricsEvent) { event.physical_view_inset_left = 0.0; // Pixel ratio must be positive. - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kInvalidArguments); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kInvalidArguments); event.pixel_ratio = 1.0; event.physical_view_inset_top = -1.0; @@ -1821,8 +1829,9 @@ TEST_F(EmbedderTest, InvalidFlutterWindowMetricsEvent) { event.physical_view_inset_left = -1.0; // Physical view insets must be non-negative. - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kInvalidArguments); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kInvalidArguments); event.physical_view_inset_top = 700; event.physical_view_inset_right = 900; @@ -1831,8 +1840,9 @@ TEST_F(EmbedderTest, InvalidFlutterWindowMetricsEvent) { // Top/bottom insets cannot be greater than height. // Left/right insets cannot be greater than width. - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kInvalidArguments); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kInvalidArguments); } static void expectSoftwareRenderingOutputMatches( @@ -1876,8 +1886,9 @@ static void expectSoftwareRenderingOutputMatches( event.width = 1; event.height = 1; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); latch.Wait(); ASSERT_TRUE(matches); @@ -2389,7 +2400,8 @@ TEST_F(EmbedderTest, VsyncCallbackPostedIntoFuture) { event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, + &event), kSuccess); }); @@ -2464,8 +2476,9 @@ TEST_F(EmbedderTest, CanSetNextFrameCallback) { event.physical_view_inset_right = 0.0; event.physical_view_inset_bottom = 0.0; event.physical_view_inset_left = 0.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), - kSuccess); + ASSERT_EQ( + FlutterEngineSendWindowMetricsEvent(engine.get(), kDefaultViewId, &event), + kSuccess); callback_latch.Wait(); } diff --git a/shell/platform/fuchsia/flutter/BUILD.gn b/shell/platform/fuchsia/flutter/BUILD.gn index 68af2224ef07b..52c4ea1831b1a 100644 --- a/shell/platform/fuchsia/flutter/BUILD.gn +++ b/shell/platform/fuchsia/flutter/BUILD.gn @@ -99,6 +99,8 @@ template("runner_sources") { "software_surface.h", "software_surface_producer.cc", "software_surface_producer.h", + "studio.cc", + "studio.h", "surface.cc", "surface.h", "surface_producer.h", diff --git a/shell/platform/fuchsia/flutter/engine.cc b/shell/platform/fuchsia/flutter/engine.cc index 40eba58810add..370cd4f269438 100644 --- a/shell/platform/fuchsia/flutter/engine.cc +++ b/shell/platform/fuchsia/flutter/engine.cc @@ -501,6 +501,9 @@ void Engine::Initialize( std::bind(&Engine::DestroyFlatlandView, this, std::placeholders::_1, std::placeholders::_2); + OnCreateStudio on_create_studio_callback = + std::bind(&Engine::CreateStudio, this); + OnCreateSurface on_create_surface_callback = std::bind(&Engine::CreateSurface, this); @@ -560,6 +563,7 @@ void Engine::Initialize( std::move(on_destroy_gfx_view_callback), on_destroy_flatland_view_callback = std::move(on_destroy_flatland_view_callback), + on_create_studio_callback = std::move(on_create_studio_callback), on_create_surface_callback = std::move(on_create_surface_callback), on_semantics_node_update_callback = std::move(on_semantics_node_update_callback), @@ -631,6 +635,7 @@ void Engine::Initialize( std::move(on_create_flatland_view_callback), std::move(on_update_view_callback), std::move(on_destroy_flatland_view_callback), + std::move(on_create_studio_callback), std::move(on_create_surface_callback), std::move(on_semantics_node_update_callback), std::move(on_request_announce_callback), @@ -652,6 +657,7 @@ void Engine::Initialize( std::move(on_create_gfx_view_callback), std::move(on_update_view_callback), std::move(on_destroy_gfx_view_callback), + std::move(on_create_studio_callback), std::move(on_create_surface_callback), std::move(on_semantics_node_update_callback), std::move(on_request_announce_callback), @@ -970,6 +976,10 @@ void Engine::DestroyFlatlandView(int64_t view_id, }); } +std::unique_ptr Engine::CreateStudio() { + return std::make_unique(surface_producer_->gr_context()); +} + std::unique_ptr Engine::CreateSurface() { return std::make_unique(thread_label_, GetExternalViewEmbedder(), surface_producer_->gr_context()); diff --git a/shell/platform/fuchsia/flutter/engine.h b/shell/platform/fuchsia/flutter/engine.h index cfcbe1e2ca007..dd5b6049c4311 100644 --- a/shell/platform/fuchsia/flutter/engine.h +++ b/shell/platform/fuchsia/flutter/engine.h @@ -19,7 +19,6 @@ #include #include "flutter/flow/embedded_views.h" -#include "flutter/flow/surface.h" #include "flutter/fml/macros.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/thread_host.h" @@ -31,6 +30,8 @@ #include "gfx_external_view_embedder.h" #include "gfx_session_connection.h" #include "isolate_configurator.h" +#include "studio.h" +#include "surface.h" #include "surface_producer.h" namespace flutter_runner { @@ -146,6 +147,8 @@ class Engine final : public fuchsia::memorypressure::Watcher { std::shared_ptr GetExternalViewEmbedder(); + std::unique_ptr CreateStudio(); + std::unique_ptr CreateSurface(); Delegate& delegate_; diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h index 00a845cde2e85..033efbe6ae62a 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h @@ -92,9 +92,6 @@ class FlatlandExternalViewEmbedder final // |ExternalViewEmbedder| void CancelFrame() override { Reset(); } - // |ExternalViewEmbedder| - bool SupportsDynamicThreadMerging() override { return false; } - // View manipulation. // |SetViewProperties| doesn't manipulate the view directly -- it sets pending // properties for the next |UpdateView| call. diff --git a/shell/platform/fuchsia/flutter/flatland_platform_view.cc b/shell/platform/fuchsia/flutter/flatland_platform_view.cc index cbadf9d47b6e0..d6a028b277c98 100644 --- a/shell/platform/fuchsia/flutter/flatland_platform_view.cc +++ b/shell/platform/fuchsia/flutter/flatland_platform_view.cc @@ -8,6 +8,8 @@ namespace flutter_runner { +static constexpr int64_t kFlutterDefaultViewId = 0ll; + FlatlandPlatformView::FlatlandPlatformView( flutter::PlatformView::Delegate& delegate, flutter::TaskRunners task_runners, @@ -26,6 +28,7 @@ FlatlandPlatformView::FlatlandPlatformView( OnCreateFlatlandView on_create_view_callback, OnUpdateView on_update_view_callback, OnDestroyFlatlandView on_destroy_view_callback, + OnCreateStudio on_create_studio_callback, OnCreateSurface on_create_surface_callback, OnSemanticsNodeUpdate on_semantics_node_update_callback, OnRequestAnnounce on_request_announce_callback, @@ -48,6 +51,7 @@ FlatlandPlatformView::FlatlandPlatformView( std::move(pointerinjector_registry), std::move(wireframe_enabled_callback), std::move(on_update_view_callback), + std::move(on_create_studio_callback), std::move(on_create_surface_callback), std::move(on_semantics_node_update_callback), std::move(on_request_announce_callback), @@ -85,30 +89,31 @@ void FlatlandPlatformView::OnGetLayout( float pixel_ratio = view_pixel_ratio_ ? *view_pixel_ratio_ : 1.0f; - SetViewportMetrics({ - pixel_ratio, // device_pixel_ratio - std::round(view_logical_size_.value()[0] * - pixel_ratio), // physical_width - std::round(view_logical_size_.value()[1] * - pixel_ratio), // physical_height - 0.0f, // physical_padding_top - 0.0f, // physical_padding_right - 0.0f, // physical_padding_bottom - 0.0f, // physical_padding_left - 0.0f, // physical_view_inset_top - 0.0f, // physical_view_inset_right - 0.0f, // physical_view_inset_bottom - 0.0f, // physical_view_inset_left - 0.0f, // p_physical_system_gesture_inset_top - 0.0f, // p_physical_system_gesture_inset_right - 0.0f, // p_physical_system_gesture_inset_bottom - 0.0f, // p_physical_system_gesture_inset_left, - -1.0, // p_physical_touch_slop, - {}, // p_physical_display_features_bounds - {}, // p_physical_display_features_type - {}, // p_physical_display_features_state - 0, // p_display_id - }); + SetViewportMetrics(kFlutterDefaultViewId, + { + pixel_ratio, // device_pixel_ratio + std::round(view_logical_size_.value()[0] * + pixel_ratio), // physical_width + std::round(view_logical_size_.value()[1] * + pixel_ratio), // physical_height + 0.0f, // physical_padding_top + 0.0f, // physical_padding_right + 0.0f, // physical_padding_bottom + 0.0f, // physical_padding_left + 0.0f, // physical_view_inset_top + 0.0f, // physical_view_inset_right + 0.0f, // physical_view_inset_bottom + 0.0f, // physical_view_inset_left + 0.0f, // p_physical_system_gesture_inset_top + 0.0f, // p_physical_system_gesture_inset_right + 0.0f, // p_physical_system_gesture_inset_bottom + 0.0f, // p_physical_system_gesture_inset_left, + -1.0, // p_physical_touch_slop, + {}, // p_physical_display_features_bounds + {}, // p_physical_display_features_type + {}, // p_physical_display_features_state + 0, // p_display_id + }); parent_viewport_watcher_->GetLayout( fit::bind_member(this, &FlatlandPlatformView::OnGetLayout)); diff --git a/shell/platform/fuchsia/flutter/flatland_platform_view.h b/shell/platform/fuchsia/flutter/flatland_platform_view.h index 8e839c9b1eee4..2a500e6a7910d 100644 --- a/shell/platform/fuchsia/flutter/flatland_platform_view.h +++ b/shell/platform/fuchsia/flutter/flatland_platform_view.h @@ -40,6 +40,7 @@ class FlatlandPlatformView final : public flutter_runner::PlatformView { OnCreateFlatlandView on_create_view_callback, OnUpdateView on_update_view_callback, OnDestroyFlatlandView on_destroy_view_callback, + OnCreateStudio on_create_studio_callback, OnCreateSurface on_create_surface_callback, OnSemanticsNodeUpdate on_semantics_node_update_callback, OnRequestAnnounce on_request_announce_callback, diff --git a/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h b/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h index eb37d2e7e2d1f..39e25dc3daeaa 100644 --- a/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h +++ b/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h @@ -115,9 +115,6 @@ class GfxExternalViewEmbedder final : public flutter::ExternalViewEmbedder { // |ExternalViewEmbedder| void CancelFrame() override { Reset(); } - // |ExternalViewEmbedder| - bool SupportsDynamicThreadMerging() override { return false; } - // View manipulation. // |SetViewProperties| doesn't manipulate the view directly -- it sets pending // properties for the next |UpdateView| call. diff --git a/shell/platform/fuchsia/flutter/gfx_platform_view.cc b/shell/platform/fuchsia/flutter/gfx_platform_view.cc index df0e9906caf50..462059f2e455c 100644 --- a/shell/platform/fuchsia/flutter/gfx_platform_view.cc +++ b/shell/platform/fuchsia/flutter/gfx_platform_view.cc @@ -8,6 +8,8 @@ namespace flutter_runner { +static constexpr int64_t kFlutterDefaultViewId = 0ll; + GfxPlatformView::GfxPlatformView( flutter::PlatformView::Delegate& delegate, flutter::TaskRunners task_runners, @@ -27,6 +29,7 @@ GfxPlatformView::GfxPlatformView( OnCreateGfxView on_create_view_callback, OnUpdateView on_update_view_callback, OnDestroyGfxView on_destroy_view_callback, + OnCreateStudio on_create_studio_callback, OnCreateSurface on_create_surface_callback, OnSemanticsNodeUpdate on_semantics_node_update_callback, OnRequestAnnounce on_request_announce_callback, @@ -49,6 +52,7 @@ GfxPlatformView::GfxPlatformView( std::move(pointerinjector_registry), std::move(wireframe_enabled_callback), std::move(on_update_view_callback), + std::move(on_create_studio_callback), std::move(on_create_surface_callback), std::move(on_semantics_node_update_callback), std::move(on_request_announce_callback), @@ -213,28 +217,30 @@ void GfxPlatformView::OnScenicEvent( metrics_changed) { const float pixel_ratio = *view_pixel_ratio_; const std::array logical_size = *view_logical_size_; - SetViewportMetrics({ - pixel_ratio, // device_pixel_ratio - std::round(logical_size[0] * pixel_ratio), // physical_width - std::round(logical_size[1] * pixel_ratio), // physical_height - 0.0f, // physical_padding_top - 0.0f, // physical_padding_right - 0.0f, // physical_padding_bottom - 0.0f, // physical_padding_left - 0.0f, // physical_view_inset_top - 0.0f, // physical_view_inset_right - 0.0f, // physical_view_inset_bottom - 0.0f, // physical_view_inset_left - 0.0f, // p_physical_system_gesture_inset_top - 0.0f, // p_physical_system_gesture_inset_right - 0.0f, // p_physical_system_gesture_inset_bottom - 0.0f, // p_physical_system_gesture_inset_left, - -1.0, // p_physical_touch_slop, - {}, // p_physical_display_features_bounds - {}, // p_physical_display_features_type - {}, // p_physical_display_features_state - 0, // pdisplay_id - }); + SetViewportMetrics( + kFlutterDefaultViewId, + { + pixel_ratio, // device_pixel_ratio + std::round(logical_size[0] * pixel_ratio), // physical_width + std::round(logical_size[1] * pixel_ratio), // physical_height + 0.0f, // physical_padding_top + 0.0f, // physical_padding_right + 0.0f, // physical_padding_bottom + 0.0f, // physical_padding_left + 0.0f, // physical_view_inset_top + 0.0f, // physical_view_inset_right + 0.0f, // physical_view_inset_bottom + 0.0f, // physical_view_inset_left + 0.0f, // p_physical_system_gesture_inset_top + 0.0f, // p_physical_system_gesture_inset_right + 0.0f, // p_physical_system_gesture_inset_bottom + 0.0f, // p_physical_system_gesture_inset_left, + -1.0, // p_physical_touch_slop, + {}, // p_physical_display_features_bounds + {}, // p_physical_display_features_type + {}, // p_physical_display_features_state + 0, // pdisplay_id + }); } } diff --git a/shell/platform/fuchsia/flutter/gfx_platform_view.h b/shell/platform/fuchsia/flutter/gfx_platform_view.h index 2e92a41f0aad6..f1bf88baf5fdf 100644 --- a/shell/platform/fuchsia/flutter/gfx_platform_view.h +++ b/shell/platform/fuchsia/flutter/gfx_platform_view.h @@ -44,6 +44,7 @@ class GfxPlatformView final : public flutter_runner::PlatformView, OnCreateGfxView on_create_view_callback, OnUpdateView on_update_view_callback, OnDestroyGfxView on_destroy_view_callback, + OnCreateStudio on_create_studio_callback, OnCreateSurface on_create_surface_callback, OnSemanticsNodeUpdate on_semantics_node_update_callback, OnRequestAnnounce on_request_announce_callback, diff --git a/shell/platform/fuchsia/flutter/platform_view.cc b/shell/platform/fuchsia/flutter/platform_view.cc index 05658820c9166..a3e8cf212d3c6 100644 --- a/shell/platform/fuchsia/flutter/platform_view.cc +++ b/shell/platform/fuchsia/flutter/platform_view.cc @@ -70,6 +70,7 @@ PlatformView::PlatformView( fuchsia::ui::pointerinjector::RegistryHandle pointerinjector_registry, OnEnableWireframe wireframe_enabled_callback, OnUpdateView on_update_view_callback, + OnCreateStudio on_create_studio_callback, OnCreateSurface on_create_surface_callback, OnSemanticsNodeUpdate on_semantics_node_update_callback, OnRequestAnnounce on_request_announce_callback, @@ -88,6 +89,7 @@ PlatformView::PlatformView( std::move(mouse_source))), wireframe_enabled_callback_(std::move(wireframe_enabled_callback)), on_update_view_callback_(std::move(on_update_view_callback)), + on_create_studio_callback_(std::move(on_create_studio_callback)), on_create_surface_callback_(std::move(on_create_surface_callback)), on_semantics_node_update_callback_( std::move(on_semantics_node_update_callback)), @@ -388,7 +390,13 @@ std::unique_ptr PlatformView::CreateVSyncWaiter() { } // |flutter::PlatformView| -std::unique_ptr PlatformView::CreateRenderingSurface() { +std::unique_ptr PlatformView::CreateRenderingStudio() { + return on_create_studio_callback_ ? on_create_studio_callback_() : nullptr; +} + +// |flutter::PlatformView| +std::unique_ptr PlatformView::CreateRenderingSurface( + int64_t view_id) { return on_create_surface_callback_ ? on_create_surface_callback_() : nullptr; } diff --git a/shell/platform/fuchsia/flutter/platform_view.h b/shell/platform/fuchsia/flutter/platform_view.h index 724780dde7e2c..8d6caf340fd7f 100644 --- a/shell/platform/fuchsia/flutter/platform_view.h +++ b/shell/platform/fuchsia/flutter/platform_view.h @@ -35,6 +35,8 @@ #include "focus_delegate.h" #include "pointer_delegate.h" #include "pointer_injector_delegate.h" +#include "studio.h" +#include "surface.h" #include "text_delegate.h" namespace flutter_runner { @@ -42,6 +44,7 @@ namespace flutter_runner { using OnEnableWireframe = fit::function; using ViewCallback = std::function; using OnUpdateView = fit::function; +using OnCreateStudio = fit::function()>; using OnCreateSurface = fit::function()>; using OnSemanticsNodeUpdate = fit::function; @@ -79,6 +82,7 @@ class PlatformView : public flutter::PlatformView { fuchsia::ui::pointerinjector::RegistryHandle pointerinjector_registry, OnEnableWireframe wireframe_enabled_callback, OnUpdateView on_update_view_callback, + OnCreateStudio on_create_studio_callback, OnCreateSurface on_create_surface_callback, OnSemanticsNodeUpdate on_semantics_node_update_callback, OnRequestAnnounce on_request_announce_callback, @@ -108,7 +112,11 @@ class PlatformView : public flutter::PlatformView { std::unique_ptr CreateVSyncWaiter() override; // |flutter::PlatformView| - std::unique_ptr CreateRenderingSurface() override; + std::unique_ptr CreateRenderingStudio() override; + + // |flutter::PlatformView| + std::unique_ptr CreateRenderingSurface( + int64_t view_id) override; // |flutter::PlatformView| void HandlePlatformMessage( @@ -188,6 +196,7 @@ class PlatformView : public flutter::PlatformView { OnEnableWireframe wireframe_enabled_callback_; OnUpdateView on_update_view_callback_; + OnCreateStudio on_create_studio_callback_; OnCreateSurface on_create_surface_callback_; OnSemanticsNodeUpdate on_semantics_node_update_callback_; OnRequestAnnounce on_request_announce_callback_; diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc index 4959461c8a115..db1a8577679f0 100644 --- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -31,6 +31,7 @@ #include "gtest/gtest.h" #include "platform/assert.h" +#include "studio.h" #include "surface.h" #include "task_runner_adapter.h" #include "tests/fakes/focuser.h" @@ -76,11 +77,7 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { } // |flutter::PlatformView::Delegate| - void OnPlatformViewCreated(std::unique_ptr surface) { - ASSERT_EQ(surface_.get(), nullptr); - - surface_ = std::move(surface); - } + void OnPlatformViewCreated() {} // |flutter::PlatformView::Delegate| void OnPlatformViewDestroyed() {} // |flutter::PlatformView::Delegate| @@ -89,6 +86,7 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) {} // |flutter::PlatformView::Delegate| void OnPlatformViewSetViewportMetrics( + int64_t view_id, const flutter::ViewportMetrics& metrics) { metrics_ = metrics; } @@ -144,7 +142,6 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { std::unique_ptr updated_asset_resolver, flutter::AssetResolver::AssetResolverType type) {} - flutter::Surface* surface() const { return surface_.get(); } flutter::PlatformMessage* message() const { return message_.get(); } const flutter::ViewportMetrics& metrics() const { return metrics_; } int32_t semantics_features() const { return semantics_features_; } @@ -161,7 +158,6 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { } private: - std::unique_ptr surface_; std::unique_ptr message_; flutter::ViewportMetrics metrics_; std::vector> pointer_packets_; @@ -302,6 +298,11 @@ class PlatformViewBuilder { return *this; } + PlatformViewBuilder& SetCreateStudioCallback(OnCreateStudio callback) { + on_create_studio_callback_ = std::move(callback); + return *this; + } + PlatformViewBuilder& SetCreateSurfaceCallback(OnCreateSurface callback) { on_create_surface_callback_ = std::move(callback); return *this; @@ -328,6 +329,7 @@ class PlatformViewBuilder { std::move(on_create_view_callback_), std::move(on_update_view_callback_), std::move(on_destroy_view_callback_), + std::move(on_create_studio_callback_), std::move(on_create_surface_callback_), std::move(on_semantics_node_update_callback_), std::move(on_request_announce_callback_), @@ -358,6 +360,7 @@ class PlatformViewBuilder { OnCreateGfxView on_create_view_callback_; OnUpdateView on_update_view_callback_; OnDestroyGfxView on_destroy_view_callback_; + OnCreateStudio on_create_studio_callback_; OnCreateSurface on_create_surface_callback_; OnSemanticsNodeUpdate on_semantics_node_update_callback_; OnRequestAnnounce on_request_announce_callback_; @@ -499,6 +502,9 @@ TEST_F(PlatformViewTests, CreateSurfaceTest) { flutter::MakeDefaultContextOptions(flutter::ContextType::kRender)); std::shared_ptr external_view_embedder = std::make_shared(); + auto CreateStudioCallback = [gr_context]() { + return std::make_unique(gr_context.get()); + }; auto CreateSurfaceCallback = [&external_view_embedder, gr_context]() { return std::make_unique( "PlatformViewTest", external_view_embedder, gr_context.get()); @@ -506,6 +512,7 @@ TEST_F(PlatformViewTests, CreateSurfaceTest) { flutter_runner::GfxPlatformView platform_view = PlatformViewBuilder(delegate, std::move(task_runners)) + .SetCreateStudioCallback(CreateStudioCallback) .SetCreateSurfaceCallback(CreateSurfaceCallback) .SetExternalViewEmbedder(external_view_embedder) .Build(); @@ -513,7 +520,8 @@ TEST_F(PlatformViewTests, CreateSurfaceTest) { RunLoopUntilIdle(); - EXPECT_EQ(gr_context.get(), delegate.surface()->GetContext()); + // TODO(dkwingsmt) + // EXPECT_EQ(gr_context.get(), delegate.surface()->GetContext()); EXPECT_EQ(external_view_embedder.get(), platform_view.CreateExternalViewEmbedder().get()); } diff --git a/shell/platform/fuchsia/flutter/studio.cc b/shell/platform/fuchsia/flutter/studio.cc new file mode 100644 index 0000000000000..2b40a531586fa --- /dev/null +++ b/shell/platform/fuchsia/flutter/studio.cc @@ -0,0 +1,30 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "studio.h" + +#include +#include +#include +#include + +#include "flutter/fml/unique_fd.h" + +namespace flutter_runner { + +Studio::Studio(GrDirectContext* gr_context) : gr_context_(gr_context) {} + +Studio::~Studio() = default; + +// |flutter::Studio| +bool Studio::IsValid() { + return true; +} + +// |flutter::Studio| +GrDirectContext* Studio::GetContext() { + return gr_context_; +} + +} // namespace flutter_runner diff --git a/shell/platform/fuchsia/flutter/studio.h b/shell/platform/fuchsia/flutter/studio.h new file mode 100644 index 0000000000000..1560238e74ee3 --- /dev/null +++ b/shell/platform/fuchsia/flutter/studio.h @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "flutter/flow/studio.h" +#include "flutter/fml/macros.h" +#include "flutter/fml/memory/weak_ptr.h" + +namespace flutter_runner { + +// The interface between the Flutter rasterizer and the underlying platform. May +// be constructed on any thread but will be used by the engine only on the +// raster thread. +class Studio final : public flutter::Studio { + public: + Studio(GrDirectContext* gr_context); + + ~Studio() override; + + private: + GrDirectContext* gr_context_; + + // |flutter::Studio| + bool IsValid() override; + + // |flutter::Studio| + GrDirectContext* GetContext() override; + + FML_DISALLOW_COPY_AND_ASSIGN(Studio); +}; + +} // namespace flutter_runner diff --git a/shell/platform/fuchsia/flutter/surface.cc b/shell/platform/fuchsia/flutter/surface.cc index 49d06f023cbf8..beb58b3d51478 100644 --- a/shell/platform/fuchsia/flutter/surface.cc +++ b/shell/platform/fuchsia/flutter/surface.cc @@ -16,9 +16,7 @@ namespace flutter_runner { Surface::Surface(std::string debug_label, std::shared_ptr view_embedder, GrDirectContext* gr_context) - : debug_label_(std::move(debug_label)), - view_embedder_(view_embedder), - gr_context_(gr_context) {} + : debug_label_(std::move(debug_label)) {} Surface::~Surface() = default; @@ -39,11 +37,6 @@ std::unique_ptr Surface::AcquireFrame( size); } -// |flutter::Surface| -GrDirectContext* Surface::GetContext() { - return gr_context_; -} - // |flutter::Surface| SkMatrix Surface::GetRootTransformation() const { // This backend does not support delegating to the underlying platform to diff --git a/shell/platform/fuchsia/flutter/surface.h b/shell/platform/fuchsia/flutter/surface.h index 5d9098fbc6e07..aa76a65d5f285 100644 --- a/shell/platform/fuchsia/flutter/surface.h +++ b/shell/platform/fuchsia/flutter/surface.h @@ -23,8 +23,6 @@ class Surface final : public flutter::Surface { private: const std::string debug_label_; - std::shared_ptr view_embedder_; - GrDirectContext* gr_context_; // |flutter::Surface| bool IsValid() override; @@ -33,9 +31,6 @@ class Surface final : public flutter::Surface { std::unique_ptr AcquireFrame( const SkISize& size) override; - // |flutter::Surface| - GrDirectContext* GetContext() override; - // |flutter::Surface| SkMatrix GetRootTransformation() const override; diff --git a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc index ce1d55fdc1c91..f0e3c6553fced 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc @@ -33,6 +33,7 @@ #include "fakes/platform_message.h" #include "fakes/touch_source.h" #include "fakes/view_ref_focused.h" +#include "flutter/shell/platform/fuchsia/flutter/studio.h" #include "flutter/shell/platform/fuchsia/flutter/surface.h" #include "flutter/shell/platform/fuchsia/flutter/task_runner_adapter.h" #include "platform/assert.h" @@ -75,11 +76,7 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { } // |flutter::PlatformView::Delegate| - void OnPlatformViewCreated(std::unique_ptr surface) { - ASSERT_EQ(surface_.get(), nullptr); - - surface_ = std::move(surface); - } + void OnPlatformViewCreated() {} // |flutter::PlatformView::Delegate| void OnPlatformViewDestroyed() {} // |flutter::PlatformView::Delegate| @@ -88,6 +85,7 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) {} // |flutter::PlatformView::Delegate| void OnPlatformViewSetViewportMetrics( + int64_t view_id, const flutter::ViewportMetrics& metrics) { metrics_ = metrics; } @@ -147,7 +145,6 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { std::unique_ptr updated_asset_resolver, flutter::AssetResolver::AssetResolverType type) {} - flutter::Surface* surface() const { return surface_.get(); } flutter::PlatformMessage* message() const { return message_.get(); } const flutter::ViewportMetrics& metrics() const { return metrics_; } int32_t semantics_features() const { return semantics_features_; } @@ -164,7 +161,6 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { } private: - std::unique_ptr surface_; std::unique_ptr message_; flutter::ViewportMetrics metrics_; std::vector> pointer_packets_; @@ -408,6 +404,11 @@ class PlatformViewBuilder { return *this; } + PlatformViewBuilder& SetCreateStudioCallback(OnCreateStudio callback) { + on_create_studio_callback_ = std::move(callback); + return *this; + } + PlatformViewBuilder& SetCreateSurfaceCallback(OnCreateSurface callback) { on_create_surface_callback_ = std::move(callback); return *this; @@ -433,6 +434,7 @@ class PlatformViewBuilder { std::move(on_create_view_callback_), std::move(on_update_view_callback_), std::move(on_destroy_view_callback_), + std::move(on_create_studio_callback_), std::move(on_create_surface_callback_), std::move(on_semantics_node_update_callback_), std::move(on_request_announce_callback_), @@ -463,6 +465,7 @@ class PlatformViewBuilder { OnCreateFlatlandView on_create_view_callback_; OnDestroyFlatlandView on_destroy_view_callback_; OnUpdateView on_update_view_callback_; + OnCreateStudio on_create_studio_callback_; OnCreateSurface on_create_surface_callback_; OnSemanticsNodeUpdate on_semantics_node_update_callback_; OnRequestAnnounce on_request_announce_callback_; @@ -618,12 +621,16 @@ TEST_F(FlatlandPlatformViewTests, CreateSurfaceTest) { flutter::MakeDefaultContextOptions(flutter::ContextType::kRender)); std::shared_ptr external_view_embedder = std::make_shared(); + auto CreateStudioCallback = [gr_context]() { + return std::make_unique(gr_context.get()); + }; auto CreateSurfaceCallback = [&external_view_embedder, gr_context]() { return std::make_unique( "PlatformViewTest", external_view_embedder, gr_context.get()); }; auto platform_view = PlatformViewBuilder(delegate, std::move(task_runners)) + .SetCreateStudioCallback(CreateStudioCallback) .SetCreateSurfaceCallback(CreateSurfaceCallback) .SetExternalViewEmbedder(external_view_embedder) .Build(); @@ -631,7 +638,8 @@ TEST_F(FlatlandPlatformViewTests, CreateSurfaceTest) { RunLoopUntilIdle(); - EXPECT_EQ(gr_context.get(), delegate.surface()->GetContext()); + // TODO(dkwingsmt) + // EXPECT_EQ(gr_context.get(), delegate.surface()->GetContext()); EXPECT_EQ(external_view_embedder.get(), platform_view.CreateExternalViewEmbedder().get()); } diff --git a/shell/platform/glfw/flutter_glfw.cc b/shell/platform/glfw/flutter_glfw.cc index d50871bd6f14c..de7dcb61fe11f 100644 --- a/shell/platform/glfw/flutter_glfw.cc +++ b/shell/platform/glfw/flutter_glfw.cc @@ -41,6 +41,7 @@ static_assert(FLUTTER_ENGINE_VERSION == 1, ""); const int kFlutterDesktopDontCare = GLFW_DONT_CARE; static constexpr double kDpPerInch = 160.0; +static constexpr int64_t kFlutterDefaultViewId = 0ll; // Struct for storing state within an instance of the GLFW Window. struct FlutterDesktopWindowControllerState { @@ -281,6 +282,7 @@ static void SendWindowMetrics(FlutterDesktopWindowControllerState* controller, double dpi = controller->window_wrapper->pixels_per_screen_coordinate * controller->monitor_screen_coordinates_per_inch; + int64_t view_id = kFlutterDefaultViewId; FlutterWindowMetricsEvent event = {}; event.struct_size = sizeof(event); event.width = width; @@ -294,7 +296,7 @@ static void SendWindowMetrics(FlutterDesktopWindowControllerState* controller, event.pixel_ratio = controller->window_wrapper->pixel_ratio_override; } FlutterEngineSendWindowMetricsEvent(controller->engine->flutter_engine, - &event); + view_id, &event); } // Populates |task_runner| with a description that uses |engine_state|'s event diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 507d9e2271470..513b1e19cd32c 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -26,6 +26,8 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h" +static constexpr int64_t kFlutterDefaultViewId = 0ll; + // Unique number associated with platform tasks. static constexpr size_t kPlatformTaskRunnerIdentifier = 1; @@ -766,12 +768,14 @@ void fl_engine_send_window_metrics_event(FlEngine* self, return; } + // TODO(dkwingsmt) + int64_t view_id = kFlutterDefaultViewId; FlutterWindowMetricsEvent event = {}; event.struct_size = sizeof(FlutterWindowMetricsEvent); event.width = width; event.height = height; event.pixel_ratio = pixel_ratio; - self->embedder_api.SendWindowMetricsEvent(self->engine, &event); + self->embedder_api.SendWindowMetricsEvent(self->engine, view_id, &event); } void fl_engine_send_mouse_pointer_event(FlEngine* self, diff --git a/shell/platform/linux/fl_engine_test.cc b/shell/platform/linux/fl_engine_test.cc index a7329a6997b0f..8b4997bd2b210 100644 --- a/shell/platform/linux/fl_engine_test.cc +++ b/shell/platform/linux/fl_engine_test.cc @@ -22,16 +22,17 @@ TEST(FlEngineTest, WindowMetrics) { FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); bool called = false; - embedder_api->SendWindowMetricsEvent = MOCK_ENGINE_PROC( - SendWindowMetricsEvent, - ([&called](auto engine, const FlutterWindowMetricsEvent* event) { - called = true; - EXPECT_EQ(event->width, static_cast(3840)); - EXPECT_EQ(event->height, static_cast(2160)); - EXPECT_EQ(event->pixel_ratio, 2.0); - - return kSuccess; - })); + embedder_api->SendWindowMetricsEvent = + MOCK_ENGINE_PROC(SendWindowMetricsEvent, + ([&called](auto engine, int64_t view_id, + const FlutterWindowMetricsEvent* event) { + called = true; + EXPECT_EQ(event->width, static_cast(3840)); + EXPECT_EQ(event->height, static_cast(2160)); + EXPECT_EQ(event->pixel_ratio, 2.0); + + return kSuccess; + })); g_autoptr(GError) error = nullptr; EXPECT_TRUE(fl_engine_start(engine, &error)); diff --git a/shell/platform/linux/testing/mock_engine.cc b/shell/platform/linux/testing/mock_engine.cc index eac0cb3809cc9..d704aaaf0608a 100644 --- a/shell/platform/linux/testing/mock_engine.cc +++ b/shell/platform/linux/testing/mock_engine.cc @@ -221,6 +221,7 @@ FlutterEngineResult FlutterEngineDeinitialize(FLUTTER_API_SYMBOL(FlutterEngine) FlutterEngineResult FlutterEngineSendWindowMetricsEvent( FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t view_id, const FlutterWindowMetricsEvent* event) { EXPECT_TRUE(engine->running); return kSuccess; diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index c6c46d7301776..db9da468007f3 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -463,9 +463,10 @@ void FlutterWindowsEngine::AddPluginRegistrarDestructionCallback( } void FlutterWindowsEngine::SendWindowMetricsEvent( + int64_t view_id, const FlutterWindowMetricsEvent& event) { if (engine_) { - embedder_api_.SendWindowMetricsEvent(engine_, &event); + embedder_api_.SendWindowMetricsEvent(engine_, view_id, &event); } } diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index 9fd7df9f4985a..3358d6c08ee01 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -154,7 +154,8 @@ class FlutterWindowsEngine { } // Informs the engine that the window metrics have changed. - void SendWindowMetricsEvent(const FlutterWindowMetricsEvent& event); + void SendWindowMetricsEvent(int64_t view_id, + const FlutterWindowMetricsEvent& event); // Informs the engine of an incoming pointer event. void SendPointerEvent(const FlutterPointerEvent& event); diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 4107546669a1e..741b4ce04df69 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -15,6 +15,8 @@ namespace flutter { namespace { +static constexpr int64_t kFlutterDefaultViewId = 0ll; + // The maximum duration to block the platform thread for while waiting // for a window resize operation to complete. constexpr std::chrono::milliseconds kWindowResizeTimeout{100}; @@ -268,12 +270,14 @@ void FlutterWindowsView::OnResetImeComposing() { void FlutterWindowsView::SendWindowMetrics(size_t width, size_t height, double dpiScale) const { + // TODO(dkwingsmt) + int64_t view_id = kFlutterDefaultViewId; FlutterWindowMetricsEvent event = {}; event.struct_size = sizeof(event); event.width = width; event.height = height; event.pixel_ratio = dpiScale; - engine_->SendWindowMetricsEvent(event); + engine_->SendWindowMetricsEvent(view_id, event); } void FlutterWindowsView::SendInitialBounds() { diff --git a/shell/platform/windows/flutter_windows_view_unittests.cc b/shell/platform/windows/flutter_windows_view_unittests.cc index 89082dd46cba1..ae24ae3e5c7a0 100644 --- a/shell/platform/windows/flutter_windows_view_unittests.cc +++ b/shell/platform/windows/flutter_windows_view_unittests.cc @@ -739,7 +739,7 @@ TEST(FlutterWindowsViewTest, WindowResizeTests) { fml::AutoResetWaitableEvent metrics_sent_latch; modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC( SendWindowMetricsEvent, - ([&metrics_sent_latch](auto engine, + ([&metrics_sent_latch](auto engine, int64_t view_id, const FlutterWindowMetricsEvent* event) { metrics_sent_latch.Signal(); return kSuccess; diff --git a/shell/platform/windows/testing/test_keyboard.cc b/shell/platform/windows/testing/test_keyboard.cc index 4d2109a657108..e9140088c38c7 100644 --- a/shell/platform/windows/testing/test_keyboard.cc +++ b/shell/platform/windows/testing/test_keyboard.cc @@ -192,7 +192,7 @@ void MockEmbedderApiForKeyboard( return kSuccess; }; modifier.embedder_api().SendWindowMetricsEvent = - [](auto engine, const FlutterWindowMetricsEvent* event) { + [](auto engine, int64_t view_id, const FlutterWindowMetricsEvent* event) { return kSuccess; }; modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; }; diff --git a/shell/testing/tester_main.cc b/shell/testing/tester_main.cc index 342b4ea7aebe9..1b1bdeabf6624 100644 --- a/shell/testing/tester_main.cc +++ b/shell/testing/tester_main.cc @@ -23,6 +23,7 @@ #include "flutter/shell/common/shell.h" #include "flutter/shell/common/switches.h" #include "flutter/shell/common/thread_host.h" +#include "flutter/shell/gpu/gpu_studio_software.h" #include "flutter/shell/gpu/gpu_surface_software.h" #include "third_party/dart/runtime/include/bin/dart_io_api.h" @@ -39,6 +40,8 @@ namespace flutter { +static constexpr int64_t kDefaultViewId = 0ll; + class TesterExternalViewEmbedder : public ExternalViewEmbedder { // |ExternalViewEmbedder| DlCanvas* GetRootCanvas() override { return nullptr; } @@ -67,13 +70,19 @@ class TesterExternalViewEmbedder : public ExternalViewEmbedder { DisplayListBuilder builder_; }; +class TesterGPUStudioSoftware : public GPUStudioSoftware { + public: + explicit TesterGPUStudioSoftware(GPUSurfaceSoftwareDelegate* delegate) + : GPUStudioSoftware(delegate) {} + + bool EnableRasterCache() const override { return false; } +}; + class TesterGPUSurfaceSoftware : public GPUSurfaceSoftware { public: TesterGPUSurfaceSoftware(GPUSurfaceSoftwareDelegate* delegate, bool render_to_surface) : GPUSurfaceSoftware(delegate, render_to_surface) {} - - bool EnableRasterCache() const override { return false; } }; class TesterPlatformView : public PlatformView, @@ -83,7 +92,14 @@ class TesterPlatformView : public PlatformView, : PlatformView(delegate, task_runners) {} // |PlatformView| - std::unique_ptr CreateRenderingSurface() override { + std::unique_ptr CreateRenderingStudio() override { + auto studio = std::make_unique(this); + FML_DCHECK(studio->IsValid()); + return studio; + } + + // |PlatformView| + std::unique_ptr CreateRenderingSurface(int64_t view_id) override { auto surface = std::make_unique( this, true /* render to surface */); FML_DCHECK(surface->IsValid()); @@ -353,7 +369,7 @@ int RunTester(const flutter::Settings& settings, metrics.physical_width = physical_width; metrics.physical_height = physical_height; metrics.display_id = 0; - shell->GetPlatformView()->SetViewportMetrics(metrics); + shell->GetPlatformView()->SetViewportMetrics(kDefaultViewId, metrics); // Run the message loop and wait for the script to do its thing. fml::MessageLoop::GetCurrent().Run();