From 135721118a719ecacfd2bd83524a9c53c6ca6015 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 30 May 2018 14:18:07 +0100 Subject: [PATCH 01/43] render: remove wlr_renderer_check_import_dmabuf It's possible to implement it outside the renderer, by creating a texture and destroying it right away. This reduces the API surface of the renderer. --- include/wlr/render/egl.h | 7 ------- include/wlr/render/interface.h | 2 -- include/wlr/render/wlr_renderer.h | 6 ------ render/egl.c | 29 ----------------------------- render/gles2/renderer.c | 7 ------- render/gles2/texture.c | 16 ++++++++++++++++ render/wlr_renderer.c | 12 ++---------- types/wlr_linux_dmabuf.c | 16 ++++++++++++++-- 8 files changed, 32 insertions(+), 63 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 7cd5c5ca..6d79cbd2 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -67,13 +67,6 @@ EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_attributes *attributes); -/** - * Try to import the given dmabuf. On success return true false otherwise. - * If this succeeds the dmabuf can be used for rendering on a texture - */ -bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, - struct wlr_dmabuf_attributes *attributes); - /** * Get the available dmabuf formats */ diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 87b3c929..80788858 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -30,8 +30,6 @@ struct wlr_renderer_impl { struct wl_resource *resource); void (*wl_drm_buffer_get_size)(struct wlr_renderer *renderer, struct wl_resource *buffer, int *width, int *height); - bool (*check_import_dmabuf)(struct wlr_renderer *renderer, - struct wlr_dmabuf_attributes *attribs); int (*get_dmabuf_formats)(struct wlr_renderer *renderer, int **formats); int (*get_dmabuf_modifiers)(struct wlr_renderer *renderer, int format, uint64_t **modifiers); diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index dd62944f..c715e4b0 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -84,12 +84,6 @@ int wlr_renderer_get_dmabuf_formats(struct wlr_renderer *renderer, */ int wlr_renderer_get_dmabuf_modifiers(struct wlr_renderer *renderer, int format, uint64_t **modifiers); -/** - * Try to import the given dmabuf. On success return true false otherwise. - * If this succeeds the dmabuf can be used for rendering on a texture - */ -bool wlr_renderer_check_import_dmabuf(struct wlr_renderer *renderer, - struct wlr_dmabuf_attributes *attributes); /** * Reads out of pixels of the currently bound surface into data. `stride` is in * bytes. diff --git a/render/egl.c b/render/egl.c index 6ac3ee2a..676a0208 100644 --- a/render/egl.c +++ b/render/egl.c @@ -413,35 +413,6 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); } -#ifndef DRM_FORMAT_BIG_ENDIAN -#define DRM_FORMAT_BIG_ENDIAN 0x80000000 -#endif -bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, - struct wlr_dmabuf_attributes *attribs) { - switch (attribs->format & ~DRM_FORMAT_BIG_ENDIAN) { - /* TODO: YUV based formats not yet supported, require multiple - * wlr_create_image_from_dmabuf */ - case WL_SHM_FORMAT_YUYV: - case WL_SHM_FORMAT_YVYU: - case WL_SHM_FORMAT_UYVY: - case WL_SHM_FORMAT_VYUY: - case WL_SHM_FORMAT_AYUV: - return false; - default: - break; - } - - EGLImage egl_image = wlr_egl_create_image_from_dmabuf(egl, attribs); - if (egl_image) { - /* We can import the image, good. No need to keep it - since wlr_texture_upload_dmabuf will import it again */ - wlr_egl_destroy_image(egl, egl_image); - return true; - } - /* TODO: import yuv dmabufs */ - return false; -} - int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats) { if (!egl->egl_exts.dmabuf_import || diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index e68bb83f..ed12fc7c 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -242,12 +242,6 @@ static int gles2_get_dmabuf_modifiers(struct wlr_renderer *wlr_renderer, return wlr_egl_get_dmabuf_modifiers(renderer->egl, format, modifiers); } -static bool gles2_check_import_dmabuf(struct wlr_renderer *wlr_renderer, - struct wlr_dmabuf_attributes *attribs) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - return wlr_egl_check_import_dmabuf(renderer->egl, attribs); -} - static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, @@ -348,7 +342,6 @@ static const struct wlr_renderer_impl renderer_impl = { .wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size, .get_dmabuf_formats = gles2_get_dmabuf_formats, .get_dmabuf_modifiers = gles2_get_dmabuf_modifiers, - .check_import_dmabuf = gles2_check_import_dmabuf, .read_pixels = gles2_read_pixels, .format_supported = gles2_format_supported, .texture_from_pixels = gles2_texture_from_pixels, diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 2627e292..89a175c4 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -198,6 +198,10 @@ struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl, return &texture->wlr_texture; } +#ifndef DRM_FORMAT_BIG_ENDIAN +#define DRM_FORMAT_BIG_ENDIAN 0x80000000 +#endif + struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_attributes *attribs) { assert(wlr_egl_is_current(egl)); @@ -212,6 +216,18 @@ struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl, return NULL; } + switch (attribs->format & ~DRM_FORMAT_BIG_ENDIAN) { + case WL_SHM_FORMAT_YUYV: + case WL_SHM_FORMAT_YVYU: + case WL_SHM_FORMAT_UYVY: + case WL_SHM_FORMAT_VYUY: + case WL_SHM_FORMAT_AYUV: + // TODO: YUV based formats not yet supported, require multiple images + return false; + default: + break; + } + struct wlr_gles2_texture *texture = calloc(1, sizeof(struct wlr_gles2_texture)); if (texture == NULL) { diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 32b0a779..98c91132 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -135,14 +135,6 @@ int wlr_renderer_get_dmabuf_modifiers(struct wlr_renderer *r, int format, return r->impl->get_dmabuf_modifiers(r, format, modifiers); } -bool wlr_renderer_check_import_dmabuf(struct wlr_renderer *r, - struct wlr_dmabuf_attributes *attribs) { - if (!r->impl->check_import_dmabuf) { - return false; - } - return r->impl->check_import_dmabuf(r, attribs); -} - bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt, uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, @@ -187,8 +179,8 @@ void wlr_renderer_init_wl_display(struct wlr_renderer *r, } struct wlr_renderer *wlr_renderer_autocreate(struct wlr_egl *egl, - EGLenum platform, void *remote_display, EGLint *config_attribs, EGLint visual_id) { - + EGLenum platform, void *remote_display, EGLint *config_attribs, + EGLint visual_id) { if (!wlr_egl_init(egl, platform, remote_display, config_attribs, visual_id)) { wlr_log(L_ERROR, "Could not initialize EGL"); return NULL; diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c index fd4bd334..542f8cbc 100644 --- a/types/wlr_linux_dmabuf.c +++ b/types/wlr_linux_dmabuf.c @@ -121,6 +121,19 @@ static void buffer_handle_resource_destroy(struct wl_resource *buffer_resource) linux_dmabuf_buffer_destroy(buffer); } +static bool check_import_dmabuf(struct wlr_dmabuf_buffer *buffer) { + struct wlr_texture *texture = + wlr_texture_from_dmabuf(buffer->renderer, &buffer->attributes); + if (texture == NULL) { + return false; + } + + // We can import the image, good. No need to keep it since wlr_surface will + // import it again on commit. + wlr_texture_destroy(texture); + return true; +} + static void params_create_common(struct wl_client *client, struct wl_resource *params_resource, uint32_t buffer_id, int32_t width, int32_t height, uint32_t format, uint32_t flags) { @@ -229,8 +242,7 @@ static void params_create_common(struct wl_client *client, } /* Check if dmabuf is usable */ - if (!wlr_renderer_check_import_dmabuf(buffer->renderer, - &buffer->attributes)) { + if (!check_import_dmabuf(buffer)) { goto err_failed; } From f90b024ad0ee2d746404e3240393fd4f13a884d1 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 30 May 2018 17:18:51 +0100 Subject: [PATCH 02/43] linux-dmabuf: fix bound checks for stride and height - Fix bound checking for offset + stride * height - Make offset bound checking more consistent - Reject zero strides --- types/wlr_linux_dmabuf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c index 542f8cbc..6e716986 100644 --- a/types/wlr_linux_dmabuf.c +++ b/types/wlr_linux_dmabuf.c @@ -207,7 +207,7 @@ static void params_create_common(struct wl_client *client, // Skip checks if kernel does no support seek on buffer continue; } - if (buffer->attributes.offset[i] >= size) { + if (buffer->attributes.offset[i] > size) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, "invalid offset %i for plane %d", @@ -215,7 +215,8 @@ static void params_create_common(struct wl_client *client, goto err_out; } - if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) { + if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size || + buffer->attributes.stride[i] == 0) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, "invalid stride %i for plane %d", @@ -225,7 +226,7 @@ static void params_create_common(struct wl_client *client, // planes > 0 might be subsampled according to fourcc format if (i == 0 && buffer->attributes.offset[i] + - buffer->attributes.stride[i] * height >= size) { + buffer->attributes.stride[i] * height > size) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, "invalid buffer stride or height for plane %d", i); From 3994762ae05d18f2ec0fe9509e4dd41224cde56e Mon Sep 17 00:00:00 2001 From: Markus Ongyerth Date: Fri, 1 Jun 2018 13:27:10 +0200 Subject: [PATCH 03/43] Add wlr_surface_get_geometry This function defaults and clips the xdg-surface geometry to the bounding box of the surface + its subsurfaces, as specified by the protocol spec. --- include/wlr/types/wlr_surface.h | 8 +++++ include/wlr/types/wlr_xdg_shell.h | 9 +++++ include/wlr/types/wlr_xdg_shell_v6.h | 9 +++++ rootston/xdg_shell.c | 12 +++---- rootston/xdg_shell_v6.c | 12 +++---- types/wlr_surface.c | 48 +++++++++++++++++++++++++ types/xdg_shell/wlr_xdg_surface.c | 23 ++++++++++-- types/xdg_shell_v6/wlr_xdg_surface_v6.c | 22 ++++++++++-- 8 files changed, 123 insertions(+), 20 deletions(-) diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index d1127c86..0fa7e9c2 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -159,6 +159,14 @@ void wlr_surface_send_leave(struct wlr_surface *surface, void wlr_surface_send_frame_done(struct wlr_surface *surface, const struct timespec *when); +struct wlr_box; +/** + * Get the bounding box that contains the surface and all subsurfaces in + * surface coordinates. + * X and y may be negative, if there are subsurfaces with negative position. + */ +void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box); + /** * Set a callback for surface commit that runs before all the other callbacks. * This is intended for use by the surface role. diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 5eb30a16..6a967bc7 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -341,6 +341,15 @@ bool wlr_surface_is_xdg_surface(struct wlr_surface *surface); struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface( struct wlr_surface *surface); +/** + * Get the surface geometry. + * This is either the geometry as set by the client, or defaulted to the bounds + * of the surface + the subsurfaces (as specified by the protocol). + * + * The x and y value can be <0 + */ +void wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *surface, struct wlr_box *box); + /** * Call `iterator` on each surface in the xdg-surface tree, with the surface's * position relative to the root xdg-surface. The function is called from root to diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 2fdf49e5..07c831ce 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -318,6 +318,15 @@ bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface); struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface( struct wlr_surface *surface); +/** + * Get the surface geometry. + * This is either the geometry as set by the client, or defaulted to the bounds + * of the surface + the subsurfaces (as specified by the protocol). + * + * The x and y value can be <0 + */ +void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box); + /** * Call `iterator` on each surface in the xdg-surface tree, with the surface's * position relative to the root xdg-surface. The function is called from root to diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c index 03ae1dc6..805fb874 100644 --- a/rootston/xdg_shell.c +++ b/rootston/xdg_shell.c @@ -132,14 +132,10 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) { assert(view->type == ROOTS_XDG_SHELL_VIEW); struct wlr_xdg_surface *surface = view->xdg_surface; - if (surface->geometry.width > 0 && surface->geometry.height > 0) { - box->width = surface->geometry.width; - box->height = surface->geometry.height; - } else { - assert(surface->surface); - box->width = surface->surface->current->width; - box->height = surface->surface->current->height; - } + struct wlr_box geo_box; + wlr_xdg_surface_get_geometry(surface, &geo_box); + box->width = geo_box.width; + box->height = geo_box.height; } static void activate(struct roots_view *view, bool active) { diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 90b11690..02ad867d 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -133,14 +133,10 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) { assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; - if (surface->geometry.width > 0 && surface->geometry.height > 0) { - box->width = surface->geometry.width; - box->height = surface->geometry.height; - } else { - assert(surface->surface); - box->width = surface->surface->current->width; - box->height = surface->surface->current->height; - } + struct wlr_box geo_box; + wlr_xdg_surface_v6_get_geometry(surface, &geo_box); + box->width = geo_box.width; + box->height = geo_box.height; } static void activate(struct roots_view *view, bool active) { diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 61284416..6df66f2c 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -16,6 +16,22 @@ #define SURFACE_VERSION 4 #define SUBSURFACE_VERSION 1 +static int min(int fst, int snd) { + if (fst < snd) { + return fst; + } else { + return snd; + } +} + +static int max(int fst, int snd) { + if (fst > snd) { + return fst; + } else { + return snd; + } +} + static void surface_state_reset_buffer(struct wlr_surface_state *state) { if (state->buffer) { wl_list_remove(&state->buffer_destroy_listener.link); @@ -1036,3 +1052,35 @@ void wlr_surface_for_each_surface(struct wlr_surface *surface, wlr_surface_iterator_func_t iterator, void *user_data) { surface_for_each_surface(surface, 0, 0, iterator, user_data); } + +struct bound_acc { + int32_t min_x, min_y; + int32_t max_x, max_y; +}; + +static void handle_bounding_box_surface(struct wlr_surface *surface, + int x, int y, void *data) { + struct bound_acc *acc = data; + + acc->min_x = min(x, acc->min_x); + acc->min_y = min(x, acc->min_y); + + acc->max_x = max(x + surface->current->width, acc->max_x); + acc->max_y = max(y + surface->current->height, acc->max_y); +} + +void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box) { + struct bound_acc acc = { + .min_x = 0, + .min_y = 0, + .max_x = surface->current->width, + .max_y = surface->current->height, + }; + + wlr_surface_for_each_surface(surface, handle_bounding_box_surface, &acc); + + box->x = acc.min_x; + box->y = acc.min_y; + box->width = acc.max_x - acc.min_x; + box->height = acc.max_y - acc.min_y; +} diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index 6f0e7264..c5d177b2 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -251,6 +251,13 @@ static void xdg_surface_handle_set_window_geometry(struct wl_client *client, return; } + if (width <= 0 || height <= 0) { + wlr_log(L_ERROR, "Client tried to set invalid geometry"); + //XXX: Switch to the proper error value once available + wl_resource_post_error(resource, -1, "Tried to set invalid xdg-surface geometry"); + return; + } + surface->has_next_geometry = true; surface->next_geometry.height = height; surface->next_geometry.width = width; @@ -474,9 +481,11 @@ static void xdg_popup_get_position(struct wlr_xdg_popup *popup, double *popup_sx, double *popup_sy) { struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(popup->parent); - *popup_sx = parent->geometry.x + popup->geometry.x - + struct wlr_box parent_geo; + wlr_xdg_surface_get_geometry(parent, &parent_geo); + *popup_sx = parent_geo.x + popup->geometry.x - popup->base->geometry.x; - *popup_sy = parent->geometry.y + popup->geometry.y - + *popup_sy = parent_geo.y + popup->geometry.y - popup->base->geometry.y; } @@ -546,3 +555,13 @@ void wlr_xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, wlr_surface_iterator_func_t iterator, void *user_data) { xdg_surface_for_each_surface(surface, 0, 0, iterator, user_data); } + +void wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *surface, struct wlr_box *box) { + wlr_surface_get_extends(surface->surface, box); + /* The client never set the geometry */ + if (!surface->geometry.width) { + return; + } + + wlr_box_intersection(&surface->geometry, box, box); +} diff --git a/types/xdg_shell_v6/wlr_xdg_surface_v6.c b/types/xdg_shell_v6/wlr_xdg_surface_v6.c index a1214a0a..e111adad 100644 --- a/types/xdg_shell_v6/wlr_xdg_surface_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_surface_v6.c @@ -198,6 +198,12 @@ static void xdg_surface_handle_set_window_geometry(struct wl_client *client, return; } + if (width <= 0 || height <= 0) { + wlr_log(L_ERROR, "Client tried to set invalid geometry"); + wl_resource_post_error(resource, -1, "Tried to set invalid xdg-surface geometry"); + } + + surface->has_next_geometry = true; surface->next_geometry.height = height; surface->next_geometry.width = width; @@ -454,9 +460,11 @@ struct wlr_xdg_surface_v6 *create_xdg_surface_v6( static void xdg_popup_v6_get_position(struct wlr_xdg_popup_v6 *popup, double *popup_sx, double *popup_sy) { struct wlr_xdg_surface_v6 *parent = popup->parent; - *popup_sx = parent->geometry.x + popup->geometry.x - + struct wlr_box parent_geo; + wlr_xdg_surface_v6_get_geometry(parent, &parent_geo); + *popup_sx = parent_geo.x + popup->geometry.x - popup->base->geometry.x; - *popup_sy = parent->geometry.y + popup->geometry.y - + *popup_sy = parent_geo.y + popup->geometry.y - popup->base->geometry.y; } @@ -526,3 +534,13 @@ void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, wlr_surface_iterator_func_t iterator, void *user_data) { xdg_surface_v6_for_each_surface(surface, 0, 0, iterator, user_data); } + +void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box) { + wlr_surface_get_extends(surface->surface, box); + /* The client never set the geometry */ + if (!surface->geometry.width) { + return; + } + + wlr_box_intersection(&surface->geometry, box, box); +} From 7b07b3f95dcfecf702db3b4fbec611640952f9c1 Mon Sep 17 00:00:00 2001 From: Markus Ongyerth Date: Fri, 1 Jun 2018 16:36:04 +0200 Subject: [PATCH 04/43] Fix type in wlr_surface_get_extends --- types/wlr_surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 6df66f2c..22026af8 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -1063,7 +1063,7 @@ static void handle_bounding_box_surface(struct wlr_surface *surface, struct bound_acc *acc = data; acc->min_x = min(x, acc->min_x); - acc->min_y = min(x, acc->min_y); + acc->min_y = min(y, acc->min_y); acc->max_x = max(x + surface->current->width, acc->max_x); acc->max_y = max(y + surface->current->height, acc->max_y); From 2eb8b240e1f2b266720055c2b7d6b2619aa66e3a Mon Sep 17 00:00:00 2001 From: Timidger Date: Sat, 2 Jun 2018 15:54:15 -0700 Subject: [PATCH 05/43] Added data field to wlr_subsurface --- include/wlr/types/wlr_surface.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 0fa7e9c2..526e4e2c 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -62,6 +62,8 @@ struct wlr_subsurface { struct { struct wl_signal destroy; } events; + + void *data; }; struct wlr_surface { From 551700e88722cf2ec77500b913c8164495d179c6 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 3 Jun 2018 13:18:57 +0100 Subject: [PATCH 06/43] backend/wayland: fix keyboard keys not pressed/released when focus changes --- backend/wayland/wl_seat.c | 40 ++++++++++++++++++++++++++++++++ include/wlr/types/wlr_keyboard.h | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/backend/wayland/wl_seat.c b/backend/wayland/wl_seat.c index cf9b9372..8ed61409 100644 --- a/backend/wayland/wl_seat.c +++ b/backend/wayland/wl_seat.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -169,12 +170,51 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, // TODO: set keymap } +static uint32_t get_current_time_msec() { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return now.tv_nsec / 1000; +} + static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { + struct wlr_input_device *dev = data; + + uint32_t time = get_current_time_msec(); + + uint32_t *keycode_ptr; + wl_array_for_each(keycode_ptr, keys) { + struct wlr_event_keyboard_key event = { + .keycode = *keycode_ptr, + .state = WLR_KEY_PRESSED, + .time_msec = time, + .update_state = false, + }; + wlr_keyboard_notify_key(dev->keyboard, &event); + } } static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface) { + struct wlr_input_device *dev = data; + + uint32_t time = get_current_time_msec(); + + uint32_t pressed[dev->keyboard->num_keycodes]; + memcpy(pressed, dev->keyboard->keycodes, + dev->keyboard->num_keycodes * sizeof(uint32_t)); + + for (size_t i = 0; i < sizeof(pressed)/sizeof(pressed[0]); ++i) { + uint32_t keycode = pressed[i]; + + struct wlr_event_keyboard_key event = { + .keycode = keycode, + .state = WLR_KEY_RELEASED, + .time_msec = time, + .update_state = false, + }; + wlr_keyboard_notify_key(dev->keyboard, &event); + } } static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, diff --git a/include/wlr/types/wlr_keyboard.h b/include/wlr/types/wlr_keyboard.h index 97288508..67d4e5be 100644 --- a/include/wlr/types/wlr_keyboard.h +++ b/include/wlr/types/wlr_keyboard.h @@ -89,7 +89,7 @@ enum wlr_key_state { struct wlr_event_keyboard_key { uint32_t time_msec; uint32_t keycode; - bool update_state; + bool update_state; // if backend doesn't update modifiers on its own enum wlr_key_state state; }; From 736309c228345bf2c58a13ed5a9d88db0655b00f Mon Sep 17 00:00:00 2001 From: Silvan Jegen Date: Sun, 3 Jun 2018 19:48:15 +0200 Subject: [PATCH 07/43] Remove redundant roots_seat_remove_device function This function is unimplemented and is redundant because all devices added with roots_seat_add_device get destruction handlers assigned already. This fixes issue #998. --- include/rootston/seat.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/rootston/seat.h b/include/rootston/seat.h index d2ef90f3..7b09f339 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -94,9 +94,6 @@ void roots_seat_destroy(struct roots_seat *seat); void roots_seat_add_device(struct roots_seat *seat, struct wlr_input_device *device); -void roots_seat_remove_device(struct roots_seat *seat, - struct wlr_input_device *device); - void roots_seat_configure_cursor(struct roots_seat *seat); void roots_seat_configure_xcursor(struct roots_seat *seat); From 58d549c98a231049a40c98f97696fc8df66ce0e8 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 3 Jun 2018 20:11:59 -0400 Subject: [PATCH 08/43] add data to wlr_drag_icon --- include/wlr/types/wlr_data_device.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 80d4bc8b..5581373d 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -94,6 +94,8 @@ struct wlr_drag_icon { struct wl_listener surface_destroy; struct wl_listener seat_client_destroy; + + void *data; }; struct wlr_drag { From 516c864d46e105fcf9b3de8109bd2fdc7bba6a1a Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 4 Jun 2018 21:56:19 +1000 Subject: [PATCH 09/43] Fix mistakes in xdg_popup and xdg_popup_v6 --- types/xdg_shell/wlr_xdg_popup.c | 6 +++--- types/xdg_shell_v6/wlr_xdg_popup_v6.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index 9c8b6eb2..e7204def 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -416,7 +416,7 @@ static bool xdg_popup_unconstrain_slide(struct wlr_xdg_popup *popup, (popup->positioner.constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X); - bool slide_y = offset_x && + bool slide_y = offset_y && (popup->positioner.constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); @@ -459,7 +459,7 @@ static bool xdg_popup_unconstrain_resize(struct wlr_xdg_popup *popup, (popup->positioner.constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X); - bool resize_y = offset_x && + bool resize_y = offset_y && (popup->positioner.constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y); @@ -471,7 +471,7 @@ static bool xdg_popup_unconstrain_resize(struct wlr_xdg_popup *popup, } xdg_popup_box_constraints(popup, toplevel_sx_box, - &offset_y, &offset_y); + &offset_x, &offset_y); return !offset_x && !offset_y; } diff --git a/types/xdg_shell_v6/wlr_xdg_popup_v6.c b/types/xdg_shell_v6/wlr_xdg_popup_v6.c index a75201d0..ff66e812 100644 --- a/types/xdg_shell_v6/wlr_xdg_popup_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_popup_v6.c @@ -443,7 +443,7 @@ static bool xdg_popup_v6_unconstrain_slide(struct wlr_xdg_popup_v6 *popup, (popup->positioner.constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X); - bool slide_y = offset_x && + bool slide_y = offset_y && (popup->positioner.constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y); @@ -486,7 +486,7 @@ static bool xdg_popup_v6_unconstrain_resize(struct wlr_xdg_popup_v6 *popup, (popup->positioner.constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X); - bool resize_y = offset_x && + bool resize_y = offset_y && (popup->positioner.constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y); @@ -498,7 +498,7 @@ static bool xdg_popup_v6_unconstrain_resize(struct wlr_xdg_popup_v6 *popup, } xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_y, &offset_y); + &offset_x, &offset_y); return !offset_x && !offset_y; } From eb8b8acca6ea8a440da548c3bee82ac01eb8c99e Mon Sep 17 00:00:00 2001 From: Bob Ham Date: Mon, 4 Jun 2018 13:20:09 +0000 Subject: [PATCH 10/43] wlr_linux_dmabuf: Fix printf conversion specifiers on armhf The printf conversion specifiers in a call to wl_resource_post_error do not specify the type correctly on armhf: ../types/wlr_linux_dmabuf.c: In function 'params_add': ../types/wlr_linux_dmabuf.c:104:21: error: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'uint64_t {aka long long unsigned int}' [-Werror=format=] "sent modifier %lu for plane %u, expected modifier %lu like other planes", ~~^ %llu To fix this, we use standard printf conversion specifier macros from inttypes.h. --- types/wlr_linux_dmabuf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c index 6e716986..3b4fc78b 100644 --- a/types/wlr_linux_dmabuf.c +++ b/types/wlr_linux_dmabuf.c @@ -101,7 +101,8 @@ static void params_add(struct wl_client *client, if (buffer->has_modifier && modifier != buffer->attributes.modifier) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, - "sent modifier %lu for plane %u, expected modifier %lu like other planes", + "sent modifier %" PRIu64 " for plane %u, expected" + " modifier %" PRIu64 " like other planes", modifier, plane_idx, buffer->attributes.modifier); close(fd); return; From 51b9883ea0201195ed7c151175725c926c94bd47 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Mon, 4 Jun 2018 08:31:27 +0900 Subject: [PATCH 11/43] seat: allow clients to bind to seat multiple times This lets clients bind to a seat multiple times by re-using the existing wlr_seat_client whenever a duplicate request happens. Previously, an independant wlr_seat_client would be created and only events from one would be processed. Fixes #1023. --- include/wlr/types/wlr_seat.h | 2 +- types/data_device/wlr_drag.c | 2 +- types/seat/wlr_seat.c | 78 +++++++++++++++++++++++------------- 3 files changed, 53 insertions(+), 29 deletions(-) diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index f4840c89..5e04003d 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -13,11 +13,11 @@ * managed by wlr_seat; some may be NULL. */ struct wlr_seat_client { - struct wl_resource *wl_resource; struct wl_client *client; struct wlr_seat *seat; // lists of wl_resource + struct wl_list wl_resources; struct wl_list pointers; struct wl_list keyboards; struct wl_list touches; diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index 331fba2f..1429d4dd 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -44,7 +44,7 @@ static void drag_set_focus(struct wlr_drag *drag, if (!drag->source && wl_resource_get_client(surface->resource) != - wl_resource_get_client(drag->seat_client->wl_resource)) { + drag->seat_client->client) { return; } diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index 4a680157..ead4b0e7 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -60,6 +60,12 @@ static void seat_client_handle_resource_destroy( struct wl_resource *seat_resource) { struct wlr_seat_client *client = wlr_seat_client_from_resource(seat_resource); + + wl_list_remove(wl_resource_get_link(seat_resource)); + if (!wl_list_empty(&client->wl_resources)) { + return; + } + wlr_signal_emit_safe(&client->events.destroy, client); if (client == client->seat->pointer_state.focused_client) { @@ -108,34 +114,43 @@ static void seat_handle_bind(struct wl_client *client, void *_wlr_seat, struct wlr_seat *wlr_seat = _wlr_seat; assert(client && wlr_seat); - struct wlr_seat_client *seat_client = - calloc(1, sizeof(struct wlr_seat_client)); - if (seat_client == NULL) { - wl_client_post_no_memory(client); - return; - } - seat_client->wl_resource = + struct wl_resource *wl_resource = wl_resource_create(client, &wl_seat_interface, version, id); - if (seat_client->wl_resource == NULL) { - free(seat_client); + if (wl_resource == NULL) { wl_client_post_no_memory(client); return; } - seat_client->client = client; - seat_client->seat = wlr_seat; - wl_list_init(&seat_client->pointers); - wl_list_init(&seat_client->keyboards); - wl_list_init(&seat_client->touches); - wl_list_init(&seat_client->data_devices); - wl_list_init(&seat_client->primary_selection_devices); - wl_resource_set_implementation(seat_client->wl_resource, &seat_impl, - seat_client, seat_client_handle_resource_destroy); - wl_list_insert(&wlr_seat->clients, &seat_client->link); - if (version >= WL_SEAT_NAME_SINCE_VERSION) { - wl_seat_send_name(seat_client->wl_resource, wlr_seat->name); + + struct wlr_seat_client *seat_client = + wlr_seat_client_for_wl_client(wlr_seat, client); + if (seat_client == NULL) { + seat_client = calloc(1, sizeof(struct wlr_seat_client)); + if (seat_client == NULL) { + wl_resource_destroy(wl_resource); + wl_client_post_no_memory(client); + return; + } + + seat_client->client = client; + seat_client->seat = wlr_seat; + wl_list_init(&seat_client->wl_resources); + wl_list_init(&seat_client->pointers); + wl_list_init(&seat_client->keyboards); + wl_list_init(&seat_client->touches); + wl_list_init(&seat_client->data_devices); + wl_list_init(&seat_client->primary_selection_devices); + wl_signal_init(&seat_client->events.destroy); + + wl_list_insert(&wlr_seat->clients, &seat_client->link); } - wl_seat_send_capabilities(seat_client->wl_resource, wlr_seat->capabilities); - wl_signal_init(&seat_client->events.destroy); + + wl_resource_set_implementation(wl_resource, &seat_impl, + seat_client, seat_client_handle_resource_destroy); + wl_list_insert(&seat_client->wl_resources, wl_resource_get_link(wl_resource)); + if (version >= WL_SEAT_NAME_SINCE_VERSION) { + wl_seat_send_name(wl_resource, wlr_seat->name); + } + wl_seat_send_capabilities(wl_resource, wlr_seat->capabilities); } void wlr_seat_destroy(struct wlr_seat *seat) { @@ -160,8 +175,11 @@ void wlr_seat_destroy(struct wlr_seat *seat) { struct wlr_seat_client *client, *tmp; wl_list_for_each_safe(client, tmp, &seat->clients, link) { - // will destroy other resources as well - wl_resource_destroy(client->wl_resource); + struct wl_resource *resource, *next_resource; + wl_resource_for_each_safe(resource, next_resource, &client->wl_resources) { + // will destroy other resources as well + wl_resource_destroy(resource); + } } wl_global_destroy(seat->wl_global); @@ -308,7 +326,10 @@ void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat, } } - wl_seat_send_capabilities(client->wl_resource, capabilities); + struct wl_resource *resource; + wl_resource_for_each(resource, &client->wl_resources) { + wl_seat_send_capabilities(resource, capabilities); + } } } @@ -317,7 +338,10 @@ void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name) { wlr_seat->name = strdup(name); struct wlr_seat_client *client; wl_list_for_each(client, &wlr_seat->clients, link) { - wl_seat_send_name(client->wl_resource, name); + struct wl_resource *resource; + wl_resource_for_each(resource, &client->wl_resources) { + wl_seat_send_name(resource, name); + } } } From cf9b8c0a8ccc4a91473551ea37345ceffe4fd1a3 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Tue, 5 Jun 2018 00:17:01 +0900 Subject: [PATCH 12/43] wlr_surface_get_root_surface: walk up parent This would dead-loop and never walk up if called on a subsurface --- types/wlr_surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 22026af8..46a39a39 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -956,7 +956,7 @@ struct wlr_surface *wlr_surface_get_root_surface(struct wlr_surface *surface) { while (wlr_surface_is_subsurface(surface)) { struct wlr_subsurface *subsurface = wlr_subsurface_from_surface(surface); - surface = subsurface->surface; + surface = subsurface->parent; } return surface; } From bcb660cb1d3a8795042ef1ae63f0d8a7daec1cc3 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 4 Jun 2018 17:16:17 -0400 Subject: [PATCH 13/43] add missing anchor case in positioner invert-x --- types/xdg_shell/wlr_xdg_positioner.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/types/xdg_shell/wlr_xdg_positioner.c b/types/xdg_shell/wlr_xdg_positioner.c index 0213c572..6f902f92 100644 --- a/types/xdg_shell/wlr_xdg_positioner.c +++ b/types/xdg_shell/wlr_xdg_positioner.c @@ -256,6 +256,8 @@ static enum xdg_positioner_anchor positioner_anchor_invert_x( return XDG_POSITIONER_ANCHOR_LEFT; case XDG_POSITIONER_ANCHOR_TOP_LEFT: return XDG_POSITIONER_ANCHOR_TOP_RIGHT; + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + return XDG_POSITIONER_ANCHOR_TOP_LEFT; case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: return XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT; case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: From 7206997e958f8fe155abdfedfb91b95a4f729d1a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 4 Jun 2018 18:56:57 -0400 Subject: [PATCH 14/43] fix wlr_box_intersection and closest_point --- types/wlr_box.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/types/wlr_box.c b/types/wlr_box.c index c92b0aa4..f8fe9dfe 100644 --- a/types/wlr_box.c +++ b/types/wlr_box.c @@ -11,8 +11,8 @@ void wlr_box_closest_point(const struct wlr_box *box, double x, double y, // find the closest x point if (x < box->x) { *dest_x = box->x; - } else if (x > box->x + box->width) { - *dest_x = box->x + box->width; + } else if (x >= box->x + box->width) { + *dest_x = box->x + box->width - 1; } else { *dest_x = x; } @@ -20,8 +20,8 @@ void wlr_box_closest_point(const struct wlr_box *box, double x, double y, // find closest y point if (y < box->y) { *dest_y = box->y; - } else if (y > box->y + box->height) { - *dest_y = box->y + box->height; + } else if (y >= box->y + box->height) { + *dest_y = box->y + box->height - 1; } else { *dest_y = y; } @@ -46,8 +46,8 @@ bool wlr_box_intersection(const struct wlr_box *box_a, int x1 = fmax(box_a->x, box_b->x); int y1 = fmax(box_a->y, box_b->y); - int x2 = fmin(box_a->x + box_a->width, box_b->x + box_b->width); - int y2 = fmin(box_a->y + box_a->height, box_b->y + box_b->height); + int x2 = fmin(box_a->x + box_a->width - 1, box_b->x + box_b->width - 1); + int y2 = fmin(box_a->y + box_a->height - 1, box_b->y + box_b->height - 1); dest->x = x1; dest->y = y1; From c6821f3dd39160289213e8e1cd1477f90d411265 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Tue, 5 Jun 2018 00:17:35 +0900 Subject: [PATCH 15/43] wlr_surface: insert subsurfaces in revert order sibling surfaces were drawn in incorrect order (e.g. latest below). This attempts to fix that by reverting the order of the list. --- types/wlr_surface.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 46a39a39..9c3eb86d 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -805,7 +805,7 @@ static void subsurface_handle_place_above(struct wl_client *client, } wl_list_remove(&subsurface->parent_pending_link); - wl_list_insert(sibling->parent_pending_link.prev, + wl_list_insert(&sibling->parent_pending_link, &subsurface->parent_pending_link); subsurface->reordered = true; @@ -832,7 +832,7 @@ static void subsurface_handle_place_below(struct wl_client *client, } wl_list_remove(&subsurface->parent_pending_link); - wl_list_insert(&sibling->parent_pending_link, + wl_list_insert(sibling->parent_pending_link.prev, &subsurface->parent_pending_link); subsurface->reordered = true; @@ -933,8 +933,8 @@ struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface, subsurface->parent = parent; wl_signal_add(&parent->events.destroy, &subsurface->parent_destroy); subsurface->parent_destroy.notify = subsurface_handle_parent_destroy; - wl_list_insert(&parent->subsurfaces, &subsurface->parent_link); - wl_list_insert(&parent->subsurface_pending_list, + wl_list_insert(parent->subsurfaces.prev, &subsurface->parent_link); + wl_list_insert(parent->subsurface_pending_list.prev, &subsurface->parent_pending_link); surface->role_data = subsurface; @@ -971,7 +971,7 @@ bool wlr_surface_point_accepts_input(struct wlr_surface *surface, struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface, double sx, double sy, double *sub_x, double *sub_y) { struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { + wl_list_for_each_reverse(subsurface, &surface->subsurfaces, parent_link) { double _sub_x = subsurface->surface->current->subsurface_position.x; double _sub_y = subsurface->surface->current->subsurface_position.y; struct wlr_surface *sub = wlr_surface_surface_at(subsurface->surface, From 1c75d4e54a877bb1918afb5bf23c2c142ca30b78 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 5 Jun 2018 18:17:42 -0400 Subject: [PATCH 16/43] rename drag-icon map to unmap --- include/rootston/seat.h | 2 +- include/wlr/types/wlr_data_device.h | 2 +- rootston/seat.c | 10 +++++----- types/data_device/wlr_drag.c | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/rootston/seat.h b/include/rootston/seat.h index 7b09f339..bed81c88 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -58,7 +58,7 @@ struct roots_drag_icon { double x, y; struct wl_listener surface_commit; - struct wl_listener map; + struct wl_listener unmap; struct wl_listener destroy; }; diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 5581373d..33fbf525 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -88,7 +88,7 @@ struct wlr_drag_icon { int32_t sx, sy; struct { - struct wl_signal map; // emitted when mapped or unmapped + struct wl_signal unmap; struct wl_signal destroy; } events; diff --git a/rootston/seat.c b/rootston/seat.c index b137ff11..81cedc5a 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -263,10 +263,10 @@ static void roots_drag_icon_handle_surface_commit(struct wl_listener *listener, roots_drag_icon_damage_whole(icon); } -static void roots_drag_icon_handle_map(struct wl_listener *listener, +static void roots_drag_icon_handle_unmap(struct wl_listener *listener, void *data) { struct roots_drag_icon *icon = - wl_container_of(listener, icon, map); + wl_container_of(listener, icon, unmap); roots_drag_icon_damage_whole(icon); } @@ -278,7 +278,7 @@ static void roots_drag_icon_handle_destroy(struct wl_listener *listener, wl_list_remove(&icon->link); wl_list_remove(&icon->surface_commit.link); - wl_list_remove(&icon->map.link); + wl_list_remove(&icon->unmap.link); wl_list_remove(&icon->destroy.link); free(icon); } @@ -297,8 +297,8 @@ static void roots_seat_handle_new_drag_icon(struct wl_listener *listener, icon->surface_commit.notify = roots_drag_icon_handle_surface_commit; wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit); - icon->map.notify = roots_drag_icon_handle_map; - wl_signal_add(&wlr_drag_icon->events.map, &icon->map); + icon->unmap.notify = roots_drag_icon_handle_unmap; + wl_signal_add(&wlr_drag_icon->events.unmap, &icon->unmap); icon->destroy.notify = roots_drag_icon_handle_destroy; wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index 1429d4dd..b4857956 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -117,7 +117,7 @@ static void drag_end(struct wlr_drag *drag) { if (drag->icon) { drag->icon->mapped = false; wl_list_remove(&drag->icon_destroy.link); - wlr_signal_emit_safe(&drag->icon->events.map, drag->icon); + wlr_signal_emit_safe(&drag->icon->events.unmap, drag->icon); } wlr_signal_emit_safe(&drag->events.destroy, drag); @@ -357,7 +357,7 @@ static struct wlr_drag_icon *drag_icon_create( icon->touch_id = touch_id; icon->mapped = true; - wl_signal_init(&icon->events.map); + wl_signal_init(&icon->events.unmap); wl_signal_init(&icon->events.destroy); wl_signal_add(&icon->surface->events.destroy, &icon->surface_destroy); From 319ebdf47628b2761fcb7cf86bf4024b882becec Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 5 Jun 2018 22:50:29 -0400 Subject: [PATCH 17/43] add back map event --- include/wlr/types/wlr_data_device.h | 1 + types/data_device/wlr_drag.c | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 33fbf525..4de4d610 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -88,6 +88,7 @@ struct wlr_drag_icon { int32_t sx, sy; struct { + struct wl_signal map; struct wl_signal unmap; struct wl_signal destroy; } events; diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index b4857956..4b42307e 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -98,6 +98,16 @@ static void drag_set_focus(struct wlr_drag *drag, wlr_signal_emit_safe(&drag->events.focus, drag); } +static void drag_icon_set_mapped(struct wlr_drag_icon *icon, bool mapped) { + if (mapped && !icon->mapped) { + wlr_signal_emit_safe(&icon->events.map, icon); + } else if (!mapped && icon->mapped) { + wlr_signal_emit_safe(&icon->events.unmap, icon); + } + + icon->mapped = mapped; +} + static void drag_end(struct wlr_drag *drag) { if (!drag->cancelling) { drag->cancelling = true; @@ -115,9 +125,8 @@ static void drag_end(struct wlr_drag *drag) { drag_set_focus(drag, NULL, 0, 0); if (drag->icon) { - drag->icon->mapped = false; wl_list_remove(&drag->icon_destroy.link); - wlr_signal_emit_safe(&drag->icon->events.unmap, drag->icon); + drag_icon_set_mapped(drag->icon, false); } wlr_signal_emit_safe(&drag->events.destroy, drag); @@ -310,9 +319,10 @@ static void drag_handle_drag_source_destroy(struct wl_listener *listener, static void drag_icon_destroy(struct wlr_drag_icon *icon) { - if (!icon) { + if (icon == NULL) { return; } + drag_icon_set_mapped(icon, false); wlr_signal_emit_safe(&icon->events.destroy, icon); wlr_surface_set_role_committed(icon->surface, NULL, NULL); wl_list_remove(&icon->surface_destroy.link); @@ -333,6 +343,8 @@ static void drag_icon_handle_surface_commit(struct wlr_surface *surface, struct wlr_drag_icon *icon = role_data; icon->sx += icon->surface->current->sx; icon->sy += icon->surface->current->sy; + + drag_icon_set_mapped(icon, wlr_surface_has_buffer(surface)); } static void drag_icon_handle_seat_client_destroy(struct wl_listener *listener, @@ -355,8 +367,8 @@ static struct wlr_drag_icon *drag_icon_create( icon->client = client; icon->is_pointer = is_pointer; icon->touch_id = touch_id; - icon->mapped = true; + wl_signal_init(&icon->events.map); wl_signal_init(&icon->events.unmap); wl_signal_init(&icon->events.destroy); @@ -372,6 +384,10 @@ static struct wlr_drag_icon *drag_icon_create( wl_list_insert(&client->seat->drag_icons, &icon->link); wlr_signal_emit_safe(&client->seat->events.new_drag_icon, icon); + if (wlr_surface_has_buffer(icon_surface)) { + drag_icon_set_mapped(icon, true); + } + return icon; } From 9333acd68e468d409cbcc30fb742fdf57c631cb9 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 5 Jun 2018 23:01:43 -0400 Subject: [PATCH 18/43] handle drag icon map in rootston --- include/rootston/seat.h | 1 + rootston/seat.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/include/rootston/seat.h b/include/rootston/seat.h index bed81c88..0e3043dd 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -58,6 +58,7 @@ struct roots_drag_icon { double x, y; struct wl_listener surface_commit; + struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; }; diff --git a/rootston/seat.c b/rootston/seat.c index 81cedc5a..132b0f35 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -263,6 +263,13 @@ static void roots_drag_icon_handle_surface_commit(struct wl_listener *listener, roots_drag_icon_damage_whole(icon); } +static void roots_drag_icon_handle_map(struct wl_listener *listener, + void *data) { + struct roots_drag_icon *icon = + wl_container_of(listener, icon, map); + roots_drag_icon_damage_whole(icon); +} + static void roots_drag_icon_handle_unmap(struct wl_listener *listener, void *data) { struct roots_drag_icon *icon = @@ -299,6 +306,8 @@ static void roots_seat_handle_new_drag_icon(struct wl_listener *listener, wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit); icon->unmap.notify = roots_drag_icon_handle_unmap; wl_signal_add(&wlr_drag_icon->events.unmap, &icon->unmap); + icon->map.notify = roots_drag_icon_handle_map; + wl_signal_add(&wlr_drag_icon->events.map, &icon->map); icon->destroy.notify = roots_drag_icon_handle_destroy; wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); From 7c888a39c6d08e9301032625987a6015fac17c6f Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 5 Jun 2018 23:45:03 -0400 Subject: [PATCH 19/43] update drag position at the right times --- rootston/seat.c | 3 +++ types/data_device/wlr_drag.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/rootston/seat.c b/rootston/seat.c index 132b0f35..33dff741 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -260,6 +260,7 @@ static void roots_drag_icon_handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_drag_icon *icon = wl_container_of(listener, icon, surface_commit); + roots_drag_icon_update_position(icon); roots_drag_icon_damage_whole(icon); } @@ -312,6 +313,8 @@ static void roots_seat_handle_new_drag_icon(struct wl_listener *listener, wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); wl_list_insert(&seat->drag_icons, &icon->link); + + roots_drag_icon_update_position(icon); } void roots_drag_icon_update_position(struct roots_drag_icon *icon) { diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index 4b42307e..4f0b2521 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -100,12 +100,12 @@ static void drag_set_focus(struct wlr_drag *drag, static void drag_icon_set_mapped(struct wlr_drag_icon *icon, bool mapped) { if (mapped && !icon->mapped) { + icon->mapped = true; wlr_signal_emit_safe(&icon->events.map, icon); } else if (!mapped && icon->mapped) { + icon->mapped = false; wlr_signal_emit_safe(&icon->events.unmap, icon); } - - icon->mapped = mapped; } static void drag_end(struct wlr_drag *drag) { From ed89a2432885d7b6cd403d7f304d3b28ea991410 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 6 Jun 2018 08:47:04 +0100 Subject: [PATCH 20/43] box: fix wlr_box_intersection --- types/wlr_box.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/wlr_box.c b/types/wlr_box.c index f8fe9dfe..ada6a733 100644 --- a/types/wlr_box.c +++ b/types/wlr_box.c @@ -46,8 +46,8 @@ bool wlr_box_intersection(const struct wlr_box *box_a, int x1 = fmax(box_a->x, box_b->x); int y1 = fmax(box_a->y, box_b->y); - int x2 = fmin(box_a->x + box_a->width - 1, box_b->x + box_b->width - 1); - int y2 = fmin(box_a->y + box_a->height - 1, box_b->y + box_b->height - 1); + int x2 = fmin(box_a->x + box_a->width, box_b->x + box_b->width); + int y2 = fmin(box_a->y + box_a->height, box_b->y + box_b->height); dest->x = x1; dest->y = y1; From a989104a6b647bde0eeffd31a3d7aebe7ff29dd2 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 6 Jun 2018 17:08:06 +0300 Subject: [PATCH 21/43] xdg-shells: add a set_parent signal to toplevel surfaces --- include/wlr/types/wlr_xdg_shell.h | 1 + include/wlr/types/wlr_xdg_shell_v6.h | 1 + types/xdg_shell/wlr_xdg_toplevel.c | 2 ++ types/xdg_shell_v6/wlr_xdg_toplevel_v6.c | 2 ++ 4 files changed, 6 insertions(+) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 6a967bc7..01dc17fe 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -118,6 +118,7 @@ struct wlr_xdg_toplevel { struct wl_signal request_move; struct wl_signal request_resize; struct wl_signal request_show_window_menu; + struct wl_signal set_parent; } events; }; diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 07c831ce..5f98eb13 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -126,6 +126,7 @@ struct wlr_xdg_toplevel_v6 { struct wl_signal request_move; struct wl_signal request_resize; struct wl_signal request_show_window_menu; + struct wl_signal set_parent; } events; }; diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index 5968c835..fa0ec929 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -218,6 +218,7 @@ static void xdg_toplevel_handle_set_parent(struct wl_client *client, } surface->toplevel->parent = parent; + wlr_signal_emit_safe(&surface->toplevel->events.set_parent, surface); } static void xdg_toplevel_handle_set_title(struct wl_client *client, @@ -464,6 +465,7 @@ void create_xdg_toplevel(struct wlr_xdg_surface *xdg_surface, wl_signal_init(&xdg_surface->toplevel->events.request_move); wl_signal_init(&xdg_surface->toplevel->events.request_resize); wl_signal_init(&xdg_surface->toplevel->events.request_show_window_menu); + wl_signal_init(&xdg_surface->toplevel->events.set_parent); xdg_surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL; xdg_surface->toplevel->base = xdg_surface; diff --git a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c index 2bcfaf0d..0f9a26d3 100644 --- a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c @@ -42,6 +42,7 @@ static void xdg_toplevel_handle_set_parent(struct wl_client *client, } surface->toplevel->parent = parent; + wlr_signal_emit_safe(&surface->toplevel->events.set_parent, surface); } static void xdg_toplevel_handle_set_title(struct wl_client *client, @@ -434,6 +435,7 @@ void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface, wl_signal_init(&xdg_surface->toplevel->events.request_move); wl_signal_init(&xdg_surface->toplevel->events.request_resize); wl_signal_init(&xdg_surface->toplevel->events.request_show_window_menu); + wl_signal_init(&xdg_surface->toplevel->events.set_parent); xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; xdg_surface->toplevel->base = xdg_surface; From 5d3e95f833ae562bf6926ddfb9f1bdb0492c1674 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 6 Jun 2018 12:02:01 -0400 Subject: [PATCH 22/43] dont damage drag icon after update_position --- rootston/seat.c | 1 - 1 file changed, 1 deletion(-) diff --git a/rootston/seat.c b/rootston/seat.c index 33dff741..91561567 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -261,7 +261,6 @@ static void roots_drag_icon_handle_surface_commit(struct wl_listener *listener, struct roots_drag_icon *icon = wl_container_of(listener, icon, surface_commit); roots_drag_icon_update_position(icon); - roots_drag_icon_damage_whole(icon); } static void roots_drag_icon_handle_map(struct wl_listener *listener, From de91c55ea9da1b4c22bc377a7013efdcc71fff06 Mon Sep 17 00:00:00 2001 From: NeKit Date: Sun, 3 Jun 2018 01:20:09 +0300 Subject: [PATCH 23/43] Fix GLES2 renderer to use glGetUniformLocations locations This is needed as uniform locations are driver implementation-specific. --- include/render/gles2.h | 36 +++++++++++-- render/gles2/renderer.c | 109 ++++++++++++++++++++++++++++------------ 2 files changed, 108 insertions(+), 37 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index 99beff29..c47751d1 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -32,11 +32,37 @@ struct wlr_gles2_renderer { const char *exts_str; struct { - GLuint quad; - GLuint ellipse; - GLuint tex_rgba; - GLuint tex_rgbx; - GLuint tex_ext; + struct { + GLuint program; + GLint proj; + GLint color; + } quad; + struct { + GLuint program; + GLint proj; + GLint color; + } ellipse; + struct { + GLuint program; + GLint proj; + GLint invert_y; + GLint tex; + GLint alpha; + } tex_rgba; + struct { + GLuint program; + GLint proj; + GLint invert_y; + GLint tex; + GLint alpha; + } tex_rgbx; + struct { + GLuint program; + GLint proj; + GLint invert_y; + GLint tex; + GLint alpha; + } tex_ext; } shaders; uint32_t viewport_width, viewport_height; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 1eeb915e..dce59d88 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -120,16 +120,36 @@ static bool gles2_render_texture_with_matrix(struct wlr_renderer *wlr_renderer, GLuint prog = 0; GLenum target = 0; + GLint proj_loc = 0; + GLint invert_y_loc = 0; + GLint tex_loc = 0; + GLint alpha_loc = 0; + switch (texture->type) { case WLR_GLES2_TEXTURE_GLTEX: case WLR_GLES2_TEXTURE_WL_DRM_GL: - prog = texture->has_alpha ? renderer->shaders.tex_rgba : - renderer->shaders.tex_rgbx; + if (texture->has_alpha) { + prog = renderer->shaders.tex_rgba.program; + proj_loc = renderer->shaders.tex_rgba.proj; + invert_y_loc = renderer->shaders.tex_rgba.invert_y; + tex_loc = renderer->shaders.tex_rgba.tex; + alpha_loc = renderer->shaders.tex_rgba.alpha; + } else { + prog = renderer->shaders.tex_rgbx.program; + proj_loc = renderer->shaders.tex_rgbx.proj; + invert_y_loc = renderer->shaders.tex_rgbx.invert_y; + tex_loc = renderer->shaders.tex_rgbx.tex; + alpha_loc = renderer->shaders.tex_rgbx.alpha; + } target = GL_TEXTURE_2D; break; case WLR_GLES2_TEXTURE_WL_DRM_EXT: case WLR_GLES2_TEXTURE_DMABUF: - prog = renderer->shaders.tex_ext; + prog = renderer->shaders.tex_ext.program; + proj_loc = renderer->shaders.tex_ext.proj; + invert_y_loc = renderer->shaders.tex_ext.invert_y; + tex_loc = renderer->shaders.tex_ext.tex; + alpha_loc = renderer->shaders.tex_ext.alpha; target = GL_TEXTURE_EXTERNAL_OES; break; } @@ -151,9 +171,10 @@ static bool gles2_render_texture_with_matrix(struct wlr_renderer *wlr_renderer, glUseProgram(prog); - glUniformMatrix3fv(0, 1, GL_FALSE, transposition); - glUniform1i(1, texture->inverted_y); - glUniform1f(3, alpha); + glUniformMatrix3fv(proj_loc, 1, GL_FALSE, transposition); + glUniform1i(invert_y_loc, texture->inverted_y); + glUniform1f(alpha_loc, alpha); + glUniform1i(tex_loc, 0); draw_quad(); @@ -173,9 +194,10 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer, wlr_matrix_transpose(transposition, matrix); PUSH_GLES2_DEBUG; - glUseProgram(renderer->shaders.quad); - glUniformMatrix3fv(0, 1, GL_FALSE, transposition); - glUniform4f(1, color[0], color[1], color[2], color[3]); + glUseProgram(renderer->shaders.quad.program); + + glUniformMatrix3fv(renderer->shaders.quad.proj, 1, GL_FALSE, transposition); + glUniform4f(renderer->shaders.quad.color, color[0], color[1], color[2], color[3]); draw_quad(); POP_GLES2_DEBUG; } @@ -191,9 +213,10 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, wlr_matrix_transpose(transposition, matrix); PUSH_GLES2_DEBUG; - glUseProgram(renderer->shaders.ellipse); - glUniformMatrix3fv(0, 1, GL_FALSE, transposition); - glUniform4f(1, color[0], color[1], color[2], color[3]); + glUseProgram(renderer->shaders.ellipse.program); + + glUniformMatrix3fv(renderer->shaders.ellipse.proj, 1, GL_FALSE, transposition); + glUniform4f(renderer->shaders.ellipse.color, color[0], color[1], color[2], color[3]); draw_quad(); POP_GLES2_DEBUG; } @@ -313,11 +336,11 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); PUSH_GLES2_DEBUG; - glDeleteProgram(renderer->shaders.quad); - glDeleteProgram(renderer->shaders.ellipse); - glDeleteProgram(renderer->shaders.tex_rgba); - glDeleteProgram(renderer->shaders.tex_rgbx); - glDeleteProgram(renderer->shaders.tex_ext); + glDeleteProgram(renderer->shaders.quad.program); + glDeleteProgram(renderer->shaders.ellipse.program); + glDeleteProgram(renderer->shaders.tex_rgba.program); + glDeleteProgram(renderer->shaders.tex_rgbx.program); + glDeleteProgram(renderer->shaders.tex_ext.program); POP_GLES2_DEBUG; if (glDebugMessageCallbackKHR) { @@ -486,31 +509,53 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { PUSH_GLES2_DEBUG; - renderer->shaders.quad = link_program(quad_vertex_src, quad_fragment_src); - if (!renderer->shaders.quad) { + GLuint prog; + renderer->shaders.quad.program = prog = + link_program(quad_vertex_src, quad_fragment_src); + if (!renderer->shaders.quad.program) { goto error; } - renderer->shaders.ellipse = + renderer->shaders.quad.proj = glGetUniformLocation(prog, "proj"); + renderer->shaders.quad.color = glGetUniformLocation(prog, "color"); + + renderer->shaders.ellipse.program = prog = link_program(quad_vertex_src, ellipse_fragment_src); - if (!renderer->shaders.ellipse) { + if (!renderer->shaders.ellipse.program) { goto error; } - renderer->shaders.tex_rgba = + renderer->shaders.ellipse.proj = glGetUniformLocation(prog, "proj"); + renderer->shaders.ellipse.color = glGetUniformLocation(prog, "color"); + + renderer->shaders.tex_rgba.program = prog = link_program(tex_vertex_src, tex_fragment_src_rgba); - if (!renderer->shaders.tex_rgba) { + if (!renderer->shaders.tex_rgba.program) { goto error; } - renderer->shaders.tex_rgbx = + renderer->shaders.tex_rgba.proj = glGetUniformLocation(prog, "proj"); + renderer->shaders.tex_rgba.invert_y = glGetUniformLocation(prog, "invert_y"); + renderer->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex"); + renderer->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha"); + + renderer->shaders.tex_rgbx.program = prog = link_program(tex_vertex_src, tex_fragment_src_rgbx); - if (!renderer->shaders.tex_rgbx) { + if (!renderer->shaders.tex_rgbx.program) { goto error; } + renderer->shaders.tex_rgbx.proj = glGetUniformLocation(prog, "proj"); + renderer->shaders.tex_rgbx.invert_y = glGetUniformLocation(prog, "invert_y"); + renderer->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex"); + renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha"); + if (glEGLImageTargetTexture2DOES) { - renderer->shaders.tex_ext = + renderer->shaders.tex_ext.program = prog = link_program(tex_vertex_src, tex_fragment_src_external); - if (!renderer->shaders.tex_ext) { + if (!renderer->shaders.tex_ext.program) { goto error; } + renderer->shaders.tex_ext.proj = glGetUniformLocation(prog, "proj"); + renderer->shaders.tex_ext.invert_y = glGetUniformLocation(prog, "invert_y"); + renderer->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex"); + renderer->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha"); } POP_GLES2_DEBUG; @@ -518,11 +563,11 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { return &renderer->wlr_renderer; error: - glDeleteProgram(renderer->shaders.quad); - glDeleteProgram(renderer->shaders.ellipse); - glDeleteProgram(renderer->shaders.tex_rgba); - glDeleteProgram(renderer->shaders.tex_rgbx); - glDeleteProgram(renderer->shaders.tex_ext); + glDeleteProgram(renderer->shaders.quad.program); + glDeleteProgram(renderer->shaders.ellipse.program); + glDeleteProgram(renderer->shaders.tex_rgba.program); + glDeleteProgram(renderer->shaders.tex_rgbx.program); + glDeleteProgram(renderer->shaders.tex_ext.program); POP_GLES2_DEBUG; From 3e83f9d6b89f9b3a7af9761b4adffd173858e637 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 7 Jun 2018 18:57:06 +0100 Subject: [PATCH 24/43] surface: don't release wl_drm and linux-dmabuf buffers early --- types/wlr_surface.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 9c3eb86d..fca4e847 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -394,6 +394,10 @@ static void surface_apply_damage(struct wlr_surface *surface, } wl_shm_buffer_end_access(buf); + + // We've uploaded the wl_shm_buffer data to the GPU, we won't access the + // wl_buffer anymore + surface_state_release_buffer(surface->current); } else if (invalid_buffer || reupload_buffer) { wlr_texture_destroy(surface->texture); @@ -409,9 +413,10 @@ static void surface_apply_damage(struct wlr_surface *surface, surface->texture = NULL; wlr_log(L_ERROR, "Unknown buffer handle attached"); } - } - surface_state_release_buffer(surface->current); + // Don't release the wl_buffer yet: since the texture is shared with the + // client, we'll access the wl_buffer when rendering + } } static void surface_commit_pending(struct wlr_surface *surface) { From cbfe0e834aa202a9c3cc713f958a043efcd15d6a Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 3 Jun 2018 09:53:03 +0100 Subject: [PATCH 25/43] Request a high priority EGL context --- include/wlr/render/egl.h | 1 + render/egl.c | 53 +++++++++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 6d79cbd2..abf51997 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -21,6 +21,7 @@ struct wlr_egl { bool dmabuf_import; bool dmabuf_import_modifiers; bool bind_wayland_display; + bool context_priority; } egl_exts; struct wl_display *wl_display; diff --git a/render/egl.c b/render/egl.c index 676a0208..546a2c71 100644 --- a/render/egl.c +++ b/render/egl.c @@ -144,17 +144,6 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, goto error; } - static const EGLint attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - - egl->context = eglCreateContext(egl->display, egl->config, - EGL_NO_CONTEXT, attribs); - - if (egl->context == EGL_NO_CONTEXT) { - wlr_log(L_ERROR, "Failed to create EGL context"); - goto error; - } - - eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl->context); egl->exts_str = eglQueryString(egl->display, EGL_EXTENSIONS); wlr_log(L_INFO, "Using EGL %d.%d", (int)major, (int)minor); @@ -177,10 +166,50 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, egl->egl_exts.dmabuf_import_modifiers = check_egl_ext(egl->exts_str, "EGL_EXT_image_dma_buf_import_modifiers") && eglQueryDmaBufFormatsEXT && eglQueryDmaBufModifiersEXT; + print_dmabuf_formats(egl); egl->egl_exts.bind_wayland_display = check_egl_ext(egl->exts_str, "EGL_WL_bind_wayland_display"); - print_dmabuf_formats(egl); + + egl->egl_exts.context_priority = + check_egl_ext(egl->exts_str, "EGL_IMG_context_priority"); + + size_t atti = 0; + EGLint attribs[5]; + attribs[atti++] = EGL_CONTEXT_CLIENT_VERSION; + attribs[atti++] = 2; + + // Try to reschedule all of our rendering to be completed first. If it + // fails, it will fallback to the default priority (MEDIUM). + if (egl->egl_exts.context_priority) { + attribs[atti++] = EGL_CONTEXT_PRIORITY_LEVEL_IMG; + attribs[atti++] = EGL_CONTEXT_PRIORITY_HIGH_IMG; + } + + attribs[atti++] = EGL_NONE; + assert(atti < sizeof(attribs)/sizeof(attribs[0])); + + egl->context = eglCreateContext(egl->display, egl->config, + EGL_NO_CONTEXT, attribs); + if (egl->context == EGL_NO_CONTEXT) { + wlr_log(L_ERROR, "Failed to create EGL context"); + goto error; + } + + if (egl->egl_exts.context_priority) { + EGLint priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG; + eglQueryContext(egl->display, egl->context, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, &priority); + if (priority != EGL_CONTEXT_PRIORITY_HIGH_IMG) { + wlr_log(L_INFO, "Failed to obtain a high priority context"); + } + } + + if (!eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, + egl->context)) { + wlr_log(L_ERROR, "Failed to make EGL context current"); + goto error; + } return true; From d425edc96c28a0b251bbe26200fa7dfbc40b241c Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 5 Jun 2018 09:59:26 +0100 Subject: [PATCH 26/43] render/egl: consistent extension checking --- include/wlr/render/egl.h | 9 +++++---- render/egl.c | 29 +++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index abf51997..26e367a1 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -16,12 +16,13 @@ struct wlr_egl { const char *exts_str; struct { - bool buffer_age; - bool swap_buffers_with_damage; - bool dmabuf_import; - bool dmabuf_import_modifiers; bool bind_wayland_display; + bool buffer_age; bool context_priority; + bool dmabuf_import_modifiers; + bool dmabuf_import; + bool image_base; + bool swap_buffers_with_damage; } egl_exts; struct wl_display *wl_display; diff --git a/render/egl.c b/render/egl.c index 546a2c71..9d54e38d 100644 --- a/render/egl.c +++ b/render/egl.c @@ -155,11 +155,17 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, goto error; } + egl->egl_exts.image_base = + check_egl_ext(egl->exts_str, "EGL_KHR_image_base") + && eglCreateImageKHR && eglDestroyImageKHR; + egl->egl_exts.buffer_age = check_egl_ext(egl->exts_str, "EGL_EXT_buffer_age"); egl->egl_exts.swap_buffers_with_damage = - check_egl_ext(egl->exts_str, "EGL_EXT_swap_buffers_with_damage") || - check_egl_ext(egl->exts_str, "EGL_KHR_swap_buffers_with_damage"); + (check_egl_ext(egl->exts_str, "EGL_EXT_swap_buffers_with_damage") && + eglSwapBuffersWithDamageEXT) || + (check_egl_ext(egl->exts_str, "EGL_KHR_swap_buffers_with_damage") && + eglSwapBuffersWithDamageKHR); egl->egl_exts.dmabuf_import = check_egl_ext(egl->exts_str, "EGL_EXT_image_dma_buf_import"); @@ -169,7 +175,9 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, print_dmabuf_formats(egl); egl->egl_exts.bind_wayland_display = - check_egl_ext(egl->exts_str, "EGL_WL_bind_wayland_display"); + check_egl_ext(egl->exts_str, "EGL_WL_bind_wayland_display") + && eglBindWaylandDisplayWL && eglUnbindWaylandDisplayWL + && eglQueryWaylandBufferWL; egl->egl_exts.context_priority = check_egl_ext(egl->exts_str, "EGL_IMG_context_priority"); @@ -228,7 +236,8 @@ void wlr_egl_finish(struct wlr_egl *egl) { } eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (egl->wl_display && egl->egl_exts.bind_wayland_display) { + if (egl->wl_display) { + assert(egl->egl_exts.bind_wayland_display); eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); } @@ -251,7 +260,7 @@ bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) } bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImage image) { - if (!eglDestroyImageKHR) { + if (!egl->egl_exts.image_base) { return false; } if (!image) { @@ -341,7 +350,7 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, struct wl_resource *data, EGLint *fmt, int *width, int *height, bool *inverted_y) { - if (!eglQueryWaylandBufferWL || !eglCreateImageKHR) { + if (!egl->egl_exts.bind_wayland_display || !egl->egl_exts.image_base) { return NULL; } @@ -370,6 +379,10 @@ EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_attributes *attributes) { + if (!egl->egl_exts.image_base) { + return NULL; + } + bool has_modifier = false; if (attributes->modifier != DRM_FORMAT_MOD_INVALID) { if (!egl->egl_exts.dmabuf_import_modifiers) { @@ -445,7 +458,7 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats) { if (!egl->egl_exts.dmabuf_import || - !egl->egl_exts.dmabuf_import_modifiers) { + !egl->egl_exts.dmabuf_import_modifiers) { wlr_log(L_DEBUG, "dmabuf extension not present"); return -1; } @@ -473,7 +486,7 @@ int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format, uint64_t **modifiers) { if (!egl->egl_exts.dmabuf_import || - !egl->egl_exts.dmabuf_import_modifiers) { + !egl->egl_exts.dmabuf_import_modifiers) { wlr_log(L_DEBUG, "dmabuf extension not present"); return -1; } From 457bfcab1978f6b2bff42982b8fcbf220246ee54 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 8 Jun 2018 00:17:45 +0100 Subject: [PATCH 27/43] render/egl: only request high priority context on DRM --- include/wlr/render/egl.h | 3 +- render/egl.c | 75 +++++++++++++++++++--------------------- render/gles2/texture.c | 2 +- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 26e367a1..55086755 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -18,12 +18,11 @@ struct wlr_egl { struct { bool bind_wayland_display; bool buffer_age; - bool context_priority; bool dmabuf_import_modifiers; bool dmabuf_import; bool image_base; bool swap_buffers_with_damage; - } egl_exts; + } exts; struct wl_display *wl_display; }; diff --git a/render/egl.c b/render/egl.c index 9d54e38d..7717b805 100644 --- a/render/egl.c +++ b/render/egl.c @@ -7,10 +7,6 @@ #include #include "glapi.h" -// Extension documentation -// https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt. -// https://cgit.freedesktop.org/mesa/mesa/tree/docs/specs/WL_bind_wayland_display.spec - static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out, EGLint visual_id) { EGLint count = 0, matched = 0, ret; @@ -61,27 +57,27 @@ static void egl_log(EGLenum error, const char *command, EGLint msg_type, _wlr_log(egl_log_importance_to_wlr(msg_type), "[EGL] %s: %s", command, msg); } -static bool check_egl_ext(const char *egl_exts, const char *ext) { +static bool check_egl_ext(const char *exts, const char *ext) { size_t extlen = strlen(ext); - const char *end = egl_exts + strlen(egl_exts); + const char *end = exts + strlen(exts); - while (egl_exts < end) { - if (*egl_exts == ' ') { - egl_exts++; + while (exts < end) { + if (*exts == ' ') { + exts++; continue; } - size_t n = strcspn(egl_exts, " "); - if (n == extlen && strncmp(ext, egl_exts, n) == 0) { + size_t n = strcspn(exts, " "); + if (n == extlen && strncmp(ext, exts, n) == 0) { return true; } - egl_exts += n; + exts += n; } return false; } static void print_dmabuf_formats(struct wlr_egl *egl) { /* Avoid log msg if extension is not present */ - if (!egl->egl_exts.dmabuf_import_modifiers) { + if (!egl->exts.dmabuf_import_modifiers) { return; } @@ -150,36 +146,31 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, wlr_log(L_INFO, "Supported EGL extensions: %s", egl->exts_str); wlr_log(L_INFO, "EGL vendor: %s", eglQueryString(egl->display, EGL_VENDOR)); - if (!check_egl_ext(egl->exts_str, "EGL_KHR_image_base")) { - wlr_log(L_ERROR, "Required EGL_KHR_image_base extension not supported"); - goto error; - } - - egl->egl_exts.image_base = + egl->exts.image_base = check_egl_ext(egl->exts_str, "EGL_KHR_image_base") && eglCreateImageKHR && eglDestroyImageKHR; - egl->egl_exts.buffer_age = + egl->exts.buffer_age = check_egl_ext(egl->exts_str, "EGL_EXT_buffer_age"); - egl->egl_exts.swap_buffers_with_damage = + egl->exts.swap_buffers_with_damage = (check_egl_ext(egl->exts_str, "EGL_EXT_swap_buffers_with_damage") && eglSwapBuffersWithDamageEXT) || (check_egl_ext(egl->exts_str, "EGL_KHR_swap_buffers_with_damage") && eglSwapBuffersWithDamageKHR); - egl->egl_exts.dmabuf_import = + egl->exts.dmabuf_import = check_egl_ext(egl->exts_str, "EGL_EXT_image_dma_buf_import"); - egl->egl_exts.dmabuf_import_modifiers = + egl->exts.dmabuf_import_modifiers = check_egl_ext(egl->exts_str, "EGL_EXT_image_dma_buf_import_modifiers") && eglQueryDmaBufFormatsEXT && eglQueryDmaBufModifiersEXT; print_dmabuf_formats(egl); - egl->egl_exts.bind_wayland_display = + egl->exts.bind_wayland_display = check_egl_ext(egl->exts_str, "EGL_WL_bind_wayland_display") && eglBindWaylandDisplayWL && eglUnbindWaylandDisplayWL && eglQueryWaylandBufferWL; - egl->egl_exts.context_priority = + bool ext_context_priority = check_egl_ext(egl->exts_str, "EGL_IMG_context_priority"); size_t atti = 0; @@ -187,9 +178,13 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, attribs[atti++] = EGL_CONTEXT_CLIENT_VERSION; attribs[atti++] = 2; + // On DRM, request a high priority context if possible + bool request_high_priority = ext_context_priority && + platform == EGL_PLATFORM_GBM_MESA; + // Try to reschedule all of our rendering to be completed first. If it // fails, it will fallback to the default priority (MEDIUM). - if (egl->egl_exts.context_priority) { + if (request_high_priority) { attribs[atti++] = EGL_CONTEXT_PRIORITY_LEVEL_IMG; attribs[atti++] = EGL_CONTEXT_PRIORITY_HIGH_IMG; } @@ -204,12 +199,14 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, goto error; } - if (egl->egl_exts.context_priority) { + if (request_high_priority) { EGLint priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG; eglQueryContext(egl->display, egl->context, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &priority); if (priority != EGL_CONTEXT_PRIORITY_HIGH_IMG) { wlr_log(L_INFO, "Failed to obtain a high priority context"); + } else { + wlr_log(L_DEBUG, "Obtained high priority context"); } } @@ -237,7 +234,7 @@ void wlr_egl_finish(struct wlr_egl *egl) { eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (egl->wl_display) { - assert(egl->egl_exts.bind_wayland_display); + assert(egl->exts.bind_wayland_display); eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); } @@ -247,7 +244,7 @@ void wlr_egl_finish(struct wlr_egl *egl) { } bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) { - if (!egl->egl_exts.bind_wayland_display) { + if (!egl->exts.bind_wayland_display) { return false; } @@ -260,7 +257,7 @@ bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) } bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImage image) { - if (!egl->egl_exts.image_base) { + if (!egl->exts.image_base) { return false; } if (!image) { @@ -281,7 +278,7 @@ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) { } static int egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) { - if (!egl->egl_exts.buffer_age) { + if (!egl->exts.buffer_age) { return -1; } @@ -316,7 +313,7 @@ bool wlr_egl_is_current(struct wlr_egl *egl) { bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, pixman_region32_t *damage) { EGLBoolean ret; - if (damage != NULL && egl->egl_exts.swap_buffers_with_damage) { + if (damage != NULL && egl->exts.swap_buffers_with_damage) { int nrects; pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); @@ -350,7 +347,7 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, struct wl_resource *data, EGLint *fmt, int *width, int *height, bool *inverted_y) { - if (!egl->egl_exts.bind_wayland_display || !egl->egl_exts.image_base) { + if (!egl->exts.bind_wayland_display || !egl->exts.image_base) { return NULL; } @@ -379,13 +376,13 @@ EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_attributes *attributes) { - if (!egl->egl_exts.image_base) { + if (!egl->exts.image_base) { return NULL; } bool has_modifier = false; if (attributes->modifier != DRM_FORMAT_MOD_INVALID) { - if (!egl->egl_exts.dmabuf_import_modifiers) { + if (!egl->exts.dmabuf_import_modifiers) { return NULL; } has_modifier = true; @@ -457,8 +454,8 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats) { - if (!egl->egl_exts.dmabuf_import || - !egl->egl_exts.dmabuf_import_modifiers) { + if (!egl->exts.dmabuf_import || + !egl->exts.dmabuf_import_modifiers) { wlr_log(L_DEBUG, "dmabuf extension not present"); return -1; } @@ -485,8 +482,8 @@ int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format, uint64_t **modifiers) { - if (!egl->egl_exts.dmabuf_import || - !egl->egl_exts.dmabuf_import_modifiers) { + if (!egl->exts.dmabuf_import || + !egl->exts.dmabuf_import_modifiers) { wlr_log(L_DEBUG, "dmabuf extension not present"); return -1; } diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 89a175c4..ca1398e8 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -210,7 +210,7 @@ struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl, return NULL; } - if (!egl->egl_exts.dmabuf_import) { + if (!egl->exts.dmabuf_import) { wlr_log(L_ERROR, "Cannot create DMA-BUF texture: EGL extension " "unavailable"); return NULL; From 3a81afed0e21a515f5694204beb0438407fc1313 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 8 Jun 2018 09:29:55 +0100 Subject: [PATCH 28/43] rootston: destroy xwayland before all clients Destroying all clients disconnects the xwayland client, and xwayland automatically restarts when disconnected. --- rootston/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rootston/main.c b/rootston/main.c index 07a41d5d..8a0205f2 100644 --- a/rootston/main.c +++ b/rootston/main.c @@ -72,6 +72,9 @@ int main(int argc, char **argv) { } wl_display_run(server.wl_display); +#ifdef WLR_HAS_XWAYLAND + wlr_xwayland_destroy(server.desktop->xwayland); +#endif wl_display_destroy_clients(server.wl_display); wl_display_destroy(server.wl_display); return 0; From e4933ab445c70b9ac3c0026718b29a18be171ed5 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 8 Jun 2018 20:06:13 +0100 Subject: [PATCH 29/43] Introduce wlr_buffer --- include/wlr/types/wlr_buffer.h | 36 +++++++ include/wlr/types/wlr_surface.h | 1 + types/meson.build | 1 + types/wlr_buffer.c | 186 ++++++++++++++++++++++++++++++++ types/wlr_surface.c | 130 +++++++--------------- 5 files changed, 263 insertions(+), 91 deletions(-) create mode 100644 include/wlr/types/wlr_buffer.h create mode 100644 types/wlr_buffer.c diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h new file mode 100644 index 00000000..28567f26 --- /dev/null +++ b/include/wlr/types/wlr_buffer.h @@ -0,0 +1,36 @@ +#ifndef WLR_TYPES_WLR_BUFFER_H +#define WLR_TYPES_WLR_BUFFER_H + +#include +#include + +struct wlr_buffer { + struct wl_resource *resource; + struct wlr_texture *texture; + bool released; + size_t n_refs; + + struct wl_listener resource_destroy; +}; + +struct wlr_renderer; + +// Checks if a resource is a wl_buffer. +bool wlr_resource_is_buffer(struct wl_resource *resource); +// Returns the buffer size. +bool wlr_buffer_get_resource_size(struct wl_resource *resource, + struct wlr_renderer *renderer, int *width, int *height); + +// Uploads the texture to the GPU and references it. +struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, + struct wl_resource *resource); +// References and unreferences the buffer. +void wlr_buffer_ref(struct wlr_buffer *buffer); +void wlr_buffer_unref(struct wlr_buffer *buffer); +// Tries to update the texture in the provided buffer. This destroys `buffer` +// and returns a new buffer. +// Fails if `buffer->n_refs` > 1 or if the texture isn't mutable. +struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer, + struct wl_resource *resource, pixman_region32_t *damage); + +#endif diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 526e4e2c..64503e78 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -69,6 +69,7 @@ struct wlr_subsurface { struct wlr_surface { struct wl_resource *resource; struct wlr_renderer *renderer; + struct wlr_buffer *buffer; struct wlr_texture *texture; struct wlr_surface_state *current, *pending; const char *role; // the lifetime-bound role or null diff --git a/types/meson.build b/types/meson.build index f9f5b469..87f21c55 100644 --- a/types/meson.build +++ b/types/meson.build @@ -20,6 +20,7 @@ lib_wlr_types = static_library( 'xdg_shell_v6/wlr_xdg_surface_v6.c', 'xdg_shell_v6/wlr_xdg_toplevel_v6.c', 'wlr_box.c', + 'wlr_buffer.c', 'wlr_compositor.c', 'wlr_cursor.c', 'wlr_gamma_control.c', diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c new file mode 100644 index 00000000..e062df4c --- /dev/null +++ b/types/wlr_buffer.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include + +bool wlr_resource_is_buffer(struct wl_resource *resource) { + return strcmp(wl_resource_get_class(resource), wl_buffer_interface.name) == 0; +} + +bool wlr_buffer_get_resource_size(struct wl_resource *resource, + struct wlr_renderer *renderer, int *width, int *height) { + assert(wlr_resource_is_buffer(resource)); + + struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource); + if (shm_buf != NULL) { + *width = wl_shm_buffer_get_width(shm_buf); + *height = wl_shm_buffer_get_height(shm_buf); + } else if (wlr_renderer_resource_is_wl_drm_buffer(renderer, + resource)) { + wlr_renderer_wl_drm_buffer_get_size(renderer, resource, + width, height); + } else if (wlr_dmabuf_resource_is_buffer(resource)) { + struct wlr_dmabuf_buffer *dmabuf = + wlr_dmabuf_buffer_from_buffer_resource(resource); + *width = dmabuf->attributes.width; + *height = dmabuf->attributes.height; + } else { + *width = *height = 0; + return false; + } + + return true; +} + + +static void buffer_resource_handle_destroy(struct wl_listener *listener, + void *data) { + struct wlr_buffer *buffer = + wl_container_of(listener, buffer, resource_destroy); + wl_list_remove(&buffer->resource_destroy.link); + wl_list_init(&buffer->resource_destroy.link); + buffer->resource = NULL; + + if (!buffer->released) { + // The texture becomes invalid + wlr_texture_destroy(buffer->texture); + buffer->texture = NULL; + } +} + +struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, + struct wl_resource *resource) { + assert(wlr_resource_is_buffer(resource)); + + struct wlr_texture *texture = NULL; + bool released = false; + + struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource); + if (shm_buf != NULL) { + enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buf); + int32_t stride = wl_shm_buffer_get_stride(shm_buf); + int32_t width = wl_shm_buffer_get_width(shm_buf); + int32_t height = wl_shm_buffer_get_height(shm_buf); + + wl_shm_buffer_begin_access(shm_buf); + void *data = wl_shm_buffer_get_data(shm_buf); + texture = wlr_texture_from_pixels(renderer, fmt, stride, + width, height, data); + wl_shm_buffer_end_access(shm_buf); + + // We have uploaded the data, we don't need to access the wl_buffer + // anymore + wl_buffer_send_release(resource); + released = true; + } else if (wlr_renderer_resource_is_wl_drm_buffer(renderer, resource)) { + texture = wlr_texture_from_wl_drm(renderer, resource); + } else if (wlr_dmabuf_resource_is_buffer(resource)) { + struct wlr_dmabuf_buffer *dmabuf = + wlr_dmabuf_buffer_from_buffer_resource(resource); + texture = wlr_texture_from_dmabuf(renderer, &dmabuf->attributes); + } else { + wlr_log(L_ERROR, "Cannot upload texture: unknown buffer type"); + return NULL; + } + + if (texture == NULL) { + wlr_log(L_ERROR, "Failed to upload texture"); + return NULL; + } + + struct wlr_buffer *buffer = calloc(1, sizeof(struct wlr_buffer)); + if (buffer == NULL) { + return NULL; + } + buffer->resource = resource; + buffer->texture = texture; + buffer->released = released; + buffer->n_refs = 1; + + wl_resource_add_destroy_listener(resource, &buffer->resource_destroy); + buffer->resource_destroy.notify = buffer_resource_handle_destroy; + + return buffer; +} + +void wlr_buffer_ref(struct wlr_buffer *buffer) { + buffer->n_refs++; +} + +void wlr_buffer_unref(struct wlr_buffer *buffer) { + if (buffer == NULL) { + return; + } + + assert(buffer->n_refs > 0); + buffer->n_refs--; + if (buffer->n_refs > 0) { + return; + } + + if (!buffer->released && buffer->resource != NULL) { + wl_buffer_send_release(buffer->resource); + } + + wl_list_remove(&buffer->resource_destroy.link); + wlr_texture_destroy(buffer->texture); + free(buffer); +} + +struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer, + struct wl_resource *resource, pixman_region32_t *damage) { + assert(wlr_resource_is_buffer(resource)); + + if (buffer->n_refs > 1) { + // Someone else still has a reference to the buffer + return NULL; + } + + struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource); + if (shm_buf == NULL) { + // Uploading only damaged regions only works for wl_shm buffers + return NULL; + } + + enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buf); + int32_t stride = wl_shm_buffer_get_stride(shm_buf); + int32_t width = wl_shm_buffer_get_width(shm_buf); + int32_t height = wl_shm_buffer_get_height(shm_buf); + + int32_t texture_width, texture_height; + wlr_texture_get_size(buffer->texture, &texture_width, &texture_height); + if (width != texture_width || height != texture_height) { + return NULL; + } + + wl_shm_buffer_begin_access(shm_buf); + void *data = wl_shm_buffer_get_data(shm_buf); + + int n; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &n); + for (int i = 0; i < n; ++i) { + pixman_box32_t *r = &rects[i]; + if (!wlr_texture_write_pixels(buffer->texture, fmt, stride, + r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1, + r->x1, r->y1, data)) { + wl_shm_buffer_end_access(shm_buf); + return NULL; + } + } + + wl_shm_buffer_end_access(shm_buf); + + // We have uploaded the data, we don't need to access the wl_buffer + // anymore + wl_buffer_send_release(resource); + + wl_list_remove(&buffer->resource_destroy.link); + wl_resource_add_destroy_listener(resource, &buffer->resource_destroy); + buffer->resource_destroy.notify = buffer_resource_handle_destroy; + + buffer->resource = resource; + buffer->released = true; + return buffer; +} diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 9c3eb86d..7d8da02f 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -1,10 +1,9 @@ #include #include #include -#include #include +#include #include -#include #include #include #include @@ -46,13 +45,6 @@ static void surface_handle_buffer_destroy(struct wl_listener *listener, surface_state_reset_buffer(state); } -static void surface_state_release_buffer(struct wlr_surface_state *state) { - if (state->buffer) { - wl_buffer_send_release(state->buffer); - surface_state_reset_buffer(state); - } -} - static void surface_state_set_buffer(struct wlr_surface_state *state, struct wl_resource *buffer) { surface_state_reset_buffer(state); @@ -175,24 +167,8 @@ static bool surface_update_size(struct wlr_surface *surface, int scale = state->scale; enum wl_output_transform transform = state->transform; - struct wl_shm_buffer *buf = wl_shm_buffer_get(state->buffer); - if (buf != NULL) { - state->buffer_width = wl_shm_buffer_get_width(buf); - state->buffer_height = wl_shm_buffer_get_height(buf); - } else if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer, - state->buffer)) { - wlr_renderer_wl_drm_buffer_get_size(surface->renderer, state->buffer, - &state->buffer_width, &state->buffer_height); - } else if (wlr_dmabuf_resource_is_buffer(state->buffer)) { - struct wlr_dmabuf_buffer *dmabuf = - wlr_dmabuf_buffer_from_buffer_resource(state->buffer); - state->buffer_width = dmabuf->attributes.width; - state->buffer_height = dmabuf->attributes.height; - } else { - wlr_log(L_ERROR, "Unknown buffer handle attached"); - state->buffer_width = 0; - state->buffer_height = 0; - } + wlr_buffer_get_resource_size(state->buffer, surface->renderer, + &state->buffer_width, &state->buffer_height); int width = state->buffer_width / scale; int height = state->buffer_height / scale; @@ -243,7 +219,6 @@ static void surface_move_state(struct wlr_surface *surface, update_size = true; } if ((next->invalid & WLR_SURFACE_INVALID_BUFFER)) { - surface_state_release_buffer(state); surface_state_set_buffer(state, next->buffer); surface_state_reset_buffer(next); state->sx = next->sx; @@ -351,86 +326,60 @@ static void surface_damage_subsurfaces(struct wlr_subsurface *subsurface) { } static void surface_apply_damage(struct wlr_surface *surface, - bool invalid_buffer, bool reupload_buffer) { + bool invalid_buffer) { struct wl_resource *resource = surface->current->buffer; if (resource == NULL) { + // NULL commit + wlr_buffer_unref(surface->buffer); + surface->buffer = NULL; + surface->texture = NULL; return; } - struct wl_shm_buffer *buf = wl_shm_buffer_get(resource); - if (buf != NULL) { - wl_shm_buffer_begin_access(buf); + if (surface->buffer != NULL && !surface->buffer->released && + !invalid_buffer) { + // The buffer is still the same, no need to re-upload + return; + } - enum wl_shm_format fmt = wl_shm_buffer_get_format(buf); - int32_t stride = wl_shm_buffer_get_stride(buf); - int32_t width = wl_shm_buffer_get_width(buf); - int32_t height = wl_shm_buffer_get_height(buf); - void *data = wl_shm_buffer_get_data(buf); + if (surface->buffer != NULL && surface->buffer->released) { + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, &surface->current->buffer_damage); + pixman_region32_intersect_rect(&damage, &damage, 0, 0, + surface->current->buffer_width, surface->current->buffer_height); - if (surface->texture == NULL || reupload_buffer) { - wlr_texture_destroy(surface->texture); - surface->texture = wlr_texture_from_pixels(surface->renderer, fmt, - stride, width, height, data); - } else { - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_copy(&damage, &surface->current->buffer_damage); - pixman_region32_intersect_rect(&damage, &damage, 0, 0, - surface->current->buffer_width, - surface->current->buffer_height); + struct wlr_buffer *updated_buffer = + wlr_buffer_apply_damage(surface->buffer, resource, &damage); - int n; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &n); - for (int i = 0; i < n; ++i) { - pixman_box32_t *r = &rects[i]; - if (!wlr_texture_write_pixels(surface->texture, fmt, stride, - r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1, - r->x1, r->y1, data)) { - break; - } - } + pixman_region32_fini(&damage); - pixman_region32_fini(&damage); - } - - wl_shm_buffer_end_access(buf); - } else if (invalid_buffer || reupload_buffer) { - wlr_texture_destroy(surface->texture); - - if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer, resource)) { - surface->texture = - wlr_texture_from_wl_drm(surface->renderer, resource); - } else if (wlr_dmabuf_resource_is_buffer(resource)) { - struct wlr_dmabuf_buffer *dmabuf = - wlr_dmabuf_buffer_from_buffer_resource(resource); - surface->texture = - wlr_texture_from_dmabuf(surface->renderer, &dmabuf->attributes); - } else { - surface->texture = NULL; - wlr_log(L_ERROR, "Unknown buffer handle attached"); + if (updated_buffer != NULL) { + surface->buffer = updated_buffer; + return; } } - surface_state_release_buffer(surface->current); + wlr_buffer_unref(surface->buffer); + surface->buffer = NULL; + surface->texture = NULL; + + struct wlr_buffer *buffer = wlr_buffer_create(surface->renderer, resource); + if (buffer == NULL) { + wlr_log(L_ERROR, "Failed to upload buffer"); + return; + } + + surface->buffer = buffer; + surface->texture = buffer->texture; } static void surface_commit_pending(struct wlr_surface *surface) { - int32_t oldw = surface->current->buffer_width; - int32_t oldh = surface->current->buffer_height; - bool invalid_buffer = surface->pending->invalid & WLR_SURFACE_INVALID_BUFFER; - bool null_buffer_commit = invalid_buffer && surface->pending->buffer == NULL; surface_move_state(surface, surface->pending, surface->current); - if (null_buffer_commit) { - wlr_texture_destroy(surface->texture); - surface->texture = NULL; - } - - bool reupload_buffer = oldw != surface->current->buffer_width || - oldh != surface->current->buffer_height; - surface_apply_damage(surface, invalid_buffer, reupload_buffer); + surface_apply_damage(surface, invalid_buffer); // commit subsurface order struct wlr_subsurface *subsurface; @@ -652,10 +601,9 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(surface->resource)); wl_list_remove(&surface->renderer_destroy.link); - wlr_texture_destroy(surface->texture); surface_state_destroy(surface->pending); surface_state_destroy(surface->current); - + wlr_buffer_unref(surface->buffer); free(surface); } From 7d24af43e5f2fc04b41c5697101a44d67a384a12 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 8 Jun 2018 20:28:57 +0100 Subject: [PATCH 30/43] buffer: improve docs --- include/wlr/types/wlr_buffer.h | 38 ++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h index 28567f26..c57d79ed 100644 --- a/include/wlr/types/wlr_buffer.h +++ b/include/wlr/types/wlr_buffer.h @@ -4,9 +4,12 @@ #include #include +/** + * A client buffer. + */ struct wlr_buffer { - struct wl_resource *resource; - struct wlr_texture *texture; + struct wl_resource *resource; // can be NULL + struct wlr_texture *texture; // can be NULL bool released; size_t n_refs; @@ -15,21 +18,38 @@ struct wlr_buffer { struct wlr_renderer; -// Checks if a resource is a wl_buffer. +/** + * Check if a resource is a wl_buffer resource. + */ bool wlr_resource_is_buffer(struct wl_resource *resource); -// Returns the buffer size. +/** + * Get the size of a wl_buffer resource. + */ bool wlr_buffer_get_resource_size(struct wl_resource *resource, struct wlr_renderer *renderer, int *width, int *height); -// Uploads the texture to the GPU and references it. +/** + * Upload a buffer to the GPU and reference it. + */ struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, struct wl_resource *resource); -// References and unreferences the buffer. +/** + * Reference the buffer. + */ void wlr_buffer_ref(struct wlr_buffer *buffer); +/** + * Unreference the buffer. After this call, `buffer` may not be accessed + * anymore. + */ void wlr_buffer_unref(struct wlr_buffer *buffer); -// Tries to update the texture in the provided buffer. This destroys `buffer` -// and returns a new buffer. -// Fails if `buffer->n_refs` > 1 or if the texture isn't mutable. +/** + * Try to update the buffer's content. On success, returns the updated buffer + * and destroys the provided `buffer`. On error, `buffer` is intact and NULL is + * returned. + * + * Fails if there's more than one reference to the buffer or if the texture + * isn't mutable. + */ struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer, struct wl_resource *resource, pixman_region32_t *damage); From 18bbe2d897345fba022fb7032d6f285d67090dd6 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Fri, 8 Jun 2018 20:25:36 -0400 Subject: [PATCH 31/43] Fix atti assert in wlr_egl_init --- render/egl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render/egl.c b/render/egl.c index 7717b805..eafaebd7 100644 --- a/render/egl.c +++ b/render/egl.c @@ -190,7 +190,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, } attribs[atti++] = EGL_NONE; - assert(atti < sizeof(attribs)/sizeof(attribs[0])); + assert(atti <= sizeof(attribs)/sizeof(attribs[0])); egl->context = eglCreateContext(egl->display, egl->config, EGL_NO_CONTEXT, attribs); From 5ec6d8230d4df137dff722bf4d72f73b0be4c8e6 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Sat, 9 Jun 2018 11:35:07 +0200 Subject: [PATCH 32/43] Split eglSwapBuffersWithDamage feature detection Detecting whether eglSwapBuffersWithDamageEXT or eglSwapBuffersWithDamageKHR is used should be based on the extension string, not only on the availability of the function. --- include/wlr/render/egl.h | 1 + render/egl.c | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 55086755..91f8f4c0 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -22,6 +22,7 @@ struct wlr_egl { bool dmabuf_import; bool image_base; bool swap_buffers_with_damage; + bool swap_buffers_with_damage_khr; } exts; struct wl_display *wl_display; diff --git a/render/egl.c b/render/egl.c index eafaebd7..61d3af1a 100644 --- a/render/egl.c +++ b/render/egl.c @@ -154,7 +154,8 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, check_egl_ext(egl->exts_str, "EGL_EXT_buffer_age"); egl->exts.swap_buffers_with_damage = (check_egl_ext(egl->exts_str, "EGL_EXT_swap_buffers_with_damage") && - eglSwapBuffersWithDamageEXT) || + eglSwapBuffersWithDamageEXT); + egl->exts.swap_buffers_with_damage_khr = (check_egl_ext(egl->exts_str, "EGL_KHR_swap_buffers_with_damage") && eglSwapBuffersWithDamageKHR); @@ -313,7 +314,8 @@ bool wlr_egl_is_current(struct wlr_egl *egl) { bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, pixman_region32_t *damage) { EGLBoolean ret; - if (damage != NULL && egl->exts.swap_buffers_with_damage) { + if (damage != NULL && (egl->exts.swap_buffers_with_damage || + egl->exts.swap_buffers_with_damage_khr)) { int nrects; pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); @@ -325,8 +327,7 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, egl_damage[4*i + 3] = rects[i].y2 - rects[i].y1; } - assert(eglSwapBuffersWithDamageEXT || eglSwapBuffersWithDamageKHR); - if (eglSwapBuffersWithDamageEXT) { + if (egl->exts.swap_buffers_with_damage) { ret = eglSwapBuffersWithDamageEXT(egl->display, surface, egl_damage, nrects); } else { From f1a62a3200ef78e2d70035862c9b5a86bae27e21 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Sat, 9 Jun 2018 18:56:04 +0200 Subject: [PATCH 33/43] Rename egl.exts to match the extension names --- include/wlr/render/egl.h | 12 ++++++------ render/egl.c | 40 ++++++++++++++++++++-------------------- render/gles2/texture.c | 2 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 91f8f4c0..0f591d60 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -16,12 +16,12 @@ struct wlr_egl { const char *exts_str; struct { - bool bind_wayland_display; - bool buffer_age; - bool dmabuf_import_modifiers; - bool dmabuf_import; - bool image_base; - bool swap_buffers_with_damage; + bool bind_wayland_display_wl; + bool buffer_age_ext; + bool image_dmabuf_import_modifiers_ext; + bool image_dmabuf_import_ext; + bool image_base_khr; + bool swap_buffers_with_damage_ext; bool swap_buffers_with_damage_khr; } exts; diff --git a/render/egl.c b/render/egl.c index 61d3af1a..450562db 100644 --- a/render/egl.c +++ b/render/egl.c @@ -77,7 +77,7 @@ static bool check_egl_ext(const char *exts, const char *ext) { static void print_dmabuf_formats(struct wlr_egl *egl) { /* Avoid log msg if extension is not present */ - if (!egl->exts.dmabuf_import_modifiers) { + if (!egl->exts.image_dmabuf_import_modifiers_ext) { return; } @@ -146,27 +146,27 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, wlr_log(L_INFO, "Supported EGL extensions: %s", egl->exts_str); wlr_log(L_INFO, "EGL vendor: %s", eglQueryString(egl->display, EGL_VENDOR)); - egl->exts.image_base = + egl->exts.image_base_khr = check_egl_ext(egl->exts_str, "EGL_KHR_image_base") && eglCreateImageKHR && eglDestroyImageKHR; - egl->exts.buffer_age = + egl->exts.buffer_age_ext = check_egl_ext(egl->exts_str, "EGL_EXT_buffer_age"); - egl->exts.swap_buffers_with_damage = + egl->exts.swap_buffers_with_damage_ext = (check_egl_ext(egl->exts_str, "EGL_EXT_swap_buffers_with_damage") && eglSwapBuffersWithDamageEXT); egl->exts.swap_buffers_with_damage_khr = (check_egl_ext(egl->exts_str, "EGL_KHR_swap_buffers_with_damage") && eglSwapBuffersWithDamageKHR); - egl->exts.dmabuf_import = + egl->exts.image_dmabuf_import_ext = check_egl_ext(egl->exts_str, "EGL_EXT_image_dma_buf_import"); - egl->exts.dmabuf_import_modifiers = + egl->exts.image_dmabuf_import_modifiers_ext = check_egl_ext(egl->exts_str, "EGL_EXT_image_dma_buf_import_modifiers") && eglQueryDmaBufFormatsEXT && eglQueryDmaBufModifiersEXT; print_dmabuf_formats(egl); - egl->exts.bind_wayland_display = + egl->exts.bind_wayland_display_wl = check_egl_ext(egl->exts_str, "EGL_WL_bind_wayland_display") && eglBindWaylandDisplayWL && eglUnbindWaylandDisplayWL && eglQueryWaylandBufferWL; @@ -235,7 +235,7 @@ void wlr_egl_finish(struct wlr_egl *egl) { eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (egl->wl_display) { - assert(egl->exts.bind_wayland_display); + assert(egl->exts.bind_wayland_display_wl); eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); } @@ -245,7 +245,7 @@ void wlr_egl_finish(struct wlr_egl *egl) { } bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) { - if (!egl->exts.bind_wayland_display) { + if (!egl->exts.bind_wayland_display_wl) { return false; } @@ -258,7 +258,7 @@ bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) } bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImage image) { - if (!egl->exts.image_base) { + if (!egl->exts.image_base_khr) { return false; } if (!image) { @@ -279,7 +279,7 @@ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) { } static int egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) { - if (!egl->exts.buffer_age) { + if (!egl->exts.buffer_age_ext) { return -1; } @@ -314,7 +314,7 @@ bool wlr_egl_is_current(struct wlr_egl *egl) { bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, pixman_region32_t *damage) { EGLBoolean ret; - if (damage != NULL && (egl->exts.swap_buffers_with_damage || + if (damage != NULL && (egl->exts.swap_buffers_with_damage_ext || egl->exts.swap_buffers_with_damage_khr)) { int nrects; pixman_box32_t *rects = @@ -327,7 +327,7 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, egl_damage[4*i + 3] = rects[i].y2 - rects[i].y1; } - if (egl->exts.swap_buffers_with_damage) { + if (egl->exts.swap_buffers_with_damage_ext) { ret = eglSwapBuffersWithDamageEXT(egl->display, surface, egl_damage, nrects); } else { @@ -348,7 +348,7 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, struct wl_resource *data, EGLint *fmt, int *width, int *height, bool *inverted_y) { - if (!egl->exts.bind_wayland_display || !egl->exts.image_base) { + if (!egl->exts.bind_wayland_display_wl || !egl->exts.image_base_khr) { return NULL; } @@ -377,13 +377,13 @@ EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_attributes *attributes) { - if (!egl->exts.image_base) { + if (!egl->exts.image_base_khr) { return NULL; } bool has_modifier = false; if (attributes->modifier != DRM_FORMAT_MOD_INVALID) { - if (!egl->exts.dmabuf_import_modifiers) { + if (!egl->exts.image_dmabuf_import_modifiers_ext) { return NULL; } has_modifier = true; @@ -455,8 +455,8 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats) { - if (!egl->exts.dmabuf_import || - !egl->exts.dmabuf_import_modifiers) { + if (!egl->exts.image_dmabuf_import_ext || + !egl->exts.image_dmabuf_import_modifiers_ext) { wlr_log(L_DEBUG, "dmabuf extension not present"); return -1; } @@ -483,8 +483,8 @@ int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format, uint64_t **modifiers) { - if (!egl->exts.dmabuf_import || - !egl->exts.dmabuf_import_modifiers) { + if (!egl->exts.image_dmabuf_import_ext || + !egl->exts.image_dmabuf_import_modifiers_ext) { wlr_log(L_DEBUG, "dmabuf extension not present"); return -1; } diff --git a/render/gles2/texture.c b/render/gles2/texture.c index ca1398e8..da98a523 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -210,7 +210,7 @@ struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl, return NULL; } - if (!egl->exts.dmabuf_import) { + if (!egl->exts.image_dmabuf_import_ext) { wlr_log(L_ERROR, "Cannot create DMA-BUF texture: EGL extension " "unavailable"); return NULL; From 38d415dd2047114badd6a9f65dab6fe0b5b8e5d0 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 11 Jun 2018 08:13:35 +0100 Subject: [PATCH 34/43] buffer: make wlr_buffer_ref return the buffer --- include/wlr/types/wlr_buffer.h | 2 +- types/wlr_buffer.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h index c57d79ed..fc348a1c 100644 --- a/include/wlr/types/wlr_buffer.h +++ b/include/wlr/types/wlr_buffer.h @@ -36,7 +36,7 @@ struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, /** * Reference the buffer. */ -void wlr_buffer_ref(struct wlr_buffer *buffer); +struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer); /** * Unreference the buffer. After this call, `buffer` may not be accessed * anymore. diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c index e062df4c..82a359f0 100644 --- a/types/wlr_buffer.c +++ b/types/wlr_buffer.c @@ -105,8 +105,9 @@ struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, return buffer; } -void wlr_buffer_ref(struct wlr_buffer *buffer) { +struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer) { buffer->n_refs++; + return buffer; } void wlr_buffer_unref(struct wlr_buffer *buffer) { From 6f29db10446662ac6741e4a63bac74380f01199e Mon Sep 17 00:00:00 2001 From: NeKit Date: Wed, 13 Jun 2018 13:43:01 +0300 Subject: [PATCH 35/43] gles2 renderer: introduce struct wlr_gles2_tex_shader --- include/render/gles2.h | 32 +++++++++++--------------------- render/gles2/renderer.c | 34 +++++++++------------------------- 2 files changed, 20 insertions(+), 46 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index c47751d1..67d4e9f5 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -25,6 +25,14 @@ struct wlr_gles2_pixel_format { bool has_alpha; }; +struct wlr_gles2_tex_shader { + GLuint program; + GLint proj; + GLint invert_y; + GLint tex; + GLint alpha; +}; + struct wlr_gles2_renderer { struct wlr_renderer wlr_renderer; @@ -42,27 +50,9 @@ struct wlr_gles2_renderer { GLint proj; GLint color; } ellipse; - struct { - GLuint program; - GLint proj; - GLint invert_y; - GLint tex; - GLint alpha; - } tex_rgba; - struct { - GLuint program; - GLint proj; - GLint invert_y; - GLint tex; - GLint alpha; - } tex_rgbx; - struct { - GLuint program; - GLint proj; - GLint invert_y; - GLint tex; - GLint alpha; - } tex_ext; + struct wlr_gles2_tex_shader tex_rgba; + struct wlr_gles2_tex_shader tex_rgbx; + struct wlr_gles2_tex_shader tex_ext; } shaders; uint32_t viewport_width, viewport_height; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index dce59d88..05426fa9 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -118,38 +118,22 @@ static bool gles2_render_texture_with_matrix(struct wlr_renderer *wlr_renderer, struct wlr_gles2_texture *texture = get_gles2_texture_in_context(wlr_texture); - GLuint prog = 0; + struct wlr_gles2_tex_shader *shader = NULL; GLenum target = 0; - GLint proj_loc = 0; - GLint invert_y_loc = 0; - GLint tex_loc = 0; - GLint alpha_loc = 0; switch (texture->type) { case WLR_GLES2_TEXTURE_GLTEX: case WLR_GLES2_TEXTURE_WL_DRM_GL: if (texture->has_alpha) { - prog = renderer->shaders.tex_rgba.program; - proj_loc = renderer->shaders.tex_rgba.proj; - invert_y_loc = renderer->shaders.tex_rgba.invert_y; - tex_loc = renderer->shaders.tex_rgba.tex; - alpha_loc = renderer->shaders.tex_rgba.alpha; + shader = &renderer->shaders.tex_rgba; } else { - prog = renderer->shaders.tex_rgbx.program; - proj_loc = renderer->shaders.tex_rgbx.proj; - invert_y_loc = renderer->shaders.tex_rgbx.invert_y; - tex_loc = renderer->shaders.tex_rgbx.tex; - alpha_loc = renderer->shaders.tex_rgbx.alpha; + shader = &renderer->shaders.tex_rgbx; } target = GL_TEXTURE_2D; break; case WLR_GLES2_TEXTURE_WL_DRM_EXT: case WLR_GLES2_TEXTURE_DMABUF: - prog = renderer->shaders.tex_ext.program; - proj_loc = renderer->shaders.tex_ext.proj; - invert_y_loc = renderer->shaders.tex_ext.invert_y; - tex_loc = renderer->shaders.tex_ext.tex; - alpha_loc = renderer->shaders.tex_ext.alpha; + shader = &renderer->shaders.tex_ext; target = GL_TEXTURE_EXTERNAL_OES; break; } @@ -169,12 +153,12 @@ static bool gles2_render_texture_with_matrix(struct wlr_renderer *wlr_renderer, glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glUseProgram(prog); + glUseProgram(shader->program); - glUniformMatrix3fv(proj_loc, 1, GL_FALSE, transposition); - glUniform1i(invert_y_loc, texture->inverted_y); - glUniform1f(alpha_loc, alpha); - glUniform1i(tex_loc, 0); + glUniformMatrix3fv(shader->proj, 1, GL_FALSE, transposition); + glUniform1i(shader->invert_y, texture->inverted_y); + glUniform1i(shader->tex, 0); + glUniform1f(shader->alpha, alpha); draw_quad(); From 0378d143d9517c7508b64b81e9267a29ab1951aa Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 13 Jun 2018 19:38:10 +0100 Subject: [PATCH 36/43] surface: remove wlr_surface.texture The texture is managed by the surface's wlr_buffer now. In particular, the buffer can destroy the texture early if it becomes invalid. --- include/wlr/types/wlr_buffer.h | 11 +++++++++-- include/wlr/types/wlr_surface.h | 14 +++++++++++++- rootston/output.c | 6 +++--- types/wlr_output.c | 10 +++++----- types/wlr_surface.c | 12 ++++++++---- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h index fc348a1c..eabc8b51 100644 --- a/include/wlr/types/wlr_buffer.h +++ b/include/wlr/types/wlr_buffer.h @@ -8,8 +8,15 @@ * A client buffer. */ struct wlr_buffer { - struct wl_resource *resource; // can be NULL - struct wlr_texture *texture; // can be NULL + /** + * The buffer resource, if any. Will be NULL if the client destroys it. + */ + struct wl_resource *resource; + /** + * The buffer's texture, if any. A buffer will not have a texture if the + * client destroys the buffer before it has been released. + */ + struct wlr_texture *texture; bool released; size_t n_refs; diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 64503e78..8517934a 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -69,8 +69,13 @@ struct wlr_subsurface { struct wlr_surface { struct wl_resource *resource; struct wlr_renderer *renderer; + /** + * The surface's buffer, if any. A surface has an attached buffer when it + * commits with a non-null buffer in its pending state. A surface will not + * have a buffer if it has never committed one, has committed a null buffer, + * or something went wrong with uploading the buffer. + */ struct wlr_buffer *buffer; - struct wlr_texture *texture; struct wlr_surface_state *current, *pending; const char *role; // the lifetime-bound role or null @@ -125,6 +130,13 @@ int wlr_surface_set_role(struct wlr_surface *surface, const char *role, */ bool wlr_surface_has_buffer(struct wlr_surface *surface); +/** + * Get the texture of the buffer currently attached to this surface. Returns + * NULL if no buffer is currently attached or if something went wrong with + * uploading the buffer. + */ +struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface); + /** * Create a new subsurface resource with the provided new ID. If `resource_list` * is non-NULL, adds the subsurface's resource to the list. diff --git a/rootston/output.c b/rootston/output.c index faa808d1..353d431f 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -189,7 +189,8 @@ static void render_surface(struct wlr_surface *surface, int sx, int sy, struct roots_output *output = data->output; float rotation = data->layout.rotation; - if (!wlr_surface_has_buffer(surface)) { + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (texture == NULL) { return; } @@ -230,8 +231,7 @@ static void render_surface(struct wlr_surface *surface, int sx, int sy, pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); - wlr_render_texture_with_matrix(renderer, surface->texture, matrix, - data->alpha); + wlr_render_texture_with_matrix(renderer, texture, matrix, data->alpha); } damage_finish: diff --git a/types/wlr_output.c b/types/wlr_output.c index a5a6d0eb..7befb651 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -367,7 +367,8 @@ static void output_fullscreen_surface_render(struct wlr_output *output, struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); assert(renderer); - if (!wlr_surface_has_buffer(surface)) { + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (texture == NULL) { wlr_renderer_clear(renderer, (float[]){0, 0, 0, 1}); return; } @@ -386,8 +387,7 @@ static void output_fullscreen_surface_render(struct wlr_output *output, for (int i = 0; i < nrects; ++i) { output_scissor(output, &rects[i]); wlr_renderer_clear(renderer, (float[]){0, 0, 0, 1}); - wlr_render_texture_with_matrix(surface->renderer, surface->texture, - matrix, 1.0f); + wlr_render_texture_with_matrix(surface->renderer, texture, matrix, 1.0f); } wlr_renderer_scissor(renderer, NULL); @@ -418,7 +418,7 @@ static void output_cursor_render(struct wlr_output_cursor *cursor, struct wlr_texture *texture = cursor->texture; if (cursor->surface != NULL) { - texture = cursor->surface->texture; + texture = wlr_surface_get_texture(cursor->surface); } if (texture == NULL) { return; @@ -700,7 +700,7 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) { enum wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; struct wlr_texture *texture = cursor->texture; if (cursor->surface != NULL) { - texture = cursor->surface->texture; + texture = wlr_surface_get_texture(cursor->surface); scale = cursor->surface->current->scale; transform = cursor->surface->current->transform; } diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 7d8da02f..af1e9446 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -332,7 +332,6 @@ static void surface_apply_damage(struct wlr_surface *surface, // NULL commit wlr_buffer_unref(surface->buffer); surface->buffer = NULL; - surface->texture = NULL; return; } @@ -362,7 +361,6 @@ static void surface_apply_damage(struct wlr_surface *surface, wlr_buffer_unref(surface->buffer); surface->buffer = NULL; - surface->texture = NULL; struct wlr_buffer *buffer = wlr_buffer_create(surface->renderer, resource); if (buffer == NULL) { @@ -371,7 +369,6 @@ static void surface_apply_damage(struct wlr_surface *surface, } surface->buffer = buffer; - surface->texture = buffer->texture; } static void surface_commit_pending(struct wlr_surface *surface) { @@ -660,8 +657,15 @@ struct wlr_surface *wlr_surface_create(struct wl_client *client, return surface; } +struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface) { + if (surface->buffer == NULL) { + return NULL; + } + return surface->buffer->texture; +} + bool wlr_surface_has_buffer(struct wlr_surface *surface) { - return surface->texture != NULL; + return wlr_surface_get_texture(surface) != NULL; } int wlr_surface_set_role(struct wlr_surface *surface, const char *role, From d27eeaa14c9a35c709f09de862aa6d4f0ef9ff83 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Wed, 13 Jun 2018 19:57:42 -0400 Subject: [PATCH 37/43] Revert "Merge pull request #1050 from emersion/wlr-buffer" This reverts commit 5e4af4862e7247528eda0891c11daa1d86786c86, reversing changes made to 9a1f0e2d5fe56870f3bd7d12113742766e89f4e6. --- include/wlr/types/wlr_buffer.h | 56 ---------- include/wlr/types/wlr_surface.h | 1 - types/meson.build | 1 - types/wlr_buffer.c | 187 -------------------------------- types/wlr_surface.c | 137 ++++++++++++++++------- 5 files changed, 97 insertions(+), 285 deletions(-) delete mode 100644 include/wlr/types/wlr_buffer.h delete mode 100644 types/wlr_buffer.c diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h deleted file mode 100644 index fc348a1c..00000000 --- a/include/wlr/types/wlr_buffer.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef WLR_TYPES_WLR_BUFFER_H -#define WLR_TYPES_WLR_BUFFER_H - -#include -#include - -/** - * A client buffer. - */ -struct wlr_buffer { - struct wl_resource *resource; // can be NULL - struct wlr_texture *texture; // can be NULL - bool released; - size_t n_refs; - - struct wl_listener resource_destroy; -}; - -struct wlr_renderer; - -/** - * Check if a resource is a wl_buffer resource. - */ -bool wlr_resource_is_buffer(struct wl_resource *resource); -/** - * Get the size of a wl_buffer resource. - */ -bool wlr_buffer_get_resource_size(struct wl_resource *resource, - struct wlr_renderer *renderer, int *width, int *height); - -/** - * Upload a buffer to the GPU and reference it. - */ -struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, - struct wl_resource *resource); -/** - * Reference the buffer. - */ -struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer); -/** - * Unreference the buffer. After this call, `buffer` may not be accessed - * anymore. - */ -void wlr_buffer_unref(struct wlr_buffer *buffer); -/** - * Try to update the buffer's content. On success, returns the updated buffer - * and destroys the provided `buffer`. On error, `buffer` is intact and NULL is - * returned. - * - * Fails if there's more than one reference to the buffer or if the texture - * isn't mutable. - */ -struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer, - struct wl_resource *resource, pixman_region32_t *damage); - -#endif diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 64503e78..526e4e2c 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -69,7 +69,6 @@ struct wlr_subsurface { struct wlr_surface { struct wl_resource *resource; struct wlr_renderer *renderer; - struct wlr_buffer *buffer; struct wlr_texture *texture; struct wlr_surface_state *current, *pending; const char *role; // the lifetime-bound role or null diff --git a/types/meson.build b/types/meson.build index 87f21c55..f9f5b469 100644 --- a/types/meson.build +++ b/types/meson.build @@ -20,7 +20,6 @@ lib_wlr_types = static_library( 'xdg_shell_v6/wlr_xdg_surface_v6.c', 'xdg_shell_v6/wlr_xdg_toplevel_v6.c', 'wlr_box.c', - 'wlr_buffer.c', 'wlr_compositor.c', 'wlr_cursor.c', 'wlr_gamma_control.c', diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c deleted file mode 100644 index 82a359f0..00000000 --- a/types/wlr_buffer.c +++ /dev/null @@ -1,187 +0,0 @@ -#include -#include -#include -#include -#include -#include - -bool wlr_resource_is_buffer(struct wl_resource *resource) { - return strcmp(wl_resource_get_class(resource), wl_buffer_interface.name) == 0; -} - -bool wlr_buffer_get_resource_size(struct wl_resource *resource, - struct wlr_renderer *renderer, int *width, int *height) { - assert(wlr_resource_is_buffer(resource)); - - struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource); - if (shm_buf != NULL) { - *width = wl_shm_buffer_get_width(shm_buf); - *height = wl_shm_buffer_get_height(shm_buf); - } else if (wlr_renderer_resource_is_wl_drm_buffer(renderer, - resource)) { - wlr_renderer_wl_drm_buffer_get_size(renderer, resource, - width, height); - } else if (wlr_dmabuf_resource_is_buffer(resource)) { - struct wlr_dmabuf_buffer *dmabuf = - wlr_dmabuf_buffer_from_buffer_resource(resource); - *width = dmabuf->attributes.width; - *height = dmabuf->attributes.height; - } else { - *width = *height = 0; - return false; - } - - return true; -} - - -static void buffer_resource_handle_destroy(struct wl_listener *listener, - void *data) { - struct wlr_buffer *buffer = - wl_container_of(listener, buffer, resource_destroy); - wl_list_remove(&buffer->resource_destroy.link); - wl_list_init(&buffer->resource_destroy.link); - buffer->resource = NULL; - - if (!buffer->released) { - // The texture becomes invalid - wlr_texture_destroy(buffer->texture); - buffer->texture = NULL; - } -} - -struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, - struct wl_resource *resource) { - assert(wlr_resource_is_buffer(resource)); - - struct wlr_texture *texture = NULL; - bool released = false; - - struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource); - if (shm_buf != NULL) { - enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buf); - int32_t stride = wl_shm_buffer_get_stride(shm_buf); - int32_t width = wl_shm_buffer_get_width(shm_buf); - int32_t height = wl_shm_buffer_get_height(shm_buf); - - wl_shm_buffer_begin_access(shm_buf); - void *data = wl_shm_buffer_get_data(shm_buf); - texture = wlr_texture_from_pixels(renderer, fmt, stride, - width, height, data); - wl_shm_buffer_end_access(shm_buf); - - // We have uploaded the data, we don't need to access the wl_buffer - // anymore - wl_buffer_send_release(resource); - released = true; - } else if (wlr_renderer_resource_is_wl_drm_buffer(renderer, resource)) { - texture = wlr_texture_from_wl_drm(renderer, resource); - } else if (wlr_dmabuf_resource_is_buffer(resource)) { - struct wlr_dmabuf_buffer *dmabuf = - wlr_dmabuf_buffer_from_buffer_resource(resource); - texture = wlr_texture_from_dmabuf(renderer, &dmabuf->attributes); - } else { - wlr_log(L_ERROR, "Cannot upload texture: unknown buffer type"); - return NULL; - } - - if (texture == NULL) { - wlr_log(L_ERROR, "Failed to upload texture"); - return NULL; - } - - struct wlr_buffer *buffer = calloc(1, sizeof(struct wlr_buffer)); - if (buffer == NULL) { - return NULL; - } - buffer->resource = resource; - buffer->texture = texture; - buffer->released = released; - buffer->n_refs = 1; - - wl_resource_add_destroy_listener(resource, &buffer->resource_destroy); - buffer->resource_destroy.notify = buffer_resource_handle_destroy; - - return buffer; -} - -struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer) { - buffer->n_refs++; - return buffer; -} - -void wlr_buffer_unref(struct wlr_buffer *buffer) { - if (buffer == NULL) { - return; - } - - assert(buffer->n_refs > 0); - buffer->n_refs--; - if (buffer->n_refs > 0) { - return; - } - - if (!buffer->released && buffer->resource != NULL) { - wl_buffer_send_release(buffer->resource); - } - - wl_list_remove(&buffer->resource_destroy.link); - wlr_texture_destroy(buffer->texture); - free(buffer); -} - -struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer, - struct wl_resource *resource, pixman_region32_t *damage) { - assert(wlr_resource_is_buffer(resource)); - - if (buffer->n_refs > 1) { - // Someone else still has a reference to the buffer - return NULL; - } - - struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource); - if (shm_buf == NULL) { - // Uploading only damaged regions only works for wl_shm buffers - return NULL; - } - - enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buf); - int32_t stride = wl_shm_buffer_get_stride(shm_buf); - int32_t width = wl_shm_buffer_get_width(shm_buf); - int32_t height = wl_shm_buffer_get_height(shm_buf); - - int32_t texture_width, texture_height; - wlr_texture_get_size(buffer->texture, &texture_width, &texture_height); - if (width != texture_width || height != texture_height) { - return NULL; - } - - wl_shm_buffer_begin_access(shm_buf); - void *data = wl_shm_buffer_get_data(shm_buf); - - int n; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &n); - for (int i = 0; i < n; ++i) { - pixman_box32_t *r = &rects[i]; - if (!wlr_texture_write_pixels(buffer->texture, fmt, stride, - r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1, - r->x1, r->y1, data)) { - wl_shm_buffer_end_access(shm_buf); - return NULL; - } - } - - wl_shm_buffer_end_access(shm_buf); - - // We have uploaded the data, we don't need to access the wl_buffer - // anymore - wl_buffer_send_release(resource); - - wl_list_remove(&buffer->resource_destroy.link); - wl_resource_add_destroy_listener(resource, &buffer->resource_destroy); - buffer->resource_destroy.notify = buffer_resource_handle_destroy; - - buffer->resource = resource; - buffer->released = true; - return buffer; -} diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 7d8da02f..fca4e847 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -1,9 +1,10 @@ #include #include #include +#include #include -#include #include +#include #include #include #include @@ -45,6 +46,13 @@ static void surface_handle_buffer_destroy(struct wl_listener *listener, surface_state_reset_buffer(state); } +static void surface_state_release_buffer(struct wlr_surface_state *state) { + if (state->buffer) { + wl_buffer_send_release(state->buffer); + surface_state_reset_buffer(state); + } +} + static void surface_state_set_buffer(struct wlr_surface_state *state, struct wl_resource *buffer) { surface_state_reset_buffer(state); @@ -167,8 +175,24 @@ static bool surface_update_size(struct wlr_surface *surface, int scale = state->scale; enum wl_output_transform transform = state->transform; - wlr_buffer_get_resource_size(state->buffer, surface->renderer, - &state->buffer_width, &state->buffer_height); + struct wl_shm_buffer *buf = wl_shm_buffer_get(state->buffer); + if (buf != NULL) { + state->buffer_width = wl_shm_buffer_get_width(buf); + state->buffer_height = wl_shm_buffer_get_height(buf); + } else if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer, + state->buffer)) { + wlr_renderer_wl_drm_buffer_get_size(surface->renderer, state->buffer, + &state->buffer_width, &state->buffer_height); + } else if (wlr_dmabuf_resource_is_buffer(state->buffer)) { + struct wlr_dmabuf_buffer *dmabuf = + wlr_dmabuf_buffer_from_buffer_resource(state->buffer); + state->buffer_width = dmabuf->attributes.width; + state->buffer_height = dmabuf->attributes.height; + } else { + wlr_log(L_ERROR, "Unknown buffer handle attached"); + state->buffer_width = 0; + state->buffer_height = 0; + } int width = state->buffer_width / scale; int height = state->buffer_height / scale; @@ -219,6 +243,7 @@ static void surface_move_state(struct wlr_surface *surface, update_size = true; } if ((next->invalid & WLR_SURFACE_INVALID_BUFFER)) { + surface_state_release_buffer(state); surface_state_set_buffer(state, next->buffer); surface_state_reset_buffer(next); state->sx = next->sx; @@ -326,60 +351,91 @@ static void surface_damage_subsurfaces(struct wlr_subsurface *subsurface) { } static void surface_apply_damage(struct wlr_surface *surface, - bool invalid_buffer) { + bool invalid_buffer, bool reupload_buffer) { struct wl_resource *resource = surface->current->buffer; if (resource == NULL) { - // NULL commit - wlr_buffer_unref(surface->buffer); - surface->buffer = NULL; - surface->texture = NULL; return; } - if (surface->buffer != NULL && !surface->buffer->released && - !invalid_buffer) { - // The buffer is still the same, no need to re-upload - return; - } + struct wl_shm_buffer *buf = wl_shm_buffer_get(resource); + if (buf != NULL) { + wl_shm_buffer_begin_access(buf); - if (surface->buffer != NULL && surface->buffer->released) { - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_copy(&damage, &surface->current->buffer_damage); - pixman_region32_intersect_rect(&damage, &damage, 0, 0, - surface->current->buffer_width, surface->current->buffer_height); + enum wl_shm_format fmt = wl_shm_buffer_get_format(buf); + int32_t stride = wl_shm_buffer_get_stride(buf); + int32_t width = wl_shm_buffer_get_width(buf); + int32_t height = wl_shm_buffer_get_height(buf); + void *data = wl_shm_buffer_get_data(buf); - struct wlr_buffer *updated_buffer = - wlr_buffer_apply_damage(surface->buffer, resource, &damage); + if (surface->texture == NULL || reupload_buffer) { + wlr_texture_destroy(surface->texture); + surface->texture = wlr_texture_from_pixels(surface->renderer, fmt, + stride, width, height, data); + } else { + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, &surface->current->buffer_damage); + pixman_region32_intersect_rect(&damage, &damage, 0, 0, + surface->current->buffer_width, + surface->current->buffer_height); - pixman_region32_fini(&damage); + int n; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &n); + for (int i = 0; i < n; ++i) { + pixman_box32_t *r = &rects[i]; + if (!wlr_texture_write_pixels(surface->texture, fmt, stride, + r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1, + r->x1, r->y1, data)) { + break; + } + } - if (updated_buffer != NULL) { - surface->buffer = updated_buffer; - return; + pixman_region32_fini(&damage); } + + wl_shm_buffer_end_access(buf); + + // We've uploaded the wl_shm_buffer data to the GPU, we won't access the + // wl_buffer anymore + surface_state_release_buffer(surface->current); + } else if (invalid_buffer || reupload_buffer) { + wlr_texture_destroy(surface->texture); + + if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer, resource)) { + surface->texture = + wlr_texture_from_wl_drm(surface->renderer, resource); + } else if (wlr_dmabuf_resource_is_buffer(resource)) { + struct wlr_dmabuf_buffer *dmabuf = + wlr_dmabuf_buffer_from_buffer_resource(resource); + surface->texture = + wlr_texture_from_dmabuf(surface->renderer, &dmabuf->attributes); + } else { + surface->texture = NULL; + wlr_log(L_ERROR, "Unknown buffer handle attached"); + } + + // Don't release the wl_buffer yet: since the texture is shared with the + // client, we'll access the wl_buffer when rendering } - - wlr_buffer_unref(surface->buffer); - surface->buffer = NULL; - surface->texture = NULL; - - struct wlr_buffer *buffer = wlr_buffer_create(surface->renderer, resource); - if (buffer == NULL) { - wlr_log(L_ERROR, "Failed to upload buffer"); - return; - } - - surface->buffer = buffer; - surface->texture = buffer->texture; } static void surface_commit_pending(struct wlr_surface *surface) { + int32_t oldw = surface->current->buffer_width; + int32_t oldh = surface->current->buffer_height; + bool invalid_buffer = surface->pending->invalid & WLR_SURFACE_INVALID_BUFFER; + bool null_buffer_commit = invalid_buffer && surface->pending->buffer == NULL; surface_move_state(surface, surface->pending, surface->current); - surface_apply_damage(surface, invalid_buffer); + if (null_buffer_commit) { + wlr_texture_destroy(surface->texture); + surface->texture = NULL; + } + + bool reupload_buffer = oldw != surface->current->buffer_width || + oldh != surface->current->buffer_height; + surface_apply_damage(surface, invalid_buffer, reupload_buffer); // commit subsurface order struct wlr_subsurface *subsurface; @@ -601,9 +657,10 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(surface->resource)); wl_list_remove(&surface->renderer_destroy.link); + wlr_texture_destroy(surface->texture); surface_state_destroy(surface->pending); surface_state_destroy(surface->current); - wlr_buffer_unref(surface->buffer); + free(surface); } From 3a2ef75d3af98e2a6e87c12b3236ff63769f8bde Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 14 Jun 2018 08:51:38 +0100 Subject: [PATCH 38/43] Add back wlr_buffer This reverts commit d27eeaa14c9a35c709f09de862aa6d4f0ef9ff83. --- include/wlr/types/wlr_buffer.h | 56 ++++++++++ include/wlr/types/wlr_surface.h | 1 + types/meson.build | 1 + types/wlr_buffer.c | 187 ++++++++++++++++++++++++++++++++ types/wlr_surface.c | 147 ++++++++----------------- 5 files changed, 290 insertions(+), 102 deletions(-) create mode 100644 include/wlr/types/wlr_buffer.h create mode 100644 types/wlr_buffer.c diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h new file mode 100644 index 00000000..fc348a1c --- /dev/null +++ b/include/wlr/types/wlr_buffer.h @@ -0,0 +1,56 @@ +#ifndef WLR_TYPES_WLR_BUFFER_H +#define WLR_TYPES_WLR_BUFFER_H + +#include +#include + +/** + * A client buffer. + */ +struct wlr_buffer { + struct wl_resource *resource; // can be NULL + struct wlr_texture *texture; // can be NULL + bool released; + size_t n_refs; + + struct wl_listener resource_destroy; +}; + +struct wlr_renderer; + +/** + * Check if a resource is a wl_buffer resource. + */ +bool wlr_resource_is_buffer(struct wl_resource *resource); +/** + * Get the size of a wl_buffer resource. + */ +bool wlr_buffer_get_resource_size(struct wl_resource *resource, + struct wlr_renderer *renderer, int *width, int *height); + +/** + * Upload a buffer to the GPU and reference it. + */ +struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, + struct wl_resource *resource); +/** + * Reference the buffer. + */ +struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer); +/** + * Unreference the buffer. After this call, `buffer` may not be accessed + * anymore. + */ +void wlr_buffer_unref(struct wlr_buffer *buffer); +/** + * Try to update the buffer's content. On success, returns the updated buffer + * and destroys the provided `buffer`. On error, `buffer` is intact and NULL is + * returned. + * + * Fails if there's more than one reference to the buffer or if the texture + * isn't mutable. + */ +struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer, + struct wl_resource *resource, pixman_region32_t *damage); + +#endif diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 526e4e2c..64503e78 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -69,6 +69,7 @@ struct wlr_subsurface { struct wlr_surface { struct wl_resource *resource; struct wlr_renderer *renderer; + struct wlr_buffer *buffer; struct wlr_texture *texture; struct wlr_surface_state *current, *pending; const char *role; // the lifetime-bound role or null diff --git a/types/meson.build b/types/meson.build index f9f5b469..87f21c55 100644 --- a/types/meson.build +++ b/types/meson.build @@ -20,6 +20,7 @@ lib_wlr_types = static_library( 'xdg_shell_v6/wlr_xdg_surface_v6.c', 'xdg_shell_v6/wlr_xdg_toplevel_v6.c', 'wlr_box.c', + 'wlr_buffer.c', 'wlr_compositor.c', 'wlr_cursor.c', 'wlr_gamma_control.c', diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c new file mode 100644 index 00000000..82a359f0 --- /dev/null +++ b/types/wlr_buffer.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include + +bool wlr_resource_is_buffer(struct wl_resource *resource) { + return strcmp(wl_resource_get_class(resource), wl_buffer_interface.name) == 0; +} + +bool wlr_buffer_get_resource_size(struct wl_resource *resource, + struct wlr_renderer *renderer, int *width, int *height) { + assert(wlr_resource_is_buffer(resource)); + + struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource); + if (shm_buf != NULL) { + *width = wl_shm_buffer_get_width(shm_buf); + *height = wl_shm_buffer_get_height(shm_buf); + } else if (wlr_renderer_resource_is_wl_drm_buffer(renderer, + resource)) { + wlr_renderer_wl_drm_buffer_get_size(renderer, resource, + width, height); + } else if (wlr_dmabuf_resource_is_buffer(resource)) { + struct wlr_dmabuf_buffer *dmabuf = + wlr_dmabuf_buffer_from_buffer_resource(resource); + *width = dmabuf->attributes.width; + *height = dmabuf->attributes.height; + } else { + *width = *height = 0; + return false; + } + + return true; +} + + +static void buffer_resource_handle_destroy(struct wl_listener *listener, + void *data) { + struct wlr_buffer *buffer = + wl_container_of(listener, buffer, resource_destroy); + wl_list_remove(&buffer->resource_destroy.link); + wl_list_init(&buffer->resource_destroy.link); + buffer->resource = NULL; + + if (!buffer->released) { + // The texture becomes invalid + wlr_texture_destroy(buffer->texture); + buffer->texture = NULL; + } +} + +struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, + struct wl_resource *resource) { + assert(wlr_resource_is_buffer(resource)); + + struct wlr_texture *texture = NULL; + bool released = false; + + struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource); + if (shm_buf != NULL) { + enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buf); + int32_t stride = wl_shm_buffer_get_stride(shm_buf); + int32_t width = wl_shm_buffer_get_width(shm_buf); + int32_t height = wl_shm_buffer_get_height(shm_buf); + + wl_shm_buffer_begin_access(shm_buf); + void *data = wl_shm_buffer_get_data(shm_buf); + texture = wlr_texture_from_pixels(renderer, fmt, stride, + width, height, data); + wl_shm_buffer_end_access(shm_buf); + + // We have uploaded the data, we don't need to access the wl_buffer + // anymore + wl_buffer_send_release(resource); + released = true; + } else if (wlr_renderer_resource_is_wl_drm_buffer(renderer, resource)) { + texture = wlr_texture_from_wl_drm(renderer, resource); + } else if (wlr_dmabuf_resource_is_buffer(resource)) { + struct wlr_dmabuf_buffer *dmabuf = + wlr_dmabuf_buffer_from_buffer_resource(resource); + texture = wlr_texture_from_dmabuf(renderer, &dmabuf->attributes); + } else { + wlr_log(L_ERROR, "Cannot upload texture: unknown buffer type"); + return NULL; + } + + if (texture == NULL) { + wlr_log(L_ERROR, "Failed to upload texture"); + return NULL; + } + + struct wlr_buffer *buffer = calloc(1, sizeof(struct wlr_buffer)); + if (buffer == NULL) { + return NULL; + } + buffer->resource = resource; + buffer->texture = texture; + buffer->released = released; + buffer->n_refs = 1; + + wl_resource_add_destroy_listener(resource, &buffer->resource_destroy); + buffer->resource_destroy.notify = buffer_resource_handle_destroy; + + return buffer; +} + +struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer) { + buffer->n_refs++; + return buffer; +} + +void wlr_buffer_unref(struct wlr_buffer *buffer) { + if (buffer == NULL) { + return; + } + + assert(buffer->n_refs > 0); + buffer->n_refs--; + if (buffer->n_refs > 0) { + return; + } + + if (!buffer->released && buffer->resource != NULL) { + wl_buffer_send_release(buffer->resource); + } + + wl_list_remove(&buffer->resource_destroy.link); + wlr_texture_destroy(buffer->texture); + free(buffer); +} + +struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer, + struct wl_resource *resource, pixman_region32_t *damage) { + assert(wlr_resource_is_buffer(resource)); + + if (buffer->n_refs > 1) { + // Someone else still has a reference to the buffer + return NULL; + } + + struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource); + if (shm_buf == NULL) { + // Uploading only damaged regions only works for wl_shm buffers + return NULL; + } + + enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buf); + int32_t stride = wl_shm_buffer_get_stride(shm_buf); + int32_t width = wl_shm_buffer_get_width(shm_buf); + int32_t height = wl_shm_buffer_get_height(shm_buf); + + int32_t texture_width, texture_height; + wlr_texture_get_size(buffer->texture, &texture_width, &texture_height); + if (width != texture_width || height != texture_height) { + return NULL; + } + + wl_shm_buffer_begin_access(shm_buf); + void *data = wl_shm_buffer_get_data(shm_buf); + + int n; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &n); + for (int i = 0; i < n; ++i) { + pixman_box32_t *r = &rects[i]; + if (!wlr_texture_write_pixels(buffer->texture, fmt, stride, + r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1, + r->x1, r->y1, data)) { + wl_shm_buffer_end_access(shm_buf); + return NULL; + } + } + + wl_shm_buffer_end_access(shm_buf); + + // We have uploaded the data, we don't need to access the wl_buffer + // anymore + wl_buffer_send_release(resource); + + wl_list_remove(&buffer->resource_destroy.link); + wl_resource_add_destroy_listener(resource, &buffer->resource_destroy); + buffer->resource_destroy.notify = buffer_resource_handle_destroy; + + buffer->resource = resource; + buffer->released = true; + return buffer; +} diff --git a/types/wlr_surface.c b/types/wlr_surface.c index fca4e847..7d8da02f 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -1,10 +1,9 @@ #include #include #include -#include #include +#include #include -#include #include #include #include @@ -46,13 +45,6 @@ static void surface_handle_buffer_destroy(struct wl_listener *listener, surface_state_reset_buffer(state); } -static void surface_state_release_buffer(struct wlr_surface_state *state) { - if (state->buffer) { - wl_buffer_send_release(state->buffer); - surface_state_reset_buffer(state); - } -} - static void surface_state_set_buffer(struct wlr_surface_state *state, struct wl_resource *buffer) { surface_state_reset_buffer(state); @@ -175,24 +167,8 @@ static bool surface_update_size(struct wlr_surface *surface, int scale = state->scale; enum wl_output_transform transform = state->transform; - struct wl_shm_buffer *buf = wl_shm_buffer_get(state->buffer); - if (buf != NULL) { - state->buffer_width = wl_shm_buffer_get_width(buf); - state->buffer_height = wl_shm_buffer_get_height(buf); - } else if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer, - state->buffer)) { - wlr_renderer_wl_drm_buffer_get_size(surface->renderer, state->buffer, - &state->buffer_width, &state->buffer_height); - } else if (wlr_dmabuf_resource_is_buffer(state->buffer)) { - struct wlr_dmabuf_buffer *dmabuf = - wlr_dmabuf_buffer_from_buffer_resource(state->buffer); - state->buffer_width = dmabuf->attributes.width; - state->buffer_height = dmabuf->attributes.height; - } else { - wlr_log(L_ERROR, "Unknown buffer handle attached"); - state->buffer_width = 0; - state->buffer_height = 0; - } + wlr_buffer_get_resource_size(state->buffer, surface->renderer, + &state->buffer_width, &state->buffer_height); int width = state->buffer_width / scale; int height = state->buffer_height / scale; @@ -243,7 +219,6 @@ static void surface_move_state(struct wlr_surface *surface, update_size = true; } if ((next->invalid & WLR_SURFACE_INVALID_BUFFER)) { - surface_state_release_buffer(state); surface_state_set_buffer(state, next->buffer); surface_state_reset_buffer(next); state->sx = next->sx; @@ -351,91 +326,60 @@ static void surface_damage_subsurfaces(struct wlr_subsurface *subsurface) { } static void surface_apply_damage(struct wlr_surface *surface, - bool invalid_buffer, bool reupload_buffer) { + bool invalid_buffer) { struct wl_resource *resource = surface->current->buffer; if (resource == NULL) { + // NULL commit + wlr_buffer_unref(surface->buffer); + surface->buffer = NULL; + surface->texture = NULL; return; } - struct wl_shm_buffer *buf = wl_shm_buffer_get(resource); - if (buf != NULL) { - wl_shm_buffer_begin_access(buf); - - enum wl_shm_format fmt = wl_shm_buffer_get_format(buf); - int32_t stride = wl_shm_buffer_get_stride(buf); - int32_t width = wl_shm_buffer_get_width(buf); - int32_t height = wl_shm_buffer_get_height(buf); - void *data = wl_shm_buffer_get_data(buf); - - if (surface->texture == NULL || reupload_buffer) { - wlr_texture_destroy(surface->texture); - surface->texture = wlr_texture_from_pixels(surface->renderer, fmt, - stride, width, height, data); - } else { - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_copy(&damage, &surface->current->buffer_damage); - pixman_region32_intersect_rect(&damage, &damage, 0, 0, - surface->current->buffer_width, - surface->current->buffer_height); - - int n; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &n); - for (int i = 0; i < n; ++i) { - pixman_box32_t *r = &rects[i]; - if (!wlr_texture_write_pixels(surface->texture, fmt, stride, - r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1, - r->x1, r->y1, data)) { - break; - } - } - - pixman_region32_fini(&damage); - } - - wl_shm_buffer_end_access(buf); - - // We've uploaded the wl_shm_buffer data to the GPU, we won't access the - // wl_buffer anymore - surface_state_release_buffer(surface->current); - } else if (invalid_buffer || reupload_buffer) { - wlr_texture_destroy(surface->texture); - - if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer, resource)) { - surface->texture = - wlr_texture_from_wl_drm(surface->renderer, resource); - } else if (wlr_dmabuf_resource_is_buffer(resource)) { - struct wlr_dmabuf_buffer *dmabuf = - wlr_dmabuf_buffer_from_buffer_resource(resource); - surface->texture = - wlr_texture_from_dmabuf(surface->renderer, &dmabuf->attributes); - } else { - surface->texture = NULL; - wlr_log(L_ERROR, "Unknown buffer handle attached"); - } - - // Don't release the wl_buffer yet: since the texture is shared with the - // client, we'll access the wl_buffer when rendering + if (surface->buffer != NULL && !surface->buffer->released && + !invalid_buffer) { + // The buffer is still the same, no need to re-upload + return; } + + if (surface->buffer != NULL && surface->buffer->released) { + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, &surface->current->buffer_damage); + pixman_region32_intersect_rect(&damage, &damage, 0, 0, + surface->current->buffer_width, surface->current->buffer_height); + + struct wlr_buffer *updated_buffer = + wlr_buffer_apply_damage(surface->buffer, resource, &damage); + + pixman_region32_fini(&damage); + + if (updated_buffer != NULL) { + surface->buffer = updated_buffer; + return; + } + } + + wlr_buffer_unref(surface->buffer); + surface->buffer = NULL; + surface->texture = NULL; + + struct wlr_buffer *buffer = wlr_buffer_create(surface->renderer, resource); + if (buffer == NULL) { + wlr_log(L_ERROR, "Failed to upload buffer"); + return; + } + + surface->buffer = buffer; + surface->texture = buffer->texture; } static void surface_commit_pending(struct wlr_surface *surface) { - int32_t oldw = surface->current->buffer_width; - int32_t oldh = surface->current->buffer_height; - bool invalid_buffer = surface->pending->invalid & WLR_SURFACE_INVALID_BUFFER; - bool null_buffer_commit = invalid_buffer && surface->pending->buffer == NULL; surface_move_state(surface, surface->pending, surface->current); - if (null_buffer_commit) { - wlr_texture_destroy(surface->texture); - surface->texture = NULL; - } - - bool reupload_buffer = oldw != surface->current->buffer_width || - oldh != surface->current->buffer_height; - surface_apply_damage(surface, invalid_buffer, reupload_buffer); + surface_apply_damage(surface, invalid_buffer); // commit subsurface order struct wlr_subsurface *subsurface; @@ -657,10 +601,9 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(surface->resource)); wl_list_remove(&surface->renderer_destroy.link); - wlr_texture_destroy(surface->texture); surface_state_destroy(surface->pending); surface_state_destroy(surface->current); - + wlr_buffer_unref(surface->buffer); free(surface); } From 47985d2dc56a6af469ac9375e7548136765aff16 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Thu, 14 Jun 2018 20:46:16 +1200 Subject: [PATCH 39/43] Multiseat fixes --- backend/libinput/backend.c | 4 +-- backend/session/direct.c | 60 +++++++++++++++++++++-------------- backend/session/logind.c | 5 +++ backend/session/session.c | 4 +-- include/wlr/backend/session.h | 6 +++- 5 files changed, 50 insertions(+), 29 deletions(-) diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index f4d54c97..1dde5854 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -55,8 +55,8 @@ static bool backend_start(struct wlr_backend *_backend) { return false; } - // TODO: Let user customize seat used - if (libinput_udev_assign_seat(backend->libinput_context, "seat0") != 0) { + if (libinput_udev_assign_seat(backend->libinput_context, + backend->session->seat) != 0) { wlr_log(L_ERROR, "Failed to assign libinput seat"); return false; } diff --git a/backend/session/direct.c b/backend/session/direct.c index 13a26d99..c1a59647 100644 --- a/backend/session/direct.c +++ b/backend/session/direct.c @@ -1,5 +1,6 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include #include #include @@ -76,30 +77,39 @@ static void direct_session_close(struct wlr_session *base, int fd) { static bool direct_change_vt(struct wlr_session *base, unsigned vt) { struct direct_session *session = wl_container_of(base, session, base); + + // Only seat0 has VTs associated with it + if (strcmp(session->base.seat, "seat0") == 0) { + return true; + } + return ioctl(session->tty_fd, VT_ACTIVATE, (int)vt) == 0; } static void direct_session_destroy(struct wlr_session *base) { struct direct_session *session = wl_container_of(base, session, base); - struct vt_mode mode = { - .mode = VT_AUTO, - }; - errno = 0; + if (strcmp(session->base.seat, "seat0") == 0) { + struct vt_mode mode = { + .mode = VT_AUTO, + }; + errno = 0; - ioctl(session->tty_fd, KDSKBMODE, session->old_kbmode); - ioctl(session->tty_fd, KDSETMODE, KD_TEXT); - ioctl(session->tty_fd, VT_SETMODE, &mode); + ioctl(session->tty_fd, KDSKBMODE, session->old_kbmode); + ioctl(session->tty_fd, KDSETMODE, KD_TEXT); + ioctl(session->tty_fd, VT_SETMODE, &mode); - if (errno) { - wlr_log(L_ERROR, "Failed to restore tty"); + if (errno) { + wlr_log(L_ERROR, "Failed to restore tty"); + } + + wl_event_source_remove(session->vt_source); + close(session->tty_fd); } direct_ipc_finish(session->sock, session->child); close(session->sock); - wl_event_source_remove(session->vt_source); - close(session->tty_fd); free(session); } @@ -138,19 +148,19 @@ static int vt_handler(int signo, void *data) { } static bool setup_tty(struct direct_session *session, struct wl_display *display) { - int fd = dup(STDIN_FILENO); + int fd = open("/dev/tty", O_RDWR); if (fd == -1) { - wlr_log_errno(L_ERROR, "Cannot open tty"); + wlr_log_errno(L_ERROR, "Cannot open /dev/tty"); return false; } - struct stat st; - if (fstat(fd, &st) == -1 || major(st.st_rdev) != TTY_MAJOR || minor(st.st_rdev) == 0) { - wlr_log(L_ERROR, "Not running from a virtual terminal"); + struct vt_stat vt_stat; + if (ioctl(fd, VT_GETSTATE, &vt_stat)) { + wlr_log_errno(L_ERROR, "Could not get current tty number"); goto error; } - int tty = minor(st.st_rdev); + int tty = vt_stat.v_active; int ret, kd_mode, old_kbmode; ret = ioctl(fd, KDGETMODE, &kd_mode); @@ -224,20 +234,24 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { goto error_session; } - if (!setup_tty(session, disp)) { - goto error_ipc; - } - - // XXX: Is it okay to trust the environment like this? const char *seat = getenv("XDG_SEAT"); if (!seat) { seat = "seat0"; } - wlr_log(L_INFO, "Successfully loaded direct session"); + if (strcmp(seat, "seat0") == 0) { + if (!setup_tty(session, disp)) { + goto error_ipc; + } + } else { + session->base.vtnr = 0; + session->tty_fd = -1; + } snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat); session->base.impl = &session_direct; + + wlr_log(L_INFO, "Successfully loaded direct session"); return &session->base; error_ipc: diff --git a/backend/session/logind.c b/backend/session/logind.c index f0ac1e93..3a3cc57d 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -109,6 +109,11 @@ static void logind_release_device(struct wlr_session *base, int fd) { static bool logind_change_vt(struct wlr_session *base, unsigned vt) { struct logind_session *session = wl_container_of(base, session, base); + // Only seat0 has VTs associated with it + if (strcmp(session->base.seat, "seat0") != 0) { + return true; + } + int ret; sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; diff --git a/backend/session/session.c b/backend/session/session.c index 2d5d9776..026040fd 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -19,9 +19,7 @@ extern const struct session_impl session_logind; extern const struct session_impl session_direct; static const struct session_impl *impls[] = { -#ifdef WLR_HAS_SYSTEMD - &session_logind, -#elif defined(WLR_HAS_ELOGIND) +#if defined(WLR_HAS_SYSTEMD) || defined(WLR_HAS_ELOGIND) &session_logind, #endif &session_direct, diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 4d04b363..1cf41939 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -25,8 +25,12 @@ struct wlr_session { struct wl_signal session_signal; bool active; + /* + * 0 if virtual terminals are not supported + * i.e. seat != "seat0" + */ unsigned vtnr; - char seat[8]; + char seat[256]; struct udev *udev; struct udev_monitor *mon; From 964e0a50beabe03d84f042209fc019909b631e05 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Thu, 14 Jun 2018 21:02:32 +1200 Subject: [PATCH 40/43] Check for seat0 properly --- backend/session/direct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/session/direct.c b/backend/session/direct.c index c1a59647..7fa7d05b 100644 --- a/backend/session/direct.c +++ b/backend/session/direct.c @@ -79,7 +79,7 @@ static bool direct_change_vt(struct wlr_session *base, unsigned vt) { struct direct_session *session = wl_container_of(base, session, base); // Only seat0 has VTs associated with it - if (strcmp(session->base.seat, "seat0") == 0) { + if (strcmp(session->base.seat, "seat0") != 0) { return true; } From da114d501322fe2f1698d19a11d6dc298000dfe4 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 14 Jun 2018 10:15:14 +0100 Subject: [PATCH 41/43] buffer: don't destroy DMA-BUF textures with wl_buffer After some discussions on #wayland, it seems that as soon as you hold a reference to a DMA-BUF (via EGLImage for instance), the underlying memory won't get free'd. The client is allowed to re-use the DMA-BUF and upload something else to it though. --- types/wlr_buffer.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c index 82a359f0..ccff7b46 100644 --- a/types/wlr_buffer.c +++ b/types/wlr_buffer.c @@ -43,11 +43,12 @@ static void buffer_resource_handle_destroy(struct wl_listener *listener, wl_list_init(&buffer->resource_destroy.link); buffer->resource = NULL; - if (!buffer->released) { - // The texture becomes invalid - wlr_texture_destroy(buffer->texture); - buffer->texture = NULL; - } + // At this point, if the wl_buffer comes from linux-dmabuf or wl_drm, we + // still haven't released it (ie. we'll read it in the future) but the + // client destroyed it. Reading the texture itself should be fine because + // we still hold a reference to the DMA-BUF via the texture. However the + // client could decide to re-use the same DMA-BUF for something else, in + // which case we'll read garbage. We decide to accept this risk. } struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, @@ -80,6 +81,10 @@ struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, struct wlr_dmabuf_buffer *dmabuf = wlr_dmabuf_buffer_from_buffer_resource(resource); texture = wlr_texture_from_dmabuf(renderer, &dmabuf->attributes); + + // We have imported the DMA-BUF, but we need to prevent the client from + // re-using the same DMA-BUF for the next frames, so we don't release + // the buffer yet. } else { wlr_log(L_ERROR, "Cannot upload texture: unknown buffer type"); return NULL; From 23707f65040546d4594e458ab5068c0bccc31bd0 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Sat, 16 Jun 2018 17:29:26 +0300 Subject: [PATCH 42/43] layer-shell: check whether the surface is mapped in layer_surface_destroy() If the layer surface has been closed by the compositor, using layer_surface_close(), then the unmap event is emitted. However, when the layer surface is later destroyed by the client, the compositor used to get a second unmap, which is fixed with this commit. --- types/wlr_layer_shell.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/types/wlr_layer_shell.c b/types/wlr_layer_shell.c index e64d7937..76d6d721 100644 --- a/types/wlr_layer_shell.c +++ b/types/wlr_layer_shell.c @@ -176,7 +176,9 @@ static void layer_surface_unmap(struct wlr_layer_surface *surface) { } static void layer_surface_destroy(struct wlr_layer_surface *surface) { - layer_surface_unmap(surface); + if (surface->configured && surface->mapped) { + layer_surface_unmap(surface); + } wlr_signal_emit_safe(&surface->events.destroy, surface); wl_resource_set_user_data(surface->resource, NULL); wl_list_remove(&surface->surface_destroy_listener.link); From 225aa815b00502c2d91897c1ac2c4c5c65f82ca5 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Jun 2018 19:01:13 +0100 Subject: [PATCH 43/43] buffer: fix wlr_texture leak on failed alloc --- types/wlr_buffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c index ccff7b46..673d7088 100644 --- a/types/wlr_buffer.c +++ b/types/wlr_buffer.c @@ -97,6 +97,7 @@ struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, struct wlr_buffer *buffer = calloc(1, sizeof(struct wlr_buffer)); if (buffer == NULL) { + wlr_texture_destroy(texture); return NULL; } buffer->resource = resource;