diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 46097e6e73e77..c6e5047eaa2bb 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1047,6 +1047,10 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExter FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.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/FlutterResizeSynchronizer.h +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.mm +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputModel.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputModel.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.h @@ -1056,6 +1060,8 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterView. FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.h +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart FILE: ../../../flutter/shell/platform/darwin/macos/framework/module.modulemap FILE: ../../../flutter/shell/platform/embedder/assets/EmbedderInfo.plist diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 9800139a8a1cf..c844d92413f3c 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -54,6 +54,10 @@ source_set("flutter_framework_source") { "framework/Source/FlutterExternalTextureGL.mm", "framework/Source/FlutterMouseCursorPlugin.h", "framework/Source/FlutterMouseCursorPlugin.mm", + "framework/Source/FlutterResizeSynchronizer.h", + "framework/Source/FlutterResizeSynchronizer.mm", + "framework/Source/FlutterSurfaceManager.h", + "framework/Source/FlutterSurfaceManager.mm", "framework/Source/FlutterTextInputModel.h", "framework/Source/FlutterTextInputModel.mm", "framework/Source/FlutterTextInputPlugin.h", @@ -62,11 +66,15 @@ source_set("flutter_framework_source") { "framework/Source/FlutterView.mm", "framework/Source/FlutterViewController.mm", "framework/Source/FlutterViewController_Internal.h", + "framework/Source/MacOSSwitchableGLContext.h", + "framework/Source/MacOSSwitchableGLContext.mm", ] sources += _flutter_framework_headers deps = [ + "//flutter/flow:flow", + "//flutter/fml:fml", "//flutter/shell/platform/common/cpp:common_cpp_switches", "//flutter/shell/platform/darwin/common:framework_shared", "//flutter/shell/platform/embedder:embedder_as_internal_library", @@ -81,6 +89,8 @@ source_set("flutter_framework_source") { libs = [ "Cocoa.framework", "CoreVideo.framework", + "IOSurface.framework", + "QuartzCore.framework", ] } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 37eb3521bc2ed..0ef5ad9654ef6 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -154,9 +154,9 @@ static bool OnPresent(FlutterEngine* engine) { return [engine engineCallbackOnPresent]; } -static uint32_t OnFBO(FlutterEngine* engine) { - // There is currently no case where a different FBO is used, so no need to forward. - return 0; +static uint32_t OnFBO(FlutterEngine* engine, const FlutterFrameInfo* info) { + CGSize size = CGSizeMake(info->size.width, info->size.height); + return [engine.viewController.flutterView getFrameBufferIdForSize:size]; } static bool OnMakeResourceCurrent(FlutterEngine* engine) { @@ -248,7 +248,8 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { .open_gl.make_current = (BoolCallback)OnMakeCurrent, .open_gl.clear_current = (BoolCallback)OnClearCurrent, .open_gl.present = (BoolCallback)OnPresent, - .open_gl.fbo_callback = (UIntCallback)OnFBO, + .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, }; @@ -297,7 +298,6 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { const FlutterCustomTaskRunners custom_task_runners = { .struct_size = sizeof(FlutterCustomTaskRunners), .platform_task_runner = &cocoa_task_runner_description, - .render_task_runner = &cocoa_task_runner_description, }; flutterArguments.custom_task_runners = &custom_task_runners; @@ -322,6 +322,7 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { [self sendUserLocales]; [self updateWindowMetrics]; [self updateDisplayConfig]; + self.viewController.flutterView.synchronousResizing = YES; return YES; } @@ -362,7 +363,9 @@ - (void)setViewController:(FlutterViewController*)controller { [self shutDownEngine]; _resourceContext = nil; } - [self updateWindowMetrics]; + if (_engine) { + self.viewController.flutterView.synchronousResizing = YES; + } } - (id)binaryMessenger { @@ -380,7 +383,7 @@ - (BOOL)running { - (NSOpenGLContext*)resourceContext { if (!_resourceContext) { NSOpenGLPixelFormatAttribute attributes[] = { - NSOpenGLPFAColorSize, 24, NSOpenGLPFAAlphaSize, 8, NSOpenGLPFADoubleBuffer, 0, + NSOpenGLPFAColorSize, 24, NSOpenGLPFAAlphaSize, 8, 0, }; NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; _resourceContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil]; @@ -479,7 +482,7 @@ - (bool)engineCallbackOnPresent { if (!_mainOpenGLContext) { return false; } - [_mainOpenGLContext flushBuffer]; + [self.viewController.flutterView present]; return true; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h b/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h new file mode 100644 index 0000000000000..fe9a0bde6f1f5 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h @@ -0,0 +1,59 @@ +#import + +@class FlutterResizeSynchronizer; + +@protocol FlutterResizeSynchronizerDelegate + +// Invoked on raster thread; Delegate should flush the OpenGL context +- (void)resizeSynchronizerFlush:(FlutterResizeSynchronizer*)synchronizer; + +// Invoked on platform thread; Delegate should flip the surfaces +- (void)resizeSynchronizerCommit:(FlutterResizeSynchronizer*)synchronizer; + +@end + +// Encapsulates the logic for blocking platform thread during window resize as +// well as synchronizing the raster and platform thread during commit (presenting frame) +// +// Flow during window resize +// +// 1. Platform thread calls [synchronizer beginResize:notify:] +// This will hold the platform thread until we're ready to display contents. +// 2. Raster thread calls [synchronizer shouldEnsureSurfaceForSize:] with target size +// This will return false for any size other than target size +// 3. Raster thread calls [synchronizer requestCommit] +// Any commit calls before shouldEnsureSurfaceForSize: is called with the right +// size are simply ignored; There's no point rasterizing and displaying frames +// with wrong size. +// Both delegate methods (flush/commit) will be invoked before beginResize returns +// +// Flow during regular operation (no resizing) +// +// 1. Raster thread calls [synchronizer requestCommit] +// This will invoke [delegate flush:] on raster thread and +// [delegate commit:] on platform thread. The requestCommit call will be blocked +// until this is done. This is necessary to ensure that rasterizer won't start +// rasterizing next frame before we flipped the surface, which must be performed +// on platform thread +@interface FlutterResizeSynchronizer : NSObject + +- (instancetype)initWithDelegate:(id)delegate; + +// Blocks the platform thread until +// - shouldEnsureSurfaceForSize is called with proper size and +// - requestCommit is called +// All requestCommit calls before `shouldEnsureSurfaceForSize` is called with +// expected size are ignored; +// The notify block is invoked immediately after synchronizer mutex is acquired +- (void)beginResize:(CGSize)size notify:(dispatch_block_t)notify; + +// Returns whether the view should ensure surfaces with given size; +// This will be false during resizing for any size other than size specified +// during beginResize +- (bool)shouldEnsureSurfaceForSize:(CGSize)size; + +// Called from rasterizer thread, will block until delegate resizeSynchronizerCommit: +// method is called (on platform thread) +- (void)requestCommit; + +@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.mm b/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.mm new file mode 100644 index 0000000000000..2e1eef3eff389 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.mm @@ -0,0 +1,104 @@ +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h" + +#import + +@interface FlutterResizeSynchronizer () { + uint32_t cookie; // counter to detect stale callbacks + + std::mutex mutex; + std::condition_variable condBlockBeginResize; // used to block [beginResize:] + std::condition_variable condBlockRequestCommit; // used to block [requestCommit] + + bool acceptingCommit; // if false, requestCommit calls are ignored until + // shouldEnsureSurfaceForSize is called with proper size + bool waiting; // waiting for resize to finish + bool pendingCommit; // requestCommit was called and [delegate commit:] must be performed on + // platform thread + CGSize newSize; // target size for resizing + + __weak id delegate; +} +@end + +@implementation FlutterResizeSynchronizer + +- (instancetype)initWithDelegate:(id)delegate_ { + if (self = [super init]) { + acceptingCommit = true; + delegate = delegate_; + } + return self; +} + +- (void)beginResize:(CGSize)size notify:(dispatch_block_t)notify { + std::unique_lock lock(mutex); + if (!delegate) { + return; + } + + ++cookie; + + // from now on, ignore all incoming commits until the block below gets + // scheduled on raster thread + acceptingCommit = false; + + // let pending commits finish to unblock the raster thread + pendingCommit = false; + condBlockBeginResize.notify_all(); + + // let the engine send resize notification + notify(); + + newSize = size; + + waiting = true; + + condBlockRequestCommit.wait(lock, [&] { return pendingCommit; }); + + [delegate resizeSynchronizerFlush:self]; + [delegate resizeSynchronizerCommit:self]; + pendingCommit = false; + condBlockBeginResize.notify_all(); + + waiting = false; +} + +- (bool)shouldEnsureSurfaceForSize:(CGSize)size { + std::unique_lock lock(mutex); + if (!acceptingCommit) { + if (CGSizeEqualToSize(newSize, size)) { + acceptingCommit = true; + } + } + return acceptingCommit; +} + +- (void)requestCommit { + std::unique_lock lock(mutex); + if (!acceptingCommit) { + return; + } + + pendingCommit = true; + if (waiting) { // BeginResize is in progress, interrupt it and schedule commit call + condBlockRequestCommit.notify_all(); + condBlockBeginResize.wait(lock, [&]() { return !pendingCommit; }); + } else { + // No resize, schedule commit on platform thread and wait until either done + // or interrupted by incoming BeginResize + [delegate resizeSynchronizerFlush:self]; + dispatch_async(dispatch_get_main_queue(), [self, cookie_ = cookie] { + std::unique_lock lock(mutex); + if (cookie_ == cookie) { + if (delegate) { + [delegate resizeSynchronizerCommit:self]; + } + pendingCommit = false; + condBlockBeginResize.notify_all(); + } + }); + condBlockBeginResize.wait(lock, [&]() { return !pendingCommit; }); + } +} + +@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h new file mode 100644 index 0000000000000..470f4f9400fda --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h @@ -0,0 +1,13 @@ +#import + +// Manages the IOSurfaces for FlutterView +@interface FlutterSurfaceManager : NSObject + +- (instancetype)initWithLayer:(CALayer*)layer openGLContext:(NSOpenGLContext*)opengLContext; + +- (void)ensureSurfaceSize:(CGSize)size; +- (void)swapBuffers; + +- (uint32_t)glFrameBufferId; + +@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm new file mode 100644 index 0000000000000..2ddb190139670 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm @@ -0,0 +1,128 @@ +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h" +#import "flutter/fml/logging.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.h" + +#include + +enum { + kFront = 0, + kBack = 1, + kBufferCount, +}; + +@interface FlutterSurfaceManager () { + CGSize surfaceSize; + CALayer* layer; // provided (parent layer) + CALayer* contentLayer; + + NSOpenGLContext* openGLContext; + uint32_t _frameBufferId[kBufferCount]; + uint32_t _backingTexture[kBufferCount]; + IOSurfaceRef _ioSurface[kBufferCount]; +} +@end + +@implementation FlutterSurfaceManager + +- (instancetype)initWithLayer:(CALayer*)layer_ openGLContext:(NSOpenGLContext*)opengLContext_ { + if (self = [super init]) { + layer = layer_; + openGLContext = opengLContext_; + + // Layer for content. This is separate from provided layer, because it needs to be flipped + // vertically if we render to OpenGL texture + contentLayer = [[CALayer alloc] init]; + [layer_ addSublayer:contentLayer]; + + flutter::GLContextSwitch context_switch( + std::make_unique(opengLContext_)); + + glGenFramebuffers(2, _frameBufferId); + glGenTextures(2, _backingTexture); + + [self createFramebuffer:_frameBufferId[0] withBackingTexture:_backingTexture[0]]; + [self createFramebuffer:_frameBufferId[1] withBackingTexture:_backingTexture[1]]; + } + return self; +} + +- (void)createFramebuffer:(uint32_t)fbo withBackingTexture:(uint32_t)texture { + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); + glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); +} + +- (void)ensureSurfaceSize:(CGSize)size { + if (CGSizeEqualToSize(size, surfaceSize)) { + return; + } + surfaceSize = size; + + flutter::GLContextSwitch context_switch( + std::make_unique(openGLContext)); + + for (int i = 0; i < kBufferCount; ++i) { + if (_ioSurface[i]) { + CFRelease(_ioSurface[i]); + } + unsigned pixelFormat = 'BGRA'; + unsigned bytesPerElement = 4; + + size_t bytesPerRow = + IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, size.width * bytesPerElement); + size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, size.height * bytesPerRow); + NSDictionary* options = @{ + (id)kIOSurfaceWidth : @(size.width), + (id)kIOSurfaceHeight : @(size.height), + (id)kIOSurfacePixelFormat : @(pixelFormat), + (id)kIOSurfaceBytesPerElement : @(bytesPerElement), + (id)kIOSurfaceBytesPerRow : @(bytesPerRow), + (id)kIOSurfaceAllocSize : @(totalBytes), + }; + _ioSurface[i] = IOSurfaceCreate((CFDictionaryRef)options); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _backingTexture[i]); + + CGLTexImageIOSurface2D(CGLGetCurrentContext(), GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, + int(size.width), int(size.height), GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, + _ioSurface[i], 0 /* plane */); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferId[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, + _backingTexture[i], 0); + + FML_DCHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + } +} + +- (void)swapBuffers { + contentLayer.frame = layer.bounds; + + // The surface is an OpenGL texture, which means it has origin in bottom left corner + // and needs to be flipped vertically + contentLayer.transform = CATransform3DMakeScale(1, -1, 1); + [contentLayer setContents:(__bridge id)_ioSurface[kBack]]; + + std::swap(_ioSurface[kBack], _ioSurface[kFront]); + std::swap(_frameBufferId[kBack], _frameBufferId[kFront]); + std::swap(_backingTexture[kBack], _backingTexture[kFront]); +} + +- (uint32_t)glFrameBufferId { + return _frameBufferId[kBack]; +} + +- (void)dealloc { + for (int i = 0; i < kBufferCount; ++i) { + if (_ioSurface[i]) { + CFRelease(_ioSurface[i]); + } + } +} + +@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterView.h b/shell/platform/darwin/macos/framework/Source/FlutterView.h index e8c7ec3bd3d93..1e4358e11ce98 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterView.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterView.h @@ -18,7 +18,10 @@ * View capable of acting as a rendering target and input source for the Flutter * engine. */ -@interface FlutterView : NSOpenGLView +@interface FlutterView : NSView + +@property(readwrite, nonatomic, nonnull) NSOpenGLContext* openGLContext; +@property(readwrite, nonatomic) BOOL synchronousResizing; - (nullable instancetype)initWithFrame:(NSRect)frame shareContext:(nonnull NSOpenGLContext*)shareContext @@ -35,4 +38,7 @@ - (nullable instancetype)initWithCoder:(nonnull NSCoder*)coder NS_UNAVAILABLE; - (nonnull instancetype)init NS_UNAVAILABLE; +- (void)present; +- (int)getFrameBufferIdForSize:(CGSize)size; + @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterView.mm b/shell/platform/darwin/macos/framework/Source/FlutterView.mm index 1b46ac600ed9e..6839640b1ebca 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterView.mm @@ -3,11 +3,23 @@ // found in the LICENSE file. #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.h" -@implementation FlutterView { +#import +#import + +@interface FlutterView () { __weak id _reshapeListener; + FlutterResizeSynchronizer* resizeSynchronizer; + FlutterSurfaceManager* surfaceManager; } +@end + +@implementation FlutterView + - (instancetype)initWithShareContext:(NSOpenGLContext*)shareContext reshapeListener:(id)reshapeListener { return [self initWithFrame:NSZeroRect shareContext:shareContext reshapeListener:reshapeListener]; @@ -20,14 +32,63 @@ - (instancetype)initWithFrame:(NSRect)frame if (self) { self.openGLContext = [[NSOpenGLContext alloc] initWithFormat:shareContext.pixelFormat shareContext:shareContext]; + + [self setWantsLayer:YES]; + + resizeSynchronizer = [[FlutterResizeSynchronizer alloc] initWithDelegate:self]; + surfaceManager = [[FlutterSurfaceManager alloc] initWithLayer:self.layer + openGLContext:self.openGLContext]; + _reshapeListener = reshapeListener; - self.wantsBestResolutionOpenGLSurface = YES; } return self; } +- (void)resizeSynchronizerFlush:(FlutterResizeSynchronizer*)synchronizer { + flutter::GLContextSwitch context_switch( + std::make_unique(self.openGLContext)); + glFlush(); +} + +- (void)resizeSynchronizerCommit:(FlutterResizeSynchronizer*)synchronizer { + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + + [surfaceManager swapBuffers]; + + [CATransaction commit]; +} + +- (int)getFrameBufferIdForSize:(CGSize)size { + if ([resizeSynchronizer shouldEnsureSurfaceForSize:size]) { + [surfaceManager ensureSurfaceSize:size]; + } + return [surfaceManager glFrameBufferId]; +} + +- (void)present { + [resizeSynchronizer requestCommit]; +} + +- (void)reshaped { + if (self.synchronousResizing) { + CGSize scaledSize = [self convertSizeToBacking:self.bounds.size]; + [resizeSynchronizer beginResize:scaledSize + notify:^{ + [_reshapeListener viewDidReshape:self]; + }]; + } else { + [_reshapeListener viewDidReshape:self]; + } +} + #pragma mark - NSView overrides +- (void)setFrameSize:(NSSize)newSize { + [super setFrameSize:newSize]; + [self reshaped]; +} + /** * Declares that the view uses a flipped coordinate system, consistent with Flutter conventions. */ @@ -39,17 +100,13 @@ - (BOOL)isOpaque { return YES; } -- (void)reshape { - [super reshape]; - [_reshapeListener viewDidReshape:self]; -} - - (BOOL)acceptsFirstResponder { return YES; } - (void)viewDidChangeBackingProperties { [super viewDidChangeBackingProperties]; + // Force redraw [_reshapeListener viewDidReshape:self]; } diff --git a/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.h b/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.h new file mode 100644 index 0000000000000..0ff951fca1e6a --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.h @@ -0,0 +1,21 @@ +#include "flutter/flow/gl_context_switch.h" +#include "flutter/fml/memory/thread_checker.h" + +#import + +class MacOSSwitchableGLContext final : public flutter::SwitchableGLContext { + public: + explicit MacOSSwitchableGLContext(NSOpenGLContext* context); + + bool SetCurrent() override; + + bool RemoveCurrent() override; + + private: + NSOpenGLContext* context_; + NSOpenGLContext* previous_context_; + + FML_DECLARE_THREAD_CHECKER(checker); + + FML_DISALLOW_COPY_AND_ASSIGN(MacOSSwitchableGLContext); +}; diff --git a/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.mm b/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.mm new file mode 100644 index 0000000000000..d68d8dfcfc585 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.mm @@ -0,0 +1,19 @@ +#import "flutter/shell/platform/darwin/macos/framework/Source/MacOSSwitchableGLContext.h" + +MacOSSwitchableGLContext::MacOSSwitchableGLContext(NSOpenGLContext* context) : context_(context) {} + +bool MacOSSwitchableGLContext::SetCurrent() { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker); + previous_context_ = [NSOpenGLContext currentContext]; + [context_ makeCurrentContext]; + return true; +} + +bool MacOSSwitchableGLContext::RemoveCurrent() { + if (previous_context_) { + [previous_context_ makeCurrentContext]; + } else { + [NSOpenGLContext clearCurrentContext]; + } + return true; +}