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: Olivier Fourdan <ofourdan@redhat.com> Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
This commit is contained in:
		
							parent
							
								
									8d4be7f6c4
								
							
						
					
					
						commit
						7765874186
					
				|  | @ -305,9 +305,10 @@ xwl_glamor_eglstream_destroy_pixmap(PixmapPtr pixmap) | ||||||
| { | { | ||||||
|     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(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); |         xwl_eglstream_unref_pixmap_stream(xwl_pixmap); | ||||||
| 
 |     } | ||||||
|     return glamor_destroy_pixmap(pixmap); |     return glamor_destroy_pixmap(pixmap); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -475,7 +476,10 @@ xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen, | ||||||
| static void | static void | ||||||
| xwl_eglstream_buffer_release_callback(void *data, struct wl_buffer *wl_buffer) | 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 = { | 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, |     wl_buffer_add_listener(xwl_pixmap->buffer, | ||||||
|                            &xwl_eglstream_buffer_release_listener, |                            &xwl_eglstream_buffer_release_listener, | ||||||
|                            xwl_pixmap); |                            pixmap); | ||||||
| 
 | 
 | ||||||
|     wl_eglstream_controller_attach_eglstream_consumer( |     wl_eglstream_controller_attach_eglstream_consumer( | ||||||
|         xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer); |         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); |     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); | ||||||
|         if (xwl_pixmap->buffer) |         if (xwl_pixmap->buffer) | ||||||
|             wl_buffer_destroy(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); |     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 * | static struct wl_buffer * | ||||||
| xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap, | xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap, | ||||||
|                                         Bool *created) |                                         Bool *created) | ||||||
|  | @ -348,6 +353,11 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     close(prime_fd); |     close(prime_fd); | ||||||
|  | 
 | ||||||
|  |     /* Add our listener now */ | ||||||
|  |     wl_buffer_add_listener(xwl_pixmap->buffer, | ||||||
|  |                            &xwl_glamor_gbm_buffer_listener, pixmap); | ||||||
|  | 
 | ||||||
|     return xwl_pixmap->buffer; |     return xwl_pixmap->buffer; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -169,13 +169,14 @@ xwl_present_free_event(struct xwl_present_event *event) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | 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; |     struct xwl_present_event *event = data; | ||||||
|  | 
 | ||||||
|     if (!event) |     if (!event) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     wl_buffer_set_user_data(buffer, NULL); |     xwl_pixmap_del_buffer_release_cb(pixmap); | ||||||
|     event->buffer_released = TRUE; |     event->buffer_released = TRUE; | ||||||
| 
 | 
 | ||||||
