mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-10-31 22:25:25 -04:00
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>
323 lines
10 KiB
XML
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>
|