Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 2 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
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;
Comment thread
RichardJCai marked this conversation as resolved.

// 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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 <vector>

#include "flutter/fml/macros.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"

namespace flutter {

// FlutterMacOSGLCompositor creates and manages the backing stores used for
// rendering Flutter content and presents Flutter content and Platform views.
// Platform views are not yet supported.
// FlutterMacOSGLCompositor is created and destroyed by FlutterEngine.
class FlutterMacOSGLCompositor {
Comment thread
RichardJCai marked this conversation as resolved.
public:
FlutterMacOSGLCompositor(FlutterViewController* view_controller);

// Creates a FlutterSurfaceManager and uses the FlutterSurfaceManager's
// underlying FBO and texture in the backing store.
// Any additional state allocated for the backing store and
// saved as user_data in the backing store must be collected
// in the backing_store's desctruction_callback field which will
// be called when the embedder collects the backing store.
bool CreateBackingStore(const FlutterBackingStoreConfig* config,
FlutterBackingStore* backing_store_out);

// Releases the memory for any state used by the backing store.
bool CollectBackingStore(const FlutterBackingStore* backing_store);

// Presents the FlutterLayers by updating FlutterView(s) using the
// layer content.
bool Present(const FlutterLayer** layers, size_t layers_count);

using PresentCallback = std::function<bool()>;

// PresentCallback is called at the end of the Present function.
void SetPresentCallback(const PresentCallback& present_callback);

private:
FlutterViewController* view_controller_;
PresentCallback present_callback_;
NSOpenGLContext* open_gl_context_;

Comment thread
RichardJCai marked this conversation as resolved.
FML_DISALLOW_COPY_AND_ASSIGN(FlutterMacOSGLCompositor);
};

} // namespace flutter
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// 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.

#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMacOSGLCompositor.h"

#import <OpenGL/gl.h>
#import "flutter/fml/logging.h"
#import "flutter/fml/platform/darwin/cf_utils.h"
#import "third_party/skia/include/core/SkCanvas.h"
#import "third_party/skia/include/core/SkSurface.h"
#import "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
#import "third_party/skia/include/utils/mac/SkCGUtils.h"

#include <unistd.h>

namespace flutter {

FlutterMacOSGLCompositor::FlutterMacOSGLCompositor(FlutterViewController* view_controller)
: view_controller_(view_controller),
open_gl_context_(view_controller.flutterView.openGLContext) {}

bool FlutterMacOSGLCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config,
FlutterBackingStore* backing_store_out) {
FlutterSurfaceManager* surfaceManager =
[[FlutterSurfaceManager alloc] initWithLayer:view_controller_.flutterView.layer
openGLContext:open_gl_context_
numFramebuffers:1];

GLuint fbo = [surfaceManager getFramebuffer];
GLuint texture = [surfaceManager getTexture];

CGSize size = CGSizeMake(config->size.width, config->size.height);
size_t kFlutterSurfaceManagerFrontBuffer = 0;
[surfaceManager backTextureWithIOSurface:kFlutterSurfaceManagerFrontBuffer
size:size
backingTexture:texture
fbo:fbo];

backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
backing_store_out->open_gl.framebuffer.target = GL_RGBA8;
backing_store_out->open_gl.framebuffer.name = fbo;
backing_store_out->open_gl.framebuffer.user_data = (__bridge_retained void*)surfaceManager;
backing_store_out->open_gl.framebuffer.destruction_callback = [](void* user_data) {
if (user_data != nullptr) {
CFRelease(user_data);
}
};

return true;
}

bool FlutterMacOSGLCompositor::CollectBackingStore(const FlutterBackingStore* backing_store) {
// The memory for FlutterSurfaceManager is handled in the destruction callback.
// No other memory has to be collected.
return true;
}

