FlutterGLCompositor.mm 5.4 KB
Newer Older
1 2 3 4 5 6 7 8
// 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/FlutterGLCompositor.h"

#import <OpenGL/gl.h>

9 10 11
#include "flutter/fml/logging.h"
#include "flutter/fml/platform/darwin/cf_utils.h"

12 13 14
#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"
15 16 17 18 19

#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
#include "third_party/skia/include/utils/mac/SkCGUtils.h"
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

namespace flutter {

FlutterGLCompositor::FlutterGLCompositor(FlutterViewController* view_controller)
    : open_gl_context_(view_controller.flutterView.openGLContext) {
  FML_CHECK(view_controller != nullptr) << "FlutterViewController* cannot be nullptr";
  view_controller_ = view_controller;
}

bool FlutterGLCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config,
                                             FlutterBackingStore* backing_store_out) {
  CGSize size = CGSizeMake(config->size.width, config->size.height);

  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 {
    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->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);
    }
  };

  return true;
}

bool FlutterGLCompositor::CollectBackingStore(const FlutterBackingStore* backing_store) {
  return true;
}

bool FlutterGLCompositor::Present(const FlutterLayer** layers, size_t layers_count) {
  for (size_t i = 0; i < layers_count; ++i) {
    const auto* layer = layers[i];
    FlutterBackingStore* backing_store = const_cast<FlutterBackingStore*>(layer->backing_store);
    switch (layer->type) {
      case kFlutterLayerContentTypeBackingStore: {
        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;

          // The surface is an OpenGL texture, which means it has origin in bottom left corner
          // and needs to be flipped vertically
          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_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_();
}

void FlutterGLCompositor::SetPresentCallback(
    const FlutterGLCompositor::PresentCallback& present_callback) {
  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& ca_layer_kvp : ca_layer_map_) {
    [ca_layer_kvp.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