From 7f87e258b2bcfd3ec85aceeb25ef9a51fbd59a19 Mon Sep 17 00:00:00 2001 From: liupeng Date: Mon, 2 Feb 2026 09:11:41 +0800 Subject: [PATCH 01/18] render/drm_syncobj: drop unnecessary drmSyncobjTimelineWait() arg Signed-off-by: liupeng --- render/drm_syncobj.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/render/drm_syncobj.c b/render/drm_syncobj.c index 912a2b6e5..38541ca98 100644 --- a/render/drm_syncobj.c +++ b/render/drm_syncobj.c @@ -167,8 +167,7 @@ bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline, etime = ETIME; #endif - uint32_t signaled_point; - int ret = drmSyncobjTimelineWait(timeline->drm_fd, &timeline->handle, &point, 1, 0, flags, &signaled_point); + int ret = drmSyncobjTimelineWait(timeline->drm_fd, &timeline->handle, &point, 1, 0, flags, NULL); if (ret != 0 && ret != -etime) { wlr_log_errno(WLR_ERROR, "drmSyncobjWait() failed"); return false; From 12c9502edfa52186248d75ae4187d268d8fd165f Mon Sep 17 00:00:00 2001 From: liupeng Date: Mon, 2 Feb 2026 09:12:39 +0800 Subject: [PATCH 02/18] render/drm_syncobj: fix function name in drmSyncobjTimelineWait() error log Signed-off-by: liupeng --- render/drm_syncobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render/drm_syncobj.c b/render/drm_syncobj.c index 38541ca98..e1a407a1e 100644 --- a/render/drm_syncobj.c +++ b/render/drm_syncobj.c @@ -169,7 +169,7 @@ bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline, int ret = drmSyncobjTimelineWait(timeline->drm_fd, &timeline->handle, &point, 1, 0, flags, NULL); if (ret != 0 && ret != -etime) { - wlr_log_errno(WLR_ERROR, "drmSyncobjWait() failed"); + wlr_log_errno(WLR_ERROR, "drmSyncobjTimelineWait() failed"); return false; } From 4fe51aa43982cafc3881b1380d7b491d245d40f5 Mon Sep 17 00:00:00 2001 From: rewine Date: Sat, 31 Jan 2026 17:59:31 +0800 Subject: [PATCH 03/18] types: Simplify wlr_keyboard_group_destroy If the wlr_keyboard_group_remove_keyboard function is expanded, the code is equivalent to: ``` wl_list_for_each_safe(device, tmp_device, &group->devices, link) { struct wlr_keyboard_group *_group = group; struct wlr_keyboard *_keyboard = device->keyboard; struct keyboard_group_device *_device, *_tmp; wl_list_for_each_safe(_device, _tmp, &_group->devices, link) { if (_device->keyboard == _keyboard) { remove_keyboard_group_device(_device); continue; } } } ``` It's just running one more loop meaninglessly. --- types/wlr_keyboard_group.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_keyboard_group.c b/types/wlr_keyboard_group.c index 0ff6d93bb..6005ba647 100644 --- a/types/wlr_keyboard_group.c +++ b/types/wlr_keyboard_group.c @@ -308,7 +308,7 @@ void wlr_keyboard_group_remove_keyboard(struct wlr_keyboard_group *group, void wlr_keyboard_group_destroy(struct wlr_keyboard_group *group) { struct keyboard_group_device *device, *tmp_device; wl_list_for_each_safe(device, tmp_device, &group->devices, link) { - wlr_keyboard_group_remove_keyboard(group, device->keyboard); + remove_keyboard_group_device(device); } // Now group->keys might not be empty if a wlr_keyboard has emitted From 98196bbd898234203a177a4e4ca553604d6ad588 Mon Sep 17 00:00:00 2001 From: rewine Date: Tue, 3 Feb 2026 21:24:32 +0800 Subject: [PATCH 04/18] wlr_cursor: add comments for signal parameters --- include/wlr/types/wlr_cursor.h | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 041f735cf..aaa18a437 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -49,30 +49,30 @@ struct wlr_cursor { * your responsibility. */ struct { - struct wl_signal motion; - struct wl_signal motion_absolute; - struct wl_signal button; - struct wl_signal axis; + struct wl_signal motion; // struct wlr_pointer_motion_event + struct wl_signal motion_absolute; // struct wlr_pointer_motion_absolute_event + struct wl_signal button; // struct wlr_pointer_button_event + struct wl_signal axis; // struct wlr_pointer_axis_event struct wl_signal frame; - struct wl_signal swipe_begin; - struct wl_signal swipe_update; - struct wl_signal swipe_end; - struct wl_signal pinch_begin; - struct wl_signal pinch_update; - struct wl_signal pinch_end; - struct wl_signal hold_begin; - struct wl_signal hold_end; + struct wl_signal swipe_begin; // struct wlr_pointer_swipe_begin_event + struct wl_signal swipe_update; // struct wlr_pointer_swipe_update_event + struct wl_signal swipe_end; // struct wlr_pointer_swipe_end_event + struct wl_signal pinch_begin; // struct wlr_pointer_pinch_begin_event + struct wl_signal pinch_update; // struct wlr_pointer_pinch_update_event + struct wl_signal pinch_end; // struct wlr_pointer_pinch_end_event + struct wl_signal hold_begin; // struct wlr_pointer_hold_begin_event + struct wl_signal hold_end; // struct wlr_pointer_hold_end_event - struct wl_signal touch_up; - struct wl_signal touch_down; - struct wl_signal touch_motion; - struct wl_signal touch_cancel; + struct wl_signal touch_up; // struct wlr_touch_up_event + struct wl_signal touch_down; // struct wlr_touch_down_event + struct wl_signal touch_motion; // struct wlr_touch_motion_event + struct wl_signal touch_cancel; // struct wlr_touch_cancel_event struct wl_signal touch_frame; - struct wl_signal tablet_tool_axis; - struct wl_signal tablet_tool_proximity; - struct wl_signal tablet_tool_tip; - struct wl_signal tablet_tool_button; + struct wl_signal tablet_tool_axis; // struct wlr_tablet_tool_axis_event + struct wl_signal tablet_tool_proximity; // struct wlr_tablet_tool_proximity_event + struct wl_signal tablet_tool_tip; // struct wlr_tablet_tool_tip_event + struct wl_signal tablet_tool_button; // struct wlr_tablet_tool_button_event } events; void *data; From 7cb4e30bfdc3f1043867aaac667ca5c47d2d1cbd Mon Sep 17 00:00:00 2001 From: rewine Date: Tue, 3 Feb 2026 21:25:50 +0800 Subject: [PATCH 05/18] wlr_cursor: fix event type in handle_tablet_tool_button --- types/wlr_cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index f2269db0f..8d0d77475 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -956,7 +956,7 @@ static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { static void handle_tablet_tool_button(struct wl_listener *listener, void *data) { - struct wlr_tablet_tool_button *event = data; + struct wlr_tablet_tool_button_event *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, tablet_tool_button); wl_signal_emit_mutable(&device->cursor->events.tablet_tool_button, event); From 90f9f59041b9d02809d4d64f45ca6ff2e61a722e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Feb 2026 00:11:35 +0100 Subject: [PATCH 06/18] xwayland: try flushing immediately in xwm_schedule_flush() wl_event_source_fd_update() goes through another event loop cycle, which delays writes. This extra cycle was introduced in 6ada67da9bb0 ("xwayland/xwm: implement somewhat asynchronous request flushing"). Try flushing the X11 WM FD immediately if we can. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/4044 --- xwayland/xwm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index c8eac2ce1..e44a11743 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -2881,5 +2882,20 @@ xcb_connection_t *wlr_xwayland_get_xwm_connection( } void xwm_schedule_flush(struct wlr_xwm *xwm) { + struct pollfd pollfd = { + .fd = xcb_get_file_descriptor(xwm->xcb_conn), + .events = POLLOUT, + }; + if (poll(&pollfd, 1, 0) < 0) { + wlr_log(WLR_ERROR, "poll() failed"); + return; + } + + // If we can write immediately, do so + if (pollfd.revents & POLLOUT) { + xcb_flush(xwm->xcb_conn); + return; + } + wl_event_source_fd_update(xwm->event_source, WL_EVENT_READABLE | WL_EVENT_WRITABLE); } From d362ed1eb9a6f3f91aff43df5b3a32c948c6a827 Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Wed, 4 Feb 2026 21:11:29 +0800 Subject: [PATCH 07/18] xwayland: fix wl_array rollback when adding selection targets Ensure mime_types and mime_types_atoms remain in sync when wl_array_add() fails. Roll back the partially added entry and free the allocated mime type to avoid leaks and inconsistent state. --- xwayland/selection/incoming.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xwayland/selection/incoming.c b/xwayland/selection/incoming.c index 72f82c279..85d7775cd 100644 --- a/xwayland/selection/incoming.c +++ b/xwayland/selection/incoming.c @@ -381,13 +381,15 @@ static bool source_get_targets(struct wlr_xwm_selection *selection, free(mime_type); break; } - *mime_type_ptr = mime_type; xcb_atom_t *atom_ptr = wl_array_add(mime_types_atoms, sizeof(*atom_ptr)); if (atom_ptr == NULL) { + mime_types->size -= sizeof(*mime_type_ptr); + free(mime_type); break; } + *mime_type_ptr = mime_type; *atom_ptr = value[i]; } } From bc11ac92ab328cc45c29dd27f114ce4af756688e Mon Sep 17 00:00:00 2001 From: rewine Date: Fri, 6 Feb 2026 10:41:42 +0800 Subject: [PATCH 08/18] ext_image_capture_source_v1: remove unused variable --- types/ext_image_capture_source_v1/scene.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/types/ext_image_capture_source_v1/scene.c b/types/ext_image_capture_source_v1/scene.c index d3bf86b6c..99d34e012 100644 --- a/types/ext_image_capture_source_v1/scene.c +++ b/types/ext_image_capture_source_v1/scene.c @@ -173,8 +173,6 @@ static void source_update_buffer_constraints(struct scene_node_source *source, } static bool output_test(struct wlr_output *output, const struct wlr_output_state *state) { - struct scene_node_source *source = wl_container_of(output, source, output); - uint32_t supported = WLR_OUTPUT_STATE_BACKEND_OPTIONAL | WLR_OUTPUT_STATE_BUFFER | From dfccf5ff02eaea45d76edb40d2f92683de190800 Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Fri, 6 Feb 2026 10:18:21 +0800 Subject: [PATCH 09/18] output/cursor: fix missing newline at end of file --- types/output/cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/output/cursor.c b/types/output/cursor.c index 11f442cdf..5e93b0b2e 100644 --- a/types/output/cursor.c +++ b/types/output/cursor.c @@ -535,4 +535,4 @@ bool output_cursor_refresh_color_transform(struct wlr_output_cursor *output_curs wlr_color_transform_unref(transforms[0]); wlr_color_transform_unref(transforms[1]); return output_cursor->color_transform != NULL; -} \ No newline at end of file +} From 19d682960158df3c7c2c28a54d180ededdb84977 Mon Sep 17 00:00:00 2001 From: Steve Williams Date: Sat, 31 Jan 2026 15:00:57 +0400 Subject: [PATCH 10/18] render/pixel-format: add function to determine YCbCr from drm fourcc --- include/render/pixel_format.h | 5 +++ render/pixel_format.c | 65 +++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/include/render/pixel_format.h b/include/render/pixel_format.h index e0b500c75..b5f2b2411 100644 --- a/include/render/pixel_format.h +++ b/include/render/pixel_format.h @@ -63,4 +63,9 @@ enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt); */ bool pixel_format_has_alpha(uint32_t fmt); +/** + * Return true if the DRM FourCC fmt belongs to a YCbCr colorspace family, false otherwise. + */ +bool pixel_format_is_ycbcr(uint32_t fmt); + #endif diff --git a/render/pixel_format.c b/render/pixel_format.c index 5f2e8644a..c60dd9d2a 100644 --- a/render/pixel_format.c +++ b/render/pixel_format.c @@ -307,3 +307,68 @@ bool pixel_format_has_alpha(uint32_t fmt) { } return true; } + +bool pixel_format_is_ycbcr(uint32_t format) { + switch (format) { + case DRM_FORMAT_AYUV: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV15: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV20: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV30: + case DRM_FORMAT_NV42: + case DRM_FORMAT_NV61: + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + case DRM_FORMAT_P030: + case DRM_FORMAT_P210: + case DRM_FORMAT_Q401: + case DRM_FORMAT_Q410: + case DRM_FORMAT_S010: + case DRM_FORMAT_S012: + case DRM_FORMAT_S016: + case DRM_FORMAT_S210: + case DRM_FORMAT_S212: + case DRM_FORMAT_S216: + case DRM_FORMAT_S410: + case DRM_FORMAT_S412: + case DRM_FORMAT_S416: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VUY101010: + case DRM_FORMAT_VUY888: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_X0L0: + case DRM_FORMAT_X0L2: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + case DRM_FORMAT_XVYU2101010: + case DRM_FORMAT_XYUV8888: + case DRM_FORMAT_Y0L0: + case DRM_FORMAT_Y0L2: + case DRM_FORMAT_Y210: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + case DRM_FORMAT_Y410: + case DRM_FORMAT_Y412: + case DRM_FORMAT_Y416: + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YUV420_10BIT: + case DRM_FORMAT_YUV420_8BIT: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVU410: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YVU444: + case DRM_FORMAT_YVYU: + return true; + } + return false; +} From 4c81cb1b9e94cc9be72831b8973c6b6b83e3746a Mon Sep 17 00:00:00 2001 From: Steve Williams Date: Sat, 31 Jan 2026 15:03:37 +0400 Subject: [PATCH 11/18] vulkan: make use of new pixel_format_is_ycbcr function --- include/render/vulkan.h | 2 +- render/vulkan/pass.c | 7 ++++--- render/vulkan/pixel_format.c | 24 ++++++++---------------- render/vulkan/renderer.c | 4 ++-- render/vulkan/texture.c | 10 +++++----- 5 files changed, 20 insertions(+), 27 deletions(-) diff --git a/include/render/vulkan.h b/include/render/vulkan.h index bb56b5534..2f8d9d241 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -86,7 +86,6 @@ struct wlr_vk_format { uint32_t drm; VkFormat vk; VkFormat vk_srgb; // sRGB version of the format, or 0 if nonexistent - bool is_ycbcr; }; extern const VkImageUsageFlags vulkan_render_usage, vulkan_shm_tex_usage, vulkan_dma_tex_usage; @@ -125,6 +124,7 @@ void vulkan_format_props_query(struct wlr_vk_device *dev, const struct wlr_vk_format_modifier_props *vulkan_format_props_find_modifier( const struct wlr_vk_format_props *props, uint64_t mod, bool render); void vulkan_format_props_finish(struct wlr_vk_format_props *props); +bool vulkan_format_is_ycbcr(const struct wlr_vk_format *format); struct wlr_vk_pipeline_layout_key { enum wlr_scale_filter_mode filter_mode; diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 31f5116bd..271b426cc 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -822,12 +822,13 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, } enum wlr_color_encoding color_encoding = options->color_encoding; - if (texture->format->is_ycbcr && color_encoding == WLR_COLOR_ENCODING_NONE) { + bool is_ycbcr = vulkan_format_is_ycbcr(texture->format); + if (is_ycbcr && color_encoding == WLR_COLOR_ENCODING_NONE) { color_encoding = WLR_COLOR_ENCODING_BT601; } enum wlr_color_range color_range = options->color_range; - if (texture->format->is_ycbcr && color_range == WLR_COLOR_RANGE_NONE) { + if (is_ycbcr && color_range == WLR_COLOR_RANGE_NONE) { color_range = WLR_COLOR_RANGE_LIMITED; } @@ -837,7 +838,7 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, .source = WLR_VK_SHADER_SOURCE_TEXTURE, .layout = { .ycbcr = { - .format = texture->format->is_ycbcr ? texture->format : NULL, + .format = is_ycbcr ? texture->format : NULL, .encoding = color_encoding, .range = color_range, }, diff --git a/render/vulkan/pixel_format.c b/render/vulkan/pixel_format.c index 902feac9a..9b17d079a 100644 --- a/render/vulkan/pixel_format.c +++ b/render/vulkan/pixel_format.c @@ -182,37 +182,30 @@ static const struct wlr_vk_format formats[] = { { .drm = DRM_FORMAT_UYVY, .vk = VK_FORMAT_B8G8R8G8_422_UNORM, - .is_ycbcr = true, }, { .drm = DRM_FORMAT_YUYV, .vk = VK_FORMAT_G8B8G8R8_422_UNORM, - .is_ycbcr = true, }, { .drm = DRM_FORMAT_NV12, .vk = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, - .is_ycbcr = true, }, { .drm = DRM_FORMAT_NV16, .vk = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, - .is_ycbcr = true, }, { .drm = DRM_FORMAT_YUV420, .vk = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, - .is_ycbcr = true, }, { .drm = DRM_FORMAT_YUV422, .vk = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, - .is_ycbcr = true, }, { .drm = DRM_FORMAT_YUV444, .vk = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, - .is_ycbcr = true, }, // 3PACK16 formats split the memory in three 16-bit words, so they have an // inverted channel order compared to DRM formats. @@ -220,27 +213,22 @@ static const struct wlr_vk_format formats[] = { { .drm = DRM_FORMAT_P010, .vk = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, - .is_ycbcr = true, }, { .drm = DRM_FORMAT_P210, .vk = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, - .is_ycbcr = true, }, { .drm = DRM_FORMAT_P012, .vk = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, - .is_ycbcr = true, }, { .drm = DRM_FORMAT_P016, .vk = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, - .is_ycbcr = true, }, { .drm = DRM_FORMAT_Q410, .vk = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, - .is_ycbcr = true, }, #endif // TODO: add DRM_FORMAT_NV24/VK_FORMAT_G8_B8R8_2PLANE_444_UNORM (requires @@ -446,7 +434,7 @@ static bool query_modifier_support(struct wlr_vk_device *dev, // check that specific modifier for render usage const char *errmsg = "unknown error"; if ((m.drmFormatModifierTilingFeatures & render_features) == render_features && - !props->format.is_ycbcr) { + !vulkan_format_is_ycbcr(&props->format)) { struct wlr_vk_format_modifier_props p = {0}; bool supported = false; if (query_modifier_usage_support(dev, props->format.vk, @@ -477,7 +465,7 @@ static bool query_modifier_support(struct wlr_vk_device *dev, // check that specific modifier for texture usage errmsg = "unknown error"; VkFormatFeatureFlags features = dma_tex_features; - if (props->format.is_ycbcr) { + if (vulkan_format_is_ycbcr(&props->format)) { features |= ycbcr_tex_features; } if ((m.drmFormatModifierTilingFeatures & features) == features) { @@ -522,7 +510,7 @@ static bool query_modifier_support(struct wlr_vk_device *dev, void vulkan_format_props_query(struct wlr_vk_device *dev, const struct wlr_vk_format *format) { - if (format->is_ycbcr && !dev->sampler_ycbcr_conversion) { + if (vulkan_format_is_ycbcr(format) && !dev->sampler_ycbcr_conversion) { return; } @@ -551,7 +539,7 @@ void vulkan_format_props_query(struct wlr_vk_device *dev, char shm_texture_status[256]; const char *errmsg = "unknown error"; if ((fmtp.formatProperties.optimalTilingFeatures & shm_tex_features) == shm_tex_features && - !format->is_ycbcr && format_info != NULL) { + !vulkan_format_is_ycbcr(format) && format_info != NULL) { VkImageFormatProperties ifmtp; bool supported = false, has_mutable_srgb = false; if (query_shm_support(dev, format->vk, format->vk_srgb, &ifmtp, &errmsg)) { @@ -621,3 +609,7 @@ const struct wlr_vk_format_modifier_props *vulkan_format_props_find_modifier( } return NULL; } + +bool vulkan_format_is_ycbcr(const struct wlr_vk_format *format) { + return pixel_format_is_ycbcr(format->drm); +} diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 0b411f5dd..cfa05e077 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -1630,8 +1630,8 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { static bool pipeline_layout_key_equals( const struct wlr_vk_pipeline_layout_key *a, const struct wlr_vk_pipeline_layout_key *b) { - assert(!a->ycbcr.format || a->ycbcr.format->is_ycbcr); - assert(!b->ycbcr.format || b->ycbcr.format->is_ycbcr); + assert(!a->ycbcr.format || vulkan_format_is_ycbcr(a->ycbcr.format)); + assert(!b->ycbcr.format || vulkan_format_is_ycbcr(b->ycbcr.format)); if (a->filter_mode != b->filter_mode) { return false; diff --git a/render/vulkan/texture.c b/render/vulkan/texture.c index 499178f5d..ffea87795 100644 --- a/render/vulkan/texture.c +++ b/render/vulkan/texture.c @@ -297,7 +297,7 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text .components.r = VK_COMPONENT_SWIZZLE_IDENTITY, .components.g = VK_COMPONENT_SWIZZLE_IDENTITY, .components.b = VK_COMPONENT_SWIZZLE_IDENTITY, - .components.a = texture->has_alpha || texture->format->is_ycbcr + .components.a = texture->has_alpha || vulkan_format_is_ycbcr(texture->format) ? VK_COMPONENT_SWIZZLE_IDENTITY : VK_COMPONENT_SWIZZLE_ONE, .subresourceRange = (VkImageSubresourceRange){ @@ -311,7 +311,7 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text }; VkSamplerYcbcrConversionInfo ycbcr_conversion_info; - if (texture->format->is_ycbcr) { + if (vulkan_format_is_ycbcr(texture->format)) { assert(pipeline_layout->ycbcr.conversion != VK_NULL_HANDLE); ycbcr_conversion_info = (VkSamplerYcbcrConversionInfo){ .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, @@ -355,7 +355,7 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text static void texture_set_format(struct wlr_vk_texture *texture, const struct wlr_vk_format *format, bool has_mutable_srgb) { - assert(!(format->is_ycbcr && has_mutable_srgb)); + assert(!(vulkan_format_is_ycbcr(format) && has_mutable_srgb)); texture->format = format; texture->using_mutable_srgb = has_mutable_srgb; @@ -366,7 +366,7 @@ static void texture_set_format(struct wlr_vk_texture *texture, texture->has_alpha = pixel_format_has_alpha(format->drm); } else { // We don't have format info for multi-planar formats - assert(texture->format->is_ycbcr); + assert(vulkan_format_is_ycbcr(texture->format)); } } @@ -378,7 +378,7 @@ static struct wlr_texture *vulkan_texture_from_pixels( const struct wlr_vk_format_props *fmt = vulkan_format_props_from_drm(renderer->dev, drm_fmt); - if (fmt == NULL || fmt->format.is_ycbcr) { + if (fmt == NULL || vulkan_format_is_ycbcr(&fmt->format)) { char *format_name = drmGetFormatName(drm_fmt); wlr_log(WLR_ERROR, "Unsupported pixel format %s (0x%08"PRIX32")", format_name, drm_fmt); From 439985fe95efec4ccb06f5e690b33422a40dc512 Mon Sep 17 00:00:00 2001 From: Steve Williams Date: Sat, 31 Jan 2026 15:10:49 +0400 Subject: [PATCH 12/18] color_representation: ensure encoding/range/drm formats compatibility --- types/wlr_color_representation_v1.c | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/types/wlr_color_representation_v1.c b/types/wlr_color_representation_v1.c index a447d77a7..a69ea46e5 100644 --- a/types/wlr_color_representation_v1.c +++ b/types/wlr_color_representation_v1.c @@ -1,13 +1,16 @@ #include +#include #include #include +#include #include #include #include #include #include "color-representation-v1-protocol.h" +#include "render/pixel_format.h" #include "util/mem.h" #define WP_COLOR_REPRESENTATION_VERSION 1 @@ -230,8 +233,42 @@ static void color_repr_manager_handle_destroy(struct wl_client *client, wl_resource_destroy(resource); } +static void surface_synced_commit(struct wlr_surface_synced *synced) { + struct wlr_color_representation_v1 *color_repr = wl_container_of(synced, color_repr, synced); + + if (color_repr->current.coefficients == 0 && color_repr->current.range == 0) { + return; + } + + struct wlr_dmabuf_attributes dmabuf; + + if (!color_repr->surface->buffer || + !wlr_buffer_get_dmabuf(&color_repr->surface->buffer->base, &dmabuf)) { + return; + } + + bool is_ycbcr = pixel_format_is_ycbcr(dmabuf.format); + + bool is_identity_full = + color_repr->current.coefficients == WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY && + color_repr->current.range == WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_FULL; + + if (is_ycbcr) { + if (is_identity_full) { + wl_resource_post_error(color_repr->resource, + WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_PIXEL_FORMAT, + "unexpected encoding/range for yuv"); + } + } else /* rgb */ { + wl_resource_post_error(color_repr->resource, + WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_PIXEL_FORMAT, + "unexpected encoding/range for rgb"); + } +} + static const struct wlr_surface_synced_impl surface_synced_impl = { .state_size = sizeof(struct wlr_color_representation_v1_surface_state), + .commit = surface_synced_commit }; static struct wlr_color_representation_v1 *color_repr_from_surface( @@ -276,6 +313,7 @@ static void color_repr_manager_handle_get_surface(struct wl_client *client, } color_repr->manager = manager_from_resource(manager_resource); + color_repr->surface = surface; if (!wlr_surface_synced_init(&color_repr->synced, surface, &surface_synced_impl, &color_repr->pending, &color_repr->current)) { From bb78861ca90e2dbac5e8823e1706e44cdf34b37b Mon Sep 17 00:00:00 2001 From: Steve Williams Date: Sat, 31 Jan 2026 15:11:14 +0400 Subject: [PATCH 13/18] color-representation: add support for identity+full --- render/vulkan/renderer.c | 4 ++-- types/scene/wlr_scene.c | 8 ++++++-- types/wlr_color_representation_v1.c | 8 +++++++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index cfa05e077..7790d40b2 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -2039,8 +2039,8 @@ struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout( }; sampler_create_info.pNext = &conversion_info; } else { - assert(key->ycbcr.encoding == WLR_COLOR_ENCODING_NONE); - assert(key->ycbcr.range == WLR_COLOR_RANGE_NONE); + assert(key->ycbcr.encoding == WLR_COLOR_ENCODING_NONE || key->ycbcr.encoding == WLR_COLOR_ENCODING_IDENTITY); + assert(key->ycbcr.range == WLR_COLOR_RANGE_NONE || key->ycbcr.range == WLR_COLOR_RANGE_FULL); } res = vkCreateSampler(renderer->dev->dev, &sampler_create_info, NULL, &pipeline_layout->sampler); diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 19617b11f..aaf9a8d74 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -2086,8 +2086,12 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout( return SCANOUT_INELIGIBLE; } - if (buffer->color_encoding != WLR_COLOR_ENCODING_NONE || - buffer->color_range != WLR_COLOR_RANGE_NONE) { + bool is_color_repr_none = buffer->color_encoding == WLR_COLOR_ENCODING_NONE && + buffer->color_range == WLR_COLOR_RANGE_NONE; + bool is_color_repr_identity_full = buffer->color_encoding == WLR_COLOR_ENCODING_IDENTITY && + buffer->color_range == WLR_COLOR_RANGE_FULL; + + if (!(is_color_repr_none || is_color_repr_identity_full)) { return SCANOUT_INELIGIBLE; } diff --git a/types/wlr_color_representation_v1.c b/types/wlr_color_representation_v1.c index a69ea46e5..432511b91 100644 --- a/types/wlr_color_representation_v1.c +++ b/types/wlr_color_representation_v1.c @@ -260,9 +260,11 @@ static void surface_synced_commit(struct wlr_surface_synced *synced) { "unexpected encoding/range for yuv"); } } else /* rgb */ { - wl_resource_post_error(color_repr->resource, + if (!is_identity_full) { + wl_resource_post_error(color_repr->resource, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_PIXEL_FORMAT, "unexpected encoding/range for rgb"); + } } } @@ -465,6 +467,10 @@ struct wlr_color_representation_manager_v1 *wlr_color_representation_manager_v1_ struct wlr_color_representation_v1_coeffs_and_range coeffs_and_ranges[COEFFICIENTS_LEN * RANGES_LEN]; size_t coeffs_and_ranges_len = 0; + coeffs_and_ranges[coeffs_and_ranges_len++] = (struct wlr_color_representation_v1_coeffs_and_range){ + .coeffs = WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY, + .range = WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_FULL, + }; for (size_t i = 0; i < COEFFICIENTS_LEN; i++) { enum wp_color_representation_surface_v1_coefficients coeffs = coefficients[i]; enum wlr_color_encoding enc = wlr_color_representation_v1_color_encoding_to_wlr(coeffs); From ef882466421492061a776c2025513a03598faeb5 Mon Sep 17 00:00:00 2001 From: Steve Williams Date: Thu, 5 Feb 2026 21:26:29 +0400 Subject: [PATCH 14/18] types/wlr_buffer: add buffer_get_drm_format helper function --- backend/x11/output.c | 12 +++--------- include/types/wlr_buffer.h | 6 ++++++ types/buffer/buffer.c | 23 ++++++++++++++++------- types/wlr_color_representation_v1.c | 13 +++++++------ 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/backend/x11/output.c b/backend/x11/output.c index 0b63a7088..181c2de14 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -20,6 +20,7 @@ #include "backend/x11.h" #include "util/time.h" +#include "types/wlr_buffer.h" #include "types/wlr_output.h" static const uint32_t SUPPORTED_OUTPUT_STATE = @@ -166,15 +167,8 @@ static bool output_test(struct wlr_output *wlr_output, if (state->committed & WLR_OUTPUT_STATE_BUFFER) { struct wlr_buffer *buffer = state->buffer; - struct wlr_dmabuf_attributes dmabuf_attrs; - struct wlr_shm_attributes shm_attrs; - uint32_t format = DRM_FORMAT_INVALID; - if (wlr_buffer_get_dmabuf(buffer, &dmabuf_attrs)) { - format = dmabuf_attrs.format; - } else if (wlr_buffer_get_shm(buffer, &shm_attrs)) { - format = shm_attrs.format; - } - if (format != x11->x11_format->drm) { + + if (buffer_get_drm_format(buffer) != x11->x11_format->drm) { wlr_log(WLR_DEBUG, "Unsupported buffer format"); return false; } diff --git a/include/types/wlr_buffer.h b/include/types/wlr_buffer.h index 9d882d47d..45acf7a1d 100644 --- a/include/types/wlr_buffer.h +++ b/include/types/wlr_buffer.h @@ -65,4 +65,10 @@ struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer, bool wlr_client_buffer_apply_damage(struct wlr_client_buffer *client_buffer, struct wlr_buffer *next, const pixman_region32_t *damage); +/** + * Return the DRM format of the buffer. If this buffer isn't shared + * memory or a DMA-BUF, returns DRM_FORMAT_INVALID. + */ +uint32_t buffer_get_drm_format(struct wlr_buffer *buffer); + #endif diff --git a/types/buffer/buffer.c b/types/buffer/buffer.c index d56255b0d..48a10d9f0 100644 --- a/types/buffer/buffer.c +++ b/types/buffer/buffer.c @@ -109,14 +109,11 @@ bool wlr_buffer_get_shm(struct wlr_buffer *buffer, bool wlr_buffer_is_opaque(struct wlr_buffer *buffer) { void *data; - uint32_t format; + uint32_t format = buffer_get_drm_format(buffer); size_t stride; - struct wlr_dmabuf_attributes dmabuf; - struct wlr_shm_attributes shm; - if (wlr_buffer_get_dmabuf(buffer, &dmabuf)) { - format = dmabuf.format; - } else if (wlr_buffer_get_shm(buffer, &shm)) { - format = shm.format; + + if (format != DRM_FORMAT_INVALID) { + // pass } else if (wlr_buffer_begin_data_ptr_access(buffer, WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) { bool opaque = false; @@ -135,3 +132,15 @@ bool wlr_buffer_is_opaque(struct wlr_buffer *buffer) { return !pixel_format_has_alpha(format); } + +uint32_t buffer_get_drm_format(struct wlr_buffer *buffer) { + uint32_t format = DRM_FORMAT_INVALID; + struct wlr_dmabuf_attributes dmabuf; + struct wlr_shm_attributes shm; + if (wlr_buffer_get_dmabuf(buffer, &dmabuf)) { + format = dmabuf.format; + } else if (wlr_buffer_get_shm(buffer, &shm)) { + format = shm.format; + } + return format; +} diff --git a/types/wlr_color_representation_v1.c b/types/wlr_color_representation_v1.c index 432511b91..ab7df30b0 100644 --- a/types/wlr_color_representation_v1.c +++ b/types/wlr_color_representation_v1.c @@ -11,6 +11,7 @@ #include "color-representation-v1-protocol.h" #include "render/pixel_format.h" +#include "types/wlr_buffer.h" #include "util/mem.h" #define WP_COLOR_REPRESENTATION_VERSION 1 @@ -240,14 +241,14 @@ static void surface_synced_commit(struct wlr_surface_synced *synced) { return; } - struct wlr_dmabuf_attributes dmabuf; - - if (!color_repr->surface->buffer || - !wlr_buffer_get_dmabuf(&color_repr->surface->buffer->base, &dmabuf)) { + uint32_t drm_format = DRM_FORMAT_INVALID; + if (!color_repr->surface->buffer){ + drm_format = buffer_get_drm_format(&color_repr->surface->buffer->base); + } + if (drm_format == DRM_FORMAT_INVALID) { return; } - - bool is_ycbcr = pixel_format_is_ycbcr(dmabuf.format); + bool is_ycbcr = pixel_format_is_ycbcr(drm_format); bool is_identity_full = color_repr->current.coefficients == WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY && From 436bcf9a4755b24f7fadc100ba8deaa7f343ba86 Mon Sep 17 00:00:00 2001 From: Steve Williams Date: Sat, 7 Feb 2026 08:36:29 +0400 Subject: [PATCH 15/18] color-representation-v1: fix condition in surface commit --- types/wlr_color_representation_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_color_representation_v1.c b/types/wlr_color_representation_v1.c index ab7df30b0..856dc84f8 100644 --- a/types/wlr_color_representation_v1.c +++ b/types/wlr_color_representation_v1.c @@ -242,7 +242,7 @@ static void surface_synced_commit(struct wlr_surface_synced *synced) { } uint32_t drm_format = DRM_FORMAT_INVALID; - if (!color_repr->surface->buffer){ + if (color_repr->surface->buffer){ drm_format = buffer_get_drm_format(&color_repr->surface->buffer->base); } if (drm_format == DRM_FORMAT_INVALID) { From c1452d88114710f5772662b1d8efb9c71edaa34c Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Sat, 7 Feb 2026 17:48:16 -0800 Subject: [PATCH 16/18] backend/libinput: fix build with libinput 1.31 --- backend/libinput/meson.build | 4 ++++ backend/libinput/switch.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/backend/libinput/meson.build b/backend/libinput/meson.build index c244eb77a..091b0e0eb 100644 --- a/backend/libinput/meson.build +++ b/backend/libinput/meson.build @@ -29,3 +29,7 @@ features += { 'libinput-backend': true } wlr_deps += libinput internal_config.set10('HAVE_LIBINPUT_BUSTYPE', libinput.version().version_compare('>=1.26.0')) +internal_config.set10( + 'HAVE_LIBINPUT_SWITCH_KEYPAD_SLIDE', + libinput.version().version_compare('>=1.30.901') +) diff --git a/backend/libinput/switch.c b/backend/libinput/switch.c index abeec86d7..9dde3c9cb 100644 --- a/backend/libinput/switch.c +++ b/backend/libinput/switch.c @@ -2,6 +2,7 @@ #include #include #include "backend/libinput.h" +#include "config.h" const struct wlr_switch_impl libinput_switch_impl = { .name = "libinput-switch", @@ -36,6 +37,10 @@ void handle_switch_toggle(struct libinput_event *event, case LIBINPUT_SWITCH_TABLET_MODE: wlr_event.switch_type = WLR_SWITCH_TYPE_TABLET_MODE; break; +#if HAVE_LIBINPUT_SWITCH_KEYPAD_SLIDE + case LIBINPUT_SWITCH_KEYPAD_SLIDE: + return; +#endif } switch (libinput_event_switch_get_switch_state(sevent)) { case LIBINPUT_SWITCH_STATE_OFF: From 3676ab4df0e7b31efd9c72f543fd8e6326af95cc Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Sat, 7 Feb 2026 17:48:16 -0800 Subject: [PATCH 17/18] backend/libinput: add support for LIBINPUT_SWITCH_KEYPAD_SLIDE --- backend/libinput/switch.c | 3 ++- include/wlr/types/wlr_switch.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/libinput/switch.c b/backend/libinput/switch.c index 9dde3c9cb..a78d37abe 100644 --- a/backend/libinput/switch.c +++ b/backend/libinput/switch.c @@ -39,7 +39,8 @@ void handle_switch_toggle(struct libinput_event *event, break; #if HAVE_LIBINPUT_SWITCH_KEYPAD_SLIDE case LIBINPUT_SWITCH_KEYPAD_SLIDE: - return; + wlr_event.switch_type = WLR_SWITCH_TYPE_KEYPAD_SLIDE; + break; #endif } switch (libinput_event_switch_get_switch_state(sevent)) { diff --git a/include/wlr/types/wlr_switch.h b/include/wlr/types/wlr_switch.h index 641df1991..2b9e91266 100644 --- a/include/wlr/types/wlr_switch.h +++ b/include/wlr/types/wlr_switch.h @@ -36,6 +36,7 @@ struct wlr_switch { enum wlr_switch_type { WLR_SWITCH_TYPE_LID, WLR_SWITCH_TYPE_TABLET_MODE, + WLR_SWITCH_TYPE_KEYPAD_SLIDE, }; enum wlr_switch_state { From 910fd264fb78f1ee6d68b79c883285c57419c7f3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 12 Feb 2026 22:47:22 +0100 Subject: [PATCH 18/18] build: bump version to 0.20.0-rc2 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 5b8f12073..b5b756bae 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'wlroots', 'c', - version: '0.20.0-rc1', + version: '0.20.0-rc2', license: 'MIT', meson_version: '>=1.3', default_options: [