Queue present events to msc values. Fake msc events with a refresh rate of about 60fps when flips are not possible. When flips are executed rely on frame callbacks with a slow updating timer as fallback.
This is important for applications, that want to limit their framerate. Signed-off-by: Roman Gilg <subd...@gmail.com> --- hw/xwayland/xwayland-present.c | 103 +++++++++++++++++++++++++++++++++++++---- hw/xwayland/xwayland.h | 2 + 2 files changed, 96 insertions(+), 9 deletions(-) diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index a8cc024..f403ff7 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -27,6 +27,13 @@ #include <present.h> +/* + * When not flipping let Present copy with 60fps. + * When flipping wait on frame_callback, otherwise + * the surface is not visible, in this case update + * with long interval. + */ +#define TIMER_LEN_COPY 17 // ~60fps #define TIMER_LEN_FLIP 1000 // 1fps static void @@ -41,13 +48,23 @@ xwl_present_timer_callback(OsTimerPtr timer, CARD32 time, void *arg); +static inline Bool +xwl_present_has_events(struct xwl_window *xwl_window) +{ + return !xorg_list_is_empty(&xwl_window->present_event_list) || + !xorg_list_is_empty(&xwl_window->present_release_queue); +} + static void xwl_present_reset_timer(struct xwl_window *xwl_window) { - if ( !xorg_list_is_empty(&xwl_window->present_release_queue) ) { + if (xwl_present_has_events(xwl_window)) { + uint32_t timer_len = xwl_window->present_window ? TIMER_LEN_FLIP : + TIMER_LEN_COPY; + xwl_window->present_timer = TimerSet(xwl_window->present_timer, 0, - TIMER_LEN_FLIP, + timer_len, &xwl_present_timer_callback, xwl_window); } else { @@ -72,6 +89,14 @@ xwl_present_cleanup(WindowPtr window) xwl_window->present_window = NULL; } + /* Clear remaining events */ + xorg_list_for_each_entry_safe(event, tmp, &xwl_window->present_event_list, list) { + if (event->present_window == window) { + xorg_list_del(&event->list); + free(event); + } + } + /* Clear remaining buffer releases and inform Present about free ressources */ xorg_list_for_each_entry_safe(event, tmp, &xwl_window->present_release_queue, list) { if (event->present_window == window) { @@ -81,7 +106,7 @@ xwl_present_cleanup(WindowPtr window) } /* Clear timer */ - if ( xorg_list_is_empty(&xwl_window->present_release_queue) ) + if (!xwl_present_has_events(xwl_window)) xwl_present_free_timer(xwl_window); } @@ -122,6 +147,25 @@ static const struct wl_buffer_listener xwl_present_release_listener = { xwl_present_buffer_release }; +static void +xwl_present_events_notify(struct xwl_window *xwl_window) +{ + uint64_t msc = xwl_window->present_msc; + struct xwl_present_event *event, *tmp; + + xorg_list_for_each_entry_safe(event, tmp, + &xwl_window->present_event_list, + list) { + if (event->target_msc <= msc) { + present_wnmd_event_notify(event->present_window, + event->event_id, + xwl_window->present_ust, + msc); + xwl_present_free_event(event); + } + } +} + CARD32 xwl_present_timer_callback(OsTimerPtr timer, CARD32 time, @@ -133,9 +177,12 @@ xwl_present_timer_callback(OsTimerPtr timer, xwl_window->present_msc++; xwl_window->present_ust = GetTimeInMicros(); - if ( !xorg_list_is_empty(&xwl_window->present_release_queue) ) { + xwl_present_events_notify(xwl_window); + + if (xwl_present_has_events(xwl_window)) { /* Still events, restart timer */ - return TIMER_LEN_FLIP; + return xwl_window->present_window ? TIMER_LEN_FLIP : + TIMER_LEN_COPY; } else { /* No more events, do not restart timer and delete it instead */ xwl_present_free_timer(xwl_window); @@ -161,6 +208,8 @@ xwl_present_frame_callback(void *data, xwl_window->present_msc++; xwl_window->present_ust = GetTimeInMicros(); + xwl_present_events_notify(xwl_window); + /* we do not need the timer anymore for this frame, * reset it for potentially the next one */ @@ -248,9 +297,34 @@ xwl_present_queue_vblank(WindowPtr present_window, uint64_t event_id, uint64_t msc) { - /* Not yet implemented - */ - return BadRequest; + struct xwl_window *xwl_window = xwl_window_of_top(present_window); + struct xwl_present_event *event; + + if (!xwl_window) + return BadMatch; + + if (xwl_window->present_crtc_fake != crtc) + return BadRequest; + + if (xwl_window->present_window && + xwl_window->present_window != present_window) + return BadMatch; + + event = malloc(sizeof *event); + if (!event) + return BadAlloc; + + event->event_id = event_id; + event->present_window = present_window; + event->xwl_window = xwl_window; + event->target_msc = msc; + + xorg_list_append(&event->list, &xwl_window->present_event_list); + + if (!xwl_window->present_timer) + xwl_present_reset_timer(xwl_window); + + return Success; } /* @@ -264,11 +338,19 @@ xwl_present_abort_vblank(WindowPtr present_window, uint64_t msc) { struct xwl_window *xwl_window = xwl_window_of_top(present_window); - struct xwl_present_event *event; + struct xwl_present_event *event, *tmp; if (!xwl_window) return; + xorg_list_for_each_entry_safe(event, tmp, &xwl_window->present_event_list, list) { + if (event->event_id == event_id) { + xorg_list_del(&event->list); + free(event); + return; + } + } + xorg_list_for_each_entry(event, &xwl_window->present_release_queue, list) { if (event->event_id == event_id) { event->abort = TRUE; @@ -411,6 +493,9 @@ xwl_present_flips_stop(WindowPtr window) assert(xwl_window->present_window == window); xwl_window->present_window = NULL; + + /* Change back to the fast refresh rate */ + xwl_present_reset_timer(xwl_window); } static present_wnmd_info_rec xwl_present_info = { diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index e6cec18..a655593 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -140,6 +140,8 @@ struct xwl_window { struct wl_callback *present_frame_callback; struct wl_callback *present_sync_callback; + + struct xorg_list present_event_list; struct xorg_list present_release_queue; }; -- 2.7.4 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel