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">
<description summary="role activated">
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 @@
<arg name="activator_surface" type="object" interface="wl_surface"
allow-null="true"/>
</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 name="test_scale_lock" version="1">

View file

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

View file

@ -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. */

View file

@ -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])

View file

@ -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;

5
test.c
View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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[@]}"

View file

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

View file

@ -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;
}