Signed-off-by: Józef Kucia jkucia@codeweavers.com ---
Version 2: Load libvkd3d just before creating a Direct3D 12 swapchain.
--- dlls/d3d12/d3d12_main.c | 16 ++ dlls/dxgi/Makefile.in | 3 +- dlls/dxgi/swapchain.c | 502 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 498 insertions(+), 23 deletions(-)
diff --git a/dlls/d3d12/d3d12_main.c b/dlls/d3d12/d3d12_main.c index 71eb1f97a73e..91525b49a790 100644 --- a/dlls/d3d12/d3d12_main.c +++ b/dlls/d3d12/d3d12_main.c @@ -34,6 +34,8 @@
#include <vkd3d.h>
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + WINE_DEFAULT_DEBUG_CHANNEL(d3d12); WINE_DECLARE_DEBUG_CHANNEL(winediag);
@@ -113,6 +115,16 @@ HRESULT WINAPI D3D12CreateDevice(IUnknown *adapter, D3D_FEATURE_LEVEL minimum_fe struct vkd3d_device_create_info device_create_info; const struct vulkan_funcs *vk_funcs;
+ static const char * const instance_extensions[] = + { + VK_KHR_SURFACE_EXTENSION_NAME, + VK_KHR_WIN32_SURFACE_EXTENSION_NAME, + }; + static const char * const device_extensions[] = + { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; + TRACE("adapter %p, minimum_feature_level %#x, iid %s, device %p.\n", adapter, minimum_feature_level, debugstr_guid(iid), device);
@@ -132,11 +144,15 @@ HRESULT WINAPI D3D12CreateDevice(IUnknown *adapter, D3D_FEATURE_LEVEL minimum_fe instance_create_info.wchar_size = sizeof(WCHAR); instance_create_info.pfn_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)vk_funcs->p_vkGetInstanceProcAddr; + instance_create_info.instance_extensions = instance_extensions; + instance_create_info.instance_extension_count = ARRAY_SIZE(instance_extensions);
memset(&device_create_info, 0, sizeof(device_create_info)); device_create_info.type = VKD3D_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.minimum_feature_level = minimum_feature_level; device_create_info.instance_create_info = &instance_create_info; + device_create_info.device_extensions = device_extensions; + device_create_info.device_extension_count = ARRAY_SIZE(device_extensions);
return vkd3d_create_device(&device_create_info, iid, device); } diff --git a/dlls/dxgi/Makefile.in b/dlls/dxgi/Makefile.in index ce76b8eecc61..c21cb18d8ffc 100644 --- a/dlls/dxgi/Makefile.in +++ b/dlls/dxgi/Makefile.in @@ -1,6 +1,7 @@ MODULE = dxgi.dll IMPORTLIB = dxgi -IMPORTS = dxguid uuid wined3d user32 +IMPORTS = gdi32 dxguid uuid wined3d user32 +EXTRAINCL = $(VKD3D_CFLAGS)
C_SRCS = \ adapter.c \ diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index ca4e59004ef2..23731e0dd07b 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -22,7 +22,21 @@
#include "dxgi_private.h"
+#ifdef SONAME_LIBVKD3D +#define VK_NO_PROTOTYPES +#define VKAPI_CALL +#define VKD3D_NO_PROTOTYPES +#define VKD3D_NO_VULKAN_H +#define VKD3D_NO_WIN32_TYPES +#define WINE_VK_ALIGN(x) +#include "wine/library.h" +#include "wine/vulkan.h" +#include "wine/vulkan_driver.h" +#include <vkd3d.h> +#endif + WINE_DEFAULT_DEBUG_CHANNEL(dxgi); +WINE_DECLARE_DEBUG_CHANNEL(winediag);
static inline struct d3d11_swapchain *d3d11_swapchain_from_IDXGISwapChain1(IDXGISwapChain1 *iface) { @@ -797,12 +811,59 @@ HRESULT d3d11_swapchain_create(IWineDXGIDevice *device, HWND window, const DXGI_ return S_OK; }
+#ifdef SONAME_LIBVKD3D + +static PFN_vkd3d_acquire_vk_queue vkd3d_acquire_vk_queue; +static PFN_vkd3d_create_image_resource vkd3d_create_image_resource; +static PFN_vkd3d_get_vk_device vkd3d_get_vk_device; +static PFN_vkd3d_get_vk_format vkd3d_get_vk_format; +static PFN_vkd3d_get_vk_physical_device vkd3d_get_vk_physical_device; +static PFN_vkd3d_get_vk_queue_family_index vkd3d_get_vk_queue_family_index; +static PFN_vkd3d_instance_from_device vkd3d_instance_from_device; +static PFN_vkd3d_instance_get_vk_instance vkd3d_instance_get_vk_instance; +static PFN_vkd3d_release_vk_queue vkd3d_release_vk_queue; +static PFN_vkd3d_resource_decref vkd3d_resource_decref; +static PFN_vkd3d_resource_incref vkd3d_resource_incref; + +struct dxgi_vk_funcs +{ + PFN_vkAcquireNextImageKHR p_vkAcquireNextImageKHR; + PFN_vkCreateSwapchainKHR p_vkCreateSwapchainKHR; + PFN_vkCreateWin32SurfaceKHR p_vkCreateWin32SurfaceKHR; + PFN_vkDestroySurfaceKHR p_vkDestroySurfaceKHR; + PFN_vkDestroySwapchainKHR p_vkDestroySwapchainKHR; + PFN_vkGetDeviceProcAddr p_vkGetDeviceProcAddr; + PFN_vkGetInstanceProcAddr p_vkGetInstanceProcAddr; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR p_vkGetPhysicalDeviceSurfaceFormatsKHR; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR p_vkGetPhysicalDeviceSurfacePresentModesKHR; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR p_vkGetPhysicalDeviceSurfaceSupportKHR; + PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR p_vkGetPhysicalDeviceWin32PresentationSupportKHR; + PFN_vkGetSwapchainImagesKHR p_vkGetSwapchainImagesKHR; + PFN_vkQueuePresentKHR p_vkQueuePresentKHR; + PFN_vkCreateFence p_vkCreateFence; + PFN_vkWaitForFences p_vkWaitForFences; + PFN_vkResetFences p_vkResetFences; + PFN_vkDestroyFence p_vkDestroyFence; +}; + struct d3d12_swapchain { IDXGISwapChain3 IDXGISwapChain3_iface; LONG refcount; struct wined3d_private_store private_store;
+ VkSwapchainKHR vk_swapchain; + VkSurfaceKHR vk_surface; + VkFence vk_fence; + VkInstance vk_instance; + VkDevice vk_device; + ID3D12Resource *buffers[DXGI_MAX_SWAP_CHAIN_BUFFERS]; + unsigned int buffer_count; + + uint32_t current_buffer_index; + struct dxgi_vk_funcs vk_funcs; + ID3D12CommandQueue *command_queue; ID3D12Device *device; IWineDXGIFactory *factory; @@ -855,7 +916,9 @@ static ULONG STDMETHODCALLTYPE d3d12_swapchain_AddRef(IDXGISwapChain3 *iface) static ULONG STDMETHODCALLTYPE d3d12_swapchain_Release(IDXGISwapChain3 *iface) { struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface); + const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs; ULONG refcount = InterlockedDecrement(&swapchain->refcount); + unsigned int i;
TRACE("%p decreasing refcount to %u.\n", swapchain, refcount);
@@ -866,6 +929,15 @@ static ULONG STDMETHODCALLTYPE d3d12_swapchain_Release(IDXGISwapChain3 *iface)
wined3d_private_store_cleanup(&swapchain->private_store);
+ for (i = 0; i < swapchain->buffer_count; ++i) + { + vkd3d_resource_decref(swapchain->buffers[i]); + } + + vk_funcs->p_vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL); + vk_funcs->p_vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL); + vk_funcs->p_vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL); + ID3D12Device_Release(swapchain->device);
heap_free(swapchain); @@ -1295,45 +1367,419 @@ static const struct IDXGISwapChain3Vtbl d3d12_swapchain_vtbl = d3d12_swapchain_ResizeBuffers1, };
+static const struct vulkan_funcs *get_vk_funcs(void) +{ + const struct vulkan_funcs *vk_funcs; + HDC hdc; + + hdc = GetDC(0); + vk_funcs = __wine_get_vulkan_driver(hdc, WINE_VULKAN_DRIVER_VERSION); + ReleaseDC(0, hdc); + return vk_funcs; +} + +static BOOL load_vkd3d_functions(void *vkd3d_handle) +{ +#define LOAD_FUNCPTR(f) if (!(f = wine_dlsym(vkd3d_handle, #f, NULL, 0))) return FALSE; + LOAD_FUNCPTR(vkd3d_acquire_vk_queue) + LOAD_FUNCPTR(vkd3d_create_image_resource) + LOAD_FUNCPTR(vkd3d_get_vk_device) + LOAD_FUNCPTR(vkd3d_get_vk_format) + LOAD_FUNCPTR(vkd3d_get_vk_physical_device) + LOAD_FUNCPTR(vkd3d_get_vk_queue_family_index) + LOAD_FUNCPTR(vkd3d_instance_from_device) + LOAD_FUNCPTR(vkd3d_instance_get_vk_instance) + LOAD_FUNCPTR(vkd3d_release_vk_queue) + LOAD_FUNCPTR(vkd3d_resource_decref) + LOAD_FUNCPTR(vkd3d_resource_incref) +#undef LOAD_FUNCPTR + + return TRUE; +} + +static BOOL init_vkd3d(void) +{ + static void *vkd3d_handle; + + if (vkd3d_handle) + return TRUE; + + TRACE("Loading vkd3d %s.\n", SONAME_LIBVKD3D); + + if (!(vkd3d_handle = wine_dlopen(SONAME_LIBVKD3D, RTLD_NOW, NULL, 0))) + return FALSE; + + if (!load_vkd3d_functions(vkd3d_handle)) + { + ERR("Failed to load vkd3d functions.\n"); + wine_dlclose(vkd3d_handle, NULL, 0); + vkd3d_handle = NULL; + return FALSE; + } + + return TRUE; +} + +static BOOL init_vk_funcs(struct dxgi_vk_funcs *dxgi, VkDevice vk_device) +{ + const struct vulkan_funcs *vk; + + if (!(vk = get_vk_funcs())) + { + ERR_(winediag)("Failed to load Wine Vulkan driver.\n"); + return FALSE; + } + + dxgi->p_vkAcquireNextImageKHR = vk->p_vkAcquireNextImageKHR; + dxgi->p_vkCreateSwapchainKHR = vk->p_vkCreateSwapchainKHR; + dxgi->p_vkCreateWin32SurfaceKHR = vk->p_vkCreateWin32SurfaceKHR; + dxgi->p_vkDestroySurfaceKHR = vk->p_vkDestroySurfaceKHR; + dxgi->p_vkDestroySwapchainKHR = vk->p_vkDestroySwapchainKHR; + dxgi->p_vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vk->p_vkGetDeviceProcAddr; + dxgi->p_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)vk->p_vkGetInstanceProcAddr; + dxgi->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = vk->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + dxgi->p_vkGetPhysicalDeviceSurfaceFormatsKHR = vk->p_vkGetPhysicalDeviceSurfaceFormatsKHR; + dxgi->p_vkGetPhysicalDeviceSurfacePresentModesKHR = vk->p_vkGetPhysicalDeviceSurfacePresentModesKHR; + dxgi->p_vkGetPhysicalDeviceSurfaceSupportKHR = vk->p_vkGetPhysicalDeviceSurfaceSupportKHR; + dxgi->p_vkGetPhysicalDeviceWin32PresentationSupportKHR = vk->p_vkGetPhysicalDeviceWin32PresentationSupportKHR; + dxgi->p_vkGetSwapchainImagesKHR = vk->p_vkGetSwapchainImagesKHR; + dxgi->p_vkQueuePresentKHR = vk->p_vkQueuePresentKHR; + +#define LOAD_DEVICE_PFN(name) \ + if (!(dxgi->p_##name = vk->p_vkGetDeviceProcAddr(vk_device, #name))) \ + { \ + ERR("Failed to get device proc "#name".\n"); \ + return FALSE; \ + } + LOAD_DEVICE_PFN(vkCreateFence) + LOAD_DEVICE_PFN(vkWaitForFences) + LOAD_DEVICE_PFN(vkResetFences) + LOAD_DEVICE_PFN(vkDestroyFence) +#undef LOAD_DEVICE_PFN + + return TRUE; +} + +static HRESULT select_vk_format(const struct dxgi_vk_funcs *vk_funcs, + VkPhysicalDevice vk_physical_device, VkSurfaceKHR vk_surface, + const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, VkFormat *vk_format) +{ + VkSurfaceFormatKHR *formats; + uint32_t format_count; + VkFormat format; + unsigned int i; + VkResult vr; + + *vk_format = VK_FORMAT_UNDEFINED; + + format = vkd3d_get_vk_format(swapchain_desc->Format); + if (format == VK_FORMAT_UNDEFINED) + return DXGI_ERROR_INVALID_CALL; + + vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL); + if (vr < 0 || !format_count) + { + WARN("Failed to get supported surface formats, vr %d.\n", vr); + return DXGI_ERROR_INVALID_CALL; + } + + if (!(formats = heap_calloc(format_count, sizeof(*formats)))) + return E_OUTOFMEMORY; + + if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, + vk_surface, &format_count, formats)) < 0) + { + WARN("Failed to enumerate supported surface formats, vr %d.\n", vr); + heap_free(formats); + return DXGI_ERROR_INVALID_CALL; + } + + for (i = 0; i < format_count; ++i) + { + if (formats[i].format == format && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + break; + } + heap_free(formats); + + if (i == format_count) + { + FIXME("Failed to find suitable format for %s.\n", debug_dxgi_format(swapchain_desc->Format)); + return DXGI_ERROR_INVALID_CALL; + } + + *vk_format = format; + return S_OK; +} + +static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGIFactory *factory, + ID3D12Device *device, ID3D12CommandQueue *queue, HWND window, + const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc) +{ + const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs; + struct vkd3d_image_resource_create_info resource_info; + struct VkSwapchainCreateInfoKHR vk_swapchain_desc; + struct VkWin32SurfaceCreateInfoKHR surface_desc; + VkImage vk_images[DXGI_MAX_SWAP_CHAIN_BUFFERS]; + VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE; + VkSurfaceKHR vk_surface = VK_NULL_HANDLE; + VkSurfaceCapabilitiesKHR surface_caps; + VkPhysicalDevice vk_physical_device; + VkFence vk_fence = VK_NULL_HANDLE; + unsigned int image_count, i, j; + VkFenceCreateInfo fence_desc; + uint32_t queue_family_index; + VkInstance vk_instance; + HRESULT hr = E_FAIL; + VkBool32 supported; + VkDevice vk_device; + VkFormat vk_format; + VkResult vr; + + swapchain->IDXGISwapChain3_iface.lpVtbl = &d3d12_swapchain_vtbl; + swapchain->refcount = 1; + + swapchain->window = window; + swapchain->desc = *swapchain_desc; + swapchain->fullscreen_desc = *fullscreen_desc; + + switch (swapchain_desc->SwapEffect) + { + case DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL: + case DXGI_SWAP_EFFECT_FLIP_DISCARD: + FIXME("Ignoring swap effect %#x.\n", swapchain_desc->SwapEffect); + break; + default: + WARN("Invalid swap effect %#x.\n", swapchain_desc->SwapEffect); + return DXGI_ERROR_INVALID_CALL; + } + + if (!init_vkd3d()) + { + ERR_(winediag)("libvkd3d could not be loaded.\n"); + return DXGI_ERROR_UNSUPPORTED; + } + + if (swapchain_desc->BufferUsage && swapchain_desc->BufferUsage != DXGI_USAGE_RENDER_TARGET_OUTPUT) + FIXME("Ignoring buffer usage %#x.\n", swapchain_desc->BufferUsage); + if (swapchain_desc->Scaling != DXGI_SCALING_STRETCH) + FIXME("Ignoring scaling %#x.\n", swapchain_desc->Scaling); + if (swapchain_desc->AlphaMode && swapchain_desc->AlphaMode != DXGI_ALPHA_MODE_IGNORE) + FIXME("Ignoring alpha mode %#x.\n", swapchain_desc->AlphaMode); + if (swapchain_desc->Flags) + FIXME("Ignoring swapchain flags %#x.\n", swapchain_desc->Flags); + + FIXME("Ignoring refresh rate.\n"); + if (fullscreen_desc->ScanlineOrdering) + FIXME("Unhandled scanline ordering %#x.\n", fullscreen_desc->ScanlineOrdering); + if (fullscreen_desc->Scaling) + FIXME("Unhandled mode scaling %#x.\n", fullscreen_desc->Scaling); + if (!fullscreen_desc->Windowed) + FIXME("Fullscreen not supported yet.\n"); + + vk_instance = vkd3d_instance_get_vk_instance(vkd3d_instance_from_device(device)); + vk_physical_device = vkd3d_get_vk_physical_device(device); + vk_device = vkd3d_get_vk_device(device); + + if (!init_vk_funcs(&swapchain->vk_funcs, vk_device)) + return E_FAIL; + + surface_desc.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + surface_desc.pNext = NULL; + surface_desc.flags = 0; + surface_desc.hinstance = GetModuleHandleA("dxgi.dll"); + surface_desc.hwnd = window; + if ((vr = vk_funcs->p_vkCreateWin32SurfaceKHR(vk_instance, &surface_desc, NULL, &vk_surface)) < 0) + { + WARN("Failed to create Vulkan surface, vr %d.\n", vr); + goto fail; + } + + queue_family_index = vkd3d_get_vk_queue_family_index(queue); + if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceSupportKHR(vk_physical_device, + queue_family_index, vk_surface, &supported)) < 0 || !supported) + { + FIXME("Queue family does not support presentation, vr %d.\n", vr); + goto fail; + } + + if (FAILED(hr = select_vk_format(vk_funcs, vk_physical_device, vk_surface, swapchain_desc, &vk_format))) + goto fail; + hr = E_FAIL; + + if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, + vk_surface, &surface_caps)) < 0) + { + WARN("Failed to get surface capabilities, vr %d.\n", vr); + goto fail; + } + + if (surface_caps.maxImageCount && (swapchain_desc->BufferCount > surface_caps.maxImageCount + || swapchain_desc->BufferCount < surface_caps.minImageCount)) + { + WARN("Buffer count %u is not supported (%u-%u).\n", swapchain_desc->BufferCount, + surface_caps.minImageCount, surface_caps.maxImageCount); + goto fail; + } + + if (swapchain_desc->Width > surface_caps.maxImageExtent.width + || swapchain_desc->Width < surface_caps.minImageExtent.width + || swapchain_desc->Height > surface_caps.maxImageExtent.height + || swapchain_desc->Height < surface_caps.minImageExtent.height) + { + FIXME("Swapchain dimensions %ux%u are not supported (%u-%u x %u-%u).\n", + swapchain_desc->Width, swapchain_desc->Height, + surface_caps.minImageExtent.width, surface_caps.maxImageExtent.width, + surface_caps.minImageExtent.height, surface_caps.maxImageExtent.height); + } + + if (!(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) + { + FIXME("Unsupported alpha mode.\n"); + goto fail; + } + + 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 = swapchain_desc->BufferCount; + vk_swapchain_desc.imageFormat = vk_format; + vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + vk_swapchain_desc.imageExtent.width = swapchain_desc->Width; + vk_swapchain_desc.imageExtent.height = swapchain_desc->Height; + vk_swapchain_desc.imageArrayLayers = 1; + vk_swapchain_desc.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + 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_FIFO_KHR; + vk_swapchain_desc.clipped = VK_TRUE; + vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE; + if ((vr = vk_funcs->p_vkCreateSwapchainKHR(vk_device, &vk_swapchain_desc, NULL, &vk_swapchain)) < 0) + { + WARN("Failed to create Vulkan swapchain, vr %d.\n", vr); + goto fail; + } + + fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_desc.pNext = NULL; + fence_desc.flags = 0; + if ((vr = vk_funcs->p_vkCreateFence(vk_device, &fence_desc, NULL, &vk_fence)) < 0) + { + WARN("Failed to create Vulkan fence, vr %d.\n", vr); + goto fail; + } + + if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL)) < 0) + { + WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr); + goto fail; + } + if (image_count != swapchain_desc->BufferCount) + FIXME("Got %u swapchain images, expected %u.\n", image_count, swapchain_desc->BufferCount); + if (image_count > ARRAY_SIZE(vk_images)) + goto fail; + if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, vk_images)) < 0) + { + WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr); + goto fail; + } + + swapchain->vk_swapchain = vk_swapchain; + swapchain->vk_surface = vk_surface; + swapchain->vk_fence = vk_fence; + swapchain->vk_instance = vk_instance; + swapchain->vk_device = vk_device; + + vk_funcs->p_vkAcquireNextImageKHR(vk_device, vk_swapchain, UINT64_MAX, + VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer_index); + vk_funcs->p_vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX); + vk_funcs->p_vkResetFences(vk_device, 1, &vk_fence); + + resource_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO; + resource_info.next = NULL; + resource_info.desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + resource_info.desc.Alignment = 0; + resource_info.desc.Width = swapchain_desc->Width; + resource_info.desc.Height = swapchain_desc->Height; + resource_info.desc.DepthOrArraySize = 1; + resource_info.desc.MipLevels = 1; + resource_info.desc.Format = swapchain_desc->Format; + resource_info.desc.SampleDesc.Count = 1; + resource_info.desc.SampleDesc.Quality = 0; + resource_info.desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + resource_info.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + resource_info.flags = VKD3D_RESOURCE_INITIAL_STATE_TRANSITION | VKD3D_RESOURCE_PRESENT_STATE_TRANSITION; + resource_info.present_state = D3D12_RESOURCE_STATE_PRESENT; + for (i = 0; i < image_count; ++i) + { + resource_info.vk_image = vk_images[i]; + if (SUCCEEDED(hr = vkd3d_create_image_resource(device, &resource_info, &swapchain->buffers[i]))) + { + vkd3d_resource_incref(swapchain->buffers[i]); + ID3D12Resource_Release(swapchain->buffers[i]); + } + else + { + ERR("Failed to create vkd3d resource for Vulkan image %u, hr %#x.\n", i, hr); + for (j = 0; j < i; ++j) + { + vkd3d_resource_decref(swapchain->buffers[j]); + } + goto fail; + } + } + swapchain->buffer_count = image_count; + + wined3d_private_store_init(&swapchain->private_store); + + ID3D12CommandQueue_AddRef(swapchain->command_queue = queue); + ID3D12Device_AddRef(swapchain->device = device); + IWineDXGIFactory_AddRef(swapchain->factory = factory); + + return S_OK; + +fail: + vk_funcs->p_vkDestroyFence(vk_device, vk_fence, NULL); + vk_funcs->p_vkDestroySwapchainKHR(vk_device, vk_swapchain, NULL); + vk_funcs->p_vkDestroySurfaceKHR(vk_instance, vk_surface, NULL); + return hr; +} + HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window, const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc, IDXGISwapChain1 **swapchain) { + DXGI_SWAP_CHAIN_FULLSCREEN_DESC default_fullscreen_desc; struct d3d12_swapchain *object; ID3D12Device *device; HRESULT hr;
- if (FAILED(hr = ID3D12CommandQueue_GetDevice(queue, &IID_ID3D12Device, (void **)&device))) + if (!fullscreen_desc) { - ERR("Failed to get D3D12 device, hr %#x.\n", hr); - return hr; + memset(&default_fullscreen_desc, 0, sizeof(default_fullscreen_desc)); + default_fullscreen_desc.Windowed = TRUE; + fullscreen_desc = &default_fullscreen_desc; }
if (!(object = heap_alloc_zero(sizeof(*object)))) - { - ID3D12Device_Release(device); return E_OUTOFMEMORY; - } - - object->IDXGISwapChain3_iface.lpVtbl = &d3d12_swapchain_vtbl; - object->refcount = 1; - - wined3d_private_store_init(&object->private_store);
- ID3D12CommandQueue_AddRef(object->command_queue = queue); - object->device = device; - IWineDXGIFactory_AddRef(object->factory = factory); - - object->window = window; - object->desc = *swapchain_desc; - if (fullscreen_desc) + if (FAILED(hr = ID3D12CommandQueue_GetDevice(queue, &IID_ID3D12Device, (void **)&device))) { - object->fullscreen_desc = *fullscreen_desc; + ERR("Failed to get D3D12 device, hr %#x.\n", hr); + heap_free(object); + return hr; } - else + + hr = d3d12_swapchain_init(object, factory, device, queue, window, swapchain_desc, fullscreen_desc); + ID3D12Device_Release(device); + if (FAILED(hr)) { - memset(&object->fullscreen_desc, 0, sizeof(object->fullscreen_desc)); - object->fullscreen_desc.Windowed = TRUE; + heap_free(object); + return hr; }
TRACE("Created swapchain %p.\n", object); @@ -1342,3 +1788,15 @@ HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *qu
return S_OK; } + +#else + +HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window, + const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc, + IDXGISwapChain1 **swapchain) +{ + ERR_(winediag)("Wine was built without Direct3D 12 support.\n"); + return DXGI_ERROR_UNSUPPORTED; +} + +#endif /* SONAME_LIBVKD3D */
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/dxgi/swapchain.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index 23731e0dd07b..e20e973a7185 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -1012,10 +1012,18 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_Present(IDXGISwapChain3 *iface, static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetBuffer(IDXGISwapChain3 *iface, UINT buffer_idx, REFIID iid, void **surface) { - FIXME("iface %p, buffer_idx %u, iid %s, surface %p stub!\n", + struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface); + + TRACE("iface %p, buffer_idx %u, iid %s, surface %p.\n", iface, buffer_idx, debugstr_guid(iid), surface);
- return E_NOTIMPL; + if (buffer_idx >= swapchain->buffer_count) + { + WARN("Invalid buffer index %u.\n", buffer_idx); + return DXGI_ERROR_INVALID_CALL; + } + + return ID3D12Resource_QueryInterface(swapchain->buffers[buffer_idx], iid, surface); }
static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d12_swapchain_SetFullscreenState(IDXGISwapChain3 *iface,
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/dxgi/swapchain.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index e20e973a7185..9c7024094d54 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -1291,9 +1291,11 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetMatrixTransform(IDXGISwapCha
static UINT STDMETHODCALLTYPE d3d12_swapchain_GetCurrentBackBufferIndex(IDXGISwapChain3 *iface) { - FIXME("iface %p stub!\n", iface); + struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface); + + TRACE("iface %p.\n", iface);
- return 0; + return swapchain->current_buffer_index; }
static HRESULT STDMETHODCALLTYPE d3d12_swapchain_CheckColorSpaceSupport(IDXGISwapChain3 *iface,
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/dxgi/swapchain.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 6 deletions(-)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index 9c7024094d54..9e50fa9567ac 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -1176,13 +1176,82 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetCoreWindow(IDXGISwapChain3 * return DXGI_ERROR_INVALID_CALL; }
+static HRESULT d3d12_swapchain_acquire_next_image(struct d3d12_swapchain *swapchain) +{ + const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs; + VkDevice vk_device = swapchain->vk_device; + VkFence vk_fence = swapchain->vk_fence; + VkResult vr; + + if ((vr = vk_funcs->p_vkAcquireNextImageKHR(vk_device, swapchain->vk_swapchain, UINT64_MAX, + VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer_index)) < 0) + { + ERR("Failed to acquire next Vulkan image, vr %d.\n", vr); + return E_FAIL; + } + + if ((vr = vk_funcs->p_vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX)) < 0) + { + ERR("Failed to wait for fences, vr %d.\n", vr); + return E_FAIL; + } + if ((vr = vk_funcs->p_vkResetFences(vk_device, 1, &vk_fence)) < 0) + { + ERR("Failed to reset fence, vr %d.\n", vr); + return E_FAIL; + } + + return S_OK; +} + static HRESULT STDMETHODCALLTYPE d3d12_swapchain_Present1(IDXGISwapChain3 *iface, UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *present_parameters) { - FIXME("iface %p, sync_interval %u, flags %#x, present_parameters %p stub!\n", + struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface); + const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs; + VkPresentInfoKHR present_desc; + VkQueue vk_queue; + + TRACE("iface %p, sync_interval %u, flags %#x, present_parameters %p.\n", iface, sync_interval, flags, present_parameters);
- return E_NOTIMPL; + if (sync_interval > 4) + { + WARN("Invalid sync interval %u.\n", sync_interval); + return DXGI_ERROR_INVALID_CALL; + } + if (sync_interval != 1) + FIXME("Ignoring sync interval %u.\n", sync_interval); + + if (flags & ~DXGI_PRESENT_TEST) + FIXME("Unimplemented flags %#x.\n", flags); + if (flags & DXGI_PRESENT_TEST) + { + WARN("Returning S_OK for DXGI_PRESENT_TEST.\n"); + return S_OK; + } + + if (present_parameters) + FIXME("Ignored present parameters %p.\n", present_parameters); + + present_desc.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + present_desc.pNext = NULL; + present_desc.waitSemaphoreCount = 0; + present_desc.pWaitSemaphores = NULL; + present_desc.swapchainCount = 1; + present_desc.pSwapchains = &swapchain->vk_swapchain; + present_desc.pImageIndices = &swapchain->current_buffer_index; + present_desc.pResults = NULL; + + if (!(vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue))) + { + ERR("Failed to acquire Vulkan queue.\n"); + return E_FAIL; + } + vk_funcs->p_vkQueuePresentKHR(vk_queue, &present_desc); + vkd3d_release_vk_queue(swapchain->command_queue); + + return d3d12_swapchain_acquire_next_image(swapchain); }
static BOOL STDMETHODCALLTYPE d3d12_swapchain_IsTemporaryMonoSupported(IDXGISwapChain3 *iface) @@ -1703,10 +1772,11 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI swapchain->vk_instance = vk_instance; swapchain->vk_device = vk_device;
- vk_funcs->p_vkAcquireNextImageKHR(vk_device, vk_swapchain, UINT64_MAX, - VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer_index); - vk_funcs->p_vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX); - vk_funcs->p_vkResetFences(vk_device, 1, &vk_fence); + if (FAILED(hr = d3d12_swapchain_acquire_next_image(swapchain))) + { + WARN("Failed to acquire Vulkan image, hr %#x.\n", hr); + goto fail; + }
resource_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO; resource_info.next = NULL;
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/dxgi/tests/device.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/dlls/dxgi/tests/device.c b/dlls/dxgi/tests/device.c index c192992020d6..784f6d2a4e9c 100644 --- a/dlls/dxgi/tests/device.c +++ b/dlls/dxgi/tests/device.c @@ -2200,17 +2200,22 @@ static void test_fullscreen_resize_target(IDXGISwapChain *swapchain, continue;
hr = IDXGIOutput_GetDesc(target, &output_desc); - ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr); + ok(hr == S_OK, "Failed to get desc, hr %#x.\n", hr);
compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state, &swapchain_desc, &output_desc.DesktopCoordinates, modes[i].Width, modes[i].Height, NULL);
hr = IDXGISwapChain_ResizeTarget(swapchain, &modes[i]); - ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#x.\n", hr); + if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) + { + skip("Failed to change to video mode %u.\n", i); + break; + } check_swapchain_fullscreen_state(swapchain, &expected_state);
hr = IDXGIOutput_GetDesc(target, &output_desc); - ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr); + ok(hr == S_OK, "Failed to get desc, hr %#x.\n", hr); ok(EqualRect(&output_desc.DesktopCoordinates, &expected_state.fullscreen_state.monitor_rect), "Got desktop coordinates %s, expected %s.\n", wine_dbgstr_rect(&output_desc.DesktopCoordinates),
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/dxgi/tests/device.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/dlls/dxgi/tests/device.c b/dlls/dxgi/tests/device.c index 784f6d2a4e9c..a395a6963aa0 100644 --- a/dlls/dxgi/tests/device.c +++ b/dlls/dxgi/tests/device.c @@ -21,6 +21,7 @@ #include "initguid.h" #include "dxgi1_6.h" #include "d3d11.h" +#include "wine/heap.h" #include "wine/test.h"
enum frame_latency @@ -801,7 +802,8 @@ static void test_output(void) ok(mode_count >= mode_count_comp, "Got unexpected mode_count %u, expected >= %u.\n", mode_count, mode_count_comp); mode_count_comp = mode_count;
- modes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*modes) * (mode_count + 10)); + modes = heap_calloc(mode_count + 10, sizeof(*modes)); + ok(!!modes, "Failed to allocate memory.\n");
hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_SCALING, NULL, modes); @@ -845,7 +847,7 @@ static void test_output(void) skip("Not enough modes for test, skipping.\n"); }
- HeapFree(GetProcessHeap(), 0, modes); + heap_free(modes); IDXGIOutput_Release(output); IDXGIAdapter_Release(adapter); refcount = IDXGIDevice_Release(device); @@ -898,7 +900,8 @@ static void test_find_closest_matching_mode(void) hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL); ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
- modes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*modes) * mode_count); + modes = heap_calloc(mode_count, sizeof(*modes)); + ok(!!modes, "Failed to allocate memory.\n");
hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes); ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr); @@ -1024,7 +1027,7 @@ static void test_find_closest_matching_mode(void) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); check_mode_desc(&matching_mode, &modes[0], MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
- HeapFree(GetProcessHeap(), 0, modes); + heap_free(modes);
done: IDXGIOutput_Release(output); @@ -1768,7 +1771,7 @@ static void test_swapchain_fullscreen_state(IDXGISwapChain *swapchain, ++output_count; }
- output_monitor_info = HeapAlloc(GetProcessHeap(), 0, output_count * sizeof(*output_monitor_info)); + output_monitor_info = heap_calloc(output_count, sizeof(*output_monitor_info)); ok(!!output_monitor_info, "Failed to allocate memory.\n"); for (i = 0; i < output_count; ++i) { @@ -1869,7 +1872,7 @@ static void test_swapchain_fullscreen_state(IDXGISwapChain *swapchain, IDXGIOutput_Release(output); }
- HeapFree(GetProcessHeap(), 0, output_monitor_info); + heap_free(output_monitor_info); }
static void test_set_fullscreen(void) @@ -2185,7 +2188,7 @@ static void test_fullscreen_resize_target(IDXGISwapChain *swapchain, return; }
- modes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*modes) * mode_count); + modes = heap_calloc(mode_count, sizeof(*modes)); ok(!!modes, "Failed to allocate memory.\n");
hr = IDXGIOutput_GetDisplayModeList(target, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes); @@ -2222,7 +2225,7 @@ static void test_fullscreen_resize_target(IDXGISwapChain *swapchain, wine_dbgstr_rect(&expected_state.fullscreen_state.monitor_rect)); }
- HeapFree(GetProcessHeap(), 0, modes); + heap_free(modes); IDXGIOutput_Release(target); }
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/dxgi/tests/device.c | 57 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 5 deletions(-)
diff --git a/dlls/dxgi/tests/device.c b/dlls/dxgi/tests/device.c index a395a6963aa0..b8dda1c94a06 100644 --- a/dlls/dxgi/tests/device.c +++ b/dlls/dxgi/tests/device.c @@ -70,6 +70,22 @@ static HRESULT check_interface_(unsigned int line, void *iface, REFIID iid, return hr; }
+static unsigned int check_multisample_quality_levels(IDXGIDevice *dxgi_device, + DXGI_FORMAT format, unsigned int sample_count) +{ + ID3D10Device *device; + unsigned int levels; + HRESULT hr; + + hr = IDXGIDevice_QueryInterface(dxgi_device, &IID_ID3D10Device, (void **)&device); + ok(hr == S_OK, "Failed to query ID3D10Device, hr %#x.\n", hr); + hr = ID3D10Device_CheckMultisampleQualityLevels(device, format, sample_count, &levels); + ok(hr == S_OK, "Failed to check multisample quality levels, hr %#x.\n", hr); + ID3D10Device_Release(device); + + return levels; +} + #define MODE_DESC_IGNORE_RESOLUTION 0x00000001u #define MODE_DESC_IGNORE_REFRESH_RATE 0x00000002u #define MODE_DESC_IGNORE_FORMAT 0x00000004u @@ -3213,13 +3229,13 @@ static void test_swapchain_parameters(void) 0, 0, 640, 480, 0, 0, 0, 0);
hr = IDXGIDevice_QueryInterface(device, &IID_IUnknown, (void **)&obj); - ok(SUCCEEDED(hr), "IDXGIDevice does not implement IUnknown.\n"); + ok(hr == S_OK, "IDXGIDevice does not implement IUnknown.\n");
hr = IDXGIDevice_GetAdapter(device, &adapter); - ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr); - + ok(hr == S_OK, "Failed to get adapter, hr %#x.\n", hr); hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory); - ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr); + ok(hr == S_OK, "Failed to get parent, hr %#x.\n", hr); + IDXGIAdapter_Release(adapter);
for (i = 0; i < ARRAY_SIZE(tests); ++i) { @@ -3372,8 +3388,39 @@ static void test_swapchain_parameters(void) IDXGISwapChain_Release(swapchain); }
+ /* multisampling */ + memset(&desc, 0, sizeof(desc)); + desc.BufferDesc.Width = registry_mode.dmPelsWidth; + desc.BufferDesc.Height = registry_mode.dmPelsHeight; + desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 4; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = 4; + desc.OutputWindow = window; + desc.Windowed = TRUE; + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain); + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr); + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain); + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr); + if (check_multisample_quality_levels(device, desc.BufferDesc.Format, desc.SampleDesc.Count)) + { + desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + IDXGISwapChain_Release(swapchain); + desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; + hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + IDXGISwapChain_Release(swapchain); + } + else + { + skip("Multisampling not supported for DXGI_FORMAT_R8G8B8A8_UNORM.\n"); + } + IDXGIFactory_Release(factory); - IDXGIAdapter_Release(adapter); IUnknown_Release(obj); refcount = IDXGIDevice_Release(device); ok(!refcount, "Device has %u references left.\n", refcount);
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/dxgi/tests/device.c | 69 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 4 deletions(-)
diff --git a/dlls/dxgi/tests/device.c b/dlls/dxgi/tests/device.c index b8dda1c94a06..8ad4935b1622 100644 --- a/dlls/dxgi/tests/device.c +++ b/dlls/dxgi/tests/device.c @@ -390,15 +390,63 @@ static void compute_expected_swapchain_fullscreen_state_after_fullscreen_change_ } }
-static IDXGIDevice *create_device(UINT flags) +static BOOL use_warp_adapter; +static unsigned int use_adapter_idx; + +static IDXGIAdapter *create_adapter(void) +{ + IDXGIFactory4 *factory4; + IDXGIFactory *factory; + IDXGIAdapter *adapter; + HRESULT hr; + + if (!use_warp_adapter && !use_adapter_idx) + return NULL; + + if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory))) + { + trace("Failed to create IDXGIFactory, hr %#x.\n", hr); + return NULL; + } + + adapter = NULL; + if (use_warp_adapter) + { + if (SUCCEEDED(hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void **)&factory4))) + { + hr = IDXGIFactory4_EnumWarpAdapter(factory4, &IID_IDXGIAdapter, (void **)&adapter); + IDXGIFactory4_Release(factory4); + } + else + { + trace("Failed to get IDXGIFactory4, hr %#x.\n", hr); + } + } + else + { + hr = IDXGIFactory_EnumAdapters(factory, use_adapter_idx, &adapter); + } + IDXGIFactory_Release(factory); + if (FAILED(hr)) + trace("Failed to get adapter, hr %#x.\n", hr); + return adapter; +} + +static IDXGIDevice *create_device(unsigned int flags) { IDXGIDevice *dxgi_device; ID3D10Device1 *device; + IDXGIAdapter *adapter; HRESULT hr;
- if (SUCCEEDED(D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, - flags, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device))) + adapter = create_adapter(); + hr = D3D10CreateDevice1(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, + flags, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device); + if (adapter) + IDXGIAdapter_Release(adapter); + if (SUCCEEDED(hr)) goto success; + if (SUCCEEDED(D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_WARP, NULL, flags, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device))) goto success; @@ -3766,13 +3814,26 @@ static void test_object_wrapping(void)
START_TEST(device) { - HMODULE dxgi_module = GetModuleHandleA("dxgi.dll"); + unsigned int argc, i; + HMODULE dxgi_module; + char **argv; + + dxgi_module = GetModuleHandleA("dxgi.dll"); pCreateDXGIFactory1 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory1"); pCreateDXGIFactory2 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory2");
registry_mode.dmSize = sizeof(registry_mode); ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, ®istry_mode), "Failed to get display mode.\n");
+ argc = winetest_get_mainargs(&argv); + for (i = 2; i < argc; ++i) + { + if (!strcmp(argv[i], "--warp")) + use_warp_adapter = TRUE; + else if (!strcmp(argv[i], "--adapter") && i + 1 < argc) + use_adapter_idx = atoi(argv[++i]); + } + test_adapter_desc(); test_adapter_luid(); test_check_interface_support();
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Hi Józef,
On 31/05/2018 12:04, Józef Kucia wrote:
+static BOOL init_vkd3d(void) +{
- static void *vkd3d_handle;
- if (vkd3d_handle)
return TRUE;
- TRACE("Loading vkd3d %s.\n", SONAME_LIBVKD3D);
- if (!(vkd3d_handle = wine_dlopen(SONAME_LIBVKD3D, RTLD_NOW, NULL, 0)))
return FALSE;
- if (!load_vkd3d_functions(vkd3d_handle))
- {
This is not thread safe. I'd suggest using InitOnceExecuteOnce.
Thanks, Jacek
Signed-off-by: Józef Kucia jkucia@codeweavers.com ---
Version 2: Load libvkd3d just before creating a Direct3D 12 swapchain. Version 3: Use InitOnceExecuteOnce().
--- dlls/d3d12/d3d12_main.c | 16 ++ dlls/dxgi/Makefile.in | 3 +- dlls/dxgi/swapchain.c | 506 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 502 insertions(+), 23 deletions(-)
diff --git a/dlls/d3d12/d3d12_main.c b/dlls/d3d12/d3d12_main.c index 71eb1f97a73e..91525b49a790 100644 --- a/dlls/d3d12/d3d12_main.c +++ b/dlls/d3d12/d3d12_main.c @@ -34,6 +34,8 @@
#include <vkd3d.h>
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + WINE_DEFAULT_DEBUG_CHANNEL(d3d12); WINE_DECLARE_DEBUG_CHANNEL(winediag);
@@ -113,6 +115,16 @@ HRESULT WINAPI D3D12CreateDevice(IUnknown *adapter, D3D_FEATURE_LEVEL minimum_fe struct vkd3d_device_create_info device_create_info; const struct vulkan_funcs *vk_funcs;
+ static const char * const instance_extensions[] = + { + VK_KHR_SURFACE_EXTENSION_NAME, + VK_KHR_WIN32_SURFACE_EXTENSION_NAME, + }; + static const char * const device_extensions[] = + { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; + TRACE("adapter %p, minimum_feature_level %#x, iid %s, device %p.\n", adapter, minimum_feature_level, debugstr_guid(iid), device);
@@ -132,11 +144,15 @@ HRESULT WINAPI D3D12CreateDevice(IUnknown *adapter, D3D_FEATURE_LEVEL minimum_fe instance_create_info.wchar_size = sizeof(WCHAR); instance_create_info.pfn_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)vk_funcs->p_vkGetInstanceProcAddr; + instance_create_info.instance_extensions = instance_extensions; + instance_create_info.instance_extension_count = ARRAY_SIZE(instance_extensions);
memset(&device_create_info, 0, sizeof(device_create_info)); device_create_info.type = VKD3D_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.minimum_feature_level = minimum_feature_level; device_create_info.instance_create_info = &instance_create_info; + device_create_info.device_extensions = device_extensions; + device_create_info.device_extension_count = ARRAY_SIZE(device_extensions);
return vkd3d_create_device(&device_create_info, iid, device); } diff --git a/dlls/dxgi/Makefile.in b/dlls/dxgi/Makefile.in index ce76b8eecc61..c21cb18d8ffc 100644 --- a/dlls/dxgi/Makefile.in +++ b/dlls/dxgi/Makefile.in @@ -1,6 +1,7 @@ MODULE = dxgi.dll IMPORTLIB = dxgi -IMPORTS = dxguid uuid wined3d user32 +IMPORTS = gdi32 dxguid uuid wined3d user32 +EXTRAINCL = $(VKD3D_CFLAGS)
C_SRCS = \ adapter.c \ diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index ca4e59004ef2..a50a8785c512 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -22,7 +22,21 @@
#include "dxgi_private.h"
+#ifdef SONAME_LIBVKD3D +#define VK_NO_PROTOTYPES +#define VKAPI_CALL +#define VKD3D_NO_PROTOTYPES +#define VKD3D_NO_VULKAN_H +#define VKD3D_NO_WIN32_TYPES +#define WINE_VK_ALIGN(x) +#include "wine/library.h" +#include "wine/vulkan.h" +#include "wine/vulkan_driver.h" +#include <vkd3d.h> +#endif + WINE_DEFAULT_DEBUG_CHANNEL(dxgi); +WINE_DECLARE_DEBUG_CHANNEL(winediag);
static inline struct d3d11_swapchain *d3d11_swapchain_from_IDXGISwapChain1(IDXGISwapChain1 *iface) { @@ -797,12 +811,59 @@ HRESULT d3d11_swapchain_create(IWineDXGIDevice *device, HWND window, const DXGI_ return S_OK; }
+#ifdef SONAME_LIBVKD3D + +static PFN_vkd3d_acquire_vk_queue vkd3d_acquire_vk_queue; +static PFN_vkd3d_create_image_resource vkd3d_create_image_resource; +static PFN_vkd3d_get_vk_device vkd3d_get_vk_device; +static PFN_vkd3d_get_vk_format vkd3d_get_vk_format; +static PFN_vkd3d_get_vk_physical_device vkd3d_get_vk_physical_device; +static PFN_vkd3d_get_vk_queue_family_index vkd3d_get_vk_queue_family_index; +static PFN_vkd3d_instance_from_device vkd3d_instance_from_device; +static PFN_vkd3d_instance_get_vk_instance vkd3d_instance_get_vk_instance; +static PFN_vkd3d_release_vk_queue vkd3d_release_vk_queue; +static PFN_vkd3d_resource_decref vkd3d_resource_decref; +static PFN_vkd3d_resource_incref vkd3d_resource_incref; + +struct dxgi_vk_funcs +{ + PFN_vkAcquireNextImageKHR p_vkAcquireNextImageKHR; + PFN_vkCreateSwapchainKHR p_vkCreateSwapchainKHR; + PFN_vkCreateWin32SurfaceKHR p_vkCreateWin32SurfaceKHR; + PFN_vkDestroySurfaceKHR p_vkDestroySurfaceKHR; + PFN_vkDestroySwapchainKHR p_vkDestroySwapchainKHR; + PFN_vkGetDeviceProcAddr p_vkGetDeviceProcAddr; + PFN_vkGetInstanceProcAddr p_vkGetInstanceProcAddr; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR p_vkGetPhysicalDeviceSurfaceFormatsKHR; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR p_vkGetPhysicalDeviceSurfacePresentModesKHR; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR p_vkGetPhysicalDeviceSurfaceSupportKHR; + PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR p_vkGetPhysicalDeviceWin32PresentationSupportKHR; + PFN_vkGetSwapchainImagesKHR p_vkGetSwapchainImagesKHR; + PFN_vkQueuePresentKHR p_vkQueuePresentKHR; + PFN_vkCreateFence p_vkCreateFence; + PFN_vkWaitForFences p_vkWaitForFences; + PFN_vkResetFences p_vkResetFences; + PFN_vkDestroyFence p_vkDestroyFence; +}; + struct d3d12_swapchain { IDXGISwapChain3 IDXGISwapChain3_iface; LONG refcount; struct wined3d_private_store private_store;
+ VkSwapchainKHR vk_swapchain; + VkSurfaceKHR vk_surface; + VkFence vk_fence; + VkInstance vk_instance; + VkDevice vk_device; + ID3D12Resource *buffers[DXGI_MAX_SWAP_CHAIN_BUFFERS]; + unsigned int buffer_count; + + uint32_t current_buffer_index; + struct dxgi_vk_funcs vk_funcs; + ID3D12CommandQueue *command_queue; ID3D12Device *device; IWineDXGIFactory *factory; @@ -855,7 +916,9 @@ static ULONG STDMETHODCALLTYPE d3d12_swapchain_AddRef(IDXGISwapChain3 *iface) static ULONG STDMETHODCALLTYPE d3d12_swapchain_Release(IDXGISwapChain3 *iface) { struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface); + const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs; ULONG refcount = InterlockedDecrement(&swapchain->refcount); + unsigned int i;
TRACE("%p decreasing refcount to %u.\n", swapchain, refcount);
@@ -866,6 +929,15 @@ static ULONG STDMETHODCALLTYPE d3d12_swapchain_Release(IDXGISwapChain3 *iface)
wined3d_private_store_cleanup(&swapchain->private_store);
+ for (i = 0; i < swapchain->buffer_count; ++i) + { + vkd3d_resource_decref(swapchain->buffers[i]); + } + + vk_funcs->p_vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL); + vk_funcs->p_vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL); + vk_funcs->p_vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL); + ID3D12Device_Release(swapchain->device);
heap_free(swapchain); @@ -1295,45 +1367,423 @@ static const struct IDXGISwapChain3Vtbl d3d12_swapchain_vtbl = d3d12_swapchain_ResizeBuffers1, };
+static const struct vulkan_funcs *get_vk_funcs(void) +{ + const struct vulkan_funcs *vk_funcs; + HDC hdc; + + hdc = GetDC(0); + vk_funcs = __wine_get_vulkan_driver(hdc, WINE_VULKAN_DRIVER_VERSION); + ReleaseDC(0, hdc); + return vk_funcs; +} + +static BOOL load_vkd3d_functions(void *vkd3d_handle) +{ +#define LOAD_FUNCPTR(f) if (!(f = wine_dlsym(vkd3d_handle, #f, NULL, 0))) return FALSE; + LOAD_FUNCPTR(vkd3d_acquire_vk_queue) + LOAD_FUNCPTR(vkd3d_create_image_resource) + LOAD_FUNCPTR(vkd3d_get_vk_device) + LOAD_FUNCPTR(vkd3d_get_vk_format) + LOAD_FUNCPTR(vkd3d_get_vk_physical_device) + LOAD_FUNCPTR(vkd3d_get_vk_queue_family_index) + LOAD_FUNCPTR(vkd3d_instance_from_device) + LOAD_FUNCPTR(vkd3d_instance_get_vk_instance) + LOAD_FUNCPTR(vkd3d_release_vk_queue) + LOAD_FUNCPTR(vkd3d_resource_decref) + LOAD_FUNCPTR(vkd3d_resource_incref) +#undef LOAD_FUNCPTR + + return TRUE; +} + +static void *vkd3d_handle; + +static BOOL WINAPI init_vkd3d_once(INIT_ONCE *once, void *param, void **context) +{ + TRACE("Loading vkd3d %s.\n", SONAME_LIBVKD3D); + + if (!(vkd3d_handle = wine_dlopen(SONAME_LIBVKD3D, RTLD_NOW, NULL, 0))) + return FALSE; + + if (!load_vkd3d_functions(vkd3d_handle)) + { + ERR("Failed to load vkd3d functions.\n"); + wine_dlclose(vkd3d_handle, NULL, 0); + vkd3d_handle = NULL; + return FALSE; + } + + return TRUE; +} + +static BOOL init_vkd3d(void) +{ + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + InitOnceExecuteOnce(&init_once, init_vkd3d_once, NULL, NULL); + return !!vkd3d_handle; +} + +static BOOL init_vk_funcs(struct dxgi_vk_funcs *dxgi, VkDevice vk_device) +{ + const struct vulkan_funcs *vk; + + if (!(vk = get_vk_funcs())) + { + ERR_(winediag)("Failed to load Wine Vulkan driver.\n"); + return FALSE; + } + + dxgi->p_vkAcquireNextImageKHR = vk->p_vkAcquireNextImageKHR; + dxgi->p_vkCreateSwapchainKHR = vk->p_vkCreateSwapchainKHR; + dxgi->p_vkCreateWin32SurfaceKHR = vk->p_vkCreateWin32SurfaceKHR; + dxgi->p_vkDestroySurfaceKHR = vk->p_vkDestroySurfaceKHR; + dxgi->p_vkDestroySwapchainKHR = vk->p_vkDestroySwapchainKHR; + dxgi->p_vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vk->p_vkGetDeviceProcAddr; + dxgi->p_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)vk->p_vkGetInstanceProcAddr; + dxgi->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = vk->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + dxgi->p_vkGetPhysicalDeviceSurfaceFormatsKHR = vk->p_vkGetPhysicalDeviceSurfaceFormatsKHR; + dxgi->p_vkGetPhysicalDeviceSurfacePresentModesKHR = vk->p_vkGetPhysicalDeviceSurfacePresentModesKHR; + dxgi->p_vkGetPhysicalDeviceSurfaceSupportKHR = vk->p_vkGetPhysicalDeviceSurfaceSupportKHR; + dxgi->p_vkGetPhysicalDeviceWin32PresentationSupportKHR = vk->p_vkGetPhysicalDeviceWin32PresentationSupportKHR; + dxgi->p_vkGetSwapchainImagesKHR = vk->p_vkGetSwapchainImagesKHR; + dxgi->p_vkQueuePresentKHR = vk->p_vkQueuePresentKHR; + +#define LOAD_DEVICE_PFN(name) \ + if (!(dxgi->p_##name = vk->p_vkGetDeviceProcAddr(vk_device, #name))) \ + { \ + ERR("Failed to get device proc "#name".\n"); \ + return FALSE; \ + } + LOAD_DEVICE_PFN(vkCreateFence) + LOAD_DEVICE_PFN(vkWaitForFences) + LOAD_DEVICE_PFN(vkResetFences) + LOAD_DEVICE_PFN(vkDestroyFence) +#undef LOAD_DEVICE_PFN + + return TRUE; +} + +static HRESULT select_vk_format(const struct dxgi_vk_funcs *vk_funcs, + VkPhysicalDevice vk_physical_device, VkSurfaceKHR vk_surface, + const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, VkFormat *vk_format) +{ + VkSurfaceFormatKHR *formats; + uint32_t format_count; + VkFormat format; + unsigned int i; + VkResult vr; + + *vk_format = VK_FORMAT_UNDEFINED; + + format = vkd3d_get_vk_format(swapchain_desc->Format); + if (format == VK_FORMAT_UNDEFINED) + return DXGI_ERROR_INVALID_CALL; + + vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL); + if (vr < 0 || !format_count) + { + WARN("Failed to get supported surface formats, vr %d.\n", vr); + return DXGI_ERROR_INVALID_CALL; + } + + if (!(formats = heap_calloc(format_count, sizeof(*formats)))) + return E_OUTOFMEMORY; + + if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, + vk_surface, &format_count, formats)) < 0) + { + WARN("Failed to enumerate supported surface formats, vr %d.\n", vr); + heap_free(formats); + return DXGI_ERROR_INVALID_CALL; + } + + for (i = 0; i < format_count; ++i) + { + if (formats[i].format == format && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + break; + } + heap_free(formats); + + if (i == format_count) + { + FIXME("Failed to find suitable format for %s.\n", debug_dxgi_format(swapchain_desc->Format)); + return DXGI_ERROR_INVALID_CALL; + } + + *vk_format = format; + return S_OK; +} + +static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGIFactory *factory, + ID3D12Device *device, ID3D12CommandQueue *queue, HWND window, + const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc) +{ + const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs; + struct vkd3d_image_resource_create_info resource_info; + struct VkSwapchainCreateInfoKHR vk_swapchain_desc; + struct VkWin32SurfaceCreateInfoKHR surface_desc; + VkImage vk_images[DXGI_MAX_SWAP_CHAIN_BUFFERS]; + VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE; + VkSurfaceKHR vk_surface = VK_NULL_HANDLE; + VkSurfaceCapabilitiesKHR surface_caps; + VkPhysicalDevice vk_physical_device; + VkFence vk_fence = VK_NULL_HANDLE; + unsigned int image_count, i, j; + VkFenceCreateInfo fence_desc; + uint32_t queue_family_index; + VkInstance vk_instance; + HRESULT hr = E_FAIL; + VkBool32 supported; + VkDevice vk_device; + VkFormat vk_format; + VkResult vr; + + swapchain->IDXGISwapChain3_iface.lpVtbl = &d3d12_swapchain_vtbl; + swapchain->refcount = 1; + + swapchain->window = window; + swapchain->desc = *swapchain_desc; + swapchain->fullscreen_desc = *fullscreen_desc; + + switch (swapchain_desc->SwapEffect) + { + case DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL: + case DXGI_SWAP_EFFECT_FLIP_DISCARD: + FIXME("Ignoring swap effect %#x.\n", swapchain_desc->SwapEffect); + break; + default: + WARN("Invalid swap effect %#x.\n", swapchain_desc->SwapEffect); + return DXGI_ERROR_INVALID_CALL; + } + + if (!init_vkd3d()) + { + ERR_(winediag)("libvkd3d could not be loaded.\n"); + return DXGI_ERROR_UNSUPPORTED; + } + + if (swapchain_desc->BufferUsage && swapchain_desc->BufferUsage != DXGI_USAGE_RENDER_TARGET_OUTPUT) + FIXME("Ignoring buffer usage %#x.\n", swapchain_desc->BufferUsage); + if (swapchain_desc->Scaling != DXGI_SCALING_STRETCH) + FIXME("Ignoring scaling %#x.\n", swapchain_desc->Scaling); + if (swapchain_desc->AlphaMode && swapchain_desc->AlphaMode != DXGI_ALPHA_MODE_IGNORE) + FIXME("Ignoring alpha mode %#x.\n", swapchain_desc->AlphaMode); + if (swapchain_desc->Flags) + FIXME("Ignoring swapchain flags %#x.\n", swapchain_desc->Flags); + + FIXME("Ignoring refresh rate.\n"); + if (fullscreen_desc->ScanlineOrdering) + FIXME("Unhandled scanline ordering %#x.\n", fullscreen_desc->ScanlineOrdering); + if (fullscreen_desc->Scaling) + FIXME("Unhandled mode scaling %#x.\n", fullscreen_desc->Scaling); + if (!fullscreen_desc->Windowed) + FIXME("Fullscreen not supported yet.\n"); + + vk_instance = vkd3d_instance_get_vk_instance(vkd3d_instance_from_device(device)); + vk_physical_device = vkd3d_get_vk_physical_device(device); + vk_device = vkd3d_get_vk_device(device); + + if (!init_vk_funcs(&swapchain->vk_funcs, vk_device)) + return E_FAIL; + + surface_desc.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + surface_desc.pNext = NULL; + surface_desc.flags = 0; + surface_desc.hinstance = GetModuleHandleA("dxgi.dll"); + surface_desc.hwnd = window; + if ((vr = vk_funcs->p_vkCreateWin32SurfaceKHR(vk_instance, &surface_desc, NULL, &vk_surface)) < 0) + { + WARN("Failed to create Vulkan surface, vr %d.\n", vr); + goto fail; + } + + queue_family_index = vkd3d_get_vk_queue_family_index(queue); + if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceSupportKHR(vk_physical_device, + queue_family_index, vk_surface, &supported)) < 0 || !supported) + { + FIXME("Queue family does not support presentation, vr %d.\n", vr); + goto fail; + } + + if (FAILED(hr = select_vk_format(vk_funcs, vk_physical_device, vk_surface, swapchain_desc, &vk_format))) + goto fail; + hr = E_FAIL; + + if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, + vk_surface, &surface_caps)) < 0) + { + WARN("Failed to get surface capabilities, vr %d.\n", vr); + goto fail; + } + + if (surface_caps.maxImageCount && (swapchain_desc->BufferCount > surface_caps.maxImageCount + || swapchain_desc->BufferCount < surface_caps.minImageCount)) + { + WARN("Buffer count %u is not supported (%u-%u).\n", swapchain_desc->BufferCount, + surface_caps.minImageCount, surface_caps.maxImageCount); + goto fail; + } + + if (swapchain_desc->Width > surface_caps.maxImageExtent.width + || swapchain_desc->Width < surface_caps.minImageExtent.width + || swapchain_desc->Height > surface_caps.maxImageExtent.height + || swapchain_desc->Height < surface_caps.minImageExtent.height) + { + FIXME("Swapchain dimensions %ux%u are not supported (%u-%u x %u-%u).\n", + swapchain_desc->Width, swapchain_desc->Height, + surface_caps.minImageExtent.width, surface_caps.maxImageExtent.width, + surface_caps.minImageExtent.height, surface_caps.maxImageExtent.height); + } + + if (!(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) + { + FIXME("Unsupported alpha mode.\n"); + goto fail; + } + + 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 = swapchain_desc->BufferCount; + vk_swapchain_desc.imageFormat = vk_format; + vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + vk_swapchain_desc.imageExtent.width = swapchain_desc->Width; + vk_swapchain_desc.imageExtent.height = swapchain_desc->Height; + vk_swapchain_desc.imageArrayLayers = 1; + vk_swapchain_desc.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + 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_FIFO_KHR; + vk_swapchain_desc.clipped = VK_TRUE; + vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE; + if ((vr = vk_funcs->p_vkCreateSwapchainKHR(vk_device, &vk_swapchain_desc, NULL, &vk_swapchain)) < 0) + { + WARN("Failed to create Vulkan swapchain, vr %d.\n", vr); + goto fail; + } + + fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_desc.pNext = NULL; + fence_desc.flags = 0; + if ((vr = vk_funcs->p_vkCreateFence(vk_device, &fence_desc, NULL, &vk_fence)) < 0) + { + WARN("Failed to create Vulkan fence, vr %d.\n", vr); + goto fail; + } + + if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL)) < 0) + { + WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr); + goto fail; + } + if (image_count != swapchain_desc->BufferCount) + FIXME("Got %u swapchain images, expected %u.\n", image_count, swapchain_desc->BufferCount); + if (image_count > ARRAY_SIZE(vk_images)) + goto fail; + if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, vk_images)) < 0) + { + WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr); + goto fail; + } + + swapchain->vk_swapchain = vk_swapchain; + swapchain->vk_surface = vk_surface; + swapchain->vk_fence = vk_fence; + swapchain->vk_instance = vk_instance; + swapchain->vk_device = vk_device; + + vk_funcs->p_vkAcquireNextImageKHR(vk_device, vk_swapchain, UINT64_MAX, + VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer_index); + vk_funcs->p_vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX); + vk_funcs->p_vkResetFences(vk_device, 1, &vk_fence); + + resource_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO; + resource_info.next = NULL; + resource_info.desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + resource_info.desc.Alignment = 0; + resource_info.desc.Width = swapchain_desc->Width; + resource_info.desc.Height = swapchain_desc->Height; + resource_info.desc.DepthOrArraySize = 1; + resource_info.desc.MipLevels = 1; + resource_info.desc.Format = swapchain_desc->Format; + resource_info.desc.SampleDesc.Count = 1; + resource_info.desc.SampleDesc.Quality = 0; + resource_info.desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + resource_info.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + resource_info.flags = VKD3D_RESOURCE_INITIAL_STATE_TRANSITION | VKD3D_RESOURCE_PRESENT_STATE_TRANSITION; + resource_info.present_state = D3D12_RESOURCE_STATE_PRESENT; + for (i = 0; i < image_count; ++i) + { + resource_info.vk_image = vk_images[i]; + if (SUCCEEDED(hr = vkd3d_create_image_resource(device, &resource_info, &swapchain->buffers[i]))) + { + vkd3d_resource_incref(swapchain->buffers[i]); + ID3D12Resource_Release(swapchain->buffers[i]); + } + else + { + ERR("Failed to create vkd3d resource for Vulkan image %u, hr %#x.\n", i, hr); + for (j = 0; j < i; ++j) + { + vkd3d_resource_decref(swapchain->buffers[j]); + } + goto fail; + } + } + swapchain->buffer_count = image_count; + + wined3d_private_store_init(&swapchain->private_store); + + ID3D12CommandQueue_AddRef(swapchain->command_queue = queue); + ID3D12Device_AddRef(swapchain->device = device); + IWineDXGIFactory_AddRef(swapchain->factory = factory); + + return S_OK; + +fail: + vk_funcs->p_vkDestroyFence(vk_device, vk_fence, NULL); + vk_funcs->p_vkDestroySwapchainKHR(vk_device, vk_swapchain, NULL); + vk_funcs->p_vkDestroySurfaceKHR(vk_instance, vk_surface, NULL); + return hr; +} + HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window, const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc, IDXGISwapChain1 **swapchain) { + DXGI_SWAP_CHAIN_FULLSCREEN_DESC default_fullscreen_desc; struct d3d12_swapchain *object; ID3D12Device *device; HRESULT hr;
- if (FAILED(hr = ID3D12CommandQueue_GetDevice(queue, &IID_ID3D12Device, (void **)&device))) + if (!fullscreen_desc) { - ERR("Failed to get D3D12 device, hr %#x.\n", hr); - return hr; + memset(&default_fullscreen_desc, 0, sizeof(default_fullscreen_desc)); + default_fullscreen_desc.Windowed = TRUE; + fullscreen_desc = &default_fullscreen_desc; }
if (!(object = heap_alloc_zero(sizeof(*object)))) - { - ID3D12Device_Release(device); return E_OUTOFMEMORY; - } - - object->IDXGISwapChain3_iface.lpVtbl = &d3d12_swapchain_vtbl; - object->refcount = 1; - - wined3d_private_store_init(&object->private_store);
- ID3D12CommandQueue_AddRef(object->command_queue = queue); - object->device = device; - IWineDXGIFactory_AddRef(object->factory = factory); - - object->window = window; - object->desc = *swapchain_desc; - if (fullscreen_desc) + if (FAILED(hr = ID3D12CommandQueue_GetDevice(queue, &IID_ID3D12Device, (void **)&device))) { - object->fullscreen_desc = *fullscreen_desc; + ERR("Failed to get D3D12 device, hr %#x.\n", hr); + heap_free(object); + return hr; } - else + + hr = d3d12_swapchain_init(object, factory, device, queue, window, swapchain_desc, fullscreen_desc); + ID3D12Device_Release(device); + if (FAILED(hr)) { - memset(&object->fullscreen_desc, 0, sizeof(object->fullscreen_desc)); - object->fullscreen_desc.Windowed = TRUE; + heap_free(object); + return hr; }
TRACE("Created swapchain %p.\n", object); @@ -1342,3 +1792,15 @@ HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *qu
return S_OK; } + +#else + +HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window, + const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc, + IDXGISwapChain1 **swapchain) +{ + ERR_(winediag)("Wine was built without Direct3D 12 support.\n"); + return DXGI_ERROR_UNSUPPORTED; +} + +#endif /* SONAME_LIBVKD3D */
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com