Skip to content

Commit

Permalink
Add additional state to manage frame status and CALayers to FlutterGL…
Browse files Browse the repository at this point in the history
…Compositor
  • Loading branch information
RichardJCai committed Dec 2, 2020
1 parent 7c09d8a commit 1c15205
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,35 @@
// 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/FlutterFrameBufferProvider.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h"

#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>

/**
* FlutterBackingStoreData holds data to be stored in the
* BackingStore's user_data.
*/
@interface FlutterBackingStoreData : NSObject

- (nullable instancetype)initWithIsRootView:(bool)isRootView;
- (nullable instancetype)initWithLayerId:(size_t)layerId
fbProvider:(nonnull FlutterFrameBufferProvider*)fbProvider
ioSurfaceHolder:(nonnull FlutterIOSurfaceHolder*)ioSurfaceHolder;

- (bool)isRootView;
/**
* layerId is the layer's key value in FlutterGLCompositor's ca_layer_map_.
*/
@property(nonatomic, readonly) size_t layerId;

/**
* frameBufferProvider used to provide the fbo for rendering the layer.
*/
@property(nonnull, nonatomic, readonly) FlutterFrameBufferProvider* frameBufferProvider;

/**
* ioSurfaceHolder contains the IOSurfaceRef with the layer contents.
*/
@property(nonnull, nonatomic, readonly) FlutterIOSurfaceHolder* ioSurfaceHolder;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,22 @@
// found in the LICENSE file.

#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.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>

@interface FlutterBackingStoreData () {
bool _isRootView;
}
@end

@implementation FlutterBackingStoreData

