Skip to content

Commit

Permalink
Refactor IOSGLContext to support multiple render targets.
Browse files Browse the repository at this point in the history
Moved the frame buffer specific logic from IOSGLContext to IOSGLRenderTarget.
  • Loading branch information
Amir Hardon committed Nov 6, 2018
1 parent e5f752c commit 08d5767
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 131 deletions.
2 changes: 2 additions & 0 deletions shell/platform/darwin/ios/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
18 changes: 4 additions & 14 deletions shell/platform/darwin/ios/ios_gl_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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);
};
Expand Down
117 changes: 7 additions & 110 deletions shell/platform/darwin/ios/ios_gl_context.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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<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() {
Expand Down
57 changes: 57 additions & 0 deletions shell/platform/darwin/ios/ios_gl_render_target.h
Original file line number Diff line number Diff line change
@@ -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 <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_
140 changes: 140 additions & 0 deletions shell/platform/darwin/ios/ios_gl_render_target.mm
Original file line number Diff line number Diff line change
@@ -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 <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
Loading

0 comments on commit 08d5767

Please sign in to comment.