vulkan/wsi/x11: Return VK_SUBOPTIMAL_KHR for X11
[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 if (complete->mode == XCB_PRESENT_COMPLETE_MODE_SUBOPTIMAL_COPY &&
763 chain->last_present_mode != XCB_PRESENT_COMPLETE_MODE_SUBOPTIMAL_COPY)
764 result = VK_SUBOPTIMAL_KHR;
765
766 /* When we go from flipping to copying, the odds are very likely that
767 * we could reallocate in a more optimal way if we didn't have to care
768 * about scanout, so we always do this.
769 */
770 if (complete->mode == XCB_PRESENT_COMPLETE_MODE_COPY &&
771 chain->last_present_mode == XCB_PRESENT_COMPLETE_MODE_FLIP)
772 result = VK_SUBOPTIMAL_KHR;
773
774 chain->last_present_mode = complete->mode;
775 return result;
776 }
777
778 default:
779 break;
780 }
781
782 return VK_SUCCESS;
783 }
784
785
786 static uint64_t wsi_get_current_time(void)
787 {
788 uint64_t current_time;
789 struct timespec tv;
790
791 clock_gettime(CLOCK_MONOTONIC, &tv);
792 current_time = tv.tv_nsec + tv.tv_sec*1000000000ull;
793 return current_time;
794 }
795
796 static uint64_t wsi_get_absolute_timeout(uint64_t timeout)
797 {
798 uint64_t current_time = wsi_get_current_time();
799
800 timeout = MIN2(UINT64_MAX - current_time, timeout);
801
802 return current_time + timeout;
803 }
804
805 static VkResult
806 x11_acquire_next_image_poll_x11(struct x11_swapchain *chain,
807 uint32_t *image_index, uint64_t timeout)
808 {
809 xcb_generic_event_t *event;
810 struct pollfd pfds;
811 uint64_t atimeout;
812 while (1) {
813 for (uint32_t i = 0; i < chain->base.image_count; i++) {
814 if (!chain->images[i].busy) {
815 /* We found a non-busy image */
816 xshmfence_await(chain->images[i].shm_fence);
817 *image_index = i;
818 chain->images[i].busy = true;
819 return x11_swapchain_result(chain, VK_SUCCESS);
820 }
821 }
822
823 xcb_flush(chain->conn);
824
825 if (timeout == UINT64_MAX) {
826 event = xcb_wait_for_special_event(chain->conn, chain->special_event);
827 if (!event)
828 return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR);
829 } else {
830 event = xcb_poll_for_special_event(chain->conn, chain->special_event);
831 if (!event) {
832 int ret;
833 if (timeout == 0)
834 return x11_swapchain_result(chain, VK_NOT_READY);
835
836 atimeout = wsi_get_absolute_timeout(timeout);
837
838 pfds.fd = xcb_get_file_descriptor(chain->conn);
839 pfds.events = POLLIN;
840 ret = poll(&pfds, 1, timeout / 1000 / 1000);
841 if (ret == 0)
842 return x11_swapchain_result(chain, VK_TIMEOUT);
843 if (ret == -1)
844 return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR);
845
846 /* If a non-special event happens, the fd will still
847 * poll. So recalculate the timeout now just in case.
848 */
849 uint64_t current_time = wsi_get_current_time();
850 if (atimeout > current_time)
851 timeout = atimeout - current_time;
852 else
853 timeout = 0;
854 continue;
855 }
856 }
857
858 /* Update the swapchain status here. We may catch non-fatal errors here,
859 * in which case we need to update the status and continue.
860 */
861 VkResult result = x11_handle_dri3_present_event(chain, (void *)event);
862 free(event);
863 if (result < 0)
864 return x11_swapchain_result(chain, result);
865 }
866 }
867
868 static VkResult
869 x11_acquire_next_image_from_queue(struct x11_swapchain *chain,
870 uint32_t *image_index_out, uint64_t timeout)
871 {
872 assert(chain->threaded);
873
874 uint32_t image_index;
875 VkResult result = wsi_queue_pull(&chain->acquire_queue,
876 &image_index, timeout);
877 if (result < 0 || result == VK_TIMEOUT) {
878 /* On error, the thread has shut down, so safe to update chain->status.
879 * Calling x11_swapchain_result with VK_TIMEOUT won't modify
880 * chain->status so that is also safe.
881 */
882 return x11_swapchain_result(chain, result);
883 } else if (chain->status < 0) {
884 return chain->status;
885 }
886
887 assert(image_index < chain->base.image_count);
888 xshmfence_await(chain->images[image_index].shm_fence);
889
890 *image_index_out = image_index;
891
892 return chain->status;
893 }
894
895 static VkResult
896 x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index,
897 uint32_t target_msc)
898 {
899 struct x11_image *image = &chain->images[image_index];
900
901 assert(image_index < chain->base.image_count);
902
903 uint32_t options = XCB_PRESENT_OPTION_NONE;
904
905 int64_t divisor = 0;
906 int64_t remainder = 0;
907
908 if (chain->base.present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR)
909 options |= XCB_PRESENT_OPTION_ASYNC;
910
911 if (chain->has_dri3_modifiers)
912 options |= XCB_PRESENT_OPTION_SUBOPTIMAL;
913
914 xshmfence_reset(image->shm_fence);
915
916 ++chain->send_sbc;
917 xcb_void_cookie_t cookie =
918 xcb_present_pixmap(chain->conn,
919 chain->window,
920 image->pixmap,
921 (uint32_t) chain->send_sbc,
922 0, /* valid */
923 0, /* update */
924 0, /* x_off */
925 0, /* y_off */
926 XCB_NONE, /* target_crtc */
927 XCB_NONE,
928 image->sync_fence,
929 options,
930 target_msc,
931 divisor,
932 remainder, 0, NULL);
933 xcb_discard_reply(chain->conn, cookie.sequence);
934 image->busy = true;
935
936 xcb_flush(chain->conn);
937
938 return x11_swapchain_result(chain, VK_SUCCESS);
939 }
940
941 static VkResult
942 x11_acquire_next_image(struct wsi_swapchain *anv_chain,
943 uint64_t timeout,
944 VkSemaphore semaphore,
945 uint32_t *image_index)
946 {
947 struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
948
949 if (chain->threaded) {
950 return x11_acquire_next_image_from_queue(chain, image_index, timeout);
951 } else {
952 return x11_acquire_next_image_poll_x11(chain, image_index, timeout);
953 }
954 }
955
956 static VkResult
957 x11_queue_present(struct wsi_swapchain *anv_chain,
958 uint32_t image_index,
959 const VkPresentRegionKHR *damage)
960 {
961 struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
962
963 if (chain->threaded) {
964 wsi_queue_push(&chain->present_queue, image_index);
965 return chain->status;
966 } else {
967 return x11_present_to_x11(chain, image_index, 0);
968 }
969 }
970
971 static void *
972 x11_manage_fifo_queues(void *state)
973 {
974 struct x11_swapchain *chain = state;
975 VkResult result;
976
977 assert(chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR);
978
979 while (chain->status >= 0) {
980 /* It should be safe to unconditionally block here. Later in the loop
981 * we blocks until the previous present has landed on-screen. At that
982 * point, we should have received IDLE_NOTIFY on all images presented
983 * before that point so the client should be able to acquire any image
984 * other than the currently presented one.
985 */
986 uint32_t image_index;
987 result = wsi_queue_pull(&chain->present_queue, &image_index, INT64_MAX);
988 assert(result != VK_TIMEOUT);
989 if (result < 0) {
990 goto fail;
991 } else if (chain->status < 0) {
992 /* The status can change underneath us if the swapchain is destroyed
993 * from another thread.
994 */
995 return NULL;
996 }
997
998 uint64_t target_msc = chain->last_present_msc + 1;
999 result = x11_present_to_x11(chain, image_index, target_msc);
1000 if (result < 0)
1001 goto fail;
1002
1003 while (chain->last_present_msc < target_msc) {
1004 xcb_generic_event_t *event =
1005 xcb_wait_for_special_event(chain->conn, chain->special_event);
1006 if (!event) {
1007 result = VK_ERROR_OUT_OF_DATE_KHR;
1008 goto fail;
1009 }
1010
1011 result = x11_handle_dri3_present_event(chain, (void *)event);
1012 free(event);
1013 if (result < 0)
1014 goto fail;
1015 }
1016 }
1017
1018 fail:
1019 result = x11_swapchain_result(chain, result);
1020 wsi_queue_push(&chain->acquire_queue, UINT32_MAX);
1021
1022 return NULL;
1023 }
1024
1025 static VkResult
1026 x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
1027 const VkSwapchainCreateInfoKHR *pCreateInfo,
1028 const VkAllocationCallbacks* pAllocator,
1029 const uint64_t *const *modifiers,
1030 const uint32_t *num_modifiers,
1031 int num_tranches, struct x11_image *image)
1032 {
1033 xcb_void_cookie_t cookie;
1034 VkResult result;
1035 uint32_t bpp = 32;
1036
1037 if (chain->base.use_prime_blit) {
1038 result = wsi_create_prime_image(&chain->base, pCreateInfo, &image->base);
1039 } else {
1040 result = wsi_create_native_image(&chain->base, pCreateInfo,
1041 num_tranches, num_modifiers, modifiers,
1042 &image->base);
1043 }
1044 if (result < 0)
1045 return result;
1046
1047 image->pixmap = xcb_generate_id(chain->conn);
1048
1049 if (image->base.drm_modifier != DRM_FORMAT_MOD_INVALID) {
1050 /* If the image has a modifier, we must have DRI3 v1.1. */
1051 assert(chain->has_dri3_modifiers);
1052
1053 cookie =
1054 xcb_dri3_pixmap_from_buffers_checked(chain->conn,
1055 image->pixmap,
1056 chain->window,
1057 image->base.num_planes,
1058 pCreateInfo->imageExtent.width,
1059 pCreateInfo->imageExtent.height,
1060 image->base.row_pitches[0],
1061 image->base.offsets[0],
1062 image->base.row_pitches[1],
1063 image->base.offsets[1],
1064 image->base.row_pitches[2],
1065 image->base.offsets[2],
1066 image->base.row_pitches[3],
1067 image->base.offsets[3],
1068 chain->depth, bpp,
1069 image->base.drm_modifier,
1070 image->base.fds);
1071 } else {
1072 /* Without passing modifiers, we can't have multi-plane RGB images. */
1073 assert(image->base.num_planes == 1);
1074
1075 cookie =
1076 xcb_dri3_pixmap_from_buffer_checked(chain->conn,
1077 image->pixmap,
1078 chain->window,
1079 image->base.sizes[0],
1080 pCreateInfo->imageExtent.width,
1081 pCreateInfo->imageExtent.height,
1082 image->base.row_pitches[0],
1083 chain->depth, bpp,
1084 image->base.fds[0]);
1085 }
1086
1087 xcb_discard_reply(chain->conn, cookie.sequence);
1088
1089 /* XCB has now taken ownership of the FDs. */
1090 for (int i = 0; i < image->base.num_planes; i++)
1091 image->base.fds[i] = -1;
1092
1093 int fence_fd = xshmfence_alloc_shm();
1094 if (fence_fd < 0)
1095 goto fail_pixmap;
1096
1097 image->shm_fence = xshmfence_map_shm(fence_fd);
1098 if (image->shm_fence == NULL)
1099 goto fail_shmfence_alloc;
1100
1101 image->sync_fence = xcb_generate_id(chain->conn);
1102 xcb_dri3_fence_from_fd(chain->conn,
1103 image->pixmap,
1104 image->sync_fence,
1105 false,
1106 fence_fd);
1107
1108 image->busy = false;
1109 xshmfence_trigger(image->shm_fence);
1110
1111 return VK_SUCCESS;
1112
1113 fail_shmfence_alloc:
1114 close(fence_fd);
1115
1116 fail_pixmap:
1117 cookie = xcb_free_pixmap(chain->conn, image->pixmap);
1118 xcb_discard_reply(chain->conn, cookie.sequence);
1119
1120 wsi_destroy_image(&chain->base, &image->base);
1121
1122 return result;
1123 }
1124
1125 static void
1126 x11_image_finish(struct x11_swapchain *chain,
1127 const VkAllocationCallbacks* pAllocator,
1128 struct x11_image *image)
1129 {
1130 xcb_void_cookie_t cookie;
1131
1132 cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence);
1133 xcb_discard_reply(chain->conn, cookie.sequence);
1134 xshmfence_unmap_shm(image->shm_fence);
1135
1136 cookie = xcb_free_pixmap(chain->conn, image->pixmap);
1137 xcb_discard_reply(chain->conn, cookie.sequence);
1138
1139 wsi_destroy_image(&chain->base, &image->base);
1140 }
1141
1142 static void
1143 wsi_x11_get_dri3_modifiers(struct wsi_x11_connection *wsi_conn,
1144 xcb_connection_t *conn, xcb_window_t window,
1145 uint8_t depth, uint8_t bpp,
1146 VkCompositeAlphaFlagsKHR vk_alpha,
1147 uint64_t **modifiers_in, uint32_t *num_modifiers_in,
1148 uint32_t *num_tranches_in,
1149 const VkAllocationCallbacks *pAllocator)
1150 {
1151 if (!wsi_conn->has_dri3_modifiers)
1152 goto out;
1153
1154 xcb_generic_error_t *error = NULL;
1155 xcb_dri3_get_supported_modifiers_cookie_t mod_cookie =
1156 xcb_dri3_get_supported_modifiers(conn, window, depth, bpp);
1157 xcb_dri3_get_supported_modifiers_reply_t *mod_reply =
1158 xcb_dri3_get_supported_modifiers_reply(conn, mod_cookie, &error);
1159 free(error);
1160
1161 if (!mod_reply || (mod_reply->num_window_modifiers == 0 &&
1162 mod_reply->num_screen_modifiers == 0)) {
1163 free(mod_reply);
1164 goto out;
1165 }
1166
1167 uint32_t n = 0;
1168 uint32_t counts[2];
1169 uint64_t *modifiers[2];
1170
1171 if (mod_reply->num_window_modifiers) {
1172 counts[n] = mod_reply->num_window_modifiers;
1173 modifiers[n] = vk_alloc(pAllocator,
1174 counts[n] * sizeof(uint64_t),
1175 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1176 if (!modifiers[n]) {
1177 free(mod_reply);
1178 goto out;
1179 }
1180
1181 memcpy(modifiers[n],
1182 xcb_dri3_get_supported_modifiers_window_modifiers(mod_reply),
1183 counts[n] * sizeof(uint64_t));
1184 n++;
1185 }
1186
1187 if (mod_reply->num_screen_modifiers) {
1188 counts[n] = mod_reply->num_screen_modifiers;
1189 modifiers[n] = vk_alloc(pAllocator,
1190 counts[n] * sizeof(uint64_t),
1191 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1192 if (!modifiers[n]) {
1193 if (n > 0)
1194 vk_free(pAllocator, modifiers[0]);
1195 free(mod_reply);
1196 goto out;
1197 }
1198
1199 memcpy(modifiers[n],
1200 xcb_dri3_get_supported_modifiers_screen_modifiers(mod_reply),
1201 counts[n] * sizeof(uint64_t));
1202 n++;
1203 }
1204
1205 for (int i = 0; i < n; i++) {
1206 modifiers_in[i] = modifiers[i];
1207 num_modifiers_in[i] = counts[i];
1208 }
1209 *num_tranches_in = n;
1210
1211 free(mod_reply);
1212 return;
1213
1214 out:
1215 *num_tranches_in = 0;
1216 }
1217
1218 static VkResult
1219 x11_swapchain_destroy(struct wsi_swapchain *anv_chain,
1220 const VkAllocationCallbacks *pAllocator)
1221 {
1222 struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
1223 xcb_void_cookie_t cookie;
1224
1225 for (uint32_t i = 0; i < chain->base.image_count; i++)
1226 x11_image_finish(chain, pAllocator, &chain->images[i]);
1227
1228 if (chain->threaded) {
1229 chain->status = VK_ERROR_OUT_OF_DATE_KHR;
1230 /* Push a UINT32_MAX to wake up the manager */
1231 wsi_queue_push(&chain->present_queue, UINT32_MAX);
1232 pthread_join(chain->queue_manager, NULL);
1233 wsi_queue_destroy(&chain->acquire_queue);
1234 wsi_queue_destroy(&chain->present_queue);
1235 }
1236
1237 xcb_unregister_for_special_event(chain->conn, chain->special_event);
1238 cookie = xcb_present_select_input_checked(chain->conn, chain->event_id,
1239 chain->window,
1240 XCB_PRESENT_EVENT_MASK_NO_EVENT);
1241 xcb_discard_reply(chain->conn, cookie.sequence);
1242
1243 wsi_swapchain_finish(&chain->base);
1244
1245 vk_free(pAllocator, chain);
1246
1247 return VK_SUCCESS;
1248 }
1249
1250 static VkResult
1251 x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
1252 VkDevice device,
1253 struct wsi_device *wsi_device,
1254 int local_fd,
1255 const VkSwapchainCreateInfoKHR *pCreateInfo,
1256 const VkAllocationCallbacks* pAllocator,
1257 struct wsi_swapchain **swapchain_out)
1258 {
1259 struct x11_swapchain *chain;
1260 xcb_void_cookie_t cookie;
1261 VkResult result;
1262
1263 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
1264
1265 const unsigned num_images = pCreateInfo->minImageCount;
1266
1267 xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
1268 struct wsi_x11_connection *wsi_conn =
1269 wsi_x11_get_connection(wsi_device, pAllocator, conn);
1270 if (!wsi_conn)
1271 return VK_ERROR_OUT_OF_HOST_MEMORY;
1272
1273 /* Check for whether or not we have a window up-front */
1274 xcb_window_t window = x11_surface_get_window(icd_surface);
1275 xcb_get_geometry_reply_t *geometry =
1276 xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), NULL);
1277 if (geometry == NULL)
1278 return VK_ERROR_SURFACE_LOST_KHR;
1279 const uint32_t bit_depth = geometry->depth;
1280 free(geometry);
1281
1282 size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
1283 chain = vk_alloc(pAllocator, size, 8,
1284 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1285 if (chain == NULL)
1286 return VK_ERROR_OUT_OF_HOST_MEMORY;
1287
1288 result = wsi_swapchain_init(wsi_device, &chain->base, device,
1289 pCreateInfo, pAllocator);
1290 if (result != VK_SUCCESS)
1291 goto fail_alloc;
1292
1293 chain->base.destroy = x11_swapchain_destroy;
1294 chain->base.get_wsi_image = x11_get_wsi_image;
1295 chain->base.acquire_next_image = x11_acquire_next_image;
1296 chain->base.queue_present = x11_queue_present;
1297 chain->base.present_mode = pCreateInfo->presentMode;
1298 chain->base.image_count = num_images;
1299 chain->conn = conn;
1300 chain->window = window;
1301 chain->depth = bit_depth;
1302 chain->extent = pCreateInfo->imageExtent;
1303 chain->send_sbc = 0;
1304 chain->last_present_msc = 0;
1305 chain->threaded = false;
1306 chain->status = VK_SUCCESS;
1307 chain->has_dri3_modifiers = wsi_conn->has_dri3_modifiers;
1308
1309 /* If we are reallocating from an old swapchain, then we inherit its
1310 * last completion mode, to ensure we don't get into reallocation
1311 * cycles. If we are starting anew, we set 'COPY', as that is the only
1312 * mode which provokes reallocation when anything changes, to make
1313 * sure we have the most optimal allocation.
1314 */
1315 struct x11_swapchain *old_chain = (void *) pCreateInfo->oldSwapchain;
1316 if (old_chain)
1317 chain->last_present_mode = old_chain->last_present_mode;
1318 else
1319 chain->last_present_mode = XCB_PRESENT_COMPLETE_MODE_COPY;
1320
1321 if (!wsi_x11_check_dri3_compatible(conn, local_fd))
1322 chain->base.use_prime_blit = true;
1323
1324 chain->event_id = xcb_generate_id(chain->conn);
1325 xcb_present_select_input(chain->conn, chain->event_id, chain->window,
1326 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
1327 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
1328 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
1329
1330 /* Create an XCB event queue to hold present events outside of the usual
1331 * application event queue
1332 */
1333 chain->special_event =
1334 xcb_register_for_special_xge(chain->conn, &xcb_present_id,
1335 chain->event_id, NULL);
1336
1337 chain->gc = xcb_generate_id(chain->conn);
1338 if (!chain->gc) {
1339 /* FINISHME: Choose a better error. */
1340 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1341 goto fail_register;
1342 }
1343
1344 cookie = xcb_create_gc(chain->conn,
1345 chain->gc,
1346 chain->window,
1347 XCB_GC_GRAPHICS_EXPOSURES,
1348 (uint32_t []) { 0 });
1349 xcb_discard_reply(chain->conn, cookie.sequence);
1350
1351 uint64_t *modifiers[2] = {NULL, NULL};
1352 uint32_t num_modifiers[2] = {0, 0};
1353 uint32_t num_tranches = 0;
1354 if (wsi_device->supports_modifiers)
1355 wsi_x11_get_dri3_modifiers(wsi_conn, conn, window, chain->depth, 32,
1356 pCreateInfo->compositeAlpha,
1357 modifiers, num_modifiers, &num_tranches,
1358 pAllocator);
1359
1360 uint32_t image = 0;
1361 for (; image < chain->base.image_count; image++) {
1362 result = x11_image_init(device, chain, pCreateInfo, pAllocator,
1363 (const uint64_t *const *)modifiers,
1364 num_modifiers, num_tranches,
1365 &chain->images[image]);
1366 if (result != VK_SUCCESS)
1367 goto fail_init_images;
1368 }
1369
1370 if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {
1371 chain->threaded = true;
1372
1373 /* Initialize our queues. We make them base.image_count + 1 because we will
1374 * occasionally use UINT32_MAX to signal the other thread that an error
1375 * has occurred and we don't want an overflow.
1376 */
1377 int ret;
1378 ret = wsi_queue_init(&chain->acquire_queue, chain->base.image_count + 1);
1379 if (ret) {
1380 goto fail_init_images;
1381 }
1382
1383 ret = wsi_queue_init(&chain->present_queue, chain->base.image_count + 1);
1384 if (ret) {
1385 wsi_queue_destroy(&chain->acquire_queue);
1386 goto fail_init_images;
1387 }
1388
1389 for (unsigned i = 0; i < chain->base.image_count; i++)
1390 wsi_queue_push(&chain->acquire_queue, i);
1391
1392 ret = pthread_create(&chain->queue_manager, NULL,
1393 x11_manage_fifo_queues, chain);
1394 if (ret) {
1395 wsi_queue_destroy(&chain->present_queue);
1396 wsi_queue_destroy(&chain->acquire_queue);
1397 goto fail_init_images;
1398 }
1399 }
1400
1401 for (int i = 0; i < 2; i++)
1402 vk_free(pAllocator, modifiers[i]);
1403 *swapchain_out = &chain->base;
1404
1405 return VK_SUCCESS;
1406
1407 fail_init_images:
1408 for (uint32_t j = 0; j < image; j++)
1409 x11_image_finish(chain, pAllocator, &chain->images[j]);
1410
1411 fail_register:
1412 for (int i = 0; i < 2; i++)
1413 vk_free(pAllocator, modifiers[i]);
1414
1415 xcb_unregister_for_special_event(chain->conn, chain->special_event);
1416
1417 wsi_swapchain_finish(&chain->base);
1418
1419 fail_alloc:
1420 vk_free(pAllocator, chain);
1421
1422 return result;
1423 }
1424
1425 VkResult
1426 wsi_x11_init_wsi(struct wsi_device *wsi_device,
1427 const VkAllocationCallbacks *alloc)
1428 {
1429 struct wsi_x11 *wsi;
1430 VkResult result;
1431
1432 wsi = vk_alloc(alloc, sizeof(*wsi), 8,
1433 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1434 if (!wsi) {
1435 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1436 goto fail;
1437 }
1438
1439 int ret = pthread_mutex_init(&wsi->mutex, NULL);
1440 if (ret != 0) {
1441 if (ret == ENOMEM) {
1442 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1443 } else {
1444 /* FINISHME: Choose a better error. */
1445 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1446 }
1447
1448 goto fail_alloc;
1449 }
1450
1451 wsi->connections = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
1452 _mesa_key_pointer_equal);
1453 if (!wsi->connections) {
1454 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1455 goto fail_mutex;
1456 }
1457
1458 wsi->base.get_support = x11_surface_get_support;
1459 wsi->base.get_capabilities = x11_surface_get_capabilities;
1460 wsi->base.get_capabilities2 = x11_surface_get_capabilities2;
1461 wsi->base.get_formats = x11_surface_get_formats;
1462 wsi->base.get_formats2 = x11_surface_get_formats2;
1463 wsi->base.get_present_modes = x11_surface_get_present_modes;
1464 wsi->base.create_swapchain = x11_surface_create_swapchain;
1465
1466 wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = &wsi->base;
1467 wsi_device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = &wsi->base;
1468
1469 return VK_SUCCESS;
1470
1471 fail_mutex:
1472 pthread_mutex_destroy(&wsi->mutex);
1473 fail_alloc:
1474 vk_free(alloc, wsi);
1475 fail:
1476 wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = NULL;
1477 wsi_device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = NULL;
1478
1479 return result;
1480 }
1481
1482 void
1483 wsi_x11_finish_wsi(struct wsi_device *wsi_device,
1484 const VkAllocationCallbacks *alloc)
1485 {
1486 struct wsi_x11 *wsi =
1487 (struct wsi_x11 *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB];
1488
1489 if (wsi) {
1490 struct hash_entry *entry;
1491 hash_table_foreach(wsi->connections, entry)
1492 wsi_x11_connection_destroy(alloc, entry->data);
1493
1494 _mesa_hash_table_destroy(wsi->connections, NULL);
1495
1496 pthread_mutex_destroy(&wsi->mutex);
1497
1498 vk_free(alloc, wsi);
1499 }
1500 }