-- v2: dxgi: Implement IDXGIFactory2::CreateSwapChainForComposition(). dxgi/tests: Add composition swapchain tests.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/dxgi/tests/dxgi.c | 146 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+)
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c index e0465b90ed0..cdb04ba2c0e 100644 --- a/dlls/dxgi/tests/dxgi.c +++ b/dlls/dxgi/tests/dxgi.c @@ -7581,6 +7581,150 @@ done: ok(!refcount, "Device has %lu references left.\n", refcount); }
+static void test_composition_swapchain(IUnknown *device, BOOL is_d3d12) +{ + DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc; + DXGI_SWAP_CHAIN_DESC1 swapchain_desc; + IDXGISwapChain1 *swapchain1; + IDXGIFactory2 *factory2; + IDXGIFactory *factory; + DXGI_MODE_DESC mode; + IDXGIOutput *output; + IUnknown *unknown; + ULONG ref_count; + HWND window; + HRESULT hr; + BOOL ret; + + get_factory(device, is_d3d12, &factory); + + hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory2, (void**)&factory2); + IDXGIFactory_Release(factory); + if (FAILED(hr)) + { + win_skip("IDXGIFactory2 not available.\n"); + return; + } + + swapchain_desc.Width = 640; + swapchain_desc.Height = 480; + swapchain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + swapchain_desc.Stereo = FALSE; + swapchain_desc.SampleDesc.Count = 1; + swapchain_desc.SampleDesc.Quality = 0; + swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapchain_desc.BufferCount = 2; + swapchain_desc.Scaling = DXGI_SCALING_STRETCH; + swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; + swapchain_desc.Flags = 0; + + /* Parameter checks */ + /* NULL device */ + hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, NULL, &swapchain_desc, NULL, &swapchain1); + if (hr == DXGI_ERROR_UNSUPPORTED) /* Win7 */ + { + win_skip("CreateSwapChainForComposition() is unsupported.\n"); + ref_count = IDXGIFactory2_Release(factory2); + ok(ref_count == !is_d3d12, "Factory has %lu references left.\n", ref_count); + return; + } + todo_wine + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + /* NULL swapchain description */ + hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, NULL, NULL, &swapchain1); + todo_wine + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + /* Invalid width */ + swapchain_desc.Width = 0; + hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, &swapchain1); + todo_wine + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + swapchain_desc.Width = 640; + + /* Invalid height */ + swapchain_desc.Height = 0; + hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, &swapchain1); + todo_wine + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + swapchain_desc.Height = 480; + + /* Invalid scaling */ + swapchain_desc.Scaling = DXGI_SCALING_NONE; + hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, &swapchain1); + todo_wine + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + swapchain_desc.Scaling = DXGI_SCALING_STRETCH; + + /* Invalid swap effect */ + swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; + hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, &swapchain1); + todo_wine + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + + /* NULL swapchain pointer */ + hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, NULL); + todo_wine + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + /* Normal call*/ + hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, &swapchain1); + todo_wine + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + { + skip("CreateSwapChainForComposition() is unsupported.\n"); + ref_count = IDXGIFactory2_Release(factory2); + ok(ref_count == !is_d3d12, "Factory has %lu references left.\n", ref_count); + return; + } + + output = (void *)0xdeadbeef; + hr = IDXGISwapChain1_GetFullscreenState(swapchain1, &ret, &output); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!ret, "Got unexpected fullscreen state.\n"); + ok(!output, "Got unexpected output.\n"); + + /* ResizeBuffers() tests */ + hr = IDXGISwapChain1_ResizeBuffers(swapchain1, 2, 0, 768, DXGI_FORMAT_B8G8R8A8_UNORM, 0); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = IDXGISwapChain1_ResizeBuffers(swapchain1, 2, 1024, 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = IDXGISwapChain1_ResizeBuffers(swapchain1, 2, 1024, 768, DXGI_FORMAT_B8G8R8A8_UNORM, 0); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + /* Invalid method calls for composition swapchains */ + hr = IDXGISwapChain1_GetFullscreenDesc(swapchain1, &fullscreen_desc); + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + hr = IDXGISwapChain1_SetFullscreenState(swapchain1, TRUE, NULL); + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + memset(&mode, 0, sizeof(mode)); + mode.Width = 1024; + mode.Height = 768; + hr = IDXGISwapChain1_ResizeTarget(swapchain1, &mode); + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + hr = IDXGISwapChain1_GetContainingOutput(swapchain1, &output); + ok(hr == DXGI_ERROR_UNSUPPORTED, "Got unexpected hr %#lx.\n", hr); + + hr = IDXGISwapChain1_GetHwnd(swapchain1, &window); + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + hr = IDXGISwapChain1_GetCoreWindow(swapchain1, &IID_IUnknown, (void **)&unknown); + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + IDXGISwapChain1_Release(swapchain1); + ref_count = IDXGIFactory2_Release(factory2); + ok(ref_count == !is_d3d12, "Factory has %lu references left.\n", ref_count); +} + static void run_on_d3d10(void (*test_func)(IUnknown *device, BOOL is_d3d12)) { IDXGIDevice *device; @@ -7705,6 +7849,7 @@ START_TEST(dxgi) run_on_d3d10(test_default_fullscreen_target_output); run_on_d3d10(test_mode_change); run_on_d3d10(test_swapchain_present_count); + run_on_d3d10(test_composition_swapchain);
if (!(d3d12_module = LoadLibraryA("d3d12.dll"))) { @@ -7736,6 +7881,7 @@ START_TEST(dxgi) run_on_d3d12(test_default_fullscreen_target_output); run_on_d3d12(test_mode_change); run_on_d3d12(test_swapchain_present_count); + run_on_d3d12(test_composition_swapchain);
FreeLibrary(d3d12_module); }
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/dxgi/dxgi_private.h | 8 +++ dlls/dxgi/factory.c | 49 +++++++++++++++- dlls/dxgi/swapchain.c | 121 +++++++++++++++++++++++++++++++++++++++ dlls/dxgi/tests/dxgi.c | 15 ----- 4 files changed, 175 insertions(+), 18 deletions(-)
diff --git a/dlls/dxgi/dxgi_private.h b/dlls/dxgi/dxgi_private.h index dd17e39eca6..e16a3211d2e 100644 --- a/dlls/dxgi/dxgi_private.h +++ b/dlls/dxgi/dxgi_private.h @@ -171,6 +171,12 @@ HRESULT dxgi_adapter_create(struct dxgi_factory *factory, UINT ordinal, struct dxgi_adapter *unsafe_impl_from_IDXGIAdapter(IDXGIAdapter *iface) DECLSPEC_HIDDEN;
/* IDXGISwapChain */ +enum dxgi_swapchain_type +{ + DXGI_SWAPCHAIN_TYPE_HWND, + DXGI_SWAPCHAIN_TYPE_COMPOSITION, +}; + struct d3d11_swapchain { IDXGISwapChain1 IDXGISwapChain1_iface; @@ -181,6 +187,8 @@ struct d3d11_swapchain IWineDXGIDevice *device; IWineDXGIFactory *factory;
+ enum dxgi_swapchain_type type; + HWND window; IDXGIOutput *target; LONG present_count; }; diff --git a/dlls/dxgi/factory.c b/dlls/dxgi/factory.c index 8de882b388d..6e07530e7ef 100644 --- a/dlls/dxgi/factory.c +++ b/dlls/dxgi/factory.c @@ -381,10 +381,53 @@ static void STDMETHODCALLTYPE dxgi_factory_UnregisterOcclusionStatus(IWineDXGIFa static HRESULT STDMETHODCALLTYPE dxgi_factory_CreateSwapChainForComposition(IWineDXGIFactory *iface, IUnknown *device, const DXGI_SWAP_CHAIN_DESC1 *desc, IDXGIOutput *output, IDXGISwapChain1 **swapchain) { - FIXME("iface %p, device %p, desc %p, output %p, swapchain %p stub!\n", - iface, device, desc, output, swapchain); + IWineDXGISwapChainFactory *swapchain_factory; + ID3D12CommandQueue *command_queue; + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, device %p, desc %p,, output %p, swapchain %p.\n", iface, device, desc, output, + swapchain); + + if (!device || !desc || !swapchain) + { + WARN("Invalid pointer.\n"); + return DXGI_ERROR_INVALID_CALL; + } + + if (desc->Stereo) + { + FIXME("Stereo swapchains are not supported.\n"); + return DXGI_ERROR_UNSUPPORTED; + } + + if (!desc->Width || !desc->Height + || desc->SwapEffect != DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL + || desc->Scaling != DXGI_SCALING_STRETCH) + return DXGI_ERROR_INVALID_CALL; + + if (!dxgi_validate_swapchain_desc(desc)) + return DXGI_ERROR_INVALID_CALL; + + if (output) + FIXME("Ignoring output %p.\n", output); + + if (SUCCEEDED(IUnknown_QueryInterface(device, &IID_IWineDXGISwapChainFactory, (void **)&swapchain_factory))) + { + hr = IWineDXGISwapChainFactory_create_swapchain(swapchain_factory, (IDXGIFactory *)iface, + NULL, desc, NULL, output, swapchain); + IWineDXGISwapChainFactory_Release(swapchain_factory); + return hr; + } + + if (SUCCEEDED(IUnknown_QueryInterface(device, &IID_ID3D12CommandQueue, (void **)&command_queue))) + { + hr = d3d12_swapchain_create(iface, command_queue, NULL, desc, NULL, swapchain); + ID3D12CommandQueue_Release(command_queue); + return hr; + } + + ERR("This is not the device we're looking for.\n"); + return DXGI_ERROR_UNSUPPORTED; }
static UINT STDMETHODCALLTYPE dxgi_factory_GetCreationFlags(IWineDXGIFactory *iface) diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index 9677142e0af..b96539f12d9 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -387,6 +387,12 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_SetFullscreen
TRACE("iface %p, fullscreen %#x, target %p.\n", iface, fullscreen, target);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_INVALID_CALL; + } + if (!fullscreen && target) { WARN("Invalid call.\n"); @@ -520,6 +526,12 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain1 * 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 (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION && (!width || !height)) + { + WARN("Invalid size for composition swapchains.\n"); + return E_INVALIDARG; + } + if (flags) FIXME("Ignoring flags %#x.\n", flags);
@@ -553,6 +565,12 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeTarget(IDXGISwapChain1 *i
TRACE("iface %p, target_mode_desc %p.\n", iface, target_mode_desc);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_INVALID_CALL; + } + state = wined3d_swapchain_get_state(swapchain->wined3d_swapchain);
return dxgi_swapchain_resize_target(state, target_mode_desc); @@ -565,6 +583,12 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetContainingOutput(IDXGISwapCh
TRACE("iface %p, output %p.\n", iface, output);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_UNSUPPORTED; + } + if (swapchain->target) { IDXGIOutput_AddRef(*output = swapchain->target); @@ -646,6 +670,12 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetFullscreenDesc(IDXGISwapChai
TRACE("iface %p, desc %p.\n", iface, desc);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_INVALID_CALL; + } + if (!desc) { WARN("Invalid pointer.\n"); @@ -673,6 +703,12 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetHwnd(IDXGISwapChain1 *iface,
TRACE("iface %p, hwnd %p.\n", iface, hwnd);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_INVALID_CALL; + } + if (!hwnd) { WARN("Invalid pointer.\n"); @@ -686,8 +722,16 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetHwnd(IDXGISwapChain1 *iface, static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetCoreWindow(IDXGISwapChain1 *iface, REFIID iid, void **core_window) { + struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface); + FIXME("iface %p, iid %s, core_window %p stub!\n", iface, debugstr_guid(iid), core_window);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_INVALID_CALL; + } + if (core_window) *core_window = NULL;
@@ -799,6 +843,8 @@ static void STDMETHODCALLTYPE d3d11_swapchain_wined3d_object_released(void *pare { struct d3d11_swapchain *swapchain = parent;
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + DestroyWindow(swapchain->window); wined3d_private_store_cleanup(&swapchain->private_store); heap_free(parent); } @@ -866,6 +912,18 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi wined3d_mutex_lock(); wined3d_private_store_init(&swapchain->private_store);
+ if (!desc->device_window) + { + swapchain->type = DXGI_SWAPCHAIN_TYPE_COMPOSITION; + desc->device_window = CreateWindowW(L"static", L"dxgi_dummy_window", WS_POPUP, 0, 0, 1, 1, + 0, 0, 0, 0); + } + else + { + swapchain->type = DXGI_SWAPCHAIN_TYPE_HWND; + } + swapchain->window = desc->device_window; + if (!desc->windowed && (!desc->backbuffer_width || !desc->backbuffer_height)) FIXME("Fullscreen swapchain with back buffer width/height equal to 0 not supported properly.\n");
@@ -1011,6 +1069,7 @@ struct d3d12_swapchain ID3D12Device *device; IWineDXGIFactory *factory;
+ enum dxgi_swapchain_type type; HWND window; IDXGIOutput *target; DXGI_SWAP_CHAIN_DESC1 desc; @@ -1843,6 +1902,9 @@ static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain) if (swapchain->vk_instance) vk_funcs->p_vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + DestroyWindow(swapchain->window); + if (swapchain->target) { WARN("Destroying fullscreen swapchain.\n"); @@ -2177,6 +2239,12 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d12_swapchain_SetFullscreen
TRACE("iface %p, fullscreen %#x, target %p.\n", iface, fullscreen, target);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_INVALID_CALL; + } + if (!fullscreen && target) { WARN("Invalid call.\n"); @@ -2363,6 +2431,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_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 (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION && (!width || !height)) + { + WARN("Invalid size for composition swapchains.\n"); + return E_INVALIDARG; + } + return d3d12_swapchain_resize_buffers(swapchain, buffer_count, width, height, format, flags); }
@@ -2373,6 +2447,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeTarget(IDXGISwapChain4 *i
TRACE("iface %p, target_mode_desc %p.\n", iface, target_mode_desc);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_INVALID_CALL; + } + return dxgi_swapchain_resize_target(swapchain->state, target_mode_desc); }
@@ -2387,6 +2467,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetContainingOutput(IDXGISwapCh
TRACE("iface %p, output %p.\n", iface, output);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_UNSUPPORTED; + } + if (swapchain->target) { IDXGIOutput_AddRef(*output = swapchain->target); @@ -2460,6 +2546,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFullscreenDesc(IDXGISwapChai
TRACE("iface %p, desc %p.\n", iface, desc);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_INVALID_CALL; + } + if (!desc) { WARN("Invalid pointer.\n"); @@ -2481,6 +2573,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetHwnd(IDXGISwapChain4 *iface,
TRACE("iface %p, hwnd %p.\n", iface, hwnd);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_INVALID_CALL; + } + if (!hwnd) { WARN("Invalid pointer.\n"); @@ -2494,8 +2592,16 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetHwnd(IDXGISwapChain4 *iface, static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetCoreWindow(IDXGISwapChain4 *iface, REFIID iid, void **core_window) { + struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain4(iface); + FIXME("iface %p, iid %s, core_window %p stub!\n", iface, debugstr_guid(iid), core_window);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION) + { + WARN("Invalid swapchain type.\n"); + return DXGI_ERROR_INVALID_CALL; + } + if (core_window) *core_window = NULL;
@@ -2700,6 +2806,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeBuffers1(IDXGISwapChain4 "node_mask %p, present_queue %p.\n", iface, buffer_count, width, height, debug_dxgi_format(format), flags, node_mask, present_queue);
+ if (swapchain->type == DXGI_SWAPCHAIN_TYPE_COMPOSITION && (!width || !height)) + { + WARN("Invalid size for composition swapchains.\n"); + return E_INVALIDARG; + } + if (!node_mask || !present_queue) return DXGI_ERROR_INVALID_CALL;
@@ -2902,6 +3014,15 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI swapchain->state_parent.ops = &d3d12_swapchain_state_parent_ops; swapchain->refcount = 1;
+ if (!window) + { + swapchain->type = DXGI_SWAPCHAIN_TYPE_COMPOSITION; + window = CreateWindowW(L"static", L"dxgi_dummy_window", WS_POPUP, 0, 0, 1, 1, 0, 0, 0, 0); + } + else + { + swapchain->type = DXGI_SWAPCHAIN_TYPE_HWND; + } swapchain->window = window; swapchain->desc = *swapchain_desc; swapchain->fullscreen_desc = *fullscreen_desc; diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c index cdb04ba2c0e..85f58055815 100644 --- a/dlls/dxgi/tests/dxgi.c +++ b/dlls/dxgi/tests/dxgi.c @@ -7629,58 +7629,43 @@ static void test_composition_swapchain(IUnknown *device, BOOL is_d3d12) ok(ref_count == !is_d3d12, "Factory has %lu references left.\n", ref_count); return; } - todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
/* NULL swapchain description */ hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, NULL, NULL, &swapchain1); - todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
/* Invalid width */ swapchain_desc.Width = 0; hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, &swapchain1); - todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); swapchain_desc.Width = 640;
/* Invalid height */ swapchain_desc.Height = 0; hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, &swapchain1); - todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); swapchain_desc.Height = 480;
/* Invalid scaling */ swapchain_desc.Scaling = DXGI_SCALING_NONE; hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, &swapchain1); - todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); swapchain_desc.Scaling = DXGI_SCALING_STRETCH;
/* Invalid swap effect */ swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, &swapchain1); - todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
/* NULL swapchain pointer */ hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, NULL); - todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
/* Normal call*/ hr = IDXGIFactory2_CreateSwapChainForComposition(factory2, device, &swapchain_desc, NULL, &swapchain1); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - if (FAILED(hr)) - { - skip("CreateSwapChainForComposition() is unsupported.\n"); - ref_count = IDXGIFactory2_Release(factory2); - ok(ref_count == !is_d3d12, "Factory has %lu references left.\n", ref_count); - return; - }
output = (void *)0xdeadbeef; hr = IDXGISwapChain1_GetFullscreenState(swapchain1, &ret, &output);
I'm not very knowledgeable in general about the subtleties of DXGI, but this looks potentially reasonable. I assume that we'll end up grabbing the window using some internal interface in IDCompositionVisual::SetContent() and then performing a GDI blit?
Please see commit_target() in https://gitlab.winehq.org/zhiyi/wine/-/commit/8d72aa74da59ccb1192fb5cb3d7986.... The whole DirectComposition branch is at https://gitlab.winehq.org/zhiyi/wine/-/tree/directcomposition. Basically, it GDI bitblts from the last backbuffer to the window DC. On Windows, it is composited by DWM. We don't have a DWM in Wine and I don't want to write platform specific code for doing composition so blitting to the window DC seems to be good enough.
Wait, so it blits from the backbuffer, not the frontbuffer? Can we rely on Commit() being called every frame *before* Present(), or something?
I can believe that this is how it's supposed to work, but it's more than a little surprising, and doesn't match what the documentation (or the example [1]) seems to suggest. I.e. I'd expect in general that Commit() doesn't need to be called every frame, and Present() should always update the screen with the contents of the current backbuffer.
[1] https://learn.microsoft.com/en-us/windows/uwp/gaming/directx-and-xaml-intero...
On Tue Feb 28 00:42:37 2023 +0000, Zebediah Figura wrote:
I'm not very knowledgeable in general about the subtleties of DXGI,
but this looks potentially reasonable. I assume that we'll end up grabbing the window using some internal interface in IDCompositionVisual::SetContent() and then performing a GDI blit?
Please see commit_target() in
https://gitlab.winehq.org/zhiyi/wine/-/commit/8d72aa74da59ccb1192fb5cb3d7986.... The whole DirectComposition branch is at https://gitlab.winehq.org/zhiyi/wine/-/tree/directcomposition. Basically, it GDI bitblts from the last backbuffer to the window DC. On Windows, it is composited by DWM. We don't have a DWM in Wine and I don't want to write platform specific code for doing composition so blitting to the window DC seems to be good enough. Wait, so it blits from the backbuffer, not the frontbuffer? Can we rely on Commit() being called every frame *before* Present(), or something? I can believe that this is how it's supposed to work, but it's more than a little surprising, and doesn't match what the documentation (or the example [1]) seems to suggest. I.e. I'd expect in general that Commit() doesn't need to be called every frame, and Present() should always update the screen with the contents of the current backbuffer. [1] https://learn.microsoft.com/en-us/windows/uwp/gaming/directx-and-xaml-intero...
It does blit from the frontbuffer. The composition swapchain must be created with DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL. So the last backbuffer is the frontbuffer, I think. That's why I use the last backbuffer the dcomp Commit() implementation. Otherwise, I will need a private interface to access the frontbuffer. The game Corgi Warlock calls Present() and then Commit() every frame. Commit() should be called every frame in DirectComposition to make it work. Please see https://learn.microsoft.com/en-us/windows/win32/directcomp/basic-concepts#tr...
On 2/27/23 20:48, Zhiyi Zhang (@zhiyi) wrote:
On Tue Feb 28 00:42:37 2023 +0000, Zebediah Figura wrote:
I'm not very knowledgeable in general about the subtleties of DXGI,
but this looks potentially reasonable. I assume that we'll end up grabbing the window using some internal interface in IDCompositionVisual::SetContent() and then performing a GDI blit?
Please see commit_target() in
https://gitlab.winehq.org/zhiyi/wine/-/commit/8d72aa74da59ccb1192fb5cb3d7986.... The whole DirectComposition branch is at https://gitlab.winehq.org/zhiyi/wine/-/tree/directcomposition. Basically, it GDI bitblts from the last backbuffer to the window DC. On Windows, it is composited by DWM. We don't have a DWM in Wine and I don't want to write platform specific code for doing composition so blitting to the window DC seems to be good enough. Wait, so it blits from the backbuffer, not the frontbuffer? Can we rely on Commit() being called every frame *before* Present(), or something? I can believe that this is how it's supposed to work, but it's more than a little surprising, and doesn't match what the documentation (or the example [1]) seems to suggest. I.e. I'd expect in general that Commit() doesn't need to be called every frame, and Present() should always update the screen with the contents of the current backbuffer. [1] https://learn.microsoft.com/en-us/windows/uwp/gaming/directx-and-xaml-intero...
It does blit from the frontbuffer. The composition swapchain must be created with DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL. So the last backbuffer is the frontbuffer, I think. That's why I use the last backbuffer the dcomp Commit() implementation. Otherwise, I will need a private interface to access the frontbuffer. The game Corgi Warlock calls Present() and then Commit() every frame. Commit() should be called every frame in DirectComposition to make it work. Please see https://learn.microsoft.com/en-us/windows/win32/directcomp/basic-concepts#tr...
Are you sure about Commit? As I understood some time ago when looking at that Commit should only be called once anything has changed WRT direct composition setup (e. g., transforms, surface configuration). Once direct composition is set up, I think one can only call Present on linked swapchains and that is supposed to be composited according to current configuration. IIRC that is how Webview2 worked.
On Tue Feb 28 03:08:39 2023 +0000, **** wrote:
Paul Gofman replied on the mailing list:
On 2/27/23 20:48, Zhiyi Zhang (@zhiyi) wrote: > On Tue Feb 28 00:42:37 2023 +0000, Zebediah Figura wrote: >>>> I'm not very knowledgeable in general about the subtleties of DXGI, >> but this looks potentially reasonable. I assume that we'll end up >> grabbing the window using some internal interface in >> IDCompositionVisual::SetContent() and then performing a GDI blit? >>> Please see commit_target() in >> https://gitlab.winehq.org/zhiyi/wine/-/commit/8d72aa74da59ccb1192fb5cb3d7986f30fb9ed2b. >> The whole DirectComposition branch is at >> https://gitlab.winehq.org/zhiyi/wine/-/tree/directcomposition. >> Basically, it GDI bitblts from the last backbuffer to the window DC. On >> Windows, it is composited by DWM. We don't have a DWM in Wine and I >> don't want to write platform specific code for doing composition so >> blitting to the window DC seems to be good enough. >> Wait, so it blits from the backbuffer, not the frontbuffer? Can we rely >> on Commit() being called every frame *before* Present(), or something? >> I can believe that this is how it's supposed to work, but it's more than >> a little surprising, and doesn't match what the documentation (or the >> example [1]) seems to suggest. I.e. I'd expect in general that Commit() >> doesn't need to be called every frame, and Present() should always >> update the screen with the contents of the current backbuffer. >> [1] https://learn.microsoft.com/en-us/windows/uwp/gaming/directx-and-xaml-interop > It does blit from the frontbuffer. The composition swapchain must be created with DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL. So the last backbuffer is the frontbuffer, I think. That's why I use the last backbuffer the dcomp Commit() implementation. Otherwise, I will need a private interface to access the frontbuffer. The game Corgi Warlock calls Present() and then Commit() every frame. Commit() should be called every frame in DirectComposition to make it work. Please see https://learn.microsoft.com/en-us/windows/win32/directcomp/basic-concepts#transactional-composition > Are you sure about Commit? As I understood some time ago when looking at that Commit should only be called once anything has changed WRT direct composition setup (e. g., transforms, surface configuration). Once direct composition is set up, I think one can only call Present on linked swapchains and that is supposed to be composited according to current configuration. IIRC that is how Webview2 worked.
That's what I am seeing in the Corgi Warlock log. Every Present() is followed by a Commit().
On 2/27/23 21:24, Zhiyi Zhang (@zhiyi) wrote:
On Tue Feb 28 03:08:39 2023 +0000, **** wrote:
Paul Gofman replied on the mailing list:
On 2/27/23 20:48, Zhiyi Zhang (@zhiyi) wrote: > On Tue Feb 28 00:42:37 2023 +0000, Zebediah Figura wrote: >>>> I'm not very knowledgeable in general about the subtleties of DXGI, >> but this looks potentially reasonable. I assume that we'll end up >> grabbing the window using some internal interface in >> IDCompositionVisual::SetContent() and then performing a GDI blit? >>> Please see commit_target() in >> https://gitlab.winehq.org/zhiyi/wine/-/commit/8d72aa74da59ccb1192fb5cb3d7986f30fb9ed2b. >> The whole DirectComposition branch is at >> https://gitlab.winehq.org/zhiyi/wine/-/tree/directcomposition. >> Basically, it GDI bitblts from the last backbuffer to the window DC. On >> Windows, it is composited by DWM. We don't have a DWM in Wine and I >> don't want to write platform specific code for doing composition so >> blitting to the window DC seems to be good enough. >> Wait, so it blits from the backbuffer, not the frontbuffer? Can we rely >> on Commit() being called every frame *before* Present(), or something? >> I can believe that this is how it's supposed to work, but it's more than >> a little surprising, and doesn't match what the documentation (or the >> example [1]) seems to suggest. I.e. I'd expect in general that Commit() >> doesn't need to be called every frame, and Present() should always >> update the screen with the contents of the current backbuffer. >> [1] https://learn.microsoft.com/en-us/windows/uwp/gaming/directx-and-xaml-interop > It does blit from the frontbuffer. The composition swapchain must be created with DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL. So the last backbuffer is the frontbuffer, I think. That's why I use the last backbuffer the dcomp Commit() implementation. Otherwise, I will need a private interface to access the frontbuffer. The game Corgi Warlock calls Present() and then Commit() every frame. Commit() should be called every frame in DirectComposition to make it work. Please see https://learn.microsoft.com/en-us/windows/win32/directcomp/basic-concepts#transactional-composition Are you sure about Commit? As I understood some time ago when looking at that Commit should only be called once anything has changed WRT direct composition setup (e. g., transforms, surface configuration). Once direct composition is set up, I think one can only call Present on linked swapchains and that is supposed to be composited according to current configuration. IIRC that is how Webview2 worked.
That's what I am seeing in the Corgi Warlock log. Every Present() is followed by a Commit().
This game might be calling this excessively. [1] only says that it should be called if there are command pending on [composition] device. I am almost sure swapchain Present works without this Commit().
1. https://learn.microsoft.com/es-es/windows/win32/api/dcomp/nf-dcomp-idcomposi...
I am almost sure swapchain Present works without this Commit().
Looks like you're right. Commit() should only be called when modifying the visual tree, not after every frame.
From https://learn.microsoft.com/en-us/windows/win32/directcomp/architecture-and-...
The requirement to call Commit is similar to the concept of a "frame" except that, because the composition engine runs asynchronously, it can present several different frames between calls to Commit. In DirectComposition, a frame is a single iteration of the composition engine, and the interval spent by an application between two calls to Commit is called a batch.
There is a dedicated thread for composition, which I didn't implement. So I think now there must be a thread that waits for a vertical blank, then does a composition, and finally present the composition content to the screen.
I will refine my Commit() patches. The DXGI changes should be good.