Add tearing control protocol

* 12to11-test.xml (test_surface) <committed>: New event.
* 12to11.c (XLMain): Initialize tearing control.
* Imakefile (SRCS, OBJS): Add tearing_control.c/.o.
(tearing-control-v1): New scanner target.

* compositor.h (enum _PresentationHint): New enum.
(struct _State): Add fields for tearing control.
(enum _ClientDataType): Add tearing control type.
* surface.c (SavePendingState, InternalCommit1): Handle
presentation hints.
* test.c (Commit): Send new committed event.
* tests/Imakefile (OBJS16, SRCS16): Add
tearing_control_test.c/tearing_control_test.o.
(PROGRAMS): Add tearing_control_test.
(tearing-control-v1): New scanner target.

* tests/buffer_test.c (test_names): Fix typos.
* tests/run_tests.sh (standard_tests): Add tearing_control_test.
* tests/svnignore.txt: Add tearing_control_test.
* xdg_surface.c (UpdateFrameRefreshPrediction): Return whether
or not refresh prediction is on.
(MaybeRunLateFrame): Don't clear StateLateFrame until after
SubcompositorUpdate.
(WasFrameQueued): New function.
(NoteFrame): If a frame was queued and async presentation was
requested, present now.
This commit is contained in:
hujianwei 2022-11-19 06:36:56 +00:00
parent 4c7b4a2c5a
commit ed9a704e69
11 changed files with 124 additions and 26 deletions

View file

@ -178,10 +178,10 @@
<event name="activated"> <event name="activated">
<description summary="role activated"> <description summary="role activated">
The activated is sent when the xdg_activation protocol causes The activated event is sent when the xdg_activation protocol
the surface associated with the role to be activated. Its causes the surface associated with the role to be activated.
parameters constitute the timestamp at which the activation Its parameters constitute the timestamp at which the
occurred. activation occurred.
If the surface that created the activation token used to If the surface that created the activation token used to
activate this test surface belongs to the same client that activate this test surface belongs to the same client that
@ -194,6 +194,20 @@
<arg name="activator_surface" type="object" interface="wl_surface" <arg name="activator_surface" type="object" interface="wl_surface"
allow-null="true"/> allow-null="true"/>
</event> </event>
<event name="committed">
<description summary="commit happened">
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.
</description>
<arg name="presentation_hint" type="uint"/>
</event>
</interface> </interface>
<interface name="test_scale_lock" version="1"> <interface name="test_scale_lock" version="1">

View file

@ -249,6 +249,7 @@ XLMain (int argc, char **argv)
XLInitIdleInhibit (); XLInitIdleInhibit ();
XLInitPointerGestures (); XLInitPointerGestures ();
XLInitXdgActivation (); XLInitXdgActivation ();
XLInitTearingControl ();
XLInitTest (); XLInitTest ();
/* This has to come after the rest of the initialization. */ /* This has to come after the rest of the initialization. */

View file

@ -18,8 +18,8 @@ MakeSubdirs($(SUBDIRS))
DependSubdirs($(SUBDIRS)) DependSubdirs($(SUBDIRS))
#endif #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 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 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 GENHEADERS = transfer_atoms.h drm_modifiers.h
HEADER = $(GENHEADERS) compositor.h HEADER = $(GENHEADERS) compositor.h
@ -106,6 +106,7 @@ ScannerTarget(idle-inhibit-unstable-v1)
ScannerTarget(pointer-gestures-unstable-v1) ScannerTarget(pointer-gestures-unstable-v1)
ScannerTarget(12to11-test) ScannerTarget(12to11-test)
ScannerTarget(xdg-activation-v1) ScannerTarget(xdg-activation-v1)
ScannerTarget(tearing-control-v1)
/* Make seat.o depend on test_seat.c, as it includes that. Both files /* Make seat.o depend on test_seat.c, as it includes that. Both files
are rather special. */ are rather special. */

View file

