dri3: allow building against older xcb (v3)
[mesa.git] / src / vulkan / wsi / wsi_common_x11.c
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
30 #include "util/macros.h"
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <fcntl.h>
37 #include <poll.h>
38 #include <xf86drm.h>
39 #include <drm_fourcc.h>
40 #include "util/hash_table.h"
41
42 #include "vk_util.h"
43 #include "wsi_common_private.h"
44 #include "wsi_common_x11.h"
45 #include "wsi_common_queue.h"
46
47 #define typed_memcpy(dest, src, count) ({ \
48 STATIC_ASSERT(sizeof(*src) == sizeof(*dest)); \
49 memcpy((dest), (src), (count) * sizeof(*(src))); \
50 })
51
52 struct wsi_x11_connection {
53 bool has_dri3;
54 bool has_dri3_modifiers;
55 bool has_present;
56 bool is_proprietary_x11;
57 };
58
59 struct wsi_x11 {
60 struct wsi_interface base;
61
62 pthread_mutex_t mutex;
63 /* Hash table of xcb_connection -> wsi_x11_connection mappings */
64 struct hash_table *connections;
65 };
66
67
68 /** wsi_dri3_open
69 *
70 * Wrapper around xcb_dri3_open
71 */
72 static int
73 wsi_dri3_open(xcb_connection_t *conn,
74 xcb_window_t root,
75 uint32_t provider)
76 {
77 xcb_dri3_open_cookie_t cookie;
78 xcb_dri3_open_reply_t *reply;
79 int fd;
80
81 cookie = xcb_dri3_open(conn,
82 root,
83 provider);
84
85 reply = xcb_dri3_open_reply(conn, cookie, NULL);
86 if (!reply)
87 return -1;
88
89 if (reply->nfd != 1) {
90 free(reply);
91 return -1;
92 }
93
94 fd = xcb_dri3_open_reply_fds(conn, reply)[0];
95 free(reply);
96 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
97
98 return fd;
99 }
100
101 static bool
102 wsi_x11_check_dri3_compatible(xcb_connection_t *conn, int local_fd)
103 {
104 xcb_screen_iterator_t screen_iter =
105 xcb_setup_roots_iterator(xcb_get_setup(conn));
106 xcb_screen_t *screen = screen_iter.data;
107
108 int dri3_fd = wsi_dri3_open(conn, screen->root, None);
109 if (dri3_fd != -1) {
110 char *local_dev = drmGetRenderDeviceNameFromFd(local_fd);
111 char *dri3_dev = drmGetRenderDeviceNameFromFd(dri3_fd);
112 int ret;
113
114 close(dri3_fd);
115
116 ret = strcmp(local_dev, dri3_dev);
117
118 free(local_dev);
119 free(dri3_dev);
120
121 if (ret != 0)
122 return false;
123 }
124 return true;
125 }
126
127 static struct wsi_x11_connection *
128 wsi_x11_connection_create(const VkAllocationCallbacks *alloc,
129 xcb_connection_t *conn)
130 {
131 xcb_query_extension_cookie_t dri3_cookie, pres_cookie, amd_cookie, nv_cookie;
132 xcb_query_extension_reply_t *dri3_reply, *pres_reply, *amd_reply, *nv_reply;
133 bool has_dri3_v1_2 = false;
134 bool has_present_v1_2 = false;
135
136 struct wsi_x11_connection *wsi_conn =
137 vk_alloc(alloc, sizeof(*wsi_conn), 8,
138 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
139 if (!wsi_conn)
140 return NULL;
141
142 dri3_cookie = xcb_query_extension(conn, 4, "DRI3");
143 pres_cookie = xcb_query_extension(conn, 7, "Present");
144
145 /* We try to be nice to users and emit a warning if they try to use a
146 * Vulkan application on a system without DRI3 enabled. However, this ends
147 * up spewing the warning when a user has, for example, both Intel
148 * integrated graphics and a discrete card with proprietary drivers and are
149 * running on the discrete card with the proprietary DDX. In this case, we
150 * really don't want to print the warning because it just confuses users.
151 * As a heuristic to detect this case, we check for a couple of proprietary
152 * X11 extensions.
153 */
154 amd_cookie = xcb_query_extension(conn, 11, "ATIFGLRXDRI");
155 nv_cookie = xcb_query_extension(conn, 10, "NV-CONTROL");
156
157 dri3_reply = xcb_query_extension_reply(conn, dri3_cookie, NULL);
158 pres_reply = xcb_query_extension_reply(conn, pres_cookie, NULL);
159 amd_reply = xcb_query_extension_reply(conn, amd_cookie, NULL);
160 nv_reply = xcb_query_extension_reply(conn, nv_cookie, NULL);
161 if (!dri3_reply || !pres_reply) {
162 free(dri3_reply);
163 free(pres_reply);
164 free(amd_reply);
165 free(nv_reply);
166 vk_free(alloc, wsi_conn);
167 return NULL;
168 }
169
170 wsi_conn->has_dri3 = dri3_reply->present != 0;
171 if (wsi_conn->has_dri3) {
172 xcb_dri3_query_version_cookie_t ver_cookie;
173 xcb_dri3_query_version_reply_t *ver_reply;
174
175 ver_cookie = xcb_dri3_query_version(conn, 1, 2);
176 ver_reply = xcb_dri3_query_version_reply(conn, ver_cookie, NULL);
177 has_dri3_v1_2 =
178 (ver_reply->major_version > 1 || ver_reply->minor_version >= 2);
179 free(ver_reply);
180 }
181
182 wsi_conn->has_present = pres_reply->present != 0;
183 if (wsi_conn->has_present) {
184 xcb_present_query_version_cookie_t ver_cookie;
185 xcb_present_query_version_reply_t *ver_reply;
186
187 ver_cookie = xcb_present_query_version(conn, 1, 2);
188 ver_reply = xcb_present_query_version_reply(conn, ver_cookie, NULL);
189 has_present_v1_2 =
190 (ver_reply->major_version > 1 || ver_reply->minor_version >= 2);
191 free(ver_reply);
192 }
193
194 wsi_conn->has_dri3_modifiers = has_dri3_v1_2 && has_present_v1_2;
195 wsi_conn->is_proprietary_x11 = false;
196 if (amd_reply && amd_reply->present)
197 wsi_conn->is_proprietary_x11 = true;
198 if (nv_reply && nv_reply->present)
199 wsi_conn->is_proprietary_x11 = true;
200
201 free(dri3_reply);
202 free(pres_reply);
203 free(amd_reply);
204 free(nv_reply);
205
206 return wsi_conn;
207 }
208
209 static void
210 wsi_x11_connection_destroy(const VkAllocationCallbacks *alloc,
211 struct wsi_x11_connection *conn)
212 {
213 vk_free(alloc, conn);
214 }
215
216 static bool
217 wsi_x11_check_for_dri3(struct wsi_x11_connection *wsi_conn)
218 {
219 if (wsi_conn->has_dri3)
220 return true;
221 if (!wsi_conn->is_proprietary_x11) {
222 fprintf(stderr, "vulkan: No DRI3 support detected - required for presentation\n"
223 "Note: you can probably enable DRI3 in your Xorg config\n");
224 }
225 return false;
226 }
227
228 static struct wsi_x11_connection *
229 wsi_x11_get_connection(struct wsi_device *wsi_dev,
230 const VkAllocationCallbacks *alloc,
231 xcb_connection_t *conn)
232 {
233 struct wsi_x11 *wsi =
234 (struct wsi_x11 *)wsi_dev->wsi[VK_ICD_WSI_PLATFORM_XCB];
235
236 pthread_mutex_lock(&wsi->mutex);
237
238 struct hash_entry *entry = _mesa_hash_table_search(wsi->connections, conn);
239 if (!entry) {
240 /* We're about to make a bunch of blocking calls. Let's drop the
241 * mutex for now so we don't block up too badly.
242 */
243 pthread_mutex_unlock(&wsi->mutex);
244
245 struct wsi_x11_connection *wsi_conn =
246 wsi_x11_connection_create(alloc, conn);
247 if (!wsi_conn)
248 return NULL;
249
250 pthread_mutex_lock(&wsi->mutex);
251
252 entry = _mesa_hash_table_search(wsi->connections, conn);
253 if (entry) {
254 /* Oops, someone raced us to it */
255 wsi_x11_connection_destroy(alloc, wsi_conn);
256 } else {
257 entry = _mesa_hash_table_insert(wsi->connections, conn, wsi_conn);
258 }
259 }
260
261 pthread_mutex_unlock(&wsi->mutex);
262
263 return entry->data;
264 }
265
266 static const VkFormat formats[] = {
267 VK_FORMAT_B8G8R8A8_SRGB,
268 VK_FORMAT_B8G8R8A8_UNORM,
269 };
270
271 static const VkPresentModeKHR present_modes[] = {
272 VK_PRESENT_MODE_IMMEDIATE_KHR,
273 VK_PRESENT_MODE_MAILBOX_KHR,
274 VK_PRESENT_MODE_FIFO_KHR,
275 };
276
277 static xcb_screen_t *
278 get_screen_for_root(xcb_connection_t *conn, xcb_window_t root)
279 {
280 xcb_screen_iterator_t screen_iter =
281 xcb_setup_roots_iterator(xcb_get_setup(conn));
282
283 for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
284 if (screen_iter.data->root == root)
285 return screen_iter.data;
286 }
287
288 return NULL;
289 }
290
291 static xcb_visualtype_t *
292 screen_get_visualtype(xcb_screen_t *screen, xcb_visualid_t visual_id,
293 unsigned *depth)
294 {
295 xcb_depth_iterator_t depth_iter =
296 xcb_screen_allowed_depths_iterator(screen);
297
298 for (; depth_iter.rem; xcb_depth_next (&depth_iter)) {
299 xcb_visualtype_iterator_t visual_iter =
300 xcb_depth_visuals_iterator (depth_iter.data);
301
302 for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
303 if (visual_iter.data->visual_id == visual_id) {
304 if (depth)
305 *depth = depth_iter.data->depth;
306 return visual_iter.data;
307 }
308 }
309 }
310
311 return NULL;
312 }
313
314 static xcb_visualtype_t *
315 connection_get_visualtype(xcb_connection_t *conn, xcb_visualid_t visual_id,
316 unsigned *depth)
317 {
318 xcb_screen_iterator_t screen_iter =
319 xcb_setup_roots_iterator(xcb_get_setup(conn));
320
321 /* For this we have to iterate over all of the screens which is rather
322 * annoying. Fortunately, there is probably only 1.
323 */
324 for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
325 xcb_visualtype_t *visual = screen_get_visualtype(screen_iter.data,
326 visual_id, depth);
327 if (visual)
328 return visual;
329 }
330
331 return NULL;
332 }
333
334 static xcb_visualtype_t *
335 get_visualtype_for_window(xcb_connection_t *conn, xcb_window_t window,
336 unsigned *depth)
337 {
338 xcb_query_tree_cookie_t tree_cookie;
339 xcb_get_window_attributes_cookie_t attrib_cookie;
340 xcb_query_tree_reply_t *tree;
341 xcb_get_window_attributes_reply_t *attrib;
342
343 tree_cookie = xcb_query_tree(conn, window);
344 attrib_cookie = xcb_get_window_attributes(conn, window);
345
346 tree = xcb_query_tree_reply(conn, tree_cookie, NULL);
347 attrib = xcb_get_window_attributes_reply(conn, attrib_cookie, NULL);
348 if (attrib == NULL || tree == NULL) {
349 free(attrib);
350 free(tree);
351 return NULL;
352 }
353
354 xcb_window_t root = tree->root;
355 xcb_visualid_t visual_id = attrib->visual;
356 free(attrib);
357 free(tree);
358
359 xcb_screen_t *screen = get_screen_for_root(conn, root);
360 if (screen == NULL)
361 return NULL;
362
363 return screen_get_visualtype(screen, visual_id, depth);
364 }
365
366 static bool
367 visual_has_alpha(xcb_visualtype_t *visual, unsigned depth)
368 {
369 uint32_t rgb_mask = visual->red_mask |
370 visual->green_mask |
371 visual->blue_mask;
372
373 uint32_t all_mask = 0xffffffff >> (32 - depth);
374
375 /* Do we have bits left over after RGB? */
376 return (all_mask & ~rgb_mask) != 0;
377 }
378
379 VkBool32 wsi_get_physical_device_xcb_presentation_support(
380 struct wsi_device *wsi_device,
381 VkAllocationCallbacks *alloc,
382 uint32_t queueFamilyIndex,
383 int fd,
384 bool can_handle_different_gpu,
385 xcb_connection_t* connection,
386 xcb_visualid_t visual_id)
387 {
388 struct wsi_x11_connection *wsi_conn =
389 wsi_x11_get_connection(wsi_device, alloc, connection);
390
391 if (!wsi_conn)
392 return false;
393
394 if (!wsi_x11_check_for_dri3(wsi_conn))
395 return false;
396
397 if (!can_handle_different_gpu)
398 if (!wsi_x11_check_dri3_compatible(connection, fd))
399 return false;
400
401 unsigned visual_depth;
402 if (!connection_get_visualtype(connection, visual_id, &visual_depth))
403 return false;
404
405 if (visual_depth != 24 && visual_depth != 32)
406 return false;
407
408 return true;
409 }
410
411 static xcb_connection_t*
412 x11_surface_get_connection(VkIcdSurfaceBase *icd_surface)
413 {
414 if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
415 return XGetXCBConnection(((VkIcdSurfaceXlib *)icd_surface)->dpy);
416 else
417 return ((VkIcdSurfaceXcb *)icd_surface)->connection;
418 }
419
420 static xcb_window_t
421 x11_surface_get_window(VkIcdSurfaceBase *icd_surface)
422 {
423 if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
424 return ((VkIcdSurfaceXlib *)icd_surface)->window;
425 else
426 return ((VkIcdSurfaceXcb *)icd_surface)->window;
427 }
428
429 static VkResult
430 x11_surface_get_support(VkIcdSurfaceBase *icd_surface,
431 struct wsi_device *wsi_device,
432 const VkAllocationCallbacks *alloc,
433 uint32_t queueFamilyIndex,
434 int local_fd,
435 VkBool32* pSupported)
436 {
437 xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
438 xcb_window_t window = x11_surface_get_window(icd_surface);
439
440 struct wsi_x11_connection *wsi_conn =
441 wsi_x11_get_connection(wsi_device, alloc, conn);
442 if (!wsi_conn)
443 return VK_ERROR_OUT_OF_HOST_MEMORY;
444
445 if (!wsi_x11_check_for_dri3(wsi_conn)) {
446 *pSupported = false;
447 return VK_SUCCESS;
448 }
449
450 unsigned visual_depth;
451 if (!get_visualtype_for_window(conn, window, &visual_depth)) {
452 *pSupported = false;
453 return VK_SUCCESS;
454 }
455
456 if (visual_depth != 24 && visual_depth != 32) {
457 *pSupported = false;
458 return VK_SUCCESS;
459 }
460
461 *pSupported = true;
462 return VK_SUCCESS;
463 }
464
465 static VkResult
466 x11_surface_get_capabilities(VkIcdSurfaceBase *icd_surface,
467 VkSurfaceCapabilitiesKHR *caps)
468 {
469 xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
470 xcb_window_t window = x11_surface_get_window(icd_surface);
471 xcb_get_geometry_cookie_t geom_cookie;
472 xcb_generic_error_t *err;
473 xcb_get_geometry_reply_t *geom;
474 unsigned visual_depth;
475
476 geom_cookie = xcb_get_geometry(conn, window);
477
478 /* This does a round-trip. This is why we do get_geometry first and
479 * wait to read the reply until after we have a visual.
480 */
481 xcb_visualtype_t *visual =
482 get_visualtype_for_window(conn, window, &visual_depth);
483
484 if (!visual)
485 return VK_ERROR_SURFACE_LOST_KHR;
486
487 geom = xcb_get_geometry_reply(conn, geom_cookie, &err);
488 if (geom) {
489 VkExtent2D extent = { geom->width, geom->height };
490 caps->currentExtent = extent;
491 caps->minImageExtent = extent;
492 caps->maxImageExtent = extent;
493 } else {
494 /* This can happen if the client didn't wait for the configure event
495 * to come back from the compositor. In that case, we don't know the
496 * size of the window so we just return valid "I don't know" stuff.
497 */
498 caps->currentExtent = (VkExtent2D) { -1, -1 };
499 caps->minImageExtent = (VkExtent2D) { 1, 1 };
500 /* This is the maximum supported size on Intel */
501 caps->maxImageExtent = (VkExtent2D) { 1 << 14, 1 << 14 };
502 }
503 free(err);
504 free(geom);
505
506 if (visual_has_alpha(visual, visual_depth)) {
507 caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
508 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
509 } else {
510 caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
511 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
512 }
513
514 /* For true mailbox mode, we need at least 4 images:
515 * 1) One to scan out from
516 * 2) One to have queued for scan-out
517 * 3) One to be currently held by the X server
518 * 4) One to render to
519 */
520 caps->minImageCount = 2;
521 /* There is no real maximum */
522 caps->maxImageCount = 0;
523
524 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
525 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
526 caps->maxImageArrayLayers = 1;
527 caps->supportedUsageFlags =
528 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
529 VK_IMAGE_USAGE_SAMPLED_BIT |
530 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
531 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
532
533 return VK_SUCCESS;
534 }
535
536 static VkResult
537 x11_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
538 const void *info_next,
539 VkSurfaceCapabilities2KHR *caps)
540 {
541 assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
542
543 return x11_surface_get_capabilities(icd_surface, &caps->surfaceCapabilities);
544 }
545
546 static VkResult
547 x11_surface_get_formats(VkIcdSurfaceBase *surface,
548 struct wsi_device *wsi_device,
549 uint32_t *pSurfaceFormatCount,
550 VkSurfaceFormatKHR *pSurfaceFormats)
551 {
552 VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount);
553
554 for (unsigned i = 0; i < ARRAY_SIZE(formats); i++) {
555 vk_outarray_append(&out, f) {
556 f->format = formats[i];
557 f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
558 }
559 }
560
561 return vk_outarray_status(&out);
562 }
563
564 static VkResult
565 x11_surface_get_formats2(VkIcdSurfaceBase *surface,
566 struct wsi_device *wsi_device,
567 const void *info_next,
568 uint32_t *pSurfaceFormatCount,
569 VkSurfaceFormat2KHR *pSurfaceFormats)
570 {
571 VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount);
572
573 for (unsigned i = 0; i < ARRAY_SIZE(formats); i++) {
574 vk_outarray_append(&out, f) {
575 assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
576 f->surfaceFormat.format = formats[i];
577 f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
578 }
579 }
580
581 return vk_outarray_status(&out);
582 }
583
584 static VkResult
585 x11_surface_get_present_modes(VkIcdSurfaceBase *surface,
586 uint32_t *pPresentModeCount,
587 VkPresentModeKHR *pPresentModes)
588 {
589 if (pPresentModes == NULL) {
590 *pPresentModeCount = ARRAY_SIZE(present_modes);
591 return VK_SUCCESS;
592 }
593
594 *pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes));
595 typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
596
597 return *pPresentModeCount < ARRAY_SIZE(present_modes) ?
598 VK_INCOMPLETE : VK_SUCCESS;
599 }
600
601 VkResult wsi_create_xcb_surface(const VkAllocationCallbacks *pAllocator,
602 const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
603 VkSurfaceKHR *pSurface)
604 {
605 VkIcdSurfaceXcb *surface;
606
607 surface = vk_alloc(pAllocator, sizeof *surface, 8,
608 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
609 if (surface == NULL)
610 return VK_ERROR_OUT_OF_HOST_MEMORY;
611
612 surface->base.platform = VK_ICD_WSI_PLATFORM_XCB;
613 surface->connection = pCreateInfo->connection;
614 surface->window = pCreateInfo->window;
615
616 *pSurface = VkIcdSurfaceBase_to_handle(&surface->base);
617 return VK_SUCCESS;
618 }
619
620 VkResult wsi_create_xlib_surface(const VkAllocationCallbacks *pAllocator,
621 const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
622 VkSurfaceKHR *pSurface)
623 {
624 VkIcdSurfaceXlib *surface;
625
626 surface = vk_alloc(pAllocator, sizeof *surface, 8,
627 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
628 if (surface == NULL)
629 return VK_ERROR_OUT_OF_HOST_MEMORY;
630
631 surface->base.platform = VK_ICD_WSI_PLATFORM_XLIB;
632 surface->dpy = pCreateInfo->dpy;
633 surface->window = pCreateInfo->window;
634
635 *pSurface = VkIcdSurfaceBase_to_handle(&surface->base);
636 return VK_SUCCESS;
637 }
638
639 struct x11_image {
640 struct wsi_image base;
641 xcb_pixmap_t pixmap;
642 bool busy;
643 struct xshmfence * shm_fence;
644 uint32_t sync_fence;
645 };
646
647 struct x11_swapchain {
648 struct wsi_swapchain base;
649
650 bool has_dri3_modifiers;
651
652 xcb_connection_t * conn;
653 xcb_window_t window;
654 xcb_gc_t gc;
655 uint32_t depth;
656 VkExtent2D extent;
657
658 xcb_present_event_t event_id;
659 xcb_special_event_t * special_event;
660 uint64_t send_sbc;
661 uint64_t last_present_msc;
662 uint32_t stamp;
663
664 bool threaded;
665 VkResult status;
666 xcb_present_complete_mode_t last_present_mode;
667 struct wsi_queue present_queue;
668 struct wsi_queue acquire_queue;
669 pthread_t queue_manager;
670
671 struct x11_image images[0];
672 };
673
674 /**
675 * Update the swapchain status with the result of an operation, and return
676 * the combined status. The chain status will eventually be returned from
677 * AcquireNextImage and QueuePresent.
678 *
679 * We make sure to 'stick' more pessimistic statuses: an out-of-date error
680 * is permanent once seen, and every subsequent call will return this. If
681 * this has not been seen, success will be returned.
682 */
683 static VkResult
684 x11_swapchain_result(struct x11_swapchain *chain, VkResult result)
685 {
686 /* Prioritise returning existing errors for consistency. */
687 if (chain->status < 0)
688 return chain->status;
689
690 /* If we have a new error, mark it as permanent on the chain and return. */
691 if (result < 0) {
692 chain->status = result;
693 return result;
694 }
695
696 /* Return temporary errors, but don't persist them. */
697 if (result == VK_TIMEOUT || result == VK_NOT_READY)
698 return result;
699
700 /* Suboptimal isn't an error, but is a status which sticks to the swapchain
701 * and is always returned rather than success.
702 */
703 if (result == VK_SUBOPTIMAL_KHR) {
704 chain->status = result;
705 return result;
706 }
707
708 /* No changes, so return the last status. */
709 return chain->status;
710 }
711
712 static struct wsi_image *
713 x11_get_wsi_image(struct wsi_swapchain *wsi_chain, uint32_t image_index)
714 {
715 struct x11_swapchain *chain = (struct x11_swapchain *)wsi_chain;
716 return &chain->images[image_index].base;
717 }
718
719 /**
720 * Process an X11 Present event. Does not update chain->status.
721 */
722 static VkResult
723 x11_handle_dri3_present_event(struct x11_swapchain *chain,
724 xcb_present_generic_event_t *event)
725 {
726 switch (event->evtype) {
727 case XCB_PRESENT_CONFIGURE_NOTIFY: {
728 xcb_present_configure_notify_event_t *config = (void *) event;
729
730 if (config->width != chain->extent.width ||
731 config->height != chain->extent.height)
732 return VK_ERROR_OUT_OF_DATE_KHR;
733
734 break;
735 }
736
737 case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
738 xcb_present_idle_notify_event_t *idle = (void *) event;
739
740 for (unsigned i = 0; i < chain->base.image_count; i++) {
741 if (chain->images[i].pixmap == idle->pixmap) {
742 chain->images[i].busy = false;
743 if (chain->threaded)
744 wsi_queue_push(&chain->acquire_queue, i);
745 break;
746 }
747 }
748
749 break;
750 }
751
752 case XCB_PRESENT_EVENT_COMPLETE_NOTIFY: {
753 xcb_present_complete_notify_event_t *complete = (void *) event;
754 if (complete->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP)
755 chain->last_present_msc = complete->msc;
756
757 VkResult result = VK_SUCCESS;
758
759 /* The winsys is now trying to flip directly and cannot due to our
760 * configuration. Request the user reallocate.
761 */
762 #ifdef HAVE_DRI3_MODIFIERS
763 if (complete->mode == XCB_PRESENT_COMPLETE_MODE_SUBOPTIMAL_COPY &&
764 chain->last_present_mode != XCB_PRESENT_COMPLETE_MODE_SUBOPTIMAL_COPY)
765 result = VK_SUBOPTIMAL_KHR;
766 #endif
767
768 /* When we go from flipping to copying, the odds are very likely that
769 * we could reallocate in a more optimal way if we didn't have to care
770 * about scanout, so we always do this.
771 */
772 if (complete->mode == XCB_PRESENT_COMPLETE_MODE_COPY &&
773 chain->last_present_mode == XCB_PRESENT_COMPLETE_MODE_FLIP)
774 result = VK_SUBOPTIMAL_KHR;
775
776 chain->last_present_mode = complete->mode;
777 return result;
778 }
779
780 default:
781 break;
782 }
783
784 return VK_SUCCESS;
785 }
786
787
788 static uint64_t wsi_get_current_time(void)
789 {
790 uint64_t current_time;
791 struct timespec tv;
792
793 clock_gettime(CLOCK_MONOTONIC, &tv);
794 current_time = tv.tv_nsec + tv.tv_sec*1000000000ull;
795 return current_time;
796 }
797
798 static uint64_t wsi_get_absolute_timeout(uint64_t timeout)
799 {
800 uint64_t current_time = wsi_get_current_time();
801
802 timeout = MIN2(UINT64_MAX - current_time, timeout);
803
804 return current_time + timeout;
805 }
806
807 static VkResult
808 x11_acquire_next_image_poll_x11(struct x11_swapchain *chain,
809 uint32_t *image_index, uint64_t timeout)
810 {
811 xcb_generic_event_t *event;
812 struct pollfd pfds;
813 uint64_t atimeout;
814 while (1) {
815 for (uint32_t i = 0; i < chain->base.image_count; i++) {
816 if (!chain->images[i].busy) {
817 /* We found a non-busy image */
818 xshmfence_await(chain->images[i].shm_fence);
819 *image_index = i;
820 chain->images[i].busy = true;
821 return x11_swapchain_result(chain, VK_SUCCESS);
822 }
823 }
824
825 xcb_flush(chain->conn);
826
827 if (timeout == UINT64_MAX) {
828 event = xcb_wait_for_special_event(chain->conn, chain->special_event);
829 if (!event)
830 return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR);
831 } else {
832 event = xcb_poll_for_special_event(chain->conn, chain->special_event);
833 if (!event) {
834 int ret;
835 if (timeout == 0)
836 return x11_swapchain_result(chain, VK_NOT_READY);
837
838 atimeout = wsi_get_absolute_timeout(timeout);
839
840 pfds.fd = xcb_get_file_descriptor(chain->conn);
841 pfds.events = POLLIN;
842 ret = poll(&pfds, 1, timeout / 1000 / 1000);
843 if (ret == 0)
844 return x11_swapchain_result(chain, VK_TIMEOUT);
845 if (ret == -1)
846 return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR);
847
848 /* If a non-special event happens, the fd will still
849 * poll. So recalculate the timeout now just in case.
850 */
851 uint64_t current_time = wsi_get_current_time();
852 if (atimeout > current_time)
853 timeout = atimeout - current_time;
854 else
855 timeout = 0;
856 continue;
857 }
858 }
859
860 /* Update the swapchain status here. We may catch non-fatal errors here,
861 * in which case we need to update the status and continue.
862 */
863 VkResult result = x11_handle_dri3_present_event(chain, (void *)event);
864 free(event);
865 if (result < 0)
866 return x11_swapchain_result(chain, result);
867 }
868 }
869
870 static VkResult
871 x11_acquire_next_image_from_queue(struct x11_swapchain *chain,
872 uint32_t *image_index_out, uint64_t timeout)
873 {
874 assert(chain->threaded);
875
876 uint32_t image_index;
877 VkResult result = wsi_queue_pull(&chain->acquire_queue,
878 &image_index, timeout);
879 if (result < 0 || result == VK_TIMEOUT) {
880 /* On error, the thread has shut down, so safe to update chain->status.
881 * Calling x11_swapchain_result with VK_TIMEOUT won't modify
882 * chain->status so that is also safe.
883 */
884 return x11_swapchain_result(chain, result);
885 } else if (chain->status < 0) {
886 return chain->status;
887 }
888
889 assert(image_index < chain->base.image_count);
890 xshmfence_await(chain->images[image_index].shm_fence);
891
892 *image_index_out = image_index;
893
894 return chain->status;
895 }
896
897 static VkResult
898 x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index,
899 uint32_t target_msc)
900 {
901 struct x11_image *image = &chain->images[image_index];
902
903 assert(image_index < chain->base.image_count);
904
905 uint32_t options = XCB_PRESENT_OPTION_NONE;
906
907 int64_t divisor = 0;
908 int64_t remainder = 0;
909
910 if (chain->base.present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR)
911 options |= XCB_PRESENT_OPTION_ASYNC;
912
913 #ifdef HAVE_DRI3_MODIFIERS
914 if (chain->has_dri3_modifiers)
915 options |= XCB_PRESENT_OPTION_SUBOPTIMAL;
916 #endif
917
918 xshmfence_reset(image->shm_fence);
919
920 ++chain->send_sbc;
921 xcb_void_cookie_t cookie =
922 xcb_present_pixmap(chain->conn,
923 chain->window,
924 image->pixmap,
925 (uint32_t) chain->send_sbc,
926 0, /* valid */
927 0, /* update */
928 0, /* x_off */
929 0, /* y_off */
930 XCB_NONE, /* target_crtc */
931 XCB_NONE,
932 image->sync_fence,
933 options,
934 target_msc,
935 divisor,
936 remainder, 0, NULL);
937 xcb_discard_reply(chain->conn, cookie.sequence);
938 image->busy = true;
939
940 xcb_flush(chain->conn);
941
942 return x11_swapchain_result(chain, VK_SUCCESS);
943 }
944
945 static VkResult
946 x11_acquire_next_image(struct wsi_swapchain *anv_chain,
947 uint64_t timeout,
948 VkSemaphore semaphore,
949 uint32_t *image_index)
950 {
951 struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
952
953 if (chain->threaded) {
954 return x11_acquire_next_image_from_queue(chain, image_index, timeout);
955 } else {
956 return x11_acquire_next_image_poll_x11(chain, image_index, timeout);
957 }
958 }
959
960 static VkResult
961 x11_queue_present(struct wsi_swapchain *anv_chain,
962 uint32_t image_index,
963 const VkPresentRegionKHR *damage)
964 {
965 struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
966
967 if (chain->threaded) {
968 wsi_queue_push(&chain->present_queue, image_index);
969 return chain->status;
970 } else {
971 return x11_present_to_x11(chain, image_index, 0);
972 }
973 }
974
975 static void *
976 x11_manage_fifo_queues(void *state)
977 {
978 struct x11_swapchain *chain = state;
979 VkResult result;
980
981 assert(chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR);
982
983 while (chain->status >= 0) {
984 /* It should be safe to unconditionally block here. Later in the loop
985 * we blocks until the previous present has landed on-screen. At that
986 * point, we should have received IDLE_NOTIFY on all images presented
987 * before that point so the client should be able to acquire any image
988 * other than the currently presented one.
989 */
990 uint32_t image_index;
991 result = wsi_queue_pull(&chain->present_queue, &image_index, INT64_MAX);
992 assert(result != VK_TIMEOUT);
993 if (result < 0) {
994 goto fail;
995 } else if (chain->status < 0) {
996 /* The status can change underneath us if the swapchain is destroyed
997 * from another thread.
998 */
999 return NULL;
1000 }
1001
1002 uint64_t target_msc = chain->last_present_msc + 1;
1003 result = x11_present_to_x11(chain, image_index, target_msc);
1004 if (result < 0)
1005 goto fail;
1006
1007 while (chain->last_present_msc < target_msc) {
1008 xcb_generic_event_t *event =
1009 xcb_wait_for_special_event(chain->conn, chain->special_event);
1010 if (!event) {
1011 result = VK_ERROR_OUT_OF_DATE_KHR;
1012 goto fail;
1013 }
1014
1015 result = x11_handle_dri3_present_event(chain, (void *)event);
1016 free(event);
1017 if (result < 0)
1018 goto fail;
1019 }
1020 }
1021
1022 fail:
1023 result = x11_swapchain_result(chain, result);
1024 wsi_queue_push(&chain->acquire_queue, UINT32_MAX);
1025
1026 return NULL;
1027 }
1028
1029 static VkResult
1030 x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
1031 const VkSwapchainCreateInfoKHR *pCreateInfo,
1032 const VkAllocationCallbacks* pAllocator,
1033 const uint64_t *const *modifiers,
1034 const uint32_t *num_modifiers,
1035 int num_tranches, struct x11_image *image)
1036 {
1037 xcb_void_cookie_t cookie;
1038 VkResult result;
1039 uint32_t bpp = 32;
1040
1041 if (chain->base.use_prime_blit) {
1042 result = wsi_create_prime_image(&chain->base, pCreateInfo, &image->base);
1043 } else {
1044 result = wsi_create_native_image(&chain->base, pCreateInfo,
1045 num_tranches, num_modifiers, modifiers,
1046 &image->base);
1047 }
1048 if (result < 0)
1049 return result;
1050
1051 image->pixmap = xcb_generate_id(chain->conn);
1052
1053 #ifdef HAVE_DRI3_MODIFIERS
1054 if (image->base.drm_modifier != DRM_FORMAT_MOD_INVALID) {
1055 /* If the image has a modifier, we must have DRI3 v1.2. */
1056 assert(chain->has_dri3_modifiers);
1057
1058 cookie =
1059 xcb_dri3_pixmap_from_buffers_checked(chain->conn,
1060 image->pixmap,
1061 chain->window,
1062 image->base.num_planes,
1063 pCreateInfo->imageExtent.width,
1064 pCreateInfo->imageExtent.height,
1065 image->base.row_pitches[0],
1066 image->base.offsets[0],
1067 image->base.row_pitches[1],
1068 image->base.offsets[1],
1069 image->base.row_pitches[2],
1070 image->base.offsets[2],
1071 image->base.row_pitches[3],
1072 image->base.offsets[3],
1073 chain->depth, bpp,
1074 image->base.drm_modifier,
1075 image->base.fds);
1076 } else
1077 #endif
1078 {
1079 /* Without passing modifiers, we can't have multi-plane RGB images. */
1080 assert(image->base.num_planes == 1);
1081
1082 cookie =
1083 xcb_dri3_pixmap_from_buffer_checked(chain->conn,
1084 image->pixmap,
1085 chain->window,
1086 image->base.sizes[0],
1087 pCreateInfo->imageExtent.width,
1088 pCreateInfo->imageExtent.height,
1089 image->base.row_pitches[0],
1090 chain->depth, bpp,
1091 image->base.fds[0]);
1092 }
1093
1094 xcb_discard_reply(chain->conn, cookie.sequence);
1095
1096 /* XCB has now taken ownership of the FDs. */
1097 for (int i = 0; i < image->base.num_planes; i++)
1098 image->base.fds[i] = -1;
1099
1100 int fence_fd = xshmfence_alloc_shm();
1101 if (fence_fd < 0)
1102 goto fail_pixmap;
1103
1104 image->shm_fence = xshmfence_map_shm(fence_fd);
1105 if (image->shm_fence == NULL)
1106 goto fail_shmfence_alloc;
1107
1108 image->sync_fence = xcb_generate_id(chain->conn);
1109 xcb_dri3_fence_from_fd(chain->conn,
1110 image->pixmap,
1111 image->sync_fence,
1112 false,
1113 fence_fd);
1114
1115 image->busy = false;
1116 xshmfence_trigger(image->shm_fence);
1117
1118 return VK_SUCCESS;
1119
1120 fail_shmfence_alloc:
1121 close(fence_fd);
1122
1123 fail_pixmap:
1124 cookie = xcb_free_pixmap(chain->conn, image->pixmap);
1125 xcb_discard_reply(chain->conn, cookie.sequence);
1126
1127 wsi_destroy_image(&chain->base, &image->base);
1128
1129 return result;
1130 }
1131
1132 static void
1133 x11_image_finish(struct x11_swapchain *chain,
1134 const VkAllocationCallbacks* pAllocator,
1135 struct x11_image *image)
1136 {
1137 xcb_void_cookie_t cookie;
1138
1139 cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence);
1140 xcb_discard_reply(chain->conn, cookie.sequence);
1141 xshmfence_unmap_shm(image->shm_fence);
1142
1143 cookie = xcb_free_pixmap(chain->conn, image->pixmap);
1144 xcb_discard_reply(chain->conn, cookie.sequence);
1145
1146 wsi_destroy_image(&chain->base, &image->base);
1147 }
1148
1149 static void
1150 wsi_x11_get_dri3_modifiers(struct wsi_x11_connection *wsi_conn,
1151 xcb_connection_t *conn, xcb_window_t window,
1152 uint8_t depth, uint8_t bpp,
1153 VkCompositeAlphaFlagsKHR vk_alpha,
1154 uint64_t **modifiers_in, uint32_t *num_modifiers_in,
1155 uint32_t *num_tranches_in,
1156 const VkAllocationCallbacks *pAllocator)
1157 {
1158 if (!wsi_conn->has_dri3_modifiers)
1159 goto out;
1160
1161 #ifdef HAVE_DRI3_MODIFIERS
1162 xcb_generic_error_t *error = NULL;
1163 xcb_dri3_get_supported_modifiers_cookie_t mod_cookie =
1164 xcb_dri3_get_supported_modifiers(conn, window, depth, bpp);
1165 xcb_dri3_get_supported_modifiers_reply_t *mod_reply =
1166 xcb_dri3_get_supported_modifiers_reply(conn, mod_cookie, &error);
1167 free(error);
1168
1169 if (!mod_reply || (mod_reply->num_window_modifiers == 0 &&
1170 mod_reply->num_screen_modifiers == 0)) {
1171 free(mod_reply);
1172 goto out;
1173 }
1174
1175 uint32_t n = 0;
1176 uint32_t counts[2];
1177 uint64_t *modifiers[2];
1178
1179 if (mod_reply->num_window_modifiers) {
1180 counts[n] = mod_reply->num_window_modifiers;
1181 modifiers[n] = vk_alloc(pAllocator,
1182 counts[n] * sizeof(uint64_t),
1183 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1184 if (!modifiers[n]) {
1185 free(mod_reply);
1186 goto out;
1187 }
1188
1189 memcpy(modifiers[n],
1190 xcb_dri3_get_supported_modifiers_window_modifiers(mod_reply),
1191 counts[n] * sizeof(uint64_t));
1192 n++;
1193 }
1194
1195 if (mod_reply->num_screen_modifiers) {
1196 counts[n] = mod_reply->num_screen_modifiers;
1197 modifiers[n] = vk_alloc(pAllocator,
1198 counts[n] * sizeof(uint64_t),
1199 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1200 if (!modifiers[n]) {
1201 if (n > 0)
1202 vk_free(pAllocator, modifiers[0]);
1203 free(mod_reply);
1204 goto out;
1205 }
1206
1207 memcpy(modifiers[n],
1208 xcb_dri3_get_supported_modifiers_screen_modifiers(mod_reply),
1209 counts[n] * sizeof(uint64_t));
1210 n++;
1211 }
1212
1213 for (int i = 0; i < n; i++) {
1214 modifiers_in[i] = modifiers[i];
1215 num_modifiers_in[i] = counts[i];
1216 }
1217 *num_tranches_in = n;
1218
1219 free(mod_reply);
1220 return;
1221 #endif
1222 out:
1223 *num_tranches_in = 0;
1224 }
1225
1226 static VkResult
1227 x11_swapchain_destroy(struct wsi_swapchain *anv_chain,
1228 const VkAllocationCallbacks *pAllocator)
1229 {
1230 struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
1231 xcb_void_cookie_t cookie;
1232
1233 for (uint32_t i = 0; i < chain->base.image_count; i++)
1234 x11_image_finish(chain, pAllocator, &chain->images[i]);
1235
1236 if (chain->threaded) {
1237 chain->status = VK_ERROR_OUT_OF_DATE_KHR;
1238 /* Push a UINT32_MAX to wake up the manager */
1239 wsi_queue_push(&chain->present_queue, UINT32_MAX);
1240 pthread_join(chain->queue_manager, NULL);
1241 wsi_queue_destroy(&chain->acquire_queue);
1242 wsi_queue_destroy(&chain->present_queue);
1243 }
1244
1245 xcb_unregister_for_special_event(chain->conn, chain->special_event);
1246 cookie = xcb_present_select_input_checked(chain->conn, chain->event_id,
1247 chain->window,
1248 XCB_PRESENT_EVENT_MASK_NO_EVENT);
1249 xcb_discard_reply(chain->conn, cookie.sequence);
1250
1251 wsi_swapchain_finish(&chain->base);
1252
1253 vk_free(pAllocator, chain);
1254
1255 return VK_SUCCESS;
1256 }
1257
1258 static VkResult
1259 x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
1260 VkDevice device,
1261 struct wsi_device *wsi_device,
1262 int local_fd,
1263 const VkSwapchainCreateInfoKHR *pCreateInfo,
1264 const VkAllocationCallbacks* pAllocator,
1265 struct wsi_swapchain **swapchain_out)
1266 {
1267 struct x11_swapchain *chain;
1268 xcb_void_cookie_t cookie;
1269 VkResult result;
1270
1271 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
1272
1273 const unsigned num_images = pCreateInfo->minImageCount;
1274
1275 xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
1276 struct wsi_x11_connection *wsi_conn =
1277 wsi_x11_get_connection(wsi_device, pAllocator, conn);
1278 if (!wsi_conn)
1279 return VK_ERROR_OUT_OF_HOST_MEMORY;
1280
1281 /* Check for whether or not we have a window up-front */
1282 xcb_window_t window = x11_surface_get_window(icd_surface);
1283 xcb_get_geometry_reply_t *geometry =
1284 xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), NULL);
1285 if (geometry == NULL)
1286 return VK_ERROR_SURFACE_LOST_KHR;
1287 const uint32_t bit_depth = geometry->depth;
1288 free(geometry);
1289
1290 size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
1291 chain = vk_alloc(pAllocator, size, 8,
1292 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1293 if (chain == NULL)
1294 return VK_ERROR_OUT_OF_HOST_MEMORY;
1295
1296 result = wsi_swapchain_init(wsi_device, &chain->base, device,
1297 pCreateInfo, pAllocator);
1298 if (result != VK_SUCCESS)
1299 goto fail_alloc;
1300
1301 chain->base.destroy = x11_swapchain_destroy;
1302 chain->base.get_wsi_image = x11_get_wsi_image;
1303 chain->base.acquire_next_image = x11_acquire_next_image;
1304 chain->base.queue_present = x11_queue_present;
1305 chain->base.present_mode = pCreateInfo->presentMode;
1306 chain->base.image_count = num_images;
1307 chain->conn = conn;
1308 chain->window = window;
1309 chain->depth = bit_depth;
1310 chain->extent = pCreateInfo->imageExtent;
1311 chain->send_sbc = 0;
1312 chain->last_present_msc = 0;
1313 chain->threaded = false;
1314 chain->status = VK_SUCCESS;
1315 chain->has_dri3_modifiers = wsi_conn->has_dri3_modifiers;
1316
1317 /* If we are reallocating from an old swapchain, then we inherit its
1318 * last completion mode, to ensure we don't get into reallocation
1319 * cycles. If we are starting anew, we set 'COPY', as that is the only
1320 * mode which provokes reallocation when anything changes, to make
1321 * sure we have the most optimal allocation.
1322 */
1323 struct x11_swapchain *old_chain = (void *) pCreateInfo->oldSwapchain;
1324 if (old_chain)
1325 chain->last_present_mode = old_chain->last_present_mode;
1326 else
1327 chain->last_present_mode = XCB_PRESENT_COMPLETE_MODE_COPY;
1328
1329 if (!wsi_x11_check_dri3_compatible(conn, local_fd))
1330 chain->base.use_prime_blit = true;
1331
1332 chain->event_id = xcb_generate_id(chain->conn);
1333 xcb_present_select_input(chain->conn, chain->event_id, chain->window,
1334 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
1335 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
1336 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
1337
1338 /* Create an XCB event queue to hold present events outside of the usual
1339 * application event queue
1340 */
1341 chain->special_event =
1342 xcb_register_for_special_xge(chain->conn, &xcb_present_id,
1343 chain->event_id, NULL);
1344
1345 chain->gc = xcb_generate_id(chain->conn);
1346 if (!chain->gc) {
1347 /* FINISHME: Choose a better error. */
1348 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1349 goto fail_register;
1350 }
1351
1352 cookie = xcb_create_gc(chain->conn,
1353 chain->gc,
1354 chain->window,
1355 XCB_GC_GRAPHICS_EXPOSURES,
1356 (uint32_t []) { 0 });
1357 xcb_discard_reply(chain->conn, cookie.sequence);
1358
1359 uint64_t *modifiers[2] = {NULL, NULL};
1360 uint32_t num_modifiers[2] = {0, 0};
1361 uint32_t num_tranches = 0;
1362 if (wsi_device->supports_modifiers)
1363 wsi_x11_get_dri3_modifiers(wsi_conn, conn, window, chain->depth, 32,
1364 pCreateInfo->compositeAlpha,
1365 modifiers, num_modifiers, &num_tranches,
1366 pAllocator);
1367
1368 uint32_t image = 0;
1369 for (; image < chain->base.image_count; image++) {
1370 result = x11_image_init(device, chain, pCreateInfo, pAllocator,
1371 (const uint64_t *const *)modifiers,
1372 num_modifiers, num_tranches,
1373 &chain->images[image]);
1374 if (result != VK_SUCCESS)
1375 goto fail_init_images;
1376 }
1377
1378 if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {
1379 chain->threaded = true;
1380
1381 /* Initialize our queues. We make them base.image_count + 1 because we will
1382 * occasionally use UINT32_MAX to signal the other thread that an error
1383 * has occurred and we don't want an overflow.
1384 */
1385 int ret;
1386 ret = wsi_queue_init(&chain->acquire_queue, chain->base.image_count + 1);
1387 if (ret) {
1388 goto fail_init_images;
1389 }
1390
1391 ret = wsi_queue_init(&chain->present_queue, chain->base.image_count + 1);
1392 if (ret) {
1393 wsi_queue_destroy(&chain->acquire_queue);
1394 goto fail_init_images;
1395 }
1396
1397 for (unsigned i = 0; i < chain->base.image_count; i++)
1398 wsi_queue_push(&chain->acquire_queue, i);
1399
1400 ret = pthread_create(&chain->queue_manager, NULL,
1401 x11_manage_fifo_queues, chain);
1402 if (ret) {
1403 wsi_queue_destroy(&chain->present_queue);
1404 wsi_queue_destroy(&chain->acquire_queue);
1405 goto fail_init_images;
1406 }
1407 }
1408
1409 for (int i = 0; i < ARRAY_SIZE(modifiers); i++)
1410 vk_free(pAllocator, modifiers[i]);
1411 *swapchain_out = &chain->base;
1412
1413 return VK_SUCCESS;
1414
1415 fail_init_images:
1416 for (uint32_t j = 0; j < image; j++)
1417 x11_image_finish(chain, pAllocator, &chain->images[j]);
1418
1419 fail_register:
1420 for (int i = 0; i < ARRAY_SIZE(modifiers); i++)
1421 vk_free(pAllocator, modifiers[i]);
1422
1423 xcb_unregister_for_special_event(chain->conn, chain->special_event);
1424
1425 wsi_swapchain_finish(&chain->base);
1426
1427 fail_alloc:
1428 vk_free(pAllocator, chain);
1429
1430 return result;
1431 }
1432
1433 VkResult
1434 wsi_x11_init_wsi(struct wsi_device *wsi_device,
1435 const VkAllocationCallbacks *alloc)
1436 {
1437 struct wsi_x11 *wsi;
1438 VkResult result;
1439
1440 wsi = vk_alloc(alloc, sizeof(*wsi), 8,
1441 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1442 if (!wsi) {
1443 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1444 goto fail;
1445 }
1446
1447 int ret = pthread_mutex_init(&wsi->mutex, NULL);
1448 if (ret != 0) {
1449 if (ret == ENOMEM) {
1450 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1451 } else {
1452 /* FINISHME: Choose a better error. */
1453 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1454 }
1455
1456 goto fail_alloc;
1457 }
1458
1459 wsi->connections = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
1460 _mesa_key_pointer_equal);
1461 if (!wsi->connections) {
1462 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1463 goto fail_mutex;
1464 }
1465
1466 wsi->base.get_support = x11_surface_get_support;
1467 wsi->base.get_capabilities = x11_surface_get_capabilities;
1468 wsi->base.get_capabilities2 = x11_surface_get_capabilities2;
1469 wsi->base.get_formats = x11_surface_get_formats;
1470 wsi->base.get_formats2 = x11_surface_get_formats2;
1471 wsi->base.get_present_modes = x11_surface_get_present_modes;
1472 wsi->base.create_swapchain = x11_surface_create_swapchain;
1473
1474 wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = &wsi->base;
1475 wsi_device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = &wsi->base;
1476
1477 return VK_SUCCESS;
1478
1479 fail_mutex:
1480 pthread_mutex_destroy(&wsi->mutex);
1481 fail_alloc:
1482 vk_free(alloc, wsi);
1483 fail:
1484 wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = NULL;
1485 wsi_device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = NULL;
1486
1487 return result;
1488 }
1489
1490 void
1491 wsi_x11_finish_wsi(struct wsi_device *wsi_device,
1492 const VkAllocationCallbacks *alloc)
1493 {
1494 struct wsi_x11 *wsi =
1495 (struct wsi_x11 *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB];
1496
1497 if (wsi) {
1498 struct hash_entry *entry;
1499 hash_table_foreach(wsi->connections, entry)
1500 wsi_x11_connection_destroy(alloc, entry->data);
1501
1502 _mesa_hash_table_destroy(wsi->connections, NULL);
1503
1504 pthread_mutex_destroy(&wsi->mutex);
1505
1506 vk_free(alloc, wsi);
1507 }
1508 }