xwayland: persistent window struct on present

Instead of reusing xwl_window introduce a persistent window struct for every
window, that asks for Present flips.

This struct saves all relevant data and is only freed on window destroy.

Signed-off-by: Roman Gilg <subdiff@gmail.com>
Tested-by: Olivier Fourdan <ofourdan@redhat.com>
This commit is contained in:
Roman Gilg 2018-05-04 03:07:31 +02:00 committed by Adam Jackson
parent c9afd8cb5e
commit cf838f5ca8
3 changed files with 214 additions and 154 deletions

View File

@ -36,11 +36,49 @@
#define TIMER_LEN_COPY 17 // ~60fps
#define TIMER_LEN_FLIP 1000 // 1fps
static void
xwl_present_free_timer(struct xwl_window *xwl_window)
static DevPrivateKeyRec xwl_present_window_private_key;
static struct xwl_present_window *
xwl_present_window_priv(WindowPtr window)
{
TimerFree(xwl_window->present_timer);
xwl_window->present_timer = NULL;
return dixGetPrivate(&window->devPrivates,
&xwl_present_window_private_key);
}
static struct xwl_present_window *
xwl_present_window_get_priv(WindowPtr window)
{
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
if (xwl_present_window == NULL) {
ScreenPtr screen = window->drawable.pScreen;
xwl_present_window = calloc (1, sizeof (struct xwl_present_window));
if (!xwl_present_window)
return NULL;
xwl_present_window->crtc_fake = RRCrtcCreate(screen,
xwl_present_window);
xwl_present_window->window = window;
xwl_present_window->msc = 1;
xwl_present_window->ust = GetTimeInMicros();
xorg_list_init(&xwl_present_window->event_list);
xorg_list_init(&xwl_present_window->release_queue);
dixSetPrivate(&window->devPrivates,
&xwl_present_window_private_key,
xwl_present_window);
}
return xwl_present_window;
}
static void
xwl_present_free_timer(struct xwl_present_window *xwl_present_window)
{
TimerFree(xwl_present_window->frame_timer);
xwl_present_window->frame_timer = NULL;
}
static CARD32
@ -49,57 +87,73 @@ xwl_present_timer_callback(OsTimerPtr timer,
void *arg);
static inline Bool
xwl_present_has_events(struct xwl_window *xwl_window)
xwl_present_has_events(struct xwl_present_window *xwl_present_window)
{
return !xorg_list_is_empty(&xwl_window->present_event_list) ||
!xorg_list_is_empty(&xwl_window->present_release_queue);
return !xorg_list_is_empty(&xwl_present_window->event_list) ||
!xorg_list_is_empty(&xwl_present_window->release_queue);
}
static inline Bool
xwl_present_is_flipping(WindowPtr window, struct xwl_window *xwl_window)
{
return xwl_window && xwl_window->present_window == window;
}
static void
xwl_present_reset_timer(struct xwl_window *xwl_window)
xwl_present_reset_timer(struct xwl_present_window *xwl_present_window)
{
if (xwl_present_has_events(xwl_window)) {
uint32_t timer_len = xwl_window->present_window ? TIMER_LEN_FLIP :
TIMER_LEN_COPY;
if (xwl_present_has_events(xwl_present_window)) {
WindowPtr present_window = xwl_present_window->window;
Bool is_flipping = xwl_present_is_flipping(present_window,
xwl_window_from_window(present_window));
xwl_window->present_timer = TimerSet(xwl_window->present_timer,
0,
timer_len,
&xwl_present_timer_callback,
xwl_window);
xwl_present_window->frame_timer = TimerSet(xwl_present_window->frame_timer,
0,
is_flipping ? TIMER_LEN_FLIP :
TIMER_LEN_COPY,
&xwl_present_timer_callback,
xwl_present_window);
} else {
xwl_present_free_timer(xwl_window);
xwl_present_free_timer(xwl_present_window);
}
}
void
xwl_present_cleanup(struct xwl_window *xwl_window, WindowPtr window)
xwl_present_cleanup(WindowPtr window)
{
struct xwl_window *xwl_window = xwl_window_from_window(window);
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
struct xwl_present_event *event, *tmp;
if (xwl_window->present_window != window && xwl_window->window != window)
if (!xwl_present_window)
return;
if (xwl_window->present_frame_callback) {
wl_callback_destroy(xwl_window->present_frame_callback);
xwl_window->present_frame_callback = NULL;
if (xwl_window && xwl_window->present_window == window)
xwl_window->present_window = NULL;
RRCrtcDestroy(xwl_present_window->crtc_fake);
if (xwl_present_window->frame_callback) {
wl_callback_destroy(xwl_present_window->frame_callback);
xwl_present_window->frame_callback = NULL;
}
xwl_window->present_window = NULL;
/* Clear remaining events */
xorg_list_for_each_entry_safe(event, tmp, &xwl_window->present_event_list, list) {
xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->event_list, list) {
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) {
xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->release_queue, list) {
xorg_list_del(&event->list);
event->abort = TRUE;
}
/* Clear timer */
xwl_present_free_timer(xwl_window);
xwl_present_free_timer(xwl_present_window);
free(xwl_present_window);
}
static void
@ -113,11 +167,10 @@ static void
xwl_present_buffer_release(void *data, struct wl_buffer *buffer)
{
struct xwl_present_event *event = data;
if (!event)
return;
wl_buffer_set_user_data(buffer, NULL);
wl_buffer_set_user_data(buffer, NULL);
event->buffer_released = TRUE;
if (event->abort) {
@ -127,10 +180,10 @@ xwl_present_buffer_release(void *data, struct wl_buffer *buffer)
}
if (!event->pending) {
present_wnmd_event_notify(event->present_window,
present_wnmd_event_notify(event->xwl_present_window->window,
event->event_id,
event->xwl_window->present_ust,
event->xwl_window->present_msc);
event->xwl_present_window->ust,
event->xwl_present_window->msc);
xwl_present_free_event(event);
}
}
@ -140,18 +193,18 @@ static const struct wl_buffer_listener xwl_present_release_listener = {
};
static void
xwl_present_events_notify(struct xwl_window *xwl_window)
xwl_present_events_notify(struct xwl_present_window *xwl_present_window)
{
uint64_t msc = xwl_window->present_msc;
uint64_t msc = xwl_present_window->msc;
struct xwl_present_event *event, *tmp;
xorg_list_for_each_entry_safe(event, tmp,
&xwl_window->present_event_list,
&xwl_present_window->event_list,
list) {
if (event->target_msc <= msc) {
present_wnmd_event_notify(event->present_window,
present_wnmd_event_notify(xwl_present_window->window,
event->event_id,
xwl_window->present_ust,
xwl_present_window->ust,
msc);
xwl_present_free_event(event);
}
@ -163,21 +216,23 @@ xwl_present_timer_callback(OsTimerPtr timer,
CARD32 time,
void *arg)
{
struct xwl_window *xwl_window = arg;
struct xwl_present_window *xwl_present_window = arg;
WindowPtr present_window = xwl_present_window->window;
struct xwl_window *xwl_window = xwl_window_from_window(present_window);
xwl_window->present_timer_firing = TRUE;
xwl_window->present_msc++;
xwl_window->present_ust = GetTimeInMicros();
xwl_present_window->frame_timer_firing = TRUE;
xwl_present_window->msc++;
xwl_present_window->ust = GetTimeInMicros();
xwl_present_events_notify(xwl_window);
xwl_present_events_notify(xwl_present_window);
if (xwl_present_has_events(xwl_window)) {
if (xwl_present_has_events(xwl_present_window)) {
/* Still events, restart timer */
return xwl_window->present_window ? TIMER_LEN_FLIP :
TIMER_LEN_COPY;
return xwl_present_is_flipping(present_window, xwl_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);
xwl_present_free_timer(xwl_present_window);
return 0;
}
}
@ -187,25 +242,25 @@ xwl_present_frame_callback(void *data,
struct wl_callback *callback,
uint32_t time)
{
struct xwl_window *xwl_window = data;
struct xwl_present_window *xwl_present_window = data;
wl_callback_destroy(xwl_window->present_frame_callback);
xwl_window->present_frame_callback = NULL;
wl_callback_destroy(xwl_present_window->frame_callback);
xwl_present_window->frame_callback = NULL;
if (xwl_window->present_timer_firing) {
if (xwl_present_window->frame_timer_firing) {
/* If the timer is firing, this frame callback is too late */
return;
}
xwl_window->present_msc++;
xwl_window->present_ust = GetTimeInMicros();
xwl_present_window->msc++;
xwl_present_window->ust = GetTimeInMicros();
xwl_present_events_notify(xwl_window);
xwl_present_events_notify(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_window);
xwl_present_reset_timer(xwl_present_window);
}
static const struct wl_callback_listener xwl_present_frame_listener = {
@ -218,7 +273,7 @@ xwl_present_sync_callback(void *data,
uint32_t time)
{
struct xwl_present_event *event = data;
struct xwl_window *xwl_window = event->xwl_window;
struct xwl_present_window *xwl_present_window = event->xwl_present_window;
event->pending = FALSE;
@ -230,17 +285,17 @@ xwl_present_sync_callback(void *data,
return;
}
present_wnmd_event_notify(event->present_window,
present_wnmd_event_notify(xwl_present_window->window,
event->event_id,
xwl_window->present_ust,
xwl_window->present_msc);
xwl_present_window->ust,
xwl_present_window->msc);
if (event->buffer_released)
/* If the buffer was already released, send the event now again */
present_wnmd_event_notify(event->present_window,
present_wnmd_event_notify(xwl_present_window->window,
event->event_id,
xwl_window->present_ust,
xwl_window->present_msc);
xwl_present_window->ust,
xwl_present_window->msc);
}
static const struct wl_callback_listener xwl_present_sync_listener = {
@ -250,35 +305,26 @@ static const struct wl_callback_listener xwl_present_sync_listener = {
static RRCrtcPtr
xwl_present_get_crtc(WindowPtr present_window)
{
struct xwl_window *xwl_window = xwl_window_from_window(present_window);
if (xwl_window == NULL)
struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
if (xwl_present_window == NULL)
return NULL;
return xwl_window->present_crtc_fake;
return xwl_present_window->crtc_fake;
}
static int
xwl_present_get_ust_msc(WindowPtr present_window, uint64_t *ust, uint64_t *msc)
{
struct xwl_window *xwl_window = xwl_window_from_window(present_window);
if (!xwl_window)
struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
if (!xwl_present_window)
return BadAlloc;
*ust = xwl_window->present_ust;
*msc = xwl_window->present_msc;
*ust = xwl_present_window->ust;
*msc = xwl_present_window->msc;
return Success;
}
static void
xwl_present_set_present_window(struct xwl_window *xwl_window,
WindowPtr present_window)
{
if (xwl_window->present_window)
return;
xwl_window->present_window = present_window;
}
/*
* Queue an event to report back to the Present extension when the specified
* MSC has past
@ -290,12 +336,13 @@ xwl_present_queue_vblank(WindowPtr present_window,
uint64_t msc)
{
struct xwl_window *xwl_window = xwl_window_from_window(present_window);
struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
struct xwl_present_event *event;
if (!xwl_window)
return BadMatch;
if (xwl_window->present_crtc_fake != crtc)
if (xwl_present_window->crtc_fake != crtc)
return BadRequest;
if (xwl_window->present_window &&
@ -307,14 +354,13 @@ xwl_present_queue_vblank(WindowPtr present_window,
return BadAlloc;
event->event_id = event_id;
event->present_window = present_window;
event->xwl_window = xwl_window;
event->xwl_present_window = xwl_present_window;
event->target_msc = msc;
xorg_list_append(&event->list, &xwl_window->present_event_list);
xorg_list_append(&event->list, &xwl_present_window->event_list);
if (!xwl_window->present_timer)
xwl_present_reset_timer(xwl_window);
if (!xwl_present_window->frame_timer)
xwl_present_reset_timer(xwl_present_window);
return Success;
}
@ -329,13 +375,13 @@ xwl_present_abort_vblank(WindowPtr present_window,
uint64_t event_id,
uint64_t msc)
{
struct xwl_window *xwl_window = xwl_window_from_window(present_window);
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(present_window);
struct xwl_present_event *event, *tmp;
if (!xwl_window)
if (!xwl_present_window)
return;
xorg_list_for_each_entry_safe(event, tmp, &xwl_window->present_event_list, list) {
xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->event_list, list) {
if (event->event_id == event_id) {
xorg_list_del(&event->list);
free(event);
@ -343,7 +389,7 @@ xwl_present_abort_vblank(WindowPtr present_window,
}
}
xorg_list_for_each_entry(event, &xwl_window->present_release_queue, list) {
xorg_list_for_each_entry(event, &xwl_present_window->release_queue, list) {
if (event->event_id == event_id) {
event->abort = TRUE;
return;
@ -378,15 +424,6 @@ xwl_present_check_flip2(RRCrtcPtr crtc,
xwl_window->present_window != present_window)
return FALSE;
if (!xwl_window->present_crtc_fake)
return FALSE;
/*
* Make sure the client doesn't try to flip to another crtc
* than the one created for 'xwl_window'.
*/
if (xwl_window->present_crtc_fake != crtc)
return FALSE;
/*
* We currently only allow flips of windows, that have the same
* dimensions as their xwl_window parent window. For the case of
@ -408,35 +445,45 @@ xwl_present_flip(WindowPtr present_window,
RegionPtr damage)
{
struct xwl_window *xwl_window = xwl_window_from_window(present_window);
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(present_window);
BoxPtr present_box, damage_box;
Bool buffer_created;
struct wl_buffer *buffer;
struct xwl_present_event *event;
if (!xwl_window)
return FALSE;
/*
* Make sure the client doesn't try to flip to another crtc
* than the one created for 'xwl_window'.
*/
if (xwl_present_window->crtc_fake != crtc)
return FALSE;
present_box = RegionExtents(&present_window->winSize);
damage_box = RegionExtents(damage);
xwl_present_set_present_window(xwl_window, present_window);
event = malloc(sizeof *event);
if (!event)
return FALSE;
xwl_window->present_window = present_window;
buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap,
present_box->x2 - present_box->x1,
present_box->y2 - present_box->y1,
&buffer_created);
event->event_id = event_id;
event->present_window = present_window;
event->xwl_window = xwl_window;
event->xwl_present_window = xwl_present_window;
event->buffer = buffer;
event->target_msc = xwl_window->present_msc;
event->target_msc = xwl_present_window->msc;
event->pending = TRUE;
event->abort = FALSE;
event->buffer_released = FALSE;
xorg_list_add(&event->list, &xwl_window->present_release_queue);
xorg_list_add(&event->list, &xwl_present_window->release_queue);
if (buffer_created)
wl_buffer_add_listener(buffer, &xwl_present_release_listener, NULL);
@ -445,18 +492,18 @@ 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->present_timer ||
xwl_window->present_timer_firing) {
if (!xwl_present_window->frame_timer ||
xwl_present_window->frame_timer_firing) {
/* Realign timer */
xwl_window->present_timer_firing = FALSE;
xwl_present_reset_timer(xwl_window);
xwl_present_window->frame_timer_firing = FALSE;
xwl_present_reset_timer(xwl_present_window);
}
if (!xwl_window->present_frame_callback) {
xwl_window->present_frame_callback = wl_surface_frame(xwl_window->surface);
wl_callback_add_listener(xwl_window->present_frame_callback,
if (!xwl_present_window->frame_callback) {
xwl_present_window->frame_callback = wl_surface_frame(xwl_window->surface);
wl_callback_add_listener(xwl_present_window->frame_callback,
&xwl_present_frame_listener,
xwl_window);
xwl_present_window);
}
wl_surface_damage(xwl_window->surface, 0, 0,
@ -465,8 +512,8 @@ xwl_present_flip(WindowPtr present_window,
wl_surface_commit(xwl_window->surface);
xwl_window->present_sync_callback = wl_display_sync(xwl_window->xwl_screen->display);
wl_callback_add_listener(xwl_window->present_sync_callback,
xwl_present_window->sync_callback = wl_display_sync(xwl_window->xwl_screen->display);
wl_callback_add_listener(xwl_present_window->sync_callback,
&xwl_present_sync_listener,
event);
@ -478,6 +525,7 @@ static void
xwl_present_flips_stop(WindowPtr window)
{
struct xwl_window *xwl_window = xwl_window_from_window(window);
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
if (!xwl_window)
return;
@ -487,7 +535,7 @@ xwl_present_flips_stop(WindowPtr window)
xwl_window->present_window = NULL;
/* Change back to the fast refresh rate */
xwl_present_reset_timer(xwl_window);
xwl_present_reset_timer(xwl_present_window);
}
static present_wnmd_info_rec xwl_present_info = {
@ -518,5 +566,8 @@ xwl_present_init(ScreenPtr screen)
if (xwl_screen->egl_backend.post_damage != NULL)
return FALSE;
if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0))
return FALSE;
return present_wnmd_screen_init(screen, &xwl_present_info);
}

View File

@ -531,17 +531,6 @@ xwl_realize_window(WindowPtr window)
wl_region_destroy(region);
}
#ifdef GLAMOR_HAS_GBM
if (xwl_screen->present) {
xwl_window->present_crtc_fake = RRCrtcCreate(xwl_screen->screen, xwl_window);
xwl_window->present_msc = 1;
xwl_window->present_ust = GetTimeInMicros();
xorg_list_init(&xwl_window->present_event_list);
xorg_list_init(&xwl_window->present_release_queue);
}
#endif
wl_display_flush(xwl_screen->display);
send_surface_id_event(xwl_window);
@ -607,12 +596,6 @@ xwl_unrealize_window(WindowPtr window)
compUnredirectWindow(serverClient, window, CompositeRedirectManual);
#ifdef GLAMOR_HAS_GBM
xwl_window = xwl_window_from_window(window);
if (xwl_window && xwl_screen->present)
xwl_present_cleanup(xwl_window, window);
#endif
screen->UnrealizeWindow = xwl_screen->UnrealizeWindow;
ret = (*screen->UnrealizeWindow) (window);
xwl_screen->UnrealizeWindow = screen->UnrealizeWindow;
@ -629,11 +612,6 @@ xwl_unrealize_window(WindowPtr window)
if (xwl_window->frame_callback)
wl_callback_destroy(xwl_window->frame_callback);
#ifdef GLAMOR_HAS_GBM
if (xwl_window->present_crtc_fake)
RRCrtcDestroy(xwl_window->present_crtc_fake);
#endif
free(xwl_window);
dixSetPrivate(&window->devPrivates, &xwl_window_private_key, NULL);
@ -661,6 +639,31 @@ static const struct wl_callback_listener frame_listener = {
frame_callback
};
static Bool
xwl_destroy_window(WindowPtr window)
{
ScreenPtr screen = window->drawable.pScreen;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
Bool ret;
#ifdef GLAMOR_HAS_GBM
if (xwl_screen->present)
xwl_present_cleanup(window);
#endif
screen->DestroyWindow = xwl_screen->DestroyWindow;
if (screen->DestroyWindow)
ret = screen->DestroyWindow (window);
else
ret = TRUE;
xwl_screen->DestroyWindow = screen->DestroyWindow;
screen->DestroyWindow = xwl_destroy_window;
return ret;
}
static void
xwl_window_post_damage(struct xwl_window *xwl_window)
{
@ -1114,6 +1117,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
xwl_screen->UnrealizeWindow = pScreen->UnrealizeWindow;
pScreen->UnrealizeWindow = xwl_unrealize_window;
xwl_screen->DestroyWindow = pScreen->DestroyWindow;
pScreen->DestroyWindow = xwl_destroy_window;
xwl_screen->CloseScreen = pScreen->CloseScreen;
pScreen->CloseScreen = xwl_close_screen;

View File

@ -77,6 +77,7 @@ struct xwl_screen {
CloseScreenProcPtr CloseScreen;
RealizeWindowProcPtr RealizeWindow;
UnrealizeWindowProcPtr UnrealizeWindow;
DestroyWindowProcPtr DestroyWindow;
XYToWindowProcPtr XYToWindow;
struct xorg_list output_list;
@ -172,26 +173,29 @@ struct xwl_window {
struct xorg_list link_damage;
struct wl_callback *frame_callback;
Bool allow_commits;
#ifdef GLAMOR_HAS_GBM
/* present */
RRCrtcPtr present_crtc_fake;
struct xorg_list present_link;
WindowPtr present_window;
uint64_t present_msc;
uint64_t present_ust;
OsTimerPtr present_timer;
Bool present_timer_firing;
struct wl_callback *present_frame_callback;
struct wl_callback *present_sync_callback;
struct xorg_list present_event_list;
struct xorg_list present_release_queue;
#endif
};
#ifdef GLAMOR_HAS_GBM
struct xwl_present_window {
struct xwl_screen *xwl_screen;
WindowPtr window;
struct xorg_list link;
RRCrtcPtr crtc_fake;
uint64_t msc;
uint64_t ust;
OsTimerPtr frame_timer;
Bool frame_timer_firing;
struct wl_callback *frame_callback;
struct wl_callback *sync_callback;
struct xorg_list event_list;
struct xorg_list release_queue;
};
struct xwl_present_event {
uint64_t event_id;
uint64_t target_msc;
@ -200,8 +204,7 @@ struct xwl_present_event {
Bool pending;
Bool buffer_released;
WindowPtr present_window;
struct xwl_window *xwl_window;
struct xwl_present_window *xwl_present_window;
struct wl_buffer *buffer;
struct xorg_list list;
@ -433,7 +436,7 @@ Bool xwl_glamor_allow_commits(struct xwl_window *xwl_window);
#ifdef GLAMOR_HAS_GBM
Bool xwl_present_init(ScreenPtr screen);
void xwl_present_cleanup(struct xwl_window *xwl_window, WindowPtr window);
void xwl_present_cleanup(WindowPtr window);
#endif
void xwl_screen_release_tablet_manager(struct xwl_screen *xwl_screen);