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;