Sunny Sachanandani | 68be7e3 | 2018-06-26 21:36:57 | [diff] [blame] | 1 | # CHROMIUM Sync Token Internals |
| 2 | |
| 3 | Chrome uses a mechanism known as "sync tokens" to synchronize different command |
| 4 | buffers in the GPU process. This document discusses the internals of the sync |
| 5 | token system. |
| 6 | |
| 7 | [TOC] |
| 8 | |
| 9 | ## Rationale |
| 10 | |
| 11 | In Chrome, multiple processes, for example browser and renderer, submit work to |
| 12 | the GPU process asynchronously in command buffer. However, there are |
| 13 | dependencies between the work submitted by different processes, such as |
kylechar | 7fbb9e9 | 2022-07-05 03:07:39 | [diff] [blame] | 14 | SkiaRenderer in the display compositor in the GPU process rendering a tile |
Sunny Sachanandani | 68be7e3 | 2018-06-26 21:36:57 | [diff] [blame] | 15 | produced by the raster worker in the renderer process. |
| 16 | |
| 17 | Sync tokens are used to synchronize the work contained in command buffers |
| 18 | without waiting for the work to complete. This improves pipelining, and with the |
| 19 | introduction of GPU scheduling, allows prioritization of work. Although |
| 20 | originally built for synchronizing command buffers, they can be used for other |
| 21 | work in the GPU process. |
| 22 | |
| 23 | ## Generation |
| 24 | |
| 25 | Sync tokens are represented by a namespace, identifier, and the *fence release |
| 26 | count*. `CommandBufferId` is a 64-bit unsigned integer which is unique within a |
| 27 | `CommandBufferNamespace`. For example IPC command buffers are in the *GPU_IO* |
| 28 | CommandBufferNamespace, and are identified by CommandBufferId with process id as |
| 29 | the MSB and IPC route id as the LSB. |
| 30 | |
Sunny Sachanandani | cec4bcb | 2018-06-27 22:58:30 | [diff] [blame] | 31 | The fence release count marks completion of some work in a command buffer. Note: |
| 32 | this is CPU side work done that includes command decoding, validation, issuing |
| 33 | GL calls to the driver, etc. and not GPU side work. See |
| 34 | [gpu_synchronication.md](/docs/design/gpu_synchronization.md) for more |
| 35 | information about synchronizing GPU work. |
| 36 | |
Sunny Sachanandani | 68be7e3 | 2018-06-26 21:36:57 | [diff] [blame] | 37 | Fences are typically generated or inserted on the client using a sequential |
| 38 | counter. The corresponding GL API is `GenSyncTokenCHROMIUM` which generates the |
| 39 | fence using `CommandBufferProxyImpl::GenerateFenceSyncRelease()`, and also adds |
Corentin Wallez | 0f412f0 | 2019-04-03 22:42:38 | [diff] [blame] | 40 | the fence to the command buffer using the internal `InsertFenceSync` command. |
Sunny Sachanandani | 68be7e3 | 2018-06-26 21:36:57 | [diff] [blame] | 41 | |
| 42 | ## Verification |
| 43 | |
| 44 | Different client processes communicate with the GPU process using *channels*. A |
| 45 | channel wraps around a message pipe which doesn't provide ordering guarantees |
| 46 | with respect to other pipes. For example, a message from the browser process |
| 47 | containing a sync token wait can arrive before the message from the renderer |
| 48 | process that releases or fulfills the sync token promise. |
| 49 | |
| 50 | To prevent the above problem, client processes must verify sync tokens before |
| 51 | sending to another process. Verification involves a synchronous nop IPC message, |
| 52 | `GpuChannelMsg_Nop`, to the GPU process which ensures that the GPU process has |
| 53 | read previous messages from the pipe. |
| 54 | |
| 55 | Sync tokens used within a process do not need to be verified, and the |
| 56 | `GenSyncTokenUnverifiedCHROMIUM` GL API serves this common case. These sync |
| 57 | tokens need to be verified using `VerifySyncTokensCHROMIUM`. Sync tokens |
| 58 | generated using `GenSyncTokenCHROMIUM` are already verified. `SyncToken` has a |
| 59 | `verified_flush` bit that guards against accidentally sending unverified sync |
| 60 | tokens over IPC. |
| 61 | |
| 62 | ## Streams |
| 63 | |
| 64 | In the GPU process, command buffers are organized into logical streams of |
| 65 | execution that are called *sequences*. Within a sequence tasks are ordered, but |
| 66 | are asynchronous with respect to tasks in other sequences. Dependencies between |
| 67 | tasks are specified as sync tokens. For IPC command buffers, this implies flush |
| 68 | ordering within a sequence. |
| 69 | |
| 70 | A sequence can be created by `Scheduler::CreateSequence` which returns a |
| 71 | `SequenceId`. Tasks are posted to a sequence using `Scheduler::ScheduleTask`. |
| 72 | Typically there is one sequence per channel, but sometimes there are more like |
| 73 | raster, compositor, and media streams in renderer's channel. |
| 74 | |
| 75 | The scheduler also provides a means for co-operative scheduling through |
| 76 | `Scheduler::ShouldYield` and `Scheduler::ContinueTask`. These allow a task to |
| 77 | yield and continue once higher priority work is complete. Together with the GPU |
| 78 | scheduler, multiple sequences provide the means for prioritization of UI work |
| 79 | over raster prepaint work. |
| 80 | |
| 81 | ## Waiting and Completion |
| 82 | |
| 83 | Sync tokens are managed in the GPU process by `SyncPointManager`, and its helper |
| 84 | classes `SyncPointOrderData` and `SyncPointClientState`. `SyncPointOrderData` |
| 85 | holds state for a logical stream of execution, typically containing work of |
| 86 | multiple command buffers from one process. `SyncPointClientState` holds sync token |
| 87 | state for a client which generated sync tokens, typically an IPC command buffer. |
| 88 | |
| 89 | GPU scheduler maintains a `SyncPointOrderData` per sequence. Clients must create |
| 90 | SyncPointClientState using `SyncPointManager::CreateSyncPointClientState` and |
| 91 | identify their namespace, id, and sequence. |
| 92 | |
| 93 | Waiting on a sync token is done by calling `SyncPointManager::Wait()` with a |
| 94 | sync token, order number for the wait, and a callback. The callbacks are |
| 95 | enqueued with the `SyncPointClientState` of the target with the release count of |
| 96 | the sync token. The scheduler does this internally for sync token dependencies |
| 97 | for scheduled tasks, but the wait can also be performed when running the |
| 98 | `WaitSyncTokenCHROMIUM` GL command. |
| 99 | |
| 100 | Sync tokens are completed when the fence is released in the GPU process by |
| 101 | calling `SyncPointClientState::ReleaseFenceSync()`. For GL command buffers, the |
Corentin Wallez | 0f412f0 | 2019-04-03 22:42:38 | [diff] [blame] | 102 | `InsertFenceSync` command, which contains the release count generated in the |
| 103 | client, calls this when executed in the service. This issues callbacks and |
Sunny Sachanandani | 68be7e3 | 2018-06-26 21:36:57 | [diff] [blame] | 104 | allows waiting command buffers to resume their work. |
| 105 | |
| 106 | ## Correctness |
| 107 | |
| 108 | Correctness of waits and releases basically amounts to checking that there are |
| 109 | no indefinite waits because of broken promises or circular wait chains. This is |
| 110 | ensured by associating an order number with each wait and release and |
| 111 | maintaining the invariant that the order number of release is less than or equal |
| 112 | to the order number of wait. |
| 113 | |
| 114 | Each task is assigned a global sequential order number generated by |
| 115 | `SyncPointOrderData::GenerateUnprocessedOrderNumber` which are stored in a queue |
| 116 | of unprocessed order numbers. In `SyncPointManager::Wait()`, the callbacks are |
| 117 | also enqueued with the order number of the waiting task in `SyncPointOrderData` |
| 118 | in a queue called `OrderFenceQueue`. |
| 119 | |
| 120 | `SyncPointOrderData` maintains the invariant that all waiting callbacks must |
| 121 | have an order number greater than the sequence's next unprocessed order number. |
| 122 | This invariant is checked when enqueuing a new callback in |
| 123 | `SyncPointOrderData::ValidateReleaseOrderNumber`, and after completing a task in |
| 124 | `SyncPointOrderData::FinishProcessingOrderNumber`. |
| 125 | |
| 126 | |
| 127 | ## See Also |
| 128 | |
| 129 | [CHROMIUM_sync_point](/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_point.txt) |
| 130 | [gpu_synchronication.md](/docs/design/gpu_synchronization.md) |
| 131 | [Lightweight GPU Sync Points](https://docs.google.com/document/d/1XwBYFuTcINI84ShNvqifkPREs3sw5NdaKzKqDDxyeHk/edit) |