Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Refactor MacOS to use Compositor to create backing stores using FlutterSurfaceManager #22500

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions flow/layers/container_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ void ContainerLayer::TryToPrepareRasterCache(PrerollContext* context,
}
}

#if defined(OS_MACOSX)
bool ContainerLayer::HasPlatformView() {
bool hasPlatformView = false;
for (auto& layer : layers_) {
if (layer->HasPlatformView()) {
hasPlatformView = true;
}
}

return hasPlatformView;
}
#endif

#if defined(LEGACY_FUCHSIA_EMBEDDER)

void ContainerLayer::CheckForChildLayerBelow(PrerollContext* context) {
Expand Down
3 changes: 3 additions & 0 deletions flow/layers/container_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class ContainerLayer : public Layer {

void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_MACOSX)
bool HasPlatformView() override;
#endif
#if defined(LEGACY_FUCHSIA_EMBEDDER)
void CheckForChildLayerBelow(PrerollContext* context) override;
void UpdateScene(std::shared_ptr<SceneUpdateContext> context) override;
Expand Down
6 changes: 6 additions & 0 deletions flow/layers/layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ uint64_t Layer::NextUniqueID() {

void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {}

#if defined(OS_MACOSX)
bool Layer::HasPlatformView() {
return false;
}
#endif

Layer::AutoPrerollSaveLayerState::AutoPrerollSaveLayerState(
PrerollContext* preroll_context,
bool save_layer_is_active,
Expand Down
4 changes: 4 additions & 0 deletions flow/layers/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ class Layer {

virtual void Preroll(PrerollContext* context, const SkMatrix& matrix);

#if defined(OS_MACOSX)
virtual bool HasPlatformView();
#endif

// Used during Preroll by layers that employ a saveLayer to manage the
// PrerollContext settings with values affected by the saveLayer mechanism.
// This object must be created before calling Preroll on the children to
Expand Down
5 changes: 5 additions & 0 deletions flow/layers/layer_tree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ bool LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
root_layer_->Preroll(&context, frame.root_surface_transformation());
return context.surface_needs_readback;
}
#if defined(OS_MACOSX)
bool LayerTree::HasPlatformView() {
return root_layer_->HasPlatformView();
}
#endif

#if defined(LEGACY_FUCHSIA_EMBEDDER)
void LayerTree::UpdateScene(std::shared_ptr<SceneUpdateContext> context) {
Expand Down
7 changes: 7 additions & 0 deletions flow/layers/layer_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ class LayerTree {
bool Preroll(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache = false);

// Used to check before Prerolling to see if the layer tree
// contains a platform view.
// Specifically used for MacOS to determine if the compositor
// should be used.
#if defined(OS_MACOSX)
bool HasPlatformView();
#endif
#if defined(LEGACY_FUCHSIA_EMBEDDER)
void UpdateScene(std::shared_ptr<SceneUpdateContext> context);
#endif
Expand Down
6 changes: 6 additions & 0 deletions flow/layers/platform_view_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ void PlatformViewLayer::Preroll(PrerollContext* context,
std::move(params));
}

#if defined(OS_MACOSX)
bool PlatformViewLayer::HasPlatformView() {
return true;
}
#endif

void PlatformViewLayer::Paint(PaintContext& context) const {
if (context.view_embedder == nullptr) {
#if !defined(LEGACY_FUCHSIA_EMBEDDER)
Expand Down
3 changes: 3 additions & 0 deletions flow/layers/platform_view_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class PlatformViewLayer : public Layer {

void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_MACOSX)
bool HasPlatformView() override;
#endif
#if defined(LEGACY_FUCHSIA_EMBEDDER)
// Updates the system composited scene.
void UpdateScene(std::shared_ptr<SceneUpdateContext> context) override;
Expand Down
2 changes: 2 additions & 0 deletions flow/surface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ bool Surface::ClearRenderContext() {
return false;
}

void Surface::SetRenderToSurface(bool render_to_surface) {}

} // namespace flutter
5 changes: 5 additions & 0 deletions flow/surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ class Surface {

virtual bool ClearRenderContext();

// SetRenderToSurface sets whether or not the surface should be rendered to.
// This is needed for MacOS as we want to render scenes without platform views
// to the surface even in the existence of a external_view_embedder.
virtual void SetRenderToSurface(bool render_to_surface);

private:
FML_DISALLOW_COPY_AND_ASSIGN(Surface);
};
Expand Down
46 changes: 39 additions & 7 deletions shell/common/rasterizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -424,13 +424,30 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
compositor_context_->ui_time().SetLapTime(layer_tree.build_time());

SkCanvas* embedder_root_canvas = nullptr;
#if defined(OS_MACOSX)
// For MacOS, we only want to use the external_view_embedder / compositor
// if there is a platform view in the layer tree.
// TODO(richardjcai): Remove branching logic for using external_view_embedder
// once the compositor supports smooth resizing.
// https://github.com/flutter/flutter/issues/70848.
bool hasPlatformView = layer_tree.HasPlatformView();
if (external_view_embedder_ && hasPlatformView) {
#else
if (external_view_embedder_) {
#endif
external_view_embedder_->BeginFrame(
layer_tree.frame_size(), surface_->GetContext(),
layer_tree.device_pixel_ratio(), raster_thread_merger_);
embedder_root_canvas = external_view_embedder_->GetRootCanvas();
}

#if defined(OS_MACOSX)
if (external_view_embedder_ && hasPlatformView) {
surface_->SetRenderToSurface(false);
} else {
surface_->SetRenderToSurface(true);
}
#endif
// On Android, the external view embedder deletes surfaces in `BeginFrame`.
//
// Deleting a surface also clears the GL context. Therefore, acquire the
Expand All @@ -450,14 +467,23 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
auto root_surface_canvas =
embedder_root_canvas ? embedder_root_canvas : frame->SkiaCanvas();

#if defined(OS_MACOSX)
auto external_view_embedder =
hasPlatformView ? external_view_embedder_.get() : nullptr;
auto raster_thread_merger = hasPlatformView ? raster_thread_merger_ : nullptr;
#else
auto external_view_embedder = external_view_embedder_.get();
auto raster_thread_merger = raster_thread_merger_;
#endif

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
frame->supports_readback(), // surface supports pixel reads
raster_thread_merger_ // thread merger
surface_->GetContext(), // skia GrContext
root_surface_canvas, // root surface canvas
external_view_embedder, // external view embedder
root_surface_transformation, // root surface transformation
true, // instrumentation enabled
frame->supports_readback(), // surface supports pixel reads
raster_thread_merger // thread merger
);

if (compositor_frame) {
Expand All @@ -466,8 +492,14 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
raster_status == RasterStatus::kSkipAndRetry) {
return raster_status;
}
#if defined(OS_MACOSX)
if (external_view_embedder_ &&
(!raster_thread_merger_ || raster_thread_merger_->IsMerged()) &&
hasPlatformView) {
#else
if (external_view_embedder_ &&
(!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
#endif
FML_DCHECK(!frame->IsSubmitted());
external_view_embedder_->SubmitFrame(surface_->GetContext(),
std::move(frame));
Expand Down
5 changes: 5 additions & 0 deletions shell/gpu/gpu_surface_gl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -343,4 +343,9 @@ bool GPUSurfaceGL::ClearRenderContext() {
return delegate_->GLContextClearCurrent();
}

// |Surface|
void GPUSurfaceGL::SetRenderToSurface(bool render_to_surface) {
render_to_surface_ = render_to_surface;
}

} // namespace flutter
5 changes: 4 additions & 1 deletion shell/gpu/gpu_surface_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class GPUSurfaceGL : public Surface {
// |Surface|
bool ClearRenderContext() override;

// |Surface|
void SetRenderToSurface(bool render_to_surface) override;

private:
GPUSurfaceGLDelegate* delegate_;
sk_sp<GrDirectContext> context_;
Expand All @@ -59,7 +62,7 @@ class GPUSurfaceGL : public Surface {
// 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
// external view embedder is present.
const bool render_to_surface_;
bool render_to_surface_;
bool valid_ = false;
fml::TaskRunnerAffineWeakPtrFactory<GPUSurfaceGL> weak_factory_;

Expand Down
2 changes: 1 addition & 1 deletion shell/gpu/gpu_surface_software.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class GPUSurfaceSoftware : public Surface {
// 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
// external view embedder is present.
const bool render_to_surface_;
bool render_to_surface_;
fml::TaskRunnerAffineWeakPtrFactory<GPUSurfaceSoftware> weak_factory_;

FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceSoftware);
Expand Down
8 changes: 8 additions & 0 deletions shell/platform/darwin/macos/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ source_set("flutter_framework_source") {
"framework/Source/FlutterEngine_Internal.h",
"framework/Source/FlutterExternalTextureGL.h",
"framework/Source/FlutterExternalTextureGL.mm",
"framework/Source/FlutterMacOSGLCompositor.h",
"framework/Source/FlutterMacOSGLCompositor.mm",
"framework/Source/FlutterMouseCursorPlugin.h",
"framework/Source/FlutterMouseCursorPlugin.mm",
"framework/Source/FlutterResizeSynchronizer.h",
Expand All @@ -73,9 +75,12 @@ source_set("flutter_framework_source") {
sources += _flutter_framework_headers

deps = [
"//flutter/flow:flow",
"//flutter/fml",
"//flutter/shell/platform/common/cpp:common_cpp_switches",
"//flutter/shell/platform/darwin/common:framework_shared",
"//flutter/shell/platform/embedder:embedder_as_internal_library",
"//third_party/skia",
]

public_configs = [ "//flutter:config" ]
Expand Down Expand Up @@ -115,7 +120,10 @@ executable("flutter_desktop_darwin_unittests") {

sources = [
"framework/Source/FlutterEngineTest.mm",
"framework/Source/FlutterMacOSGLCompositorUnittests.mm",
"framework/Source/FlutterViewControllerTest.mm",
"framework/Source/FlutterViewControllerTestUtils.h",
"framework/Source/FlutterViewControllerTestUtils.mm",
]

cflags_objcc = [ "-fobjc-arc" ]
Expand Down
51 changes: 50 additions & 1 deletion shell/platform/darwin/macos/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMacOSGLCompositor.h"
#import "flutter/shell/platform/embedder/embedder.h"

/**
Expand Down Expand Up @@ -197,6 +197,15 @@ @implementation FlutterEngine {

// Pointer to the Dart AOT snapshot and instruction data.
_FlutterEngineAOTData* _aotData;

// FlutterMacOSGLCompositor is created by the engine.
// This is only created when the engine has a FlutterViewController
// and used to support platform views.
// Creation / Destruction.
std::unique_ptr<flutter::FlutterMacOSGLCompositor> _macOSCompositor;

// FlutterCompositor is copied and used in embedder.cc.
FlutterCompositor _compositor;
}

- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project {
Expand Down Expand Up @@ -306,6 +315,9 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
flutterArguments.aot_data = _aotData;
}

[self setupCompositor];
flutterArguments.compositor = &_compositor;

FlutterEngineResult result = _embedderAPI.Initialize(
FLUTTER_ENGINE_VERSION, &rendererConfig, &flutterArguments, (__bridge void*)(self), &_engine);
if (result != kSuccess) {
Expand Down Expand Up @@ -360,6 +372,43 @@ - (void)setViewController:(FlutterViewController*)controller {
}
}

- (void)setupCompositor {
[_mainOpenGLContext makeCurrentContext];

_macOSCompositor = std::make_unique<flutter::FlutterMacOSGLCompositor>(_viewController);

_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<flutter::FlutterMacOSGLCompositor*>(user_data)->CreateBackingStore(
config, backing_store_out);
};

_compositor.collect_backing_store_callback = [](const FlutterBackingStore* backing_store, //
void* user_data //
) {
return reinterpret_cast<flutter::FlutterMacOSGLCompositor*>(user_data)->CollectBackingStore(
backing_store);
};

_compositor.present_layers_callback = [](const FlutterLayer** layers, //
size_t layers_count, //
void* user_data //
) {
return reinterpret_cast<flutter::FlutterMacOSGLCompositor*>(user_data)->Present(layers,
layers_count);
};

__weak FlutterEngine* weak_self = self;
_macOSCompositor->SetPresentCallback(
[weak_self]() { return [weak_self engineCallbackOnPresent]; });
}

- (id<FlutterBinaryMessenger>)binaryMessenger {
// TODO(stuartmorgan): Switch to FlutterBinaryMessengerRelay to avoid plugins
// keeping the engine alive.
Expand Down
Loading