Silk.rst (25128B)
1 Silk Overview 2 ========================== 3 4 .. image:: SilkArchitecture.png 5 6 Architecture 7 ------------ 8 9 Our current architecture is to align three components to hardware vsync 10 timers: 11 12 1. Compositor 13 2. RefreshDriver / Painting 14 3. Input Events 15 16 The flow of our rendering engine is as follows: 17 18 1. Hardware Vsync event occurs on an OS specific *Hardware Vsync Thread* 19 on a per monitor basis. 20 2. The *Hardware Vsync Thread* attached to the monitor notifies the 21 ``CompositorVsyncDispatchers`` and ``VsyncDispatcher``. 22 3. For every Firefox window on the specific monitor, notify a 23 ``CompositorVsyncDispatcher``. The ``CompositorVsyncDispatcher`` is 24 specific to one window. 25 4. The ``CompositorVsyncDispatcher`` notifies a 26 ``CompositorWidgetVsyncObserver`` when remote compositing, or a 27 ``CompositorVsyncScheduler::Observer`` when compositing in-process. 28 5. If remote compositing, a vsync notification is sent from the 29 ``CompositorWidgetVsyncObserver`` to the ``VsyncBridgeChild`` on the 30 UI process, which sends an IPDL message to the ``VsyncBridgeParent`` 31 on the compositor thread of the GPU process, which then dispatches to 32 ``CompositorVsyncScheduler::Observer``. 33 6. The ``VsyncDispatcher`` notifies the Chrome 34 ``RefreshTimer`` that a vsync has occurred. 35 7. The ``VsyncDispatcher`` sends IPC messages to all content 36 processes to tick their respective active ``RefreshTimer``. 37 8. The ``Compositor`` dispatches input events on the *Compositor 38 Thread*, then composites. Input events are only dispatched on the 39 *Compositor Thread* on b2g. 40 9. The ``RefreshDriver`` paints on the *Main Thread*. 41 42 Hardware Vsync 43 -------------- 44 45 Hardware vsync events from (1), occur on a specific ``Display`` Object. 46 The ``Display`` object is responsible for enabling / disabling vsync on 47 a per connected display basis. For example, if two monitors are 48 connected, two ``Display`` objects will be created, each listening to 49 vsync events for their respective displays. We require one ``Display`` 50 object per monitor as each monitor may have different vsync rates. As a 51 fallback solution, we have one global ``Display`` object that can 52 synchronize across all connected displays. The global ``Display`` is 53 useful if a window is positioned halfway between the two monitors. Each 54 platform will have to implement a specific ``Display`` object to hook 55 and listen to vsync events. As of this writing, both Firefox OS and OS X 56 create their own hardware specific *Hardware Vsync Thread* that executes 57 after a vsync has occurred. OS X creates one *Hardware Vsync Thread* per 58 ``CVDisplayLinkRef``. We do not currently support multiple displays, so 59 we use one global ``CVDisplayLinkRef`` that works across all active 60 displays. On Windows, we have to create a new platform ``thread`` that 61 waits for DwmFlush(), which works across all active displays. Once the 62 thread wakes up from DwmFlush(), the actual vsync timestamp is retrieved 63 from DwmGetCompositionTimingInfo(), which is the timestamp that is 64 actually passed into the compositor and refresh driver. 65 66 When a vsync occurs on a ``Display``, the *Hardware Vsync Thread* 67 callback fetches all ``CompositorVsyncDispatchers`` associated with the 68 ``Display``. Each ``CompositorVsyncDispatcher`` is notified that a vsync 69 has occurred with the vsync’s timestamp. It is the responsibility of the 70 ``CompositorVsyncDispatcher`` to notify the ``Compositor`` that is 71 awaiting vsync notifications. The ``Display`` will then notify the 72 associated ``VsyncDispatcher``, which should notify all 73 active ``RefreshDrivers`` to tick. 74 75 All ``Display`` objects are encapsulated in a ``VsyncSource`` object. 76 The ``VsyncSource`` object lives in ``gfxPlatform`` and is instantiated 77 only on the parent process when ``gfxPlatform`` is created. The 78 ``VsyncSource`` is destroyed when ``gfxPlatform`` is destroyed. It can 79 also be destroyed when the layout frame rate pref (or other prefs that 80 influence frame rate) are changed. This may mean we switch from hardware 81 to software vsync (or vice versa) at runtime. During the switch, there 82 may briefly be 2 vsync sources. Otherwise, there is only one 83 ``VsyncSource`` object throughout the entire lifetime of Firefox. Each 84 platform is expected to implement their own ``VsyncSource`` to manage 85 vsync events. On OS X, this is through ``CVDisplayLinkRef``. On 86 Windows, it should be through ``DwmGetCompositionTimingInfo``. 87 88 Compositor 89 ---------- 90 91 When the ``CompositorVsyncDispatcher`` is notified of the vsync event, 92 the ``CompositorVsyncScheduler::Observer`` associated with the 93 ``CompositorVsyncDispatcher`` begins execution. Since the 94 ``CompositorVsyncDispatcher`` executes on the *Hardware Vsync Thread* 95 and the ``Compositor`` composites on the ``CompositorThread``, the 96 ``CompositorVsyncScheduler::Observer`` posts a task to the 97 ``CompositorThread``. The ``CompositorBridgeParent`` then composites. 98 The model where the ``CompositorVsyncDispatcher`` notifies components on 99 the *Hardware Vsync Thread*, and the component schedules the task on the 100 appropriate thread is used everywhere. 101 102 The ``CompositorVsyncScheduler::Observer`` listens to vsync events as 103 needed and stops listening to vsync when composites are no longer 104 scheduled or required. Every ``CompositorBridgeParent`` is associated 105 and tied to one ``CompositorVsyncScheduler::Observer``, which is 106 associated with the ``CompositorVsyncDispatcher``. Each 107 ``CompositorBridgeParent`` is associated with one widget and is created 108 when a new platform window or ``nsIWidget`` is created. The 109 ``CompositorBridgeParent``, ``CompositorVsyncDispatcher``, 110 ``CompositorVsyncScheduler::Observer``, and ``nsIWidget`` all have 111 the same lifetimes, which are created and destroyed together. 112 113 Out-of-process Compositors 114 -------------------------- 115 116 When compositing out-of-process, this model changes slightly. In this 117 case there are effectively two observers: a UI process observer 118 (``CompositorWidgetVsyncObserver``), and the 119 ``CompositorVsyncScheduler::Observer`` in the GPU process. There are 120 also two dispatchers: the widget dispatcher in the UI process 121 (``CompositorVsyncDispatcher``), and the IPDL-based dispatcher in the 122 GPU process (``CompositorBridgeParent::NotifyVsync``). The UI process 123 observer and the GPU process dispatcher are linked via an IPDL protocol 124 called PVsyncBridge. ``PVsyncBridge`` is a top-level protocol for 125 sending vsync notifications to the compositor thread in the GPU process. 126 The compositor controls vsync observation through a separate actor, 127 ``PCompositorWidget``, which (as a subactor for 128 ``CompositorBridgeChild``) links the compositor thread in the GPU 129 process to the main thread in the UI process. 130 131 Out-of-process compositors do not go through 132 ``CompositorVsyncDispatcher`` directly. Instead, the 133 ``CompositorWidgetDelegate`` in the UI process creates one, and gives it 134 a ``CompositorWidgetVsyncObserver``. This observer forwards 135 notifications to a Vsync I/O thread, where ``VsyncBridgeChild`` then 136 forwards the notification again to the compositor thread in the GPU 137 process. The notification is received by a ``VsyncBridgeParent``. The 138 GPU process uses the layers ID in the notification to find the correct 139 compositor to dispatch the notification to. 140 141 CompositorVsyncDispatcher 142 ------------------------- 143 144 The ``CompositorVsyncDispatcher`` executes on the *Hardware Vsync 145 Thread*. It contains references to the ``nsIWidget`` it is associated 146 with and has a lifetime equal to the ``nsIWidget``. The 147 ``CompositorVsyncDispatcher`` is responsible for notifying the 148 ``CompositorBridgeParent`` that a vsync event has occurred. There can be 149 multiple ``CompositorVsyncDispatchers`` per ``Display``, one 150 ``CompositorVsyncDispatcher`` per window. The only responsibility of the 151 ``CompositorVsyncDispatcher`` is to notify components when a vsync event 152 has occurred, and to stop listening to vsync when no components require 153 vsync events. We require one ``CompositorVsyncDispatcher`` per window so 154 that we can handle multiple ``Displays``. When compositing in-process, 155 the ``CompositorVsyncDispatcher`` is attached to the CompositorWidget 156 for the window. When out-of-process, it is attached to the 157 CompositorWidgetDelegate, which forwards observer notifications over 158 IPDL. In the latter case, its lifetime is tied to a CompositorSession 159 rather than the nsIWidget. 160 161 Multiple Displays 162 ----------------- 163 164 The ``VsyncSource`` has an API to switch a ``CompositorVsyncDispatcher`` 165 from one ``Display`` to another ``Display``. For example, when one 166 window either goes into full screen mode or moves from one connected 167 monitor to another. When one window moves to another monitor, we expect 168 a platform specific notification to occur. The detection of when a 169 window enters full screen mode or moves is not covered by Silk itself, 170 but the framework is built to support this use case. The expected flow 171 is that the OS notification occurs on ``nsIWidget``, which retrieves the 172 associated ``CompositorVsyncDispatcher``. The 173 ``CompositorVsyncDispatcher`` then notifies the ``VsyncSource`` to 174 switch to the correct ``Display`` the ``CompositorVsyncDispatcher`` is 175 connected to. Because the notification works through the ``nsIWidget``, 176 the actual switching of the ``CompositorVsyncDispatcher`` to the correct 177 ``Display`` should occur on the *Main Thread*. The current 178 implementation of Silk does not handle this case and needs to be built 179 out. 180 181 CompositorVsyncScheduler::Observer 182 ---------------------------------- 183 184 The ``CompositorVsyncScheduler::Observer`` handles the vsync 185 notifications and interactions with the ``CompositorVsyncDispatcher``. 186 When the ``Compositor`` requires a scheduled composite, it notifies the 187 ``CompositorVsyncScheduler::Observer`` that it needs to listen to vsync. 188 The ``CompositorVsyncScheduler::Observer`` then observes / unobserves 189 vsync as needed from the ``CompositorVsyncDispatcher`` to enable 190 composites. 191 192 GeckoTouchDispatcher 193 -------------------- 194 195 The ``GeckoTouchDispatcher`` is a singleton that resamples touch events 196 to smooth out jank while tracking a user’s finger. Because input and 197 composite are linked together, the 198 ``CompositorVsyncScheduler::Observer`` has a reference to the 199 ``GeckoTouchDispatcher`` and vice versa. 200 201 Input Events 202 ------------ 203 204 One large goal of Silk is to align touch events with vsync events. On 205 Firefox OS, touchscreens often have different touch scan rates than the 206 display refreshes. A Flame device has a touch refresh rate of 75 HZ, 207 while a Nexus 4 has a touch refresh rate of 100 HZ, while the device’s 208 display refresh rate is 60HZ. When a vsync event occurs, we resample 209 touch events, and then dispatch the resampled touch event to APZ. Touch 210 events on Firefox OS occur on a *Touch Input Thread* whereas they are 211 processed by APZ on the *APZ Controller Thread*. We use `Google 212 Android’s touch 213 resampling <https://web.archive.org/web/20200909082458/http://www.masonchang.com/blog/2014/8/25/androids-touch-resampling-algorithm>`__ 214 algorithm to resample touch events. 215 216 Currently, we have a strict ordering between Composites and touch 217 events. When a touch event occurs on the *Touch Input Thread*, we store 218 the touch event in a queue. When a vsync event occurs, the 219 ``CompositorVsyncDispatcher`` notifies the ``Compositor`` of a vsync 220 event, which notifies the ``GeckoTouchDispatcher``. The 221 ``GeckoTouchDispatcher`` processes the touch event first on the *APZ 222 Controller Thread*, which is the same as the *Compositor Thread* on b2g, 223 then the ``Compositor`` finishes compositing. We require this strict 224 ordering because if a vsync notification is dispatched to both the 225 ``Compositor`` and ``GeckoTouchDispatcher`` at the same time, a race 226 condition occurs between processing the touch event and therefore 227 position versus compositing. In practice, this creates very janky 228 scrolling. As of this writing, we have not analyzed input events on 229 desktop platforms. 230 231 One slight quirk is that input events can start a composite, for example 232 during a scroll and after the ``Compositor`` is no longer listening to 233 vsync events. In these cases, we notify the ``Compositor`` to observe 234 vsync so that it dispatches touch events. If touch events were not 235 dispatched, and since the ``Compositor`` is not listening to vsync 236 events, the touch events would never be dispatched. The 237 ``GeckoTouchDispatcher`` handles this case by always forcing the 238 ``Compositor`` to listen to vsync events while touch events are 239 occurring. 240 241 Widget, Compositor, CompositorVsyncDispatcher, GeckoTouchDispatcher Shutdown Procedure 242 -------------------------------------------------------------------------------------- 243 244 When the `nsIWidget shuts 245 down <https://hg.mozilla.org/mozilla-central/file/0df249a0e4d3/widget/nsIWidget.cpp#l182>`__ 246 - It calls nsIWidget::DestroyCompositor on the *Gecko Main Thread*. 247 During nsIWidget::DestroyCompositor, it first destroys the 248 CompositorBridgeChild. CompositorBridgeChild sends a sync IPC call to 249 CompositorBridgeParent::RecvStop, which calls 250 `CompositorBridgeParent::Destroy <https://hg.mozilla.org/mozilla-central/file/ab0490972e1e/gfx/layers/ipc/CompositorParent.cpp#l509>`__. 251 During this time, the *main thread* is blocked on the parent process. 252 CompositorBridgeParent::RecvStop runs on the *Compositor thread* and 253 cleans up some resources, including setting the 254 ``CompositorVsyncScheduler::Observer`` to nullptr. 255 CompositorBridgeParent::RecvStop also explicitly keeps the 256 CompositorBridgeParent alive and posts another task to run 257 CompositorBridgeParent::DeferredDestroy on the Compositor loop so that 258 all ipdl code can finish executing. The 259 ``CompositorVsyncScheduler::Observer`` also unobserves from vsync and 260 cancels any pending composite tasks. Once 261 CompositorBridgeParent::RecvStop finishes, the *main thread* in the 262 parent process continues shutting down the nsIWidget. 263 264 At the same time, the *Compositor thread* is executing tasks until 265 CompositorBridgeParent::DeferredDestroy runs, which flushes the 266 compositor message loop. Now we have two tasks as both the nsIWidget 267 releases a reference to the Compositor on the *main thread* during 268 destruction and the CompositorBridgeParent::DeferredDestroy releases a 269 reference to the CompositorBridgeParent on the *Compositor Thread*. 270 Finally, the CompositorBridgeParent itself is destroyed on the *main 271 thread* once both references are gone due to explicit `main thread 272 destruction <https://hg.mozilla.org/mozilla-central/file/50b95032152c/gfx/layers/ipc/CompositorParent.h#l148>`__. 273 274 With the ``CompositorVsyncScheduler::Observer``, any accesses to the 275 widget after nsIWidget::DestroyCompositor executes are invalid. Any 276 accesses to the compositor between the time the 277 nsIWidget::DestroyCompositor runs and the 278 CompositorVsyncScheduler::Observer’s destructor runs aren’t safe yet a 279 hardware vsync event could occur between these times. Since any tasks 280 posted on the Compositor loop after 281 CompositorBridgeParent::DeferredDestroy is posted are invalid, we make 282 sure that no vsync tasks can be posted once 283 CompositorBridgeParent::RecvStop executes and DeferredDestroy is posted 284 on the Compositor thread. When the sync call to 285 CompositorBridgeParent::RecvStop executes, we explicitly set the 286 CompositorVsyncScheduler::Observer to null to prevent vsync 287 notifications from occurring. If vsync notifications were allowed to 288 occur, since the ``CompositorVsyncScheduler::Observer``\ ’s vsync 289 notification executes on the *hardware vsync thread*, it would post a 290 task to the Compositor loop and may execute after 291 CompositorBridgeParent::DeferredDestroy. Thus, we explicitly shut down 292 vsync events in the ``CompositorVsyncDispatcher`` and 293 ``CompositorVsyncScheduler::Observer`` during nsIWidget::Shutdown to 294 prevent any vsync tasks from executing after 295 CompositorBridgeParent::DeferredDestroy. 296 297 The ``CompositorVsyncDispatcher`` may be destroyed on either the *main 298 thread* or *Compositor Thread*, since both the nsIWidget and 299 ``CompositorVsyncScheduler::Observer`` race to destroy on different 300 threads. nsIWidget is destroyed on the *main thread* and releases a 301 reference to the ``CompositorVsyncDispatcher`` during destruction. The 302 ``CompositorVsyncScheduler::Observer`` has a race to be destroyed either 303 during CompositorBridgeParent shutdown or from the 304 ``GeckoTouchDispatcher`` which is destroyed on the main thread with 305 `ClearOnShutdown <https://hg.mozilla.org/mozilla-central/file/21567e9a6e40/xpcom/base/ClearOnShutdown.h#l15>`__. 306 Whichever object, the CompositorBridgeParent or the 307 ``GeckoTouchDispatcher`` is destroyed last will hold the last reference 308 to the ``CompositorVsyncDispatcher``, which destroys the object. 309 310 Refresh Driver 311 -------------- 312 313 The Refresh Driver is ticked from a `single active 314 timer <https://hg.mozilla.org/mozilla-central/file/ab0490972e1e/layout/base/nsRefreshDriver.cpp#l11>`__. 315 The assumption is that there are multiple ``RefreshDrivers`` connected 316 to a single ``RefreshTimer``. There are two ``RefreshTimers``: an active 317 and an inactive ``RefreshTimer``. Each Tab has its own 318 ``RefreshDriver``, which connects to one of the global 319 ``RefreshTimers``. The ``RefreshTimers`` execute on the *Main Thread* 320 and tick their connected ``RefreshDrivers``. We do not want to break 321 this model of multiple ``RefreshDrivers`` per a set of two global 322 ``RefreshTimers``. Each ``RefreshDriver`` switches between the active 323 and inactive ``RefreshTimer``. 324 325 Instead, we create a new ``RefreshTimer``, the ``VsyncRefreshTimer`` 326 which ticks based on vsync messages. We replace the current active timer 327 with a ``VsyncRefreshTimer``. All tabs will then tick based on this new 328 active timer. Since the ``RefreshTimer`` has a lifetime of the process, 329 we only need to create a single ``VsyncDispatcher`` per 330 ``Display`` when Firefox starts. Even if we do not have any content 331 processes, the Chrome process will still need a ``VsyncRefreshTimer``, 332 thus we can associate the ``VsyncDispatcher`` with each 333 ``Display``. 334 335 When Firefox starts, we initially create a new ``VsyncRefreshTimer`` in 336 the Chrome process. The ``VsyncRefreshTimer`` will listen to vsync 337 notifications from ``VsyncDispatcher`` on the global 338 ``Display``. When nsRefreshDriver::Shutdown executes, it will delete the 339 ``VsyncRefreshTimer``. This creates a problem as all the 340 ``RefreshTimers`` are currently manually memory managed whereas 341 ``VsyncObservers`` are ref counted. To work around this problem, we 342 create a new ``RefreshDriverVsyncObserver`` as an inner class to 343 ``VsyncRefreshTimer``, which actually receives vsync notifications. It 344 then ticks the ``RefreshDrivers`` inside ``VsyncRefreshTimer``. 345 346 With Content processes, the start up process is more complicated. We 347 send vsync IPC messages via the use of the PBackground thread on the 348 parent process, which allows us to send messages from the Parent 349 process’ without waiting on the *main thread*. This sends messages from 350 the Parent::\ *PBackground Thread* to the Child::\ *Main Thread*. The 351 *main thread* receiving IPC messages on the content process is 352 acceptable because ``RefreshDrivers`` must execute on the *main thread*. 353 However, there is some amount of time required to setup the IPC 354 connection upon process creation and during this time, the 355 ``RefreshDrivers`` must tick to set up the process. To get around this, 356 we initially use software ``RefreshTimers`` that already exist during 357 content process startup and swap in the ``VsyncRefreshTimer`` once the 358 IPC connection is created. 359 360 During nsRefreshDriver::ChooseTimer, we create an async PBackground IPC 361 open request to create a ``VsyncParent`` and ``VsyncChild``. At the same 362 time, we create a software ``RefreshTimer`` and tick the 363 ``RefreshDrivers`` as normal. Once the PBackground callback is executed 364 and an IPC connection exists, we swap all ``RefreshDrivers`` currently 365 associated with the active ``RefreshTimer`` and swap the 366 ``RefreshDrivers`` to use the ``VsyncRefreshTimer``. Since all 367 interactions on the content process occur on the main thread, there are 368 no need for locks. The ``VsyncParent`` listens to vsync events through 369 the ``VsyncRefreshTimerDispatcher`` on the parent side and sends vsync 370 IPC messages to the ``VsyncChild``. The ``VsyncChild`` notifies the 371 ``VsyncRefreshTimer`` on the content process. 372 373 During the shutdown process of the content process, ActorDestroy is 374 called on the ``VsyncChild`` and ``VsyncParent`` due to the normal 375 PBackground shutdown process. Once ActorDestroy is called, no IPC 376 messages should be sent across the channel. After ActorDestroy is 377 called, the IPDL machinery will delete the **VsyncParent/Child** pair. 378 The ``VsyncParent``, due to being a ``VsyncObserver``, is ref counted. 379 After ``VsyncParent::ActorDestroy`` is called, it unregisters itself 380 from the ``VsyncDispatcher``, which holds the last reference 381 to the ``VsyncParent``, and the object will be deleted. 382 383 Thus the overall flow during normal execution is: 384 385 1. VsyncSource::Display::VsyncDispatcher receives a Vsync 386 notification from the OS in the parent process. 387 2. VsyncDispatcher notifies 388 VsyncRefreshTimer::RefreshDriverVsyncObserver that a vsync occurred on 389 the parent process on the hardware vsync thread. 390 3. VsyncDispatcher notifies the VsyncParent on the hardware 391 vsync thread that a vsync occurred. 392 4. The VsyncRefreshTimer::RefreshDriverVsyncObserver in the parent 393 process posts a task to the main thread that ticks the refresh 394 drivers. 395 5. VsyncParent posts a task to the PBackground thread to send a vsync 396 IPC message to VsyncChild. 397 6. VsyncChild receive a vsync notification on the content process on the 398 main thread and ticks their respective RefreshDrivers. 399 400 Compressing Vsync Messages 401 -------------------------- 402 403 Vsync messages occur quite often and the *main thread* can be busy for 404 long periods of time due to JavaScript. Consistently sending vsync 405 messages to the refresh driver timer can flood the *main thread* with 406 refresh driver ticks, causing even more delays. To avoid this problem, 407 we compress vsync messages on both the parent and child processes. 408 409 On the parent process, newer vsync messages update a vsync timestamp but 410 do not actually queue any tasks on the *main thread*. Once the parent 411 process’ *main thread* executes the refresh driver tick, it uses the 412 most updated vsync timestamp to tick the refresh driver. After the 413 refresh driver has ticked, one single vsync message is queued for 414 another refresh driver tick task. On the content process, the IPDL 415 ``compress`` keyword automatically compresses IPC messages. 416 417 Multiple Monitors 418 ----------------- 419 420 In order to have multiple monitor support for the ``RefreshDrivers``, we 421 have multiple active ``RefreshTimers``. Each ``RefreshTimer`` is 422 associated with a specific ``Display`` via an id and tick when it’s 423 respective ``Display`` vsync occurs. We have **N RefreshTimers**, where 424 N is the number of connected displays. Each ``RefreshTimer`` still has 425 multiple ``RefreshDrivers``. 426 427 When a tab or window changes monitors, the ``nsIWidget`` receives a 428 display changed notification. Based on which display the window is on, 429 the window switches to the correct ``VsyncDispatcher`` and 430 ``CompositorVsyncDispatcher`` on the parent process based on the display 431 id. Each ``TabParent`` should also send a notification to their child. 432 Each ``TabChild``, given the display ID, switches to the correct 433 ``RefreshTimer`` associated with the display ID. When each display vsync 434 occurs, it sends one IPC message to notify vsync. The vsync message 435 contains a display ID, to tick the appropriate ``RefreshTimer`` on the 436 content process. There is still only one **VsyncParent/VsyncChild** 437 pair, just each vsync notification will include a display ID, which maps 438 to the correct ``RefreshTimer``. 439 440 Object Lifetime 441 --------------- 442 443 1. CompositorVsyncDispatcher - Lives as long as the nsIWidget 444 associated with the VsyncDispatcher 445 2. CompositorVsyncScheduler::Observer - Lives and dies the same time as 446 the CompositorBridgeParent. 447 3. VsyncDispatcher - As long as the associated display 448 object, which is the lifetime of Firefox. 449 4. VsyncSource - Lives as long as the gfxPlatform on the chrome process, 450 which is the lifetime of Firefox. 451 5. VsyncParent/VsyncChild - Lives as long as the content process 452 6. RefreshTimer - Lives as long as the process 453 454 Threads 455 ------- 456 457 All ``VsyncObservers`` are notified on the *Hardware Vsync Thread*. It 458 is the responsibility of the ``VsyncObservers`` to post tasks to their 459 respective correct thread. For example, the 460 ``CompositorVsyncScheduler::Observer`` will be notified on the *Hardware 461 Vsync Thread*, and post a task to the *Compositor Thread* to do the 462 actual composition. 463 464 1. Compositor Thread - Nothing changes 465 2. Main Thread - PVsyncChild receives IPC messages on the main thread. 466 We also enable/disable vsync on the main thread. 467 3. PBackground Thread - Creates a connection from the PBackground thread 468 on the parent process to the main thread in the content process. 469 4. Hardware Vsync Thread - Every platform is different, but we always 470 have the concept of a hardware vsync thread. Sometimes this is 471 actually created by the host OS. On Windows, we have to create a 472 separate platform thread that blocks on DwmFlush().