Skip to content

Commit

Permalink
[macOS, multiwindow] Compositor gets FlutterView lazily (flutter#36392)
Browse files Browse the repository at this point in the history
  • Loading branch information
dkwingsmt authored Nov 3, 2022
1 parent 491032c commit 5108942
Show file tree
Hide file tree
Showing 16 changed files with 317 additions and 49 deletions.
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -2662,6 +2662,10 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewC
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderUnittests.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/KeyCodeMap.g.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/KeyCodeMap_Internal.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/MacOSGLContextSwitch.h
Expand Down
4 changes: 4 additions & 0 deletions shell/platform/darwin/macos/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ source_set("flutter_framework_source") {
"framework/Source/FlutterView.mm",
"framework/Source/FlutterViewController.mm",
"framework/Source/FlutterViewController_Internal.h",
"framework/Source/FlutterViewEngineProvider.h",
"framework/Source/FlutterViewEngineProvider.mm",
"framework/Source/FlutterViewProvider.h",
"framework/Source/KeyCodeMap.g.mm",
"framework/Source/MacOSGLContextSwitch.h",
"framework/Source/MacOSGLContextSwitch.mm",
Expand Down Expand Up @@ -202,6 +205,7 @@ executable("flutter_desktop_darwin_unittests") {
"framework/Source/FlutterViewControllerTest.mm",
"framework/Source/FlutterViewControllerTestUtils.h",
"framework/Source/FlutterViewControllerTestUtils.mm",
"framework/Source/FlutterViewEngineProviderUnitTests.mm",
"framework/Source/TestFlutterPlatformView.h",
"framework/Source/TestFlutterPlatformView.mm",
]
Expand Down
21 changes: 17 additions & 4 deletions shell/platform/darwin/macos/framework/Source/FlutterCompositor.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
#include <list>

#include "flutter/fml/macros.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h"
#include "flutter/shell/platform/embedder/embedder.h"

namespace flutter {
Expand All @@ -19,7 +20,12 @@ namespace flutter {
// Platform views are not yet supported.
class FlutterCompositor {
public:
explicit FlutterCompositor(FlutterViewController* view_controller);
// Create a FlutterCompositor with a view provider.
//
// 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<FlutterViewProvider> view_provider);

virtual ~FlutterCompositor() = default;

Expand Down Expand Up @@ -62,7 +68,10 @@ class FlutterCompositor {
typedef enum { kStarted, kPresenting, kEnded } FrameStatus;

protected:
__weak const FlutterViewController* view_controller_;
// Get the view associated with the view ID.
//
// Returns nil if the ID is invalid.
FlutterView* GetView(uint64_t view_id);

// Gets and sets the FrameStatus for the current frame.
void SetFrameStatus(FrameStatus frame_status);
Expand All @@ -76,15 +85,19 @@ class FlutterCompositor {
bool EndFrame(bool has_flutter_content);

// Creates a CALayer object which is backed by the supplied IOSurface, and
// adds it to the root CALayer for this FlutterViewController's view.
// adds it to the root CALayer for the given view.
void InsertCALayerForIOSurface(
FlutterView* view,
const IOSurfaceRef& io_surface,
CATransform3D transform = CATransform3DIdentity);

private:
// A list of the active CALayer objects for the frame that need to be removed.
std::list<CALayer*> active_ca_layers_;

// Where the compositor can query FlutterViews. Must not be null.
id<FlutterViewProvider> const view_provider_;

// Callback set by the embedder to be called when the layer tree has been
// correctly set up for this frame.
PresentCallback present_callback_;
Expand Down
18 changes: 11 additions & 7 deletions shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@

namespace flutter {

FlutterCompositor::FlutterCompositor(FlutterViewController* view_controller) {
FML_CHECK(view_controller != nullptr) << "FlutterViewController* cannot be nullptr";

view_controller_ = view_controller;
FlutterCompositor::FlutterCompositor(id<FlutterViewProvider> view_provider)
: view_provider_(view_provider) {
FML_CHECK(view_provider != nullptr) << "FlutterViewProvider* cannot be nullptr";
}

void FlutterCompositor::SetPresentCallback(
Expand All @@ -35,6 +34,10 @@
return status;
}

FlutterView* FlutterCompositor::GetView(uint64_t view_id) {
return [view_provider_ getView:view_id];
}

void FlutterCompositor::SetFrameStatus(FlutterCompositor::FrameStatus frame_status) {
frame_status_ = frame_status;
}
Expand All @@ -43,14 +46,15 @@
return frame_status_;
}

void FlutterCompositor::InsertCALayerForIOSurface(const IOSurfaceRef& io_surface,
void FlutterCompositor::InsertCALayerForIOSurface(FlutterView* view,
const IOSurfaceRef& io_surface,
CATransform3D transform) {
// FlutterCompositor manages the lifecycle of CALayers.
CALayer* content_layer = [[CALayer alloc] init];
content_layer.transform = transform;
content_layer.frame = view_controller_.flutterView.layer.bounds;
content_layer.frame = view.layer.bounds;
[content_layer setContents:(__bridge id)io_surface];
[view_controller_.flutterView.layer addSublayer:content_layer];
[view.layer addSublayer:content_layer];

active_ca_layers_.push_back(content_layer);
}
Expand Down
10 changes: 7 additions & 3 deletions shell/platform/darwin/macos/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderingBackend.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.h"
#include "flutter/shell/platform/embedder/embedder.h"

/**
Expand Down Expand Up @@ -211,6 +212,8 @@ @implementation FlutterEngine {
// This is either a FlutterGLCompositor or a FlutterMetalCompositor instance.
std::unique_ptr<flutter::FlutterCompositor> _macOSCompositor;

FlutterViewEngineProvider* _viewProvider;

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

Expand Down Expand Up @@ -244,6 +247,7 @@ - (instancetype)initWithName:(NSString*)labelPrefix
_currentMessengerConnection = 1;
_allowHeadlessExecution = allowHeadlessExecution;
_semanticsEnabled = NO;
_viewProvider = [[FlutterViewEngineProvider alloc] initWithEngine:self];

_embedderAPI.struct_size = sizeof(FlutterEngineProcTable);
FlutterEngineGetProcAddresses(&_embedderAPI);
Expand Down Expand Up @@ -437,12 +441,12 @@ - (FlutterCompositor*)createFlutterCompositor {
if ([FlutterRenderingBackend renderUsingMetal]) {
FlutterMetalRenderer* metalRenderer = reinterpret_cast<FlutterMetalRenderer*>(_renderer);
_macOSCompositor = std::make_unique<flutter::FlutterMetalCompositor>(
_viewController, _platformViewController, metalRenderer.device);
_viewProvider, _platformViewController, metalRenderer.device);
} else {
FlutterOpenGLRenderer* openGLRenderer = reinterpret_cast<FlutterOpenGLRenderer*>(_renderer);
[openGLRenderer.openGLContext makeCurrentContext];
_macOSCompositor = std::make_unique<flutter::FlutterGLCompositor>(_viewController,
openGLRenderer.openGLContext);
_macOSCompositor =
std::make_unique<flutter::FlutterGLCompositor>(_viewProvider, openGLRenderer.openGLContext);
}
_macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) {
if (has_flutter_content) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace flutter {
// FlutterGLCompositor is created and destroyed by FlutterEngine.
class FlutterGLCompositor : public FlutterCompositor {
public:
FlutterGLCompositor(FlutterViewController* view_controller,
FlutterGLCompositor(id<FlutterViewProvider> view_provider,
NSOpenGLContext* opengl_context);

virtual ~FlutterGLCompositor() = default;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@

namespace flutter {

FlutterGLCompositor::FlutterGLCompositor(FlutterViewController* view_controller,
FlutterGLCompositor::FlutterGLCompositor(id<FlutterViewProvider> view_provider,
NSOpenGLContext* opengl_context)
: FlutterCompositor(view_controller), open_gl_context_(opengl_context) {}
: FlutterCompositor(view_provider), open_gl_context_(opengl_context) {}

bool FlutterGLCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config,
FlutterBackingStore* backing_store_out) {
if (!view_controller_) {
// 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 = GetView(kFlutterDefaultViewId);
if (!view) {
return false;
}

Expand All @@ -36,8 +40,7 @@
// If the backing store is for the first layer, return the fbo for the
// FlutterView.
FlutterOpenGLRenderBackingStore* backingStore =
reinterpret_cast<FlutterOpenGLRenderBackingStore*>(
[view_controller_.flutterView backingStoreForSize:size]);
reinterpret_cast<FlutterOpenGLRenderBackingStore*>([view backingStoreForSize:size]);
backing_store_out->open_gl.framebuffer.name = backingStore.frameBufferID;
} else {
FlutterFrameBufferProvider* fb_provider =
Expand Down Expand Up @@ -75,6 +78,14 @@
}

bool FlutterGLCompositor::Present(const FlutterLayer** layers, size_t layers_count) {
// 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 = GetView(kFlutterDefaultViewId);
if (!view) {
return false;
}

SetFrameStatus(FrameStatus::kPresenting);

bool has_flutter_content = false;
Expand All @@ -93,7 +104,7 @@

// The surface is an OpenGL texture, which means it has origin in bottom left corner
// and needs to be flipped vertically
InsertCALayerForIOSurface(io_surface, CATransform3DMakeScale(1, -1, 1));
InsertCALayerForIOSurface(view, io_surface, CATransform3DMakeScale(1, -1, 1));
}
has_flutter_content = true;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,52 @@
// found in the LICENSE file.

#import <Foundation/Foundation.h>
#import <OCMock/OCMock.h>

#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h"
#import "flutter/testing/testing.h"

@interface FlutterViewMockProviderGL : NSObject <FlutterViewProvider> {
FlutterView* _defaultView;
}
/**
* Create a FlutterViewMockProviderGL with the provided view as the default view.
*/
- (nonnull instancetype)initWithDefaultView:(nonnull FlutterView*)view;
@end

@implementation FlutterViewMockProviderGL

- (nonnull instancetype)initWithDefaultView:(nonnull FlutterView*)view {
self = [super init];
if (self != nil) {
_defaultView = view;
}
return self;
}

- (nullable FlutterView*)getView:(uint64_t)viewId {
if (viewId == kFlutterDefaultViewId) {
return _defaultView;
}
return nil;
}

@end

namespace flutter::testing {
namespace {

TEST(FlutterGLCompositorTest, TestPresent) {
id mockViewController = CreateMockViewController();
id<FlutterViewProvider> MockViewProvider() {
id viewMock = OCMClassMock([FlutterView class]);
return [[FlutterViewMockProviderGL alloc] initWithDefaultView:viewMock];
}
} // namespace

TEST(FlutterGLCompositorTest, TestPresent) {
std::unique_ptr<flutter::FlutterGLCompositor> macos_compositor =
std::make_unique<FlutterGLCompositor>(mockViewController, nullptr);
std::make_unique<FlutterGLCompositor>(MockViewProvider(), nullptr);

bool flag = false;
macos_compositor->SetPresentCallback([f = &flag](bool has_flutter_content) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace flutter {
class FlutterMetalCompositor : public FlutterCompositor {
public:
explicit FlutterMetalCompositor(
FlutterViewController* view_controller,
id<FlutterViewProvider> view_provider,
FlutterPlatformViewController* platform_views_controller,
id<MTLDevice> mtl_device);

Expand Down Expand Up @@ -46,8 +46,11 @@ class FlutterMetalCompositor : public FlutterCompositor {

private:
// Presents the platform view layer represented by `layer`. `layer_index` is
// used to position the layer in the z-axis.
void PresentPlatformView(const FlutterLayer* layer, size_t layer_index);
// used to position the layer in the z-axis. If the layer does not have a
// superview, it will become subview of `default_base_view`.
void PresentPlatformView(FlutterView* default_base_view,
const FlutterLayer* layer,
size_t layer_position);

const id<MTLDevice> mtl_device_;
const FlutterPlatformViewController* platform_views_controller_;
Expand Down
Loading

0 comments on commit 5108942

Please sign in to comment.