Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ FLUTTER_DARWIN_EXPORT
- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint;

/**
* The `FlutterViewController` associated with this engine, if any.
* The default `FlutterViewController` associated with this engine, if any.
*
* The default view always has ID kFlutterDefaultViewId, and is the view
* operated by the APIs that do not have a view ID specified.
*/
@property(nonatomic, nullable, weak) FlutterViewController* viewController;

Expand Down
9 changes: 6 additions & 3 deletions shell/platform/darwin/macos/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,6 @@ - (void)loadAOTData:(NSString*)assetsDir {
- (void)setViewController:(FlutterViewController*)controller {
if (_viewController != controller) {
_viewController = controller;
[_renderer setFlutterView:controller.flutterView];
Copy link
Contributor

Choose a reason for hiding this comment

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

Where is the view registered with the view provider?

Copy link
Contributor Author

@dkwingsmt dkwingsmt Nov 14, 2022

Choose a reason for hiding this comment

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

Any other places. The view provider is just a protocol/facade over other classes, and will have other methods to register views, which is not shown as a view provider.
In the real application the view provider is macos/FlutterEngine, which is the source-of-truth of the set of views.


if (_semanticsEnabled && _bridge) {
_bridge->UpdateDefaultViewController(_viewController);
Expand All @@ -425,10 +424,14 @@ - (FlutterCompositor*)createFlutterCompositor {
_macOSCompositor = std::make_unique<flutter::FlutterCompositor>(
_viewProvider, _platformViewController, _renderer.device);
_macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) {
// TODO(dkwingsmt): The compositor only supports single-view for now. As
// more classes are gradually converted to multi-view, it should get the
// view ID from somewhere.
uint64_t viewId = kFlutterDefaultViewId;
if (has_flutter_content) {
return [weakSelf.renderer present] == YES;
return [weakSelf.renderer present:viewId] == YES;
} else {
[weakSelf.renderer presentWithoutContent];
[weakSelf.renderer presentWithoutContent:viewId];
return true;
}
});
Expand Down
15 changes: 5 additions & 10 deletions shell/platform/darwin/macos/framework/Source/FlutterRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,30 +30,25 @@
*/
- (nullable instancetype)initWithFlutterEngine:(nonnull FlutterEngine*)flutterEngine;

/**
* Sets the FlutterView to render to.
*/
- (void)setFlutterView:(nullable FlutterView*)view;

/**
* Creates a FlutterRendererConfig that renders using the appropriate backend.
*/
- (FlutterRendererConfig)createRendererConfig;

/**
* Called by the engine when the context's buffers should be swapped.
* Called by the engine when the given view's buffers should be swapped.
*/
- (BOOL)present;
- (BOOL)present:(uint64_t)viewId;

/**
* Tells the renderer that there is no Flutter content available for this frame.
*/
- (void)presentWithoutContent;
- (void)presentWithoutContent:(uint64_t)viewId;

/**
* Creates a Metal texture for the given size.
* Creates a Metal texture for the given view with the given size.
*/
- (FlutterMetalTexture)createTextureForSize:(CGSize)size;
- (FlutterMetalTexture)createTextureForView:(uint64_t)viewId size:(CGSize)size;

/**
* Populates the texture registry with the provided metalTexture.
Expand Down
57 changes: 36 additions & 21 deletions shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@

#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTexture.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.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"

#pragma mark - Static callbacks that require the engine.

static FlutterMetalTexture OnGetNextDrawable(FlutterEngine* engine,
const FlutterFrameInfo* frameInfo) {
static FlutterMetalTexture OnGetNextDrawableForDefaultView(FlutterEngine* engine,
const FlutterFrameInfo* frameInfo) {
// 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, or pass the ID via FlutterFrameInfo.
uint64_t viewId = kFlutterDefaultViewId;
CGSize size = CGSizeMake(frameInfo->size.width, frameInfo->size.height);
return [engine.renderer createTextureForSize:size];
return [engine.renderer createTextureForView:viewId size:size];
}

static bool OnPresentDrawable(FlutterEngine* engine, const FlutterMetalTexture* texture) {
return [engine.renderer present];
static bool OnPresentDrawableOfDefaultView(FlutterEngine* engine,
const FlutterMetalTexture* texture) {
// 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.
uint64_t viewId = kFlutterDefaultViewId;
return [engine.renderer present:viewId];
}

static bool OnAcquireExternalTexture(FlutterEngine* engine,
Expand All @@ -33,14 +43,15 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
#pragma mark - FlutterRenderer implementation

@implementation FlutterRenderer {
FlutterView* _flutterView;
FlutterViewEngineProvider* _viewProvider;

FlutterDarwinContextMetalSkia* _darwinMetalContext;
}

- (instancetype)initWithFlutterEngine:(nonnull FlutterEngine*)flutterEngine {
self = [super initWithDelegate:self engine:flutterEngine];
if (self) {
_viewProvider = [[FlutterViewEngineProvider alloc] initWithEngine:flutterEngine];
_device = MTLCreateSystemDefaultDevice();
if (!_device) {
NSLog(@"Could not acquire Metal device.");
Expand All @@ -59,20 +70,16 @@ - (instancetype)initWithFlutterEngine:(nonnull FlutterEngine*)flutterEngine {
return self;
}

- (void)setFlutterView:(FlutterView*)view {
_flutterView = view;
}

- (FlutterRendererConfig)createRendererConfig {
FlutterRendererConfig config = {
.type = FlutterRendererType::kMetal,
.metal.struct_size = sizeof(FlutterMetalRendererConfig),
.metal.device = (__bridge FlutterMetalDeviceHandle)_device,
.metal.present_command_queue = (__bridge FlutterMetalCommandQueueHandle)_commandQueue,
.metal.get_next_drawable_callback =
reinterpret_cast<FlutterMetalTextureCallback>(OnGetNextDrawable),
reinterpret_cast<FlutterMetalTextureCallback>(OnGetNextDrawableForDefaultView),
.metal.present_drawable_callback =
reinterpret_cast<FlutterMetalPresentCallback>(OnPresentDrawable),
reinterpret_cast<FlutterMetalPresentCallback>(OnPresentDrawableOfDefaultView),
.metal.external_texture_frame_callback =
reinterpret_cast<FlutterMetalTextureFrameCallback>(OnAcquireExternalTexture),
};
Expand All @@ -81,9 +88,15 @@ - (FlutterRendererConfig)createRendererConfig {

#pragma mark - Embedder callback implementations.

- (FlutterMetalTexture)createTextureForSize:(CGSize)size {
- (FlutterMetalTexture)createTextureForView:(uint64_t)viewId size:(CGSize)size {
FlutterView* view = [_viewProvider getView:viewId];
NSAssert(view != nil, @"Can't create texture on a non-existent view 0x%llx.", viewId);
if (view == nil) {
// FlutterMetalTexture has texture `null`, therefore is discarded.
return FlutterMetalTexture{};
}
FlutterMetalRenderBackingStore* backingStore =
(FlutterMetalRenderBackingStore*)[_flutterView backingStoreForSize:size];
(FlutterMetalRenderBackingStore*)[view backingStoreForSize:size];
id<MTLTexture> texture = backingStore.texture;
FlutterMetalTexture embedderTexture;
embedderTexture.struct_size = sizeof(FlutterMetalTexture);
Expand All @@ -92,19 +105,21 @@ - (FlutterMetalTexture)createTextureForSize:(CGSize)size {
return embedderTexture;
}

- (BOOL)present {
if (!_flutterView) {
- (BOOL)present:(uint64_t)viewId {
FlutterView* view = [_viewProvider getView:viewId];
if (view == nil) {
return NO;
}
[_flutterView present];
[view present];
return YES;
}

- (void)presentWithoutContent {
if (!_flutterView) {
- (void)presentWithoutContent:(uint64_t)viewId {
FlutterView* view = [_viewProvider getView:viewId];
if (view == nil) {
return;
}
[_flutterView presentWithoutContent];
[view presentWithoutContent];
}

#pragma mark - FlutterTextureRegistrar methods.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
#include "flutter/testing/testing.h"
Expand All @@ -24,21 +25,29 @@
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
return [[FlutterEngine alloc] initWithName:@"test" project:project allowHeadlessExecution:true];
}

void SetEngineDefaultView(FlutterEngine* engine, id flutterView) {
id mockFlutterViewController = OCMClassMock([FlutterViewController class]);
OCMStub([mockFlutterViewController flutterView]).andReturn(flutterView);
[engine setViewController:mockFlutterViewController];
}

} // namespace

TEST(FlutterRenderer, PresentDelegatesToFlutterView) {
FlutterEngine* engine = CreateTestEngine();
FlutterRenderer* renderer = [[FlutterRenderer alloc] initWithFlutterEngine:engine];
id mockFlutterView = OCMClassMock([FlutterView class]);
SetEngineDefaultView(engine, mockFlutterView);
[(FlutterView*)[mockFlutterView expect] present];
[renderer setFlutterView:mockFlutterView];
[renderer present];
[renderer present:kFlutterDefaultViewId];
}

TEST(FlutterRenderer, TextureReturnedByFlutterView) {
FlutterEngine* engine = CreateTestEngine();
FlutterRenderer* renderer = [[FlutterRenderer alloc] initWithFlutterEngine:engine];
id mockFlutterView = OCMClassMock([FlutterView class]);
SetEngineDefaultView(engine, mockFlutterView);
FlutterFrameInfo frameInfo;
frameInfo.struct_size = sizeof(FlutterFrameInfo);
FlutterUIntSize dimensions;
Expand All @@ -47,8 +56,7 @@
frameInfo.size = dimensions;
CGSize size = CGSizeMake(dimensions.width, dimensions.height);
[[mockFlutterView expect] backingStoreForSize:size];
[renderer setFlutterView:mockFlutterView];
[renderer createTextureForSize:size];
[renderer createTextureForView:kFlutterDefaultViewId size:size];
}

} // namespace flutter::testing
6 changes: 5 additions & 1 deletion shell/platform/embedder/embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,9 @@ typedef struct {
/// This information is passed to the embedder when requesting a frame buffer
/// object.
///
/// See: \ref FlutterOpenGLRendererConfig.fbo_with_frame_info_callback.
/// See: \ref FlutterOpenGLRendererConfig.fbo_with_frame_info_callback,
/// \ref FlutterMetalRendererConfig.get_next_drawable_callback,
/// and \ref FlutterVulkanRendererConfig.get_next_image_callback.
typedef struct {
/// The size of this struct. Must be sizeof(FlutterFrameInfo).
size_t struct_size;
Expand Down Expand Up @@ -633,6 +635,8 @@ typedef struct {
int64_t texture_id;
/// Handle to the MTLTexture that is owned by the embedder. Engine will render
/// the frame into this texture.
///
/// A NULL texture is considered invalid.
FlutterMetalTextureHandle texture;
/// A baton that is not interpreted by the engine in any way. It will be given
/// back to the embedder in the destruction callback below. Embedder resources
Expand Down