Commit 77658741 authored by Olivier Fourdan's avatar Olivier Fourdan
Browse files

xwayland: Add buffer release callback



The API `wl_buffer_add_listener` is misleading in the sense that there
can be only one `wl_buffer` release callback, and trying to add a new
listener when once is already in place will lead to a protocol error.

The Xwayland EGL backends may need to set up their own `wl_buffer`
release listener, meaning that there is no way to our own `wl_buffer`
release callback.

To avoid the problem, add our own callback API to be notified when the
`wl_buffer` associated with an `xwl_pixmap` is released, triggered from
the different `xwl_pixmap` implementations.

Also update the Present code to use the new buffer release callback API.
Signed-off-by: default avatarOlivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer's avatarMichel Dänzer <mdaenzer@redhat.com>
parent 8d4be7f6
......@@ -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);
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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);
......
......@@ -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
......
......@@ -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);
......
Markdown is supported
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