Adding synchronization to the WM spec



There are quite a few outstanding issues related to synchronization
between applications and the compositor. We want the compositor
to avoid drawing a window when it is only half done with an update,
we want to throttle the drawing rate in the application, and we
need to incorporate NVIDIA's fence sync objects if we want to get
composited drawing correct with their driver.

This update to the window manager specification attempts to address
these needs in a unified way. What I'm basically proposing here is:

 * A new form of _NET_WM_SYNC_REQUEST where a client can update
   the counter to an odd value saying "I'm starting the frame"
   and to an even value to end the frame.

 * A message _NET_WM_SYNC_DRAWN that is sent when the compositor
   has drawn the frame.

 * A property _NET_WM_SYNC_FENCES that can be combined with the
   counter value to find an appropriate fence to wait on.

I did implementations of the first two for Mutter a while ago to
validate the ideas; the third portion is, so far, just speculative.

The details are found in the attached patch to the WM Spec.
(I've filed a bug against freedesktop sysadmin to get the wm-spec
moved over to git.)

What the patch is about is basically "frames", but I've avoided
the term in the spec, because of confusion with window decoration
frames.

Potential issues:

 * The bundling of the a legacy counter and a new counter into
   _NET_WM_SYNC_REQUEST counter could be considered messy
   It does save fetching another property at startup, and the behavior
   described here tightly couples the two counters to avoid excessive
   duplication and unclear interactions.

 * I'm not really sure how the fence synchronization is supposed
   to work for the case of a direct rendering GL client. Is the combination
   of glXSwapBuffers() and XSyncTriggerFence() sufficient?

 * It's unclear to me exactly what timing information (if any) it's 
   useful to include in _NET_WM_SYNC_DRAWN. I've just omitted all
   information in this draft, I'll try to work through the various 
   use cases and come up with a proposal later.

Some references:

 I originally brought up the need to be able to do an atomic frame:
   http://mail.gnome.org/archives/wm-spec-list/2009-June/msg00002.html

 The idea of using two counters in the _NET_WM_SYNC_REQUEST comes from
 Denis Dzyubenko:
   http://mail.gnome.org/archives/wm-spec-list/2009-July/msg00005.html

 Information about how the sync fence objects are used for GPU-level
 synchronization can be found in:
   http://lists.x.org/archives/xorg-devel/2010-December/016510.html

 The relevant additions to the Sync extension for fences are found in:
http://cgit.freedesktop.org/xorg/proto/xextproto/commit/?id=9ba2065b63ea0e61a17b8221ad454c02a1755373

 And are used with:
  http://www.opengl.org/registry/specs/ARB/sync.txt
  http://www.opengl.org/registry/specs/EXT/x11_sync_object.txt

>From 6c2e603ca62b32bf87185ff6ba9fdb22459b93e8 Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor fishsoup net>
Date: Fri, 28 Oct 2011 19:08:11 -0400
Subject: [PATCH] Add support for deliminating updates

To support an application marking the beginning and end of the
frame, add a new form of _NET_WM_SYNC_REQUEST where a client can
update the counter to an odd value saying "I'm starting the frame"
and to an even value to end the frame.

On top of that are built:

 * A message _NET_WM_SYNC_DRAWN that is sent when the compositor
   has drawn the frame.

 * A property _NET_WM_SYNC_FENCES that can be combined with the
   counter value to find an appropriate fence to wait on.
---
 wm-spec.xml |  192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 185 insertions(+), 7 deletions(-)

diff --git a/wm-spec.xml b/wm-spec.xml
index 98f9f9b..55b7325 100644
--- a/wm-spec.xml
+++ b/wm-spec.xml
@@ -1,7 +1,7 @@
 <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
 "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"; [
-<!ENTITY version "Draft version 1.4.draft-2">
-<!ENTITY date "Fri September 29, 2006">
+<!ENTITY version "Draft version 1.5.draft-2">
+<!ENTITY date "Fri October 28, 2011">
 ]>
 <article id="index">
 <articleinfo>
@@ -1594,9 +1594,19 @@ the library documentation</ulink>) to let client and window manager
 synchronize the repaint of the window manager frame and the client
 window. A client indicates that it is willing to participate in the
 protocol by listing _NET_WM_SYNC_REQUEST in the WM_PROTOCOLS property