@ -876,6 +876,7 @@ typedef struct _State State;
typedef struct _FrameCallback FrameCallback; typedef struct _FrameCallback FrameCallback;
typedef enum _RoleType RoleType; typedef enum _RoleType RoleType;
typedef enum _FocusMode FocusMode; typedef enum _FocusMode FocusMode;
typedef enum _PresentationHint PresentationHint;
enum _FocusMode enum _FocusMode
{ {
@ -913,12 +914,19 @@ enum
PendingViewportSrc = (1 << 9), PendingViewportSrc = (1 << 9),
PendingViewportDest = (1 << 10), PendingViewportDest = (1 << 10),
PendingBufferTransform = (1 << 11), PendingBufferTransform = (1 << 11),
PendingPresentationHint = (1 << 12),
/* Flags here are stored in `pending' of the current state for /* Flags here are stored in `pending' of the current state for
space reasons. */ space reasons. */
BufferAlreadyReleased = (1 << 19), BufferAlreadyReleased = (1 << 19),
}; };
enum _PresentationHint
{
PresentationHintVsync,
PresentationHintAsync,
};
struct _FrameCallback struct _FrameCallback
{ {
/* The next and last callbacks. */ /* The next and last callbacks. */
@ -968,6 +976,9 @@ struct _State
/* Viewport source rectangle. */ /* Viewport source rectangle. */
double src_x, src_y, src_width, src_height; double src_x, src_y, src_width, src_height;
/* The presentation hint. Defaults to PresentationHintVsync. */
PresentationHint presentation_hint;
}; };
typedef enum _ClientDataType ClientDataType; typedef enum _ClientDataType ClientDataType;
@ -987,6 +998,7 @@ enum _ClientDataType
IdleInhibitData, IdleInhibitData,
MaxClientData, MaxClientData,
XdgActivationData, XdgActivationData,
TearingControlData,
}; };
struct _DestroyCallback struct _DestroyCallback
@ -1889,6 +1901,10 @@ extern void XLGetTestSeat (struct wl_client *, struct wl_resource *,
extern void XLInitXdgActivation (void); extern void XLInitXdgActivation (void);
/* Defined in tearing_control.c. */
extern void XLInitTearingControl (void);
/* Utility functions that don't belong in a specific file. */ /* Utility functions that don't belong in a specific file. */
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0]) #define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])

View file

