diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index d1d43abf19779..daa6f0fe19e44 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -19,76 +19,362 @@ namespace flutter { -/// Takes |LayerTree|s and draws its contents. +//------------------------------------------------------------------------------ +/// The rasterizer is a component owned by the shell that resides on the GPU +/// task runner. Each shell owns exactly one instance of a rasterizer. The +/// rasterizer may only be created, used and collected on the GPU task runner. +/// +/// 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. +/// class Rasterizer final { public: + //---------------------------------------------------------------------------- + /// @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 + /// are made on the GPU task runner. Any delegate must ensure that + /// they can handle the threading implications. + /// class Delegate { public: - virtual void OnFrameRasterized(const FrameTiming&) = 0; + //-------------------------------------------------------------------------- + /// @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; }; + // TODO(dnfield): remove once embedders have caught up. class DummyDelegate : public Delegate { void OnFrameRasterized(const FrameTiming&) override {} }; + + //---------------------------------------------------------------------------- + /// @brief Creates a new instance of a rasterizer. Rasterizers may only + /// be created on the GPU task runner. Rasterizers are currently + /// only created by the shell. Usually, the shell also sets itself + /// up as the rasterizer delegate. But, this constructor sets up a + /// dummy rasterizer delegate. + /// + // TODO(chinmaygarde): The rasterizer does not use the task runners for + // anything other than thread checks. Remove the same as an argument. + /// + /// @param[in] task_runners The task runners used by the shell. + /// @param[in] compositor_context The compositor context used to hold all + /// the GPU state used by the rasterizer. + /// Rasterizer(TaskRunners task_runners, std::unique_ptr compositor_context); + //---------------------------------------------------------------------------- + /// @brief Creates a new instance of a rasterizer. Rasterizers may only + /// be created on the GPU task runner. Rasterizers are currently + /// only created by the shell (which also sets itself up as the + /// rasterizer delegate). + /// + // TODO(chinmaygarde): The rasterizer does not use the task runners for + // anything other than thread checks. Remove the same as an argument. + /// + /// @param[in] delegate The rasterizer delegate. + /// @param[in] task_runners The task runners used by the shell. + /// Rasterizer(Delegate& delegate, TaskRunners task_runners); + //---------------------------------------------------------------------------- + /// @brief Creates a new instance of a rasterizer. Rasterizers may only + /// be created on the GPU task runner. Rasterizers are currently + /// only created by the shell (which also sets itself up as the + /// rasterizer delegate). + /// + // TODO(chinmaygarde): The rasterizer does not use the task runners for + // anything other than thread checks. Remove the same as an argument. + /// + /// @param[in] delegate The rasterizer delegate. + /// @param[in] task_runners The task runners used by the shell. + /// @param[in] compositor_context The compositor context used to hold all + /// the GPU state used by the rasterizer. + /// Rasterizer(Delegate& delegate, TaskRunners task_runners, std::unique_ptr compositor_context); + //---------------------------------------------------------------------------- + /// @brief Destroys the rasterizer. This must happen on the GPU task + /// runner. All GPU resources are collected before this call + /// returns. Any context setup by the embedder to hold these + /// resources can be immediately collected as well. + /// ~Rasterizer(); + //---------------------------------------------------------------------------- + /// @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 + /// (if this is not the first time the surface has been setup) is + /// user error. + /// + /// @see `Rasterizer::Teardown` + /// + /// @param[in] surface The on-screen render surface. + /// void Setup(std::unique_ptr surface); + //---------------------------------------------------------------------------- + /// @brief Releases the previously setup on-screen render surface and + /// 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. + /// void Teardown(); - // Frees up Skia GPU resources. - // - // This method must be called from the GPU task runner. + //---------------------------------------------------------------------------- + /// @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. + /// void NotifyLowMemoryWarning() const; + //---------------------------------------------------------------------------- + /// @brief Gets a weak pointer to the rasterizer. The rasterizer may only + /// be accessed on the GPU task runner. + /// + /// @return The weak pointer to the rasterizer. + /// fml::WeakPtr GetWeakPtr() const; + //---------------------------------------------------------------------------- + /// @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. + /// flutter::LayerTree* GetLastLayerTree(); + //---------------------------------------------------------------------------- + /// @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 + /// a cadence different from that of the the Flutter application. + /// 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. + /// void DrawLastLayerTree(); + //---------------------------------------------------------------------------- + /// @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. + /// flutter::TextureRegistry* GetTextureRegistry(); + //---------------------------------------------------------------------------- + /// @brief Takes the next item from the layer tree pipeline and executes + /// the GPU thread frame workload for that pipeline item to render + /// a frame on the on-screen surface. + /// + /// Why does the draw call take a layer tree pipeline and not the + /// layer tree directly? + /// + /// 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. + /// + /// @see `Rasterizer::DoDraw` + /// + /// @param[in] pipeline The layer tree pipeline to take the next layer tree + /// to render from. + /// void Draw(fml::RefPtr> pipeline); + //---------------------------------------------------------------------------- + /// @brief The type of the screenshot to obtain of the previously + /// rendered layer tree. + /// enum class ScreenshotType { + //-------------------------------------------------------------------------- + /// 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/ + /// SkiaPicture, - UncompressedImage, // In kN32_SkColorType format + + //-------------------------------------------------------------------------- + /// 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. + /// CompressedImage, }; + //---------------------------------------------------------------------------- + /// @brief A POD type used to return the screenshot data along with the + /// size of the frame. + /// struct Screenshot { + //-------------------------------------------------------------------------- + /// 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` + /// sk_sp data; + + //-------------------------------------------------------------------------- + /// The size of the screenshot in texels. + /// SkISize frame_size = SkISize::MakeEmpty(); + //-------------------------------------------------------------------------- + /// @brief Creates an empty screenshot + /// Screenshot(); + //-------------------------------------------------------------------------- + /// @brief Creates a screenshot with the specified data and size. + /// + /// @param[in] p_data The screenshot data + /// @param[in] p_size The screenshot size. + /// Screenshot(sk_sp p_data, SkISize p_size); + //-------------------------------------------------------------------------- + /// @brief The copy constructor for a screenshot. + /// + /// @param[in] other The screenshot to copy from. + /// Screenshot(const Screenshot& other); + //-------------------------------------------------------------------------- + /// @brief Destroys the screenshot object and releases underlying data. + /// ~Screenshot(); }; + //---------------------------------------------------------------------------- + /// @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. + /// Screenshot ScreenshotLastLayerTree(ScreenshotType type, bool base64_encode); - // Sets a callback that will be executed after the next frame is submitted to - // the surface on the GPU task runner. + //---------------------------------------------------------------------------- + /// @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. + /// void SetNextFrameCallback(fml::closure callback); + //---------------------------------------------------------------------------- + /// @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. + /// flutter::CompositorContext* compositor_context() { return compositor_context_.get(); } + //---------------------------------------------------------------------------- + /// @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. + /// void SetResourceCacheMaxBytes(int max_bytes); private: