wsi_common_x11.c revision 7ec681f3
1/*
2 * Copyright © 2015 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include <X11/Xlib-xcb.h>
25#include <X11/xshmfence.h>
26#include <xcb/xcb.h>
27#include <xcb/dri3.h>
28#include <xcb/present.h>
29#include <xcb/shm.h>
30
31#include "util/macros.h"
32#include <stdlib.h>
33#include <stdio.h>
34#include <unistd.h>
35#include <errno.h>
36#include <string.h>
37#include <fcntl.h>
38#include <poll.h>
39#include <xf86drm.h>
40#include "drm-uapi/drm_fourcc.h"
41#include "util/hash_table.h"
42#include "util/u_debug.h"
43#include "util/u_thread.h"
44#include "util/xmlconfig.h"
45
46#include "vk_instance.h"
47#include "vk_physical_device.h"
48#include "vk_util.h"
49#include "vk_enum_to_str.h"
50#include "wsi_common_entrypoints.h"
51#include "wsi_common_private.h"
52#include "wsi_common_queue.h"
53
54#ifdef HAVE_SYS_SHM_H
55#include <sys/ipc.h>
56#include <sys/shm.h>
57#endif
58
59struct wsi_x11_connection {
60   bool has_dri3;
61   bool has_dri3_modifiers;
62   bool has_present;
63   bool is_proprietary_x11;
64   bool is_xwayland;
65   bool has_mit_shm;
66};
67
68struct wsi_x11 {
69   struct wsi_interface base;
70
71   pthread_mutex_t                              mutex;
72   /* Hash table of xcb_connection -> wsi_x11_connection mappings */
73   struct hash_table *connections;
74};
75
76
77/** wsi_dri3_open
78 *
79 * Wrapper around xcb_dri3_open
80 */
81static int
82wsi_dri3_open(xcb_connection_t *conn,
83	      xcb_window_t root,
84	      uint32_t provider)
85{
86   xcb_dri3_open_cookie_t       cookie;
87   xcb_dri3_open_reply_t        *reply;
88   int                          fd;
89
90   cookie = xcb_dri3_open(conn,
91                          root,
92                          provider);
93
94   reply = xcb_dri3_open_reply(conn, cookie, NULL);
95   if (!reply)
96      return -1;
97
98   if (reply->nfd != 1) {
99      free(reply);
100      return -1;
101   }
102
103   fd = xcb_dri3_open_reply_fds(conn, reply)[0];
104   free(reply);
105   fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
106
107   return fd;
108}
109
110static bool
111wsi_x11_check_dri3_compatible(const struct wsi_device *wsi_dev,
112                              xcb_connection_t *conn)
113{
114   xcb_screen_iterator_t screen_iter =
115      xcb_setup_roots_iterator(xcb_get_setup(conn));
116   xcb_screen_t *screen = screen_iter.data;
117
118   int dri3_fd = wsi_dri3_open(conn, screen->root, None);
119   if (dri3_fd == -1)
120      return true;
121
122   bool match = wsi_device_matches_drm_fd(wsi_dev, dri3_fd);
123
124   close(dri3_fd);
125
126   return match;
127}
128
129static bool
130wsi_x11_detect_xwayland(xcb_connection_t *conn)
131{
132   xcb_randr_query_version_cookie_t ver_cookie =
133      xcb_randr_query_version_unchecked(conn, 1, 3);
134   xcb_randr_query_version_reply_t *ver_reply =
135      xcb_randr_query_version_reply(conn, ver_cookie, NULL);
136   bool has_randr_v1_3 = ver_reply && (ver_reply->major_version > 1 ||
137                                       ver_reply->minor_version >= 3);
138   free(ver_reply);
139
140   if (!has_randr_v1_3)
141      return false;
142
143   const xcb_setup_t *setup = xcb_get_setup(conn);
144   xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
145
146   xcb_randr_get_screen_resources_current_cookie_t gsr_cookie =
147      xcb_randr_get_screen_resources_current_unchecked(conn, iter.data->root);
148   xcb_randr_get_screen_resources_current_reply_t *gsr_reply =
149      xcb_randr_get_screen_resources_current_reply(conn, gsr_cookie, NULL);
150
151   if (!gsr_reply || gsr_reply->num_outputs == 0) {
152      free(gsr_reply);
153      return false;
154   }
155
156   xcb_randr_output_t *randr_outputs =
157      xcb_randr_get_screen_resources_current_outputs(gsr_reply);
158   xcb_randr_get_output_info_cookie_t goi_cookie =
159      xcb_randr_get_output_info(conn, randr_outputs[0], gsr_reply->config_timestamp);
160   free(gsr_reply);
161
162   xcb_randr_get_output_info_reply_t *goi_reply =
163      xcb_randr_get_output_info_reply(conn, goi_cookie, NULL);
164   if (!goi_reply) {
165      return false;
166   }
167
168   char *output_name = (char*)xcb_randr_get_output_info_name(goi_reply);
169   bool is_xwayland = output_name && strncmp(output_name, "XWAYLAND", 8) == 0;
170   free(goi_reply);
171
172   return is_xwayland;
173}
174
175static struct wsi_x11_connection *
176wsi_x11_connection_create(struct wsi_device *wsi_dev,
177                          xcb_connection_t *conn)
178{
179   xcb_query_extension_cookie_t dri3_cookie, pres_cookie, randr_cookie, amd_cookie, nv_cookie, shm_cookie, sync_cookie;
180   xcb_query_extension_reply_t *dri3_reply, *pres_reply, *randr_reply, *amd_reply, *nv_reply, *shm_reply = NULL;
181   bool has_dri3_v1_2 = false;
182   bool has_present_v1_2 = false;
183
184   struct wsi_x11_connection *wsi_conn =
185      vk_alloc(&wsi_dev->instance_alloc, sizeof(*wsi_conn), 8,
186                VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
187   if (!wsi_conn)
188      return NULL;
189
190   sync_cookie = xcb_query_extension(conn, 4, "SYNC");
191   dri3_cookie = xcb_query_extension(conn, 4, "DRI3");
192   pres_cookie = xcb_query_extension(conn, 7, "Present");
193   randr_cookie = xcb_query_extension(conn, 5, "RANDR");
194
195   if (wsi_dev->sw)
196      shm_cookie = xcb_query_extension(conn, 7, "MIT-SHM");
197
198   /* We try to be nice to users and emit a warning if they try to use a
199    * Vulkan application on a system without DRI3 enabled.  However, this ends
200    * up spewing the warning when a user has, for example, both Intel
201    * integrated graphics and a discrete card with proprietary drivers and are
202    * running on the discrete card with the proprietary DDX.  In this case, we
203    * really don't want to print the warning because it just confuses users.
204    * As a heuristic to detect this case, we check for a couple of proprietary
205    * X11 extensions.
206    */
207   amd_cookie = xcb_query_extension(conn, 11, "ATIFGLRXDRI");
208   nv_cookie = xcb_query_extension(conn, 10, "NV-CONTROL");
209
210   xcb_discard_reply(conn, sync_cookie.sequence);
211   dri3_reply = xcb_query_extension_reply(conn, dri3_cookie, NULL);
212   pres_reply = xcb_query_extension_reply(conn, pres_cookie, NULL);
213   randr_reply = xcb_query_extension_reply(conn, randr_cookie, NULL);
214   amd_reply = xcb_query_extension_reply(conn, amd_cookie, NULL);
215   nv_reply = xcb_query_extension_reply(conn, nv_cookie, NULL);
216   if (wsi_dev->sw)
217      shm_reply = xcb_query_extension_reply(conn, shm_cookie, NULL);
218   if (!dri3_reply || !pres_reply) {
219      free(dri3_reply);
220      free(pres_reply);
221      free(randr_reply);
222      free(amd_reply);
223      free(nv_reply);
224      if (wsi_dev->sw)
225         free(shm_reply);
226      vk_free(&wsi_dev->instance_alloc, wsi_conn);
227      return NULL;
228   }
229
230   wsi_conn->has_dri3 = dri3_reply->present != 0;
231#ifdef HAVE_DRI3_MODIFIERS
232   if (wsi_conn->has_dri3) {
233      xcb_dri3_query_version_cookie_t ver_cookie;
234      xcb_dri3_query_version_reply_t *ver_reply;
235
236      ver_cookie = xcb_dri3_query_version(conn, 1, 2);
237      ver_reply = xcb_dri3_query_version_reply(conn, ver_cookie, NULL);
238      has_dri3_v1_2 =
239         (ver_reply->major_version > 1 || ver_reply->minor_version >= 2);
240      free(ver_reply);
241   }
242#endif
243
244   wsi_conn->has_present = pres_reply->present != 0;
245#ifdef HAVE_DRI3_MODIFIERS
246   if (wsi_conn->has_present) {
247      xcb_present_query_version_cookie_t ver_cookie;
248      xcb_present_query_version_reply_t *ver_reply;
249
250      ver_cookie = xcb_present_query_version(conn, 1, 2);
251      ver_reply = xcb_present_query_version_reply(conn, ver_cookie, NULL);
252      has_present_v1_2 =
253        (ver_reply->major_version > 1 || ver_reply->minor_version >= 2);
254      free(ver_reply);
255   }
256#endif
257
258   if (randr_reply && randr_reply->present != 0)
259      wsi_conn->is_xwayland = wsi_x11_detect_xwayland(conn);
260   else
261      wsi_conn->is_xwayland = false;
262
263   wsi_conn->has_dri3_modifiers = has_dri3_v1_2 && has_present_v1_2;
264   wsi_conn->is_proprietary_x11 = false;
265   if (amd_reply && amd_reply->present)
266      wsi_conn->is_proprietary_x11 = true;
267   if (nv_reply && nv_reply->present)
268      wsi_conn->is_proprietary_x11 = true;
269
270   wsi_conn->has_mit_shm = false;
271   if (wsi_conn->has_dri3 && wsi_conn->has_present && wsi_dev->sw) {
272      bool has_mit_shm = shm_reply->present != 0;
273
274      xcb_shm_query_version_cookie_t ver_cookie;
275      xcb_shm_query_version_reply_t *ver_reply;
276
277      ver_cookie = xcb_shm_query_version(conn);
278      ver_reply = xcb_shm_query_version_reply(conn, ver_cookie, NULL);
279
280      has_mit_shm = ver_reply->shared_pixmaps;
281      free(ver_reply);
282      xcb_void_cookie_t cookie;
283      xcb_generic_error_t *error;
284
285      if (has_mit_shm) {
286         cookie = xcb_shm_detach_checked(conn, 0);
287         if ((error = xcb_request_check(conn, cookie))) {
288            if (error->error_code != BadRequest)
289               wsi_conn->has_mit_shm = true;
290            free(error);
291         }
292      }
293      free(shm_reply);
294   }
295
296   free(dri3_reply);
297   free(pres_reply);
298   free(randr_reply);
299   free(amd_reply);
300   free(nv_reply);
301
302   return wsi_conn;
303}
304
305static void
306wsi_x11_connection_destroy(struct wsi_device *wsi_dev,
307                           struct wsi_x11_connection *conn)
308{
309   vk_free(&wsi_dev->instance_alloc, conn);
310}
311
312static bool
313wsi_x11_check_for_dri3(struct wsi_x11_connection *wsi_conn)
314{
315  if (wsi_conn->has_dri3)
316    return true;
317  if (!wsi_conn->is_proprietary_x11) {
318    fprintf(stderr, "vulkan: No DRI3 support detected - required for presentation\n"
319                    "Note: you can probably enable DRI3 in your Xorg config\n");
320  }
321  return false;
322}
323
324static struct wsi_x11_connection *
325wsi_x11_get_connection(struct wsi_device *wsi_dev,
326                       xcb_connection_t *conn)
327{
328   struct wsi_x11 *wsi =
329      (struct wsi_x11 *)wsi_dev->wsi[VK_ICD_WSI_PLATFORM_XCB];
330
331   pthread_mutex_lock(&wsi->mutex);
332
333   struct hash_entry *entry = _mesa_hash_table_search(wsi->connections, conn);
334   if (!entry) {
335      /* We're about to make a bunch of blocking calls.  Let's drop the
336       * mutex for now so we don't block up too badly.
337       */
338      pthread_mutex_unlock(&wsi->mutex);
339
340      struct wsi_x11_connection *wsi_conn =
341         wsi_x11_connection_create(wsi_dev, conn);
342      if (!wsi_conn)
343         return NULL;
344
345      pthread_mutex_lock(&wsi->mutex);
346
347      entry = _mesa_hash_table_search(wsi->connections, conn);
348      if (entry) {
349         /* Oops, someone raced us to it */
350         wsi_x11_connection_destroy(wsi_dev, wsi_conn);
351      } else {
352         entry = _mesa_hash_table_insert(wsi->connections, conn, wsi_conn);
353      }
354   }
355
356   pthread_mutex_unlock(&wsi->mutex);
357
358   return entry->data;
359}
360
361static const VkFormat formats[] = {
362   VK_FORMAT_B8G8R8A8_SRGB,
363   VK_FORMAT_B8G8R8A8_UNORM,
364};
365
366static const VkPresentModeKHR present_modes[] = {
367   VK_PRESENT_MODE_IMMEDIATE_KHR,
368   VK_PRESENT_MODE_MAILBOX_KHR,
369   VK_PRESENT_MODE_FIFO_KHR,
370   VK_PRESENT_MODE_FIFO_RELAXED_KHR,
371};
372
373static xcb_screen_t *
374get_screen_for_root(xcb_connection_t *conn, xcb_window_t root)
375{
376   xcb_screen_iterator_t screen_iter =
377      xcb_setup_roots_iterator(xcb_get_setup(conn));
378
379   for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
380      if (screen_iter.data->root == root)
381         return screen_iter.data;
382   }
383
384   return NULL;
385}
386
387static xcb_visualtype_t *
388screen_get_visualtype(xcb_screen_t *screen, xcb_visualid_t visual_id,
389                      unsigned *depth)
390{
391   xcb_depth_iterator_t depth_iter =
392      xcb_screen_allowed_depths_iterator(screen);
393
394   for (; depth_iter.rem; xcb_depth_next (&depth_iter)) {
395      xcb_visualtype_iterator_t visual_iter =
396         xcb_depth_visuals_iterator (depth_iter.data);
397
398      for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
399         if (visual_iter.data->visual_id == visual_id) {
400            if (depth)
401               *depth = depth_iter.data->depth;
402            return visual_iter.data;
403         }
404      }
405   }
406
407   return NULL;
408}
409
410static xcb_visualtype_t *
411connection_get_visualtype(xcb_connection_t *conn, xcb_visualid_t visual_id,
412                          unsigned *depth)
413{
414   xcb_screen_iterator_t screen_iter =
415      xcb_setup_roots_iterator(xcb_get_setup(conn));
416
417   /* For this we have to iterate over all of the screens which is rather
418    * annoying.  Fortunately, there is probably only 1.
419    */
420   for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
421      xcb_visualtype_t *visual = screen_get_visualtype(screen_iter.data,
422                                                       visual_id, depth);
423      if (visual)
424         return visual;
425   }
426
427   return NULL;
428}
429
430static xcb_visualtype_t *
431get_visualtype_for_window(xcb_connection_t *conn, xcb_window_t window,
432                          unsigned *depth)
433{
434   xcb_query_tree_cookie_t tree_cookie;
435   xcb_get_window_attributes_cookie_t attrib_cookie;
436   xcb_query_tree_reply_t *tree;
437   xcb_get_window_attributes_reply_t *attrib;
438
439   tree_cookie = xcb_query_tree(conn, window);
440   attrib_cookie = xcb_get_window_attributes(conn, window);
441
442   tree = xcb_query_tree_reply(conn, tree_cookie, NULL);
443   attrib = xcb_get_window_attributes_reply(conn, attrib_cookie, NULL);
444   if (attrib == NULL || tree == NULL) {
445      free(attrib);
446      free(tree);
447      return NULL;
448   }
449
450   xcb_window_t root = tree->root;
451   xcb_visualid_t visual_id = attrib->visual;
452   free(attrib);
453   free(tree);
454
455   xcb_screen_t *screen = get_screen_for_root(conn, root);
456   if (screen == NULL)
457      return NULL;
458
459   return screen_get_visualtype(screen, visual_id, depth);
460}
461
462static bool
463visual_has_alpha(xcb_visualtype_t *visual, unsigned depth)
464{
465   uint32_t rgb_mask = visual->red_mask |
466                       visual->green_mask |
467                       visual->blue_mask;
468
469   uint32_t all_mask = 0xffffffff >> (32 - depth);
470
471   /* Do we have bits left over after RGB? */
472   return (all_mask & ~rgb_mask) != 0;
473}
474
475VKAPI_ATTR VkBool32 VKAPI_CALL
476wsi_GetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice,
477                                               uint32_t queueFamilyIndex,
478                                               xcb_connection_t *connection,
479                                               xcb_visualid_t visual_id)
480{
481   VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
482   struct wsi_device *wsi_device = pdevice->wsi_device;
483   struct wsi_x11_connection *wsi_conn =
484      wsi_x11_get_connection(wsi_device, connection);
485
486   if (!wsi_conn)
487      return false;
488
489   if (!wsi_device->sw) {
490      if (!wsi_x11_check_for_dri3(wsi_conn))
491         return false;
492   }
493
494   unsigned visual_depth;
495   if (!connection_get_visualtype(connection, visual_id, &visual_depth))
496      return false;
497
498   if (visual_depth != 24 && visual_depth != 32)
499      return false;
500
501   return true;
502}
503
504VKAPI_ATTR VkBool32 VKAPI_CALL
505wsi_GetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice,
506                                                uint32_t queueFamilyIndex,
507                                                Display *dpy,
508                                                VisualID visualID)
509{
510   return wsi_GetPhysicalDeviceXcbPresentationSupportKHR(physicalDevice,
511                                                         queueFamilyIndex,
512                                                         XGetXCBConnection(dpy),
513                                                         visualID);
514}
515
516static xcb_connection_t*
517x11_surface_get_connection(VkIcdSurfaceBase *icd_surface)
518{
519   if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
520      return XGetXCBConnection(((VkIcdSurfaceXlib *)icd_surface)->dpy);
521   else
522      return ((VkIcdSurfaceXcb *)icd_surface)->connection;
523}
524
525static xcb_window_t
526x11_surface_get_window(VkIcdSurfaceBase *icd_surface)
527{
528   if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
529      return ((VkIcdSurfaceXlib *)icd_surface)->window;
530   else
531      return ((VkIcdSurfaceXcb *)icd_surface)->window;
532}
533
534static VkResult
535x11_surface_get_support(VkIcdSurfaceBase *icd_surface,
536                        struct wsi_device *wsi_device,
537                        uint32_t queueFamilyIndex,
538                        VkBool32* pSupported)
539{
540   xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
541   xcb_window_t window = x11_surface_get_window(icd_surface);
542
543   struct wsi_x11_connection *wsi_conn =
544      wsi_x11_get_connection(wsi_device, conn);
545   if (!wsi_conn)
546      return VK_ERROR_OUT_OF_HOST_MEMORY;
547
548   if (!wsi_device->sw) {
549      if (!wsi_x11_check_for_dri3(wsi_conn)) {
550         *pSupported = false;
551         return VK_SUCCESS;
552      }
553   }
554
555   unsigned visual_depth;
556   if (!get_visualtype_for_window(conn, window, &visual_depth)) {
557      *pSupported = false;
558      return VK_SUCCESS;
559   }
560
561   if (visual_depth != 24 && visual_depth != 32) {
562      *pSupported = false;
563      return VK_SUCCESS;
564   }
565
566   *pSupported = true;
567   return VK_SUCCESS;
568}
569
570static uint32_t
571x11_get_min_image_count(struct wsi_device *wsi_device)
572{
573   if (wsi_device->x11.override_minImageCount)
574      return wsi_device->x11.override_minImageCount;
575
576   /* For IMMEDIATE and FIFO, most games work in a pipelined manner where the
577    * can produce frames at a rate of 1/MAX(CPU duration, GPU duration), but
578    * the render latency is CPU duration + GPU duration.
579    *
580    * This means that with scanout from pageflipping we need 3 frames to run
581    * full speed:
582    * 1) CPU rendering work
583    * 2) GPU rendering work
584    * 3) scanout
585    *
586    * Once we have a nonblocking acquire that returns a semaphore we can merge
587    * 1 and 3. Hence the ideal implementation needs only 2 images, but games
588    * cannot tellwe currently do not have an ideal implementation and that
589    * hence they need to allocate 3 images. So let us do it for them.
590    *
591    * This is a tradeoff as it uses more memory than needed for non-fullscreen
592    * and non-performance intensive applications.
593    */
594   return 3;
595}
596
597static VkResult
598x11_surface_get_capabilities(VkIcdSurfaceBase *icd_surface,
599                             struct wsi_device *wsi_device,
600                             VkSurfaceCapabilitiesKHR *caps)
601{
602   xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
603   xcb_window_t window = x11_surface_get_window(icd_surface);
604   xcb_get_geometry_cookie_t geom_cookie;
605   xcb_generic_error_t *err;
606   xcb_get_geometry_reply_t *geom;
607   unsigned visual_depth;
608
609   geom_cookie = xcb_get_geometry(conn, window);
610
611   /* This does a round-trip.  This is why we do get_geometry first and
612    * wait to read the reply until after we have a visual.
613    */
614   xcb_visualtype_t *visual =
615      get_visualtype_for_window(conn, window, &visual_depth);
616
617   if (!visual)
618      return VK_ERROR_SURFACE_LOST_KHR;
619
620   geom = xcb_get_geometry_reply(conn, geom_cookie, &err);
621   if (geom) {
622      VkExtent2D extent = { geom->width, geom->height };
623      caps->currentExtent = extent;
624      caps->minImageExtent = extent;
625      caps->maxImageExtent = extent;
626   }
627   free(err);
628   free(geom);
629   if (!geom)
630       return VK_ERROR_SURFACE_LOST_KHR;
631
632   if (visual_has_alpha(visual, visual_depth)) {
633      caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
634                                      VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
635   } else {
636      caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
637                                      VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
638   }
639
640   caps->minImageCount = x11_get_min_image_count(wsi_device);
641   /* There is no real maximum */
642   caps->maxImageCount = 0;
643
644   caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
645   caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
646   caps->maxImageArrayLayers = 1;
647   caps->supportedUsageFlags =
648      VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
649      VK_IMAGE_USAGE_SAMPLED_BIT |
650      VK_IMAGE_USAGE_TRANSFER_DST_BIT |
651      VK_IMAGE_USAGE_STORAGE_BIT |
652      VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
653
654   return VK_SUCCESS;
655}
656
657static VkResult
658x11_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
659                              struct wsi_device *wsi_device,
660                              const void *info_next,
661                              VkSurfaceCapabilities2KHR *caps)
662{
663   assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
664
665   VkResult result =
666      x11_surface_get_capabilities(icd_surface, wsi_device,
667                                   &caps->surfaceCapabilities);
668
669   if (result != VK_SUCCESS)
670      return result;
671
672   vk_foreach_struct(ext, caps->pNext) {
673      switch (ext->sType) {
674      case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
675         VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;
676         protected->supportsProtected = VK_FALSE;
677         break;
678      }
679
680      default:
681         /* Ignored */
682         break;
683      }
684   }
685
686   return result;
687}
688
689static void
690get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats)
691{
692   memcpy(sorted_formats, formats, sizeof(formats));
693
694   if (wsi_device->force_bgra8_unorm_first) {
695      for (unsigned i = 0; i < ARRAY_SIZE(formats); i++) {
696         if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) {
697            sorted_formats[i] = sorted_formats[0];
698            sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM;
699            break;
700         }
701      }
702   }
703}
704
705static VkResult
706x11_surface_get_formats(VkIcdSurfaceBase *surface,
707                        struct wsi_device *wsi_device,
708                        uint32_t *pSurfaceFormatCount,
709                        VkSurfaceFormatKHR *pSurfaceFormats)
710{
711   VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount);
712
713   VkFormat sorted_formats[ARRAY_SIZE(formats)];
714   get_sorted_vk_formats(wsi_device, sorted_formats);
715
716   for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
717      vk_outarray_append(&out, f) {
718         f->format = sorted_formats[i];
719         f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
720      }
721   }
722
723   return vk_outarray_status(&out);
724}
725
726static VkResult
727x11_surface_get_formats2(VkIcdSurfaceBase *surface,
728                        struct wsi_device *wsi_device,
729                        const void *info_next,
730                        uint32_t *pSurfaceFormatCount,
731                        VkSurfaceFormat2KHR *pSurfaceFormats)
732{
733   VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount);
734
735   VkFormat sorted_formats[ARRAY_SIZE(formats)];
736   get_sorted_vk_formats(wsi_device, sorted_formats);
737
738   for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
739      vk_outarray_append(&out, f) {
740         assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
741         f->surfaceFormat.format = sorted_formats[i];
742         f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
743      }
744   }
745
746   return vk_outarray_status(&out);
747}
748
749static VkResult
750x11_surface_get_present_modes(VkIcdSurfaceBase *surface,
751                              uint32_t *pPresentModeCount,
752                              VkPresentModeKHR *pPresentModes)
753{
754   if (pPresentModes == NULL) {
755      *pPresentModeCount = ARRAY_SIZE(present_modes);
756      return VK_SUCCESS;
757   }
758
759   *pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes));
760   typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
761
762   return *pPresentModeCount < ARRAY_SIZE(present_modes) ?
763      VK_INCOMPLETE : VK_SUCCESS;
764}
765
766static VkResult
767x11_surface_get_present_rectangles(VkIcdSurfaceBase *icd_surface,
768                                   struct wsi_device *wsi_device,
769                                   uint32_t* pRectCount,
770                                   VkRect2D* pRects)
771{
772   xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
773   xcb_window_t window = x11_surface_get_window(icd_surface);
774   VK_OUTARRAY_MAKE(out, pRects, pRectCount);
775
776   vk_outarray_append(&out, rect) {
777      xcb_generic_error_t *err = NULL;
778      xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(conn, window);
779      xcb_get_geometry_reply_t *geom =
780         xcb_get_geometry_reply(conn, geom_cookie, &err);
781      free(err);
782      if (geom) {
783         *rect = (VkRect2D) {
784            .offset = { 0, 0 },
785            .extent = { geom->width, geom->height },
786         };
787      }
788      free(geom);
789      if (!geom)
790          return VK_ERROR_SURFACE_LOST_KHR;
791   }
792
793   return vk_outarray_status(&out);
794}
795
796VKAPI_ATTR VkResult VKAPI_CALL
797wsi_CreateXcbSurfaceKHR(VkInstance _instance,
798                        const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
799                        const VkAllocationCallbacks *pAllocator,
800                        VkSurfaceKHR *pSurface)
801{
802   VK_FROM_HANDLE(vk_instance, instance, _instance);
803   VkIcdSurfaceXcb *surface;
804
805   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR);
806
807   surface = vk_alloc2(&instance->alloc, pAllocator, sizeof *surface, 8,
808                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
809   if (surface == NULL)
810      return VK_ERROR_OUT_OF_HOST_MEMORY;
811
812   surface->base.platform = VK_ICD_WSI_PLATFORM_XCB;
813   surface->connection = pCreateInfo->connection;
814   surface->window = pCreateInfo->window;
815
816   *pSurface = VkIcdSurfaceBase_to_handle(&surface->base);
817   return VK_SUCCESS;
818}
819
820VKAPI_ATTR VkResult VKAPI_CALL
821wsi_CreateXlibSurfaceKHR(VkInstance _instance,
822                         const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
823                         const VkAllocationCallbacks *pAllocator,
824                         VkSurfaceKHR *pSurface)
825{
826   VK_FROM_HANDLE(vk_instance, instance, _instance);
827   VkIcdSurfaceXlib *surface;
828
829   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR);
830
831   surface = vk_alloc2(&instance->alloc, pAllocator, sizeof *surface, 8,
832                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
833   if (surface == NULL)
834      return VK_ERROR_OUT_OF_HOST_MEMORY;
835
836   surface->base.platform = VK_ICD_WSI_PLATFORM_XLIB;
837   surface->dpy = pCreateInfo->dpy;
838   surface->window = pCreateInfo->window;
839
840   *pSurface = VkIcdSurfaceBase_to_handle(&surface->base);
841   return VK_SUCCESS;
842}
843
844struct x11_image {
845   struct wsi_image                          base;
846   xcb_pixmap_t                              pixmap;
847   bool                                      busy;
848   bool                                      present_queued;
849   struct xshmfence *                        shm_fence;
850   uint32_t                                  sync_fence;
851   uint32_t                                  serial;
852   xcb_shm_seg_t                             shmseg;
853   int                                       shmid;
854   uint8_t *                                 shmaddr;
855};
856
857struct x11_swapchain {
858   struct wsi_swapchain                        base;
859
860   bool                                         has_dri3_modifiers;
861   bool                                         has_mit_shm;
862
863   xcb_connection_t *                           conn;
864   xcb_window_t                                 window;
865   xcb_gc_t                                     gc;
866   uint32_t                                     depth;
867   VkExtent2D                                   extent;
868
869   xcb_present_event_t                          event_id;
870   xcb_special_event_t *                        special_event;
871   uint64_t                                     send_sbc;
872   uint64_t                                     last_present_msc;
873   uint32_t                                     stamp;
874   int                                          sent_image_count;
875
876   bool                                         has_present_queue;
877   bool                                         has_acquire_queue;
878   VkResult                                     status;
879   bool                                         copy_is_suboptimal;
880   struct wsi_queue                             present_queue;
881   struct wsi_queue                             acquire_queue;
882   pthread_t                                    queue_manager;
883
884   struct x11_image                             images[0];
885};
886VK_DEFINE_NONDISP_HANDLE_CASTS(x11_swapchain, base.base, VkSwapchainKHR,
887                               VK_OBJECT_TYPE_SWAPCHAIN_KHR)
888
889/**
890 * Update the swapchain status with the result of an operation, and return
891 * the combined status. The chain status will eventually be returned from
892 * AcquireNextImage and QueuePresent.
893 *
894 * We make sure to 'stick' more pessimistic statuses: an out-of-date error
895 * is permanent once seen, and every subsequent call will return this. If
896 * this has not been seen, success will be returned.
897 */
898static VkResult
899_x11_swapchain_result(struct x11_swapchain *chain, VkResult result,
900                      const char *file, int line)
901{
902   /* Prioritise returning existing errors for consistency. */
903   if (chain->status < 0)
904      return chain->status;
905
906   /* If we have a new error, mark it as permanent on the chain and return. */
907   if (result < 0) {
908#ifndef NDEBUG
909      fprintf(stderr, "%s:%d: Swapchain status changed to %s\n",
910              file, line, vk_Result_to_str(result));
911#endif
912      chain->status = result;
913      return result;
914   }
915
916   /* Return temporary errors, but don't persist them. */
917   if (result == VK_TIMEOUT || result == VK_NOT_READY)
918      return result;
919
920   /* Suboptimal isn't an error, but is a status which sticks to the swapchain
921    * and is always returned rather than success.
922    */
923   if (result == VK_SUBOPTIMAL_KHR) {
924#ifndef NDEBUG
925      if (chain->status != VK_SUBOPTIMAL_KHR) {
926         fprintf(stderr, "%s:%d: Swapchain status changed to %s\n",
927                 file, line, vk_Result_to_str(result));
928      }
929#endif
930      chain->status = result;
931      return result;
932   }
933
934   /* No changes, so return the last status. */
935   return chain->status;
936}
937#define x11_swapchain_result(chain, result) \
938   _x11_swapchain_result(chain, result, __FILE__, __LINE__)
939
940static struct wsi_image *
941x11_get_wsi_image(struct wsi_swapchain *wsi_chain, uint32_t image_index)
942{
943   struct x11_swapchain *chain = (struct x11_swapchain *)wsi_chain;
944   return &chain->images[image_index].base;
945}
946
947/**
948 * Process an X11 Present event. Does not update chain->status.
949 */
950static VkResult
951x11_handle_dri3_present_event(struct x11_swapchain *chain,
952                              xcb_present_generic_event_t *event)
953{
954   switch (event->evtype) {
955   case XCB_PRESENT_CONFIGURE_NOTIFY: {
956      xcb_present_configure_notify_event_t *config = (void *) event;
957
958      if (config->width != chain->extent.width ||
959          config->height != chain->extent.height)
960         return VK_SUBOPTIMAL_KHR;
961
962      break;
963   }
964
965   case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
966      xcb_present_idle_notify_event_t *idle = (void *) event;
967
968      for (unsigned i = 0; i < chain->base.image_count; i++) {
969         if (chain->images[i].pixmap == idle->pixmap) {
970            chain->images[i].busy = false;
971            chain->sent_image_count--;
972            assert(chain->sent_image_count >= 0);
973            if (chain->has_acquire_queue)
974               wsi_queue_push(&chain->acquire_queue, i);
975            break;
976         }
977      }
978
979      break;
980   }
981
982   case XCB_PRESENT_EVENT_COMPLETE_NOTIFY: {
983      xcb_present_complete_notify_event_t *complete = (void *) event;
984      if (complete->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
985         unsigned i;
986         for (i = 0; i < chain->base.image_count; i++) {
987            struct x11_image *image = &chain->images[i];
988            if (image->present_queued && image->serial == complete->serial)
989               image->present_queued = false;
990         }
991         chain->last_present_msc = complete->msc;
992      }
993
994      VkResult result = VK_SUCCESS;
995      switch (complete->mode) {
996      case XCB_PRESENT_COMPLETE_MODE_COPY:
997         if (chain->copy_is_suboptimal)
998            result = VK_SUBOPTIMAL_KHR;
999         break;
1000      case XCB_PRESENT_COMPLETE_MODE_FLIP:
1001         /* If we ever go from flipping to copying, the odds are very likely
1002          * that we could reallocate in a more optimal way if we didn't have
1003          * to care about scanout, so we always do this.
1004          */
1005         chain->copy_is_suboptimal = true;
1006         break;
1007#ifdef HAVE_DRI3_MODIFIERS
1008      case XCB_PRESENT_COMPLETE_MODE_SUBOPTIMAL_COPY:
1009         /* The winsys is now trying to flip directly and cannot due to our
1010          * configuration. Request the user reallocate.
1011          */
1012         result = VK_SUBOPTIMAL_KHR;
1013         break;
1014#endif
1015      default:
1016         break;
1017      }
1018
1019      return result;
1020   }
1021
1022   default:
1023      break;
1024   }
1025
1026   return VK_SUCCESS;
1027}
1028
1029
1030static uint64_t wsi_get_absolute_timeout(uint64_t timeout)
1031{
1032   uint64_t current_time = wsi_common_get_current_time();
1033
1034   timeout = MIN2(UINT64_MAX - current_time, timeout);
1035
1036   return current_time + timeout;
1037}
1038
1039static VkResult
1040x11_acquire_next_image_poll_x11(struct x11_swapchain *chain,
1041                                uint32_t *image_index, uint64_t timeout)
1042{
1043   xcb_generic_event_t *event;
1044   struct pollfd pfds;
1045   uint64_t atimeout;
1046   while (1) {
1047      for (uint32_t i = 0; i < chain->base.image_count; i++) {
1048         if (!chain->images[i].busy) {
1049            /* We found a non-busy image */
1050            xshmfence_await(chain->images[i].shm_fence);
1051            *image_index = i;
1052            chain->images[i].busy = true;
1053            return x11_swapchain_result(chain, VK_SUCCESS);
1054         }
1055      }
1056
1057      xcb_flush(chain->conn);
1058
1059      if (timeout == UINT64_MAX) {
1060         event = xcb_wait_for_special_event(chain->conn, chain->special_event);
1061         if (!event)
1062            return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR);
1063      } else {
1064         event = xcb_poll_for_special_event(chain->conn, chain->special_event);
1065         if (!event) {
1066            int ret;
1067            if (timeout == 0)
1068               return x11_swapchain_result(chain, VK_NOT_READY);
1069
1070            atimeout = wsi_get_absolute_timeout(timeout);
1071
1072            pfds.fd = xcb_get_file_descriptor(chain->conn);
1073            pfds.events = POLLIN;
1074            ret = poll(&pfds, 1, timeout / 1000 / 1000);
1075            if (ret == 0)
1076               return x11_swapchain_result(chain, VK_TIMEOUT);
1077            if (ret == -1)
1078               return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR);
1079
1080            /* If a non-special event happens, the fd will still
1081             * poll. So recalculate the timeout now just in case.
1082             */
1083            uint64_t current_time = wsi_common_get_current_time();
1084            if (atimeout > current_time)
1085               timeout = atimeout - current_time;
1086            else
1087               timeout = 0;
1088            continue;
1089         }
1090      }
1091
1092      /* Update the swapchain status here. We may catch non-fatal errors here,
1093       * in which case we need to update the status and continue.
1094       */
1095      VkResult result = x11_handle_dri3_present_event(chain, (void *)event);
1096      /* Ensure that VK_SUBOPTIMAL_KHR is reported to the application */
1097      result = x11_swapchain_result(chain, result);
1098      free(event);
1099      if (result < 0)
1100         return result;
1101   }
1102}
1103
1104static VkResult
1105x11_acquire_next_image_from_queue(struct x11_swapchain *chain,
1106                                  uint32_t *image_index_out, uint64_t timeout)
1107{
1108   assert(chain->has_acquire_queue);
1109
1110   uint32_t image_index;
1111   VkResult result = wsi_queue_pull(&chain->acquire_queue,
1112                                    &image_index, timeout);
1113   if (result < 0 || result == VK_TIMEOUT) {
1114      /* On error, the thread has shut down, so safe to update chain->status.
1115       * Calling x11_swapchain_result with VK_TIMEOUT won't modify
1116       * chain->status so that is also safe.
1117       */
1118      return x11_swapchain_result(chain, result);
1119   } else if (chain->status < 0) {
1120      return chain->status;
1121   }
1122
1123   assert(image_index < chain->base.image_count);
1124   xshmfence_await(chain->images[image_index].shm_fence);
1125
1126   *image_index_out = image_index;
1127
1128   return chain->status;
1129}
1130
1131static VkResult
1132x11_present_to_x11_dri3(struct x11_swapchain *chain, uint32_t image_index,
1133                        uint64_t target_msc)
1134{
1135   struct x11_image *image = &chain->images[image_index];
1136
1137   assert(image_index < chain->base.image_count);
1138
1139   uint32_t options = XCB_PRESENT_OPTION_NONE;
1140
1141   int64_t divisor = 0;
1142   int64_t remainder = 0;
1143
1144   struct wsi_x11_connection *wsi_conn =
1145      wsi_x11_get_connection((struct wsi_device*)chain->base.wsi, chain->conn);
1146   if (!wsi_conn)
1147      return VK_ERROR_OUT_OF_HOST_MEMORY;
1148
1149   if (chain->base.present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR ||
1150       (chain->base.present_mode == VK_PRESENT_MODE_MAILBOX_KHR &&
1151        wsi_conn->is_xwayland) ||
1152       chain->base.present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)
1153      options |= XCB_PRESENT_OPTION_ASYNC;
1154
1155#ifdef HAVE_DRI3_MODIFIERS
1156   if (chain->has_dri3_modifiers)
1157      options |= XCB_PRESENT_OPTION_SUBOPTIMAL;
1158#endif
1159
1160   /* Poll for any available event and update the swapchain status. This could
1161    * update the status of the swapchain to SUBOPTIMAL or OUT_OF_DATE if the
1162    * associated X11 surface has been resized.
1163    */
1164   xcb_generic_event_t *event;
1165   while ((event = xcb_poll_for_special_event(chain->conn, chain->special_event))) {
1166      VkResult result = x11_handle_dri3_present_event(chain, (void *)event);
1167      /* Ensure that VK_SUBOPTIMAL_KHR is reported to the application */
1168      result = x11_swapchain_result(chain, result);
1169      free(event);
1170      if (result < 0)
1171         return result;
1172   }
1173
1174   xshmfence_reset(image->shm_fence);
1175
1176   ++chain->sent_image_count;
1177   assert(chain->sent_image_count <= chain->base.image_count);
1178
1179   ++chain->send_sbc;
1180   image->present_queued = true;
1181   image->serial = (uint32_t) chain->send_sbc;
1182
1183   xcb_void_cookie_t cookie =
1184      xcb_present_pixmap(chain->conn,
1185                         chain->window,
1186                         image->pixmap,
1187                         image->serial,
1188                         0,                                    /* valid */
1189                         0,                                    /* update */
1190                         0,                                    /* x_off */
1191                         0,                                    /* y_off */
1192                         XCB_NONE,                             /* target_crtc */
1193                         XCB_NONE,
1194                         image->sync_fence,
1195                         options,
1196                         target_msc,
1197                         divisor,
1198                         remainder, 0, NULL);
1199   xcb_discard_reply(chain->conn, cookie.sequence);
1200
1201   xcb_flush(chain->conn);
1202
1203   return x11_swapchain_result(chain, VK_SUCCESS);
1204}
1205
1206static VkResult
1207x11_present_to_x11_sw(struct x11_swapchain *chain, uint32_t image_index,
1208                      uint64_t target_msc)
1209{
1210   struct x11_image *image = &chain->images[image_index];
1211
1212   xcb_void_cookie_t cookie;
1213   void *myptr;
1214   chain->base.wsi->MapMemory(chain->base.device,
1215                              image->base.memory,
1216                              0, 0, 0, &myptr);
1217
1218   cookie = xcb_put_image(chain->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
1219                          chain->window,
1220                          chain->gc,
1221			  image->base.row_pitches[0] / 4,
1222                          chain->extent.height,
1223                          0,0,0,24,
1224                          image->base.row_pitches[0] * chain->extent.height,
1225                          myptr);
1226
1227   chain->base.wsi->UnmapMemory(chain->base.device, image->base.memory);
1228   xcb_discard_reply(chain->conn, cookie.sequence);
1229   xcb_flush(chain->conn);
1230   return x11_swapchain_result(chain, VK_SUCCESS);
1231}
1232static VkResult
1233x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index,
1234                   uint64_t target_msc)
1235{
1236   if (chain->base.wsi->sw && !chain->has_mit_shm)
1237      return x11_present_to_x11_sw(chain, image_index, target_msc);
1238   return x11_present_to_x11_dri3(chain, image_index, target_msc);
1239}
1240
1241static VkResult
1242x11_acquire_next_image(struct wsi_swapchain *anv_chain,
1243                       const VkAcquireNextImageInfoKHR *info,
1244                       uint32_t *image_index)
1245{
1246   struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
1247   uint64_t timeout = info->timeout;
1248
1249   /* If the swapchain is in an error state, don't go any further. */
1250   if (chain->status < 0)
1251      return chain->status;
1252
1253   if (chain->base.wsi->sw && !chain->has_mit_shm) {
1254      *image_index = 0;
1255      return VK_SUCCESS;
1256   }
1257   if (chain->has_acquire_queue) {
1258      return x11_acquire_next_image_from_queue(chain, image_index, timeout);
1259   } else {
1260      return x11_acquire_next_image_poll_x11(chain, image_index, timeout);
1261   }
1262}
1263
1264static VkResult
1265x11_queue_present(struct wsi_swapchain *anv_chain,
1266                  uint32_t image_index,
1267                  const VkPresentRegionKHR *damage)
1268{
1269   struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
1270
1271   /* If the swapchain is in an error state, don't go any further. */
1272   if (chain->status < 0)
1273      return chain->status;
1274
1275   chain->images[image_index].busy = true;
1276   if (chain->has_present_queue) {
1277      wsi_queue_push(&chain->present_queue, image_index);
1278      return chain->status;
1279   } else {
1280      return x11_present_to_x11(chain, image_index, 0);
1281   }
1282}
1283
1284static bool
1285x11_needs_wait_for_fences(const struct wsi_device *wsi_device,
1286                          struct wsi_x11_connection *wsi_conn,
1287                          VkPresentModeKHR present_mode)
1288{
1289   if (wsi_conn->is_xwayland && !wsi_device->x11.xwaylandWaitReady) {
1290      return false;
1291   }
1292
1293   switch (present_mode) {
1294   case VK_PRESENT_MODE_MAILBOX_KHR:
1295      return true;
1296   case VK_PRESENT_MODE_IMMEDIATE_KHR:
1297      return wsi_conn->is_xwayland;
1298   default:
1299      return false;
1300   }
1301}
1302
1303static void *
1304x11_manage_fifo_queues(void *state)
1305{
1306   struct x11_swapchain *chain = state;
1307   struct wsi_x11_connection *wsi_conn =
1308      wsi_x11_get_connection((struct wsi_device*)chain->base.wsi, chain->conn);
1309   VkResult result = VK_SUCCESS;
1310
1311   assert(chain->has_present_queue);
1312
1313   u_thread_setname("WSI swapchain queue");
1314
1315   while (chain->status >= 0) {
1316      /* We can block here unconditionally because after an image was sent to
1317       * the server (later on in this loop) we ensure at least one image is
1318       * acquirable by the consumer or wait there on such an event.
1319       */
1320      uint32_t image_index = 0;
1321      result = wsi_queue_pull(&chain->present_queue, &image_index, INT64_MAX);
1322      assert(result != VK_TIMEOUT);
1323      if (result < 0) {
1324         goto fail;
1325      } else if (chain->status < 0) {
1326         /* The status can change underneath us if the swapchain is destroyed
1327          * from another thread.
1328          */
1329         return NULL;
1330      }
1331
1332      if (x11_needs_wait_for_fences(chain->base.wsi, wsi_conn,
1333                                    chain->base.present_mode)) {
1334         result = chain->base.wsi->WaitForFences(chain->base.device, 1,
1335                                        &chain->base.fences[image_index],
1336                                        true, UINT64_MAX);
1337         if (result != VK_SUCCESS) {
1338            result = VK_ERROR_OUT_OF_DATE_KHR;
1339            goto fail;
1340         }
1341      }
1342
1343      uint64_t target_msc = 0;
1344      if (chain->has_acquire_queue)
1345         target_msc = chain->last_present_msc + 1;
1346
1347      result = x11_present_to_x11(chain, image_index, target_msc);
1348      if (result < 0)
1349         goto fail;
1350
1351      if (chain->has_acquire_queue) {
1352         /* Wait for our presentation to occur and ensure we have at least one
1353          * image that can be acquired by the client afterwards. This ensures we
1354          * can pull on the present-queue on the next loop.
1355          */
1356         while (chain->images[image_index].present_queued ||
1357                chain->sent_image_count == chain->base.image_count) {
1358            xcb_generic_event_t *event =
1359               xcb_wait_for_special_event(chain->conn, chain->special_event);
1360            if (!event) {
1361               result = VK_ERROR_OUT_OF_DATE_KHR;
1362               goto fail;
1363            }
1364
1365            result = x11_handle_dri3_present_event(chain, (void *)event);
1366            /* Ensure that VK_SUBOPTIMAL_KHR is reported to the application */
1367            result = x11_swapchain_result(chain, result);
1368            free(event);
1369            if (result < 0)
1370               goto fail;
1371         }
1372      }
1373   }
1374
1375fail:
1376   x11_swapchain_result(chain, result);
1377   if (chain->has_acquire_queue)
1378      wsi_queue_push(&chain->acquire_queue, UINT32_MAX);
1379
1380   return NULL;
1381}
1382
1383static uint8_t *
1384alloc_shm(struct wsi_image *imagew, unsigned size)
1385{
1386#ifdef HAVE_SYS_SHM_H
1387   struct x11_image *image = (struct x11_image *)imagew;
1388   image->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
1389   if (image->shmid < 0)
1390      return NULL;
1391
1392   uint8_t *addr = (uint8_t *)shmat(image->shmid, 0, 0);
1393   /* mark the segment immediately for deletion to avoid leaks */
1394   shmctl(image->shmid, IPC_RMID, 0);
1395
1396   if (addr == (uint8_t *) -1)
1397      return NULL;
1398
1399   image->shmaddr = addr;
1400   return addr;
1401#else
1402   return NULL;
1403#endif
1404}
1405
1406static VkResult
1407x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
1408               const VkSwapchainCreateInfoKHR *pCreateInfo,
1409               const VkAllocationCallbacks* pAllocator,
1410               const uint64_t *const *modifiers,
1411               const uint32_t *num_modifiers,
1412               int num_tranches, struct x11_image *image)
1413{
1414   xcb_void_cookie_t cookie;
1415   VkResult result;
1416   uint32_t bpp = 32;
1417   int fence_fd;
1418
1419   if (chain->base.use_prime_blit) {
1420      bool use_modifier = num_tranches > 0;
1421      result = wsi_create_prime_image(&chain->base, pCreateInfo, use_modifier, &image->base);
1422   } else {
1423      result = wsi_create_native_image(&chain->base, pCreateInfo,
1424                                       num_tranches, num_modifiers, modifiers,
1425                                       chain->has_mit_shm ? &alloc_shm : NULL,
1426                                       &image->base);
1427   }
1428   if (result < 0)
1429      return result;
1430
1431   if (chain->base.wsi->sw) {
1432      if (!chain->has_mit_shm) {
1433         image->busy = false;
1434         return VK_SUCCESS;
1435      }
1436
1437      image->shmseg = xcb_generate_id(chain->conn);
1438
1439      xcb_shm_attach(chain->conn,
1440                     image->shmseg,
1441                     image->shmid,
1442                     0);
1443      image->pixmap = xcb_generate_id(chain->conn);
1444      cookie = xcb_shm_create_pixmap_checked(chain->conn,
1445                                             image->pixmap,
1446                                             chain->window,
1447                                             image->base.row_pitches[0] / 4,
1448                                             pCreateInfo->imageExtent.height,
1449                                             chain->depth,
1450                                             image->shmseg, 0);
1451      xcb_discard_reply(chain->conn, cookie.sequence);
1452      goto out_fence;
1453   }
1454   image->pixmap = xcb_generate_id(chain->conn);
1455
1456#ifdef HAVE_DRI3_MODIFIERS
1457   if (image->base.drm_modifier != DRM_FORMAT_MOD_INVALID) {
1458      /* If the image has a modifier, we must have DRI3 v1.2. */
1459      assert(chain->has_dri3_modifiers);
1460
1461      cookie =
1462         xcb_dri3_pixmap_from_buffers_checked(chain->conn,
1463                                              image->pixmap,
1464                                              chain->window,
1465                                              image->base.num_planes,
1466                                              pCreateInfo->imageExtent.width,
1467                                              pCreateInfo->imageExtent.height,
1468                                              image->base.row_pitches[0],
1469                                              image->base.offsets[0],
1470                                              image->base.row_pitches[1],
1471                                              image->base.offsets[1],
1472                                              image->base.row_pitches[2],
1473                                              image->base.offsets[2],
1474                                              image->base.row_pitches[3],
1475                                              image->base.offsets[3],
1476                                              chain->depth, bpp,
1477                                              image->base.drm_modifier,
1478                                              image->base.fds);
1479   } else
1480#endif
1481   {
1482      /* Without passing modifiers, we can't have multi-plane RGB images. */
1483      assert(image->base.num_planes == 1);
1484
1485      cookie =
1486         xcb_dri3_pixmap_from_buffer_checked(chain->conn,
1487                                             image->pixmap,
1488                                             chain->window,
1489                                             image->base.sizes[0],
1490                                             pCreateInfo->imageExtent.width,
1491                                             pCreateInfo->imageExtent.height,
1492                                             image->base.row_pitches[0],
1493                                             chain->depth, bpp,
1494                                             image->base.fds[0]);
1495   }
1496
1497   xcb_discard_reply(chain->conn, cookie.sequence);
1498
1499   /* XCB has now taken ownership of the FDs. */
1500   for (int i = 0; i < image->base.num_planes; i++)
1501      image->base.fds[i] = -1;
1502
1503out_fence:
1504   fence_fd = xshmfence_alloc_shm();
1505   if (fence_fd < 0)
1506      goto fail_pixmap;
1507
1508   image->shm_fence = xshmfence_map_shm(fence_fd);
1509   if (image->shm_fence == NULL)
1510      goto fail_shmfence_alloc;
1511
1512   image->sync_fence = xcb_generate_id(chain->conn);
1513   xcb_dri3_fence_from_fd(chain->conn,
1514                          image->pixmap,
1515                          image->sync_fence,
1516                          false,
1517                          fence_fd);
1518
1519   image->busy = false;
1520   xshmfence_trigger(image->shm_fence);
1521
1522   return VK_SUCCESS;
1523
1524fail_shmfence_alloc:
1525   close(fence_fd);
1526
1527fail_pixmap:
1528   cookie = xcb_free_pixmap(chain->conn, image->pixmap);
1529   xcb_discard_reply(chain->conn, cookie.sequence);
1530
1531   wsi_destroy_image(&chain->base, &image->base);
1532
1533   return result;
1534}
1535
1536static void
1537x11_image_finish(struct x11_swapchain *chain,
1538                 const VkAllocationCallbacks* pAllocator,
1539                 struct x11_image *image)
1540{
1541   xcb_void_cookie_t cookie;
1542
1543   if (!chain->base.wsi->sw || chain->has_mit_shm) {
1544      cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence);
1545      xcb_discard_reply(chain->conn, cookie.sequence);
1546      xshmfence_unmap_shm(image->shm_fence);
1547
1548      cookie = xcb_free_pixmap(chain->conn, image->pixmap);
1549      xcb_discard_reply(chain->conn, cookie.sequence);
1550   }
1551
1552   wsi_destroy_image(&chain->base, &image->base);
1553#ifdef HAVE_SYS_SHM_H
1554   if (image->shmaddr)
1555      shmdt(image->shmaddr);
1556#endif
1557}
1558
1559static void
1560wsi_x11_get_dri3_modifiers(struct wsi_x11_connection *wsi_conn,
1561                           xcb_connection_t *conn, xcb_window_t window,
1562                           uint8_t depth, uint8_t bpp,
1563                           VkCompositeAlphaFlagsKHR vk_alpha,
1564                           uint64_t **modifiers_in, uint32_t *num_modifiers_in,
1565                           uint32_t *num_tranches_in,
1566                           const VkAllocationCallbacks *pAllocator)
1567{
1568   if (!wsi_conn->has_dri3_modifiers)
1569      goto out;
1570
1571#ifdef HAVE_DRI3_MODIFIERS
1572   xcb_generic_error_t *error = NULL;
1573   xcb_dri3_get_supported_modifiers_cookie_t mod_cookie =
1574      xcb_dri3_get_supported_modifiers(conn, window, depth, bpp);
1575   xcb_dri3_get_supported_modifiers_reply_t *mod_reply =
1576      xcb_dri3_get_supported_modifiers_reply(conn, mod_cookie, &error);
1577   free(error);
1578
1579   if (!mod_reply || (mod_reply->num_window_modifiers == 0 &&
1580                      mod_reply->num_screen_modifiers == 0)) {
1581      free(mod_reply);
1582      goto out;
1583   }
1584
1585   uint32_t n = 0;
1586   uint32_t counts[2];
1587   uint64_t *modifiers[2];
1588
1589   if (mod_reply->num_window_modifiers) {
1590      counts[n] = mod_reply->num_window_modifiers;
1591      modifiers[n] = vk_alloc(pAllocator,
1592                              counts[n] * sizeof(uint64_t),
1593                              8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1594      if (!modifiers[n]) {
1595         free(mod_reply);
1596         goto out;
1597      }
1598
1599      memcpy(modifiers[n],
1600             xcb_dri3_get_supported_modifiers_window_modifiers(mod_reply),
1601             counts[n] * sizeof(uint64_t));
1602      n++;
1603   }
1604
1605   if (mod_reply->num_screen_modifiers) {
1606      counts[n] = mod_reply->num_screen_modifiers;
1607      modifiers[n] = vk_alloc(pAllocator,
1608                              counts[n] * sizeof(uint64_t),
1609                              8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1610      if (!modifiers[n]) {
1611	 if (n > 0)
1612            vk_free(pAllocator, modifiers[0]);
1613         free(mod_reply);
1614         goto out;
1615      }
1616
1617      memcpy(modifiers[n],
1618             xcb_dri3_get_supported_modifiers_screen_modifiers(mod_reply),
1619             counts[n] * sizeof(uint64_t));
1620      n++;
1621   }
1622
1623   for (int i = 0; i < n; i++) {
1624      modifiers_in[i] = modifiers[i];
1625      num_modifiers_in[i] = counts[i];
1626   }
1627   *num_tranches_in = n;
1628
1629   free(mod_reply);
1630   return;
1631#endif
1632out:
1633   *num_tranches_in = 0;
1634}
1635
1636static VkResult
1637x11_swapchain_destroy(struct wsi_swapchain *anv_chain,
1638                      const VkAllocationCallbacks *pAllocator)
1639{
1640   struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
1641   xcb_void_cookie_t cookie;
1642
1643   if (chain->has_present_queue) {
1644      chain->status = VK_ERROR_OUT_OF_DATE_KHR;
1645      /* Push a UINT32_MAX to wake up the manager */
1646      wsi_queue_push(&chain->present_queue, UINT32_MAX);
1647      pthread_join(chain->queue_manager, NULL);
1648
1649      if (chain->has_acquire_queue)
1650         wsi_queue_destroy(&chain->acquire_queue);
1651      wsi_queue_destroy(&chain->present_queue);
1652   }
1653
1654   for (uint32_t i = 0; i < chain->base.image_count; i++)
1655      x11_image_finish(chain, pAllocator, &chain->images[i]);
1656
1657   xcb_unregister_for_special_event(chain->conn, chain->special_event);
1658   cookie = xcb_present_select_input_checked(chain->conn, chain->event_id,
1659                                             chain->window,
1660                                             XCB_PRESENT_EVENT_MASK_NO_EVENT);
1661   xcb_discard_reply(chain->conn, cookie.sequence);
1662
1663   wsi_swapchain_finish(&chain->base);
1664
1665   vk_free(pAllocator, chain);
1666
1667   return VK_SUCCESS;
1668}
1669
1670static void
1671wsi_x11_set_adaptive_sync_property(xcb_connection_t *conn,
1672                                   xcb_drawable_t drawable,
1673                                   uint32_t state)
1674{
1675   static char const name[] = "_VARIABLE_REFRESH";
1676   xcb_intern_atom_cookie_t cookie;
1677   xcb_intern_atom_reply_t* reply;
1678   xcb_void_cookie_t check;
1679
1680   cookie = xcb_intern_atom(conn, 0, strlen(name), name);
1681   reply = xcb_intern_atom_reply(conn, cookie, NULL);
1682   if (reply == NULL)
1683      return;
1684
1685   if (state)
1686      check = xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE,
1687                                          drawable, reply->atom,
1688                                          XCB_ATOM_CARDINAL, 32, 1, &state);
1689   else
1690      check = xcb_delete_property_checked(conn, drawable, reply->atom);
1691
1692   xcb_discard_reply(conn, check.sequence);
1693   free(reply);
1694}
1695
1696
1697static VkResult
1698x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
1699                             VkDevice device,
1700                             struct wsi_device *wsi_device,
1701                             const VkSwapchainCreateInfoKHR *pCreateInfo,
1702                             const VkAllocationCallbacks* pAllocator,
1703                             struct wsi_swapchain **swapchain_out)
1704{
1705   struct x11_swapchain *chain;
1706   xcb_void_cookie_t cookie;
1707   VkResult result;
1708   VkPresentModeKHR present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo);
1709
1710   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
1711
1712   xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
1713   struct wsi_x11_connection *wsi_conn =
1714      wsi_x11_get_connection(wsi_device, conn);
1715   if (!wsi_conn)
1716      return VK_ERROR_OUT_OF_HOST_MEMORY;
1717
1718   unsigned num_images = pCreateInfo->minImageCount;
1719   if (wsi_device->x11.strict_imageCount)
1720      num_images = pCreateInfo->minImageCount;
1721   else if (x11_needs_wait_for_fences(wsi_device, wsi_conn, present_mode))
1722      num_images = MAX2(num_images, 5);
1723   else if (wsi_device->x11.ensure_minImageCount)
1724      num_images = MAX2(num_images, x11_get_min_image_count(wsi_device));
1725
1726   /* Check for whether or not we have a window up-front */
1727   xcb_window_t window = x11_surface_get_window(icd_surface);
1728   xcb_get_geometry_reply_t *geometry =
1729      xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), NULL);
1730   if (geometry == NULL)
1731      return VK_ERROR_SURFACE_LOST_KHR;
1732   const uint32_t bit_depth = geometry->depth;
1733   const uint16_t cur_width = geometry->width;
1734   const uint16_t cur_height = geometry->height;
1735   free(geometry);
1736
1737   size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
1738   chain = vk_zalloc(pAllocator, size, 8,
1739                      VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1740   if (chain == NULL)
1741      return VK_ERROR_OUT_OF_HOST_MEMORY;
1742
1743   result = wsi_swapchain_init(wsi_device, &chain->base, device,
1744                               pCreateInfo, pAllocator);
1745   if (result != VK_SUCCESS)
1746      goto fail_alloc;
1747
1748   chain->base.destroy = x11_swapchain_destroy;
1749   chain->base.get_wsi_image = x11_get_wsi_image;
1750   chain->base.acquire_next_image = x11_acquire_next_image;
1751   chain->base.queue_present = x11_queue_present;
1752   chain->base.present_mode = present_mode;
1753   chain->base.image_count = num_images;
1754   chain->conn = conn;
1755   chain->window = window;
1756   chain->depth = bit_depth;
1757   chain->extent = pCreateInfo->imageExtent;
1758   chain->send_sbc = 0;
1759   chain->sent_image_count = 0;
1760   chain->last_present_msc = 0;
1761   chain->has_acquire_queue = false;
1762   chain->has_present_queue = false;
1763   chain->status = VK_SUCCESS;
1764   chain->has_dri3_modifiers = wsi_conn->has_dri3_modifiers;
1765   chain->has_mit_shm = wsi_conn->has_mit_shm;
1766
1767   if (chain->extent.width != cur_width || chain->extent.height != cur_height)
1768       chain->status = VK_SUBOPTIMAL_KHR;
1769
1770   /* We used to inherit copy_is_suboptimal from pCreateInfo->oldSwapchain.
1771    * When it was true, and when the next present was completed with copying,
1772    * we would return VK_SUBOPTIMAL_KHR and hint the app to reallocate again
1773    * for no good reason.  If all following presents on the surface were
1774    * completed with copying because of some surface state change, we would
1775    * always return VK_SUBOPTIMAL_KHR no matter how many times the app had
1776    * reallocated.
1777    */
1778   chain->copy_is_suboptimal = false;
1779
1780   if (!wsi_device->sw)
1781      if (!wsi_x11_check_dri3_compatible(wsi_device, conn))
1782         chain->base.use_prime_blit = true;
1783
1784   chain->event_id = xcb_generate_id(chain->conn);
1785   xcb_present_select_input(chain->conn, chain->event_id, chain->window,
1786                            XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
1787                            XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
1788                            XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
1789
1790   /* Create an XCB event queue to hold present events outside of the usual
1791    * application event queue
1792    */
1793   chain->special_event =
1794      xcb_register_for_special_xge(chain->conn, &xcb_present_id,
1795                                   chain->event_id, NULL);
1796
1797   chain->gc = xcb_generate_id(chain->conn);
1798   if (!chain->gc) {
1799      /* FINISHME: Choose a better error. */
1800      result = VK_ERROR_OUT_OF_HOST_MEMORY;
1801      goto fail_register;
1802   }
1803
1804   cookie = xcb_create_gc(chain->conn,
1805                          chain->gc,
1806                          chain->window,
1807                          XCB_GC_GRAPHICS_EXPOSURES,
1808                          (uint32_t []) { 0 });
1809   xcb_discard_reply(chain->conn, cookie.sequence);
1810
1811   uint64_t *modifiers[2] = {NULL, NULL};
1812   uint32_t num_modifiers[2] = {0, 0};
1813   uint32_t num_tranches = 0;
1814   if (wsi_device->supports_modifiers)
1815      wsi_x11_get_dri3_modifiers(wsi_conn, conn, window, chain->depth, 32,
1816                                 pCreateInfo->compositeAlpha,
1817                                 modifiers, num_modifiers, &num_tranches,
1818                                 pAllocator);
1819
1820   uint32_t image = 0;
1821   for (; image < chain->base.image_count; image++) {
1822      result = x11_image_init(device, chain, pCreateInfo, pAllocator,
1823                              (const uint64_t *const *)modifiers,
1824                              num_modifiers, num_tranches,
1825                              &chain->images[image]);
1826      if (result != VK_SUCCESS)
1827         goto fail_init_images;
1828   }
1829
1830   if ((chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR ||
1831        chain->base.present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR ||
1832        x11_needs_wait_for_fences(wsi_device, wsi_conn,
1833                                  chain->base.present_mode)) &&
1834       !chain->base.wsi->sw) {
1835      chain->has_present_queue = true;
1836
1837      /* Initialize our queues.  We make them base.image_count + 1 because we will
1838       * occasionally use UINT32_MAX to signal the other thread that an error
1839       * has occurred and we don't want an overflow.
1840       */
1841      int ret;
1842      ret = wsi_queue_init(&chain->present_queue, chain->base.image_count + 1);
1843      if (ret) {
1844         goto fail_init_images;
1845      }
1846
1847      if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR ||
1848          chain->base.present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR) {
1849         chain->has_acquire_queue = true;
1850
1851         ret = wsi_queue_init(&chain->acquire_queue, chain->base.image_count + 1);
1852         if (ret) {
1853            wsi_queue_destroy(&chain->present_queue);
1854            goto fail_init_images;
1855         }
1856
1857         for (unsigned i = 0; i < chain->base.image_count; i++)
1858            wsi_queue_push(&chain->acquire_queue, i);
1859      }
1860
1861      ret = pthread_create(&chain->queue_manager, NULL,
1862                           x11_manage_fifo_queues, chain);
1863      if (ret) {
1864         wsi_queue_destroy(&chain->present_queue);
1865         if (chain->has_acquire_queue)
1866            wsi_queue_destroy(&chain->acquire_queue);
1867
1868         goto fail_init_images;
1869      }
1870   }
1871
1872   assert(chain->has_present_queue || !chain->has_acquire_queue);
1873
1874   for (int i = 0; i < ARRAY_SIZE(modifiers); i++)
1875      vk_free(pAllocator, modifiers[i]);
1876
1877   /* It is safe to set it here as only one swapchain can be associated with
1878    * the window, and swapchain creation does the association. At this point
1879    * we know the creation is going to succeed. */
1880   wsi_x11_set_adaptive_sync_property(conn, window,
1881                                      wsi_device->enable_adaptive_sync);
1882
1883   *swapchain_out = &chain->base;
1884
1885   return VK_SUCCESS;
1886
1887fail_init_images:
1888   for (uint32_t j = 0; j < image; j++)
1889      x11_image_finish(chain, pAllocator, &chain->images[j]);
1890
1891   for (int i = 0; i < ARRAY_SIZE(modifiers); i++)
1892      vk_free(pAllocator, modifiers[i]);
1893
1894fail_register:
1895   xcb_unregister_for_special_event(chain->conn, chain->special_event);
1896
1897   wsi_swapchain_finish(&chain->base);
1898
1899fail_alloc:
1900   vk_free(pAllocator, chain);
1901
1902   return result;
1903}
1904
1905VkResult
1906wsi_x11_init_wsi(struct wsi_device *wsi_device,
1907                 const VkAllocationCallbacks *alloc,
1908                 const struct driOptionCache *dri_options)
1909{
1910   struct wsi_x11 *wsi;
1911   VkResult result;
1912
1913   wsi = vk_alloc(alloc, sizeof(*wsi), 8,
1914                   VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1915   if (!wsi) {
1916      result = VK_ERROR_OUT_OF_HOST_MEMORY;
1917      goto fail;
1918   }
1919
1920   int ret = pthread_mutex_init(&wsi->mutex, NULL);
1921   if (ret != 0) {
1922      if (ret == ENOMEM) {
1923         result = VK_ERROR_OUT_OF_HOST_MEMORY;
1924      } else {
1925         /* FINISHME: Choose a better error. */
1926         result = VK_ERROR_OUT_OF_HOST_MEMORY;
1927      }
1928
1929      goto fail_alloc;
1930   }
1931
1932   wsi->connections = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
1933                                              _mesa_key_pointer_equal);
1934   if (!wsi->connections) {
1935      result = VK_ERROR_OUT_OF_HOST_MEMORY;
1936      goto fail_mutex;
1937   }
1938
1939   if (dri_options) {
1940      if (driCheckOption(dri_options, "vk_x11_override_min_image_count", DRI_INT)) {
1941         wsi_device->x11.override_minImageCount =
1942            driQueryOptioni(dri_options, "vk_x11_override_min_image_count");
1943      }
1944      if (driCheckOption(dri_options, "vk_x11_strict_image_count", DRI_BOOL)) {
1945         wsi_device->x11.strict_imageCount =
1946            driQueryOptionb(dri_options, "vk_x11_strict_image_count");
1947      }
1948      if (driCheckOption(dri_options, "vk_x11_ensure_min_image_count", DRI_BOOL)) {
1949         wsi_device->x11.ensure_minImageCount =
1950            driQueryOptionb(dri_options, "vk_x11_ensure_min_image_count");
1951      }
1952      wsi_device->x11.xwaylandWaitReady = true;
1953      if (driCheckOption(dri_options, "vk_xwayland_wait_ready", DRI_BOOL)) {
1954         wsi_device->x11.xwaylandWaitReady =
1955            driQueryOptionb(dri_options, "vk_xwayland_wait_ready");
1956      }
1957   }
1958
1959   wsi->base.get_support = x11_surface_get_support;
1960   wsi->base.get_capabilities2 = x11_surface_get_capabilities2;
1961   wsi->base.get_formats = x11_surface_get_formats;
1962   wsi->base.get_formats2 = x11_surface_get_formats2;
1963   wsi->base.get_present_modes = x11_surface_get_present_modes;
1964   wsi->base.get_present_rectangles = x11_surface_get_present_rectangles;
1965   wsi->base.create_swapchain = x11_surface_create_swapchain;
1966
1967   wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = &wsi->base;
1968   wsi_device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = &wsi->base;
1969
1970   return VK_SUCCESS;
1971
1972fail_mutex:
1973   pthread_mutex_destroy(&wsi->mutex);
1974fail_alloc:
1975   vk_free(alloc, wsi);
1976fail:
1977   wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = NULL;
1978   wsi_device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = NULL;
1979
1980   return result;
1981}
1982
1983void
1984wsi_x11_finish_wsi(struct wsi_device *wsi_device,
1985                   const VkAllocationCallbacks *alloc)
1986{
1987   struct wsi_x11 *wsi =
1988      (struct wsi_x11 *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB];
1989
1990   if (wsi) {
1991      hash_table_foreach(wsi->connections, entry)
1992         wsi_x11_connection_destroy(wsi_device, entry->data);
1993
1994      _mesa_hash_table_destroy(wsi->connections, NULL);
1995
1996      pthread_mutex_destroy(&wsi->mutex);
1997
1998      vk_free(alloc, wsi);
1999   }
2000}
2001