[Multiwindow] Renderers receive view IDs as argument (flutter/engine#36593)

* Impl

* Format

* TODO comments

* Fix compile

* Better empty indication

* Change invalid ID to -1

* fix doc

* Change to default view

* Better doc

* Update doc of FlutterFrameInfo

* Change to ID

* Address comment

* Fix comment

* To assertion

* Fix compile
This commit is contained in:
Tong Mu 2022-11-17 12:11:53 -08:00 committed by GitHub
parent 0b728cbf70
commit d3c69d6108
6 changed files with 68 additions and 40 deletions

View File

@ -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;

View File

@ -400,7 +400,6 @@ static void OnPlatformMessage(const FlutterPlatformMessage* message, FlutterEngi
- (void)setViewController:(FlutterViewController*)controller {
if (_viewController != controller) {
_viewController = controller;
[_renderer setFlutterView:controller.flutterView];
if (_semanticsEnabled && _bridge) {
_bridge->UpdateDefaultViewController(_viewController);
@ -425,10 +424,14 @@ static void OnPlatformMessage(const FlutterPlatformMessage* message, FlutterEngi
_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;
}
});

View File

@ -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.

View File

@ -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,
@ -33,7 +43,7 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
#pragma mark - FlutterRenderer implementation
@implementation FlutterRenderer {
FlutterView* _flutterView;
FlutterViewEngineProvider* _viewProvider;
FlutterDarwinContextMetalSkia* _darwinMetalContext;
}
@ -41,6 +51,7 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
- (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.");
@ -59,10 +70,6 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
return self;
}
- (void)setFlutterView:(FlutterView*)view {
_flutterView = view;
}
- (FlutterRendererConfig)createRendererConfig {
FlutterRendererConfig config = {
.type = FlutterRendererType::kMetal,
@ -70,9 +77,9 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
.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),
};
@ -81,9 +88,15 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
#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);
@ -92,19 +105,21 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
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.

View File

@ -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"
@ -24,21 +25,29 @@ FlutterEngine* CreateTestEngine() {
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;
@ -47,8 +56,7 @@ TEST(FlutterRenderer, TextureReturnedByFlutterView) {
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

View File

@ -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;
@ -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