From: Conor McCarthy Subject: [PATCH 3/6] dxgi: Handle creation and cleanup of D3D12 fullscreen swapchains. Message-Id: <20191008041354.61092-3-cmccarthy@codeweavers.com> Date: Tue, 8 Oct 2019 14:13:51 +1000 In-Reply-To: <20191008041354.61092-1-cmccarthy@codeweavers.com> References: <20191008041354.61092-1-cmccarthy@codeweavers.com> Signed-off-by: Conor McCarthy --- dlls/dxgi/swapchain.c | 89 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index c76ad1d1..1787ced5 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -1877,6 +1877,10 @@ static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain) { const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs; void *vulkan_module = vk_funcs->vulkan_module; + struct dxgi_adapter *dxgi_adapter; + IUnknown *device_parent; + IDXGIAdapter *adapter; + HRESULT hr; d3d12_swapchain_destroy_buffers(swapchain, TRUE); @@ -1885,6 +1889,18 @@ static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain) wined3d_private_store_cleanup(&swapchain->private_store); + device_parent = vkd3d_get_device_parent(swapchain->device); + if (SUCCEEDED(hr = IUnknown_QueryInterface(device_parent, &IID_IDXGIAdapter, (void **)&adapter))) + { + dxgi_adapter = unsafe_impl_from_IDXGIAdapter(adapter); + wined3d_swapchain_state_cleanup_fullscreen(swapchain->state, dxgi_adapter->factory->wined3d, dxgi_adapter->ordinal, NULL); + IDXGIAdapter_Release(adapter); + } + else + { + ERR("Failed to get adapter for fullscreen state cleanup, hr %#x.\n", hr); + } + if (swapchain->vk_device) { vk_funcs->p_vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL); @@ -2807,6 +2823,36 @@ static BOOL init_vk_funcs(struct dxgi_vk_funcs *dxgi, VkInstance vk_instance, Vk return TRUE; } +static HRESULT d3d12_swapchain_desc_adjust_display_mode(HWND window, struct wined3d_swapchain_desc *wined3d_desc, + const struct dxgi_adapter *dxgi_adapter) +{ + struct wined3d_display_mode wined3d_mode; + HRESULT hr; + + wined3d_mode.width = wined3d_desc->backbuffer_width; + wined3d_mode.height = wined3d_desc->backbuffer_height; + wined3d_mode.refresh_rate = wined3d_desc->refresh_rate; + wined3d_mode.format_id = wined3d_desc->backbuffer_format; + wined3d_mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN; + + wined3d_mutex_lock(); + hr = wined3d_find_closest_matching_adapter_mode(dxgi_adapter->factory->wined3d, dxgi_adapter->ordinal, &wined3d_mode); + wined3d_mutex_unlock(); + + if (SUCCEEDED(hr)) + { + if (wined3d_desc->backbuffer_width != wined3d_mode.width || wined3d_desc->backbuffer_height != wined3d_mode.height) + TRACE("Adjusting resolution from (%ux%u) to (%ux%u).\n", wined3d_desc->backbuffer_width, + wined3d_desc->backbuffer_height, wined3d_mode.width, wined3d_mode.height); + wined3d_desc->backbuffer_width = wined3d_mode.width; + wined3d_desc->backbuffer_height = wined3d_mode.height; + wined3d_desc->backbuffer_format = wined3d_mode.format_id; + wined3d_desc->refresh_rate = wined3d_mode.refresh_rate; + } + + return hr; +} + 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) @@ -2867,10 +2913,21 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI IDXGIAdapter_Release(adapter); if (FAILED(hr = wined3d_swapchain_desc_from_dxgi(&wined3d_desc, window, swapchain_desc, fullscreen_desc))) return hr; + + /* For fullscreen swapchains, D3D12 changes the swapchain size to match the mode resolution. */ + if (!fullscreen_desc->Windowed && FAILED(hr = d3d12_swapchain_desc_adjust_display_mode(window, + &wined3d_desc, dxgi_adapter))) + ERR("Failed to adjust resolution for fullscreen swapchain, hr %#x.\n", hr); + + wined3d_desc.windowed = TRUE; if (FAILED(hr = wined3d_swapchain_state_create(&wined3d_desc, window, dxgi_adapter->factory->wined3d, dxgi_adapter->ordinal, &swapchain->state))) return hr; + swapchain->desc.Width = wined3d_desc.backbuffer_width; + swapchain->desc.Height = wined3d_desc.backbuffer_height; + swapchain->desc.Format = dxgi_format_from_wined3dformat(wined3d_desc.backbuffer_format); + 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) @@ -2885,8 +2942,6 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI 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); @@ -2930,10 +2985,7 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI ID3D12Device_AddRef(swapchain->device = device); if (FAILED(hr = d3d12_swapchain_create_vulkan_swapchain(swapchain))) - { - d3d12_swapchain_destroy(swapchain); - return hr; - } + goto cleanup; fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fence_desc.pNext = NULL; @@ -2955,7 +3007,32 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI IWineDXGIFactory_AddRef(swapchain->factory = factory); + if (!fullscreen_desc->Windowed) + { + if (FAILED(hr = IDXGISwapChain3_GetContainingOutput(&swapchain->IDXGISwapChain3_iface, + &swapchain->target))) + { + ERR("Failed to get target output for fullscreen swapchain, hr %#x.\n", hr); + goto cleanup; + } + + wined3d_desc.windowed = FALSE; + wined3d_mutex_lock(); + hr = dxgi_swapchain_set_fullscreen_state(swapchain->state, &wined3d_desc, swapchain->target); + wined3d_mutex_unlock(); + if (FAILED(hr)) + { + WARN("Failed to set fullscreen state, hr %#x.\n", hr); + IDXGIOutput_Release(swapchain->target); + goto cleanup; + } + } + return S_OK; + +cleanup: + d3d12_swapchain_destroy(swapchain); + return hr; } HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window, -- 2.23.0