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