+ return iface->get_support(surface, wsi_device, alloc,
+ queueFamilyIndex, local_fd, 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];
+
+ return iface->get_capabilities(surface, pSurfaceCapabilities);
+}
+
+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, pSurfaceInfo->pNext,
+ pSurfaceCapabilities);
+}
+
+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_create_swapchain(struct wsi_device *wsi,
+ VkDevice device,
+ int fd,
+ 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, fd,
+ pCreateInfo, pAllocator,
+ &swapchain);
+ if (result != VK_SUCCESS)
+ return result;
+
+ *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_image(const struct wsi_device *wsi,
+ VkDevice device,
+ VkSwapchainKHR _swapchain,
+ uint64_t timeout,
+ VkSemaphore semaphore,
+ uint32_t *pImageIndex)
+{
+ WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
+
+ return swapchain->acquire_next_image(swapchain, timeout,
+ semaphore, 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]);
+ VkResult result;
+
+ if (swapchain->fences[0] == 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[0]);
+ if (result != VK_SUCCESS)
+ goto fail_present;
+ } else {
+ wsi->ResetFences(device, 1, &swapchain->fences[0]);
+ }
+
+ VkSubmitInfo submit_info = {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ .pNext = NULL,
+ };
+
+ 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.
+ */
+ struct wsi_image *image =
+ swapchain->get_wsi_image(swapchain, pPresentInfo->pImageIndices[i]);
+ submit_info.commandBufferCount = 1;
+ submit_info.pCommandBuffers =
+ &image->prime.blit_cmd_buffers[queue_family_index];
+ }
+
+ result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[0]);
+ 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,
+ pPresentInfo->pImageIndices[i],
+ region);
+ if (result != VK_SUCCESS)
+ goto fail_present;
+
+ VkFence last = swapchain->fences[2];
+ swapchain->fences[2] = swapchain->fences[1];
+ swapchain->fences[1] = swapchain->fences[0];
+ swapchain->fences[0] = last;
+
+ if (last != VK_NULL_HANDLE) {
+ wsi->WaitForFences(device, 1, &last, true, 1);
+ }
+
+ 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;