vulkan/wsi: free cmd pools
[mesa.git] / src / vulkan / wsi / wsi_common.c
1 /*
2 * Copyright © 2017 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 "wsi_common_private.h"
25 #include "util/macros.h"
26 #include "vk_util.h"
27
28 VkResult
29 wsi_device_init(struct wsi_device *wsi,
30 VkPhysicalDevice pdevice,
31 WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
32 const VkAllocationCallbacks *alloc)
33 {
34 VkResult result;
35
36 memset(wsi, 0, sizeof(*wsi));
37
38 #define WSI_GET_CB(func) \
39 PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
40 WSI_GET_CB(GetPhysicalDeviceMemoryProperties);
41 WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties);
42 #undef WSI_GET_CB
43
44 GetPhysicalDeviceMemoryProperties(pdevice, &wsi->memory_props);
45 GetPhysicalDeviceQueueFamilyProperties(pdevice, &wsi->queue_family_count, NULL);
46
47 #define WSI_GET_CB(func) \
48 wsi->func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
49 WSI_GET_CB(AllocateMemory);
50 WSI_GET_CB(AllocateCommandBuffers);
51 WSI_GET_CB(BindBufferMemory);
52 WSI_GET_CB(BindImageMemory);
53 WSI_GET_CB(BeginCommandBuffer);
54 WSI_GET_CB(CmdCopyImageToBuffer);
55 WSI_GET_CB(CreateBuffer);
56 WSI_GET_CB(CreateCommandPool);
57 WSI_GET_CB(CreateFence);
58 WSI_GET_CB(CreateImage);
59 WSI_GET_CB(DestroyBuffer);
60 WSI_GET_CB(DestroyCommandPool);
61 WSI_GET_CB(DestroyFence);
62 WSI_GET_CB(DestroyImage);
63 WSI_GET_CB(EndCommandBuffer);
64 WSI_GET_CB(FreeMemory);
65 WSI_GET_CB(FreeCommandBuffers);
66 WSI_GET_CB(GetBufferMemoryRequirements);
67 WSI_GET_CB(GetImageMemoryRequirements);
68 WSI_GET_CB(GetImageSubresourceLayout);
69 WSI_GET_CB(GetMemoryFdKHR);
70 WSI_GET_CB(GetPhysicalDeviceFormatProperties);
71 WSI_GET_CB(ResetFences);
72 WSI_GET_CB(QueueSubmit);
73 WSI_GET_CB(WaitForFences);
74 #undef WSI_GET_CB
75
76 #ifdef VK_USE_PLATFORM_XCB_KHR
77 result = wsi_x11_init_wsi(wsi, alloc);
78 if (result != VK_SUCCESS)
79 return result;
80 #endif
81
82 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
83 result = wsi_wl_init_wsi(wsi, alloc, pdevice);
84 if (result != VK_SUCCESS) {
85 #ifdef VK_USE_PLATFORM_XCB_KHR
86 wsi_x11_finish_wsi(wsi, alloc);
87 #endif
88 return result;
89 }
90 #endif
91
92 return VK_SUCCESS;
93 }
94
95 void
96 wsi_device_finish(struct wsi_device *wsi,
97 const VkAllocationCallbacks *alloc)
98 {
99 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
100 wsi_wl_finish_wsi(wsi, alloc);
101 #endif
102 #ifdef VK_USE_PLATFORM_XCB_KHR
103 wsi_x11_finish_wsi(wsi, alloc);
104 #endif
105 }
106
107 VkResult
108 wsi_swapchain_init(const struct wsi_device *wsi,
109 struct wsi_swapchain *chain,
110 VkDevice device,
111 const VkSwapchainCreateInfoKHR *pCreateInfo,
112 const VkAllocationCallbacks *pAllocator)
113 {
114 VkResult result;
115
116 memset(chain, 0, sizeof(*chain));
117
118 chain->wsi = wsi;
119 chain->device = device;
120 chain->alloc = *pAllocator;
121 chain->use_prime_blit = false;
122
123 chain->cmd_pools =
124 vk_zalloc(pAllocator, sizeof(VkCommandPool) * wsi->queue_family_count, 8,
125 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
126 if (!chain->cmd_pools)
127 return VK_ERROR_OUT_OF_HOST_MEMORY;
128
129 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
130 const VkCommandPoolCreateInfo cmd_pool_info = {
131 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
132 .pNext = NULL,
133 .flags = 0,
134 .queueFamilyIndex = i,
135 };
136 result = wsi->CreateCommandPool(device, &cmd_pool_info, &chain->alloc,
137 &chain->cmd_pools[i]);
138 if (result != VK_SUCCESS)
139 goto fail;
140 }
141
142 return VK_SUCCESS;
143
144 fail:
145 wsi_swapchain_finish(chain);
146 return result;
147 }
148
149 void
150 wsi_swapchain_finish(struct wsi_swapchain *chain)
151 {
152 for (unsigned i = 0; i < ARRAY_SIZE(chain->fences); i++)
153 chain->wsi->DestroyFence(chain->device, chain->fences[i], &chain->alloc);
154
155 for (uint32_t i = 0; i < chain->wsi->queue_family_count; i++) {
156 chain->wsi->DestroyCommandPool(chain->device, chain->cmd_pools[i],
157 &chain->alloc);
158 }
159 vk_free(&chain->alloc, chain->cmd_pools);
160 }
161
162 static uint32_t
163 select_memory_type(const struct wsi_device *wsi,
164 VkMemoryPropertyFlags props,
165 uint32_t type_bits)
166 {
167 for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) {
168 const VkMemoryType type = wsi->memory_props.memoryTypes[i];
169 if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props)
170 return i;
171 }
172
173 unreachable("No memory type found");
174 }
175
176 static uint32_t
177 vk_format_size(VkFormat format)
178 {
179 switch (format) {
180 case VK_FORMAT_B8G8R8A8_UNORM:
181 case VK_FORMAT_B8G8R8A8_SRGB:
182 return 4;
183 default:
184 unreachable("Unknown WSI Format");
185 }
186 }
187
188 static inline uint32_t
189 align_u32(uint32_t v, uint32_t a)
190 {
191 assert(a != 0 && a == (a & -a));
192 return (v + a - 1) & ~(a - 1);
193 }
194
195 VkResult
196 wsi_create_native_image(const struct wsi_swapchain *chain,
197 const VkSwapchainCreateInfoKHR *pCreateInfo,
198 struct wsi_image *image)
199 {
200 const struct wsi_device *wsi = chain->wsi;
201 VkResult result;
202
203 memset(image, 0, sizeof(*image));
204
205 const struct wsi_image_create_info image_wsi_info = {
206 .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA,
207 .pNext = NULL,
208 .scanout = true,
209 };
210 const VkImageCreateInfo image_info = {
211 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
212 .pNext = &image_wsi_info,
213 .flags = 0,
214 .imageType = VK_IMAGE_TYPE_2D,
215 .format = pCreateInfo->imageFormat,
216 .extent = {
217 .width = pCreateInfo->imageExtent.width,
218 .height = pCreateInfo->imageExtent.height,
219 .depth = 1,
220 },
221 .mipLevels = 1,
222 .arrayLayers = 1,
223 .samples = VK_SAMPLE_COUNT_1_BIT,
224 .tiling = VK_IMAGE_TILING_OPTIMAL,
225 .usage = pCreateInfo->imageUsage,
226 .sharingMode = pCreateInfo->imageSharingMode,
227 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
228 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
229 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
230 };
231 result = wsi->CreateImage(chain->device, &image_info,
232 &chain->alloc, &image->image);
233 if (result != VK_SUCCESS)
234 goto fail;
235
236 VkMemoryRequirements reqs;
237 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
238
239 VkSubresourceLayout image_layout;
240 const VkImageSubresource image_subresource = {
241 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
242 .mipLevel = 0,
243 .arrayLayer = 0,
244 };
245 wsi->GetImageSubresourceLayout(chain->device, image->image,
246 &image_subresource, &image_layout);
247
248 const struct wsi_memory_allocate_info memory_wsi_info = {
249 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
250 .pNext = NULL,
251 .implicit_sync = true,
252 };
253 const VkExportMemoryAllocateInfoKHR memory_export_info = {
254 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
255 .pNext = &memory_wsi_info,
256 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
257 };
258 const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = {
259 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
260 .pNext = &memory_export_info,
261 .image = image->image,
262 .buffer = VK_NULL_HANDLE,
263 };
264 const VkMemoryAllocateInfo memory_info = {
265 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
266 .pNext = &memory_dedicated_info,
267 .allocationSize = reqs.size,
268 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
269 reqs.memoryTypeBits),
270 };
271 result = wsi->AllocateMemory(chain->device, &memory_info,
272 &chain->alloc, &image->memory);
273 if (result != VK_SUCCESS)
274 goto fail;
275
276 result = wsi->BindImageMemory(chain->device, image->image,
277 image->memory, 0);
278 if (result != VK_SUCCESS)
279 goto fail;
280
281 const VkMemoryGetFdInfoKHR memory_get_fd_info = {
282 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
283 .pNext = NULL,
284 .memory = image->memory,
285 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
286 };
287 int fd;
288 result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd);
289 if (result != VK_SUCCESS)
290 goto fail;
291
292 image->size = reqs.size;
293 image->row_pitch = image_layout.rowPitch;
294 image->offset = 0;
295 image->fd = fd;
296
297 return VK_SUCCESS;
298
299 fail:
300 wsi_destroy_image(chain, image);
301
302 return result;
303 }
304
305 #define WSI_PRIME_LINEAR_STRIDE_ALIGN 256
306
307 VkResult
308 wsi_create_prime_image(const struct wsi_swapchain *chain,
309 const VkSwapchainCreateInfoKHR *pCreateInfo,
310 struct wsi_image *image)
311 {
312 const struct wsi_device *wsi = chain->wsi;
313 VkResult result;
314
315 memset(image, 0, sizeof(*image));
316
317 const uint32_t cpp = vk_format_size(pCreateInfo->imageFormat);
318 const uint32_t linear_stride = align_u32(pCreateInfo->imageExtent.width * cpp,
319 WSI_PRIME_LINEAR_STRIDE_ALIGN);
320
321 uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height;
322 linear_size = align_u32(linear_size, 4096);
323
324 const VkExternalMemoryBufferCreateInfoKHR prime_buffer_external_info = {
325 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR,
326 .pNext = NULL,
327 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
328 };
329 const VkBufferCreateInfo prime_buffer_info = {
330 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
331 .pNext = &prime_buffer_external_info,
332 .size = linear_size,
333 .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
334 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
335 };
336 result = wsi->CreateBuffer(chain->device, &prime_buffer_info,
337 &chain->alloc, &image->prime.buffer);
338 if (result != VK_SUCCESS)
339 goto fail;
340
341 VkMemoryRequirements reqs;
342 wsi->GetBufferMemoryRequirements(chain->device, image->prime.buffer, &reqs);
343 assert(reqs.size <= linear_size);
344
345 const struct wsi_memory_allocate_info memory_wsi_info = {
346 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
347 .pNext = NULL,
348 .implicit_sync = true,
349 };
350 const VkExportMemoryAllocateInfoKHR prime_memory_export_info = {
351 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
352 .pNext = &memory_wsi_info,
353 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
354 };
355 const VkMemoryDedicatedAllocateInfoKHR prime_memory_dedicated_info = {
356 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
357 .pNext = &prime_memory_export_info,
358 .image = VK_NULL_HANDLE,
359 .buffer = image->prime.buffer,
360 };
361 const VkMemoryAllocateInfo prime_memory_info = {
362 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
363 .pNext = &prime_memory_dedicated_info,
364 .allocationSize = linear_size,
365 .memoryTypeIndex = select_memory_type(wsi, 0, reqs.memoryTypeBits),
366 };
367 result = wsi->AllocateMemory(chain->device, &prime_memory_info,
368 &chain->alloc, &image->prime.memory);
369 if (result != VK_SUCCESS)
370 goto fail;
371
372 result = wsi->BindBufferMemory(chain->device, image->prime.buffer,
373 image->prime.memory, 0);
374 if (result != VK_SUCCESS)
375 goto fail;
376
377 const VkImageCreateInfo image_info = {
378 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
379 .pNext = NULL,
380 .flags = 0,
381 .imageType = VK_IMAGE_TYPE_2D,
382 .format = pCreateInfo->imageFormat,
383 .extent = {
384 .width = pCreateInfo->imageExtent.width,
385 .height = pCreateInfo->imageExtent.height,
386 .depth = 1,
387 },
388 .mipLevels = 1,
389 .arrayLayers = 1,
390 .samples = VK_SAMPLE_COUNT_1_BIT,
391 .tiling = VK_IMAGE_TILING_OPTIMAL,
392 .usage = pCreateInfo->imageUsage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
393 .sharingMode = pCreateInfo->imageSharingMode,
394 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
395 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
396 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
397 };
398 result = wsi->CreateImage(chain->device, &image_info,
399 &chain->alloc, &image->image);
400 if (result != VK_SUCCESS)
401 goto fail;
402
403 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
404
405 const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = {
406 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
407 .pNext = NULL,
408 .image = image->image,
409 .buffer = VK_NULL_HANDLE,
410 };
411 const VkMemoryAllocateInfo memory_info = {
412 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
413 .pNext = &memory_dedicated_info,
414 .allocationSize = reqs.size,
415 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
416 reqs.memoryTypeBits),
417 };
418 result = wsi->AllocateMemory(chain->device, &memory_info,
419 &chain->alloc, &image->memory);
420 if (result != VK_SUCCESS)
421 goto fail;
422
423 result = wsi->BindImageMemory(chain->device, image->image,
424 image->memory, 0);
425 if (result != VK_SUCCESS)
426 goto fail;
427
428 image->prime.blit_cmd_buffers =
429 vk_zalloc(&chain->alloc,
430 sizeof(VkCommandBuffer) * wsi->queue_family_count, 8,
431 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
432 if (!image->prime.blit_cmd_buffers)
433 goto fail;
434
435 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
436 const VkCommandBufferAllocateInfo cmd_buffer_info = {
437 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
438 .pNext = NULL,
439 .commandPool = chain->cmd_pools[i],
440 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
441 .commandBufferCount = 1,
442 };
443 result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info,
444 &image->prime.blit_cmd_buffers[i]);
445 if (result != VK_SUCCESS)
446 goto fail;
447
448 const VkCommandBufferBeginInfo begin_info = {
449 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
450 };
451 wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info);
452
453 struct VkBufferImageCopy buffer_image_copy = {
454 .bufferOffset = 0,
455 .bufferRowLength = linear_stride / cpp,
456 .bufferImageHeight = 0,
457 .imageSubresource = {
458 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
459 .mipLevel = 0,
460 .baseArrayLayer = 0,
461 .layerCount = 1,
462 },
463 .imageOffset = { .x = 0, .y = 0, .z = 0 },
464 .imageExtent = {
465 .width = pCreateInfo->imageExtent.width,
466 .height = pCreateInfo->imageExtent.height,
467 .depth = 1,
468 },
469 };
470 wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i],
471 image->image,
472 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
473 image->prime.buffer,
474 1, &buffer_image_copy);
475
476 result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]);
477 if (result != VK_SUCCESS)
478 goto fail;
479 }
480
481 const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
482 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
483 .pNext = NULL,
484 .memory = image->prime.memory,
485 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
486 };
487 int fd;
488 result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd);
489 if (result != VK_SUCCESS)
490 goto fail;
491
492 image->size = linear_size;
493 image->row_pitch = linear_stride;
494 image->offset = 0;
495 image->fd = fd;
496
497 return VK_SUCCESS;
498
499 fail:
500 wsi_destroy_image(chain, image);
501
502 return result;
503 }
504
505 void
506 wsi_destroy_image(const struct wsi_swapchain *chain,
507 struct wsi_image *image)
508 {
509 const struct wsi_device *wsi = chain->wsi;
510
511 if (image->prime.blit_cmd_buffers) {
512 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
513 wsi->FreeCommandBuffers(chain->device, chain->cmd_pools[i],
514 1, &image->prime.blit_cmd_buffers[i]);
515 }
516 vk_free(&chain->alloc, image->prime.blit_cmd_buffers);
517 }
518
519 wsi->FreeMemory(chain->device, image->memory, &chain->alloc);
520 wsi->DestroyImage(chain->device, image->image, &chain->alloc);
521 wsi->FreeMemory(chain->device, image->prime.memory, &chain->alloc);
522 wsi->DestroyBuffer(chain->device, image->prime.buffer, &chain->alloc);
523 }
524
525 VkResult
526 wsi_common_get_surface_support(struct wsi_device *wsi_device,
527 int local_fd,
528 uint32_t queueFamilyIndex,
529 VkSurfaceKHR _surface,
530 const VkAllocationCallbacks *alloc,
531 VkBool32* pSupported)
532 {
533 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
534 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
535
536 return iface->get_support(surface, wsi_device, alloc,
537 queueFamilyIndex, local_fd, pSupported);
538 }
539
540 VkResult
541 wsi_common_get_surface_capabilities(struct wsi_device *wsi_device,
542 VkSurfaceKHR _surface,
543 VkSurfaceCapabilitiesKHR *pSurfaceCapabilities)
544 {
545 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
546 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
547
548 return iface->get_capabilities(surface, pSurfaceCapabilities);
549 }
550
551 VkResult
552 wsi_common_get_surface_capabilities2(struct wsi_device *wsi_device,
553 const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
554 VkSurfaceCapabilities2KHR *pSurfaceCapabilities)
555 {
556 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
557 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
558
559 return iface->get_capabilities2(surface, pSurfaceInfo->pNext,
560 pSurfaceCapabilities);
561 }
562
563 VkResult
564 wsi_common_get_surface_formats(struct wsi_device *wsi_device,
565 VkSurfaceKHR _surface,
566 uint32_t *pSurfaceFormatCount,
567 VkSurfaceFormatKHR *pSurfaceFormats)
568 {
569 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
570 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
571
572 return iface->get_formats(surface, wsi_device,
573 pSurfaceFormatCount, pSurfaceFormats);
574 }
575
576 VkResult
577 wsi_common_get_surface_formats2(struct wsi_device *wsi_device,
578 const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
579 uint32_t *pSurfaceFormatCount,
580 VkSurfaceFormat2KHR *pSurfaceFormats)
581 {
582 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
583 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
584
585 return iface->get_formats2(surface, wsi_device, pSurfaceInfo->pNext,
586 pSurfaceFormatCount, pSurfaceFormats);
587 }
588
589 VkResult
590 wsi_common_get_surface_present_modes(struct wsi_device *wsi_device,
591 VkSurfaceKHR _surface,
592 uint32_t *pPresentModeCount,
593 VkPresentModeKHR *pPresentModes)
594 {
595 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
596 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
597
598 return iface->get_present_modes(surface, pPresentModeCount,
599 pPresentModes);
600 }
601
602 VkResult
603 wsi_common_create_swapchain(struct wsi_device *wsi,
604 VkDevice device,
605 int fd,
606 const VkSwapchainCreateInfoKHR *pCreateInfo,
607 const VkAllocationCallbacks *pAllocator,
608 VkSwapchainKHR *pSwapchain)
609 {
610 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface);
611 struct wsi_interface *iface = wsi->wsi[surface->platform];
612 struct wsi_swapchain *swapchain;
613
614 VkResult result = iface->create_swapchain(surface, device, wsi, fd,
615 pCreateInfo, pAllocator,
616 &swapchain);
617 if (result != VK_SUCCESS)
618 return result;
619
620 *pSwapchain = wsi_swapchain_to_handle(swapchain);
621
622 return VK_SUCCESS;
623 }
624
625 void
626 wsi_common_destroy_swapchain(VkDevice device,
627 VkSwapchainKHR _swapchain,
628 const VkAllocationCallbacks *pAllocator)
629 {
630 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
631 if (!swapchain)
632 return;
633
634 swapchain->destroy(swapchain, pAllocator);
635 }
636
637 VkResult
638 wsi_common_get_images(VkSwapchainKHR _swapchain,
639 uint32_t *pSwapchainImageCount,
640 VkImage *pSwapchainImages)
641 {
642 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
643 VK_OUTARRAY_MAKE(images, pSwapchainImages, pSwapchainImageCount);
644
645 for (uint32_t i = 0; i < swapchain->image_count; i++) {
646 vk_outarray_append(&images, image) {
647 *image = swapchain->get_wsi_image(swapchain, i)->image;
648 }
649 }
650
651 return vk_outarray_status(&images);
652 }
653
654 VkResult
655 wsi_common_acquire_next_image(const struct wsi_device *wsi,
656 VkDevice device,
657 VkSwapchainKHR _swapchain,
658 uint64_t timeout,
659 VkSemaphore semaphore,
660 uint32_t *pImageIndex)
661 {
662 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
663
664 return swapchain->acquire_next_image(swapchain, timeout,
665 semaphore, pImageIndex);
666 }
667
668 VkResult
669 wsi_common_queue_present(const struct wsi_device *wsi,
670 VkDevice device,
671 VkQueue queue,
672 int queue_family_index,
673 const VkPresentInfoKHR *pPresentInfo)
674 {
675 VkResult final_result = VK_SUCCESS;
676
677 const VkPresentRegionsKHR *regions =
678 vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR);
679
680 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
681 WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]);
682 VkResult result;
683
684 if (swapchain->fences[0] == VK_NULL_HANDLE) {
685 const VkFenceCreateInfo fence_info = {
686 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
687 .pNext = NULL,
688 .flags = 0,
689 };
690 result = wsi->CreateFence(device, &fence_info,
691 &swapchain->alloc,
692 &swapchain->fences[0]);
693 if (result != VK_SUCCESS)
694 goto fail_present;
695 } else {
696 wsi->ResetFences(device, 1, &swapchain->fences[0]);
697 }
698
699 VkSubmitInfo submit_info = {
700 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
701 .pNext = NULL,
702 };
703
704 VkPipelineStageFlags *stage_flags = NULL;
705 if (i == 0) {
706 /* We only need/want to wait on semaphores once. After that, we're
707 * guaranteed ordering since it all happens on the same queue.
708 */
709 submit_info.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount,
710 submit_info.pWaitSemaphores = pPresentInfo->pWaitSemaphores,
711
712 /* Set up the pWaitDstStageMasks */
713 stage_flags = vk_alloc(&swapchain->alloc,
714 sizeof(VkPipelineStageFlags) *
715 pPresentInfo->waitSemaphoreCount,
716 8,
717 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
718 if (!stage_flags) {
719 result = VK_ERROR_OUT_OF_HOST_MEMORY;
720 goto fail_present;
721 }
722 for (uint32_t s = 0; s < pPresentInfo->waitSemaphoreCount; s++)
723 stage_flags[s] = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
724
725 submit_info.pWaitDstStageMask = stage_flags;
726 }
727
728 if (swapchain->use_prime_blit) {
729 /* If we are using prime blits, we need to perform the blit now. The
730 * command buffer is attached to the image.
731 */
732 struct wsi_image *image =
733 swapchain->get_wsi_image(swapchain, pPresentInfo->pImageIndices[i]);
734 submit_info.commandBufferCount = 1;
735 submit_info.pCommandBuffers =
736 &image->prime.blit_cmd_buffers[queue_family_index];
737 }
738
739 result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[0]);
740 vk_free(&swapchain->alloc, stage_flags);
741 if (result != VK_SUCCESS)
742 goto fail_present;
743
744 const VkPresentRegionKHR *region = NULL;
745 if (regions && regions->pRegions)
746 region = &regions->pRegions[i];
747
748 result = swapchain->queue_present(swapchain,
749 pPresentInfo->pImageIndices[i],
750 region);
751 if (result != VK_SUCCESS)
752 goto fail_present;
753
754 VkFence last = swapchain->fences[2];
755 swapchain->fences[2] = swapchain->fences[1];
756 swapchain->fences[1] = swapchain->fences[0];
757 swapchain->fences[0] = last;
758
759 if (last != VK_NULL_HANDLE) {
760 wsi->WaitForFences(device, 1, &last, true, 1);
761 }
762
763 fail_present:
764 if (pPresentInfo->pResults != NULL)
765 pPresentInfo->pResults[i] = result;
766
767 /* Let the final result be our first unsuccessful result */
768 if (final_result == VK_SUCCESS)
769 final_result = result;
770 }
771
772 return final_result;
773 }