Flutter Engine
gpu_surface_gl.cc
Go to the documentation of this file.
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/gpu/gpu_surface_gl.h"
6 
7 #include "flutter/common/graphics/persistent_cache.h"
8 #include "flutter/fml/base32.h"
9 #include "flutter/fml/logging.h"
10 #include "flutter/fml/size.h"
11 #include "flutter/fml/trace_event.h"
12 #include "flutter/shell/common/context_options.h"
13 #include "third_party/skia/include/core/SkColorFilter.h"
14 #include "third_party/skia/include/core/SkSurface.h"
15 #include "third_party/skia/include/gpu/GrBackendSurface.h"
16 #include "third_party/skia/include/gpu/GrContextOptions.h"
17 
18 // These are common defines present on all OpenGL headers. However, we don't
19 // want to perform GL header reasolution on each platform we support. So just
20 // define these upfront. It is unlikely we will need more. But, if we do, we can
21 // add the same here.
22 #define GPU_GL_RGBA8 0x8058
23 #define GPU_GL_RGBA4 0x8056
24 #define GPU_GL_RGB565 0x8D62
25 
26 namespace flutter {
27 
28 // Default maximum number of budgeted resources in the cache.
29 static const int kGrCacheMaxCount = 8192;
30 
31 // Default maximum number of bytes of GPU memory of budgeted resources in the
32 // cache.
33 // The shell will dynamically increase or decrease this cache based on the
34 // viewport size, unless a user has specifically requested a size on the Skia
35 // system channel.
36 static const size_t kGrCacheMaxByteSize = 24 * (1 << 20);
37 
38 sk_sp<GrDirectContext> GPUSurfaceGL::MakeGLContext(
39  GPUSurfaceGLDelegate* delegate) {
40  auto context_switch = delegate->GLContextMakeCurrent();
41  if (!context_switch->GetResult()) {
42  FML_LOG(ERROR)
43  << "Could not make the context current to set up the Gr context.";
44  return nullptr;
45  }
46 
47  const auto options =
49 
50  auto context = GrDirectContext::MakeGL(delegate->GetGLInterface(), options);
51 
52  if (!context) {
53  FML_LOG(ERROR) << "Failed to set up Skia Gr context.";
54  return nullptr;
55  }
56 
57  context->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);
58 
60 
61  return context;
62 }
63 
65  bool render_to_surface)
66  : GPUSurfaceGL(MakeGLContext(delegate), delegate, render_to_surface) {
67  context_owner_ = true;
68 }
69 
70 GPUSurfaceGL::GPUSurfaceGL(sk_sp<GrDirectContext> gr_context,
71  GPUSurfaceGLDelegate* delegate,
72  bool render_to_surface)
73  : delegate_(delegate),
74  context_(gr_context),
75  context_owner_(false),
76  render_to_surface_(render_to_surface),
77  weak_factory_(this) {
78  auto context_switch = delegate_->GLContextMakeCurrent();
79  if (!context_switch->GetResult()) {
80  FML_LOG(ERROR)
81  << "Could not make the context current to set up the Gr context.";
82  return;
83  }
84 
85  delegate_->GLContextClearCurrent();
86 
87  valid_ = gr_context != nullptr;
88 }
89 
91  if (!valid_) {
92  return;
93  }
94  auto context_switch = delegate_->GLContextMakeCurrent();
95  if (!context_switch->GetResult()) {
96  FML_LOG(ERROR) << "Could not make the context current to destroy the "
97  "GrDirectContext resources.";
98  return;
99  }
100 
101  onscreen_surface_ = nullptr;
102  fbo_id_ = 0;
103  if (context_owner_) {
104  context_->releaseResourcesAndAbandonContext();
105  }
106  context_ = nullptr;
107 
108  delegate_->GLContextClearCurrent();
109 }
110 
111 // |Surface|
113  return valid_;
114 }
115 
116 static SkColorType FirstSupportedColorType(GrDirectContext* context,
117  GrGLenum* format) {
118 #define RETURN_IF_RENDERABLE(x, y) \
119  if (context->colorTypeSupportedAsSurface((x))) { \
120  *format = (y); \
121  return (x); \
122  }
123  RETURN_IF_RENDERABLE(kRGBA_8888_SkColorType, GPU_GL_RGBA8);
124  RETURN_IF_RENDERABLE(kARGB_4444_SkColorType, GPU_GL_RGBA4);
125  RETURN_IF_RENDERABLE(kRGB_565_SkColorType, GPU_GL_RGB565);
126  return kUnknown_SkColorType;
127 }
128 
129 static sk_sp<SkSurface> WrapOnscreenSurface(GrDirectContext* context,
130  const SkISize& size,
131  intptr_t fbo) {
132  GrGLenum format;
133  const SkColorType color_type = FirstSupportedColorType(context, &format);
134 
135  GrGLFramebufferInfo framebuffer_info = {};
136  framebuffer_info.fFBOID = static_cast<GrGLuint>(fbo);
137  framebuffer_info.fFormat = format;
138 
139  GrBackendRenderTarget render_target(size.width(), // width
140  size.height(), // height
141  0, // sample count
142  0, // stencil bits (TODO)
143  framebuffer_info // framebuffer info
144  );
145 
146  sk_sp<SkColorSpace> colorspace = SkColorSpace::MakeSRGB();
147  SkSurfaceProps surface_props(0, kUnknown_SkPixelGeometry);
148 
149  return SkSurface::MakeFromBackendRenderTarget(
150  context, // Gr context
151  render_target, // render target
152  GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin, // origin
153  color_type, // color type
154  colorspace, // colorspace
155  &surface_props // surface properties
156  );
157 }
158 
159 bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
160  if (onscreen_surface_ != nullptr &&
161  size == SkISize::Make(onscreen_surface_->width(),
162  onscreen_surface_->height())) {
163  // Surface size appears unchanged. So bail.
164  return true;
165  }
166 
167  // We need to do some updates.
168  TRACE_EVENT0("flutter", "UpdateSurfacesSize");
169 
170  // Either way, we need to get rid of previous surface.
171  onscreen_surface_ = nullptr;
172  fbo_id_ = 0;
173 
174  if (size.isEmpty()) {
175  FML_LOG(ERROR) << "Cannot create surfaces of empty size.";
176  return false;
177  }
178 
179  sk_sp<SkSurface> onscreen_surface;
180 
181  GLFrameInfo frame_info = {static_cast<uint32_t>(size.width()),
182  static_cast<uint32_t>(size.height())};
183  const uint32_t fbo_id = delegate_->GLContextFBO(frame_info);
184  onscreen_surface = WrapOnscreenSurface(context_.get(), // GL context
185  size, // root surface size
186  fbo_id // window FBO ID
187  );
188 
189  if (onscreen_surface == nullptr) {
190  // If the onscreen surface could not be wrapped. There is absolutely no
191  // point in moving forward.
192  FML_LOG(ERROR) << "Could not wrap onscreen surface.";
193  return false;
194  }
195 
196  onscreen_surface_ = std::move(onscreen_surface);
197  fbo_id_ = fbo_id;
198 
199  return true;
200 }
201 
202 // |Surface|
204  return delegate_->GLContextSurfaceTransformation();
205 }
206 
207 // |Surface|
208 std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
209  if (delegate_ == nullptr) {
210  return nullptr;
211  }
212  auto context_switch = delegate_->GLContextMakeCurrent();
213  if (!context_switch->GetResult()) {
214  FML_LOG(ERROR)
215  << "Could not make the context current to acquire the frame.";
216  return nullptr;
217  }
218 
219  // TODO(38466): Refactor GPU surface APIs take into account the fact that an
220  // external view embedder may want to render to the root surface.
221  if (!render_to_surface_) {
222  return std::make_unique<SurfaceFrame>(
223  nullptr, true, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
224  return true;
225  });
226  }
227 
228  const auto root_surface_transformation = GetRootTransformation();
229 
230  sk_sp<SkSurface> surface =
231  AcquireRenderSurface(size, root_surface_transformation);
232 
233  if (surface == nullptr) {
234  return nullptr;
235  }
236 
237  surface->getCanvas()->setMatrix(root_surface_transformation);
238  SurfaceFrame::SubmitCallback submit_callback =
239  [weak = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame,
240  SkCanvas* canvas) {
241  return weak ? weak->PresentSurface(canvas) : false;
242  };
243 
244  return std::make_unique<SurfaceFrame>(
245  surface, delegate_->SurfaceSupportsReadback(), submit_callback,
246  std::move(context_switch));
247 }
248 
249 bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
250  if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) {
251  return false;
252  }
253 
254  {
255  TRACE_EVENT0("flutter", "SkCanvas::Flush");
256  onscreen_surface_->getCanvas()->flush();
257  }
258 
259  if (!delegate_->GLContextPresent(fbo_id_)) {
260  return false;
261  }
262 
263  if (delegate_->GLContextFBOResetAfterPresent()) {
264  auto current_size =
265  SkISize::Make(onscreen_surface_->width(), onscreen_surface_->height());
266 
267  GLFrameInfo frame_info = {static_cast<uint32_t>(current_size.width()),
268  static_cast<uint32_t>(current_size.height())};
269 
270  // The FBO has changed, ask the delegate for the new FBO and do a surface
271  // re-wrap.
272  const uint32_t fbo_id = delegate_->GLContextFBO(frame_info);
273  auto new_onscreen_surface =
274  WrapOnscreenSurface(context_.get(), // GL context
275  current_size, // root surface size
276  fbo_id // window FBO ID
277  );
278 
279  if (!new_onscreen_surface) {
280  return false;
281  }
282 
283  onscreen_surface_ = std::move(new_onscreen_surface);
284  fbo_id_ = fbo_id;
285  }
286 
287  return true;
288 }
289 
290 sk_sp<SkSurface> GPUSurfaceGL::AcquireRenderSurface(
291  const SkISize& untransformed_size,
292  const SkMatrix& root_surface_transformation) {
293  const auto transformed_rect = root_surface_transformation.mapRect(
294  SkRect::MakeWH(untransformed_size.width(), untransformed_size.height()));
295 
296  const auto transformed_size =
297  SkISize::Make(transformed_rect.width(), transformed_rect.height());
298 
299  if (!CreateOrUpdateSurfaces(transformed_size)) {
300  return nullptr;
301  }
302 
303  return onscreen_surface_;
304 }
305 
306 // |Surface|
307 GrDirectContext* GPUSurfaceGL::GetContext() {
308  return context_.get();
309 }
310 
311 // |Surface|
312 std::unique_ptr<GLContextResult> GPUSurfaceGL::MakeRenderContextCurrent() {
313  return delegate_->GLContextMakeCurrent();
314 }
315 
316 // |Surface|
318  return delegate_->GLContextClearCurrent();
319 }
320 
321 // |Surface|
323  return delegate_->AllowsDrawingWhenGpuDisabled();
324 }
325 
326 } // namespace flutter
std::function< bool(const SurfaceFrame &surface_frame, SkCanvas *canvas)> SubmitCallback
Definition: surface_frame.h:22
#define RETURN_IF_RENDERABLE(x, y)
static const size_t kGrCacheMaxByteSize
virtual SkMatrix GLContextSurfaceTransformation() const
static sk_sp< SkSurface > WrapOnscreenSurface(GrDirectContext *context, const SkISize &size, intptr_t fbo)
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:90
size_t PrecompileKnownSkSLs(GrDirectContext *context) const
Precompile SkSLs packaged with the application and gathered during previous runs in the given context...
virtual bool GLContextFBOResetAfterPresent() const
GrDirectContext * GetContext() override
uint32_t color_type
virtual bool GLContextPresent(uint32_t fbo_id)=0
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
uint32_t uint32_t * format
#define FML_LOG(severity)
Definition: logging.h:65
static const int kGrCacheMaxCount
#define GPU_GL_RGBA4
virtual bool SurfaceSupportsReadback() const
SkMatrix GetRootTransformation() const override
virtual bool AllowsDrawingWhenGpuDisabled() const
virtual bool GLContextClearCurrent()=0
virtual intptr_t GLContextFBO(GLFrameInfo frame_info) const =0
#define GPU_GL_RGB565
bool AllowsDrawingWhenGpuDisabled() const override
static sk_sp< GrDirectContext > MakeGLContext(GPUSurfaceGLDelegate *delegate)
static PersistentCache * GetCacheForProcess()
static SkColorType FirstSupportedColorType(GrDirectContext *context, GrGLenum *format)
The context is used to render to a texture or renderbuffer.
#define GPU_GL_RGBA8
bool ClearRenderContext() override
GPUSurfaceGL(GPUSurfaceGLDelegate *delegate, bool render_to_surface)
virtual std::unique_ptr< GLContextResult > GLContextMakeCurrent()=0
std::unique_ptr< GLContextResult > MakeRenderContextCurrent() override
std::unique_ptr< SurfaceFrame > AcquireFrame(const SkISize &size) override
GrContextOptions MakeDefaultContextOptions(ContextType type, std::optional< GrBackendApi > api)
Initializes GrContextOptions with values suitable for Flutter. The options can be further tweaked bef...
virtual sk_sp< const GrGLInterface > GetGLInterface() const
bool IsValid() override