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
43struct dma_buf_export_sync_file_wsi {
44   __u32 flags;
45   __s32 fd;
46};
47
48struct 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
56static VkResult
57wsi_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
83static VkResult
84wsi_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
108static VkResult
109prepare_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
146VkResult
147wsi_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
164VkResult
165wsi_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
186static const struct vk_sync_type *
187get_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
202VkResult
203wsi_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
235fail_destroy_sync:
236   vk_sync_destroy(device, sync);
237fail_close_sync_file:
238   close(sync_file_fd);
239
240   return result;
241}
242
243bool
244wsi_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
267bool
268wsi_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
296static uint32_t
297prime_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
305static const struct VkDrmFormatModifierPropertiesEXT *
306get_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
315static VkResult
316wsi_create_native_image_mem(const struct wsi_swapchain *chain,
317                            const struct wsi_image_info *info,
318                            struct wsi_image *image);
319
320VkResult
321wsi_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
456fail_oom:
457   wsi_destroy_image_info(chain, info);
458   return VK_ERROR_OUT_OF_HOST_MEMORY;
459}
460
461static VkResult
462wsi_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
564static VkResult
565wsi_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
594VkResult
595wsi_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