diff --git a/12to11-test.xml b/12to11-test.xml
index 7604a4c..eeac4b5 100644
--- a/12to11-test.xml
+++ b/12to11-test.xml
@@ -178,10 +178,10 @@
- The activated is sent when the xdg_activation protocol causes
- the surface associated with the role to be activated. Its
- parameters constitute the timestamp at which the activation
- occurred.
+ The activated event is sent when the xdg_activation protocol
+ causes the surface associated with the role to be activated.
+ Its parameters constitute the timestamp at which the
+ activation occurred.
If the surface that created the activation token used to
activate this test surface belongs to the same client that
@@ -194,6 +194,20 @@
+
+
+
+ The committed event is sent immediately after the role is
+ committed, and contains some information about what choices
+ were taken by the protocol translator during presentation.
+
+ presentation_hint is the presentation hint used by the
+ protocol translator during drawing. Its value is that of the
+ enumerator used internally, where 1 means async and 0 means
+ vsync.
+
+
+
diff --git a/12to11.c b/12to11.c
index 3a40370..92ba0f3 100644
--- a/12to11.c
+++ b/12to11.c
@@ -249,6 +249,7 @@ XLMain (int argc, char **argv)
XLInitIdleInhibit ();
XLInitPointerGestures ();
XLInitXdgActivation ();
+ XLInitTearingControl ();
XLInitTest ();
/* This has to come after the rest of the initialization. */
diff --git a/Imakefile b/Imakefile
index 54456cc..06fae2e 100644
--- a/Imakefile
+++ b/Imakefile
@@ -18,8 +18,8 @@ MakeSubdirs($(SUBDIRS))
DependSubdirs($(SUBDIRS))
#endif
- SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c surface.c region.c shm.c atoms.c subcompositor.c positioner.c xdg_wm.c xdg_surface.c xdg_toplevel.c frame_clock.c xerror.c ewmh.c timer.c subsurface.c seat.c data_device.c xdg_popup.c dmabuf.c buffer.c select.c xdata.c xsettings.c dnd.c icon_surface.c primary_selection.c renderer.c picture_renderer.c explicit_synchronization.c transform.c wp_viewporter.c decoration.c text_input.c single_pixel_buffer.c drm_lease.c pointer_constraints.c time.c relative_pointer.c keyboard_shortcuts_inhibit.c idle_inhibit.c process.c fence_ring.c pointer_gestures.c test.c buffer_release.c xdg_activation.c
- OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o surface.o region.o shm.o atoms.o subcompositor.o positioner.o xdg_wm.o xdg_surface.o xdg_toplevel.o frame_clock.o xerror.o ewmh.o timer.o subsurface.o seat.o data_device.o xdg_popup.o dmabuf.o buffer.o select.o xdata.o xsettings.o dnd.o icon_surface.o primary_selection.o renderer.o picture_renderer.o explicit_synchronization.o transform.o wp_viewporter.o decoration.o text_input.o single_pixel_buffer.o drm_lease.o pointer_constraints.o time.o relative_pointer.o keyboard_shortcuts_inhibit.o idle_inhibit.o process.o fence_ring.o pointer_gestures.o test.o buffer_release.o xdg_activation.o
+ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c surface.c region.c shm.c atoms.c subcompositor.c positioner.c xdg_wm.c xdg_surface.c xdg_toplevel.c frame_clock.c xerror.c ewmh.c timer.c subsurface.c seat.c data_device.c xdg_popup.c dmabuf.c buffer.c select.c xdata.c xsettings.c dnd.c icon_surface.c primary_selection.c renderer.c picture_renderer.c explicit_synchronization.c transform.c wp_viewporter.c decoration.c text_input.c single_pixel_buffer.c drm_lease.c pointer_constraints.c time.c relative_pointer.c keyboard_shortcuts_inhibit.c idle_inhibit.c process.c fence_ring.c pointer_gestures.c test.c buffer_release.c xdg_activation.c tearing_control.c
+ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o surface.o region.o shm.o atoms.o subcompositor.o positioner.o xdg_wm.o xdg_surface.o xdg_toplevel.o frame_clock.o xerror.o ewmh.o timer.o subsurface.o seat.o data_device.o xdg_popup.o dmabuf.o buffer.o select.o xdata.o xsettings.o dnd.o icon_surface.o primary_selection.o renderer.o picture_renderer.o explicit_synchronization.o transform.o wp_viewporter.o decoration.o text_input.o single_pixel_buffer.o drm_lease.o pointer_constraints.o time.o relative_pointer.o keyboard_shortcuts_inhibit.o idle_inhibit.o process.o fence_ring.o pointer_gestures.o test.o buffer_release.o xdg_activation.o tearing_control.o
GENHEADERS = transfer_atoms.h drm_modifiers.h
HEADER = $(GENHEADERS) compositor.h
@@ -106,6 +106,7 @@ ScannerTarget(idle-inhibit-unstable-v1)
ScannerTarget(pointer-gestures-unstable-v1)
ScannerTarget(12to11-test)
ScannerTarget(xdg-activation-v1)
+ScannerTarget(tearing-control-v1)
/* Make seat.o depend on test_seat.c, as it includes that. Both files
are rather special. */
diff --git a/compositor.h b/compositor.h
index a3fcef7..118eb5b 100644
--- a/compositor.h
+++ b/compositor.h
@@ -876,6 +876,7 @@ typedef struct _State State;
typedef struct _FrameCallback FrameCallback;
typedef enum _RoleType RoleType;
typedef enum _FocusMode FocusMode;
+typedef enum _PresentationHint PresentationHint;
enum _FocusMode
{
@@ -901,24 +902,31 @@ enum _RoleType
enum
{
- PendingNone = 0,
- PendingOpaqueRegion = 1,
- PendingInputRegion = (1 << 2),
- PendingDamage = (1 << 3),
- PendingSurfaceDamage = (1 << 4),
- PendingBuffer = (1 << 5),
- PendingFrameCallbacks = (1 << 6),
- PendingBufferScale = (1 << 7),
- PendingAttachments = (1 << 8),
- PendingViewportSrc = (1 << 9),
- PendingViewportDest = (1 << 10),
- PendingBufferTransform = (1 << 11),
+ PendingNone = 0,
+ PendingOpaqueRegion = 1,
+ PendingInputRegion = (1 << 2),
+ PendingDamage = (1 << 3),
+ PendingSurfaceDamage = (1 << 4),
+ PendingBuffer = (1 << 5),
+ PendingFrameCallbacks = (1 << 6),
+ PendingBufferScale = (1 << 7),
+ PendingAttachments = (1 << 8),
+ PendingViewportSrc = (1 << 9),
+ PendingViewportDest = (1 << 10),
+ PendingBufferTransform = (1 << 11),
+ PendingPresentationHint = (1 << 12),
/* Flags here are stored in `pending' of the current state for
space reasons. */
BufferAlreadyReleased = (1 << 19),
};
+enum _PresentationHint
+ {
+ PresentationHintVsync,
+ PresentationHintAsync,
+ };
+
struct _FrameCallback
{
/* The next and last callbacks. */
@@ -968,6 +976,9 @@ struct _State
/* Viewport source rectangle. */
double src_x, src_y, src_width, src_height;
+
+ /* The presentation hint. Defaults to PresentationHintVsync. */
+ PresentationHint presentation_hint;
};
typedef enum _ClientDataType ClientDataType;
@@ -987,6 +998,7 @@ enum _ClientDataType
IdleInhibitData,
MaxClientData,
XdgActivationData,
+ TearingControlData,
};
struct _DestroyCallback
@@ -1889,6 +1901,10 @@ extern void XLGetTestSeat (struct wl_client *, struct wl_resource *,
extern void XLInitXdgActivation (void);
+/* Defined in tearing_control.c. */
+
+extern void XLInitTearingControl (void);
+
/* Utility functions that don't belong in a specific file. */
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])
diff --git a/surface.c b/surface.c
index e46e005..0e1c04b 100644
--- a/surface.c
+++ b/surface.c
@@ -917,6 +917,10 @@ SavePendingState (Surface *surface)
pixman_region32_copy (&surface->cached_state.opaque,
&surface->pending_state.opaque);
+ if (surface->pending_state.pending & PendingPresentationHint)
+ surface->cached_state.presentation_hint
+ = surface->pending_state.presentation_hint;
+
if (surface->pending_state.pending & PendingBufferScale)
surface->cached_state.buffer_scale
= surface->pending_state.buffer_scale;
@@ -1052,6 +1056,10 @@ InternalCommit1 (Surface *surface, State *pending)
}
}
+ if (pending->pending & PendingPresentationHint)
+ surface->current_state.presentation_hint
+ = pending->presentation_hint;
+
if (pending->pending & PendingBufferScale)
{
surface->current_state.buffer_scale = pending->buffer_scale;
diff --git a/test.c b/test.c
index 48d47a4..7f07b2e 100644
--- a/test.c
+++ b/test.c
@@ -226,6 +226,11 @@ Commit (Surface *surface, Role *role)
mapped. */
if (test->flags & IsSurfaceMapped)
SubcompositorUpdate (test->subcompositor);
+
+ /* And send the presentation hint. */
+ if (test->role.resource)
+ test_surface_send_committed (test->role.resource,
+ surface->current_state.presentation_hint);
}
static Bool
diff --git a/tests/Imakefile b/tests/Imakefile
index fe00a46..e13dd20 100644
--- a/tests/Imakefile
+++ b/tests/Imakefile
@@ -28,6 +28,7 @@ ScannerTarget(viewporter)
ScannerTarget(linux-dmabuf-unstable-v1)
ScannerTarget(xdg-activation-v1)
ScannerTarget(single-pixel-buffer-v1)
+ScannerTarget(tearing-control-v1)
/* Not actually a test. */
SRCS1 = $(COMMONSRCS) imgview.c
@@ -60,10 +61,25 @@ ScannerTarget(single-pixel-buffer-v1)
OBJS14 = $(COMMONSRCS) single_pixel_buffer_test.o
SRCS15 = $(COMMONSRCS) buffer_test.c
OBJS15 = $(COMMONSRCS) buffer_test.o
- PROGRAMS = imgview simple_test damage_test transform_test viewporter_test subsurface_test scale_test seat_test dmabuf_test select_test select_helper select_helper_multiple xdg_activation_test single_pixel_buffer_test buffer_test
+ SRCS16 = $(COMMONSRCS) tearing_control_test.c
+ OBJS16 = $(COMMONSRCS) tearing_control_test.o
+ PROGRAMS = imgview simple_test damage_test transform_test viewporter_test subsurface_test scale_test seat_test dmabuf_test select_test select_helper select_helper_multiple xdg_activation_test single_pixel_buffer_test buffer_test tearing_control_test
/* Make all objects depend on HEADER. */
$(OBJS1): $(HEADER)
+$(OBJS2): $(HEADER)
+$(OBJS3): $(HEADER)
+$(OBJS4): $(HEADER)
+$(OBJS5): $(HEADER)
+$(OBJS6): $(HEADER)
+$(OBJS7): $(HEADER)
+$(OBJS8): $(HEADER)
+$(OBJS9): $(HEADER)
+$(OBJS10): $(HEADER)
+$(OBJS13): $(HEADER)
+$(OBJS14): $(HEADER)
+$(OBJS15): $(HEADER)
+$(OBJS16): $(HEADER)
/* And depend on all sources and headers. */
depend:: $(HEADER) $(COMMONSRCS)
@@ -83,11 +99,13 @@ NormalProgramTarget(select_helper_multiple,$(OBJS12),NullParameter,$(XLIB),NullP
NormalProgramTarget(xdg_activation_test,$(OBJS13),NullParameter,$(LOCAL_LIBRARIES),NullParameter)
NormalProgramTarget(single_pixel_buffer_test,$(OBJS14),NullParameter,$(LOCAL_LIBRARIES),NullParameter)
NormalProgramTarget(buffer_test,$(OBJS15),NullParameter,$(LOCAL_LIBRARIES),NullParameter)
+NormalProgramTarget(tearing_control_test,$(OBJS16),NullParameter,$(LOCAL_LIBRARIES),NullParameter)
DependTarget3($(SRCS1),$(SRCS2),$(SRCS3))
DependTarget3($(SRCS4),$(SRCS5),$(SRCS6))
DependTarget3($(SRCS7),$(SRCS8),$(SRCS9))
DependTarget3($(SRCS10),$(SRCS11),$(SRCS12))
DependTarget3($(SRCS13),$(SRCS14),$(SRCS15))
+DependTarget3($(SRCS16),NullParameter,NullParameter)
all:: $(PROGRAMS)
diff --git a/tests/buffer_test.c b/tests/buffer_test.c
index e8967bb..a9ac825 100644
--- a/tests/buffer_test.c
+++ b/tests/buffer_test.c
@@ -30,7 +30,7 @@ enum test_kind
static const char *test_names[] =
{
"buffer_release",
- "buffer_destroy_kind",
+ "buffer_destroy",
};
#define LAST_TEST BUFFER_DESTROY_KIND
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 72b125f..375ff24 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -23,6 +23,7 @@ declare -a standard_tests=(
simple_test damage_test transform_test viewporter_test
subsurface_test scale_test seat_test dmabuf_test
xdg_activation_test single_pixel_buffer_test buffer_test
+ tearing_control_test
)
make -C . "${standard_tests[@]}"
diff --git a/tests/svnignore.txt b/tests/svnignore.txt
index 7c81a58..f8e0cf1 100644
--- a/tests/svnignore.txt
+++ b/tests/svnignore.txt
@@ -15,6 +15,7 @@ select_helper_multiple
xdg_activation_test
single_pixel_buffer_test
buffer_test
+tearing_control_test
imgview
reject.dump
Makefile
diff --git a/xdg_surface.c b/xdg_surface.c
index 5bca78a..0de8d46 100644
--- a/xdg_surface.c
+++ b/xdg_surface.c
@@ -276,7 +276,7 @@ RunFrameCallbacksConditionally (XdgRole *role)
role->state |= StatePendingFrameCallback;
}
-static void
+static Bool
UpdateFrameRefreshPrediction (XdgRole *role)
{
int desync_children;
@@ -296,7 +296,11 @@ UpdateFrameRefreshPrediction (XdgRole *role)
XLFrameClockSetPredictRefresh (role->clock);
else
XLFrameClockDisablePredictRefresh (role->clock);
+
+ return desync_children > 0;
}
+
+ return False;
}
static void
@@ -862,15 +866,15 @@ MaybeRunLateFrame (XdgRole *role)
if (role->state & StateLateFrame)
{
- /* Clear the late frame flag. */
- role->state &= ~StateLateFrame;
-
if (role->state & StateLateFrameAcked)
XLFrameClockUnfreeze (role->clock);
/* Now apply the state in the late frame. */
SubcompositorUpdate (role->subcompositor);
+ /* Clear the late frame flag. */
+ role->state &= ~StateLateFrame;
+
/* Return True, as a new update has started. */
return True;
}
@@ -1169,10 +1173,20 @@ WriteRedirectProperty (XdgRole *role)
(unsigned char *) &bypass_compositor, 1);
}
+static Bool
+WasFrameQueued (XdgRole *role)
+{
+ /* Return whether or not the translator slept before displaying this
+ frame in response to a frame drawn event. */
+
+ return (role->state & StateLateFrame) != 0;
+}
+
static void
NoteFrame (FrameMode mode, uint64_t id, void *data)
{
XdgRole *role;
+ Bool predict_refresh, urgent;
role = data;
@@ -1186,9 +1200,28 @@ NoteFrame (FrameMode mode, uint64_t id, void *data)
{
/* Update whether or not frame refresh prediction is to be
used. */
- UpdateFrameRefreshPrediction (role);
+ predict_refresh = UpdateFrameRefreshPrediction (role);
- if (XLFrameClockStartFrame (role->clock, False))
+ /* A rule of thumb is to never let the compositing manager
+ read or try to scan out incomplete buffer contents.
+ Thus, if the client asked for async presentation, Commit
+ will still wait for the compositor to finish drawing the
+ last frame.
+
+ In addition, how subsurfaces fit into all of this is
+ unclear. At present, the presentation hint of
+ subsurfaces is simply discarded, and the hint of the
+ topmost surface used instead. In addition, asynchronous
+ subsurfaces will prevent async presentation from taking
+ place at all. */
+
+ urgent = (WasFrameQueued (role)
+ && !predict_refresh
+ && role->role.surface
+ && (role->role.surface->current_state.presentation_hint
+ == PresentationHintAsync));
+
+ if (XLFrameClockStartFrame (role->clock, urgent))
role->state |= StateFrameStarted;
}