90ed07b7857a8dd331a0e95899ad572190eaeeda
[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 result = VK_ERROR_OUT_OF_HOST_MEMORY;
434 goto fail;
435 }
436
437 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
438 const VkCommandBufferAllocateInfo cmd_buffer_info = {
439 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
440 .pNext = NULL,
441 .commandPool = chain->cmd_pools[i],
442 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
443 .commandBufferCount = 1,
444 };
445 result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info,
446 &image->prime.blit_cmd_buffers[i]);
447 if (result != VK_SUCCESS)
448 goto fail;
449
450 const VkCommandBufferBeginInfo begin_info = {
451 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
452 };
453 wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info);
454
455 struct VkBufferImageCopy buffer_image_copy = {
456 .bufferOffset = 0,
457 .bufferRowLength = linear_stride / cpp,
458 .bufferImageHeight = 0,
459 .imageSubresource = {
460 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
461 .mipLevel = 0,
462 .baseArrayLayer = 0,
463 .layerCount = 1,
464 },
465 .imageOffset = { .x = 0, .y = 0, .z = 0 },
466 .imageExtent = {
467 .width = pCreateInfo->imageExtent.width,
468 .height = pCreateInfo->imageExtent.height,
469 .depth = 1,
470 },
471 };
472 wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i],
473 image->image,
474 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
475 image->prime.buffer,
476 1, &buffer_image_copy);
477
478 result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]);
479 if (result != VK_SUCCESS)
480 goto fail;
481 }
482
483 const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
484 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
485 .pNext = NULL,
486 .memory = image->prime.memory,
487 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
488 };
489 int fd;
490 result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd);
491 if (result != VK_SUCCESS)
492 goto fail;
493
494 image->size = linear_size;
495 image->row_pitch = linear_stride;
496 image->offset = 0;
497 image->fd = fd;
498
499 return VK_SUCCESS;
500
501 fail:
502 wsi_destroy_image(chain, image);
503
504 return result;
505 }
506
507 void
508 wsi_destroy_image(const struct wsi_swapchain *chain,
509 struct wsi_image *image)
510 {
511 const struct wsi_device *wsi = chain->wsi;
512
513 if (image->prime.blit_cmd_buffers) {
514 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
515 wsi->FreeCommandBuffers(chain->device, chain->cmd_pools[i],
516 1, &image->prime.blit_cmd_buffers[i]);
517 }
518 vk_free(&chain->alloc, image->prime.blit_cmd_buffers);
519 }
520
521 wsi->FreeMemory(chain->device, image->memory, &chain->alloc);
522 wsi->DestroyImage(chain->device, image->image, &chain->alloc);
523 wsi->FreeMemory(chain->device, image->prime.memory, &chain->alloc);
524 wsi->DestroyBuffer(chain->device, image->prime.buffer, &chain->alloc);
525 }
526
527 VkResult
528 wsi_common_get_surface_support(struct wsi_device *wsi_device,
529 int local_fd,
530 uint32_t queueFamilyIndex,
531 VkSurfaceKHR _surface,
532 const VkAllocationCallbacks *alloc,
533 VkBool32* pSupported)
534 {
535 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
536 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
537
538 return iface->get_support(surface, wsi_device, alloc,
539 queueFamilyIndex, local_fd, pSupported);
540 }
541
542 VkResult
543 wsi_common_get_surface_capabilities(struct wsi_device *wsi_device,
544 VkSurfaceKHR _surface,
545 VkSurfaceCapabilitiesKHR *pSurfaceCapabilities)
546 {
547 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
548 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
549
550 return iface->get_capabilities(surface, pSurfaceCapabilities);
551 }
552
553 VkResult
554 wsi_common_get_surface_capabilities2(struct wsi_device *wsi_device,
555 const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
556 VkSurfaceCapabilities2KHR *pSurfaceCapabilities)
557 {
558 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
559 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
560
561 return iface->get_capabilities2(surface, pSurfaceInfo->pNext,
562 pSurfaceCapabilities);
563 }
564
565 VkResult
566 wsi_common_get_surface_formats(struct wsi_device *wsi_device,
567 VkSurfaceKHR _surface,
568 uint32_t *pSurfaceFormatCount,
569 VkSurfaceFormatKHR *pSurfaceFormats)
570 {
571 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
572 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
573
574 return iface->get_formats(surface, wsi_device,
575 pSurfaceFormatCount, pSurfaceFormats);
576 }
577
578 VkResult
579 wsi_common_get_surface_formats2(struct wsi_device *wsi_device,
580 const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
581 uint32_t *pSurfaceFormatCount,
582 VkSurfaceFormat2KHR *pSurfaceFormats)
583 {
584 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
585 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
586
587 return iface->get_formats2(surface, wsi_device, pSurfaceInfo->pNext,
588 pSurfaceFormatCount, pSurfaceFormats);
589 }
590
591 VkResult
592 wsi_common_get_surface_present_modes(struct wsi_device *wsi_device,
593 VkSurfaceKHR _surface,
594 uint32_t *pPresentModeCount,
595 VkPresentModeKHR *pPresentModes)
596 {
597 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
598 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
599
600 return iface->get_present_modes(surface, pPresentModeCount,
601 pPresentModes);
602 }
603
604 VkResult
605 wsi_common_create_swapchain(struct wsi_device *wsi,
606 VkDevice device,
607 int fd,
608 const VkSwapchainCreateInfoKHR *pCreateInfo,
609 const VkAllocationCallbacks *pAllocator,
610 VkSwapchainKHR *pSwapchain)
611 {
612 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface);
613 struct wsi_interface *iface = wsi->wsi[surface->platform];
614 struct wsi_swapchain *swapchain;
615
616 VkResult result = iface->create_swapchain(surface, device, wsi, fd,
617 pCreateInfo, pAllocator,
618 &swapchain);
619 if (result != VK_SUCCESS)
620 return result;
621
622 *pSwapchain = wsi_swapchain_to_handle(swapchain);
623
624 return VK_SUCCESS;
625 }
626
627 void
628 wsi_common_destroy_swapchain(VkDevice device,
629 VkSwapchainKHR _swapchain,
630 const VkAllocationCallbacks *pAllocator)
631 {
632 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
633 if (!swapchain)
634 return;
635
636 swapchain->destroy(swapchain, pAllocator);
637 }
638
639 VkResult
640 wsi_common_get_images(VkSwapchainKHR _swapchain,
641 uint32_t *pSwapchainImageCount,
642 VkImage *pSwapchainImages)
643 {
644 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
645 VK_OUTARRAY_MAKE(images, pSwapchainImages, pSwapchainImageCount);
646
647 for (uint32_t i = 0; i < swapchain->image_count; i++) {
648 vk_outarray_append(&images, image) {
649 *image = swapchain->get_wsi_image(swapchain, i)->image;
650 }
651 }
652
653 return vk_outarray_status(&images);
654 }
655
656 VkResult
657 wsi_common_acquire_next_image(const struct wsi_device *wsi,
658 VkDevice device,
659 VkSwapchainKHR _swapchain,
660 uint64_t timeout,
661 VkSemaphore semaphore,
662 uint32_t *pImageIndex)
663 {
664 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
665
666 return swapchain->acquire_next_image(swapchain, timeout,
667 semaphore, pImageIndex);
668 }
669
670 VkResult
671 wsi_common_queue_present(const struct wsi_device *wsi,
672 VkDevice device,
673 VkQueue queue,
674 int queue_family_index,
675 const VkPresentInfoKHR *pPresentInfo)
676 {
677 VkResult final_result = VK_SUCCESS;
678
679 const VkPresentRegionsKHR *regions =
680 vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR);
681
682 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
683 WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]);
684 VkResult result;
685
686 if (swapchain->fences[0] == VK_NULL_HANDLE) {
687 const VkFenceCreateInfo fence_info = {
688 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
689 .pNext = NULL,
690 .flags = 0,
691 };
692 result = wsi->CreateFence(device, &fence_info,
693 &swapchain->alloc,
694 &swapchain->fences[0]);
695 if (result != VK_SUCCESS)
696 goto fail_present;
697 } else {
698 wsi->ResetFences(device, 1, &swapchain->fences[0]);
699 }
700
701 VkSubmitInfo submit_info = {
702 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
703 .pNext = NULL,
704 };
705
706 VkPipelineStageFlags *stage_flags = NULL;
707 if (i == 0) {
708 /* We only need/want to wait on semaphores once. After that, we're
709 * guaranteed ordering since it all happens on the same queue.
710 */
711 submit_info.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount,
712 submit_info.pWaitSemaphores = pPresentInfo->pWaitSemaphores,
713
714 /* Set up the pWaitDstStageMasks */
715 stage_flags = vk_alloc(&swapchain->alloc,
716 sizeof(VkPipelineStageFlags) *
717 pPresentInfo->waitSemaphoreCount,
718 8,
719 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
720 if (!stage_flags) {
721 result = VK_ERROR_OUT_OF_HOST_MEMORY;
722 goto fail_present;
723 }
724 for (uint32_t s = 0; s < pPresentInfo->waitSemaphoreCount; s++)
725 stage_flags[s] = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
726
727 submit_info.pWaitDstStageMask = stage_flags;
728 }
729
730 if (swapchain->use_prime_blit) {
731 /* If we are using prime blits, we need to perform the blit now. The
732 * command buffer is attached to the image.
733 */
734 struct wsi_image *image =
735 swapchain->get_wsi_image(swapchain, pPresentInfo->pImageIndices[i]);
736 submit_info.commandBufferCount = 1;
737 submit_info.pCommandBuffers =
738 &image->prime.blit_cmd_buffers[queue_family_index];
739 }
740
741 result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[0]);
742 vk_free(&swapchain->alloc, stage_flags);
743 if (result != VK_SUCCESS)
744 goto fail_present;
745
746 const VkPresentRegionKHR *region = NULL;
747 if (regions && regions->pRegions)
748 region = &regions->pRegions[i];
749
750 result = swapchain->queue_present(swapchain,
751 pPresentInfo->pImageIndices[i],
752 region);
753 if (result != VK_SUCCESS)
754 goto fail_present;
755
756 VkFence last = swapchain->fences[2];
757 swapchain->fences[2] = swapchain->fences[1];
758 swapchain->fences[1] = swapchain->fences[0];
759 swapchain->fences[0] = last;
760
761 if (last != VK_NULL_HANDLE) {
762 wsi->WaitForFences(device, 1, &last, true, 1);
763 }
764
765 fail_present:
766 if (pPresentInfo->pResults != NULL)
767 pPresentInfo->pResults[i] = result;
768
769 /* Let the final result be our first unsuccessful result */
770 if (final_result == VK_SUCCESS)
771 final_result = result;
772 }
773
774 return final_result;
775 }