[PATCH 5/5] wined3d: Implement swapchains for the Vulkan adapter.

Henri Verbeet hverbeet at codeweavers.com
Fri May 29 11:03:35 CDT 2020


Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/wined3d/adapter_vk.c      |  13 +-
 dlls/wined3d/swapchain.c       | 613 ++++++++++++++++++++++++++++++++-
 dlls/wined3d/wined3d_private.h |  24 +-
 dlls/wined3d/wined3d_vk.h      |  18 +-
 4 files changed, 658 insertions(+), 10 deletions(-)

diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index cbde5d3683c..586be3751a0 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -421,6 +421,7 @@ vulkan_device_extensions[] =
     {VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,    ~0u},
     {VK_KHR_MAINTENANCE1_EXTENSION_NAME,                VK_API_VERSION_1_1},
     {VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,      VK_API_VERSION_1_1},
+    {VK_KHR_SWAPCHAIN_EXTENSION_NAME,                   ~0u},
 };
 
 static bool enable_vulkan_device_extensions(VkPhysicalDevice physical_device, uint32_t *extension_count,
@@ -1180,7 +1181,7 @@ static void adapter_vk_copy_bo_address(struct wined3d_context *context,
 static HRESULT adapter_vk_create_swapchain(struct wined3d_device *device, struct wined3d_swapchain_desc *desc,
         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_swapchain **swapchain)
 {
-    struct wined3d_swapchain *swapchain_vk;
+    struct wined3d_swapchain_vk *swapchain_vk;
     HRESULT hr;
 
     TRACE("device %p, desc %p, parent %p, parent_ops %p, swapchain %p.\n",
@@ -1197,15 +1198,17 @@ static HRESULT adapter_vk_create_swapchain(struct wined3d_device *device, struct
     }
 
     TRACE("Created swapchain %p.\n", swapchain_vk);
-    *swapchain = swapchain_vk;
+    *swapchain = &swapchain_vk->s;
 
     return hr;
 }
 
 static void adapter_vk_destroy_swapchain(struct wined3d_swapchain *swapchain)
 {
-    wined3d_swapchain_cleanup(swapchain);
-    heap_free(swapchain);
+    struct wined3d_swapchain_vk *swapchain_vk = wined3d_swapchain_vk(swapchain);
+
+    wined3d_swapchain_vk_cleanup(swapchain_vk);
+    heap_free(swapchain_vk);
 }
 
 unsigned int wined3d_adapter_vk_get_memory_type_index(const struct wined3d_adapter_vk *adapter_vk,
@@ -1827,6 +1830,8 @@ static const struct
 vulkan_instance_extensions[] =
 {
     {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_API_VERSION_1_1, FALSE},
+    {VK_KHR_SURFACE_EXTENSION_NAME,                          ~0u,                TRUE},
+    {VK_KHR_WIN32_SURFACE_EXTENSION_NAME,                    ~0u,                TRUE},
 };
 
 static BOOL enable_vulkan_instance_extensions(uint32_t *extension_count,
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 465ab08eb82..e23da1180c1 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -113,6 +113,45 @@ void wined3d_swapchain_gl_cleanup(struct wined3d_swapchain_gl *swapchain_gl)
     }
 }
 
+static void wined3d_swapchain_vk_destroy_vulkan_swapchain(struct wined3d_swapchain_vk *swapchain_vk)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
+    const struct wined3d_vk_info *vk_info;
+    unsigned int i;
+    VkResult vr;
+
+    TRACE("swapchain_vk %p.\n", swapchain_vk);
+
+    vk_info = &wined3d_adapter_vk(device_vk->d.adapter)->vk_info;
+
+    if ((vr = VK_CALL(vkQueueWaitIdle(device_vk->vk_queue))) < 0)
+        ERR("Failed to wait on queue, vr %s.\n", wined3d_debug_vkresult(vr));
+    heap_free(swapchain_vk->vk_images);
+    for (i = 0; i < swapchain_vk->image_count; ++i)
+    {
+        VK_CALL(vkDestroySemaphore(device_vk->vk_device, swapchain_vk->vk_semaphores[i].available, NULL));
+        VK_CALL(vkDestroySemaphore(device_vk->vk_device, swapchain_vk->vk_semaphores[i].presentable, NULL));
+    }
+    heap_free(swapchain_vk->vk_semaphores);
+    VK_CALL(vkDestroySwapchainKHR(device_vk->vk_device, swapchain_vk->vk_swapchain, NULL));
+    VK_CALL(vkDestroySurfaceKHR(vk_info->instance, swapchain_vk->vk_surface, NULL));
+}
+
+static void wined3d_swapchain_vk_destroy_object(void *object)
+{
+    wined3d_swapchain_vk_destroy_vulkan_swapchain(object);
+}
+
+void wined3d_swapchain_vk_cleanup(struct wined3d_swapchain_vk *swapchain_vk)
+{
+    struct wined3d_cs *cs = swapchain_vk->s.device->cs;
+
+    wined3d_cs_destroy_object(cs, wined3d_swapchain_vk_destroy_object, swapchain_vk);
+    wined3d_cs_finish(cs, WINED3D_CS_QUEUE_DEFAULT);
+
+    wined3d_swapchain_cleanup(&swapchain_vk->s);
+}
+
 ULONG CDECL wined3d_swapchain_incref(struct wined3d_swapchain *swapchain)
 {
     ULONG refcount = InterlockedIncrement(&swapchain->ref);
@@ -551,10 +590,561 @@ static const struct wined3d_swapchain_ops swapchain_gl_ops =
     swapchain_frontbuffer_updated,
 };
 
+static bool wined3d_swapchain_vk_present_mode_supported(struct wined3d_swapchain_vk *swapchain_vk,
+        VkPresentModeKHR vk_present_mode)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
+    const struct wined3d_vk_info *vk_info;
+    struct wined3d_adapter_vk *adapter_vk;
+    VkPhysicalDevice vk_physical_device;
+    VkPresentModeKHR *vk_modes;
+    bool supported = false;
+    uint32_t count, i;
+    VkResult vr;
+
+    adapter_vk = wined3d_adapter_vk(device_vk->d.adapter);
+    vk_physical_device = adapter_vk->physical_device;
+    vk_info = &adapter_vk->vk_info;
+
+    if ((vr = VK_CALL(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical_device,
+            swapchain_vk->vk_surface, &count, NULL))) < 0)
+    {
+        ERR("Failed to get supported present mode count, vr %s.\n", wined3d_debug_vkresult(vr));
+        return false;
+    }
+
+    if (!(vk_modes = heap_calloc(count, sizeof(*vk_modes))))
+        return false;
+
+    if ((vr = VK_CALL(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical_device,
+            swapchain_vk->vk_surface, &count, vk_modes))) < 0)
+    {
+        ERR("Failed to get supported present modes, vr %s.\n", wined3d_debug_vkresult(vr));
+        goto done;
+    }
+
+    for (i = 0; i < count; ++i)
+    {
+        if (vk_modes[i] == vk_present_mode)
+        {
+            supported = true;
+            goto done;
+        }
+    }
+
+done:
+    heap_free(vk_modes);
+    return supported;
+}
+
+static VkFormat wined3d_swapchain_vk_select_vk_format(struct wined3d_swapchain_vk *swapchain_vk,
+        VkSurfaceKHR vk_surface)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
+    const struct wined3d_swapchain_desc *desc = &swapchain_vk->s.state.desc;
+    const struct wined3d_vk_info *vk_info;
+    struct wined3d_adapter_vk *adapter_vk;
+    const struct wined3d_format *format;
+    VkPhysicalDevice vk_physical_device;
+    VkSurfaceFormatKHR *vk_formats;
+    uint32_t format_count, i;
+    VkFormat vk_format;
+    VkResult vr;
+
+    adapter_vk = wined3d_adapter_vk(device_vk->d.adapter);
+    vk_physical_device = adapter_vk->physical_device;
+    vk_info = &adapter_vk->vk_info;
+
+    if ((format = wined3d_get_format(&adapter_vk->a, desc->backbuffer_format, WINED3D_BIND_RENDER_TARGET)))
+        vk_format = wined3d_format_vk(format)->vk_format;
+    else
+        vk_format = VK_FORMAT_B8G8R8A8_UNORM;
+
+    vr = VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL));
+    if (vr < 0 || !format_count)
+    {
+        WARN("Failed to get supported surface format count, vr %s.\n", wined3d_debug_vkresult(vr));
+        return VK_FORMAT_UNDEFINED;
+    }
+
+    if (!(vk_formats = heap_calloc(format_count, sizeof(*vk_formats))))
+        return VK_FORMAT_UNDEFINED;
+
+    if ((vr = VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device,
+            vk_surface, &format_count, vk_formats))) < 0)
+    {
+        WARN("Failed to get supported surface formats, vr %s.\n", wined3d_debug_vkresult(vr));
+        heap_free(vk_formats);
+        return VK_FORMAT_UNDEFINED;
+    }
+
+    for (i = 0; i < format_count; ++i)
+    {
+        if (vk_formats[i].format == vk_format && vk_formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
+            break;
+    }
+    if (i == format_count)
+    {
+        /* Try to create a swapchain with format conversion. */
+        vk_format = VK_FORMAT_B8G8R8A8_UNORM;
+        WARN("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(desc->backbuffer_format));
+        for (i = 0; i < format_count; ++i)
+        {
+            if (vk_formats[i].format == vk_format && vk_formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
+                break;
+        }
+    }
+    heap_free(vk_formats);
+    if (i == format_count)
+    {
+        FIXME("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(desc->backbuffer_format));
+        return VK_FORMAT_UNDEFINED;
+    }
+
+    TRACE("Using Vulkan swapchain format %#x.\n", vk_format);
+
+    return vk_format;
+}
+
+static bool wined3d_swapchain_vk_create_vulkan_swapchain_images(struct wined3d_swapchain_vk *swapchain_vk,
+        VkSwapchainKHR vk_swapchain)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
+    const struct wined3d_vk_info *vk_info;
+    VkSemaphoreCreateInfo semaphore_info;
+    uint32_t image_count, i;
+    VkResult vr;
+
+    vk_info = &wined3d_adapter_vk(device_vk->d.adapter)->vk_info;
+
+    if ((vr = VK_CALL(vkGetSwapchainImagesKHR(device_vk->vk_device, vk_swapchain, &image_count, NULL))) < 0)
+    {
+        ERR("Failed to get image count, vr %s\n", wined3d_debug_vkresult(vr));
+        return false;
+    }
+
+    if (!(swapchain_vk->vk_images = heap_calloc(image_count, sizeof(*swapchain_vk->vk_images))))
+    {
+        ERR("Failed to allocate images array.\n");
+        return false;
+    }
+
+    if ((vr = VK_CALL(vkGetSwapchainImagesKHR(device_vk->vk_device,
+            vk_swapchain, &image_count, swapchain_vk->vk_images))) < 0)
+    {
+        ERR("Failed to get swapchain images, vr %s.\n", wined3d_debug_vkresult(vr));
+        heap_free(swapchain_vk->vk_images);
+        return false;
+    }
+
+    if (!(swapchain_vk->vk_semaphores = heap_calloc(image_count, sizeof(*swapchain_vk->vk_semaphores))))
+    {
+        ERR("Failed to allocate semaphores array.\n");
+        heap_free(swapchain_vk->vk_images);
+        return false;
+    }
+
+    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    semaphore_info.pNext = NULL;
+    semaphore_info.flags = 0;
+    for (i = 0; i < image_count; ++i)
+    {
+        if ((vr = VK_CALL(vkCreateSemaphore(device_vk->vk_device,
+                &semaphore_info, NULL, &swapchain_vk->vk_semaphores[i].available))) < 0)
+        {
+            ERR("Failed to create semaphore, vr %s.\n", wined3d_debug_vkresult(vr));
+            goto fail;
+        }
+
+        if ((vr = VK_CALL(vkCreateSemaphore(device_vk->vk_device,
+                &semaphore_info, NULL, &swapchain_vk->vk_semaphores[i].presentable))) < 0)
+        {
+            ERR("Failed to create semaphore, vr %s.\n", wined3d_debug_vkresult(vr));
+            goto fail;
+        }
+    }
+    swapchain_vk->image_count = image_count;
+
+    return true;
+
+fail:
+    for (i = 0; i < image_count; ++i)
+    {
+        if (swapchain_vk->vk_semaphores[i].available)
+            VK_CALL(vkDestroySemaphore(device_vk->vk_device, swapchain_vk->vk_semaphores[i].available, NULL));
+        if (swapchain_vk->vk_semaphores[i].presentable)
+            VK_CALL(vkDestroySemaphore(device_vk->vk_device, swapchain_vk->vk_semaphores[i].presentable, NULL));
+    }
+    heap_free(swapchain_vk->vk_semaphores);
+    heap_free(swapchain_vk->vk_images);
+    return false;
+}
+
+static HRESULT wined3d_swapchain_vk_create_vulkan_swapchain(struct wined3d_swapchain_vk *swapchain_vk)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
+    const struct wined3d_swapchain_desc *desc = &swapchain_vk->s.state.desc;
+    VkSwapchainCreateInfoKHR vk_swapchain_desc;
+    VkWin32SurfaceCreateInfoKHR surface_desc;
+    unsigned int width, height, image_count;
+    const struct wined3d_vk_info *vk_info;
+    VkSurfaceCapabilitiesKHR surface_caps;
+    struct wined3d_adapter_vk *adapter_vk;
+    VkPresentModeKHR vk_present_mode;
+    VkSwapchainKHR vk_swapchain;
+    VkImageUsageFlags usage;
+    VkSurfaceKHR vk_surface;
+    VkBool32 supported;
+    VkFormat vk_format;
+    VkResult vr;
+
+    adapter_vk = wined3d_adapter_vk(device_vk->d.adapter);
+    vk_info = &adapter_vk->vk_info;
+
+    surface_desc.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+    surface_desc.pNext = NULL;
+    surface_desc.flags = 0;
+    surface_desc.hinstance = (HINSTANCE)GetWindowLongPtrW(swapchain_vk->s.win_handle, GWLP_HINSTANCE);
+    surface_desc.hwnd = swapchain_vk->s.win_handle;
+    if ((vr = VK_CALL(vkCreateWin32SurfaceKHR(vk_info->instance, &surface_desc, NULL, &vk_surface))) < 0)
+    {
+        ERR("Failed to create Vulkan surface, vr %s.\n", wined3d_debug_vkresult(vr));
+        return E_FAIL;
+    }
+    swapchain_vk->vk_surface = vk_surface;
+
+    if ((vr = VK_CALL(vkGetPhysicalDeviceSurfaceSupportKHR(adapter_vk->physical_device,
+            device_vk->vk_queue_family_index, vk_surface, &supported))) < 0 || !supported)
+    {
+        ERR("Queue family does not support presentation on this surface, vr %s.\n", wined3d_debug_vkresult(vr));
+        goto fail;
+    }
+
+    if ((vk_format = wined3d_swapchain_vk_select_vk_format(swapchain_vk, vk_surface)) == VK_FORMAT_UNDEFINED)
+    {
+        ERR("Failed to select swapchain format.\n");
+        goto fail;
+    }
+
+    if ((vr = VK_CALL(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(adapter_vk->physical_device,
+            swapchain_vk->vk_surface, &surface_caps))) < 0)
+    {
+        ERR("Failed to get surface capabilities, vr %s.\n", wined3d_debug_vkresult(vr));
+        goto fail;
+    }
+
+    image_count = desc->backbuffer_count;
+    if (image_count < surface_caps.minImageCount)
+        image_count = surface_caps.minImageCount;
+    else if (surface_caps.maxImageCount && image_count > surface_caps.maxImageCount)
+        image_count = surface_caps.maxImageCount;
+
+    if (image_count != desc->backbuffer_count)
+        WARN("Image count %u is not supported (%u-%u).\n", desc->backbuffer_count,
+                surface_caps.minImageCount, surface_caps.maxImageCount);
+
+    width = desc->backbuffer_width;
+    if (width < surface_caps.minImageExtent.width)
+        width = surface_caps.minImageExtent.width;
+    else if (width > surface_caps.maxImageExtent.width)
+        width = surface_caps.maxImageExtent.width;
+
+    height = desc->backbuffer_height;
+    if (height < surface_caps.minImageExtent.height)
+        height = surface_caps.minImageExtent.height;
+    else if (height > surface_caps.maxImageExtent.height)
+        height = surface_caps.maxImageExtent.height;
+
+    if (width != desc->backbuffer_width || height != desc->backbuffer_height)
+        WARN("Swapchain dimensions %ux%u are not supported (%u-%u x %u-%u).\n",
+                desc->backbuffer_width, desc->backbuffer_height,
+                surface_caps.minImageExtent.width, surface_caps.maxImageExtent.width,
+                surface_caps.minImageExtent.height, surface_caps.maxImageExtent.height);
+
+    usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+    usage |= surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+    usage |= surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+    if (!(usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) || !(usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
+        WARN("Transfer not supported for swapchain images.\n");
+
+    if (!(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
+    {
+        FIXME("Unsupported alpha mode, %#x.\n", surface_caps.supportedCompositeAlpha);
+        goto fail;
+    }
+
+    vk_present_mode = VK_PRESENT_MODE_FIFO_KHR;
+    if (!swapchain_vk->s.swap_interval)
+    {
+        if (wined3d_swapchain_vk_present_mode_supported(swapchain_vk, VK_PRESENT_MODE_IMMEDIATE_KHR))
+            vk_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
+        else
+            FIXME("Unsupported swap interval %u.\n", swapchain_vk->s.swap_interval);
+    }
+
+    vk_swapchain_desc.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+    vk_swapchain_desc.pNext = NULL;
+    vk_swapchain_desc.flags = 0;
+    vk_swapchain_desc.surface = vk_surface;
+    vk_swapchain_desc.minImageCount = image_count;
+    vk_swapchain_desc.imageFormat = vk_format;
+    vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
+    vk_swapchain_desc.imageExtent.width = width;
+    vk_swapchain_desc.imageExtent.height = height;
+    vk_swapchain_desc.imageArrayLayers = 1;
+    vk_swapchain_desc.imageUsage = usage;
+    vk_swapchain_desc.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+    vk_swapchain_desc.queueFamilyIndexCount = 0;
+    vk_swapchain_desc.pQueueFamilyIndices = NULL;
+    vk_swapchain_desc.preTransform = surface_caps.currentTransform;
+    vk_swapchain_desc.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+    vk_swapchain_desc.presentMode = vk_present_mode;
+    vk_swapchain_desc.clipped = VK_TRUE;
+    vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE;
+    if ((vr = VK_CALL(vkCreateSwapchainKHR(device_vk->vk_device, &vk_swapchain_desc, NULL, &vk_swapchain))) < 0)
+    {
+        ERR("Failed to create Vulkan swapchain, vr %s.\n", wined3d_debug_vkresult(vr));
+        goto fail;
+    }
+    swapchain_vk->vk_swapchain = vk_swapchain;
+
+    if (!wined3d_swapchain_vk_create_vulkan_swapchain_images(swapchain_vk, vk_swapchain))
+    {
+        VK_CALL(vkDestroySwapchainKHR(device_vk->vk_device, vk_swapchain, NULL));
+        goto fail;
+    }
+
+    return WINED3D_OK;
+
+fail:
+    VK_CALL(vkDestroySurfaceKHR(vk_info->instance, vk_surface, NULL));
+    return E_FAIL;
+}
+
+static HRESULT wined3d_swapchain_vk_recreate(struct wined3d_swapchain_vk *swapchain_vk)
+{
+    TRACE("swapchain_vk %p.\n", swapchain_vk);
+
+    wined3d_swapchain_vk_destroy_vulkan_swapchain(swapchain_vk);
+
+    return wined3d_swapchain_vk_create_vulkan_swapchain(swapchain_vk);
+}
+
+static void wined3d_swapchain_vk_set_swap_interval(struct wined3d_swapchain_vk *swapchain_vk,
+        unsigned int swap_interval)
+{
+    if (swap_interval > 1)
+    {
+        if (swap_interval <= 4)
+            FIXME("Unsupported swap interval %u.\n", swap_interval);
+        swap_interval = 1;
+    }
+
+    if (swapchain_vk->s.swap_interval == swap_interval)
+        return;
+
+    swapchain_vk->s.swap_interval = swap_interval;
+    wined3d_swapchain_vk_recreate(swapchain_vk);
+}
+
+static void 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]);
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
+    const struct wined3d_swapchain_desc *desc = &swapchain_vk->s.state.desc;
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    VkCommandBuffer vk_command_buffer;
+    VkPresentInfoKHR present_desc;
+    unsigned int present_idx;
+    VkImageLayout vk_layout;
+    uint32_t image_idx;
+    VkImageBlit blit;
+    VkResult vr;
+    HRESULT hr;
+
+    static const VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+
+    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;
+    }
+
+    vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
+
+    wined3d_context_vk_end_current_render_pass(context_vk);
+
+    wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
+            VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
+            vk_access_mask_from_bind_flags(back_buffer_vk->t.resource.bind_flags),
+            VK_ACCESS_TRANSFER_READ_BIT,
+            back_buffer_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+            back_buffer_vk->vk_image, VK_IMAGE_ASPECT_COLOR_BIT);
+
+    wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
+            VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
+            0, VK_ACCESS_TRANSFER_WRITE_BIT,
+            VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+            swapchain_vk->vk_images[image_idx], VK_IMAGE_ASPECT_COLOR_BIT);
+
+    blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    blit.srcSubresource.mipLevel = 0;
+    blit.srcSubresource.baseArrayLayer = 0;
+    blit.srcSubresource.layerCount = 1;
+    blit.srcOffsets[0].x = src_rect->left;
+    blit.srcOffsets[0].y = src_rect->top;
+    blit.srcOffsets[0].z = 0;
+    blit.srcOffsets[1].x = src_rect->right;
+    blit.srcOffsets[1].y = src_rect->bottom;
+    blit.srcOffsets[1].z = 1;
+    blit.dstSubresource = blit.srcSubresource;
+    blit.dstOffsets[0].x = dst_rect->left;
+    blit.dstOffsets[0].y = dst_rect->top;
+    blit.dstOffsets[0].z = 0;
+    blit.dstOffsets[1].x = dst_rect->right;
+    blit.dstOffsets[1].y = dst_rect->bottom;
+    blit.dstOffsets[1].z = 1;
+    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));
+
+    wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
+            VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+            VK_ACCESS_TRANSFER_WRITE_BIT, 0,
+            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+            swapchain_vk->vk_images[image_idx], VK_IMAGE_ASPECT_COLOR_BIT);
+
+    if (desc->swap_effect == WINED3D_SWAP_EFFECT_DISCARD || desc->swap_effect == WINED3D_SWAP_EFFECT_FLIP_DISCARD)
+        vk_layout = VK_IMAGE_LAYOUT_UNDEFINED;
+    else
+        vk_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+    wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
+            VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+            VK_ACCESS_TRANSFER_READ_BIT,
+            vk_access_mask_from_bind_flags(back_buffer_vk->t.resource.bind_flags),
+            vk_layout, back_buffer_vk->layout,
+            back_buffer_vk->vk_image, VK_IMAGE_ASPECT_COLOR_BIT);
+
+    swapchain_vk->vk_semaphores[present_idx].command_buffer_id = context_vk->current_command_buffer.id;
+    wined3d_context_vk_submit_command_buffer(context_vk,
+            1, &swapchain_vk->vk_semaphores[present_idx].available, &wait_stage,
+            1, &swapchain_vk->vk_semaphores[present_idx].presentable);
+
+    present_desc.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+    present_desc.pNext = NULL;
+    present_desc.waitSemaphoreCount = 1;
+    present_desc.pWaitSemaphores = &swapchain_vk->vk_semaphores[present_idx].presentable;
+    present_desc.swapchainCount = 1;
+    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));
+}
+
+static void wined3d_swapchain_vk_rotate(struct wined3d_swapchain *swapchain, struct wined3d_context_vk *context_vk)
+{
+    struct wined3d_texture_sub_resource *sub_resource;
+    struct wined3d_texture_vk *texture, *texture_prev;
+    struct wined3d_allocator_block *memory0;
+    VkDescriptorImageInfo vk_info0;
+    VkDeviceMemory vk_memory0;
+    VkImageLayout vk_layout0;
+    VkImage vk_image0;
+    DWORD locations0;
+    unsigned int i;
+    uint64_t id0;
+
+    static const DWORD supported_locations = WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_RB_MULTISAMPLE;
+
+    if (swapchain->state.desc.backbuffer_count < 2)
+        return;
+
+    texture_prev = wined3d_texture_vk(swapchain->back_buffers[0]);
+
+    /* Back buffer 0 is already in the draw binding. */
+    vk_image0 = texture_prev->vk_image;
+    memory0 = texture_prev->memory;
+    vk_memory0 = texture_prev->vk_memory;
+    vk_layout0 = texture_prev->layout;
+    id0 = texture_prev->command_buffer_id;
+    vk_info0 = texture_prev->default_image_info;
+    locations0 = texture_prev->t.sub_resources[0].locations;
+
+    for (i = 1; i < swapchain->state.desc.backbuffer_count; ++i)
+    {
+        texture = wined3d_texture_vk(swapchain->back_buffers[i]);
+        sub_resource = &texture->t.sub_resources[0];
+
+        if (!(sub_resource->locations & supported_locations))
+            wined3d_texture_load_location(&texture->t, 0, &context_vk->c, texture->t.resource.draw_binding);
+
+        texture_prev->vk_image = texture->vk_image;
+        texture_prev->memory = texture->memory;
+        texture_prev->vk_memory = texture->vk_memory;
+        texture_prev->layout = texture->layout;
+        texture_prev->command_buffer_id = texture->command_buffer_id;
+        texture_prev->default_image_info = texture->default_image_info;
+
+        wined3d_texture_validate_location(&texture_prev->t, 0, sub_resource->locations & supported_locations);
+        wined3d_texture_invalidate_location(&texture_prev->t, 0, ~(sub_resource->locations & supported_locations));
+
+        texture_prev = texture;
+    }
+
+    texture_prev->vk_image = vk_image0;
+    texture_prev->memory = memory0;
+    texture_prev->vk_memory = vk_memory0;
+    texture_prev->layout = vk_layout0;
+    texture_prev->command_buffer_id = id0;
+    texture_prev->default_image_info = vk_info0;
+
+    wined3d_texture_validate_location(&texture_prev->t, 0, locations0 & supported_locations);
+    wined3d_texture_invalidate_location(&texture_prev->t, 0, ~(locations0 & supported_locations));
+
+    device_invalidate_state(swapchain->device, STATE_FRAMEBUFFER);
+}
+
 static void swapchain_vk_present(struct wined3d_swapchain *swapchain, const RECT *src_rect,
         const RECT *dst_rect, unsigned int swap_interval, uint32_t flags)
 {
-    FIXME("Not implemented.\n");
+    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;
+
+    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);
+
+    wined3d_swapchain_vk_rotate(swapchain, context_vk);
+
+    wined3d_texture_validate_location(swapchain->front_buffer, 0, WINED3D_LOCATION_DRAWABLE);
+    wined3d_texture_invalidate_location(swapchain->front_buffer, 0, ~WINED3D_LOCATION_DRAWABLE);
+
+    TRACE("Starting new frame.\n");
+
+    context_release(&context_vk->c);
 }
 
 static const struct wined3d_swapchain_ops swapchain_vk_ops =
