From b8eb0f88d3d28dda97d1cf236410fde7d9998e4d Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 27 Jan 2026 12:08:59 +0000 Subject: [PATCH] vulkan/wsi/wayland: Correctly map 24bpp format types VK_FORMAT_{R8G8B8,B8G8R8}_{UNORM,SRGB} describe a 3-component, 8bpc, 24bpp, format. This is mapped to that type for Android, and implemented as such by panvk. radv maps these to 4-component/32bpp formats, but only support these formats for buffers rather than images. The outlier is ANV, which relies on the 24->32bpp mapping to happen. The Wayland WSI was mapping this to the 32bpp R8G8B8A8/B8G8R8A8 formats instead. This would cause a failure to import the dmabuf into the compositor on panvk, as it would send a buffer which was too small. (Or, if it did import: garbage.) Signed-off-by: Daniel Stone Part-of: --- src/intel/vulkan/anv_wsi.c | 5 +- src/intel/vulkan_hasvk/anv_wsi.c | 5 +- src/vulkan/wsi/wsi_common.c | 1 + src/vulkan/wsi/wsi_common.h | 9 +++ src/vulkan/wsi/wsi_common_wayland.c | 88 +++++++++++++++++++++-------- 5 files changed, 82 insertions(+), 26 deletions(-) diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c index 28609d7dcb8..d7ba71126a8 100644 --- a/src/intel/vulkan/anv_wsi.c +++ b/src/intel/vulkan/anv_wsi.c @@ -49,7 +49,10 @@ anv_init_wsi(struct anv_physical_device *physical_device) &physical_device->instance->vk.alloc, physical_device->master_fd, &physical_device->instance->dri_options, - &(struct wsi_device_options){.sw_device = false}); + &(struct wsi_device_options){ + .sw_device = false, + .emulate_24as32 = true, + }); if (result != VK_SUCCESS) return result; diff --git a/src/intel/vulkan_hasvk/anv_wsi.c b/src/intel/vulkan_hasvk/anv_wsi.c index 9bb069f63a7..5f002735166 100644 --- a/src/intel/vulkan_hasvk/anv_wsi.c +++ b/src/intel/vulkan_hasvk/anv_wsi.c @@ -49,7 +49,10 @@ anv_init_wsi(struct anv_physical_device *physical_device) &physical_device->instance->vk.alloc, physical_device->master_fd, &physical_device->instance->dri_options, - &(struct wsi_device_options){.sw_device = false}); + &(struct wsi_device_options){ + .sw_device = false, + .emulate_24as32 = false + }); if (result != VK_SUCCESS) return result; diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index 6783fbd6efb..44367b6b80b 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -89,6 +89,7 @@ wsi_device_init(struct wsi_device *wsi, wsi->wants_linear = (WSI_DEBUG & WSI_DEBUG_LINEAR) != 0; wsi->x11.extra_xwayland_image = device_options->extra_xwayland_image; wsi->wayland.disable_timestamps = (WSI_DEBUG & WSI_DEBUG_NOWLTS) != 0; + wsi->emulate_24as32 = device_options->emulate_24as32; #define WSI_GET_CB(func) \ PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func) WSI_GET_CB(GetPhysicalDeviceExternalSemaphoreProperties); diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h index c17a79c6b13..8c9f1f1da50 100644 --- a/src/vulkan/wsi/wsi_common.h +++ b/src/vulkan/wsi/wsi_common.h @@ -75,6 +75,14 @@ struct wsi_device { bool has_import_memory_host; bool has_timeline_semaphore; + /** Whether the device uses 32bpp formats for 24bpp + * + * If true, VkImages created with R8G8B8/B8G8R8 formats will be + * exported as 32bpp to the window system, as if they were B8G8R8A8 + * or R8G8B8A8 + */ + bool emulate_24as32; + /** Indicates if wsi_image_create_info::scanout is supported * * If false, WSI will always use either modifiers or the prime blit path. @@ -253,6 +261,7 @@ typedef PFN_vkVoidFunction (VKAPI_PTR *WSI_FN_GetPhysicalDeviceProcAddr)(VkPhysi struct wsi_device_options { bool sw_device; bool extra_xwayland_image; + bool emulate_24as32; }; VkResult diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c index e36b46c640f..bd43a0c2ea9 100644 --- a/src/vulkan/wsi/wsi_common_wayland.c +++ b/src/vulkan/wsi/wsi_common_wayland.c @@ -409,6 +409,8 @@ wsi_wl_display_add_drm_format_modifier(struct wsi_wl_display *display, uint32_t drm_format, uint64_t modifier) { VK_FROM_HANDLE(vk_physical_device, pdevice, display->wsi_wl->physical_device); + struct wsi_device *wsi_device = pdevice->wsi_device; + /* From Vulkan 1.3 onwards, we can always try adding the 4444 formats. * If the format isn't supported or isn't renderable, * wsi_wl_display_add_vk_format() will reject it via @@ -567,16 +569,34 @@ wsi_wl_display_add_drm_format_modifier(struct wsi_wl_display *display, * linear -> nonlinear SRGB colorspace conversion before the data is stored. * The inverse function is applied when sampling from SRGB images. * From Wayland's perspective nothing changes, the difference is just how - * Vulkan interprets the pixel data. */ + * Vulkan interprets the pixel data. + * + * For bonus points, 24bpp VkFormats may appear as 32bpp, depending on the + * driver. + */ + case DRM_FORMAT_BGR888: + if (!wsi_device->emulate_24as32) { + wsi_wl_display_add_vk_format_modifier(display, formats, + VK_FORMAT_R8G8B8_SRGB, + WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, + modifier); + wsi_wl_display_add_vk_format_modifier(display, formats, + VK_FORMAT_R8G8B8_UNORM, + WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, + modifier); + } + break; case DRM_FORMAT_XBGR8888: - wsi_wl_display_add_vk_format_modifier(display, formats, - VK_FORMAT_R8G8B8_SRGB, - WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, - modifier); - wsi_wl_display_add_vk_format_modifier(display, formats, - VK_FORMAT_R8G8B8_UNORM, - WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, - modifier); + if (wsi_device->emulate_24as32) { + wsi_wl_display_add_vk_format_modifier(display, formats, + VK_FORMAT_R8G8B8_SRGB, + WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, + modifier); + wsi_wl_display_add_vk_format_modifier(display, formats, + VK_FORMAT_R8G8B8_UNORM, + WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, + modifier); + } wsi_wl_display_add_vk_format_modifier(display, formats, VK_FORMAT_R8G8B8A8_SRGB, WSI_WL_FMT_OPAQUE, modifier); @@ -592,15 +612,29 @@ wsi_wl_display_add_drm_format_modifier(struct wsi_wl_display *display, VK_FORMAT_R8G8B8A8_UNORM, WSI_WL_FMT_ALPHA, modifier); break; + case DRM_FORMAT_RGB888: + if (!wsi_device->emulate_24as32) { + wsi_wl_display_add_vk_format_modifier(display, formats, + VK_FORMAT_B8G8R8_SRGB, + WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, + modifier); + wsi_wl_display_add_vk_format_modifier(display, formats, + VK_FORMAT_B8G8R8_UNORM, + WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, + modifier); + } + break; case DRM_FORMAT_XRGB8888: - wsi_wl_display_add_vk_format_modifier(display, formats, - VK_FORMAT_B8G8R8_SRGB, - WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, - modifier); - wsi_wl_display_add_vk_format_modifier(display, formats, - VK_FORMAT_B8G8R8_UNORM, - WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, - modifier); + if (wsi_device->emulate_24as32) { + wsi_wl_display_add_vk_format_modifier(display, formats, + VK_FORMAT_B8G8R8_SRGB, + WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, + modifier); + wsi_wl_display_add_vk_format_modifier(display, formats, + VK_FORMAT_B8G8R8_UNORM, + WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, + modifier); + } wsi_wl_display_add_vk_format_modifier(display, formats, VK_FORMAT_B8G8R8A8_SRGB, WSI_WL_FMT_OPAQUE, modifier); @@ -645,7 +679,8 @@ wsi_wl_display_add_wl_shm_format(struct wsi_wl_display *display, } static uint32_t -wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha) +wl_drm_format_for_vk_format(struct wsi_device *wsi_device, + VkFormat vk_format, bool alpha) { switch (vk_format) { case VK_FORMAT_A4R4G4B4_UNORM_PACK16: @@ -678,13 +713,13 @@ wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha) #endif case VK_FORMAT_R8G8B8_UNORM: case VK_FORMAT_R8G8B8_SRGB: - return DRM_FORMAT_XBGR8888; + return wsi_device->emulate_24as32 ? DRM_FORMAT_XBGR8888 : DRM_FORMAT_BGR888; case VK_FORMAT_R8G8B8A8_UNORM: case VK_FORMAT_R8G8B8A8_SRGB: return alpha ? DRM_FORMAT_ABGR8888 : DRM_FORMAT_XBGR8888; case VK_FORMAT_B8G8R8_UNORM: case VK_FORMAT_B8G8R8_SRGB: - return DRM_FORMAT_BGRX8888; + return wsi_device->emulate_24as32 ? DRM_FORMAT_XRGB8888 : DRM_FORMAT_RGB888; case VK_FORMAT_B8G8R8A8_UNORM: case VK_FORMAT_B8G8R8A8_SRGB: return alpha ? DRM_FORMAT_ARGB8888 : DRM_FORMAT_XRGB8888; @@ -696,9 +731,12 @@ wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha) } static enum wl_shm_format -wl_shm_format_for_vk_format(VkFormat vk_format, bool alpha) +wl_shm_format_for_vk_format(struct wsi_device *wsi_device, + VkFormat vk_format, bool alpha) { - uint32_t drm_format = wl_drm_format_for_vk_format(vk_format, alpha); + uint32_t drm_format = + wl_drm_format_for_vk_format(wsi_device, vk_format, alpha); + if (drm_format == DRM_FORMAT_INVALID) { return 0; } @@ -3799,9 +3837,11 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, chain->vk_format = pCreateInfo->imageFormat; chain->buffer_type = buffer_type; if (buffer_type == WSI_WL_BUFFER_NATIVE) { - chain->drm_format = wl_drm_format_for_vk_format(chain->vk_format, alpha); + chain->drm_format = wl_drm_format_for_vk_format(wsi_device, + chain->vk_format, alpha); } else { - chain->shm_format = wl_shm_format_for_vk_format(chain->vk_format, alpha); + chain->shm_format = wl_shm_format_for_vk_format(wsi_device, + chain->vk_format, alpha); } chain->num_drm_modifiers = num_drm_modifiers; if (num_drm_modifiers) {