| 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 FLUTTER_FLOW_COMPOSITOR_CONTEXT_H_ |
| 6 | #define FLUTTER_FLOW_COMPOSITOR_CONTEXT_H_ |
| 7 | |
| 8 | #include <memory> |
| 9 | #include <string> |
| 10 | |
| 11 | #include "flutter/common/graphics/texture.h" |
| 12 | #include "flutter/flow/diff_context.h" |
| 13 | #include "flutter/flow/embedded_views.h" |
| 14 | #include "flutter/flow/instrumentation.h" |
| 15 | #include "flutter/flow/layer_snapshot_store.h" |
| 16 | #include "flutter/flow/raster_cache.h" |
| 17 | #include "flutter/fml/macros.h" |
| 18 | #include "flutter/fml/raster_thread_merger.h" |
| 19 | #include "third_party/skia/include/core/SkCanvas.h" |
| 20 | #include "third_party/skia/include/gpu/GrDirectContext.h" |
| 21 | |
| 22 | namespace flutter { |
| 23 | |
| 24 | class LayerTree; |
| 25 | |
| 26 | enum class RasterStatus { |
| 27 | // Frame has been successfully rasterized. |
| 28 | kSuccess, |
| 29 | // Frame is submitted twice. This is only used on Android when |
| 30 | // switching the background surface to FlutterImageView. |
| 31 | // |
| 32 | // On Android, the first frame doesn't make the image available |
| 33 | // to the ImageReader right away. The second frame does. |
| 34 | // |
| 35 | // TODO(egarciad): https://github.com/flutter/flutter/issues/65652 |
| 36 | kResubmit, |
| 37 | // Frame is dropped and a new frame with the same layer tree is |
| 38 | // attempted. |
| 39 | // |
| 40 | // This is currently used to wait for the thread merger to merge |
| 41 | // the raster and platform threads. |
| 42 | // |
| 43 | // Since the thread merger may be disabled, |
| 44 | kSkipAndRetry, |
| 45 | // Frame has been successfully rasterized, but "there are additional items in |
| 46 | // the pipeline waiting to be consumed. This is currently |
| 47 | // only used when thread configuration change occurs. |
| 48 | kEnqueuePipeline, |
| 49 | // Failed to rasterize the frame. |
| 50 | kFailed, |
| 51 | // Layer tree was discarded due to LayerTreeDiscardCallback or inability to |
| 52 | // access the GPU. |
| 53 | kDiscarded, |
| 54 | // Drawing was yielded to allow the correct thread to draw as a result of the |
| 55 | // RasterThreadMerger. |
| 56 | kYielded, |
| 57 | }; |
| 58 | |
| 59 | class FrameDamage { |
| 60 | public: |
| 61 | // Sets previous layer tree for calculating frame damage. If not set, entire |
| 62 | // frame will be repainted. |
| 63 | void SetPreviousLayerTree(const LayerTree* prev_layer_tree) { |
| 64 | prev_layer_tree_ = prev_layer_tree; |
| 65 | } |
| 66 | |
| 67 | // Adds additional damage (accumulated for double / triple buffering). |
| 68 | // This is area that will be repainted alongside any changed part. |
| 69 | void AddAdditionalDamage(const SkIRect& damage) { |
| 70 | additional_damage_.join(r: damage); |
| 71 | } |
| 72 | |
| 73 | // Specifies clip rect alignment. |
| 74 | void SetClipAlignment(int horizontal, int vertical) { |
| 75 | horizontal_clip_alignment_ = horizontal; |
| 76 | vertical_clip_alignment_ = vertical; |
| 77 | } |
| 78 | |
| 79 | // Calculates clip rect for current rasterization. This is diff of layer tree |
| 80 | // and previous layer tree + any additional provided damage. |
| 81 | // If previous layer tree is not specified, clip rect will be nullopt, |
| 82 | // but the paint region of layer_tree will be calculated so that it can be |
| 83 | // used for diffing of subsequent frames. |
| 84 | std::optional<SkRect> ComputeClipRect(flutter::LayerTree& layer_tree, |
| 85 | bool has_raster_cache, |
| 86 | bool impeller_enabled); |
| 87 | |
| 88 | // See Damage::frame_damage. |
| 89 | std::optional<SkIRect> GetFrameDamage() const { |
| 90 | return damage_ ? std::make_optional(v: damage_->frame_damage) : std::nullopt; |
| 91 | } |
| 92 | |
| 93 | // See Damage::buffer_damage. |
| 94 | std::optional<SkIRect> GetBufferDamage() { |
| 95 | return (damage_ && !ignore_damage_) |
| 96 | ? std::make_optional(v&: damage_->buffer_damage) |
| 97 | : std::nullopt; |
| 98 | } |
| 99 | |
| 100 | // Remove reported buffer_damage to inform clients that a partial repaint |
| 101 | // should not be performed on this frame. |
| 102 | // frame_damage is required to correctly track accumulated damage for |
| 103 | // subsequent frames. |
| 104 | void Reset() { ignore_damage_ = true; } |
| 105 | |
| 106 | private: |
| 107 | SkIRect additional_damage_ = SkIRect::MakeEmpty(); |
| 108 | std::optional<Damage> damage_; |
| 109 | const LayerTree* prev_layer_tree_ = nullptr; |
| 110 | int vertical_clip_alignment_ = 1; |
| 111 | int horizontal_clip_alignment_ = 1; |
| 112 | bool ignore_damage_ = false; |
| 113 | }; |
| 114 | |
| 115 | class CompositorContext { |
| 116 | public: |
| 117 | class ScopedFrame { |
| 118 | public: |
| 119 | ScopedFrame(CompositorContext& context, |
| 120 | GrDirectContext* gr_context, |
| 121 | DlCanvas* canvas, |
| 122 | ExternalViewEmbedder* view_embedder, |
| 123 | const SkMatrix& root_surface_transformation, |
| 124 | bool instrumentation_enabled, |
| 125 | bool surface_supports_readback, |
| 126 | fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger, |
| 127 | impeller::AiksContext* aiks_context); |
| 128 | |
| 129 | virtual ~ScopedFrame(); |
| 130 | |
| 131 | DlCanvas* canvas() { return canvas_; } |
| 132 | |
| 133 | ExternalViewEmbedder* view_embedder() { return view_embedder_; } |
| 134 | |
| 135 | CompositorContext& context() const { return context_; } |
| 136 | |
| 137 | const SkMatrix& root_surface_transformation() const { |
| 138 | return root_surface_transformation_; |
| 139 | } |
| 140 | |
| 141 | bool surface_supports_readback() { return surface_supports_readback_; } |
| 142 | |
| 143 | GrDirectContext* gr_context() const { return gr_context_; } |
| 144 | |
| 145 | impeller::AiksContext* aiks_context() const { return aiks_context_; } |
| 146 | |
| 147 | virtual RasterStatus Raster(LayerTree& layer_tree, |
| 148 | bool ignore_raster_cache, |
| 149 | FrameDamage* frame_damage); |
| 150 | |
| 151 | private: |
| 152 | void PaintLayerTreeSkia(flutter::LayerTree& layer_tree, |
| 153 | std::optional<SkRect> clip_rect, |
| 154 | bool needs_save_layer, |
| 155 | bool ignore_raster_cache); |
| 156 | |
| 157 | void PaintLayerTreeImpeller(flutter::LayerTree& layer_tree, |
| 158 | std::optional<SkRect> clip_rect, |
| 159 | bool ignore_raster_cache); |
| 160 | |
| 161 | CompositorContext& context_; |
| 162 | GrDirectContext* gr_context_; |
| 163 | DlCanvas* canvas_; |
| 164 | impeller::AiksContext* aiks_context_; |
| 165 | ExternalViewEmbedder* view_embedder_; |
| 166 | const SkMatrix& root_surface_transformation_; |
| 167 | const bool instrumentation_enabled_; |
| 168 | const bool surface_supports_readback_; |
| 169 | fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger_; |
| 170 | |
| 171 | FML_DISALLOW_COPY_AND_ASSIGN(ScopedFrame); |
| 172 | }; |
| 173 | |
| 174 | CompositorContext(); |
| 175 | |
| 176 | explicit CompositorContext(Stopwatch::RefreshRateUpdater& updater); |
| 177 | |
| 178 | virtual ~CompositorContext(); |
| 179 | |
| 180 | virtual std::unique_ptr<ScopedFrame> AcquireFrame( |
| 181 | GrDirectContext* gr_context, |
| 182 | DlCanvas* canvas, |
| 183 | ExternalViewEmbedder* view_embedder, |
| 184 | const SkMatrix& root_surface_transformation, |
| 185 | bool instrumentation_enabled, |
| 186 | bool surface_supports_readback, |
| 187 | fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger, |
| 188 | impeller::AiksContext* aiks_context); |
| 189 | |
| 190 | void OnGrContextCreated(); |
| 191 | |
| 192 | void OnGrContextDestroyed(); |
| 193 | |
| 194 | RasterCache& raster_cache() { return raster_cache_; } |
| 195 | |
| 196 | std::shared_ptr<TextureRegistry> texture_registry() { |
| 197 | return texture_registry_; |
| 198 | } |
| 199 | |
| 200 | const Stopwatch& raster_time() const { return raster_time_; } |
| 201 | |
| 202 | Stopwatch& ui_time() { return ui_time_; } |
| 203 | |
| 204 | LayerSnapshotStore& snapshot_store() { return layer_snapshot_store_; } |
| 205 | |
| 206 | private: |
| 207 | RasterCache raster_cache_; |
| 208 | std::shared_ptr<TextureRegistry> texture_registry_; |
| 209 | Stopwatch raster_time_; |
| 210 | Stopwatch ui_time_; |
| 211 | LayerSnapshotStore layer_snapshot_store_; |
| 212 | |
| 213 | /// Only used by default constructor of `CompositorContext`. |
| 214 | FixedRefreshRateUpdater fixed_refresh_rate_updater_; |
| 215 | |
| 216 | void BeginFrame(ScopedFrame& frame, bool enable_instrumentation); |
| 217 | |
| 218 | void EndFrame(ScopedFrame& frame, bool enable_instrumentation); |
| 219 | |
| 220 | /// @brief Whether Impeller shouild attempt a partial repaint. |
| 221 | /// The Impeller backend requires an additional blit pass, which may |
| 222 | /// not be worthwhile if the damage region is large. |
| 223 | static bool ShouldPerformPartialRepaint(std::optional<SkRect> damage_rect, |
| 224 | SkISize layer_tree_size); |
| 225 | |
| 226 | FML_DISALLOW_COPY_AND_ASSIGN(CompositorContext); |
| 227 | }; |
| 228 | |
| 229 | } // namespace flutter |
| 230 | |
| 231 | #endif // FLUTTER_FLOW_COMPOSITOR_CONTEXT_H_ |
| 232 | |