@ -917,6 +917,10 @@ SavePendingState (Surface *surface)
pixman_region32_copy (&surface->cached_state.opaque, pixman_region32_copy (&surface->cached_state.opaque,
&surface->pending_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) if (surface->pending_state.pending & PendingBufferScale)
surface->cached_state.buffer_scale surface->cached_state.buffer_scale
= surface->pending_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) if (pending->pending & PendingBufferScale)
{ {
surface->current_state.buffer_scale = pending->buffer_scale; surface->current_state.buffer_scale = pending->buffer_scale;

5
test.c
View file

@ -226,6 +226,11 @@ Commit (Surface *surface, Role *role)
mapped. */ mapped. */
if (test->flags & IsSurfaceMapped) if (test->flags & IsSurfaceMapped)
SubcompositorUpdate (test->subcompositor); 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 static Bool

View file

@ -28,6 +28,7 @@ ScannerTarget(viewporter)
ScannerTarget(linux-dmabuf-unstable-v1) ScannerTarget(linux-dmabuf-unstable-v1)
ScannerTarget(xdg-activation-v1) ScannerTarget(xdg-activation-v1)
ScannerTarget(single-pixel-buffer-v1) ScannerTarget(single-pixel-buffer-v1)
ScannerTarget(tearing-control-v1)
/* Not actually a test. */ /* Not actually a test. */
SRCS1 = $(COMMONSRCS) imgview.c SRCS1 = $(COMMONSRCS) imgview.c
@ -60,10 +61,25 @@ ScannerTarget(single-pixel-buffer-v1)
OBJS14 = $(COMMONSRCS) single_pixel_buffer_test.o OBJS14 = $(COMMONSRCS) single_pixel_buffer_test.o
SRCS15 = $(COMMONSRCS) buffer_test.c SRCS15 = $(COMMONSRCS) buffer_test.c
OBJS15 = $(COMMONSRCS) buffer_test.o 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. */ /* Make all objects depend on HEADER. */
$(OBJS1): $(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. */ /* And depend on all sources and headers. */
depend:: $(HEADER) $(COMMONSRCS) 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(xdg_activation_test,$(OBJS13),NullParameter,$(LOCAL_LIBRARIES),NullParameter)
NormalProgramTarget(single_pixel_buffer_test,$(OBJS14),NullParameter,$(LOCAL_LIBRARIES),NullParameter) NormalProgramTarget(single_pixel_buffer_test,$(OBJS14),NullParameter,$(LOCAL_LIBRARIES),NullParameter)
NormalProgramTarget(buffer_test,$(OBJS15),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($(SRCS1),$(SRCS2),$(SRCS3))
DependTarget3($(SRCS4),$(SRCS5),$(SRCS6)) DependTarget3($(SRCS4),$(SRCS5),$(SRCS6))
DependTarget3($(SRCS7),$(SRCS8),$(SRCS9)) DependTarget3($(SRCS7),$(SRCS8),$(SRCS9))
DependTarget3($(SRCS10),$(SRCS11),$(SRCS12)) DependTarget3($(SRCS10),$(SRCS11),$(SRCS12))
DependTarget3($(SRCS13),$(SRCS14),$(SRCS15)) DependTarget3($(SRCS13),$(SRCS14),$(SRCS15))
DependTarget3($(SRCS16),NullParameter,NullParameter)
all:: $(PROGRAMS) all:: $(PROGRAMS)

View file

@ -30,7 +30,7 @@ enum test_kind
static const char *test_names[] = static const char *test_names[] =
{ {
"buffer_release", "buffer_release",
"buffer_destroy_kind", "buffer_destroy",
}; };
#define LAST_TEST BUFFER_DESTROY_KIND #define LAST_TEST BUFFER_DESTROY_KIND

View file

@ -23,6 +23,7 @@ declare -a standard_tests=(
simple_test damage_test transform_test viewporter_test simple_test damage_test transform_test viewporter_test
subsurface_test scale_test seat_test dmabuf_test subsurface_test scale_test seat_test dmabuf_test
xdg_activation_test single_pixel_buffer_test buffer_test xdg_activation_test single_pixel_buffer_test buffer_test
tearing_control_test
) )
make -C . "${standard_tests[@]}" make -C . "${standard_tests[@]}"

View file

@ -15,6 +15,7 @@ select_helper_multiple
xdg_activation_test xdg_activation_test
single_pixel_buffer_test single_pixel_buffer_test
buffer_test buffer_test
tearing_control_test
imgview imgview
reject.dump reject.dump
Makefile Makefile

View file

@ -276,7 +276,7 @@ RunFrameCallbacksConditionally (XdgRole *role)
role->state |= StatePendingFrameCallback; role->state |= StatePendingFrameCallback;
} }
static void static Bool
UpdateFrameRefreshPrediction (XdgRole *role) UpdateFrameRefreshPrediction (XdgRole *role)
{ {
int desync_children; int desync_children;
@ -296,7 +296,11 @@ UpdateFrameRefreshPrediction (XdgRole *role)
XLFrameClockSetPredictRefresh (role->clock); XLFrameClockSetPredictRefresh (role->clock);
else else
XLFrameClockDisablePredictRefresh (role->clock); XLFrameClockDisablePredictRefresh (role->clock);
return desync_children > 0;
} }
return False;
} }
static void static void
@ -862,15 +866,15 @@ MaybeRunLateFrame (XdgRole *role)
if (role->state & StateLateFrame) if (role->state & StateLateFrame)
{ {
/* Clear the late frame flag. */
role->state &= ~StateLateFrame;
if (role->state & StateLateFrameAcked) if (role->state & StateLateFrameAcked)
XLFrameClockUnfreeze (role->clock); XLFrameClockUnfreeze (role->clock);
/* Now apply the state in the late frame. */ /* Now apply the state in the late frame. */
SubcompositorUpdate (role->subcompositor); SubcompositorUpdate (role->subcompositor);
/* Clear the late frame flag. */
role->state &= ~StateLateFrame;
/* Return True, as a new update has started. */ /* Return True, as a new update has started. */
return True; return True;
} }
@ -1169,10 +1173,20 @@ WriteRedirectProperty (XdgRole *role)
(unsigned char *) &bypass_compositor, 1); (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 static void
NoteFrame (FrameMode mode, uint64_t id, void *data) NoteFrame (FrameMode mode, uint64_t id, void *data)
{ {
XdgRole *role; XdgRole *role;
Bool predict_refresh, urgent;
role = data; role = data;
@ -1186,9 +1200,28 @@ NoteFrame (FrameMode mode, uint64_t id, void *data)
{ {
/* Update whether or not frame refresh prediction is to be /* Update whether or not frame refresh prediction is to be
used. */ 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; role->state |= StateFrameStarted;
} }