vulkan/wsi: Add multiple planes to wsi_image
[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 for (int i = 0; i < ARRAY_SIZE(image->fds); i++)
205 image->fds[i] = -1;
206
207 const struct wsi_image_create_info image_wsi_info = {
208 .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA,
209 .pNext = NULL,
210 .scanout = true,
211 };
212 const VkImageCreateInfo image_info = {
213 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
214 .pNext = &image_wsi_info,
215 .flags = 0,
216 .imageType = VK_IMAGE_TYPE_2D,
217 .format = pCreateInfo->imageFormat,
218 .extent = {
219 .width = pCreateInfo->imageExtent.width,
220 .height = pCreateInfo->imageExtent.height,
221 .depth = 1,
222 },
223 .mipLevels = 1,
224 .arrayLayers = 1,
225 .samples = VK_SAMPLE_COUNT_1_BIT,
226 .tiling = VK_IMAGE_TILING_OPTIMAL,
227 .usage = pCreateInfo->imageUsage,
228 .sharingMode = pCreateInfo->imageSharingMode,
229 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
230 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
231 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
232 };
233 result = wsi->CreateImage(chain->device, &image_info,
234 &chain->alloc, &image->image);
235 if (result != VK_SUCCESS)
236 goto fail;
237
238 VkMemoryRequirements reqs;
239 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
240
241 VkSubresourceLayout image_layout;
242 const VkImageSubresource image_subresource = {
243 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
244 .mipLevel = 0,
245 .arrayLayer = 0,
246 };
247 wsi->GetImageSubresourceLayout(chain->device, image->image,
248 &image_subresource, &image_layout);
249
250 const struct wsi_memory_allocate_info memory_wsi_info = {
251 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
252 .pNext = NULL,
253 .implicit_sync = true,
254 };
255 const VkExportMemoryAllocateInfoKHR memory_export_info = {
256 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
257 .pNext = &memory_wsi_info,
258 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
259 };
260 const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = {
261 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
262 .pNext = &memory_export_info,
263 .image = image->image,
264 .buffer = VK_NULL_HANDLE,
265 };
266 const VkMemoryAllocateInfo memory_info = {
267 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
268 .pNext = &memory_dedicated_info,
269 .allocationSize = reqs.size,
270 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
271 reqs.memoryTypeBits),
272 };
273 result = wsi->AllocateMemory(chain->device, &memory_info,
274 &chain->alloc, &image->memory);
275 if (result != VK_SUCCESS)
276 goto fail;
277
278 result = wsi->BindImageMemory(chain->device, image->image,
279 image->memory, 0);
280 if (result != VK_SUCCESS)
281 goto fail;
282
283 const VkMemoryGetFdInfoKHR memory_get_fd_info = {
284 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
285 .pNext = NULL,
286 .memory = image->memory,
287 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
288 };
289 int fd;
290 result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd);
291 if (result != VK_SUCCESS)
292 goto fail;
293
294 image->num_planes = 1;
295 image->sizes[0] = reqs.size;
296 image->row_pitches[0] = image_layout.rowPitch;
297 image->offsets[0] = 0;
298 image->fds[0] = fd;
299
300 return VK_SUCCESS;
301
302 fail:
303 wsi_destroy_image(chain, image);
304
305 return result;
306 }
307
308 #define WSI_PRIME_LINEAR_STRIDE_ALIGN 256
309
310 VkResult
311 wsi_create_prime_image(const struct wsi_swapchain *chain,
312 const VkSwapchainCreateInfoKHR *pCreateInfo,
313 struct wsi_image *image)
314 {
315 const struct wsi_device *wsi = chain->wsi;
316 VkResult result;
317
318 memset(image, 0, sizeof(*image));
319
320 const uint32_t cpp = vk_format_size(pCreateInfo->imageFormat);
321 const uint32_t linear_stride = align_u32(pCreateInfo->imageExtent.width * cpp,
322 WSI_PRIME_LINEAR_STRIDE_ALIGN);
323
324 uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height;
325 linear_size = align_u32(linear_size, 4096);
326
327 const VkExternalMemoryBufferCreateInfoKHR prime_buffer_external_info = {
328 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR,
329 .pNext = NULL,
330 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
331 };
332 const VkBufferCreateInfo prime_buffer_info = {
333 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
334 .pNext = &prime_buffer_external_info,
335 .size = linear_size,
336 .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
337 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
338 };
339 result = wsi->CreateBuffer(chain->device, &prime_buffer_info,
340 &chain->alloc, &image->prime.buffer);
341 if (result != VK_SUCCESS)
342 goto fail;
343
344 VkMemoryRequirements reqs;
345 wsi->GetBufferMemoryRequirements(chain->device, image->prime.buffer, &reqs);
346 assert(reqs.size <= linear_size);
347
348 const struct wsi_memory_allocate_info memory_wsi_info = {
349 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
350 .pNext = NULL,
351 .implicit_sync = true,
352 };
353 const VkExportMemoryAllocateInfoKHR prime_memory_export_info = {
354 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
355 .pNext = &memory_wsi_info,
356 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
357 };
358 const VkMemoryDedicatedAllocateInfoKHR prime_memory_dedicated_info = {
359 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
360 .pNext = &prime_memory_export_info,
361 .image = VK_NULL_HANDLE,
362 .buffer = image->prime.buffer,
363 };
364 const VkMemoryAllocateInfo prime_memory_info = {
365 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
366 .pNext = &prime_memory_dedicated_info,
367 .allocationSize = linear_size,
368 .memoryTypeIndex = select_memory_type(wsi, 0, reqs.memoryTypeBits),
369 };
370 result = wsi->AllocateMemory(chain->device, &prime_memory_info,
371 &chain->alloc, &image->prime.memory);
372 if (result != VK_SUCCESS)
373 goto fail;
374
375 result = wsi->BindBufferMemory(chain->device, image->prime.buffer,
376 image->prime.memory, 0);
377 if (result != VK_SUCCESS)
378 goto fail;
379
380 const VkImageCreateInfo image_info = {
381 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
382 .pNext = NULL,
383 .flags = 0,
384 .imageType = VK_IMAGE_TYPE_2D,
385 .format = pCreateInfo->imageFormat,
386 .extent = {
387 .width = pCreateInfo->imageExtent.width,
388 .height = pCreateInfo->imageExtent.height,
389 .depth = 1,
390 },
391 .mipLevels = 1,
392 .arrayLayers = 1,
393 .samples = VK_SAMPLE_COUNT_1_BIT,
394 .tiling = VK_IMAGE_TILING_OPTIMAL,
395 .usage = pCreateInfo->imageUsage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
396 .sharingMode = pCreateInfo->imageSharingMode,
397 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
398 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
399 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
400 };
401 result = wsi->CreateImage(chain->device, &image_info,
402 &chain->alloc, &image->image);
403 if (result != VK_SUCCESS)
404 goto fail;
405
406 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
407
408 const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = {
409 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
410 .pNext = NULL,
411 .image = image->image,
412 .buffer = VK_NULL_HANDLE,
413 };
414 const VkMemoryAllocateInfo memory_info = {
415 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
416 .pNext = &memory_dedicated_info,
417 .allocationSize = reqs.size,
418 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
419 reqs.memoryTypeBits),
420 };
421 result = wsi->AllocateMemory(chain->device, &memory_info,
422 &chain->alloc, &image->memory);
423 if (result != VK_SUCCESS)
424 goto fail;
425
426 result = wsi->BindImageMemory(chain->device, image->image,
427 image->memory, 0);
428 if (result != VK_SUCCESS)
429 goto fail;
430
431 image->prime.blit_cmd_buffers =
432 vk_zalloc(&chain->alloc,
433 sizeof(VkCommandBuffer) * wsi->queue_family_count, 8,
434 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
435 if (!image->prime.blit_cmd_buffers) {
436 result = VK_ERROR_OUT_OF_HOST_MEMORY;
437 goto fail;
438 }
439
440 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
441 const VkCommandBufferAllocateInfo cmd_buffer_info = {
442 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
443 .pNext = NULL,
444 .commandPool = chain->cmd_pools[i],
445 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
446 .commandBufferCount = 1,
447 };
448 result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info,
449 &image->prime.blit_cmd_buffers[i]);
450 if (result != VK_SUCCESS)
451 goto fail;
452
453 const VkCommandBufferBeginInfo begin_info = {
454 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
455 };
456 wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info);
457
458 struct VkBufferImageCopy buffer_image_copy = {
459 .bufferOffset = 0,
460 .bufferRowLength = linear_stride / cpp,
461 .bufferImageHeight = 0,
462 .imageSubresource = {
463 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
464 .mipLevel = 0,
465 .baseArrayLayer = 0,
466 .layerCount = 1,
467 },
468 .imageOffset = { .x = 0, .y = 0, .z = 0 },
469 .imageExtent = {
470 .width = pCreateInfo->imageExtent.width,
471 .height = pCreateInfo->imageExtent.height,
472 .depth = 1,
473 },
474 };
475 wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i],
476 image->image,
477 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
478 image->prime.buffer,
479 1, &buffer_image_copy);
480
481 result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]);
482 if (result != VK_SUCCESS)
483 goto fail;
484 }
485
486 const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
487 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
488 .pNext = NULL,
489 .memory = image->prime.memory,
490 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
491 };
492 int fd;
493 result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd);
494 if (result != VK_SUCCESS)
495 goto fail;
496
497 image->num_planes = 1;
498 image->sizes[0] = linear_size;
499 image->row_pitches[0] = linear_stride;
500 image->offsets[0] = 0;
501 image->fds[0] = fd;
502
503 return VK_SUCCESS;
504
505 fail:
506 wsi_destroy_image(chain, image);
507
508 return result;
509 }
510
511 void
512 wsi_destroy_image(const struct wsi_swapchain *chain,
513 struct wsi_image *image)
514 {
515 const struct wsi_device *wsi = chain->wsi;
516
517 if (image->prime.blit_cmd_buffers) {
518 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
519 wsi->FreeCommandBuffers(chain->device, chain->cmd_pools[i],
520 1, &image->prime.blit_cmd_buffers[i]);
521 }
522 vk_free(&chain->alloc, image->prime.blit_cmd_buffers);
523 }
524
525 wsi->FreeMemory(chain->device, image->memory, &chain->alloc);
526 wsi->DestroyImage(chain->device, image->image, &chain->alloc);
527 wsi->FreeMemory(chain->device, image->prime.memory, &chain->alloc);
528 wsi->DestroyBuffer(chain->device, image->prime.buffer, &chain->alloc);
529 }
530
531 VkResult
532 wsi_common_get_surface_support(struct wsi_device *wsi_device,
533 int local_fd,
534 uint32_t queueFamilyIndex,
535 VkSurfaceKHR _surface,
536 const VkAllocationCallbacks *alloc,
537 VkBool32* pSupported)
538 {
539 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
540 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
541
542 return iface->get_support(surface, wsi_device, alloc,
543 queueFamilyIndex, local_fd, pSupported);
544 }
545
546 VkResult
547 wsi_common_get_surface_capabilities(struct wsi_device *wsi_device,
548 VkSurfaceKHR _surface,
549 VkSurfaceCapabilitiesKHR *pSurfaceCapabilities)
550 {
551 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
552 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
553
554 return iface->get_capabilities(surface, pSurfaceCapabilities);
555 }
556
557 VkResult
558 wsi_common_get_surface_capabilities2(struct wsi_device *wsi_device,
559 const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
560 VkSurfaceCapabilities2KHR *pSurfaceCapabilities)
561 {
562 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
563 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
564
565 return iface->get_capabilities2(surface, pSurfaceInfo->pNext,
566 pSurfaceCapabilities);
567 }
568
569 VkResult
570 wsi_common_get_surface_formats(struct wsi_device *wsi_device,
571 VkSurfaceKHR _surface,
572 uint32_t *pSurfaceFormatCount,
573 VkSurfaceFormatKHR *pSurfaceFormats)
574 {
575 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
576 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
577
578 return iface->get_formats(surface, wsi_device,
579 pSurfaceFormatCount, pSurfaceFormats);
580 }
581
582 VkResult
583 wsi_common_get_surface_formats2(struct wsi_device *wsi_device,
584 const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
585 uint32_t *pSurfaceFormatCount,
586 VkSurfaceFormat2KHR *pSurfaceFormats)
587 {
588 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
589 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
590
591 return iface->get_formats2(surface, wsi_device, pSurfaceInfo->pNext,
592 pSurfaceFormatCount, pSurfaceFormats);
593 }
594
595 VkResult
596 wsi_common_get_surface_present_modes(struct wsi_device *wsi_device,
597 VkSurfaceKHR _surface,
598 uint32_t *pPresentModeCount,
599 VkPresentModeKHR *pPresentModes)
600 {
601 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
602 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
603
604 return iface->get_present_modes(surface, pPresentModeCount,
605 pPresentModes);
606 }
607
608 VkResult
609 wsi_common_create_swapchain(struct wsi_device *wsi,
610 VkDevice device,
611 int fd,
612 const VkSwapchainCreateInfoKHR *pCreateInfo,
613 const VkAllocationCallbacks *pAllocator,
614 VkSwapchainKHR *pSwapchain)
615 {
616 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface);
617 struct wsi_interface *iface = wsi->wsi[surface->platform];
618 struct wsi_swapchain *swapchain;
619
620 VkResult result = iface->create_swapchain(surface, device, wsi, fd,
621 pCreateInfo, pAllocator,
622 &swapchain);
623 if (result != VK_SUCCESS)
624 return result;
625
626 *pSwapchain = wsi_swapchain_to_handle(swapchain);
627
628 return VK_SUCCESS;
629 }
630
631 void
632 wsi_common_destroy_swapchain(VkDevice device,
633 VkSwapchainKHR _swapchain,
634 const VkAllocationCallbacks *pAllocator)
635 {
636 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
637 if (!swapchain)
638 return;
639
640 swapchain->destroy(swapchain, pAllocator);
641 }
642
643 VkResult
644 wsi_common_get_images(VkSwapchainKHR _swapchain,
645 uint32_t *pSwapchainImageCount,
646 VkImage *pSwapchainImages)
647 {
648 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
649 VK_OUTARRAY_MAKE(images, pSwapchainImages, pSwapchainImageCount);
650
651 for (uint32_t i = 0; i < swapchain->image_count; i++) {
652 vk_outarray_append(&images, image) {
653 *image = swapchain->get_wsi_image(swapchain, i)->image;
654 }
655 }
656
657 return vk_outarray_status(&images);
658 }
659
660 VkResult
661 wsi_common_acquire_next_image(const struct wsi_device *wsi,
662 VkDevice device,
663 VkSwapchainKHR _swapchain,
664 uint64_t timeout,
665 VkSemaphore semaphore,
666 uint32_t *pImageIndex)
667 {
668 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
669
670 return swapchain->acquire_next_image(swapchain, timeout,
671 semaphore, pImageIndex);
672 }
673
674 VkResult
675 wsi_common_queue_present(const struct wsi_device *wsi,
676 VkDevice device,
677 VkQueue queue,
678 int queue_family_index,
679 const VkPresentInfoKHR *pPresentInfo)
680 {
681 VkResult final_result = VK_SUCCESS;
682
683 const VkPresentRegionsKHR *regions =
684 vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR);
685
686 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
687 WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]);
688 VkResult result;
689
690 if (swapchain->fences[0] == VK_NULL_HANDLE) {
691 const VkFenceCreateInfo fence_info = {
692 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
693 .pNext = NULL,
694 .flags = 0,
695 };
696 result = wsi->CreateFence(device, &fence_info,
697 &swapchain->alloc,
698 &swapchain->fences[0]);
699 if (result != VK_SUCCESS)
700 goto fail_present;
701 } else {
702 wsi->ResetFences(device, 1, &swapchain->fences[0]);
703 }
704
705 VkSubmitInfo submit_info = {
706 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
707 .pNext = NULL,
708 };
709
710 VkPipelineStageFlags *stage_flags = NULL;
711 if (i == 0) {
712 /* We only need/want to wait on semaphores once. After that, we're
713 * guaranteed ordering since it all happens on the same queue.
714 */
715 submit_info.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount,
716 submit_info.pWaitSemaphores = pPresentInfo->pWaitSemaphores,
717
718 /* Set up the pWaitDstStageMasks */
719 stage_flags = vk_alloc(&swapchain->alloc,
720 sizeof(VkPipelineStageFlags) *
721 pPresentInfo->waitSemaphoreCount,
722 8,
723 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
724 if (!stage_flags) {
725 result = VK_ERROR_OUT_OF_HOST_MEMORY;
726 goto fail_present;
727 }
728 for (uint32_t s = 0; s < pPresentInfo->waitSemaphoreCount; s++)
729 stage_flags[s] = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
730
731 submit_info.pWaitDstStageMask = stage_flags;
732 }
733
734 if (swapchain->use_prime_blit) {
735 /* If we are using prime blits, we need to perform the blit now. The
736 * command buffer is attached to the image.
737 */
738 struct wsi_image *image =
739 swapchain->get_wsi_image(swapchain, pPresentInfo->pImageIndices[i]);
740 submit_info.commandBufferCount = 1;
741 submit_info.pCommandBuffers =
742 &image->prime.blit_cmd_buffers[queue_family_index];
743 }
744
745 result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[0]);
746 vk_free(&swapchain->alloc, stage_flags);
747 if (result != VK_SUCCESS)
748 goto fail_present;
749
750 const VkPresentRegionKHR *region = NULL;
751 if (regions && regions->pRegions)
752 region = &regions->pRegions[i];
753
754 result = swapchain->queue_present(swapchain,
755 pPresentInfo->pImageIndices[i],
756 region);
757 if (result != VK_SUCCESS)
758 goto fail_present;
759
760 VkFence last = swapchain->fences[2];
761 swapchain->fences[2] = swapchain->fences[1];
762 swapchain->fences[1] = swapchain->fences[0];
763 swapchain->fences[0] = last;
764
765 if (last != VK_NULL_HANDLE) {
766 wsi->WaitForFences(device, 1, &last, true, 1);
767 }
768
769 fail_present:
770 if (pPresentInfo->pResults != NULL)
771 pPresentInfo->pResults[i] = result;
772
773 /* Let the final result be our first unsuccessful result */
774 if (final_result == VK_SUCCESS)
775 final_result = result;
776 }
777
778 return final_result;
779 }