wayland/doc/publican/Content_Updates.xml
Sebastian Wick cc4192ba6d doc: Add a chapter on content updates
The behavior of content updates, specifically in combination with sync
subsrufaces and constrains can become quite complicated. This introduces
a chapter in the wayland book which explains the behavior of the core
specification in this regard, and shows examples.

Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-10-28 16:49:40 +01:00

323 lines
10 KiB
XML

<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
%BOOK_ENTITIES;
]>
<chapter id="chap-Content-Updates">
<title>Content Updates</title>
<section id="sect-Content-Updates-preface">
<title>Overview</title>
<para>
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.
</para>
<para>
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.
</para>
<para>
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.
</para>
<para>
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.
</para>
</section>
<section id="sect-Content-Updates-rules">
<title>Rules</title>
<para>
The core protocol specifies the behavior in wl_subsurface and
wl_surface.commit. The behavior can be summarized by the following rules:
</para>
<orderedlist numeration="arabic">
<listitem>
<para>
Content Updates contain all double-buffered state of the surface and
selected state from their direct children.
</para>
</listitem>
<listitem>
<para>
Surfaces which are effectively synchronized create Synchronized
Content Updates (SCU), otherwise they create Desync Content Updates
(DCU).
</para>
</listitem>
<listitem>
<para>
Content Updates (CU) have a dependency on the previous CU of the same
queues (if it exists).
</para>
</listitem>
<listitem>
<para>
CUs have dependencies on the last SCU of direct child surfaces that
are not reachable (if they exists).
</para>
</listitem>
<listitem>
<para>
The CUs and their dependencies form a DAG, where CUs are nodes and
dependencies are edges.
</para>
</listitem>
<listitem>
<para>
All DCUs starting from the front of the queues until the first SCU or
the back of the queue is reached are candidates.
</para>
</listitem>
<listitem>
<para>
If the DAG that's reachable from a candidate (candidate DAG) does not
have any constraints, then this DAG must be applied atomically.
</para>
</listitem>
<listitem>
<para>
A DAG is applied by recursively applying a content update without
dependencies and removing it from the DAG.
</para>
</listitem>
<listitem>
<para>
Surfaces transition from effectively sync to effectively desync after
their parents.
</para>
</listitem>
<listitem>
<para>
When a surface transitions to effectively desync, all SCUs in its
queue which are not reachable by a DCU become DCUs.
</para>
</listitem>
</orderedlist>
</section>
<section id="sect-Content-Updates-examples">
<title>Examples</title>
<para>
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.
</para>
<figure>
<title>Legend</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/content-update-legend.png"/>
</imageobject>
</mediaobject>
</figure>
<figure>
<title>Complex Synchronized Subsurface Case 1</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-subsurf-case1-1.png"/>
</imageobject>
<caption>
<para>
Every DCU (<emphasis>1</emphasis> and <emphasis>6</emphasis>) contain
CUs with constraints in their reachable DAG
</para>
</caption>
</mediaobject>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-subsurf-case1-2.png"/>
</imageobject>
<caption>
<para>
Waiting until the <emphasis>buffer-sync</emphasis> constrain on CU
<emphasis>1</emphasis> is cleared, the candidate DAG of CU
<emphasis>1</emphasis> does not contain constraints and can be applied
</para>
</caption>
</mediaobject>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-subsurf-case1-3.png"/>
</imageobject>
<caption>
<para>
That leaves the candidate DAG of CU <emphasis>6</emphasis> which still
contains another CU with a <emphasis>buffer-sync</emphasis> constrain
</para>
</caption>
</mediaobject>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-subsurf-case1-4.png"/>
</imageobject>
<caption>
<para>
Waiting until the <emphasis>buffer-sync</emphasis> constrain on CU
<emphasis>6</emphasis> is cleared, the candidate DAG of
<emphasis>6</emphasis> does not contain CUs with constraints and can
be applied.
</para>
</caption>
</mediaobject>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-subsurf-case1-5.png"/>
</imageobject>
<caption>
<para>
There is no DCU left and no constraint remaining. Nothing more can be
applied without a new CU.
</para>
</caption>
</mediaobject>
</figure>
<figure>
<title>Complex Synchronized Subsurface Case 2</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-subsurf-case2-1.png"/>
</imageobject>
<caption>
<para>
Both DCUs (<emphasis>1</emphasis> and <emphasis>6</emphasis>) have a
reachable DAG containing CU <emphasis>1</emphasis> with a constraint
</para>
</caption>
</mediaobject>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-subsurf-case2-2.png"/>
</imageobject>
<caption>
<para>
Waiting until the <emphasis>buffer-sync</emphasis> constrain on
<emphasis>1</emphasis> is cleared, both DAGs contain no CU with
constraints and can be applied in any order
</para>
</caption>
</mediaobject>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-subsurf-case2-3.png"/>
</imageobject>
<caption>
<para>
That leaves the same state as in the previous case
</para>
</caption>
</mediaobject>
</figure>
<figure>
<title>Synchronized to Desynchronized Subsurface</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-to-desync-subsurf-1.png"/>
</imageobject>
<caption>
<para>
There is one DCU (<emphasis>1</emphasis>) with its reachable DAG
that cannot be applied because CU <emphasis>1</emphasis> contains a
constraint
</para>
</caption>
</mediaobject>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-to-desync-subsurf-2.png"/>
</imageobject>
<caption>
<para>
Surface <emphasis>SS1</emphasis> transitions from effectively
synchronized to effectively desynchronized. SCU
<emphasis>2</emphasis> is reachable by DCU <emphasis>4</emphasis> so
nothing changes.
</para>
</caption>
</mediaobject>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-to-desync-subsurf-3.png"/>
</imageobject>
<caption>
<para>
Surface <emphasis>SS1</emphasis> provides a new DCU
(<emphasis>5</emphasis>) but because the CU before
(<emphasis>2</emphasis>) is a Synchronized CU, it is not a candidate
</para>
</caption>
</mediaobject>
</figure>
<figure>
<title>Synchronized to Desynchronized Transition</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-to-desync-transition-1.png"/>
</imageobject>
<caption>
<para>
There are three SCUs and all surfaces are effectively synchronized.
</para>
</caption>
</mediaobject>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-to-desync-transition-2.png"/>
</imageobject>
<caption>
<para>
Surface <emphasis>SS1</emphasis> transitions to effectively
desynchronized and SCU <emphasis>2</emphasis> becomes a DCU because
it is not reachable from a DCU
</para>
</caption>
</mediaobject>
<mediaobject>
<imageobject>
<imagedata fileref="images/sync-to-desync-transition-3.png"/>
</imageobject>
<caption>
<para>
Surface <emphasis>SS2</emphasis> transitions to effectively
desynchronized. SCUs <emphasis>3</emphasis> and
<emphasis>4</emphasis> become DCUs because they are not reachable
from a DCU. SCU <emphasis>1</emphasis> does not change because it is
reachable by DCU <emphasis>2</emphasis>.
</para>
</caption>
</mediaobject>
</figure>
</section>
</chapter>