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