mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-11-24 06:59:50 -05:00
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>
This commit is contained in:
parent
96129e4ed0
commit
cc4192ba6d
24 changed files with 2729 additions and 0 deletions
323
doc/publican/Content_Updates.xml
Normal file
323
doc/publican/Content_Updates.xml
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
<?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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue