mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[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:
parent
0b728cbf70
commit
d3c69d6108
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user