X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fvulkan%2Fwsi%2Fwsi_common.c;h=3abffe3dee70df38b7fc88b021673ae119542af2;hb=48e23a64067ab7f775b1c4e2966041fbbf9d42e3;hp=7cb5d894e772f0f3f004bbc5368e4d12029fd58c;hpb=d50937f137201e1d90ce18bbea1383af7a7ebd5d;p=mesa.git diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index 7cb5d894e77..3abffe3dee7 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -22,21 +22,51 @@ */ #include "wsi_common_private.h" +#include "drm-uapi/drm_fourcc.h" #include "util/macros.h" +#include "util/xmlconfig.h" +#include "vk_util.h" -void +#include +#include +#include +#include +#include + +VkResult wsi_device_init(struct wsi_device *wsi, VkPhysicalDevice pdevice, - WSI_FN_GetPhysicalDeviceProcAddr proc_addr) + WSI_FN_GetPhysicalDeviceProcAddr proc_addr, + const VkAllocationCallbacks *alloc, + int display_fd, + const struct driOptionCache *dri_options) { + const char *present_mode; + VkResult result; + memset(wsi, 0, sizeof(*wsi)); + wsi->instance_alloc = *alloc; + wsi->pdevice = pdevice; + #define WSI_GET_CB(func) \ PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func) + WSI_GET_CB(GetPhysicalDeviceProperties2); WSI_GET_CB(GetPhysicalDeviceMemoryProperties); WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties); #undef WSI_GET_CB + wsi->pci_bus_info.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT; + VkPhysicalDeviceProperties2 pdp2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + .pNext = &wsi->pci_bus_info, + }; + GetPhysicalDeviceProperties2(pdevice, &pdp2); + + wsi->maxImageDimension2D = pdp2.properties.limits.maxImageDimension2D; + wsi->override_present_mode = VK_PRESENT_MODE_MAX_ENUM_KHR; + GetPhysicalDeviceMemoryProperties(pdevice, &wsi->memory_props); GetPhysicalDeviceQueueFamilyProperties(pdevice, &wsi->queue_family_count, NULL); @@ -50,18 +80,109 @@ wsi_device_init(struct wsi_device *wsi, WSI_GET_CB(CmdCopyImageToBuffer); WSI_GET_CB(CreateBuffer); WSI_GET_CB(CreateCommandPool); + WSI_GET_CB(CreateFence); WSI_GET_CB(CreateImage); WSI_GET_CB(DestroyBuffer); WSI_GET_CB(DestroyCommandPool); + WSI_GET_CB(DestroyFence); WSI_GET_CB(DestroyImage); WSI_GET_CB(EndCommandBuffer); WSI_GET_CB(FreeMemory); WSI_GET_CB(FreeCommandBuffers); WSI_GET_CB(GetBufferMemoryRequirements); WSI_GET_CB(GetImageMemoryRequirements); + WSI_GET_CB(GetImageSubresourceLayout); WSI_GET_CB(GetMemoryFdKHR); + WSI_GET_CB(GetPhysicalDeviceFormatProperties); + WSI_GET_CB(GetPhysicalDeviceFormatProperties2KHR); + WSI_GET_CB(ResetFences); WSI_GET_CB(QueueSubmit); + WSI_GET_CB(WaitForFences); #undef WSI_GET_CB + +#ifdef VK_USE_PLATFORM_XCB_KHR + result = wsi_x11_init_wsi(wsi, alloc, dri_options); + if (result != VK_SUCCESS) + goto fail; +#endif + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + result = wsi_wl_init_wsi(wsi, alloc, pdevice); + if (result != VK_SUCCESS) + goto fail; +#endif + +#ifdef VK_USE_PLATFORM_DISPLAY_KHR + result = wsi_display_init_wsi(wsi, alloc, display_fd); + if (result != VK_SUCCESS) + goto fail; +#endif + + present_mode = getenv("MESA_VK_WSI_PRESENT_MODE"); + if (present_mode) { + if (!strcmp(present_mode, "fifo")) { + wsi->override_present_mode = VK_PRESENT_MODE_FIFO_KHR; + } else if (!strcmp(present_mode, "mailbox")) { + wsi->override_present_mode = VK_PRESENT_MODE_MAILBOX_KHR; + } else if (!strcmp(present_mode, "immediate")) { + wsi->override_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR; + } else { + fprintf(stderr, "Invalid MESA_VK_WSI_PRESENT_MODE value!\n"); + } + } + + if (dri_options) { + if (driCheckOption(dri_options, "adaptive_sync", DRI_BOOL)) + wsi->enable_adaptive_sync = driQueryOptionb(dri_options, + "adaptive_sync"); + } + + return VK_SUCCESS; + +fail: + wsi_device_finish(wsi, alloc); + return result; +} + +void +wsi_device_finish(struct wsi_device *wsi, + const VkAllocationCallbacks *alloc) +{ +#ifdef VK_USE_PLATFORM_DISPLAY_KHR + wsi_display_finish_wsi(wsi, alloc); +#endif +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + wsi_wl_finish_wsi(wsi, alloc); +#endif +#ifdef VK_USE_PLATFORM_XCB_KHR + wsi_x11_finish_wsi(wsi, alloc); +#endif +} + +bool +wsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd) +{ + drmDevicePtr fd_device; + int ret = drmGetDevice2(drm_fd, 0, &fd_device); + if (ret) + return false; + + bool match = false; + switch (fd_device->bustype) { + case DRM_BUS_PCI: + match = wsi->pci_bus_info.pciDomain == fd_device->businfo.pci->domain && + wsi->pci_bus_info.pciBus == fd_device->businfo.pci->bus && + wsi->pci_bus_info.pciDevice == fd_device->businfo.pci->dev && + wsi->pci_bus_info.pciFunction == fd_device->businfo.pci->func; + break; + + default: + break; + } + + drmFreeDevice(&fd_device); + + return match; } VkResult @@ -78,6 +199,7 @@ wsi_swapchain_init(const struct wsi_device *wsi, chain->wsi = wsi; chain->device = device; chain->alloc = *pAllocator; + chain->use_prime_blit = false; chain->cmd_pools = vk_zalloc(pAllocator, sizeof(VkCommandPool) * wsi->queue_family_count, 8, @@ -105,13 +227,74 @@ fail: return result; } +static bool +wsi_swapchain_is_present_mode_supported(struct wsi_device *wsi, + const VkSwapchainCreateInfoKHR *pCreateInfo, + VkPresentModeKHR mode) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface); + struct wsi_interface *iface = wsi->wsi[surface->platform]; + VkPresentModeKHR *present_modes; + uint32_t present_mode_count; + bool supported = false; + VkResult result; + + result = iface->get_present_modes(surface, &present_mode_count, NULL); + if (result != VK_SUCCESS) + return supported; + + present_modes = malloc(present_mode_count * sizeof(*present_modes)); + if (!present_modes) + return supported; + + result = iface->get_present_modes(surface, &present_mode_count, + present_modes); + if (result != VK_SUCCESS) + goto fail; + + for (uint32_t i = 0; i < present_mode_count; i++) { + if (present_modes[i] == mode) { + supported = true; + break; + } + } + +fail: + free(present_modes); + return supported; +} + +enum VkPresentModeKHR +wsi_swapchain_get_present_mode(struct wsi_device *wsi, + const VkSwapchainCreateInfoKHR *pCreateInfo) +{ + if (wsi->override_present_mode == VK_PRESENT_MODE_MAX_ENUM_KHR) + return pCreateInfo->presentMode; + + if (!wsi_swapchain_is_present_mode_supported(wsi, pCreateInfo, + wsi->override_present_mode)) { + fprintf(stderr, "Unsupported MESA_VK_WSI_PRESENT_MODE value!\n"); + return pCreateInfo->presentMode; + } + + return wsi->override_present_mode; +} + void wsi_swapchain_finish(struct wsi_swapchain *chain) { + if (chain->fences) { + for (unsigned i = 0; i < chain->image_count; i++) + chain->wsi->DestroyFence(chain->device, chain->fences[i], &chain->alloc); + + vk_free(&chain->alloc, chain->fences); + } + for (uint32_t i = 0; i < chain->wsi->queue_family_count; i++) { chain->wsi->DestroyCommandPool(chain->device, chain->cmd_pools[i], &chain->alloc); } + vk_free(&chain->alloc, chain->cmd_pools); } static uint32_t @@ -147,11 +330,251 @@ align_u32(uint32_t v, uint32_t a) return (v + a - 1) & ~(a - 1); } +VkResult +wsi_create_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, + struct wsi_image *image) +{ + const struct wsi_device *wsi = chain->wsi; + VkResult result; + + memset(image, 0, sizeof(*image)); + for (int i = 0; i < ARRAY_SIZE(image->fds); i++) + image->fds[i] = -1; + + struct wsi_image_create_info image_wsi_info = { + .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA, + .pNext = NULL, + }; + + uint32_t image_modifier_count = 0, modifier_prop_count = 0; + struct wsi_format_modifier_properties *modifier_props = NULL; + uint64_t *image_modifiers = NULL; + if (num_modifier_lists == 0) { + /* If we don't have modifiers, fall back to the legacy "scanout" flag */ + image_wsi_info.scanout = true; + } else { + /* The winsys can't request modifiers if we don't support them. */ + assert(wsi->supports_modifiers); + struct wsi_format_modifier_properties_list modifier_props_list = { + .sType = VK_STRUCTURE_TYPE_WSI_FORMAT_MODIFIER_PROPERTIES_LIST_MESA, + .pNext = NULL, + }; + VkFormatProperties2 format_props = { + .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, + .pNext = &modifier_props_list, + }; + wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice, + pCreateInfo->imageFormat, + &format_props); + assert(modifier_props_list.modifier_count > 0); + modifier_props = vk_alloc(&chain->alloc, + sizeof(*modifier_props) * + modifier_props_list.modifier_count, + 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!modifier_props) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + modifier_props_list.modifier_properties = modifier_props; + wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice, + pCreateInfo->imageFormat, + &format_props); + modifier_prop_count = modifier_props_list.modifier_count; + + uint32_t max_modifier_count = 0; + for (uint32_t l = 0; l < num_modifier_lists; l++) + max_modifier_count = MAX2(max_modifier_count, num_modifiers[l]); + + image_modifiers = vk_alloc(&chain->alloc, + sizeof(*image_modifiers) * + max_modifier_count, + 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!image_modifiers) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + image_modifier_count = 0; + for (uint32_t l = 0; l < num_modifier_lists; l++) { + /* Walk the modifier lists and construct a list of supported + * modifiers. + */ + for (uint32_t i = 0; i < num_modifiers[l]; i++) { + for (uint32_t j = 0; j < modifier_prop_count; j++) { + if (modifier_props[j].modifier == modifiers[l][i]) + image_modifiers[image_modifier_count++] = modifiers[l][i]; + } + } + + /* We only want to take the modifiers from the first list */ + if (image_modifier_count > 0) + break; + } + + if (image_modifier_count > 0) { + image_wsi_info.modifier_count = image_modifier_count; + image_wsi_info.modifiers = image_modifiers; + } else { + /* TODO: Add a proper error here */ + assert(!"Failed to find a supported modifier! This should never " + "happen because LINEAR should always be available"); + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + } + + const VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = &image_wsi_info, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = pCreateInfo->imageFormat, + .extent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = pCreateInfo->imageUsage, + .sharingMode = pCreateInfo->imageSharingMode, + .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, + .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + result = wsi->CreateImage(chain->device, &image_info, + &chain->alloc, &image->image); + if (result != VK_SUCCESS) + goto fail; + + VkMemoryRequirements reqs; + wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); + + const struct wsi_memory_allocate_info memory_wsi_info = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, + .pNext = NULL, + .implicit_sync = true, + }; + const VkExportMemoryAllocateInfo memory_export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, + .pNext = &memory_wsi_info, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + const VkMemoryDedicatedAllocateInfo memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + .pNext = &memory_export_info, + .image = image->image, + .buffer = VK_NULL_HANDLE, + }; + const VkMemoryAllocateInfo memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &memory_dedicated_info, + .allocationSize = reqs.size, + .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &memory_info, + &chain->alloc, &image->memory); + if (result != VK_SUCCESS) + goto fail; + + result = wsi->BindImageMemory(chain->device, image->image, + image->memory, 0); + if (result != VK_SUCCESS) + goto fail; + + const VkMemoryGetFdInfoKHR memory_get_fd_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, + .pNext = NULL, + .memory = image->memory, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + int fd; + result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd); + if (result != VK_SUCCESS) + goto fail; + + if (num_modifier_lists > 0) { + image->drm_modifier = wsi->image_get_modifier(image->image); + assert(image->drm_modifier != DRM_FORMAT_MOD_INVALID); + + for (uint32_t j = 0; j < modifier_prop_count; j++) { + if (modifier_props[j].modifier == image->drm_modifier) { + image->num_planes = modifier_props[j].modifier_plane_count; + break; + } + } + + for (uint32_t p = 0; p < image->num_planes; p++) { + const VkImageSubresource image_subresource = { + .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << p, + .mipLevel = 0, + .arrayLayer = 0, + }; + VkSubresourceLayout image_layout; + wsi->GetImageSubresourceLayout(chain->device, image->image, + &image_subresource, &image_layout); + image->sizes[p] = image_layout.size; + image->row_pitches[p] = image_layout.rowPitch; + image->offsets[p] = image_layout.offset; + if (p == 0) { + image->fds[p] = fd; + } else { + image->fds[p] = dup(fd); + if (image->fds[p] == -1) { + for (uint32_t i = 0; i < p; i++) + close(image->fds[p]); + + goto fail; + } + } + } + } else { + const VkImageSubresource image_subresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .arrayLayer = 0, + }; + VkSubresourceLayout image_layout; + wsi->GetImageSubresourceLayout(chain->device, image->image, + &image_subresource, &image_layout); + + image->drm_modifier = DRM_FORMAT_MOD_INVALID; + image->num_planes = 1; + image->sizes[0] = reqs.size; + image->row_pitches[0] = image_layout.rowPitch; + image->offsets[0] = 0; + image->fds[0] = fd; + } + + vk_free(&chain->alloc, modifier_props); + vk_free(&chain->alloc, image_modifiers); + + return VK_SUCCESS; + +fail: + vk_free(&chain->alloc, modifier_props); + vk_free(&chain->alloc, image_modifiers); + wsi_destroy_image(chain, image); + + return result; +} + #define WSI_PRIME_LINEAR_STRIDE_ALIGN 256 VkResult wsi_create_prime_image(const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, + bool use_modifier, struct wsi_image *image) { const struct wsi_device *wsi = chain->wsi; @@ -166,8 +589,8 @@ wsi_create_prime_image(const struct wsi_swapchain *chain, uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height; linear_size = align_u32(linear_size, 4096); - const VkExternalMemoryBufferCreateInfoKHR prime_buffer_external_info = { - .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR, + const VkExternalMemoryBufferCreateInfo prime_buffer_external_info = { + .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, .pNext = NULL, .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, }; @@ -192,13 +615,13 @@ wsi_create_prime_image(const struct wsi_swapchain *chain, .pNext = NULL, .implicit_sync = true, }; - const VkExportMemoryAllocateInfoKHR prime_memory_export_info = { - .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR, + const VkExportMemoryAllocateInfo prime_memory_export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, .pNext = &memory_wsi_info, .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, }; - const VkMemoryDedicatedAllocateInfoKHR prime_memory_dedicated_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, + const VkMemoryDedicatedAllocateInfo prime_memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, .pNext = &prime_memory_export_info, .image = VK_NULL_HANDLE, .buffer = image->prime.buffer, @@ -247,8 +670,8 @@ wsi_create_prime_image(const struct wsi_swapchain *chain, wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); - const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, + const VkMemoryDedicatedAllocateInfo memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, .pNext = NULL, .image = image->image, .buffer = VK_NULL_HANDLE, @@ -274,8 +697,10 @@ wsi_create_prime_image(const struct wsi_swapchain *chain, vk_zalloc(&chain->alloc, sizeof(VkCommandBuffer) * wsi->queue_family_count, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - if (!image->prime.blit_cmd_buffers) + if (!image->prime.blit_cmd_buffers) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; goto fail; + } for (uint32_t i = 0; i < wsi->queue_family_count; i++) { const VkCommandBufferAllocateInfo cmd_buffer_info = { @@ -334,22 +759,24 @@ wsi_create_prime_image(const struct wsi_swapchain *chain, if (result != VK_SUCCESS) goto fail; - image->size = linear_size; - image->row_pitch = linear_stride; - image->offset = 0; - image->fd = fd; + image->drm_modifier = use_modifier ? DRM_FORMAT_MOD_LINEAR : DRM_FORMAT_MOD_INVALID; + image->num_planes = 1; + image->sizes[0] = linear_size; + image->row_pitches[0] = linear_stride; + image->offsets[0] = 0; + image->fds[0] = fd; return VK_SUCCESS; fail: - wsi_destroy_prime_image(chain, image); + wsi_destroy_image(chain, image); return result; } void -wsi_destroy_prime_image(const struct wsi_swapchain *chain, - struct wsi_image *image) +wsi_destroy_image(const struct wsi_swapchain *chain, + struct wsi_image *image) { const struct wsi_device *wsi = chain->wsi; @@ -368,25 +795,330 @@ wsi_destroy_prime_image(const struct wsi_swapchain *chain, } VkResult -wsi_prime_image_blit_to_linear(const struct wsi_swapchain *chain, - struct wsi_image *image, - VkQueue queue, - uint32_t waitSemaphoreCount, - const VkSemaphore *pWaitSemaphores) +wsi_common_get_surface_support(struct wsi_device *wsi_device, + uint32_t queueFamilyIndex, + VkSurfaceKHR _surface, + VkBool32* pSupported) { - uint32_t queue_family = chain->wsi->queue_get_family_index(queue); + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; - VkPipelineStageFlags stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - const VkSubmitInfo submit_info = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .pNext = NULL, - .waitSemaphoreCount = waitSemaphoreCount, - .pWaitSemaphores = pWaitSemaphores, - .pWaitDstStageMask = &stage_flags, - .commandBufferCount = 1, - .pCommandBuffers = &image->prime.blit_cmd_buffers[queue_family], - .signalSemaphoreCount = 0, - .pSignalSemaphores = NULL, + return iface->get_support(surface, wsi_device, + queueFamilyIndex, pSupported); +} + +VkResult +wsi_common_get_surface_capabilities(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + VkSurfaceCapabilities2KHR caps2 = { + .sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR, + }; + + VkResult result = iface->get_capabilities2(surface, wsi_device, NULL, &caps2); + + if (result == VK_SUCCESS) + *pSurfaceCapabilities = caps2.surfaceCapabilities; + + return result; +} + +VkResult +wsi_common_get_surface_capabilities2(struct wsi_device *wsi_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_capabilities2(surface, wsi_device, pSurfaceInfo->pNext, + pSurfaceCapabilities); +} + +VkResult +wsi_common_get_surface_capabilities2ext( + struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + VkSurfaceCapabilities2EXT *pSurfaceCapabilities) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + assert(pSurfaceCapabilities->sType == + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT); + + struct wsi_surface_supported_counters counters = { + .sType = VK_STRUCTURE_TYPE_WSI_SURFACE_SUPPORTED_COUNTERS_MESA, + .pNext = pSurfaceCapabilities->pNext, + .supported_surface_counters = 0, + }; + + VkSurfaceCapabilities2KHR caps2 = { + .sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR, + .pNext = &counters, }; - return chain->wsi->QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + + VkResult result = iface->get_capabilities2(surface, wsi_device, NULL, &caps2); + + if (result == VK_SUCCESS) { + VkSurfaceCapabilities2EXT *ext_caps = pSurfaceCapabilities; + VkSurfaceCapabilitiesKHR khr_caps = caps2.surfaceCapabilities; + + ext_caps->minImageCount = khr_caps.minImageCount; + ext_caps->maxImageCount = khr_caps.maxImageCount; + ext_caps->currentExtent = khr_caps.currentExtent; + ext_caps->minImageExtent = khr_caps.minImageExtent; + ext_caps->maxImageExtent = khr_caps.maxImageExtent; + ext_caps->maxImageArrayLayers = khr_caps.maxImageArrayLayers; + ext_caps->supportedTransforms = khr_caps.supportedTransforms; + ext_caps->currentTransform = khr_caps.currentTransform; + ext_caps->supportedCompositeAlpha = khr_caps.supportedCompositeAlpha; + ext_caps->supportedUsageFlags = khr_caps.supportedUsageFlags; + ext_caps->supportedSurfaceCounters = counters.supported_surface_counters; + } + + return result; +} + +VkResult +wsi_common_get_surface_formats(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormatKHR *pSurfaceFormats) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_formats(surface, wsi_device, + pSurfaceFormatCount, pSurfaceFormats); +} + +VkResult +wsi_common_get_surface_formats2(struct wsi_device *wsi_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormat2KHR *pSurfaceFormats) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_formats2(surface, wsi_device, pSurfaceInfo->pNext, + pSurfaceFormatCount, pSurfaceFormats); +} + +VkResult +wsi_common_get_surface_present_modes(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + uint32_t *pPresentModeCount, + VkPresentModeKHR *pPresentModes) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_present_modes(surface, pPresentModeCount, + pPresentModes); +} + +VkResult +wsi_common_get_present_rectangles(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + uint32_t* pRectCount, + VkRect2D* pRects) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_present_rectangles(surface, wsi_device, + pRectCount, pRects); +} + +VkResult +wsi_common_create_swapchain(struct wsi_device *wsi, + VkDevice device, + const VkSwapchainCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSwapchainKHR *pSwapchain) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface); + struct wsi_interface *iface = wsi->wsi[surface->platform]; + struct wsi_swapchain *swapchain; + + VkResult result = iface->create_swapchain(surface, device, wsi, + pCreateInfo, pAllocator, + &swapchain); + if (result != VK_SUCCESS) + return result; + + swapchain->fences = vk_zalloc(pAllocator, + sizeof (*swapchain->fences) * swapchain->image_count, + sizeof (*swapchain->fences), + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!swapchain->fences) { + swapchain->destroy(swapchain, pAllocator); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + *pSwapchain = wsi_swapchain_to_handle(swapchain); + + return VK_SUCCESS; +} + +void +wsi_common_destroy_swapchain(VkDevice device, + VkSwapchainKHR _swapchain, + const VkAllocationCallbacks *pAllocator) +{ + WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); + if (!swapchain) + return; + + swapchain->destroy(swapchain, pAllocator); +} + +VkResult +wsi_common_get_images(VkSwapchainKHR _swapchain, + uint32_t *pSwapchainImageCount, + VkImage *pSwapchainImages) +{ + WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); + VK_OUTARRAY_MAKE(images, pSwapchainImages, pSwapchainImageCount); + + for (uint32_t i = 0; i < swapchain->image_count; i++) { + vk_outarray_append(&images, image) { + *image = swapchain->get_wsi_image(swapchain, i)->image; + } + } + + return vk_outarray_status(&images); +} + +VkResult +wsi_common_acquire_next_image2(const struct wsi_device *wsi, + VkDevice device, + const VkAcquireNextImageInfoKHR *pAcquireInfo, + uint32_t *pImageIndex) +{ + WSI_FROM_HANDLE(wsi_swapchain, swapchain, pAcquireInfo->swapchain); + + return swapchain->acquire_next_image(swapchain, pAcquireInfo, pImageIndex); +} + +VkResult +wsi_common_queue_present(const struct wsi_device *wsi, + VkDevice device, + VkQueue queue, + int queue_family_index, + const VkPresentInfoKHR *pPresentInfo) +{ + VkResult final_result = VK_SUCCESS; + + const VkPresentRegionsKHR *regions = + vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR); + + for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) { + WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]); + uint32_t image_index = pPresentInfo->pImageIndices[i]; + VkResult result; + + if (swapchain->fences[image_index] == VK_NULL_HANDLE) { + const VkFenceCreateInfo fence_info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + }; + result = wsi->CreateFence(device, &fence_info, + &swapchain->alloc, + &swapchain->fences[image_index]); + if (result != VK_SUCCESS) + goto fail_present; + } else { + wsi->WaitForFences(device, 1, &swapchain->fences[image_index], + true, 1); + + wsi->ResetFences(device, 1, &swapchain->fences[image_index]); + } + + struct wsi_image *image = + swapchain->get_wsi_image(swapchain, image_index); + + struct wsi_memory_signal_submit_info mem_signal = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA, + .pNext = NULL, + .memory = image->memory, + }; + + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = &mem_signal, + }; + + VkPipelineStageFlags *stage_flags = NULL; + if (i == 0) { + /* We only need/want to wait on semaphores once. After that, we're + * guaranteed ordering since it all happens on the same queue. + */ + submit_info.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount; + submit_info.pWaitSemaphores = pPresentInfo->pWaitSemaphores; + + /* Set up the pWaitDstStageMasks */ + stage_flags = vk_alloc(&swapchain->alloc, + sizeof(VkPipelineStageFlags) * + pPresentInfo->waitSemaphoreCount, + 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!stage_flags) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail_present; + } + for (uint32_t s = 0; s < pPresentInfo->waitSemaphoreCount; s++) + stage_flags[s] = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + + submit_info.pWaitDstStageMask = stage_flags; + } + + if (swapchain->use_prime_blit) { + /* If we are using prime blits, we need to perform the blit now. The + * command buffer is attached to the image. + */ + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = + &image->prime.blit_cmd_buffers[queue_family_index]; + mem_signal.memory = image->prime.memory; + } + + result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[image_index]); + vk_free(&swapchain->alloc, stage_flags); + if (result != VK_SUCCESS) + goto fail_present; + + const VkPresentRegionKHR *region = NULL; + if (regions && regions->pRegions) + region = ®ions->pRegions[i]; + + result = swapchain->queue_present(swapchain, image_index, region); + if (result != VK_SUCCESS) + goto fail_present; + + fail_present: + if (pPresentInfo->pResults != NULL) + pPresentInfo->pResults[i] = result; + + /* Let the final result be our first unsuccessful result */ + if (final_result == VK_SUCCESS) + final_result = result; + } + + return final_result; +} + +uint64_t +wsi_common_get_current_time(void) +{ + struct timespec current; + clock_gettime(CLOCK_MONOTONIC, ¤t); + return current.tv_nsec + current.tv_sec * 1000000000ull; }