| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef FLUTTER_SHELL_COMMON_RASTERIZER_H_ | |
| #define FLUTTER_SHELL_COMMON_RASTERIZER_H_ | |
| #include <memory> | |
| #include <optional> | |
| #include <unordered_map> | |
| #include "flutter/common/settings.h" | |
| #include "flutter/common/task_runners.h" | |
| #include "flutter/display_list/image/dl_image.h" | |
| #include "flutter/flow/compositor_context.h" | |
| #include "flutter/flow/embedded_views.h" | |
| #include "flutter/flow/frame_timings.h" | |
| #include "flutter/flow/layers/layer_tree.h" | |
| #include "flutter/flow/surface.h" | |
| #include "flutter/fml/closure.h" | |
| #include "flutter/fml/memory/weak_ptr.h" | |
| #include "flutter/fml/raster_thread_merger.h" | |
| #include "flutter/fml/synchronization/sync_switch.h" | |
| #include "flutter/fml/synchronization/waitable_event.h" | |
| #include "flutter/fml/time/time_delta.h" | |
| #include "flutter/fml/time/time_point.h" | |
| #if IMPELLER_SUPPORTS_RENDERING | |
| #include "impeller/aiks/aiks_context.h" // nogncheck | |
| #include "impeller/core/formats.h" // nogncheck | |
| #include "impeller/renderer/context.h" // nogncheck | |
| #include "impeller/typographer/backends/skia/typographer_context_skia.h" // nogncheck | |
| #endif // IMPELLER_SUPPORTS_RENDERING | |
| #include "flutter/lib/ui/snapshot_delegate.h" | |
| #include "flutter/shell/common/pipeline.h" | |
| #include "flutter/shell/common/snapshot_controller.h" | |
| #include "flutter/shell/common/snapshot_surface_producer.h" | |
| #include "third_party/skia/include/core/SkData.h" | |
| #include "third_party/skia/include/core/SkImage.h" | |
| #include "third_party/skia/include/core/SkRect.h" | |
| #include "third_party/skia/include/core/SkRefCnt.h" | |
| #include "third_party/skia/include/gpu/GrDirectContext.h" | |
| #if !IMPELLER_SUPPORTS_RENDERING | |
| namespace impeller { | |
| class Context; | |
| class AiksContext; | |
| } // namespace impeller | |
| #endif // !IMPELLER_SUPPORTS_RENDERING | |
| namespace flutter { | |
| // The result status of Rasterizer::Draw. This is only used for unit tests. | |
| enum class DrawStatus { | |
| // The drawing was done without any specified status. | |
| kDone, | |
| // Failed to rasterize the frame because the Rasterizer is not set up. | |
| kNotSetUp, | |
| // Nothing was done, because the call was not on the raster thread. Yielded to | |
| // let this frame be serviced on the right thread. | |
| kYielded, | |
| // Nothing was done, because the pipeline was empty. | |
| kPipelineEmpty, | |
| // Nothing was done, because the GPU was unavailable. | |
| kGpuUnavailable, | |
| }; | |
| // The result status of drawing to a view. This is only used for unit tests. | |
| enum class DrawSurfaceStatus { | |
| // The layer tree was successfully rasterized. | |
| kSuccess, | |
| // The layer tree must be submitted again. | |
| // | |
| // This can occur on Android when switching the background surface to | |
| // FlutterImageView. On Android, the first frame doesn't make the image | |
| // available to the ImageReader right away. The second frame does. | |
| // TODO(egarciad): https://github.com/flutter/flutter/issues/65652 | |
| // | |
| // This can also occur when the frame is dropped to wait for the thread | |
| // merger to merge the raster and platform threads. | |
| kRetry, | |
| // Failed to rasterize the frame. | |
| kFailed, | |
| // Layer tree was discarded because its size does not match the view size. | |
| // This typically occurs during resizing. | |
| kDiscarded, | |
| }; | |
| // The information to draw to all views of a frame. | |
| struct FrameItem { | |
| FrameItem(std::vector<std::unique_ptr<LayerTreeTask>> tasks, | |
| std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) | |
| : layer_tree_tasks(std::move(tasks)), | |
| frame_timings_recorder(std::move(frame_timings_recorder)) {} | |
| std::vector<std::unique_ptr<LayerTreeTask>> layer_tree_tasks; | |
| std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder; | |
| }; | |
| using FramePipeline = Pipeline<FrameItem>; | |
| //------------------------------------------------------------------------------ | |
| /// The rasterizer is a component owned by the shell that resides on the raster | |
| /// task runner. Each shell owns exactly one instance of a rasterizer. The | |
| /// rasterizer may only be created, used and collected on the raster 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 SnapshotDelegate, | |
| public Stopwatch::RefreshRateUpdater, | |
| public SnapshotController::Delegate { | |
| 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 raster task runner. Any delegate must ensure | |
| /// that they can handle the threading implications. | |
| /// | |
| class Delegate { | |
| public: | |
| //-------------------------------------------------------------------------- | |
| /// @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; | |
| /// Time limit for a smooth frame. | |
| /// | |
| /// See: `DisplayManager::GetMainDisplayRefreshRate`. | |
| virtual fml::Milliseconds GetFrameBudget() = 0; | |
| /// Target time for the latest frame. See also `Shell::OnAnimatorBeginFrame` | |
| /// for when this time gets updated. | |
| virtual fml::TimePoint GetLatestFrameTargetTime() const = 0; | |
| /// Task runners used by the shell. | |
| virtual const TaskRunners& GetTaskRunners() const = 0; | |
| /// The raster thread merger from parent shell's rasterizer. | |
| virtual const fml::RefPtr<fml::RasterThreadMerger> | |
| GetParentRasterThreadMerger() const = 0; | |
| /// 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. | |
| virtual std::shared_ptr<const fml::SyncSwitch> GetIsGpuDisabledSyncSwitch() | |
| const = 0; | |
| virtual const Settings& GetSettings() const = 0; | |
| virtual bool ShouldDiscardLayerTree(int64_t view_id, | |
| const flutter::LayerTree& tree) = 0; | |
| }; | |
| //---------------------------------------------------------------------------- | |
| /// @brief How to handle calls to MakeSkiaGpuImage. | |
| enum class MakeGpuImageBehavior { | |
| /// MakeSkiaGpuImage returns a GPU resident image, if possible. | |
| kGpu, | |
| /// MakeSkiaGpuImage returns a checkerboard bitmap. This is useful in test | |
| /// contexts where no GPU surface is available. | |
| kBitmap, | |
| }; | |
| //---------------------------------------------------------------------------- | |
| /// @brief Creates a new instance of a rasterizer. Rasterizers may only | |
| /// be created on the raster task runner. Rasterizers are | |
| /// currently only created by the shell (which also sets itself up | |
| /// as the rasterizer delegate). | |
| /// | |
| /// @param[in] delegate The rasterizer delegate. | |
| /// @param[in] gpu_image_behavior How to handle calls to | |
| /// MakeSkiaGpuImage. | |
| /// | |
| explicit Rasterizer( | |
| Delegate& delegate, | |
| MakeGpuImageBehavior gpu_image_behavior = MakeGpuImageBehavior::kGpu); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Destroys the rasterizer. This must happen on the raster task | |
| /// runner. All GPU resources are collected before this call | |
| /// returns. Any context set up by the embedder to hold these | |
| /// resources can be immediately collected as well. | |
| /// | |
| ~Rasterizer(); | |
| void SetImpellerContext(std::weak_ptr<impeller::Context> impeller_context); | |
| //---------------------------------------------------------------------------- | |
| /// @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 set up) is | |
| /// user error. | |
| /// | |
| /// @see `Rasterizer::Teardown` | |
| /// | |
| /// @param[in] surface The on-screen render surface. | |
| /// | |
| void Setup(std::unique_ptr<Surface> surface); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Releases the previously set up 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. | |
| /// Calling this method multiple times is safe. | |
| /// | |
| void Teardown(); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Releases any resource used by the external view embedder. | |
| /// For example, overlay surfaces or Android views. | |
| /// On Android, this method post a task to the platform thread, | |
| /// and waits until it completes. | |
| void TeardownExternalViewEmbedder(); | |
| //---------------------------------------------------------------------------- | |
| /// @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 raster task runner. | |
| /// | |
| /// @return The weak pointer to the rasterizer. | |
| /// | |
| fml::TaskRunnerAffineWeakPtr<Rasterizer> GetWeakPtr() const; | |
| fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> GetSnapshotDelegate() const; | |
| //---------------------------------------------------------------------------- | |
| /// @brief Deallocate the resources for displaying a view. | |
| /// | |
| /// This method must be called on the raster task runner when a | |
| /// view is removed from the engine. | |
| /// | |
| /// When the rasterizer is requested to draw an unrecognized view, | |
| /// it implicitly allocates necessary resources. These resources | |
| /// must be explicitly deallocated. | |
| /// | |
| /// @param[in] view_id The ID of the view. | |
| /// | |
| void CollectView(int64_t view_id); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Returns the last successfully drawn layer tree for the given | |
| /// view, or nullptr if there isn't any. This is useful during | |
| /// `DrawLastLayerTrees` and computing frame damage. | |
| /// | |
| /// @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 to the given view. | |
| /// | |
| flutter::LayerTree* GetLastLayerTree(int64_t view_id); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Draws the last layer trees with their last configuration. 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 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. | |
| /// | |
| /// Calling this method clears all last layer trees | |
| /// (GetLastLayerTree). | |
| /// | |
| void DrawLastLayerTrees( | |
| std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder); | |
| // |SnapshotDelegate| | |
| GrDirectContext* GetGrContext() override; | |
| std::shared_ptr<flutter::TextureRegistry> GetTextureRegistry() override; | |
| //---------------------------------------------------------------------------- | |
| /// @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. | |
| /// | |
| /// 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. | |
| /// | |
| DrawStatus Draw(const std::shared_ptr<FramePipeline>& pipeline); | |
| //---------------------------------------------------------------------------- | |
| /// @brief The type of the screenshot to obtain of the previously | |
| /// rendered layer tree. | |
| /// | |
| enum class ScreenshotType { | |
| // NOLINTBEGIN(readability-identifier-naming) | |
| //-------------------------------------------------------------------------- | |
| /// 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, | |
| //-------------------------------------------------------------------------- | |
| /// A format used to denote uncompressed image data. For Skia, this format | |
| /// is 32 bits per pixel, 8 bits per component and | |
| /// denoted by the `kN32_SkColorType ` Skia color type. For Impeller, its | |
| /// format is specified in Screenshot::pixel_format. | |
| /// | |
| UncompressedImage, | |
| //-------------------------------------------------------------------------- | |
| /// A format used to denote compressed image data. The PNG compressed | |
| /// container is used. | |
| /// | |
| CompressedImage, | |
| //-------------------------------------------------------------------------- | |
| /// Reads the data directly from the Rasterizer's surface. The pixel format | |
| /// is determined from the surface. This is the only way to read wide gamut | |
| /// color data, but isn't supported everywhere. | |
| SurfaceData, | |
| // NOLINTEND(readability-identifier-naming) | |
| }; | |
| // Specifies the format of pixel data in a Screenshot. | |
| enum class ScreenshotFormat { | |
| // Unknown format, or Skia default. | |
| kUnknown, | |
| // RGBA 8 bits per channel. | |
| kR8G8B8A8UNormInt, | |
| // BGRA 8 bits per channel. | |
| kB8G8R8A8UNormInt, | |
| // RGBA 16 bit floating point per channel. | |
| kR16G16B16A16Float, | |
| }; | |
| //---------------------------------------------------------------------------- | |
| /// @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<SkData> data; | |
| //-------------------------------------------------------------------------- | |
| /// The size of the screenshot in texels. | |
| /// | |
| SkISize frame_size = SkISize::MakeEmpty(); | |
| //-------------------------------------------------------------------------- | |
| /// Characterization of the format of the data in `data`. | |
| /// | |
| std::string format; | |
| //-------------------------------------------------------------------------- | |
| /// The pixel format of the data in `data`. | |
| /// | |
| /// If the impeller backend is not used, this value is always kUnknown and | |
| /// the data is in RGBA8888 format. | |
| ScreenshotFormat pixel_format = ScreenshotFormat::kUnknown; | |
| //-------------------------------------------------------------------------- | |
| /// @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. | |
| /// @param[in] p_format The screenshot format. | |
| /// @param[in] p_pixel_format The screenshot format. | |
| /// | |
| Screenshot(sk_sp<SkData> p_data, | |
| SkISize p_size, | |
| const std::string& p_format, | |
| ScreenshotFormat p_pixel_format); | |
| //-------------------------------------------------------------------------- | |
| /// @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); | |
| //---------------------------------------------------------------------------- | |
| /// @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(const fml::closure& callback); | |
| //---------------------------------------------------------------------------- | |
| /// @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); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Set the snapshot surface producer. This is done on shell | |
| /// initialization. This is non-null on platforms that support taking | |
| /// GPU accelerated raster snapshots in the background. | |
| /// | |
| /// @param[in] producer A surface producer for raster snapshotting when the | |
| /// onscreen surface is not available. | |
| /// | |
| void SetSnapshotSurfaceProducer( | |
| std::unique_ptr<SnapshotSurfaceProducer> producer); | |
| //---------------------------------------------------------------------------- | |
| /// @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 Returns the raster thread merger used by this rasterizer. | |
| /// This may be `nullptr`. | |
| /// | |
| /// @return The raster thread merger used by this rasterizer. | |
| /// | |
| fml::RefPtr<fml::RasterThreadMerger> GetRasterThreadMerger(); | |
| //---------------------------------------------------------------------------- | |
| /// @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. | |
| /// @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. | |
| /// | |
| 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; | |
| //---------------------------------------------------------------------------- | |
| /// @brief Enables the thread merger if the external view embedder | |
| /// supports dynamic thread merging. | |
| /// | |
| /// @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. | |
| /// | |
| /// @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(); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Returns whether TearDown has been called. | |
| /// | |
| /// This method is used only in unit tests. | |
| /// | |
| bool IsTornDown(); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Returns the last status of drawing the specific view. | |
| /// | |
| /// This method is used only in unit tests. | |
| /// | |
| std::optional<DrawSurfaceStatus> GetLastDrawStatus(int64_t view_id); | |
| private: | |
| // The result status of DoDraw, DrawToSurfaces, and DrawToSurfacesUnsafe. | |
| enum class DoDrawStatus { | |
| // The drawing was done without any specified status. | |
| kDone, | |
| // Frame has been successfully rasterized, but there are additional items | |
| // in the pipeline waiting to be consumed. This is currently only used when | |
| // thread configuration change occurs. | |
| kEnqueuePipeline, | |
| // Failed to rasterize the frame because the Rasterizer is not set up. | |
| kNotSetUp, | |
| // Nothing was done, because GPU was unavailable. | |
| kGpuUnavailable, | |
| }; | |
| // The result of DoDraw. | |
| struct DoDrawResult { | |
| // The overall status of the drawing process. | |
| // | |
| // The status of drawing a specific view is available at GetLastDrawStatus. | |
| DoDrawStatus status = DoDrawStatus::kDone; | |
| // The frame item that needs to be submitted again. | |
| // | |
| // See RasterStatus::kResubmit and kSkipAndRetry for when it happens. | |
| // | |
| // If `resubmitted_item` is not null, its `tasks` is guaranteed to be | |
| // non-empty. | |
| std::unique_ptr<FrameItem> resubmitted_item; | |
| }; | |
| struct ViewRecord { | |
| std::unique_ptr<LayerTreeTask> last_successful_task; | |
| std::optional<DrawSurfaceStatus> last_draw_status; | |
| }; | |
| // |SnapshotDelegate| | |
| std::unique_ptr<GpuImageResult> MakeSkiaGpuImage( | |
| sk_sp<DisplayList> display_list, | |
| const SkImageInfo& image_info) override; | |
| // |SnapshotDelegate| | |
| sk_sp<DlImage> MakeRasterSnapshot(sk_sp<DisplayList> display_list, | |
| SkISize picture_size) override; | |
| // |SnapshotDelegate| | |
| sk_sp<SkImage> ConvertToRasterImage(sk_sp<SkImage> image) override; | |
| // |Stopwatch::Delegate| | |
| /// Time limit for a smooth frame. | |
| /// | |
| /// See: `DisplayManager::GetMainDisplayRefreshRate`. | |
| fml::Milliseconds GetFrameBudget() const override; | |
| // |SnapshotController::Delegate| | |
| const std::unique_ptr<Surface>& GetSurface() const override { | |
| return surface_; | |
| } | |
| // |SnapshotController::Delegate| | |
| std::shared_ptr<impeller::AiksContext> GetAiksContext() const override { | |
| #if IMPELLER_SUPPORTS_RENDERING | |
| if (surface_) { | |
| return surface_->GetAiksContext(); | |
| } | |
| if (auto context = impeller_context_.lock()) { | |
| return std::make_shared<impeller::AiksContext>( | |
| context, impeller::TypographerContextSkia::Make()); | |
| } | |
| #endif | |
| return nullptr; | |
| } | |
| // |SnapshotController::Delegate| | |
| const std::unique_ptr<SnapshotSurfaceProducer>& GetSnapshotSurfaceProducer() | |
| const override { | |
| return snapshot_surface_producer_; | |
| } | |
| // |SnapshotController::Delegate| | |
| std::shared_ptr<const fml::SyncSwitch> GetIsGpuDisabledSyncSwitch() | |
| const override { | |
| return delegate_.GetIsGpuDisabledSyncSwitch(); | |
| } | |
| std::pair<sk_sp<SkData>, ScreenshotFormat> ScreenshotLayerTreeAsImage( | |
| flutter::LayerTree* tree, | |
| flutter::CompositorContext& compositor_context, | |
| bool compressed); | |
| // This method starts with the frame timing recorder at build end. This | |
| // method might push it to raster end and get the recorded time, or abort in | |
| // the middle and not get the recorded time. | |
| DoDrawResult DoDraw( | |
| std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder, | |
| std::vector<std::unique_ptr<LayerTreeTask>> tasks); | |
| // This method pushes the frame timing recorder from build end to raster end. | |
| DoDrawResult DrawToSurfaces( | |
| FrameTimingsRecorder& frame_timings_recorder, | |
| std::vector<std::unique_ptr<LayerTreeTask>> tasks); | |
| // Draws the specified layer trees to views, assuming we have access to the | |
| // GPU. | |
| // | |
| // If any layer trees need resubmitting, this method returns the frame item to | |
| // be resubmitted. Otherwise, it returns nullptr. | |
| // | |
| // Unsafe because it assumes we have access to the GPU which isn't the case | |
| // when iOS is backgrounded, for example. | |
| // | |
| // This method pushes the frame timing recorder from build end to raster end. | |
| std::unique_ptr<FrameItem> DrawToSurfacesUnsafe( | |
| FrameTimingsRecorder& frame_timings_recorder, | |
| std::vector<std::unique_ptr<LayerTreeTask>> tasks); | |
| // Draws the layer tree to the specified view, assuming we have access to the | |
| // GPU. | |
| // | |
| // This method is not affiliated with the frame timing recorder, but must be | |
| // included between the RasterStart and RasterEnd. | |
| DrawSurfaceStatus DrawToSurfaceUnsafe( | |
| int64_t view_id, | |
| flutter::LayerTree& layer_tree, | |
| float device_pixel_ratio, | |
| std::optional<fml::TimePoint> presentation_time); | |
| ViewRecord& EnsureViewRecord(int64_t view_id); | |
| void FireNextFrameCallbackIfPresent(); | |
| static bool ShouldResubmitFrame(const DoDrawResult& result); | |
| static DrawStatus ToDrawStatus(DoDrawStatus status); | |
| bool is_torn_down_ = false; | |
| Delegate& delegate_; | |
| MakeGpuImageBehavior gpu_image_behavior_; | |
| std::weak_ptr<impeller::Context> impeller_context_; | |
| std::unique_ptr<Surface> surface_; | |
| std::unique_ptr<SnapshotSurfaceProducer> snapshot_surface_producer_; | |
| std::unique_ptr<flutter::CompositorContext> compositor_context_; | |
| std::unordered_map<int64_t, ViewRecord> view_records_; | |
| fml::closure next_frame_callback_; | |
| bool user_override_resource_cache_bytes_ = false; | |
| std::optional<size_t> max_cache_bytes_; | |
| fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger_; | |
| std::shared_ptr<ExternalViewEmbedder> external_view_embedder_; | |
| std::unique_ptr<SnapshotController> snapshot_controller_; | |
| // WeakPtrFactory must be the last member. | |
| fml::TaskRunnerAffineWeakPtrFactory<Rasterizer> weak_factory_; | |
| FML_DISALLOW_COPY_AND_ASSIGN(Rasterizer); | |
| }; | |
| } // namespace flutter | |
| #endif // FLUTTER_SHELL_COMMON_RASTERIZER_H_ |