vulkan/wsi/wayland: Include pthread.h
[mesa.git] / src / vulkan / wsi / wsi_common_wayland.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 <wayland-client.h>
25 #include <wayland-drm-client-protocol.h>
26
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <pthread.h>
34
35 #include "wsi_common_wayland.h"
36
37 #include <util/hash_table.h>
38 #include <util/u_vector.h>
39
40 #define typed_memcpy(dest, src, count) ({ \
41 static_assert(sizeof(*src) == sizeof(*dest), ""); \
42 memcpy((dest), (src), (count) * sizeof(*(src))); \
43 })
44
45 #define MIN_NUM_IMAGES 2
46
47 struct wsi_wayland;
48
49 struct wsi_wl_display {
50 struct wl_display * display;
51 struct wl_drm * drm;
52
53 struct wsi_wayland *wsi_wl;
54 /* Vector of VkFormats supported */
55 struct u_vector formats;
56
57 uint32_t capabilities;
58 };
59
60 struct wsi_wayland {
61 struct wsi_interface base;
62
63 const VkAllocationCallbacks *alloc;
64 VkPhysicalDevice physical_device;
65
66 pthread_mutex_t mutex;
67 /* Hash table of wl_display -> wsi_wl_display mappings */
68 struct hash_table * displays;
69
70 const struct wsi_callbacks *cbs;
71 };
72
73 static void
74 wsi_wl_display_add_vk_format(struct wsi_wl_display *display, VkFormat format)
75 {
76 /* Don't add a format that's already in the list */
77 VkFormat *f;
78 u_vector_foreach(f, &display->formats)
79 if (*f == format)
80 return;
81
82 /* Don't add formats that aren't renderable. */
83 VkFormatProperties props;
84
85 display->wsi_wl->cbs->get_phys_device_format_properties(display->wsi_wl->physical_device,
86 format, &props);
87 if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
88 return;
89
90 f = u_vector_add(&display->formats);
91 if (f)
92 *f = format;
93 }
94
95 static void
96 drm_handle_device(void *data, struct wl_drm *drm, const char *name)
97 {
98 fprintf(stderr, "wl_drm.device(%s)\n", name);
99 }
100
101 static uint32_t
102 wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha)
103 {
104 switch (vk_format) {
105 /* TODO: Figure out what all the formats mean and make this table
106 * correct.
107 */
108 #if 0
109 case VK_FORMAT_R4G4B4A4_UNORM:
110 return alpha ? WL_DRM_FORMAT_ABGR4444 : WL_DRM_FORMAT_XBGR4444;
111 case VK_FORMAT_R5G6B5_UNORM:
112 return WL_DRM_FORMAT_BGR565;
113 case VK_FORMAT_R5G5B5A1_UNORM:
114 return alpha ? WL_DRM_FORMAT_ABGR1555 : WL_DRM_FORMAT_XBGR1555;
115 case VK_FORMAT_R8G8B8_UNORM:
116 return WL_DRM_FORMAT_XBGR8888;
117 case VK_FORMAT_R8G8B8A8_UNORM:
118 return alpha ? WL_DRM_FORMAT_ABGR8888 : WL_DRM_FORMAT_XBGR8888;
119 case VK_FORMAT_R10G10B10A2_UNORM:
120 return alpha ? WL_DRM_FORMAT_ABGR2101010 : WL_DRM_FORMAT_XBGR2101010;
121 case VK_FORMAT_B4G4R4A4_UNORM:
122 return alpha ? WL_DRM_FORMAT_ARGB4444 : WL_DRM_FORMAT_XRGB4444;
123 case VK_FORMAT_B5G6R5_UNORM:
124 return WL_DRM_FORMAT_RGB565;
125 case VK_FORMAT_B5G5R5A1_UNORM:
126 return alpha ? WL_DRM_FORMAT_XRGB1555 : WL_DRM_FORMAT_XRGB1555;
127 #endif
128 case VK_FORMAT_B8G8R8_UNORM:
129 case VK_FORMAT_B8G8R8_SRGB:
130 return WL_DRM_FORMAT_BGRX8888;
131 case VK_FORMAT_B8G8R8A8_UNORM:
132 case VK_FORMAT_B8G8R8A8_SRGB:
133 return alpha ? WL_DRM_FORMAT_ARGB8888 : WL_DRM_FORMAT_XRGB8888;
134 #if 0
135 case VK_FORMAT_B10G10R10A2_UNORM:
136 return alpha ? WL_DRM_FORMAT_ARGB2101010 : WL_DRM_FORMAT_XRGB2101010;
137 #endif
138
139 default:
140 assert(!"Unsupported Vulkan format");
141 return 0;
142 }
143 }
144
145 static void
146 drm_handle_format(void *data, struct wl_drm *drm, uint32_t wl_format)
147 {
148 struct wsi_wl_display *display = data;
149
150 switch (wl_format) {
151 #if 0
152 case WL_DRM_FORMAT_ABGR4444:
153 case WL_DRM_FORMAT_XBGR4444:
154 wsi_wl_display_add_vk_format(display, VK_FORMAT_R4G4B4A4_UNORM);
155 break;
156 case WL_DRM_FORMAT_BGR565:
157 wsi_wl_display_add_vk_format(display, VK_FORMAT_R5G6B5_UNORM);
158 break;
159 case WL_DRM_FORMAT_ABGR1555:
160 case WL_DRM_FORMAT_XBGR1555:
161 wsi_wl_display_add_vk_format(display, VK_FORMAT_R5G5B5A1_UNORM);
162 break;
163 case WL_DRM_FORMAT_XBGR8888:
164 wsi_wl_display_add_vk_format(display, VK_FORMAT_R8G8B8_UNORM);
165 /* fallthrough */
166 case WL_DRM_FORMAT_ABGR8888:
167 wsi_wl_display_add_vk_format(display, VK_FORMAT_R8G8B8A8_UNORM);
168 break;
169 case WL_DRM_FORMAT_ABGR2101010:
170 case WL_DRM_FORMAT_XBGR2101010:
171 wsi_wl_display_add_vk_format(display, VK_FORMAT_R10G10B10A2_UNORM);
172 break;
173 case WL_DRM_FORMAT_ARGB4444:
174 case WL_DRM_FORMAT_XRGB4444:
175 wsi_wl_display_add_vk_format(display, VK_FORMAT_B4G4R4A4_UNORM);
176 break;
177 case WL_DRM_FORMAT_RGB565:
178 wsi_wl_display_add_vk_format(display, VK_FORMAT_B5G6R5_UNORM);
179 break;
180 case WL_DRM_FORMAT_ARGB1555:
181 case WL_DRM_FORMAT_XRGB1555:
182 wsi_wl_display_add_vk_format(display, VK_FORMAT_B5G5R5A1_UNORM);
183 break;
184 #endif
185 case WL_DRM_FORMAT_XRGB8888:
186 wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8_SRGB);
187 wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8_UNORM);
188 /* fallthrough */
189 case WL_DRM_FORMAT_ARGB8888:
190 wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8A8_SRGB);
191 wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8A8_UNORM);
192 break;
193 #if 0
194 case WL_DRM_FORMAT_ARGB2101010:
195 case WL_DRM_FORMAT_XRGB2101010:
196 wsi_wl_display_add_vk_format(display, VK_FORMAT_B10G10R10A2_UNORM);
197 break;
198 #endif
199 }
200 }
201
202 static void
203 drm_handle_authenticated(void *data, struct wl_drm *drm)
204 {
205 }
206
207 static void
208 drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t capabilities)
209 {
210 struct wsi_wl_display *display = data;
211
212 display->capabilities = capabilities;
213 }
214
215 static const struct wl_drm_listener drm_listener = {
216 drm_handle_device,
217 drm_handle_format,
218 drm_handle_authenticated,
219 drm_handle_capabilities,
220 };
221
222 static void
223 registry_handle_global(void *data, struct wl_registry *registry,
224 uint32_t name, const char *interface, uint32_t version)
225 {
226 struct wsi_wl_display *display = data;
227
228 if (strcmp(interface, "wl_drm") == 0) {
229 assert(display->drm == NULL);
230
231 assert(version >= 2);
232 display->drm = wl_registry_bind(registry, name, &wl_drm_interface, 2);
233
234 if (display->drm)
235 wl_drm_add_listener(display->drm, &drm_listener, display);
236 }
237 }
238
239 static void
240 registry_handle_global_remove(void *data, struct wl_registry *registry,
241 uint32_t name)
242 { /* No-op */ }
243
244 static const struct wl_registry_listener registry_listener = {
245 registry_handle_global,
246 registry_handle_global_remove
247 };
248
249 static void
250 wsi_wl_display_destroy(struct wsi_wayland *wsi, struct wsi_wl_display *display)
251 {
252 u_vector_finish(&display->formats);
253 if (display->drm)
254 wl_drm_destroy(display->drm);
255 vk_free(wsi->alloc, display);
256 }
257
258 static struct wsi_wl_display *
259 wsi_wl_display_create(struct wsi_wayland *wsi, struct wl_display *wl_display)
260 {
261 struct wsi_wl_display *display =
262 vk_alloc(wsi->alloc, sizeof(*display), 8,
263 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
264 if (!display)
265 return NULL;
266
267 memset(display, 0, sizeof(*display));
268
269 display->display = wl_display;
270 display->wsi_wl = wsi;
271
272 if (!u_vector_init(&display->formats, sizeof(VkFormat), 8))
273 goto fail;
274
275 struct wl_registry *registry = wl_display_get_registry(wl_display);
276 if (!registry)
277 return NULL;
278
279 wl_registry_add_listener(registry, &registry_listener, display);
280
281 /* Round-rip to get the wl_drm global */
282 wl_display_roundtrip(wl_display);
283
284 if (!display->drm)
285 goto fail;
286
287 /* Round-rip to get wl_drm formats and capabilities */
288 wl_display_roundtrip(wl_display);
289
290 /* We need prime support */
291 if (!(display->capabilities & WL_DRM_CAPABILITY_PRIME))
292 goto fail;
293
294 /* We don't need this anymore */
295 wl_registry_destroy(registry);
296
297 return display;
298
299 fail:
300 if (registry)
301 wl_registry_destroy(registry);
302
303 wsi_wl_display_destroy(wsi, display);
304 return NULL;
305 }
306
307 static struct wsi_wl_display *
308 wsi_wl_get_display(struct wsi_device *wsi_device,
309 struct wl_display *wl_display)
310 {
311 struct wsi_wayland *wsi =
312 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
313
314 pthread_mutex_lock(&wsi->mutex);
315
316 struct hash_entry *entry = _mesa_hash_table_search(wsi->displays,
317 wl_display);
318 if (!entry) {
319 /* We're about to make a bunch of blocking calls. Let's drop the
320 * mutex for now so we don't block up too badly.
321 */
322 pthread_mutex_unlock(&wsi->mutex);
323
324 struct wsi_wl_display *display = wsi_wl_display_create(wsi, wl_display);
325
326 pthread_mutex_lock(&wsi->mutex);
327
328 entry = _mesa_hash_table_search(wsi->displays, wl_display);
329 if (entry) {
330 /* Oops, someone raced us to it */
331 wsi_wl_display_destroy(wsi, display);
332 } else {
333 entry = _mesa_hash_table_insert(wsi->displays, wl_display, display);
334 }
335 }
336
337 pthread_mutex_unlock(&wsi->mutex);
338
339 return entry->data;
340 }
341
342 VkBool32
343 wsi_wl_get_presentation_support(struct wsi_device *wsi_device,
344 struct wl_display *wl_display)
345 {
346 return wsi_wl_get_display(wsi_device, wl_display) != NULL;
347 }
348
349 static VkResult
350 wsi_wl_surface_get_support(VkIcdSurfaceBase *surface,
351 struct wsi_device *wsi_device,
352 const VkAllocationCallbacks *alloc,
353 uint32_t queueFamilyIndex,
354 VkBool32* pSupported)
355 {
356 *pSupported = true;
357
358 return VK_SUCCESS;
359 }
360
361 static const VkPresentModeKHR present_modes[] = {
362 VK_PRESENT_MODE_MAILBOX_KHR,
363 VK_PRESENT_MODE_FIFO_KHR,
364 };
365
366 static VkResult
367 wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface,
368 VkSurfaceCapabilitiesKHR* caps)
369 {
370 caps->minImageCount = MIN_NUM_IMAGES;
371 caps->maxImageCount = 4;
372 caps->currentExtent = (VkExtent2D) { -1, -1 };
373 caps->minImageExtent = (VkExtent2D) { 1, 1 };
374 caps->maxImageExtent = (VkExtent2D) { INT16_MAX, INT16_MAX };
375 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
376 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
377 caps->maxImageArrayLayers = 1;
378
379 caps->supportedCompositeAlpha =
380 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
381 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
382
383 caps->supportedUsageFlags =
384 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
385 VK_IMAGE_USAGE_SAMPLED_BIT |
386 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
387 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
388
389 return VK_SUCCESS;
390 }
391
392 static VkResult
393 wsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface,
394 struct wsi_device *wsi_device,
395 uint32_t* pSurfaceFormatCount,
396 VkSurfaceFormatKHR* pSurfaceFormats)
397 {
398 VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
399 struct wsi_wl_display *display =
400 wsi_wl_get_display(wsi_device, surface->display);
401
402 uint32_t count = u_vector_length(&display->formats);
403
404 if (pSurfaceFormats == NULL) {
405 *pSurfaceFormatCount = count;
406 return VK_SUCCESS;
407 }
408
409 assert(*pSurfaceFormatCount >= count);
410 *pSurfaceFormatCount = count;
411
412 VkFormat *f;
413 u_vector_foreach(f, &display->formats) {
414 *(pSurfaceFormats++) = (VkSurfaceFormatKHR) {
415 .format = *f,
416 /* TODO: We should get this from the compositor somehow */
417 .colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR,
418 };
419 }
420
421 return VK_SUCCESS;
422 }
423
424 static VkResult
425 wsi_wl_surface_get_present_modes(VkIcdSurfaceBase *surface,
426 uint32_t* pPresentModeCount,
427 VkPresentModeKHR* pPresentModes)
428 {
429 if (pPresentModes == NULL) {
430 *pPresentModeCount = ARRAY_SIZE(present_modes);
431 return VK_SUCCESS;
432 }
433
434 assert(*pPresentModeCount >= ARRAY_SIZE(present_modes));
435 typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
436 *pPresentModeCount = ARRAY_SIZE(present_modes);
437
438 return VK_SUCCESS;
439 }
440
441 VkResult wsi_create_wl_surface(const VkAllocationCallbacks *pAllocator,
442 const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
443 VkSurfaceKHR *pSurface)
444 {
445 VkIcdSurfaceWayland *surface;
446
447 surface = vk_alloc(pAllocator, sizeof *surface, 8,
448 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
449 if (surface == NULL)
450 return VK_ERROR_OUT_OF_HOST_MEMORY;
451
452 surface->base.platform = VK_ICD_WSI_PLATFORM_WAYLAND;
453 surface->display = pCreateInfo->display;
454 surface->surface = pCreateInfo->surface;
455
456 *pSurface = _VkIcdSurfaceBase_to_handle(&surface->base);
457
458 return VK_SUCCESS;
459 }
460
461 struct wsi_wl_image {
462 VkImage image;
463 VkDeviceMemory memory;
464 struct wl_buffer * buffer;
465 bool busy;
466 };
467
468 struct wsi_wl_swapchain {
469 struct wsi_swapchain base;
470
471 struct wsi_wl_display * display;
472 struct wl_event_queue * queue;
473 struct wl_surface * surface;
474
475 VkExtent2D extent;
476 VkFormat vk_format;
477 uint32_t drm_format;
478
479 VkPresentModeKHR present_mode;
480 bool fifo_ready;
481
482 uint32_t image_count;
483 struct wsi_wl_image images[0];
484 };
485
486 static VkResult
487 wsi_wl_swapchain_get_images(struct wsi_swapchain *wsi_chain,
488 uint32_t *pCount, VkImage *pSwapchainImages)
489 {
490 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
491
492 if (pSwapchainImages == NULL) {
493 *pCount = chain->image_count;
494 return VK_SUCCESS;
495 }
496
497 assert(chain->image_count <= *pCount);
498 for (uint32_t i = 0; i < chain->image_count; i++)
499 pSwapchainImages[i] = chain->images[i].image;
500
501 *pCount = chain->image_count;
502
503 return VK_SUCCESS;
504 }
505
506 static VkResult
507 wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain,
508 uint64_t timeout,
509 VkSemaphore semaphore,
510 uint32_t *image_index)
511 {
512 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
513
514 int ret = wl_display_dispatch_queue_pending(chain->display->display,
515 chain->queue);
516 /* XXX: I'm not sure if out-of-date is the right error here. If
517 * wl_display_dispatch_queue_pending fails it most likely means we got
518 * kicked by the server so this seems more-or-less correct.
519 */
520 if (ret < 0)
521 return VK_ERROR_OUT_OF_DATE_KHR;
522
523 while (1) {
524 for (uint32_t i = 0; i < chain->image_count; i++) {
525 if (!chain->images[i].busy) {
526 /* We found a non-busy image */
527 *image_index = i;
528 chain->images[i].busy = true;
529 return VK_SUCCESS;
530 }
531 }
532
533 /* This time we do a blocking dispatch because we can't go
534 * anywhere until we get an event.
535 */
536 int ret = wl_display_roundtrip_queue(chain->display->display,
537 chain->queue);
538 if (ret < 0)
539 return VK_ERROR_OUT_OF_DATE_KHR;
540 }
541 }
542
543 static void
544 frame_handle_done(void *data, struct wl_callback *callback, uint32_t serial)
545 {
546 struct wsi_wl_swapchain *chain = data;
547
548 chain->fifo_ready = true;
549
550 wl_callback_destroy(callback);
551 }
552
553 static const struct wl_callback_listener frame_listener = {
554 frame_handle_done,
555 };
556
557 static VkResult
558 wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain,
559 uint32_t image_index)
560 {
561 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
562
563 if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {
564 while (!chain->fifo_ready) {
565 int ret = wl_display_dispatch_queue(chain->display->display,
566 chain->queue);
567 if (ret < 0)
568 return VK_ERROR_OUT_OF_DATE_KHR;
569 }
570 }
571
572 assert(image_index < chain->image_count);
573 wl_surface_attach(chain->surface, chain->images[image_index].buffer, 0, 0);
574 wl_surface_damage(chain->surface, 0, 0, INT32_MAX, INT32_MAX);
575
576 if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {
577 struct wl_callback *frame = wl_surface_frame(chain->surface);
578 wl_proxy_set_queue((struct wl_proxy *)frame, chain->queue);
579 wl_callback_add_listener(frame, &frame_listener, chain);
580 chain->fifo_ready = false;
581 }
582
583 chain->images[image_index].busy = true;
584 wl_surface_commit(chain->surface);
585 wl_display_flush(chain->display->display);
586
587 return VK_SUCCESS;
588 }
589
590 static void
591 buffer_handle_release(void *data, struct wl_buffer *buffer)
592 {
593 struct wsi_wl_image *image = data;
594
595 assert(image->buffer == buffer);
596
597 image->busy = false;
598 }
599
600 static const struct wl_buffer_listener buffer_listener = {
601 buffer_handle_release,
602 };
603
604 static VkResult
605 wsi_wl_image_init(struct wsi_wl_swapchain *chain,
606 struct wsi_wl_image *image,
607 const VkSwapchainCreateInfoKHR *pCreateInfo,
608 const VkAllocationCallbacks* pAllocator)
609 {
610 VkDevice vk_device = chain->base.device;
611 VkResult result;
612 int fd;
613 uint32_t size;
614 uint32_t row_pitch;
615 uint32_t offset;
616 result = chain->base.image_fns->create_wsi_image(vk_device,
617 pCreateInfo,
618 pAllocator,
619 &image->image,
620 &image->memory,
621 &size,
622 &offset,
623 &row_pitch,
624 &fd);
625 if (result != VK_SUCCESS)
626 return result;
627
628 image->buffer = wl_drm_create_prime_buffer(chain->display->drm,
629 fd, /* name */
630 chain->extent.width,
631 chain->extent.height,
632 chain->drm_format,
633 offset,
634 row_pitch,
635 0, 0, 0, 0 /* unused */);
636 wl_display_roundtrip(chain->display->display);
637 close(fd);
638
639 if (!image->buffer)
640 goto fail_image;
641
642 wl_proxy_set_queue((struct wl_proxy *)image->buffer, chain->queue);
643 wl_buffer_add_listener(image->buffer, &buffer_listener, image);
644
645 return VK_SUCCESS;
646
647 fail_image:
648 chain->base.image_fns->free_wsi_image(vk_device, pAllocator,
649 image->image, image->memory);
650
651 return result;
652 }
653
654 static VkResult
655 wsi_wl_swapchain_destroy(struct wsi_swapchain *wsi_chain,
656 const VkAllocationCallbacks *pAllocator)
657 {
658 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
659
660 for (uint32_t i = 0; i < chain->image_count; i++) {
661 if (chain->images[i].buffer)
662 chain->base.image_fns->free_wsi_image(chain->base.device, pAllocator,
663 chain->images[i].image,
664 chain->images[i].memory);
665 }
666
667 vk_free(pAllocator, chain);
668
669 return VK_SUCCESS;
670 }
671
672 static VkResult
673 wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
674 VkDevice device,
675 struct wsi_device *wsi_device,
676 const VkSwapchainCreateInfoKHR* pCreateInfo,
677 const VkAllocationCallbacks* pAllocator,
678 const struct wsi_image_fns *image_fns,
679 struct wsi_swapchain **swapchain_out)
680 {
681 VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
682 struct wsi_wl_swapchain *chain;
683 VkResult result;
684
685 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
686
687 int num_images = pCreateInfo->minImageCount;
688
689 assert(num_images >= MIN_NUM_IMAGES);
690
691 /* For true mailbox mode, we need at least 4 images:
692 * 1) One to scan out from
693 * 2) One to have queued for scan-out
694 * 3) One to be currently held by the Wayland compositor
695 * 4) One to render to
696 */
697 if (pCreateInfo->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
698 num_images = MAX2(num_images, 4);
699
700 size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
701 chain = vk_alloc(pAllocator, size, 8,
702 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
703 if (chain == NULL)
704 return VK_ERROR_OUT_OF_HOST_MEMORY;
705
706 bool alpha = pCreateInfo->compositeAlpha ==
707 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
708
709 chain->base.device = device;
710 chain->base.destroy = wsi_wl_swapchain_destroy;
711 chain->base.get_images = wsi_wl_swapchain_get_images;
712 chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image;
713 chain->base.queue_present = wsi_wl_swapchain_queue_present;
714 chain->base.image_fns = image_fns;
715 chain->base.present_mode = pCreateInfo->presentMode;
716 chain->surface = surface->surface;
717 chain->extent = pCreateInfo->imageExtent;
718 chain->vk_format = pCreateInfo->imageFormat;
719 chain->drm_format = wl_drm_format_for_vk_format(chain->vk_format, alpha);
720
721 chain->fifo_ready = true;
722
723 chain->image_count = num_images;
724
725 /* Mark a bunch of stuff as NULL. This way we can just call
726 * destroy_swapchain for cleanup.
727 */
728 for (uint32_t i = 0; i < chain->image_count; i++)
729 chain->images[i].buffer = NULL;
730 chain->queue = NULL;
731
732 chain->display = wsi_wl_get_display(wsi_device,
733 surface->display);
734 if (!chain->display) {
735 result = VK_ERROR_INITIALIZATION_FAILED;
736 goto fail;
737 }
738
739 chain->queue = wl_display_create_queue(chain->display->display);
740 if (!chain->queue) {
741 result = VK_ERROR_INITIALIZATION_FAILED;
742 goto fail;
743 }
744
745 for (uint32_t i = 0; i < chain->image_count; i++) {
746 result = wsi_wl_image_init(chain, &chain->images[i],
747 pCreateInfo, pAllocator);
748 if (result != VK_SUCCESS)
749 goto fail;
750 chain->images[i].busy = false;
751 }
752
753 *swapchain_out = &chain->base;
754
755 return VK_SUCCESS;
756
757 fail:
758 wsi_wl_swapchain_destroy(&chain->base, pAllocator);
759
760 return result;
761 }
762
763 VkResult
764 wsi_wl_init_wsi(struct wsi_device *wsi_device,
765 const VkAllocationCallbacks *alloc,
766 VkPhysicalDevice physical_device,
767 const struct wsi_callbacks *cbs)
768 {
769 struct wsi_wayland *wsi;
770 VkResult result;
771
772 wsi = vk_alloc(alloc, sizeof(*wsi), 8,
773 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
774 if (!wsi) {
775 result = VK_ERROR_OUT_OF_HOST_MEMORY;
776 goto fail;
777 }
778
779 wsi->physical_device = physical_device;
780 wsi->alloc = alloc;
781 wsi->cbs = cbs;
782 int ret = pthread_mutex_init(&wsi->mutex, NULL);
783 if (ret != 0) {
784 if (ret == ENOMEM) {
785 result = VK_ERROR_OUT_OF_HOST_MEMORY;
786 } else {
787 /* FINISHME: Choose a better error. */
788 result = VK_ERROR_OUT_OF_HOST_MEMORY;
789 }
790
791 goto fail_alloc;
792 }
793
794 wsi->displays = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
795 _mesa_key_pointer_equal);
796 if (!wsi->displays) {
797 result = VK_ERROR_OUT_OF_HOST_MEMORY;
798 goto fail_mutex;
799 }
800
801 wsi->base.get_support = wsi_wl_surface_get_support;
802 wsi->base.get_capabilities = wsi_wl_surface_get_capabilities;
803 wsi->base.get_formats = wsi_wl_surface_get_formats;
804 wsi->base.get_present_modes = wsi_wl_surface_get_present_modes;
805 wsi->base.create_swapchain = wsi_wl_surface_create_swapchain;
806
807 wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base;
808
809 return VK_SUCCESS;
810
811 fail_mutex:
812 pthread_mutex_destroy(&wsi->mutex);
813
814 fail_alloc:
815 vk_free(alloc, wsi);
816 fail:
817 wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = NULL;
818
819 return result;
820 }
821
822 void
823 wsi_wl_finish_wsi(struct wsi_device *wsi_device,
824 const VkAllocationCallbacks *alloc)
825 {
826 struct wsi_wayland *wsi =
827 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
828
829 if (wsi) {
830 _mesa_hash_table_destroy(wsi->displays, NULL);
831
832 pthread_mutex_destroy(&wsi->mutex);
833
834 vk_free(alloc, wsi);
835 }
836 }