1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2019 Google LLC 3bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * based in part on anv and radv which are: 6bf215546Sopenharmony_ci * Copyright © 2015 Intel Corporation 7bf215546Sopenharmony_ci * Copyright © 2016 Red Hat. 8bf215546Sopenharmony_ci * Copyright © 2016 Bas Nieuwenhuizen 9bf215546Sopenharmony_ci */ 10bf215546Sopenharmony_ci 11bf215546Sopenharmony_ci#include "vn_wsi.h" 12bf215546Sopenharmony_ci 13bf215546Sopenharmony_ci#include "drm-uapi/drm_fourcc.h" 14bf215546Sopenharmony_ci#include "vk_enum_to_str.h" 15bf215546Sopenharmony_ci#include "wsi_common_entrypoints.h" 16bf215546Sopenharmony_ci 17bf215546Sopenharmony_ci#include "vn_device.h" 18bf215546Sopenharmony_ci#include "vn_image.h" 19bf215546Sopenharmony_ci#include "vn_instance.h" 20bf215546Sopenharmony_ci#include "vn_physical_device.h" 21bf215546Sopenharmony_ci#include "vn_queue.h" 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ci/* The common WSI support makes some assumptions about the driver. 24bf215546Sopenharmony_ci * 25bf215546Sopenharmony_ci * In wsi_device_init, it assumes VK_EXT_pci_bus_info is available. In 26bf215546Sopenharmony_ci * wsi_create_native_image and wsi_create_prime_image, it assumes 27bf215546Sopenharmony_ci * VK_KHR_external_memory_fd and VK_EXT_external_memory_dma_buf are enabled. 28bf215546Sopenharmony_ci * 29bf215546Sopenharmony_ci * In wsi_create_native_image, if wsi_device::supports_modifiers is set and 30bf215546Sopenharmony_ci * the window system supports modifiers, it assumes 31bf215546Sopenharmony_ci * VK_EXT_image_drm_format_modifier is enabled. Otherwise, it assumes that 32bf215546Sopenharmony_ci * wsi_image_create_info can be chained to VkImageCreateInfo and 33bf215546Sopenharmony_ci * vkGetImageSubresourceLayout can be called even the tiling is 34bf215546Sopenharmony_ci * VK_IMAGE_TILING_OPTIMAL. 35bf215546Sopenharmony_ci * 36bf215546Sopenharmony_ci * Together, it knows how to share dma-bufs, with explicit or implicit 37bf215546Sopenharmony_ci * modifiers, to the window system. 38bf215546Sopenharmony_ci * 39bf215546Sopenharmony_ci * For venus, we use explicit modifiers when the renderer and the window 40bf215546Sopenharmony_ci * system support them. Otherwise, we have to fall back to 41bf215546Sopenharmony_ci * VK_IMAGE_TILING_LINEAR (or trigger the prime blit path). But the fallback 42bf215546Sopenharmony_ci * can be problematic when the memory is scanned out directly and special 43bf215546Sopenharmony_ci * requirements (e.g., alignments) must be met. 44bf215546Sopenharmony_ci * 45bf215546Sopenharmony_ci * The common WSI support makes other assumptions about the driver to support 46bf215546Sopenharmony_ci * implicit fencing. In wsi_create_native_image and wsi_create_prime_image, 47bf215546Sopenharmony_ci * it assumes wsi_memory_allocate_info can be chained to VkMemoryAllocateInfo. 48bf215546Sopenharmony_ci * In wsi_common_queue_present, it assumes wsi_memory_signal_submit_info can 49bf215546Sopenharmony_ci * be chained to VkSubmitInfo. Finally, in wsi_common_acquire_next_image2, it 50bf215546Sopenharmony_ci * calls wsi_device::signal_semaphore_for_memory, and 51bf215546Sopenharmony_ci * wsi_device::signal_fence_for_memory if the driver provides them. 52bf215546Sopenharmony_ci * 53bf215546Sopenharmony_ci * Some drivers use wsi_memory_allocate_info to set up implicit fencing. 54bf215546Sopenharmony_ci * Others use wsi_memory_signal_submit_info to set up implicit IN-fences and 55bf215546Sopenharmony_ci * use wsi_device::signal_*_for_memory to set up implicit OUT-fences. 56bf215546Sopenharmony_ci * 57bf215546Sopenharmony_ci * For venus, implicit fencing is broken (and there is no explicit fencing 58bf215546Sopenharmony_ci * support yet). The kernel driver assumes everything is in the same fence 59bf215546Sopenharmony_ci * context and no synchronization is needed. It should be fixed for 60bf215546Sopenharmony_ci * correctness, but it is still not ideal. venus requires explicit fencing 61bf215546Sopenharmony_ci * (and renderer-side synchronization) to work well. 62bf215546Sopenharmony_ci */ 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci/* cast a WSI object to a pointer for logging */ 65bf215546Sopenharmony_ci#define VN_WSI_PTR(obj) ((const void *)(uintptr_t)(obj)) 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_cistatic PFN_vkVoidFunction 68bf215546Sopenharmony_civn_wsi_proc_addr(VkPhysicalDevice physicalDevice, const char *pName) 69bf215546Sopenharmony_ci{ 70bf215546Sopenharmony_ci struct vn_physical_device *physical_dev = 71bf215546Sopenharmony_ci vn_physical_device_from_handle(physicalDevice); 72bf215546Sopenharmony_ci return vk_instance_get_proc_addr_unchecked( 73bf215546Sopenharmony_ci &physical_dev->instance->base.base, pName); 74bf215546Sopenharmony_ci} 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ciVkResult 77bf215546Sopenharmony_civn_wsi_init(struct vn_physical_device *physical_dev) 78bf215546Sopenharmony_ci{ 79bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc = 80bf215546Sopenharmony_ci &physical_dev->instance->base.base.alloc; 81bf215546Sopenharmony_ci VkResult result = wsi_device_init( 82bf215546Sopenharmony_ci &physical_dev->wsi_device, vn_physical_device_to_handle(physical_dev), 83bf215546Sopenharmony_ci vn_wsi_proc_addr, alloc, -1, &physical_dev->instance->dri_options, 84bf215546Sopenharmony_ci false); 85bf215546Sopenharmony_ci if (result != VK_SUCCESS) 86bf215546Sopenharmony_ci return result; 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci if (physical_dev->base.base.supported_extensions 89bf215546Sopenharmony_ci .EXT_image_drm_format_modifier) 90bf215546Sopenharmony_ci physical_dev->wsi_device.supports_modifiers = true; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci physical_dev->base.base.wsi_device = &physical_dev->wsi_device; 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci return VK_SUCCESS; 95bf215546Sopenharmony_ci} 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_civoid 98bf215546Sopenharmony_civn_wsi_fini(struct vn_physical_device *physical_dev) 99bf215546Sopenharmony_ci{ 100bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc = 101bf215546Sopenharmony_ci &physical_dev->instance->base.base.alloc; 102bf215546Sopenharmony_ci physical_dev->base.base.wsi_device = NULL; 103bf215546Sopenharmony_ci wsi_device_finish(&physical_dev->wsi_device, alloc); 104bf215546Sopenharmony_ci} 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ciVkResult 107bf215546Sopenharmony_civn_wsi_create_image(struct vn_device *dev, 108bf215546Sopenharmony_ci const VkImageCreateInfo *create_info, 109bf215546Sopenharmony_ci const struct wsi_image_create_info *wsi_info, 110bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc, 111bf215546Sopenharmony_ci struct vn_image **out_img) 112bf215546Sopenharmony_ci{ 113bf215546Sopenharmony_ci /* TODO This is the legacy path used by wsi_create_native_image when there 114bf215546Sopenharmony_ci * is no modifier support. Instead of forcing linear tiling, we should ask 115bf215546Sopenharmony_ci * wsi to use wsi_create_prime_image instead. 116bf215546Sopenharmony_ci * 117bf215546Sopenharmony_ci * In fact, this is not enough when the image is truely used for scanout by 118bf215546Sopenharmony_ci * the host compositor. There can be requirements we fail to meet. We 119bf215546Sopenharmony_ci * should require modifier support at some point. 120bf215546Sopenharmony_ci */ 121bf215546Sopenharmony_ci const uint64_t modifier = DRM_FORMAT_MOD_LINEAR; 122bf215546Sopenharmony_ci const VkImageDrmFormatModifierListCreateInfoEXT mod_list_info = { 123bf215546Sopenharmony_ci .sType = 124bf215546Sopenharmony_ci VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT, 125bf215546Sopenharmony_ci .pNext = create_info->pNext, 126bf215546Sopenharmony_ci .drmFormatModifierCount = 1, 127bf215546Sopenharmony_ci .pDrmFormatModifiers = &modifier, 128bf215546Sopenharmony_ci }; 129bf215546Sopenharmony_ci VkImageCreateInfo local_create_info; 130bf215546Sopenharmony_ci if (wsi_info->scanout) { 131bf215546Sopenharmony_ci assert(!vk_find_struct_const( 132bf215546Sopenharmony_ci create_info->pNext, IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT)); 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci local_create_info = *create_info; 135bf215546Sopenharmony_ci local_create_info.pNext = &mod_list_info; 136bf215546Sopenharmony_ci local_create_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; 137bf215546Sopenharmony_ci create_info = &local_create_info; 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci if (VN_DEBUG(WSI)) 140bf215546Sopenharmony_ci vn_log(dev->instance, "forcing scanout image linear"); 141bf215546Sopenharmony_ci } 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci struct vn_image *img; 144bf215546Sopenharmony_ci VkResult result = vn_image_create(dev, create_info, alloc, &img); 145bf215546Sopenharmony_ci if (result != VK_SUCCESS) 146bf215546Sopenharmony_ci return result; 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci img->wsi.is_wsi = true; 149bf215546Sopenharmony_ci img->wsi.is_prime_blit_src = wsi_info->buffer_blit_src; 150bf215546Sopenharmony_ci img->wsi.tiling_override = create_info->tiling; 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci if (create_info->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) { 153bf215546Sopenharmony_ci VkDevice dev_handle = vn_device_to_handle(dev); 154bf215546Sopenharmony_ci VkImage img_handle = vn_image_to_handle(img); 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci VkImageDrmFormatModifierPropertiesEXT props = { 157bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT, 158bf215546Sopenharmony_ci }; 159bf215546Sopenharmony_ci result = vn_GetImageDrmFormatModifierPropertiesEXT(dev_handle, 160bf215546Sopenharmony_ci img_handle, &props); 161bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 162bf215546Sopenharmony_ci vn_DestroyImage(dev_handle, img_handle, alloc); 163bf215546Sopenharmony_ci return result; 164bf215546Sopenharmony_ci } 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci img->wsi.drm_format_modifier = props.drmFormatModifier; 167bf215546Sopenharmony_ci } 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci *out_img = img; 170bf215546Sopenharmony_ci return VK_SUCCESS; 171bf215546Sopenharmony_ci} 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ciVkResult 174bf215546Sopenharmony_civn_wsi_create_image_from_swapchain( 175bf215546Sopenharmony_ci struct vn_device *dev, 176bf215546Sopenharmony_ci const VkImageCreateInfo *create_info, 177bf215546Sopenharmony_ci const VkImageSwapchainCreateInfoKHR *swapchain_info, 178bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc, 179bf215546Sopenharmony_ci struct vn_image **out_img) 180bf215546Sopenharmony_ci{ 181bf215546Sopenharmony_ci const struct vn_image *swapchain_img = vn_image_from_handle( 182bf215546Sopenharmony_ci wsi_common_get_image(swapchain_info->swapchain, 0)); 183bf215546Sopenharmony_ci assert(swapchain_img->wsi.is_wsi); 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci /* must match what the common WSI and vn_wsi_create_image do */ 186bf215546Sopenharmony_ci VkImageCreateInfo local_create_info = *create_info; 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci /* match external memory */ 189bf215546Sopenharmony_ci const VkExternalMemoryImageCreateInfo local_external_info = { 190bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, 191bf215546Sopenharmony_ci .pNext = local_create_info.pNext, 192bf215546Sopenharmony_ci .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, 193bf215546Sopenharmony_ci }; 194bf215546Sopenharmony_ci local_create_info.pNext = &local_external_info; 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci /* match image tiling */ 197bf215546Sopenharmony_ci local_create_info.tiling = swapchain_img->wsi.tiling_override; 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci VkImageDrmFormatModifierListCreateInfoEXT local_mod_info; 200bf215546Sopenharmony_ci if (local_create_info.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) { 201bf215546Sopenharmony_ci local_mod_info = (const VkImageDrmFormatModifierListCreateInfoEXT){ 202bf215546Sopenharmony_ci .sType = 203bf215546Sopenharmony_ci VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT, 204bf215546Sopenharmony_ci .pNext = local_create_info.pNext, 205bf215546Sopenharmony_ci .drmFormatModifierCount = 1, 206bf215546Sopenharmony_ci .pDrmFormatModifiers = &swapchain_img->wsi.drm_format_modifier, 207bf215546Sopenharmony_ci }; 208bf215546Sopenharmony_ci local_create_info.pNext = &local_mod_info; 209bf215546Sopenharmony_ci } 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci /* match image usage */ 212bf215546Sopenharmony_ci if (swapchain_img->wsi.is_prime_blit_src) 213bf215546Sopenharmony_ci local_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci create_info = &local_create_info; 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci struct vn_image *img; 218bf215546Sopenharmony_ci VkResult result = vn_image_create(dev, create_info, alloc, &img); 219bf215546Sopenharmony_ci if (result != VK_SUCCESS) 220bf215546Sopenharmony_ci return result; 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_ci img->wsi.is_wsi = true; 223bf215546Sopenharmony_ci img->wsi.tiling_override = swapchain_img->wsi.tiling_override; 224bf215546Sopenharmony_ci img->wsi.drm_format_modifier = swapchain_img->wsi.drm_format_modifier; 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci *out_img = img; 227bf215546Sopenharmony_ci return VK_SUCCESS; 228bf215546Sopenharmony_ci} 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci/* swapchain commands */ 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ciVkResult 233bf215546Sopenharmony_civn_CreateSwapchainKHR(VkDevice device, 234bf215546Sopenharmony_ci const VkSwapchainCreateInfoKHR *pCreateInfo, 235bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator, 236bf215546Sopenharmony_ci VkSwapchainKHR *pSwapchain) 237bf215546Sopenharmony_ci{ 238bf215546Sopenharmony_ci struct vn_device *dev = vn_device_from_handle(device); 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci VkResult result = 241bf215546Sopenharmony_ci wsi_CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); 242bf215546Sopenharmony_ci if (VN_DEBUG(WSI) && result == VK_SUCCESS) { 243bf215546Sopenharmony_ci vn_log(dev->instance, 244bf215546Sopenharmony_ci "swapchain %p: created with surface %p, min count %d, size " 245bf215546Sopenharmony_ci "%dx%d, mode %s, old %p", 246bf215546Sopenharmony_ci VN_WSI_PTR(*pSwapchain), VN_WSI_PTR(pCreateInfo->surface), 247bf215546Sopenharmony_ci pCreateInfo->minImageCount, pCreateInfo->imageExtent.width, 248bf215546Sopenharmony_ci pCreateInfo->imageExtent.height, 249bf215546Sopenharmony_ci vk_PresentModeKHR_to_str(pCreateInfo->presentMode), 250bf215546Sopenharmony_ci VN_WSI_PTR(pCreateInfo->oldSwapchain)); 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci 253bf215546Sopenharmony_ci return vn_result(dev->instance, result); 254bf215546Sopenharmony_ci} 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_civoid 257bf215546Sopenharmony_civn_DestroySwapchainKHR(VkDevice device, 258bf215546Sopenharmony_ci VkSwapchainKHR swapchain, 259bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator) 260bf215546Sopenharmony_ci{ 261bf215546Sopenharmony_ci struct vn_device *dev = vn_device_from_handle(device); 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci wsi_DestroySwapchainKHR(device, swapchain, pAllocator); 264bf215546Sopenharmony_ci if (VN_DEBUG(WSI)) 265bf215546Sopenharmony_ci vn_log(dev->instance, "swapchain %p: destroyed", VN_WSI_PTR(swapchain)); 266bf215546Sopenharmony_ci} 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ciVkResult 269bf215546Sopenharmony_civn_QueuePresentKHR(VkQueue _queue, const VkPresentInfoKHR *pPresentInfo) 270bf215546Sopenharmony_ci{ 271bf215546Sopenharmony_ci VN_TRACE_FUNC(); 272bf215546Sopenharmony_ci struct vn_queue *queue = vn_queue_from_handle(_queue); 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci VkResult result = 275bf215546Sopenharmony_ci wsi_common_queue_present(&queue->device->physical_device->wsi_device, 276bf215546Sopenharmony_ci vn_device_to_handle(queue->device), _queue, 277bf215546Sopenharmony_ci queue->family, pPresentInfo); 278bf215546Sopenharmony_ci if (VN_DEBUG(WSI) && result != VK_SUCCESS) { 279bf215546Sopenharmony_ci for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) { 280bf215546Sopenharmony_ci const VkResult r = 281bf215546Sopenharmony_ci pPresentInfo->pResults ? pPresentInfo->pResults[i] : result; 282bf215546Sopenharmony_ci vn_log(queue->device->instance, 283bf215546Sopenharmony_ci "swapchain %p: presented image %d: %s", 284bf215546Sopenharmony_ci VN_WSI_PTR(pPresentInfo->pSwapchains[i]), 285bf215546Sopenharmony_ci pPresentInfo->pImageIndices[i], vk_Result_to_str(r)); 286bf215546Sopenharmony_ci } 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci return vn_result(queue->device->instance, result); 290bf215546Sopenharmony_ci} 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ciVkResult 293bf215546Sopenharmony_civn_AcquireNextImage2KHR(VkDevice device, 294bf215546Sopenharmony_ci const VkAcquireNextImageInfoKHR *pAcquireInfo, 295bf215546Sopenharmony_ci uint32_t *pImageIndex) 296bf215546Sopenharmony_ci{ 297bf215546Sopenharmony_ci VN_TRACE_FUNC(); 298bf215546Sopenharmony_ci struct vn_device *dev = vn_device_from_handle(device); 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci VkResult result = wsi_common_acquire_next_image2( 301bf215546Sopenharmony_ci &dev->physical_device->wsi_device, device, pAcquireInfo, pImageIndex); 302bf215546Sopenharmony_ci if (VN_DEBUG(WSI) && result != VK_SUCCESS) { 303bf215546Sopenharmony_ci const int idx = result >= VK_SUCCESS ? *pImageIndex : -1; 304bf215546Sopenharmony_ci vn_log(dev->instance, "swapchain %p: acquired image %d: %s", 305bf215546Sopenharmony_ci VN_WSI_PTR(pAcquireInfo->swapchain), idx, 306bf215546Sopenharmony_ci vk_Result_to_str(result)); 307bf215546Sopenharmony_ci } 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci /* XXX this relies on implicit sync */ 310bf215546Sopenharmony_ci if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) { 311bf215546Sopenharmony_ci struct vn_semaphore *sem = 312bf215546Sopenharmony_ci vn_semaphore_from_handle(pAcquireInfo->semaphore); 313bf215546Sopenharmony_ci if (sem) 314bf215546Sopenharmony_ci vn_semaphore_signal_wsi(dev, sem); 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci struct vn_fence *fence = vn_fence_from_handle(pAcquireInfo->fence); 317bf215546Sopenharmony_ci if (fence) 318bf215546Sopenharmony_ci vn_fence_signal_wsi(dev, fence); 319bf215546Sopenharmony_ci } 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci return vn_result(dev->instance, result); 322bf215546Sopenharmony_ci} 323