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/flow/layers/layer_tree.h" |
6 | |
7 | #include "flutter/flow/layers/layer.h" |
8 | #include "flutter/fml/trace_event.h" |
9 | #include "third_party/skia/include/core/SkPictureRecorder.h" |
10 | #include "third_party/skia/include/utils/SkNWayCanvas.h" |
11 | |
12 | namespace flutter { |
13 | |
14 | LayerTree::LayerTree(const SkISize& frame_size, float device_pixel_ratio) |
15 | : frame_size_(frame_size), |
16 | device_pixel_ratio_(device_pixel_ratio), |
17 | rasterizer_tracing_threshold_(0), |
18 | checkerboard_raster_cache_images_(false), |
19 | checkerboard_offscreen_layers_(false) { |
20 | FML_CHECK(device_pixel_ratio_ != 0.0f); |
21 | } |
22 | |
23 | void LayerTree::RecordBuildTime(fml::TimePoint vsync_start, |
24 | fml::TimePoint build_start, |
25 | fml::TimePoint target_time) { |
26 | vsync_start_ = vsync_start; |
27 | build_start_ = build_start; |
28 | target_time_ = target_time; |
29 | build_finish_ = fml::TimePoint::Now(); |
30 | } |
31 | |
32 | bool LayerTree::Preroll(CompositorContext::ScopedFrame& frame, |
33 | bool ignore_raster_cache) { |
34 | TRACE_EVENT0("flutter" , "LayerTree::Preroll" ); |
35 | |
36 | if (!root_layer_) { |
37 | FML_LOG(ERROR) << "The scene did not specify any layers." ; |
38 | return false; |
39 | } |
40 | |
41 | SkColorSpace* color_space = |
42 | frame.canvas() ? frame.canvas()->imageInfo().colorSpace() : nullptr; |
43 | frame.context().raster_cache().SetCheckboardCacheImages( |
44 | checkerboard_raster_cache_images_); |
45 | MutatorsStack stack; |
46 | PrerollContext context = { |
47 | ignore_raster_cache ? nullptr : &frame.context().raster_cache(), |
48 | frame.gr_context(), |
49 | frame.view_embedder(), |
50 | stack, |
51 | color_space, |
52 | kGiantRect, |
53 | false, |
54 | frame.context().raster_time(), |
55 | frame.context().ui_time(), |
56 | frame.context().texture_registry(), |
57 | checkerboard_offscreen_layers_, |
58 | device_pixel_ratio_}; |
59 | |
60 | root_layer_->Preroll(&context, frame.root_surface_transformation()); |
61 | return context.surface_needs_readback; |
62 | } |
63 | |
64 | #if defined(LEGACY_FUCHSIA_EMBEDDER) |
65 | void LayerTree::UpdateScene(SceneUpdateContext& context) { |
66 | TRACE_EVENT0("flutter" , "LayerTree::UpdateScene" ); |
67 | |
68 | // Reset for a new Scene. |
69 | context.Reset(); |
70 | |
71 | const float inv_dpr = 1.0f / device_pixel_ratio_; |
72 | SceneUpdateContext::Transform transform(context, inv_dpr, inv_dpr, 1.0f); |
73 | |
74 | SceneUpdateContext::Frame frame( |
75 | context, |
76 | SkRRect::MakeRect( |
77 | SkRect::MakeWH(frame_size_.width(), frame_size_.height())), |
78 | SK_ColorTRANSPARENT, SK_AlphaOPAQUE, "flutter::LayerTree" ); |
79 | if (root_layer_->needs_system_composite()) { |
80 | root_layer_->UpdateScene(context); |
81 | } |
82 | if (root_layer_->needs_painting()) { |
83 | frame.AddPaintLayer(root_layer_.get()); |
84 | } |
85 | context.root_node().AddChild(transform.entity_node()); |
86 | } |
87 | #endif |
88 | |
89 | void LayerTree::Paint(CompositorContext::ScopedFrame& frame, |
90 | bool ignore_raster_cache) const { |
91 | TRACE_EVENT0("flutter" , "LayerTree::Paint" ); |
92 | |
93 | if (!root_layer_) { |
94 | FML_LOG(ERROR) << "The scene did not specify any layers to paint." ; |
95 | return; |
96 | } |
97 | |
98 | SkISize canvas_size = frame.canvas()->getBaseLayerSize(); |
99 | SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height()); |
100 | internal_nodes_canvas.addCanvas(frame.canvas()); |
101 | if (frame.view_embedder() != nullptr) { |
102 | auto overlay_canvases = frame.view_embedder()->GetCurrentCanvases(); |
103 | for (size_t i = 0; i < overlay_canvases.size(); i++) { |
104 | internal_nodes_canvas.addCanvas(overlay_canvases[i]); |
105 | } |
106 | } |
107 | |
108 | Layer::PaintContext context = { |
109 | static_cast<SkCanvas*>(&internal_nodes_canvas), |
110 | frame.canvas(), |
111 | frame.gr_context(), |
112 | frame.view_embedder(), |
113 | frame.context().raster_time(), |
114 | frame.context().ui_time(), |
115 | frame.context().texture_registry(), |
116 | ignore_raster_cache ? nullptr : &frame.context().raster_cache(), |
117 | checkerboard_offscreen_layers_, |
118 | device_pixel_ratio_}; |
119 | |
120 | if (root_layer_->needs_painting()) { |
121 | root_layer_->Paint(context); |
122 | } |
123 | } |
124 | |
125 | sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) { |
126 | TRACE_EVENT0("flutter" , "LayerTree::Flatten" ); |
127 | |
128 | SkPictureRecorder recorder; |
129 | auto* canvas = recorder.beginRecording(bounds); |
130 | |
131 | if (!canvas) { |
132 | return nullptr; |
133 | } |
134 | |
135 | MutatorsStack unused_stack; |
136 | const Stopwatch unused_stopwatch; |
137 | TextureRegistry unused_texture_registry; |
138 | SkMatrix root_surface_transformation; |
139 | // No root surface transformation. So assume identity. |
140 | root_surface_transformation.reset(); |
141 | |
142 | PrerollContext preroll_context{ |
143 | nullptr, // raster_cache (don't consult the cache) |
144 | nullptr, // gr_context (used for the raster cache) |
145 | nullptr, // external view embedder |
146 | unused_stack, // mutator stack |
147 | nullptr, // SkColorSpace* dst_color_space |
148 | kGiantRect, // SkRect cull_rect |
149 | false, // layer reads from surface |
150 | unused_stopwatch, // frame time (dont care) |
151 | unused_stopwatch, // engine time (dont care) |
152 | unused_texture_registry, // texture registry (not supported) |
153 | false, // checkerboard_offscreen_layers |
154 | device_pixel_ratio_ // ratio between logical and physical |
155 | }; |
156 | |
157 | SkISize canvas_size = canvas->getBaseLayerSize(); |
158 | SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height()); |
159 | internal_nodes_canvas.addCanvas(canvas); |
160 | |
161 | Layer::PaintContext paint_context = { |
162 | static_cast<SkCanvas*>(&internal_nodes_canvas), |
163 | canvas, // canvas |
164 | nullptr, |
165 | nullptr, |
166 | unused_stopwatch, // frame time (dont care) |
167 | unused_stopwatch, // engine time (dont care) |
168 | unused_texture_registry, // texture registry (not supported) |
169 | nullptr, // raster cache |
170 | false, // checkerboard offscreen layers |
171 | device_pixel_ratio_ // ratio between logical and physical |
172 | }; |
173 | |
174 | // Even if we don't have a root layer, we still need to create an empty |
175 | // picture. |
176 | if (root_layer_) { |
177 | root_layer_->Preroll(&preroll_context, root_surface_transformation); |
178 | // The needs painting flag may be set after the preroll. So check it after. |
179 | if (root_layer_->needs_painting()) { |
180 | root_layer_->Paint(paint_context); |
181 | } |
182 | } |
183 | |
184 | return recorder.finishRecordingAsPicture(); |
185 | } |
186 | |
187 | } // namespace flutter |
188 | |