diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b4e6ed14db649..125b745183048 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 983e091448762..e98c98a6e1cc7 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 b5be5e49e51eb..29d534b2a4430 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 91d004440366c..5978584f74cea 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 6929604616436..d00345d2c3477 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 a11cf1cd33db5..235dfa054facd 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 b104902689aff..a344179057bab 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 81c4e815a4459..6b7d8bbf093e5 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -63,14 +63,15 @@ + (Class)layerClass { #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 f0b800737aa42..01c7e63126c7e 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::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 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 @@ 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 @@ 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 @@ 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 2e40d9c861743..f6fa9c4a02a97 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 e7a3f558f8285..08778d21319a7 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 2cd3a8f4c90bd..c8819a78b8372 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 @@ 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 @@ break; } } - - NSString* drawableColorFormat = kEAGLColorFormatRGBA8; - layer_.get().drawableProperties = @{ - kEAGLDrawablePropertyColorFormat : drawableColorFormat, - kEAGLDrawablePropertyRetainedBacking : @(NO), - }; - - valid_ = true; -} - -IOSGLContext::~IOSGLContext() { - 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 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); +IOSGLContext::~IOSGLContext() = default; - 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 0000000000000..9b9639f7f997b --- /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 0000000000000..ffeee8f30bb79 --- /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 066e5fdcaf6ce..f0e898a1bb00e 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 6f0d7648051af..3a5315a261713 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -11,21 +11,30 @@ 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 @@ 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::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::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 @@ 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 068d9f132257a..1642497f27dfd 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 a5ca5357372d9..3252b3e1cd418 100644 --- a/shell/platform/darwin/ios/ios_surface_software.mm +++ b/shell/platform/darwin/ios/ios_surface_software.mm @@ -123,11 +123,7 @@ 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 @@ 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