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