|     if (event->abort) { |     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 | static void | ||||||
| xwl_present_msc_bump(struct xwl_present_window *xwl_present_window) | 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_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_window   *xwl_present_window = xwl_present_window_priv(present_window); | ||||||
|     BoxPtr                      damage_box; |     BoxPtr                      damage_box; | ||||||
|     Bool                        buffer_created; |  | ||||||
|     struct wl_buffer            *buffer; |     struct wl_buffer            *buffer; | ||||||
|     struct xwl_present_event    *event; |     struct xwl_present_event    *event; | ||||||
| 
 | 
 | ||||||
|  | @ -465,7 +461,7 @@ xwl_present_flip(WindowPtr present_window, | ||||||
|     if (!event) |     if (!event) | ||||||
|         return FALSE; |         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->event_id = event_id; | ||||||
|     event->xwl_present_window = xwl_present_window; |     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); |         xorg_list_add(&event->list, &xwl_present_window->release_queue); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (buffer_created) |     xwl_pixmap_set_buffer_release_cb(pixmap, xwl_present_buffer_release, event); | ||||||
|         wl_buffer_add_listener(buffer, &xwl_present_release_listener, NULL); |  | ||||||
|     wl_buffer_set_user_data(buffer, event); |  | ||||||
| 
 | 
 | ||||||
|     /* We can flip directly to the main surface (full screen window without clips) */ |     /* We can flip directly to the main surface (full screen window without clips) */ | ||||||
|     wl_surface_attach(xwl_window->surface, buffer, 0, 0); |     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 | PixmapPtr | ||||||
| xwl_shm_create_pixmap(ScreenPtr screen, | xwl_shm_create_pixmap(ScreenPtr screen, | ||||||
|                       int width, int height, int depth, unsigned int hint) |                       int width, int height, int depth, unsigned int hint) | ||||||
|  | @ -241,6 +245,9 @@ xwl_shm_create_pixmap(ScreenPtr screen, | ||||||
|     wl_shm_pool_destroy(pool); |     wl_shm_pool_destroy(pool); | ||||||
|     close(fd); |     close(fd); | ||||||
| 
 | 
 | ||||||
|  |     wl_buffer_add_listener(xwl_pixmap->buffer, | ||||||
|  |                            &xwl_shm_buffer_listener, pixmap); | ||||||
|  | 
 | ||||||
|     xwl_pixmap_set_private(pixmap, xwl_pixmap); |     xwl_pixmap_set_private(pixmap, xwl_pixmap); | ||||||
| 
 | 
 | ||||||
|     return pixmap; |     return pixmap; | ||||||
|  | @ -263,6 +270,7 @@ xwl_shm_destroy_pixmap(PixmapPtr pixmap) | ||||||
|     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(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); | ||||||
|         if (xwl_pixmap->buffer) |         if (xwl_pixmap->buffer) | ||||||
|             wl_buffer_destroy(xwl_pixmap->buffer); |             wl_buffer_destroy(xwl_pixmap->buffer); | ||||||
|         munmap(xwl_pixmap->data, xwl_pixmap->size); |         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_window_private_key; | ||||||
| static DevPrivateKeyRec xwl_screen_private_key; | static DevPrivateKeyRec xwl_screen_private_key; | ||||||
| static DevPrivateKeyRec xwl_pixmap_private_key; | static DevPrivateKeyRec xwl_pixmap_private_key; | ||||||
|  | static DevPrivateKeyRec xwl_pixmap_cb_private_key; | ||||||
| static DevPrivateKeyRec xwl_damage_private_key; | static DevPrivateKeyRec xwl_damage_private_key; | ||||||
| 
 | 
 | ||||||
| struct xwl_client * | struct xwl_client * | ||||||
|  | @ -298,6 +299,64 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure, | ||||||
|         xwl_window_property_allow_commits(xwl_window, rec); |         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 | static Bool | ||||||
| xwl_close_screen(ScreenPtr screen) | xwl_close_screen(ScreenPtr screen) | ||||||
| { | { | ||||||
|  | @ -1348,6 +1407,8 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) | ||||||
|         return FALSE; |         return FALSE; | ||||||
|     if (!dixRegisterPrivateKey(&xwl_pixmap_private_key, PRIVATE_PIXMAP, 0)) |     if (!dixRegisterPrivateKey(&xwl_pixmap_private_key, PRIVATE_PIXMAP, 0)) | ||||||
|         return FALSE; |         return FALSE; | ||||||
|  |     if (!dixRegisterPrivateKey(&xwl_pixmap_cb_private_key, PRIVATE_PIXMAP, 0)) | ||||||
|  |         return FALSE; | ||||||
|     if (!dixRegisterPrivateKey(&xwl_damage_private_key, PRIVATE_WINDOW, 0)) |     if (!dixRegisterPrivateKey(&xwl_damage_private_key, PRIVATE_WINDOW, 0)) | ||||||
|         return FALSE; |         return FALSE; | ||||||
|     /* There are no easy to use new / delete client hooks, we could use a
 |     /* 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_window; | ||||||
| struct xwl_screen; | struct xwl_screen; | ||||||
| 
 | 
 | ||||||
|  | typedef void (*xwl_pixmap_cb) (PixmapPtr pixmap, void *data); | ||||||
|  | 
 | ||||||
| struct xwl_egl_backend { | struct xwl_egl_backend { | ||||||
|     /* Set by the backend if available */ |     /* Set by the backend if available */ | ||||||
|     Bool is_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); | void xwl_pixmap_set_private(PixmapPtr pixmap, struct xwl_pixmap *xwl_pixmap); | ||||||
| struct xwl_pixmap *xwl_pixmap_get(PixmapPtr 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); | struct xwl_window *xwl_window_from_window(WindowPtr window); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue