-
Notifications
You must be signed in to change notification settings - Fork 6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
363 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#import <Cocoa/Cocoa.h> | ||
|
||
@class FlutterResizeSynchronizer; | ||
|
||
@protocol FlutterResizeSynchronizerDelegate | ||
|
||
// Invoked on platform thread; Delegate should flush OpenGL context and | ||
// flip the surfaces | ||
- (void)resizeSynchronizerCommit:(FlutterResizeSynchronizer*)synchronizer; | ||
|
||
@end | ||
|
||
// Encapsulates the logic for blocking platform thread during window resize | ||
@interface FlutterResizeSynchronizer : NSObject | ||
|
||
- (instancetype)initWithDelegate:(id<FlutterResizeSynchronizerDelegate>)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; | ||
- (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 |
97 changes: 97 additions & 0 deletions
97
shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.mm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h" | ||
|
||
#import <mutex> | ||
|
||
@interface FlutterResizeSynchronizer () { | ||
uint32_t cookie; // counter to detect stale callbacks | ||
std::mutex mutex; | ||
std::condition_variable condRun; | ||
std::condition_variable condBlock; | ||
bool accepting; | ||
bool waiting; | ||
bool pendingCommit; | ||
CGSize newSize; | ||
__weak id<FlutterResizeSynchronizerDelegate> delegate; | ||
} | ||
@end | ||
|
||
@implementation FlutterResizeSynchronizer | ||
|
||
- (instancetype)initWithDelegate:(id<FlutterResizeSynchronizerDelegate>)delegate_ { | ||
if (self = [super init]) { | ||
accepting = true; | ||
delegate = delegate_; | ||
} | ||
return self; | ||
} | ||
|
||
- (void)beginResize:(CGSize)size notify:(dispatch_block_t)notify { | ||
std::unique_lock<std::mutex> lock(mutex); | ||
if (!delegate) { | ||
return; | ||
} | ||
|
||
++cookie; | ||
|
||
// from now on, ignore all incoming commits until the block below gets | ||
// scheduled on raster thread | ||
accepting = false; | ||
|
||
// let pending commits finish to unblock the raster thread | ||
condRun.notify_all(); | ||
|
||
// let the engine send resize notification | ||
notify(); | ||
|
||
newSize = size; | ||
|
||
waiting = true; | ||
|
||
condBlock.wait(lock); | ||
|
||
if (pendingCommit) { | ||
[delegate resizeSynchronizerCommit:self]; | ||
pendingCommit = false; | ||
condRun.notify_all(); | ||
} | ||
|
||
waiting = false; | ||
} | ||
|
||
- (bool)shouldEnsureSurfaceForSize:(CGSize)size { | ||
std::unique_lock<std::mutex> lock(mutex); | ||
if (!accepting) { | ||
if (CGSizeEqualToSize(newSize, size)) { | ||
accepting = true; | ||
} | ||
} | ||
return accepting; | ||
} | ||
|
||
- (void)requestCommit { | ||
std::unique_lock<std::mutex> lock(mutex); | ||
if (!accepting) { | ||
return; | ||
} | ||
|
||
if (waiting) { // BeginResize is in progress, interrupt it and schedule commit call | ||
pendingCommit = true; | ||
condBlock.notify_all(); | ||
condRun.wait(lock); | ||
} else { | ||
// No resize, schedule commit on platform thread and wait until either done | ||
// or interrupted by incoming BeginResize | ||
dispatch_async(dispatch_get_main_queue(), [self, cookie_ = cookie] { | ||
std::unique_lock<std::mutex> lock(mutex); | ||
if (cookie_ == cookie) { | ||
if (delegate) { | ||
[delegate resizeSynchronizerCommit:self]; | ||
} | ||
condRun.notify_all(); | ||
} | ||
}); | ||
condRun.wait(lock); | ||
} | ||
} | ||
|
||
@end |
13 changes: 13 additions & 0 deletions
13
shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#import <Cocoa/Cocoa.h> | ||
|
||
// 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 |
119 changes: 119 additions & 0 deletions
119
shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h" | ||
|
||
#include <OpenGL/gl.h> | ||
|
||
enum { | ||
kFront = 0, | ||
kBack = 1, | ||
kBufferCount, | ||
}; | ||
|
||
@interface FlutterSurfaceManager () { | ||
CGSize surfaceSize; | ||
CALayer* layer; | ||
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_; | ||
|
||
NSOpenGLContext* prev = [NSOpenGLContext currentContext]; | ||
[openGLContext makeCurrentContext]; | ||
glGenFramebuffers(2, _frameBufferId); | ||
glGenTextures(2, _backingTexture); | ||
|
||
glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferId[0]); | ||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _backingTexture[0]); | ||
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); | ||
|
||
glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferId[1]); | ||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _backingTexture[1]); | ||
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); | ||
|
||
if (prev) { | ||
[prev makeCurrentContext]; | ||
} else { | ||
[NSOpenGLContext clearCurrentContext]; | ||
} | ||
} | ||
return self; | ||
} | ||
|
||
- (void)ensureSurfaceSize:(CGSize)size { | ||
if (CGSizeEqualToSize(size, surfaceSize)) { | ||
return; | ||
} | ||
surfaceSize = size; | ||
NSOpenGLContext* prev = [NSOpenGLContext currentContext]; | ||
[openGLContext makeCurrentContext]; | ||
|
||
for (int i = 0; i < 2; ++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); | ||
} | ||
if (prev) { | ||
[prev makeCurrentContext]; | ||
} else { | ||
[NSOpenGLContext clearCurrentContext]; | ||
} | ||
} | ||
|
||
- (void)swapBuffers { | ||
[layer 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.