rasterizer.h 22.4 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 The Flutter Authors. All rights reserved.
A
Adam Barth 已提交
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef SHELL_COMMON_RASTERIZER_H_
#define SHELL_COMMON_RASTERIZER_H_
A
Adam Barth 已提交
7 8

#include <memory>
9
#include <optional>
A
Adam Barth 已提交
10

11
#include "flutter/common/settings.h"
12
#include "flutter/common/task_runners.h"
13
#include "flutter/flow/compositor_context.h"
14 15
#include "flutter/flow/embedded_views.h"
#include "flutter/flow/frame_timings.h"
16
#include "flutter/flow/layers/layer_tree.h"
17
#include "flutter/flow/surface.h"
18
#include "flutter/fml/closure.h"
19
#include "flutter/fml/memory/weak_ptr.h"
20
#include "flutter/fml/raster_thread_merger.h"
21
#include "flutter/fml/synchronization/sync_switch.h"
22
#include "flutter/fml/synchronization/waitable_event.h"
23 24
#include "flutter/fml/time/time_delta.h"
#include "flutter/fml/time/time_point.h"
25
#include "flutter/lib/ui/snapshot_delegate.h"
26
#include "flutter/shell/common/pipeline.h"
A
Adam Barth 已提交
27

28
namespace flutter {
A
Adam Barth 已提交
29

30
//------------------------------------------------------------------------------
31
/// The rasterizer is a component owned by the shell that resides on the raster
32
/// task runner. Each shell owns exactly one instance of a rasterizer. The
33 34
/// rasterizer may only be created, used and collected on the raster task
/// runner.
35 36 37 38 39 40 41 42 43
///
/// The rasterizer owns the instance of the currently active on-screen render
/// surface. On this surface, it renders the contents of layer trees submitted
/// to it by the `Engine` (which lives on the UI task runner).
///
/// The primary components owned by the rasterizer are the compositor context
/// and the on-screen render surface. The compositor context has all the GPU
/// state necessary to render frames to the render surface.
///
44
class Rasterizer final : public SnapshotDelegate {
A
Adam Barth 已提交
45
 public:
46 47 48 49 50 51 52
  //----------------------------------------------------------------------------
  /// @brief      Used to forward events from the rasterizer to interested
  ///             subsystems. Currently, the shell sets itself up as the
  ///             rasterizer delegate to listen for frame rasterization events.
  ///             It can then forward these events to the engine.
  ///
  ///             Like all rasterizer operation, the rasterizer delegate call
53 54
  ///             are made on the raster task runner. Any delegate must ensure
  ///             that they can handle the threading implications.
55
  ///
D
Dan Field 已提交
56
  class Delegate {
57
   public:
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    //--------------------------------------------------------------------------
    /// @brief      Notifies the delegate that a frame has been rendered. The
    ///             rasterizer collects profiling information for each part of
    ///             the frame workload. This profiling information is made
    ///             available to the delegate for forwarding to subsystems
    ///             interested in collecting such profiles. Currently, the shell
    ///             (the delegate) forwards this to the engine where Dart code
    ///             can react to this information.
    ///
    /// @see        `FrameTiming`
    ///
    /// @param[in]  frame_timing  Instrumentation information for each phase of
    ///                           the frame workload.
    ///
    virtual void OnFrameRasterized(const FrameTiming& frame_timing) = 0;
73

74 75 76
    /// Time limit for a smooth frame.
    ///
    /// See: `DisplayManager::GetMainDisplayRefreshRate`.
77
    virtual fml::Milliseconds GetFrameBudget() = 0;
78 79 80 81

