Commit 8db9b345 authored by Simon Ser's avatar Simon Ser
Browse files

xwayland: add support for presentation-time



This change just replaces wl_surface.frame with presentation-time
when available. This allows the X11 PresentCompleteNotify events to
be sent right after vblank like X11 clients expect, even if the
compositor sends delayed wl_surface.frame events (e.g. Sway can be
configured to do so).

This is groundwork for taking advantage of more presentation-time
features, like accurate timing information and multiple frames in
flight at the same time.

Signed-off-by: Simon Ser's avatarSimon Ser <contact@emersion.fr>
parent 6c51818a
Pipeline #286334 passed with stages
in 6 minutes and 43 seconds
......@@ -108,7 +108,9 @@ Xwayland_built_sources += \
viewporter-client-protocol.h \
viewporter-protocol.c\
xdg-shell-client-protocol.h\
xdg-shell-protocol.c
xdg-shell-protocol.c\
presentation-time-client-protocol.h\
presentation-time-protocol.c
if XWAYLAND_EGLSTREAM
Xwayland_built_sources += \
......@@ -170,6 +172,11 @@ xdg-shell-protocol.c: $(WAYLAND_PROTOCOLS_DATADIR)/stable/xdg-shell/xdg-shell.xm
xdg-shell-client-protocol.h: $(WAYLAND_PROTOCOLS_DATADIR)/stable/xdg-shell/xdg-shell.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
presentation-time-protocol.c: $(WAYLAND_PROTOCOLS_DATADIR)/stable/presentation-time/presentation-time.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@
presentation-time-client-protocol.h: $(WAYLAND_PROTOCOLS_DATADIR)/stable/presentation-time/presentation-time.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
wayland-eglstream-client-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
wayland-eglstream-controller-client-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream-controller.xml
......
......@@ -42,6 +42,7 @@ xdg_output_xml = join_paths(protodir, 'unstable', 'xdg-output', 'xdg-output-unst
dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml')
viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml')
xdg_shell_xml = join_paths(protodir, 'stable', 'xdg-shell', 'xdg-shell.xml')
presentation_time_xml = join_paths(protodir, 'stable', 'presentation-time', 'presentation-time.xml')
client_header = generator(scanner,
output : '@BASENAME@-client-protocol.h',
......@@ -66,6 +67,7 @@ srcs += client_header.process(xdg_output_xml)
srcs += client_header.process(dmabuf_xml)
srcs += client_header.process(viewporter_xml)
srcs += client_header.process(xdg_shell_xml)
srcs += client_header.process(presentation_time_xml)
srcs += code.process(relative_xml)
srcs += code.process(pointer_xml)
srcs += code.process(tablet_xml)
......@@ -74,6 +76,7 @@ srcs += code.process(xdg_output_xml)
srcs += code.process(dmabuf_xml)
srcs += code.process(viewporter_xml)
srcs += code.process(xdg_shell_xml)
srcs += code.process(presentation_time_xml)
xwayland_glamor = []
eglstream_srcs = []
......
......@@ -34,6 +34,8 @@
#include "xwayland-pixmap.h"
#include "glamor.h"
#include "presentation-time-client-protocol.h"
/*
* When not flipping let Present copy with 60fps.
* When flipping wait on frame_callback, otherwise
......@@ -97,13 +99,27 @@ xwl_present_has_pending_events(struct xwl_present_window *xwl_present_window)
!xorg_list_is_empty(&xwl_present_window->wait_list);
}
static Bool
xwl_present_has_pending_presentation_feedbacks(struct xwl_present_window *xwl_present_window)
{
struct xwl_present_event *event;
xorg_list_for_each_entry(event, &xwl_present_window->wait_list, list) {
if (event->presentation_feedback)
return TRUE;
}
return FALSE;
}
static void
xwl_present_reset_timer(struct xwl_present_window *xwl_present_window)
{
if (xwl_present_has_pending_events(xwl_present_window)) {
CARD32 timeout;
if (!xorg_list_is_empty(&xwl_present_window->frame_callback_list))
if (!xorg_list_is_empty(&xwl_present_window->frame_callback_list) ||
xwl_present_has_pending_presentation_feedbacks(xwl_present_window))
timeout = TIMER_LEN_FLIP;
else
timeout = TIMER_LEN_COPY;
......@@ -134,6 +150,9 @@ xwl_present_free_event(struct xwl_present_event *event)
if (!event)
return;
if (event->presentation_feedback)
wp_presentation_feedback_destroy(event->presentation_feedback);
xwl_present_release_pixmap(event);
xorg_list_del(&event->list);
free(event);
......@@ -285,6 +304,46 @@ static const struct wl_callback_listener xwl_present_sync_listener = {
xwl_present_sync_callback
};
static void
xwl_presentation_feedback_sync_output(void *data,
struct wp_presentation_feedback *feedback,
struct wl_output *output)
{
/* no-op */
}
static void
xwl_presentation_feedback_presented(void *data,
struct wp_presentation_feedback *feedback,
uint32_t tv_sec_hi, uint32_t tv_sec_lo,
uint32_t tv_nsec, uint32_t refresh,
uint32_t seq_hi, uint32_t seq_lo,
uint32_t flags)
{
struct xwl_present_event *event = data;
struct xwl_present_window *xwl_present_window = event->xwl_present_window;
xwl_present_msc_bump(xwl_present_window);
/* we do not need the timer anymore for this frame,
* reset it for potentially the next one
*/
xwl_present_reset_timer(xwl_present_window);
}
static void
xwl_presentation_feedback_discarded(void *data,
struct wp_presentation_feedback *feedback)
{
/* no-op */
}
static const struct wp_presentation_feedback_listener xwl_presentation_feedback_listener = {
.sync_output = xwl_presentation_feedback_sync_output,
.presented = xwl_presentation_feedback_presented,
.discarded = xwl_presentation_feedback_discarded,
};
static RRCrtcPtr
xwl_present_get_crtc(WindowPtr present_window)
{
......@@ -337,11 +396,21 @@ xwl_present_queue_vblank(WindowPtr present_window,
event->pixmap = NULL;
event->xwl_present_window = xwl_present_window;
event->target_msc = msc;
event->presentation_feedback = NULL;
xorg_list_append(&event->list, &xwl_present_window->wait_list);
/* If there's a pending frame callback, use that */
if (xwl_window && xwl_window->frame_callback &&
if (xwl_window->xwl_screen->presentation) {
/* TODO: might miss a vblank here... */
event->presentation_feedback =
wp_presentation_feedback(xwl_window->xwl_screen->presentation,
xwl_window->surface);
wp_presentation_feedback_add_listener(event->presentation_feedback,
&xwl_presentation_feedback_listener,
event);
wl_surface_commit(xwl_window->surface);
} else if (xwl_window && xwl_window->frame_callback &&
xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
xorg_list_add(&xwl_present_window->frame_callback_list,
&xwl_window->frame_callback_list);
......@@ -455,6 +524,7 @@ xwl_present_flip(WindowPtr present_window,
event->target_msc = target_msc;
event->pending = TRUE;
event->abort = FALSE;
event->presentation_feedback = NULL;
if (sync_flip) {
xorg_list_init(&event->list);
......@@ -468,12 +538,21 @@ xwl_present_flip(WindowPtr present_window,
/* We can flip directly to the main surface (full screen window without clips) */
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
if (!xwl_window->frame_callback)
xwl_window_create_frame_callback(xwl_window);
if (xwl_window->xwl_screen->presentation) {
event->presentation_feedback =
wp_presentation_feedback(xwl_window->xwl_screen->presentation,
xwl_window->surface);
wp_presentation_feedback_add_listener(event->presentation_feedback,
&xwl_presentation_feedback_listener,
event);
} else {
if (!xwl_window->frame_callback)
xwl_window_create_frame_callback(xwl_window);
if (xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
xorg_list_add(&xwl_present_window->frame_callback_list,
&xwl_window->frame_callback_list);
if (xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
xorg_list_add(&xwl_present_window->frame_callback_list,
&xwl_window->frame_callback_list);
}
}
/* Realign timer */
......@@ -516,6 +595,7 @@ xwl_present_unrealize_window(struct xwl_present_window *xwl_present_window)
* the frame timer interval.
*/
xorg_list_del(&xwl_present_window->frame_callback_list);
/* TODO: delete presentation feedback? */
xwl_present_reset_timer(xwl_present_window);
}
......
......@@ -59,6 +59,8 @@ struct xwl_present_event {
struct xwl_present_window *xwl_present_window;
PixmapPtr pixmap;
struct wp_presentation_feedback *presentation_feedback;
struct xorg_list list;
};
......
......@@ -55,6 +55,7 @@
#include "xdg-output-unstable-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#include "presentation-time-client-protocol.h"
static DevPrivateKeyRec xwl_screen_private_key;
static DevPrivateKeyRec xwl_client_private_key;
......@@ -164,6 +165,9 @@ xwl_close_screen(ScreenPtr screen)
xwl_screen_release_tablet_manager(xwl_screen);
if (xwl_screen->presentation)
wp_presentation_destroy(xwl_screen->presentation);
RemoveNotifyFd(xwl_screen->wayland_fd);
wl_display_disconnect(xwl_screen->display);
......@@ -391,6 +395,9 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
else if (strcmp(interface, "wp_viewporter") == 0) {
xwl_screen->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1);
}
else if (strcmp(interface, wp_presentation_interface.name) == 0) {
xwl_screen->presentation = wl_registry_bind(registry, id, &wp_presentation_interface, 1);
}
#ifdef XWL_HAS_GLAMOR
else if (xwl_screen->glamor) {
xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface,
......
......@@ -85,6 +85,7 @@ struct xwl_screen {
struct zwp_xwayland_keyboard_grab_manager_v1 *wp_grab;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wp_viewporter *viewporter;
struct wp_presentation *presentation;
uint32_t serial;
#define XWL_FORMAT_ARGB8888 (1 << 0)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment