Flutter Engine
 
Loading...
Searching...
No Matches
compositor_context.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
6
7#include <optional>
8#include <utility>
10
11namespace flutter {
12
13std::optional<DlRect> FrameDamage::ComputeClipRect(
14 flutter::LayerTree& layer_tree,
15 bool has_raster_cache,
16 bool impeller_enabled) {
17 if (layer_tree.root_layer()) {
18 PaintRegionMap empty_paint_region_map;
19 DiffContext context(layer_tree.frame_size(), layer_tree.paint_region_map(),
20 prev_layer_tree_ ? prev_layer_tree_->paint_region_map()
21 : empty_paint_region_map,
22 has_raster_cache, impeller_enabled);
23 context.PushCullRect(DlRect::MakeSize(layer_tree.frame_size()));
24 {
25 DiffContext::AutoSubtreeRestore subtree(&context);
26 const Layer* prev_root_layer = nullptr;
27 if (!prev_layer_tree_ ||
28 prev_layer_tree_->frame_size() != layer_tree.frame_size()) {
29 // If there is no previous layer tree assume the entire frame must be
30 // repainted.
31 context.MarkSubtreeDirty(DlRect::MakeSize(layer_tree.frame_size()));
32 } else {
33 prev_root_layer = prev_layer_tree_->root_layer();
34 }
35 layer_tree.root_layer()->Diff(&context, prev_root_layer);
36 }
37
38 damage_ =
39 context.ComputeDamage(additional_damage_, horizontal_clip_alignment_,
40 vertical_clip_alignment_);
41 return DlRect::Make(damage_->buffer_damage);
42 }
43 return std::nullopt;
44}
45
47 : texture_registry_(std::make_shared<TextureRegistry>()),
48 raster_time_(fixed_refresh_rate_updater_),
49 ui_time_(fixed_refresh_rate_updater_) {}
50
52 : texture_registry_(std::make_shared<TextureRegistry>()),
53 raster_time_(updater),
54 ui_time_(updater) {}
55
57
58void CompositorContext::BeginFrame(ScopedFrame& frame,
59 bool enable_instrumentation) {
60 if (enable_instrumentation) {
61 raster_time_.Start();
62 }
63}
64
65void CompositorContext::EndFrame(ScopedFrame& frame,
66 bool enable_instrumentation) {
67 if (enable_instrumentation) {
68 raster_time_.Stop();
69 }
70}
71
72std::unique_ptr<CompositorContext::ScopedFrame> CompositorContext::AcquireFrame(
73 GrDirectContext* gr_context,
74 DlCanvas* canvas,
75 ExternalViewEmbedder* view_embedder,
76 const DlMatrix& root_surface_transformation,
77 bool instrumentation_enabled,
78 bool surface_supports_readback,
80 raster_thread_merger, // NOLINT(performance-unnecessary-value-param)
81 impeller::AiksContext* aiks_context) {
82 return std::make_unique<ScopedFrame>(
83 *this, gr_context, canvas, view_embedder, root_surface_transformation,
84 instrumentation_enabled, surface_supports_readback, raster_thread_merger,
85 aiks_context);
86}
87
89 CompositorContext& context,
90 GrDirectContext* gr_context,
91 DlCanvas* canvas,
92 ExternalViewEmbedder* view_embedder,
93 const DlMatrix& root_surface_transformation,
94 bool instrumentation_enabled,
95 bool surface_supports_readback,
96 fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger,
97 impeller::AiksContext* aiks_context)
98 : context_(context),
99 gr_context_(gr_context),
100 canvas_(canvas),
101 aiks_context_(aiks_context),
102 view_embedder_(view_embedder),
103 root_surface_transformation_(root_surface_transformation),
104 instrumentation_enabled_(instrumentation_enabled),
105 surface_supports_readback_(surface_supports_readback),
106 raster_thread_merger_(std::move(raster_thread_merger)) {
107 context_.BeginFrame(*this, instrumentation_enabled_);
108}
109
111 context_.EndFrame(*this, instrumentation_enabled_);
112}
113
115 flutter::LayerTree& layer_tree,
116 bool ignore_raster_cache,
117 FrameDamage* frame_damage) {
118 TRACE_EVENT0("flutter", "CompositorContext::ScopedFrame::Raster");
119
120 std::optional<DlRect> clip_rect;
121 if (frame_damage) {
122 clip_rect = frame_damage->ComputeClipRect(layer_tree, !ignore_raster_cache,
123 !gr_context_);
124
125 if (aiks_context_ &&
126 !ShouldPerformPartialRepaint(clip_rect, layer_tree.frame_size())) {
127 clip_rect = std::nullopt;
128 frame_damage->Reset();
129 }
130 }
131
132 bool root_needs_readback = layer_tree.Preroll(
133 *this, ignore_raster_cache, clip_rect ? *clip_rect : kGiantRect);
134 bool needs_save_layer = root_needs_readback && !surface_supports_readback();
136 if (view_embedder_ && raster_thread_merger_) {
137 post_preroll_result =
138 view_embedder_->PostPrerollAction(raster_thread_merger_);
139 }
140
141 if (post_preroll_result == PostPrerollResult::kResubmitFrame) {
143 }
144 if (post_preroll_result == PostPrerollResult::kSkipAndRetryFrame) {
146 }
147
148 if (aiks_context_) {
149 PaintLayerTreeImpeller(layer_tree, clip_rect, ignore_raster_cache);
150 } else {
151 PaintLayerTreeSkia(layer_tree, clip_rect, needs_save_layer,
152 ignore_raster_cache);
153 }
155}
156
157void CompositorContext::ScopedFrame::PaintLayerTreeSkia(
158 flutter::LayerTree& layer_tree,
159 std::optional<DlRect> clip_rect,
160 bool needs_save_layer,
161 bool ignore_raster_cache) {
162 DlAutoCanvasRestore restore(canvas(), clip_rect.has_value());
163
164 if (canvas()) {
165 if (clip_rect) {
166 canvas()->ClipRect(*clip_rect);
167 }
168
169 if (needs_save_layer) {
170 TRACE_EVENT0("flutter", "Canvas::saveLayer");
171 DlRect bounds = DlRect::MakeSize(layer_tree.frame_size());
172 DlPaint paint;
173 paint.setBlendMode(DlBlendMode::kSrc);
174 canvas()->SaveLayer(bounds, &paint);
175 }
176 canvas()->Clear(DlColor::kTransparent());
177 }
178
179 // The canvas()->Restore() is taken care of by the DlAutoCanvasRestore
180 layer_tree.Paint(*this, ignore_raster_cache);
181}
182
183void CompositorContext::ScopedFrame::PaintLayerTreeImpeller(
184 flutter::LayerTree& layer_tree,
185 std::optional<DlRect> clip_rect,
186 bool ignore_raster_cache) {
187 DlAutoCanvasRestore restore(canvas(), clip_rect.has_value());
188
189 if (canvas()) {
190 if (clip_rect) {
191 canvas()->ClipRect(clip_rect.value());
192 }
193 }
194
195 // The canvas()->Restore() is taken care of by the DlAutoCanvasRestore
196 layer_tree.Paint(*this, ignore_raster_cache);
197}
198
199/// @brief The max ratio of pixel width or height to size that is dirty which
200/// results in a partial repaint.
201///
202/// Performing a partial repaint has a small overhead - Impeller needs to
203/// allocate a fairly large resolve texture for the root pass instead of
204/// using the drawable texture, and a final blit must be performed. At a
205/// minimum, if the damage rect is the entire buffer, we must not perform
206/// a partial repaint. Beyond that, we could only experimentally
207/// determine what this value should be. From looking at the Flutter
208/// Gallery, we noticed that there are occassionally small partial
209/// repaints which shave off trivial numbers of pixels.
210constexpr float kImpellerRepaintRatio = 0.7f;
211
212bool CompositorContext::ShouldPerformPartialRepaint(
213 std::optional<DlRect> damage_rect,
214 DlISize layer_tree_size) {
215 if (!damage_rect.has_value()) {
216 return false;
217 }
218 if (damage_rect->GetWidth() >= layer_tree_size.width &&
219 damage_rect->GetHeight() >= layer_tree_size.height) {
220 return false;
221 }
222 auto rx = damage_rect->GetWidth() / layer_tree_size.width;
223 auto ry = damage_rect->GetHeight() / layer_tree_size.height;
224 return rx <= kImpellerRepaintRatio || ry <= kImpellerRepaintRatio;
225}
226
228 texture_registry_->OnGrContextCreated();
229#if !SLIMPELLER
230 raster_cache_.Clear();
231#endif // !SLIMPELLER
232}
233
235 texture_registry_->OnGrContextDestroyed();
236#if !SLIMPELLER
237 raster_cache_.Clear();
238#endif // !SLIMPELLER
239}
240
241} // namespace flutter
virtual RasterStatus Raster(LayerTree &layer_tree, bool ignore_raster_cache, FrameDamage *frame_damage)
ScopedFrame(CompositorContext &context, GrDirectContext *gr_context, DlCanvas *canvas, ExternalViewEmbedder *view_embedder, const DlMatrix &root_surface_transformation, bool instrumentation_enabled, bool surface_supports_readback, fml::RefPtr< fml::RasterThreadMerger > raster_thread_merger, impeller::AiksContext *aiks_context)
virtual std::unique_ptr< ScopedFrame > AcquireFrame(GrDirectContext *gr_context, DlCanvas *canvas, ExternalViewEmbedder *view_embedder, const DlMatrix &root_surface_transformation, bool instrumentation_enabled, bool surface_supports_readback, fml::RefPtr< fml::RasterThreadMerger > raster_thread_merger, impeller::AiksContext *aiks_context)
bool PushCullRect(const DlRect &clip)
Developer-facing API for rendering anything within the engine.
Definition dl_canvas.h:32
DlPaint & setBlendMode(DlBlendMode mode)
Definition dl_paint.h:85
std::optional< DlRect > ComputeClipRect(flutter::LayerTree &layer_tree, bool has_raster_cache, bool impeller_enabled)
virtual void Diff(DiffContext *context, const Layer *old_layer)
Definition layer.h:144
Layer * root_layer() const
Definition layer_tree.h:53
void Paint(CompositorContext::ScopedFrame &frame, bool ignore_raster_cache=false) const
Definition layer_tree.cc:96
const PaintRegionMap & paint_region_map() const
Definition layer_tree.h:56
const DlISize & frame_size() const
Definition layer_tree.h:54
bool Preroll(CompositorContext::ScopedFrame &frame, bool ignore_raster_cache=false, DlRect cull_rect=kGiantRect)
Definition layer_tree.cc:28
The refresh rate interface for Stopwatch.
Definition stopwatch.h:23
std::map< uint64_t, PaintRegion > PaintRegionMap
constexpr float kImpellerRepaintRatio
The max ratio of pixel width or height to size that is dirty which results in a partial repaint.
static constexpr DlRect kGiantRect
Definition layer.h:40
Definition ref_ptr.h:261
static constexpr DlColor kTransparent()
Definition dl_color.h:68
A 4x4 matrix using column-major storage.
Definition matrix.h:37
static constexpr std::enable_if_t< std::is_floating_point_v< FT >, TRect > Make(const TRect< U > &rect)
Definition rect.h:157
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150
Type height
Definition size.h:29
Type width
Definition size.h:28
#define TRACE_EVENT0(category_group, name)