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