-of the client window and storing the XID of an XSync counter in the
-property _NET_WM_SYNC_REQUEST_COUNTER. The initial value of this
-counter is not defined by this specification.
+of the client window and setting the _NET_WM_SYNC_REQUEST_COUNTER
+property on a window. There are two forms of the protocol, a basic
+form and an extended form. A client indicates support for the  extended form
+by setting _NET_WM_SYNC_REQUEST_COUNTER to a property containing two counters;
+if _NET_WM_SYNC_REQUEST_COUNTER contains only a single counter, the window
+manager must use the basic form of the protocol.
+                </para>
+    <sect3>
+                <title>Basic form</title>
+                <para>
+The initial value of the counter (which is the first value in
+_NET_WM_SYNC_REQUEST_COUNTER if it contains two values, and the only
+value if it contains one value) is not defined by the specification.
 		</para>
 		<para>
 A window manager uses this protocol by preceding a ConfigureNotify
@@ -1617,7 +1627,7 @@ other data.l[] elements = 0
 		<para>
 After receiving one or more such message/ConfigureNotify pairs, and
 having handled all repainting associated with the ConfigureNotify
-events, the client MUST set the _NET_WM_SYNC_REQUEST_COUNTER to the 64
+events, the client MUST set the counter to the 64
 bit number indicated by the data.l[2] and data.l[3] fields of the last
 client message received.
 		</para>
@@ -1636,7 +1646,48 @@ this specification, the window manager MAY set the value of the XSync
 counter at any time, and MUST do so when it first manages a new
 window.
 		</para>
