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 COMMON_PLATFORM_VIEW_H_ 6 #define COMMON_PLATFORM_VIEW_H_ 7 8 #include <memory> 9 10 #include "flutter/common/task_runners.h" 11 #include "flutter/flow/texture.h" 12 #include "flutter/fml/macros.h" 13 #include "flutter/fml/memory/weak_ptr.h" 14 #include "flutter/lib/ui/window/platform_message.h" 15 #include "flutter/lib/ui/window/pointer_data_packet.h" 16 #include "flutter/lib/ui/window/viewport_metrics.h" 17 #include "flutter/shell/common/surface.h" 18 #include "flutter/shell/common/vsync_waiter.h" 19 #include "third_party/skia/include/core/SkSize.h" 20 #include "third_party/skia/include/gpu/GrContext.h" 21 22 namespace flutter { 23 using IdleCallback = std::function<void(int64_t)>; 24 25 class Shell; 26 27 //------------------------------------------------------------------------------ 28 /// @brief Platform views are created by the shell on the platform task 29 /// runner. Unless explicitly specified, all platform view methods 30 /// are called on the platform task runner as well. Platform views 31 /// are usually sub-classed on a per platform basis and the bulk of 32 /// the window system integration happens using that subclass. Since 33 /// most platform window toolkits are usually only safe to access on 34 /// a single "main" thread, any interaction that requires access to 35 /// the underlying platform's window toolkit is routed through the 36 /// platform view associated with that shell. This involves 37 /// operations like settings up and tearing down the render surface, 38 /// platform messages, interacting with accessibility features on 39 /// the platform, input events, etc. 40 /// 41 class PlatformView { 42 public: 43 //---------------------------------------------------------------------------- 44 /// @brief Used to forward events from the platform view to interested 45 /// subsystems. This forwarding is done by the shell which sets 46 /// itself up as the delegate of the platform view. 47 /// 48 class Delegate { 49 public: 50 //-------------------------------------------------------------------------- 51 /// @brief Notifies the delegate that the platform view was created 52 /// with the given render surface. This surface is platform 53 /// (iOS, Android) and client-rendering API (OpenGL, Software, 54 /// Metal, Vulkan) specific. This is usually a sign to the 55 /// rasterizer to setup and begin rendering to that surface. 56 /// 57 /// @param[in] surface The surface 58 /// 59 virtual void OnPlatformViewCreated(std::unique_ptr<Surface> surface) = 0; 60 61 //-------------------------------------------------------------------------- 62 /// @brief Notifies the delegate that the platform view was destroyed. 63 /// This is usually a sign to the rasterizer to suspend 64 /// rendering a previously configured surface and collect any 65 /// intermediate resources. 66 /// 67 virtual void OnPlatformViewDestroyed() = 0; 68 69 //-------------------------------------------------------------------------- 70 /// @brief Notifies the delegate that the specified callback needs to 71 /// be invoked after the rasterizer is done rendering the next 72 /// frame. This callback will be called on the render thread and 73 /// it is caller responsibility to perform any re-threading as 74 /// necessary. Due to the asynchronous nature of rendering in 75 /// Flutter, embedders usually add a placeholder over the 76 /// contents in which Flutter is going to render when Flutter is 77 /// first initialized. This callback may be used as a signal to 78 /// remove that placeholder. 79 /// 80 /// @attention The callback will be invoked on the render thread and not 81 /// the calling thread. 82 /// 83 /// @param[in] closure The callback to execute on the next frame. 84 /// 85 virtual void OnPlatformViewSetNextFrameCallback(fml::closure closure) = 0; 86 87 //-------------------------------------------------------------------------- 88 /// @brief ACE PC preview. 89 /// 90 virtual void OnSetIdleNotificationCallback(const IdleCallback& idleCallback) = 0; 91 92 //-------------------------------------------------------------------------- 93 /// @brief Notifies the delegate the viewport metrics of the platform 94 /// view have been updated. The rasterizer will need to be 95 /// reconfigured to render the frame in the updated viewport 96 /// metrics. 97 /// 98 /// @param[in] metrics The updated viewport metrics. 99 /// 100 virtual void OnPlatformViewSetViewportMetrics( 101 const ViewportMetrics& metrics) = 0; 102 103 //-------------------------------------------------------------------------- 104 /// @brief Notifies the delegate that the platform has dispatched a 105 /// platform message from the embedder to the Flutter 106 /// application. This message must be forwarded to the running 107 /// isolate hosted by the engine on the UI thread. 108 /// 109 /// @param[in] message The platform message to dispatch to the running 110 /// root isolate. 111 /// 112 virtual void OnPlatformViewDispatchPlatformMessage( 113 fml::RefPtr<PlatformMessage> message) = 0; 114 115 //-------------------------------------------------------------------------- 116 /// @brief Notifies the delegate that the platform view has encountered 117 /// a pointer event. This pointer event needs to be forwarded to 118 /// the running root isolate hosted by the engine on the UI 119 /// thread. 120 /// 121 /// @param[in] packet The pointer data packet containing multiple pointer 122 /// events. 123 /// 124 virtual void OnPlatformViewDispatchPointerDataPacket( 125 std::unique_ptr<PointerDataPacket> packet) = 0; 126 127 //-------------------------------------------------------------------------- 128 /// @brief Notifies the delegate that the embedder has specified a 129 /// texture that it want the rasterizer to composite within the 130 /// Flutter layer tree. All textures must have a unique 131 /// identifier. When the rasterizer encounters an external 132 /// texture within its hierarchy, it gives the embedder a chance 133 /// to update that texture on the GPU thread before it 134 /// composites the same on-screen. 135 /// 136 /// @param[in] texture The texture that is being updated by the embedder 137 /// but composited by Flutter in its own hierarchy. 138 /// 139 virtual void OnPlatformViewRegisterTexture( 140 std::shared_ptr<Texture> texture) = 0; 141 142 //-------------------------------------------------------------------------- 143 /// @brief Notifies the delegate that the embedder will no longer 144 /// attempt to composite the specified texture within the layer 145 /// tree. This allows the rasterizer to collect associated 146 /// resources. 147 /// 148 /// @param[in] texture_id The identifier of the texture to unregister. If 149 /// the texture has not been previously registered, 150 /// this call does nothing. 151 /// 152 virtual void OnPlatformViewUnregisterTexture(int64_t texture_id) = 0; 153 154 //-------------------------------------------------------------------------- 155 /// @brief Notifies the delegate that the embedder has updated the 156 /// contents of the texture with the specified identifier. 157 /// Typically, Flutter will only render a frame if there is an 158 /// updated layer tree. However, in cases where the layer tree 159 /// is static but one of the externally composited textures has 160 /// been updated by the embedder, the embedder needs to notify 161 /// the rasterizer to render a new frame. In such cases, the 162 /// existing layer tree may be reused with the frame composited 163 /// with all updated external textures. 164 /// 165 /// @param[in] texture_id The identifier of the texture that has been 166 /// updated. 167 /// 168 virtual void OnPlatformViewMarkTextureFrameAvailable( 169 int64_t texture_id) = 0; 170 }; 171 172 //---------------------------------------------------------------------------- 173 /// @brief Creates a platform view with the specified delegate and task 174 /// runner. The base class by itself does not do much but is 175 /// suitable for use in test environments where full platform 176 /// integration may not be necessary. The platform view may only 177 /// be created, accessed and destroyed on the platform task 178 /// runner. 179 /// 180 /// @param delegate The delegate. This is typically the shell. 181 /// @param[in] task_runners The task runners used by this platform view. 182 /// 183 explicit PlatformView(Delegate& delegate, TaskRunners task_runners); 184 185 //---------------------------------------------------------------------------- 186 /// @brief Destroys the platform view. The platform view is owned by the 187 /// shell and will be destroyed by the same on the platform tasks 188 /// runner. 189 /// 190 virtual ~PlatformView(); 191 192 //---------------------------------------------------------------------------- 193 /// @brief Invoked by the shell to obtain a platform specific vsync 194 /// waiter. It is optional for platforms to override this method 195 /// and provide a custom vsync waiter because a timer based 196 /// fall-back waiter is used by default. However, it is highly 197 /// recommended that platform provide their own Vsync waiter as 198 /// the timer based fall-back will not render frames aligned with 199 /// vsync boundaries. 200 /// 201 /// @attention If a timer based fall-back is used, a warning is logged to the 202 /// console. In case this method is overridden in a subclass, it 203 /// must return a valid vsync waiter. Returning null will lead to 204 /// internal errors. If a valid vsync waiter cannot be returned, 205 /// subclasses should just call the based class method instead. 206 /// 207 /// @return A vsync waiter. If is an internal error to return a null 208 /// waiter. 209 /// 210 virtual std::unique_ptr<VsyncWaiter> CreateVSyncWaiter(int32_t platform); 211 212 //---------------------------------------------------------------------------- 213 /// @brief Used by embedders to dispatch a platform message to a 214 /// running root isolate hosted by the engine. If an isolate is 215 /// not running, the message is dropped. If there is no one on the 216 /// other side listening on the channel, the message is dropped. 217 /// When a platform message is dropped, any response handles 218 /// associated with that message will be dropped as well. All 219 /// users of platform messages must assume that message may not be 220 /// delivered and/or their response handles may not be invoked. 221 /// Platform messages are not buffered. 222 /// 223 /// For embedders that wish to respond to platform message 224 /// directed from the framework to the embedder, the 225 /// `HandlePlatformMessage` method may be overridden. 226 /// 227 /// @see HandlePlatformMessage() 228 /// 229 /// @param[in] message The platform message to deliver to the root isolate. 230 /// 231 void DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message); 232 233 //---------------------------------------------------------------------------- 234 /// @brief Overridden by embedders to perform actions in response to 235 /// platform messages sent from the framework to the embedder. 236 /// Default implementation of this method simply returns an empty 237 /// response. 238 /// 239 /// Embedders that wish to send platform messages to the framework 240 /// may use the `DispatchPlatformMessage` method. This method is 241 /// for messages that go the other way. 242 /// 243 /// @see DisplatchPlatformMessage() 244 /// 245 /// @param[in] message The message 246 /// 247 virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message); 248 249 //---------------------------------------------------------------------------- 250 /// @brief Ace PC preivew 251 /// 252 void SetIdleNotificationCallback(const IdleCallback& idleCallback); 253 254 //---------------------------------------------------------------------------- 255 /// @brief Used by embedders to specify the updated viewport metrics. In 256 /// response to this call, on the GPU thread, the rasterizer may 257 /// need to be reconfigured to the updated viewport dimensions. On 258 /// the UI thread, the framework may need to start generating a 259 /// new frame for the updated viewport metrics as well. 260 /// 261 /// @param[in] metrics The updated viewport metrics. 262 /// 263 void SetViewportMetrics(const ViewportMetrics& metrics); 264 265 //---------------------------------------------------------------------------- 266 /// @brief Used by embedders to notify the shell that a platform view 267 /// has been created. This notification is used to create a 268 /// rendering surface and pick the client rendering API to use to 269 /// render into this surface. No frames will be scheduled or 270 /// rendered before this call. The surface must remain valid till 271 /// the corresponding call to NotifyDestroyed. 272 /// 273 void NotifyCreated(); 274 275 //---------------------------------------------------------------------------- 276 /// @brief Used by embedders to notify the shell that the platform view 277 /// has been destroyed. This notification used to collect the 278 /// rendering surface and all associated resources. Frame 279 /// scheduling is also suspended. 280 /// 281 /// @attention Subclasses may choose to override this method to perform 282 /// platform specific functions. However, they must call the base 283 /// class method at some point in their implementation. 284 /// 285 virtual void NotifyDestroyed(); 286 287 //---------------------------------------------------------------------------- 288 /// @brief Used by the shell to obtain a Skia GPU context that is capable 289 /// of operating on the IO thread. The context must be in the same 290 /// share-group as the Skia GPU context used on the render thread. 291 /// This context will always be used on the IO thread. Because it 292 /// is in the same share-group as the separate render thread 293 /// context, any GPU resources uploaded in this context will be 294 /// visible to the render thread context (synchronization of GPU 295 /// resources is managed by Skia). 296 /// 297 /// If such context cannot be created on the IO thread, callers 298 /// may return `nullptr`. This will mean that all texture uploads 299 /// will be queued onto the render thread which will cause 300 /// performance issues. When this context is `nullptr`, an error 301 /// is logged to the console. It is highly recommended that all 302 /// platforms provide a resource context. 303 /// 304 /// @attention Unlike all other methods on the platform view, this will be 305 /// called on IO task runner. 306 /// 307 /// @return The Skia GPU context that is in the same share-group as the 308 /// main render thread GPU context. May be `nullptr` in case such 309 /// a context cannot be created. 310 /// 311 virtual sk_sp<GrContext> CreateResourceContext() const; 312 313 //---------------------------------------------------------------------------- 314 /// @brief Used by the shell to notify the embedder that the resource 315 /// context previously obtained via a call to 316 /// `CreateResourceContext()` is being collected. The embedder is 317 /// free to collect an platform specific resources associated with 318 /// this context. 319 /// 320 /// @attention Unlike all other methods on the platform view, this will be 321 /// called on IO task runner. 322 /// 323 virtual void ReleaseResourceContext() const; 324 325 //---------------------------------------------------------------------------- 326 /// @brief Returns a weak pointer to the platform view. Since the 327 /// platform view may only be created, accessed and destroyed on 328 /// the platform thread, any access to the platform view from a 329 /// non-platform task runner needs a weak pointer to the platform 330 /// view along with a reference to the platform task runner. A 331 /// task must be posted to the platform task runner with the weak 332 /// pointer captured in the same. The platform view method may 333 /// only be called in the posted task once the weak pointer 334 /// validity has been checked. This method is used by callers to 335 /// obtain that weak pointer. 336 /// 337 /// @return The weak pointer to the platform view. 338 /// 339 fml::WeakPtr<PlatformView> GetWeakPtr() const; 340 341 //---------------------------------------------------------------------------- 342 /// @brief Gives embedders a chance to react to a "cold restart" of the 343 /// running isolate. The default implementation of this method 344 /// does nothing. 345 /// 346 /// While a "hot restart" patches a running isolate, a "cold 347 /// restart" restarts the root isolate in a running shell. 348 /// 349 virtual void OnPreEngineRestart() const; 350 351 //---------------------------------------------------------------------------- 352 /// @brief Sets a callback that gets executed when the rasterizer renders 353 /// the next frame. Due to the asynchronous nature of rendering in 354 /// Flutter, embedders usually add a placeholder over the 355 /// contents in which Flutter is going to render when Flutter is 356 /// first initialized. This callback may be used as a signal to 357 /// remove that placeholder. The callback is executed on the 358 /// render task runner and not the platform task runner. It is 359 /// the embedder's responsibility to re-thread as necessary. 360 /// 361 /// @attention The callback is executed on the render task runner and not the 362 /// platform task runner. Embedders must re-thread as necessary. 363 /// 364 /// @param[in] closure The callback to execute on the render thread when the 365 /// next frame gets rendered. 366 /// 367 void SetNextFrameCallback(fml::closure closure); 368 369 //---------------------------------------------------------------------------- 370 /// @brief Dispatches pointer events from the embedder to the 371 /// framework. Each pointer data packet may contain multiple 372 /// pointer input events. Each call to this method wakes up the UI 373 /// thread. 374 /// 375 /// @param[in] packet The pointer data packet to dispatch to the framework. 376 /// 377 void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet); 378 379 //-------------------------------------------------------------------------- 380 /// @brief Used by the embedder to specify a texture that it wants the 381 /// rasterizer to composite within the Flutter layer tree. All 382 /// textures must have a unique identifier. When the rasterizer 383 /// encounters an external texture within its hierarchy, it gives 384 /// the embedder a chance to update that texture on the GPU thread 385 /// before it composites the same on-screen. 386 /// 387 /// @attention This method must only be called once per texture. When the 388 /// texture is updated, calling `MarkTextureFrameAvailable` with 389 /// the specified texture identifier is sufficient to make Flutter 390 /// re-render the frame with the updated texture composited 391 /// in-line. 392 /// 393 /// @see UnregisterTexture, MarkTextureFrameAvailable 394 /// 395 /// @param[in] texture The texture that is being updated by the embedder 396 /// but composited by Flutter in its own hierarchy. 397 /// 398 void RegisterTexture(std::shared_ptr<flutter::Texture> texture); 399 400 //-------------------------------------------------------------------------- 401 /// @brief Used by the embedder to notify the rasterizer that it will no 402 /// longer attempt to composite the specified texture within the 403 /// layer tree. This allows the rasterizer to collect associated 404 /// resources. 405 /// 406 /// @attention This call must only be called once per texture identifier. 407 /// 408 /// @see RegisterTexture, MarkTextureFrameAvailable 409 /// 410 /// @param[in] texture_id The identifier of the texture to unregister. If 411 /// the texture has not been previously registered, 412 /// this call does nothing. 413 /// 414 void UnregisterTexture(int64_t texture_id); 415 416 //-------------------------------------------------------------------------- 417 /// @brief Used by the embedder to notify the rasterizer that the context 418 /// of the previously registered texture have been updated. 419 /// Typically, Flutter will only render a frame if there is an 420 /// updated layer tree. However, in cases where the layer tree 421 /// is static but one of the externally composited textures has 422 /// been updated by the embedder, the embedder needs to notify 423 /// the rasterizer to render a new frame. In such cases, the 424 /// existing layer tree may be reused with the frame re-composited 425 /// with all updated external textures. Unlike the calls to 426 /// register and unregister the texture, this call must be made 427 /// each time a new texture frame is available. 428 /// 429 /// @see RegisterTexture, UnregisterTexture 430 /// 431 /// @param[in] texture_id The identifier of the texture that has been 432 /// updated. 433 /// 434 void MarkTextureFrameAvailable(int64_t texture_id); 435 436 protected: 437 PlatformView::Delegate& delegate_; 438 const TaskRunners task_runners_; 439 440 SkISize size_; 441 fml::WeakPtrFactory<PlatformView> weak_factory_; 442 443 // Unlike all other methods on the platform view, this is called on the GPU 444 // task runner. 445 virtual std::unique_ptr<Surface> CreateRenderingSurface(); 446 447 private: 448 FML_DISALLOW_COPY_AND_ASSIGN(PlatformView); 449 }; 450 451 } // namespace flutter 452 453 #endif // COMMON_PLATFORM_VIEW_H_ 454