+
+ 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;