    /// Target time for the latest frame. See also `Shell::OnAnimatorBeginFrame`
    /// for when this time gets updated.
    virtual fml::TimePoint GetLatestFrameTargetTime() const = 0;
82

83 84
    /// Task runners used by the shell.
    virtual const TaskRunners& GetTaskRunners() const = 0;
85

86 87 88 89 90
    /// Accessor for the shell's GPU sync switch, which determines whether GPU
    /// operations are allowed on the current thread.
    ///
    /// For example, on some platforms when the application is backgrounded it
    /// is critical that GPU operations are not processed.
D
Dan Field 已提交
91
    virtual std::shared_ptr<const fml::SyncSwitch> GetIsGpuDisabledSyncSwitch()
92 93
        const = 0;
  };
D
Dan Field 已提交
94

95 96
  //----------------------------------------------------------------------------
  /// @brief      Creates a new instance of a rasterizer. Rasterizers may only
97 98 99
  ///             be created on the raster task runner. Rasterizers are
  ///             currently only created by the shell (which also sets itself up
  ///             as the rasterizer delegate).
100
  ///
101
  /// @param[in]  delegate            The rasterizer delegate.
102
  ///
103
  Rasterizer(Delegate& delegate);
104

105
  //----------------------------------------------------------------------------
106
  /// @brief      Destroys the rasterizer. This must happen on the raster task
107
  ///             runner. All GPU resources are collected before this call
108
  ///             returns. Any context set up by the embedder to hold these
109 110
  ///             resources can be immediately collected as well.
  ///
111
  ~Rasterizer();
112

113 114 115 116 117 118 119 120
  //----------------------------------------------------------------------------
  /// @brief      Rasterizers may be created well before an on-screen surface is
  ///             available for rendering. Shells usually create a rasterizer in
  ///             their constructors. Once an on-screen surface is available
  ///             however, one may be provided to the rasterizer using this
  ///             call. No rendering may occur before this call. The surface is
  ///             held till the balancing call to `Rasterizer::Teardown` is
  ///             made. Calling a setup before tearing down the previous surface
121
  ///             (if this is not the first time the surface has been set up) is
122 123 124 125 126 127
  ///             user error.
  ///
  /// @see        `Rasterizer::Teardown`
  ///
  /// @param[in]  surface  The on-screen render surface.
  ///
128
  void Setup(std::unique_ptr<Surface> surface);
129

130
  //----------------------------------------------------------------------------
131
  /// @brief      Releases the previously set up on-screen render surface and
132 133 134 135
  ///             collects associated resources. No more rendering may occur
  ///             till the next call to `Rasterizer::Setup` with a new render
  ///             surface. Calling a teardown without a setup is user error.
  ///
136
  void Teardown();
137

138 139 140 141 142 143
  //----------------------------------------------------------------------------
  /// @brief      Notifies the rasterizer that there is a low memory situation
  ///             and it must purge as many unnecessary resources as possible.
  ///             Currently, the Skia context associated with onscreen rendering
  ///             is told to free GPU resources.
  ///
144 145
  void NotifyLowMemoryWarning() const;

146 147
  //----------------------------------------------------------------------------
  /// @brief      Gets a weak pointer to the rasterizer. The rasterizer may only
148
  ///             be accessed on the raster task runner.
149 150 151
  ///
  /// @return     The weak pointer to the rasterizer.
  ///
152
  fml::TaskRunnerAffineWeakPtr<Rasterizer> GetWeakPtr() const;
A
Adam Barth 已提交
153

154
  fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> GetSnapshotDelegate() const;
155

156 157 158 159 160 161 162 163 164 165 166 167 168
  //----------------------------------------------------------------------------
  /// @brief      Sometimes, it may be necessary to render the same frame again
  ///             without having to wait for the framework to build a whole new
  ///             layer tree describing the same contents. One such case is when
  ///             external textures (video or camera streams for example) are
  ///             updated in an otherwise static layer tree. To support this use
  ///             case, the rasterizer holds onto the last rendered layer tree.
  ///
  /// @bug        https://github.com/flutter/flutter/issues/33939
  ///
  /// @return     A pointer to the last layer or `nullptr` if this rasterizer
  ///             has never rendered a frame.
  ///
169
  flutter::LayerTree* GetLastLayerTree();
170

171 172 173 174 175 176 177 178
  //----------------------------------------------------------------------------
  /// @brief      Draws a last layer tree to the render surface. This may seem
  ///             entirely redundant at first glance. After all, on surface loss
  ///             and re-acquisition, the framework generates a new layer tree.
  ///             Otherwise, why render the same contents to the screen again?
  ///             This is used as an optimization in cases where there are
  ///             external textures (video or camera streams for example) in
  ///             referenced in the layer tree. These textures may be updated at
D
Dan Field 已提交
179
  ///             a cadence different from that of the Flutter application.
180 181 182 183
  ///             Flutter can re-render the layer tree with just the updated
  ///             textures instead of waiting for the framework to do the work
  ///             to generate the layer tree describing the same contents.
  ///
184 185
  void DrawLastLayerTree(
      std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder);
186

187 188 189 190 191 192 193 194 195
  //----------------------------------------------------------------------------
  /// @brief      Gets the registry of external textures currently in use by the
  ///             rasterizer. These textures may be updated at a cadence
  ///             different from that of the Flutter application. When an
  ///             external texture is referenced in the Flutter layer tree, that
  ///             texture is composited within the Flutter layer tree.
  ///
  /// @return     A pointer to the external texture registry.
  ///
196
  flutter::TextureRegistry* GetTextureRegistry();
197

198 199
  using LayerTreeDiscardCallback = std::function<bool(flutter::LayerTree&)>;

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

235 236 237 238
  //----------------------------------------------------------------------------
  /// @brief      The type of the screenshot to obtain of the previously
  ///             rendered layer tree.
  ///
239
  enum class ScreenshotType {
240 241 242 243 244 245 246 247 248
    //--------------------------------------------------------------------------
    /// A format used to denote a Skia picture. A Skia picture is a serialized
    /// representation of an `SkPicture` that can be used to introspect the
    /// series of commands used to draw that picture.
    ///
    /// Skia pictures are typically stored as files with the .skp extension on
    /// disk. These files may be viewed in an interactive debugger available at
    /// https://debugger.skia.org/
    ///
249
    SkiaPicture,
250 251 252 253 254 255 256 257 258 259 260 261

