Support platform view overlays with GL rendering (#6769)

Moved the frame buffer specific logic from IOSGLContext to IOSGLRenderTarget.

use recording canvases for overlays

Support platform view overlays with gl rendering.

This also changes the overlay canvases (for both software and gl
rendering) be recording canvases, and only rasterize them after
finishing the paint traversal.
This commit is contained in:
Amir Hardon 2018-11-08 19:52:43 -08:00 committed by GitHub
parent b2479f8d29
commit 099b4eeada
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 399 additions and 179 deletions

View File

@ -626,6 +626,42 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
====================================================================================================
====================================================================================================
LIBRARY: engine
ORIGIN: ../../../flutter/shell/platform/darwin/ios/ios_gl_render_target.h + ../../../LICENSE
TYPE: LicenseType.bsd
FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_render_target.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_render_target.mm
----------------------------------------------------------------------------------------------------
Copyright 2018 The Chromium Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
====================================================================================================
====================================================================================================
LIBRARY: txt
ORIGIN: ../../../flutter/third_party/txt/LICENSE
@ -912,4 +948,4 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
====================================================================================================
Total license count: 2
Total license count: 3

View File

@ -37,6 +37,8 @@ class ExternalViewEmbedder {
virtual SkCanvas* CompositeEmbeddedView(int view_id,
const EmbeddedViewParams& params) = 0;
virtual bool SubmitFrame(GrContext* context) { return false; };
virtual ~ExternalViewEmbedder() = default;
FML_DISALLOW_COPY_AND_ASSIGN(ExternalViewEmbedder);

View File

@ -178,6 +178,9 @@ bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) {
if (compositor_frame && compositor_frame->Raster(layer_tree, false)) {
frame->Submit();
if (external_view_embedder != nullptr) {
external_view_embedder->SubmitFrame(surface_->GetContext());
}
FireNextFrameCallbackIfPresent();
return true;
}

View File

@ -89,6 +89,24 @@ GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate)
delegate_->GLContextClearCurrent();
valid_ = true;
context_owner_ = true;
}
GPUSurfaceGL::GPUSurfaceGL(sk_sp<GrContext> gr_context,
GPUSurfaceGLDelegate* delegate)
: delegate_(delegate), context_(gr_context), weak_factory_(this) {
if (!delegate_->GLContextMakeCurrent()) {
FML_LOG(ERROR)
<< "Could not make the context current to setup the gr context.";
return;
}
proc_resolver_ = delegate_->GetGLProcResolver();
delegate_->GLContextClearCurrent();
valid_ = true;
context_owner_ = false;
}
GPUSurfaceGL::~GPUSurfaceGL() {
@ -103,7 +121,9 @@ GPUSurfaceGL::~GPUSurfaceGL() {
}
onscreen_surface_ = nullptr;
context_->releaseResourcesAndAbandonContext();
if (context_owner_) {
context_->releaseResourcesAndAbandonContext();
}
context_ = nullptr;
delegate_->GLContextClearCurrent();

View File

@ -49,6 +49,9 @@ class GPUSurfaceGL : public Surface {
public:
GPUSurfaceGL(GPUSurfaceGLDelegate* delegate);
// Creates a new GL surface reusing an existing GrContext.
GPUSurfaceGL(sk_sp<GrContext> gr_context, GPUSurfaceGLDelegate* delegate);
~GPUSurfaceGL() override;
// |shell::Surface|
@ -74,6 +77,7 @@ class GPUSurfaceGL : public Surface {
sk_sp<SkSurface> offscreen_surface_;
bool valid_ = false;
fml::WeakPtrFactory<GPUSurfaceGL> weak_factory_;
bool context_owner_;
bool CreateOrUpdateSurfaces(const SkISize& size);

View File

@ -87,6 +87,8 @@ shared_library("create_flutter_framework_dylib") {
"ios_external_texture_gl.mm",
"ios_gl_context.h",
"ios_gl_context.mm",
"ios_gl_render_target.h",
"ios_gl_render_target.mm",
"ios_surface.h",
"ios_surface.mm",
"ios_surface_gl.h",

View File

@ -13,7 +13,9 @@
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/shell/common/shell.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_context.h"
#include "flutter/shell/platform/darwin/ios/ios_surface.h"
#include "flutter/shell/platform/darwin/ios/ios_surface_gl.h"
@interface FlutterOverlayView : UIView
@ -21,7 +23,9 @@
- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (std::unique_ptr<shell::IOSSurface>)createSurface;
- (std::unique_ptr<shell::IOSSurface>)createSoftwareSurface;
- (std::unique_ptr<shell::IOSSurfaceGL>)createGLSurfaceWithContext:
(std::shared_ptr<shell::IOSGLContext>)gl_context;
@end

View File

@ -63,14 +63,15 @@
#endif // TARGET_IPHONE_SIMULATOR
}
- (std::unique_ptr<shell::IOSSurface>)createSurface {
if ([self.layer isKindOfClass:[CAEAGLLayer class]]) {
// TODO(amirh): create a GL surface.
return nullptr;
} else {
fml::scoped_nsobject<CALayer> layer(reinterpret_cast<CALayer*>([self.layer retain]));
return std::make_unique<shell::IOSSurfaceSoftware>(std::move(layer), nullptr);
}
- (std::unique_ptr<shell::IOSSurface>)createSoftwareSurface {
fml::scoped_nsobject<CALayer> layer(reinterpret_cast<CALayer*>([self.layer retain]));
return std::make_unique<shell::IOSSurfaceSoftware>(std::move(layer), nullptr);
}
- (std::unique_ptr<shell::IOSSurfaceGL>)createGLSurfaceWithContext:
(std::shared_ptr<shell::IOSGLContext>)gl_context {
fml::scoped_nsobject<CAEAGLLayer> eagl_layer(reinterpret_cast<CAEAGLLayer*>([self.layer retain]));
return std::make_unique<shell::IOSSurfaceGL>(eagl_layer, std::move(gl_context));
}
// TODO(amirh): implement drawLayer to suppoer snapshotting.

View File

@ -6,6 +6,7 @@
#import "FlutterOverlayView.h"
#import "flutter/shell/platform/darwin/ios/ios_surface.h"
#import "flutter/shell/platform/darwin/ios/ios_surface_gl.h"
#include <map>
#include <memory>
@ -138,8 +139,9 @@ void FlutterPlatformViewsController::SetFrameSize(SkISize frame_size) {
}
void FlutterPlatformViewsController::PrerollCompositeEmbeddedView(int view_id) {
EnsureOverlayInitialized(view_id);
composition_frames_[view_id] = (overlays_[view_id]->surface->AcquireFrame(frame_size_));
picture_recorders_[view_id] = std::make_unique<SkPictureRecorder>();
picture_recorders_[view_id]->beginRecording(SkRect::Make(frame_size_));
picture_recorders_[view_id]->getRecordingCanvas()->clear(SK_ColorTRANSPARENT);
composition_order_.push_back(view_id);
}
@ -147,15 +149,14 @@ std::vector<SkCanvas*> FlutterPlatformViewsController::GetCurrentCanvases() {
std::vector<SkCanvas*> canvases;
for (size_t i = 0; i < composition_order_.size(); i++) {
int64_t view_id = composition_order_[i];
canvases.push_back(composition_frames_[view_id]->SkiaCanvas());
canvases.push_back(picture_recorders_[view_id]->getRecordingCanvas());
}
return canvases;
}
SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(
int view_id,
const flow::EmbeddedViewParams& params,
IOSSurface& ios_surface) {
const flow::EmbeddedViewParams& params) {
// TODO(amirh): assert that this is running on the platform thread once we support the iOS
// embedded views thread configuration.
// TODO(amirh): do nothing if the params didn't change.
@ -167,9 +168,7 @@ SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(
UIView* touch_interceptor = touch_interceptors_[view_id].get();
[touch_interceptor setFrame:rect];
SkCanvas* canvas = composition_frames_[view_id]->SkiaCanvas();
canvas->clear(SK_ColorTRANSPARENT);
return canvas;
return picture_recorders_[view_id]->getRecordingCanvas();
}
void FlutterPlatformViewsController::Reset() {
@ -181,16 +180,27 @@ void FlutterPlatformViewsController::Reset() {
overlays_.clear();
composition_order_.clear();
active_composition_order_.clear();
composition_frames_.clear();
picture_recorders_.clear();
}
bool FlutterPlatformViewsController::Present() {
bool FlutterPlatformViewsController::SubmitFrame(bool gl_rendering,
GrContext* gr_context,
std::shared_ptr<IOSGLContext> gl_context) {
bool did_submit = true;
for (size_t i = 0; i < composition_order_.size(); i++) {
int64_t view_id = composition_order_[i];
did_submit &= composition_frames_[view_id]->Submit();
if (gl_rendering) {
EnsureGLOverlayInitialized(view_id, gl_context, gr_context);
} else {
EnsureOverlayInitialized(view_id);
}
auto frame = overlays_[view_id]->surface->AcquireFrame(frame_size_);
SkCanvas* canvas = frame->SkiaCanvas();
canvas->drawPicture(picture_recorders_[view_id]->finishRecordingAsPicture());
canvas->flush();
did_submit &= frame->Submit();
}
composition_frames_.clear();
picture_recorders_.clear();
if (composition_order_ == active_composition_order_) {
composition_order_.clear();
return did_submit;
@ -226,10 +236,28 @@ void FlutterPlatformViewsController::EnsureOverlayInitialized(int64_t overlay_id
overlay_view.frame = flutter_view_.get().bounds;
overlay_view.autoresizingMask =
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
std::unique_ptr<IOSSurface> ios_surface = overlay_view.createSurface;
std::unique_ptr<IOSSurface> ios_surface = overlay_view.createSoftwareSurface;
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface();
overlays_[overlay_id] = std::make_unique<FlutterPlatformViewLayer>(
overlay_view, std::move(ios_surface), std::move(surface));
fml::scoped_nsobject<UIView>(overlay_view), std::move(ios_surface), std::move(surface));
}
void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
int64_t overlay_id,
std::shared_ptr<IOSGLContext> gl_context,
GrContext* gr_context) {
if (overlays_.count(overlay_id) != 0) {
return;
}
FlutterOverlayView* overlay_view = [[FlutterOverlayView alloc] init];
overlay_view.frame = flutter_view_.get().bounds;
overlay_view.autoresizingMask =
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
std::unique_ptr<IOSSurfaceGL> ios_surface =
[overlay_view createGLSurfaceWithContext:std::move(gl_context)];
std::unique_ptr<Surface> surface = ios_surface->CreateSecondaryGPUSurface(gr_context);
overlays_[overlay_id] = std::make_unique<FlutterPlatformViewLayer>(
fml::scoped_nsobject<UIView>(overlay_view), std::move(ios_surface), std::move(surface));
}
} // namespace shell

View File

@ -26,13 +26,14 @@
namespace shell {
class IOSGLContext;
class IOSSurface;
struct FlutterPlatformViewLayer {
FlutterPlatformViewLayer(UIView* overlay_view,
FlutterPlatformViewLayer(fml::scoped_nsobject<UIView> overlay_view,
std::unique_ptr<IOSSurface> ios_surface,
std::unique_ptr<Surface> surface)
: overlay_view([overlay_view retain]),
: overlay_view(std::move(overlay_view)),
ios_surface(std::move(ios_surface)),
surface(std::move(surface)){};
@ -55,14 +56,14 @@ class FlutterPlatformViewsController {
std::vector<SkCanvas*> GetCurrentCanvases();
SkCanvas* CompositeEmbeddedView(int view_id,
const flow::EmbeddedViewParams& params,
IOSSurface& surface);
SkCanvas* CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params);
// Discards all platform views instances and auxiliary resources.
void Reset();
bool Present();
bool SubmitFrame(bool gl_rendering,
GrContext* gr_context,
std::shared_ptr<IOSGLContext> gl_context);
void OnMethodCall(FlutterMethodCall* call, FlutterResult& result);
@ -82,13 +83,16 @@ class FlutterPlatformViewsController {
// The latest composition order that was presented in Present().
std::vector<int64_t> active_composition_order_;
std::map<int64_t, std::unique_ptr<SurfaceFrame>> composition_frames_;
std::map<int64_t, std::unique_ptr<SkPictureRecorder>> picture_recorders_;
void OnCreate(FlutterMethodCall* call, FlutterResult& result);
void OnDispose(FlutterMethodCall* call, FlutterResult& result);
void OnAcceptGesture(FlutterMethodCall* call, FlutterResult& result);
void EnsureOverlayInitialized(int64_t overlay_id);
void EnsureGLOverlayInitialized(int64_t overlay_id,
std::shared_ptr<IOSGLContext> gl_context,
GrContext* gr_context);
FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewsController);
};

View File

@ -13,22 +13,18 @@
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/platform_view.h"
#include "ios_gl_render_target.h"
namespace shell {
class IOSGLContext {
public:
IOSGLContext(fml::scoped_nsobject<CAEAGLLayer> layer);
IOSGLContext();
~IOSGLContext();
bool IsValid() const;
bool PresentRenderBuffer() const;
GLuint framebuffer() const { return framebuffer_; }
bool UpdateStorageSizeIfNecessary();
std::unique_ptr<IOSGLRenderTarget> CreateRenderTarget(
fml::scoped_nsobject<CAEAGLLayer> layer);
bool MakeCurrent();
@ -37,15 +33,9 @@ class IOSGLContext {
sk_sp<SkColorSpace> ColorSpace() const { return color_space_; }
private:
fml::scoped_nsobject<CAEAGLLayer> layer_;
fml::scoped_nsobject<EAGLContext> context_;
fml::scoped_nsobject<EAGLContext> resource_context_;
GLuint framebuffer_;
GLuint colorbuffer_;
GLint storage_size_width_;
GLint storage_size_height_;
sk_sp<SkColorSpace> color_space_;
bool valid_;
FML_DISALLOW_COPY_AND_ASSIGN(IOSGLContext);
};

View File

@ -12,13 +12,7 @@
namespace shell {
IOSGLContext::IOSGLContext(fml::scoped_nsobject<CAEAGLLayer> layer)
: layer_(std::move(layer)),
framebuffer_(GL_NONE),
colorbuffer_(GL_NONE),
storage_size_width_(0),
storage_size_height_(0),
valid_(false) {
IOSGLContext::IOSGLContext() {
context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]);
if (context_ != nullptr) {
resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3
@ -29,35 +23,6 @@ IOSGLContext::IOSGLContext(fml::scoped_nsobject<CAEAGLLayer> layer)
sharegroup:context_.get().sharegroup]);
}
FML_DCHECK(layer_ != nullptr);
FML_DCHECK(context_ != nullptr);
FML_DCHECK(resource_context_ != nullptr);
bool context_current = [EAGLContext setCurrentContext:context_];
FML_DCHECK(context_current);
FML_DCHECK(glGetError() == GL_NO_ERROR);
// Generate the framebuffer
glGenFramebuffers(1, &framebuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
FML_DCHECK(framebuffer_ != GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
// Setup color attachment
glGenRenderbuffers(1, &colorbuffer_);
FML_DCHECK(colorbuffer_ != GL_NONE);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
// TODO:
// iOS displays are more variable than just P3 or sRGB. Reading the display
// gamut just tells us what color space it makes sense to render into. We
@ -78,86 +43,18 @@ IOSGLContext::IOSGLContext(fml::scoped_nsobject<CAEAGLLayer> layer)
break;
}
}
NSString* drawableColorFormat = kEAGLColorFormatRGBA8;
layer_.get().drawableProperties = @{
kEAGLDrawablePropertyColorFormat : drawableColorFormat,
kEAGLDrawablePropertyRetainedBacking : @(NO),
};
valid_ = true;
}
IOSGLContext::~IOSGLContext() {
FML_DCHECK(glGetError() == GL_NO_ERROR);
IOSGLContext::~IOSGLContext() = default;
// Deletes on GL_NONEs are ignored
glDeleteFramebuffers(1, &framebuffer_);
glDeleteRenderbuffers(1, &colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
}
bool IOSGLContext::IsValid() const {
return valid_;
}
bool IOSGLContext::PresentRenderBuffer() const {
const GLenum discards[] = {
GL_DEPTH_ATTACHMENT,
GL_STENCIL_ATTACHMENT,
};
glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof(discards) / sizeof(GLenum), discards);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
return [[EAGLContext currentContext] presentRenderbuffer:GL_RENDERBUFFER];
}
bool IOSGLContext::UpdateStorageSizeIfNecessary() {
const CGSize layer_size = [layer_.get() bounds].size;
const CGFloat contents_scale = layer_.get().contentsScale;
const GLint size_width = layer_size.width * contents_scale;
const GLint size_height = layer_size.height * contents_scale;
if (size_width == storage_size_width_ && size_height == storage_size_height_) {
// Nothing to since the stoage size is already consistent with the layer.
return true;
}
TRACE_EVENT_INSTANT0("flutter", "IOSGLContext::UpdateStorageSizeIfNecessary");
FML_DLOG(INFO) << "Updating render buffer storage size.";
FML_DCHECK(glGetError() == GL_NO_ERROR);
if (![EAGLContext setCurrentContext:context_]) {
return false;
}
FML_DCHECK(glGetError() == GL_NO_ERROR);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
if (![context_.get() renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer_.get()]) {
return false;
}
// Fetch the dimensions of the color buffer whose backing was just updated.
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &storage_size_width_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &storage_size_height_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
FML_DCHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
return true;
std::unique_ptr<IOSGLRenderTarget> IOSGLContext::CreateRenderTarget(
fml::scoped_nsobject<CAEAGLLayer> layer) {
return std::make_unique<IOSGLRenderTarget>(std::move(layer), context_.get(),
resource_context_.get());
}
bool IOSGLContext::MakeCurrent() {
return UpdateStorageSizeIfNecessary() && [EAGLContext setCurrentContext:context_.get()];
return [EAGLContext setCurrentContext:context_.get()];
}
bool IOSGLContext::ResourceMakeCurrent() {

View File

@ -0,0 +1,57 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_RENDER_TARGET_H_
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_RENDER_TARGET_H_
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#import <QuartzCore/CAEAGLLayer.h>
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/platform_view.h"
namespace shell {
class IOSGLRenderTarget {
public:
IOSGLRenderTarget(fml::scoped_nsobject<CAEAGLLayer> layer,
EAGLContext* context,
EAGLContext* resource_context);
~IOSGLRenderTarget();
bool IsValid() const;
bool PresentRenderBuffer() const;
GLuint framebuffer() const { return framebuffer_; }
bool UpdateStorageSizeIfNecessary();
bool MakeCurrent();
bool ResourceMakeCurrent();
sk_sp<SkColorSpace> ColorSpace() const { return color_space_; }
private:
fml::scoped_nsobject<CAEAGLLayer> layer_;
fml::scoped_nsobject<EAGLContext> context_;
fml::scoped_nsobject<EAGLContext> resource_context_;
GLuint framebuffer_;
GLuint colorbuffer_;
GLint storage_size_width_;
GLint storage_size_height_;
sk_sp<SkColorSpace> color_space_;
bool valid_;
FML_DISALLOW_COPY_AND_ASSIGN(IOSGLRenderTarget);
};
} // namespace shell
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_RENDER_TARGET_H_

View File

@ -0,0 +1,140 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/darwin/ios/ios_gl_render_target.h"
#include <UIKit/UIKit.h>
#include "flutter/fml/trace_event.h"
#include "third_party/skia/include/gpu/GrContextOptions.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
namespace shell {
IOSGLRenderTarget::IOSGLRenderTarget(fml::scoped_nsobject<CAEAGLLayer> layer,
EAGLContext* context,
EAGLContext* resource_context)
: layer_(std::move(layer)),
context_([context retain]),
resource_context_([resource_context retain]),
framebuffer_(GL_NONE),
colorbuffer_(GL_NONE),
storage_size_width_(0),
storage_size_height_(0),
valid_(false) {
FML_DCHECK(layer_ != nullptr);
FML_DCHECK(context_ != nullptr);
FML_DCHECK(resource_context_ != nullptr);
bool context_current = [EAGLContext setCurrentContext:context_];
FML_DCHECK(context_current);
FML_DCHECK(glGetError() == GL_NO_ERROR);
// Generate the framebuffer
glGenFramebuffers(1, &framebuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
FML_DCHECK(framebuffer_ != GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
// Setup color attachment
glGenRenderbuffers(1, &colorbuffer_);
FML_DCHECK(colorbuffer_ != GL_NONE);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
NSString* drawableColorFormat = kEAGLColorFormatRGBA8;
layer_.get().drawableProperties = @{
kEAGLDrawablePropertyColorFormat : drawableColorFormat,
kEAGLDrawablePropertyRetainedBacking : @(NO),
};
valid_ = true;
}
IOSGLRenderTarget::~IOSGLRenderTarget() {
FML_DCHECK(glGetError() == GL_NO_ERROR);
// Deletes on GL_NONEs are ignored
glDeleteFramebuffers(1, &framebuffer_);
glDeleteRenderbuffers(1, &colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
}
bool IOSGLRenderTarget::IsValid() const {
return valid_;
}
bool IOSGLRenderTarget::PresentRenderBuffer() const {
const GLenum discards[] = {
GL_DEPTH_ATTACHMENT,
GL_STENCIL_ATTACHMENT,
};
glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof(discards) / sizeof(GLenum), discards);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
return [[EAGLContext currentContext] presentRenderbuffer:GL_RENDERBUFFER];
}
bool IOSGLRenderTarget::UpdateStorageSizeIfNecessary() {
const CGSize layer_size = [layer_.get() bounds].size;
const CGFloat contents_scale = layer_.get().contentsScale;
const GLint size_width = layer_size.width * contents_scale;
const GLint size_height = layer_size.height * contents_scale;
if (size_width == storage_size_width_ && size_height == storage_size_height_) {
// Nothing to since the stoage size is already consistent with the layer.
return true;
}
TRACE_EVENT_INSTANT0("flutter", "IOSGLRenderTarget::UpdateStorageSizeIfNecessary");
FML_DLOG(INFO) << "Updating render buffer storage size.";
FML_DCHECK(glGetError() == GL_NO_ERROR);
if (![EAGLContext setCurrentContext:context_]) {
return false;
}
FML_DCHECK(glGetError() == GL_NO_ERROR);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
if (![context_.get() renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer_.get()]) {
return false;
}
// Fetch the dimensions of the color buffer whose backing was just updated.
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &storage_size_width_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &storage_size_height_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
FML_DCHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
return true;
}
bool IOSGLRenderTarget::MakeCurrent() {
return UpdateStorageSizeIfNecessary() && [EAGLContext setCurrentContext:context_.get()];
}
bool IOSGLRenderTarget::ResourceMakeCurrent() {
return [EAGLContext setCurrentContext:resource_context_.get()];
}
} // namespace shell

View File

@ -9,6 +9,7 @@
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/gpu/gpu_surface_gl.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_context.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_render_target.h"
#include "flutter/shell/platform/darwin/ios/ios_surface.h"
@class CAEAGLLayer;
@ -22,6 +23,8 @@ class IOSSurfaceGL : public IOSSurface,
IOSSurfaceGL(fml::scoped_nsobject<CAEAGLLayer> layer,
FlutterPlatformViewsController* platform_views_controller);
IOSSurfaceGL(fml::scoped_nsobject<CAEAGLLayer> layer, std::shared_ptr<IOSGLContext> context);
~IOSSurfaceGL() override;
bool IsValid() const override;
@ -32,6 +35,8 @@ class IOSSurfaceGL : public IOSSurface,
std::unique_ptr<Surface> CreateGPUSurface() override;
std::unique_ptr<Surface> CreateSecondaryGPUSurface(GrContext* gr_context);
bool GLContextMakeCurrent() override;
bool GLContextClearCurrent() override;
@ -57,8 +62,12 @@ class IOSSurfaceGL : public IOSSurface,
// |flow::ExternalViewEmbedder|
SkCanvas* CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) override;
// |flow::ExternalViewEmbedder|
virtual bool SubmitFrame(GrContext* context) override;
private:
IOSGLContext context_;
std::shared_ptr<IOSGLContext> context_;
std::unique_ptr<IOSGLRenderTarget> render_target_;
FML_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceGL);
};

View File

@ -11,21 +11,30 @@ namespace shell {
IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject<CAEAGLLayer> layer,
FlutterPlatformViewsController* platform_views_controller)
: IOSSurface(platform_views_controller), context_(std::move(layer)) {}
: IOSSurface(platform_views_controller) {
context_ = std::make_shared<IOSGLContext>();
render_target_ = context_->CreateRenderTarget(std::move(layer));
}
IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject<CAEAGLLayer> layer,
std::shared_ptr<IOSGLContext> context)
: IOSSurface(nullptr), context_(context) {
render_target_ = context_->CreateRenderTarget(std::move(layer));
}
IOSSurfaceGL::~IOSSurfaceGL() = default;
bool IOSSurfaceGL::IsValid() const {
return context_.IsValid();
return render_target_->IsValid();
}
bool IOSSurfaceGL::ResourceContextMakeCurrent() {
return IsValid() ? context_.ResourceMakeCurrent() : false;
return render_target_->IsValid() ? context_->ResourceMakeCurrent() : false;
}
void IOSSurfaceGL::UpdateStorageSizeIfNecessary() {
if (IsValid()) {
context_.UpdateStorageSizeIfNecessary();
render_target_->UpdateStorageSizeIfNecessary();
}
}
@ -33,8 +42,12 @@ std::unique_ptr<Surface> IOSSurfaceGL::CreateGPUSurface() {
return std::make_unique<GPUSurfaceGL>(this);
}
std::unique_ptr<Surface> IOSSurfaceGL::CreateSecondaryGPUSurface(GrContext* gr_context) {
return std::make_unique<GPUSurfaceGL>(sk_ref_sp(gr_context), this);
}
intptr_t IOSSurfaceGL::GLContextFBO() const {
return IsValid() ? context_.framebuffer() : GL_NONE;
return IsValid() ? render_target_->framebuffer() : GL_NONE;
}
bool IOSSurfaceGL::UseOffscreenSurface() const {
@ -45,7 +58,10 @@ bool IOSSurfaceGL::UseOffscreenSurface() const {
}
bool IOSSurfaceGL::GLContextMakeCurrent() {
return IsValid() ? context_.MakeCurrent() : false;
if (!IsValid()) {
return false;
}
return render_target_->UpdateStorageSizeIfNecessary() && context_->MakeCurrent();
}
bool IOSSurfaceGL::GLContextClearCurrent() {
@ -55,15 +71,7 @@ bool IOSSurfaceGL::GLContextClearCurrent() {
bool IOSSurfaceGL::GLContextPresent() {
TRACE_EVENT0("flutter", "IOSSurfaceGL::GLContextPresent");
if (!IsValid() || !context_.PresentRenderBuffer()) {
return false;
}
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
if (platform_views_controller == nullptr) {
return true;
}
return platform_views_controller->Present();
return IsValid() && render_target_->PresentRenderBuffer();
}
flow::ExternalViewEmbedder* IOSSurfaceGL::GetExternalViewEmbedder() {
@ -95,7 +103,15 @@ std::vector<SkCanvas*> IOSSurfaceGL::GetCurrentCanvases() {
SkCanvas* IOSSurfaceGL::CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
return platform_views_controller->CompositeEmbeddedView(view_id, params, *this);
return platform_views_controller->CompositeEmbeddedView(view_id, params);
}
bool IOSSurfaceGL::SubmitFrame(GrContext* context) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
if (platform_views_controller == nullptr) {
return true;
}
return platform_views_controller->SubmitFrame(true, std::move(context), context_);
}
} // namespace shell

View File

@ -57,6 +57,9 @@ class IOSSurfaceSoftware final : public IOSSurface,
// |flow::ExternalViewEmbedder|
SkCanvas* CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) override;
// |flow::ExternalViewEmbedder|
virtual bool SubmitFrame(GrContext* context) override;
private:
fml::scoped_nsobject<CALayer> layer_;
sk_sp<SkSurface> sk_surface_;

View File

@ -123,11 +123,7 @@ bool IOSSurfaceSoftware::PresentBackingStore(sk_sp<SkSurface> backing_store) {
layer_.get().contents = reinterpret_cast<id>(static_cast<CGImageRef>(pixmap_image));
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
if (platform_views_controller == nullptr) {
return true;
}
return platform_views_controller->Present();
return true;
}
flow::ExternalViewEmbedder* IOSSurfaceSoftware::GetExternalViewEmbedder() {
@ -160,7 +156,15 @@ SkCanvas* IOSSurfaceSoftware::CompositeEmbeddedView(int view_id,
const flow::EmbeddedViewParams& params) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
return platform_views_controller->CompositeEmbeddedView(view_id, params, *this);
return platform_views_controller->CompositeEmbeddedView(view_id, params);
}
bool IOSSurfaceSoftware::SubmitFrame(GrContext* context) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
if (platform_views_controller == nullptr) {
return true;
}
return platform_views_controller->SubmitFrame(false, nullptr, nullptr);
}
} // namespace shell