-	</sect2>
+    </sect3>
+    <sect3>
+                <title>Extended form</title>
+                <para>
+In the extended form of the protocol, the counter used is the second
+value that the client stores in _NET_WM_SYNC_REQUEST_COUNTER and the
+first value is ignored. The initial value of this second counter is is
+initialized by the client to a value of its choosing before it requests
+the window to be mapped.
+                </para>
+		<para>
+The added feature of the extended form of the protocol is that a
+client can at any point increment value of the second counter;
+this is used to <link linkend="deliminated_updates">deliminate updates</link>.
+		</para>
+		<para>
+If a window manager supports the extended form, when it discovers a
+_NET_WM_SYNCf_REQUEST_COUNTER property with two values, it should use
+the second value in the property as the counter for the protocol.  The
+window must track the value of this property by reading an initial
+value using XSyncQueryCounter() and then using an an Alarm to watch
+for subsequent changes.
+		</para>
+		<para>
+Handling of _NET_WM_SYNC_REQUEST is largely the same as for the basic
+form of the protoocol, but with small changes on the client and window
+manager side: When the window manager sends a _NET_WM_SYNC_REQUEST message,
+it should choose the value in the message by picking an even number at
+least 100 greater than the last value it has seen for the counter.
+(The number 100 here is arbitrary - it is chosen to be large enough
+so that updates done spontaneously by the client will not cause conflicts.)
+                </para>
+		<para>
+A client supporting the extended form of the protocol handles a
+_NET_WM_SYNC_REQUEST_COUNTER message by, after handling all painting
+associated with the following ConfigureNotify message, setting the
+first counter to the newly received value, and the second counter to
+the next even number equal to or greater than the newly received
+value.
+		</para>
+    </sect3>
+    </sect2>
     <sect2>
 		<title>_NET_WM_FULLSCREEN_MONITORS</title>
 		<programlisting><![CDATA[
@@ -1768,6 +1819,111 @@ As an example, a Client should set WM_TRANSIENT_FOR on dropdown menus
 to the toplevel application window that contains the menubar.
       </para>
     </sect2>
+    <sect2 id="deliminated_updates">
+      <title>Deliminated Updates</title>
+      <para>
+When a compositing manager is running, optimum display requires
+applications and the compositing manager to synchronize drawing. When
+the application starts drawing an update to its window, the window
+manager should not redraw when it is first notified of damage to the
+window contents, but only when the application is done with the
+update. This provides the user with a consistent view of the window
+contents. Then application should not start drawing the next frame until
+it has been notified that the window manager is finished drawing the
+previous frame. This avoids having the application waste CPU and GPU
+resources drawing frames that will never be displayed to the user.
+A mechanism to do this is built upon the extended form of the
+_NET_WM_SYNC_REQUEST protocol.
+      </para>
+      <para>
+To deliminate updates, the application uses the counter that it has stored
+as the second value in _NET_WM_SYNC_REQUEST_COUNTER. An application
+deliminates an update by incrementing the counter to an odd value,
+making changes to the window contents by operations such as drawing,
+scrolling, and moving child windows, and then ends the update by
+incrementing the counter again to an even value. The end value of the
+counter uniquely identifies the update. An application can also map
+a window with an odd value of the sync request counter to make the
+map of the window and the initial paint of its contents a single update.
+      </para>
+      <para>
+When the compositing manager receives damage events for a window that
+is is in the middle of an update, it should not immediately redraw the
+portion of the screen including the window, but should instead wait
+until the window's counter is updated to an even value and only then
+redraw the window. If the portion of the screen needs to be redrawn
+for some other reason, such as a content update for another window or
+a window being moved, then the compositing manager may either update
+it immediately or wait for a short timeout before updating. A
+compositing manager must not block redrawing operations indefinitely
+if an application does not complete an update.
+      </para>
+    </sect2>
+    <sect2>
+      <title>_NET_WM_SYNC_DRAWN</title>
+      <para>
+This client message allows a client to know when an update it has
+created has been drawn to the screen by the compositing window manager.
+If this atom present in _NET_WM_SUPPORTED_LIST, then a client that
+supports the extended form of _NET_WM_SYNC_REQUEST will be sent a
+client message at the next redraw after the end of a deliminated update.
+(Note that the window manager is allowed to compress multiple deliminated
+updates together and only send one message for the last one in a sequence.)
+The contents of the message are as follows:
+      </para>
+      <programlisting><![CDATA[
+type = ClientMessage
+window = the respective client window
+message_type = WM_PROTOCOLS
+format = 32
+data.l[0] = _NET_WM_SYNC_DRAWN
+data.l[1] = low 32 bits of the update request number
+data.l[2] = high 32 bits of the update request number
+other data.l[] elements = 0
+]]></programlisting>
+      <para>
+In addition to sending one message at the end of each update, the window
+manager must send one message for each newly mapped window that uses the
+extended form of _NET_WM_SYNC_REQUEST after the window is first drawn,
+even if the initial value that the window manager reads from the counter
+is even.
+      </para>
+    </sect2>
+    <sect2>
+      <title>_NET_WM_SYNC_FENCES</title>
+      <para>
+On some systems with loose synchronization between different clients using
+the graphics system, simply waiting for notification from the X server
+that the client has ended an update is not sufficient, and a GL-based
+compositing manager must also insert GL-level synchronization to ensure
+correct drawing.
+      </para>
+      <para>
+The _NET_WM_SYNC_FENCES property is set on a toplevel by an
+application and contains a list of XSync fence objects. Before ending
+an update by setting the XSync counter to an even value N, the application,
+must use XSyncTriggerFence() to trigger the fence object stored in the property
+at index (N / 2) % L, where L is the number of counters in property.  If
+an application waits for the _NET_WM_SYNC_DRAWN message before making
+a new update, 2 is a sufficiently large value for L.
+      </para>
+      <para>
+When the window is mapped, the GL-based compositor must import the fences
+in _NET_WM_SYNC_FENCES as GL sync objects using the ImportSyncEXT()
+procedure from the <link linkend="x11_sync_object">EXT_x11_sync_object</link>.
+After receiving a frame update ending with counter value N, the next time
+that the window is redrawn, the compositing manager should use glWaitSync()
+on the fence at index (N / 2) % L.
+      </para>
+      <para>
+Note that if an application window doesn't export _NET_WM_SYNC_FENCES, or
+draws outside a frame update, the compositing manager still has to ensure
+correct synchronization. If the compositing manager has received damage
+events not part of any frame update, then before redrawing the screen,
+the compositing manager must use XSyncTriggerFence() trigger an X fence it
+has created itself and then wait for that with glWaitSync().
+      </para>
+    </sect2>
 </sect1>
 <sect1>
 	<title>Implementation notes</title>
@@ -2174,6 +2330,18 @@ int net_get_hostname (char *buf, size_t maxlen)
     </para>
     </listitem>
     </varlistentry>
+    <varlistentry>
+    <term>[x11_sync_object]</term>
+    <listitem>
+    <para id="x11_sync_object">
+      Piers Daniell, Pierre-Loup Griffais, James Jones,  Aaron Plattner,
+      "EXT_x11_sync_object".
+      <ulink url="http://www.opengl.org/registry/specs/EXT/x11_sync_object.txt";>
+      http://www.opengl.org/registry/specs/EXT/x11_sync_object.txt
+      </ulink>
+    </para>
+    </listitem>
+    </varlistentry>
     </variablelist>
   </sect1>
   <sect1>
@@ -2240,6 +2408,16 @@ OR OTHER DEALINGS IN THE SOFTWARE.
 	</sect1>
   <sect1>
     <title>Change history</title>
+	    <sect2>
+		<title>Changes since 1.4draft</title>
+		<itemizedlist>
+		<listitem><para>
+Added extended form of the _NET_WM_SYNC_REQUEST protocol, along with
+_NET_WM_SYNC_DRAWN and _NET_WM_SYNC_FENCES, to allow applications to
+deliminate updates.
+		</para></listitem>
+		</itemizedlist>
+	    </sect2>
  	    <sect2>
  		<title>Changes since 1.3</title>
  		<itemizedlist>
-- 
1.7.7



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]