From 1dd6d16b7c4118144aa56ae966c4937a89908620 Mon Sep 17 00:00:00 2001 From: richardjcai Date: Fri, 20 Nov 2020 19:19:11 -0500 Subject: [PATCH] Create a wrapper for IOSurface to handle creation and binding IOSurfaces to textures / framebuffers. --- ci/licenses_golden/licenses_flutter | 2 + shell/platform/darwin/macos/BUILD.gn | 2 + .../framework/Source/FlutterIOSurfaceHolder.h | 29 ++++++++ .../Source/FlutterIOSurfaceHolder.mm | 66 +++++++++++++++++++ .../framework/Source/FlutterSurfaceManager.mm | 58 ++++------------ 5 files changed, 113 insertions(+), 44 deletions(-) create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.mm diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b70e0f86c285c..616a6acfc721d 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1056,6 +1056,8 @@ 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/FlutterFrameBufferProvider.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterFrameBufferProvider.mm +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.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 diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 6731939cf7975..8a7f69477aed5 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -54,6 +54,8 @@ source_set("flutter_framework_source") { "framework/Source/FlutterExternalTextureGL.mm", "framework/Source/FlutterFrameBufferProvider.h", "framework/Source/FlutterFrameBufferProvider.mm", + "framework/Source/FlutterIOSurfaceHolder.h", + "framework/Source/FlutterIOSurfaceHolder.mm", "framework/Source/FlutterMouseCursorPlugin.h", "framework/Source/FlutterMouseCursorPlugin.mm", "framework/Source/FlutterResizeSynchronizer.h", diff --git a/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h b/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h new file mode 100644 index 0000000000000..39b4e4b515dd6 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h @@ -0,0 +1,29 @@ +// 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 + +/** + * FlutterIOSurfaceHolder maintains an IOSurface + * and provides an interface to bind the IOSurface to a texture. + */ +@interface FlutterIOSurfaceHolder : NSObject + +/** + * Bind the IOSurface to the provided texture and fbo. + */ +- (void)bindSurfaceToTexture:(GLuint)texture fbo:(GLuint)fbo size:(CGSize)size; + +/** + * Releases the current IOSurface if one exists + * and creates a new IOSurface with the specified size. + */ +- (void)recreateIOSurfaceWithSize:(CGSize)size; + +/** + * Returns a reference to the underlying IOSurface. + */ +- (const IOSurfaceRef&)ioSurface; + +@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.mm b/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.mm new file mode 100644 index 0000000000000..c7127393e9aea --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.mm @@ -0,0 +1,66 @@ +// 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/FlutterIOSurfaceHolder.h" + +#include + +@interface FlutterIOSurfaceHolder () { + IOSurfaceRef _ioSurface; +} +@end + +@implementation FlutterIOSurfaceHolder + +- (void)bindSurfaceToTexture:(GLuint)texture fbo:(GLuint)fbo size:(CGSize)size { + [self recreateIOSurfaceWithSize:size]; + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); + + 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, + 0 /* plane */); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, texture, + 0); + + NSAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, + @"Framebuffer status check failed"); +} + +- (void)recreateIOSurfaceWithSize:(CGSize)size { + if (_ioSurface) { + CFRelease(_ioSurface); + } + + 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 = IOSurfaceCreate((CFDictionaryRef)options); +} + +- (const IOSurfaceRef&)ioSurface { + return _ioSurface; +} + +- (void)dealloc { + if (_ioSurface) { + CFRelease(_ioSurface); + } +} + +@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm index a1076bb395eb4..20a1b1a341dc4 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm @@ -4,6 +4,7 @@ #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterFrameBufferProvider.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h" #include @@ -22,7 +23,7 @@ @interface FlutterSurfaceManager () { NSOpenGLContext* _openGLContext; - IOSurfaceRef _ioSurface[kFlutterSurfaceManagerBufferCount]; + FlutterIOSurfaceHolder* _ioSurfaces[kFlutterSurfaceManagerBufferCount]; FlutterFrameBufferProvider* _frameBuffers[kFlutterSurfaceManagerBufferCount]; } @end @@ -42,6 +43,9 @@ - (instancetype)initWithLayer:(CALayer*)containingLayer _frameBuffers[0] = [[FlutterFrameBufferProvider alloc] initWithOpenGLContext:_openGLContext]; _frameBuffers[1] = [[FlutterFrameBufferProvider alloc] initWithOpenGLContext:_openGLContext]; + + _ioSurfaces[0] = [FlutterIOSurfaceHolder alloc]; + _ioSurfaces[1] = [FlutterIOSurfaceHolder alloc]; } return self; } @@ -55,38 +59,11 @@ - (void)ensureSurfaceSize:(CGSize)size { MacOSGLContextSwitch context_switch(_openGLContext); for (int i = 0; i < kFlutterSurfaceManagerBufferCount; ++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, [_frameBuffers[i] glTextureId]); - - 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, [_frameBuffers[i] glFrameBufferId]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, - [_frameBuffers[i] glTextureId], 0); - - NSAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, - @"Framebuffer status check failed"); + [_ioSurfaces[i] recreateIOSurfaceWithSize:size]; + + GLuint fbo = [_frameBuffers[i] glFrameBufferId]; + GLuint texture = [_frameBuffers[i] glTextureId]; + [_ioSurfaces[i] bindSurfaceToTexture:texture fbo:fbo size:size]; } } @@ -96,10 +73,11 @@ - (void)swapBuffers { // 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[kFlutterSurfaceManagerBackBuffer]]; + IOSurfaceRef contentIOSurface = [_ioSurfaces[kFlutterSurfaceManagerBackBuffer] ioSurface]; + [_contentLayer setContents:(__bridge id)contentIOSurface]; - std::swap(_ioSurface[kFlutterSurfaceManagerBackBuffer], - _ioSurface[kFlutterSurfaceManagerFrontBuffer]); + std::swap(_ioSurfaces[kFlutterSurfaceManagerBackBuffer], + _ioSurfaces[kFlutterSurfaceManagerFrontBuffer]); std::swap(_frameBuffers[kFlutterSurfaceManagerBackBuffer], _frameBuffers[kFlutterSurfaceManagerFrontBuffer]); } @@ -108,12 +86,4 @@ - (uint32_t)glFrameBufferId { return [_frameBuffers[kFlutterSurfaceManagerBackBuffer] glFrameBufferId]; } -- (void)dealloc { - for (int i = 0; i < kFlutterSurfaceManagerBufferCount; ++i) { - if (_ioSurface[i]) { - CFRelease(_ioSurface[i]); - } - } -} - @end