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_format.h"
30 #include "vk_util.h"
31 #include "drm-uapi/drm_fourcc.h"
32
33 #include <time.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <xf86drm.h>
38
39 bool
wsi_common_drm_devices_equal(int fd_a,int fd_b)40 wsi_common_drm_devices_equal(int fd_a, int fd_b)
41 {
42 drmDevicePtr device_a, device_b;
43 int ret;
44
45 ret = drmGetDevice2(fd_a, 0, &device_a);
46 if (ret)
47 return false;
48
49 ret = drmGetDevice2(fd_b, 0, &device_b);
50 if (ret) {
51 drmFreeDevice(&device_a);
52 return false;
53 }
54
55 bool result = drmDevicesEqual(device_a, device_b);
56
57 drmFreeDevice(&device_a);
58 drmFreeDevice(&device_b);
59
60 return result;
61 }
62
63 bool
wsi_device_matches_drm_fd(const struct wsi_device * wsi,int drm_fd)64 wsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd)
65 {
66 if (wsi->can_present_on_device)
67 return wsi->can_present_on_device(wsi->pdevice, drm_fd);
68
69 drmDevicePtr fd_device;
70 int ret = drmGetDevice2(drm_fd, 0, &fd_device);
71 if (ret)
72 return false;
73
74 bool match = false;
75 switch (fd_device->bustype) {
76 case DRM_BUS_PCI:
77 match = wsi->pci_bus_info.pciDomain == fd_device->businfo.pci->domain &&
78 wsi->pci_bus_info.pciBus == fd_device->businfo.pci->bus &&
79 wsi->pci_bus_info.pciDevice == fd_device->businfo.pci->dev &&
80 wsi->pci_bus_info.pciFunction == fd_device->businfo.pci->func;
81 break;
82
83 default:
84 break;
85 }
86
87 drmFreeDevice(&fd_device);
88
89 return match;
90 }
91
92 static uint32_t
select_memory_type(const struct wsi_device * wsi,bool want_device_local,uint32_t type_bits)93 select_memory_type(const struct wsi_device *wsi,
94 bool want_device_local,
95 uint32_t type_bits)
96 {
97 assert(type_bits);
98
99 bool all_local = true;
100 for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) {
101 const VkMemoryType type = wsi->memory_props.memoryTypes[i];
102 bool local = type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
103
104 if ((type_bits & (1 << i)) && local == want_device_local)
105 return i;
106 all_local &= local;
107 }
108
109 /* ignore want_device_local when all memory types are device-local */
110 if (all_local) {
111 assert(!want_device_local);
112 return ffs(type_bits) - 1;
113 }
114
115 unreachable("No memory type found");
116 }
117
118 static uint32_t
prime_select_buffer_memory_type(const struct wsi_device * wsi,uint32_t type_bits)119 prime_select_buffer_memory_type(const struct wsi_device *wsi,
120 uint32_t type_bits)
121 {
122 return select_memory_type(wsi, false, type_bits);
123 }
124
125 static uint32_t
prime_select_image_memory_type(const struct wsi_device * wsi,uint32_t type_bits)126 prime_select_image_memory_type(const struct wsi_device *wsi,
127 uint32_t type_bits)
128 {
129 return select_memory_type(wsi, true, type_bits);
130 }
131
132 static const struct VkDrmFormatModifierPropertiesEXT *
get_modifier_props(const struct wsi_image_info * info,uint64_t modifier)133 get_modifier_props(const struct wsi_image_info *info, uint64_t modifier)
134 {
135 for (uint32_t i = 0; i < info->modifier_prop_count; i++) {
136 if (info->modifier_props[i].drmFormatModifier == modifier)
137 return &info->modifier_props[i];
138 }
139 return NULL;
140 }
141
142 static VkResult
143 wsi_create_native_image_mem(const struct wsi_swapchain *chain,
144 const struct wsi_image_info *info,
145 struct wsi_image *image);
146
147 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,uint8_t * (alloc_shm)(struct wsi_image * image,unsigned size),struct wsi_image_info * info)148 wsi_configure_native_image(const struct wsi_swapchain *chain,
149 const VkSwapchainCreateInfoKHR *pCreateInfo,
150 uint32_t num_modifier_lists,
151 const uint32_t *num_modifiers,
152 const uint64_t *const *modifiers,
153 uint8_t *(alloc_shm)(struct wsi_image *image,
154 unsigned size),
155 struct wsi_image_info *info)
156 {
157 const struct wsi_device *wsi = chain->wsi;
158
159 VkExternalMemoryHandleTypeFlags handle_type =
160 wsi->sw ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT :
161 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
162
163 VkResult result = wsi_configure_image(chain, pCreateInfo, handle_type, info);
164 if (result != VK_SUCCESS)
165 return result;
166
167 if (num_modifier_lists == 0) {
168 /* If we don't have modifiers, fall back to the legacy "scanout" flag */
169 info->wsi.scanout = true;
170 } else {
171 /* The winsys can't request modifiers if we don't support them. */
172 assert(wsi->supports_modifiers);
173 struct VkDrmFormatModifierPropertiesListEXT modifier_props_list = {
174 .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
175 };
176 VkFormatProperties2 format_props = {
177 .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
178 .pNext = &modifier_props_list,
179 };
180 wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice,
181 pCreateInfo->imageFormat,
182 &format_props);
183 assert(modifier_props_list.drmFormatModifierCount > 0);
184 info->modifier_props =
185 vk_alloc(&chain->alloc,
186 sizeof(*info->modifier_props) *
187 modifier_props_list.drmFormatModifierCount,
188 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
189 if (info->modifier_props == NULL)
190 goto fail_oom;
191
192 modifier_props_list.pDrmFormatModifierProperties = info->modifier_props;
193 wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice,
194 pCreateInfo->imageFormat,
195 &format_props);
196
197 /* Call GetImageFormatProperties with every modifier and filter the list
198 * down to those that we know work.
199 */
200 info->modifier_prop_count = 0;
201 for (uint32_t i = 0; i < modifier_props_list.drmFormatModifierCount; i++) {
202 VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info = {
203 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
204 .drmFormatModifier = info->modifier_props[i].drmFormatModifier,
205 .sharingMode = pCreateInfo->imageSharingMode,
206 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
207 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
208 };
209 VkPhysicalDeviceImageFormatInfo2 format_info = {
210 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
211 .format = pCreateInfo->imageFormat,
212 .type = VK_IMAGE_TYPE_2D,
213 .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
214 .usage = pCreateInfo->imageUsage,
215 .flags = info->create.flags,
216 };
217
218 VkImageFormatListCreateInfoKHR format_list;
219 if (info->create.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) {
220 format_list = info->format_list;
221 format_list.pNext = NULL;
222 __vk_append_struct(&format_info, &format_list);
223 }
224
225 VkImageFormatProperties2 format_props = {
226 .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
227 .pNext = NULL,
228 };
229 __vk_append_struct(&format_info, &mod_info);
230 result = wsi->GetPhysicalDeviceImageFormatProperties2(wsi->pdevice,
231 &format_info,
232 &format_props);
233 if (result == VK_SUCCESS)
234 info->modifier_props[info->modifier_prop_count++] = info->modifier_props[i];
235 }
236
237 uint32_t max_modifier_count = 0;
238 for (uint32_t l = 0; l < num_modifier_lists; l++)
239 max_modifier_count = MAX2(max_modifier_count, num_modifiers[l]);
240
241 uint64_t *image_modifiers =
242 vk_alloc(&chain->alloc, sizeof(*image_modifiers) * max_modifier_count,
243 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
244 if (!image_modifiers)
245 goto fail_oom;
246
247 uint32_t image_modifier_count = 0;
248 for (uint32_t l = 0; l < num_modifier_lists; l++) {
249 /* Walk the modifier lists and construct a list of supported
250 * modifiers.
251 */
252 for (uint32_t i = 0; i < num_modifiers[l]; i++) {
253 if (get_modifier_props(info, modifiers[l][i]))
254 image_modifiers[image_modifier_count++] = modifiers[l][i];
255 }
256
257 /* We only want to take the modifiers from the first list */
258 if (image_modifier_count > 0)
259 break;
260 }
261
262 if (image_modifier_count > 0) {
263 info->create.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
264 info->drm_mod_list = (VkImageDrmFormatModifierListCreateInfoEXT) {
265 .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
266 .drmFormatModifierCount = image_modifier_count,
267 .pDrmFormatModifiers = image_modifiers,
268 };
269 image_modifiers = NULL;
270 __vk_append_struct(&info->create, &info->drm_mod_list);
271 } else {
272 vk_free(&chain->alloc, image_modifiers);
273 /* TODO: Add a proper error here */
274 assert(!"Failed to find a supported modifier! This should never "
275 "happen because LINEAR should always be available");
276 goto fail_oom;
277 }
278 }
279
280 info->alloc_shm = alloc_shm;
281 info->create_mem = wsi_create_native_image_mem;
282
283 return VK_SUCCESS;
284
285 fail_oom:
286 wsi_destroy_image_info(chain, info);
287 return VK_ERROR_OUT_OF_HOST_MEMORY;
288 }
289
290 static VkResult
wsi_create_native_image_mem(const struct wsi_swapchain * chain,const struct wsi_image_info * info,struct wsi_image * image)291 wsi_create_native_image_mem(const struct wsi_swapchain *chain,
292 const struct wsi_image_info *info,
293 struct wsi_image *image)
294 {
295 const struct wsi_device *wsi = chain->wsi;
296 VkResult result;
297
298 VkMemoryRequirements reqs;
299 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
300
301 void *sw_host_ptr = NULL;
302 if (info->alloc_shm) {
303 VkSubresourceLayout layout;
304
305 wsi->GetImageSubresourceLayout(chain->device, image->image,
306 &(VkImageSubresource) {
307 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
308 .mipLevel = 0,
309 .arrayLayer = 0,
310 }, &layout);
311 sw_host_ptr = info->alloc_shm(image, layout.size);
312 }
313
314 const struct wsi_memory_allocate_info memory_wsi_info = {
315 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
316 .pNext = NULL,
317 .implicit_sync = true,
318 };
319 const VkExportMemoryAllocateInfo memory_export_info = {
320 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
321 .pNext = &memory_wsi_info,
322 .handleTypes = wsi->sw ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT :
323 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
324 };
325 const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {
326 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
327 .pNext = &memory_export_info,
328 .image = image->image,
329 .buffer = VK_NULL_HANDLE,
330 };
331 const VkImportMemoryHostPointerInfoEXT host_ptr_info = {
332 .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
333 .pNext = &memory_dedicated_info,
334 .pHostPointer = sw_host_ptr,
335 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
336 };
337 const VkMemoryAllocateInfo memory_info = {
338 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
339 .pNext = sw_host_ptr ? (void *)&host_ptr_info : (void *)&memory_dedicated_info,
340 .allocationSize = reqs.size,
341 .memoryTypeIndex = select_memory_type(wsi, true, reqs.memoryTypeBits),
342 };
343 result = wsi->AllocateMemory(chain->device, &memory_info,
344 &chain->alloc, &image->memory);
345 if (result != VK_SUCCESS)
346 return result;
347
348 int fd = -1;
349 if (!wsi->sw) {
350 const VkMemoryGetFdInfoKHR memory_get_fd_info = {
351 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
352 .pNext = NULL,
353 .memory = image->memory,
354 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
355 };
356
357 result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd);
358 if (result != VK_SUCCESS)
359 return result;
360 }
361
362 if (!wsi->sw && info->drm_mod_list.drmFormatModifierCount > 0) {
363 VkImageDrmFormatModifierPropertiesEXT image_mod_props = {
364 .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
365 };
366 result = wsi->GetImageDrmFormatModifierPropertiesEXT(chain->device,
367 image->image,
368 &image_mod_props);
369 if (result != VK_SUCCESS) {
370 close(fd);
371 return result;
372 }
373 image->drm_modifier = image_mod_props.drmFormatModifier;
374 assert(image->drm_modifier != DRM_FORMAT_MOD_INVALID);
375
376 const struct VkDrmFormatModifierPropertiesEXT *mod_props =
377 get_modifier_props(info, image->drm_modifier);
378 image->num_planes = mod_props->drmFormatModifierPlaneCount;
379
380 for (uint32_t p = 0; p < image->num_planes; p++) {
381 const VkImageSubresource image_subresource = {
382 .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << p,
383 .mipLevel = 0,
384 .arrayLayer = 0,
385 };
386 VkSubresourceLayout image_layout;
387 wsi->GetImageSubresourceLayout(chain->device, image->image,
388 &image_subresource, &image_layout);
389 image->sizes[p] = image_layout.size;
390 image->row_pitches[p] = image_layout.rowPitch;
391 image->offsets[p] = image_layout.offset;
392 if (p == 0) {
393 image->fds[p] = fd;
394 } else {
395 image->fds[p] = os_dupfd_cloexec(fd);
396 if (image->fds[p] == -1) {
397 for (uint32_t i = 0; i < p; i++)
398 close(image->fds[i]);
399
400 return VK_ERROR_OUT_OF_HOST_MEMORY;
401 }
402 }
403 }
404 } else {
405 const VkImageSubresource image_subresource = {
406 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
407 .mipLevel = 0,
408 .arrayLayer = 0,
409 };
410 VkSubresourceLayout image_layout;
411 wsi->GetImageSubresourceLayout(chain->device, image->image,
412 &image_subresource, &image_layout);
413
414 image->drm_modifier = DRM_FORMAT_MOD_INVALID;
415 image->num_planes = 1;
416 image->sizes[0] = reqs.size;
417 image->row_pitches[0] = image_layout.rowPitch;
418 image->offsets[0] = 0;
419 image->fds[0] = fd;
420 }
421
422 return VK_SUCCESS;
423 }
424
425 #define WSI_PRIME_LINEAR_STRIDE_ALIGN 256
426
427 static VkResult
wsi_create_prime_image_mem(const struct wsi_swapchain * chain,const struct wsi_image_info * info,struct wsi_image * image)428 wsi_create_prime_image_mem(const struct wsi_swapchain *chain,
429 const struct wsi_image_info *info,
430 struct wsi_image *image)
431 {
432 const struct wsi_device *wsi = chain->wsi;
433 VkResult result =
434 wsi_create_buffer_image_mem(chain, info, image,
435 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
436 true);
437 if (result != VK_SUCCESS)
438 return result;
439
440 const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
441 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
442 .pNext = NULL,
443 .memory = image->buffer.memory,
444 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
445 };
446 int fd;
447 result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd);
448 if (result != VK_SUCCESS)
449 return result;
450
451 image->drm_modifier = info->prime_use_linear_modifier ?
452 DRM_FORMAT_MOD_LINEAR : DRM_FORMAT_MOD_INVALID;
453 image->fds[0] = fd;
454
455 return VK_SUCCESS;
456 }
457
458 VkResult
wsi_configure_prime_image(UNUSED const struct wsi_swapchain * chain,const VkSwapchainCreateInfoKHR * pCreateInfo,bool use_modifier,struct wsi_image_info * info)459 wsi_configure_prime_image(UNUSED const struct wsi_swapchain *chain,
460 const VkSwapchainCreateInfoKHR *pCreateInfo,
461 bool use_modifier,
462 struct wsi_image_info *info)
463 {
464 VkResult result =
465 wsi_configure_buffer_image(chain, pCreateInfo, info);
466 if (result != VK_SUCCESS)
467 return result;
468
469 info->prime_use_linear_modifier = use_modifier;
470
471 const uint32_t cpp = vk_format_get_blocksize(info->create.format);
472 info->linear_stride = ALIGN_POT(info->create.extent.width * cpp,
473 WSI_PRIME_LINEAR_STRIDE_ALIGN);
474 info->size_align = 4096;
475
476 info->create_mem = wsi_create_prime_image_mem;
477 info->select_buffer_memory_type = prime_select_buffer_memory_type;
478 info->select_image_memory_type = prime_select_image_memory_type;
479
480 return VK_SUCCESS;
481 }
482