Vulkan/wsi: Implement VK_EXT_display_surface_counter
[mesa.git] / src / vulkan / wsi / wsi_common.c
index f149846e454066635855495ddf65f7d64d068f41..f2d90a6bba2d17d485e9aa193c5f65f40f18c7b8 100644 (file)
  */
 
 #include "wsi_common_private.h"
+#include "drm_fourcc.h"
 #include "util/macros.h"
 #include "vk_util.h"
 
-void
+#include <unistd.h>
+
+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)
 {
+   VkResult result;
+
    memset(wsi, 0, sizeof(*wsi));
 
+   wsi->pdevice = pdevice;
+
 #define WSI_GET_CB(func) \
    PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
    WSI_GET_CB(GetPhysicalDeviceMemoryProperties);
@@ -64,10 +73,51 @@ wsi_device_init(struct wsi_device *wsi,
    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);
+   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
+
+   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
 }
 
 VkResult
@@ -84,6 +134,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,
@@ -114,10 +165,14 @@ fail:
 void
 wsi_swapchain_finish(struct wsi_swapchain *chain)
 {
+   for (unsigned i = 0; i < ARRAY_SIZE(chain->fences); i++)
+      chain->wsi->DestroyFence(chain->device, chain->fences[i], &chain->alloc);
+
    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
@@ -156,18 +211,103 @@ align_u32(uint32_t v, uint32_t a)
 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;
 
-   const struct wsi_image_create_info image_wsi_info = {
+   struct wsi_image_create_info image_wsi_info = {
       .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA,
       .pNext = NULL,
-      .scanout = true,
    };
+
+   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,
+      };
+      VkFormatProperties2KHR format_props = {
+         .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR,
+         .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,
@@ -197,15 +337,6 @@ wsi_create_native_image(const struct wsi_swapchain *chain,
    VkMemoryRequirements reqs;
    wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
 
-   VkSubresourceLayout image_layout;
-   const VkImageSubresource image_subresource = {
-      .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
-      .mipLevel = 0,
-      .arrayLayer = 0,
-   };
-   wsi->GetImageSubresourceLayout(chain->device, image->image,
-                                  &image_subresource, &image_layout);
-
    const struct wsi_memory_allocate_info memory_wsi_info = {
       .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
       .pNext = NULL,
@@ -250,14 +381,67 @@ wsi_create_native_image(const struct wsi_swapchain *chain,
    if (result != VK_SUCCESS)
       goto fail;
 
-   image->size = reqs.size;
-   image->row_pitch = image_layout.rowPitch;
-   image->offset = 0;
-   image->fd = fd;
+   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_KHR << 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;
@@ -268,6 +452,7 @@ fail:
 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;
@@ -390,8 +575,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 = {
@@ -450,10 +637,12 @@ 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;
 
@@ -484,27 +673,200 @@ wsi_destroy_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,
+                               int local_fd,
+                               uint32_t queueFamilyIndex,
+                               VkSurfaceKHR _surface,
+                               const VkAllocationCallbacks *alloc,
+                               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, 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];
+
+   VkSurfaceCapabilities2KHR caps2 = {
+      .sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
    };
-   return chain->wsi->QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
+
+   VkResult result = iface->get_capabilities2(surface, 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, 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,
+   };
+
+   VkResult result = iface->get_capabilities2(surface, 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_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
@@ -541,10 +903,45 @@ wsi_common_queue_present(const struct wsi_device *wsi,
       VkSubmitInfo submit_info = {
          .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
          .pNext = NULL,
-         .waitSemaphoreCount = pPresentInfo->waitSemaphoreCount,
-         .pWaitSemaphores = pPresentInfo->pWaitSemaphores,
       };
+
+      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;
 
@@ -553,9 +950,6 @@ wsi_common_queue_present(const struct wsi_device *wsi,
          region = &regions->pRegions[i];
 
       result = swapchain->queue_present(swapchain,
-                                        queue,
-                                        pPresentInfo->waitSemaphoreCount,
-                                        pPresentInfo->pWaitSemaphores,
                                         pPresentInfo->pImageIndices[i],
                                         region);
       if (result != VK_SUCCESS)