• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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