    //--------------------------------------------------------------------------
    /// A format used to denote uncompressed image data. This format
    /// is 32 bits per pixel, 8 bits per component and
    /// denoted by the `kN32_SkColorType ` Skia color type.
    ///
    UncompressedImage,

    //--------------------------------------------------------------------------
    /// A format used to denote compressed image data. The PNG compressed
    /// container is used.
    ///
262 263
    CompressedImage,
  };
264

265 266 267 268
  //----------------------------------------------------------------------------
  /// @brief      A POD type used to return the screenshot data along with the
  ///             size of the frame.
  ///
269
  struct Screenshot {
270 271 272 273 274 275
    //--------------------------------------------------------------------------
    /// The data used to describe the screenshot. The data format depends on the
    /// type of screenshot taken and any further encoding done to the same.
    ///
    /// @see      `ScreenshotType`
    ///
276
    sk_sp<SkData> data;
277 278 279 280

    //--------------------------------------------------------------------------
    /// The size of the screenshot in texels.
    ///
281 282
    SkISize frame_size = SkISize::MakeEmpty();

283 284 285
    //--------------------------------------------------------------------------
    /// @brief      Creates an empty screenshot
    ///
286
    Screenshot();
287

288 289 290 291 292 293
    //--------------------------------------------------------------------------
    /// @brief      Creates a screenshot with the specified data and size.
    ///
    /// @param[in]  p_data  The screenshot data
    /// @param[in]  p_size  The screenshot size.
    ///
294 295
    Screenshot(sk_sp<SkData> p_data, SkISize p_size);

296 297 298 299 300
    //--------------------------------------------------------------------------
    /// @brief      The copy constructor for a screenshot.
    ///
    /// @param[in]  other  The screenshot to copy from.
    ///
301 302
    Screenshot(const Screenshot& other);

303 304 305
    //--------------------------------------------------------------------------
    /// @brief      Destroys the screenshot object and releases underlying data.
    ///
306
    ~Screenshot();
307 308
  };

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

326 327 328 329 330 331 332 333 334 335 336 337 338 339
  //----------------------------------------------------------------------------
  /// @brief      Sets a callback that will be executed when the next layer tree
  ///             in rendered to the on-screen surface. This is used by
  ///             embedders to listen for one time operations like listening for
  ///             when the first frame is rendered so that they may hide splash
  ///             screens.
  ///
  ///             The callback is only executed once and dropped on the GPU
  ///             thread when executed (lambda captures must be able to deal
  ///             with the threading repercussions of this behavior).
  ///
  /// @param[in]  callback  The callback to execute when the next layer tree is
  ///                       rendered on-screen.
  ///
340
  void SetNextFrameCallback(const fml::closure& callback);
341

342 343 344 345 346 347 348 349 350 351
  //----------------------------------------------------------------------------
  /// @brief Set the External View Embedder. This is done on shell
  ///        initialization. This is non-null on platforms that support
  ///        embedding externally composited views.
  ///
  /// @param[in] view_embedder The external view embedder object.
  ///
  void SetExternalViewEmbedder(
      const std::shared_ptr<ExternalViewEmbedder>& view_embedder);

352 353 354 355 356 357
  //----------------------------------------------------------------------------
  /// @brief      Returns a pointer to the compositor context used by this
  ///             rasterizer. This pointer will never be `nullptr`.
  ///
  /// @return     The compositor context used by this rasterizer.
  ///
358
  flutter::CompositorContext* compositor_context() {
359 360 361
    return compositor_context_.get();
  }

362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
  //----------------------------------------------------------------------------
  /// @brief      Skia has no notion of time. To work around the performance
  ///             implications of this, it may cache GPU resources to reference
  ///             them from one frame to the next. Using this call, embedders
  ///             may set the maximum bytes cached by Skia in its caches
  ///             dedicated to on-screen rendering.
  ///
  /// @attention  This cache setting will be invalidated when the surface is
  ///             torn down via `Rasterizer::Teardown`. This call must be made
  ///             again with new limits after surface re-acquisition.
  ///
  /// @attention  This cache does not describe the entirety of GPU resources
  ///             that may be cached. The `RasterCache` also holds very large
  ///             GPU resources.
  ///
  /// @see        `RasterCache`
  ///
  /// @param[in]  max_bytes  The maximum byte size of resource that may be
  ///                        cached for GPU rendering.
381 382 383
  /// @param[in]  from_user  Whether this request was from user code, e.g. via
  ///                        the flutter/skia message channel, in which case
  ///                        it should not be overridden by the platform.
384
  ///
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
  void SetResourceCacheMaxBytes(size_t max_bytes, bool from_user);

