Skip to content

Commit

Permalink
Create a wrapper for IOSurface to handle creation and (flutter#22663)
Browse files Browse the repository at this point in the history
binding IOSurfaces to textures / framebuffers.
  • Loading branch information
RichardJCai committed Nov 23, 2020
1 parent 2eea247 commit 07af6a9
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 44 deletions.
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions shell/platform/darwin/macos/BUILD.gn
Expand Up @@ -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",
Expand Down
@@ -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 <Cocoa/Cocoa.h>

/**
* 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
@@ -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 <OpenGL/gl.h>

@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
Expand Up @@ -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 <OpenGL/gl.h>

Expand All @@ -22,7 +23,7 @@ @interface FlutterSurfaceManager () {

NSOpenGLContext* _openGLContext;

IOSurfaceRef _ioSurface[kFlutterSurfaceManagerBufferCount];
FlutterIOSurfaceHolder* _ioSurfaces[kFlutterSurfaceManagerBufferCount];
FlutterFrameBufferProvider* _frameBuffers[kFlutterSurfaceManagerBufferCount];
}
@end
Expand All @@ -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;
}
Expand All @@ -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];
}
}

Expand All @@ -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]);
}
Expand All @@ -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

0 comments on commit 07af6a9

Please sign in to comment.