%BOOK_ENTITIES; ]> Content Updates
Overview In the Wayland protocol, requests are asynchronous but take effect immediately when the compositor receives them. However, some requests on surfaces are not applied immediately but are instead double-buffered to allow atomic changes. These double-buffered changes are committed through the wl_surface.commit request, which creates a Content Update. Content Updates encapsulate all double-buffered state changes and can be applied by the compositor. The complexity arises when considering subsurfaces, which can operate in synchronized mode. When a subsurface is synchronized, its Content Updates must be applied atomically together with the parent surface's state. This synchronization can extend through an entire tree of subsurfaces, where child subsurfaces inherit the synchronized behavior from their parents. Historically, Content Updates from synchronized subsurfaces were merged into the pending state of the parent surface on commit. However, the introduction of constraints—which can defer the application of Content Updates—necessitated a more sophisticated model. This led to the implementation of per-surface queues of Content Updates, with dependencies between Content Updates across different queues. This queuing model maintains backwards compatibility with the earlier approach of merging Content Updates into the parent's pending state on commit. The core protocol defines the semantics of Content Updates using per-surface queues, but compositors that do not need to support constraints may implement the simpler legacy model where synchronized subsurface states are merged directly into the parent's pending state.
Rules The core protocol specifies the behavior in wl_subsurface and wl_surface.commit. The behavior can be summarized by the following rules: Content Updates contain all double-buffered state of the surface and selected state from their direct children. Surfaces which are effectively synchronized create Synchronized Content Updates (SCU), otherwise they create Desync Content Updates (DCU). Content Updates (CU) have a dependency on the previous CU of the same queues (if it exists). CUs have dependencies on the last SCU of direct child surfaces that are not reachable (if they exists). The CUs and their dependencies form a DAG, where CUs are nodes and dependencies are edges. All DCUs starting from the front of the queues until the first SCU or the back of the queue is reached are candidates. If the DAG that's reachable from a candidate (candidate DAG) does not have any constraints, then this DAG must be applied atomically. A DAG is applied by recursively applying a content update without dependencies and removing it from the DAG. Surfaces transition from effectively sync to effectively desync after their parents. When a surface transitions to effectively desync, all SCUs in its queue which are not reachable by a DCU become DCUs.
Examples These examples should help to build an intuition for how content updates actually behave. They cover the interesting edge cases, such as subsurfaces with constraints, and transitioning from a sync subsurface to a desync one.
Legend
Complex Synchronized Subsurface Case 1 Every DCU (1 and 6) contain CUs with constraints in their reachable DAG Waiting until the buffer-sync constrain on CU 1 is cleared, the candidate DAG of CU 1 does not contain constraints and can be applied That leaves the candidate DAG of CU 6 which still contains another CU with a buffer-sync constrain Waiting until the buffer-sync constrain on CU 6 is cleared, the candidate DAG of 6 does not contain CUs with constraints and can be applied. There is no DCU left and no constraint remaining. Nothing more can be applied without a new CU.
Complex Synchronized Subsurface Case 2 Both DCUs (1 and 6) have a reachable DAG containing CU 1 with a constraint Waiting until the buffer-sync constrain on 1 is cleared, both DAGs contain no CU with constraints and can be applied in any order That leaves the same state as in the previous case
Synchronized to Desynchronized Subsurface There is one DCU (1) with its reachable DAG that cannot be applied because CU 1 contains a constraint Surface SS1 transitions from effectively synchronized to effectively desynchronized. SCU 2 is reachable by DCU 4 so nothing changes. Surface SS1 provides a new DCU (5) but because the CU before (2) is a Synchronized CU, it is not a candidate
Synchronized to Desynchronized Transition There are three SCUs and all surfaces are effectively synchronized. Surface SS1 transitions to effectively desynchronized and SCU 2 becomes a DCU because it is not reachable from a DCU Surface SS2 transitions to effectively desynchronized. SCUs 3 and 4 become DCUs because they are not reachable from a DCU. SCU 1 does not change because it is reachable by DCU 2.