blob: cb442ea768ffb9c6c618745cbeba71977ce17bba [file] [log] [blame]
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterThreadSynchronizer.h"
#import <QuartzCore/QuartzCore.h>
#include <mutex>
#include <vector>
#import "flutter/fml/logging.h"
#import "flutter/fml/synchronization/waitable_event.h"
@interface FlutterThreadSynchronizer () {
std::mutex _mutex;
BOOL _shuttingDown;
CGSize _contentSize;
std::vector<dispatch_block_t> _scheduledBlocks;
BOOL _beginResizeWaiting;
// Used to block [beginResize:].
std::condition_variable _condBlockBeginResize;
}
@end
@implementation FlutterThreadSynchronizer
- (void)drain {
FML_DCHECK([NSThread isMainThread]);
[CATransaction begin];
[CATransaction setDisableActions:YES];
for (dispatch_block_t block : _scheduledBlocks) {
block();
}
[CATransaction commit];
_scheduledBlocks.clear();
}
- (void)blockUntilFrameAvailable {
std::unique_lock<std::mutex> lock(_mutex);
_beginResizeWaiting = YES;
while (CGSizeEqualToSize(_contentSize, CGSizeZero) && !_shuttingDown) {
_condBlockBeginResize.wait(lock);
[self drain];
}
_beginResizeWaiting = NO;
}
- (void)beginResize:(CGSize)size notify:(nonnull dispatch_block_t)notify {
std::unique_lock<std::mutex> lock(_mutex);
if (CGSizeEqualToSize(_contentSize, CGSizeZero) || _shuttingDown) {
// No blocking until framework produces at least one frame
notify();
return;
}
[self drain];
notify();
_contentSize = CGSizeMake(-1, -1);
_beginResizeWaiting = YES;
while (!CGSizeEqualToSize(_contentSize, size) && //
!CGSizeEqualToSize(_contentSize, CGSizeZero) && !_shuttingDown) {
_condBlockBeginResize.wait(lock);
[self drain];
}
_beginResizeWaiting = NO;
}
- (void)performCommit:(CGSize)size notify:(nonnull dispatch_block_t)notify {
fml::AutoResetWaitableEvent event;
{
std::unique_lock<std::mutex> lock(_mutex);
if (_shuttingDown) {
// Engine is shutting down, main thread may be blocked by the engine
// waiting for raster thread to finish.
return;
}
fml::AutoResetWaitableEvent& e = event;
_scheduledBlocks.push_back(^{
notify();
_contentSize = size;
e.Signal();
});
if (_beginResizeWaiting) {
_condBlockBeginResize.notify_all();
} else {
dispatch_async(dispatch_get_main_queue(), ^{
std::unique_lock<std::mutex> lock(_mutex);
[self drain];
});
}
}
event.Wait();
}
- (void)shutdown {
std::unique_lock<std::mutex> lock(_mutex);
_shuttingDown = YES;
_condBlockBeginResize.notify_all();
[self drain];
}
@end