Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- dlls/dxgi/swapchain.c | 150 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 146 insertions(+), 4 deletions(-)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index 86659d4..c623b95 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -1084,8 +1084,12 @@ struct d3d12_swapchain IWineDXGIFactory *factory;
HWND window; + IDXGIOutput *target; DXGI_SWAP_CHAIN_DESC1 desc; DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc; + struct wined3d_fullscreen_state fullscreen_state; + DXGI_MODE_DESC original_mode; + RECT orig_window_rect; };
static DXGI_FORMAT dxgi_format_from_vk_format(VkFormat vk_format) @@ -2177,17 +2181,122 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetBuffer(IDXGISwapChain3 *ifac static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d12_swapchain_SetFullscreenState(IDXGISwapChain3 *iface, BOOL fullscreen, IDXGIOutput *target) { - FIXME("iface %p, fullscreen %#x, target %p stub!\n", iface, fullscreen, target); + struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface); + DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc = &swapchain->fullscreen_desc; + const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc = &swapchain->desc; + HWND window = swapchain->window; + DXGI_MODE_DESC actual_mode; + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("iface %p, fullscreen %#x, target %p.\n", iface, fullscreen, target); + + if (!fullscreen && target) + { + WARN("Invalid call.\n"); + return DXGI_ERROR_INVALID_CALL; + } + + if (target) + { + IDXGIOutput_AddRef(target); + } + else if (FAILED(hr = IDXGISwapChain3_GetContainingOutput(iface, &target))) + { + WARN("Failed to get default target output for swapchain, hr %#x.\n", hr); + return hr; + } + + wined3d_mutex_lock(); + + if (swapchain_desc->Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH) + { + if (fullscreen) + { + actual_mode.Width = swapchain_desc->Width; + actual_mode.Height = swapchain_desc->Height; + actual_mode.RefreshRate = fullscreen_desc->RefreshRate; + actual_mode.Format = swapchain_desc->Format; + actual_mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + } + else + { + actual_mode = swapchain->original_mode; + } + + if (FAILED(hr = dxgi_output_set_display_mode(target, &actual_mode))) + goto release; + } + else + { + if (FAILED(hr = dxgi_output_get_display_mode(target, &actual_mode))) + { + ERR("Failed to get display mode, hr %#x.\n", hr); + hr = DXGI_ERROR_INVALID_CALL; + goto release; + } + } + + if (fullscreen) + { + if (fullscreen_desc->Windowed) + { + if (FAILED(hr = wined3d_fullscreen_setup_window(&swapchain->fullscreen_state, + window, actual_mode.Width, actual_mode.Height))) + goto release; + } + else + { + /* Fullscreen -> fullscreen mode change */ + MoveWindow(window, 0, 0, actual_mode.Width, actual_mode.Height, TRUE); + ShowWindow(window, SW_SHOW); + } + } + else if (!fullscreen_desc->Windowed) + { + /* Fullscreen -> windowed switch */ + wined3d_fullscreen_restore_window(&swapchain->fullscreen_state, window, &swapchain->orig_window_rect); + } + + wined3d_mutex_unlock(); + fullscreen_desc->Windowed = !fullscreen; + + if (!fullscreen) + { + IDXGIOutput_Release(target); + target = NULL; + } + + if (swapchain->target) + IDXGIOutput_Release(swapchain->target); + swapchain->target = target; + + return S_OK; + +release: + wined3d_mutex_unlock(); + IDXGIOutput_Release(target); + + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; }
static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFullscreenState(IDXGISwapChain3 *iface, BOOL *fullscreen, IDXGIOutput **target) { - FIXME("iface %p, fullscreen %p, target %p stub!\n", iface, fullscreen, target); + struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
- return E_NOTIMPL; + TRACE("iface %p, fullscreen %p, target %p.\n", iface, fullscreen, target); + + if (fullscreen) + *fullscreen = !swapchain->fullscreen_desc.Windowed; + + if (target) + { + *target = swapchain->target; + if (*target) + IDXGIOutput_AddRef(*target); + } + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDesc(IDXGISwapChain3 *iface, DXGI_SWAP_CHAIN_DESC *desc) @@ -2316,6 +2425,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetContainingOutput(IDXGISwapCh
TRACE("iface %p, output %p.\n", iface, output);
+ if (swapchain->target) + { + IDXGIOutput_AddRef(*output = swapchain->target); + return S_OK; + } + device_parent = vkd3d_get_device_parent(swapchain->device);
if (SUCCEEDED(hr = IUnknown_QueryInterface(device_parent, &IID_IDXGIAdapter, (void **)&adapter))) @@ -2756,6 +2871,7 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI swapchain->refcount = 1;
swapchain->window = window; + GetWindowRect(window, &swapchain->orig_window_rect); swapchain->desc = *swapchain_desc; swapchain->fullscreen_desc = *fullscreen_desc;
@@ -2862,6 +2978,26 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI return S_OK; }
+static HRESULT d3d12_swapchain_fullscreen_init(struct d3d12_swapchain *swapchain) +{ + IDXGISwapChain3 *iface = &swapchain->IDXGISwapChain3_iface; + IDXGIOutput *output; + HRESULT hr; + + if (FAILED(hr = d3d12_swapchain_GetContainingOutput(iface, &output))) + { + ERR("Failed to get containing output, hr %#x.\n", hr); + return hr; + } + + if (FAILED(hr = dxgi_output_get_display_mode(output, &swapchain->original_mode))) + ERR("Failed to get current display mode, hr %#x.\n", hr); + + IDXGIOutput_Release(output); + + 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) @@ -2899,6 +3035,12 @@ HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *qu return hr; }
+ if(FAILED(hr = d3d12_swapchain_fullscreen_init(object))) + { + heap_free(object); + return hr; + } + TRACE("Created swapchain %p.\n", object);
*swapchain = (IDXGISwapChain1 *)&object->IDXGISwapChain3_iface;