diff --git a/configure.ac b/configure.ac index 40e7855994a..f84903dffeb 100644 --- a/configure.ac +++ b/configure.ac @@ -92,6 +92,7 @@ WAYLAND_REQUIRED=1.11 WAYLAND_PROTOCOLS_REQUIRED=1.8 XCB_REQUIRED=1.9.3 XCBDRI2_REQUIRED=1.8 +XCBDRI3_REQUIRED=1.13 XCBGLX_REQUIRED=1.8.1 XDAMAGE_REQUIRED=1.1 XSHMFENCE_REQUIRED=1.1 @@ -1849,7 +1850,7 @@ fi if test x"$enable_dri3" = xyes; then DEFINES="$DEFINES -DHAVE_DRI3" - dri3_modules="x11-xcb xcb >= $XCB_REQUIRED xcb-dri3 xcb-xfixes xcb-present xcb-sync xshmfence >= $XSHMFENCE_REQUIRED" + dri3_modules="x11-xcb xcb >= $XCB_REQUIRED xcb-dri3 >= $XCBDRI3_REQUIRED xcb-xfixes xcb-present xcb-sync xshmfence >= $XSHMFENCE_REQUIRED" PKG_CHECK_MODULES([XCB_DRI3], [$dri3_modules]) fi diff --git a/meson.build b/meson.build index 7658f6e63da..34090de4525 100644 --- a/meson.build +++ b/meson.build @@ -1234,7 +1234,7 @@ if with_platform_x11 if with_dri3 pre_args += '-DHAVE_DRI3' - dep_xcb_dri3 = dependency('xcb-dri3') + dep_xcb_dri3 = dependency('xcb-dri3', version : '>= 1.13') dep_xcb_present = dependency('xcb-present') dep_xcb_sync = dependency('xcb-sync') dep_xshmfence = dependency('xshmfence', version : '>= 1.1') diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c index e5e719e1d50..ab577868ab1 100644 --- a/src/vulkan/wsi/wsi_common_x11.c +++ b/src/vulkan/wsi/wsi_common_x11.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "util/hash_table.h" #include "vk_util.h" @@ -50,6 +51,7 @@ struct wsi_x11_connection { bool has_dri3; + bool has_dri3_modifiers; bool has_present; bool is_proprietary_x11; }; @@ -164,6 +166,17 @@ wsi_x11_connection_create(const VkAllocationCallbacks *alloc, } wsi_conn->has_dri3 = dri3_reply->present != 0; + if (wsi_conn->has_dri3) { + xcb_dri3_query_version_cookie_t ver_cookie; + xcb_dri3_query_version_reply_t *ver_reply; + + ver_cookie = xcb_dri3_query_version(conn, 1, 2); + ver_reply = xcb_dri3_query_version_reply(conn, ver_cookie, NULL); + wsi_conn->has_dri3_modifiers = + (ver_reply->major_version > 1 || ver_reply->minor_version >= 2); + free(ver_reply); + } + wsi_conn->has_present = pres_reply->present != 0; wsi_conn->is_proprietary_x11 = false; if (amd_reply && amd_reply->present) @@ -620,6 +633,8 @@ struct x11_image { struct x11_swapchain { struct wsi_swapchain base; + bool has_dri3_modifiers; + xcb_connection_t * conn; xcb_window_t window; xcb_gc_t gc; @@ -966,7 +981,9 @@ static VkResult x11_image_init(VkDevice device_h, struct x11_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks* pAllocator, - struct x11_image *image) + const uint64_t *const *modifiers, + const uint32_t *num_modifiers, + int num_tranches, struct x11_image *image) { xcb_void_cookie_t cookie; VkResult result; @@ -976,28 +993,57 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain, result = wsi_create_prime_image(&chain->base, pCreateInfo, &image->base); } else { result = wsi_create_native_image(&chain->base, pCreateInfo, - 0, NULL, NULL, &image->base); + num_tranches, num_modifiers, modifiers, + &image->base); } if (result < 0) return result; image->pixmap = xcb_generate_id(chain->conn); - /* Without passing modifiers, we can't have multi-plane RGB images. */ - assert(image->base.num_planes == 1); + if (image->base.drm_modifier != DRM_FORMAT_MOD_INVALID) { + /* If the image has a modifier, we must have DRI3 v1.1. */ + assert(chain->has_dri3_modifiers); + + cookie = + xcb_dri3_pixmap_from_buffers_checked(chain->conn, + image->pixmap, + chain->window, + image->base.num_planes, + pCreateInfo->imageExtent.width, + pCreateInfo->imageExtent.height, + image->base.row_pitches[0], + image->base.offsets[0], + image->base.row_pitches[1], + image->base.offsets[1], + image->base.row_pitches[2], + image->base.offsets[2], + image->base.row_pitches[3], + image->base.offsets[3], + chain->depth, bpp, + image->base.drm_modifier, + image->base.fds); + } else { + /* Without passing modifiers, we can't have multi-plane RGB images. */ + assert(image->base.num_planes == 1); + + cookie = + xcb_dri3_pixmap_from_buffer_checked(chain->conn, + image->pixmap, + chain->window, + image->base.sizes[0], + pCreateInfo->imageExtent.width, + pCreateInfo->imageExtent.height, + image->base.row_pitches[0], + chain->depth, bpp, + image->base.fds[0]); + } - cookie = - xcb_dri3_pixmap_from_buffer_checked(chain->conn, - image->pixmap, - chain->window, - image->base.sizes[0], - pCreateInfo->imageExtent.width, - pCreateInfo->imageExtent.height, - image->base.row_pitches[0], - chain->depth, bpp, - image->base.fds[0]); xcb_discard_reply(chain->conn, cookie.sequence); - image->base.fds[0] = -1; /* XCB has now taken ownership of the FD */ + + /* XCB has now taken ownership of the FDs. */ + for (int i = 0; i < image->base.num_planes; i++) + image->base.fds[i] = -1; int fence_fd = xshmfence_alloc_shm(); if (fence_fd < 0) @@ -1048,6 +1094,82 @@ x11_image_finish(struct x11_swapchain *chain, wsi_destroy_image(&chain->base, &image->base); } +static void +wsi_x11_get_dri3_modifiers(struct wsi_x11_connection *wsi_conn, + xcb_connection_t *conn, xcb_window_t window, + uint8_t depth, uint8_t bpp, + VkCompositeAlphaFlagsKHR vk_alpha, + uint64_t **modifiers_in, uint32_t *num_modifiers_in, + uint32_t *num_tranches_in, + const VkAllocationCallbacks *pAllocator) +{ + if (!wsi_conn->has_dri3_modifiers) + goto out; + + xcb_generic_error_t *error = NULL; + xcb_dri3_get_supported_modifiers_cookie_t mod_cookie = + xcb_dri3_get_supported_modifiers(conn, window, depth, bpp); + xcb_dri3_get_supported_modifiers_reply_t *mod_reply = + xcb_dri3_get_supported_modifiers_reply(conn, mod_cookie, &error); + free(error); + + if (!mod_reply || (mod_reply->num_window_modifiers == 0 && + mod_reply->num_screen_modifiers == 0)) { + free(mod_reply); + goto out; + } + + uint32_t n = 0; + uint32_t counts[2]; + uint64_t *modifiers[2]; + + if (mod_reply->num_window_modifiers) { + counts[n] = mod_reply->num_window_modifiers; + modifiers[n] = vk_alloc(pAllocator, + counts[n] * sizeof(uint64_t), + 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!modifiers[n]) { + free(mod_reply); + goto out; + } + + memcpy(modifiers[n], + xcb_dri3_get_supported_modifiers_window_modifiers(mod_reply), + counts[n] * sizeof(uint64_t)); + n++; + } + + if (mod_reply->num_screen_modifiers) { + counts[n] = mod_reply->num_screen_modifiers; + modifiers[n] = vk_alloc(pAllocator, + counts[n] * sizeof(uint64_t), + 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!modifiers[n]) { + if (n > 0) + vk_free(pAllocator, modifiers[0]); + free(mod_reply); + goto out; + } + + memcpy(modifiers[n], + xcb_dri3_get_supported_modifiers_screen_modifiers(mod_reply), + counts[n] * sizeof(uint64_t)); + n++; + } + + for (int i = 0; i < n; i++) { + modifiers_in[i] = modifiers[i]; + num_modifiers_in[i] = counts[i]; + } + *num_tranches_in = n; + + free(mod_reply); + return; + +out: + *num_tranches_in = 0; +} + static VkResult x11_swapchain_destroy(struct wsi_swapchain *anv_chain, const VkAllocationCallbacks *pAllocator) @@ -1097,8 +1219,13 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, const unsigned num_images = pCreateInfo->minImageCount; - /* Check for whether or not we have a window up-front */ xcb_connection_t *conn = x11_surface_get_connection(icd_surface); + struct wsi_x11_connection *wsi_conn = + wsi_x11_get_connection(wsi_device, pAllocator, conn); + if (!wsi_conn) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + /* Check for whether or not we have a window up-front */ xcb_window_t window = x11_surface_get_window(icd_surface); xcb_get_geometry_reply_t *geometry = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), NULL); @@ -1132,6 +1259,7 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, chain->last_present_msc = 0; chain->threaded = false; chain->status = VK_SUCCESS; + chain->has_dri3_modifiers = wsi_conn->has_dri3_modifiers; if (!wsi_x11_check_dri3_compatible(conn, local_fd)) chain->base.use_prime_blit = true; @@ -1163,9 +1291,20 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, (uint32_t []) { 0 }); xcb_discard_reply(chain->conn, cookie.sequence); + uint64_t *modifiers[2] = {NULL, NULL}; + uint32_t num_modifiers[2] = {0, 0}; + uint32_t num_tranches = 0; + if (wsi_device->supports_modifiers) + wsi_x11_get_dri3_modifiers(wsi_conn, conn, window, chain->depth, 32, + pCreateInfo->compositeAlpha, + modifiers, num_modifiers, &num_tranches, + pAllocator); + uint32_t image = 0; for (; image < chain->base.image_count; image++) { result = x11_image_init(device, chain, pCreateInfo, pAllocator, + (const uint64_t *const *)modifiers, + num_modifiers, num_tranches, &chain->images[image]); if (result != VK_SUCCESS) goto fail_init_images; @@ -1202,6 +1341,8 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, } } + for (int i = 0; i < 2; i++) + vk_free(pAllocator, modifiers[i]); *swapchain_out = &chain->base; return VK_SUCCESS; @@ -1211,6 +1352,9 @@ fail_init_images: x11_image_finish(chain, pAllocator, &chain->images[j]); fail_register: + for (int i = 0; i < 2; i++) + vk_free(pAllocator, modifiers[i]); + xcb_unregister_for_special_event(chain->conn, chain->special_event); wsi_swapchain_finish(&chain->base);