diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 80c2e31bd05f0..1aed72b686913 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/ios_gl_context.h b/shell/platform/darwin/ios/ios_gl_context.h index e81954d58a0ef..fae9772df262c 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 b3debd6f64372..2e8f41070c78e 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..ffbd663fa2a07 --- /dev/null +++ b/shell/platform/darwin/ios/ios_gl_render_target.h @@ -0,0 +1,57 @@ +// Copyright 2017 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..03dad3a055bdf --- /dev/null +++ b/shell/platform/darwin/ios/ios_gl_render_target.mm @@ -0,0 +1,140 @@ +// Copyright 2017 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 db52590728145..20e7fc3f8d9a6 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; @@ -59,6 +60,7 @@ class IOSSurfaceGL : public IOSSurface, private: IOSGLContext 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 1def88423df32..305af261e5047 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -11,21 +11,23 @@ IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, FlutterPlatformViewsController* platform_views_controller) - : IOSSurface(platform_views_controller), context_(std::move(layer)) {} + : IOSSurface(platform_views_controller), 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(); } } @@ -34,7 +36,7 @@ } intptr_t IOSSurfaceGL::GLContextFBO() const { - return IsValid() ? context_.framebuffer() : GL_NONE; + return IsValid() ? render_target_->framebuffer() : GL_NONE; } bool IOSSurfaceGL::UseOffscreenSurface() const { @@ -45,7 +47,10 @@ } bool IOSSurfaceGL::GLContextMakeCurrent() { - return IsValid() ? context_.MakeCurrent() : false; + if (!IsValid()) { + return false; + } + return render_target_->UpdateStorageSizeIfNecessary() && context_.MakeCurrent(); } bool IOSSurfaceGL::GLContextClearCurrent() { @@ -55,7 +60,7 @@ bool IOSSurfaceGL::GLContextPresent() { TRACE_EVENT0("flutter", "IOSSurfaceGL::GLContextPresent"); - if (!IsValid() || !context_.PresentRenderBuffer()) { + if (!IsValid() || !render_target_->PresentRenderBuffer()) { return false; }