Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit dd937e0

Browse files
authored
Document //flutter/shell/common/rasterizer (#9809)
1 parent 0fa6f40 commit dd937e0

File tree

1 file changed

+294
-8
lines changed

1 file changed

+294
-8
lines changed

shell/common/rasterizer.h

Lines changed: 294 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,76 +19,362 @@
1919

2020
namespace flutter {
2121

22-
/// Takes |LayerTree|s and draws its contents.
22+
//------------------------------------------------------------------------------
23+
/// The rasterizer is a component owned by the shell that resides on the GPU
24+
/// task runner. Each shell owns exactly one instance of a rasterizer. The
25+
/// rasterizer may only be created, used and collected on the GPU task runner.
26+
///
27+
/// The rasterizer owns the instance of the currently active on-screen render
28+
/// surface. On this surface, it renders the contents of layer trees submitted
29+
/// to it by the `Engine` (which lives on the UI task runner).
30+
///
31+
/// The primary components owned by the rasterizer are the compositor context
32+
/// and the on-screen render surface. The compositor context has all the GPU
33+
/// state necessary to render frames to the render surface.
34+
///
2335
class Rasterizer final {
2436
public:
37+
//----------------------------------------------------------------------------
38+
/// @brief Used to forward events from the rasterizer to interested
39+
/// subsystems. Currently, the shell sets itself up as the
40+
/// rasterizer delegate to listen for frame rasterization events.
41+
/// It can then forward these events to the engine.
42+
///
43+
/// Like all rasterizer operation, the rasterizer delegate call
44+
/// are made on the GPU task runner. Any delegate must ensure that
45+
/// they can handle the threading implications.
46+
///
2547
class Delegate {
2648
public:
27-
virtual void OnFrameRasterized(const FrameTiming&) = 0;
49+
//--------------------------------------------------------------------------
50+
/// @brief Notifies the delegate that a frame has been rendered. The
51+
/// rasterizer collects profiling information for each part of
52+
/// the frame workload. This profiling information is made
53+
/// available to the delegate for forwarding to subsystems
54+
/// interested in collecting such profiles. Currently, the shell
55+
/// (the delegate) forwards this to the engine where Dart code
56+
/// can react to this information.
57+
///
58+
/// @see `FrameTiming`
59+
///
60+
/// @param[in] frame_timing Instrumentation information for each phase of
61+
/// the frame workload.
62+
///
63+
virtual void OnFrameRasterized(const FrameTiming& frame_timing) = 0;
2864
};
65+
2966
// TODO(dnfield): remove once embedders have caught up.
3067
class DummyDelegate : public Delegate {
3168
void OnFrameRasterized(const FrameTiming&) override {}
3269
};
70+
71+
//----------------------------------------------------------------------------
72+
/// @brief Creates a new instance of a rasterizer. Rasterizers may only
73+
/// be created on the GPU task runner. Rasterizers are currently
74+
/// only created by the shell. Usually, the shell also sets itself
75+
/// up as the rasterizer delegate. But, this constructor sets up a
76+
/// dummy rasterizer delegate.
77+
///
78+
// TODO(chinmaygarde): The rasterizer does not use the task runners for
79+
// anything other than thread checks. Remove the same as an argument.
80+
///
81+
/// @param[in] task_runners The task runners used by the shell.
82+
/// @param[in] compositor_context The compositor context used to hold all
83+
/// the GPU state used by the rasterizer.
84+
///
3385
Rasterizer(TaskRunners task_runners,
3486
std::unique_ptr<flutter::CompositorContext> compositor_context);
3587

88+
//----------------------------------------------------------------------------
89+
/// @brief Creates a new instance of a rasterizer. Rasterizers may only
90+
/// be created on the GPU task runner. Rasterizers are currently
91+
/// only created by the shell (which also sets itself up as the
92+
/// rasterizer delegate).
93+
///
94+
// TODO(chinmaygarde): The rasterizer does not use the task runners for
95+
// anything other than thread checks. Remove the same as an argument.
96+
///
97+
/// @param[in] delegate The rasterizer delegate.
98+
/// @param[in] task_runners The task runners used by the shell.
99+
///
36100
Rasterizer(Delegate& delegate, TaskRunners task_runners);
37101

102+
//----------------------------------------------------------------------------
103+
/// @brief Creates a new instance of a rasterizer. Rasterizers may only
104+
/// be created on the GPU task runner. Rasterizers are currently
105+
/// only created by the shell (which also sets itself up as the
106+
/// rasterizer delegate).
107+
///
108+
// TODO(chinmaygarde): The rasterizer does not use the task runners for
109+
// anything other than thread checks. Remove the same as an argument.
110+
///
111+
/// @param[in] delegate The rasterizer delegate.
112+
/// @param[in] task_runners The task runners used by the shell.
113+
/// @param[in] compositor_context The compositor context used to hold all
114+
/// the GPU state used by the rasterizer.
115+
///
38116
Rasterizer(Delegate& delegate,
39117
TaskRunners task_runners,
40118
std::unique_ptr<flutter::CompositorContext> compositor_context);
41119

120+
//----------------------------------------------------------------------------
121+
/// @brief Destroys the rasterizer. This must happen on the GPU task
122+
/// runner. All GPU resources are collected before this call
123+
/// returns. Any context setup by the embedder to hold these
124+
/// resources can be immediately collected as well.
125+
///
42126
~Rasterizer();
43127

128+
//----------------------------------------------------------------------------
129+
/// @brief Rasterizers may be created well before an on-screen surface is
130+
/// available for rendering. Shells usually create a rasterizer in
131+
/// their constructors. Once an on-screen surface is available
132+
/// however, one may be provided to the rasterizer using this
133+
/// call. No rendering may occur before this call. The surface is
134+
/// held till the balancing call to `Rasterizer::Teardown` is
135+
/// made. Calling a setup before tearing down the previous surface
136+
/// (if this is not the first time the surface has been setup) is
137+
/// user error.
138+
///
139+
/// @see `Rasterizer::Teardown`
140+
///
141+
/// @param[in] surface The on-screen render surface.
142+
///
44143
void Setup(std::unique_ptr<Surface> surface);
45144

145+
//----------------------------------------------------------------------------
146+
/// @brief Releases the previously setup on-screen render surface and
147+
/// collects associated resources. No more rendering may occur
148+
/// till the next call to `Rasterizer::Setup` with a new render
149+
/// surface. Calling a teardown without a setup is user error.
150+
///
46151
void Teardown();
47152

48-
// Frees up Skia GPU resources.
49-
//
50-
// This method must be called from the GPU task runner.
153+
//----------------------------------------------------------------------------
154+
/// @brief Notifies the rasterizer that there is a low memory situation
155+
/// and it must purge as many unnecessary resources as possible.
156+
/// Currently, the Skia context associated with onscreen rendering
157+
/// is told to free GPU resources.
158+
///
51159
void NotifyLowMemoryWarning() const;
52160

161+
//----------------------------------------------------------------------------
162+
/// @brief Gets a weak pointer to the rasterizer. The rasterizer may only
163+
/// be accessed on the GPU task runner.
164+
///
165+
/// @return The weak pointer to the rasterizer.
166+
///
53167
fml::WeakPtr<Rasterizer> GetWeakPtr() const;
54168

169+
//----------------------------------------------------------------------------
170+
/// @brief Sometimes, it may be necessary to render the same frame again
171+
/// without having to wait for the framework to build a whole new
172+
/// layer tree describing the same contents. One such case is when
173+
/// external textures (video or camera streams for example) are
174+
/// updated in an otherwise static layer tree. To support this use
175+
/// case, the rasterizer holds onto the last rendered layer tree.
176+
///
177+
/// @bug https://github.com/flutter/flutter/issues/33939
178+
///
179+
/// @return A pointer to the last layer or `nullptr` if this rasterizer
180+
/// has never rendered a frame.
181+
///
55182
flutter::LayerTree* GetLastLayerTree();
56183

184+
//----------------------------------------------------------------------------
185+
/// @brief Draws a last layer tree to the render surface. This may seem
186+
/// entirely redundant at first glance. After all, on surface loss
187+
/// and re-acquisition, the framework generates a new layer tree.
188+
/// Otherwise, why render the same contents to the screen again?
189+
/// This is used as an optimization in cases where there are
190+
/// external textures (video or camera streams for example) in
191+
/// referenced in the layer tree. These textures may be updated at
192+
/// a cadence different from that of the the Flutter application.
193+
/// Flutter can re-render the layer tree with just the updated
194+
/// textures instead of waiting for the framework to do the work
195+
/// to generate the layer tree describing the same contents.
196+
///
57197
void DrawLastLayerTree();
58198

199+
//----------------------------------------------------------------------------
200+
/// @brief Gets the registry of external textures currently in use by the
201+
/// rasterizer. These textures may be updated at a cadence
202+
/// different from that of the Flutter application. When an
203+
/// external texture is referenced in the Flutter layer tree, that
204+
/// texture is composited within the Flutter layer tree.
205+
///
206+
/// @return A pointer to the external texture registry.
207+
///
59208
flutter::TextureRegistry* GetTextureRegistry();
60209

210+
//----------------------------------------------------------------------------
211+
/// @brief Takes the next item from the layer tree pipeline and executes
212+
/// the GPU thread frame workload for that pipeline item to render
213+
/// a frame on the on-screen surface.
214+
///
215+
/// Why does the draw call take a layer tree pipeline and not the
216+
/// layer tree directly?
217+
///
218+
/// The pipeline is the way book-keeping of frame workloads
219+
/// distributed across the multiple threads is managed. The
220+
/// rasterizer deals with the pipelines directly (instead of layer
221+
/// trees which is what it actually renders) because the pipeline
222+
/// consumer's workload must be accounted for within the pipeline
223+
/// itself. If the rasterizer took the layer tree directly, it
224+
/// would have to be taken out of the pipeline. That would signal
225+
/// the end of the frame workload and the pipeline would be ready
226+
/// for new frames. But the last frame has not been rendered by
227+
/// the frame yet! On the other hand, the pipeline must own the
228+
/// layer tree it renders because it keeps a reference to the last
229+
/// layer tree around till a new frame is rendered. So a simple
230+
/// reference wont work either. The `Rasterizer::DoDraw` method
231+
/// actually performs the GPU operations within the layer tree
232+
/// pipeline.
233+
///
234+
/// @see `Rasterizer::DoDraw`
235+
///
236+
/// @param[in] pipeline The layer tree pipeline to take the next layer tree
237+
/// to render from.
238+
///
61239
void Draw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline);
62240

241+
//----------------------------------------------------------------------------
242+
/// @brief The type of the screenshot to obtain of the previously
243+
/// rendered layer tree.
244+
///
63245
enum class ScreenshotType {
246+
//--------------------------------------------------------------------------
247+
/// A format used to denote a Skia picture. A Skia picture is a serialized
248+
/// representation of an `SkPicture` that can be used to introspect the
249+
/// series of commands used to draw that picture.
250+
///
251+
/// Skia pictures are typically stored as files with the .skp extension on
252+
/// disk. These files may be viewed in an interactive debugger available at
253+
/// https://debugger.skia.org/
254+
///
64255
SkiaPicture,
65-
UncompressedImage, // In kN32_SkColorType format
256+
257+
//--------------------------------------------------------------------------
258+
/// A format used to denote uncompressed image data. This format
259+
/// is 32 bits per pixel, 8 bits per component and
260+
/// denoted by the `kN32_SkColorType ` Skia color type.
261+
///
262+
UncompressedImage,
263+
264+
//--------------------------------------------------------------------------
265+
/// A format used to denote compressed image data. The PNG compressed
266+
/// container is used.
267+
///
66268
CompressedImage,
67269
};
68270

271+
//----------------------------------------------------------------------------
272+
/// @brief A POD type used to return the screenshot data along with the
273+
/// size of the frame.
274+
///
69275
struct Screenshot {
276+
//--------------------------------------------------------------------------
277+
/// The data used to describe the screenshot. The data format depends on the
278+
/// type of screenshot taken and any further encoding done to the same.
279+
///
280+
/// @see `ScreenshotType`
281+
///
70282
sk_sp<SkData> data;
283+
284+
//--------------------------------------------------------------------------
285+
/// The size of the screenshot in texels.
286+
///
71287
SkISize frame_size = SkISize::MakeEmpty();
72288

289+
//--------------------------------------------------------------------------
290+
/// @brief Creates an empty screenshot
291+
///
73292
Screenshot();
74293

294+
//--------------------------------------------------------------------------
295+
/// @brief Creates a screenshot with the specified data and size.
296+
///
297+
/// @param[in] p_data The screenshot data
298+
/// @param[in] p_size The screenshot size.
299+
///
75300
Screenshot(sk_sp<SkData> p_data, SkISize p_size);
76301

302+
//--------------------------------------------------------------------------
303+
/// @brief The copy constructor for a screenshot.
304+
///
305+
/// @param[in] other The screenshot to copy from.
306+
///
77307
Screenshot(const Screenshot& other);
78308

309+
//--------------------------------------------------------------------------
310+
/// @brief Destroys the screenshot object and releases underlying data.
311+
///
79312
~Screenshot();
80313
};
81314

315+
//----------------------------------------------------------------------------
316+
/// @brief Screenshots the last layer tree to one of the supported
317+
/// screenshot types and optionally Base 64 encodes that data for
318+
/// easier transmission and packaging (usually over the service
319+
/// protocol for instrumentation tools running on the host).
320+
///
321+
/// @param[in] type The type of the screenshot to gather.
322+
/// @param[in] base64_encode Whether Base 64 encoding must be applied to the
323+
/// data after a screenshot has been captured.
324+
///
325+
/// @return A non-empty screenshot if one could be captured. A screenshot
326+
/// capture may fail if there were no layer trees previously
327+
/// rendered by this rasterizer, or, due to an unspecified
328+
/// internal error. Internal error will be logged to the console.
329+
///
82330
Screenshot ScreenshotLastLayerTree(ScreenshotType type, bool base64_encode);
83331

84-
// Sets a callback that will be executed after the next frame is submitted to
85-
// the surface on the GPU task runner.
332+
//----------------------------------------------------------------------------
333+
/// @brief Sets a callback that will be executed when the next layer tree
334+
/// in rendered to the on-screen surface. This is used by
335+
/// embedders to listen for one time operations like listening for
336+
/// when the first frame is rendered so that they may hide splash
337+
/// screens.
338+
///
339+
/// The callback is only executed once and dropped on the GPU
340+
/// thread when executed (lambda captures must be able to deal
341+
/// with the threading repercussions of this behavior).
342+
///
343+
/// @param[in] callback The callback to execute when the next layer tree is
344+
/// rendered on-screen.
345+
///
86346
void SetNextFrameCallback(fml::closure callback);
87347

348+
//----------------------------------------------------------------------------
349+
/// @brief Returns a pointer to the compositor context used by this
350+
/// rasterizer. This pointer will never be `nullptr`.
351+
///
352+
/// @return The compositor context used by this rasterizer.
353+
///
88354
flutter::CompositorContext* compositor_context() {
89355
return compositor_context_.get();
90356
}
91357

358+
//----------------------------------------------------------------------------
359+
/// @brief Skia has no notion of time. To work around the performance
360+
/// implications of this, it may cache GPU resources to reference
361+
/// them from one frame to the next. Using this call, embedders
362+
/// may set the maximum bytes cached by Skia in its caches
363+
/// dedicated to on-screen rendering.
364+
///
365+
/// @attention This cache setting will be invalidated when the surface is
366+
/// torn down via `Rasterizer::Teardown`. This call must be made
367+
/// again with new limits after surface re-acquisition.
368+
///
369+
/// @attention This cache does not describe the entirety of GPU resources
370+
/// that may be cached. The `RasterCache` also holds very large
371+
/// GPU resources.
372+
///
373+
/// @see `RasterCache`
374+
///
375+
/// @param[in] max_bytes The maximum byte size of resource that may be
376+
/// cached for GPU rendering.
377+
///
92378
void SetResourceCacheMaxBytes(int max_bytes);
93379

94380
private:

0 commit comments

Comments
 (0)