diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c index c897c74a8..ed10355ed 100644 --- a/hw/xwayland/xwayland-glamor-eglstream.c +++ b/hw/xwayland/xwayland-glamor-eglstream.c @@ -305,9 +305,10 @@ xwl_glamor_eglstream_destroy_pixmap(PixmapPtr pixmap) { struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); - if (xwl_pixmap && pixmap->refcnt == 1) + if (xwl_pixmap && pixmap->refcnt == 1) { + xwl_pixmap_del_buffer_release_cb(pixmap); xwl_eglstream_unref_pixmap_stream(xwl_pixmap); - + } return glamor_destroy_pixmap(pixmap); } @@ -475,7 +476,10 @@ xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen, static void xwl_eglstream_buffer_release_callback(void *data, struct wl_buffer *wl_buffer) { - xwl_eglstream_unref_pixmap_stream(data); + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(data); + + xwl_pixmap_buffer_release_cb(data, wl_buffer); + xwl_eglstream_unref_pixmap_stream(xwl_pixmap); } static const struct wl_buffer_listener xwl_eglstream_buffer_release_listener = { @@ -517,7 +521,7 @@ xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen, wl_buffer_add_listener(xwl_pixmap->buffer, &xwl_eglstream_buffer_release_listener, - xwl_pixmap); + pixmap); wl_eglstream_controller_attach_eglstream_consumer( xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer); diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c index e3a4ba382..9b7d6e286 100644 --- a/hw/xwayland/xwayland-glamor-gbm.c +++ b/hw/xwayland/xwayland-glamor-gbm.c @@ -260,6 +260,7 @@ xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap) struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); if (xwl_pixmap && pixmap->refcnt == 1) { + xwl_pixmap_del_buffer_release_cb(pixmap); if (xwl_pixmap->buffer) wl_buffer_destroy(xwl_pixmap->buffer); @@ -272,6 +273,10 @@ xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap) return glamor_destroy_pixmap(pixmap); } +static const struct wl_buffer_listener xwl_glamor_gbm_buffer_listener = { + xwl_pixmap_buffer_release_cb, +}; + static struct wl_buffer * xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap, Bool *created) @@ -348,6 +353,11 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap, } close(prime_fd); + + /* Add our listener now */ + wl_buffer_add_listener(xwl_pixmap->buffer, + &xwl_glamor_gbm_buffer_listener, pixmap); + return xwl_pixmap->buffer; } diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index b7da261b7..7f0b951ab 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -169,13 +169,14 @@ xwl_present_free_event(struct xwl_present_event *event) } static void -xwl_present_buffer_release(void *data, struct wl_buffer *buffer) +xwl_present_buffer_release(PixmapPtr pixmap, void *data) { struct xwl_present_event *event = data; + if (!event) return; - wl_buffer_set_user_data(buffer, NULL); + xwl_pixmap_del_buffer_release_cb(pixmap); event->buffer_released = TRUE; if (event->abort) { @@ -193,10 +194,6 @@ xwl_present_buffer_release(void *data, struct wl_buffer *buffer) } } -static const struct wl_buffer_listener xwl_present_release_listener = { - xwl_present_buffer_release -}; - static void xwl_present_msc_bump(struct xwl_present_window *xwl_present_window) { @@ -452,7 +449,6 @@ xwl_present_flip(WindowPtr present_window, 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 damage_box; - Bool buffer_created; struct wl_buffer *buffer; struct xwl_present_event *event; @@ -465,7 +461,7 @@ xwl_present_flip(WindowPtr present_window, if (!event) return FALSE; - buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap, &buffer_created); + buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap, NULL); event->event_id = event_id; event->xwl_present_window = xwl_present_window; @@ -482,9 +478,7 @@ xwl_present_flip(WindowPtr present_window, xorg_list_add(&event->list, &xwl_present_window->release_queue); } - if (buffer_created) - wl_buffer_add_listener(buffer, &xwl_present_release_listener, NULL); - wl_buffer_set_user_data(buffer, event); + xwl_pixmap_set_buffer_release_cb(pixmap, xwl_present_buffer_release, event); /* We can flip directly to the main surface (full screen window without clips) */ wl_surface_attach(xwl_window->surface, buffer, 0, 0); diff --git a/hw/xwayland/xwayland-shm.c b/hw/xwayland/xwayland-shm.c index bce74fa1d..b76ab1a8f 100644 --- a/hw/xwayland/xwayland-shm.c +++ b/hw/xwayland/xwayland-shm.c @@ -189,6 +189,10 @@ shm_format_for_depth(int depth) } } +static const struct wl_buffer_listener xwl_shm_buffer_listener = { + xwl_pixmap_buffer_release_cb, +}; + PixmapPtr xwl_shm_create_pixmap(ScreenPtr screen, int width, int height, int depth, unsigned int hint) @@ -241,6 +245,9 @@ xwl_shm_create_pixmap(ScreenPtr screen, wl_shm_pool_destroy(pool); close(fd); + wl_buffer_add_listener(xwl_pixmap->buffer, + &xwl_shm_buffer_listener, pixmap); + xwl_pixmap_set_private(pixmap, xwl_pixmap); return pixmap; @@ -263,6 +270,7 @@ xwl_shm_destroy_pixmap(PixmapPtr pixmap) struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); if (xwl_pixmap && pixmap->refcnt == 1) { + xwl_pixmap_del_buffer_release_cb(pixmap); if (xwl_pixmap->buffer) wl_buffer_destroy(xwl_pixmap->buffer); munmap(xwl_pixmap->data, xwl_pixmap->size); diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index acb77a638..3ec754047 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -169,6 +169,7 @@ static DevPrivateKeyRec xwl_client_private_key; static DevPrivateKeyRec xwl_window_private_key; static DevPrivateKeyRec xwl_screen_private_key; static DevPrivateKeyRec xwl_pixmap_private_key; +static DevPrivateKeyRec xwl_pixmap_cb_private_key; static DevPrivateKeyRec xwl_damage_private_key; struct xwl_client * @@ -298,6 +299,64 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure, xwl_window_property_allow_commits(xwl_window, rec); } +struct xwl_pixmap_buffer_release_cb { + xwl_pixmap_cb callback; + void *data; +}; + +Bool +xwl_pixmap_set_buffer_release_cb(PixmapPtr pixmap, + xwl_pixmap_cb func, void *data) +{ + struct xwl_pixmap_buffer_release_cb *xwl_pixmap_buffer_release_cb; + + xwl_pixmap_buffer_release_cb = dixLookupPrivate(&pixmap->devPrivates, + &xwl_pixmap_cb_private_key); + + if (xwl_pixmap_buffer_release_cb == NULL) { + xwl_pixmap_buffer_release_cb = + calloc(1, sizeof (struct xwl_pixmap_buffer_release_cb)); + + if (xwl_pixmap_buffer_release_cb == NULL) { + ErrorF("Failed to allocate pixmap callback data\n"); + return FALSE; + } + dixSetPrivate(&pixmap->devPrivates, &xwl_pixmap_cb_private_key, + xwl_pixmap_buffer_release_cb); + } + + xwl_pixmap_buffer_release_cb->callback = func; + xwl_pixmap_buffer_release_cb->data = data; + + return TRUE; +} + +void +xwl_pixmap_del_buffer_release_cb(PixmapPtr pixmap) +{ + struct xwl_pixmap_buffer_release_cb *xwl_pixmap_buffer_release_cb; + + xwl_pixmap_buffer_release_cb = dixLookupPrivate(&pixmap->devPrivates, + &xwl_pixmap_cb_private_key); + if (xwl_pixmap_buffer_release_cb) { + dixSetPrivate(&pixmap->devPrivates, &xwl_pixmap_cb_private_key, NULL); + free(xwl_pixmap_buffer_release_cb); + } +} + +void +xwl_pixmap_buffer_release_cb(void *data, struct wl_buffer *wl_buffer) +{ + PixmapPtr pixmap = data; + struct xwl_pixmap_buffer_release_cb *xwl_pixmap_buffer_release_cb; + + xwl_pixmap_buffer_release_cb = dixLookupPrivate(&pixmap->devPrivates, + &xwl_pixmap_cb_private_key); + if (xwl_pixmap_buffer_release_cb) + (*xwl_pixmap_buffer_release_cb->callback) + (pixmap, xwl_pixmap_buffer_release_cb->data); +} + static Bool xwl_close_screen(ScreenPtr screen) { @@ -1348,6 +1407,8 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) return FALSE; if (!dixRegisterPrivateKey(&xwl_pixmap_private_key, PRIVATE_PIXMAP, 0)) return FALSE; + if (!dixRegisterPrivateKey(&xwl_pixmap_cb_private_key, PRIVATE_PIXMAP, 0)) + return FALSE; if (!dixRegisterPrivateKey(&xwl_damage_private_key, PRIVATE_WINDOW, 0)) return FALSE; /* There are no easy to use new / delete client hooks, we could use a diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index 9728cc512..21e833cc9 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -60,6 +60,8 @@ struct xwl_pixmap; struct xwl_window; struct xwl_screen; +typedef void (*xwl_pixmap_cb) (PixmapPtr pixmap, void *data); + struct xwl_egl_backend { /* Set by the backend if available */ Bool is_available; @@ -461,6 +463,10 @@ RRModePtr xwayland_cvt(int HDisplay, int VDisplay, void xwl_pixmap_set_private(PixmapPtr pixmap, struct xwl_pixmap *xwl_pixmap); struct xwl_pixmap *xwl_pixmap_get(PixmapPtr pixmap); +Bool xwl_pixmap_set_buffer_release_cb(PixmapPtr pixmap, + xwl_pixmap_cb func, void *data); +void xwl_pixmap_del_buffer_release_cb(PixmapPtr pixmap); +void xwl_pixmap_buffer_release_cb(void *data, struct wl_buffer *wl_buffer); struct xwl_window *xwl_window_from_window(WindowPtr window);