wined3d: Implement swapchains for the Vulkan adapter.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Henri Verbeet 2020-05-29 20:33:35 +04:30 committed by Alexandre Julliard
parent a8141ef080
commit 9aeef376e5
4 changed files with 658 additions and 10 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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;