[PATCH v3 1/5] wined3d: Handle blits to Vulkan swapchains not matching the D3D swapchain.

Matteo Bruni mbruni at codeweavers.com
Wed Mar 17 07:35:19 CDT 2021


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50119
Signed-off-by: Matteo Bruni <mbruni at codeweavers.com>
---
v2: Fix off-by-one (not sure how I convinced myself that right and
bottom coordinates were inclusive, they clearly are not), also
recreate swapchain on VK_SUBOPTIMAL_KHR, retry to present the image
after swapchain recreation.
v3: Fix swapchain recreation and blit retry.

 dlls/wined3d/swapchain.c       | 72 ++++++++++++++++++++++------------
 dlls/wined3d/wined3d_private.h |  1 +
 2 files changed, 49 insertions(+), 24 deletions(-)

diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 0683ffef6fe..f362408fa7b 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -998,6 +998,9 @@ static HRESULT wined3d_swapchain_vk_create_vulkan_swapchain(struct wined3d_swapc
         goto fail;
     }
 
+    swapchain_vk->width = width;
+    swapchain_vk->height = height;
+
     return WINED3D_OK;
 
 fail:
@@ -1031,7 +1034,7 @@ static void wined3d_swapchain_vk_set_swap_interval(struct wined3d_swapchain_vk *
     wined3d_swapchain_vk_recreate(swapchain_vk);
 }
 
