From cf654be16b4751860a56ca7fe90360e679091c70 Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Mon, 14 Jul 2025 10:38:12 -0400 Subject: [PATCH] vulkan/wsi/x11: Refuse to connect to thread-unsafe Displays We heavily rely on threading in Vulkan WSI. There's no way this is safe if XInitThreads() hasn't been called. Fortunately, this should never be the case since 2022 or so. Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/13530 Cc: mesa-stable Acked-by: Mike Blumenkrantz Part-of: --- src/vulkan/wsi/wsi_common_x11.c | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c index 898cbc12af7..0c4cb9d7d42 100644 --- a/src/vulkan/wsi/wsi_common_x11.c +++ b/src/vulkan/wsi/wsi_common_x11.c @@ -21,6 +21,7 @@ * IN THE SOFTWARE. */ +#include #include #include #define XK_MISCELLANY @@ -609,18 +610,42 @@ wsi_GetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice, return true; } +static bool +xlib_display_is_thread_safe(Display *dpy) +{ + /* 'lock_fns' is the XLockDisplay function pointer of the X11 display 'dpy'. + * It will be NULL if XInitThreads wasn't called. + */ + return dpy->lock_fns != NULL; +} + VKAPI_ATTR VkBool32 VKAPI_CALL wsi_GetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display *dpy, VisualID visualID) { + /* Our WSI implementation for X11 relies on threads. Check Xlib is running + * in thread safe mode before advertising support. + */ + if (!xlib_display_is_thread_safe(dpy)) + return false; + return wsi_GetPhysicalDeviceXcbPresentationSupportKHR(physicalDevice, queueFamilyIndex, XGetXCBConnection(dpy), visualID); } +static bool +x11_surface_is_thread_safe(VkIcdSurfaceBase *icd_surface) +{ + if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB) + return xlib_display_is_thread_safe(((VkIcdSurfaceXlib *)icd_surface)->dpy); + else + return true; +} + static xcb_connection_t* x11_surface_get_connection(VkIcdSurfaceBase *icd_surface) { @@ -645,6 +670,11 @@ x11_surface_get_support(VkIcdSurfaceBase *icd_surface, uint32_t queueFamilyIndex, VkBool32* pSupported) { + if (!x11_surface_is_thread_safe(icd_surface)) { + *pSupported = false; + return VK_SUCCESS; + } + xcb_connection_t *conn = x11_surface_get_connection(icd_surface); xcb_window_t window = x11_surface_get_window(icd_surface); @@ -2555,6 +2585,15 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); + /* We really shouldn't get here as we return no WSI support for XLib when + * it's not threadsafe. However, one final check doesn't cost much. + */ + if (!x11_surface_is_thread_safe(icd_surface)) { + fprintf(stderr, "vulkan: xlib Display is not thread-safe. Call " + "XInitThreads() in your app\n"); + return VK_ERROR_UNKNOWN; + } + /* Get xcb connection from the icd_surface and from that our internal struct * representing it. */