diff options
author | Denis | 2023-12-19 21:47:21 +0100 |
---|---|---|
committer | Denis | 2023-12-19 21:47:21 +0100 |
commit | 1b696bc7941a951d94c22425e3bff09634145908 (patch) | |
tree | d847ad6ded19e6e163ddb4bc283caf2cd3e5b1d4 | |
parent | 6ae54c5c2eabeb8a3cc033149795c245b7f2c53a (diff) | |
download | aur-1b696bc7941a951d94c22425e3bff09634145908.tar.gz |
Remove unused files
-rw-r--r-- | .SRCINFO | 4 | ||||
-rw-r--r-- | PKGBUILD | 4 | ||||
-rw-r--r-- | gamescope.patch | 6572 | ||||
-rw-r--r-- | llvm32.native | 2 |
4 files changed, 0 insertions, 6582 deletions
@@ -42,8 +42,6 @@ pkgbase = lib32-mesa-amdonly-gaming-git options = !lto source = mesa::git+https://gitlab.freedesktop.org/mesa/mesa.git#branch=main source = LICENSE - source = llvm32.native - source = gamescope.patch validpgpkeys = 8703B6700E7EE06D7A39B8D6EDAE37B02CEB490D validpgpkeys = 946D09B5E4C9845E63075FF1D961C596A7203456 validpgpkeys = E3E8F480C52ADD73B278EE78E1ECBE07D7D70895 @@ -52,8 +50,6 @@ pkgbase = lib32-mesa-amdonly-gaming-git validpgpkeys = 57551DE15B968F6341C248F68D8E31AFC32428A6 b2sums = SKIP b2sums = cc60238726b35133b5b729fb4ed1e76e04136588533615d84b4a54656d5b41727d5e7ff06ef4de3eb102eed6669d6c5c5cb8ac9fbdf6fc25aa477877c5c3ba87 - b2sums = f84a2ec7aa5cd0e3efcfee69897e3da5c6c7031a07b7c93b43f1a709cc0ae0fd312c56c659e7cb7f2e276cbe49be6e586f117320404d2978b09ae0969d919eaf - b2sums = 6219a0797724ab17b36f85a134349ffa52f3fce74490834c5f86b474ba893cbb34ebef604cd72c851436296add906dbdb8fca9eb50d1e5f74c7caa8e2963bdcc pkgname = lib32-amdonly-gaming-vulkan-mesa-layers pkgdesc = Mesa's Vulkan layers (32-bit) @@ -73,13 +73,9 @@ makedepends=( source=( 'mesa::git+https://gitlab.freedesktop.org/mesa/mesa.git#branch=main' 'LICENSE' - 'llvm32.native' - gamescope.patch ) b2sums=('SKIP' 'cc60238726b35133b5b729fb4ed1e76e04136588533615d84b4a54656d5b41727d5e7ff06ef4de3eb102eed6669d6c5c5cb8ac9fbdf6fc25aa477877c5c3ba87' # LICENSE - 'f84a2ec7aa5cd0e3efcfee69897e3da5c6c7031a07b7c93b43f1a709cc0ae0fd312c56c659e7cb7f2e276cbe49be6e586f117320404d2978b09ae0969d919eaf' # llvm32.native - '6219a0797724ab17b36f85a134349ffa52f3fce74490834c5f86b474ba893cbb34ebef604cd72c851436296add906dbdb8fca9eb50d1e5f74c7caa8e2963bdcc' # gamescope.patch ) validpgpkeys=('8703B6700E7EE06D7A39B8D6EDAE37B02CEB490D' # Emil Velikov <emil.l.velikov@gmail.com> '946D09B5E4C9845E63075FF1D961C596A7203456' # Andres Gomez <tanty@igalia.com> diff --git a/gamescope.patch b/gamescope.patch deleted file mode 100644 index 2858db116864..000000000000 --- a/gamescope.patch +++ /dev/null @@ -1,6572 +0,0 @@ -From 9286f07049608623388a09256ef223bac86c2bac Mon Sep 17 00:00:00 2001 -From: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl> -Date: Mon, 21 Feb 2022 18:43:54 +0100 -Subject: [PATCH 1/5] STEAMOS: Dynamic swapchain override for gamescope limiter - ---- - src/loader/loader_dri3_helper.c | 42 +++++++++++++++++++++++++++++++-- - src/loader/loader_dri3_helper.h | 1 + - src/loader/meson.build | 2 +- - src/vulkan/wsi/wsi_common_x11.c | 38 +++++++++++++++++++++++++++++ - 4 files changed, 80 insertions(+), 3 deletions(-) - -diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c -index 2631a9e2fd5..dbf6db349c6 100644 ---- a/src/loader/loader_dri3_helper.c -+++ b/src/loader/loader_dri3_helper.c -@@ -289,6 +289,30 @@ dri3_update_max_num_back(struct loader_dri3_drawable *draw) - } - } - -+static unsigned -+gamescope_swapchain_override() -+{ -+ const char *path = getenv("GAMESCOPE_LIMITER_FILE"); -+ if (!path) -+ return 0; -+ -+ static simple_mtx_t mtx = SIMPLE_MTX_INITIALIZER; -+ static int fd = -1; -+ -+ simple_mtx_lock(&mtx); -+ if (fd < 0) { -+ fd = open(path, O_RDONLY); -+ } -+ simple_mtx_unlock(&mtx); -+ -+ if (fd < 0) -+ return 0; -+ -+ uint32_t override_value = 0; -+ pread(fd, &override_value, sizeof(override_value), 0); -+ return override_value; -+} -+ - void - loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval) - { -@@ -303,10 +327,12 @@ loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval) - * PS. changing from value A to B and A < B won't cause swap out of order but - * may still gets wrong target_msc value at the beginning. - */ -- if (draw->swap_interval != interval) -+ if (draw->orig_swap_interval != interval) - loader_dri3_swapbuffer_barrier(draw); - -- draw->swap_interval = interval; -+ draw->orig_swap_interval = interval; -+ if (gamescope_swapchain_override() != 1) -+ draw->swap_interval = interval; - } - - static void -@@ -438,6 +464,12 @@ loader_dri3_drawable_init(xcb_connection_t *conn, - draw->swap_interval = dri_get_initial_swap_interval(draw->dri_screen_render_gpu, - draw->ext->config); - -+ draw->orig_swap_interval = draw->swap_interval; -+ -+ unsigned gamescope_override = gamescope_swapchain_override(); -+ if (gamescope_override == 1) -+ draw->swap_interval = 1; -+ - dri3_update_max_num_back(draw); - - /* Create a new drawable */ -@@ -1085,6 +1117,12 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw, - if (draw->type == LOADER_DRI3_DRAWABLE_WINDOW) { - dri3_fence_reset(draw->conn, back); - -+ unsigned gamescope_override = gamescope_swapchain_override(); -+ if (gamescope_override == 1) -+ draw->swap_interval = 1; -+ else -+ draw->swap_interval = draw->orig_swap_interval; -+ - /* Compute when we want the frame shown by taking the last known - * successful MSC and adding in a swap interval for each outstanding swap - * request. target_msc=divisor=remainder=0 means "Use glXSwapBuffers() -diff --git a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h -index cc2362dd599..fe73b3f329c 100644 ---- a/src/loader/loader_dri3_helper.h -+++ b/src/loader/loader_dri3_helper.h -@@ -178,6 +178,7 @@ struct loader_dri3_drawable { - bool block_on_depleted_buffers; - bool queries_buffer_age; - int swap_interval; -+ int orig_swap_interval; - - struct loader_dri3_extensions *ext; - const struct loader_dri3_vtable *vtable; -diff --git a/src/loader/meson.build b/src/loader/meson.build -index 043cc852112..8391ff38936 100644 ---- a/src/loader/meson.build -+++ b/src/loader/meson.build -@@ -29,7 +29,7 @@ if with_platform_x11 and with_dri3 - dependencies : [ - idep_mesautil, - dep_libdrm, dep_xcb_dri3, dep_xcb_present, dep_xcb_sync, dep_xshmfence, -- dep_xcb_xfixes, -+ dep_xcb_xfixes, dep_xcb_xrandr, idep_mesautil - ], - build_by_default : false, - ) -diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c -index b7724c028ea..0302e90d40e 100644 ---- a/src/vulkan/wsi/wsi_common_x11.c -+++ b/src/vulkan/wsi/wsi_common_x11.c -@@ -48,6 +48,7 @@ - #include "util/hash_table.h" - #include "util/os_file.h" - #include "util/os_time.h" -+#include "util/simple_mtx.h" - #include "util/u_debug.h" - #include "util/u_thread.h" - #include "util/xmlconfig.h" -@@ -219,6 +220,30 @@ wsi_x11_detect_xwayland(xcb_connection_t *conn, - return is_xwayland; - } - -+static unsigned -+gamescope_swapchain_override() -+{ -+ const char *path = getenv("GAMESCOPE_LIMITER_FILE"); -+ if (!path) -+ return 0; -+ -+ static simple_mtx_t mtx = SIMPLE_MTX_INITIALIZER; -+ static int fd = -1; -+ -+ simple_mtx_lock(&mtx); -+ if (fd < 0) { -+ fd = open(path, O_RDONLY); -+ } -+ simple_mtx_unlock(&mtx); -+ -+ if (fd < 0) -+ return 0; -+ -+ uint32_t override_value = 0; -+ pread(fd, &override_value, sizeof(override_value), 0); -+ return override_value; -+} -+ - static struct wsi_x11_connection * - wsi_x11_connection_create(struct wsi_device *wsi_dev, - xcb_connection_t *conn) -@@ -1104,6 +1129,8 @@ struct x11_swapchain { - /* Total number of images returned to application in AcquireNextImage. */ - uint64_t present_poll_acquire_count; - -+ VkPresentModeKHR orig_present_mode; -+ - struct x11_image images[0]; - }; - VK_DEFINE_NONDISP_HANDLE_CASTS(x11_swapchain, base.base, VkSwapchainKHR, -@@ -1854,6 +1881,12 @@ x11_queue_present(struct wsi_swapchain *anv_chain, - if (chain->status < 0) - return chain->status; - -+ unsigned gamescope_override = gamescope_swapchain_override(); -+ if ((gamescope_override == 1 && chain->base.present_mode != VK_PRESENT_MODE_FIFO_KHR) || -+ (gamescope_override != 1 && chain->base.present_mode != chain->orig_present_mode)) { -+ return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR); -+ } -+ - if (damage && damage->pRectangles && damage->rectangleCount > 0 && - damage->rectangleCount <= MAX_DAMAGE_RECTS) { - xcb_rectangle_t rects[MAX_DAMAGE_RECTS]; -@@ -2612,6 +2645,10 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, - xcb_void_cookie_t cookie; - VkResult result; - VkPresentModeKHR present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo); -+ VkPresentModeKHR orig_present_mode = present_mode; -+ -+ if (gamescope_swapchain_override() == 1) -+ present_mode = VK_PRESENT_MODE_FIFO_KHR; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); - -@@ -2724,6 +2761,7 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, - chain->base.wait_for_present = x11_wait_for_present; - chain->base.release_images = x11_release_images; - chain->base.present_mode = present_mode; -+ chain->orig_present_mode = orig_present_mode; - chain->base.image_count = num_images; - chain->conn = conn; - chain->window = window; --- -2.43.0 - - -From 172b4926c459e8eda16549814d450e206ef0eab2 Mon Sep 17 00:00:00 2001 -From: Derek Foreman <derek.foreman@collabora.com> -Date: Wed, 20 Sep 2023 10:40:33 -0500 -Subject: [PATCH 2/5] vulkan/wsi/wayland: refactor wayland dispatch code - -We currently have two similar but different bits of code to dispatch -wayland event queues. Pull out as much common code as possible. - -Signed-off-by: Derek Foreman <derek.foreman@collabora.com> ---- - src/vulkan/wsi/wsi_common_wayland.c | 399 +++++++++++++++------------- - 1 file changed, 208 insertions(+), 191 deletions(-) - -diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c -index 4d52171e28b..75e1a361a0b 100644 ---- a/src/vulkan/wsi/wsi_common_wayland.c -+++ b/src/vulkan/wsi/wsi_common_wayland.c -@@ -96,6 +96,11 @@ struct wsi_wl_display { - struct wl_display *wl_display; - /* Actually a proxy wrapper around the event queue */ - struct wl_display *wl_display_wrapper; -+ -+ pthread_mutex_t wl_fd_lock; -+ pthread_cond_t wl_fd_reader_finished; -+ bool wl_fd_read_in_progress; -+ - struct wl_event_queue *queue; - - struct wl_shm *wl_shm; -@@ -157,6 +162,8 @@ struct wsi_wl_surface { - struct wsi_wl_swapchain { - struct wsi_swapchain base; - -+ struct wl_event_queue *queue; -+ - struct wsi_wl_surface *wsi_wl_surface; - struct wp_tearing_control_v1 *tearing_control; - -@@ -180,10 +187,7 @@ struct wsi_wl_swapchain { - pthread_mutex_t lock; /* protects all members */ - uint64_t max_completed; - struct wl_list outstanding_list; -- pthread_cond_t list_advanced; -- struct wl_event_queue *queue; - struct wp_presentation *wp_presentation; -- bool dispatch_in_progress; - } present_ids; - - struct wsi_wl_image images[0]; -@@ -208,6 +212,135 @@ find_format(struct u_vector *formats, VkFormat format) - return NULL; - } - -+static int -+wsi_wl_display_read_queue_with_timeout_internal(struct wsi_wl_display *wsi_wl_display, -+ struct wl_event_queue *queue, -+ uint64_t atimeout) -+{ -+ uint64_t current_time_nsec; -+ struct timespec rel_timeout, end_time, current_time; -+ int ret; -+ -+ if (wl_display_prepare_read_queue(wsi_wl_display->wl_display, queue) < 0) { -+ /* Another thread might have read events for our queue already. Go -+ * back to dispatch them. -+ */ -+ pthread_mutex_unlock(&wsi_wl_display->wl_fd_lock); -+ if (errno == EAGAIN) -+ return VK_SUCCESS; -+ -+ return VK_ERROR_OUT_OF_DATE_KHR; -+ } -+ -+ wsi_wl_display->wl_fd_read_in_progress = true; -+ pthread_mutex_unlock(&wsi_wl_display->wl_fd_lock); -+ -+ while (1) { -+ struct pollfd pollfd = { -+ .fd = wl_display_get_fd(wsi_wl_display->wl_display), -+ .events = POLLIN -+ }; -+ -+ current_time_nsec = os_time_get_nano(); -+ if (current_time_nsec > atimeout) { -+ rel_timeout.tv_sec = 0; -+ rel_timeout.tv_nsec = 0; -+ } else { -+ timespec_from_nsec(¤t_time, current_time_nsec); -+ timespec_from_nsec(&end_time, atimeout); -+ timespec_sub(&rel_timeout, &end_time, ¤t_time); -+ } -+ -+ ret = ppoll(&pollfd, 1, &rel_timeout, NULL); -+ if (ret < 0) { -+ if (errno == EINTR || errno == EAGAIN) -+ continue; -+ -+ ret = VK_ERROR_OUT_OF_DATE_KHR; -+ } else if (ret == 0) -+ ret = VK_TIMEOUT; -+ else -+ ret = VK_SUCCESS; -+ -+ break; -+ } -+ -+ if (ret != VK_SUCCESS) { -+ wl_display_cancel_read(wsi_wl_display->wl_display); -+ } else { -+ ret = wl_display_read_events(wsi_wl_display->wl_display); -+ if (ret != 0) -+ ret = VK_ERROR_OUT_OF_DATE_KHR; -+ } -+ -+ pthread_mutex_lock(&wsi_wl_display->wl_fd_lock); -+ wsi_wl_display->wl_fd_read_in_progress = false; -+ pthread_cond_broadcast(&wsi_wl_display->wl_fd_reader_finished); -+ return ret; -+} -+ -+static int -+wsi_wl_display_dispatch_queue_with_timeout(struct wsi_wl_display *wsi_wl_display, -+ struct wl_event_queue *queue, -+ uint64_t timeout) -+{ -+ int err; -+ int n_events; -+ uint64_t atimeout, now; -+ -+ if (timeout == UINT64_MAX) -+ atimeout = timeout; -+ else -+ atimeout = os_time_get_absolute_timeout(timeout); -+ -+ while (1) { -+ n_events = wl_display_dispatch_queue_pending(wsi_wl_display->wl_display, -+ queue); -+ if (n_events > 0) { -+ err = VK_SUCCESS; -+ break; -+ } -+ pthread_mutex_lock(&wsi_wl_display->wl_fd_lock); -+ -+ if (wsi_wl_display->wl_fd_read_in_progress) { -+ struct timespec end_time; -+ -+ timespec_from_nsec(&end_time, atimeout); -+ -+ err = pthread_cond_timedwait(&wsi_wl_display->wl_fd_reader_finished, -+ &wsi_wl_display->wl_fd_lock, -+ &end_time); -+ if (err) { -+ if (errno == ETIMEDOUT) -+ err = VK_TIMEOUT; -+ else -+ err = VK_ERROR_OUT_OF_DATE_KHR; -+ } else { -+ /* We don't know if the other thread actually -+ * dispatched anything, so let the caller decide -+ * whether it should continue. -+ */ -+ err = VK_INCOMPLETE; -+ } -+ } else { -+ err = wsi_wl_display_read_queue_with_timeout_internal(wsi_wl_display, -+ queue, -+ timeout); -+ } -+ -+ pthread_mutex_unlock(&wsi_wl_display->wl_fd_lock); -+ -+ now = os_time_get_nano(); -+ if (now > atimeout) { -+ err = VK_TIMEOUT; -+ break; -+ } -+ -+ } -+ -+ return err; -+} -+ - static struct wsi_wl_format * - wsi_wl_display_add_vk_format(struct wsi_wl_display *display, - struct u_vector *formats, -@@ -833,6 +966,8 @@ wsi_wl_display_finish(struct wsi_wl_display *display) - wl_proxy_wrapper_destroy(display->wl_display_wrapper); - if (display->queue) - wl_event_queue_destroy(display->queue); -+ pthread_mutex_destroy(&display->wl_fd_lock); -+ pthread_cond_destroy(&display->wl_fd_reader_finished); - } - - static VkResult -@@ -851,6 +986,11 @@ wsi_wl_display_init(struct wsi_wayland *wsi_wl, - display->wl_display = wl_display; - display->sw = sw; - -+ display->wl_fd_read_in_progress = false; -+ pthread_mutex_init(&display->wl_fd_lock, NULL); -+ if (!wsi_init_pthread_cond_monotonic(&display->wl_fd_reader_finished)) -+ goto fail; -+ - display->queue = wl_display_create_queue(wl_display); - if (!display->queue) { - result = VK_ERROR_OUT_OF_HOST_MEMORY; -@@ -951,6 +1091,7 @@ fail_registry: - wl_registry_destroy(registry); - - fail: -+ pthread_mutex_destroy(&display->wl_fd_lock); - wsi_wl_display_finish(display); - return result; - } -@@ -1672,19 +1813,15 @@ wsi_wl_swapchain_wait_for_present(struct wsi_swapchain *wsi_chain, - uint64_t timeout) - { - struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -- struct wl_display *wl_display = chain->wsi_wl_surface->display->wl_display; -- struct timespec end_time; -- int wl_fd = wl_display_get_fd(wl_display); -- VkResult ret; -- int err; -+ uint64_t end_time, time_left, now; -+ int ret; -+ bool expired = false; -+ bool finished; - -- uint64_t atimeout; -- if (timeout == 0 || timeout == UINT64_MAX) -- atimeout = timeout; -+ if (timeout == UINT64_MAX) -+ end_time = timeout; - else -- atimeout = os_time_get_absolute_timeout(timeout); -- -- timespec_from_nsec(&end_time, atimeout); -+ end_time = os_time_get_absolute_timeout(timeout); - - /* Need to observe that the swapchain semaphore has been unsignalled, - * as this is guaranteed when a present is complete. */ -@@ -1700,141 +1837,45 @@ wsi_wl_swapchain_wait_for_present(struct wsi_swapchain *wsi_chain, - return VK_SUCCESS; - } - -+ while (1) { -+ ret = wl_display_dispatch_queue_pending(chain->wsi_wl_surface->display->wl_display, -+ chain->queue); -+ if (ret < 0) -+ return VK_ERROR_OUT_OF_DATE_KHR; -+ - /* PresentWait can be called concurrently. - * If there is contention on this mutex, it means there is currently a dispatcher in flight holding the lock. - * The lock is only held while there is forward progress processing events from Wayland, - * so there should be no problem locking without timeout. - * We would like to be able to support timeout = 0 to query the current max_completed count. - * A timedlock with no timeout can be problematic in that scenario. */ -- err = pthread_mutex_lock(&chain->present_ids.lock); -- if (err != 0) -- return VK_ERROR_OUT_OF_DATE_KHR; -- -- if (chain->present_ids.max_completed >= present_id) { -+ pthread_mutex_lock(&chain->present_ids.lock); -+ finished = chain->present_ids.max_completed >= present_id; - pthread_mutex_unlock(&chain->present_ids.lock); -- return VK_SUCCESS; -- } -- -- /* Someone else is dispatching events; wait for them to update the chain -- * status and wake us up. */ -- while (chain->present_ids.dispatch_in_progress) { -- /* We only own the lock when the wait succeeds. */ -- err = pthread_cond_timedwait(&chain->present_ids.list_advanced, -- &chain->present_ids.lock, &end_time); -- -- if (err == ETIMEDOUT) { -- pthread_mutex_unlock(&chain->present_ids.lock); -- return VK_TIMEOUT; -- } else if (err != 0) { -- pthread_mutex_unlock(&chain->present_ids.lock); -- return VK_ERROR_OUT_OF_DATE_KHR; -- } -- -- if (chain->present_ids.max_completed >= present_id) { -- pthread_mutex_unlock(&chain->present_ids.lock); -+ if (finished) - return VK_SUCCESS; -- } -- -- /* Whoever was previously dispatching the events isn't anymore, so we -- * will take over and fall through below. */ -- if (!chain->present_ids.dispatch_in_progress) -- break; -- } -- -- assert(!chain->present_ids.dispatch_in_progress); -- chain->present_ids.dispatch_in_progress = true; -- -- /* Whether or not we were dispatching the events before, we are now: pull -- * all the new events from our event queue, post them, and wake up everyone -- * else who might be waiting. */ -- while (1) { -- ret = wl_display_dispatch_queue_pending(wl_display, chain->present_ids.queue); -- if (ret < 0) { -- ret = VK_ERROR_OUT_OF_DATE_KHR; -- goto relinquish_dispatch; -- } -- -- /* Some events dispatched: check the new completions. */ -- if (ret > 0) { -- /* Completed our own present; stop our own dispatching and let -- * someone else pick it up. */ -- if (chain->present_ids.max_completed >= present_id) { -- ret = VK_SUCCESS; -- goto relinquish_dispatch; -- } -- -- /* Wake up other waiters who may have been unblocked by the events -- * we just read. */ -- pthread_cond_broadcast(&chain->present_ids.list_advanced); -- } -- -- /* Check for timeout, and relinquish the dispatch to another thread -- * if we're over our budget. */ -- uint64_t current_time_nsec = os_time_get_nano(); -- if (current_time_nsec > atimeout) { -- ret = VK_TIMEOUT; -- goto relinquish_dispatch; -- } -- -- /* To poll and read from WL fd safely, we must be cooperative. -- * See wl_display_prepare_read_queue in https://wayland.freedesktop.org/docs/html/apb.html */ -- -- /* Try to read events from the server. */ -- ret = wl_display_prepare_read_queue(wl_display, chain->present_ids.queue); -- if (ret < 0) { -- /* Another thread might have read events for our queue already. Go -- * back to dispatch them. -- */ -- if (errno == EAGAIN) -- continue; -- ret = VK_ERROR_OUT_OF_DATE_KHR; -- goto relinquish_dispatch; -- } - -- /* Drop the lock around poll, so people can wait whilst we sleep. */ -- pthread_mutex_unlock(&chain->present_ids.lock); -- -- struct pollfd pollfd = { -- .fd = wl_fd, -- .events = POLLIN -- }; -- struct timespec current_time, rel_timeout; -- timespec_from_nsec(¤t_time, current_time_nsec); -- timespec_sub(&rel_timeout, &end_time, ¤t_time); -- ret = ppoll(&pollfd, 1, &rel_timeout, NULL); -+ if (expired) -+ return VK_TIMEOUT; - -- /* Re-lock after poll; either we're dispatching events under the lock or -- * bouncing out from an error also under the lock. We can't use timedlock -- * here because we need to acquire to clear dispatch_in_progress. */ -- pthread_mutex_lock(&chain->present_ids.lock); -+ now = os_time_get_nano(); -+ if (now > end_time) -+ time_left = 0; -+ else -+ time_left = end_time - now; - -- if (ret <= 0) { -- int lerrno = errno; -- wl_display_cancel_read(wl_display); -- if (ret < 0) { -- /* If ppoll() was interrupted, try again. */ -- if (lerrno == EINTR || lerrno == EAGAIN) -- continue; -- ret = VK_ERROR_OUT_OF_DATE_KHR; -- goto relinquish_dispatch; -- } -- assert(ret == 0); -+ ret = wsi_wl_display_dispatch_queue_with_timeout(chain->wsi_wl_surface->display, -+ chain->queue, -+ time_left); -+ if (ret == VK_INCOMPLETE) - continue; -- } - -- ret = wl_display_read_events(wl_display); -- if (ret < 0) { -- ret = VK_ERROR_OUT_OF_DATE_KHR; -- goto relinquish_dispatch; -- } -- } -+ if (ret != VK_SUCCESS && ret != VK_TIMEOUT) -+ return ret; - --relinquish_dispatch: -- assert(chain->present_ids.dispatch_in_progress); -- chain->present_ids.dispatch_in_progress = false; -- pthread_cond_broadcast(&chain->present_ids.list_advanced); -- pthread_mutex_unlock(&chain->present_ids.lock); -- return ret; -+ if (time_left == 0) -+ expired = true; -+ } - } - - static VkResult -@@ -1844,19 +1885,18 @@ wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain, - { - struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; - struct wsi_wl_surface *wsi_wl_surface = chain->wsi_wl_surface; -- struct timespec start_time, end_time; -- struct timespec rel_timeout; -- int wl_fd = wl_display_get_fd(wsi_wl_surface->display->wl_display); -- -- timespec_from_nsec(&rel_timeout, info->timeout); -+ uint64_t end_time, time_left, now; -+ bool expired = false; -+ int ret; - -- clock_gettime(CLOCK_MONOTONIC, &start_time); -- timespec_add(&end_time, &rel_timeout, &start_time); -+ if (info->timeout == UINT64_MAX) -+ end_time = info->timeout; -+ else -+ end_time = os_time_get_absolute_timeout(info->timeout); - - while (1) { -- /* Try to dispatch potential events. */ -- int ret = wl_display_dispatch_queue_pending(wsi_wl_surface->display->wl_display, -- wsi_wl_surface->display->queue); -+ ret = wl_display_dispatch_queue_pending(wsi_wl_surface->display->wl_display, -+ wsi_wl_surface->display->queue); - if (ret < 0) - return VK_ERROR_OUT_OF_DATE_KHR; - -@@ -1870,46 +1910,26 @@ wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain, - } - } - -- /* Check for timeout. */ -- struct timespec current_time; -- clock_gettime(CLOCK_MONOTONIC, ¤t_time); -- if (timespec_after(¤t_time, &end_time)) -- return (info->timeout ? VK_TIMEOUT : VK_NOT_READY); -+ if (expired) -+ return info->timeout ? VK_TIMEOUT : VK_NOT_READY; - -- /* Try to read events from the server. */ -- ret = wl_display_prepare_read_queue(wsi_wl_surface->display->wl_display, -- wsi_wl_surface->display->queue); -- if (ret < 0) { -- /* Another thread might have read events for our queue already. Go -- * back to dispatch them. -- */ -- if (errno == EAGAIN) -- continue; -- return VK_ERROR_OUT_OF_DATE_KHR; -- } -+ now = os_time_get_nano(); -+ if (now > end_time) -+ time_left = 0; -+ else -+ time_left = end_time - now; - -- struct pollfd pollfd = { -- .fd = wl_fd, -- .events = POLLIN -- }; -- timespec_sub(&rel_timeout, &end_time, ¤t_time); -- ret = ppoll(&pollfd, 1, &rel_timeout, NULL); -- if (ret <= 0) { -- int lerrno = errno; -- wl_display_cancel_read(wsi_wl_surface->display->wl_display); -- if (ret < 0) { -- /* If ppoll() was interrupted, try again. */ -- if (lerrno == EINTR || lerrno == EAGAIN) -- continue; -- return VK_ERROR_OUT_OF_DATE_KHR; -- } -- assert(ret == 0); -+ ret = wsi_wl_display_dispatch_queue_with_timeout(wsi_wl_surface->display, -+ wsi_wl_surface->display->queue, -+ time_left); -+ if (ret == VK_ERROR_OUT_OF_DATE_KHR) -+ return ret; -+ -+ if (ret == VK_INCOMPLETE) - continue; -- } - -- ret = wl_display_read_events(wsi_wl_surface->display->wl_display); -- if (ret < 0) -- return VK_ERROR_OUT_OF_DATE_KHR; -+ if (ret == VK_TIMEOUT) -+ expired = true; - } - } - -@@ -1930,9 +1950,10 @@ presentation_handle_presented(void *data, - { - struct wsi_wl_present_id *id = data; - -- /* present_ids.lock already held around dispatch */ -+ pthread_mutex_lock(&id->chain->present_ids.lock); - if (id->present_id > id->chain->present_ids.max_completed) - id->chain->present_ids.max_completed = id->present_id; -+ pthread_mutex_unlock(&id->chain->present_ids.lock); - - wp_presentation_feedback_destroy(feedback); - wl_list_remove(&id->link); -@@ -1945,9 +1966,10 @@ presentation_handle_discarded(void *data, - { - struct wsi_wl_present_id *id = data; - -- /* present_ids.lock already held around dispatch */ -+ pthread_mutex_lock(&id->chain->present_ids.lock); - if (id->present_id > id->chain->present_ids.max_completed) - id->chain->present_ids.max_completed = id->present_id; -+ pthread_mutex_unlock(&id->chain->present_ids.lock); - - wp_presentation_feedback_destroy(feedback); - wl_list_remove(&id->link); -@@ -2195,8 +2217,6 @@ wsi_wl_swapchain_chain_free(struct wsi_wl_swapchain *chain, - chain->wsi_wl_surface->chain = NULL; - - if (chain->present_ids.wp_presentation) { -- assert(!chain->present_ids.dispatch_in_progress); -- - /* In VK_EXT_swapchain_maintenance1 there is no requirement to wait for all present IDs to be complete. - * Waiting for the swapchain fence is enough. - * Just clean up anything user did not wait for. */ -@@ -2208,7 +2228,6 @@ wsi_wl_swapchain_chain_free(struct wsi_wl_swapchain *chain, - } - - wl_proxy_wrapper_destroy(chain->present_ids.wp_presentation); -- pthread_cond_destroy(&chain->present_ids.list_advanced); - pthread_mutex_destroy(&chain->present_ids.lock); - } - -@@ -2369,18 +2388,16 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, - chain->num_drm_modifiers = num_drm_modifiers; - chain->drm_modifiers = drm_modifiers; - -+ chain->queue = wl_display_create_queue(chain->wsi_wl_surface->display->wl_display); -+ - if (chain->wsi_wl_surface->display->wp_presentation_notwrapped) { -- if (!wsi_init_pthread_cond_monotonic(&chain->present_ids.list_advanced)) -- goto fail; - pthread_mutex_init(&chain->present_ids.lock, NULL); - - wl_list_init(&chain->present_ids.outstanding_list); -- chain->present_ids.queue = -- wl_display_create_queue(chain->wsi_wl_surface->display->wl_display); - chain->present_ids.wp_presentation = - wl_proxy_create_wrapper(chain->wsi_wl_surface->display->wp_presentation_notwrapped); - wl_proxy_set_queue((struct wl_proxy *) chain->present_ids.wp_presentation, -- chain->present_ids.queue); -+ chain->queue); - } - - chain->fifo_ready = true; --- -2.43.0 - - -From b9a2fb065c30a9065615c894d7da4a4796a4f487 Mon Sep 17 00:00:00 2001 -From: Denis <benato.denis96@gmail.com> -Date: Sun, 10 Dec 2023 14:46:16 +0100 -Subject: [PATCH 3/5] vulkan/wsi/wayland: Use commit_timing/commit_queue - protocol for FIFO - -The commit_timing protocol allows us to set a presentation timestamp, -and the commit_queue protocol allows us to request FIFO semantics for -committed state (instead of the default mailbox). - -I these are available, use them to implement Vulkan's FIFO presentation -mode. - -Signed-off-by: Derek Foreman <derek.foreman@collabora.com> ---- - src/egl/wayland/wayland-drm/meson.build | 2 + - src/vulkan/wsi/meson.build | 2 + - src/vulkan/wsi/wsi_common_wayland.c | 138 +- - src/vulkan/wsi/wsi_common_wayland.c.orig | 2475 ++++++++++++++++++++++ - 4 files changed, 2605 insertions(+), 12 deletions(-) - create mode 100644 src/vulkan/wsi/wsi_common_wayland.c.orig - -diff --git a/src/egl/wayland/wayland-drm/meson.build b/src/egl/wayland/wayland-drm/meson.build -index ac822acec67..8b6044f09e5 100644 ---- a/src/egl/wayland/wayland-drm/meson.build -+++ b/src/egl/wayland/wayland-drm/meson.build -@@ -59,6 +59,8 @@ libwayland_drm = static_library( - # here for now as the maybe-least-bad solution. - wp_dir = dep_wl_protocols.get_variable(pkgconfig : 'pkgdatadir', internal : 'pkgdatadir') - wp_protos = { -+ 'commit-queue-v1': 'staging/commit-queue/commit-queue-v1.xml', -+ 'commit-timing-v1': 'staging/commit-timing/commit-timing-v1.xml', - 'linux-dmabuf-unstable-v1': 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml', - 'presentation-time': 'stable/presentation-time/presentation-time.xml', - 'tearing-control-v1': 'staging/tearing-control/tearing-control-v1.xml', -diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build -index c8206eac996..48ea09b99aa 100644 ---- a/src/vulkan/wsi/meson.build -+++ b/src/vulkan/wsi/meson.build -@@ -31,6 +31,8 @@ endif - - if with_platform_wayland - files_vulkan_wsi += files('wsi_common_wayland.c') -+ files_vulkan_wsi += wp_files['commit-queue-v1'] -+ files_vulkan_wsi += wp_files['commit-timing-v1'] - files_vulkan_wsi += wp_files['linux-dmabuf-unstable-v1'] - files_vulkan_wsi += wp_files['presentation-time'] - files_vulkan_wsi += wp_files['tearing-control-v1'] -diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c -index 75e1a361a0b..16848fb0a2a 100644 ---- a/src/vulkan/wsi/wsi_common_wayland.c -+++ b/src/vulkan/wsi/wsi_common_wayland.c -@@ -41,6 +41,8 @@ - #include "vk_util.h" - #include "wsi_common_entrypoints.h" - #include "wsi_common_private.h" -+#include "commit-queue-v1-client-protocol.h" -+#include "commit-timing-v1-client-protocol.h" - #include "linux-dmabuf-unstable-v1-client-protocol.h" - #include "presentation-time-client-protocol.h" - #include "tearing-control-v1-client-protocol.h" -@@ -113,6 +115,9 @@ struct wsi_wl_display { - /* users want per-chain wsi_wl_swapchain->present_ids.wp_presentation */ - struct wp_presentation *wp_presentation_notwrapped; - -+ struct wp_commit_queue_manager_v1 *commit_queue_manager; -+ struct wp_commit_timing_manager_v1 *commit_timing_manager; -+ - struct wsi_wayland *wsi_wl; - - /* Formats populated by zwp_linux_dmabuf_v1 or wl_shm interfaces */ -@@ -135,6 +140,7 @@ struct wsi_wayland { - - struct wsi_wl_image { - struct wsi_image base; -+ struct wsi_wl_swapchain *chain; - struct wl_buffer *buffer; - bool busy; - int shm_fd; -@@ -166,6 +172,9 @@ struct wsi_wl_swapchain { - - struct wsi_wl_surface *wsi_wl_surface; - struct wp_tearing_control_v1 *tearing_control; -+ struct wp_commit_queue_v1 *commit_queue; -+ struct wp_commit_timer_v1 *commit_timer; -+ bool can_timestamp; - - struct wl_callback *frame; - -@@ -181,13 +190,17 @@ struct wsi_wl_swapchain { - const uint64_t *drm_modifiers; - - VkPresentModeKHR present_mode; -- bool fifo_ready; -+ bool legacy_fifo_ready; -+ -+ uint64_t last_target_time; - - struct { - pthread_mutex_t lock; /* protects all members */ - uint64_t max_completed; - struct wl_list outstanding_list; - struct wp_presentation *wp_presentation; -+ uint64_t phase_time; -+ unsigned int refresh_nsec; - } present_ids; - - struct wsi_wl_image images[0]; -@@ -934,6 +947,12 @@ registry_handle_global(void *data, struct wl_registry *registry, - } else if (strcmp(interface, wp_tearing_control_manager_v1_interface.name) == 0) { - display->tearing_control_manager = - wl_registry_bind(registry, name, &wp_tearing_control_manager_v1_interface, 1); -+ } else if (strcmp(interface, wp_commit_timing_manager_v1_interface.name) == 0) { -+ display->commit_timing_manager = -+ wl_registry_bind(registry, name, &wp_commit_timing_manager_v1_interface, 1); -+ } else if (strcmp(interface, wp_commit_queue_manager_v1_interface.name) == 0) { -+ display->commit_queue_manager = -+ wl_registry_bind(registry, name, &wp_commit_queue_manager_v1_interface, 1); - } - } - -@@ -960,6 +979,10 @@ wsi_wl_display_finish(struct wsi_wl_display *display) - zwp_linux_dmabuf_v1_destroy(display->wl_dmabuf); - if (display->wp_presentation_notwrapped) - wp_presentation_destroy(display->wp_presentation_notwrapped); -+ if (display->commit_queue_manager) -+ wp_commit_queue_manager_v1_destroy(display->commit_queue_manager); -+ if (display->commit_timing_manager) -+ wp_commit_timing_manager_v1_destroy(display->commit_timing_manager); - if (display->tearing_control_manager) - wp_tearing_control_manager_v1_destroy(display->tearing_control_manager); - if (display->wl_display_wrapper) -@@ -1919,6 +1942,16 @@ wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain, - else - time_left = end_time - now; - -+ /* If we can use timestamps, we want to make sure to dispatch the queue -+ * feedback events are in so we can get a refresh rate and a vsync time to -+ * phase lock to */ -+ if (chain->can_timestamp) { -+ ret = wl_display_dispatch_queue_pending(wsi_wl_surface->display->wl_display, -+ chain->queue); -+ if (ret < 0) -+ return VK_ERROR_OUT_OF_DATE_KHR; -+ } -+ - ret = wsi_wl_display_dispatch_queue_with_timeout(wsi_wl_surface->display, - wsi_wl_surface->display->queue, - time_left); -@@ -1949,10 +1982,16 @@ presentation_handle_presented(void *data, - uint32_t flags) - { - struct wsi_wl_present_id *id = data; -+ struct timespec presentation_time; - - pthread_mutex_lock(&id->chain->present_ids.lock); - if (id->present_id > id->chain->present_ids.max_completed) - id->chain->present_ids.max_completed = id->present_id; -+ -+ presentation_time.tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo; -+ presentation_time.tv_nsec = tv_nsec; -+ id->chain->present_ids.phase_time = timespec_to_nsec(&presentation_time); -+ id->chain->present_ids.refresh_nsec = refresh; - pthread_mutex_unlock(&id->chain->present_ids.lock); - - wp_presentation_feedback_destroy(feedback); -@@ -1988,8 +2027,10 @@ frame_handle_done(void *data, struct wl_callback *callback, uint32_t serial) - { - struct wsi_wl_swapchain *chain = data; - -+ assert(!chain->can_timestamp); -+ - chain->frame = NULL; -- chain->fifo_ready = true; -+ chain->legacy_fifo_ready = true; - - wl_callback_destroy(callback); - } -@@ -1998,6 +2039,46 @@ static const struct wl_callback_listener frame_listener = { - frame_handle_done, - }; - -+static void -+set_timestamp(struct wsi_wl_swapchain *chain) -+{ -+ uint64_t now, target; -+ struct timespec target_ts; -+ uint64_t refresh; -+ uint64_t phase_time; -+ -+ now = os_time_get_nano(); -+ -+ pthread_mutex_lock(&chain->present_ids.lock); -+ phase_time = chain->present_ids.phase_time; -+ refresh = chain->present_ids.refresh_nsec; -+ pthread_mutex_unlock(&chain->present_ids.lock); -+ -+ if (refresh == 0) -+ refresh = 16666666; -+ -+ target = chain->last_target_time + refresh; -+ -+ if (now > target) { -+ uint64_t offset; -+ -+ if (phase_time > now) -+ now = phase_time; -+ -+ offset = (now - phase_time) % refresh; -+ target = now - offset + refresh; -+ } -+ -+ timespec_from_nsec(&target_ts, target); -+ wp_commit_timer_v1_set_timestamp(chain->commit_timer, -+ target_ts.tv_sec >> 32, target_ts.tv_sec, -+ target_ts.tv_nsec); -+ -+ wp_commit_queue_v1_set_queue_mode(chain->commit_queue, -+ WP_COMMIT_QUEUE_V1_QUEUE_MODE_FIFO); -+ chain->last_target_time = target; -+} -+ - static VkResult - wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, - uint32_t image_index, -@@ -2006,6 +2087,7 @@ wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, - { - struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; - struct wsi_wl_surface *wsi_wl_surface = chain->wsi_wl_surface; -+ bool mode_fifo = chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR; - - if (chain->buffer_type == WSI_WL_BUFFER_SHM_MEMCPY) { - struct wsi_wl_image *image = &chain->images[image_index]; -@@ -2015,7 +2097,7 @@ wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, - - /* For EXT_swapchain_maintenance1. We might have transitioned from FIFO to MAILBOX. - * In this case we need to let the FIFO request complete, before presenting MAILBOX. */ -- while (!chain->fifo_ready) { -+ while (!chain->can_timestamp && !chain->legacy_fifo_ready) { - int ret = wl_display_dispatch_queue(wsi_wl_surface->display->wl_display, - wsi_wl_surface->display->queue); - if (ret < 0) -@@ -2038,16 +2120,19 @@ wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, - wl_surface_damage(wsi_wl_surface->surface, 0, 0, INT32_MAX, INT32_MAX); - } - -- if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) { -- chain->frame = wl_surface_frame(wsi_wl_surface->surface); -- wl_callback_add_listener(chain->frame, &frame_listener, chain); -- chain->fifo_ready = false; -- } else { -- /* If we present MAILBOX, any subsequent presentation in FIFO can replace this image. */ -- chain->fifo_ready = true; -+ if (!chain->can_timestamp) { -+ if (mode_fifo) { -+ chain->frame = wl_surface_frame(wsi_wl_surface->surface); -+ wl_callback_add_listener(chain->frame, &frame_listener, chain); -+ chain->legacy_fifo_ready = false; -+ } else { -+ /* If we present MAILBOX, any subsequent presentation in FIFO can replace this image. */ -+ chain->legacy_fifo_ready = true; -+ } - } - -- if (present_id > 0 && chain->present_ids.wp_presentation) { -+ if (chain->present_ids.wp_presentation && -+ (present_id > 0 || (chain->can_timestamp && mode_fifo))) { - struct wsi_wl_present_id *id = - vk_zalloc(chain->wsi_wl_surface->display->wsi_wl->alloc, sizeof(*id), sizeof(uintptr_t), - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); -@@ -2066,6 +2151,10 @@ wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, - } - - chain->images[image_index].busy = true; -+ -+ if (chain->can_timestamp && mode_fifo) -+ set_timestamp(chain); -+ - wl_surface_commit(wsi_wl_surface->surface); - wl_display_flush(wsi_wl_surface->display->wl_display); - -@@ -2181,6 +2270,7 @@ wsi_wl_image_init(struct wsi_wl_swapchain *chain, - goto fail_image; - - wl_buffer_add_listener(image->buffer, &buffer_listener, image); -+ image->chain = chain; - - return VK_SUCCESS; - -@@ -2231,6 +2321,12 @@ wsi_wl_swapchain_chain_free(struct wsi_wl_swapchain *chain, - pthread_mutex_destroy(&chain->present_ids.lock); - } - -+ if (chain->commit_queue) -+ wp_commit_queue_v1_destroy(chain->commit_queue); -+ -+ if (chain->commit_timer) -+ wp_commit_timer_v1_destroy(chain->commit_timer); -+ - wsi_swapchain_finish(&chain->base); - } - -@@ -2285,6 +2381,15 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, - wp_tearing_control_v1_destroy(old_chain->tearing_control); - old_chain->tearing_control = NULL; - } -+ if (old_chain->commit_queue) { -+ wp_commit_queue_v1_destroy(old_chain->commit_queue); -+ old_chain->commit_queue = NULL; -+ old_chain->can_timestamp = false; -+ } -+ if (old_chain->commit_timer) { -+ wp_commit_timer_v1_destroy(old_chain->commit_timer); -+ old_chain->commit_timer = NULL; -+ } - } - - /* Take ownership of the wsi_wl_surface */ -@@ -2400,7 +2505,16 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, - chain->queue); - } - -- chain->fifo_ready = true; -+ chain->legacy_fifo_ready = true; -+ struct wsi_wl_display *dpy = chain->wsi_wl_surface->display; -+ if (dpy->commit_queue_manager && -+ dpy->commit_timing_manager) { -+ chain->commit_queue = wp_commit_queue_manager_v1_get_queue_controller(dpy->commit_queue_manager, -+ chain->wsi_wl_surface->surface); -+ chain->commit_timer = wp_commit_timing_manager_v1_get_timer(dpy->commit_timing_manager, -+ chain->wsi_wl_surface->surface); -+ chain->can_timestamp = true; -+ } - - for (uint32_t i = 0; i < chain->base.image_count; i++) { - result = wsi_wl_image_init(chain, &chain->images[i], -diff --git a/src/vulkan/wsi/wsi_common_wayland.c.orig b/src/vulkan/wsi/wsi_common_wayland.c.orig -new file mode 100644 -index 00000000000..75e1a361a0b ---- /dev/null -+++ b/src/vulkan/wsi/wsi_common_wayland.c.orig -@@ -0,0 +1,2475 @@ -+/* -+ * Copyright © 2015 Intel Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -+ * IN THE SOFTWARE. -+ */ -+ -+#include <wayland-client.h> -+ -+#include <assert.h> -+#include <stdlib.h> -+#include <stdio.h> -+#include <unistd.h> -+#include <errno.h> -+#include <string.h> -+#include <pthread.h> -+#include <poll.h> -+#include <sys/mman.h> -+#include <sys/types.h> -+ -+#include "drm-uapi/drm_fourcc.h" -+ -+#include "vk_instance.h" -+#include "vk_physical_device.h" -+#include "vk_util.h" -+#include "wsi_common_entrypoints.h" -+#include "wsi_common_private.h" -+#include "linux-dmabuf-unstable-v1-client-protocol.h" -+#include "presentation-time-client-protocol.h" -+#include "tearing-control-v1-client-protocol.h" -+ -+#include <util/compiler.h> -+#include <util/hash_table.h> -+#include <util/timespec.h> -+#include <util/u_endian.h> -+#include <util/u_vector.h> -+#include <util/u_dynarray.h> -+#include <util/anon_file.h> -+#include <util/os_time.h> -+ -+#ifdef MAJOR_IN_MKDEV -+#include <sys/mkdev.h> -+#endif -+#ifdef MAJOR_IN_SYSMACROS -+#include <sys/sysmacros.h> -+#endif -+ -+struct wsi_wayland; -+ -+struct wsi_wl_format { -+ VkFormat vk_format; -+ uint32_t flags; -+ struct u_vector modifiers; -+}; -+ -+struct dmabuf_feedback_format_table { -+ unsigned int size; -+ struct { -+ uint32_t format; -+ uint32_t padding; /* unused */ -+ uint64_t modifier; -+ } *data; -+}; -+ -+struct dmabuf_feedback_tranche { -+ dev_t target_device; -+ uint32_t flags; -+ struct u_vector formats; -+}; -+ -+struct dmabuf_feedback { -+ dev_t main_device; -+ struct dmabuf_feedback_format_table format_table; -+ struct util_dynarray tranches; -+ struct dmabuf_feedback_tranche pending_tranche; -+}; -+ -+struct wsi_wl_display { -+ /* The real wl_display */ -+ struct wl_display *wl_display; -+ /* Actually a proxy wrapper around the event queue */ -+ struct wl_display *wl_display_wrapper; -+ -+ pthread_mutex_t wl_fd_lock; -+ pthread_cond_t wl_fd_reader_finished; -+ bool wl_fd_read_in_progress; -+ -+ struct wl_event_queue *queue; -+ -+ struct wl_shm *wl_shm; -+ struct zwp_linux_dmabuf_v1 *wl_dmabuf; -+ struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback; -+ struct wp_tearing_control_manager_v1 *tearing_control_manager; -+ -+ struct dmabuf_feedback_format_table format_table; -+ -+ /* users want per-chain wsi_wl_swapchain->present_ids.wp_presentation */ -+ struct wp_presentation *wp_presentation_notwrapped; -+ -+ struct wsi_wayland *wsi_wl; -+ -+ /* Formats populated by zwp_linux_dmabuf_v1 or wl_shm interfaces */ -+ struct u_vector formats; -+ -+ bool sw; -+ -+ dev_t main_device; -+ bool same_gpu; -+}; -+ -+struct wsi_wayland { -+ struct wsi_interface base; -+ -+ struct wsi_device *wsi; -+ -+ const VkAllocationCallbacks *alloc; -+ VkPhysicalDevice physical_device; -+}; -+ -+struct wsi_wl_image { -+ struct wsi_image base; -+ struct wl_buffer *buffer; -+ bool busy; -+ int shm_fd; -+ void *shm_ptr; -+ unsigned shm_size; -+}; -+ -+enum wsi_wl_buffer_type { -+ WSI_WL_BUFFER_NATIVE, -+ WSI_WL_BUFFER_GPU_SHM, -+ WSI_WL_BUFFER_SHM_MEMCPY, -+}; -+ -+struct wsi_wl_surface { -+ VkIcdSurfaceWayland base; -+ -+ struct wsi_wl_swapchain *chain; -+ struct wl_surface *surface; -+ struct wsi_wl_display *display; -+ -+ struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback; -+ struct dmabuf_feedback dmabuf_feedback, pending_dmabuf_feedback; -+}; -+ -+struct wsi_wl_swapchain { -+ struct wsi_swapchain base; -+ -+ struct wl_event_queue *queue; -+ -+ struct wsi_wl_surface *wsi_wl_surface; -+ struct wp_tearing_control_v1 *tearing_control; -+ -+ struct wl_callback *frame; -+ -+ VkExtent2D extent; -+ VkFormat vk_format; -+ enum wsi_wl_buffer_type buffer_type; -+ uint32_t drm_format; -+ enum wl_shm_format shm_format; -+ -+ bool suboptimal; -+ -+ uint32_t num_drm_modifiers; -+ const uint64_t *drm_modifiers; -+ -+ VkPresentModeKHR present_mode; -+ bool fifo_ready; -+ -+ struct { -+ pthread_mutex_t lock; /* protects all members */ -+ uint64_t max_completed; -+ struct wl_list outstanding_list; -+ struct wp_presentation *wp_presentation; -+ } present_ids; -+ -+ struct wsi_wl_image images[0]; -+}; -+VK_DEFINE_NONDISP_HANDLE_CASTS(wsi_wl_swapchain, base.base, VkSwapchainKHR, -+ VK_OBJECT_TYPE_SWAPCHAIN_KHR) -+ -+enum wsi_wl_fmt_flag { -+ WSI_WL_FMT_ALPHA = 1 << 0, -+ WSI_WL_FMT_OPAQUE = 1 << 1, -+}; -+ -+static struct wsi_wl_format * -+find_format(struct u_vector *formats, VkFormat format) -+{ -+ struct wsi_wl_format *f; -+ -+ u_vector_foreach(f, formats) -+ if (f->vk_format == format) -+ return f; -+ -+ return NULL; -+} -+ -+static int -+wsi_wl_display_read_queue_with_timeout_internal(struct wsi_wl_display *wsi_wl_display, -+ struct wl_event_queue *queue, -+ uint64_t atimeout) -+{ -+ uint64_t current_time_nsec; -+ struct timespec rel_timeout, end_time, current_time; -+ int ret; -+ -+ if (wl_display_prepare_read_queue(wsi_wl_display->wl_display, queue) < 0) { -+ /* Another thread might have read events for our queue already. Go -+ * back to dispatch them. -+ */ -+ pthread_mutex_unlock(&wsi_wl_display->wl_fd_lock); -+ if (errno == EAGAIN) -+ return VK_SUCCESS; -+ -+ return VK_ERROR_OUT_OF_DATE_KHR; -+ } -+ -+ wsi_wl_display->wl_fd_read_in_progress = true; -+ pthread_mutex_unlock(&wsi_wl_display->wl_fd_lock); -+ -+ while (1) { -+ struct pollfd pollfd = { -+ .fd = wl_display_get_fd(wsi_wl_display->wl_display), -+ .events = POLLIN -+ }; -+ -+ current_time_nsec = os_time_get_nano(); -+ if (current_time_nsec > atimeout) { -+ rel_timeout.tv_sec = 0; -+ rel_timeout.tv_nsec = 0; -+ } else { -+ timespec_from_nsec(¤t_time, current_time_nsec); -+ timespec_from_nsec(&end_time, atimeout); -+ timespec_sub(&rel_timeout, &end_time, ¤t_time); -+ } -+ -+ ret = ppoll(&pollfd, 1, &rel_timeout, NULL); -+ if (ret < 0) { -+ if (errno == EINTR || errno == EAGAIN) -+ continue; -+ -+ ret = VK_ERROR_OUT_OF_DATE_KHR; -+ } else if (ret == 0) -+ ret = VK_TIMEOUT; -+ else -+ ret = VK_SUCCESS; -+ -+ break; -+ } -+ -+ if (ret != VK_SUCCESS) { -+ wl_display_cancel_read(wsi_wl_display->wl_display); -+ } else { -+ ret = wl_display_read_events(wsi_wl_display->wl_display); -+ if (ret != 0) -+ ret = VK_ERROR_OUT_OF_DATE_KHR; -+ } -+ -+ pthread_mutex_lock(&wsi_wl_display->wl_fd_lock); -+ wsi_wl_display->wl_fd_read_in_progress = false; -+ pthread_cond_broadcast(&wsi_wl_display->wl_fd_reader_finished); -+ return ret; -+} -+ -+static int -+wsi_wl_display_dispatch_queue_with_timeout(struct wsi_wl_display *wsi_wl_display, -+ struct wl_event_queue *queue, -+ uint64_t timeout) -+{ -+ int err; -+ int n_events; -+ uint64_t atimeout, now; -+ -+ if (timeout == UINT64_MAX) -+ atimeout = timeout; -+ else -+ atimeout = os_time_get_absolute_timeout(timeout); -+ -+ while (1) { -+ n_events = wl_display_dispatch_queue_pending(wsi_wl_display->wl_display, -+ queue); -+ if (n_events > 0) { -+ err = VK_SUCCESS; -+ break; -+ } -+ pthread_mutex_lock(&wsi_wl_display->wl_fd_lock); -+ -+ if (wsi_wl_display->wl_fd_read_in_progress) { -+ struct timespec end_time; -+ -+ timespec_from_nsec(&end_time, atimeout); -+ -+ err = pthread_cond_timedwait(&wsi_wl_display->wl_fd_reader_finished, -+ &wsi_wl_display->wl_fd_lock, -+ &end_time); -+ if (err) { -+ if (errno == ETIMEDOUT) -+ err = VK_TIMEOUT; -+ else -+ err = VK_ERROR_OUT_OF_DATE_KHR; -+ } else { -+ /* We don't know if the other thread actually -+ * dispatched anything, so let the caller decide -+ * whether it should continue. -+ */ -+ err = VK_INCOMPLETE; -+ } -+ } else { -+ err = wsi_wl_display_read_queue_with_timeout_internal(wsi_wl_display, -+ queue, -+ timeout); -+ } -+ -+ pthread_mutex_unlock(&wsi_wl_display->wl_fd_lock); -+ -+ now = os_time_get_nano(); -+ if (now > atimeout) { -+ err = VK_TIMEOUT; -+ break; -+ } -+ -+ } -+ -+ return err; -+} -+ -+static struct wsi_wl_format * -+wsi_wl_display_add_vk_format(struct wsi_wl_display *display, -+ struct u_vector *formats, -+ VkFormat format, uint32_t flags) -+{ -+ assert(flags & (WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE)); -+ -+ /* Don't add a format that's already in the list */ -+ struct wsi_wl_format *f = find_format(formats, format); -+ if (f) { -+ f->flags |= flags; -+ return f; -+ } -+ -+ /* Don't add formats that aren't renderable. */ -+ VkFormatProperties props; -+ -+ display->wsi_wl->wsi->GetPhysicalDeviceFormatProperties(display->wsi_wl->physical_device, -+ format, &props); -+ if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) -+ return NULL; -+ -+ struct u_vector modifiers; -+ if (!u_vector_init_pow2(&modifiers, 4, sizeof(uint64_t))) -+ return NULL; -+ -+ f = u_vector_add(formats); -+ if (!f) { -+ u_vector_finish(&modifiers); -+ return NULL; -+ } -+ -+ f->vk_format = format; -+ f->flags = flags; -+ f->modifiers = modifiers; -+ -+ return f; -+} -+ -+static void -+wsi_wl_format_add_modifier(struct wsi_wl_format *format, uint64_t modifier) -+{ -+ uint64_t *mod; -+ -+ if (modifier == DRM_FORMAT_MOD_INVALID) -+ return; -+ -+ u_vector_foreach(mod, &format->modifiers) -+ if (*mod == modifier) -+ return; -+ -+ mod = u_vector_add(&format->modifiers); -+ if (mod) -+ *mod = modifier; -+} -+ -+static void -+wsi_wl_display_add_vk_format_modifier(struct wsi_wl_display *display, -+ struct u_vector *formats, -+ VkFormat vk_format, uint32_t flags, -+ uint64_t modifier) -+{ -+ struct wsi_wl_format *format; -+ -+ format = wsi_wl_display_add_vk_format(display, formats, vk_format, flags); -+ if (format) -+ wsi_wl_format_add_modifier(format, modifier); -+} -+ -+static void -+wsi_wl_display_add_drm_format_modifier(struct wsi_wl_display *display, -+ struct u_vector *formats, -+ uint32_t drm_format, uint64_t modifier) -+{ -+ switch (drm_format) { -+#if 0 -+ /* TODO: These are only available when VK_EXT_4444_formats is enabled, so -+ * we probably need to make their use conditional on this extension. */ -+ case DRM_FORMAT_ARGB4444: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_A4R4G4B4_UNORM_PACK16, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_XRGB4444: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_A4R4G4B4_UNORM_PACK16, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ case DRM_FORMAT_ABGR4444: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_A4B4G4R4_UNORM_PACK16, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_XBGR4444: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_A4B4G4R4_UNORM_PACK16, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+#endif -+ -+ /* Vulkan _PACKN formats have the same component order as DRM formats -+ * on little endian systems, on big endian there exists no analog. */ -+#if UTIL_ARCH_LITTLE_ENDIAN -+ case DRM_FORMAT_RGBA4444: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R4G4B4A4_UNORM_PACK16, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_RGBX4444: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R4G4B4A4_UNORM_PACK16, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ case DRM_FORMAT_BGRA4444: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_B4G4R4A4_UNORM_PACK16, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_BGRX4444: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_B4G4R4A4_UNORM_PACK16, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ case DRM_FORMAT_RGB565: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R5G6B5_UNORM_PACK16, -+ WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, -+ modifier); -+ break; -+ case DRM_FORMAT_BGR565: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_B5G6R5_UNORM_PACK16, -+ WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, -+ modifier); -+ break; -+ case DRM_FORMAT_ARGB1555: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_A1R5G5B5_UNORM_PACK16, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_XRGB1555: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_A1R5G5B5_UNORM_PACK16, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ case DRM_FORMAT_RGBA5551: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R5G5B5A1_UNORM_PACK16, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_RGBX5551: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R5G5B5A1_UNORM_PACK16, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ case DRM_FORMAT_BGRA5551: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_B5G5R5A1_UNORM_PACK16, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_BGRX5551: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_B5G5R5A1_UNORM_PACK16, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ case DRM_FORMAT_ARGB2101010: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_A2R10G10B10_UNORM_PACK32, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_XRGB2101010: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_A2R10G10B10_UNORM_PACK32, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ case DRM_FORMAT_ABGR2101010: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_A2B10G10R10_UNORM_PACK32, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_XBGR2101010: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_A2B10G10R10_UNORM_PACK32, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ -+ /* Vulkan 16-bits-per-channel formats have an inverted channel order -+ * compared to DRM formats, just like the 8-bits-per-channel ones. -+ * On little endian systems the memory representation of each channel -+ * matches the DRM formats'. */ -+ case DRM_FORMAT_ABGR16161616: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R16G16B16A16_UNORM, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_XBGR16161616: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R16G16B16A16_UNORM, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ case DRM_FORMAT_ABGR16161616F: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R16G16B16A16_SFLOAT, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ case DRM_FORMAT_XBGR16161616F: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R16G16B16A16_SFLOAT, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+#endif -+ -+ /* Non-packed 8-bit formats have an inverted channel order compared to the -+ * little endian DRM formats, because the DRM channel ordering is high->low -+ * but the vulkan channel ordering is in memory byte order -+ * -+ * For all UNORM formats which have a SRGB variant, we must support both if -+ * we can. SRGB in this context means that rendering to it will result in a -+ * 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. */ -+ 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); -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R8G8B8A8_SRGB, -+ WSI_WL_FMT_OPAQUE, modifier); -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R8G8B8A8_UNORM, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ case DRM_FORMAT_ABGR8888: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R8G8B8A8_SRGB, -+ WSI_WL_FMT_ALPHA, modifier); -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_R8G8B8A8_UNORM, -+ WSI_WL_FMT_ALPHA, 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); -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_B8G8R8A8_SRGB, -+ WSI_WL_FMT_OPAQUE, modifier); -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_B8G8R8A8_UNORM, -+ WSI_WL_FMT_OPAQUE, modifier); -+ break; -+ case DRM_FORMAT_ARGB8888: -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_B8G8R8A8_SRGB, -+ WSI_WL_FMT_ALPHA, modifier); -+ wsi_wl_display_add_vk_format_modifier(display, formats, -+ VK_FORMAT_B8G8R8A8_UNORM, -+ WSI_WL_FMT_ALPHA, modifier); -+ break; -+ } -+} -+ -+static uint32_t -+drm_format_for_wl_shm_format(enum wl_shm_format shm_format) -+{ -+ /* wl_shm formats are identical to DRM, except ARGB8888 and XRGB8888 */ -+ switch (shm_format) { -+ case WL_SHM_FORMAT_ARGB8888: -+ return DRM_FORMAT_ARGB8888; -+ case WL_SHM_FORMAT_XRGB8888: -+ return DRM_FORMAT_XRGB8888; -+ default: -+ return shm_format; -+ } -+} -+ -+static void -+wsi_wl_display_add_wl_shm_format(struct wsi_wl_display *display, -+ struct u_vector *formats, -+ enum wl_shm_format shm_format) -+{ -+ uint32_t drm_format = drm_format_for_wl_shm_format(shm_format); -+ -+ wsi_wl_display_add_drm_format_modifier(display, formats, drm_format, -+ DRM_FORMAT_MOD_INVALID); -+} -+ -+static uint32_t -+wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha) -+{ -+ switch (vk_format) { -+#if 0 -+ case VK_FORMAT_A4R4G4B4_UNORM_PACK16: -+ return alpha ? DRM_FORMAT_ARGB4444 : DRM_FORMAT_XRGB4444; -+ case VK_FORMAT_A4B4G4R4_UNORM_PACK16: -+ return alpha ? DRM_FORMAT_ABGR4444 : DRM_FORMAT_XBGR4444; -+#endif -+#if UTIL_ARCH_LITTLE_ENDIAN -+ case VK_FORMAT_R4G4B4A4_UNORM_PACK16: -+ return alpha ? DRM_FORMAT_RGBA4444 : DRM_FORMAT_RGBX4444; -+ case VK_FORMAT_B4G4R4A4_UNORM_PACK16: -+ return alpha ? DRM_FORMAT_BGRA4444 : DRM_FORMAT_BGRX4444; -+ case VK_FORMAT_R5G6B5_UNORM_PACK16: -+ return DRM_FORMAT_RGB565; -+ case VK_FORMAT_B5G6R5_UNORM_PACK16: -+ return DRM_FORMAT_BGR565; -+ case VK_FORMAT_A1R5G5B5_UNORM_PACK16: -+ return alpha ? DRM_FORMAT_ARGB1555 : DRM_FORMAT_XRGB1555; -+ case VK_FORMAT_R5G5B5A1_UNORM_PACK16: -+ return alpha ? DRM_FORMAT_RGBA5551 : DRM_FORMAT_RGBX5551; -+ case VK_FORMAT_B5G5R5A1_UNORM_PACK16: -+ return alpha ? DRM_FORMAT_BGRA5551 : DRM_FORMAT_BGRX5551; -+ case VK_FORMAT_A2R10G10B10_UNORM_PACK32: -+ return alpha ? DRM_FORMAT_ARGB2101010 : DRM_FORMAT_XRGB2101010; -+ case VK_FORMAT_A2B10G10R10_UNORM_PACK32: -+ return alpha ? DRM_FORMAT_ABGR2101010 : DRM_FORMAT_XBGR2101010; -+ case VK_FORMAT_R16G16B16A16_UNORM: -+ return alpha ? DRM_FORMAT_ABGR16161616 : DRM_FORMAT_XBGR16161616; -+ case VK_FORMAT_R16G16B16A16_SFLOAT: -+ return alpha ? DRM_FORMAT_ABGR16161616F : DRM_FORMAT_XBGR16161616F; -+#endif -+ case VK_FORMAT_R8G8B8_UNORM: -+ case VK_FORMAT_R8G8B8_SRGB: -+ return DRM_FORMAT_XBGR8888; -+ 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; -+ case VK_FORMAT_B8G8R8A8_UNORM: -+ case VK_FORMAT_B8G8R8A8_SRGB: -+ return alpha ? DRM_FORMAT_ARGB8888 : DRM_FORMAT_XRGB8888; -+ -+ default: -+ assert(!"Unsupported Vulkan format"); -+ return DRM_FORMAT_INVALID; -+ } -+} -+ -+static enum wl_shm_format -+wl_shm_format_for_vk_format(VkFormat vk_format, bool alpha) -+{ -+ uint32_t drm_format = wl_drm_format_for_vk_format(vk_format, alpha); -+ if (drm_format == DRM_FORMAT_INVALID) { -+ return 0; -+ } -+ -+ /* wl_shm formats are identical to DRM, except ARGB8888 and XRGB8888 */ -+ switch (drm_format) { -+ case DRM_FORMAT_ARGB8888: -+ return WL_SHM_FORMAT_ARGB8888; -+ case DRM_FORMAT_XRGB8888: -+ return WL_SHM_FORMAT_XRGB8888; -+ default: -+ return drm_format; -+ } -+} -+ -+static void -+dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, -+ uint32_t format) -+{ -+ /* Formats are implicitly advertised by the modifier event, so we ignore -+ * them here. */ -+} -+ -+static void -+dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, -+ uint32_t format, uint32_t modifier_hi, -+ uint32_t modifier_lo) -+{ -+ struct wsi_wl_display *display = data; -+ uint64_t modifier; -+ -+ /* Ignore this if the compositor advertised dma-buf feedback. From version 4 -+ * onwards (when dma-buf feedback was introduced), the compositor should not -+ * advertise this event anymore, but let's keep this for safety. */ -+ if (display->wl_dmabuf_feedback) -+ return; -+ -+ modifier = ((uint64_t) modifier_hi << 32) | modifier_lo; -+ wsi_wl_display_add_drm_format_modifier(display, &display->formats, -+ format, modifier); -+} -+ -+static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { -+ dmabuf_handle_format, -+ dmabuf_handle_modifier, -+}; -+ -+static void -+dmabuf_feedback_format_table_fini(struct dmabuf_feedback_format_table *format_table) -+{ -+ if (format_table->data && format_table->data != MAP_FAILED) -+ munmap(format_table->data, format_table->size); -+} -+ -+static void -+dmabuf_feedback_format_table_init(struct dmabuf_feedback_format_table *format_table) -+{ -+ memset(format_table, 0, sizeof(*format_table)); -+} -+ -+static void -+dmabuf_feedback_tranche_fini(struct dmabuf_feedback_tranche *tranche) -+{ -+ struct wsi_wl_format *format; -+ -+ u_vector_foreach(format, &tranche->formats) -+ u_vector_finish(&format->modifiers); -+ -+ u_vector_finish(&tranche->formats); -+} -+ -+static int -+dmabuf_feedback_tranche_init(struct dmabuf_feedback_tranche *tranche) -+{ -+ memset(tranche, 0, sizeof(*tranche)); -+ -+ if (!u_vector_init(&tranche->formats, 8, sizeof(struct wsi_wl_format))) -+ return -1; -+ -+ return 0; -+} -+ -+static void -+dmabuf_feedback_fini(struct dmabuf_feedback *dmabuf_feedback) -+{ -+ dmabuf_feedback_tranche_fini(&dmabuf_feedback->pending_tranche); -+ -+ util_dynarray_foreach(&dmabuf_feedback->tranches, -+ struct dmabuf_feedback_tranche, tranche) -+ dmabuf_feedback_tranche_fini(tranche); -+ util_dynarray_fini(&dmabuf_feedback->tranches); -+ -+ dmabuf_feedback_format_table_fini(&dmabuf_feedback->format_table); -+} -+ -+static int -+dmabuf_feedback_init(struct dmabuf_feedback *dmabuf_feedback) -+{ -+ memset(dmabuf_feedback, 0, sizeof(*dmabuf_feedback)); -+ -+ if (dmabuf_feedback_tranche_init(&dmabuf_feedback->pending_tranche) < 0) -+ return -1; -+ -+ util_dynarray_init(&dmabuf_feedback->tranches, NULL); -+ -+ dmabuf_feedback_format_table_init(&dmabuf_feedback->format_table); -+ -+ return 0; -+} -+ -+static void -+default_dmabuf_feedback_format_table(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, -+ int32_t fd, uint32_t size) -+{ -+ struct wsi_wl_display *display = data; -+ -+ display->format_table.size = size; -+ display->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); -+ -+ close(fd); -+} -+ -+static void -+default_dmabuf_feedback_main_device(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -+ struct wl_array *device) -+{ -+ struct wsi_wl_display *display = data; -+ -+ assert(device->size == sizeof(dev_t)); -+ memcpy(&display->main_device, device->data, device->size); -+} -+ -+static void -+default_dmabuf_feedback_tranche_target_device(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -+ struct wl_array *device) -+{ -+ /* ignore this event */ -+} -+ -+static void -+default_dmabuf_feedback_tranche_flags(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -+ uint32_t flags) -+{ -+ /* ignore this event */ -+} -+ -+static void -+default_dmabuf_feedback_tranche_formats(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -+ struct wl_array *indices) -+{ -+ struct wsi_wl_display *display = data; -+ uint32_t format; -+ uint64_t modifier; -+ uint16_t *index; -+ -+ /* We couldn't map the format table or the compositor didn't advertise it, -+ * so we have to ignore the feedback. */ -+ if (display->format_table.data == MAP_FAILED || -+ display->format_table.data == NULL) -+ return; -+ -+ wl_array_for_each(index, indices) { -+ format = display->format_table.data[*index].format; -+ modifier = display->format_table.data[*index].modifier; -+ wsi_wl_display_add_drm_format_modifier(display, &display->formats, -+ format, modifier); -+ } -+} -+ -+static void -+default_dmabuf_feedback_tranche_done(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) -+{ -+ /* ignore this event */ -+} -+ -+static void -+default_dmabuf_feedback_done(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) -+{ -+ /* ignore this event */ -+} -+ -+static const struct zwp_linux_dmabuf_feedback_v1_listener -+dmabuf_feedback_listener = { -+ .format_table = default_dmabuf_feedback_format_table, -+ .main_device = default_dmabuf_feedback_main_device, -+ .tranche_target_device = default_dmabuf_feedback_tranche_target_device, -+ .tranche_flags = default_dmabuf_feedback_tranche_flags, -+ .tranche_formats = default_dmabuf_feedback_tranche_formats, -+ .tranche_done = default_dmabuf_feedback_tranche_done, -+ .done = default_dmabuf_feedback_done, -+}; -+ -+static void -+shm_handle_format(void *data, struct wl_shm *shm, uint32_t format) -+{ -+ struct wsi_wl_display *display = data; -+ -+ wsi_wl_display_add_wl_shm_format(display, &display->formats, format); -+} -+ -+static const struct wl_shm_listener shm_listener = { -+ .format = shm_handle_format -+}; -+ -+static void -+registry_handle_global(void *data, struct wl_registry *registry, -+ uint32_t name, const char *interface, uint32_t version) -+{ -+ struct wsi_wl_display *display = data; -+ -+ if (display->sw) { -+ if (strcmp(interface, wl_shm_interface.name) == 0) { -+ display->wl_shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); -+ wl_shm_add_listener(display->wl_shm, &shm_listener, display); -+ } -+ } else { -+ if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0 && version >= 3) { -+ display->wl_dmabuf = -+ wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, -+ MIN2(version, ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION)); -+ zwp_linux_dmabuf_v1_add_listener(display->wl_dmabuf, -+ &dmabuf_listener, display); -+ } -+ } -+ -+ if (strcmp(interface, wp_presentation_interface.name) == 0) { -+ display->wp_presentation_notwrapped = -+ wl_registry_bind(registry, name, &wp_presentation_interface, 1); -+ } else if (strcmp(interface, wp_tearing_control_manager_v1_interface.name) == 0) { -+ display->tearing_control_manager = -+ wl_registry_bind(registry, name, &wp_tearing_control_manager_v1_interface, 1); -+ } -+} -+ -+static void -+registry_handle_global_remove(void *data, struct wl_registry *registry, -+ uint32_t name) -+{ /* No-op */ } -+ -+static const struct wl_registry_listener registry_listener = { -+ registry_handle_global, -+ registry_handle_global_remove -+}; -+ -+static void -+wsi_wl_display_finish(struct wsi_wl_display *display) -+{ -+ struct wsi_wl_format *f; -+ u_vector_foreach(f, &display->formats) -+ u_vector_finish(&f->modifiers); -+ u_vector_finish(&display->formats); -+ if (display->wl_shm) -+ wl_shm_destroy(display->wl_shm); -+ if (display->wl_dmabuf) -+ zwp_linux_dmabuf_v1_destroy(display->wl_dmabuf); -+ if (display->wp_presentation_notwrapped) -+ wp_presentation_destroy(display->wp_presentation_notwrapped); -+ if (display->tearing_control_manager) -+ wp_tearing_control_manager_v1_destroy(display->tearing_control_manager); -+ if (display->wl_display_wrapper) -+ wl_proxy_wrapper_destroy(display->wl_display_wrapper); -+ if (display->queue) -+ wl_event_queue_destroy(display->queue); -+ pthread_mutex_destroy(&display->wl_fd_lock); -+ pthread_cond_destroy(&display->wl_fd_reader_finished); -+} -+ -+static VkResult -+wsi_wl_display_init(struct wsi_wayland *wsi_wl, -+ struct wsi_wl_display *display, -+ struct wl_display *wl_display, -+ bool get_format_list, bool sw) -+{ -+ VkResult result = VK_SUCCESS; -+ memset(display, 0, sizeof(*display)); -+ -+ if (!u_vector_init(&display->formats, 8, sizeof(struct wsi_wl_format))) -+ return VK_ERROR_OUT_OF_HOST_MEMORY; -+ -+ display->wsi_wl = wsi_wl; -+ display->wl_display = wl_display; -+ display->sw = sw; -+ -+ display->wl_fd_read_in_progress = false; -+ pthread_mutex_init(&display->wl_fd_lock, NULL); -+ if (!wsi_init_pthread_cond_monotonic(&display->wl_fd_reader_finished)) -+ goto fail; -+ -+ display->queue = wl_display_create_queue(wl_display); -+ if (!display->queue) { -+ result = VK_ERROR_OUT_OF_HOST_MEMORY; -+ goto fail; -+ } -+ -+ display->wl_display_wrapper = wl_proxy_create_wrapper(wl_display); -+ if (!display->wl_display_wrapper) { -+ result = VK_ERROR_OUT_OF_HOST_MEMORY; -+ goto fail; -+ } -+ -+ wl_proxy_set_queue((struct wl_proxy *) display->wl_display_wrapper, -+ display->queue); -+ -+ struct wl_registry *registry = -+ wl_display_get_registry(display->wl_display_wrapper); -+ if (!registry) { -+ result = VK_ERROR_OUT_OF_HOST_MEMORY; -+ goto fail; -+ } -+ -+ wl_registry_add_listener(registry, ®istry_listener, display); -+ -+ /* Round-trip to get wl_shm and zwp_linux_dmabuf_v1 globals */ -+ wl_display_roundtrip_queue(display->wl_display, display->queue); -+ if (!display->wl_dmabuf && !display->wl_shm) { -+ result = VK_ERROR_SURFACE_LOST_KHR; -+ goto fail_registry; -+ } -+ -+ /* Caller doesn't expect us to query formats/modifiers, so return */ -+ if (!get_format_list) -+ goto out; -+ -+ /* Default assumption */ -+ display->same_gpu = true; -+ -+ /* Get the default dma-buf feedback */ -+ if (display->wl_dmabuf && zwp_linux_dmabuf_v1_get_version(display->wl_dmabuf) >= -+ ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) { -+ dmabuf_feedback_format_table_init(&display->format_table); -+ display->wl_dmabuf_feedback = -+ zwp_linux_dmabuf_v1_get_default_feedback(display->wl_dmabuf); -+ zwp_linux_dmabuf_feedback_v1_add_listener(display->wl_dmabuf_feedback, -+ &dmabuf_feedback_listener, display); -+ -+ /* Round-trip again to fetch dma-buf feedback */ -+ wl_display_roundtrip_queue(display->wl_display, display->queue); -+ -+ if (wsi_wl->wsi->drm_info.hasRender || -+ wsi_wl->wsi->drm_info.hasPrimary) { -+ /* Apparently some wayland compositor do not send the render -+ * device node but the primary, so test against both. -+ */ -+ display->same_gpu = -+ (wsi_wl->wsi->drm_info.hasRender && -+ major(display->main_device) == wsi_wl->wsi->drm_info.renderMajor && -+ minor(display->main_device) == wsi_wl->wsi->drm_info.renderMinor) || -+ (wsi_wl->wsi->drm_info.hasPrimary && -+ major(display->main_device) == wsi_wl->wsi->drm_info.primaryMajor && -+ minor(display->main_device) == wsi_wl->wsi->drm_info.primaryMinor); -+ } -+ } -+ -+ /* Round-trip again to get formats and modifiers */ -+ wl_display_roundtrip_queue(display->wl_display, display->queue); -+ -+ if (wsi_wl->wsi->force_bgra8_unorm_first) { -+ /* Find BGRA8_UNORM in the list and swap it to the first position if we -+ * can find it. Some apps get confused if SRGB is first in the list. -+ */ -+ struct wsi_wl_format *first_fmt = u_vector_head(&display->formats); -+ struct wsi_wl_format *f, tmp_fmt; -+ f = find_format(&display->formats, VK_FORMAT_B8G8R8A8_UNORM); -+ if (f) { -+ tmp_fmt = *f; -+ *f = *first_fmt; -+ *first_fmt = tmp_fmt; -+ } -+ } -+ -+out: -+ /* We don't need this anymore */ -+ wl_registry_destroy(registry); -+ -+ /* Destroy default dma-buf feedback object and format table */ -+ if (display->wl_dmabuf_feedback) { -+ zwp_linux_dmabuf_feedback_v1_destroy(display->wl_dmabuf_feedback); -+ display->wl_dmabuf_feedback = NULL; -+ dmabuf_feedback_format_table_fini(&display->format_table); -+ } -+ -+ return VK_SUCCESS; -+ -+fail_registry: -+ if (registry) -+ wl_registry_destroy(registry); -+ -+fail: -+ pthread_mutex_destroy(&display->wl_fd_lock); -+ wsi_wl_display_finish(display); -+ return result; -+} -+ -+static VkResult -+wsi_wl_display_create(struct wsi_wayland *wsi, struct wl_display *wl_display, -+ bool sw, -+ struct wsi_wl_display **display_out) -+{ -+ struct wsi_wl_display *display = -+ vk_alloc(wsi->alloc, sizeof(*display), 8, -+ VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); -+ if (!display) -+ return VK_ERROR_OUT_OF_HOST_MEMORY; -+ -+ VkResult result = wsi_wl_display_init(wsi, display, wl_display, true, -+ sw); -+ if (result != VK_SUCCESS) { -+ vk_free(wsi->alloc, display); -+ return result; -+ } -+ -+ *display_out = display; -+ -+ return result; -+} -+ -+static void -+wsi_wl_display_destroy(struct wsi_wl_display *display) -+{ -+ struct wsi_wayland *wsi = display->wsi_wl; -+ wsi_wl_display_finish(display); -+ vk_free(wsi->alloc, display); -+} -+ -+VKAPI_ATTR VkBool32 VKAPI_CALL -+wsi_GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice, -+ uint32_t queueFamilyIndex, -+ struct wl_display *wl_display) -+{ -+ VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); -+ struct wsi_device *wsi_device = pdevice->wsi_device; -+ struct wsi_wayland *wsi = -+ (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -+ -+ if (!(wsi_device->queue_supports_blit & BITFIELD64_BIT(queueFamilyIndex))) -+ return false; -+ -+ struct wsi_wl_display display; -+ VkResult ret = wsi_wl_display_init(wsi, &display, wl_display, false, -+ wsi_device->sw); -+ if (ret == VK_SUCCESS) -+ wsi_wl_display_finish(&display); -+ -+ return ret == VK_SUCCESS; -+} -+ -+static VkResult -+wsi_wl_surface_get_support(VkIcdSurfaceBase *surface, -+ struct wsi_device *wsi_device, -+ uint32_t queueFamilyIndex, -+ VkBool32* pSupported) -+{ -+ *pSupported = true; -+ -+ return VK_SUCCESS; -+} -+ -+static uint32_t -+wsi_wl_surface_get_min_image_count(const VkSurfacePresentModeEXT *present_mode) -+{ -+ if (present_mode && (present_mode->presentMode == VK_PRESENT_MODE_FIFO_KHR || -+ present_mode->presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)) { -+ /* If we receive a FIFO present mode, only 2 images is required for forward progress. -+ * Performance with 2 images will be questionable, but we only allow it for applications -+ * using the new API, so we don't risk breaking any existing apps this way. -+ * Other ICDs expose 2 images here already. */ -+ return 2; -+ } else { -+ /* For true mailbox mode, we need at least 4 images: -+ * 1) One to scan out from -+ * 2) One to have queued for scan-out -+ * 3) One to be currently held by the Wayland compositor -+ * 4) One to render to -+ */ -+ return 4; -+ } -+} -+ -+static uint32_t -+wsi_wl_surface_get_min_image_count_for_mode_group(const VkSwapchainPresentModesCreateInfoEXT *modes) -+{ -+ /* If we don't provide the PresentModeCreateInfo struct, we must be backwards compatible, -+ * and assume that minImageCount is the default one, i.e. 4, which supports both FIFO and MAILBOX. */ -+ if (!modes) { -+ return wsi_wl_surface_get_min_image_count(NULL); -+ } -+ -+ uint32_t max_required = 0; -+ for (uint32_t i = 0; i < modes->presentModeCount; i++) { -+ const VkSurfacePresentModeEXT mode = { -+ VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT, -+ NULL, -+ modes->pPresentModes[i] -+ }; -+ max_required = MAX2(max_required, wsi_wl_surface_get_min_image_count(&mode)); -+ } -+ -+ return max_required; -+} -+ -+static VkResult -+wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface, -+ struct wsi_device *wsi_device, -+ const VkSurfacePresentModeEXT *present_mode, -+ VkSurfaceCapabilitiesKHR* caps) -+{ -+ caps->minImageCount = wsi_wl_surface_get_min_image_count(present_mode); -+ /* There is no real maximum */ -+ caps->maxImageCount = 0; -+ -+ caps->currentExtent = (VkExtent2D) { UINT32_MAX, UINT32_MAX }; -+ caps->minImageExtent = (VkExtent2D) { 1, 1 }; -+ caps->maxImageExtent = (VkExtent2D) { -+ wsi_device->maxImageDimension2D, -+ wsi_device->maxImageDimension2D, -+ }; -+ -+ caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; -+ caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; -+ caps->maxImageArrayLayers = 1; -+ -+ caps->supportedCompositeAlpha = -+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | -+ VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; -+ -+ caps->supportedUsageFlags = wsi_caps_get_image_usage(); -+ -+ VK_FROM_HANDLE(vk_physical_device, pdevice, wsi_device->pdevice); -+ if (pdevice->supported_extensions.EXT_attachment_feedback_loop_layout) -+ caps->supportedUsageFlags |= VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT; -+ -+ return VK_SUCCESS; -+} -+ -+static VkResult -+wsi_wl_surface_get_capabilities2(VkIcdSurfaceBase *surface, -+ struct wsi_device *wsi_device, -+ const void *info_next, -+ VkSurfaceCapabilities2KHR* caps) -+{ -+ assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); -+ -+ const VkSurfacePresentModeEXT *present_mode = vk_find_struct_const(info_next, SURFACE_PRESENT_MODE_EXT); -+ -+ VkResult result = -+ wsi_wl_surface_get_capabilities(surface, wsi_device, present_mode, -+ &caps->surfaceCapabilities); -+ -+ vk_foreach_struct(ext, caps->pNext) { -+ switch (ext->sType) { -+ case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { -+ VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext; -+ protected->supportsProtected = VK_FALSE; -+ break; -+ } -+ -+ case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: { -+ /* Unsupported. */ -+ VkSurfacePresentScalingCapabilitiesEXT *scaling = (void *)ext; -+ scaling->supportedPresentScaling = 0; -+ scaling->supportedPresentGravityX = 0; -+ scaling->supportedPresentGravityY = 0; -+ scaling->minScaledImageExtent = caps->surfaceCapabilities.minImageExtent; -+ scaling->maxScaledImageExtent = caps->surfaceCapabilities.maxImageExtent; -+ break; -+ } -+ -+ case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: { -+ /* Can easily toggle between FIFO and MAILBOX on Wayland. */ -+ VkSurfacePresentModeCompatibilityEXT *compat = (void *)ext; -+ if (compat->pPresentModes) { -+ assert(present_mode); -+ VK_OUTARRAY_MAKE_TYPED(VkPresentModeKHR, modes, compat->pPresentModes, &compat->presentModeCount); -+ /* Must always return queried present mode even when truncating. */ -+ vk_outarray_append_typed(VkPresentModeKHR, &modes, mode) { -+ *mode = present_mode->presentMode; -+ } -+ switch (present_mode->presentMode) { -+ case VK_PRESENT_MODE_MAILBOX_KHR: -+ vk_outarray_append_typed(VkPresentModeKHR, &modes, mode) { -+ *mode = VK_PRESENT_MODE_FIFO_KHR; -+ } -+ break; -+ case VK_PRESENT_MODE_FIFO_KHR: -+ vk_outarray_append_typed(VkPresentModeKHR, &modes, mode) { -+ *mode = VK_PRESENT_MODE_MAILBOX_KHR; -+ } -+ break; -+ default: -+ break; -+ } -+ } else { -+ if (!present_mode) { -+ wsi_common_vk_warn_once("Use of VkSurfacePresentModeCompatibilityEXT " -+ "without a VkSurfacePresentModeEXT set. This is an " -+ "application bug.\n"); -+ compat->presentModeCount = 1; -+ } else { -+ switch (present_mode->presentMode) { -+ case VK_PRESENT_MODE_MAILBOX_KHR: -+ case VK_PRESENT_MODE_FIFO_KHR: -+ compat->presentModeCount = 2; -+ break; -+ default: -+ compat->presentModeCount = 1; -+ break; -+ } -+ } -+ } -+ break; -+ } -+ -+ default: -+ /* Ignored */ -+ break; -+ } -+ } -+ -+ return result; -+} -+ -+static VkResult -+wsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface, -+ struct wsi_device *wsi_device, -+ uint32_t* pSurfaceFormatCount, -+ VkSurfaceFormatKHR* pSurfaceFormats) -+{ -+ VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; -+ struct wsi_wayland *wsi = -+ (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -+ -+ struct wsi_wl_display display; -+ if (wsi_wl_display_init(wsi, &display, surface->display, true, -+ wsi_device->sw)) -+ return VK_ERROR_SURFACE_LOST_KHR; -+ -+ VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out, -+ pSurfaceFormats, pSurfaceFormatCount); -+ -+ struct wsi_wl_format *disp_fmt; -+ u_vector_foreach(disp_fmt, &display.formats) { -+ /* Skip formats for which we can't support both alpha & opaque -+ * formats. -+ */ -+ if (!(disp_fmt->flags & WSI_WL_FMT_ALPHA) || -+ !(disp_fmt->flags & WSI_WL_FMT_OPAQUE)) -+ continue; -+ -+ vk_outarray_append_typed(VkSurfaceFormatKHR, &out, out_fmt) { -+ out_fmt->format = disp_fmt->vk_format; -+ out_fmt->colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; -+ } -+ } -+ -+ wsi_wl_display_finish(&display); -+ -+ return vk_outarray_status(&out); -+} -+ -+static VkResult -+wsi_wl_surface_get_formats2(VkIcdSurfaceBase *icd_surface, -+ struct wsi_device *wsi_device, -+ const void *info_next, -+ uint32_t* pSurfaceFormatCount, -+ VkSurfaceFormat2KHR* pSurfaceFormats) -+{ -+ VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; -+ struct wsi_wayland *wsi = -+ (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -+ -+ struct wsi_wl_display display; -+ if (wsi_wl_display_init(wsi, &display, surface->display, true, -+ wsi_device->sw)) -+ return VK_ERROR_SURFACE_LOST_KHR; -+ -+ VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out, -+ pSurfaceFormats, pSurfaceFormatCount); -+ -+ struct wsi_wl_format *disp_fmt; -+ u_vector_foreach(disp_fmt, &display.formats) { -+ /* Skip formats for which we can't support both alpha & opaque -+ * formats. -+ */ -+ if (!(disp_fmt->flags & WSI_WL_FMT_ALPHA) || -+ !(disp_fmt->flags & WSI_WL_FMT_OPAQUE)) -+ continue; -+ -+ vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, out_fmt) { -+ out_fmt->surfaceFormat.format = disp_fmt->vk_format; -+ out_fmt->surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; -+ } -+ } -+ -+ wsi_wl_display_finish(&display); -+ -+ return vk_outarray_status(&out); -+} -+ -+static VkResult -+wsi_wl_surface_get_present_modes(VkIcdSurfaceBase *icd_surface, -+ struct wsi_device *wsi_device, -+ uint32_t* pPresentModeCount, -+ VkPresentModeKHR* pPresentModes) -+{ -+ VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; -+ struct wsi_wayland *wsi = -+ (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -+ -+ struct wsi_wl_display display; -+ if (wsi_wl_display_init(wsi, &display, surface->display, true, -+ wsi_device->sw)) -+ return VK_ERROR_SURFACE_LOST_KHR; -+ -+ VkPresentModeKHR present_modes[3]; -+ uint32_t present_modes_count = 0; -+ -+ /* The following two modes are always supported */ -+ present_modes[present_modes_count++] = VK_PRESENT_MODE_MAILBOX_KHR; -+ present_modes[present_modes_count++] = VK_PRESENT_MODE_FIFO_KHR; -+ -+ if (display.tearing_control_manager) -+ present_modes[present_modes_count++] = VK_PRESENT_MODE_IMMEDIATE_KHR; -+ -+ assert(present_modes_count <= ARRAY_SIZE(present_modes)); -+ wsi_wl_display_finish(&display); -+ -+ if (pPresentModes == NULL) { -+ *pPresentModeCount = present_modes_count; -+ return VK_SUCCESS; -+ } -+ -+ *pPresentModeCount = MIN2(*pPresentModeCount, present_modes_count); -+ typed_memcpy(pPresentModes, present_modes, *pPresentModeCount); -+ -+ if (*pPresentModeCount < present_modes_count) -+ return VK_INCOMPLETE; -+ else -+ return VK_SUCCESS; -+} -+ -+static VkResult -+wsi_wl_surface_get_present_rectangles(VkIcdSurfaceBase *surface, -+ struct wsi_device *wsi_device, -+ uint32_t* pRectCount, -+ VkRect2D* pRects) -+{ -+ VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount); -+ -+ vk_outarray_append_typed(VkRect2D, &out, rect) { -+ /* We don't know a size so just return the usual "I don't know." */ -+ *rect = (VkRect2D) { -+ .offset = { 0, 0 }, -+ .extent = { UINT32_MAX, UINT32_MAX }, -+ }; -+ } -+ -+ return vk_outarray_status(&out); -+} -+ -+void -+wsi_wl_surface_destroy(VkIcdSurfaceBase *icd_surface, VkInstance _instance, -+ const VkAllocationCallbacks *pAllocator) -+{ -+ VK_FROM_HANDLE(vk_instance, instance, _instance); -+ struct wsi_wl_surface *wsi_wl_surface = -+ wl_container_of((VkIcdSurfaceWayland *)icd_surface, wsi_wl_surface, base); -+ -+ if (wsi_wl_surface->wl_dmabuf_feedback) { -+ zwp_linux_dmabuf_feedback_v1_destroy(wsi_wl_surface->wl_dmabuf_feedback); -+ dmabuf_feedback_fini(&wsi_wl_surface->dmabuf_feedback); -+ dmabuf_feedback_fini(&wsi_wl_surface->pending_dmabuf_feedback); -+ } -+ -+ if (wsi_wl_surface->surface) -+ wl_proxy_wrapper_destroy(wsi_wl_surface->surface); -+ -+ if (wsi_wl_surface->display) -+ wsi_wl_display_destroy(wsi_wl_surface->display); -+ -+ vk_free2(&instance->alloc, pAllocator, wsi_wl_surface); -+} -+ -+static struct wsi_wl_format * -+pick_format_from_surface_dmabuf_feedback(struct wsi_wl_surface *wsi_wl_surface, -+ VkFormat vk_format) -+{ -+ struct wsi_wl_format *f = NULL; -+ -+ /* If the main_device was not advertised, we don't have valid feedback */ -+ if (wsi_wl_surface->dmabuf_feedback.main_device == 0) -+ return NULL; -+ -+ util_dynarray_foreach(&wsi_wl_surface->dmabuf_feedback.tranches, -+ struct dmabuf_feedback_tranche, tranche) { -+ f = find_format(&tranche->formats, vk_format); -+ if (f) -+ break; -+ } -+ -+ return f; -+} -+ -+static void -+surface_dmabuf_feedback_format_table(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, -+ int32_t fd, uint32_t size) -+{ -+ struct wsi_wl_surface *wsi_wl_surface = data; -+ struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -+ -+ feedback->format_table.size = size; -+ feedback->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); -+ -+ close(fd); -+} -+ -+static void -+surface_dmabuf_feedback_main_device(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -+ struct wl_array *device) -+{ -+ struct wsi_wl_surface *wsi_wl_surface = data; -+ struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -+ -+ memcpy(&feedback->main_device, device->data, sizeof(feedback->main_device)); -+} -+ -+static void -+surface_dmabuf_feedback_tranche_target_device(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -+ struct wl_array *device) -+{ -+ struct wsi_wl_surface *wsi_wl_surface = data; -+ struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -+ -+ memcpy(&feedback->pending_tranche.target_device, device->data, -+ sizeof(feedback->pending_tranche.target_device)); -+} -+ -+static void -+surface_dmabuf_feedback_tranche_flags(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -+ uint32_t flags) -+{ -+ struct wsi_wl_surface *wsi_wl_surface = data; -+ struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -+ -+ feedback->pending_tranche.flags = flags; -+} -+ -+static void -+surface_dmabuf_feedback_tranche_formats(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -+ struct wl_array *indices) -+{ -+ struct wsi_wl_surface *wsi_wl_surface = data; -+ struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -+ uint32_t format; -+ uint64_t modifier; -+ uint16_t *index; -+ -+ /* Compositor may advertise or not a format table. If it does, we use it. -+ * Otherwise, we steal the most recent advertised format table. If we don't have -+ * a most recent advertised format table, compositor did something wrong. */ -+ if (feedback->format_table.data == NULL) { -+ feedback->format_table = wsi_wl_surface->dmabuf_feedback.format_table; -+ dmabuf_feedback_format_table_init(&wsi_wl_surface->dmabuf_feedback.format_table); -+ } -+ if (feedback->format_table.data == MAP_FAILED || -+ feedback->format_table.data == NULL) -+ return; -+ -+ wl_array_for_each(index, indices) { -+ format = feedback->format_table.data[*index].format; -+ modifier = feedback->format_table.data[*index].modifier; -+ -+ wsi_wl_display_add_drm_format_modifier(wsi_wl_surface->display, -+ &wsi_wl_surface->pending_dmabuf_feedback.pending_tranche.formats, -+ format, modifier); -+ } -+} -+ -+static void -+surface_dmabuf_feedback_tranche_done(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) -+{ -+ struct wsi_wl_surface *wsi_wl_surface = data; -+ struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -+ -+ /* Add tranche to array of tranches. */ -+ util_dynarray_append(&feedback->tranches, struct dmabuf_feedback_tranche, -+ feedback->pending_tranche); -+ -+ dmabuf_feedback_tranche_init(&feedback->pending_tranche); -+} -+ -+static bool -+sets_of_modifiers_are_the_same(uint32_t num_drm_modifiers_A, const uint64_t *modifiers_A, -+ uint32_t num_drm_modifiers_B, const uint64_t *modifiers_B) -+{ -+ uint32_t i, j; -+ bool mod_found; -+ -+ if (num_drm_modifiers_A != num_drm_modifiers_B) -+ return false; -+ -+ for (i = 0; i < num_drm_modifiers_A; i++) { -+ mod_found = false; -+ for (j = 0; j < num_drm_modifiers_B; j++) { -+ if (modifiers_A[i] == modifiers_B[j]) { -+ mod_found = true; -+ break; -+ } -+ } -+ if (!mod_found) -+ return false; -+ } -+ -+ return true; -+} -+ -+static void -+surface_dmabuf_feedback_done(void *data, -+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) -+{ -+ struct wsi_wl_surface *wsi_wl_surface = data; -+ struct wsi_wl_swapchain *chain = wsi_wl_surface->chain; -+ struct wsi_wl_format *f; -+ -+ dmabuf_feedback_fini(&wsi_wl_surface->dmabuf_feedback); -+ wsi_wl_surface->dmabuf_feedback = wsi_wl_surface->pending_dmabuf_feedback; -+ dmabuf_feedback_init(&wsi_wl_surface->pending_dmabuf_feedback); -+ -+ /* It's not just because we received dma-buf feedback that re-allocation is a -+ * good idea. In order to know if we should re-allocate or not, we must -+ * compare the most recent parameters that we used to allocate with the ones -+ * from the feedback we just received. -+ * -+ * The allocation parameters are: the format, its set of modifiers and the -+ * tranche flags. On WSI we are not using the tranche flags for anything, so -+ * we disconsider this. As we can't switch to another format (it is selected -+ * by the client), we just need to compare the set of modifiers. -+ * -+ * So we just look for the vk_format in the tranches (respecting their -+ * preferences), and compare its set of modifiers with the set of modifiers -+ * we've used to allocate previously. If they differ, we are using suboptimal -+ * parameters and should re-allocate. -+ */ -+ f = pick_format_from_surface_dmabuf_feedback(wsi_wl_surface, chain->vk_format); -+ if (f && !sets_of_modifiers_are_the_same(u_vector_length(&f->modifiers), -+ u_vector_tail(&f->modifiers), -+ chain->num_drm_modifiers, -+ chain->drm_modifiers)) -+ wsi_wl_surface->chain->suboptimal = true; -+} -+ -+static const struct zwp_linux_dmabuf_feedback_v1_listener -+surface_dmabuf_feedback_listener = { -+ .format_table = surface_dmabuf_feedback_format_table, -+ .main_device = surface_dmabuf_feedback_main_device, -+ .tranche_target_device = surface_dmabuf_feedback_tranche_target_device, -+ .tranche_flags = surface_dmabuf_feedback_tranche_flags, -+ .tranche_formats = surface_dmabuf_feedback_tranche_formats, -+ .tranche_done = surface_dmabuf_feedback_tranche_done, -+ .done = surface_dmabuf_feedback_done, -+}; -+ -+static VkResult wsi_wl_surface_bind_to_dmabuf_feedback(struct wsi_wl_surface *wsi_wl_surface) -+{ -+ wsi_wl_surface->wl_dmabuf_feedback = -+ zwp_linux_dmabuf_v1_get_surface_feedback(wsi_wl_surface->display->wl_dmabuf, -+ wsi_wl_surface->surface); -+ -+ zwp_linux_dmabuf_feedback_v1_add_listener(wsi_wl_surface->wl_dmabuf_feedback, -+ &surface_dmabuf_feedback_listener, -+ wsi_wl_surface); -+ -+ if (dmabuf_feedback_init(&wsi_wl_surface->dmabuf_feedback) < 0) -+ goto fail; -+ if (dmabuf_feedback_init(&wsi_wl_surface->pending_dmabuf_feedback) < 0) -+ goto fail_pending; -+ -+ return VK_SUCCESS; -+ -+fail_pending: -+ dmabuf_feedback_fini(&wsi_wl_surface->dmabuf_feedback); -+fail: -+ zwp_linux_dmabuf_feedback_v1_destroy(wsi_wl_surface->wl_dmabuf_feedback); -+ wsi_wl_surface->wl_dmabuf_feedback = NULL; -+ return VK_ERROR_OUT_OF_HOST_MEMORY; -+} -+ -+static VkResult wsi_wl_surface_init(struct wsi_wl_surface *wsi_wl_surface, -+ struct wsi_device *wsi_device) -+{ -+ struct wsi_wayland *wsi = -+ (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -+ VkResult result; -+ -+ /* wsi_wl_surface has already been initialized. */ -+ if (wsi_wl_surface->display) -+ return VK_SUCCESS; -+ -+ result = wsi_wl_display_create(wsi, wsi_wl_surface->base.display, -+ wsi_device->sw, &wsi_wl_surface->display); -+ if (result != VK_SUCCESS) -+ goto fail; -+ -+ wsi_wl_surface->surface = wl_proxy_create_wrapper(wsi_wl_surface->base.surface); -+ if (!wsi_wl_surface->surface) { -+ result = VK_ERROR_OUT_OF_HOST_MEMORY; -+ goto fail; -+ } -+ wl_proxy_set_queue((struct wl_proxy *) wsi_wl_surface->surface, -+ wsi_wl_surface->display->queue); -+ -+ /* Bind wsi_wl_surface to dma-buf feedback. */ -+ if (wsi_wl_surface->display->wl_dmabuf && -+ zwp_linux_dmabuf_v1_get_version(wsi_wl_surface->display->wl_dmabuf) >= -+ ZWP_LINUX_DMABUF_V1_GET_SURFACE_FEEDBACK_SINCE_VERSION) { -+ result = wsi_wl_surface_bind_to_dmabuf_feedback(wsi_wl_surface); -+ if (result != VK_SUCCESS) -+ goto fail; -+ -+ wl_display_roundtrip_queue(wsi_wl_surface->display->wl_display, -+ wsi_wl_surface->display->queue); -+ } -+ -+ return VK_SUCCESS; -+ -+fail: -+ if (wsi_wl_surface->surface) -+ wl_proxy_wrapper_destroy(wsi_wl_surface->surface); -+ -+ if (wsi_wl_surface->display) -+ wsi_wl_display_destroy(wsi_wl_surface->display); -+ return result; -+} -+ -+VKAPI_ATTR VkResult VKAPI_CALL -+wsi_CreateWaylandSurfaceKHR(VkInstance _instance, -+ const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, -+ const VkAllocationCallbacks *pAllocator, -+ VkSurfaceKHR *pSurface) -+{ -+ VK_FROM_HANDLE(vk_instance, instance, _instance); -+ struct wsi_wl_surface *wsi_wl_surface; -+ VkIcdSurfaceWayland *surface; -+ -+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR); -+ -+ wsi_wl_surface = vk_zalloc2(&instance->alloc, pAllocator, sizeof *wsi_wl_surface, -+ 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); -+ if (wsi_wl_surface == NULL) -+ return VK_ERROR_OUT_OF_HOST_MEMORY; -+ -+ surface = &wsi_wl_surface->base; -+ -+ surface->base.platform = VK_ICD_WSI_PLATFORM_WAYLAND; -+ surface->display = pCreateInfo->display; -+ surface->surface = pCreateInfo->surface; -+ -+ *pSurface = VkIcdSurfaceBase_to_handle(&surface->base); -+ -+ return VK_SUCCESS; -+} -+ -+struct wsi_wl_present_id { -+ struct wp_presentation_feedback *feedback; -+ uint64_t present_id; -+ const VkAllocationCallbacks *alloc; -+ struct wsi_wl_swapchain *chain; -+ struct wl_list link; -+}; -+ -+static struct wsi_image * -+wsi_wl_swapchain_get_wsi_image(struct wsi_swapchain *wsi_chain, -+ uint32_t image_index) -+{ -+ struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -+ return &chain->images[image_index].base; -+} -+ -+static VkResult -+wsi_wl_swapchain_release_images(struct wsi_swapchain *wsi_chain, -+ uint32_t count, const uint32_t *indices) -+{ -+ struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -+ for (uint32_t i = 0; i < count; i++) { -+ uint32_t index = indices[i]; -+ assert(chain->images[index].busy); -+ chain->images[index].busy = false; -+ } -+ return VK_SUCCESS; -+} -+ -+static void -+wsi_wl_swapchain_set_present_mode(struct wsi_swapchain *wsi_chain, -+ VkPresentModeKHR mode) -+{ -+ struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -+ chain->base.present_mode = mode; -+} -+ -+static VkResult -+wsi_wl_swapchain_wait_for_present(struct wsi_swapchain *wsi_chain, -+ uint64_t present_id, -+ uint64_t timeout) -+{ -+ struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -+ uint64_t end_time, time_left, now; -+ int ret; -+ bool expired = false; -+ bool finished; -+ -+ if (timeout == UINT64_MAX) -+ end_time = timeout; -+ else -+ end_time = os_time_get_absolute_timeout(timeout); -+ -+ /* Need to observe that the swapchain semaphore has been unsignalled, -+ * as this is guaranteed when a present is complete. */ -+ VkResult result = wsi_swapchain_wait_for_present_semaphore( -+ &chain->base, present_id, timeout); -+ if (result != VK_SUCCESS) -+ return result; -+ -+ if (!chain->present_ids.wp_presentation) { -+ /* If we're enabling present wait despite the protocol not being supported, -+ * use best effort not to crash, even if result will not be correct. -+ * For correctness, we must at least wait for the timeline semaphore to complete. */ -+ return VK_SUCCESS; -+ } -+ -+ while (1) { -+ ret = wl_display_dispatch_queue_pending(chain->wsi_wl_surface->display->wl_display, -+ chain->queue); -+ if (ret < 0) -+ return VK_ERROR_OUT_OF_DATE_KHR; -+ -+ /* PresentWait can be called concurrently. -+ * If there is contention on this mutex, it means there is currently a dispatcher in flight holding the lock. -+ * The lock is only held while there is forward progress processing events from Wayland, -+ * so there should be no problem locking without timeout. -+ * We would like to be able to support timeout = 0 to query the current max_completed count. -+ * A timedlock with no timeout can be problematic in that scenario. */ -+ pthread_mutex_lock(&chain->present_ids.lock); -+ finished = chain->present_ids.max_completed >= present_id; -+ pthread_mutex_unlock(&chain->present_ids.lock); -+ if (finished) -+ return VK_SUCCESS; -+ -+ if (expired) -+ return VK_TIMEOUT; -+ -+ now = os_time_get_nano(); -+ if (now > end_time) -+ time_left = 0; -+ else -+ time_left = end_time - now; -+ -+ ret = wsi_wl_display_dispatch_queue_with_timeout(chain->wsi_wl_surface->display, -+ chain->queue, -+ time_left); -+ if (ret == VK_INCOMPLETE) -+ continue; -+ -+ if (ret != VK_SUCCESS && ret != VK_TIMEOUT) -+ return ret; -+ -+ if (time_left == 0) -+ expired = true; -+ } -+} -+ -+static VkResult -+wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain, -+ const VkAcquireNextImageInfoKHR *info, -+ uint32_t *image_index) -+{ -+ struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -+ struct wsi_wl_surface *wsi_wl_surface = chain->wsi_wl_surface; -+ uint64_t end_time, time_left, now; -+ bool expired = false; -+ int ret; -+ -+ if (info->timeout == UINT64_MAX) -+ end_time = info->timeout; -+ else -+ end_time = os_time_get_absolute_timeout(info->timeout); -+ -+ while (1) { -+ ret = wl_display_dispatch_queue_pending(wsi_wl_surface->display->wl_display, -+ wsi_wl_surface->display->queue); -+ if (ret < 0) -+ return VK_ERROR_OUT_OF_DATE_KHR; -+ -+ /* Try to find a free image. */ -+ for (uint32_t i = 0; i < chain->base.image_count; i++) { -+ if (!chain->images[i].busy) { -+ /* We found a non-busy image */ -+ *image_index = i; -+ chain->images[i].busy = true; -+ return (chain->suboptimal ? VK_SUBOPTIMAL_KHR : VK_SUCCESS); -+ } -+ } -+ -+ if (expired) -+ return info->timeout ? VK_TIMEOUT : VK_NOT_READY; -+ -+ now = os_time_get_nano(); -+ if (now > end_time) -+ time_left = 0; -+ else -+ time_left = end_time - now; -+ -+ ret = wsi_wl_display_dispatch_queue_with_timeout(wsi_wl_surface->display, -+ wsi_wl_surface->display->queue, -+ time_left); -+ if (ret == VK_ERROR_OUT_OF_DATE_KHR) -+ return ret; -+ -+ if (ret == VK_INCOMPLETE) -+ continue; -+ -+ if (ret == VK_TIMEOUT) -+ expired = true; -+ } -+} -+ -+static void -+presentation_handle_sync_output(void *data, -+ struct wp_presentation_feedback *feedback, -+ struct wl_output *output) -+{ -+} -+ -+static void -+presentation_handle_presented(void *data, -+ struct wp_presentation_feedback *feedback, -+ uint32_t tv_sec_hi, uint32_t tv_sec_lo, -+ uint32_t tv_nsec, uint32_t refresh, -+ uint32_t seq_hi, uint32_t seq_lo, -+ uint32_t flags) -+{ -+ struct wsi_wl_present_id *id = data; -+ -+ pthread_mutex_lock(&id->chain->present_ids.lock); -+ if (id->present_id > id->chain->present_ids.max_completed) -+ id->chain->present_ids.max_completed = id->present_id; -+ pthread_mutex_unlock(&id->chain->present_ids.lock); -+ -+ wp_presentation_feedback_destroy(feedback); -+ wl_list_remove(&id->link); -+ vk_free(id->alloc, id); -+} -+ -+static void -+presentation_handle_discarded(void *data, -+ struct wp_presentation_feedback *feedback) -+{ -+ struct wsi_wl_present_id *id = data; -+ -+ pthread_mutex_lock(&id->chain->present_ids.lock); -+ if (id->present_id > id->chain->present_ids.max_completed) -+ id->chain->present_ids.max_completed = id->present_id; -+ pthread_mutex_unlock(&id->chain->present_ids.lock); -+ -+ wp_presentation_feedback_destroy(feedback); -+ wl_list_remove(&id->link); -+ vk_free(id->alloc, id); -+} -+ -+static const struct wp_presentation_feedback_listener -+ pres_feedback_listener = { -+ presentation_handle_sync_output, -+ presentation_handle_presented, -+ presentation_handle_discarded, -+}; -+ -+static void -+frame_handle_done(void *data, struct wl_callback *callback, uint32_t serial) -+{ -+ struct wsi_wl_swapchain *chain = data; -+ -+ chain->frame = NULL; -+ chain->fifo_ready = true; -+ -+ wl_callback_destroy(callback); -+} -+ -+static const struct wl_callback_listener frame_listener = { -+ frame_handle_done, -+}; -+ -+static VkResult -+wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, -+ uint32_t image_index, -+ uint64_t present_id, -+ const VkPresentRegionKHR *damage) -+{ -+ struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -+ struct wsi_wl_surface *wsi_wl_surface = chain->wsi_wl_surface; -+ -+ if (chain->buffer_type == WSI_WL_BUFFER_SHM_MEMCPY) { -+ struct wsi_wl_image *image = &chain->images[image_index]; -+ memcpy(image->shm_ptr, image->base.cpu_map, -+ image->base.row_pitches[0] * chain->extent.height); -+ } -+ -+ /* For EXT_swapchain_maintenance1. We might have transitioned from FIFO to MAILBOX. -+ * In this case we need to let the FIFO request complete, before presenting MAILBOX. */ -+ while (!chain->fifo_ready) { -+ int ret = wl_display_dispatch_queue(wsi_wl_surface->display->wl_display, -+ wsi_wl_surface->display->queue); -+ if (ret < 0) -+ return VK_ERROR_OUT_OF_DATE_KHR; -+ } -+ -+ assert(image_index < chain->base.image_count); -+ wl_surface_attach(wsi_wl_surface->surface, chain->images[image_index].buffer, 0, 0); -+ -+ if (wl_surface_get_version(wsi_wl_surface->surface) >= 4 && damage && -+ damage->pRectangles && damage->rectangleCount > 0) { -+ for (unsigned i = 0; i < damage->rectangleCount; i++) { -+ const VkRectLayerKHR *rect = &damage->pRectangles[i]; -+ assert(rect->layer == 0); -+ wl_surface_damage_buffer(wsi_wl_surface->surface, -+ rect->offset.x, rect->offset.y, -+ rect->extent.width, rect->extent.height); -+ } -+ } else { -+ wl_surface_damage(wsi_wl_surface->surface, 0, 0, INT32_MAX, INT32_MAX); -+ } -+ -+ if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) { -+ chain->frame = wl_surface_frame(wsi_wl_surface->surface); -+ wl_callback_add_listener(chain->frame, &frame_listener, chain); -+ chain->fifo_ready = false; -+ } else { -+ /* If we present MAILBOX, any subsequent presentation in FIFO can replace this image. */ -+ chain->fifo_ready = true; -+ } -+ -+ if (present_id > 0 && chain->present_ids.wp_presentation) { -+ struct wsi_wl_present_id *id = -+ vk_zalloc(chain->wsi_wl_surface->display->wsi_wl->alloc, sizeof(*id), sizeof(uintptr_t), -+ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); -+ id->chain = chain; -+ id->present_id = present_id; -+ id->alloc = chain->wsi_wl_surface->display->wsi_wl->alloc; -+ -+ pthread_mutex_lock(&chain->present_ids.lock); -+ id->feedback = wp_presentation_feedback(chain->present_ids.wp_presentation, -+ chain->wsi_wl_surface->surface); -+ wp_presentation_feedback_add_listener(id->feedback, -+ &pres_feedback_listener, -+ id); -+ wl_list_insert(&chain->present_ids.outstanding_list, &id->link); -+ pthread_mutex_unlock(&chain->present_ids.lock); -+ } -+ -+ chain->images[image_index].busy = true; -+ wl_surface_commit(wsi_wl_surface->surface); -+ wl_display_flush(wsi_wl_surface->display->wl_display); -+ -+ return VK_SUCCESS; -+} -+ -+static void -+buffer_handle_release(void *data, struct wl_buffer *buffer) -+{ -+ struct wsi_wl_image *image = data; -+ -+ assert(image->buffer == buffer); -+ -+ image->busy = false; -+} -+ -+static const struct wl_buffer_listener buffer_listener = { -+ buffer_handle_release, -+}; -+ -+static uint8_t * -+wsi_wl_alloc_image_shm(struct wsi_image *imagew, unsigned size) -+{ -+ struct wsi_wl_image *image = (struct wsi_wl_image *)imagew; -+ -+ /* Create a shareable buffer */ -+ int fd = os_create_anonymous_file(size, NULL); -+ if (fd < 0) -+ return NULL; -+ -+ void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -+ if (ptr == MAP_FAILED) { -+ close(fd); -+ return NULL; -+ } -+ -+ image->shm_fd = fd; -+ image->shm_ptr = ptr; -+ image->shm_size = size; -+ -+ return ptr; -+} -+ -+static VkResult -+wsi_wl_image_init(struct wsi_wl_swapchain *chain, -+ struct wsi_wl_image *image, -+ const VkSwapchainCreateInfoKHR *pCreateInfo, -+ const VkAllocationCallbacks* pAllocator) -+{ -+ struct wsi_wl_display *display = chain->wsi_wl_surface->display; -+ VkResult result; -+ -+ result = wsi_create_image(&chain->base, &chain->base.image_info, -+ &image->base); -+ if (result != VK_SUCCESS) -+ return result; -+ -+ switch (chain->buffer_type) { -+ case WSI_WL_BUFFER_GPU_SHM: -+ case WSI_WL_BUFFER_SHM_MEMCPY: { -+ if (chain->buffer_type == WSI_WL_BUFFER_SHM_MEMCPY) { -+ wsi_wl_alloc_image_shm(&image->base, image->base.row_pitches[0] * -+ chain->extent.height); -+ } -+ assert(image->shm_ptr != NULL); -+ -+ /* Share it in a wl_buffer */ -+ struct wl_shm_pool *pool = wl_shm_create_pool(display->wl_shm, -+ image->shm_fd, -+ image->shm_size); -+ wl_proxy_set_queue((struct wl_proxy *)pool, display->queue); -+ image->buffer = wl_shm_pool_create_buffer(pool, 0, chain->extent.width, -+ chain->extent.height, -+ image->base.row_pitches[0], -+ chain->shm_format); -+ wl_shm_pool_destroy(pool); -+ break; -+ } -+ -+ case WSI_WL_BUFFER_NATIVE: { -+ assert(display->wl_dmabuf); -+ -+ struct zwp_linux_buffer_params_v1 *params = -+ zwp_linux_dmabuf_v1_create_params(display->wl_dmabuf); -+ if (!params) -+ goto fail_image; -+ -+ for (int i = 0; i < image->base.num_planes; i++) { -+ zwp_linux_buffer_params_v1_add(params, -+ image->base.dma_buf_fd, -+ i, -+ image->base.offsets[i], -+ image->base.row_pitches[i], -+ image->base.drm_modifier >> 32, -+ image->base.drm_modifier & 0xffffffff); -+ } -+ -+ image->buffer = -+ zwp_linux_buffer_params_v1_create_immed(params, -+ chain->extent.width, -+ chain->extent.height, -+ chain->drm_format, -+ 0); -+ zwp_linux_buffer_params_v1_destroy(params); -+ break; -+ } -+ -+ default: -+ unreachable("Invalid buffer type"); -+ } -+ -+ if (!image->buffer) -+ goto fail_image; -+ -+ wl_buffer_add_listener(image->buffer, &buffer_listener, image); -+ -+ return VK_SUCCESS; -+ -+fail_image: -+ wsi_destroy_image(&chain->base, &image->base); -+ -+ return VK_ERROR_OUT_OF_HOST_MEMORY; -+} -+ -+static void -+wsi_wl_swapchain_images_free(struct wsi_wl_swapchain *chain) -+{ -+ for (uint32_t i = 0; i < chain->base.image_count; i++) { -+ if (chain->images[i].buffer) { -+ wl_buffer_destroy(chain->images[i].buffer); -+ wsi_destroy_image(&chain->base, &chain->images[i].base); -+ if (chain->images[i].shm_size) { -+ close(chain->images[i].shm_fd); -+ munmap(chain->images[i].shm_ptr, chain->images[i].shm_size); -+ } -+ } -+ } -+} -+ -+static void -+wsi_wl_swapchain_chain_free(struct wsi_wl_swapchain *chain, -+ const VkAllocationCallbacks *pAllocator) -+{ -+ if (chain->frame) -+ wl_callback_destroy(chain->frame); -+ if (chain->tearing_control) -+ wp_tearing_control_v1_destroy(chain->tearing_control); -+ if (chain->wsi_wl_surface) -+ chain->wsi_wl_surface->chain = NULL; -+ -+ if (chain->present_ids.wp_presentation) { -+ /* In VK_EXT_swapchain_maintenance1 there is no requirement to wait for all present IDs to be complete. -+ * Waiting for the swapchain fence is enough. -+ * Just clean up anything user did not wait for. */ -+ struct wsi_wl_present_id *id, *tmp; -+ wl_list_for_each_safe(id, tmp, &chain->present_ids.outstanding_list, link) { -+ wp_presentation_feedback_destroy(id->feedback); -+ wl_list_remove(&id->link); -+ vk_free(id->alloc, id); -+ } -+ -+ wl_proxy_wrapper_destroy(chain->present_ids.wp_presentation); -+ pthread_mutex_destroy(&chain->present_ids.lock); -+ } -+ -+ wsi_swapchain_finish(&chain->base); -+} -+ -+static VkResult -+wsi_wl_swapchain_destroy(struct wsi_swapchain *wsi_chain, -+ const VkAllocationCallbacks *pAllocator) -+{ -+ struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -+ -+ wsi_wl_swapchain_images_free(chain); -+ wsi_wl_swapchain_chain_free(chain, pAllocator); -+ -+ vk_free(pAllocator, chain); -+ -+ return VK_SUCCESS; -+} -+ -+static VkResult -+wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, -+ VkDevice device, -+ struct wsi_device *wsi_device, -+ const VkSwapchainCreateInfoKHR* pCreateInfo, -+ const VkAllocationCallbacks* pAllocator, -+ struct wsi_swapchain **swapchain_out) -+{ -+ struct wsi_wl_surface *wsi_wl_surface = -+ wl_container_of((VkIcdSurfaceWayland *)icd_surface, wsi_wl_surface, base); -+ struct wsi_wl_swapchain *chain; -+ VkResult result; -+ -+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); -+ -+ int num_images = pCreateInfo->minImageCount; -+ -+ size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]); -+ chain = vk_zalloc(pAllocator, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); -+ if (chain == NULL) -+ return VK_ERROR_OUT_OF_HOST_MEMORY; -+ -+ /* We are taking ownership of the wsi_wl_surface, so remove ownership from -+ * oldSwapchain. If the surface is currently owned by a swapchain that is -+ * not oldSwapchain we return an error. -+ */ -+ if (wsi_wl_surface->chain && -+ wsi_swapchain_to_handle(&wsi_wl_surface->chain->base) != pCreateInfo->oldSwapchain) { -+ return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; -+ } -+ if (pCreateInfo->oldSwapchain) { -+ VK_FROM_HANDLE(wsi_wl_swapchain, old_chain, pCreateInfo->oldSwapchain); -+ old_chain->wsi_wl_surface = NULL; -+ if (old_chain->tearing_control) { -+ wp_tearing_control_v1_destroy(old_chain->tearing_control); -+ old_chain->tearing_control = NULL; -+ } -+ } -+ -+ /* Take ownership of the wsi_wl_surface */ -+ chain->wsi_wl_surface = wsi_wl_surface; -+ wsi_wl_surface->chain = chain; -+ -+ result = wsi_wl_surface_init(wsi_wl_surface, wsi_device); -+ if (result != VK_SUCCESS) -+ goto fail; -+ -+ VkPresentModeKHR present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo); -+ if (present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) { -+ chain->tearing_control = -+ wp_tearing_control_manager_v1_get_tearing_control(wsi_wl_surface->display->tearing_control_manager, -+ wsi_wl_surface->surface); -+ if (!chain->tearing_control) { -+ result = VK_ERROR_OUT_OF_HOST_MEMORY; -+ goto fail; -+ } -+ wp_tearing_control_v1_set_presentation_hint(chain->tearing_control, -+ WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC); -+ } -+ -+ enum wsi_wl_buffer_type buffer_type; -+ struct wsi_base_image_params *image_params = NULL; -+ struct wsi_cpu_image_params cpu_image_params; -+ struct wsi_drm_image_params drm_image_params; -+ uint32_t num_drm_modifiers = 0; -+ const uint64_t *drm_modifiers = NULL; -+ if (wsi_device->sw) { -+ cpu_image_params = (struct wsi_cpu_image_params) { -+ .base.image_type = WSI_IMAGE_TYPE_CPU, -+ }; -+ if (wsi_device->has_import_memory_host && -+ !(WSI_DEBUG & WSI_DEBUG_NOSHM)) { -+ buffer_type = WSI_WL_BUFFER_GPU_SHM; -+ cpu_image_params.alloc_shm = wsi_wl_alloc_image_shm; -+ } else { -+ buffer_type = WSI_WL_BUFFER_SHM_MEMCPY; -+ } -+ image_params = &cpu_image_params.base; -+ } else { -+ drm_image_params = (struct wsi_drm_image_params) { -+ .base.image_type = WSI_IMAGE_TYPE_DRM, -+ .same_gpu = wsi_wl_surface->display->same_gpu, -+ }; -+ /* Use explicit DRM format modifiers when both the server and the driver -+ * support them. -+ */ -+ if (wsi_wl_surface->display->wl_dmabuf && wsi_device->supports_modifiers) { -+ struct wsi_wl_format *f = NULL; -+ /* Try to select modifiers for our vk_format from surface dma-buf -+ * feedback. If that doesn't work, fallback to the list of supported -+ * formats/modifiers by the display. */ -+ if (wsi_wl_surface->wl_dmabuf_feedback) -+ f = pick_format_from_surface_dmabuf_feedback(wsi_wl_surface, -+ pCreateInfo->imageFormat); -+ if (f == NULL) -+ f = find_format(&chain->wsi_wl_surface->display->formats, -+ pCreateInfo->imageFormat); -+ if (f != NULL) { -+ num_drm_modifiers = u_vector_length(&f->modifiers); -+ drm_modifiers = u_vector_tail(&f->modifiers); -+ if (num_drm_modifiers > 0) -+ drm_image_params.num_modifier_lists = 1; -+ else -+ drm_image_params.num_modifier_lists = 0; -+ drm_image_params.num_modifiers = &num_drm_modifiers; -+ drm_image_params.modifiers = &drm_modifiers; -+ } -+ } -+ buffer_type = WSI_WL_BUFFER_NATIVE; -+ image_params = &drm_image_params.base; -+ } -+ -+ result = wsi_swapchain_init(wsi_device, &chain->base, device, -+ pCreateInfo, image_params, pAllocator); -+ if (result != VK_SUCCESS) -+ goto fail; -+ -+ bool alpha = pCreateInfo->compositeAlpha == -+ VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; -+ -+ chain->base.destroy = wsi_wl_swapchain_destroy; -+ chain->base.get_wsi_image = wsi_wl_swapchain_get_wsi_image; -+ chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image; -+ chain->base.queue_present = wsi_wl_swapchain_queue_present; -+ chain->base.release_images = wsi_wl_swapchain_release_images; -+ chain->base.set_present_mode = wsi_wl_swapchain_set_present_mode; -+ chain->base.wait_for_present = wsi_wl_swapchain_wait_for_present; -+ chain->base.present_mode = present_mode; -+ chain->base.image_count = num_images; -+ chain->extent = pCreateInfo->imageExtent; -+ 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); -+ } else { -+ chain->shm_format = wl_shm_format_for_vk_format(chain->vk_format, alpha); -+ } -+ chain->num_drm_modifiers = num_drm_modifiers; -+ chain->drm_modifiers = drm_modifiers; -+ -+ chain->queue = wl_display_create_queue(chain->wsi_wl_surface->display->wl_display); -+ -+ if (chain->wsi_wl_surface->display->wp_presentation_notwrapped) { -+ pthread_mutex_init(&chain->present_ids.lock, NULL); -+ -+ wl_list_init(&chain->present_ids.outstanding_list); -+ chain->present_ids.wp_presentation = -+ wl_proxy_create_wrapper(chain->wsi_wl_surface->display->wp_presentation_notwrapped); -+ wl_proxy_set_queue((struct wl_proxy *) chain->present_ids.wp_presentation, -+ chain->queue); -+ } -+ -+ chain->fifo_ready = true; -+ -+ for (uint32_t i = 0; i < chain->base.image_count; i++) { -+ result = wsi_wl_image_init(chain, &chain->images[i], -+ pCreateInfo, pAllocator); -+ if (result != VK_SUCCESS) -+ goto fail_image_init; -+ chain->images[i].busy = false; -+ } -+ -+ *swapchain_out = &chain->base; -+ -+ return VK_SUCCESS; -+ -+fail_image_init: -+ wsi_wl_swapchain_images_free(chain); -+ -+ wsi_wl_swapchain_chain_free(chain, pAllocator); -+fail: -+ vk_free(pAllocator, chain); -+ wsi_wl_surface->chain = NULL; -+ -+ return result; -+} -+ -+VkResult -+wsi_wl_init_wsi(struct wsi_device *wsi_device, -+ const VkAllocationCallbacks *alloc, -+ VkPhysicalDevice physical_device) -+{ -+ struct wsi_wayland *wsi; -+ VkResult result; -+ -+ wsi = vk_alloc(alloc, sizeof(*wsi), 8, -+ VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); -+ if (!wsi) { -+ result = VK_ERROR_OUT_OF_HOST_MEMORY; -+ goto fail; -+ } -+ -+ wsi->physical_device = physical_device; -+ wsi->alloc = alloc; -+ wsi->wsi = wsi_device; -+ -+ wsi->base.get_support = wsi_wl_surface_get_support; -+ wsi->base.get_capabilities2 = wsi_wl_surface_get_capabilities2; -+ wsi->base.get_formats = wsi_wl_surface_get_formats; -+ wsi->base.get_formats2 = wsi_wl_surface_get_formats2; -+ wsi->base.get_present_modes = wsi_wl_surface_get_present_modes; -+ wsi->base.get_present_rectangles = wsi_wl_surface_get_present_rectangles; -+ wsi->base.create_swapchain = wsi_wl_surface_create_swapchain; -+ -+ wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base; -+ -+ return VK_SUCCESS; -+ -+fail: -+ wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = NULL; -+ -+ return result; -+} -+ -+void -+wsi_wl_finish_wsi(struct wsi_device *wsi_device, -+ const VkAllocationCallbacks *alloc) -+{ -+ struct wsi_wayland *wsi = -+ (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -+ if (!wsi) -+ return; -+ -+ vk_free(alloc, wsi); -+} --- -2.43.0 - - -From 0b8b0e5784431e94813fbc62b09ec99e013bca72 Mon Sep 17 00:00:00 2001 -From: Denis <benato.denis96@gmail.com> -Date: Sun, 10 Dec 2023 14:48:09 +0100 -Subject: [PATCH 4/5] hack: rip out commit-timing-v1 - ---- - src/egl/wayland/wayland-drm/meson.build | 6 +- - src/vulkan/wsi/meson.build | 2 +- - src/vulkan/wsi/wsi_common_wayland.c | 24 +- - src/vulkan/wsi/wsi_common_wayland.c.orig | 2475 ---------------------- - 4 files changed, 6 insertions(+), 2501 deletions(-) - delete mode 100644 src/vulkan/wsi/wsi_common_wayland.c.orig - -diff --git a/src/egl/wayland/wayland-drm/meson.build b/src/egl/wayland/wayland-drm/meson.build -index 8b6044f09e5..48c676d7be4 100644 ---- a/src/egl/wayland/wayland-drm/meson.build -+++ b/src/egl/wayland/wayland-drm/meson.build -@@ -60,7 +60,7 @@ libwayland_drm = static_library( - wp_dir = dep_wl_protocols.get_variable(pkgconfig : 'pkgdatadir', internal : 'pkgdatadir') - wp_protos = { - 'commit-queue-v1': 'staging/commit-queue/commit-queue-v1.xml', -- 'commit-timing-v1': 'staging/commit-timing/commit-timing-v1.xml', -+ #'commit-timing-v1': 'staging/commit-timing/commit-timing-v1.xml', - 'linux-dmabuf-unstable-v1': 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml', - 'presentation-time': 'stable/presentation-time/presentation-time.xml', - 'tearing-control-v1': 'staging/tearing-control/tearing-control-v1.xml', -@@ -69,13 +69,13 @@ wp_files = {} - foreach name, xml : wp_protos - code = custom_target( - name + '-protocol.c', -- input : files(join_paths(wp_dir, xml)), -+ input : files(wp_dir / xml), - output : name + '-protocol.c', - command : [prog_wl_scanner, wl_scanner_arg, '@INPUT@', '@OUTPUT@'], - ) - header = custom_target( - name + '-client-protocol.h', -- input : files(join_paths(wp_dir, xml)), -+ input : files(wp_dir / xml), - output : name + '-client-protocol.h', - command : [prog_wl_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], - ) -diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build -index 48ea09b99aa..5caea0e8f4f 100644 ---- a/src/vulkan/wsi/meson.build -+++ b/src/vulkan/wsi/meson.build -@@ -32,7 +32,7 @@ endif - if with_platform_wayland - files_vulkan_wsi += files('wsi_common_wayland.c') - files_vulkan_wsi += wp_files['commit-queue-v1'] -- files_vulkan_wsi += wp_files['commit-timing-v1'] -+ #files_vulkan_wsi += wp_files['commit-timing-v1'] - files_vulkan_wsi += wp_files['linux-dmabuf-unstable-v1'] - files_vulkan_wsi += wp_files['presentation-time'] - files_vulkan_wsi += wp_files['tearing-control-v1'] -diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c -index 16848fb0a2a..d9069dee499 100644 ---- a/src/vulkan/wsi/wsi_common_wayland.c -+++ b/src/vulkan/wsi/wsi_common_wayland.c -@@ -42,7 +42,6 @@ - #include "wsi_common_entrypoints.h" - #include "wsi_common_private.h" - #include "commit-queue-v1-client-protocol.h" --#include "commit-timing-v1-client-protocol.h" - #include "linux-dmabuf-unstable-v1-client-protocol.h" - #include "presentation-time-client-protocol.h" - #include "tearing-control-v1-client-protocol.h" -@@ -116,7 +115,6 @@ struct wsi_wl_display { - struct wp_presentation *wp_presentation_notwrapped; - - struct wp_commit_queue_manager_v1 *commit_queue_manager; -- struct wp_commit_timing_manager_v1 *commit_timing_manager; - - struct wsi_wayland *wsi_wl; - -@@ -173,7 +171,6 @@ struct wsi_wl_swapchain { - struct wsi_wl_surface *wsi_wl_surface; - struct wp_tearing_control_v1 *tearing_control; - struct wp_commit_queue_v1 *commit_queue; -- struct wp_commit_timer_v1 *commit_timer; - bool can_timestamp; - - struct wl_callback *frame; -@@ -947,9 +944,6 @@ registry_handle_global(void *data, struct wl_registry *registry, - } else if (strcmp(interface, wp_tearing_control_manager_v1_interface.name) == 0) { - display->tearing_control_manager = - wl_registry_bind(registry, name, &wp_tearing_control_manager_v1_interface, 1); -- } else if (strcmp(interface, wp_commit_timing_manager_v1_interface.name) == 0) { -- display->commit_timing_manager = -- wl_registry_bind(registry, name, &wp_commit_timing_manager_v1_interface, 1); - } else if (strcmp(interface, wp_commit_queue_manager_v1_interface.name) == 0) { - display->commit_queue_manager = - wl_registry_bind(registry, name, &wp_commit_queue_manager_v1_interface, 1); -@@ -981,8 +975,6 @@ wsi_wl_display_finish(struct wsi_wl_display *display) - wp_presentation_destroy(display->wp_presentation_notwrapped); - if (display->commit_queue_manager) - wp_commit_queue_manager_v1_destroy(display->commit_queue_manager); -- if (display->commit_timing_manager) -- wp_commit_timing_manager_v1_destroy(display->commit_timing_manager); - if (display->tearing_control_manager) - wp_tearing_control_manager_v1_destroy(display->tearing_control_manager); - if (display->wl_display_wrapper) -@@ -2070,9 +2062,6 @@ set_timestamp(struct wsi_wl_swapchain *chain) - } - - timespec_from_nsec(&target_ts, target); -- wp_commit_timer_v1_set_timestamp(chain->commit_timer, -- target_ts.tv_sec >> 32, target_ts.tv_sec, -- target_ts.tv_nsec); - - wp_commit_queue_v1_set_queue_mode(chain->commit_queue, - WP_COMMIT_QUEUE_V1_QUEUE_MODE_FIFO); -@@ -2088,6 +2077,7 @@ wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, - struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; - struct wsi_wl_surface *wsi_wl_surface = chain->wsi_wl_surface; - bool mode_fifo = chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR; -+ //fprintf(stderr, "FIFO = %d\n", mode_fifo); - - if (chain->buffer_type == WSI_WL_BUFFER_SHM_MEMCPY) { - struct wsi_wl_image *image = &chain->images[image_index]; -@@ -2324,9 +2314,6 @@ wsi_wl_swapchain_chain_free(struct wsi_wl_swapchain *chain, - if (chain->commit_queue) - wp_commit_queue_v1_destroy(chain->commit_queue); - -- if (chain->commit_timer) -- wp_commit_timer_v1_destroy(chain->commit_timer); -- - wsi_swapchain_finish(&chain->base); - } - -@@ -2386,10 +2373,6 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, - old_chain->commit_queue = NULL; - old_chain->can_timestamp = false; - } -- if (old_chain->commit_timer) { -- wp_commit_timer_v1_destroy(old_chain->commit_timer); -- old_chain->commit_timer = NULL; -- } - } - - /* Take ownership of the wsi_wl_surface */ -@@ -2507,12 +2490,9 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, - - chain->legacy_fifo_ready = true; - struct wsi_wl_display *dpy = chain->wsi_wl_surface->display; -- if (dpy->commit_queue_manager && -- dpy->commit_timing_manager) { -+ if (dpy->commit_queue_manager) { - chain->commit_queue = wp_commit_queue_manager_v1_get_queue_controller(dpy->commit_queue_manager, - chain->wsi_wl_surface->surface); -- chain->commit_timer = wp_commit_timing_manager_v1_get_timer(dpy->commit_timing_manager, -- chain->wsi_wl_surface->surface); - chain->can_timestamp = true; - } - -diff --git a/src/vulkan/wsi/wsi_common_wayland.c.orig b/src/vulkan/wsi/wsi_common_wayland.c.orig -deleted file mode 100644 -index 75e1a361a0b..00000000000 ---- a/src/vulkan/wsi/wsi_common_wayland.c.orig -+++ /dev/null -@@ -1,2475 +0,0 @@ --/* -- * Copyright © 2015 Intel Corporation -- * -- * Permission is hereby granted, free of charge, to any person obtaining a -- * copy of this software and associated documentation files (the "Software"), -- * to deal in the Software without restriction, including without limitation -- * the rights to use, copy, modify, merge, publish, distribute, sublicense, -- * and/or sell copies of the Software, and to permit persons to whom the -- * Software is furnished to do so, subject to the following conditions: -- * -- * The above copyright notice and this permission notice (including the next -- * paragraph) shall be included in all copies or substantial portions of the -- * Software. -- * -- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -- * IN THE SOFTWARE. -- */ -- --#include <wayland-client.h> -- --#include <assert.h> --#include <stdlib.h> --#include <stdio.h> --#include <unistd.h> --#include <errno.h> --#include <string.h> --#include <pthread.h> --#include <poll.h> --#include <sys/mman.h> --#include <sys/types.h> -- --#include "drm-uapi/drm_fourcc.h" -- --#include "vk_instance.h" --#include "vk_physical_device.h" --#include "vk_util.h" --#include "wsi_common_entrypoints.h" --#include "wsi_common_private.h" --#include "linux-dmabuf-unstable-v1-client-protocol.h" --#include "presentation-time-client-protocol.h" --#include "tearing-control-v1-client-protocol.h" -- --#include <util/compiler.h> --#include <util/hash_table.h> --#include <util/timespec.h> --#include <util/u_endian.h> --#include <util/u_vector.h> --#include <util/u_dynarray.h> --#include <util/anon_file.h> --#include <util/os_time.h> -- --#ifdef MAJOR_IN_MKDEV --#include <sys/mkdev.h> --#endif --#ifdef MAJOR_IN_SYSMACROS --#include <sys/sysmacros.h> --#endif -- --struct wsi_wayland; -- --struct wsi_wl_format { -- VkFormat vk_format; -- uint32_t flags; -- struct u_vector modifiers; --}; -- --struct dmabuf_feedback_format_table { -- unsigned int size; -- struct { -- uint32_t format; -- uint32_t padding; /* unused */ -- uint64_t modifier; -- } *data; --}; -- --struct dmabuf_feedback_tranche { -- dev_t target_device; -- uint32_t flags; -- struct u_vector formats; --}; -- --struct dmabuf_feedback { -- dev_t main_device; -- struct dmabuf_feedback_format_table format_table; -- struct util_dynarray tranches; -- struct dmabuf_feedback_tranche pending_tranche; --}; -- --struct wsi_wl_display { -- /* The real wl_display */ -- struct wl_display *wl_display; -- /* Actually a proxy wrapper around the event queue */ -- struct wl_display *wl_display_wrapper; -- -- pthread_mutex_t wl_fd_lock; -- pthread_cond_t wl_fd_reader_finished; -- bool wl_fd_read_in_progress; -- -- struct wl_event_queue *queue; -- -- struct wl_shm *wl_shm; -- struct zwp_linux_dmabuf_v1 *wl_dmabuf; -- struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback; -- struct wp_tearing_control_manager_v1 *tearing_control_manager; -- -- struct dmabuf_feedback_format_table format_table; -- -- /* users want per-chain wsi_wl_swapchain->present_ids.wp_presentation */ -- struct wp_presentation *wp_presentation_notwrapped; -- -- struct wsi_wayland *wsi_wl; -- -- /* Formats populated by zwp_linux_dmabuf_v1 or wl_shm interfaces */ -- struct u_vector formats; -- -- bool sw; -- -- dev_t main_device; -- bool same_gpu; --}; -- --struct wsi_wayland { -- struct wsi_interface base; -- -- struct wsi_device *wsi; -- -- const VkAllocationCallbacks *alloc; -- VkPhysicalDevice physical_device; --}; -- --struct wsi_wl_image { -- struct wsi_image base; -- struct wl_buffer *buffer; -- bool busy; -- int shm_fd; -- void *shm_ptr; -- unsigned shm_size; --}; -- --enum wsi_wl_buffer_type { -- WSI_WL_BUFFER_NATIVE, -- WSI_WL_BUFFER_GPU_SHM, -- WSI_WL_BUFFER_SHM_MEMCPY, --}; -- --struct wsi_wl_surface { -- VkIcdSurfaceWayland base; -- -- struct wsi_wl_swapchain *chain; -- struct wl_surface *surface; -- struct wsi_wl_display *display; -- -- struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback; -- struct dmabuf_feedback dmabuf_feedback, pending_dmabuf_feedback; --}; -- --struct wsi_wl_swapchain { -- struct wsi_swapchain base; -- -- struct wl_event_queue *queue; -- -- struct wsi_wl_surface *wsi_wl_surface; -- struct wp_tearing_control_v1 *tearing_control; -- -- struct wl_callback *frame; -- -- VkExtent2D extent; -- VkFormat vk_format; -- enum wsi_wl_buffer_type buffer_type; -- uint32_t drm_format; -- enum wl_shm_format shm_format; -- -- bool suboptimal; -- -- uint32_t num_drm_modifiers; -- const uint64_t *drm_modifiers; -- -- VkPresentModeKHR present_mode; -- bool fifo_ready; -- -- struct { -- pthread_mutex_t lock; /* protects all members */ -- uint64_t max_completed; -- struct wl_list outstanding_list; -- struct wp_presentation *wp_presentation; -- } present_ids; -- -- struct wsi_wl_image images[0]; --}; --VK_DEFINE_NONDISP_HANDLE_CASTS(wsi_wl_swapchain, base.base, VkSwapchainKHR, -- VK_OBJECT_TYPE_SWAPCHAIN_KHR) -- --enum wsi_wl_fmt_flag { -- WSI_WL_FMT_ALPHA = 1 << 0, -- WSI_WL_FMT_OPAQUE = 1 << 1, --}; -- --static struct wsi_wl_format * --find_format(struct u_vector *formats, VkFormat format) --{ -- struct wsi_wl_format *f; -- -- u_vector_foreach(f, formats) -- if (f->vk_format == format) -- return f; -- -- return NULL; --} -- --static int --wsi_wl_display_read_queue_with_timeout_internal(struct wsi_wl_display *wsi_wl_display, -- struct wl_event_queue *queue, -- uint64_t atimeout) --{ -- uint64_t current_time_nsec; -- struct timespec rel_timeout, end_time, current_time; -- int ret; -- -- if (wl_display_prepare_read_queue(wsi_wl_display->wl_display, queue) < 0) { -- /* Another thread might have read events for our queue already. Go -- * back to dispatch them. -- */ -- pthread_mutex_unlock(&wsi_wl_display->wl_fd_lock); -- if (errno == EAGAIN) -- return VK_SUCCESS; -- -- return VK_ERROR_OUT_OF_DATE_KHR; -- } -- -- wsi_wl_display->wl_fd_read_in_progress = true; -- pthread_mutex_unlock(&wsi_wl_display->wl_fd_lock); -- -- while (1) { -- struct pollfd pollfd = { -- .fd = wl_display_get_fd(wsi_wl_display->wl_display), -- .events = POLLIN -- }; -- -- current_time_nsec = os_time_get_nano(); -- if (current_time_nsec > atimeout) { -- rel_timeout.tv_sec = 0; -- rel_timeout.tv_nsec = 0; -- } else { -- timespec_from_nsec(¤t_time, current_time_nsec); -- timespec_from_nsec(&end_time, atimeout); -- timespec_sub(&rel_timeout, &end_time, ¤t_time); -- } -- -- ret = ppoll(&pollfd, 1, &rel_timeout, NULL); -- if (ret < 0) { -- if (errno == EINTR || errno == EAGAIN) -- continue; -- -- ret = VK_ERROR_OUT_OF_DATE_KHR; -- } else if (ret == 0) -- ret = VK_TIMEOUT; -- else -- ret = VK_SUCCESS; -- -- break; -- } -- -- if (ret != VK_SUCCESS) { -- wl_display_cancel_read(wsi_wl_display->wl_display); -- } else { -- ret = wl_display_read_events(wsi_wl_display->wl_display); -- if (ret != 0) -- ret = VK_ERROR_OUT_OF_DATE_KHR; -- } -- -- pthread_mutex_lock(&wsi_wl_display->wl_fd_lock); -- wsi_wl_display->wl_fd_read_in_progress = false; -- pthread_cond_broadcast(&wsi_wl_display->wl_fd_reader_finished); -- return ret; --} -- --static int --wsi_wl_display_dispatch_queue_with_timeout(struct wsi_wl_display *wsi_wl_display, -- struct wl_event_queue *queue, -- uint64_t timeout) --{ -- int err; -- int n_events; -- uint64_t atimeout, now; -- -- if (timeout == UINT64_MAX) -- atimeout = timeout; -- else -- atimeout = os_time_get_absolute_timeout(timeout); -- -- while (1) { -- n_events = wl_display_dispatch_queue_pending(wsi_wl_display->wl_display, -- queue); -- if (n_events > 0) { -- err = VK_SUCCESS; -- break; -- } -- pthread_mutex_lock(&wsi_wl_display->wl_fd_lock); -- -- if (wsi_wl_display->wl_fd_read_in_progress) { -- struct timespec end_time; -- -- timespec_from_nsec(&end_time, atimeout); -- -- err = pthread_cond_timedwait(&wsi_wl_display->wl_fd_reader_finished, -- &wsi_wl_display->wl_fd_lock, -- &end_time); -- if (err) { -- if (errno == ETIMEDOUT) -- err = VK_TIMEOUT; -- else -- err = VK_ERROR_OUT_OF_DATE_KHR; -- } else { -- /* We don't know if the other thread actually -- * dispatched anything, so let the caller decide -- * whether it should continue. -- */ -- err = VK_INCOMPLETE; -- } -- } else { -- err = wsi_wl_display_read_queue_with_timeout_internal(wsi_wl_display, -- queue, -- timeout); -- } -- -- pthread_mutex_unlock(&wsi_wl_display->wl_fd_lock); -- -- now = os_time_get_nano(); -- if (now > atimeout) { -- err = VK_TIMEOUT; -- break; -- } -- -- } -- -- return err; --} -- --static struct wsi_wl_format * --wsi_wl_display_add_vk_format(struct wsi_wl_display *display, -- struct u_vector *formats, -- VkFormat format, uint32_t flags) --{ -- assert(flags & (WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE)); -- -- /* Don't add a format that's already in the list */ -- struct wsi_wl_format *f = find_format(formats, format); -- if (f) { -- f->flags |= flags; -- return f; -- } -- -- /* Don't add formats that aren't renderable. */ -- VkFormatProperties props; -- -- display->wsi_wl->wsi->GetPhysicalDeviceFormatProperties(display->wsi_wl->physical_device, -- format, &props); -- if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) -- return NULL; -- -- struct u_vector modifiers; -- if (!u_vector_init_pow2(&modifiers, 4, sizeof(uint64_t))) -- return NULL; -- -- f = u_vector_add(formats); -- if (!f) { -- u_vector_finish(&modifiers); -- return NULL; -- } -- -- f->vk_format = format; -- f->flags = flags; -- f->modifiers = modifiers; -- -- return f; --} -- --static void --wsi_wl_format_add_modifier(struct wsi_wl_format *format, uint64_t modifier) --{ -- uint64_t *mod; -- -- if (modifier == DRM_FORMAT_MOD_INVALID) -- return; -- -- u_vector_foreach(mod, &format->modifiers) -- if (*mod == modifier) -- return; -- -- mod = u_vector_add(&format->modifiers); -- if (mod) -- *mod = modifier; --} -- --static void --wsi_wl_display_add_vk_format_modifier(struct wsi_wl_display *display, -- struct u_vector *formats, -- VkFormat vk_format, uint32_t flags, -- uint64_t modifier) --{ -- struct wsi_wl_format *format; -- -- format = wsi_wl_display_add_vk_format(display, formats, vk_format, flags); -- if (format) -- wsi_wl_format_add_modifier(format, modifier); --} -- --static void --wsi_wl_display_add_drm_format_modifier(struct wsi_wl_display *display, -- struct u_vector *formats, -- uint32_t drm_format, uint64_t modifier) --{ -- switch (drm_format) { --#if 0 -- /* TODO: These are only available when VK_EXT_4444_formats is enabled, so -- * we probably need to make their use conditional on this extension. */ -- case DRM_FORMAT_ARGB4444: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_A4R4G4B4_UNORM_PACK16, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_XRGB4444: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_A4R4G4B4_UNORM_PACK16, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- case DRM_FORMAT_ABGR4444: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_A4B4G4R4_UNORM_PACK16, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_XBGR4444: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_A4B4G4R4_UNORM_PACK16, -- WSI_WL_FMT_OPAQUE, modifier); -- break; --#endif -- -- /* Vulkan _PACKN formats have the same component order as DRM formats -- * on little endian systems, on big endian there exists no analog. */ --#if UTIL_ARCH_LITTLE_ENDIAN -- case DRM_FORMAT_RGBA4444: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R4G4B4A4_UNORM_PACK16, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_RGBX4444: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R4G4B4A4_UNORM_PACK16, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- case DRM_FORMAT_BGRA4444: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_B4G4R4A4_UNORM_PACK16, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_BGRX4444: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_B4G4R4A4_UNORM_PACK16, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- case DRM_FORMAT_RGB565: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R5G6B5_UNORM_PACK16, -- WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, -- modifier); -- break; -- case DRM_FORMAT_BGR565: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_B5G6R5_UNORM_PACK16, -- WSI_WL_FMT_ALPHA | WSI_WL_FMT_OPAQUE, -- modifier); -- break; -- case DRM_FORMAT_ARGB1555: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_A1R5G5B5_UNORM_PACK16, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_XRGB1555: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_A1R5G5B5_UNORM_PACK16, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- case DRM_FORMAT_RGBA5551: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R5G5B5A1_UNORM_PACK16, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_RGBX5551: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R5G5B5A1_UNORM_PACK16, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- case DRM_FORMAT_BGRA5551: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_B5G5R5A1_UNORM_PACK16, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_BGRX5551: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_B5G5R5A1_UNORM_PACK16, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- case DRM_FORMAT_ARGB2101010: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_A2R10G10B10_UNORM_PACK32, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_XRGB2101010: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_A2R10G10B10_UNORM_PACK32, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- case DRM_FORMAT_ABGR2101010: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_A2B10G10R10_UNORM_PACK32, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_XBGR2101010: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_A2B10G10R10_UNORM_PACK32, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- -- /* Vulkan 16-bits-per-channel formats have an inverted channel order -- * compared to DRM formats, just like the 8-bits-per-channel ones. -- * On little endian systems the memory representation of each channel -- * matches the DRM formats'. */ -- case DRM_FORMAT_ABGR16161616: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R16G16B16A16_UNORM, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_XBGR16161616: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R16G16B16A16_UNORM, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- case DRM_FORMAT_ABGR16161616F: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R16G16B16A16_SFLOAT, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- case DRM_FORMAT_XBGR16161616F: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R16G16B16A16_SFLOAT, -- WSI_WL_FMT_OPAQUE, modifier); -- break; --#endif -- -- /* Non-packed 8-bit formats have an inverted channel order compared to the -- * little endian DRM formats, because the DRM channel ordering is high->low -- * but the vulkan channel ordering is in memory byte order -- * -- * For all UNORM formats which have a SRGB variant, we must support both if -- * we can. SRGB in this context means that rendering to it will result in a -- * 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. */ -- 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); -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R8G8B8A8_SRGB, -- WSI_WL_FMT_OPAQUE, modifier); -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R8G8B8A8_UNORM, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- case DRM_FORMAT_ABGR8888: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R8G8B8A8_SRGB, -- WSI_WL_FMT_ALPHA, modifier); -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_R8G8B8A8_UNORM, -- WSI_WL_FMT_ALPHA, 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); -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_B8G8R8A8_SRGB, -- WSI_WL_FMT_OPAQUE, modifier); -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_B8G8R8A8_UNORM, -- WSI_WL_FMT_OPAQUE, modifier); -- break; -- case DRM_FORMAT_ARGB8888: -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_B8G8R8A8_SRGB, -- WSI_WL_FMT_ALPHA, modifier); -- wsi_wl_display_add_vk_format_modifier(display, formats, -- VK_FORMAT_B8G8R8A8_UNORM, -- WSI_WL_FMT_ALPHA, modifier); -- break; -- } --} -- --static uint32_t --drm_format_for_wl_shm_format(enum wl_shm_format shm_format) --{ -- /* wl_shm formats are identical to DRM, except ARGB8888 and XRGB8888 */ -- switch (shm_format) { -- case WL_SHM_FORMAT_ARGB8888: -- return DRM_FORMAT_ARGB8888; -- case WL_SHM_FORMAT_XRGB8888: -- return DRM_FORMAT_XRGB8888; -- default: -- return shm_format; -- } --} -- --static void --wsi_wl_display_add_wl_shm_format(struct wsi_wl_display *display, -- struct u_vector *formats, -- enum wl_shm_format shm_format) --{ -- uint32_t drm_format = drm_format_for_wl_shm_format(shm_format); -- -- wsi_wl_display_add_drm_format_modifier(display, formats, drm_format, -- DRM_FORMAT_MOD_INVALID); --} -- --static uint32_t --wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha) --{ -- switch (vk_format) { --#if 0 -- case VK_FORMAT_A4R4G4B4_UNORM_PACK16: -- return alpha ? DRM_FORMAT_ARGB4444 : DRM_FORMAT_XRGB4444; -- case VK_FORMAT_A4B4G4R4_UNORM_PACK16: -- return alpha ? DRM_FORMAT_ABGR4444 : DRM_FORMAT_XBGR4444; --#endif --#if UTIL_ARCH_LITTLE_ENDIAN -- case VK_FORMAT_R4G4B4A4_UNORM_PACK16: -- return alpha ? DRM_FORMAT_RGBA4444 : DRM_FORMAT_RGBX4444; -- case VK_FORMAT_B4G4R4A4_UNORM_PACK16: -- return alpha ? DRM_FORMAT_BGRA4444 : DRM_FORMAT_BGRX4444; -- case VK_FORMAT_R5G6B5_UNORM_PACK16: -- return DRM_FORMAT_RGB565; -- case VK_FORMAT_B5G6R5_UNORM_PACK16: -- return DRM_FORMAT_BGR565; -- case VK_FORMAT_A1R5G5B5_UNORM_PACK16: -- return alpha ? DRM_FORMAT_ARGB1555 : DRM_FORMAT_XRGB1555; -- case VK_FORMAT_R5G5B5A1_UNORM_PACK16: -- return alpha ? DRM_FORMAT_RGBA5551 : DRM_FORMAT_RGBX5551; -- case VK_FORMAT_B5G5R5A1_UNORM_PACK16: -- return alpha ? DRM_FORMAT_BGRA5551 : DRM_FORMAT_BGRX5551; -- case VK_FORMAT_A2R10G10B10_UNORM_PACK32: -- return alpha ? DRM_FORMAT_ARGB2101010 : DRM_FORMAT_XRGB2101010; -- case VK_FORMAT_A2B10G10R10_UNORM_PACK32: -- return alpha ? DRM_FORMAT_ABGR2101010 : DRM_FORMAT_XBGR2101010; -- case VK_FORMAT_R16G16B16A16_UNORM: -- return alpha ? DRM_FORMAT_ABGR16161616 : DRM_FORMAT_XBGR16161616; -- case VK_FORMAT_R16G16B16A16_SFLOAT: -- return alpha ? DRM_FORMAT_ABGR16161616F : DRM_FORMAT_XBGR16161616F; --#endif -- case VK_FORMAT_R8G8B8_UNORM: -- case VK_FORMAT_R8G8B8_SRGB: -- return DRM_FORMAT_XBGR8888; -- 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; -- case VK_FORMAT_B8G8R8A8_UNORM: -- case VK_FORMAT_B8G8R8A8_SRGB: -- return alpha ? DRM_FORMAT_ARGB8888 : DRM_FORMAT_XRGB8888; -- -- default: -- assert(!"Unsupported Vulkan format"); -- return DRM_FORMAT_INVALID; -- } --} -- --static enum wl_shm_format --wl_shm_format_for_vk_format(VkFormat vk_format, bool alpha) --{ -- uint32_t drm_format = wl_drm_format_for_vk_format(vk_format, alpha); -- if (drm_format == DRM_FORMAT_INVALID) { -- return 0; -- } -- -- /* wl_shm formats are identical to DRM, except ARGB8888 and XRGB8888 */ -- switch (drm_format) { -- case DRM_FORMAT_ARGB8888: -- return WL_SHM_FORMAT_ARGB8888; -- case DRM_FORMAT_XRGB8888: -- return WL_SHM_FORMAT_XRGB8888; -- default: -- return drm_format; -- } --} -- --static void --dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, -- uint32_t format) --{ -- /* Formats are implicitly advertised by the modifier event, so we ignore -- * them here. */ --} -- --static void --dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, -- uint32_t format, uint32_t modifier_hi, -- uint32_t modifier_lo) --{ -- struct wsi_wl_display *display = data; -- uint64_t modifier; -- -- /* Ignore this if the compositor advertised dma-buf feedback. From version 4 -- * onwards (when dma-buf feedback was introduced), the compositor should not -- * advertise this event anymore, but let's keep this for safety. */ -- if (display->wl_dmabuf_feedback) -- return; -- -- modifier = ((uint64_t) modifier_hi << 32) | modifier_lo; -- wsi_wl_display_add_drm_format_modifier(display, &display->formats, -- format, modifier); --} -- --static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { -- dmabuf_handle_format, -- dmabuf_handle_modifier, --}; -- --static void --dmabuf_feedback_format_table_fini(struct dmabuf_feedback_format_table *format_table) --{ -- if (format_table->data && format_table->data != MAP_FAILED) -- munmap(format_table->data, format_table->size); --} -- --static void --dmabuf_feedback_format_table_init(struct dmabuf_feedback_format_table *format_table) --{ -- memset(format_table, 0, sizeof(*format_table)); --} -- --static void --dmabuf_feedback_tranche_fini(struct dmabuf_feedback_tranche *tranche) --{ -- struct wsi_wl_format *format; -- -- u_vector_foreach(format, &tranche->formats) -- u_vector_finish(&format->modifiers); -- -- u_vector_finish(&tranche->formats); --} -- --static int --dmabuf_feedback_tranche_init(struct dmabuf_feedback_tranche *tranche) --{ -- memset(tranche, 0, sizeof(*tranche)); -- -- if (!u_vector_init(&tranche->formats, 8, sizeof(struct wsi_wl_format))) -- return -1; -- -- return 0; --} -- --static void --dmabuf_feedback_fini(struct dmabuf_feedback *dmabuf_feedback) --{ -- dmabuf_feedback_tranche_fini(&dmabuf_feedback->pending_tranche); -- -- util_dynarray_foreach(&dmabuf_feedback->tranches, -- struct dmabuf_feedback_tranche, tranche) -- dmabuf_feedback_tranche_fini(tranche); -- util_dynarray_fini(&dmabuf_feedback->tranches); -- -- dmabuf_feedback_format_table_fini(&dmabuf_feedback->format_table); --} -- --static int --dmabuf_feedback_init(struct dmabuf_feedback *dmabuf_feedback) --{ -- memset(dmabuf_feedback, 0, sizeof(*dmabuf_feedback)); -- -- if (dmabuf_feedback_tranche_init(&dmabuf_feedback->pending_tranche) < 0) -- return -1; -- -- util_dynarray_init(&dmabuf_feedback->tranches, NULL); -- -- dmabuf_feedback_format_table_init(&dmabuf_feedback->format_table); -- -- return 0; --} -- --static void --default_dmabuf_feedback_format_table(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, -- int32_t fd, uint32_t size) --{ -- struct wsi_wl_display *display = data; -- -- display->format_table.size = size; -- display->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); -- -- close(fd); --} -- --static void --default_dmabuf_feedback_main_device(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -- struct wl_array *device) --{ -- struct wsi_wl_display *display = data; -- -- assert(device->size == sizeof(dev_t)); -- memcpy(&display->main_device, device->data, device->size); --} -- --static void --default_dmabuf_feedback_tranche_target_device(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -- struct wl_array *device) --{ -- /* ignore this event */ --} -- --static void --default_dmabuf_feedback_tranche_flags(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -- uint32_t flags) --{ -- /* ignore this event */ --} -- --static void --default_dmabuf_feedback_tranche_formats(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -- struct wl_array *indices) --{ -- struct wsi_wl_display *display = data; -- uint32_t format; -- uint64_t modifier; -- uint16_t *index; -- -- /* We couldn't map the format table or the compositor didn't advertise it, -- * so we have to ignore the feedback. */ -- if (display->format_table.data == MAP_FAILED || -- display->format_table.data == NULL) -- return; -- -- wl_array_for_each(index, indices) { -- format = display->format_table.data[*index].format; -- modifier = display->format_table.data[*index].modifier; -- wsi_wl_display_add_drm_format_modifier(display, &display->formats, -- format, modifier); -- } --} -- --static void --default_dmabuf_feedback_tranche_done(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) --{ -- /* ignore this event */ --} -- --static void --default_dmabuf_feedback_done(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) --{ -- /* ignore this event */ --} -- --static const struct zwp_linux_dmabuf_feedback_v1_listener --dmabuf_feedback_listener = { -- .format_table = default_dmabuf_feedback_format_table, -- .main_device = default_dmabuf_feedback_main_device, -- .tranche_target_device = default_dmabuf_feedback_tranche_target_device, -- .tranche_flags = default_dmabuf_feedback_tranche_flags, -- .tranche_formats = default_dmabuf_feedback_tranche_formats, -- .tranche_done = default_dmabuf_feedback_tranche_done, -- .done = default_dmabuf_feedback_done, --}; -- --static void --shm_handle_format(void *data, struct wl_shm *shm, uint32_t format) --{ -- struct wsi_wl_display *display = data; -- -- wsi_wl_display_add_wl_shm_format(display, &display->formats, format); --} -- --static const struct wl_shm_listener shm_listener = { -- .format = shm_handle_format --}; -- --static void --registry_handle_global(void *data, struct wl_registry *registry, -- uint32_t name, const char *interface, uint32_t version) --{ -- struct wsi_wl_display *display = data; -- -- if (display->sw) { -- if (strcmp(interface, wl_shm_interface.name) == 0) { -- display->wl_shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); -- wl_shm_add_listener(display->wl_shm, &shm_listener, display); -- } -- } else { -- if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0 && version >= 3) { -- display->wl_dmabuf = -- wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, -- MIN2(version, ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION)); -- zwp_linux_dmabuf_v1_add_listener(display->wl_dmabuf, -- &dmabuf_listener, display); -- } -- } -- -- if (strcmp(interface, wp_presentation_interface.name) == 0) { -- display->wp_presentation_notwrapped = -- wl_registry_bind(registry, name, &wp_presentation_interface, 1); -- } else if (strcmp(interface, wp_tearing_control_manager_v1_interface.name) == 0) { -- display->tearing_control_manager = -- wl_registry_bind(registry, name, &wp_tearing_control_manager_v1_interface, 1); -- } --} -- --static void --registry_handle_global_remove(void *data, struct wl_registry *registry, -- uint32_t name) --{ /* No-op */ } -- --static const struct wl_registry_listener registry_listener = { -- registry_handle_global, -- registry_handle_global_remove --}; -- --static void --wsi_wl_display_finish(struct wsi_wl_display *display) --{ -- struct wsi_wl_format *f; -- u_vector_foreach(f, &display->formats) -- u_vector_finish(&f->modifiers); -- u_vector_finish(&display->formats); -- if (display->wl_shm) -- wl_shm_destroy(display->wl_shm); -- if (display->wl_dmabuf) -- zwp_linux_dmabuf_v1_destroy(display->wl_dmabuf); -- if (display->wp_presentation_notwrapped) -- wp_presentation_destroy(display->wp_presentation_notwrapped); -- if (display->tearing_control_manager) -- wp_tearing_control_manager_v1_destroy(display->tearing_control_manager); -- if (display->wl_display_wrapper) -- wl_proxy_wrapper_destroy(display->wl_display_wrapper); -- if (display->queue) -- wl_event_queue_destroy(display->queue); -- pthread_mutex_destroy(&display->wl_fd_lock); -- pthread_cond_destroy(&display->wl_fd_reader_finished); --} -- --static VkResult --wsi_wl_display_init(struct wsi_wayland *wsi_wl, -- struct wsi_wl_display *display, -- struct wl_display *wl_display, -- bool get_format_list, bool sw) --{ -- VkResult result = VK_SUCCESS; -- memset(display, 0, sizeof(*display)); -- -- if (!u_vector_init(&display->formats, 8, sizeof(struct wsi_wl_format))) -- return VK_ERROR_OUT_OF_HOST_MEMORY; -- -- display->wsi_wl = wsi_wl; -- display->wl_display = wl_display; -- display->sw = sw; -- -- display->wl_fd_read_in_progress = false; -- pthread_mutex_init(&display->wl_fd_lock, NULL); -- if (!wsi_init_pthread_cond_monotonic(&display->wl_fd_reader_finished)) -- goto fail; -- -- display->queue = wl_display_create_queue(wl_display); -- if (!display->queue) { -- result = VK_ERROR_OUT_OF_HOST_MEMORY; -- goto fail; -- } -- -- display->wl_display_wrapper = wl_proxy_create_wrapper(wl_display); -- if (!display->wl_display_wrapper) { -- result = VK_ERROR_OUT_OF_HOST_MEMORY; -- goto fail; -- } -- -- wl_proxy_set_queue((struct wl_proxy *) display->wl_display_wrapper, -- display->queue); -- -- struct wl_registry *registry = -- wl_display_get_registry(display->wl_display_wrapper); -- if (!registry) { -- result = VK_ERROR_OUT_OF_HOST_MEMORY; -- goto fail; -- } -- -- wl_registry_add_listener(registry, ®istry_listener, display); -- -- /* Round-trip to get wl_shm and zwp_linux_dmabuf_v1 globals */ -- wl_display_roundtrip_queue(display->wl_display, display->queue); -- if (!display->wl_dmabuf && !display->wl_shm) { -- result = VK_ERROR_SURFACE_LOST_KHR; -- goto fail_registry; -- } -- -- /* Caller doesn't expect us to query formats/modifiers, so return */ -- if (!get_format_list) -- goto out; -- -- /* Default assumption */ -- display->same_gpu = true; -- -- /* Get the default dma-buf feedback */ -- if (display->wl_dmabuf && zwp_linux_dmabuf_v1_get_version(display->wl_dmabuf) >= -- ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) { -- dmabuf_feedback_format_table_init(&display->format_table); -- display->wl_dmabuf_feedback = -- zwp_linux_dmabuf_v1_get_default_feedback(display->wl_dmabuf); -- zwp_linux_dmabuf_feedback_v1_add_listener(display->wl_dmabuf_feedback, -- &dmabuf_feedback_listener, display); -- -- /* Round-trip again to fetch dma-buf feedback */ -- wl_display_roundtrip_queue(display->wl_display, display->queue); -- -- if (wsi_wl->wsi->drm_info.hasRender || -- wsi_wl->wsi->drm_info.hasPrimary) { -- /* Apparently some wayland compositor do not send the render -- * device node but the primary, so test against both. -- */ -- display->same_gpu = -- (wsi_wl->wsi->drm_info.hasRender && -- major(display->main_device) == wsi_wl->wsi->drm_info.renderMajor && -- minor(display->main_device) == wsi_wl->wsi->drm_info.renderMinor) || -- (wsi_wl->wsi->drm_info.hasPrimary && -- major(display->main_device) == wsi_wl->wsi->drm_info.primaryMajor && -- minor(display->main_device) == wsi_wl->wsi->drm_info.primaryMinor); -- } -- } -- -- /* Round-trip again to get formats and modifiers */ -- wl_display_roundtrip_queue(display->wl_display, display->queue); -- -- if (wsi_wl->wsi->force_bgra8_unorm_first) { -- /* Find BGRA8_UNORM in the list and swap it to the first position if we -- * can find it. Some apps get confused if SRGB is first in the list. -- */ -- struct wsi_wl_format *first_fmt = u_vector_head(&display->formats); -- struct wsi_wl_format *f, tmp_fmt; -- f = find_format(&display->formats, VK_FORMAT_B8G8R8A8_UNORM); -- if (f) { -- tmp_fmt = *f; -- *f = *first_fmt; -- *first_fmt = tmp_fmt; -- } -- } -- --out: -- /* We don't need this anymore */ -- wl_registry_destroy(registry); -- -- /* Destroy default dma-buf feedback object and format table */ -- if (display->wl_dmabuf_feedback) { -- zwp_linux_dmabuf_feedback_v1_destroy(display->wl_dmabuf_feedback); -- display->wl_dmabuf_feedback = NULL; -- dmabuf_feedback_format_table_fini(&display->format_table); -- } -- -- return VK_SUCCESS; -- --fail_registry: -- if (registry) -- wl_registry_destroy(registry); -- --fail: -- pthread_mutex_destroy(&display->wl_fd_lock); -- wsi_wl_display_finish(display); -- return result; --} -- --static VkResult --wsi_wl_display_create(struct wsi_wayland *wsi, struct wl_display *wl_display, -- bool sw, -- struct wsi_wl_display **display_out) --{ -- struct wsi_wl_display *display = -- vk_alloc(wsi->alloc, sizeof(*display), 8, -- VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); -- if (!display) -- return VK_ERROR_OUT_OF_HOST_MEMORY; -- -- VkResult result = wsi_wl_display_init(wsi, display, wl_display, true, -- sw); -- if (result != VK_SUCCESS) { -- vk_free(wsi->alloc, display); -- return result; -- } -- -- *display_out = display; -- -- return result; --} -- --static void --wsi_wl_display_destroy(struct wsi_wl_display *display) --{ -- struct wsi_wayland *wsi = display->wsi_wl; -- wsi_wl_display_finish(display); -- vk_free(wsi->alloc, display); --} -- --VKAPI_ATTR VkBool32 VKAPI_CALL --wsi_GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice, -- uint32_t queueFamilyIndex, -- struct wl_display *wl_display) --{ -- VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); -- struct wsi_device *wsi_device = pdevice->wsi_device; -- struct wsi_wayland *wsi = -- (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -- -- if (!(wsi_device->queue_supports_blit & BITFIELD64_BIT(queueFamilyIndex))) -- return false; -- -- struct wsi_wl_display display; -- VkResult ret = wsi_wl_display_init(wsi, &display, wl_display, false, -- wsi_device->sw); -- if (ret == VK_SUCCESS) -- wsi_wl_display_finish(&display); -- -- return ret == VK_SUCCESS; --} -- --static VkResult --wsi_wl_surface_get_support(VkIcdSurfaceBase *surface, -- struct wsi_device *wsi_device, -- uint32_t queueFamilyIndex, -- VkBool32* pSupported) --{ -- *pSupported = true; -- -- return VK_SUCCESS; --} -- --static uint32_t --wsi_wl_surface_get_min_image_count(const VkSurfacePresentModeEXT *present_mode) --{ -- if (present_mode && (present_mode->presentMode == VK_PRESENT_MODE_FIFO_KHR || -- present_mode->presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)) { -- /* If we receive a FIFO present mode, only 2 images is required for forward progress. -- * Performance with 2 images will be questionable, but we only allow it for applications -- * using the new API, so we don't risk breaking any existing apps this way. -- * Other ICDs expose 2 images here already. */ -- return 2; -- } else { -- /* For true mailbox mode, we need at least 4 images: -- * 1) One to scan out from -- * 2) One to have queued for scan-out -- * 3) One to be currently held by the Wayland compositor -- * 4) One to render to -- */ -- return 4; -- } --} -- --static uint32_t --wsi_wl_surface_get_min_image_count_for_mode_group(const VkSwapchainPresentModesCreateInfoEXT *modes) --{ -- /* If we don't provide the PresentModeCreateInfo struct, we must be backwards compatible, -- * and assume that minImageCount is the default one, i.e. 4, which supports both FIFO and MAILBOX. */ -- if (!modes) { -- return wsi_wl_surface_get_min_image_count(NULL); -- } -- -- uint32_t max_required = 0; -- for (uint32_t i = 0; i < modes->presentModeCount; i++) { -- const VkSurfacePresentModeEXT mode = { -- VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT, -- NULL, -- modes->pPresentModes[i] -- }; -- max_required = MAX2(max_required, wsi_wl_surface_get_min_image_count(&mode)); -- } -- -- return max_required; --} -- --static VkResult --wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface, -- struct wsi_device *wsi_device, -- const VkSurfacePresentModeEXT *present_mode, -- VkSurfaceCapabilitiesKHR* caps) --{ -- caps->minImageCount = wsi_wl_surface_get_min_image_count(present_mode); -- /* There is no real maximum */ -- caps->maxImageCount = 0; -- -- caps->currentExtent = (VkExtent2D) { UINT32_MAX, UINT32_MAX }; -- caps->minImageExtent = (VkExtent2D) { 1, 1 }; -- caps->maxImageExtent = (VkExtent2D) { -- wsi_device->maxImageDimension2D, -- wsi_device->maxImageDimension2D, -- }; -- -- caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; -- caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; -- caps->maxImageArrayLayers = 1; -- -- caps->supportedCompositeAlpha = -- VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | -- VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; -- -- caps->supportedUsageFlags = wsi_caps_get_image_usage(); -- -- VK_FROM_HANDLE(vk_physical_device, pdevice, wsi_device->pdevice); -- if (pdevice->supported_extensions.EXT_attachment_feedback_loop_layout) -- caps->supportedUsageFlags |= VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT; -- -- return VK_SUCCESS; --} -- --static VkResult --wsi_wl_surface_get_capabilities2(VkIcdSurfaceBase *surface, -- struct wsi_device *wsi_device, -- const void *info_next, -- VkSurfaceCapabilities2KHR* caps) --{ -- assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); -- -- const VkSurfacePresentModeEXT *present_mode = vk_find_struct_const(info_next, SURFACE_PRESENT_MODE_EXT); -- -- VkResult result = -- wsi_wl_surface_get_capabilities(surface, wsi_device, present_mode, -- &caps->surfaceCapabilities); -- -- vk_foreach_struct(ext, caps->pNext) { -- switch (ext->sType) { -- case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { -- VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext; -- protected->supportsProtected = VK_FALSE; -- break; -- } -- -- case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: { -- /* Unsupported. */ -- VkSurfacePresentScalingCapabilitiesEXT *scaling = (void *)ext; -- scaling->supportedPresentScaling = 0; -- scaling->supportedPresentGravityX = 0; -- scaling->supportedPresentGravityY = 0; -- scaling->minScaledImageExtent = caps->surfaceCapabilities.minImageExtent; -- scaling->maxScaledImageExtent = caps->surfaceCapabilities.maxImageExtent; -- break; -- } -- -- case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: { -- /* Can easily toggle between FIFO and MAILBOX on Wayland. */ -- VkSurfacePresentModeCompatibilityEXT *compat = (void *)ext; -- if (compat->pPresentModes) { -- assert(present_mode); -- VK_OUTARRAY_MAKE_TYPED(VkPresentModeKHR, modes, compat->pPresentModes, &compat->presentModeCount); -- /* Must always return queried present mode even when truncating. */ -- vk_outarray_append_typed(VkPresentModeKHR, &modes, mode) { -- *mode = present_mode->presentMode; -- } -- switch (present_mode->presentMode) { -- case VK_PRESENT_MODE_MAILBOX_KHR: -- vk_outarray_append_typed(VkPresentModeKHR, &modes, mode) { -- *mode = VK_PRESENT_MODE_FIFO_KHR; -- } -- break; -- case VK_PRESENT_MODE_FIFO_KHR: -- vk_outarray_append_typed(VkPresentModeKHR, &modes, mode) { -- *mode = VK_PRESENT_MODE_MAILBOX_KHR; -- } -- break; -- default: -- break; -- } -- } else { -- if (!present_mode) { -- wsi_common_vk_warn_once("Use of VkSurfacePresentModeCompatibilityEXT " -- "without a VkSurfacePresentModeEXT set. This is an " -- "application bug.\n"); -- compat->presentModeCount = 1; -- } else { -- switch (present_mode->presentMode) { -- case VK_PRESENT_MODE_MAILBOX_KHR: -- case VK_PRESENT_MODE_FIFO_KHR: -- compat->presentModeCount = 2; -- break; -- default: -- compat->presentModeCount = 1; -- break; -- } -- } -- } -- break; -- } -- -- default: -- /* Ignored */ -- break; -- } -- } -- -- return result; --} -- --static VkResult --wsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface, -- struct wsi_device *wsi_device, -- uint32_t* pSurfaceFormatCount, -- VkSurfaceFormatKHR* pSurfaceFormats) --{ -- VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; -- struct wsi_wayland *wsi = -- (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -- -- struct wsi_wl_display display; -- if (wsi_wl_display_init(wsi, &display, surface->display, true, -- wsi_device->sw)) -- return VK_ERROR_SURFACE_LOST_KHR; -- -- VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out, -- pSurfaceFormats, pSurfaceFormatCount); -- -- struct wsi_wl_format *disp_fmt; -- u_vector_foreach(disp_fmt, &display.formats) { -- /* Skip formats for which we can't support both alpha & opaque -- * formats. -- */ -- if (!(disp_fmt->flags & WSI_WL_FMT_ALPHA) || -- !(disp_fmt->flags & WSI_WL_FMT_OPAQUE)) -- continue; -- -- vk_outarray_append_typed(VkSurfaceFormatKHR, &out, out_fmt) { -- out_fmt->format = disp_fmt->vk_format; -- out_fmt->colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; -- } -- } -- -- wsi_wl_display_finish(&display); -- -- return vk_outarray_status(&out); --} -- --static VkResult --wsi_wl_surface_get_formats2(VkIcdSurfaceBase *icd_surface, -- struct wsi_device *wsi_device, -- const void *info_next, -- uint32_t* pSurfaceFormatCount, -- VkSurfaceFormat2KHR* pSurfaceFormats) --{ -- VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; -- struct wsi_wayland *wsi = -- (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -- -- struct wsi_wl_display display; -- if (wsi_wl_display_init(wsi, &display, surface->display, true, -- wsi_device->sw)) -- return VK_ERROR_SURFACE_LOST_KHR; -- -- VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out, -- pSurfaceFormats, pSurfaceFormatCount); -- -- struct wsi_wl_format *disp_fmt; -- u_vector_foreach(disp_fmt, &display.formats) { -- /* Skip formats for which we can't support both alpha & opaque -- * formats. -- */ -- if (!(disp_fmt->flags & WSI_WL_FMT_ALPHA) || -- !(disp_fmt->flags & WSI_WL_FMT_OPAQUE)) -- continue; -- -- vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, out_fmt) { -- out_fmt->surfaceFormat.format = disp_fmt->vk_format; -- out_fmt->surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; -- } -- } -- -- wsi_wl_display_finish(&display); -- -- return vk_outarray_status(&out); --} -- --static VkResult --wsi_wl_surface_get_present_modes(VkIcdSurfaceBase *icd_surface, -- struct wsi_device *wsi_device, -- uint32_t* pPresentModeCount, -- VkPresentModeKHR* pPresentModes) --{ -- VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; -- struct wsi_wayland *wsi = -- (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -- -- struct wsi_wl_display display; -- if (wsi_wl_display_init(wsi, &display, surface->display, true, -- wsi_device->sw)) -- return VK_ERROR_SURFACE_LOST_KHR; -- -- VkPresentModeKHR present_modes[3]; -- uint32_t present_modes_count = 0; -- -- /* The following two modes are always supported */ -- present_modes[present_modes_count++] = VK_PRESENT_MODE_MAILBOX_KHR; -- present_modes[present_modes_count++] = VK_PRESENT_MODE_FIFO_KHR; -- -- if (display.tearing_control_manager) -- present_modes[present_modes_count++] = VK_PRESENT_MODE_IMMEDIATE_KHR; -- -- assert(present_modes_count <= ARRAY_SIZE(present_modes)); -- wsi_wl_display_finish(&display); -- -- if (pPresentModes == NULL) { -- *pPresentModeCount = present_modes_count; -- return VK_SUCCESS; -- } -- -- *pPresentModeCount = MIN2(*pPresentModeCount, present_modes_count); -- typed_memcpy(pPresentModes, present_modes, *pPresentModeCount); -- -- if (*pPresentModeCount < present_modes_count) -- return VK_INCOMPLETE; -- else -- return VK_SUCCESS; --} -- --static VkResult --wsi_wl_surface_get_present_rectangles(VkIcdSurfaceBase *surface, -- struct wsi_device *wsi_device, -- uint32_t* pRectCount, -- VkRect2D* pRects) --{ -- VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount); -- -- vk_outarray_append_typed(VkRect2D, &out, rect) { -- /* We don't know a size so just return the usual "I don't know." */ -- *rect = (VkRect2D) { -- .offset = { 0, 0 }, -- .extent = { UINT32_MAX, UINT32_MAX }, -- }; -- } -- -- return vk_outarray_status(&out); --} -- --void --wsi_wl_surface_destroy(VkIcdSurfaceBase *icd_surface, VkInstance _instance, -- const VkAllocationCallbacks *pAllocator) --{ -- VK_FROM_HANDLE(vk_instance, instance, _instance); -- struct wsi_wl_surface *wsi_wl_surface = -- wl_container_of((VkIcdSurfaceWayland *)icd_surface, wsi_wl_surface, base); -- -- if (wsi_wl_surface->wl_dmabuf_feedback) { -- zwp_linux_dmabuf_feedback_v1_destroy(wsi_wl_surface->wl_dmabuf_feedback); -- dmabuf_feedback_fini(&wsi_wl_surface->dmabuf_feedback); -- dmabuf_feedback_fini(&wsi_wl_surface->pending_dmabuf_feedback); -- } -- -- if (wsi_wl_surface->surface) -- wl_proxy_wrapper_destroy(wsi_wl_surface->surface); -- -- if (wsi_wl_surface->display) -- wsi_wl_display_destroy(wsi_wl_surface->display); -- -- vk_free2(&instance->alloc, pAllocator, wsi_wl_surface); --} -- --static struct wsi_wl_format * --pick_format_from_surface_dmabuf_feedback(struct wsi_wl_surface *wsi_wl_surface, -- VkFormat vk_format) --{ -- struct wsi_wl_format *f = NULL; -- -- /* If the main_device was not advertised, we don't have valid feedback */ -- if (wsi_wl_surface->dmabuf_feedback.main_device == 0) -- return NULL; -- -- util_dynarray_foreach(&wsi_wl_surface->dmabuf_feedback.tranches, -- struct dmabuf_feedback_tranche, tranche) { -- f = find_format(&tranche->formats, vk_format); -- if (f) -- break; -- } -- -- return f; --} -- --static void --surface_dmabuf_feedback_format_table(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, -- int32_t fd, uint32_t size) --{ -- struct wsi_wl_surface *wsi_wl_surface = data; -- struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -- -- feedback->format_table.size = size; -- feedback->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); -- -- close(fd); --} -- --static void --surface_dmabuf_feedback_main_device(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -- struct wl_array *device) --{ -- struct wsi_wl_surface *wsi_wl_surface = data; -- struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -- -- memcpy(&feedback->main_device, device->data, sizeof(feedback->main_device)); --} -- --static void --surface_dmabuf_feedback_tranche_target_device(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -- struct wl_array *device) --{ -- struct wsi_wl_surface *wsi_wl_surface = data; -- struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -- -- memcpy(&feedback->pending_tranche.target_device, device->data, -- sizeof(feedback->pending_tranche.target_device)); --} -- --static void --surface_dmabuf_feedback_tranche_flags(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -- uint32_t flags) --{ -- struct wsi_wl_surface *wsi_wl_surface = data; -- struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -- -- feedback->pending_tranche.flags = flags; --} -- --static void --surface_dmabuf_feedback_tranche_formats(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, -- struct wl_array *indices) --{ -- struct wsi_wl_surface *wsi_wl_surface = data; -- struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -- uint32_t format; -- uint64_t modifier; -- uint16_t *index; -- -- /* Compositor may advertise or not a format table. If it does, we use it. -- * Otherwise, we steal the most recent advertised format table. If we don't have -- * a most recent advertised format table, compositor did something wrong. */ -- if (feedback->format_table.data == NULL) { -- feedback->format_table = wsi_wl_surface->dmabuf_feedback.format_table; -- dmabuf_feedback_format_table_init(&wsi_wl_surface->dmabuf_feedback.format_table); -- } -- if (feedback->format_table.data == MAP_FAILED || -- feedback->format_table.data == NULL) -- return; -- -- wl_array_for_each(index, indices) { -- format = feedback->format_table.data[*index].format; -- modifier = feedback->format_table.data[*index].modifier; -- -- wsi_wl_display_add_drm_format_modifier(wsi_wl_surface->display, -- &wsi_wl_surface->pending_dmabuf_feedback.pending_tranche.formats, -- format, modifier); -- } --} -- --static void --surface_dmabuf_feedback_tranche_done(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) --{ -- struct wsi_wl_surface *wsi_wl_surface = data; -- struct dmabuf_feedback *feedback = &wsi_wl_surface->pending_dmabuf_feedback; -- -- /* Add tranche to array of tranches. */ -- util_dynarray_append(&feedback->tranches, struct dmabuf_feedback_tranche, -- feedback->pending_tranche); -- -- dmabuf_feedback_tranche_init(&feedback->pending_tranche); --} -- --static bool --sets_of_modifiers_are_the_same(uint32_t num_drm_modifiers_A, const uint64_t *modifiers_A, -- uint32_t num_drm_modifiers_B, const uint64_t *modifiers_B) --{ -- uint32_t i, j; -- bool mod_found; -- -- if (num_drm_modifiers_A != num_drm_modifiers_B) -- return false; -- -- for (i = 0; i < num_drm_modifiers_A; i++) { -- mod_found = false; -- for (j = 0; j < num_drm_modifiers_B; j++) { -- if (modifiers_A[i] == modifiers_B[j]) { -- mod_found = true; -- break; -- } -- } -- if (!mod_found) -- return false; -- } -- -- return true; --} -- --static void --surface_dmabuf_feedback_done(void *data, -- struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) --{ -- struct wsi_wl_surface *wsi_wl_surface = data; -- struct wsi_wl_swapchain *chain = wsi_wl_surface->chain; -- struct wsi_wl_format *f; -- -- dmabuf_feedback_fini(&wsi_wl_surface->dmabuf_feedback); -- wsi_wl_surface->dmabuf_feedback = wsi_wl_surface->pending_dmabuf_feedback; -- dmabuf_feedback_init(&wsi_wl_surface->pending_dmabuf_feedback); -- -- /* It's not just because we received dma-buf feedback that re-allocation is a -- * good idea. In order to know if we should re-allocate or not, we must -- * compare the most recent parameters that we used to allocate with the ones -- * from the feedback we just received. -- * -- * The allocation parameters are: the format, its set of modifiers and the -- * tranche flags. On WSI we are not using the tranche flags for anything, so -- * we disconsider this. As we can't switch to another format (it is selected -- * by the client), we just need to compare the set of modifiers. -- * -- * So we just look for the vk_format in the tranches (respecting their -- * preferences), and compare its set of modifiers with the set of modifiers -- * we've used to allocate previously. If they differ, we are using suboptimal -- * parameters and should re-allocate. -- */ -- f = pick_format_from_surface_dmabuf_feedback(wsi_wl_surface, chain->vk_format); -- if (f && !sets_of_modifiers_are_the_same(u_vector_length(&f->modifiers), -- u_vector_tail(&f->modifiers), -- chain->num_drm_modifiers, -- chain->drm_modifiers)) -- wsi_wl_surface->chain->suboptimal = true; --} -- --static const struct zwp_linux_dmabuf_feedback_v1_listener --surface_dmabuf_feedback_listener = { -- .format_table = surface_dmabuf_feedback_format_table, -- .main_device = surface_dmabuf_feedback_main_device, -- .tranche_target_device = surface_dmabuf_feedback_tranche_target_device, -- .tranche_flags = surface_dmabuf_feedback_tranche_flags, -- .tranche_formats = surface_dmabuf_feedback_tranche_formats, -- .tranche_done = surface_dmabuf_feedback_tranche_done, -- .done = surface_dmabuf_feedback_done, --}; -- --static VkResult wsi_wl_surface_bind_to_dmabuf_feedback(struct wsi_wl_surface *wsi_wl_surface) --{ -- wsi_wl_surface->wl_dmabuf_feedback = -- zwp_linux_dmabuf_v1_get_surface_feedback(wsi_wl_surface->display->wl_dmabuf, -- wsi_wl_surface->surface); -- -- zwp_linux_dmabuf_feedback_v1_add_listener(wsi_wl_surface->wl_dmabuf_feedback, -- &surface_dmabuf_feedback_listener, -- wsi_wl_surface); -- -- if (dmabuf_feedback_init(&wsi_wl_surface->dmabuf_feedback) < 0) -- goto fail; -- if (dmabuf_feedback_init(&wsi_wl_surface->pending_dmabuf_feedback) < 0) -- goto fail_pending; -- -- return VK_SUCCESS; -- --fail_pending: -- dmabuf_feedback_fini(&wsi_wl_surface->dmabuf_feedback); --fail: -- zwp_linux_dmabuf_feedback_v1_destroy(wsi_wl_surface->wl_dmabuf_feedback); -- wsi_wl_surface->wl_dmabuf_feedback = NULL; -- return VK_ERROR_OUT_OF_HOST_MEMORY; --} -- --static VkResult wsi_wl_surface_init(struct wsi_wl_surface *wsi_wl_surface, -- struct wsi_device *wsi_device) --{ -- struct wsi_wayland *wsi = -- (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -- VkResult result; -- -- /* wsi_wl_surface has already been initialized. */ -- if (wsi_wl_surface->display) -- return VK_SUCCESS; -- -- result = wsi_wl_display_create(wsi, wsi_wl_surface->base.display, -- wsi_device->sw, &wsi_wl_surface->display); -- if (result != VK_SUCCESS) -- goto fail; -- -- wsi_wl_surface->surface = wl_proxy_create_wrapper(wsi_wl_surface->base.surface); -- if (!wsi_wl_surface->surface) { -- result = VK_ERROR_OUT_OF_HOST_MEMORY; -- goto fail; -- } -- wl_proxy_set_queue((struct wl_proxy *) wsi_wl_surface->surface, -- wsi_wl_surface->display->queue); -- -- /* Bind wsi_wl_surface to dma-buf feedback. */ -- if (wsi_wl_surface->display->wl_dmabuf && -- zwp_linux_dmabuf_v1_get_version(wsi_wl_surface->display->wl_dmabuf) >= -- ZWP_LINUX_DMABUF_V1_GET_SURFACE_FEEDBACK_SINCE_VERSION) { -- result = wsi_wl_surface_bind_to_dmabuf_feedback(wsi_wl_surface); -- if (result != VK_SUCCESS) -- goto fail; -- -- wl_display_roundtrip_queue(wsi_wl_surface->display->wl_display, -- wsi_wl_surface->display->queue); -- } -- -- return VK_SUCCESS; -- --fail: -- if (wsi_wl_surface->surface) -- wl_proxy_wrapper_destroy(wsi_wl_surface->surface); -- -- if (wsi_wl_surface->display) -- wsi_wl_display_destroy(wsi_wl_surface->display); -- return result; --} -- --VKAPI_ATTR VkResult VKAPI_CALL --wsi_CreateWaylandSurfaceKHR(VkInstance _instance, -- const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, -- const VkAllocationCallbacks *pAllocator, -- VkSurfaceKHR *pSurface) --{ -- VK_FROM_HANDLE(vk_instance, instance, _instance); -- struct wsi_wl_surface *wsi_wl_surface; -- VkIcdSurfaceWayland *surface; -- -- assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR); -- -- wsi_wl_surface = vk_zalloc2(&instance->alloc, pAllocator, sizeof *wsi_wl_surface, -- 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); -- if (wsi_wl_surface == NULL) -- return VK_ERROR_OUT_OF_HOST_MEMORY; -- -- surface = &wsi_wl_surface->base; -- -- surface->base.platform = VK_ICD_WSI_PLATFORM_WAYLAND; -- surface->display = pCreateInfo->display; -- surface->surface = pCreateInfo->surface; -- -- *pSurface = VkIcdSurfaceBase_to_handle(&surface->base); -- -- return VK_SUCCESS; --} -- --struct wsi_wl_present_id { -- struct wp_presentation_feedback *feedback; -- uint64_t present_id; -- const VkAllocationCallbacks *alloc; -- struct wsi_wl_swapchain *chain; -- struct wl_list link; --}; -- --static struct wsi_image * --wsi_wl_swapchain_get_wsi_image(struct wsi_swapchain *wsi_chain, -- uint32_t image_index) --{ -- struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -- return &chain->images[image_index].base; --} -- --static VkResult --wsi_wl_swapchain_release_images(struct wsi_swapchain *wsi_chain, -- uint32_t count, const uint32_t *indices) --{ -- struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -- for (uint32_t i = 0; i < count; i++) { -- uint32_t index = indices[i]; -- assert(chain->images[index].busy); -- chain->images[index].busy = false; -- } -- return VK_SUCCESS; --} -- --static void --wsi_wl_swapchain_set_present_mode(struct wsi_swapchain *wsi_chain, -- VkPresentModeKHR mode) --{ -- struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -- chain->base.present_mode = mode; --} -- --static VkResult --wsi_wl_swapchain_wait_for_present(struct wsi_swapchain *wsi_chain, -- uint64_t present_id, -- uint64_t timeout) --{ -- struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -- uint64_t end_time, time_left, now; -- int ret; -- bool expired = false; -- bool finished; -- -- if (timeout == UINT64_MAX) -- end_time = timeout; -- else -- end_time = os_time_get_absolute_timeout(timeout); -- -- /* Need to observe that the swapchain semaphore has been unsignalled, -- * as this is guaranteed when a present is complete. */ -- VkResult result = wsi_swapchain_wait_for_present_semaphore( -- &chain->base, present_id, timeout); -- if (result != VK_SUCCESS) -- return result; -- -- if (!chain->present_ids.wp_presentation) { -- /* If we're enabling present wait despite the protocol not being supported, -- * use best effort not to crash, even if result will not be correct. -- * For correctness, we must at least wait for the timeline semaphore to complete. */ -- return VK_SUCCESS; -- } -- -- while (1) { -- ret = wl_display_dispatch_queue_pending(chain->wsi_wl_surface->display->wl_display, -- chain->queue); -- if (ret < 0) -- return VK_ERROR_OUT_OF_DATE_KHR; -- -- /* PresentWait can be called concurrently. -- * If there is contention on this mutex, it means there is currently a dispatcher in flight holding the lock. -- * The lock is only held while there is forward progress processing events from Wayland, -- * so there should be no problem locking without timeout. -- * We would like to be able to support timeout = 0 to query the current max_completed count. -- * A timedlock with no timeout can be problematic in that scenario. */ -- pthread_mutex_lock(&chain->present_ids.lock); -- finished = chain->present_ids.max_completed >= present_id; -- pthread_mutex_unlock(&chain->present_ids.lock); -- if (finished) -- return VK_SUCCESS; -- -- if (expired) -- return VK_TIMEOUT; -- -- now = os_time_get_nano(); -- if (now > end_time) -- time_left = 0; -- else -- time_left = end_time - now; -- -- ret = wsi_wl_display_dispatch_queue_with_timeout(chain->wsi_wl_surface->display, -- chain->queue, -- time_left); -- if (ret == VK_INCOMPLETE) -- continue; -- -- if (ret != VK_SUCCESS && ret != VK_TIMEOUT) -- return ret; -- -- if (time_left == 0) -- expired = true; -- } --} -- --static VkResult --wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain, -- const VkAcquireNextImageInfoKHR *info, -- uint32_t *image_index) --{ -- struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -- struct wsi_wl_surface *wsi_wl_surface = chain->wsi_wl_surface; -- uint64_t end_time, time_left, now; -- bool expired = false; -- int ret; -- -- if (info->timeout == UINT64_MAX) -- end_time = info->timeout; -- else -- end_time = os_time_get_absolute_timeout(info->timeout); -- -- while (1) { -- ret = wl_display_dispatch_queue_pending(wsi_wl_surface->display->wl_display, -- wsi_wl_surface->display->queue); -- if (ret < 0) -- return VK_ERROR_OUT_OF_DATE_KHR; -- -- /* Try to find a free image. */ -- for (uint32_t i = 0; i < chain->base.image_count; i++) { -- if (!chain->images[i].busy) { -- /* We found a non-busy image */ -- *image_index = i; -- chain->images[i].busy = true; -- return (chain->suboptimal ? VK_SUBOPTIMAL_KHR : VK_SUCCESS); -- } -- } -- -- if (expired) -- return info->timeout ? VK_TIMEOUT : VK_NOT_READY; -- -- now = os_time_get_nano(); -- if (now > end_time) -- time_left = 0; -- else -- time_left = end_time - now; -- -- ret = wsi_wl_display_dispatch_queue_with_timeout(wsi_wl_surface->display, -- wsi_wl_surface->display->queue, -- time_left); -- if (ret == VK_ERROR_OUT_OF_DATE_KHR) -- return ret; -- -- if (ret == VK_INCOMPLETE) -- continue; -- -- if (ret == VK_TIMEOUT) -- expired = true; -- } --} -- --static void --presentation_handle_sync_output(void *data, -- struct wp_presentation_feedback *feedback, -- struct wl_output *output) --{ --} -- --static void --presentation_handle_presented(void *data, -- struct wp_presentation_feedback *feedback, -- uint32_t tv_sec_hi, uint32_t tv_sec_lo, -- uint32_t tv_nsec, uint32_t refresh, -- uint32_t seq_hi, uint32_t seq_lo, -- uint32_t flags) --{ -- struct wsi_wl_present_id *id = data; -- -- pthread_mutex_lock(&id->chain->present_ids.lock); -- if (id->present_id > id->chain->present_ids.max_completed) -- id->chain->present_ids.max_completed = id->present_id; -- pthread_mutex_unlock(&id->chain->present_ids.lock); -- -- wp_presentation_feedback_destroy(feedback); -- wl_list_remove(&id->link); -- vk_free(id->alloc, id); --} -- --static void --presentation_handle_discarded(void *data, -- struct wp_presentation_feedback *feedback) --{ -- struct wsi_wl_present_id *id = data; -- -- pthread_mutex_lock(&id->chain->present_ids.lock); -- if (id->present_id > id->chain->present_ids.max_completed) -- id->chain->present_ids.max_completed = id->present_id; -- pthread_mutex_unlock(&id->chain->present_ids.lock); -- -- wp_presentation_feedback_destroy(feedback); -- wl_list_remove(&id->link); -- vk_free(id->alloc, id); --} -- --static const struct wp_presentation_feedback_listener -- pres_feedback_listener = { -- presentation_handle_sync_output, -- presentation_handle_presented, -- presentation_handle_discarded, --}; -- --static void --frame_handle_done(void *data, struct wl_callback *callback, uint32_t serial) --{ -- struct wsi_wl_swapchain *chain = data; -- -- chain->frame = NULL; -- chain->fifo_ready = true; -- -- wl_callback_destroy(callback); --} -- --static const struct wl_callback_listener frame_listener = { -- frame_handle_done, --}; -- --static VkResult --wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, -- uint32_t image_index, -- uint64_t present_id, -- const VkPresentRegionKHR *damage) --{ -- struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -- struct wsi_wl_surface *wsi_wl_surface = chain->wsi_wl_surface; -- -- if (chain->buffer_type == WSI_WL_BUFFER_SHM_MEMCPY) { -- struct wsi_wl_image *image = &chain->images[image_index]; -- memcpy(image->shm_ptr, image->base.cpu_map, -- image->base.row_pitches[0] * chain->extent.height); -- } -- -- /* For EXT_swapchain_maintenance1. We might have transitioned from FIFO to MAILBOX. -- * In this case we need to let the FIFO request complete, before presenting MAILBOX. */ -- while (!chain->fifo_ready) { -- int ret = wl_display_dispatch_queue(wsi_wl_surface->display->wl_display, -- wsi_wl_surface->display->queue); -- if (ret < 0) -- return VK_ERROR_OUT_OF_DATE_KHR; -- } -- -- assert(image_index < chain->base.image_count); -- wl_surface_attach(wsi_wl_surface->surface, chain->images[image_index].buffer, 0, 0); -- -- if (wl_surface_get_version(wsi_wl_surface->surface) >= 4 && damage && -- damage->pRectangles && damage->rectangleCount > 0) { -- for (unsigned i = 0; i < damage->rectangleCount; i++) { -- const VkRectLayerKHR *rect = &damage->pRectangles[i]; -- assert(rect->layer == 0); -- wl_surface_damage_buffer(wsi_wl_surface->surface, -- rect->offset.x, rect->offset.y, -- rect->extent.width, rect->extent.height); -- } -- } else { -- wl_surface_damage(wsi_wl_surface->surface, 0, 0, INT32_MAX, INT32_MAX); -- } -- -- if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) { -- chain->frame = wl_surface_frame(wsi_wl_surface->surface); -- wl_callback_add_listener(chain->frame, &frame_listener, chain); -- chain->fifo_ready = false; -- } else { -- /* If we present MAILBOX, any subsequent presentation in FIFO can replace this image. */ -- chain->fifo_ready = true; -- } -- -- if (present_id > 0 && chain->present_ids.wp_presentation) { -- struct wsi_wl_present_id *id = -- vk_zalloc(chain->wsi_wl_surface->display->wsi_wl->alloc, sizeof(*id), sizeof(uintptr_t), -- VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); -- id->chain = chain; -- id->present_id = present_id; -- id->alloc = chain->wsi_wl_surface->display->wsi_wl->alloc; -- -- pthread_mutex_lock(&chain->present_ids.lock); -- id->feedback = wp_presentation_feedback(chain->present_ids.wp_presentation, -- chain->wsi_wl_surface->surface); -- wp_presentation_feedback_add_listener(id->feedback, -- &pres_feedback_listener, -- id); -- wl_list_insert(&chain->present_ids.outstanding_list, &id->link); -- pthread_mutex_unlock(&chain->present_ids.lock); -- } -- -- chain->images[image_index].busy = true; -- wl_surface_commit(wsi_wl_surface->surface); -- wl_display_flush(wsi_wl_surface->display->wl_display); -- -- return VK_SUCCESS; --} -- --static void --buffer_handle_release(void *data, struct wl_buffer *buffer) --{ -- struct wsi_wl_image *image = data; -- -- assert(image->buffer == buffer); -- -- image->busy = false; --} -- --static const struct wl_buffer_listener buffer_listener = { -- buffer_handle_release, --}; -- --static uint8_t * --wsi_wl_alloc_image_shm(struct wsi_image *imagew, unsigned size) --{ -- struct wsi_wl_image *image = (struct wsi_wl_image *)imagew; -- -- /* Create a shareable buffer */ -- int fd = os_create_anonymous_file(size, NULL); -- if (fd < 0) -- return NULL; -- -- void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -- if (ptr == MAP_FAILED) { -- close(fd); -- return NULL; -- } -- -- image->shm_fd = fd; -- image->shm_ptr = ptr; -- image->shm_size = size; -- -- return ptr; --} -- --static VkResult --wsi_wl_image_init(struct wsi_wl_swapchain *chain, -- struct wsi_wl_image *image, -- const VkSwapchainCreateInfoKHR *pCreateInfo, -- const VkAllocationCallbacks* pAllocator) --{ -- struct wsi_wl_display *display = chain->wsi_wl_surface->display; -- VkResult result; -- -- result = wsi_create_image(&chain->base, &chain->base.image_info, -- &image->base); -- if (result != VK_SUCCESS) -- return result; -- -- switch (chain->buffer_type) { -- case WSI_WL_BUFFER_GPU_SHM: -- case WSI_WL_BUFFER_SHM_MEMCPY: { -- if (chain->buffer_type == WSI_WL_BUFFER_SHM_MEMCPY) { -- wsi_wl_alloc_image_shm(&image->base, image->base.row_pitches[0] * -- chain->extent.height); -- } -- assert(image->shm_ptr != NULL); -- -- /* Share it in a wl_buffer */ -- struct wl_shm_pool *pool = wl_shm_create_pool(display->wl_shm, -- image->shm_fd, -- image->shm_size); -- wl_proxy_set_queue((struct wl_proxy *)pool, display->queue); -- image->buffer = wl_shm_pool_create_buffer(pool, 0, chain->extent.width, -- chain->extent.height, -- image->base.row_pitches[0], -- chain->shm_format); -- wl_shm_pool_destroy(pool); -- break; -- } -- -- case WSI_WL_BUFFER_NATIVE: { -- assert(display->wl_dmabuf); -- -- struct zwp_linux_buffer_params_v1 *params = -- zwp_linux_dmabuf_v1_create_params(display->wl_dmabuf); -- if (!params) -- goto fail_image; -- -- for (int i = 0; i < image->base.num_planes; i++) { -- zwp_linux_buffer_params_v1_add(params, -- image->base.dma_buf_fd, -- i, -- image->base.offsets[i], -- image->base.row_pitches[i], -- image->base.drm_modifier >> 32, -- image->base.drm_modifier & 0xffffffff); -- } -- -- image->buffer = -- zwp_linux_buffer_params_v1_create_immed(params, -- chain->extent.width, -- chain->extent.height, -- chain->drm_format, -- 0); -- zwp_linux_buffer_params_v1_destroy(params); -- break; -- } -- -- default: -- unreachable("Invalid buffer type"); -- } -- -- if (!image->buffer) -- goto fail_image; -- -- wl_buffer_add_listener(image->buffer, &buffer_listener, image); -- -- return VK_SUCCESS; -- --fail_image: -- wsi_destroy_image(&chain->base, &image->base); -- -- return VK_ERROR_OUT_OF_HOST_MEMORY; --} -- --static void --wsi_wl_swapchain_images_free(struct wsi_wl_swapchain *chain) --{ -- for (uint32_t i = 0; i < chain->base.image_count; i++) { -- if (chain->images[i].buffer) { -- wl_buffer_destroy(chain->images[i].buffer); -- wsi_destroy_image(&chain->base, &chain->images[i].base); -- if (chain->images[i].shm_size) { -- close(chain->images[i].shm_fd); -- munmap(chain->images[i].shm_ptr, chain->images[i].shm_size); -- } -- } -- } --} -- --static void --wsi_wl_swapchain_chain_free(struct wsi_wl_swapchain *chain, -- const VkAllocationCallbacks *pAllocator) --{ -- if (chain->frame) -- wl_callback_destroy(chain->frame); -- if (chain->tearing_control) -- wp_tearing_control_v1_destroy(chain->tearing_control); -- if (chain->wsi_wl_surface) -- chain->wsi_wl_surface->chain = NULL; -- -- if (chain->present_ids.wp_presentation) { -- /* In VK_EXT_swapchain_maintenance1 there is no requirement to wait for all present IDs to be complete. -- * Waiting for the swapchain fence is enough. -- * Just clean up anything user did not wait for. */ -- struct wsi_wl_present_id *id, *tmp; -- wl_list_for_each_safe(id, tmp, &chain->present_ids.outstanding_list, link) { -- wp_presentation_feedback_destroy(id->feedback); -- wl_list_remove(&id->link); -- vk_free(id->alloc, id); -- } -- -- wl_proxy_wrapper_destroy(chain->present_ids.wp_presentation); -- pthread_mutex_destroy(&chain->present_ids.lock); -- } -- -- wsi_swapchain_finish(&chain->base); --} -- --static VkResult --wsi_wl_swapchain_destroy(struct wsi_swapchain *wsi_chain, -- const VkAllocationCallbacks *pAllocator) --{ -- struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; -- -- wsi_wl_swapchain_images_free(chain); -- wsi_wl_swapchain_chain_free(chain, pAllocator); -- -- vk_free(pAllocator, chain); -- -- return VK_SUCCESS; --} -- --static VkResult --wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, -- VkDevice device, -- struct wsi_device *wsi_device, -- const VkSwapchainCreateInfoKHR* pCreateInfo, -- const VkAllocationCallbacks* pAllocator, -- struct wsi_swapchain **swapchain_out) --{ -- struct wsi_wl_surface *wsi_wl_surface = -- wl_container_of((VkIcdSurfaceWayland *)icd_surface, wsi_wl_surface, base); -- struct wsi_wl_swapchain *chain; -- VkResult result; -- -- assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); -- -- int num_images = pCreateInfo->minImageCount; -- -- size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]); -- chain = vk_zalloc(pAllocator, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); -- if (chain == NULL) -- return VK_ERROR_OUT_OF_HOST_MEMORY; -- -- /* We are taking ownership of the wsi_wl_surface, so remove ownership from -- * oldSwapchain. If the surface is currently owned by a swapchain that is -- * not oldSwapchain we return an error. -- */ -- if (wsi_wl_surface->chain && -- wsi_swapchain_to_handle(&wsi_wl_surface->chain->base) != pCreateInfo->oldSwapchain) { -- return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; -- } -- if (pCreateInfo->oldSwapchain) { -- VK_FROM_HANDLE(wsi_wl_swapchain, old_chain, pCreateInfo->oldSwapchain); -- old_chain->wsi_wl_surface = NULL; -- if (old_chain->tearing_control) { -- wp_tearing_control_v1_destroy(old_chain->tearing_control); -- old_chain->tearing_control = NULL; -- } -- } -- -- /* Take ownership of the wsi_wl_surface */ -- chain->wsi_wl_surface = wsi_wl_surface; -- wsi_wl_surface->chain = chain; -- -- result = wsi_wl_surface_init(wsi_wl_surface, wsi_device); -- if (result != VK_SUCCESS) -- goto fail; -- -- VkPresentModeKHR present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo); -- if (present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) { -- chain->tearing_control = -- wp_tearing_control_manager_v1_get_tearing_control(wsi_wl_surface->display->tearing_control_manager, -- wsi_wl_surface->surface); -- if (!chain->tearing_control) { -- result = VK_ERROR_OUT_OF_HOST_MEMORY; -- goto fail; -- } -- wp_tearing_control_v1_set_presentation_hint(chain->tearing_control, -- WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC); -- } -- -- enum wsi_wl_buffer_type buffer_type; -- struct wsi_base_image_params *image_params = NULL; -- struct wsi_cpu_image_params cpu_image_params; -- struct wsi_drm_image_params drm_image_params; -- uint32_t num_drm_modifiers = 0; -- const uint64_t *drm_modifiers = NULL; -- if (wsi_device->sw) { -- cpu_image_params = (struct wsi_cpu_image_params) { -- .base.image_type = WSI_IMAGE_TYPE_CPU, -- }; -- if (wsi_device->has_import_memory_host && -- !(WSI_DEBUG & WSI_DEBUG_NOSHM)) { -- buffer_type = WSI_WL_BUFFER_GPU_SHM; -- cpu_image_params.alloc_shm = wsi_wl_alloc_image_shm; -- } else { -- buffer_type = WSI_WL_BUFFER_SHM_MEMCPY; -- } -- image_params = &cpu_image_params.base; -- } else { -- drm_image_params = (struct wsi_drm_image_params) { -- .base.image_type = WSI_IMAGE_TYPE_DRM, -- .same_gpu = wsi_wl_surface->display->same_gpu, -- }; -- /* Use explicit DRM format modifiers when both the server and the driver -- * support them. -- */ -- if (wsi_wl_surface->display->wl_dmabuf && wsi_device->supports_modifiers) { -- struct wsi_wl_format *f = NULL; -- /* Try to select modifiers for our vk_format from surface dma-buf -- * feedback. If that doesn't work, fallback to the list of supported -- * formats/modifiers by the display. */ -- if (wsi_wl_surface->wl_dmabuf_feedback) -- f = pick_format_from_surface_dmabuf_feedback(wsi_wl_surface, -- pCreateInfo->imageFormat); -- if (f == NULL) -- f = find_format(&chain->wsi_wl_surface->display->formats, -- pCreateInfo->imageFormat); -- if (f != NULL) { -- num_drm_modifiers = u_vector_length(&f->modifiers); -- drm_modifiers = u_vector_tail(&f->modifiers); -- if (num_drm_modifiers > 0) -- drm_image_params.num_modifier_lists = 1; -- else -- drm_image_params.num_modifier_lists = 0; -- drm_image_params.num_modifiers = &num_drm_modifiers; -- drm_image_params.modifiers = &drm_modifiers; -- } -- } -- buffer_type = WSI_WL_BUFFER_NATIVE; -- image_params = &drm_image_params.base; -- } -- -- result = wsi_swapchain_init(wsi_device, &chain->base, device, -- pCreateInfo, image_params, pAllocator); -- if (result != VK_SUCCESS) -- goto fail; -- -- bool alpha = pCreateInfo->compositeAlpha == -- VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; -- -- chain->base.destroy = wsi_wl_swapchain_destroy; -- chain->base.get_wsi_image = wsi_wl_swapchain_get_wsi_image; -- chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image; -- chain->base.queue_present = wsi_wl_swapchain_queue_present; -- chain->base.release_images = wsi_wl_swapchain_release_images; -- chain->base.set_present_mode = wsi_wl_swapchain_set_present_mode; -- chain->base.wait_for_present = wsi_wl_swapchain_wait_for_present; -- chain->base.present_mode = present_mode; -- chain->base.image_count = num_images; -- chain->extent = pCreateInfo->imageExtent; -- 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); -- } else { -- chain->shm_format = wl_shm_format_for_vk_format(chain->vk_format, alpha); -- } -- chain->num_drm_modifiers = num_drm_modifiers; -- chain->drm_modifiers = drm_modifiers; -- -- chain->queue = wl_display_create_queue(chain->wsi_wl_surface->display->wl_display); -- -- if (chain->wsi_wl_surface->display->wp_presentation_notwrapped) { -- pthread_mutex_init(&chain->present_ids.lock, NULL); -- -- wl_list_init(&chain->present_ids.outstanding_list); -- chain->present_ids.wp_presentation = -- wl_proxy_create_wrapper(chain->wsi_wl_surface->display->wp_presentation_notwrapped); -- wl_proxy_set_queue((struct wl_proxy *) chain->present_ids.wp_presentation, -- chain->queue); -- } -- -- chain->fifo_ready = true; -- -- for (uint32_t i = 0; i < chain->base.image_count; i++) { -- result = wsi_wl_image_init(chain, &chain->images[i], -- pCreateInfo, pAllocator); -- if (result != VK_SUCCESS) -- goto fail_image_init; -- chain->images[i].busy = false; -- } -- -- *swapchain_out = &chain->base; -- -- return VK_SUCCESS; -- --fail_image_init: -- wsi_wl_swapchain_images_free(chain); -- -- wsi_wl_swapchain_chain_free(chain, pAllocator); --fail: -- vk_free(pAllocator, chain); -- wsi_wl_surface->chain = NULL; -- -- return result; --} -- --VkResult --wsi_wl_init_wsi(struct wsi_device *wsi_device, -- const VkAllocationCallbacks *alloc, -- VkPhysicalDevice physical_device) --{ -- struct wsi_wayland *wsi; -- VkResult result; -- -- wsi = vk_alloc(alloc, sizeof(*wsi), 8, -- VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); -- if (!wsi) { -- result = VK_ERROR_OUT_OF_HOST_MEMORY; -- goto fail; -- } -- -- wsi->physical_device = physical_device; -- wsi->alloc = alloc; -- wsi->wsi = wsi_device; -- -- wsi->base.get_support = wsi_wl_surface_get_support; -- wsi->base.get_capabilities2 = wsi_wl_surface_get_capabilities2; -- wsi->base.get_formats = wsi_wl_surface_get_formats; -- wsi->base.get_formats2 = wsi_wl_surface_get_formats2; -- wsi->base.get_present_modes = wsi_wl_surface_get_present_modes; -- wsi->base.get_present_rectangles = wsi_wl_surface_get_present_rectangles; -- wsi->base.create_swapchain = wsi_wl_surface_create_swapchain; -- -- wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base; -- -- return VK_SUCCESS; -- --fail: -- wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = NULL; -- -- return result; --} -- --void --wsi_wl_finish_wsi(struct wsi_device *wsi_device, -- const VkAllocationCallbacks *alloc) --{ -- struct wsi_wayland *wsi = -- (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; -- if (!wsi) -- return; -- -- vk_free(alloc, wsi); --} --- -2.43.0 - - -From 6c20c68d10ed9cbb440819a70fc12796418f2726 Mon Sep 17 00:00:00 2001 -From: Denis <benato.denis96@gmail.com> -Date: Sun, 10 Dec 2023 14:51:30 +0100 -Subject: [PATCH 5/5] wsi: Use vendored gamescope-commit-queue-v1 protocol - ---- - .../wayland-drm/gamescope-commit-queue-v1.xml | 181 ++++++++++++++++++ - src/egl/wayland/wayland-drm/meson.build | 22 ++- - src/vulkan/wsi/meson.build | 2 +- - src/vulkan/wsi/wsi_common_wayland.c | 22 +-- - 4 files changed, 214 insertions(+), 13 deletions(-) - create mode 100644 src/egl/wayland/wayland-drm/gamescope-commit-queue-v1.xml - -diff --git a/src/egl/wayland/wayland-drm/gamescope-commit-queue-v1.xml b/src/egl/wayland/wayland-drm/gamescope-commit-queue-v1.xml -new file mode 100644 -index 00000000000..d460e0bc10f ---- /dev/null -+++ b/src/egl/wayland/wayland-drm/gamescope-commit-queue-v1.xml -@@ -0,0 +1,181 @@ -+<?xml version="1.0" encoding="UTF-8"?> -+<protocol name="gamescope_commit_queue_v1"> -+ <copyright> -+ Copyright © 2023 Valve Corporation -+ -+ Permission is hereby granted, free of charge, to any person obtaining a -+ copy of this software and associated documentation files (the "Software"), -+ to deal in the Software without restriction, including without limitation -+ the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ and/or sell copies of the Software, and to permit persons to whom the -+ Software is furnished to do so, subject to the following conditions: -+ -+ The above copyright notice and this permission notice (including the next -+ paragraph) shall be included in all copies or substantial portions of the -+ Software. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ DEALINGS IN THE SOFTWARE. -+ </copyright> -+ -+ <interface name="gamescope_commit_queue_manager_v1" version="1"> -+ <description summary="commit queuing"> -+ By design Wayland uses a "mailbox" style presentation model. Under -+ the mailbox model, when wl_surface.commit is called, the currently -+ pending state is intended to replace the current state immediately. -+ -+ If state is committed many times before the compositor repaints a -+ scene, each commit takes place immediately, updating the existing -+ state. When the compositor repaints the display only the most -+ recent accumulation of state is visible. This may lead to client -+ buffers being released without presentation if they were replaced -+ before being displayed. -+ -+ There are other presentation models such as FIFO (First In First -+ Out) in which state commits are explicitly queued for future -+ repaint intervals, and client buffers should not be released -+ without being displayed. -+ -+ Graphics APIs such as Vulkan aim to support these presentation -+ models, but they are not implementable on top of our mailbox model -+ without the ability to change the default surface state handling -+ behaviour. -+ -+ This interface provides a way to control the compositor's surface -+ state handling to enable presentation models other than mailbox. -+ -+ It does so by exposing control of a compositor surface state queue, -+ and specifying for each call of wl_surface.commit whether the -+ pending state should be handled in a mailbox or a FIFO fashion. -+ -+ Warning! The protocol described in this file is currently in the testing -+ phase. Backward compatible changes may be added together with the -+ corresponding interface version bump. Backward incompatible changes can -+ only be done by creating a new major version of the extension. -+ </description> -+ <enum name="error"> -+ <description summary="fatal presentation error"> -+ These fatal protocol errors may be emitted in response to -+ illegal requests. -+ </description> -+ <entry name="queue_controller_already_exists" value="0" -+ summary="commit queue controller already exists for surface"/> -+ </enum> -+ -+ <request name="destroy" type="destructor"> -+ <description summary="unbind from the surface queuing interface"> -+ Informs the server that the client will no longer be using -+ this protocol object. Existing objects created by this object -+ are not affected. -+ </description> -+ </request> -+ -+ <request name="get_queue_controller"> -+ <description summary="request commit queue submission interface for surface"> -+ Establish a queue controller for a surface. -+ -+ Graphics APIs (EGL, Vulkan) will likely use this protocol -+ internally, so clients using them shouldn't directly use this -+ protocol on surfaces managed by those APIs, or a -+ queue_controller_already_exists protocol error will occur. -+ </description> -+ <arg name="id" type="new_id" interface="gamescope_commit_queue_v1"/> -+ <arg name="surface" type="object" interface="wl_surface"/> -+ </request> -+ </interface> -+ -+ <interface name="gamescope_commit_queue_v1" version="1"> -+ <description summary="commit queue controller"> -+ A queue controller for a surface. -+ -+ A wayland compositor may implicitly queue surface state to -+ allow it to pick the most recently ready state at repaint time, -+ or to allow surface state to contain timing information. -+ -+ The commit queue controller object allows explicit control over -+ the queue of upcoming surface state by allowing a client to attach -+ a queue drain mode to pending surface state before it calls -+ wl_surface.commit. -+ </description> -+ -+ <enum name="error"> -+ <description summary="fatal presentation error"> -+ These fatal protocol errors may be emitted in response to -+ illegal requests. -+ </description> -+ <entry name="invalid_queue_mode" value="0" -+ summary="invalid queue mode"/> -+ </enum> -+ -+ <enum name="queue_mode"> -+ <description summary="Queue drain mode"> -+ This enum is used to choose how the compositor processes a queue -+ entry at output repaint time. -+ </description> -+ <entry name="mailbox" value="0"> -+ <description summary="Fast forward through past timestamps"> -+ State from this queue slot may be updated immediately (without -+ completing a repaint) if newer state is ready to display at -+ repaint time. -+ </description> -+ </entry> -+ <entry name="fifo" value="1"> -+ <description summary="Attempt to display each queued commit"> -+ This queue slot will be the last state update for this surface -+ that the compositor will process during the repaint in which -+ it is ready for display. -+ -+ If the compositor is presenting with tearing, the surface state -+ must be made current for an iteration of the compositor's repaint -+ loop. This may result in the state being visible for a very short -+ duration, with visible artifacts, or even not visible at all for -+ surfaces that aren't full screen. -+ -+ The compositor must not cause state processing to stall indefinitely -+ for a surface that is occluded or otherwise not visible. Instead, -+ if the compositor is choosing not to present a surface for reasons -+ unrelated to state readiness, the FIFO condition must be considered -+ satisfied at the moment new state becomes ready to replace the -+ undisplayed state. -+ </description> -+ </entry> -+ </enum> -+ -+ <request name="set_queue_mode"> -+ <description summary="set the queue draining mode for the pending commit"> -+ This request adds a queue drain mode to the pending surface -+ state, which will be commit by the next wl_surface.commit. -+ -+ This request tells the compositor how to process the state -+ from that commit when handling its internal state queue. -+ -+ If the drain mode is "mailbox", the compositor may continue -+ processing the next state in the queue before it repaints -+ the display. -+ -+ If the drain mode is "fifo", the compositor should ensure the -+ queue is not advanced until after this state has been current -+ for a repaint. The queue may be advance without repaint in the -+ case of off-screen or occluded surfaces. -+ -+ The default drain mode when none is specified is "mailbox". -+ </description> -+ <arg name="mode" type="uint" enum="drain_mode"/> -+ </request> -+ -+ <request name="destroy" type="destructor"> -+ <description summary="Destroy the surface queue controller"> -+ Informs the server that the client will no longer be using -+ this protocol object. -+ -+ Surface state changes previously made by this protocol are -+ unaffected by this object's destruction. -+ </description> -+ </request> -+ </interface> -+</protocol> -diff --git a/src/egl/wayland/wayland-drm/meson.build b/src/egl/wayland/wayland-drm/meson.build -index 48c676d7be4..3fb5a1723b3 100644 ---- a/src/egl/wayland/wayland-drm/meson.build -+++ b/src/egl/wayland/wayland-drm/meson.build -@@ -59,7 +59,7 @@ libwayland_drm = static_library( - # here for now as the maybe-least-bad solution. - wp_dir = dep_wl_protocols.get_variable(pkgconfig : 'pkgdatadir', internal : 'pkgdatadir') - wp_protos = { -- 'commit-queue-v1': 'staging/commit-queue/commit-queue-v1.xml', -+ #'commit-queue-v1': 'staging/commit-queue/commit-queue-v1.xml', - #'commit-timing-v1': 'staging/commit-timing/commit-timing-v1.xml', - 'linux-dmabuf-unstable-v1': 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml', - 'presentation-time': 'stable/presentation-time/presentation-time.xml', -@@ -81,3 +81,23 @@ foreach name, xml : wp_protos - ) - wp_files += { name: [code, header] } - endforeach -+ -+gamescope_protos = { -+ 'gamescope-commit-queue-v1': 'gamescope-commit-queue-v1.xml', -+} -+foreach name, xml : gamescope_protos -+ code = custom_target( -+ name + '-protocol.c', -+ input : xml, -+ output : name + '-protocol.c', -+ command : [prog_wl_scanner, wl_scanner_arg, '@INPUT@', '@OUTPUT@'], -+ ) -+ header = custom_target( -+ name + '-client-protocol.h', -+ input : xml, -+ output : name + '-client-protocol.h', -+ command : [prog_wl_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], -+ ) -+ wp_files += { name: [code, header] } -+endforeach -+ -diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build -index 5caea0e8f4f..d90722be253 100644 ---- a/src/vulkan/wsi/meson.build -+++ b/src/vulkan/wsi/meson.build -@@ -31,7 +31,7 @@ endif - - if with_platform_wayland - files_vulkan_wsi += files('wsi_common_wayland.c') -- files_vulkan_wsi += wp_files['commit-queue-v1'] -+ files_vulkan_wsi += wp_files['gamescope-commit-queue-v1'] - #files_vulkan_wsi += wp_files['commit-timing-v1'] - files_vulkan_wsi += wp_files['linux-dmabuf-unstable-v1'] - files_vulkan_wsi += wp_files['presentation-time'] -diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c -index d9069dee499..b5f956974af 100644 ---- a/src/vulkan/wsi/wsi_common_wayland.c -+++ b/src/vulkan/wsi/wsi_common_wayland.c -@@ -41,7 +41,7 @@ - #include "vk_util.h" - #include "wsi_common_entrypoints.h" - #include "wsi_common_private.h" --#include "commit-queue-v1-client-protocol.h" -+#include "gamescope-commit-queue-v1-client-protocol.h" - #include "linux-dmabuf-unstable-v1-client-protocol.h" - #include "presentation-time-client-protocol.h" - #include "tearing-control-v1-client-protocol.h" -@@ -114,7 +114,7 @@ struct wsi_wl_display { - /* users want per-chain wsi_wl_swapchain->present_ids.wp_presentation */ - struct wp_presentation *wp_presentation_notwrapped; - -- struct wp_commit_queue_manager_v1 *commit_queue_manager; -+ struct gamescope_commit_queue_manager_v1 *commit_queue_manager; - - struct wsi_wayland *wsi_wl; - -@@ -170,7 +170,7 @@ struct wsi_wl_swapchain { - - struct wsi_wl_surface *wsi_wl_surface; - struct wp_tearing_control_v1 *tearing_control; -- struct wp_commit_queue_v1 *commit_queue; -+ struct gamescope_commit_queue_v1 *commit_queue; - bool can_timestamp; - - struct wl_callback *frame; -@@ -944,9 +944,9 @@ registry_handle_global(void *data, struct wl_registry *registry, - } else if (strcmp(interface, wp_tearing_control_manager_v1_interface.name) == 0) { - display->tearing_control_manager = - wl_registry_bind(registry, name, &wp_tearing_control_manager_v1_interface, 1); -- } else if (strcmp(interface, wp_commit_queue_manager_v1_interface.name) == 0) { -+ } else if (strcmp(interface, gamescope_commit_queue_manager_v1_interface.name) == 0) { - display->commit_queue_manager = -- wl_registry_bind(registry, name, &wp_commit_queue_manager_v1_interface, 1); -+ wl_registry_bind(registry, name, &gamescope_commit_queue_manager_v1_interface, 1); - } - } - -@@ -974,7 +974,7 @@ wsi_wl_display_finish(struct wsi_wl_display *display) - if (display->wp_presentation_notwrapped) - wp_presentation_destroy(display->wp_presentation_notwrapped); - if (display->commit_queue_manager) -- wp_commit_queue_manager_v1_destroy(display->commit_queue_manager); -+ gamescope_commit_queue_manager_v1_destroy(display->commit_queue_manager); - if (display->tearing_control_manager) - wp_tearing_control_manager_v1_destroy(display->tearing_control_manager); - if (display->wl_display_wrapper) -@@ -2063,8 +2063,8 @@ set_timestamp(struct wsi_wl_swapchain *chain) - - timespec_from_nsec(&target_ts, target); - -- wp_commit_queue_v1_set_queue_mode(chain->commit_queue, -- WP_COMMIT_QUEUE_V1_QUEUE_MODE_FIFO); -+ gamescope_commit_queue_v1_set_queue_mode(chain->commit_queue, -+ GAMESCOPE_COMMIT_QUEUE_V1_QUEUE_MODE_FIFO); - chain->last_target_time = target; - } - -@@ -2312,7 +2312,7 @@ wsi_wl_swapchain_chain_free(struct wsi_wl_swapchain *chain, - } - - if (chain->commit_queue) -- wp_commit_queue_v1_destroy(chain->commit_queue); -+ gamescope_commit_queue_v1_destroy(chain->commit_queue); - - wsi_swapchain_finish(&chain->base); - } -@@ -2369,7 +2369,7 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, - old_chain->tearing_control = NULL; - } - if (old_chain->commit_queue) { -- wp_commit_queue_v1_destroy(old_chain->commit_queue); -+ gamescope_commit_queue_v1_destroy(old_chain->commit_queue); - old_chain->commit_queue = NULL; - old_chain->can_timestamp = false; - } -@@ -2491,7 +2491,7 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, - chain->legacy_fifo_ready = true; - struct wsi_wl_display *dpy = chain->wsi_wl_surface->display; - if (dpy->commit_queue_manager) { -- chain->commit_queue = wp_commit_queue_manager_v1_get_queue_controller(dpy->commit_queue_manager, -+ chain->commit_queue = gamescope_commit_queue_manager_v1_get_queue_controller(dpy->commit_queue_manager, - chain->wsi_wl_surface->surface); - chain->can_timestamp = true; - } --- -2.43.0 - diff --git a/llvm32.native b/llvm32.native deleted file mode 100644 index cb4442fff26e..000000000000 --- a/llvm32.native +++ /dev/null @@ -1,2 +0,0 @@ -[binaries] -llvm-config = '/usr/bin/llvm-config32' |