vulkan/wsi: Add a driconf option to force WSI to advertise BGRA8_UNORM first
[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-uapi/drm_fourcc.h"
26 #include "util/macros.h"
27 #include "util/xmlconfig.h"
28 #include "vk_util.h"
29
30 #include <time.h>
31 #include <unistd.h>
32 #include <xf86drm.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35
36 VkResult
37 wsi_device_init(struct wsi_device *wsi,
38 VkPhysicalDevice pdevice,
39 WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
40 const VkAllocationCallbacks *alloc,
41 int display_fd,
42 const struct driOptionCache *dri_options)
43 {
44 const char *present_mode;
45 VkResult result;
46
47 memset(wsi, 0, sizeof(*wsi));
48
49 wsi->instance_alloc = *alloc;
50 wsi->pdevice = pdevice;
51
52 #define WSI_GET_CB(func) \
53 PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
54 WSI_GET_CB(GetPhysicalDeviceProperties2);
55 WSI_GET_CB(GetPhysicalDeviceMemoryProperties);
56 WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties);
57 #undef WSI_GET_CB
58
59 wsi->pci_bus_info.sType =
60 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT;
61 VkPhysicalDeviceProperties2 pdp2 = {
62 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
63 .pNext = &wsi->pci_bus_info,
64 };
65 GetPhysicalDeviceProperties2(pdevice, &pdp2);
66
67 wsi->maxImageDimension2D = pdp2.properties.limits.maxImageDimension2D;
68 wsi->override_present_mode = VK_PRESENT_MODE_MAX_ENUM_KHR;
69
70 GetPhysicalDeviceMemoryProperties(pdevice, &wsi->memory_props);
71 GetPhysicalDeviceQueueFamilyProperties(pdevice, &wsi->queue_family_count, NULL);
72
73 #define WSI_GET_CB(func) \
74 wsi->func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
75 WSI_GET_CB(AllocateMemory);
76 WSI_GET_CB(AllocateCommandBuffers);
77 WSI_GET_CB(BindBufferMemory);
78 WSI_GET_CB(BindImageMemory);
79 WSI_GET_CB(BeginCommandBuffer);
80 WSI_GET_CB(CmdCopyImageToBuffer);
81 WSI_GET_CB(CreateBuffer);
82 WSI_GET_CB(CreateCommandPool);
83 WSI_GET_CB(CreateFence);
84 WSI_GET_CB(CreateImage);
85 WSI_GET_CB(DestroyBuffer);
86 WSI_GET_CB(DestroyCommandPool);
87 WSI_GET_CB(DestroyFence);
88 WSI_GET_CB(DestroyImage);
89 WSI_GET_CB(EndCommandBuffer);
90 WSI_GET_CB(FreeMemory);
91 WSI_GET_CB(FreeCommandBuffers);
92 WSI_GET_CB(GetBufferMemoryRequirements);
93 WSI_GET_CB(GetImageMemoryRequirements);
94 WSI_GET_CB(GetImageSubresourceLayout);
95 WSI_GET_CB(GetMemoryFdKHR);
96 WSI_GET_CB(GetPhysicalDeviceFormatProperties);
97 WSI_GET_CB(GetPhysicalDeviceFormatProperties2KHR);
98 WSI_GET_CB(ResetFences);
99 WSI_GET_CB(QueueSubmit);
100 WSI_GET_CB(WaitForFences);
101 #undef WSI_GET_CB
102
103 #ifdef VK_USE_PLATFORM_XCB_KHR
104 result = wsi_x11_init_wsi(wsi, alloc, dri_options);
105 if (result != VK_SUCCESS)
106 goto fail;
107 #endif
108
109 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
110 result = wsi_wl_init_wsi(wsi, alloc, pdevice);
111 if (result != VK_SUCCESS)
112 goto fail;
113 #endif
114
115 #ifdef VK_USE_PLATFORM_DISPLAY_KHR
116 result = wsi_display_init_wsi(wsi, alloc, display_fd);
117 if (result != VK_SUCCESS)
118 goto fail;
119 #endif
120
121 present_mode = getenv("MESA_VK_WSI_PRESENT_MODE");
122 if (present_mode) {
123 if (!strcmp(present_mode, "fifo")) {
124 wsi->override_present_mode = VK_PRESENT_MODE_FIFO_KHR;
125 } else if (!strcmp(present_mode, "mailbox")) {
126 wsi->override_present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
127 } else if (!strcmp(present_mode, "immediate")) {
128 wsi->override_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
129 } else {
130 fprintf(stderr, "Invalid MESA_VK_WSI_PRESENT_MODE value!\n");
131 }
132 }
133
134 if (dri_options) {
135 if (driCheckOption(dri_options, "adaptive_sync", DRI_BOOL))
136 wsi->enable_adaptive_sync = driQueryOptionb(dri_options,
137 "adaptive_sync");
138
139 if (driCheckOption(dri_options, "vk_wsi_force_bgra8_unorm_first", DRI_BOOL)) {
140 wsi->force_bgra8_unorm_first =
141 driQueryOptionb(dri_options, "vk_wsi_force_bgra8_unorm_first");
142 }
143 }
144
145 return VK_SUCCESS;
146
147 fail:
148 wsi_device_finish(wsi, alloc);
149 return result;
150 }
151
152 void
153 wsi_device_finish(struct wsi_device *wsi,
154 const VkAllocationCallbacks *alloc)
155 {
156 #ifdef VK_USE_PLATFORM_DISPLAY_KHR
157 wsi_display_finish_wsi(wsi, alloc);
158 #endif
159 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
160 wsi_wl_finish_wsi(wsi, alloc);
161 #endif
162 #ifdef VK_USE_PLATFORM_XCB_KHR
163 wsi_x11_finish_wsi(wsi, alloc);
164 #endif
165 }
166
167 bool
168 wsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd)
169 {
170 drmDevicePtr fd_device;
171 int ret = drmGetDevice2(drm_fd, 0, &fd_device);
172 if (ret)
173 return false;
174
175 bool match = false;
176 switch (fd_device->bustype) {
177 case DRM_BUS_PCI:
178 match = wsi->pci_bus_info.pciDomain == fd_device->businfo.pci->domain &&
179 wsi->pci_bus_info.pciBus == fd_device->businfo.pci->bus &&
180 wsi->pci_bus_info.pciDevice == fd_device->businfo.pci->dev &&
181 wsi->pci_bus_info.pciFunction == fd_device->businfo.pci->func;
182 break;
183
184 default:
185 break;
186 }
187
188 drmFreeDevice(&fd_device);
189
190 return match;
191 }
192
193 VkResult
194 wsi_swapchain_init(const struct wsi_device *wsi,
195 struct wsi_swapchain *chain,
196 VkDevice device,
197 const VkSwapchainCreateInfoKHR *pCreateInfo,
198 const VkAllocationCallbacks *pAllocator)
199 {
200 VkResult result;
201
202 memset(chain, 0, sizeof(*chain));
203
204 chain->wsi = wsi;
205 chain->device = device;
206 chain->alloc = *pAllocator;
207 chain->use_prime_blit = false;
208
209 chain->cmd_pools =
210 vk_zalloc(pAllocator, sizeof(VkCommandPool) * wsi->queue_family_count, 8,
211 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
212 if (!chain->cmd_pools)
213 return VK_ERROR_OUT_OF_HOST_MEMORY;
214
215 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
216 const VkCommandPoolCreateInfo cmd_pool_info = {
217 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
218 .pNext = NULL,
219 .flags = 0,
220 .queueFamilyIndex = i,
221 };
222 result = wsi->CreateCommandPool(device, &cmd_pool_info, &chain->alloc,
223 &chain->cmd_pools[i]);
224 if (result != VK_SUCCESS)
225 goto fail;
226 }
227
228 return VK_SUCCESS;
229
230 fail:
231 wsi_swapchain_finish(chain);
232 return result;
233 }
234
235 static bool
236 wsi_swapchain_is_present_mode_supported(struct wsi_device *wsi,
237 const VkSwapchainCreateInfoKHR *pCreateInfo,
238 VkPresentModeKHR mode)
239 {
240 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface);
241 struct wsi_interface *iface = wsi->wsi[surface->platform];
242 VkPresentModeKHR *present_modes;
243 uint32_t present_mode_count;
244 bool supported = false;
245 VkResult result;
246
247 result = iface->get_present_modes(surface, &present_mode_count, NULL);
248 if (result != VK_SUCCESS)
249 return supported;
250
251 present_modes = malloc(present_mode_count * sizeof(*present_modes));
252 if (!present_modes)
253 return supported;
254
255 result = iface->get_present_modes(surface, &present_mode_count,
256 present_modes);
257 if (result != VK_SUCCESS)
258 goto fail;
259
260 for (uint32_t i = 0; i < present_mode_count; i++) {
261 if (present_modes[i] == mode) {
262 supported = true;
263 break;
264 }
265 }
266
267 fail:
268 free(present_modes);
269 return supported;
270 }
271
272 enum VkPresentModeKHR
273 wsi_swapchain_get_present_mode(struct wsi_device *wsi,
274 const VkSwapchainCreateInfoKHR *pCreateInfo)
275 {
276 if (wsi->override_present_mode == VK_PRESENT_MODE_MAX_ENUM_KHR)
277 return pCreateInfo->presentMode;
278
279 if (!wsi_swapchain_is_present_mode_supported(wsi, pCreateInfo,
280 wsi->override_present_mode)) {
281 fprintf(stderr, "Unsupported MESA_VK_WSI_PRESENT_MODE value!\n");
282 return pCreateInfo->presentMode;
283 }
284
285 return wsi->override_present_mode;
286 }
287
288 void
289 wsi_swapchain_finish(struct wsi_swapchain *chain)
290 {
291 if (chain->fences) {
292 for (unsigned i = 0; i < chain->image_count; i++)
293 chain->wsi->DestroyFence(chain->device, chain->fences[i], &chain->alloc);
294
295 vk_free(&chain->alloc, chain->fences);
296 }
297
298 for (uint32_t i = 0; i < chain->wsi->queue_family_count; i++) {
299 chain->wsi->DestroyCommandPool(chain->device, chain->cmd_pools[i],
300 &chain->alloc);
301 }
302 vk_free(&chain->alloc, chain->cmd_pools);
303 }
304
305 static uint32_t
306 select_memory_type(const struct wsi_device *wsi,
307 VkMemoryPropertyFlags props,
308 uint32_t type_bits)
309 {
310 for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) {
311 const VkMemoryType type = wsi->memory_props.memoryTypes[i];
312 if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props)
313 return i;
314 }
315
316 unreachable("No memory type found");
317 }
318
319 static uint32_t
320 vk_format_size(VkFormat format)
321 {
322 switch (format) {
323 case VK_FORMAT_B8G8R8A8_UNORM:
324 case VK_FORMAT_B8G8R8A8_SRGB:
325 return 4;
326 default:
327 unreachable("Unknown WSI Format");
328 }
329 }
330
331 static inline uint32_t
332 align_u32(uint32_t v, uint32_t a)
333 {
334 assert(a != 0 && a == (a & -a));
335 return (v + a - 1) & ~(a - 1);
336 }
337
338 VkResult
339 wsi_create_native_image(const struct wsi_swapchain *chain,
340 const VkSwapchainCreateInfoKHR *pCreateInfo,
341 uint32_t num_modifier_lists,
342 const uint32_t *num_modifiers,
343 const uint64_t *const *modifiers,
344 struct wsi_image *image)
345 {
346 const struct wsi_device *wsi = chain->wsi;
347 VkResult result;
348
349 memset(image, 0, sizeof(*image));
350 for (int i = 0; i < ARRAY_SIZE(image->fds); i++)
351 image->fds[i] = -1;
352
353 struct wsi_image_create_info image_wsi_info = {
354 .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA,
355 .pNext = NULL,
356 };
357
358 uint32_t image_modifier_count = 0, modifier_prop_count = 0;
359 struct wsi_format_modifier_properties *modifier_props = NULL;
360 uint64_t *image_modifiers = NULL;
361 if (num_modifier_lists == 0) {
362 /* If we don't have modifiers, fall back to the legacy "scanout" flag */
363 image_wsi_info.scanout = true;
364 } else {
365 /* The winsys can't request modifiers if we don't support them. */
366 assert(wsi->supports_modifiers);
367 struct wsi_format_modifier_properties_list modifier_props_list = {
368 .sType = VK_STRUCTURE_TYPE_WSI_FORMAT_MODIFIER_PROPERTIES_LIST_MESA,
369 .pNext = NULL,
370 };
371 VkFormatProperties2 format_props = {
372 .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
373 .pNext = &modifier_props_list,
374 };
375 wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice,
376 pCreateInfo->imageFormat,
377 &format_props);
378 assert(modifier_props_list.modifier_count > 0);
379 modifier_props = vk_alloc(&chain->alloc,
380 sizeof(*modifier_props) *
381 modifier_props_list.modifier_count,
382 8,
383 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
384 if (!modifier_props) {
385 result = VK_ERROR_OUT_OF_HOST_MEMORY;
386 goto fail;
387 }
388
389 modifier_props_list.modifier_properties = modifier_props;
390 wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice,
391 pCreateInfo->imageFormat,
392 &format_props);
393 modifier_prop_count = modifier_props_list.modifier_count;
394
395 uint32_t max_modifier_count = 0;
396 for (uint32_t l = 0; l < num_modifier_lists; l++)
397 max_modifier_count = MAX2(max_modifier_count, num_modifiers[l]);
398
399 image_modifiers = vk_alloc(&chain->alloc,
400 sizeof(*image_modifiers) *
401 max_modifier_count,
402 8,
403 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
404 if (!image_modifiers) {
405 result = VK_ERROR_OUT_OF_HOST_MEMORY;
406 goto fail;
407 }
408
409 image_modifier_count = 0;
410 for (uint32_t l = 0; l < num_modifier_lists; l++) {
411 /* Walk the modifier lists and construct a list of supported
412 * modifiers.
413 */
414 for (uint32_t i = 0; i < num_modifiers[l]; i++) {
415 for (uint32_t j = 0; j < modifier_prop_count; j++) {
416 if (modifier_props[j].modifier == modifiers[l][i])
417 image_modifiers[image_modifier_count++] = modifiers[l][i];
418 }
419 }
420
421 /* We only want to take the modifiers from the first list */
422 if (image_modifier_count > 0)
423 break;
424 }
425
426 if (image_modifier_count > 0) {
427 image_wsi_info.modifier_count = image_modifier_count;
428 image_wsi_info.modifiers = image_modifiers;
429 } else {
430 /* TODO: Add a proper error here */
431 assert(!"Failed to find a supported modifier! This should never "
432 "happen because LINEAR should always be available");
433 result = VK_ERROR_OUT_OF_HOST_MEMORY;
434 goto fail;
435 }
436 }
437
438 const VkImageCreateInfo image_info = {
439 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
440 .pNext = &image_wsi_info,
441 .flags = 0,
442 .imageType = VK_IMAGE_TYPE_2D,
443 .format = pCreateInfo->imageFormat,
444 .extent = {
445 .width = pCreateInfo->imageExtent.width,
446 .height = pCreateInfo->imageExtent.height,
447 .depth = 1,
448 },
449 .mipLevels = 1,
450 .arrayLayers = 1,
451 .samples = VK_SAMPLE_COUNT_1_BIT,
452 .tiling = VK_IMAGE_TILING_OPTIMAL,
453 .usage = pCreateInfo->imageUsage,
454 .sharingMode = pCreateInfo->imageSharingMode,
455 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
456 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
457 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
458 };
459 result = wsi->CreateImage(chain->device, &image_info,
460 &chain->alloc, &image->image);
461 if (result != VK_SUCCESS)
462 goto fail;
463
464 VkMemoryRequirements reqs;
465 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
466
467 const struct wsi_memory_allocate_info memory_wsi_info = {
468 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
469 .pNext = NULL,
470 .implicit_sync = true,
471 };
472 const VkExportMemoryAllocateInfo memory_export_info = {
473 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
474 .pNext = &memory_wsi_info,
475 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
476 };
477 const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {
478 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
479 .pNext = &memory_export_info,
480 .image = image->image,
481 .buffer = VK_NULL_HANDLE,
482 };
483 const VkMemoryAllocateInfo memory_info = {
484 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
485 .pNext = &memory_dedicated_info,
486 .allocationSize = reqs.size,
487 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
488 reqs.memoryTypeBits),
489 };
490 result = wsi->AllocateMemory(chain->device, &memory_info,
491 &chain->alloc, &image->memory);
492 if (result != VK_SUCCESS)
493 goto fail;
494
495 result = wsi->BindImageMemory(chain->device, image->image,
496 image->memory, 0);
497 if (result != VK_SUCCESS)
498 goto fail;
499
500 const VkMemoryGetFdInfoKHR memory_get_fd_info = {
501 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
502 .pNext = NULL,
503 .memory = image->memory,
504 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
505 };
506 int fd;
507 result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd);
508 if (result != VK_SUCCESS)
509 goto fail;
510
511 if (num_modifier_lists > 0) {
512 image->drm_modifier = wsi->image_get_modifier(image->image);
513 assert(image->drm_modifier != DRM_FORMAT_MOD_INVALID);
514
515 for (uint32_t j = 0; j < modifier_prop_count; j++) {
516 if (modifier_props[j].modifier == image->drm_modifier) {
517 image->num_planes = modifier_props[j].modifier_plane_count;
518 break;
519 }
520 }
521
522 for (uint32_t p = 0; p < image->num_planes; p++) {
523 const VkImageSubresource image_subresource = {
524 .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << p,
525 .mipLevel = 0,
526 .arrayLayer = 0,
527 };
528 VkSubresourceLayout image_layout;
529 wsi->GetImageSubresourceLayout(chain->device, image->image,
530 &image_subresource, &image_layout);
531 image->sizes[p] = image_layout.size;
532 image->row_pitches[p] = image_layout.rowPitch;
533 image->offsets[p] = image_layout.offset;
534 if (p == 0) {
535 image->fds[p] = fd;
536 } else {
537 image->fds[p] = dup(fd);
538 if (image->fds[p] == -1) {
539 for (uint32_t i = 0; i < p; i++)
540 close(image->fds[p]);
541
542 goto fail;
543 }
544 }
545 }
546 } else {
547 const VkImageSubresource image_subresource = {
548 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
549 .mipLevel = 0,
550 .arrayLayer = 0,
551 };
552 VkSubresourceLayout image_layout;
553 wsi->GetImageSubresourceLayout(chain->device, image->image,
554 &image_subresource, &image_layout);
555
556 image->drm_modifier = DRM_FORMAT_MOD_INVALID;
557 image->num_planes = 1;
558 image->sizes[0] = reqs.size;
559 image->row_pitches[0] = image_layout.rowPitch;
560 image->offsets[0] = 0;
561 image->fds[0] = fd;
562 }
563
564 vk_free(&chain->alloc, modifier_props);
565 vk_free(&chain->alloc, image_modifiers);
566
567 return VK_SUCCESS;
568
569 fail:
570 vk_free(&chain->alloc, modifier_props);
571 vk_free(&chain->alloc, image_modifiers);
572 wsi_destroy_image(chain, image);
573
574 return result;
575 }
576
577 #define WSI_PRIME_LINEAR_STRIDE_ALIGN 256
578
579 VkResult
580 wsi_create_prime_image(const struct wsi_swapchain *chain,
581 const VkSwapchainCreateInfoKHR *pCreateInfo,
582 bool use_modifier,
583 struct wsi_image *image)
584 {
585 const struct wsi_device *wsi = chain->wsi;
586 VkResult result;
587
588 memset(image, 0, sizeof(*image));
589
590 const uint32_t cpp = vk_format_size(pCreateInfo->imageFormat);
591 const uint32_t linear_stride = align_u32(pCreateInfo->imageExtent.width * cpp,
592 WSI_PRIME_LINEAR_STRIDE_ALIGN);
593
594 uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height;
595 linear_size = align_u32(linear_size, 4096);
596
597 const VkExternalMemoryBufferCreateInfo prime_buffer_external_info = {
598 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
599 .pNext = NULL,
600 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
601 };
602 const VkBufferCreateInfo prime_buffer_info = {
603 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
604 .pNext = &prime_buffer_external_info,
605 .size = linear_size,
606 .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
607 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
608 };
609 result = wsi->CreateBuffer(chain->device, &prime_buffer_info,
610 &chain->alloc, &image->prime.buffer);
611 if (result != VK_SUCCESS)
612 goto fail;
613
614 VkMemoryRequirements reqs;
615 wsi->GetBufferMemoryRequirements(chain->device, image->prime.buffer, &reqs);
616 assert(reqs.size <= linear_size);
617
618 const struct wsi_memory_allocate_info memory_wsi_info = {
619 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
620 .pNext = NULL,
621 .implicit_sync = true,
622 };
623 const VkExportMemoryAllocateInfo prime_memory_export_info = {
624 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
625 .pNext = &memory_wsi_info,
626 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
627 };
628 const VkMemoryDedicatedAllocateInfo prime_memory_dedicated_info = {
629 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
630 .pNext = &prime_memory_export_info,
631 .image = VK_NULL_HANDLE,
632 .buffer = image->prime.buffer,
633 };
634 const VkMemoryAllocateInfo prime_memory_info = {
635 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
636 .pNext = &prime_memory_dedicated_info,
637 .allocationSize = linear_size,
638 .memoryTypeIndex = select_memory_type(wsi, 0, reqs.memoryTypeBits),
639 };
640 result = wsi->AllocateMemory(chain->device, &prime_memory_info,
641 &chain->alloc, &image->prime.memory);
642 if (result != VK_SUCCESS)
643 goto fail;
644
645 result = wsi->BindBufferMemory(chain->device, image->prime.buffer,
646 image->prime.memory, 0);
647 if (result != VK_SUCCESS)
648 goto fail;
649
650 const VkImageCreateInfo image_info = {
651 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
652 .pNext = NULL,
653 .flags = 0,
654 .imageType = VK_IMAGE_TYPE_2D,
655 .format = pCreateInfo->imageFormat,
656 .extent = {
657 .width = pCreateInfo->imageExtent.width,
658 .height = pCreateInfo->imageExtent.height,
659 .depth = 1,
660 },
661 .mipLevels = 1,
662 .arrayLayers = 1,
663 .samples = VK_SAMPLE_COUNT_1_BIT,
664 .tiling = VK_IMAGE_TILING_OPTIMAL,
665 .usage = pCreateInfo->imageUsage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
666 .sharingMode = pCreateInfo->imageSharingMode,
667 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
668 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
669 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
670 };
671 result = wsi->CreateImage(chain->device, &image_info,
672 &chain->alloc, &image->image);
673 if (result != VK_SUCCESS)
674 goto fail;
675
676 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
677
678 const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {
679 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
680 .pNext = NULL,
681 .image = image->image,
682 .buffer = VK_NULL_HANDLE,
683 };
684 const VkMemoryAllocateInfo memory_info = {
685 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
686 .pNext = &memory_dedicated_info,
687 .allocationSize = reqs.size,
688 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
689 reqs.memoryTypeBits),
690 };
691 result = wsi->AllocateMemory(chain->device, &memory_info,
692 &chain->alloc, &image->memory);
693 if (result != VK_SUCCESS)
694 goto fail;
695
696 result = wsi->BindImageMemory(chain->device, image->image,
697 image->memory, 0);
698 if (result != VK_SUCCESS)
699 goto fail;
700
701 image->prime.blit_cmd_buffers =
702 vk_zalloc(&chain->alloc,
703 sizeof(VkCommandBuffer) * wsi->queue_family_count, 8,
704 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
705 if (!image->prime.blit_cmd_buffers) {
706 result = VK_ERROR_OUT_OF_HOST_MEMORY;
707 goto fail;
708 }
709
710 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
711 const VkCommandBufferAllocateInfo cmd_buffer_info = {
712 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
713 .pNext = NULL,
714 .commandPool = chain->cmd_pools[i],
715 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
716 .commandBufferCount = 1,
717 };
718 result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info,
719 &image->prime.blit_cmd_buffers[i]);
720 if (result != VK_SUCCESS)
721 goto fail;
722
723 const VkCommandBufferBeginInfo begin_info = {
724 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
725 };
726 wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info);
727
728 struct VkBufferImageCopy buffer_image_copy = {
729 .bufferOffset = 0,
730 .bufferRowLength = linear_stride / cpp,
731 .bufferImageHeight = 0,
732 .imageSubresource = {
733 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
734 .mipLevel = 0,
735 .baseArrayLayer = 0,
736 .layerCount = 1,
737 },
738 .imageOffset = { .x = 0, .y = 0, .z = 0 },
739 .imageExtent = {
740 .width = pCreateInfo->imageExtent.width,
741 .height = pCreateInfo->imageExtent.height,
742 .depth = 1,
743 },
744 };
745 wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i],
746 image->image,
747 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
748 image->prime.buffer,
749 1, &buffer_image_copy);
750
751 result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]);
752 if (result != VK_SUCCESS)
753 goto fail;
754 }
755
756 const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
757 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
758 .pNext = NULL,
759 .memory = image->prime.memory,
760 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
761 };
762 int fd;
763 result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd);
764 if (result != VK_SUCCESS)
765 goto fail;
766
767 image->drm_modifier = use_modifier ? DRM_FORMAT_MOD_LINEAR : DRM_FORMAT_MOD_INVALID;
768 image->num_planes = 1;
769 image->sizes[0] = linear_size;
770 image->row_pitches[0] = linear_stride;
771 image->offsets[0] = 0;
772 image->fds[0] = fd;
773
774 return VK_SUCCESS;
775
776 fail:
777 wsi_destroy_image(chain, image);
778
779 return result;
780 }
781
782 void
783 wsi_destroy_image(const struct wsi_swapchain *chain,
784 struct wsi_image *image)
785 {
786 const struct wsi_device *wsi = chain->wsi;
787
788 if (image->prime.blit_cmd_buffers) {
789 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
790 wsi->FreeCommandBuffers(chain->device, chain->cmd_pools[i],
791 1, &image->prime.blit_cmd_buffers[i]);
792 }
793 vk_free(&chain->alloc, image->prime.blit_cmd_buffers);
794 }
795
796 wsi->FreeMemory(chain->device, image->memory, &chain->alloc);
797 wsi->DestroyImage(chain->device, image->image, &chain->alloc);
798 wsi->FreeMemory(chain->device, image->prime.memory, &chain->alloc);
799 wsi->DestroyBuffer(chain->device, image->prime.buffer, &chain->alloc);
800 }
801
802 VkResult
803 wsi_common_get_surface_support(struct wsi_device *wsi_device,
804 uint32_t queueFamilyIndex,
805 VkSurfaceKHR _surface,
806 VkBool32* pSupported)
807 {
808 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
809 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
810
811 return iface->get_support(surface, wsi_device,
812 queueFamilyIndex, pSupported);
813 }
814
815 VkResult
816 wsi_common_get_surface_capabilities(struct wsi_device *wsi_device,
817 VkSurfaceKHR _surface,
818 VkSurfaceCapabilitiesKHR *pSurfaceCapabilities)
819 {
820 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
821 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
822
823 VkSurfaceCapabilities2KHR caps2 = {
824 .sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
825 };
826
827 VkResult result = iface->get_capabilities2(surface, wsi_device, NULL, &caps2);
828
829 if (result == VK_SUCCESS)
830 *pSurfaceCapabilities = caps2.surfaceCapabilities;
831
832 return result;
833 }
834
835 VkResult
836 wsi_common_get_surface_capabilities2(struct wsi_device *wsi_device,
837 const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
838 VkSurfaceCapabilities2KHR *pSurfaceCapabilities)
839 {
840 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
841 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
842
843 return iface->get_capabilities2(surface, wsi_device, pSurfaceInfo->pNext,
844 pSurfaceCapabilities);
845 }
846
847 VkResult
848 wsi_common_get_surface_capabilities2ext(
849 struct wsi_device *wsi_device,
850 VkSurfaceKHR _surface,
851 VkSurfaceCapabilities2EXT *pSurfaceCapabilities)
852 {
853 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
854 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
855
856 assert(pSurfaceCapabilities->sType ==
857 VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT);
858
859 struct wsi_surface_supported_counters counters = {
860 .sType = VK_STRUCTURE_TYPE_WSI_SURFACE_SUPPORTED_COUNTERS_MESA,
861 .pNext = pSurfaceCapabilities->pNext,
862 .supported_surface_counters = 0,
863 };
864
865 VkSurfaceCapabilities2KHR caps2 = {
866 .sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
867 .pNext = &counters,
868 };
869
870 VkResult result = iface->get_capabilities2(surface, wsi_device, NULL, &caps2);
871
872 if (result == VK_SUCCESS) {
873 VkSurfaceCapabilities2EXT *ext_caps = pSurfaceCapabilities;
874 VkSurfaceCapabilitiesKHR khr_caps = caps2.surfaceCapabilities;
875
876 ext_caps->minImageCount = khr_caps.minImageCount;
877 ext_caps->maxImageCount = khr_caps.maxImageCount;
878 ext_caps->currentExtent = khr_caps.currentExtent;
879 ext_caps->minImageExtent = khr_caps.minImageExtent;
880 ext_caps->maxImageExtent = khr_caps.maxImageExtent;
881 ext_caps->maxImageArrayLayers = khr_caps.maxImageArrayLayers;
882 ext_caps->supportedTransforms = khr_caps.supportedTransforms;
883 ext_caps->currentTransform = khr_caps.currentTransform;
884 ext_caps->supportedCompositeAlpha = khr_caps.supportedCompositeAlpha;
885 ext_caps->supportedUsageFlags = khr_caps.supportedUsageFlags;
886 ext_caps->supportedSurfaceCounters = counters.supported_surface_counters;
887 }
888
889 return result;
890 }
891
892 VkResult
893 wsi_common_get_surface_formats(struct wsi_device *wsi_device,
894 VkSurfaceKHR _surface,
895 uint32_t *pSurfaceFormatCount,
896 VkSurfaceFormatKHR *pSurfaceFormats)
897 {
898 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
899 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
900
901 return iface->get_formats(surface, wsi_device,
902 pSurfaceFormatCount, pSurfaceFormats);
903 }
904
905 VkResult
906 wsi_common_get_surface_formats2(struct wsi_device *wsi_device,
907 const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
908 uint32_t *pSurfaceFormatCount,
909 VkSurfaceFormat2KHR *pSurfaceFormats)
910 {
911 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
912 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
913
914 return iface->get_formats2(surface, wsi_device, pSurfaceInfo->pNext,
915 pSurfaceFormatCount, pSurfaceFormats);
916 }
917
918 VkResult
919 wsi_common_get_surface_present_modes(struct wsi_device *wsi_device,
920 VkSurfaceKHR _surface,
921 uint32_t *pPresentModeCount,
922 VkPresentModeKHR *pPresentModes)
923 {
924 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
925 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
926
927 return iface->get_present_modes(surface, pPresentModeCount,
928 pPresentModes);
929 }
930
931 VkResult
932 wsi_common_get_present_rectangles(struct wsi_device *wsi_device,
933 VkSurfaceKHR _surface,
934 uint32_t* pRectCount,
935 VkRect2D* pRects)
936 {
937 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
938 struct wsi_interface *iface = wsi_device->wsi[surface->platform];
939
940 return iface->get_present_rectangles(surface, wsi_device,
941 pRectCount, pRects);
942 }
943
944 VkResult
945 wsi_common_create_swapchain(struct wsi_device *wsi,
946 VkDevice device,
947 const VkSwapchainCreateInfoKHR *pCreateInfo,
948 const VkAllocationCallbacks *pAllocator,
949 VkSwapchainKHR *pSwapchain)
950 {
951 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface);
952 struct wsi_interface *iface = wsi->wsi[surface->platform];
953 struct wsi_swapchain *swapchain;
954
955 VkResult result = iface->create_swapchain(surface, device, wsi,
956 pCreateInfo, pAllocator,
957 &swapchain);
958 if (result != VK_SUCCESS)
959 return result;
960
961 swapchain->fences = vk_zalloc(pAllocator,
962 sizeof (*swapchain->fences) * swapchain->image_count,
963 sizeof (*swapchain->fences),
964 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
965 if (!swapchain->fences) {
966 swapchain->destroy(swapchain, pAllocator);
967 return VK_ERROR_OUT_OF_HOST_MEMORY;
968 }
969
970 *pSwapchain = wsi_swapchain_to_handle(swapchain);
971
972 return VK_SUCCESS;
973 }
974
975 void
976 wsi_common_destroy_swapchain(VkDevice device,
977 VkSwapchainKHR _swapchain,
978 const VkAllocationCallbacks *pAllocator)
979 {
980 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
981 if (!swapchain)
982 return;
983
984 swapchain->destroy(swapchain, pAllocator);
985 }
986
987 VkResult
988 wsi_common_get_images(VkSwapchainKHR _swapchain,
989 uint32_t *pSwapchainImageCount,
990 VkImage *pSwapchainImages)
991 {
992 WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
993 VK_OUTARRAY_MAKE(images, pSwapchainImages, pSwapchainImageCount);
994
995 for (uint32_t i = 0; i < swapchain->image_count; i++) {
996 vk_outarray_append(&images, image) {
997 *image = swapchain->get_wsi_image(swapchain, i)->image;
998 }
999 }
1000
1001 return vk_outarray_status(&images);
1002 }
1003
1004 VkResult
1005 wsi_common_acquire_next_image2(const struct wsi_device *wsi,
1006 VkDevice device,
1007 const VkAcquireNextImageInfoKHR *pAcquireInfo,
1008 uint32_t *pImageIndex)
1009 {
1010 WSI_FROM_HANDLE(wsi_swapchain, swapchain, pAcquireInfo->swapchain);
1011
1012 VkResult result = swapchain->acquire_next_image(swapchain, pAcquireInfo,
1013 pImageIndex);
1014 if (result != VK_SUCCESS)
1015 return result;
1016
1017 if (pAcquireInfo->semaphore != VK_NULL_HANDLE &&
1018 wsi->signal_semaphore_for_memory != NULL) {
1019 struct wsi_image *image =
1020 swapchain->get_wsi_image(swapchain, *pImageIndex);
1021 wsi->signal_semaphore_for_memory(device, pAcquireInfo->semaphore,
1022 image->memory);
1023 }
1024
1025 if (pAcquireInfo->fence != VK_NULL_HANDLE &&
1026 wsi->signal_fence_for_memory != NULL) {
1027 struct wsi_image *image =
1028 swapchain->get_wsi_image(swapchain, *pImageIndex);
1029 wsi->signal_fence_for_memory(device, pAcquireInfo->fence,
1030 image->memory);
1031 }
1032
1033 return VK_SUCCESS;
1034 }
1035
1036 VkResult
1037 wsi_common_queue_present(const struct wsi_device *wsi,
1038 VkDevice device,
1039 VkQueue queue,
1040 int queue_family_index,
1041 const VkPresentInfoKHR *pPresentInfo)
1042 {
1043 VkResult final_result = VK_SUCCESS;
1044
1045 const VkPresentRegionsKHR *regions =
1046 vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR);
1047
1048 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
1049 WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]);
1050 uint32_t image_index = pPresentInfo->pImageIndices[i];
1051 VkResult result;
1052
1053 if (swapchain->fences[image_index] == VK_NULL_HANDLE) {
1054 const VkFenceCreateInfo fence_info = {
1055 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1056 .pNext = NULL,
1057 .flags = 0,
1058 };
1059 result = wsi->CreateFence(device, &fence_info,
1060 &swapchain->alloc,
1061 &swapchain->fences[image_index]);
1062 if (result != VK_SUCCESS)
1063 goto fail_present;
1064 } else {
1065 result =
1066 wsi->WaitForFences(device, 1, &swapchain->fences[image_index],
1067 true, ~0ull);
1068 if (result != VK_SUCCESS)
1069 goto fail_present;
1070
1071 result =
1072 wsi->ResetFences(device, 1, &swapchain->fences[image_index]);
1073 if (result != VK_SUCCESS)
1074 goto fail_present;
1075 }
1076
1077 struct wsi_image *image =
1078 swapchain->get_wsi_image(swapchain, image_index);
1079
1080 struct wsi_memory_signal_submit_info mem_signal = {
1081 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA,
1082 .pNext = NULL,
1083 .memory = image->memory,
1084 };
1085
1086 VkSubmitInfo submit_info = {
1087 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1088 .pNext = &mem_signal,
1089 };
1090
1091 VkPipelineStageFlags *stage_flags = NULL;
1092 if (i == 0) {
1093 /* We only need/want to wait on semaphores once. After that, we're
1094 * guaranteed ordering since it all happens on the same queue.
1095 */
1096 submit_info.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount;
1097 submit_info.pWaitSemaphores = pPresentInfo->pWaitSemaphores;
1098
1099 /* Set up the pWaitDstStageMasks */
1100 stage_flags = vk_alloc(&swapchain->alloc,
1101 sizeof(VkPipelineStageFlags) *
1102 pPresentInfo->waitSemaphoreCount,
1103 8,
1104 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
1105 if (!stage_flags) {
1106 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1107 goto fail_present;
1108 }
1109 for (uint32_t s = 0; s < pPresentInfo->waitSemaphoreCount; s++)
1110 stage_flags[s] = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1111
1112 submit_info.pWaitDstStageMask = stage_flags;
1113 }
1114
1115 if (swapchain->use_prime_blit) {
1116 /* If we are using prime blits, we need to perform the blit now. The
1117 * command buffer is attached to the image.
1118 */
1119 submit_info.commandBufferCount = 1;
1120 submit_info.pCommandBuffers =
1121 &image->prime.blit_cmd_buffers[queue_family_index];
1122 mem_signal.memory = image->prime.memory;
1123 }
1124
1125 result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[image_index]);
1126 vk_free(&swapchain->alloc, stage_flags);
1127 if (result != VK_SUCCESS)
1128 goto fail_present;
1129
1130 const VkPresentRegionKHR *region = NULL;
1131 if (regions && regions->pRegions)
1132 region = &regions->pRegions[i];
1133
1134 result = swapchain->queue_present(swapchain, image_index, region);
1135 if (result != VK_SUCCESS)
1136 goto fail_present;
1137
1138 fail_present:
1139 if (pPresentInfo->pResults != NULL)
1140 pPresentInfo->pResults[i] = result;
1141
1142 /* Let the final result be our first unsuccessful result */
1143 if (final_result == VK_SUCCESS)
1144 final_result = result;
1145 }
1146
1147 return final_result;
1148 }
1149
1150 uint64_t
1151 wsi_common_get_current_time(void)
1152 {
1153 struct timespec current;
1154 clock_gettime(CLOCK_MONOTONIC, &current);
1155 return current.tv_nsec + current.tv_sec * 1000000000ull;
1156 }