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 SHELL_COMMON_RASTERIZER_H_ 6 #define SHELL_COMMON_RASTERIZER_H_ 7 8 #include <memory> 9 #include <optional> 10 11 #include "flutter/common/settings.h" 12 #include "flutter/common/task_runners.h" 13 #include "flutter/flow/compositor_context.h" 14 #include "flutter/flow/layers/layer_tree.h" 15 #include "flutter/fml/closure.h" 16 #include "flutter/fml/gpu_thread_merger.h" 17 #include "flutter/fml/memory/weak_ptr.h" 18 #include "flutter/fml/synchronization/waitable_event.h" 19 #include "flutter/shell/common/pipeline.h" 20 #include "flutter/shell/common/surface.h" 21 22 namespace flutter { 23 24 //------------------------------------------------------------------------------ 25 /// The rasterizer is a component owned by the shell that resides on the GPU 26 /// task runner. Each shell owns exactly one instance of a rasterizer. The 27 /// rasterizer may only be created, used and collected on the GPU task runner. 28 /// 29 /// The rasterizer owns the instance of the currently active on-screen render 30 /// surface. On this surface, it renders the contents of layer trees submitted 31 /// to it by the `Engine` (which lives on the UI task runner). 32 /// 33 /// The primary components owned by the rasterizer are the compositor context 34 /// and the on-screen render surface. The compositor context has all the GPU 35 /// state necessary to render frames to the render surface. 36 /// 37 class Rasterizer final { 38 public: 39 //---------------------------------------------------------------------------- 40 /// @brief Used to forward events from the rasterizer to interested 41 /// subsystems. Currently, the shell sets itself up as the 42 /// rasterizer delegate to listen for frame rasterization events. 43 /// It can then forward these events to the engine. 44 /// 45 /// Like all rasterizer operation, the rasterizer delegate call 46 /// are made on the GPU task runner. Any delegate must ensure that 47 /// they can handle the threading implications. 48 /// 49 class Delegate { 50 public: 51 //-------------------------------------------------------------------------- 52 /// @brief Notifies the delegate that a frame has been rendered. The 53 /// rasterizer collects profiling information for each part of 54 /// the frame workload. This profiling information is made 55 /// available to the delegate for forwarding to subsystems 56 /// interested in collecting such profiles. Currently, the shell 57 /// (the delegate) forwards this to the engine where Dart code 58 /// can react to this information. 59 /// 60 /// @see `FrameTiming` 61 /// 62 /// @param[in] frame_timing Instrumentation information for each phase of 63 /// the frame workload. 64 /// 65 virtual void OnFrameRasterized(const FrameTiming& frame_timing) = 0; 66 }; 67 68 // TODO(dnfield): remove once embedders have caught up. 69 class DummyDelegate : public Delegate { OnFrameRasterized(const FrameTiming &)70 void OnFrameRasterized(const FrameTiming&) override {} 71 }; 72 73 //---------------------------------------------------------------------------- 74 /// @brief Creates a new instance of a rasterizer. Rasterizers may only 75 /// be created on the GPU task runner. Rasterizers are currently 76 /// only created by the shell. Usually, the shell also sets itself 77 /// up as the rasterizer delegate. But, this constructor sets up a 78 /// dummy rasterizer delegate. 79 /// 80 // TODO(chinmaygarde): The rasterizer does not use the task runners for 81 // anything other than thread checks. Remove the same as an argument. 82 /// 83 /// @param[in] task_runners The task runners used by the shell. 84 /// @param[in] compositor_context The compositor context used to hold all 85 /// the GPU state used by the rasterizer. 86 /// 87 Rasterizer(TaskRunners task_runners, 88 std::unique_ptr<flutter::CompositorContext> compositor_context); 89 90 //---------------------------------------------------------------------------- 91 /// @brief Creates a new instance of a rasterizer. Rasterizers may only 92 /// be created on the GPU task runner. Rasterizers are currently 93 /// only created by the shell (which also sets itself up as the 94 /// rasterizer delegate). 95 /// 96 // TODO(chinmaygarde): The rasterizer does not use the task runners for 97 // anything other than thread checks. Remove the same as an argument. 98 /// 99 /// @param[in] delegate The rasterizer delegate. 100 /// @param[in] task_runners The task runners used by the shell. 101 /// 102 Rasterizer(Delegate& delegate, TaskRunners task_runners); 103 104 //---------------------------------------------------------------------------- 105 /// @brief Creates a new instance of a rasterizer. Rasterizers may only 106 /// be created on the GPU task runner. Rasterizers are currently 107 /// only created by the shell (which also sets itself up as the 108 /// rasterizer delegate). 109 /// 110 // TODO(chinmaygarde): The rasterizer does not use the task runners for 111 // anything other than thread checks. Remove the same as an argument. 112 /// 113 /// @param[in] delegate The rasterizer delegate. 114 /// @param[in] task_runners The task runners used by the shell. 115 /// @param[in] compositor_context The compositor context used to hold all 116 /// the GPU state used by the rasterizer. 117 /// 118 Rasterizer(Delegate& delegate, 119 TaskRunners task_runners, 120 std::unique_ptr<flutter::CompositorContext> compositor_context); 121 122 //---------------------------------------------------------------------------- 123 /// @brief Destroys the rasterizer. This must happen on the GPU task 124 /// runner. All GPU resources are collected before this call 125 /// returns. Any context setup by the embedder to hold these 126 /// resources can be immediately collected as well. 127 /// 128 ~Rasterizer(); 129 130 //---------------------------------------------------------------------------- 131 /// @brief Rasterizers may be created well before an on-screen surface is 132 /// available for rendering. Shells usually create a rasterizer in 133 /// their constructors. Once an on-screen surface is available 134 /// however, one may be provided to the rasterizer using this 135 /// call. No rendering may occur before this call. The surface is 136 /// held till the balancing call to `Rasterizer::Teardown` is 137 /// made. Calling a setup before tearing down the previous surface 138 /// (if this is not the first time the surface has been setup) is 139 /// user error. 140 /// 141 /// @see `Rasterizer::Teardown` 142 /// 143 /// @param[in] surface The on-screen render surface. 144 /// 145 void Setup(std::unique_ptr<Surface> surface); 146 147 //---------------------------------------------------------------------------- 148 /// @brief Releases the previously setup on-screen render surface and 149 /// collects associated resources. No more rendering may occur 150 /// till the next call to `Rasterizer::Setup` with a new render 151 /// surface. Calling a teardown without a setup is user error. 152 /// 153 void Teardown(); 154 155 //---------------------------------------------------------------------------- 156 /// @brief Notifies the rasterizer that there is a low memory situation 157 /// and it must purge as many unnecessary resources as possible. 158 /// Currently, the Skia context associated with onscreen rendering 159 /// is told to free GPU resources. 160 /// 161 void NotifyLowMemoryWarning() const; 162 163 //---------------------------------------------------------------------------- 164 /// @brief Gets a weak pointer to the rasterizer. The rasterizer may only 165 /// be accessed on the GPU task runner. 166 /// 167 /// @return The weak pointer to the rasterizer. 168 /// 169 fml::WeakPtr<Rasterizer> GetWeakPtr() const; 170 171 //---------------------------------------------------------------------------- 172 /// @brief Sometimes, it may be necessary to render the same frame again 173 /// without having to wait for the framework to build a whole new 174 /// layer tree describing the same contents. One such case is when 175 /// external textures (video or camera streams for example) are 176 /// updated in an otherwise static layer tree. To support this use 177 /// case, the rasterizer holds onto the last rendered layer tree. 178 /// 179 /// @bug https://github.com/flutter/flutter/issues/33939 180 /// 181 /// @return A pointer to the last layer or `nullptr` if this rasterizer 182 /// has never rendered a frame. 183 /// 184 flutter::LayerTree* GetLastLayerTree(); 185 186 //---------------------------------------------------------------------------- 187 /// @brief Draws a last layer tree to the render surface. This may seem 188 /// entirely redundant at first glance. After all, on surface loss 189 /// and re-acquisition, the framework generates a new layer tree. 190 /// Otherwise, why render the same contents to the screen again? 191 /// This is used as an optimization in cases where there are 192 /// external textures (video or camera streams for example) in 193 /// referenced in the layer tree. These textures may be updated at 194 /// a cadence different from that of the the Flutter application. 195 /// Flutter can re-render the layer tree with just the updated 196 /// textures instead of waiting for the framework to do the work 197 /// to generate the layer tree describing the same contents. 198 /// 199 void DrawLastLayerTree(); 200 201 //---------------------------------------------------------------------------- 202 /// @brief Gets the registry of external textures currently in use by the 203 /// rasterizer. These textures may be updated at a cadence 204 /// different from that of the Flutter application. When an 205 /// external texture is referenced in the Flutter layer tree, that 206 /// texture is composited within the Flutter layer tree. 207 /// 208 /// @return A pointer to the external texture registry. 209 /// 210 flutter::TextureRegistry* GetTextureRegistry(); 211 212 //---------------------------------------------------------------------------- 213 /// @brief Takes the next item from the layer tree pipeline and executes 214 /// the GPU thread frame workload for that pipeline item to render 215 /// a frame on the on-screen surface. 216 /// 217 /// Why does the draw call take a layer tree pipeline and not the 218 /// layer tree directly? 219 /// 220 /// The pipeline is the way book-keeping of frame workloads 221 /// distributed across the multiple threads is managed. The 222 /// rasterizer deals with the pipelines directly (instead of layer 223 /// trees which is what it actually renders) because the pipeline 224 /// consumer's workload must be accounted for within the pipeline 225 /// itself. If the rasterizer took the layer tree directly, it 226 /// would have to be taken out of the pipeline. That would signal 227 /// the end of the frame workload and the pipeline would be ready 228 /// for new frames. But the last frame has not been rendered by 229 /// the frame yet! On the other hand, the pipeline must own the 230 /// layer tree it renders because it keeps a reference to the last 231 /// layer tree around till a new frame is rendered. So a simple 232 /// reference wont work either. The `Rasterizer::DoDraw` method 233 /// actually performs the GPU operations within the layer tree 234 /// pipeline. 235 /// 236 /// @see `Rasterizer::DoDraw` 237 /// 238 /// @param[in] pipeline The layer tree pipeline to take the next layer tree 239 /// to render from. 240 /// 241 void Draw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline); 242 243 //---------------------------------------------------------------------------- 244 /// @brief The type of the screenshot to obtain of the previously 245 /// rendered layer tree. 246 /// 247 enum class ScreenshotType { 248 //-------------------------------------------------------------------------- 249 /// A format used to denote a Skia picture. A Skia picture is a serialized 250 /// representation of an `SkPicture` that can be used to introspect the 251 /// series of commands used to draw that picture. 252 /// 253 /// Skia pictures are typically stored as files with the .skp extension on 254 /// disk. These files may be viewed in an interactive debugger available at 255 /// https://debugger.skia.org/ 256 /// 257 SkiaPicture, 258 259 //-------------------------------------------------------------------------- 260 /// A format used to denote uncompressed image data. This format 261 /// is 32 bits per pixel, 8 bits per component and 262 /// denoted by the `kN32_SkColorType ` Skia color type. 263 /// 264 UncompressedImage, 265 266 //-------------------------------------------------------------------------- 267 /// A format used to denote compressed image data. The PNG compressed 268 /// container is used. 269 /// 270 CompressedImage, 271 }; 272 273 //---------------------------------------------------------------------------- 274 /// @brief A POD type used to return the screenshot data along with the 275 /// size of the frame. 276 /// 277 struct Screenshot { 278 //-------------------------------------------------------------------------- 279 /// The data used to describe the screenshot. The data format depends on the 280 /// type of screenshot taken and any further encoding done to the same. 281 /// 282 /// @see `ScreenshotType` 283 /// 284 sk_sp<SkData> data; 285 286 //-------------------------------------------------------------------------- 287 /// The size of the screenshot in texels. 288 /// 289 SkISize frame_size = SkISize::MakeEmpty(); 290 291 //-------------------------------------------------------------------------- 292 /// @brief Creates an empty screenshot 293 /// 294 Screenshot(); 295 296 //-------------------------------------------------------------------------- 297 /// @brief Creates a screenshot with the specified data and size. 298 /// 299 /// @param[in] p_data The screenshot data 300 /// @param[in] p_size The screenshot size. 301 /// 302 Screenshot(sk_sp<SkData> p_data, SkISize p_size); 303 304 //-------------------------------------------------------------------------- 305 /// @brief The copy constructor for a screenshot. 306 /// 307 /// @param[in] other The screenshot to copy from. 308 /// 309 Screenshot(const Screenshot& other); 310 311 //-------------------------------------------------------------------------- 312 /// @brief Destroys the screenshot object and releases underlying data. 313 /// 314 ~Screenshot(); 315 }; 316 317 //---------------------------------------------------------------------------- 318 /// @brief Screenshots the last layer tree to one of the supported 319 /// screenshot types and optionally Base 64 encodes that data for 320 /// easier transmission and packaging (usually over the service 321 /// protocol for instrumentation tools running on the host). 322 /// 323 /// @param[in] type The type of the screenshot to gather. 324 /// @param[in] base64_encode Whether Base 64 encoding must be applied to the 325 /// data after a screenshot has been captured. 326 /// 327 /// @return A non-empty screenshot if one could be captured. A screenshot 328 /// capture may fail if there were no layer trees previously 329 /// rendered by this rasterizer, or, due to an unspecified 330 /// internal error. Internal error will be logged to the console. 331 /// 332 Screenshot ScreenshotLastLayerTree(ScreenshotType type, bool base64_encode); 333 334 //---------------------------------------------------------------------------- 335 /// @brief Sets a callback that will be executed when the next layer tree 336 /// in rendered to the on-screen surface. This is used by 337 /// embedders to listen for one time operations like listening for 338 /// when the first frame is rendered so that they may hide splash 339 /// screens. 340 /// 341 /// The callback is only executed once and dropped on the GPU 342 /// thread when executed (lambda captures must be able to deal 343 /// with the threading repercussions of this behavior). 344 /// 345 /// @param[in] callback The callback to execute when the next layer tree is 346 /// rendered on-screen. 347 /// 348 void SetNextFrameCallback(fml::closure callback); 349 350 //---------------------------------------------------------------------------- 351 /// @brief Returns a pointer to the compositor context used by this 352 /// rasterizer. This pointer will never be `nullptr`. 353 /// 354 /// @return The compositor context used by this rasterizer. 355 /// compositor_context()356 flutter::CompositorContext* compositor_context() { 357 return compositor_context_.get(); 358 } 359 360 //---------------------------------------------------------------------------- 361 /// @brief Skia has no notion of time. To work around the performance 362 /// implications of this, it may cache GPU resources to reference 363 /// them from one frame to the next. Using this call, embedders 364 /// may set the maximum bytes cached by Skia in its caches 365 /// dedicated to on-screen rendering. 366 /// 367 /// @attention This cache setting will be invalidated when the surface is 368 /// torn down via `Rasterizer::Teardown`. This call must be made 369 /// again with new limits after surface re-acquisition. 370 /// 371 /// @attention This cache does not describe the entirety of GPU resources 372 /// that may be cached. The `RasterCache` also holds very large 373 /// GPU resources. 374 /// 375 /// @see `RasterCache` 376 /// 377 /// @param[in] max_bytes The maximum byte size of resource that may be 378 /// cached for GPU rendering. 379 /// @param[in] from_user Whether this request was from user code, e.g. via 380 /// the flutter/skia message channel, in which case 381 /// it should not be overridden by the platform. 382 /// 383 void SetResourceCacheMaxBytes(size_t max_bytes, bool from_user); 384 385 //---------------------------------------------------------------------------- 386 /// @brief The current value of Skia's resource cache size, if a surface 387 /// is present. 388 /// 389 /// @attention This cache does not describe the entirety of GPU resources 390 /// that may be cached. The `RasterCache` also holds very large 391 /// GPU resources. 392 /// 393 /// @see `RasterCache` 394 /// 395 /// @return The size of Skia's resource cache, if available. 396 /// 397 std::optional<size_t> GetResourceCacheMaxBytes() const; 398 399 private: 400 Delegate& delegate_; 401 TaskRunners task_runners_; 402 std::unique_ptr<Surface> surface_; 403 std::unique_ptr<flutter::CompositorContext> compositor_context_; 404 // This is the last successfully rasterized layer tree. 405 std::unique_ptr<flutter::LayerTree> last_layer_tree_; 406 // Set when we need attempt to rasterize the layer tree again. This layer_tree 407 // has not successfully rasterized. This can happen due to the change in the 408 // thread configuration. This will be inserted to the front of the pipeline. 409 std::unique_ptr<flutter::LayerTree> resubmitted_layer_tree_; 410 fml::closure next_frame_callback_; 411 bool user_override_resource_cache_bytes_; 412 std::optional<size_t> max_cache_bytes_; 413 fml::WeakPtrFactory<Rasterizer> weak_factory_; 414 fml::RefPtr<fml::GpuThreadMerger> gpu_thread_merger_; 415 416 RasterStatus DoDraw(std::unique_ptr<flutter::LayerTree> layer_tree); 417 418 RasterStatus DrawToSurface(flutter::LayerTree& layer_tree); 419 420 void FireNextFrameCallbackIfPresent(); 421 422 FML_DISALLOW_COPY_AND_ASSIGN(Rasterizer); 423 }; 424 425 } // namespace flutter 426 427 #endif // SHELL_COMMON_RASTERIZER_H_ 428