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