[macos] Re-land FlutterOpenGLRenderer isolation (flutter/engine#22607)

This commit is contained in:
Kaushik Iska 2021-01-07 10:04:48 -06:00 committed by GitHub
parent aca3f41cbd
commit 131e179b7c
16 changed files with 458 additions and 177 deletions

View File

@ -1083,6 +1083,9 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterInter
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterIntermediateKeyResponder.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRendererTest.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h

View File

@ -39,7 +39,7 @@ FLUTTER_EXPORT
/**
* Registers a `FlutterTexture` for usage in Flutter and returns an id that can be used to reference
* that texture when calling into Flutter with channels. Textures must be registered on the
* platform thread.
* platform thread. On success returns the pointer to the registered texture, else returns 0.
*/
- (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture;
/**

View File

@ -64,6 +64,8 @@ source_set("flutter_framework_source") {
"framework/Source/FlutterIntermediateKeyResponder.mm",
"framework/Source/FlutterMouseCursorPlugin.h",
"framework/Source/FlutterMouseCursorPlugin.mm",
"framework/Source/FlutterOpenGLRenderer.h",
"framework/Source/FlutterOpenGLRenderer.mm",
"framework/Source/FlutterResizeSynchronizer.h",
"framework/Source/FlutterResizeSynchronizer.mm",
"framework/Source/FlutterSurfaceManager.h",
@ -129,6 +131,7 @@ executable("flutter_desktop_darwin_unittests") {
sources = [
"framework/Source/FlutterEngineTest.mm",
"framework/Source/FlutterGLCompositorUnittests.mm",
"framework/Source/FlutterOpenGLRendererTest.mm",
"framework/Source/FlutterViewControllerTest.mm",
"framework/Source/FlutterViewControllerTestUtils.h",
"framework/Source/FlutterViewControllerTestUtils.mm",

View File

@ -11,6 +11,8 @@
#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/FlutterGLCompositor.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
#import "flutter/shell/platform/embedder/embedder.h"
/**
@ -37,42 +39,11 @@ static FlutterLocale FlutterLocaleFromNSLocale(NSLocale* locale) {
*/
- (void)sendUserLocales;
/**
* Called by the engine to make the context the engine should draw into current.
*/
- (bool)engineCallbackOnMakeCurrent;
/**
* Called by the engine to clear the context the engine should draw into.
*/
- (bool)engineCallbackOnClearCurrent;
/**
* Called by the engine when the context's buffers should be swapped.
*/
- (bool)engineCallbackOnPresent;
/**
* Called by the engine when framebuffer object ID is requested.
*/
- (uint32_t)engineCallbackOnFBO:(const FlutterFrameInfo*)info;
/**
* Makes the resource context the current context.
*/
- (bool)engineCallbackOnMakeResourceCurrent;
/**
* Handles a platform message from the engine.
*/
- (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message;
/**
* Forwards texture copy request to the corresponding texture via |textureID|.
*/
- (BOOL)populateTextureWithIdentifier:(int64_t)textureID
openGLTexture:(FlutterOpenGLTexture*)openGLTexture;
/**
* Requests that the task be posted back the to the Flutter engine at the target time. The target
* time is in the clock used by the Flutter engine.
@ -100,7 +71,6 @@ static FlutterLocale FlutterLocaleFromNSLocale(NSLocale* locale) {
@implementation FlutterEngineRegistrar {
NSString* _pluginKey;
FlutterEngine* _flutterEngine;
FlutterEngineProcTable _embedderAPI;
}
- (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine {
@ -119,7 +89,7 @@ static FlutterLocale FlutterLocaleFromNSLocale(NSLocale* locale) {
}
- (id<FlutterTextureRegistry>)textures {
return _flutterEngine;
return _flutterEngine.openGLRenderer;
}
- (NSView*)view {
@ -138,38 +108,10 @@ static FlutterLocale FlutterLocaleFromNSLocale(NSLocale* locale) {
// Callbacks provided to the engine. See the called methods for documentation.
#pragma mark - Static methods provided to engine configuration
static bool OnMakeCurrent(FlutterEngine* engine) {
return [engine engineCallbackOnMakeCurrent];
}
static bool OnClearCurrent(FlutterEngine* engine) {
return [engine engineCallbackOnClearCurrent];
}
static bool OnPresent(FlutterEngine* engine) {
return [engine engineCallbackOnPresent];
}
static uint32_t OnFBO(FlutterEngine* engine, const FlutterFrameInfo* info) {
return [engine engineCallbackOnFBO:info];
}
static bool OnMakeResourceCurrent(FlutterEngine* engine) {
return [engine engineCallbackOnMakeResourceCurrent];
}
static void OnPlatformMessage(const FlutterPlatformMessage* message, FlutterEngine* engine) {
[engine engineCallbackOnPlatformMessage:message];
}
static bool OnAcquireExternalTexture(FlutterEngine* engine,
int64_t texture_identifier,
size_t width,
size_t height,
FlutterOpenGLTexture* open_gl_texture) {
return [engine populateTextureWithIdentifier:texture_identifier openGLTexture:open_gl_texture];
}
#pragma mark -
@implementation FlutterEngine {
@ -179,22 +121,12 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
// The project being run by this engine.
FlutterDartProject* _project;
// The context provided to the Flutter engine for resource loading.
NSOpenGLContext* _resourceContext;
// The context that is owned by the currently displayed FlutterView. This is stashed in the engine
// so that the view doesn't need to be accessed from a background thread.
NSOpenGLContext* _mainOpenGLContext;
// A mapping of channel names to the registered handlers for those channels.
NSMutableDictionary<NSString*, FlutterBinaryMessageHandler>* _messageHandlers;
// Whether the engine can continue running after the view controller is removed.
BOOL _allowHeadlessExecution;
// A mapping of textureID to internal FlutterExternalTextureGL adapter.
NSMutableDictionary<NSNumber*, FlutterExternalTextureGL*>* _textures;
// Pointer to the Dart AOT snapshot and instruction data.
_FlutterEngineAOTData* _aotData;
@ -218,10 +150,10 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
_project = project ?: [[FlutterDartProject alloc] init];
_messageHandlers = [[NSMutableDictionary alloc] init];
_textures = [[NSMutableDictionary alloc] init];
_allowHeadlessExecution = allowHeadlessExecution;
_embedderAPI.struct_size = sizeof(FlutterEngineProcTable);
FlutterEngineGetProcAddresses(&_embedderAPI);
_openGLRenderer = [[FlutterOpenGLRenderer alloc] initWithFlutterEngine:self];
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
@ -249,17 +181,7 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
return NO;
}
const FlutterRendererConfig rendererConfig = {
.type = kOpenGL,
.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig),
.open_gl.make_current = (BoolCallback)OnMakeCurrent,
.open_gl.clear_current = (BoolCallback)OnClearCurrent,
.open_gl.present = (BoolCallback)OnPresent,
.open_gl.fbo_with_frame_info_callback = (UIntFrameInfoCallback)OnFBO,
.open_gl.fbo_reset_after_present = true,
.open_gl.make_resource_current = (BoolCallback)OnMakeResourceCurrent,
.open_gl.gl_external_texture_frame_callback = (TextureFrameCallback)OnAcquireExternalTexture,
};
const FlutterRendererConfig rendererConfig = [_openGLRenderer createRendererConfig];
// TODO(stuartmorgan): Move internal channel registration from FlutterViewController to here.
@ -362,10 +284,10 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
- (void)setViewController:(FlutterViewController*)controller {
_viewController = controller;
_mainOpenGLContext = controller.flutterView.openGLContext;
[_openGLRenderer setFlutterView:controller.flutterView];
if (!controller && !_allowHeadlessExecution) {
[self shutDownEngine];
_resourceContext = nil;
}
}
@ -377,9 +299,10 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
return nullptr;
}
[_mainOpenGLContext makeCurrentContext];
[_openGLRenderer.openGLContext makeCurrentContext];
_macOSGLCompositor = std::make_unique<flutter::FlutterGLCompositor>(_viewController);
_macOSGLCompositor = std::make_unique<flutter::FlutterGLCompositor>(
_viewController, _openGLRenderer.openGLContext);
_compositor = {};
_compositor.struct_size = sizeof(FlutterCompositor);
@ -410,7 +333,7 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
__weak FlutterEngine* weak_self = self;
_macOSGLCompositor->SetPresentCallback(
[weak_self]() { return [weak_self engineCallbackOnPresent]; });
[weak_self]() { return [weak_self.openGLRenderer glPresent]; });
_compositor.avoid_backing_store_cache = true;
@ -429,17 +352,6 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
return _engine != nullptr;
}
- (NSOpenGLContext*)resourceContext {
if (!_resourceContext) {
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFAColorSize, 24, NSOpenGLPFAAlphaSize, 8, 0,
};
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
_resourceContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
}
return _resourceContext;
}
- (void)updateDisplayConfig {
if (!_engine) {
return;
@ -518,37 +430,6 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
_embedderAPI.UpdateLocales(_engine, flutterLocaleList.data(), flutterLocaleList.size());
}
- (bool)engineCallbackOnMakeCurrent {
if (!_mainOpenGLContext) {
return false;
}
[_mainOpenGLContext makeCurrentContext];
return true;
}
- (uint32_t)engineCallbackOnFBO:(const FlutterFrameInfo*)info {
CGSize size = CGSizeMake(info->size.width, info->size.height);
return [_viewController.flutterView frameBufferIDForSize:size];
}
- (bool)engineCallbackOnClearCurrent {
[NSOpenGLContext clearCurrentContext];
return true;
}
- (bool)engineCallbackOnPresent {
if (!_mainOpenGLContext) {
return false;
}
[self.viewController.flutterView present];
return true;
}
- (bool)engineCallbackOnMakeResourceCurrent {
[self.resourceContext makeCurrentContext];
return true;
}
- (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message {
NSData* messageData = [NSData dataWithBytesNoCopy:(void*)message->message
length:message->message_size
@ -677,27 +558,28 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
#pragma mark - FlutterTextureRegistrar
- (BOOL)populateTextureWithIdentifier:(int64_t)textureID
openGLTexture:(FlutterOpenGLTexture*)openGLTexture {
return [_textures[@(textureID)] populateTexture:openGLTexture];
- (int64_t)registerTexture:(id<FlutterTexture>)texture {
return [_openGLRenderer registerTexture:texture];
}
- (int64_t)registerTexture:(id<FlutterTexture>)texture {
FlutterExternalTextureGL* FlutterTexture =
[[FlutterExternalTextureGL alloc] initWithFlutterTexture:texture];
int64_t textureID = [FlutterTexture textureID];
_embedderAPI.RegisterExternalTexture(_engine, textureID);
_textures[@(textureID)] = FlutterTexture;
return textureID;
- (BOOL)registerTextureWithID:(int64_t)textureId {
return _embedderAPI.RegisterExternalTexture(_engine, textureId) == kSuccess;
}
- (void)textureFrameAvailable:(int64_t)textureID {
_embedderAPI.MarkExternalTextureFrameAvailable(_engine, textureID);
[_openGLRenderer textureFrameAvailable:textureID];
}
- (BOOL)markTextureFrameAvailable:(int64_t)textureID {
return _embedderAPI.MarkExternalTextureFrameAvailable(_engine, textureID) == kSuccess;
}
- (void)unregisterTexture:(int64_t)textureID {
_embedderAPI.UnregisterExternalTexture(_engine, textureID);
[_textures removeObjectForKey:@(textureID)];
[_openGLRenderer unregisterTexture:textureID];
}
- (BOOL)unregisterTextureWithID:(int64_t)textureID {
return _embedderAPI.UnregisterExternalTexture(_engine, textureID) == kSuccess;
}
#pragma mark - Task runner integration

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <OCMock/OCMock.h>
#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
@ -12,7 +14,7 @@
namespace flutter::testing {
namespace {
// Returns an engine configured for the text fixture resource configuration.
// Returns an engine configured for the test fixture resource configuration.
FlutterEngine* CreateTestEngine() {
NSString* fixtures = @(testing::GetFixturesPath());
FlutterDartProject* project = [[FlutterDartProject alloc]
@ -50,4 +52,4 @@ TEST(FlutterEngine, MessengerSend) {
[engine shutDownEngine];
}
} // flutter::testing
} // namespace flutter::testing

View File

@ -6,6 +6,7 @@
#import <Cocoa/Cocoa.h>
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h"
#include "flutter/shell/platform/embedder/embedder.h"
@interface FlutterEngine ()
@ -16,10 +17,10 @@
@property(nonatomic, readonly) BOOL running;
/**
* The resource context used by the engine for texture uploads. FlutterViews associated with this
* engine should be created to share with this context.
* Provides the renderer config needed to initialize the engine and also handles external texture
* management.
*/
@property(nonatomic, readonly, nullable) NSOpenGLContext* resourceContext;
@property(nonatomic, readonly, nonnull) FlutterOpenGLRenderer* openGLRenderer;
/**
* Function pointers for interacting with the embedder.h API.
@ -36,4 +37,19 @@
*/
- (void)sendPointerEvent:(const FlutterPointerEvent&)event;
/**
* Registers an external texture with the given id. Returns YES on success.
*/
- (BOOL)registerTextureWithID:(int64_t)textureId;
/**
* Marks texture with the given id as available. Returns YES on success.
*/
- (BOOL)markTextureFrameAvailable:(int64_t)textureID;
/**
* Unregisters an external texture with the given id. Returns YES on success.
*/
- (BOOL)unregisterTextureWithID:(int64_t)textureID;
@end

View File

@ -32,7 +32,7 @@ static void OnCVOpenGLTextureRelease(CVOpenGLTextureRef cvOpenGLTexture) {
}
- (int64_t)textureID {
return reinterpret_cast<int64_t>(self);
return reinterpret_cast<int64_t>(_texture);
}
- (BOOL)populateTexture:(FlutterOpenGLTexture*)openGLTexture {

View File

@ -18,7 +18,8 @@ namespace flutter {
// FlutterGLCompositor is created and destroyed by FlutterEngine.
class FlutterGLCompositor {
public:
FlutterGLCompositor(FlutterViewController* view_controller);
FlutterGLCompositor(FlutterViewController* view_controller,
NSOpenGLContext* opengl_context);
// Creates a BackingStore and saves updates the backing_store_out
// data with the new BackingStore data.

View File

@ -20,8 +20,9 @@
namespace flutter {
FlutterGLCompositor::FlutterGLCompositor(FlutterViewController* view_controller)
: open_gl_context_(view_controller.flutterView.openGLContext) {
FlutterGLCompositor::FlutterGLCompositor(FlutterViewController* view_controller,
NSOpenGLContext* opengl_context)
: open_gl_context_(opengl_context) {
FML_CHECK(view_controller != nullptr) << "FlutterViewController* cannot be nullptr";
view_controller_ = view_controller;
}

View File

@ -14,7 +14,7 @@ TEST(FlutterGLCompositorTest, TestPresent) {
id mockViewController = CreateMockViewController(nil);
std::unique_ptr<flutter::FlutterGLCompositor> macos_compositor =
std::make_unique<FlutterGLCompositor>(mockViewController);
std::make_unique<FlutterGLCompositor>(mockViewController, nullptr);
bool flag = false;
macos_compositor->SetPresentCallback([f = &flag]() {

View File

@ -0,0 +1,77 @@
// 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>
#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h"
#import "flutter/shell/platform/embedder/embedder.h"
/**
* Provides the renderer config needed to initialize the embedder engine and also handles external
* texture management. This is initialized during FlutterEngine creation and then attached to the
* FlutterView once the FlutterViewController is initializer.
*/
@interface FlutterOpenGLRenderer : NSObject <FlutterTextureRegistry>
/**
* The resource context used by the engine for texture uploads. FlutterViews associated with this
* engine should be created to share with this context.
*/
@property(nonatomic, readonly, nullable) NSOpenGLContext* resourceContext;
/**
* The main OpenGL which will be used for rendering contents to the FlutterView.
*/
@property(readwrite, nonatomic, nonnull) NSOpenGLContext* openGLContext;
/**
* Intializes the renderer with the given FlutterEngine.
*/
- (nullable instancetype)initWithFlutterEngine:(nonnull FlutterEngine*)flutterEngine;
/**
* Sets the FlutterView and the corresponding rendering OpenGL context. Unsets the resource context
* if the view is nil.
*/
- (void)setFlutterView:(nullable FlutterView*)view;
/**
* Called by the engine to make the context the engine should draw into current.
*/
- (BOOL)makeCurrent;
/**
* Called by the engine to clear the context the engine should draw into.
*/
- (BOOL)clearCurrent;
/**
* Called by the engine when the context's buffers should be swapped.
*/
- (BOOL)glPresent;
/**
* Called by the engine when framebuffer object ID is requested.
*/
- (uint32_t)fboForFrameInfo:(nonnull const FlutterFrameInfo*)info;
/**
* Makes the resource context the current context.
*/
- (BOOL)makeResourceCurrent;
/**
* Populates the texture registry with the provided openGLTexture.
*/
- (BOOL)populateTextureWithIdentifier:(int64_t)textureID
openGLTexture:(nonnull FlutterOpenGLTexture*)openGLTexture;
/**
* Creates a FlutterRendererConfig that renders using OpenGL context(s) held
* by this class.
*/
- (FlutterRendererConfig)createRendererConfig;
@end

View File

@ -0,0 +1,184 @@
// 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/FlutterOpenGLRenderer.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h"
#include "flutter/shell/platform/embedder/embedder.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.h"
#pragma mark - Static methods for openGL callbacks that require the engine.
static bool OnMakeCurrent(FlutterEngine* engine) {
return [engine.openGLRenderer makeCurrent];
}
static bool OnClearCurrent(FlutterEngine* engine) {
return [engine.openGLRenderer clearCurrent];
}
static bool OnPresent(FlutterEngine* engine) {
return [engine.openGLRenderer glPresent];
}
static uint32_t OnFBO(FlutterEngine* engine, const FlutterFrameInfo* info) {
return [engine.openGLRenderer fboForFrameInfo:info];
}
static bool OnMakeResourceCurrent(FlutterEngine* engine) {
return [engine.openGLRenderer makeResourceCurrent];
}
static bool OnAcquireExternalTexture(FlutterEngine* engine,
int64_t textureIdentifier,
size_t width,
size_t height,
FlutterOpenGLTexture* openGlTexture) {
return [engine.openGLRenderer populateTextureWithIdentifier:textureIdentifier
openGLTexture:openGlTexture];
}
#pragma mark - FlutterOpenGLRenderer implementation.
@implementation FlutterOpenGLRenderer {
FlutterView* _flutterView;
// The context provided to the Flutter engine for rendering to the FlutterView. This is lazily
// created during initialization of the FlutterView. This is used to render content into the
// FlutterView.
NSOpenGLContext* _openGLContext;
// The context provided to the Flutter engine for resource loading.
NSOpenGLContext* _resourceContext;
// A mapping of textureID to internal FlutterExternalTextureGL adapter.
NSMutableDictionary<NSNumber*, FlutterExternalTextureGL*>* _textures;
FlutterEngine* _flutterEngine;
}
- (instancetype)initWithFlutterEngine:(FlutterEngine*)flutterEngine {
self = [super init];
if (self) {
_flutterEngine = flutterEngine;
_textures = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)setFlutterView:(FlutterView*)view {
_flutterView = view;
if (!view) {
_resourceContext = nil;
}
}
- (BOOL)makeCurrent {
if (!_openGLContext) {
return false;
}
[_openGLContext makeCurrentContext];
return true;
}
- (BOOL)clearCurrent {
[NSOpenGLContext clearCurrentContext];
return true;
}
- (BOOL)glPresent {
if (!_openGLContext) {
return false;
}
[_flutterView present];
return true;
}
- (uint32_t)fboForFrameInfo:(const FlutterFrameInfo*)info {
CGSize size = CGSizeMake(info->size.width, info->size.height);
return [_flutterView frameBufferIDForSize:size];
}
- (NSOpenGLContext*)resourceContext {
if (!_resourceContext) {
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFAColorSize, 24, NSOpenGLPFAAlphaSize, 8, 0,
};
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
_resourceContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
}
return _resourceContext;
}
- (NSOpenGLContext*)openGLContext {
if (!_openGLContext) {
NSOpenGLContext* shareContext = [self resourceContext];
_openGLContext = [[NSOpenGLContext alloc] initWithFormat:shareContext.pixelFormat
shareContext:shareContext];
}
return _openGLContext;
}
- (BOOL)makeResourceCurrent {
[self.resourceContext makeCurrentContext];
return YES;
}
#pragma mark - FlutterTextureRegistrar
- (BOOL)populateTextureWithIdentifier:(int64_t)textureID
openGLTexture:(FlutterOpenGLTexture*)openGLTexture {
return [_textures[@(textureID)] populateTexture:openGLTexture];
}
- (int64_t)registerTexture:(id<FlutterTexture>)texture {
FlutterExternalTextureGL* externalTexture =
[[FlutterExternalTextureGL alloc] initWithFlutterTexture:texture];
int64_t textureID = [externalTexture textureID];
BOOL success = [_flutterEngine registerTextureWithID:textureID];
if (success) {
_textures[@(textureID)] = externalTexture;
return textureID;
} else {
NSLog(@"Unable to register the texture with id: %lld.", textureID);
return 0;
}
}
- (void)textureFrameAvailable:(int64_t)textureID {
BOOL success = [_flutterEngine markTextureFrameAvailable:textureID];
if (success) {
NSLog(@"Unable to mark texture with id %lld as available.", textureID);
}
}
- (void)unregisterTexture:(int64_t)textureID {
bool success = [_flutterEngine unregisterTextureWithID:textureID];
if (success) {
[_textures removeObjectForKey:@(textureID)];
} else {
NSLog(@"Unable to unregister texture with id: %lld.", textureID);
}
}
#pragma mark - Private methods
- (FlutterRendererConfig)createRendererConfig {
const FlutterRendererConfig rendererConfig = {
.type = kOpenGL,
.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig),
.open_gl.make_current = reinterpret_cast<BoolCallback>(OnMakeCurrent),
.open_gl.clear_current = reinterpret_cast<BoolCallback>(OnClearCurrent),
.open_gl.present = reinterpret_cast<BoolCallback>(OnPresent),
.open_gl.fbo_with_frame_info_callback = reinterpret_cast<UIntFrameInfoCallback>(OnFBO),
.open_gl.fbo_reset_after_present = true,
.open_gl.make_resource_current = reinterpret_cast<BoolCallback>(OnMakeResourceCurrent),
.open_gl.gl_external_texture_frame_callback =
reinterpret_cast<TextureFrameCallback>(OnAcquireExternalTexture),
};
return rendererConfig;
}
@end

View File

@ -0,0 +1,118 @@
// 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 <OCMock/OCMock.h>
#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
#include "flutter/testing/testing.h"
namespace flutter::testing {
namespace {
// Returns an engine configured for the test fixture resource configuration.
FlutterEngine* CreateTestEngine() {
NSString* fixtures = @(testing::GetFixturesPath());
FlutterDartProject* project = [[FlutterDartProject alloc]
initWithAssetsPath:fixtures
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
return [[FlutterEngine alloc] initWithName:@"test" project:project allowHeadlessExecution:true];
}
} // namespace
TEST(FlutterOpenGLRenderer, RegisterExternalTexture) {
FlutterEngine* engine = CreateTestEngine();
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
id<FlutterTexture> flutterTexture = OCMProtocolMock(@protocol(FlutterTexture));
bool called = false;
engine.embedderAPI.RegisterExternalTexture =
MOCK_ENGINE_PROC(RegisterExternalTexture, [&](auto engine, int64_t textureIdentifier) {
called = true;
EXPECT_EQ(textureIdentifier, reinterpret_cast<int64_t>(flutterTexture));
return kSuccess;
});
[engine.openGLRenderer registerTexture:flutterTexture];
EXPECT_TRUE(called);
[engine shutDownEngine];
}
TEST(FlutterOpenGLRenderer, UnregisterExternalTexture) {
FlutterEngine* engine = CreateTestEngine();
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
id<FlutterTexture> flutterTexture = OCMProtocolMock(@protocol(FlutterTexture));
bool called = false;
int64_t registeredTextureId = [engine.openGLRenderer registerTexture:flutterTexture];
engine.embedderAPI.UnregisterExternalTexture =
MOCK_ENGINE_PROC(UnregisterExternalTexture, [&](auto engine, int64_t textureIdentifier) {
called = true;
EXPECT_EQ(textureIdentifier, registeredTextureId);
return kSuccess;
});
[engine.openGLRenderer unregisterTexture:registeredTextureId];
EXPECT_TRUE(called);
[engine shutDownEngine];
}
TEST(FlutterOpenGLRenderer, MarkExternalTextureFrameAvailable) {
FlutterEngine* engine = CreateTestEngine();
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
id<FlutterTexture> flutterTexture = OCMProtocolMock(@protocol(FlutterTexture));
bool called = false;
int64_t registeredTextureId = [engine.openGLRenderer registerTexture:flutterTexture];
engine.embedderAPI.MarkExternalTextureFrameAvailable = MOCK_ENGINE_PROC(
MarkExternalTextureFrameAvailable, [&](auto engine, int64_t textureIdentifier) {
called = true;
EXPECT_EQ(textureIdentifier, registeredTextureId);
return kSuccess;
});
[engine.openGLRenderer textureFrameAvailable:registeredTextureId];
EXPECT_TRUE(called);
[engine shutDownEngine];
}
TEST(FlutterOpenGLRenderer, PresetDelegatesToFlutterView) {
FlutterEngine* engine = CreateTestEngine();
FlutterOpenGLRenderer* renderer = [[FlutterOpenGLRenderer alloc] initWithFlutterEngine:engine];
id mockFlutterView = OCMClassMock([FlutterView class]);
[[mockFlutterView expect] present];
[renderer setFlutterView:mockFlutterView];
[renderer openGLContext];
[renderer glPresent];
}
TEST(FlutterOpenGLRenderer, FBOReturnedByFlutterView) {
FlutterEngine* engine = CreateTestEngine();
FlutterOpenGLRenderer* renderer = [[FlutterOpenGLRenderer alloc] initWithFlutterEngine:engine];
id mockFlutterView = OCMClassMock([FlutterView class]);
FlutterFrameInfo frameInfo;
frameInfo.struct_size = sizeof(FlutterFrameInfo);
FlutterUIntSize dimensions;
dimensions.width = 100;
dimensions.height = 200;
frameInfo.size = dimensions;
CGSize size = CGSizeMake(dimensions.width, dimensions.height);
[[mockFlutterView expect] frameBufferIDForSize:size];
[renderer setFlutterView:mockFlutterView];
[renderer openGLContext];
[renderer fboForFrameInfo:&frameInfo];
}
} // namespace flutter::testing

View File

@ -20,19 +20,14 @@
*/
@interface FlutterView : NSView
/**
* The OpenGL context of backing surface.
*/
@property(readwrite, nonatomic, nonnull) NSOpenGLContext* openGLContext;
- (nullable instancetype)initWithFrame:(NSRect)frame
shareContext:(nonnull NSOpenGLContext*)shareContext
mainContext:(nonnull NSOpenGLContext*)mainContext
reshapeListener:(nonnull id<FlutterViewReshapeListener>)reshapeListener
NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithShareContext:(nonnull NSOpenGLContext*)shareContext
reshapeListener:
(nonnull id<FlutterViewReshapeListener>)reshapeListener;
- (nullable instancetype)initWithMainContext:(nonnull NSOpenGLContext*)mainContext
reshapeListener:
(nonnull id<FlutterViewReshapeListener>)reshapeListener;
- (nullable instancetype)initWithFrame:(NSRect)frameRect
pixelFormat:(nullable NSOpenGLPixelFormat*)format NS_UNAVAILABLE;

View File

@ -15,30 +15,29 @@
__weak id<FlutterViewReshapeListener> _reshapeListener;
FlutterResizeSynchronizer* _resizeSynchronizer;
FlutterSurfaceManager* _surfaceManager;
NSOpenGLContext* _openGLContext;
}
@end
@implementation FlutterView
- (instancetype)initWithShareContext:(NSOpenGLContext*)shareContext
reshapeListener:(id<FlutterViewReshapeListener>)reshapeListener {
return [self initWithFrame:NSZeroRect shareContext:shareContext reshapeListener:reshapeListener];
- (instancetype)initWithMainContext:(NSOpenGLContext*)mainContext
reshapeListener:(id<FlutterViewReshapeListener>)reshapeListener {
return [self initWithFrame:NSZeroRect mainContext:mainContext reshapeListener:reshapeListener];
}
- (instancetype)initWithFrame:(NSRect)frame
shareContext:(NSOpenGLContext*)shareContext
mainContext:(NSOpenGLContext*)mainContext
reshapeListener:(id<FlutterViewReshapeListener>)reshapeListener {
self = [super initWithFrame:frame];
if (self) {
self.openGLContext = [[NSOpenGLContext alloc] initWithFormat:shareContext.pixelFormat
shareContext:shareContext];
_openGLContext = mainContext;
[self setWantsLayer:YES];
_resizeSynchronizer = [[FlutterResizeSynchronizer alloc] initWithDelegate:self];
_surfaceManager = [[FlutterSurfaceManager alloc] initWithLayer:self.layer
openGLContext:self.openGLContext];
openGLContext:_openGLContext];
_reshapeListener = reshapeListener;
}
@ -46,7 +45,7 @@
}
- (void)resizeSynchronizerFlush:(FlutterResizeSynchronizer*)synchronizer {
MacOSGLContextSwitch context_switch(self.openGLContext);
MacOSGLContextSwitch context_switch(_openGLContext);
glFlush();
}

View File

@ -275,13 +275,13 @@ static void CommonInit(FlutterViewController* controller) {
}
- (void)loadView {
NSOpenGLContext* resourceContext = _engine.resourceContext;
if (!resourceContext) {
NSLog(@"Unable to create FlutterView; no resource context available.");
NSOpenGLContext* mainContext = _engine.openGLRenderer.openGLContext;
if (!mainContext) {
NSLog(@"Unable to create FlutterView; no GL context available.");
return;
}
FlutterView* flutterView = [[FlutterView alloc] initWithShareContext:resourceContext
reshapeListener:self];
FlutterView* flutterView = [[FlutterView alloc] initWithMainContext:mainContext
reshapeListener:self];
self.view = flutterView;
}