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 <daniels@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39552>
This commit is contained in:
Daniel Stone 2026-01-27 12:08:59 +00:00 committed by Marge Bot
parent ec6d077351
commit b8eb0f88d3
5 changed files with 82 additions and 26 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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) {