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