Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- dlls/dxgi/swapchain.c | 144 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 4 deletions(-)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index b7a3cc0..457d187 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -1085,8 +1085,12 @@ struct d3d12_swapchain IWineDXGIFactory *factory;
HWND window; + IDXGIOutput *target; DXGI_SWAP_CHAIN_DESC1 desc; DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc; + struct wined3d_window_state window_state; + DXGI_MODE_DESC original_mode; + RECT orig_window_rect; };
static DXGI_FORMAT dxgi_format_from_vk_format(VkFormat vk_format) @@ -2178,17 +2182,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_window_setup_fullscreen(&swapchain->window_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_window_restore_from_fullscreen(&swapchain->window_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) @@ -2306,6 +2415,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))) @@ -2752,6 +2867,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;
@@ -2865,6 +2981,7 @@ HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *qu DXGI_SWAP_CHAIN_FULLSCREEN_DESC default_fullscreen_desc; struct d3d12_swapchain *object; ID3D12Device *device; + IDXGIOutput *output; HRESULT hr;
if (swapchain_desc->Format == DXGI_FORMAT_UNKNOWN) @@ -2895,11 +3012,30 @@ HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *qu return hr; }
+ if (FAILED(hr = d3d12_swapchain_GetContainingOutput(&object->IDXGISwapChain3_iface, &output))) + { + ERR("Failed to get containing output, hr %#x.\n", hr); + goto cleanup; + } + + hr = dxgi_output_get_display_mode(output, &object->original_mode); + IDXGIOutput_Release(output); + if (FAILED(hr)) + { + ERR("Failed to get current display mode, hr %#x.\n", hr); + goto cleanup; + } + TRACE("Created swapchain %p.\n", object);
*swapchain = (IDXGISwapChain1 *)&object->IDXGISwapChain3_iface;
return S_OK; + +cleanup: + d3d12_swapchain_destroy(object); + heap_free(object); + return hr; }
#else