17ec681f3Smrg/*
27ec681f3Smrg * Copyright 2019 Google LLC
37ec681f3Smrg * SPDX-License-Identifier: MIT
47ec681f3Smrg *
57ec681f3Smrg * based in part on anv and radv which are:
67ec681f3Smrg * Copyright © 2015 Intel Corporation
77ec681f3Smrg * Copyright © 2016 Red Hat.
87ec681f3Smrg * Copyright © 2016 Bas Nieuwenhuizen
97ec681f3Smrg */
107ec681f3Smrg
117ec681f3Smrg#include "vn_wsi.h"
127ec681f3Smrg
137ec681f3Smrg#include "vk_enum_to_str.h"
147ec681f3Smrg
157ec681f3Smrg#include "wsi_common_entrypoints.h"
167ec681f3Smrg
177ec681f3Smrg#include "vn_device.h"
187ec681f3Smrg#include "vn_image.h"
197ec681f3Smrg#include "vn_instance.h"
207ec681f3Smrg#include "vn_physical_device.h"
217ec681f3Smrg#include "vn_queue.h"
227ec681f3Smrg
237ec681f3Smrg/* The common WSI support makes some assumptions about the driver.
247ec681f3Smrg *
257ec681f3Smrg * In wsi_device_init, it assumes VK_EXT_pci_bus_info is available.  In
267ec681f3Smrg * wsi_create_native_image and wsi_create_prime_image, it assumes
277ec681f3Smrg * VK_KHR_external_memory_fd and VK_EXT_external_memory_dma_buf are enabled.
287ec681f3Smrg *
297ec681f3Smrg * In wsi_create_native_image, if wsi_device::supports_modifiers is set and
307ec681f3Smrg * the window system supports modifiers, it assumes
317ec681f3Smrg * VK_EXT_image_drm_format_modifier is enabled.  Otherwise, it assumes that
327ec681f3Smrg * wsi_image_create_info can be chained to VkImageCreateInfo and
337ec681f3Smrg * vkGetImageSubresourceLayout can be called even the tiling is
347ec681f3Smrg * VK_IMAGE_TILING_OPTIMAL.
357ec681f3Smrg *
367ec681f3Smrg * Together, it knows how to share dma-bufs, with explicit or implicit
377ec681f3Smrg * modifiers, to the window system.
387ec681f3Smrg *
397ec681f3Smrg * For venus, we use explicit modifiers when the renderer and the window
407ec681f3Smrg * system support them.  Otherwise, we have to fall back to
417ec681f3Smrg * VK_IMAGE_TILING_LINEAR (or trigger the prime blit path).  But the fallback
427ec681f3Smrg * can be problematic when the memory is scanned out directly and special
437ec681f3Smrg * requirements (e.g., alignments) must be met.
447ec681f3Smrg *
457ec681f3Smrg * The common WSI support makes other assumptions about the driver to support
467ec681f3Smrg * implicit fencing.  In wsi_create_native_image and wsi_create_prime_image,
477ec681f3Smrg * it assumes wsi_memory_allocate_info can be chained to VkMemoryAllocateInfo.
487ec681f3Smrg * In wsi_common_queue_present, it assumes wsi_memory_signal_submit_info can
497ec681f3Smrg * be chained to VkSubmitInfo.  Finally, in wsi_common_acquire_next_image2, it
507ec681f3Smrg * calls wsi_device::signal_semaphore_for_memory, and
517ec681f3Smrg * wsi_device::signal_fence_for_memory if the driver provides them.
527ec681f3Smrg *
537ec681f3Smrg * Some drivers use wsi_memory_allocate_info to set up implicit fencing.
547ec681f3Smrg * Others use wsi_memory_signal_submit_info to set up implicit IN-fences and
557ec681f3Smrg * use wsi_device::signal_*_for_memory to set up implicit OUT-fences.
567ec681f3Smrg *
577ec681f3Smrg * For venus, implicit fencing is broken (and there is no explicit fencing
587ec681f3Smrg * support yet).  The kernel driver assumes everything is in the same fence
597ec681f3Smrg * context and no synchronization is needed.  It should be fixed for
607ec681f3Smrg * correctness, but it is still not ideal.  venus requires explicit fencing
617ec681f3Smrg * (and renderer-side synchronization) to work well.
627ec681f3Smrg */
637ec681f3Smrg
647ec681f3Smrg/* cast a WSI object to a pointer for logging */
657ec681f3Smrg#define VN_WSI_PTR(obj) ((const void *)(uintptr_t)(obj))
667ec681f3Smrg
677ec681f3Smrgstatic PFN_vkVoidFunction
687ec681f3Smrgvn_wsi_proc_addr(VkPhysicalDevice physicalDevice, const char *pName)
697ec681f3Smrg{
707ec681f3Smrg   struct vn_physical_device *physical_dev =
717ec681f3Smrg      vn_physical_device_from_handle(physicalDevice);
727ec681f3Smrg   return vk_instance_get_proc_addr_unchecked(
737ec681f3Smrg      &physical_dev->instance->base.base, pName);
747ec681f3Smrg}
757ec681f3Smrg
767ec681f3SmrgVkResult
777ec681f3Smrgvn_wsi_init(struct vn_physical_device *physical_dev)
787ec681f3Smrg{
797ec681f3Smrg   const VkAllocationCallbacks *alloc =
807ec681f3Smrg      &physical_dev->instance->base.base.alloc;
817ec681f3Smrg   VkResult result = wsi_device_init(
827ec681f3Smrg      &physical_dev->wsi_device, vn_physical_device_to_handle(physical_dev),
837ec681f3Smrg      vn_wsi_proc_addr, alloc, -1, &physical_dev->instance->dri_options,
847ec681f3Smrg      false);
857ec681f3Smrg   if (result != VK_SUCCESS)
867ec681f3Smrg      return result;
877ec681f3Smrg
887ec681f3Smrg   if (physical_dev->base.base.supported_extensions
897ec681f3Smrg          .EXT_image_drm_format_modifier)
907ec681f3Smrg      physical_dev->wsi_device.supports_modifiers = true;
917ec681f3Smrg
927ec681f3Smrg   physical_dev->base.base.wsi_device = &physical_dev->wsi_device;
937ec681f3Smrg
947ec681f3Smrg   return VK_SUCCESS;
957ec681f3Smrg}
967ec681f3Smrg
977ec681f3Smrgvoid
987ec681f3Smrgvn_wsi_fini(struct vn_physical_device *physical_dev)
997ec681f3Smrg{
1007ec681f3Smrg   const VkAllocationCallbacks *alloc =
1017ec681f3Smrg      &physical_dev->instance->base.base.alloc;
1027ec681f3Smrg   physical_dev->base.base.wsi_device = NULL;
1037ec681f3Smrg   wsi_device_finish(&physical_dev->wsi_device, alloc);
1047ec681f3Smrg}
1057ec681f3Smrg
1067ec681f3SmrgVkResult
1077ec681f3Smrgvn_wsi_create_image(struct vn_device *dev,
1087ec681f3Smrg                    const VkImageCreateInfo *create_info,
1097ec681f3Smrg                    const struct wsi_image_create_info *wsi_info,
1107ec681f3Smrg                    const VkAllocationCallbacks *alloc,
1117ec681f3Smrg                    struct vn_image **out_img)
1127ec681f3Smrg{
1137ec681f3Smrg   /* TODO This is the legacy path used by wsi_create_native_image when there
1147ec681f3Smrg    * is no modifier support.  Instead of forcing VK_IMAGE_TILING_LINEAR, we
1157ec681f3Smrg    * should ask wsi to use wsi_create_prime_image instead.
1167ec681f3Smrg    *
1177ec681f3Smrg    * In fact, this is not enough when the image is truely used for scanout by
1187ec681f3Smrg    * the host compositor.  There can be requirements we fail to meet.  We
1197ec681f3Smrg    * should require modifier support at some point.
1207ec681f3Smrg    */
1217ec681f3Smrg   VkImageCreateInfo local_create_info;
1227ec681f3Smrg   if (wsi_info->scanout) {
1237ec681f3Smrg      local_create_info = *create_info;
1247ec681f3Smrg      local_create_info.tiling = VK_IMAGE_TILING_LINEAR;
1257ec681f3Smrg      create_info = &local_create_info;
1267ec681f3Smrg
1277ec681f3Smrg      if (VN_DEBUG(WSI))
1287ec681f3Smrg         vn_log(dev->instance, "forcing scanout image linear");
1297ec681f3Smrg   }
1307ec681f3Smrg
1317ec681f3Smrg   struct vn_image *img;
1327ec681f3Smrg   VkResult result = vn_image_create(dev, create_info, alloc, &img);
1337ec681f3Smrg   if (result != VK_SUCCESS)
1347ec681f3Smrg      return result;
1357ec681f3Smrg
1367ec681f3Smrg   img->is_wsi = true;
1377ec681f3Smrg   img->is_prime_blit_src = wsi_info->prime_blit_src;
1387ec681f3Smrg
1397ec681f3Smrg   *out_img = img;
1407ec681f3Smrg   return VK_SUCCESS;
1417ec681f3Smrg}
1427ec681f3Smrg
1437ec681f3Smrg/* swapchain commands */
1447ec681f3Smrg
1457ec681f3SmrgVkResult
1467ec681f3Smrgvn_CreateSwapchainKHR(VkDevice device,
1477ec681f3Smrg                      const VkSwapchainCreateInfoKHR *pCreateInfo,
1487ec681f3Smrg                      const VkAllocationCallbacks *pAllocator,
1497ec681f3Smrg                      VkSwapchainKHR *pSwapchain)
1507ec681f3Smrg{
1517ec681f3Smrg   struct vn_device *dev = vn_device_from_handle(device);
1527ec681f3Smrg
1537ec681f3Smrg   VkResult result = wsi_CreateSwapchainKHR(device, pCreateInfo,
1547ec681f3Smrg                                            pAllocator, pSwapchain);
1557ec681f3Smrg   if (VN_DEBUG(WSI) && result == VK_SUCCESS) {
1567ec681f3Smrg      vn_log(dev->instance,
1577ec681f3Smrg             "swapchain %p: created with surface %p, min count %d, size "
1587ec681f3Smrg             "%dx%d, mode %s, old %p",
1597ec681f3Smrg             VN_WSI_PTR(*pSwapchain), VN_WSI_PTR(pCreateInfo->surface),
1607ec681f3Smrg             pCreateInfo->minImageCount, pCreateInfo->imageExtent.width,
1617ec681f3Smrg             pCreateInfo->imageExtent.height,
1627ec681f3Smrg             vk_PresentModeKHR_to_str(pCreateInfo->presentMode),
1637ec681f3Smrg             VN_WSI_PTR(pCreateInfo->oldSwapchain));
1647ec681f3Smrg   }
1657ec681f3Smrg
1667ec681f3Smrg   return vn_result(dev->instance, result);
1677ec681f3Smrg}
1687ec681f3Smrg
1697ec681f3Smrgvoid
1707ec681f3Smrgvn_DestroySwapchainKHR(VkDevice device,
1717ec681f3Smrg                       VkSwapchainKHR swapchain,
1727ec681f3Smrg                       const VkAllocationCallbacks *pAllocator)
1737ec681f3Smrg{
1747ec681f3Smrg   struct vn_device *dev = vn_device_from_handle(device);
1757ec681f3Smrg
1767ec681f3Smrg   wsi_DestroySwapchainKHR(device, swapchain, pAllocator);
1777ec681f3Smrg   if (VN_DEBUG(WSI))
1787ec681f3Smrg      vn_log(dev->instance, "swapchain %p: destroyed", VN_WSI_PTR(swapchain));
1797ec681f3Smrg}
1807ec681f3Smrg
1817ec681f3SmrgVkResult
1827ec681f3Smrgvn_QueuePresentKHR(VkQueue _queue, const VkPresentInfoKHR *pPresentInfo)
1837ec681f3Smrg{
1847ec681f3Smrg   struct vn_queue *queue = vn_queue_from_handle(_queue);
1857ec681f3Smrg
1867ec681f3Smrg   VkResult result =
1877ec681f3Smrg      wsi_common_queue_present(&queue->device->physical_device->wsi_device,
1887ec681f3Smrg                               vn_device_to_handle(queue->device), _queue,
1897ec681f3Smrg                               queue->family, pPresentInfo);
1907ec681f3Smrg   if (VN_DEBUG(WSI) && result != VK_SUCCESS) {
1917ec681f3Smrg      for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
1927ec681f3Smrg         const VkResult r =
1937ec681f3Smrg            pPresentInfo->pResults ? pPresentInfo->pResults[i] : result;
1947ec681f3Smrg         vn_log(queue->device->instance,
1957ec681f3Smrg                "swapchain %p: presented image %d: %s",
1967ec681f3Smrg                VN_WSI_PTR(pPresentInfo->pSwapchains[i]),
1977ec681f3Smrg                pPresentInfo->pImageIndices[i], vk_Result_to_str(r));
1987ec681f3Smrg      }
1997ec681f3Smrg   }
2007ec681f3Smrg
2017ec681f3Smrg   return vn_result(queue->device->instance, result);
2027ec681f3Smrg}
2037ec681f3Smrg
2047ec681f3SmrgVkResult
2057ec681f3Smrgvn_AcquireNextImage2KHR(VkDevice device,
2067ec681f3Smrg                        const VkAcquireNextImageInfoKHR *pAcquireInfo,
2077ec681f3Smrg                        uint32_t *pImageIndex)
2087ec681f3Smrg{
2097ec681f3Smrg   struct vn_device *dev = vn_device_from_handle(device);
2107ec681f3Smrg
2117ec681f3Smrg   VkResult result = wsi_common_acquire_next_image2(
2127ec681f3Smrg      &dev->physical_device->wsi_device, device, pAcquireInfo, pImageIndex);
2137ec681f3Smrg   if (VN_DEBUG(WSI) && result != VK_SUCCESS) {
2147ec681f3Smrg      const int idx = result >= VK_SUCCESS ? *pImageIndex : -1;
2157ec681f3Smrg      vn_log(dev->instance, "swapchain %p: acquired image %d: %s",
2167ec681f3Smrg             VN_WSI_PTR(pAcquireInfo->swapchain), idx,
2177ec681f3Smrg             vk_Result_to_str(result));
2187ec681f3Smrg   }
2197ec681f3Smrg
2207ec681f3Smrg   /* XXX this relies on implicit sync */
2217ec681f3Smrg   if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
2227ec681f3Smrg      struct vn_semaphore *sem =
2237ec681f3Smrg         vn_semaphore_from_handle(pAcquireInfo->semaphore);
2247ec681f3Smrg      if (sem)
2257ec681f3Smrg         vn_semaphore_signal_wsi(dev, sem);
2267ec681f3Smrg
2277ec681f3Smrg      struct vn_fence *fence = vn_fence_from_handle(pAcquireInfo->fence);
2287ec681f3Smrg      if (fence)
2297ec681f3Smrg         vn_fence_signal_wsi(dev, fence);
2307ec681f3Smrg   }
2317ec681f3Smrg
2327ec681f3Smrg   return vn_result(dev->instance, result);
2337ec681f3Smrg}
234