-static void wined3d_swapchain_vk_blit(struct wined3d_swapchain_vk *swapchain_vk,
+static VkResult wined3d_swapchain_vk_blit(struct wined3d_swapchain_vk *swapchain_vk,
         struct wined3d_context_vk *context_vk, const RECT *src_rect, const RECT *dst_rect, unsigned int swap_interval)
 {
     struct wined3d_texture_vk *back_buffer_vk = wined3d_texture_vk(swapchain_vk->s.back_buffers[0]);
@@ -1044,34 +1047,36 @@ static void wined3d_swapchain_vk_blit(struct wined3d_swapchain_vk *swapchain_vk,
     unsigned int present_idx;
     VkImageLayout vk_layout;
     uint32_t image_idx;
+    RECT dst_rect_tmp;
     VkImageBlit blit;
+    VkFilter filter;
     VkResult vr;
-    HRESULT hr;
 
     static const VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
 
+    TRACE("swapchain_vk %p, context_vk %p, src_rect %s, dst_rect %s, swap_interval %u.\n",
+            swapchain_vk, context_vk, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect), swap_interval);
+
     wined3d_swapchain_vk_set_swap_interval(swapchain_vk, swap_interval);
 
     present_idx = swapchain_vk->current++ % swapchain_vk->image_count;
     wined3d_context_vk_wait_command_buffer(context_vk, swapchain_vk->vk_semaphores[present_idx].command_buffer_id);
-    vr = VK_CALL(vkAcquireNextImageKHR(device_vk->vk_device, swapchain_vk->vk_swapchain, UINT64_MAX,
-            swapchain_vk->vk_semaphores[present_idx].available, VK_NULL_HANDLE, &image_idx));
-    if (vr == VK_ERROR_OUT_OF_DATE_KHR)
-    {
-        if (FAILED(hr = wined3d_swapchain_vk_recreate(swapchain_vk)))
-        {
-            ERR("Failed to recreate swapchain, hr %#x.\n", hr);
-            return;
-        }
-        vr = VK_CALL(vkAcquireNextImageKHR(device_vk->vk_device, swapchain_vk->vk_swapchain, UINT64_MAX,
-                swapchain_vk->vk_semaphores[present_idx].available, VK_NULL_HANDLE, &image_idx));
-    }
-    if (vr < 0)
-    {
-        ERR("Failed to acquire next Vulkan image, vr %s.\n", wined3d_debug_vkresult(vr));
-        return;
-    }
-
+    if ((vr = VK_CALL(vkAcquireNextImageKHR(device_vk->vk_device, swapchain_vk->vk_swapchain, UINT64_MAX,
+            swapchain_vk->vk_semaphores[present_idx].available, VK_NULL_HANDLE, &image_idx))) < 0)
+        return vr;
+
+    if (dst_rect->right > swapchain_vk->width || dst_rect->bottom > swapchain_vk->height)
+    {
+        dst_rect_tmp = *dst_rect;
+        if (dst_rect->right > swapchain_vk->width)
+            dst_rect_tmp.right = swapchain_vk->width;
+        if (dst_rect->bottom > swapchain_vk->height)
+            dst_rect_tmp.bottom = swapchain_vk->height;
+        dst_rect = &dst_rect_tmp;
+    }
+    filter = src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
+            || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top
+            ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
     vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
 
     wined3d_context_vk_end_current_render_pass(context_vk);
@@ -1115,7 +1120,7 @@ static void wined3d_swapchain_vk_blit(struct wined3d_swapchain_vk *swapchain_vk,
     VK_CALL(vkCmdBlitImage(vk_command_buffer,
             back_buffer_vk->vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
             swapchain_vk->vk_images[image_idx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-            1, &blit, VK_FILTER_NEAREST));
+            1, &blit, filter));
 
     wined3d_context_vk_reference_texture(context_vk, back_buffer_vk);
     wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
@@ -1149,8 +1154,7 @@ static void wined3d_swapchain_vk_blit(struct wined3d_swapchain_vk *swapchain_vk,
     present_desc.pSwapchains = &swapchain_vk->vk_swapchain;
     present_desc.pImageIndices = &image_idx;
     present_desc.pResults = NULL;
-    if ((vr = VK_CALL(vkQueuePresentKHR(device_vk->vk_queue, &present_desc))))
-        ERR("Present returned vr %s.\n", wined3d_debug_vkresult(vr));
+    return VK_CALL(vkQueuePresentKHR(device_vk->vk_queue, &present_desc));
 }
 
 static void wined3d_swapchain_vk_rotate(struct wined3d_swapchain *swapchain, struct wined3d_context_vk *context_vk)
@@ -1222,15 +1226,35 @@ static void swapchain_vk_present(struct wined3d_swapchain *swapchain, const RECT
     struct wined3d_swapchain_vk *swapchain_vk = wined3d_swapchain_vk(swapchain);
     struct wined3d_texture *back_buffer = swapchain->back_buffers[0];
     struct wined3d_context_vk *context_vk;
+    VkResult vr;
+    HRESULT hr;
 
     context_vk = wined3d_context_vk(context_acquire(swapchain->device, back_buffer, 0));
 
     wined3d_texture_load_location(back_buffer, 0, &context_vk->c, back_buffer->resource.draw_binding);
 
     if (swapchain_vk->vk_swapchain)
-        wined3d_swapchain_vk_blit(swapchain_vk, context_vk, src_rect, dst_rect, swap_interval);
+    {
+        if ((vr = wined3d_swapchain_vk_blit(swapchain_vk, context_vk, src_rect, dst_rect, swap_interval)))
+        {
+            if (vr == VK_ERROR_OUT_OF_DATE_KHR || vr == VK_SUBOPTIMAL_KHR)
+            {
+                if (FAILED(hr = wined3d_swapchain_vk_recreate(swapchain_vk)))
+                    ERR("Failed to recreate swapchain, hr %#x.\n", hr);
+                else if (vr == VK_ERROR_OUT_OF_DATE_KHR && (vr = wined3d_swapchain_vk_blit(
+                        swapchain_vk, context_vk, src_rect, dst_rect, swap_interval)))
+                    ERR("Failed to blit image, vr %s.\n", wined3d_debug_vkresult(vr));
+            }
+            else
+            {
+                ERR("Failed to blit image, vr %s.\n", wined3d_debug_vkresult(vr));
+            }
+        }
+    }
     else
+    {
         swapchain_blit_gdi(swapchain, &context_vk->c, src_rect, dst_rect);
+    }
 
     wined3d_swapchain_vk_rotate(swapchain, context_vk);
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 4ad0c05d34a..2b7e4186bc7 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -5304,6 +5304,7 @@ struct wined3d_swapchain_vk
         uint64_t command_buffer_id;
     } *vk_semaphores;
     unsigned int current, image_count;
+    unsigned int width, height;
 };
 
 static inline struct wined3d_swapchain_vk *wined3d_swapchain_vk(struct wined3d_swapchain *swapchain)
-- 
2.26.2




More information about the wine-devel mailing list