From 099b4eeada852df67ed5d36a638762de3a8fa079 Mon Sep 17 00:00:00 2001 From: Amir Hardon Date: Thu, 8 Nov 2018 19:52:43 -0800 Subject: [PATCH] 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. --- ci/licenses_golden/licenses_flutter | 38 ++++- flow/embedded_views.h | 2 + shell/common/rasterizer.cc | 3 + shell/gpu/gpu_surface_gl.cc | 22 ++- shell/gpu/gpu_surface_gl.h | 4 + shell/platform/darwin/ios/BUILD.gn | 2 + .../ios/framework/Source/FlutterOverlayView.h | 6 +- .../framework/Source/FlutterOverlayView.mm | 17 ++- .../framework/Source/FlutterPlatformViews.mm | 56 +++++-- .../Source/FlutterPlatformViews_Internal.h | 18 ++- shell/platform/darwin/ios/ios_gl_context.h | 18 +-- shell/platform/darwin/ios/ios_gl_context.mm | 117 +-------------- .../darwin/ios/ios_gl_render_target.h | 57 +++++++ .../darwin/ios/ios_gl_render_target.mm | 140 ++++++++++++++++++ shell/platform/darwin/ios/ios_surface_gl.h | 11 +- shell/platform/darwin/ios/ios_surface_gl.mm | 48 ++++-- .../darwin/ios/ios_surface_software.h | 3 + .../darwin/ios/ios_surface_software.mm | 16 +- 18 files changed, 399 insertions(+), 179 deletions(-) create mode 100644 shell/platform/darwin/ios/ios_gl_render_target.h create mode 100644 shell/platform/darwin/ios/ios_gl_render_target.mm diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b4e6ed14db6..125b7451830 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -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 diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 983e0914487..e98c98a6e1c 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -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); diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index b5be5e49e51..29d534b2a44 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -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; } diff --git a/shell/gpu/gpu_surface_gl.cc b/shell/gpu/gpu_surface_gl.cc index 91d00444036..5978584f74c 100644 --- a/shell/gpu/gpu_surface_gl.cc +++ b/shell/gpu/gpu_surface_gl.cc @@ -89,6 +89,24 @@ GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate) delegate_->GLContextClearCurrent(); valid_ = true; + context_owner_ = true; +} + +GPUSurfaceGL::GPUSurfaceGL(sk_sp 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(); diff --git a/shell/gpu/gpu_surface_gl.h b/shell/gpu/gpu_surface_gl.h index 69296046164..d00345d2c34 100644 --- a/shell/gpu/gpu_surface_gl.h +++ b/shell/gpu/gpu_surface_gl.h @@ -49,6 +49,9 @@ class GPUSurfaceGL : public Surface { public: GPUSurfaceGL(GPUSurfaceGLDelegate* delegate); + // Creates a new GL surface reusing an existing GrContext. + GPUSurfaceGL(sk_sp gr_context, GPUSurfaceGLDelegate* delegate); + ~GPUSurfaceGL() override; // |shell::Surface| @@ -74,6 +77,7 @@ class GPUSurfaceGL : public Surface { sk_sp offscreen_surface_; bool valid_ = false; fml::WeakPtrFactory weak_factory_; + bool context_owner_; bool CreateOrUpdateSurfaces(const SkISize& size); diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index a11cf1cd33d..235dfa054fa 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -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", diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h index b104902689a..a344179057b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h @@ -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)createSurface; +- (std::unique_ptr)createSoftwareSurface; +- (std::unique_ptr)createGLSurfaceWithContext: + (std::shared_ptr)gl_context; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm index 81c4e815a44..6b7d8bbf093 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -63,14 +63,15 @@ #endif // TARGET_IPHONE_SIMULATOR } -- (std::unique_ptr)createSurface { - if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { - // TODO(amirh): create a GL surface. - return nullptr; - } else { - fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); - return std::make_unique(std::move(layer), nullptr); - } +- (std::unique_ptr)createSoftwareSurface { + fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); + return std::make_unique(std::move(layer), nullptr); +} + +- (std::unique_ptr)createGLSurfaceWithContext: + (std::shared_ptr)gl_context { + fml::scoped_nsobject eagl_layer(reinterpret_cast([self.layer retain])); + return std::make_unique(eagl_layer, std::move(gl_context)); } // TODO(amirh): implement drawLayer to suppoer snapshotting. diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index f0b800737aa..01c7e63126c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -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 #include @@ -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(); + 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 FlutterPlatformViewsController::GetCurrentCanvases() { std::vector 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 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 ios_surface = overlay_view.createSurface; + std::unique_ptr ios_surface = overlay_view.createSoftwareSurface; std::unique_ptr surface = ios_surface->CreateGPUSurface(); overlays_[overlay_id] = std::make_unique( - overlay_view, std::move(ios_surface), std::move(surface)); + fml::scoped_nsobject(overlay_view), std::move(ios_surface), std::move(surface)); +} + +void FlutterPlatformViewsController::EnsureGLOverlayInitialized( + int64_t overlay_id, + std::shared_ptr 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 ios_surface = + [overlay_view createGLSurfaceWithContext:std::move(gl_context)]; + std::unique_ptr surface = ios_surface->CreateSecondaryGPUSurface(gr_context); + overlays_[overlay_id] = std::make_unique( + fml::scoped_nsobject(overlay_view), std::move(ios_surface), std::move(surface)); } } // namespace shell diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 2e40d9c8617..f6fa9c4a02a 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -26,13 +26,14 @@ namespace shell { +class IOSGLContext; class IOSSurface; struct FlutterPlatformViewLayer { - FlutterPlatformViewLayer(UIView* overlay_view, + FlutterPlatformViewLayer(fml::scoped_nsobject overlay_view, std::unique_ptr ios_surface, std::unique_ptr 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 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 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 active_composition_order_; - std::map> composition_frames_; + std::map> 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 gl_context, + GrContext* gr_context); FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewsController); }; diff --git a/shell/platform/darwin/ios/ios_gl_context.h b/shell/platform/darwin/ios/ios_gl_context.h index e7a3f558f82..08778d21319 100644 --- a/shell/platform/darwin/ios/ios_gl_context.h +++ b/shell/platform/darwin/ios/ios_gl_context.h @@ -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 layer); + IOSGLContext(); ~IOSGLContext(); - bool IsValid() const; - - bool PresentRenderBuffer() const; - - GLuint framebuffer() const { return framebuffer_; } - - bool UpdateStorageSizeIfNecessary(); + std::unique_ptr CreateRenderTarget( + fml::scoped_nsobject layer); bool MakeCurrent(); @@ -37,15 +33,9 @@ class IOSGLContext { sk_sp ColorSpace() const { return color_space_; } private: - fml::scoped_nsobject layer_; fml::scoped_nsobject context_; fml::scoped_nsobject resource_context_; - GLuint framebuffer_; - GLuint colorbuffer_; - GLint storage_size_width_; - GLint storage_size_height_; sk_sp color_space_; - bool valid_; FML_DISALLOW_COPY_AND_ASSIGN(IOSGLContext); }; diff --git a/shell/platform/darwin/ios/ios_gl_context.mm b/shell/platform/darwin/ios/ios_gl_context.mm index 2cd3a8f4c90..c8819a78b83 100644 --- a/shell/platform/darwin/ios/ios_gl_context.mm +++ b/shell/platform/darwin/ios/ios_gl_context.mm @@ -12,13 +12,7 @@ namespace shell { -IOSGLContext::IOSGLContext(fml::scoped_nsobject 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 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 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 IOSGLContext::CreateRenderTarget( + fml::scoped_nsobject layer) { + return std::make_unique(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() { diff --git a/shell/platform/darwin/ios/ios_gl_render_target.h b/shell/platform/darwin/ios/ios_gl_render_target.h new file mode 100644 index 00000000000..9b9639f7f99 --- /dev/null +++ b/shell/platform/darwin/ios/ios_gl_render_target.h @@ -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 +#import +#import +#import + +#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 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 ColorSpace() const { return color_space_; } + + private: + fml::scoped_nsobject layer_; + fml::scoped_nsobject context_; + fml::scoped_nsobject resource_context_; + GLuint framebuffer_; + GLuint colorbuffer_; + GLint storage_size_width_; + GLint storage_size_height_; + sk_sp color_space_; + bool valid_; + + FML_DISALLOW_COPY_AND_ASSIGN(IOSGLRenderTarget); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_RENDER_TARGET_H_ diff --git a/shell/platform/darwin/ios/ios_gl_render_target.mm b/shell/platform/darwin/ios/ios_gl_render_target.mm new file mode 100644 index 00000000000..ffeee8f30bb --- /dev/null +++ b/shell/platform/darwin/ios/ios_gl_render_target.mm @@ -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 + +#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 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 diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index 066e5fdcaf6..f0e898a1bb0 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -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 layer, FlutterPlatformViewsController* platform_views_controller); + IOSSurfaceGL(fml::scoped_nsobject layer, std::shared_ptr context); + ~IOSSurfaceGL() override; bool IsValid() const override; @@ -32,6 +35,8 @@ class IOSSurfaceGL : public IOSSurface, std::unique_ptr CreateGPUSurface() override; + std::unique_ptr 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 context_; + std::unique_ptr render_target_; FML_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceGL); }; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index 6f0d7648051..3a5315a2617 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -11,21 +11,30 @@ namespace shell { IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, FlutterPlatformViewsController* platform_views_controller) - : IOSSurface(platform_views_controller), context_(std::move(layer)) {} + : IOSSurface(platform_views_controller) { + context_ = std::make_shared(); + render_target_ = context_->CreateRenderTarget(std::move(layer)); +} + +IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, + std::shared_ptr 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 IOSSurfaceGL::CreateGPUSurface() { return std::make_unique(this); } +std::unique_ptr IOSSurfaceGL::CreateSecondaryGPUSurface(GrContext* gr_context) { + return std::make_unique(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 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 diff --git a/shell/platform/darwin/ios/ios_surface_software.h b/shell/platform/darwin/ios/ios_surface_software.h index 068d9f13225..1642497f27d 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -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 layer_; sk_sp sk_surface_; diff --git a/shell/platform/darwin/ios/ios_surface_software.mm b/shell/platform/darwin/ios/ios_surface_software.mm index a5ca5357372..3252b3e1cd4 100644 --- a/shell/platform/darwin/ios/ios_surface_software.mm +++ b/shell/platform/darwin/ios/ios_surface_software.mm @@ -123,11 +123,7 @@ bool IOSSurfaceSoftware::PresentBackingStore(sk_sp backing_store) { layer_.get().contents = reinterpret_cast(static_cast(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