blob: 28fb24263b262cab7ff4b16831b726b35ed0c253 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "flutter/shell/platform/darwin/ios/ios_render_target_gl.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 flutter {
IOSRenderTargetGL::IOSRenderTargetGL(fml::scoped_nsobject<CAEAGLLayer> layer,
fml::scoped_nsobject<EAGLContext> context)
: layer_(std::move(layer)), context_(context) {
FML_DCHECK(layer_ != nullptr);
FML_DCHECK(context_ != nullptr);
if (@available(iOS 9.0, *)) {
[layer_ setPresentsWithTransaction:YES];
}
auto context_switch = GLContextSwitch(std::make_unique<IOSSwitchableGLContext>(context_.get()));
bool context_current = context_switch.GetResult();
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;
}
IOSRenderTargetGL::~IOSRenderTargetGL() {
auto context_switch = GLContextSwitch(std::make_unique<IOSSwitchableGLContext>(context_.get()));
FML_DCHECK(glGetError() == GL_NO_ERROR);
// Deletes on GL_NONEs are ignored
glDeleteFramebuffers(1, &framebuffer_);
glDeleteRenderbuffers(1, &colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
}
// |IOSRenderTarget|
bool IOSRenderTargetGL::IsValid() const {
return valid_;
}
// |IOSRenderTarget|
intptr_t IOSRenderTargetGL::GetFramebuffer() const {
return framebuffer_;
}
// |IOSRenderTarget|
bool IOSRenderTargetGL::PresentRenderBuffer() const {
const GLenum discards[] = {
GL_DEPTH_ATTACHMENT,
GL_STENCIL_ATTACHMENT,
};
glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof(discards) / sizeof(GLenum), discards);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
auto current_context = [EAGLContext currentContext];
FML_DCHECK(current_context != nullptr);
return [current_context presentRenderbuffer:GL_RENDERBUFFER];
}
// |IOSRenderTarget|
bool IOSRenderTargetGL::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 do since the storage size is already consistent with the layer.
return true;
}
TRACE_EVENT_INSTANT0("flutter", "IOSRenderTargetGL::UpdateStorageSizeIfNecessary");
FML_DLOG(INFO) << "Updating render buffer storage size.";
FML_DCHECK(glGetError() == GL_NO_ERROR);
auto context_switch = GLContextSwitch(std::make_unique<IOSSwitchableGLContext>(context_.get()));
if (!context_switch.GetResult()) {
return false;
}
FML_DCHECK(glGetError() == GL_NO_ERROR);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
auto current_context = [EAGLContext currentContext];
if (![current_context 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;
}
} // namespace flutter