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