1// Copyright 2013 The Flutter Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "flutter/shell/platform/darwin/ios/ios_gl_render_target.h" 6 7#include <UIKit/UIKit.h> 8 9#include "flutter/fml/trace_event.h" 10#include "third_party/skia/include/gpu/GrContextOptions.h" 11#include "third_party/skia/include/gpu/gl/GrGLInterface.h" 12 13namespace flutter { 14 15IOSGLRenderTarget::IOSGLRenderTarget(fml::scoped_nsobject<CAEAGLLayer> layer, 16 EAGLContext* context, 17 EAGLContext* resource_context) 18 : layer_(std::move(layer)), 19 context_([context retain]), 20 resource_context_([resource_context retain]), 21 framebuffer_(GL_NONE), 22 colorbuffer_(GL_NONE), 23 storage_size_width_(0), 24 storage_size_height_(0), 25 valid_(false) { 26 FML_DCHECK(layer_ != nullptr); 27 FML_DCHECK(context_ != nullptr); 28 FML_DCHECK(resource_context_ != nullptr); 29 30 bool context_current = [EAGLContext setCurrentContext:context_]; 31 32 FML_DCHECK(context_current); 33 FML_DCHECK(glGetError() == GL_NO_ERROR); 34 35 // Generate the framebuffer 36 37 glGenFramebuffers(1, &framebuffer_); 38 FML_DCHECK(glGetError() == GL_NO_ERROR); 39 FML_DCHECK(framebuffer_ != GL_NONE); 40 41 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_); 42 FML_DCHECK(glGetError() == GL_NO_ERROR); 43 44 // Setup color attachment 45 46 glGenRenderbuffers(1, &colorbuffer_); 47 FML_DCHECK(colorbuffer_ != GL_NONE); 48 49 glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_); 50 FML_DCHECK(glGetError() == GL_NO_ERROR); 51 52 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer_); 53 FML_DCHECK(glGetError() == GL_NO_ERROR); 54 55 NSString* drawableColorFormat = kEAGLColorFormatRGBA8; 56 layer_.get().drawableProperties = @{ 57 kEAGLDrawablePropertyColorFormat : drawableColorFormat, 58 kEAGLDrawablePropertyRetainedBacking : @(NO), 59 }; 60 61 valid_ = true; 62} 63 64IOSGLRenderTarget::~IOSGLRenderTarget() { 65 EAGLContext* context = EAGLContext.currentContext; 66 [EAGLContext setCurrentContext:context_]; 67 FML_DCHECK(glGetError() == GL_NO_ERROR); 68 69 // Deletes on GL_NONEs are ignored 70 glDeleteFramebuffers(1, &framebuffer_); 71 glDeleteRenderbuffers(1, &colorbuffer_); 72 73 FML_DCHECK(glGetError() == GL_NO_ERROR); 74 [EAGLContext setCurrentContext:context]; 75} 76 77bool IOSGLRenderTarget::IsValid() const { 78 return valid_; 79} 80 81bool IOSGLRenderTarget::PresentRenderBuffer() const { 82 const GLenum discards[] = { 83 GL_DEPTH_ATTACHMENT, 84 GL_STENCIL_ATTACHMENT, 85 }; 86 87 glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof(discards) / sizeof(GLenum), discards); 88 89 glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_); 90 return [[EAGLContext currentContext] presentRenderbuffer:GL_RENDERBUFFER]; 91} 92 93bool IOSGLRenderTarget::UpdateStorageSizeIfNecessary() { 94 const CGSize layer_size = [layer_.get() bounds].size; 95 const CGFloat contents_scale = layer_.get().contentsScale; 96 const GLint size_width = layer_size.width * contents_scale; 97 const GLint size_height = layer_size.height * contents_scale; 98 99 if (size_width == storage_size_width_ && size_height == storage_size_height_) { 100 // Nothing to since the stoage size is already consistent with the layer. 101 return true; 102 } 103 TRACE_EVENT_INSTANT0("flutter", "IOSGLRenderTarget::UpdateStorageSizeIfNecessary"); 104 FML_DLOG(INFO) << "Updating render buffer storage size."; 105 106 FML_DCHECK(glGetError() == GL_NO_ERROR); 107 108 if (![EAGLContext setCurrentContext:context_]) { 109 return false; 110 } 111 112 FML_DCHECK(glGetError() == GL_NO_ERROR); 113 114 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_); 115 116 glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_); 117 FML_DCHECK(glGetError() == GL_NO_ERROR); 118 119 if (![context_.get() renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer_.get()]) { 120 return false; 121 } 122 123 // Fetch the dimensions of the color buffer whose backing was just updated. 124 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &storage_size_width_); 125 FML_DCHECK(glGetError() == GL_NO_ERROR); 126 127 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &storage_size_height_); 128 FML_DCHECK(glGetError() == GL_NO_ERROR); 129 130 FML_DCHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 131 132 return true; 133} 134 135bool IOSGLRenderTarget::MakeCurrent() { 136 return UpdateStorageSizeIfNecessary() && [EAGLContext setCurrentContext:context_.get()]; 137} 138 139bool IOSGLRenderTarget::ResourceMakeCurrent() { 140 return [EAGLContext setCurrentContext:resource_context_.get()]; 141} 142 143} // namespace flutter 144