From: Zhiyi Zhang <zzhang@codeweavers.com> Overwatch 2 (SteamID: 2357570) doesn't create its swapchain with DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH. It relies on IDXGISwapChain::ResizeBuffers() to add the flag so that it can change the display resolution after the swapchain creation. --- dlls/ddraw/ddraw.c | 3 ++- dlls/dxgi/dxgi_private.h | 1 + dlls/dxgi/swapchain.c | 17 ++++++++++++++--- dlls/dxgi/tests/dxgi.c | 15 +++++++-------- dlls/dxgi/utils.c | 2 +- dlls/wined3d/device.c | 2 +- dlls/wined3d/swapchain.c | 10 +++++++++- dlls/wined3d/wined3d.spec | 2 +- include/wine/wined3d.h | 3 ++- 9 files changed, 38 insertions(+), 17 deletions(-) diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index c4ce81234bc..8814c32447d 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -1143,7 +1143,8 @@ static HRESULT WINAPI ddraw7_SetDisplayMode(IDirectDraw7 *iface, DWORD width, DW DDSURFACEDESC2 *surface_desc = &ddraw->primary->surface_desc; if (FAILED(hr = wined3d_swapchain_resize_buffers(ddraw->wined3d_swapchain, 0, - surface_desc->dwWidth, surface_desc->dwHeight, mode.format_id, WINED3D_MULTISAMPLE_NONE, 0))) + surface_desc->dwWidth, surface_desc->dwHeight, mode.format_id, + WINED3D_MULTISAMPLE_NONE, 0, 0))) ERR("Failed to resize buffers, hr %#lx.\n", hr); else ddrawformat_from_wined3dformat(&ddraw->primary->surface_desc.ddpfPixelFormat, mode.format_id); diff --git a/dlls/dxgi/dxgi_private.h b/dlls/dxgi/dxgi_private.h index cbe7c0981e6..ed82d366799 100644 --- a/dlls/dxgi/dxgi_private.h +++ b/dlls/dxgi/dxgi_private.h @@ -95,6 +95,7 @@ void wined3d_display_mode_from_dxgi1(struct wined3d_display_mode *wined3d_mode, DXGI_USAGE dxgi_usage_from_wined3d_bind_flags(unsigned int wined3d_bind_flags); unsigned int wined3d_bind_flags_from_dxgi_usage(DXGI_USAGE usage); unsigned int dxgi_swapchain_flags_from_wined3d(unsigned int wined3d_flags); +unsigned int wined3d_swapchain_flags_from_dxgi(unsigned int flags); HRESULT dxgi_get_output_from_window(IWineDXGIFactory *factory, HWND window, IDXGIOutput **dxgi_output) ; HRESULT wined3d_swapchain_desc_from_dxgi(struct wined3d_swapchain_desc *wined3d_desc, diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index eee4a2a42b3..a5811b9b4cc 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -549,6 +549,9 @@ static HRESULT d3d11_swapchain_create_d3d11_textures(struct d3d11_swapchain *swa static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain4 *iface, UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags) { + static const UINT supported_flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH + | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE + | DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain4(iface); struct wined3d_swapchain_desc wined3d_desc; struct wined3d_texture *texture; @@ -559,11 +562,17 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain4 * TRACE("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x.\n", iface, buffer_count, width, height, debug_dxgi_format(format), flags); - if (flags) - FIXME("Ignoring flags %#x.\n", flags); + if (flags & ~supported_flags) + FIXME("Ignoring flags %#x.\n", flags & ~supported_flags); wined3d_mutex_lock(); wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc); + if (!(wined3d_desc.flags & WINED3D_SWAPCHAIN_FRAME_LATENCY_WAITABLE_OBJECT) + != !(flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)) + { + wined3d_mutex_unlock(); + return E_INVALIDARG; + } for (i = 0; i < wined3d_desc.backbuffer_count; ++i) { texture = wined3d_swapchain_get_back_buffer(swapchain->wined3d_swapchain, i); @@ -577,8 +586,10 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain4 * } if (format != DXGI_FORMAT_UNKNOWN) wined3d_desc.backbuffer_format = wined3dformat_from_dxgi_format(format); + wined3d_desc.flags = wined3d_swapchain_flags_from_dxgi(flags); hr = wined3d_swapchain_resize_buffers(swapchain->wined3d_swapchain, buffer_count, width, height, - wined3d_desc.backbuffer_format, wined3d_desc.multisample_type, wined3d_desc.multisample_quality); + wined3d_desc.backbuffer_format, wined3d_desc.multisample_type, + wined3d_desc.multisample_quality, wined3d_desc.flags); /* wined3d_swapchain_resize_buffers() may recreate swapchain textures. * We do not need to remove the reference to the wined3d swapchain from the * old d3d11 textures: we just validated above that they have 0 references, diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c index 0aa7ee5a2ad..d8c560b89c4 100644 --- a/dlls/dxgi/tests/dxgi.c +++ b/dlls/dxgi/tests/dxgi.c @@ -4758,7 +4758,7 @@ static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12) || flag == DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO || flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) { - todo_wine + todo_wine_if(is_d3d12 || flag != DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); } else @@ -4766,7 +4766,8 @@ static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine + todo_wine_if(is_d3d12 || !(flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH + || flag == DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE)) ok(swapchain_desc.Flags == flag, "Got unexpected Flags %#x.\n", swapchain_desc.Flags); } @@ -4819,7 +4820,7 @@ static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12) || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); else - todo_wine + todo_wine_if(is_d3d12 || flag != DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) ok(hr == DXGI_ERROR_INVALID_CALL || hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); IDXGISwapChain_Release(tmp_swapchain); DestroyWindow(swapchain_desc.OutputWindow); @@ -4976,17 +4977,15 @@ static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine + todo_wine_if(is_d3d12) ok(swapchain_desc.Flags == DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE, "Got unexpected Flags %#x.\n", swapchain_desc.Flags); hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface1, (void **)&surface1); if (hr == S_OK) { hr = IDXGISurface1_GetDC(surface1, FALSE, &hdc); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - if (hr == S_OK) - IDXGISurface1_ReleaseDC(surface1, NULL); + IDXGISurface1_ReleaseDC(surface1, NULL); IDXGISurface1_Release(surface1); } @@ -4999,7 +4998,7 @@ static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12) if (hr == S_OK) { hr = IDXGISurface1_GetDC(surface1, FALSE, &hdc); - todo_wine + todo_wine_if(hr == 0x8876086c) ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); IDXGISurface1_Release(surface1); } diff --git a/dlls/dxgi/utils.c b/dlls/dxgi/utils.c index e958c4d043b..84402864e7b 100644 --- a/dlls/dxgi/utils.c +++ b/dlls/dxgi/utils.c @@ -552,7 +552,7 @@ unsigned int dxgi_swapchain_flags_from_wined3d(unsigned int wined3d_flags) return flags; } -static unsigned int wined3d_swapchain_flags_from_dxgi(unsigned int flags) +unsigned int wined3d_swapchain_flags_from_dxgi(unsigned int flags) { unsigned int wined3d_flags = DXGI_WINED3D_SWAPCHAIN_FLAGS; /* WINED3D_SWAPCHAIN_DISCARD_DEPTHSTENCIL? */ diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 11934fccad2..49a14165e7a 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -5166,7 +5166,7 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device, if (FAILED(hr = wined3d_swapchain_resize_buffers(swapchain, swapchain_desc->backbuffer_count, swapchain_desc->backbuffer_width, swapchain_desc->backbuffer_height, swapchain_desc->backbuffer_format, - swapchain_desc->multisample_type, swapchain_desc->multisample_quality))) + swapchain_desc->multisample_type, swapchain_desc->multisample_quality, swapchain_desc->flags))) return hr; if (swapchain_desc->flags != current_desc->flags) diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 06451c93d65..01a16b17b4b 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -2030,7 +2030,8 @@ void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activa HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapchain, unsigned int buffer_count, unsigned int width, unsigned int height, enum wined3d_format_id format_id, - enum wined3d_multisample_type multisample_type, unsigned int multisample_quality) + enum wined3d_multisample_type multisample_type, unsigned int multisample_quality, + unsigned int flags) { struct wined3d_swapchain_desc *desc = &swapchain->state.desc; bool recreate = false; @@ -2096,6 +2097,13 @@ HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapcha recreate = true; } + if (flags) + { + if ((desc->flags ^ flags) & WINED3D_SWAPCHAIN_GDI_COMPATIBLE) + recreate = true; + desc->flags = flags; + } + if (recreate) { struct wined3d_texture *new_texture; diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 4f40e55f1bd..da7db0c2184 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -310,7 +310,7 @@ @ cdecl wined3d_swapchain_get_state(ptr) @ cdecl wined3d_swapchain_incref(ptr) @ cdecl wined3d_swapchain_present(ptr ptr ptr ptr long long) -@ cdecl wined3d_swapchain_resize_buffers(ptr long long long long long long) +@ cdecl wined3d_swapchain_resize_buffers(ptr long long long long long long long) @ cdecl wined3d_swapchain_set_gamma_ramp(ptr long ptr) @ cdecl wined3d_swapchain_set_max_frame_latency(ptr long) @ cdecl wined3d_swapchain_set_palette(ptr ptr) diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 002bab2b9c6..49c6672fa3f 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2922,7 +2922,8 @@ HRESULT __cdecl wined3d_swapchain_present(struct wined3d_swapchain *swapchain, c const RECT *dst_rect, HWND dst_window_override, unsigned int swap_interval, uint32_t flags); HRESULT __cdecl wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapchain, unsigned int buffer_count, unsigned int width, unsigned int height, enum wined3d_format_id format_id, - enum wined3d_multisample_type multisample_type, unsigned int multisample_quality); + enum wined3d_multisample_type multisample_type, unsigned int multisample_quality, + unsigned int flags); HRESULT __cdecl wined3d_swapchain_set_gamma_ramp(const struct wined3d_swapchain *swapchain, uint32_t flags, const struct wined3d_gamma_ramp *ramp); HRESULT __cdecl wined3d_swapchain_set_max_frame_latency(struct wined3d_swapchain *swapchain, unsigned int latency); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11391