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