@@ -994,13 +1584,30 @@ HRESULT wined3d_swapchain_gl_init(struct wined3d_swapchain_gl *swapchain_gl, str
     return hr;
 }
 
-HRESULT wined3d_swapchain_vk_init(struct wined3d_swapchain *swapchain_vk, struct wined3d_device *device,
+HRESULT wined3d_swapchain_vk_init(struct wined3d_swapchain_vk *swapchain_vk, struct wined3d_device *device,
         struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops)
 {
+    HRESULT hr;
+
     TRACE("swapchain_vk %p, device %p, desc %p, parent %p, parent_ops %p.\n",
             swapchain_vk, device, desc, parent, parent_ops);
 
-    return wined3d_swapchain_init(swapchain_vk, device, desc, parent, parent_ops, &swapchain_vk_ops);
+    if (FAILED(hr = wined3d_swapchain_init(&swapchain_vk->s, device, desc, parent, parent_ops, &swapchain_vk_ops)))
+        return hr;
+
+    if (swapchain_vk->s.win_handle == GetDesktopWindow())
+    {
+        WARN("Creating a desktop window swapchain.\n");
+        return hr;
+    }
+
+    if (FAILED(hr = wined3d_swapchain_vk_create_vulkan_swapchain(swapchain_vk)))
+    {
+        wined3d_swapchain_cleanup(&swapchain_vk->s);
+        return hr;
+    }
+
+    return hr;
 }
 
 HRESULT CDECL wined3d_swapchain_create(struct wined3d_device *device, struct wined3d_swapchain_desc *desc,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 8eee18ad17a..d96f27ccc69 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -5084,7 +5084,29 @@ HRESULT wined3d_swapchain_gl_init(struct wined3d_swapchain_gl *swapchain_gl,
         struct wined3d_device *device, struct wined3d_swapchain_desc *desc,
         void *parent, const struct wined3d_parent_ops *parent_ops) DECLSPEC_HIDDEN;
 
-HRESULT wined3d_swapchain_vk_init(struct wined3d_swapchain *swapchain_vk,
+struct wined3d_swapchain_vk
+{
+    struct wined3d_swapchain s;
+
+    VkSwapchainKHR vk_swapchain;
+    VkSurfaceKHR vk_surface;
+    VkImage *vk_images;
+    struct
+    {
+        VkSemaphore available;
+        VkSemaphore presentable;
+        uint64_t command_buffer_id;
+    } *vk_semaphores;
+    unsigned int current, image_count;
+};
+
+static inline struct wined3d_swapchain_vk *wined3d_swapchain_vk(struct wined3d_swapchain *swapchain)
+{
+    return CONTAINING_RECORD(swapchain, struct wined3d_swapchain_vk, s);
+}
+
+void wined3d_swapchain_vk_cleanup(struct wined3d_swapchain_vk *swapchain_vk) DECLSPEC_HIDDEN;
+HRESULT wined3d_swapchain_vk_init(struct wined3d_swapchain_vk *swapchain_vk,
         struct wined3d_device *device, struct wined3d_swapchain_desc *desc,
         void *parent, const struct wined3d_parent_ops *parent_ops) DECLSPEC_HIDDEN;
 
diff --git a/dlls/wined3d/wined3d_vk.h b/dlls/wined3d/wined3d_vk.h
index 4a872bcdaa0..ae81fe945ee 100644
--- a/dlls/wined3d/wined3d_vk.h
+++ b/dlls/wined3d/wined3d_vk.h
@@ -41,7 +41,15 @@
     VK_INSTANCE_PFN(vkGetPhysicalDeviceSparseImageFormatProperties) \
     /* Vulkan 1.1 */ \
     VK_INSTANCE_EXT_PFN(vkGetPhysicalDeviceFeatures2) \
-    VK_INSTANCE_EXT_PFN(vkGetPhysicalDeviceProperties2)
+    VK_INSTANCE_EXT_PFN(vkGetPhysicalDeviceProperties2) \
+    /* VK_KHR_surface */ \
+    VK_INSTANCE_PFN(vkDestroySurfaceKHR) \
+    VK_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
+    VK_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceFormatsKHR) \
+    VK_INSTANCE_PFN(vkGetPhysicalDeviceSurfacePresentModesKHR) \
+    VK_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceSupportKHR) \
+    /* VK_KHR_win32_surface */ \
+    VK_INSTANCE_PFN(vkCreateWin32SurfaceKHR)
 
 #define VK_DEVICE_FUNCS() \
     VK_DEVICE_PFN(vkAllocateCommandBuffers) \
@@ -163,7 +171,13 @@
     VK_DEVICE_PFN(vkSetEvent) \
     VK_DEVICE_PFN(vkUnmapMemory) \
     VK_DEVICE_PFN(vkUpdateDescriptorSets) \
-    VK_DEVICE_PFN(vkWaitForFences)
+    VK_DEVICE_PFN(vkWaitForFences) \
+    /* VK_KHR_swapchain */ \
+    VK_DEVICE_PFN(vkAcquireNextImageKHR) \
+    VK_DEVICE_PFN(vkCreateSwapchainKHR) \
+    VK_DEVICE_PFN(vkDestroySwapchainKHR) \
+    VK_DEVICE_PFN(vkGetSwapchainImagesKHR) \
+    VK_DEVICE_PFN(vkQueuePresentKHR)
 
 #define DECLARE_VK_PFN(name) PFN_##name name;
 
-- 
2.20.1




More information about the wine-devel mailing list