mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[macos] Re-land FlutterOpenGLRenderer isolation (flutter/engine#22607)
This commit is contained in:
parent
aca3f41cbd
commit
131e179b7c
@ -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
|
||||
|
||||
@ -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;
|
||||
/**
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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]() {
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user