• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "wsi_common_drm.h"
26 #include "util/macros.h"
27 #include "util/os_file.h"
28 #include "util/xmlconfig.h"
29 #include "vk_device.h"
30 #include "vk_physical_device.h"
31 #include "vk_util.h"
32 #include "drm-uapi/drm_fourcc.h"
33 
34 #include <errno.h>
35 #include <linux/dma-buf.h>
36 #include <linux/sync_file.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <xf86drm.h>
42 
43 struct dma_buf_export_sync_file_wsi {
44    __u32 flags;
45    __s32 fd;
46 };
47 
48 struct dma_buf_import_sync_file_wsi {
49    __u32 flags;
50    __s32 fd;
51 };
52 
53 #define DMA_BUF_IOCTL_EXPORT_SYNC_FILE_WSI   _IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file_wsi)
54 #define DMA_BUF_IOCTL_IMPORT_SYNC_FILE_WSI   _IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file_wsi)
55 
56 static VkResult
wsi_dma_buf_export_sync_file(int dma_buf_fd,int * sync_file_fd)57 wsi_dma_buf_export_sync_file(int dma_buf_fd, int *sync_file_fd)
58 {
59    /* Don't keep trying an IOCTL that doesn't exist. */
60    static bool no_dma_buf_sync_file = false;
61    if (no_dma_buf_sync_file)
62       return VK_ERROR_FEATURE_NOT_PRESENT;
63 
64    struct dma_buf_export_sync_file_wsi export = {
65       .flags = DMA_BUF_SYNC_RW,
66       .fd = -1,
67    };
68    int ret = drmIoctl(dma_buf_fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE_WSI, &export);
69    if (ret) {
70       if (errno == ENOTTY || errno == EBADF || errno == ENOSYS) {
71          no_dma_buf_sync_file = true;
72          return VK_ERROR_FEATURE_NOT_PRESENT;
73       } else {
74          return VK_ERROR_OUT_OF_HOST_MEMORY;
75       }
76    }
77 
78    *sync_file_fd = export.fd;
79 
80    return VK_SUCCESS;
81 }
82 
83 static VkResult
wsi_dma_buf_import_sync_file(int dma_buf_fd,int sync_file_fd)84 wsi_dma_buf_import_sync_file(int dma_buf_fd, int sync_file_fd)
85 {
86    /* Don't keep trying an IOCTL that doesn't exist. */
87    static bool no_dma_buf_sync_file = false;
88    if (no_dma_buf_sync_file)
89       return VK_ERROR_FEATURE_NOT_PRESENT;
90 
91    struct dma_buf_import_sync_file_wsi import = {
92       .flags = DMA_BUF_SYNC_RW,
93       .fd = sync_file_fd,
94    };
95    int ret = drmIoctl(dma_buf_fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE_WSI, &import);
96    if (ret) {
97       if (errno == ENOTTY || errno == EBADF || errno == ENOSYS) {
98          no_dma_buf_sync_file = true;
99          return VK_ERROR_FEATURE_NOT_PRESENT;
100       } else {
101          return VK_ERROR_OUT_OF_HOST_MEMORY;
102       }
103    }
104 
105    return VK_SUCCESS;
106 }
107 
108 static VkResult
prepare_signal_dma_buf_from_semaphore(struct wsi_swapchain * chain,const struct wsi_image * image)109 prepare_signal_dma_buf_from_semaphore(struct wsi_swapchain *chain,
110                                       const struct wsi_image *image)
111 {
112    VkResult result;
113 
114    if (!(chain->wsi->semaphore_export_handle_types &
115          VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT))
116       return VK_ERROR_FEATURE_NOT_PRESENT;
117 
118    int sync_file_fd = -1;
119    result = wsi_dma_buf_export_sync_file(image->dma_buf_fd, &sync_file_fd);
120    if (result != VK_SUCCESS)
121       return result;
122 
123    result = wsi_dma_buf_import_sync_file(image->dma_buf_fd, sync_file_fd);
124    close(sync_file_fd);
125    if (result != VK_SUCCESS)
126       return result;
127 
128    /* If we got here, all our checks pass.  Create the actual semaphore */
129    const VkExportSemaphoreCreateInfo export_info = {
130       .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
131       .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
132    };
133    const VkSemaphoreCreateInfo semaphore_info = {
134       .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
135       .pNext = &export_info,
136    };
137    result = chain->wsi->CreateSemaphore(chain->device, &semaphore_info,
138                                         &chain->alloc,
139                                         &chain->dma_buf_semaphore);
140    if (result != VK_SUCCESS)
141       return result;
142 
143    return VK_SUCCESS;
144 }
145 
146 VkResult
wsi_prepare_signal_dma_buf_from_semaphore(struct wsi_swapchain * chain,const struct wsi_image * image)147 wsi_prepare_signal_dma_buf_from_semaphore(struct wsi_swapchain *chain,
148                                           const struct wsi_image *image)
149 {
150    VkResult result;
151 
152    /* We cache result - 1 in the swapchain */
153    if (unlikely(chain->signal_dma_buf_from_semaphore == 0)) {
154       result = prepare_signal_dma_buf_from_semaphore(chain, image);
155       assert(result <= 0);
156       chain->signal_dma_buf_from_semaphore = (int)result - 1;
157    } else {
158       result = (VkResult)(chain->signal_dma_buf_from_semaphore + 1);
159    }
160 
161    return result;
162 }
163 
164 VkResult
wsi_signal_dma_buf_from_semaphore(const struct wsi_swapchain * chain,const struct wsi_image * image)165 wsi_signal_dma_buf_from_semaphore(const struct wsi_swapchain *chain,
166                                   const struct wsi_image *image)
167 {
168    VkResult result;
169 
170    const VkSemaphoreGetFdInfoKHR get_fd_info = {
171       .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
172       .semaphore = chain->dma_buf_semaphore,
173       .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
174    };
175    int sync_file_fd = -1;
176    result = chain->wsi->GetSemaphoreFdKHR(chain->device, &get_fd_info,
177                                           &sync_file_fd);
178    if (result != VK_SUCCESS)
179       return result;
180 
181    result = wsi_dma_buf_import_sync_file(image->dma_buf_fd, sync_file_fd);
182    close(sync_file_fd);
183    return result;
184 }
185 
186 static const struct vk_sync_type *
get_sync_file_sync_type(struct vk_device * device,enum vk_sync_features req_features)187 get_sync_file_sync_type(struct vk_device *device,
188                         enum vk_sync_features req_features)
189 {
190    for (const struct vk_sync_type *const *t =
191         device->physical->supported_sync_types; *t; t++) {
192       if (req_features & ~(*t)->features)
193          continue;
194 
195       if ((*t)->import_sync_file != NULL)
196          return *t;
197    }
198 
199    return NULL;
200 }
201 
202 VkResult
wsi_create_sync_for_dma_buf_wait(const struct wsi_swapchain * chain,const struct wsi_image * image,enum vk_sync_features req_features,struct vk_sync ** sync_out)203 wsi_create_sync_for_dma_buf_wait(const struct wsi_swapchain *chain,
204                                  const struct wsi_image *image,
205                                  enum vk_sync_features req_features,
206                                  struct vk_sync **sync_out)
207 {
208    VK_FROM_HANDLE(vk_device, device, chain->device);
209    VkResult result;
210 
211    const struct vk_sync_type *sync_type =
212       get_sync_file_sync_type(device, req_features);
213    if (sync_type == NULL)
214       return VK_ERROR_FEATURE_NOT_PRESENT;
215 
216    int sync_file_fd = -1;
217    result = wsi_dma_buf_export_sync_file(image->dma_buf_fd, &sync_file_fd);
218    if (result != VK_SUCCESS)
219       return result;
220 
221    struct vk_sync *sync = NULL;
222    result = vk_sync_create(device, sync_type, VK_SYNC_IS_SHAREABLE, 0, &sync);
223    if (result != VK_SUCCESS)
224       goto fail_close_sync_file;
225 
226    result = vk_sync_import_sync_file(device, sync, sync_file_fd);
227    if (result != VK_SUCCESS)
228       goto fail_destroy_sync;
229 
230    close(sync_file_fd);
231    *sync_out = sync;
232 
233    return VK_SUCCESS;
234 
235 fail_destroy_sync:
236    vk_sync_destroy(device, sync);
237 fail_close_sync_file:
238    close(sync_file_fd);
239 
240    return result;
241 }
242 
243 bool
wsi_common_drm_devices_equal(int fd_a,int fd_b)244 wsi_common_drm_devices_equal(int fd_a, int fd_b)
245 {
246    drmDevicePtr device_a, device_b;
247    int ret;
248 
249    ret = drmGetDevice2(fd_a, 0, &device_a);
250    if (ret)
251       return false;
252 
253    ret = drmGetDevice2(fd_b, 0, &device_b);
254    if (ret) {
255       drmFreeDevice(&device_a);
256       return false;
257    }
258 
259    bool result = drmDevicesEqual(device_a, device_b);
260 
261    drmFreeDevice(&device_a);
262    drmFreeDevice(&device_b);
263 
264    return result;
265 }
266 
267 bool
wsi_device_matches_drm_fd(const struct wsi_device * wsi,int drm_fd)268 wsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd)
269 {
270    if (wsi->can_present_on_device)
271       return wsi->can_present_on_device(wsi->pdevice, drm_fd);
272 
273    drmDevicePtr fd_device;
274    int ret = drmGetDevice2(drm_fd, 0, &fd_device);
275    if (ret)
276       return false;
277 
278    bool match = false;
279    switch (fd_device->bustype) {
280    case DRM_BUS_PCI:
281       match = wsi->pci_bus_info.pciDomain == fd_device->businfo.pci->domain &&
282               wsi->pci_bus_info.pciBus == fd_device->businfo.pci->bus &&
283               wsi->pci_bus_info.pciDevice == fd_device->businfo.pci->dev &&
284               wsi->pci_bus_info.pciFunction == fd_device->businfo.pci->func;
285       break;
286 
287    default:
288       break;
289    }
290 
291    drmFreeDevice(&fd_device);
292 
293    return match;
294 }
295 
296 static uint32_t
prime_select_buffer_memory_type(const struct wsi_device * wsi,uint32_t type_bits)297 prime_select_buffer_memory_type(const struct wsi_device *wsi,
298                                 uint32_t type_bits)
299 {
300    return wsi_select_memory_type(wsi, 0 /* req_props */,
301                                  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
302                                  type_bits);
303 }
304 
305 static const struct VkDrmFormatModifierPropertiesEXT *
get_modifier_props(const struct wsi_image_info * info,uint64_t modifier)306 get_modifier_props(const struct wsi_image_info *info, uint64_t modifier)
307 {
308    for (uint32_t i = 0; i < info->modifier_prop_count; i++) {
309       if (info->modifier_props[i].drmFormatModifier == modifier)
310          return &info->modifier_props[i];
311    }
312    return NULL;
313 }
314 
315 static VkResult
316 wsi_create_native_image_mem(const struct wsi_swapchain *chain,
317                             const struct wsi_image_info *info,
318                             struct wsi_image *image);
319 
320 VkResult
wsi_configure_native_image(const struct wsi_swapchain * chain,const VkSwapchainCreateInfoKHR * pCreateInfo,uint32_t num_modifier_lists,const uint32_t * num_modifiers,const uint64_t * const * modifiers,struct wsi_image_info * info)321 wsi_configure_native_image(const struct wsi_swapchain *chain,
322                            const VkSwapchainCreateInfoKHR *pCreateInfo,
323                            uint32_t num_modifier_lists,
324                            const uint32_t *num_modifiers,
325                            const uint64_t *const *modifiers,
326                            struct wsi_image_info *info)
327 {
328    const struct wsi_device *wsi = chain->wsi;
329 
330    VkExternalMemoryHandleTypeFlags handle_type =
331       VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
332 
333    VkResult result = wsi_configure_image(chain, pCreateInfo, handle_type, info);
334    if (result != VK_SUCCESS)
335       return result;
336 
337    if (num_modifier_lists == 0) {
338       /* If we don't have modifiers, fall back to the legacy "scanout" flag */
339       info->wsi.scanout = true;
340    } else {
341       /* The winsys can't request modifiers if we don't support them. */
342       assert(wsi->supports_modifiers);
343       struct VkDrmFormatModifierPropertiesListEXT modifier_props_list = {
344          .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
345       };
346       VkFormatProperties2 format_props = {
347          .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
348          .pNext = &modifier_props_list,
349       };
350       wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice,
351                                                  pCreateInfo->imageFormat,
352                                                  &format_props);
353       assert(modifier_props_list.drmFormatModifierCount > 0);
354       info->modifier_props =
355          vk_alloc(&chain->alloc,
356                   sizeof(*info->modifier_props) *
357                   modifier_props_list.drmFormatModifierCount,
358                   8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
359       if (info->modifier_props == NULL)
360          goto fail_oom;
361 
362       modifier_props_list.pDrmFormatModifierProperties = info->modifier_props;
363       wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice,
364                                                  pCreateInfo->imageFormat,
365                                                  &format_props);
366 
367       /* Call GetImageFormatProperties with every modifier and filter the list
368        * down to those that we know work.
369        */
370       info->modifier_prop_count = 0;
371       for (uint32_t i = 0; i < modifier_props_list.drmFormatModifierCount; i++) {
372          VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info = {
373             .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
374             .drmFormatModifier = info->modifier_props[i].drmFormatModifier,
375             .sharingMode = pCreateInfo->imageSharingMode,
376             .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
377             .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
378          };
379          VkPhysicalDeviceImageFormatInfo2 format_info = {
380             .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
381             .format = pCreateInfo->imageFormat,
382             .type = VK_IMAGE_TYPE_2D,
383             .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
384             .usage = pCreateInfo->imageUsage,
385             .flags = info->create.flags,
386          };
387 
388          VkImageFormatListCreateInfo format_list;
389          if (info->create.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) {
390             format_list = info->format_list;
391             format_list.pNext = NULL;
392             __vk_append_struct(&format_info, &format_list);
393          }
394 
395          VkImageFormatProperties2 format_props = {
396             .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
397             .pNext = NULL,
398          };
399          __vk_append_struct(&format_info, &mod_info);
400          result = wsi->GetPhysicalDeviceImageFormatProperties2(wsi->pdevice,
401                                                                &format_info,
402                                                                &format_props);
403          if (result == VK_SUCCESS &&
404              pCreateInfo->imageExtent.width <= format_props.imageFormatProperties.maxExtent.width &&
405              pCreateInfo->imageExtent.height <= format_props.imageFormatProperties.maxExtent.height)
406             info->modifier_props[info->modifier_prop_count++] = info->modifier_props[i];
407       }
408 
409       uint32_t max_modifier_count = 0;
410       for (uint32_t l = 0; l < num_modifier_lists; l++)
411          max_modifier_count = MAX2(max_modifier_count, num_modifiers[l]);
412 
413       uint64_t *image_modifiers =
414          vk_alloc(&chain->alloc, sizeof(*image_modifiers) * max_modifier_count,
415                   8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
416       if (!image_modifiers)
417          goto fail_oom;
418 
419       uint32_t image_modifier_count = 0;
420       for (uint32_t l = 0; l < num_modifier_lists; l++) {
421          /* Walk the modifier lists and construct a list of supported
422           * modifiers.
423           */
424          for (uint32_t i = 0; i < num_modifiers[l]; i++) {
425             if (get_modifier_props(info, modifiers[l][i]))
426                image_modifiers[image_modifier_count++] = modifiers[l][i];
427          }
428 
429          /* We only want to take the modifiers from the first list */
430          if (image_modifier_count > 0)
431             break;
432       }
433 
434       if (image_modifier_count > 0) {
435          info->create.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
436          info->drm_mod_list = (VkImageDrmFormatModifierListCreateInfoEXT) {
437             .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
438             .drmFormatModifierCount = image_modifier_count,
439             .pDrmFormatModifiers = image_modifiers,
440          };
441          image_modifiers = NULL;
442          __vk_append_struct(&info->create, &info->drm_mod_list);
443       } else {
444          vk_free(&chain->alloc, image_modifiers);
445          /* TODO: Add a proper error here */
446          assert(!"Failed to find a supported modifier!  This should never "
447                  "happen because LINEAR should always be available");
448          goto fail_oom;
449       }
450    }
451 
452    info->create_mem = wsi_create_native_image_mem;
453 
454    return VK_SUCCESS;
455 
456 fail_oom:
457    wsi_destroy_image_info(chain, info);
458    return VK_ERROR_OUT_OF_HOST_MEMORY;
459 }
460 
461 static VkResult
wsi_create_native_image_mem(const struct wsi_swapchain * chain,const struct wsi_image_info * info,struct wsi_image * image)462 wsi_create_native_image_mem(const struct wsi_swapchain *chain,
463                             const struct wsi_image_info *info,
464                             struct wsi_image *image)
465 {
466    const struct wsi_device *wsi = chain->wsi;
467    VkResult result;
468 
469    VkMemoryRequirements reqs;
470    wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
471 
472    const struct wsi_memory_allocate_info memory_wsi_info = {
473       .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
474       .pNext = NULL,
475       .implicit_sync = true,
476    };
477    const VkExportMemoryAllocateInfo memory_export_info = {
478       .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
479       .pNext = &memory_wsi_info,
480       .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
481    };
482    const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {
483       .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
484       .pNext = &memory_export_info,
485       .image = image->image,
486       .buffer = VK_NULL_HANDLE,
487    };
488    const VkMemoryAllocateInfo memory_info = {
489       .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
490       .pNext = &memory_dedicated_info,
491       .allocationSize = reqs.size,
492       .memoryTypeIndex =
493          wsi_select_device_memory_type(wsi, reqs.memoryTypeBits),
494    };
495    result = wsi->AllocateMemory(chain->device, &memory_info,
496                                 &chain->alloc, &image->memory);
497    if (result != VK_SUCCESS)
498       return result;
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 
507    result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info,
508                                 &image->dma_buf_fd);
509    if (result != VK_SUCCESS)
510       return result;
511 
512    if (info->drm_mod_list.drmFormatModifierCount > 0) {
513       VkImageDrmFormatModifierPropertiesEXT image_mod_props = {
514          .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
515       };
516       result = wsi->GetImageDrmFormatModifierPropertiesEXT(chain->device,
517                                                            image->image,
518                                                            &image_mod_props);
519       if (result != VK_SUCCESS)
520          return result;
521 
522       image->drm_modifier = image_mod_props.drmFormatModifier;
523       assert(image->drm_modifier != DRM_FORMAT_MOD_INVALID);
524 
525       const struct VkDrmFormatModifierPropertiesEXT *mod_props =
526          get_modifier_props(info, image->drm_modifier);
527       image->num_planes = mod_props->drmFormatModifierPlaneCount;
528 
529       for (uint32_t p = 0; p < image->num_planes; p++) {
530          const VkImageSubresource image_subresource = {
531             .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << p,
532             .mipLevel = 0,
533             .arrayLayer = 0,
534          };
535          VkSubresourceLayout image_layout;
536          wsi->GetImageSubresourceLayout(chain->device, image->image,
537                                         &image_subresource, &image_layout);
538          image->sizes[p] = image_layout.size;
539          image->row_pitches[p] = image_layout.rowPitch;
540          image->offsets[p] = image_layout.offset;
541       }
542    } else {
543       const VkImageSubresource image_subresource = {
544          .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
545          .mipLevel = 0,
546          .arrayLayer = 0,
547       };
548       VkSubresourceLayout image_layout;
549       wsi->GetImageSubresourceLayout(chain->device, image->image,
550                                      &image_subresource, &image_layout);
551 
552       image->drm_modifier = DRM_FORMAT_MOD_INVALID;
553       image->num_planes = 1;
554       image->sizes[0] = reqs.size;
555       image->row_pitches[0] = image_layout.rowPitch;
556       image->offsets[0] = 0;
557    }
558 
559    return VK_SUCCESS;
560 }
561 
562 #define WSI_PRIME_LINEAR_STRIDE_ALIGN 256
563 
564 static VkResult
wsi_create_prime_image_mem(const struct wsi_swapchain * chain,const struct wsi_image_info * info,struct wsi_image * image)565 wsi_create_prime_image_mem(const struct wsi_swapchain *chain,
566                            const struct wsi_image_info *info,
567                            struct wsi_image *image)
568 {
569    const struct wsi_device *wsi = chain->wsi;
570    VkResult result =
571       wsi_create_buffer_image_mem(chain, info, image,
572                                   VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
573                                   true);
574    if (result != VK_SUCCESS)
575       return result;
576 
577    const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
578       .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
579       .pNext = NULL,
580       .memory = image->buffer.memory,
581       .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
582    };
583    result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info,
584                                 &image->dma_buf_fd);
585    if (result != VK_SUCCESS)
586       return result;
587 
588    image->drm_modifier = info->prime_use_linear_modifier ?
589                          DRM_FORMAT_MOD_LINEAR : DRM_FORMAT_MOD_INVALID;
590 
591    return VK_SUCCESS;
592 }
593 
594 VkResult
wsi_configure_prime_image(UNUSED const struct wsi_swapchain * chain,const VkSwapchainCreateInfoKHR * pCreateInfo,bool use_modifier,struct wsi_image_info * info)595 wsi_configure_prime_image(UNUSED const struct wsi_swapchain *chain,
596                           const VkSwapchainCreateInfoKHR *pCreateInfo,
597                           bool use_modifier,
598                           struct wsi_image_info *info)
599 {
600    VkResult result =
601       wsi_configure_buffer_image(chain, pCreateInfo,
602                                  WSI_PRIME_LINEAR_STRIDE_ALIGN, 4096,
603                                  info);
604    if (result != VK_SUCCESS)
605       return result;
606 
607    info->prime_use_linear_modifier = use_modifier;
608 
609    info->create_mem = wsi_create_prime_image_mem;
610    info->select_buffer_memory_type = prime_select_buffer_memory_type;
611    info->select_image_memory_type = wsi_select_device_memory_type;
612 
613    return VK_SUCCESS;
614 }
615