- (nullable instancetype)initWithIsRootView:(bool)isRootView {
- (nullable instancetype)initWithLayerId:(size_t)layerId
fbProvider:(nonnull FlutterFrameBufferProvider*)fbProvider
ioSurfaceHolder:(nonnull FlutterIOSurfaceHolder*)ioSurfaceHolder {
if (self = [super init]) {
_isRootView = isRootView;
_layerId = layerId;
_frameBufferProvider = fbProvider;
_ioSurfaceHolder = ioSurfaceHolder;
}
return self;
}

- (bool)isRootView {
return _isRootView;
}

@end
2 changes: 2 additions & 0 deletions shell/platform/darwin/macos/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ - (FlutterCompositor*)createFlutterCompositor {
_macOSGLCompositor->SetPresentCallback(
[weak_self]() { return [weak_self engineCallbackOnPresent]; });

_compositor.avoid_backing_store_cache = true;

return &_compositor;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/
@interface FlutterFrameBufferProvider : NSObject

- (nullable instancetype)initWithOpenGLContext:(nonnull NSOpenGLContext*)opengLContext;
- (nullable instancetype)initWithOpenGLContext:(nonnull const NSOpenGLContext*)opengLContext;

/**
* Returns the id of the framebuffer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ @interface FlutterFrameBufferProvider () {
@end

@implementation FlutterFrameBufferProvider
- (instancetype)initWithOpenGLContext:(NSOpenGLContext*)openGLContext {
- (instancetype)initWithOpenGLContext:(const NSOpenGLContext*)openGLContext {
if (self = [super init]) {
MacOSGLContextSwitch context_switch(openGLContext);

Expand Down
29 changes: 26 additions & 3 deletions shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>
#include <map>

#include "flutter/fml/macros.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h"
Expand Down Expand Up @@ -38,6 +38,7 @@ class FlutterGLCompositor {

// Presents the FlutterLayers by updating FlutterView(s) using the
// layer content.
// Present sets frame_started_ to false.
bool Present(const FlutterLayer** layers, size_t layers_count);

using PresentCallback = std::function<bool()>;
Expand All @@ -46,9 +47,31 @@ class FlutterGLCompositor {
void SetPresentCallback(const PresentCallback& present_callback);

private:
FlutterViewController* view_controller_;
const FlutterViewController* view_controller_;
const NSOpenGLContext* open_gl_context_;
PresentCallback present_callback_;
NSOpenGLContext* open_gl_context_;

// Count for how many CALayers have been created for a frame.
// Resets when a frame is finished.
// ca_layer_count_ is also used as a layerId.
size_t ca_layer_count_ = 0;

// Maps a layer_id (size_t) to a CALayer.
// The layer_id starts at 0 for a given frame
// and increments by 1 for each new CALayer.
std::map<size_t, CALayer*> ca_layer_map_;

// frame_started_ keeps track of if a layer has been
// created for the frame.
bool frame_started_ = false;

// Set frame_started_ to true and reset all layer state.
void StartFrame();

// Creates a CALayer and adds it to ca_layer_map_ and increments
// ca_layer_count_; Returns the key value (size_t) for the layer in
// ca_layer_map_.
size_t CreateCALayer();

FML_DISALLOW_COPY_AND_ASSIGN(FlutterGLCompositor);
};
Expand Down
95 changes: 72 additions & 23 deletions shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@
// found in the LICENSE file.

#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterFrameBufferProvider.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h"

#import <OpenGL/gl.h>

#import "flutter/fml/logging.h"
#import "flutter/fml/platform/darwin/cf_utils.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterFrameBufferProvider.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h"
#import "third_party/skia/include/core/SkCanvas.h"
#import "third_party/skia/include/core/SkSurface.h"
#import "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
#import "third_party/skia/include/utils/mac/SkCGUtils.h"

#include <unistd.h>

namespace flutter {

FlutterGLCompositor::FlutterGLCompositor(FlutterViewController* view_controller)
Expand All @@ -26,25 +25,36 @@
bool FlutterGLCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config,
FlutterBackingStore* backing_store_out) {
CGSize size = CGSizeMake(config->size.width, config->size.height);
FlutterBackingStoreData* data =
[[FlutterBackingStoreData alloc] initWithIsRootView:config->is_root_view];

backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
backing_store_out->is_cacheable = true;
backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
backing_store_out->open_gl.framebuffer.target = GL_RGBA8;

if (config->is_root_view) {
// The root view uses FlutterSurfaceManager and is not cacheable since
// the fbo id changes on every present.
backing_store_out->is_cacheable = false;
if (!frame_started_) {
StartFrame();
// If the backing store is for the first layer, return the fbo for the
// FlutterView.
auto fbo = [view_controller_.flutterView frameBufferIDForSize:size];
backing_store_out->open_gl.framebuffer.name = fbo;
} else {
FML_CHECK(false) << "Compositor only supports creating a backing store for the root view";
FlutterFrameBufferProvider* fb_provider =
[[FlutterFrameBufferProvider alloc] initWithOpenGLContext:open_gl_context_];
FlutterIOSurfaceHolder* io_surface_holder = [FlutterIOSurfaceHolder alloc];

GLuint fbo = [fb_provider glFrameBufferId];
GLuint texture = [fb_provider glTextureId];

size_t layer_id = CreateCALayer();

[io_surface_holder bindSurfaceToTexture:texture fbo:fbo size:size];
FlutterBackingStoreData* data =
[[FlutterBackingStoreData alloc] initWithLayerId:layer_id
fbProvider:fb_provider
ioSurfaceHolder:io_surface_holder];

backing_store_out->open_gl.framebuffer.name = fbo;
backing_store_out->open_gl.framebuffer.user_data = (__bridge_retained void*)data;
}

backing_store_out->open_gl.framebuffer.user_data = (__bridge_retained void*)data;
backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
backing_store_out->open_gl.framebuffer.target = GL_RGBA8;
backing_store_out->open_gl.framebuffer.destruction_callback = [](void* user_data) {
if (user_data != nullptr) {
CFRelease(user_data);
Expand All @@ -64,19 +74,33 @@
FlutterBackingStore* backing_store = const_cast<FlutterBackingStore*>(layer->backing_store);
switch (layer->type) {
case kFlutterLayerContentTypeBackingStore: {
FlutterBackingStoreData* data =
(__bridge FlutterBackingStoreData*)(backing_store->open_gl.framebuffer.user_data);
if (![data isRootView]) {
FML_CHECK(false) << "Compositor only supports presenting the root view.";
if (backing_store->open_gl.framebuffer.user_data) {
FlutterBackingStoreData* backing_store_data =
(__bridge FlutterBackingStoreData*)backing_store->open_gl.framebuffer.user_data;

FlutterIOSurfaceHolder* io_surface_holder = [backing_store_data ioSurfaceHolder];
size_t layer_id = [backing_store_data layerId];

CALayer* content_layer = ca_layer_map_[layer_id];

FML_CHECK(content_layer) << "Unable to find a content layer with layer id " << layer_id;

content_layer.frame = content_layer.superlayer.bounds;
content_layer.transform = CATransform3DMakeScale(1, -1, 1);
IOSurfaceRef io_surface_contents = [io_surface_holder ioSurface];
[content_layer setContents:(__bridge id)io_surface_contents];
}
break;
}
case kFlutterLayerContentTypePlatformView:
// Add functionality in follow up PR.
FML_CHECK(false) << "Presenting PlatformViews not yet supported";
FML_LOG(WARNING) << "Presenting PlatformViews not yet supported";
break;
};
}
// The frame has been presented, prepare FlutterGLCompositor to
// render a new frame.
frame_started_ = false;
return present_callback_();
}

Expand All @@ -85,4 +109,29 @@
present_callback_ = present_callback;
}

void FlutterGLCompositor::StartFrame() {
// First reset all the state.
ca_layer_count_ = 0;

// First remove all CALayers from the superlayer.
for (auto const& x : ca_layer_map_) {
[x.second removeFromSuperlayer];
}

// Reset layer map.
ca_layer_map_.clear();

frame_started_ = true;
}

size_t FlutterGLCompositor::CreateCALayer() {
// FlutterGLCompositor manages the lifecycle of content layers.
// The id for a CALayer starts at 0 and increments by 1 for
// any given frame.
CALayer* content_layer = [[CALayer alloc] init];
[view_controller_.flutterView.layer addSublayer:content_layer];
ca_layer_map_[ca_layer_count_] = content_layer;
return ca_layer_count_++;
}

} // namespace flutter
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/
class MacOSGLContextSwitch {
public:
explicit MacOSGLContextSwitch(NSOpenGLContext* context);
explicit MacOSGLContextSwitch(const NSOpenGLContext* context);
~MacOSGLContextSwitch();

MacOSGLContextSwitch(const MacOSGLContextSwitch&) = delete;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#import "flutter/shell/platform/darwin/macos/framework/Source/MacOSGLContextSwitch.h"

MacOSGLContextSwitch::MacOSGLContextSwitch(NSOpenGLContext* context) {
MacOSGLContextSwitch::MacOSGLContextSwitch(const NSOpenGLContext* context) {
previous_ = [NSOpenGLContext currentContext];
[context makeCurrentContext];
}
Expand Down

0 comments on commit 1c15205

Please sign in to comment.