bool FlutterMacOSGLCompositor::Present(const FlutterLayer** layers, size_t layers_count) {
for (size_t i = 0; i < layers_count; ++i) {
const auto* layer = layers[i];
FlutterBackingStore* backing_store = const_cast<FlutterBackingStore*>(layer->backing_store);
switch (layer->type) {
case kFlutterLayerContentTypeBackingStore: {
FlutterSurfaceManager* surfaceManager =
(__bridge FlutterSurfaceManager*)backing_store->open_gl.framebuffer.user_data;

CGSize size = CGSizeMake(layer->size.width, layer->size.height);
[view_controller_.flutterView frameBufferIDForSize:size];
size_t kFlutterSurfaceManagerFrontBuffer = 0;
[surfaceManager setLayerContentWithIOSurface:kFlutterSurfaceManagerFrontBuffer];
break;
}
case kFlutterLayerContentTypePlatformView:
// Add functionality in follow up PR.
Comment thread
RichardJCai marked this conversation as resolved.
FML_CHECK(false) << "Presenting PlatformViews not yet supported";
break;
};
}
return present_callback_();
}

void FlutterMacOSGLCompositor::SetPresentCallback(
const FlutterMacOSGLCompositor::PresentCallback& present_callback) {
present_callback_ = present_callback;
}

} // namespace flutter
Original file line number Diff line number Diff line change
@@ -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.

#import <Foundation/Foundation.h>

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

namespace flutter::testing {

TEST(FlutterMacOSGLCompositorTest, TestPresent) {
id mockViewController = CreateMockViewController(nil);

std::unique_ptr<flutter::FlutterMacOSGLCompositor> macos_compositor =
std::make_unique<FlutterMacOSGLCompositor>(mockViewController);

bool flag = false;
macos_compositor->SetPresentCallback([f = &flag]() {
*f = true;
return true;
});

ASSERT_TRUE(macos_compositor->Present(nil, 0));
ASSERT_TRUE(flag);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a test to ensure after collect backing store gets called, we invoke the destructor.

} // flutter::testing
Original file line number Diff line number Diff line change
@@ -1,18 +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.

#import <Cocoa/Cocoa.h>

// Manages the IOSurfaces for FlutterView
@interface FlutterSurfaceManager : NSObject

- (nullable instancetype)initWithLayer:(nonnull CALayer*)containingLayer
openGLContext:(nonnull NSOpenGLContext*)opengLContext;
- (instancetype)initWithLayer:(CALayer*)containingLayer
openGLContext:(NSOpenGLContext*)openGLContext
numFramebuffers:(int)numFramebuffers;

- (void)ensureSurfaceSize:(CGSize)size;
- (void)swapBuffers;

- (uint32_t)glFrameBufferId;

/**
* Sets the CALayer content to the content of _ioSurface[kBack].
*/
- (void)setLayerContent;
Comment thread
RichardJCai marked this conversation as resolved.

/**
* Sets the CALayer content to the content of ioSurface at ioSurfaceNum.
*/
// TODO(richardjcai): Fix this and remove setLayerContent.
- (void)setLayerContentWithIOSurface:(int)ioSurfaceNum;

/**
* Binds the IOSurface to the provided texture/framebuffer.
*/
- (void)backTextureWithIOSurface:(int)ioSurfaceNum
size:(CGSize)size
backingTexture:(GLuint)texture
fbo:(GLuint)fbo;

// Methods used by FlutterMacOSCompositor to render Flutter content
// using a single Framebuffer/Texture/IOSurface.

/**
* Returns the kFront framebuffer.
* The framebuffer is used by FlutterMacOSCompositor to create a backing store.
* The framebuffer is collected when the backing store that uses the
* framebuffer is collected.
*/
- (uint32_t)getFramebuffer;
Comment thread
RichardJCai marked this conversation as resolved.
Outdated

/**
* Returns the kFront texture.
* The texture is used by FlutterMacOSCompositor to create a backing store.
* The texture is collected when the backing store that uses the
* texture is collected.
*/
- (uint32_t)getTexture;

@end
Loading