  //----------------------------------------------------------------------------
  /// @brief      The current value of Skia's resource cache size, if a surface
  ///             is present.
  ///
  /// @attention  This cache does not describe the entirety of GPU resources
  ///             that may be cached. The `RasterCache` also holds very large
  ///             GPU resources.
  ///
  /// @see        `RasterCache`
  ///
  /// @return     The size of Skia's resource cache, if available.
  ///
  std::optional<size_t> GetResourceCacheMaxBytes() const;
400

401
  //----------------------------------------------------------------------------
402 403
  /// @brief      Enables the thread merger if the external view embedder
  ///             supports dynamic thread merging.
404
  ///
405 406 407
  /// @attention  This method is thread-safe. When the thread merger is enabled,
  ///             the raster task queue can run in the platform thread at any
  ///             time.
408
  ///
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
  /// @see        `ExternalViewEmbedder`
  ///
  void EnableThreadMergerIfNeeded();

  //----------------------------------------------------------------------------
  /// @brief      Disables the thread merger if the external view embedder
  ///             supports dynamic thread merging.
  ///
  /// @attention  This method is thread-safe. When the thread merger is
  ///             disabled, the raster task queue will continue to run in the
  ///             same thread until |EnableThreadMergerIfNeeded| is called.
  ///
  /// @see        `ExternalViewEmbedder`
  ///
  void DisableThreadMergerIfNeeded();
424

425 426 427 428 429 430 431 432 433
  /// @brief   Mechanism to stop thread merging when using shared engine
  ///          components.
  /// @details This is a temporary workaround until thread merging can be
  ///          supported correctly.  This should be called on the raster
  ///          thread.
  /// @see     https://github.com/flutter/flutter/issues/73620
  ///
  void BlockThreadMerging() { shared_engine_block_thread_merging_ = true; }

434
 private:
435
  Delegate& delegate_;
436
  std::unique_ptr<Surface> surface_;
437
  std::unique_ptr<flutter::CompositorContext> compositor_context_;
438
  // This is the last successfully rasterized layer tree.
439
  std::unique_ptr<flutter::LayerTree> last_layer_tree_;
440 441
  // Set when we need attempt to rasterize the layer tree again. This layer_tree
  // has not successfully rasterized. This can happen due to the change in the
442
  // thread configuration. This will be inserted to the front of the pipeline.
443
  std::unique_ptr<flutter::LayerTree> resubmitted_layer_tree_;
444
  fml::closure next_frame_callback_;
445 446
  bool user_override_resource_cache_bytes_;
  std::optional<size_t> max_cache_bytes_;
447
  fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger_;
448
  fml::TaskRunnerAffineWeakPtrFactory<Rasterizer> weak_factory_;
449
  std::shared_ptr<ExternalViewEmbedder> external_view_embedder_;
450
  bool shared_engine_block_thread_merging_ = false;
451

452 453 454 455 456
  // |SnapshotDelegate|
  sk_sp<SkImage> MakeRasterSnapshot(
      std::function<void(SkCanvas*)> draw_callback,
      SkISize picture_size) override;

457 458 459 460
  // |SnapshotDelegate|
  sk_sp<SkImage> MakeRasterSnapshot(sk_sp<SkPicture> picture,
                                    SkISize picture_size) override;

461 462 463
  // |SnapshotDelegate|
  sk_sp<SkImage> ConvertToRasterImage(sk_sp<SkImage> image) override;

464 465 466
  sk_sp<SkData> ScreenshotLayerTreeAsImage(
      flutter::LayerTree* tree,
      flutter::CompositorContext& compositor_context,
467
      GrDirectContext* surface_context,
468 469
      bool compressed);

470 471 472 473
  sk_sp<SkImage> DoMakeRasterSnapshot(
      SkISize size,
      std::function<void(SkCanvas*)> draw_callback);

474 475 476
  RasterStatus DoDraw(
      std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
      std::unique_ptr<flutter::LayerTree> layer_tree);
477

478
  RasterStatus DrawToSurface(FrameTimingsRecorder& frame_timings_recorder,
479
                             flutter::LayerTree& layer_tree);
480 481 482

  void FireNextFrameCallbackIfPresent();

483 484
  static bool NoDiscard(const flutter::LayerTree& layer_tree) { return false; }

485
  FML_DISALLOW_COPY_AND_ASSIGN(Rasterizer);
A
Adam Barth 已提交
486 487
};

488
}  // namespace flutter
A
Adam Barth 已提交
489

490
#endif  // SHELL_COMMON_RASTERIZER_H_