• 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 #ifndef SHELL_COMMON_RASTERIZER_H_
6 #define SHELL_COMMON_RASTERIZER_H_
7 
8 #include <memory>
9 #include <optional>
10 
11 #include "flutter/common/settings.h"
12 #include "flutter/common/task_runners.h"
13 #include "flutter/flow/compositor_context.h"
14 #include "flutter/flow/layers/layer_tree.h"
15 #include "flutter/fml/closure.h"
16 #include "flutter/fml/gpu_thread_merger.h"
17 #include "flutter/fml/memory/weak_ptr.h"
18 #include "flutter/fml/synchronization/waitable_event.h"
19 #include "flutter/shell/common/pipeline.h"
20 #include "flutter/shell/common/surface.h"
21 
22 namespace flutter {
23 
24 //------------------------------------------------------------------------------
25 /// The rasterizer is a component owned by the shell that resides on the GPU
26 /// task runner. Each shell owns exactly one instance of a rasterizer. The
27 /// rasterizer may only be created, used and collected on the GPU task runner.
28 ///
29 /// The rasterizer owns the instance of the currently active on-screen render
30 /// surface. On this surface, it renders the contents of layer trees submitted
31 /// to it by the `Engine` (which lives on the UI task runner).
32 ///
33 /// The primary components owned by the rasterizer are the compositor context
34 /// and the on-screen render surface. The compositor context has all the GPU
35 /// state necessary to render frames to the render surface.
36 ///
37 class Rasterizer final {
38  public:
39   //----------------------------------------------------------------------------
40   /// @brief      Used to forward events from the rasterizer to interested
41   ///             subsystems. Currently, the shell sets itself up as the
42   ///             rasterizer delegate to listen for frame rasterization events.
43   ///             It can then forward these events to the engine.
44   ///
45   ///             Like all rasterizer operation, the rasterizer delegate call
46   ///             are made on the GPU task runner. Any delegate must ensure that
47   ///             they can handle the threading implications.
48   ///
49   class Delegate {
50    public:
51     //--------------------------------------------------------------------------
52     /// @brief      Notifies the delegate that a frame has been rendered. The
53     ///             rasterizer collects profiling information for each part of
54     ///             the frame workload. This profiling information is made
55     ///             available to the delegate for forwarding to subsystems
56     ///             interested in collecting such profiles. Currently, the shell
57     ///             (the delegate) forwards this to the engine where Dart code
58     ///             can react to this information.
59     ///
60     /// @see        `FrameTiming`
61     ///
62     /// @param[in]  frame_timing  Instrumentation information for each phase of
63     ///                           the frame workload.
64     ///
65     virtual void OnFrameRasterized(const FrameTiming& frame_timing) = 0;
66   };
67 
68   // TODO(dnfield): remove once embedders have caught up.
69   class DummyDelegate : public Delegate {
OnFrameRasterized(const FrameTiming &)70     void OnFrameRasterized(const FrameTiming&) override {}
71   };
72 
73   //----------------------------------------------------------------------------
74   /// @brief      Creates a new instance of a rasterizer. Rasterizers may only
75   ///             be created on the GPU task runner. Rasterizers are currently
76   ///             only created by the shell. Usually, the shell also sets itself
77   ///             up as the rasterizer delegate. But, this constructor sets up a
78   ///             dummy rasterizer delegate.
79   ///
80   //  TODO(chinmaygarde): The rasterizer does not use the task runners for
81   //  anything other than thread checks. Remove the same as an argument.
82   ///
83   /// @param[in]  task_runners        The task runners used by the shell.
84   /// @param[in]  compositor_context  The compositor context used to hold all
85   ///                                 the GPU state used by the rasterizer.
86   ///
87   Rasterizer(TaskRunners task_runners,
88              std::unique_ptr<flutter::CompositorContext> compositor_context);
89 
90   //----------------------------------------------------------------------------
91   /// @brief      Creates a new instance of a rasterizer. Rasterizers may only
92   ///             be created on the GPU task runner. Rasterizers are currently
93   ///             only created by the shell (which also sets itself up as the
94   ///             rasterizer delegate).
95   ///
96   //  TODO(chinmaygarde): The rasterizer does not use the task runners for
97   //  anything other than thread checks. Remove the same as an argument.
98   ///
99   /// @param[in]  delegate            The rasterizer delegate.
100   /// @param[in]  task_runners        The task runners used by the shell.
101   ///
102   Rasterizer(Delegate& delegate, TaskRunners task_runners);
103 
104   //----------------------------------------------------------------------------
105   /// @brief      Creates a new instance of a rasterizer. Rasterizers may only
106   ///             be created on the GPU task runner. Rasterizers are currently
107   ///             only created by the shell (which also sets itself up as the
108   ///             rasterizer delegate).
109   ///
110   //  TODO(chinmaygarde): The rasterizer does not use the task runners for
111   //  anything other than thread checks. Remove the same as an argument.
112   ///
113   /// @param[in]  delegate            The rasterizer delegate.
114   /// @param[in]  task_runners        The task runners used by the shell.
115   /// @param[in]  compositor_context  The compositor context used to hold all
116   ///                                 the GPU state used by the rasterizer.
117   ///
118   Rasterizer(Delegate& delegate,
119              TaskRunners task_runners,
120              std::unique_ptr<flutter::CompositorContext> compositor_context);
121 
122   //----------------------------------------------------------------------------
123   /// @brief      Destroys the rasterizer. This must happen on the GPU task
124   ///             runner. All GPU resources are collected before this call
125   ///             returns. Any context setup by the embedder to hold these
126   ///             resources can be immediately collected as well.
127   ///
128   ~Rasterizer();
129 
130   //----------------------------------------------------------------------------
131   /// @brief      Rasterizers may be created well before an on-screen surface is
132   ///             available for rendering. Shells usually create a rasterizer in
133   ///             their constructors. Once an on-screen surface is available
134   ///             however, one may be provided to the rasterizer using this
135   ///             call. No rendering may occur before this call. The surface is
136   ///             held till the balancing call to `Rasterizer::Teardown` is
137   ///             made. Calling a setup before tearing down the previous surface
138   ///             (if this is not the first time the surface has been setup) is
139   ///             user error.
140   ///
141   /// @see        `Rasterizer::Teardown`
142   ///
143   /// @param[in]  surface  The on-screen render surface.
144   ///
145   void Setup(std::unique_ptr<Surface> surface);
146 
147   //----------------------------------------------------------------------------
148   /// @brief      Releases the previously setup on-screen render surface and
149   ///             collects associated resources. No more rendering may occur
150   ///             till the next call to `Rasterizer::Setup` with a new render
151   ///             surface. Calling a teardown without a setup is user error.
152   ///
153   void Teardown();
154 
155   //----------------------------------------------------------------------------
156   /// @brief      Notifies the rasterizer that there is a low memory situation
157   ///             and it must purge as many unnecessary resources as possible.
158   ///             Currently, the Skia context associated with onscreen rendering
159   ///             is told to free GPU resources.
160   ///
161   void NotifyLowMemoryWarning() const;
162 
163   //----------------------------------------------------------------------------
164   /// @brief      Gets a weak pointer to the rasterizer. The rasterizer may only
165   ///             be accessed on the GPU task runner.
166   ///
167   /// @return     The weak pointer to the rasterizer.
168   ///
169   fml::WeakPtr<Rasterizer> GetWeakPtr() const;
170 
171   //----------------------------------------------------------------------------
172   /// @brief      Sometimes, it may be necessary to render the same frame again
173   ///             without having to wait for the framework to build a whole new
174   ///             layer tree describing the same contents. One such case is when
175   ///             external textures (video or camera streams for example) are
176   ///             updated in an otherwise static layer tree. To support this use
177   ///             case, the rasterizer holds onto the last rendered layer tree.
178   ///
179   /// @bug        https://github.com/flutter/flutter/issues/33939
180   ///
181   /// @return     A pointer to the last layer or `nullptr` if this rasterizer
182   ///             has never rendered a frame.
183   ///
184   flutter::LayerTree* GetLastLayerTree();
185 
186   //----------------------------------------------------------------------------
187   /// @brief      Draws a last layer tree to the render surface. This may seem
188   ///             entirely redundant at first glance. After all, on surface loss
189   ///             and re-acquisition, the framework generates a new layer tree.
190   ///             Otherwise, why render the same contents to the screen again?
191   ///             This is used as an optimization in cases where there are
192   ///             external textures (video or camera streams for example) in
193   ///             referenced in the layer tree. These textures may be updated at
194   ///             a cadence different from that of the the Flutter application.
195   ///             Flutter can re-render the layer tree with just the updated
196   ///             textures instead of waiting for the framework to do the work
197   ///             to generate the layer tree describing the same contents.
198   ///
199   void DrawLastLayerTree();
200 
201   //----------------------------------------------------------------------------
202   /// @brief      Gets the registry of external textures currently in use by the
203   ///             rasterizer. These textures may be updated at a cadence
204   ///             different from that of the Flutter application. When an
205   ///             external texture is referenced in the Flutter layer tree, that
206   ///             texture is composited within the Flutter layer tree.
207   ///
208   /// @return     A pointer to the external texture registry.
209   ///
210   flutter::TextureRegistry* GetTextureRegistry();
211 
212   //----------------------------------------------------------------------------
213   /// @brief      Takes the next item from the layer tree pipeline and executes
214   ///             the GPU thread frame workload for that pipeline item to render
215   ///             a frame on the on-screen surface.
216   ///
217   ///             Why does the draw call take a layer tree pipeline and not the
218   ///             layer tree directly?
219   ///
220   ///             The pipeline is the way book-keeping of frame workloads
221   ///             distributed across the multiple threads is managed. The
222   ///             rasterizer deals with the pipelines directly (instead of layer
223   ///             trees which is what it actually renders) because the pipeline
224   ///             consumer's workload must be accounted for within the pipeline
225   ///             itself. If the rasterizer took the layer tree directly, it
226   ///             would have to be taken out of the pipeline. That would signal
227   ///             the end of the frame workload and the pipeline would be ready
228   ///             for new frames. But the last frame has not been rendered by
229   ///             the frame yet! On the other hand, the pipeline must own the
230   ///             layer tree it renders because it keeps a reference to the last
231   ///             layer tree around till a new frame is rendered. So a simple
232   ///             reference wont work either. The `Rasterizer::DoDraw` method
233   ///             actually performs the GPU operations within the layer tree
234   ///             pipeline.
235   ///
236   /// @see        `Rasterizer::DoDraw`
237   ///
238   /// @param[in]  pipeline  The layer tree pipeline to take the next layer tree
239   ///                       to render from.
240   ///
241   void Draw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline);
242 
243   //----------------------------------------------------------------------------
244   /// @brief      The type of the screenshot to obtain of the previously
245   ///             rendered layer tree.
246   ///
247   enum class ScreenshotType {
248     //--------------------------------------------------------------------------
249     /// A format used to denote a Skia picture. A Skia picture is a serialized
250     /// representation of an `SkPicture` that can be used to introspect the
251     /// series of commands used to draw that picture.
252     ///
253     /// Skia pictures are typically stored as files with the .skp extension on
254     /// disk. These files may be viewed in an interactive debugger available at
255     /// https://debugger.skia.org/
256     ///
257     SkiaPicture,
258 
259     //--------------------------------------------------------------------------
260     /// A format used to denote uncompressed image data. This format
261     /// is 32 bits per pixel, 8 bits per component and
262     /// denoted by the `kN32_SkColorType ` Skia color type.
263     ///
264     UncompressedImage,
265 
266     //--------------------------------------------------------------------------
267     /// A format used to denote compressed image data. The PNG compressed
268     /// container is used.
269     ///
270     CompressedImage,
271   };
272 
273   //----------------------------------------------------------------------------
274   /// @brief      A POD type used to return the screenshot data along with the
275   ///             size of the frame.
276   ///
277   struct Screenshot {
278     //--------------------------------------------------------------------------
279     /// The data used to describe the screenshot. The data format depends on the
280     /// type of screenshot taken and any further encoding done to the same.
281     ///
282     /// @see      `ScreenshotType`
283     ///
284     sk_sp<SkData> data;
285 
286     //--------------------------------------------------------------------------
287     /// The size of the screenshot in texels.
288     ///
289     SkISize frame_size = SkISize::MakeEmpty();
290 
291     //--------------------------------------------------------------------------
292     /// @brief      Creates an empty screenshot
293     ///
294     Screenshot();
295 
296     //--------------------------------------------------------------------------
297     /// @brief      Creates a screenshot with the specified data and size.
298     ///
299     /// @param[in]  p_data  The screenshot data
300     /// @param[in]  p_size  The screenshot size.
301     ///
302     Screenshot(sk_sp<SkData> p_data, SkISize p_size);
303 
304     //--------------------------------------------------------------------------
305     /// @brief      The copy constructor for a screenshot.
306     ///
307     /// @param[in]  other  The screenshot to copy from.
308     ///
309     Screenshot(const Screenshot& other);
310 
311     //--------------------------------------------------------------------------
312     /// @brief      Destroys the screenshot object and releases underlying data.
313     ///
314     ~Screenshot();
315   };
316 
317   //----------------------------------------------------------------------------
318   /// @brief      Screenshots the last layer tree to one of the supported
319   ///             screenshot types and optionally Base 64 encodes that data for
320   ///             easier transmission and packaging (usually over the service
321   ///             protocol for instrumentation tools running on the host).
322   ///
323   /// @param[in]  type           The type of the screenshot to gather.
324   /// @param[in]  base64_encode  Whether Base 64 encoding must be applied to the
325   ///                            data after a screenshot has been captured.
326   ///
327   /// @return     A non-empty screenshot if one could be captured. A screenshot
328   ///             capture may fail if there were no layer trees previously
329   ///             rendered by this rasterizer, or, due to an unspecified
330   ///             internal error. Internal error will be logged to the console.
331   ///
332   Screenshot ScreenshotLastLayerTree(ScreenshotType type, bool base64_encode);
333 
334   //----------------------------------------------------------------------------
335   /// @brief      Sets a callback that will be executed when the next layer tree
336   ///             in rendered to the on-screen surface. This is used by
337   ///             embedders to listen for one time operations like listening for
338   ///             when the first frame is rendered so that they may hide splash
339   ///             screens.
340   ///
341   ///             The callback is only executed once and dropped on the GPU
342   ///             thread when executed (lambda captures must be able to deal
343   ///             with the threading repercussions of this behavior).
344   ///
345   /// @param[in]  callback  The callback to execute when the next layer tree is
346   ///                       rendered on-screen.
347   ///
348   void SetNextFrameCallback(fml::closure callback);
349 
350   //----------------------------------------------------------------------------
351   /// @brief      Returns a pointer to the compositor context used by this
352   ///             rasterizer. This pointer will never be `nullptr`.
353   ///
354   /// @return     The compositor context used by this rasterizer.
355   ///
compositor_context()356   flutter::CompositorContext* compositor_context() {
357     return compositor_context_.get();
358   }
359 
360   //----------------------------------------------------------------------------
361   /// @brief      Skia has no notion of time. To work around the performance
362   ///             implications of this, it may cache GPU resources to reference
363   ///             them from one frame to the next. Using this call, embedders
364   ///             may set the maximum bytes cached by Skia in its caches
365   ///             dedicated to on-screen rendering.
366   ///
367   /// @attention  This cache setting will be invalidated when the surface is
368   ///             torn down via `Rasterizer::Teardown`. This call must be made
369   ///             again with new limits after surface re-acquisition.
370   ///
371   /// @attention  This cache does not describe the entirety of GPU resources
372   ///             that may be cached. The `RasterCache` also holds very large
373   ///             GPU resources.
374   ///
375   /// @see        `RasterCache`
376   ///
377   /// @param[in]  max_bytes  The maximum byte size of resource that may be
378   ///                        cached for GPU rendering.
379   /// @param[in]  from_user  Whether this request was from user code, e.g. via
380   ///                        the flutter/skia message channel, in which case
381   ///                        it should not be overridden by the platform.
382   ///
383   void SetResourceCacheMaxBytes(size_t max_bytes, bool from_user);
384 
385   //----------------------------------------------------------------------------
386   /// @brief      The current value of Skia's resource cache size, if a surface
387   ///             is present.
388   ///
389   /// @attention  This cache does not describe the entirety of GPU resources
390   ///             that may be cached. The `RasterCache` also holds very large
391   ///             GPU resources.
392   ///
393   /// @see        `RasterCache`
394   ///
395   /// @return     The size of Skia's resource cache, if available.
396   ///
397   std::optional<size_t> GetResourceCacheMaxBytes() const;
398 
399  private:
400   Delegate& delegate_;
401   TaskRunners task_runners_;
402   std::unique_ptr<Surface> surface_;
403   std::unique_ptr<flutter::CompositorContext> compositor_context_;
404   // This is the last successfully rasterized layer tree.
405   std::unique_ptr<flutter::LayerTree> last_layer_tree_;
406   // Set when we need attempt to rasterize the layer tree again. This layer_tree
407   // has not successfully rasterized. This can happen due to the change in the
408   // thread configuration. This will be inserted to the front of the pipeline.
409   std::unique_ptr<flutter::LayerTree> resubmitted_layer_tree_;
410   fml::closure next_frame_callback_;
411   bool user_override_resource_cache_bytes_;
412   std::optional<size_t> max_cache_bytes_;
413   fml::WeakPtrFactory<Rasterizer> weak_factory_;
414   fml::RefPtr<fml::GpuThreadMerger> gpu_thread_merger_;
415 
416   RasterStatus DoDraw(std::unique_ptr<flutter::LayerTree> layer_tree);
417 
418   RasterStatus DrawToSurface(flutter::LayerTree& layer_tree);
419 
420   void FireNextFrameCallbackIfPresent();
421 
422   FML_DISALLOW_COPY_AND_ASSIGN(Rasterizer);
423 };
424 
425 }  // namespace flutter
426 
427 #endif  // SHELL_COMMON_RASTERIZER_H_
428