From 7864f26d73aa478a163f801a63f9d6cca4704410 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 19 Dec 2021 16:39:57 +0100 Subject: [PATCH 01/14] backend: error out in autocreate without libinput support The libinput backend is now optional. However, this means that a user building wlroots without the correct libinput dependencies will end up with a compositor which doesn't respond to input events. wlr_backend_autocreate is supposed to return a sensible setup, so in this case let's just error out and explain what happened. Users can suppress the check by setting WLR_LIBINPUT_NO_DEVICES=1 (already used to suppress the zero input device case inside the libinput backend). Compositors which really want to create a bare DRM backend can easily create it manually instead of using wlr_backend_autocreate. (cherry picked from commit ec2845750862cc0b175bef59de4305f6da91960a) --- backend/backend.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/backend/backend.c b/backend/backend.c index 24150b13..bfb43ba0 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -364,6 +364,19 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { return NULL; } wlr_multi_backend_add(backend, libinput); +#else + const char *no_devs = getenv("WLR_LIBINPUT_NO_DEVICES"); + if (no_devs && strcmp(no_devs, "1") == 0) { + wlr_log(WLR_INFO, "WLR_LIBINPUT_NO_DEVICES is set, " + "starting without libinput backend"); + } else { + wlr_log(WLR_ERROR, "libinput support is not compiled in, " + "refusing to start"); + wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check"); + wlr_session_destroy(multi->session); + wlr_backend_destroy(backend); + return NULL; + } #endif #if WLR_HAS_DRM_BACKEND From 4b358c2f91146f30533ec6492abbd63643181608 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 20 Dec 2021 20:41:44 +0000 Subject: [PATCH 02/14] wlr_texture: remove wlr_texture_from_wl_drm() from header This function was already removed in e5b5592a but it was forgotten to remove it from the header. (cherry picked from commit 823476e76ed166762095330a8f51eabc825febff) --- include/wlr/render/wlr_texture.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 3495c443..1dbcba1d 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -33,16 +33,6 @@ struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer, uint32_t fmt, uint32_t stride, uint32_t width, uint32_t height, const void *data); -/** - * Create a new texture from a wl_drm resource. The returned texture is - * immutable. - * - * Should not be called in a rendering block like renderer_begin()/end() or - * between attaching a renderer to an output and committing it. - */ -struct wlr_texture *wlr_texture_from_wl_drm(struct wlr_renderer *renderer, - struct wl_resource *data); - /** * Create a new texture from a DMA-BUF. The returned texture is immutable. * From df945b665c008d9faefd55ccb6af34e434fb4bbe Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 23 Dec 2021 16:30:24 +0100 Subject: [PATCH 03/14] scene: schedule an output frame on wl_surface.frame Some clients (e.g. mpv, Firefox) request a new wl_surface.frame callback without damaging their surface. When this happens, schedule a new output frame. Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3350 (cherry picked from commit 812951f5bc47f502429406e49f4e24f377b7799b) --- types/scene/wlr_scene.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 7b550963..a0c06b6b 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -236,10 +236,6 @@ static void scene_surface_handle_surface_commit(struct wl_listener *listener, wl_container_of(listener, scene_surface, surface_commit); struct wlr_surface *surface = scene_surface->surface; - if (!pixman_region32_not_empty(&surface->buffer_damage)) { - return; - } - struct wlr_scene *scene = scene_node_get_root(&scene_surface->node); int lx, ly; @@ -256,6 +252,17 @@ static void scene_surface_handle_surface_commit(struct wl_listener *listener, return; } + // Even if the surface hasn't submitted damage, schedule a new frame if + // the client has requested a wl_surface.frame callback. + if (!wl_list_empty(&surface->current.frame_callback_list) && + scene_surface->primary_output != NULL) { + wlr_output_schedule_frame(scene_surface->primary_output); + } + + if (!pixman_region32_not_empty(&surface->buffer_damage)) { + return; + } + struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { struct wlr_output *output = scene_output->output; From a59a957f2b1d3c759f0eafdd8e970e667b0ca9c7 Mon Sep 17 00:00:00 2001 From: nyorain Date: Sun, 26 Dec 2021 13:21:54 +0100 Subject: [PATCH 04/14] vulkan: Fix imported image layout (cherry picked from commit 9988eb3378dbc3301059aa9b5e1ff476354cb92b) --- render/vulkan/renderer.c | 2 +- render/vulkan/texture.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index a1d8d41e..21b36bdd 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -598,7 +598,7 @@ static void vulkan_end(struct wlr_renderer *wlr_renderer) { wl_list_for_each_safe(texture, tmp_tex, &renderer->foreign_textures, foreign_link) { VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL; if (!texture->transitioned) { - src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED; + src_layout = VK_IMAGE_LAYOUT_UNDEFINED; texture->transitioned = true; } diff --git a/render/vulkan/texture.c b/render/vulkan/texture.c index 76c37011..b705603c 100644 --- a/render/vulkan/texture.c +++ b/render/vulkan/texture.c @@ -438,7 +438,7 @@ VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer, img_info.arrayLayers = 1; img_info.samples = VK_SAMPLE_COUNT_1_BIT; img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - img_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; img_info.extent = (VkExtent3D) { attribs->width, attribs->height, 1 }; img_info.usage = for_render ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : From ea77cc5cb2a8ba287b1c737771d17028dc7cfcc3 Mon Sep 17 00:00:00 2001 From: Thomas Hebb Date: Wed, 5 Jan 2022 00:16:59 -0800 Subject: [PATCH 05/14] render/gles2: don't constrain shm formats to ones that support reading commit 44e8451cd93e ("render/gles2: hide shm formats without GL support") added the is_gles2_pixel_format_supported() function to render/gles2/pixel_format.c, whose stated purpose is to "check whether the renderer has the needed GL extensions to read a given pixel format." It then used that function to filter the pixel formats returned by get_gles2_shm_formats(). The result of this change is that RGB formats are no longer reported for GL drivers that don't implement EXT_read_format_bgra, even when those formats are supported for rendering (which they have to be for wlr_gles2_renderer_create() to succeed). This is a pretty clear regression, since wlr_renderer_init_wl_shm() fails when either of WL_SHM_FORMAT_ARGB8888 or WL_SHM_FORMAT_XRGB8888 are missing. To fix the regression, change is_gles2_pixel_format_supported() to accept all pixel formats that support rendering, regardless of whether we can read them or not, and move the check for EXT_read_format_bgra back into gles2_read_pixels(). (There's already a check for this extension in gles2_preferred_read_format(), so we're not breaking any abstraction that wasn't already broken.) Tested on the NVIDIA 495.46 proprietary driver, which doesn't support EXT_read_format_bgra. Fixes: 44e8451cd93e ("render/gles2: hide shm formats without GL support") (cherry picked from commit 59b9518f072527ac59593e51df7f5d5331a34f0e) --- render/gles2/pixel_format.c | 14 ++++++++++---- render/gles2/renderer.c | 6 ++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/render/gles2/pixel_format.c b/render/gles2/pixel_format.c index 31bb3908..b155bbbe 100644 --- a/render/gles2/pixel_format.c +++ b/render/gles2/pixel_format.c @@ -98,6 +98,10 @@ static const struct wlr_gles2_pixel_format formats[] = { // TODO: more pixel formats +/* + * Return true if supported for texturing, even if other operations like + * reading aren't supported. + */ bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer, const struct wlr_gles2_pixel_format *format) { if (format->gl_type == GL_UNSIGNED_INT_2_10_10_10_REV_EXT @@ -108,10 +112,12 @@ bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer, && !renderer->exts.OES_texture_half_float_linear) { return false; } - if (format->gl_format == GL_BGRA_EXT - && !renderer->exts.EXT_read_format_bgra) { - return false; - } + /* + * Note that we don't need to check for GL_EXT_texture_format_BGRA8888 + * here, since we've already checked if we have it at renderer creation + * time and bailed out if not. We do the check there because Wayland + * requires all compositors to support SHM buffers in that format. + */ return true; } diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 527d85bf..67b8ead4 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -441,6 +441,12 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, return false; } + if (fmt->gl_format == GL_BGRA_EXT && !renderer->exts.EXT_read_format_bgra) { + wlr_log(WLR_ERROR, + "Cannot read pixels: missing GL_EXT_read_format_bgra extension"); + return false; + } + const struct wlr_pixel_format_info *drm_fmt = drm_get_pixel_format_info(fmt->drm_format); assert(drm_fmt); From 7dde2b66d681f40ca8ad7cb7facbad3772f9fa8b Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 1 Jan 2022 14:04:53 +0300 Subject: [PATCH 06/14] scene/subsurface_tree: fix handling subsurface destruction This commit renames map/unmap listeners to clarify that they handle subsurface events, and ensures the node is always destroyed before the subsurface. Without this patch, wl_list_remove() would operate on listener links in already freed memory. glibc is usually lenient to bugs like this, but musl isn't. (cherry picked from commit 83ab5055fd36bd0f8a0106257e45d8ed303636d8) --- types/scene/subsurface_tree.c | 65 +++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/types/scene/subsurface_tree.c b/types/scene/subsurface_tree.c index 3f22ee3d..bb3c7ff7 100644 --- a/types/scene/subsurface_tree.c +++ b/types/scene/subsurface_tree.c @@ -13,15 +13,20 @@ struct wlr_scene_subsurface_tree { struct wlr_surface *surface; struct wlr_scene_surface *scene_surface; - struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface - struct wlr_addon surface_addon; // only set if there's a parent - struct wl_listener tree_destroy; struct wl_listener surface_destroy; struct wl_listener surface_commit; - struct wl_listener surface_map; - struct wl_listener surface_unmap; struct wl_listener surface_new_subsurface; + + struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface + + // Only valid if the surface is a sub-surface + + struct wlr_addon surface_addon; + + struct wl_listener subsurface_destroy; + struct wl_listener subsurface_map; + struct wl_listener subsurface_unmap; }; static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, @@ -31,23 +36,17 @@ static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, // tree and scene_surface will be cleaned up by scene_node_finish if (subsurface_tree->parent) { wlr_addon_finish(&subsurface_tree->surface_addon); + wl_list_remove(&subsurface_tree->subsurface_destroy.link); + wl_list_remove(&subsurface_tree->subsurface_map.link); + wl_list_remove(&subsurface_tree->subsurface_unmap.link); } wl_list_remove(&subsurface_tree->tree_destroy.link); wl_list_remove(&subsurface_tree->surface_destroy.link); wl_list_remove(&subsurface_tree->surface_commit.link); - wl_list_remove(&subsurface_tree->surface_map.link); - wl_list_remove(&subsurface_tree->surface_unmap.link); wl_list_remove(&subsurface_tree->surface_new_subsurface.link); free(subsurface_tree); } -static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener, - void *data) { - struct wlr_scene_subsurface_tree *subsurface_tree = - wl_container_of(listener, subsurface_tree, surface_destroy); - wlr_scene_node_destroy(&subsurface_tree->tree->node); -} - static const struct wlr_addon_interface subsurface_tree_addon_impl; static struct wlr_scene_subsurface_tree *subsurface_tree_from_subsurface( @@ -97,6 +96,13 @@ static void subsurface_tree_reconfigure( } } +static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, surface_destroy); + wlr_scene_node_destroy(&subsurface_tree->tree->node); +} + static void subsurface_tree_handle_surface_commit(struct wl_listener *listener, void *data) { struct wlr_scene_subsurface_tree *subsurface_tree = @@ -106,18 +112,25 @@ static void subsurface_tree_handle_surface_commit(struct wl_listener *listener, subsurface_tree_reconfigure(subsurface_tree); } -static void subsurface_tree_handle_surface_map(struct wl_listener *listener, +static void subsurface_tree_handle_subsurface_destroy(struct wl_listener *listener, void *data) { struct wlr_scene_subsurface_tree *subsurface_tree = - wl_container_of(listener, subsurface_tree, surface_map); + wl_container_of(listener, subsurface_tree, subsurface_destroy); + wlr_scene_node_destroy(&subsurface_tree->tree->node); +} + +static void subsurface_tree_handle_subsurface_map(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, subsurface_map); wlr_scene_node_set_enabled(&subsurface_tree->tree->node, true); } -static void subsurface_tree_handle_surface_unmap(struct wl_listener *listener, +static void subsurface_tree_handle_subsurface_unmap(struct wl_listener *listener, void *data) { struct wlr_scene_subsurface_tree *subsurface_tree = - wl_container_of(listener, subsurface_tree, surface_unmap); + wl_container_of(listener, subsurface_tree, subsurface_unmap); wlr_scene_node_set_enabled(&subsurface_tree->tree->node, false); } @@ -151,8 +164,14 @@ static bool subsurface_tree_create_subsurface( wlr_addon_init(&child->surface_addon, &subsurface->surface->addons, parent, &subsurface_tree_addon_impl); - wl_signal_add(&subsurface->events.map, &child->surface_map); - wl_signal_add(&subsurface->events.unmap, &child->surface_unmap); + child->subsurface_destroy.notify = subsurface_tree_handle_subsurface_destroy; + wl_signal_add(&subsurface->events.destroy, &child->subsurface_destroy); + + child->subsurface_map.notify = subsurface_tree_handle_subsurface_map; + wl_signal_add(&subsurface->events.map, &child->subsurface_map); + + child->subsurface_unmap.notify = subsurface_tree_handle_subsurface_unmap; + wl_signal_add(&subsurface->events.unmap, &child->subsurface_unmap); return true; } @@ -214,12 +233,6 @@ static struct wlr_scene_subsurface_tree *scene_surface_tree_create( subsurface_tree->surface_commit.notify = subsurface_tree_handle_surface_commit; wl_signal_add(&surface->events.commit, &subsurface_tree->surface_commit); - subsurface_tree->surface_map.notify = subsurface_tree_handle_surface_map; - wl_list_init(&subsurface_tree->surface_map.link); - - subsurface_tree->surface_unmap.notify = subsurface_tree_handle_surface_unmap; - wl_list_init(&subsurface_tree->surface_unmap.link); - subsurface_tree->surface_new_subsurface.notify = subsurface_tree_handle_surface_new_subsurface; wl_signal_add(&surface->events.new_subsurface, From b0fee56974fe9304cee4f6350ba8a301a047b583 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Thu, 30 Dec 2021 22:49:48 -0700 Subject: [PATCH 07/14] input_method_v2: improve mapping detection Detect NULL commits before the surface is actually committed, allowing the surface to be properly damaged on unmap. (cherry picked from commit 5091118bed82394de5a151d658e895bb44059b61) --- types/wlr_input_method_v2.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/types/wlr_input_method_v2.c b/types/wlr_input_method_v2.c index 7ccd31ee..f28eb191 100644 --- a/types/wlr_input_method_v2.c +++ b/types/wlr_input_method_v2.c @@ -157,9 +157,22 @@ static void popup_surface_surface_role_commit(struct wlr_surface *surface) { && popup_surface->input_method->client_active); } +static void popup_surface_surface_role_precommit(struct wlr_surface *surface) { + struct wlr_input_popup_surface_v2 *popup_surface = surface->role_data; + if (popup_surface == NULL) { + return; + } + if (surface->pending.committed & WLR_SURFACE_STATE_BUFFER && + surface->pending.buffer == NULL) { + // This is a NULL commit + popup_surface_set_mapped(popup_surface, false); + } +} + static const struct wlr_surface_role input_popup_surface_v2_role = { .name = "zwp_input_popup_surface_v2", .commit = popup_surface_surface_role_commit, + .precommit = popup_surface_surface_role_precommit, }; bool wlr_surface_is_input_popup_surface_v2(struct wlr_surface *surface) { From 304c61307aa012139a5cf4704e3dcbf22c29cc33 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 22 Jan 2022 11:35:22 +0300 Subject: [PATCH 08/14] compositor: damage the whole buffer on viewport src change wp_viewporter protocol doesn't seem to say anything about damage, but Firefox assumes that wp_viewport::set_source alone is enough to damage the whole surface, and that assumption kinda makes sense, so let's do that. (cherry picked from commit da2491d4163e1d8e627d00c8ae594c7f8003472e) --- types/wlr_surface.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index d5d49571..6a0992fe 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -207,8 +207,12 @@ static void surface_update_damage(pixman_region32_t *buffer_damage, pixman_region32_clear(buffer_damage); if (pending->width != current->width || - pending->height != current->height) { - // Damage the whole buffer on resize + pending->height != current->height || + pending->viewport.src.x != current->viewport.src.x || + pending->viewport.src.y != current->viewport.src.y || + pending->viewport.src.width != current->viewport.src.width || + pending->viewport.src.height != current->viewport.src.height) { + // Damage the whole buffer on resize or viewport source box change pixman_region32_union_rect(buffer_damage, buffer_damage, 0, 0, pending->buffer_width, pending->buffer_height); } else { @@ -491,7 +495,7 @@ static void collect_subsurface_damage_iter(struct wlr_surface *surface, static void subsurface_parent_commit(struct wlr_subsurface *subsurface) { struct wlr_surface *surface = subsurface->surface; - + bool moved = subsurface->current.x != subsurface->pending.x || subsurface->current.y != subsurface->pending.y; if (subsurface->mapped && moved) { From 68c5fa340d5c1b4134a4fd25c831fd10a92104c0 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Tue, 25 Jan 2022 22:30:36 +0300 Subject: [PATCH 09/14] subsurface: unlock cached state on commit if desynced wl_subsurface::set_desync description states: "If cached state exists when wl_surface.commit is called in desynchronized mode, the pending state is added to the cached state, and applied as a whole." This commit reintroduces an implementation of said behavior, previously removed in 7daf6da9ac05be2cb74c0983e3caee0b21db75d4. Strictly speaking, this logic isn't fully correct, as the cached state and the pending state are applied individually instead, if the cached state isn't locked by anything else. However, the end result is still the same. This commit fixes the issue with Firefox permission popups. (cherry picked from commit 77951968dc9df7214c04c33f4905a9a7aa92f60c) --- types/wlr_surface.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 6a0992fe..ac89f0a9 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -534,6 +534,9 @@ static void subsurface_commit(struct wlr_subsurface *subsurface) { } subsurface->has_cache = true; subsurface->cached_seq = wlr_surface_lock_pending(surface); + } else if (subsurface->has_cache) { + wlr_surface_unlock_cached(surface, subsurface->cached_seq); + subsurface->has_cache = false; } } From ec3780e6ea01d8f4fbd4ffeafb60298932bdef20 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 18 Jan 2022 14:27:37 +0100 Subject: [PATCH 10/14] scene: try to import buffers as textures before rendering The wlroots APIs currently don't allow importing/uploading a buffer during rendering operations. Scene-graph buffer nodes need to turn their wlr_buffer into a wlr_texture at some point. It's not always possible to do so at wlr_scene_buffer creation time because the scene-graph may have zero outputs at this point, thus no way to grab a wlr_renderer. Instead, add scene-graph buffers to a pending list and try to import them in wlr_scene_output_commit. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3354 (cherry picked from commit 3db1bcbe641b407b9f5c9e5d0a012b45aa2c6cb7) --- include/wlr/types/wlr_scene.h | 4 ++++ types/scene/wlr_scene.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index e0b370ad..8810721d 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -68,6 +68,9 @@ struct wlr_scene { // May be NULL struct wlr_presentation *presentation; struct wl_listener presentation_destroy; + + // List of buffers which need to be imported as textures + struct wl_list pending_buffers; // wlr_scene_buffer.pending_link }; /** A sub-tree in the scene-graph. */ @@ -114,6 +117,7 @@ struct wlr_scene_buffer { struct wlr_fbox src_box; int dst_width, dst_height; enum wl_output_transform transform; + struct wl_list pending_link; // wlr_scene.pending_buffers }; /** A viewport for an output in the scene-graph */ diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index a0c06b6b..797f1962 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -130,6 +130,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + wl_list_remove(&scene_buffer->pending_link); wlr_texture_destroy(scene_buffer->texture); wlr_buffer_unlock(scene_buffer->buffer); free(scene_buffer); @@ -145,6 +146,7 @@ struct wlr_scene *wlr_scene_create(void) { scene_node_init(&scene->node, WLR_SCENE_NODE_ROOT, NULL); wl_list_init(&scene->outputs); wl_list_init(&scene->presentation_destroy.link); + wl_list_init(&scene->pending_buffers); return scene; } @@ -360,6 +362,9 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, scene_node_damage_whole(&scene_buffer->node); + struct wlr_scene *scene = scene_node_get_root(parent); + wl_list_insert(&scene->pending_buffers, &scene_buffer->pending_link); + return scene_buffer; } @@ -1113,6 +1118,15 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { return true; } + // Try to import new buffers as textures + struct wlr_scene_buffer *scene_buffer, *scene_buffer_tmp; + wl_list_for_each_safe(scene_buffer, scene_buffer_tmp, + &scene_output->scene->pending_buffers, pending_link) { + scene_buffer_get_texture(scene_buffer, renderer); + wl_list_remove(&scene_buffer->pending_link); + wl_list_init(&scene_buffer->pending_link); + } + wlr_renderer_begin(renderer, output->width, output->height); int nrects; From c4824b680ab2f031df8aefcff2a200dcb3f76784 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 20 Jan 2022 09:39:13 -0500 Subject: [PATCH 11/14] xdg-foreign: Fix crash on destroy of degenerate surface I am running a custom compiled version of chromium with a patch to get it up and running on sway git at the moment, and in that development build I compiled there is a bug where the browser will crash if you try to open a file select dialog. When this crash happens, chromium will not close, but instead will remain open and impossible to close unless you send a SIGKILL signal to the process. However, sway will crash to tty when you send the SIGKILL. I have a hunch that when chromium is opening the file select dialog it is creating some sort of a xdg toplevel surface. But it freezes before it fully initializes the surface. When the SIGKILL signal is given, sway/wlroots will try to free the xdg_toplevel surface but because it hasn't fully initialized due to the frozen window, it segfaults. Don't be fooled by the assert, the assert is not firing, the surface pointer is indeed NULL here. * thread #1, name = 'sway', stop reason = signal SIGSEGV: invalid address (fault address: 0x28) frame #0: 0x00007ffff78b9041 libwlroots.so.11`wlr_xdg_toplevel_set_parent(surface=0x0000000000000000, parent=0x0000000000000000) at wlr_xdg_toplevel.c:159:37 156 157 void wlr_xdg_toplevel_set_parent(struct wlr_xdg_surface *surface, 158 struct wlr_xdg_surface *parent) { -> 159 assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); 160 assert(!parent || parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); 161 162 if (surface->toplevel->parent) { (lldb) up error: sway {0x0003442a}: DIE has DW_AT_ranges(DW_FORM_sec_offset 0x67) attribute, but range extraction failed (invalid range list offset 0x67), please file a bug and attach the file at the start of this error message error: sway {0x0003442a}: DIE has DW_AT_ranges(DW_FORM_sec_offset 0x67) attribute, but range extraction failed (invalid range list offset 0x67), please file a bug and attach the file at the start of this error message frame #1: 0x00007ffff78e176e libwlroots.so.11`destroy_imported(imported=0x000055555626d570) at wlr_xdg_foreign_v1.c:154:3 151 wl_list_for_each_safe(child, child_tmp, &imported->children, link) { 152 struct wlr_xdg_surface *xdg_child = 153 wlr_xdg_surface_from_wlr_surface(child->surface); -> 154 wlr_xdg_toplevel_set_parent(xdg_child, NULL); 155 } 156 157 wl_list_remove(&imported->exported_destroyed.link); (lldb) up frame #2: 0x00007ffff78e1b9d libwlroots.so.11`xdg_imported_handle_resource_destroy(resource=0x00005555562555a0) at wlr_xdg_foreign_v1.c:280:2 277 struct wl_resource *resource) { 278 struct wlr_xdg_imported_v1 *imported = xdg_imported_from_resource(resource); 279 if (!imported) { -> 280 return; 281 } 282 283 destroy_imported(imported); (lldb) up frame #3: 0x00007ffff794989a libwayland-server.so.0`___lldb_unnamed_symbol211 + 154 libwayland-server.so.0`___lldb_unnamed_symbol211: -> 0x7ffff794989a <+154>: andl $0x1, %r13d 0x7ffff794989e <+158>: je 0x7ffff79498b0 ; <+176> 0x7ffff79498a0 <+160>: addq $0x8, %rsp 0x7ffff79498a4 <+164>: movl $0x1, %eax (lldb) up frame #4: 0x00007ffff794fec0 libwayland-server.so.0`___lldb_unnamed_symbol290 + 64 libwayland-server.so.0`___lldb_unnamed_symbol290: -> 0x7ffff794fec0 <+64>: cmpl $0x1, %eax 0x7ffff794fec3 <+67>: jne 0x7ffff794fed3 ; <+83> 0x7ffff794fec5 <+69>: addq $0x8, %rbx 0x7ffff794fec9 <+73>: cmpq %rbx, %r13 (lldb) up frame #5: 0x00007ffff79503e0 libwayland-server.so.0`___lldb_unnamed_symbol300 + 32 libwayland-server.so.0`___lldb_unnamed_symbol300: -> 0x7ffff79503e0 <+32>: cmpl $0x1, %eax 0x7ffff79503e3 <+35>: je 0x7ffff79503f0 ; <+48> 0x7ffff79503e5 <+37>: popq %rbx 0x7ffff79503e6 <+38>: popq %r12 (lldb) up frame #6: 0x00007ffff794a30e libwayland-server.so.0`wl_client_destroy + 126 libwayland-server.so.0`wl_client_destroy: -> 0x7ffff794a30e <+126>: movq %r12, %rdi 0x7ffff794a311 <+129>: callq 0x7ffff7950150 ; ___lldb_unnamed_symbol293 0x7ffff794a317 <+135>: movq 0x8(%rbp), %rdi 0x7ffff794a31b <+139>: callq *0xdc77(%rip) (lldb) up frame #7: 0x00007ffff794a3f7 libwayland-server.so.0`___lldb_unnamed_symbol214 + 119 libwayland-server.so.0`___lldb_unnamed_symbol214: -> 0x7ffff794a3f7 <+119>: movq 0x28(%rsp), %rax 0x7ffff794a3fc <+124>: subq %fs:0x28, %rax 0x7ffff794a405 <+133>: jne 0x7ffff794a727 ; <+935> 0x7ffff794a40b <+139>: addq $0x38, %rsp (lldb) up frame #8: 0x00007ffff794d1ca libwayland-server.so.0`wl_event_loop_dispatch + 202 libwayland-server.so.0`wl_event_loop_dispatch: -> 0x7ffff794d1ca <+202>: addq $0xc, %r15 0x7ffff794d1ce <+206>: cmpq %r15, %rbp 0x7ffff794d1d1 <+209>: jne 0x7ffff794d1b8 ; <+184> 0x7ffff794d1d3 <+211>: movq 0x8(%rsp), %rcx (lldb) up frame #9: 0x00007ffff794ad37 libwayland-server.so.0`wl_display_run + 39 libwayland-server.so.0`wl_display_run: -> 0x7ffff794ad37 <+39>: movl 0x8(%rbx), %eax 0x7ffff794ad3a <+42>: testl %eax, %eax 0x7ffff794ad3c <+44>: jne 0x7ffff794ad20 ; <+16> 0x7ffff794ad3e <+46>: popq %rbx (lldb) up frame #10: 0x000055555557689a sway`server_run(server=0x00005555555f26c0) at server.c:307:2 304 wlr_backend_destroy(server->backend); 305 return false; 306 } -> 307 308 return true; 309 } 310 (lldb) up frame #11: 0x0000555555575a93 sway`main(argc=3, argv=0x00007fffffffe978) at main.c:431:2 428 swaynag_show(&config->swaynag_config_errors); 429 } 430 -> 431 server_run(&server); 432 433 shutdown: 434 sway_log(SWAY_INFO, "Shutting down sway"); (cherry picked from commit cddc1c1bd9f796709c50f4bbb300788edd42fd4f) --- types/wlr_xdg_foreign_v1.c | 7 +++++-- types/wlr_xdg_foreign_v2.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/types/wlr_xdg_foreign_v1.c b/types/wlr_xdg_foreign_v1.c index 49216e68..bb747517 100644 --- a/types/wlr_xdg_foreign_v1.c +++ b/types/wlr_xdg_foreign_v1.c @@ -33,7 +33,7 @@ static bool verify_is_toplevel(struct wl_resource *client_resource, if (wlr_surface_is_xdg_surface(surface)) { struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(surface); - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + if (xdg_surface == NULL || xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { wl_resource_post_error(client_resource, -1, "surface must be an xdg_toplevel"); return false; @@ -151,7 +151,10 @@ static void destroy_imported(struct wlr_xdg_imported_v1 *imported) { wl_list_for_each_safe(child, child_tmp, &imported->children, link) { struct wlr_xdg_surface *xdg_child = wlr_xdg_surface_from_wlr_surface(child->surface); - wlr_xdg_toplevel_set_parent(xdg_child, NULL); + + if (xdg_child != NULL) { + wlr_xdg_toplevel_set_parent(xdg_child, NULL); + } } wl_list_remove(&imported->exported_destroyed.link); diff --git a/types/wlr_xdg_foreign_v2.c b/types/wlr_xdg_foreign_v2.c index c9ef5496..7f7bff06 100644 --- a/types/wlr_xdg_foreign_v2.c +++ b/types/wlr_xdg_foreign_v2.c @@ -42,7 +42,7 @@ static bool verify_is_toplevel(struct wl_resource *client_resource, struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(surface); - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + if (xdg_surface == NULL || xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { wl_resource_post_error(client_resource, ZXDG_EXPORTER_V2_ERROR_INVALID_SURFACE, "surface must be an xdg_toplevel"); @@ -157,7 +157,10 @@ static void destroy_imported(struct wlr_xdg_imported_v2 *imported) { wl_list_for_each_safe(child, child_tmp, &imported->children, link) { struct wlr_xdg_surface *xdg_child = wlr_xdg_surface_from_wlr_surface(child->surface); - wlr_xdg_toplevel_set_parent(xdg_child, NULL); + + if (xdg_child != NULL) { + wlr_xdg_toplevel_set_parent(xdg_child, NULL); + } } wl_list_remove(&imported->exported_destroyed.link); From a819c512eca4529f13f1f0cd8bbc53f4758a8a4d Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 17 Jan 2022 19:11:08 +0100 Subject: [PATCH 12/14] foreign-toplevel: send enter if needed on output bind Currently the output enter event is never sent if the client has not yet bound the output, which happens every time the compositor creates a new output. To fix this, listen for the output bind event and inform clients as if needed. (cherry picked from commit 1bd0ea3a809bdba092ef051120bb6d32f79c0ffb) --- .../wlr_foreign_toplevel_management_v1.h | 7 +++++-- types/wlr_foreign_toplevel_management_v1.c | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_foreign_toplevel_management_v1.h b/include/wlr/types/wlr_foreign_toplevel_management_v1.h index 6ea9d47f..d9030b2e 100644 --- a/include/wlr/types/wlr_foreign_toplevel_management_v1.h +++ b/include/wlr/types/wlr_foreign_toplevel_management_v1.h @@ -36,10 +36,13 @@ enum wlr_foreign_toplevel_handle_v1_state { struct wlr_foreign_toplevel_handle_v1_output { struct wl_list link; // wlr_foreign_toplevel_handle_v1::outputs - struct wl_listener output_destroy; struct wlr_output *output; - struct wlr_foreign_toplevel_handle_v1 *toplevel; + + // private state + + struct wl_listener output_bind; + struct wl_listener output_destroy; }; struct wlr_foreign_toplevel_handle_v1 { diff --git a/types/wlr_foreign_toplevel_management_v1.c b/types/wlr_foreign_toplevel_management_v1.c index 49805ef9..742ffea0 100644 --- a/types/wlr_foreign_toplevel_management_v1.c +++ b/types/wlr_foreign_toplevel_management_v1.c @@ -256,6 +256,23 @@ static void toplevel_send_output(struct wlr_foreign_toplevel_handle_v1 *toplevel toplevel_update_idle_source(toplevel); } +static void toplevel_handle_output_bind(struct wl_listener *listener, + void *data) { + struct wlr_foreign_toplevel_handle_v1_output *toplevel_output = + wl_container_of(listener, toplevel_output, output_bind); + struct wlr_output_event_bind *event = data; + struct wl_client *client = wl_resource_get_client(event->resource); + + struct wl_resource *resource; + wl_resource_for_each(resource, &toplevel_output->toplevel->resources) { + if (wl_resource_get_client(resource) == client) { + send_output_to_resource(resource, toplevel_output->output, true); + } + } + + toplevel_update_idle_source(toplevel_output->toplevel); +} + static void toplevel_handle_output_destroy(struct wl_listener *listener, void *data) { struct wlr_foreign_toplevel_handle_v1_output *toplevel_output = @@ -285,6 +302,9 @@ void wlr_foreign_toplevel_handle_v1_output_enter( toplevel_output->toplevel = toplevel; wl_list_insert(&toplevel->outputs, &toplevel_output->link); + toplevel_output->output_bind.notify = toplevel_handle_output_bind; + wl_signal_add(&output->events.bind, &toplevel_output->output_bind); + toplevel_output->output_destroy.notify = toplevel_handle_output_destroy; wl_signal_add(&output->events.destroy, &toplevel_output->output_destroy); @@ -294,6 +314,7 @@ void wlr_foreign_toplevel_handle_v1_output_enter( static void toplevel_output_destroy( struct wlr_foreign_toplevel_handle_v1_output *toplevel_output) { wl_list_remove(&toplevel_output->link); + wl_list_remove(&toplevel_output->output_bind.link); wl_list_remove(&toplevel_output->output_destroy.link); free(toplevel_output); } From eb1a451803c2d6f8a274980f888ea9689a025e38 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 14 Jan 2022 20:46:20 +0100 Subject: [PATCH 13/14] tinywl: fix check whether client is focused or not Currently this check is too strict and denies the move/resize request if a subsurface of the client has pointer focus. (cherry picked from commit 89dc9a44968fbd3fe8a08a41858d1537ee145668) --- tinywl/tinywl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index faa0a9a1..dd442aac 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -611,7 +611,8 @@ static void begin_interactive(struct tinywl_view *view, struct tinywl_server *server = view->server; struct wlr_surface *focused_surface = server->seat->pointer_state.focused_surface; - if (view->xdg_surface->surface != focused_surface) { + if (view->xdg_surface->surface != + wlr_surface_get_root_surface(focused_surface)) { /* Deny move/resize requests from unfocused clients. */ return; } From 29938b74251e826f3778f6bf9c54974a30488cc1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 3 Feb 2022 22:19:54 +0100 Subject: [PATCH 14/14] build: bump version to 0.15.1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 681b07cc..8f0135a9 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'wlroots', 'c', - version: '0.15.0', + version: '0.15.1', license: 'MIT', meson_version: '>=0.58.1', default_options: [