uiautomationcore: Initialize VARIANT in test_uia_prov_from_acc_properties() (Coverity).
[wine.git] / dlls / dxgi / tests / dxgi.c
blob1874bcc08343a42e2fd1d8b00e7854f1395bb533
1 /*
2 * Copyright 2008 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <assert.h>
20 #include "ntstatus.h"
21 #define WIN32_NO_STATUS
22 #define COBJMACROS
23 #include "initguid.h"
24 #include "dxgi1_6.h"
25 #include "d3d11.h"
26 #include "d3d12.h"
27 #include "d3d12sdklayers.h"
28 #include "winternl.h"
29 #include "ddk/d3dkmthk.h"
30 #include "wine/heap.h"
31 #include "wine/test.h"
33 enum frame_latency
35 DEFAULT_FRAME_LATENCY = 3,
36 MAX_FRAME_LATENCY = 16,
39 static DEVMODEW registry_mode;
41 static HRESULT (WINAPI *pCreateDXGIFactory1)(REFIID iid, void **factory);
42 static HRESULT (WINAPI *pCreateDXGIFactory2)(UINT flags, REFIID iid, void **factory);
44 static NTSTATUS (WINAPI *pD3DKMTCheckVidPnExclusiveOwnership)(const D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP *desc);
45 static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER *desc);
46 static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *desc);
48 static HRESULT (WINAPI *pD3D11CreateDevice)(IDXGIAdapter *adapter, D3D_DRIVER_TYPE driver_type, HMODULE swrast, UINT flags,
49 const D3D_FEATURE_LEVEL *feature_levels, UINT levels, UINT sdk_version, ID3D11Device **device_out,
50 D3D_FEATURE_LEVEL *obtained_feature_level, ID3D11DeviceContext **immediate_context);
52 static PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice;
53 static PFN_D3D12_GET_DEBUG_INTERFACE pD3D12GetDebugInterface;
55 static unsigned int use_adapter_idx;
56 static BOOL use_warp_adapter;
57 static BOOL use_mt = TRUE;
59 static struct test_entry
61 void (*test)(void);
62 } *mt_tests;
63 size_t mt_tests_size, mt_test_count;
65 static void queue_test(void (*test)(void))
67 if (mt_test_count >= mt_tests_size)
69 mt_tests_size = max(16, mt_tests_size * 2);
70 mt_tests = heap_realloc(mt_tests, mt_tests_size * sizeof(*mt_tests));
72 mt_tests[mt_test_count++].test = test;
75 static DWORD WINAPI thread_func(void *ctx)
77 LONG *i = ctx, j;
79 while (*i < mt_test_count)
81 j = *i;
82 if (InterlockedCompareExchange(i, j + 1, j) == j)
83 mt_tests[j].test();
86 return 0;
89 static void run_queued_tests(void)
91 unsigned int thread_count, i;
92 HANDLE *threads;
93 SYSTEM_INFO si;
94 LONG test_idx;
96 if (!use_mt)
98 for (i = 0; i < mt_test_count; ++i)
100 mt_tests[i].test();
103 return;
106 GetSystemInfo(&si);
107 thread_count = si.dwNumberOfProcessors;
108 threads = heap_calloc(thread_count, sizeof(*threads));
109 for (i = 0, test_idx = 0; i < thread_count; ++i)
111 threads[i] = CreateThread(NULL, 0, thread_func, &test_idx, 0, NULL);
112 ok(!!threads[i], "Failed to create thread %u.\n", i);
114 WaitForMultipleObjects(thread_count, threads, TRUE, INFINITE);
115 for (i = 0; i < thread_count; ++i)
117 CloseHandle(threads[i]);
119 heap_free(threads);
122 static ULONG get_refcount(void *iface)
124 IUnknown *unknown = iface;
125 IUnknown_AddRef(unknown);
126 return IUnknown_Release(unknown);
129 static void get_virtual_rect(RECT *rect)
131 rect->left = GetSystemMetrics(SM_XVIRTUALSCREEN);
132 rect->top = GetSystemMetrics(SM_YVIRTUALSCREEN);
133 rect->right = rect->left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
134 rect->bottom = rect->top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
137 static BOOL equal_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
139 return mode1->dmPosition.x == mode2->dmPosition.x
140 && mode1->dmPosition.y == mode2->dmPosition.y
141 && mode1->dmPelsWidth == mode2->dmPelsWidth
142 && mode1->dmPelsHeight == mode2->dmPelsHeight;
145 /* Free original_modes after finished using it */
146 static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
148 unsigned int number, size = 2, count = 0, index = 0;
149 DISPLAY_DEVICEW display_device;
150 DEVMODEW *modes, *tmp;
152 if (!(modes = heap_alloc(size * sizeof(*modes))))
153 return FALSE;
155 display_device.cb = sizeof(display_device);
156 while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
158 /* Skip software devices */
159 if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
160 continue;
162 if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
163 continue;
165 if (count >= size)
167 size *= 2;
168 if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
170 heap_free(modes);
171 return FALSE;
173 modes = tmp;
176 memset(&modes[count], 0, sizeof(modes[count]));
177 modes[count].dmSize = sizeof(modes[count]);
178 if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
180 heap_free(modes);
181 return FALSE;
184 lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
187 *original_modes = modes;
188 *display_count = count;
189 return TRUE;
192 static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
194 unsigned int index;
195 LONG ret;
197 for (index = 0; index < count; ++index)
199 ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
200 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
201 if (ret != DISP_CHANGE_SUCCESSFUL)
202 return FALSE;
204 ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
205 return ret == DISP_CHANGE_SUCCESSFUL;
208 /* try to make sure pending X events have been processed before continuing */
209 static void flush_events(void)
211 int diff = 200;
212 DWORD time;
213 MSG msg;
215 time = GetTickCount() + diff;
216 while (diff > 0)
218 if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT)
219 break;
220 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
221 DispatchMessageA(&msg);
222 diff = time - GetTickCount();
226 #define check_interface(a, b, c, d) check_interface_(__LINE__, a, b, c, d)
227 static HRESULT check_interface_(unsigned int line, void *iface, REFIID iid,
228 BOOL supported, BOOL is_broken)
230 HRESULT hr, expected_hr, broken_hr;
231 IUnknown *unknown = iface, *out;
233 if (supported)
235 expected_hr = S_OK;
236 broken_hr = E_NOINTERFACE;
238 else
240 expected_hr = E_NOINTERFACE;
241 broken_hr = S_OK;
244 out = (IUnknown *)0xdeadbeef;
245 hr = IUnknown_QueryInterface(unknown, iid, (void **)&out);
246 ok_(__FILE__, line)(hr == expected_hr || broken(is_broken && hr == broken_hr),
247 "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
248 if (SUCCEEDED(hr))
249 IUnknown_Release(out);
250 else
251 ok_(__FILE__, line)(!out, "Got unexpected pointer %p.\n", out);
252 return hr;
255 static BOOL is_flip_model(DXGI_SWAP_EFFECT swap_effect)
257 return swap_effect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
258 || swap_effect == DXGI_SWAP_EFFECT_FLIP_DISCARD;
261 static unsigned int check_multisample_quality_levels(IDXGIDevice *dxgi_device,
262 DXGI_FORMAT format, unsigned int sample_count)
264 ID3D10Device *device;
265 unsigned int levels;
266 HRESULT hr;
268 hr = IDXGIDevice_QueryInterface(dxgi_device, &IID_ID3D10Device, (void **)&device);
269 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
270 hr = ID3D10Device_CheckMultisampleQualityLevels(device, format, sample_count, &levels);
271 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
272 ID3D10Device_Release(device);
274 return levels;
277 #define MODE_DESC_IGNORE_RESOLUTION 0x00000001u
278 #define MODE_DESC_IGNORE_REFRESH_RATE 0x00000002u
279 #define MODE_DESC_IGNORE_FORMAT 0x00000004u
280 #define MODE_DESC_IGNORE_SCANLINE_ORDERING 0x00000008u
281 #define MODE_DESC_IGNORE_SCALING 0x00000010u
282 #define MODE_DESC_IGNORE_EXACT_RESOLUTION 0x00000020u
284 #define MODE_DESC_CHECK_RESOLUTION (~MODE_DESC_IGNORE_RESOLUTION & ~MODE_DESC_IGNORE_EXACT_RESOLUTION)
285 #define MODE_DESC_CHECK_FORMAT (~MODE_DESC_IGNORE_FORMAT)
287 #define check_mode_desc(a, b, c) check_mode_desc_(__LINE__, a, b, c)
288 static void check_mode_desc_(unsigned int line, const DXGI_MODE_DESC *desc,
289 const DXGI_MODE_DESC *expected_desc, unsigned int ignore_flags)
291 if (!(ignore_flags & MODE_DESC_IGNORE_RESOLUTION))
293 if (ignore_flags & MODE_DESC_IGNORE_EXACT_RESOLUTION)
294 ok_(__FILE__, line)(desc->Width * desc->Height ==
295 expected_desc->Width * expected_desc->Height,
296 "Got resolution %ux%u, expected %ux%u.\n",
297 desc->Width, desc->Height, expected_desc->Width, expected_desc->Height);
298 else
299 ok_(__FILE__, line)(desc->Width == expected_desc->Width &&
300 desc->Height == expected_desc->Height,
301 "Got resolution %ux%u, expected %ux%u.\n",
302 desc->Width, desc->Height, expected_desc->Width, expected_desc->Height);
304 if (!(ignore_flags & MODE_DESC_IGNORE_REFRESH_RATE))
306 ok_(__FILE__, line)(desc->RefreshRate.Numerator == expected_desc->RefreshRate.Numerator
307 && desc->RefreshRate.Denominator == expected_desc->RefreshRate.Denominator,
308 "Got refresh rate %u / %u, expected %u / %u.\n",
309 desc->RefreshRate.Numerator, desc->RefreshRate.Denominator,
310 expected_desc->RefreshRate.Denominator, expected_desc->RefreshRate.Denominator);
312 if (!(ignore_flags & MODE_DESC_IGNORE_FORMAT))
314 ok_(__FILE__, line)(desc->Format == expected_desc->Format,
315 "Got format %#x, expected %#x.\n", desc->Format, expected_desc->Format);
317 if (!(ignore_flags & MODE_DESC_IGNORE_SCANLINE_ORDERING))
319 ok_(__FILE__, line)(desc->ScanlineOrdering == expected_desc->ScanlineOrdering,
320 "Got scanline ordering %#x, expected %#x.\n",
321 desc->ScanlineOrdering, expected_desc->ScanlineOrdering);
323 if (!(ignore_flags & MODE_DESC_IGNORE_SCALING))
325 ok_(__FILE__, line)(desc->Scaling == expected_desc->Scaling,
326 "Got scaling %#x, expected %#x.\n",
327 desc->Scaling, expected_desc->Scaling);
331 static BOOL equal_luid(LUID a, LUID b)
333 return a.LowPart == b.LowPart && a.HighPart == b.HighPart;
336 #define check_adapter_desc(a, b) check_adapter_desc_(__LINE__, a, b)
337 static void check_adapter_desc_(unsigned int line, const DXGI_ADAPTER_DESC *desc,
338 const struct DXGI_ADAPTER_DESC *expected_desc)
340 ok_(__FILE__, line)(!lstrcmpW(desc->Description, expected_desc->Description),
341 "Got description %s, expected %s.\n",
342 wine_dbgstr_w(desc->Description), wine_dbgstr_w(expected_desc->Description));
343 ok_(__FILE__, line)(desc->VendorId == expected_desc->VendorId,
344 "Got vendor id %04x, expected %04x.\n",
345 desc->VendorId, expected_desc->VendorId);
346 ok_(__FILE__, line)(desc->DeviceId == expected_desc->DeviceId,
347 "Got device id %04x, expected %04x.\n",
348 desc->DeviceId, expected_desc->DeviceId);
349 ok_(__FILE__, line)(desc->SubSysId == expected_desc->SubSysId,
350 "Got subsys id %04x, expected %04x.\n",
351 desc->SubSysId, expected_desc->SubSysId);
352 ok_(__FILE__, line)(desc->Revision == expected_desc->Revision,
353 "Got revision %02x, expected %02x.\n",
354 desc->Revision, expected_desc->Revision);
355 ok_(__FILE__, line)(desc->DedicatedVideoMemory == expected_desc->DedicatedVideoMemory,
356 "Got dedicated video memory %Iu, expected %Iu.\n",
357 desc->DedicatedVideoMemory, expected_desc->DedicatedVideoMemory);
358 ok_(__FILE__, line)(desc->DedicatedSystemMemory == expected_desc->DedicatedSystemMemory,
359 "Got dedicated system memory %Iu, expected %Iu.\n",
360 desc->DedicatedSystemMemory, expected_desc->DedicatedSystemMemory);
361 ok_(__FILE__, line)(desc->SharedSystemMemory == expected_desc->SharedSystemMemory,
362 "Got shared system memory %Iu, expected %Iu.\n",
363 desc->SharedSystemMemory, expected_desc->SharedSystemMemory);
364 ok_(__FILE__, line)(equal_luid(desc->AdapterLuid, expected_desc->AdapterLuid),
365 "Got LUID %08lx:%08lx, expected %08lx:%08lx.\n",
366 desc->AdapterLuid.HighPart, desc->AdapterLuid.LowPart,
367 expected_desc->AdapterLuid.HighPart, expected_desc->AdapterLuid.LowPart);
370 #define check_output_desc(a, b) check_output_desc_(__LINE__, a, b)
371 static void check_output_desc_(unsigned int line, const DXGI_OUTPUT_DESC *desc,
372 const struct DXGI_OUTPUT_DESC *expected_desc)
374 ok_(__FILE__, line)(!lstrcmpW(desc->DeviceName, expected_desc->DeviceName),
375 "Got unexpected device name %s, expected %s.\n",
376 wine_dbgstr_w(desc->DeviceName), wine_dbgstr_w(expected_desc->DeviceName));
377 ok_(__FILE__, line)(EqualRect(&desc->DesktopCoordinates, &expected_desc->DesktopCoordinates),
378 "Got unexpected desktop coordinates %s, expected %s.\n",
379 wine_dbgstr_rect(&desc->DesktopCoordinates),
380 wine_dbgstr_rect(&expected_desc->DesktopCoordinates));
383 #define check_output_equal(a, b) check_output_equal_(__LINE__, a, b)
384 static void check_output_equal_(unsigned int line, IDXGIOutput *output1, IDXGIOutput *output2)
386 DXGI_OUTPUT_DESC desc1, desc2;
387 HRESULT hr;
389 hr = IDXGIOutput_GetDesc(output1, &desc1);
390 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
391 hr = IDXGIOutput_GetDesc(output2, &desc2);
392 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
393 check_output_desc_(line, &desc1, &desc2);
396 static BOOL output_belongs_to_adapter(IDXGIOutput *output, IDXGIAdapter *adapter)
398 DXGI_OUTPUT_DESC output_desc, desc;
399 unsigned int output_idx;
400 IDXGIOutput *o;
401 HRESULT hr;
403 hr = IDXGIOutput_GetDesc(output, &output_desc);
404 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
406 for (output_idx = 0; IDXGIAdapter_EnumOutputs(adapter, output_idx, &o) != DXGI_ERROR_NOT_FOUND; ++output_idx)
408 hr = IDXGIOutput_GetDesc(o, &desc);
409 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
410 IDXGIOutput_Release(o);
412 if (!lstrcmpW(desc.DeviceName, output_desc.DeviceName)
413 && EqualRect(&desc.DesktopCoordinates, &output_desc.DesktopCoordinates))
414 return TRUE;
417 return FALSE;
420 struct fullscreen_state
422 DWORD style;
423 DWORD exstyle;
424 RECT window_rect;
425 RECT client_rect;
426 HMONITOR monitor;
427 RECT monitor_rect;
430 struct swapchain_fullscreen_state
432 struct fullscreen_state fullscreen_state;
433 BOOL fullscreen;
434 IDXGIOutput *target;
437 #define capture_fullscreen_state(a, b) capture_fullscreen_state_(__LINE__, a, b)
438 static void capture_fullscreen_state_(unsigned int line, struct fullscreen_state *state, HWND window)
440 MONITORINFOEXW monitor_info;
441 BOOL ret;
443 state->style = GetWindowLongA(window, GWL_STYLE);
444 state->exstyle = GetWindowLongA(window, GWL_EXSTYLE);
446 ret = GetWindowRect(window, &state->window_rect);
447 ok_(__FILE__, line)(ret, "GetWindowRect failed.\n");
448 ret = GetClientRect(window, &state->client_rect);
449 ok_(__FILE__, line)(ret, "GetClientRect failed.\n");
451 state->monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
452 ok_(__FILE__, line)(!!state->monitor, "Failed to get monitor from window.\n");
454 monitor_info.cbSize = sizeof(monitor_info);
455 ret = GetMonitorInfoW(state->monitor, (MONITORINFO *)&monitor_info);
456 ok_(__FILE__, line)(ret, "Failed to get monitor info.\n");
457 state->monitor_rect = monitor_info.rcMonitor;
460 static void check_fullscreen_state_(unsigned int line, const struct fullscreen_state *state,
461 const struct fullscreen_state *expected_state, BOOL windowed)
463 todo_wine_if(!windowed)
464 ok_(__FILE__, line)((state->style & ~WS_VISIBLE) == (expected_state->style & ~WS_VISIBLE),
465 "Got style %#lx, expected %#lx.\n",
466 state->style & ~(DWORD)WS_VISIBLE, expected_state->style & ~(DWORD)WS_VISIBLE);
467 ok_(__FILE__, line)((state->exstyle & ~WS_EX_TOPMOST) == (expected_state->exstyle & ~WS_EX_TOPMOST),
468 "Got exstyle %#lx, expected %#lx.\n",
469 state->exstyle & ~(DWORD)WS_EX_TOPMOST, expected_state->exstyle & ~(DWORD)WS_EX_TOPMOST);
470 ok_(__FILE__, line)(EqualRect(&state->window_rect, &expected_state->window_rect),
471 "Got window rect %s, expected %s.\n",
472 wine_dbgstr_rect(&state->window_rect), wine_dbgstr_rect(&expected_state->window_rect));
473 ok_(__FILE__, line)(EqualRect(&state->client_rect, &expected_state->client_rect),
474 "Got client rect %s, expected %s.\n",
475 wine_dbgstr_rect(&state->client_rect), wine_dbgstr_rect(&expected_state->client_rect));
476 ok_(__FILE__, line)(state->monitor == expected_state->monitor,
477 "Got monitor %p, expected %p.\n",
478 state->monitor, expected_state->monitor);
479 ok_(__FILE__, line)(EqualRect(&state->monitor_rect, &expected_state->monitor_rect),
480 "Got monitor rect %s, expected %s.\n",
481 wine_dbgstr_rect(&state->monitor_rect), wine_dbgstr_rect(&expected_state->monitor_rect));
484 #define check_window_fullscreen_state(a, b) check_window_fullscreen_state_(__LINE__, a, b, TRUE)
485 static void check_window_fullscreen_state_(unsigned int line, HWND window,
486 const struct fullscreen_state *expected_state, BOOL windowed)
488 struct fullscreen_state current_state;
489 capture_fullscreen_state_(line, &current_state, window);
490 check_fullscreen_state_(line, &current_state, expected_state, windowed);
493 #define check_swapchain_fullscreen_state(a, b) check_swapchain_fullscreen_state_(__LINE__, a, b)
494 static void check_swapchain_fullscreen_state_(unsigned int line, IDXGISwapChain *swapchain,
495 const struct swapchain_fullscreen_state *expected_state)
497 IDXGIOutput *containing_output, *target;
498 DXGI_SWAP_CHAIN_DESC swapchain_desc;
499 BOOL fullscreen;
500 HRESULT hr;
502 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
503 ok_(__FILE__, line)(hr == S_OK, "Failed to get swapchain desc, hr %#lx.\n", hr);
504 check_window_fullscreen_state_(line, swapchain_desc.OutputWindow,
505 &expected_state->fullscreen_state, swapchain_desc.Windowed);
507 ok_(__FILE__, line)(swapchain_desc.Windowed == !expected_state->fullscreen,
508 "Got windowed %#x, expected %#x.\n",
509 swapchain_desc.Windowed, !expected_state->fullscreen);
511 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
512 ok_(__FILE__, line)(hr == S_OK, "Failed to get fullscreen state, hr %#lx.\n", hr);
513 ok_(__FILE__, line)(fullscreen == expected_state->fullscreen, "Got fullscreen %#x, expected %#x.\n",
514 fullscreen, expected_state->fullscreen);
516 if (!swapchain_desc.Windowed && expected_state->fullscreen)
518 IDXGIAdapter *adapter;
520 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
521 ok_(__FILE__, line)(hr == S_OK, "Failed to get containing output, hr %#lx.\n", hr);
523 hr = IDXGIOutput_GetParent(containing_output, &IID_IDXGIAdapter, (void **)&adapter);
524 ok_(__FILE__, line)(hr == S_OK, "Failed to get parent, hr %#lx.\n", hr);
526 check_output_equal_(line, target, expected_state->target);
527 ok_(__FILE__, line)(target == containing_output, "Got target %p, expected %p.\n",
528 target, containing_output);
529 ok_(__FILE__, line)(output_belongs_to_adapter(target, adapter),
530 "Output %p doesn't belong to adapter %p.\n",
531 target, adapter);
533 IDXGIOutput_Release(target);
534 IDXGIOutput_Release(containing_output);
535 IDXGIAdapter_Release(adapter);
537 else
539 ok_(__FILE__, line)(!target, "Got unexpected target %p.\n", target);
543 #define compute_expected_swapchain_fullscreen_state_after_fullscreen_change(a, b, c, d, e, f) \
544 compute_expected_swapchain_fullscreen_state_after_fullscreen_change_(__LINE__, a, b, c, d, e, f)
545 static void compute_expected_swapchain_fullscreen_state_after_fullscreen_change_(unsigned int line,
546 struct swapchain_fullscreen_state *state, const DXGI_SWAP_CHAIN_DESC *swapchain_desc,
547 const RECT *old_monitor_rect, unsigned int new_width, unsigned int new_height, IDXGIOutput *target)
549 if (!new_width && !new_height)
551 RECT client_rect;
552 GetClientRect(swapchain_desc->OutputWindow, &client_rect);
553 new_width = client_rect.right - client_rect.left;
554 new_height = client_rect.bottom - client_rect.top;
557 if (target)
559 DXGI_MODE_DESC mode_desc = swapchain_desc->BufferDesc;
560 HRESULT hr;
562 mode_desc.Width = new_width;
563 mode_desc.Height = new_height;
564 hr = IDXGIOutput_FindClosestMatchingMode(target, &mode_desc, &mode_desc, NULL);
565 ok_(__FILE__, line)(SUCCEEDED(hr), "FindClosestMatchingMode failed, hr %#lx.\n", hr);
566 new_width = mode_desc.Width;
567 new_height = mode_desc.Height;
570 state->fullscreen_state.style &= WS_VISIBLE | WS_CLIPSIBLINGS;
571 state->fullscreen_state.exstyle &= WS_EX_TOPMOST;
573 state->fullscreen = TRUE;
574 if (swapchain_desc->Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)
576 unsigned int new_x = (old_monitor_rect->left >= 0)
577 ? old_monitor_rect->left : old_monitor_rect->right - new_width;
578 unsigned new_y = (old_monitor_rect->top >= 0)
579 ? old_monitor_rect->top : old_monitor_rect->bottom - new_height;
580 RECT new_monitor_rect = {0, 0, new_width, new_height};
581 OffsetRect(&new_monitor_rect, new_x, new_y);
583 SetRect(&state->fullscreen_state.client_rect, 0, 0, new_width, new_height);
584 state->fullscreen_state.monitor_rect = new_monitor_rect;
585 state->fullscreen_state.window_rect = new_monitor_rect;
587 if (target)
588 state->target = target;
590 else
592 state->fullscreen_state.window_rect = *old_monitor_rect;
593 SetRect(&state->fullscreen_state.client_rect, 0, 0,
594 old_monitor_rect->right - old_monitor_rect->left,
595 old_monitor_rect->bottom - old_monitor_rect->top);
599 #define wait_fullscreen_state(a, b, c) wait_fullscreen_state_(__LINE__, a, b, c)
600 static void wait_fullscreen_state_(unsigned int line, IDXGISwapChain *swapchain, BOOL expected, BOOL todo)
602 static const unsigned int wait_timeout = 2000;
603 static const unsigned int wait_step = 100;
604 unsigned int total_time = 0;
605 HRESULT hr;
606 BOOL state;
608 while (total_time < wait_timeout)
610 state = !expected;
611 if (FAILED(hr = IDXGISwapChain_GetFullscreenState(swapchain, &state, NULL)))
612 break;
613 if (state == expected)
614 break;
615 Sleep(wait_step);
616 total_time += wait_step;
618 ok_(__FILE__, line)(hr == S_OK, "Failed to get fullscreen state, hr %#lx.\n", hr);
619 todo_wine_if(todo) ok_(__FILE__, line)(state == expected,
620 "Got unexpected state %#x, expected %#x.\n", state, expected);
623 /* VidPN exclusive ownership doesn't change immediately.
624 * This helper is used to wait for the expected status */
625 #define get_expected_vidpn_exclusive_ownership(a, b) \
626 get_expected_vidpn_exclusive_ownership_(__LINE__, a, b)
627 static NTSTATUS get_expected_vidpn_exclusive_ownership_(unsigned int line,
628 const D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP *desc, NTSTATUS expected)
630 static const unsigned int wait_timeout = 2000;
631 static const unsigned int wait_step = 100;
632 unsigned int total_time = 0;
633 NTSTATUS status;
635 while (total_time < wait_timeout)
637 status = pD3DKMTCheckVidPnExclusiveOwnership(desc);
638 if (status == expected)
639 break;
640 Sleep(wait_step);
641 total_time += wait_step;
643 return status;
646 static HWND create_window(void)
648 RECT r = {0, 0, 640, 480};
650 AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE);
652 return CreateWindowA("static", "dxgi_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
653 0, 0, r.right - r.left, r.bottom - r.top, NULL, NULL, NULL, NULL);
656 static IDXGIAdapter *create_adapter(void)
658 IDXGIFactory4 *factory4;
659 IDXGIFactory *factory;
660 IDXGIAdapter *adapter;
661 HRESULT hr;
663 if (!use_warp_adapter && !use_adapter_idx)
664 return NULL;
666 if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory)))
668 trace("Failed to create IDXGIFactory, hr %#lx.\n", hr);
669 return NULL;
672 adapter = NULL;
673 if (use_warp_adapter)
675 if (SUCCEEDED(hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void **)&factory4)))
677 hr = IDXGIFactory4_EnumWarpAdapter(factory4, &IID_IDXGIAdapter, (void **)&adapter);
678 IDXGIFactory4_Release(factory4);
680 else
682 trace("Failed to get IDXGIFactory4, hr %#lx.\n", hr);
685 else
687 hr = IDXGIFactory_EnumAdapters(factory, use_adapter_idx, &adapter);
689 IDXGIFactory_Release(factory);
690 if (FAILED(hr))
691 trace("Failed to get adapter, hr %#lx.\n", hr);
692 return adapter;
695 static IDXGIDevice *create_device(unsigned int flags)
697 IDXGIDevice *dxgi_device;
698 ID3D10Device1 *device;
699 IDXGIAdapter *adapter;
700 HRESULT hr;
702 adapter = create_adapter();
703 hr = D3D10CreateDevice1(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL,
704 flags, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device);
705 if (adapter)
706 IDXGIAdapter_Release(adapter);
707 if (SUCCEEDED(hr))
708 goto success;
710 if (SUCCEEDED(D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_WARP, NULL,
711 flags, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device)))
712 goto success;
713 if (SUCCEEDED(D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_REFERENCE, NULL,
714 flags, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device)))
715 goto success;
717 return NULL;
719 success:
720 hr = ID3D10Device1_QueryInterface(device, &IID_IDXGIDevice, (void **)&dxgi_device);
721 ok(SUCCEEDED(hr), "Created device does not implement IDXGIDevice\n");
722 ID3D10Device1_Release(device);
724 return dxgi_device;
727 static IDXGIDevice *create_d3d11_device(void)
729 static const D3D_FEATURE_LEVEL feature_level[] =
731 D3D_FEATURE_LEVEL_11_0,
733 unsigned int feature_level_count = ARRAY_SIZE(feature_level);
734 IDXGIDevice *device = NULL;
735 ID3D11Device *d3d_device;
736 HRESULT hr;
738 if (!pD3D11CreateDevice)
739 return NULL;
741 hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, feature_level, feature_level_count,
742 D3D11_SDK_VERSION, &d3d_device, NULL, NULL);
743 if (FAILED(hr))
744 hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_WARP, NULL, 0, feature_level, feature_level_count,
745 D3D11_SDK_VERSION, &d3d_device, NULL, NULL);
746 if (FAILED(hr))
747 hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, 0, feature_level, feature_level_count,
748 D3D11_SDK_VERSION, &d3d_device, NULL, NULL);
750 if (SUCCEEDED(hr))
752 hr = ID3D11Device_QueryInterface(d3d_device, &IID_IDXGIDevice, (void **)&device);
753 ok(SUCCEEDED(hr), "Created device does not implement IDXGIDevice.\n");
754 ID3D11Device_Release(d3d_device);
757 return device;
760 static ID3D12Device *create_d3d12_device(void)
762 IDXGIAdapter *adapter;
763 ID3D12Device *device;
764 HRESULT hr;
766 if (!pD3D12CreateDevice)
767 return NULL;
769 adapter = create_adapter();
770 hr = pD3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&device);
771 if (adapter)
772 IDXGIAdapter_Release(adapter);
773 if (FAILED(hr))
774 return NULL;
776 return device;
779 static ID3D12CommandQueue *create_d3d12_direct_queue(ID3D12Device *device)
781 D3D12_COMMAND_QUEUE_DESC command_queue_desc;
782 ID3D12CommandQueue *queue;
783 HRESULT hr;
785 command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
786 command_queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
787 command_queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
788 command_queue_desc.NodeMask = 0;
789 hr = ID3D12Device_CreateCommandQueue(device, &command_queue_desc,
790 &IID_ID3D12CommandQueue, (void **)&queue);
791 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
792 return queue;
795 static HRESULT wait_for_fence(ID3D12Fence *fence, UINT64 value)
797 HANDLE event;
798 HRESULT hr;
799 DWORD ret;
801 if (ID3D12Fence_GetCompletedValue(fence) >= value)
802 return S_OK;
804 if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL)))
805 return E_FAIL;
807 if (FAILED(hr = ID3D12Fence_SetEventOnCompletion(fence, value, event)))
809 CloseHandle(event);
810 return hr;
813 ret = WaitForSingleObject(event, INFINITE);
814 CloseHandle(event);
815 return ret == WAIT_OBJECT_0 ? S_OK : E_FAIL;
818 #define wait_queue_idle(a, b) wait_queue_idle_(__LINE__, a, b)
819 static void wait_queue_idle_(unsigned int line, ID3D12Device *device, ID3D12CommandQueue *queue)
821 ID3D12Fence *fence;
822 HRESULT hr;
824 hr = ID3D12Device_CreateFence(device, 0, D3D12_FENCE_FLAG_NONE,
825 &IID_ID3D12Fence, (void **)&fence);
826 ok_(__FILE__, line)(hr == S_OK, "Failed to create fence, hr %#lx.\n", hr);
828 hr = ID3D12CommandQueue_Signal(queue, fence, 1);
829 ok_(__FILE__, line)(hr == S_OK, "Failed to signal fence, hr %#lx.\n", hr);
830 hr = wait_for_fence(fence, 1);
831 ok_(__FILE__, line)(hr == S_OK, "Failed to wait for fence, hr %#lx.\n", hr);
833 ID3D12Fence_Release(fence);
836 #define wait_device_idle(a) wait_device_idle_(__LINE__, a)
837 static void wait_device_idle_(unsigned int line, IUnknown *device)
839 ID3D12Device *d3d12_device;
840 ID3D12CommandQueue *queue;
841 HRESULT hr;
843 hr = IUnknown_QueryInterface(device, &IID_ID3D12CommandQueue, (void **)&queue);
844 if (hr != S_OK)
845 return;
847 hr = ID3D12CommandQueue_GetDevice(queue, &IID_ID3D12Device, (void **)&d3d12_device);
848 ok_(__FILE__, line)(hr == S_OK, "Failed to get d3d12 device, hr %#lx.\n", hr);
850 wait_queue_idle_(line, d3d12_device, queue);
852 ID3D12CommandQueue_Release(queue);
853 ID3D12Device_Release(d3d12_device);
856 #define get_factory(a, b, c) get_factory_(__LINE__, a, b, c)
857 static void get_factory_(unsigned int line, IUnknown *device, BOOL is_d3d12, IDXGIFactory **factory)
859 IDXGIDevice *dxgi_device;
860 IDXGIAdapter *adapter;
861 HRESULT hr;
863 if (is_d3d12)
865 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)factory);
866 ok_(__FILE__, line)(hr == S_OK, "Failed to create factory, hr %#lx.\n", hr);
868 else
870 dxgi_device = (IDXGIDevice *)device;
871 hr = IDXGIDevice_GetAdapter(dxgi_device, &adapter);
872 ok_(__FILE__, line)(hr == S_OK, "Failed to get adapter, hr %#lx.\n", hr);
873 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)factory);
874 ok_(__FILE__, line)(hr == S_OK, "Failed to get parent, hr %#lx.\n", hr);
875 IDXGIAdapter_Release(adapter);
879 #define get_adapter(a, b) get_adapter_(__LINE__, a, b)
880 static IDXGIAdapter *get_adapter_(unsigned int line, IUnknown *device, BOOL is_d3d12)
882 IDXGIAdapter *adapter = NULL;
883 ID3D12Device *d3d12_device;
884 IDXGIFactory4 *factory4;
885 IDXGIFactory *factory;
886 HRESULT hr;
887 LUID luid;
889 if (is_d3d12)
891 get_factory_(line, device, is_d3d12, &factory);
892 hr = ID3D12CommandQueue_GetDevice((ID3D12CommandQueue *)device, &IID_ID3D12Device, (void **)&d3d12_device);
893 ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
894 luid = ID3D12Device_GetAdapterLuid(d3d12_device);
895 ID3D12Device_Release(d3d12_device);
896 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void **)&factory4);
897 ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
898 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, luid, &IID_IDXGIAdapter, (void **)&adapter);
899 IDXGIFactory4_Release(factory4);
900 IDXGIFactory_Release(factory);
902 else
904 hr = IDXGIDevice_GetAdapter((IDXGIDevice *)device, &adapter);
905 ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
908 return adapter;
911 #define create_swapchain(a, b, c) create_swapchain_(__LINE__, a, b, c)
912 static IDXGISwapChain *create_swapchain_(unsigned int line, IUnknown *device, BOOL is_d3d12, HWND window)
914 DXGI_SWAP_CHAIN_DESC desc;
915 IDXGISwapChain *swapchain;
916 IDXGIFactory *factory;
917 HRESULT hr;
919 desc.BufferDesc.Width = 640;
920 desc.BufferDesc.Height = 480;
921 desc.BufferDesc.RefreshRate.Numerator = 60;
922 desc.BufferDesc.RefreshRate.Denominator = 1;
923 desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
924 desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
925 desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
926 desc.SampleDesc.Count = 1;
927 desc.SampleDesc.Quality = 0;
928 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
929 desc.BufferCount = is_d3d12 ? 2 : 1;
930 desc.OutputWindow = window;
931 desc.Windowed = TRUE;
932 desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
933 desc.Flags = 0;
935 get_factory(device, is_d3d12, &factory);
936 hr = IDXGIFactory_CreateSwapChain(factory, device, &desc, &swapchain);
937 ok_(__FILE__, line)(hr == S_OK, "Failed to create swapchain, hr %#lx.\n", hr);
938 IDXGIFactory_Release(factory);
940 return swapchain;
943 static void test_adapter_desc(void)
945 DXGI_ADAPTER_DESC1 desc1;
946 IDXGIAdapter1 *adapter1;
947 DXGI_ADAPTER_DESC desc;
948 IDXGIAdapter *adapter;
949 IDXGIDevice *device;
950 ULONG refcount;
951 HRESULT hr;
953 if (!(device = create_device(0)))
955 skip("Failed to create device.\n");
956 return;
959 hr = IDXGIDevice_GetAdapter(device, &adapter);
960 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
962 hr = IDXGIAdapter_GetDesc(adapter, NULL);
963 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
965 hr = IDXGIAdapter_GetDesc(adapter, &desc);
966 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
968 trace("%s.\n", wine_dbgstr_w(desc.Description));
969 trace("%04x: %04x:%04x (rev %02x).\n",
970 desc.SubSysId, desc.VendorId, desc.DeviceId, desc.Revision);
971 trace("Dedicated video memory: %Iu (%Iu MB).\n",
972 desc.DedicatedVideoMemory, desc.DedicatedVideoMemory / (1024 * 1024));
973 trace("Dedicated system memory: %Iu (%Iu MB).\n",
974 desc.DedicatedSystemMemory, desc.DedicatedSystemMemory / (1024 * 1024));
975 trace("Shared system memory: %Iu (%Iu MB).\n",
976 desc.SharedSystemMemory, desc.SharedSystemMemory / (1024 * 1024));
977 trace("LUID: %08lx:%08lx.\n", desc.AdapterLuid.HighPart, desc.AdapterLuid.LowPart);
979 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter1, (void **)&adapter1);
980 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Got unexpected hr %#lx.\n", hr);
981 if (hr == E_NOINTERFACE)
982 goto done;
984 hr = IDXGIAdapter1_GetDesc1(adapter1, &desc1);
985 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
987 ok(!lstrcmpW(desc.Description, desc1.Description),
988 "Got unexpected description %s.\n", wine_dbgstr_w(desc1.Description));
989 ok(desc1.VendorId == desc.VendorId, "Got unexpected vendor ID %04x.\n", desc1.VendorId);
990 ok(desc1.DeviceId == desc.DeviceId, "Got unexpected device ID %04x.\n", desc1.DeviceId);
991 ok(desc1.SubSysId == desc.SubSysId, "Got unexpected sub system ID %04x.\n", desc1.SubSysId);
992 ok(desc1.Revision == desc.Revision, "Got unexpected revision %02x.\n", desc1.Revision);
993 ok(desc1.DedicatedVideoMemory == desc.DedicatedVideoMemory,
994 "Got unexpected dedicated video memory %Iu.\n", desc1.DedicatedVideoMemory);
995 ok(desc1.DedicatedSystemMemory == desc.DedicatedSystemMemory,
996 "Got unexpected dedicated system memory %Iu.\n", desc1.DedicatedSystemMemory);
997 ok(desc1.SharedSystemMemory == desc.SharedSystemMemory,
998 "Got unexpected shared system memory %Iu.\n", desc1.SharedSystemMemory);
999 ok(equal_luid(desc1.AdapterLuid, desc.AdapterLuid),
1000 "Got unexpected adapter LUID %08lx:%08lx.\n", desc1.AdapterLuid.HighPart, desc1.AdapterLuid.LowPart);
1001 trace("Flags: %08x.\n", desc1.Flags);
1003 IDXGIAdapter1_Release(adapter1);
1005 done:
1006 IDXGIAdapter_Release(adapter);
1007 refcount = IDXGIDevice_Release(device);
1008 ok(!refcount, "Device has %lu references left.\n", refcount);
1011 static void test_adapter_luid(void)
1013 DXGI_ADAPTER_DESC device_adapter_desc, desc, desc2;
1014 static const LUID luid = {0xdeadbeef, 0xdeadbeef};
1015 IDXGIAdapter *adapter, *adapter2;
1016 unsigned int found_adapter_count;
1017 unsigned int adapter_index;
1018 BOOL is_null_luid_adapter;
1019 IDXGIFactory4 *factory4;
1020 IDXGIFactory *factory;
1021 BOOL have_unique_luid;
1022 IDXGIDevice *device;
1023 ULONG refcount;
1024 HRESULT hr;
1026 if (!(device = create_device(0)))
1028 skip("Failed to create device.\n");
1029 return;
1032 hr = IDXGIDevice_GetAdapter(device, &adapter);
1033 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1034 hr = IDXGIAdapter_GetDesc(adapter, &device_adapter_desc);
1035 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1036 IDXGIAdapter_Release(adapter);
1037 refcount = IDXGIDevice_Release(device);
1038 ok(!refcount, "Device has %lu references left.\n", refcount);
1040 is_null_luid_adapter = !device_adapter_desc.AdapterLuid.LowPart
1041 && !device_adapter_desc.SubSysId && !device_adapter_desc.Revision
1042 && !device_adapter_desc.VendorId && !device_adapter_desc.DeviceId;
1044 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory);
1045 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1047 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void **)&factory4);
1048 ok(hr == S_OK || hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
1050 have_unique_luid = TRUE;
1051 found_adapter_count = 0;
1052 adapter_index = 0;
1053 while ((hr = IDXGIFactory_EnumAdapters(factory, adapter_index, &adapter)) == S_OK)
1055 hr = IDXGIAdapter_GetDesc(adapter, &desc);
1056 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1058 if (equal_luid(desc.AdapterLuid, device_adapter_desc.AdapterLuid))
1060 check_adapter_desc(&desc, &device_adapter_desc);
1061 ++found_adapter_count;
1064 if (equal_luid(desc.AdapterLuid, luid))
1065 have_unique_luid = FALSE;
1067 if (factory4)
1069 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, desc.AdapterLuid,
1070 &IID_IDXGIAdapter, (void **)&adapter2);
1071 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1072 hr = IDXGIAdapter_GetDesc(adapter2, &desc2);
1073 ok(hr == S_OK, "Failed to get adapter desc, hr %#lx.\n", hr);
1074 check_adapter_desc(&desc2, &desc);
1075 ok(adapter2 != adapter, "Expected to get new instance of IDXGIAdapter.\n");
1076 refcount = IDXGIAdapter_Release(adapter2);
1077 ok(!refcount, "Adapter has %lu references left.\n", refcount);
1080 refcount = IDXGIAdapter_Release(adapter);
1081 ok(!refcount, "Adapter has %lu references left.\n", refcount);
1083 ++adapter_index;
1085 ok(hr == DXGI_ERROR_NOT_FOUND, "Got unexpected hr %#lx.\n", hr);
1087 /* Older versions of WARP aren't enumerated by IDXGIFactory_EnumAdapters(). */
1088 ok(found_adapter_count == 1 || broken(is_null_luid_adapter),
1089 "Found %u adapters for LUID %08lx:%08lx.\n",
1090 found_adapter_count, device_adapter_desc.AdapterLuid.HighPart,
1091 device_adapter_desc.AdapterLuid.LowPart);
1093 if (factory4)
1094 IDXGIFactory4_Release(factory4);
1095 refcount = IDXGIFactory_Release(factory);
1096 ok(!refcount, "Factory has %lu references left.\n", refcount);
1098 if (!pCreateDXGIFactory2
1099 || FAILED(hr = pCreateDXGIFactory2(0, &IID_IDXGIFactory4, (void **)&factory4)))
1101 skip("DXGI 1.4 is not available.\n");
1102 return;
1105 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, device_adapter_desc.AdapterLuid,
1106 &IID_IDXGIAdapter, NULL);
1107 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1109 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, device_adapter_desc.AdapterLuid,
1110 &IID_IDXGIAdapter, (void **)&adapter);
1111 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1112 if (SUCCEEDED(hr))
1114 hr = IDXGIAdapter_GetDesc(adapter, &desc);
1115 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1116 check_adapter_desc(&desc, &device_adapter_desc);
1117 refcount = IDXGIAdapter_Release(adapter);
1118 ok(!refcount, "Adapter has %lu references left.\n", refcount);
1121 if (have_unique_luid)
1123 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, luid, &IID_IDXGIAdapter, (void **)&adapter);
1124 ok(hr == DXGI_ERROR_NOT_FOUND, "Got unexpected hr %#lx.\n", hr);
1126 else
1128 skip("Our LUID is not unique.\n");
1131 refcount = IDXGIFactory4_Release(factory4);
1132 ok(!refcount, "Factory has %lu references left.\n", refcount);
1135 static void test_query_video_memory_info(void)
1137 DXGI_QUERY_VIDEO_MEMORY_INFO memory_info;
1138 IDXGIAdapter3 *adapter3;
1139 IDXGIAdapter *adapter;
1140 IDXGIDevice *device;
1141 ULONG refcount;
1142 HRESULT hr;
1144 if (!(device = create_device(0)))
1146 skip("Failed to create device.\n");
1147 return;
1150 hr = IDXGIDevice_GetAdapter(device, &adapter);
1151 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1152 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter3, (void **)&adapter3);
1153 ok(hr == S_OK || hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
1154 if (hr == E_NOINTERFACE)
1155 goto done;
1157 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &memory_info);
1158 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1159 ok(memory_info.Budget >= memory_info.AvailableForReservation,
1160 "Available for reservation 0x%s is greater than budget 0x%s.\n",
1161 wine_dbgstr_longlong(memory_info.AvailableForReservation),
1162 wine_dbgstr_longlong(memory_info.Budget));
1163 ok(!memory_info.CurrentReservation, "Got unexpected current reservation 0x%s.\n",
1164 wine_dbgstr_longlong(memory_info.CurrentReservation));
1166 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &memory_info);
1167 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1168 ok(memory_info.Budget >= memory_info.AvailableForReservation,
1169 "Available for reservation 0x%s is greater than budget 0x%s.\n",
1170 wine_dbgstr_longlong(memory_info.AvailableForReservation),
1171 wine_dbgstr_longlong(memory_info.Budget));
1172 ok(!memory_info.CurrentReservation, "Got unexpected current reservation 0x%s.\n",
1173 wine_dbgstr_longlong(memory_info.CurrentReservation));
1175 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL + 1, &memory_info);
1176 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
1178 IDXGIAdapter3_Release(adapter3);
1180 done:
1181 IDXGIAdapter_Release(adapter);
1182 refcount = IDXGIDevice_Release(device);
1183 ok(!refcount, "Device has %lu references left.\n", refcount);
1186 static void test_check_interface_support(void)
1188 LARGE_INTEGER driver_version;
1189 IDXGIAdapter *adapter;
1190 IDXGIDevice *device;
1191 IUnknown *iface;
1192 ULONG refcount;
1193 HRESULT hr;
1195 if (!(device = create_device(0)))
1197 skip("Failed to create device.\n");
1198 return;
1201 hr = IDXGIDevice_GetAdapter(device, &adapter);
1202 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1204 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_IDXGIDevice, NULL);
1205 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1206 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_IDXGIDevice, &driver_version);
1207 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1208 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device, NULL);
1209 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1210 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device, &driver_version);
1211 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1213 trace("UMD version: %u.%u.%u.%u.\n",
1214 HIWORD(U(driver_version).HighPart), LOWORD(U(driver_version).HighPart),
1215 HIWORD(U(driver_version).LowPart), LOWORD(U(driver_version).LowPart));
1217 hr = IDXGIDevice_QueryInterface(device, &IID_ID3D10Device1, (void **)&iface);
1218 if (SUCCEEDED(hr))
1220 IUnknown_Release(iface);
1221 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device1, NULL);
1222 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1223 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device1, &driver_version);
1224 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1226 else
1228 win_skip("D3D10.1 is not supported.\n");
1231 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D11Device, NULL);
1232 ok(hr == DXGI_ERROR_UNSUPPORTED, "Got unexpected hr %#lx.\n", hr);
1233 driver_version.LowPart = driver_version.HighPart = 0xdeadbeef;
1234 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D11Device, &driver_version);
1235 ok(hr == DXGI_ERROR_UNSUPPORTED, "Got unexpected hr %#lx.\n", hr);
1236 ok(driver_version.HighPart == 0xdeadbeef, "Got unexpected driver version %#lx.\n", driver_version.HighPart);
1237 ok(driver_version.LowPart == 0xdeadbeef, "Got unexpected driver version %#lx.\n", driver_version.LowPart);
1239 IDXGIAdapter_Release(adapter);
1240 refcount = IDXGIDevice_Release(device);
1241 ok(!refcount, "Device has %lu references left.\n", refcount);
1244 static void test_create_surface(void)
1246 ID3D11Texture2D *texture2d;
1247 DXGI_SURFACE_DESC desc;
1248 IDXGISurface *surface;
1249 IDXGIDevice *device;
1250 ULONG refcount;
1251 HRESULT hr;
1253 if (!(device = create_device(0)))
1255 skip("Failed to create device.\n");
1256 return;
1259 desc.Width = 512;
1260 desc.Height = 512;
1261 desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1262 desc.SampleDesc.Count = 1;
1263 desc.SampleDesc.Quality = 0;
1265 hr = IDXGIDevice_CreateSurface(device, &desc, 1, DXGI_USAGE_RENDER_TARGET_OUTPUT, NULL, &surface);
1266 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1268 check_interface(surface, &IID_IDXGIResource, TRUE, FALSE);
1269 check_interface(surface, &IID_ID3D10Texture2D, TRUE, FALSE);
1270 /* Not available on all Windows versions. */
1271 check_interface(surface, &IID_ID3D11Texture2D, TRUE, TRUE);
1272 /* Not available on all Windows versions. */
1273 check_interface(surface, &IID_IDXGISurface1, TRUE, TRUE);
1275 IDXGISurface_Release(surface);
1276 refcount = IDXGIDevice_Release(device);
1277 ok(!refcount, "Device has %lu references left.\n", refcount);
1279 /* DXGI_USAGE_UNORDERED_ACCESS */
1280 if (!(device = create_d3d11_device()))
1282 skip("Failed to create D3D11 device.\n");
1283 return;
1286 surface = NULL;
1287 hr = IDXGIDevice_CreateSurface(device, &desc, 1, DXGI_USAGE_UNORDERED_ACCESS, NULL, &surface);
1288 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1290 if (surface)
1292 ID3D11UnorderedAccessView *uav;
1293 ID3D11Device *d3d_device;
1295 hr = IDXGISurface_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture2d);
1296 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1298 ID3D11Texture2D_GetDevice(texture2d, &d3d_device);
1300 hr = ID3D11Device_CreateUnorderedAccessView(d3d_device, (ID3D11Resource *)texture2d, NULL, &uav);
1301 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1302 ID3D11UnorderedAccessView_Release(uav);
1304 ID3D11Device_Release(d3d_device);
1305 ID3D11Texture2D_Release(texture2d);
1307 IDXGISurface_Release(surface);
1310 refcount = IDXGIDevice_Release(device);
1311 ok(!refcount, "Device has %lu references left.\n", refcount);
1314 static void test_parents(void)
1316 DXGI_SURFACE_DESC surface_desc;
1317 IDXGISurface *surface;
1318 IDXGIFactory *factory;
1319 IDXGIAdapter *adapter;
1320 IDXGIDevice *device;
1321 IDXGIOutput *output;
1322 IUnknown *parent;
1323 ULONG refcount;
1324 HRESULT hr;
1326 if (!(device = create_device(0)))
1328 skip("Failed to create device.\n");
1329 return;
1332 surface_desc.Width = 512;
1333 surface_desc.Height = 512;
1334 surface_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1335 surface_desc.SampleDesc.Count = 1;
1336 surface_desc.SampleDesc.Quality = 0;
1338 hr = IDXGIDevice_CreateSurface(device, &surface_desc, 1, DXGI_USAGE_RENDER_TARGET_OUTPUT, NULL, &surface);
1339 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1341 hr = IDXGISurface_GetParent(surface, &IID_IDXGIDevice, (void **)&parent);
1342 IDXGISurface_Release(surface);
1343 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1344 ok(parent == (IUnknown *)device, "Got parent %p, expected %p.\n", parent, device);
1345 IUnknown_Release(parent);
1347 hr = IDXGIDevice_GetAdapter(device, &adapter);
1348 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1350 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
1351 if (hr == DXGI_ERROR_NOT_FOUND)
1353 skip("Adapter has not outputs.\n");
1355 else
1357 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1359 hr = IDXGIOutput_GetParent(output, &IID_IDXGIAdapter, (void **)&parent);
1360 IDXGIOutput_Release(output);
1361 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1362 ok(parent == (IUnknown *)adapter, "Got parent %p, expected %p.\n", parent, adapter);
1363 IUnknown_Release(parent);
1366 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1367 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1369 hr = IDXGIFactory_GetParent(factory, &IID_IUnknown, (void **)&parent);
1370 ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
1371 ok(parent == NULL, "Got parent %p, expected %p.\n", parent, NULL);
1372 IDXGIFactory_Release(factory);
1374 hr = IDXGIDevice_GetParent(device, &IID_IDXGIAdapter, (void **)&parent);
1375 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1376 ok(parent == (IUnknown *)adapter, "Got parent %p, expected %p.\n", parent, adapter);
1377 IUnknown_Release(parent);
1379 IDXGIAdapter_Release(adapter);
1380 refcount = IDXGIDevice_Release(device);
1381 ok(!refcount, "Device has %lu references left.\n", refcount);
1384 static void test_output(void)
1386 unsigned int mode_count, mode_count_comp, i, last_height, last_width;
1387 double last_refresh_rate;
1388 IDXGIAdapter *adapter;
1389 IDXGIDevice *device;
1390 HRESULT hr;
1391 IDXGIOutput *output;
1392 ULONG refcount;
1393 DXGI_MODE_DESC *modes;
1395 if (!(device = create_device(0)))
1397 skip("Failed to create device.\n");
1398 return;
1401 hr = IDXGIDevice_GetAdapter(device, &adapter);
1402 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1404 hr = IDXGIAdapter_EnumOutputs(adapter, 0, NULL);
1405 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
1407 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
1408 if (hr == DXGI_ERROR_NOT_FOUND)
1410 skip("Adapter doesn't have any outputs.\n");
1411 IDXGIAdapter_Release(adapter);
1412 IDXGIDevice_Release(device);
1413 return;
1415 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1417 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, NULL, NULL);
1418 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1420 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
1421 ok(hr == S_OK|| broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Remote Desktop Services / Win 7 testbot */
1422 "Got unexpected hr %#lx.\n", hr);
1423 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
1425 win_skip("GetDisplayModeList() not supported.\n");
1426 IDXGIOutput_Release(output);
1427 IDXGIAdapter_Release(adapter);
1428 IDXGIDevice_Release(device);
1429 return;
1431 mode_count_comp = mode_count;
1433 hr = IDXGIOutput_GetDisplayModeList(output, 0, 0, &mode_count, NULL);
1434 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1435 ok(!mode_count, "Got unexpected mode_count %u.\n", mode_count);
1437 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1438 DXGI_ENUM_MODES_SCALING, &mode_count, NULL);
1439 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1440 ok(mode_count >= mode_count_comp, "Got unexpected mode_count %u, expected >= %u.\n", mode_count, mode_count_comp);
1441 mode_count_comp = mode_count;
1443 modes = heap_calloc(mode_count + 10, sizeof(*modes));
1444 ok(!!modes, "Failed to allocate memory.\n");
1446 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1447 DXGI_ENUM_MODES_SCALING, NULL, modes);
1448 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1449 ok(!modes[0].Height, "No output was expected.\n");
1451 mode_count = 0;
1452 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1453 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1454 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#lx.\n", hr);
1455 ok(!modes[0].Height, "No output was expected.\n");
1457 mode_count = mode_count_comp;
1458 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1459 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1460 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1461 ok(mode_count == mode_count_comp, "Got unexpected mode_count %u, expected %u.\n", mode_count, mode_count_comp);
1463 last_width = last_height = 0;
1464 last_refresh_rate = 0.;
1465 for (i = 0; i < mode_count; i++)
1467 double refresh_rate = modes[i].RefreshRate.Numerator / (double)modes[i].RefreshRate.Denominator;
1469 ok(modes[i].Width && modes[i].Height, "Mode %u: Invalid dimensions %ux%u.\n",
1470 i, modes[i].Width, modes[i].Height);
1472 ok(modes[i].Width >= last_width,
1473 "Mode %u: Modes should have been sorted, width %u < %u.\n", i, modes[i].Width, last_width);
1474 if (modes[i].Width != last_width)
1476 last_width = modes[i].Width;
1477 last_height = 0;
1478 last_refresh_rate = 0.;
1479 continue;
1482 ok(modes[i].Height >= last_height,
1483 "Mode %u: Modes should have been sorted, height %u < %u.\n", i, modes[i].Height, last_height);
1484 if (modes[i].Height != last_height)
1486 last_height = modes[i].Height;
1487 last_refresh_rate = 0.;
1488 continue;
1491 ok(refresh_rate >= last_refresh_rate,
1492 "Mode %u: Modes should have been sorted, refresh rate %f < %f.\n", i, refresh_rate, last_refresh_rate);
1493 if (refresh_rate != last_refresh_rate)
1494 last_refresh_rate = refresh_rate;
1497 mode_count += 5;
1498 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1499 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1500 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1501 ok(mode_count == mode_count_comp, "Got unexpected mode_count %u, expected %u.\n", mode_count, mode_count_comp);
1503 if (mode_count_comp)
1505 mode_count = mode_count_comp - 1;
1506 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1507 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1508 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#lx.\n", hr);
1509 ok(mode_count == mode_count_comp - 1, "Got unexpected mode_count %u, expected %u.\n",
1510 mode_count, mode_count_comp - 1);
1512 else
1514 skip("Not enough modes for test.\n");
1517 heap_free(modes);
1518 IDXGIOutput_Release(output);
1519 IDXGIAdapter_Release(adapter);
1520 refcount = IDXGIDevice_Release(device);
1521 ok(!refcount, "Device has %lu references left.\n", refcount);
1524 static void test_find_closest_matching_mode(void)
1526 static const DXGI_MODE_SCALING scaling_tests[] =
1528 DXGI_MODE_SCALING_CENTERED,
1529 DXGI_MODE_SCALING_STRETCHED
1531 DXGI_MODE_DESC *modes, mode, matching_mode;
1532 unsigned int i, j, mode_count;
1533 IDXGIAdapter *adapter;
1534 IDXGIDevice *device;
1535 IDXGIOutput *output;
1536 ULONG refcount;
1537 HRESULT hr;
1539 if (!(device = create_device(0)))
1541 skip("Failed to create device.\n");
1542 return;
1545 hr = IDXGIDevice_GetAdapter(device, &adapter);
1546 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1548 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
1549 if (hr == DXGI_ERROR_NOT_FOUND)
1551 win_skip("Adapter doesn't have any outputs.\n");
1552 IDXGIAdapter_Release(adapter);
1553 IDXGIDevice_Release(device);
1554 return;
1556 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1558 memset(&mode, 0, sizeof(mode));
1559 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1560 ok(hr == DXGI_ERROR_INVALID_CALL || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Win 7 testbot */
1561 "Got unexpected hr %#lx.\n", hr);
1562 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
1564 win_skip("FindClosestMatchingMode() not supported.\n");
1565 goto done;
1568 memset(&mode, 0, sizeof(mode));
1569 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, (IUnknown *)device);
1570 todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1572 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
1573 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1575 modes = heap_calloc(mode_count, sizeof(*modes));
1576 ok(!!modes, "Failed to allocate memory.\n");
1578 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes);
1579 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1581 for (i = 0; i < mode_count; ++i)
1583 mode = modes[i];
1584 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1585 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1586 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING);
1588 mode.Format = DXGI_FORMAT_UNKNOWN;
1589 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1590 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1592 mode = modes[i];
1593 mode.Width = 0;
1594 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1595 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1597 mode = modes[i];
1598 mode.Height = 0;
1599 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1600 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1602 mode = modes[i];
1603 mode.Width = mode.Height = 0;
1604 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1605 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1606 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING | MODE_DESC_IGNORE_RESOLUTION);
1607 ok(matching_mode.Width > 0 && matching_mode.Height > 0, "Got unexpected resolution %ux%u.\n",
1608 matching_mode.Width, matching_mode.Height);
1610 mode = modes[i];
1611 mode.RefreshRate.Numerator = mode.RefreshRate.Denominator = 0;
1612 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1613 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1614 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING | MODE_DESC_IGNORE_REFRESH_RATE);
1615 ok(matching_mode.RefreshRate.Numerator > 0 && matching_mode.RefreshRate.Denominator > 0,
1616 "Got unexpected refresh rate %u / %u.\n",
1617 matching_mode.RefreshRate.Numerator, matching_mode.RefreshRate.Denominator);
1619 mode = modes[i];
1620 mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1621 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1622 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1623 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING | MODE_DESC_IGNORE_SCANLINE_ORDERING);
1624 ok(matching_mode.ScanlineOrdering, "Got unexpected scanline ordering %#x.\n",
1625 matching_mode.ScanlineOrdering);
1627 memset(&mode, 0, sizeof(mode));
1628 mode.Width = modes[i].Width;
1629 mode.Height = modes[i].Height;
1630 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1631 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1632 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1633 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1635 memset(&mode, 0, sizeof(mode));
1636 mode.Width = modes[i].Width - 1;
1637 mode.Height = modes[i].Height - 1;
1638 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1639 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1640 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1641 check_mode_desc(&matching_mode, &modes[i],
1642 (MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT) | MODE_DESC_IGNORE_EXACT_RESOLUTION);
1644 memset(&mode, 0, sizeof(mode));
1645 mode.Width = modes[i].Width + 1;
1646 mode.Height = modes[i].Height + 1;
1647 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1648 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1649 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1650 check_mode_desc(&matching_mode, &modes[i],
1651 (MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT) | MODE_DESC_IGNORE_EXACT_RESOLUTION);
1654 memset(&mode, 0, sizeof(mode));
1655 mode.Width = mode.Height = 10;
1656 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1657 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1658 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1659 /* Find mode for the lowest resolution. */
1660 mode = modes[0];
1661 for (i = 0; i < mode_count; ++i)
1663 if (mode.Width >= modes[i].Width && mode.Height >= modes[i].Height)
1664 mode = modes[i];
1666 check_mode_desc(&matching_mode, &mode, MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1668 memset(&mode, 0, sizeof(mode));
1669 mode.Width = modes[0].Width;
1670 mode.Height = modes[0].Height;
1671 mode.Format = modes[0].Format;
1672 mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST;
1673 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1674 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1675 check_mode_desc(&matching_mode, &modes[0], MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1677 memset(&mode, 0, sizeof(mode));
1678 mode.Width = modes[0].Width;
1679 mode.Height = modes[0].Height;
1680 mode.Format = modes[0].Format;
1681 mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST;
1682 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1683 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1684 check_mode_desc(&matching_mode, &modes[0], MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1686 for (i = 0; i < ARRAY_SIZE(scaling_tests); ++i)
1688 for (j = 0; j < mode_count; ++j)
1690 if (modes[j].Scaling != scaling_tests[i])
1691 continue;
1693 memset(&mode, 0, sizeof(mode));
1694 mode.Width = modes[j].Width;
1695 mode.Height = modes[j].Height;
1696 mode.Format = modes[j].Format;
1697 mode.Scaling = modes[j].Scaling;
1698 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1699 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1700 check_mode_desc(&matching_mode, &modes[j],
1701 MODE_DESC_IGNORE_REFRESH_RATE | MODE_DESC_IGNORE_SCANLINE_ORDERING);
1702 break;
1706 heap_free(modes);
1708 done:
1709 IDXGIOutput_Release(output);
1710 IDXGIAdapter_Release(adapter);
1711 refcount = IDXGIDevice_Release(device);
1712 ok(!refcount, "Device has %lu references left.\n", refcount);
1715 struct refresh_rates
1717 UINT numerator;
1718 UINT denominator;
1719 BOOL numerator_should_pass;
1720 BOOL denominator_should_pass;
1723 static void test_create_swapchain(void)
1725 struct swapchain_fullscreen_state initial_state, expected_state;
1726 unsigned int i, expected_width, expected_height;
1727 DXGI_SWAP_CHAIN_DESC creation_desc, result_desc;
1728 DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc;
1729 DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
1730 IDXGIDevice *device, *bgra_device;
1731 ULONG refcount, expected_refcount;
1732 IUnknown *obj, *obj2, *parent;
1733 IDXGISwapChain1 *swapchain1;
1734 RECT *expected_client_rect;
1735 IDXGISwapChain *swapchain;
1736 IDXGISurface1 *surface;
1737 IDXGIAdapter *adapter;
1738 IDXGIFactory *factory;
1739 IDXGIOutput *target;
1740 BOOL fullscreen;
1741 HWND window;
1742 HRESULT hr;
1744 const struct refresh_rates refresh_list[] =
1746 {60, 60, FALSE, FALSE},
1747 {60, 0, TRUE, FALSE},
1748 {60, 1, TRUE, TRUE},
1749 { 0, 60, TRUE, FALSE},
1750 { 0, 0, TRUE, FALSE},
1753 if (!(device = create_device(0)))
1755 skip("Failed to create device.\n");
1756 return;
1759 creation_desc.BufferDesc.Width = 800;
1760 creation_desc.BufferDesc.Height = 600;
1761 creation_desc.BufferDesc.RefreshRate.Numerator = 60;
1762 creation_desc.BufferDesc.RefreshRate.Denominator = 60;
1763 creation_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1764 creation_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1765 creation_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
1766 creation_desc.SampleDesc.Count = 1;
1767 creation_desc.SampleDesc.Quality = 0;
1768 creation_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1769 creation_desc.BufferCount = 1;
1770 creation_desc.OutputWindow = NULL;
1771 creation_desc.Windowed = TRUE;
1772 creation_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
1773 creation_desc.Flags = 0;
1775 hr = IDXGIDevice_QueryInterface(device, &IID_IUnknown, (void **)&obj);
1776 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1778 hr = IDXGIDevice_GetAdapter(device, &adapter);
1779 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1781 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1782 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1784 expected_refcount = get_refcount(adapter);
1785 refcount = get_refcount(factory);
1786 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
1787 refcount = get_refcount(device);
1788 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
1790 creation_desc.OutputWindow = NULL;
1791 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1792 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1794 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 0, 0, 0, 0, 0, 0);
1795 memset(&initial_state, 0, sizeof(initial_state));
1796 capture_fullscreen_state(&initial_state.fullscreen_state, creation_desc.OutputWindow);
1798 hr = IDXGIFactory_CreateSwapChain(factory, NULL, &creation_desc, &swapchain);
1799 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1800 hr = IDXGIFactory_CreateSwapChain(factory, obj, NULL, &swapchain);
1801 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1802 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, NULL);
1803 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1804 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1805 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1807 refcount = get_refcount(adapter);
1808 ok(refcount >= expected_refcount, "Got refcount %lu, expected >= %lu.\n", refcount, expected_refcount);
1809 refcount = get_refcount(factory);
1810 todo_wine ok(refcount == 4, "Got unexpected refcount %lu.\n", refcount);
1811 refcount = get_refcount(device);
1812 ok(refcount == 3, "Got unexpected refcount %lu.\n", refcount);
1814 hr = IDXGISwapChain_GetDesc(swapchain, NULL);
1815 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
1817 hr = IDXGISwapChain_GetParent(swapchain, &IID_IUnknown, (void **)&parent);
1818 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1819 ok(parent == (IUnknown *)factory, "Got unexpected parent interface pointer %p.\n", parent);
1820 refcount = IUnknown_Release(parent);
1821 todo_wine ok(refcount == 4, "Got unexpected refcount %lu.\n", refcount);
1823 hr = IDXGISwapChain_GetParent(swapchain, &IID_IDXGIFactory, (void **)&parent);
1824 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1825 ok(parent == (IUnknown *)factory, "Got unexpected parent interface pointer %p.\n", parent);
1826 refcount = IUnknown_Release(parent);
1827 todo_wine ok(refcount == 4, "Got unexpected refcount %lu.\n", refcount);
1829 hr = IDXGISwapChain_QueryInterface(swapchain, &IID_IDXGISwapChain1, (void **)&swapchain1);
1830 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
1831 "Got unexpected hr %#lx.\n", hr);
1832 if (SUCCEEDED(hr))
1834 hr = IDXGISwapChain1_GetDesc1(swapchain1, NULL);
1835 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
1836 hr = IDXGISwapChain1_GetDesc1(swapchain1, &swapchain_desc);
1837 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1838 ok(!swapchain_desc.Stereo, "Got unexpected stereo %#x.\n", swapchain_desc.Stereo);
1839 ok(swapchain_desc.Scaling == DXGI_SCALING_STRETCH,
1840 "Got unexpected scaling %#x.\n", swapchain_desc.Scaling);
1841 ok(swapchain_desc.AlphaMode == DXGI_ALPHA_MODE_IGNORE,
1842 "Got unexpected alpha mode %#x.\n", swapchain_desc.AlphaMode);
1843 hr = IDXGISwapChain1_GetFullscreenDesc(swapchain1, NULL);
1844 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
1845 hr = IDXGISwapChain1_GetFullscreenDesc(swapchain1, &fullscreen_desc);
1846 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1847 ok(fullscreen_desc.Windowed == creation_desc.Windowed,
1848 "Got unexpected windowed %#x.\n", fullscreen_desc.Windowed);
1849 hr = IDXGISwapChain1_GetHwnd(swapchain1, &window);
1850 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1851 ok(window == creation_desc.OutputWindow, "Got unexpected window %p.\n", window);
1852 IDXGISwapChain1_Release(swapchain1);
1855 refcount = IDXGISwapChain_Release(swapchain);
1856 ok(!refcount, "Swapchain has %lu references left.\n", refcount);
1858 refcount = get_refcount(factory);
1859 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
1861 for (i = 0; i < ARRAY_SIZE(refresh_list); ++i)
1863 creation_desc.BufferDesc.RefreshRate.Numerator = refresh_list[i].numerator;
1864 creation_desc.BufferDesc.RefreshRate.Denominator = refresh_list[i].denominator;
1866 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1867 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1869 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
1870 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1872 ok(result_desc.Windowed == creation_desc.Windowed, "Test %u: Got unexpected windowed %#x.\n",
1873 i, result_desc.Windowed);
1875 todo_wine_if (!refresh_list[i].numerator_should_pass)
1876 ok(result_desc.BufferDesc.RefreshRate.Numerator == refresh_list[i].numerator,
1877 "Numerator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Numerator);
1879 todo_wine_if (!refresh_list[i].denominator_should_pass)
1880 ok(result_desc.BufferDesc.RefreshRate.Denominator == refresh_list[i].denominator,
1881 "Denominator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Denominator);
1883 fullscreen = 0xdeadbeef;
1884 target = (void *)0xdeadbeef;
1885 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
1886 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1887 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
1888 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
1890 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, NULL);
1891 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1892 fullscreen = 0xdeadbeef;
1893 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
1894 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1895 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
1896 target = (void *)0xdeadbeef;
1897 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
1898 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1899 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
1901 check_swapchain_fullscreen_state(swapchain, &initial_state);
1902 IDXGISwapChain_Release(swapchain);
1905 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
1907 /* Test GDI-compatible swapchain */
1908 bgra_device = create_device(D3D10_CREATE_DEVICE_BGRA_SUPPORT);
1909 ok(!!bgra_device, "Failed to create BGRA capable device.\n");
1911 hr = IDXGIDevice_QueryInterface(bgra_device, &IID_IUnknown, (void **)&obj2);
1912 ok(hr == S_OK, "IDXGIDevice does not implement IUnknown.\n");
1914 hr = IDXGIFactory_CreateSwapChain(factory, obj2, &creation_desc, &swapchain);
1915 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1917 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface1, (void **)&surface);
1918 if (SUCCEEDED(hr))
1920 HDC hdc;
1922 hr = IDXGISurface1_GetDC(surface, FALSE, &hdc);
1923 ok(FAILED(hr), "Got unexpected hr %#lx.\n", hr);
1925 IDXGISurface1_Release(surface);
1926 IDXGISwapChain_Release(swapchain);
1928 creation_desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
1929 creation_desc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
1931 hr = IDXGIFactory_CreateSwapChain(factory, obj2, &creation_desc, &swapchain);
1932 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1934 creation_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1935 creation_desc.Flags = 0;
1937 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface1, (void **)&surface);
1938 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1940 hr = IDXGISurface1_GetDC(surface, FALSE, &hdc);
1941 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1942 IDXGISurface1_ReleaseDC(surface, NULL);
1944 IDXGISurface1_Release(surface);
1945 IDXGISwapChain_Release(swapchain);
1947 else
1949 win_skip("IDXGISurface1 is not supported, skipping GetDC() tests.\n");
1950 IDXGISwapChain_Release(swapchain);
1952 IUnknown_Release(obj2);
1953 IDXGIDevice_Release(bgra_device);
1955 creation_desc.Windowed = FALSE;
1957 for (i = 0; i < ARRAY_SIZE(refresh_list); ++i)
1959 creation_desc.BufferDesc.RefreshRate.Numerator = refresh_list[i].numerator;
1960 creation_desc.BufferDesc.RefreshRate.Denominator = refresh_list[i].denominator;
1962 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1963 ok(hr == S_OK || hr == DXGI_STATUS_OCCLUDED, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1965 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
1966 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1968 /* When numerator is non-zero and denominator is zero, the windowed mode is used.
1969 * Additionally, some versions of WARP seem to always fail to change fullscreen state. */
1970 if (result_desc.Windowed != creation_desc.Windowed)
1971 trace("Test %u: Failed to change fullscreen state.\n", i);
1973 todo_wine_if (!refresh_list[i].numerator_should_pass)
1974 ok(result_desc.BufferDesc.RefreshRate.Numerator == refresh_list[i].numerator,
1975 "Numerator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Numerator);
1977 todo_wine_if (!refresh_list[i].denominator_should_pass)
1978 ok(result_desc.BufferDesc.RefreshRate.Denominator == refresh_list[i].denominator,
1979 "Denominator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Denominator);
1981 fullscreen = FALSE;
1982 target = NULL;
1983 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
1984 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1985 ok(fullscreen == !result_desc.Windowed, "Test %u: Got fullscreen %#x, expected %#x.\n",
1986 i, fullscreen, result_desc.Windowed);
1987 ok(result_desc.Windowed ? !target : !!target, "Test %u: Got unexpected target %p.\n", i, target);
1988 if (!result_desc.Windowed)
1990 IDXGIOutput *containing_output;
1991 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
1992 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1993 ok(containing_output == target, "Test %u: Got unexpected containing output pointer %p.\n",
1994 i, containing_output);
1995 IDXGIOutput_Release(containing_output);
1997 ok(output_belongs_to_adapter(target, adapter),
1998 "Test %u: Output %p doesn't belong to adapter %p.\n",
1999 i, target, adapter);
2000 IDXGIOutput_Release(target);
2002 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, NULL);
2003 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
2004 fullscreen = FALSE;
2005 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2006 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
2007 ok(fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
2008 target = NULL;
2009 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
2010 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
2011 ok(!!target, "Test %u: Got unexpected target %p.\n", i, target);
2012 IDXGIOutput_Release(target);
2015 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2016 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
2018 fullscreen = 0xdeadbeef;
2019 target = (void *)0xdeadbeef;
2020 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
2021 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
2022 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
2023 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
2025 check_swapchain_fullscreen_state(swapchain, &initial_state);
2026 IDXGISwapChain_Release(swapchain);
2029 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2031 /* Test swapchain creation with DXGI_FORMAT_UNKNOWN. */
2032 creation_desc.BufferDesc.Format = DXGI_FORMAT_UNKNOWN;
2033 creation_desc.Windowed = TRUE;
2034 creation_desc.Flags = 0;
2035 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2036 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2038 creation_desc.Windowed = FALSE;
2039 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2040 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2042 creation_desc.BufferCount = 2;
2043 creation_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
2044 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2045 ok(hr == E_INVALIDARG || hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
2046 creation_desc.BufferCount = 1;
2047 creation_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
2049 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2051 /* Test swapchain creation with backbuffer width and height equal to 0. */
2052 expected_state = initial_state;
2053 expected_client_rect = &expected_state.fullscreen_state.client_rect;
2055 /* Windowed */
2056 expected_width = expected_client_rect->right;
2057 expected_height = expected_client_rect->bottom;
2059 creation_desc.BufferDesc.Width = 0;
2060 creation_desc.BufferDesc.Height = 0;
2061 creation_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2062 creation_desc.Windowed = TRUE;
2063 creation_desc.Flags = 0;
2064 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2065 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2066 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2067 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2068 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2069 result_desc.BufferDesc.Width, expected_width);
2070 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2071 result_desc.BufferDesc.Height, expected_height);
2072 check_swapchain_fullscreen_state(swapchain, &expected_state);
2073 IDXGISwapChain_Release(swapchain);
2075 DestroyWindow(creation_desc.OutputWindow);
2076 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
2077 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
2078 0, 0, 222, 222, 0, 0, 0, 0);
2079 expected_state.fullscreen_state.style = WS_CLIPSIBLINGS | WS_CAPTION
2080 | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
2081 SetRect(&expected_state.fullscreen_state.window_rect, 0, 0, 222, 222);
2082 GetClientRect(creation_desc.OutputWindow, expected_client_rect);
2083 expected_width = expected_client_rect->right;
2084 expected_height = expected_client_rect->bottom;
2086 creation_desc.BufferDesc.Width = 0;
2087 creation_desc.BufferDesc.Height = 0;
2088 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2089 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2090 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2091 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2092 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2093 result_desc.BufferDesc.Width, expected_width);
2094 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2095 result_desc.BufferDesc.Height, expected_height);
2096 check_swapchain_fullscreen_state(swapchain, &expected_state);
2097 IDXGISwapChain_Release(swapchain);
2099 DestroyWindow(creation_desc.OutputWindow);
2100 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
2101 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
2102 1, 1, 0, 0, 0, 0, 0, 0);
2103 expected_state.fullscreen_state.style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
2104 expected_state.fullscreen_state.exstyle = 0;
2105 SetRect(&expected_state.fullscreen_state.window_rect, 1, 1, 1, 1);
2106 SetRectEmpty(expected_client_rect);
2107 expected_width = expected_height = 8;
2109 creation_desc.BufferDesc.Width = 0;
2110 creation_desc.BufferDesc.Height = 0;
2111 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2112 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2113 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2114 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2115 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2116 result_desc.BufferDesc.Width, expected_width);
2117 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2118 result_desc.BufferDesc.Height, expected_height);
2119 check_swapchain_fullscreen_state(swapchain, &expected_state);
2120 IDXGISwapChain_Release(swapchain);
2122 DestroyWindow(creation_desc.OutputWindow);
2123 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 0, 0, 0, 0, 0, 0);
2124 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2126 /* Fullscreen */
2127 creation_desc.Windowed = FALSE;
2128 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2129 ok(hr == S_OK || hr == DXGI_STATUS_OCCLUDED, "Got unexpected hr %#lx.\n", hr);
2130 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2131 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2132 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2133 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2134 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
2135 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
2136 "Got unexpected hr %#lx.\n", hr);
2137 check_swapchain_fullscreen_state(swapchain, &initial_state);
2138 IDXGISwapChain_Release(swapchain);
2139 if (hr == DXGI_ERROR_UNSUPPORTED)
2141 win_skip("GetContainingOutput() not supported.\n");
2142 goto done;
2144 if (result_desc.Windowed)
2146 win_skip("Fullscreen not supported.\n");
2147 IDXGIOutput_Release(expected_state.target);
2148 goto done;
2151 creation_desc.BufferDesc.Width = 0;
2152 creation_desc.BufferDesc.Height = 0;
2153 creation_desc.Windowed = FALSE;
2154 creation_desc.Flags = 0;
2155 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2156 &creation_desc, &initial_state.fullscreen_state.monitor_rect, 0, 0, expected_state.target);
2157 expected_width = expected_client_rect->right - expected_client_rect->left;
2158 expected_height = expected_client_rect->bottom - expected_client_rect->top;
2160 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2161 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2162 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2163 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2164 todo_wine ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2165 result_desc.BufferDesc.Width, expected_width);
2166 todo_wine ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2167 result_desc.BufferDesc.Height, expected_height);
2168 check_swapchain_fullscreen_state(swapchain, &expected_state);
2169 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2170 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2171 check_swapchain_fullscreen_state(swapchain, &initial_state);
2172 IDXGISwapChain_Release(swapchain);
2174 /* Fullscreen and DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH */
2175 creation_desc.BufferDesc.Width = 0;
2176 creation_desc.BufferDesc.Height = 0;
2177 creation_desc.Windowed = FALSE;
2178 creation_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
2179 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2180 &creation_desc, &initial_state.fullscreen_state.monitor_rect, 0, 0, expected_state.target);
2181 expected_width = expected_client_rect->right - expected_client_rect->left;
2182 expected_height = expected_client_rect->bottom - expected_client_rect->top;
2184 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2185 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2186 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2187 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2188 todo_wine ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2189 result_desc.BufferDesc.Width, expected_width);
2190 todo_wine ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2191 result_desc.BufferDesc.Height, expected_height);
2192 check_swapchain_fullscreen_state(swapchain, &expected_state);
2193 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2194 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2195 check_swapchain_fullscreen_state(swapchain, &initial_state);
2196 IDXGISwapChain_Release(swapchain);
2198 IDXGIOutput_Release(expected_state.target);
2200 done:
2201 IUnknown_Release(obj);
2202 refcount = IDXGIDevice_Release(device);
2203 ok(!refcount, "Device has %lu references left.\n", refcount);
2204 refcount = IDXGIAdapter_Release(adapter);
2205 ok(!refcount, "Adapter has %lu references left.\n", refcount);
2206 refcount = IDXGIFactory_Release(factory);
2207 ok(!refcount, "Factory has %lu references left.\n", refcount);
2208 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2209 DestroyWindow(creation_desc.OutputWindow);
2212 static void test_get_containing_output(IUnknown *device, BOOL is_d3d12)
2214 unsigned int adapter_idx, output_idx, output_count;
2215 DXGI_OUTPUT_DESC output_desc, output_desc2;
2216 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2217 IDXGIOutput *output, *output2;
2218 MONITORINFOEXW monitor_info;
2219 IDXGISwapChain *swapchain;
2220 IDXGIFactory *factory;
2221 IDXGIAdapter *adapter;
2222 POINT points[4 * 16];
2223 unsigned int i, j;
2224 HMONITOR monitor;
2225 BOOL fullscreen;
2226 ULONG refcount;
2227 HRESULT hr;
2228 BOOL ret;
2230 adapter = get_adapter(device, is_d3d12);
2231 if (!adapter)
2233 skip("Failed to get adapter on Direct3D %d.\n", is_d3d12 ? 12 : 10);
2234 return;
2237 output_count = 0;
2238 while ((hr = IDXGIAdapter_EnumOutputs(adapter, output_count, &output)) != DXGI_ERROR_NOT_FOUND)
2240 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2241 IDXGIOutput_Release(output);
2242 ++output_count;
2244 IDXGIAdapter_Release(adapter);
2246 swapchain_desc.BufferDesc.Width = 100;
2247 swapchain_desc.BufferDesc.Height = 100;
2248 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
2249 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
2250 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2251 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
2252 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
2253 swapchain_desc.SampleDesc.Count = 1;
2254 swapchain_desc.SampleDesc.Quality = 0;
2255 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2256 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
2257 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
2258 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 100, 100, 0, 0, 0, 0);
2259 swapchain_desc.Windowed = TRUE;
2260 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
2261 swapchain_desc.Flags = 0;
2263 get_factory(device, is_d3d12, &factory);
2264 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2265 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2267 monitor = MonitorFromWindow(swapchain_desc.OutputWindow, 0);
2268 ok(!!monitor, "MonitorFromWindow failed.\n");
2270 monitor_info.cbSize = sizeof(monitor_info);
2271 ret = GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info);
2272 ok(ret, "Failed to get monitor info.\n");
2274 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2275 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
2276 "Got unexpected hr %#lx.\n", hr);
2277 if (hr == DXGI_ERROR_UNSUPPORTED)
2279 win_skip("GetContainingOutput() not supported.\n");
2280 goto done;
2283 hr = IDXGIOutput_GetDesc(output, &output_desc);
2284 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2286 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2287 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2288 ok(output != output2, "Got unexpected output pointers %p, %p.\n", output, output2);
2289 check_output_equal(output, output2);
2291 refcount = IDXGIOutput_Release(output);
2292 ok(!refcount, "IDXGIOutput has %lu references left.\n", refcount);
2293 refcount = IDXGIOutput_Release(output2);
2294 ok(!refcount, "IDXGIOutput has %lu references left.\n", refcount);
2296 ok(!lstrcmpW(output_desc.DeviceName, monitor_info.szDevice),
2297 "Got unexpected device name %s, expected %s.\n",
2298 wine_dbgstr_w(output_desc.DeviceName), wine_dbgstr_w(monitor_info.szDevice));
2299 ok(EqualRect(&output_desc.DesktopCoordinates, &monitor_info.rcMonitor),
2300 "Got unexpected desktop coordinates %s, expected %s.\n",
2301 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
2302 wine_dbgstr_rect(&monitor_info.rcMonitor));
2304 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2305 ++adapter_idx)
2307 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
2308 ++output_idx)
2310 hr = IDXGIOutput_GetDesc(output, &output_desc);
2311 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx,
2312 output_idx, hr);
2314 /* Move the OutputWindow to the current output. */
2315 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc.DesktopCoordinates.left,
2316 output_desc.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2317 ok(ret, "Adapter %u output %u: SetWindowPos failed.\n", adapter_idx, output_idx);
2319 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2320 if (FAILED(hr))
2322 win_skip("Adapter %u output %u: GetContainingOutput failed, hr %#lx.\n",
2323 adapter_idx, output_idx, hr);
2324 IDXGIOutput_Release(output);
2325 continue;
2328 check_output_equal(output, output2);
2330 refcount = IDXGIOutput_Release(output2);
2331 ok(!refcount, "Adapter %u output %u: IDXGIOutput has %lu references left.\n",
2332 adapter_idx, output_idx, refcount);
2334 /* Move the OutputWindow around the corners of the current output desktop coordinates. */
2335 for (i = 0; i < 4; ++i)
2337 static const POINT offsets[] =
2339 { 0, 0},
2340 {-49, 0}, {-50, 0}, {-51, 0},
2341 { 0, -49}, { 0, -50}, { 0, -51},
2342 {-49, -49}, {-50, -49}, {-51, -49},
2343 {-49, -50}, {-50, -50}, {-51, -50},
2344 {-49, -51}, {-50, -51}, {-51, -51},
2346 unsigned int x = 0, y = 0;
2348 switch (i)
2350 case 0:
2351 x = output_desc.DesktopCoordinates.left;
2352 y = output_desc.DesktopCoordinates.top;
2353 break;
2354 case 1:
2355 x = output_desc.DesktopCoordinates.right;
2356 y = output_desc.DesktopCoordinates.top;
2357 break;
2358 case 2:
2359 x = output_desc.DesktopCoordinates.right;
2360 y = output_desc.DesktopCoordinates.bottom;
2361 break;
2362 case 3:
2363 x = output_desc.DesktopCoordinates.left;
2364 y = output_desc.DesktopCoordinates.bottom;
2365 break;
2368 for (j = 0; j < ARRAY_SIZE(offsets); ++j)
2370 unsigned int idx = ARRAY_SIZE(offsets) * i + j;
2371 assert(idx < ARRAY_SIZE(points));
2372 points[idx].x = x + offsets[j].x;
2373 points[idx].y = y + offsets[j].y;
2377 for (i = 0; i < ARRAY_SIZE(points); ++i)
2379 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, points[i].x, points[i].y,
2380 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2381 ok(ret, "Adapter %u output %u point %u: Failed to set window position.\n",
2382 adapter_idx, output_idx, i);
2384 monitor = MonitorFromWindow(swapchain_desc.OutputWindow, MONITOR_DEFAULTTONEAREST);
2385 ok(!!monitor, "Adapter %u output %u point %u: Failed to get monitor from window.\n",
2386 adapter_idx, output_idx, i);
2388 monitor_info.cbSize = sizeof(monitor_info);
2389 ret = GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info);
2390 ok(ret, "Adapter %u output %u point %u: Failed to get monitor info.\n", adapter_idx,
2391 output_idx, i);
2393 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2394 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED),
2395 "Adapter %u output %u point %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, i, hr);
2396 if (hr != S_OK)
2397 continue;
2398 ok(!!output2, "Adapter %u output %u point %u: Got unexpected containing output %p.\n",
2399 adapter_idx, output_idx, i, output2);
2400 hr = IDXGIOutput_GetDesc(output2, &output_desc);
2401 ok(hr == S_OK, "Adapter %u output %u point %u: Got unexpected hr %#lx.\n",
2402 adapter_idx, output_idx, i, hr);
2403 refcount = IDXGIOutput_Release(output2);
2404 ok(!refcount, "Adapter %u output %u point %u: IDXGIOutput has %lu references left.\n",
2405 adapter_idx, output_idx, i, refcount);
2407 ok(!lstrcmpW(output_desc.DeviceName, monitor_info.szDevice),
2408 "Adapter %u output %u point %u: Got unexpected device name %s, expected %s.\n",
2409 adapter_idx, output_idx, i, wine_dbgstr_w(output_desc.DeviceName),
2410 wine_dbgstr_w(monitor_info.szDevice));
2411 ok(EqualRect(&output_desc.DesktopCoordinates, &monitor_info.rcMonitor),
2412 "Adapter %u output %u point %u: Expect desktop coordinates %s, got %s.\n",
2413 adapter_idx, output_idx, i,
2414 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
2415 wine_dbgstr_rect(&monitor_info.rcMonitor));
2417 IDXGIOutput_Release(output);
2419 IDXGIAdapter_Release(adapter);
2422 /* Test GetContainingOutput with a full screen swapchain. The containing output should stay
2423 * the same even if the device window is moved */
2424 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2425 if (FAILED(hr))
2427 skip("SetFullscreenState failed, hr %#lx.\n", hr);
2428 goto done;
2431 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2432 if (FAILED(hr))
2434 win_skip("GetContainingOutput failed, hr %#lx.\n", hr);
2435 IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2436 goto done;
2439 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2440 ++adapter_idx)
2442 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
2443 ++output_idx)
2445 hr = IDXGIOutput_GetDesc(output, &output_desc);
2446 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2447 IDXGIOutput_Release(output);
2449 /* Move the OutputWindow to the current output. */
2450 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc.DesktopCoordinates.left,
2451 output_desc.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2452 ok(ret, "Adapter %u output %u: SetWindowPos failed.\n", adapter_idx, output_idx);
2454 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
2455 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n",
2456 adapter_idx, output_idx, hr);
2457 ok(fullscreen, "Adapter %u output %u: Expect swapchain full screen.\n", adapter_idx,
2458 output_idx);
2459 ok(output == output2, "Adapter %u output %u: Expect output %p, got %p.\n",
2460 adapter_idx, output_idx, output2, output);
2461 IDXGIOutput_Release(output);
2463 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2464 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2465 ok(output == output2, "Adapter %u output %u: Expect output %p, got %p.\n",
2466 adapter_idx, output_idx, output2, output);
2467 IDXGIOutput_Release(output);
2469 IDXGIAdapter_Release(adapter);
2472 IDXGIOutput_Release(output2);
2473 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2474 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2476 /* Test GetContainingOutput after a full screen swapchain is made windowed by pressing
2477 * Alt+Enter, then move it to another output and use Alt+Enter to enter full screen */
2478 output = NULL;
2479 output2 = NULL;
2480 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2481 ++adapter_idx)
2483 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx,
2484 output ? &output2 : &output)); ++output_idx)
2486 if (output2)
2487 break;
2490 IDXGIAdapter_Release(adapter);
2491 if (output2)
2492 break;
2495 if (output && output2)
2497 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2498 IDXGIOutput_Release(output);
2499 if (FAILED(hr))
2501 skip("SetFullscreenState failed, hr %#lx.\n", hr);
2502 IDXGIOutput_Release(output2);
2503 goto done;
2506 /* Post an Alt + VK_RETURN WM_SYSKEYDOWN to leave full screen on the first output */
2507 PostMessageA(swapchain_desc.OutputWindow, WM_SYSKEYDOWN, VK_RETURN,
2508 (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x20000001);
2509 flush_events();
2510 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2511 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2512 ok(!fullscreen, "Expect swapchain not full screen.\n");
2514 /* Move the swapchain output window to the second output */
2515 hr = IDXGIOutput_GetDesc(output2, &output_desc2);
2516 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2517 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc2.DesktopCoordinates.left,
2518 output_desc2.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2519 ok(ret, "SetWindowPos failed.\n");
2521 /* Post an Alt + VK_RETURN WM_SYSKEYDOWN to enter full screen on the second output */
2522 PostMessageA(swapchain_desc.OutputWindow, WM_SYSKEYDOWN, VK_RETURN,
2523 (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x20000001);
2524 flush_events();
2525 output = NULL;
2526 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
2527 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2528 ok(fullscreen, "Expect swapchain full screen.\n");
2529 ok(!!output, "Expect output not NULL.\n");
2530 hr = IDXGIOutput_GetDesc(output, &output_desc);
2531 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2532 hr = IDXGIOutput_GetDesc(output2, &output_desc2);
2533 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2534 ok(!lstrcmpW(output_desc.DeviceName, output_desc2.DeviceName),
2535 "Expect device name %s, got %s.\n", wine_dbgstr_w(output_desc2.DeviceName),
2536 wine_dbgstr_w(output_desc.DeviceName));
2537 IDXGIOutput_Release(output);
2539 output = NULL;
2540 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2541 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2542 hr = IDXGIOutput_GetDesc(output, &output_desc);
2543 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2544 hr = IDXGIOutput_GetDesc(output2, &output_desc2);
2545 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2546 ok(!lstrcmpW(output_desc.DeviceName, output_desc2.DeviceName),
2547 "Expect device name %s, got %s.\n", wine_dbgstr_w(output_desc2.DeviceName),
2548 wine_dbgstr_w(output_desc.DeviceName));
2550 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2551 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2553 else
2555 skip("This test requires two outputs.\n");
2558 if (output)
2559 IDXGIOutput_Release(output);
2560 if (output2)
2561 IDXGIOutput_Release(output2);
2563 done:
2564 refcount = IDXGISwapChain_Release(swapchain);
2565 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2566 refcount = IDXGIFactory_Release(factory);
2567 ok(refcount == !is_d3d12, "IDXGIFactory has %lu references left.\n", refcount);
2568 DestroyWindow(swapchain_desc.OutputWindow);
2571 static void test_swapchain_fullscreen_state(IDXGISwapChain *swapchain,
2572 IDXGIAdapter *adapter, const struct swapchain_fullscreen_state *initial_state)
2574 MONITORINFOEXW monitor_info, *output_monitor_info;
2575 struct swapchain_fullscreen_state expected_state;
2576 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2577 DXGI_OUTPUT_DESC output_desc;
2578 unsigned int i, output_count;
2579 IDXGIOutput *output;
2580 HRESULT hr;
2581 BOOL ret;
2583 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
2584 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2586 check_swapchain_fullscreen_state(swapchain, initial_state);
2588 expected_state = *initial_state;
2589 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2590 &swapchain_desc, &initial_state->fullscreen_state.monitor_rect, 800, 600, NULL);
2591 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
2592 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2594 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2595 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#lx.\n", hr);
2596 if (FAILED(hr))
2598 skip("Could not change fullscreen state.\n");
2599 IDXGIOutput_Release(expected_state.target);
2600 return;
2602 check_swapchain_fullscreen_state(swapchain, &expected_state);
2604 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2605 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2606 check_swapchain_fullscreen_state(swapchain, &expected_state);
2608 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2609 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2610 check_swapchain_fullscreen_state(swapchain, initial_state);
2612 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2613 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2614 check_swapchain_fullscreen_state(swapchain, initial_state);
2616 IDXGIOutput_Release(expected_state.target);
2617 expected_state.target = NULL;
2619 output_count = 0;
2620 while (IDXGIAdapter_EnumOutputs(adapter, output_count, &output) != DXGI_ERROR_NOT_FOUND)
2622 IDXGIOutput_Release(output);
2623 ++output_count;
2626 output_monitor_info = heap_calloc(output_count, sizeof(*output_monitor_info));
2627 ok(!!output_monitor_info, "Failed to allocate memory.\n");
2628 for (i = 0; i < output_count; ++i)
2630 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
2631 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2633 hr = IDXGIOutput_GetDesc(output, &output_desc);
2634 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2636 output_monitor_info[i].cbSize = sizeof(*output_monitor_info);
2637 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&output_monitor_info[i]);
2638 ok(ret, "Failed to get monitor info.\n");
2640 IDXGIOutput_Release(output);
2643 for (i = 0; i < output_count; ++i)
2645 RECT orig_monitor_rect = output_monitor_info[i].rcMonitor;
2646 IDXGIOutput *target;
2647 BOOL fullscreen;
2649 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
2650 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2651 hr = IDXGIOutput_GetDesc(output, &output_desc);
2652 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2654 expected_state = *initial_state;
2655 expected_state.target = output;
2656 expected_state.fullscreen_state.monitor = output_desc.Monitor;
2657 expected_state.fullscreen_state.monitor_rect = orig_monitor_rect;
2658 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2659 &swapchain_desc, &orig_monitor_rect, 800, 600, NULL);
2661 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2662 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2663 check_swapchain_fullscreen_state(swapchain, &expected_state);
2665 target = NULL;
2666 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
2667 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2668 ok(target == output, "Got target pointer %p, expected %p.\n", target, output);
2669 IDXGIOutput_Release(target);
2670 fullscreen = FALSE;
2671 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2672 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2673 ok(fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2675 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2676 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2677 check_swapchain_fullscreen_state(swapchain, &expected_state);
2678 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, output);
2679 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
2680 check_swapchain_fullscreen_state(swapchain, &expected_state);
2681 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2682 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2683 check_swapchain_fullscreen_state(swapchain, initial_state);
2685 fullscreen = TRUE;
2686 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2687 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2688 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2690 check_swapchain_fullscreen_state(swapchain, initial_state);
2691 monitor_info.cbSize = sizeof(monitor_info);
2692 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&monitor_info);
2693 ok(ret, "Failed to get monitor info.\n");
2694 ok(EqualRect(&monitor_info.rcMonitor, &orig_monitor_rect), "Got monitor rect %s, expected %s.\n",
2695 wine_dbgstr_rect(&monitor_info.rcMonitor), wine_dbgstr_rect(&orig_monitor_rect));
2697 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2698 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2700 IDXGIOutput_Release(output);
2703 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2704 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2705 check_swapchain_fullscreen_state(swapchain, initial_state);
2707 for (i = 0; i < output_count; ++i)
2709 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
2710 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2712 hr = IDXGIOutput_GetDesc(output, &output_desc);
2713 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2715 monitor_info.cbSize = sizeof(monitor_info);
2716 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&monitor_info);
2717 ok(ret, "Failed to get monitor info.\n");
2719 ok(EqualRect(&monitor_info.rcMonitor, &output_monitor_info[i].rcMonitor),
2720 "Got monitor rect %s, expected %s.\n",
2721 wine_dbgstr_rect(&monitor_info.rcMonitor),
2722 wine_dbgstr_rect(&output_monitor_info[i].rcMonitor));
2724 IDXGIOutput_Release(output);
2727 heap_free(output_monitor_info);
2730 static void test_set_fullscreen(IUnknown *device, BOOL is_d3d12)
2732 struct swapchain_fullscreen_state initial_state;
2733 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2734 IDXGIAdapter *adapter = NULL;
2735 IDXGISwapChain *swapchain;
2736 IDXGIFactory *factory;
2737 IDXGIOutput *output;
2738 BOOL fullscreen;
2739 ULONG refcount;
2740 HRESULT hr;
2742 get_factory(device, is_d3d12, &factory);
2744 swapchain_desc.BufferDesc.Width = 800;
2745 swapchain_desc.BufferDesc.Height = 600;
2746 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
2747 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
2748 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2749 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
2750 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
2751 swapchain_desc.SampleDesc.Count = 1;
2752 swapchain_desc.SampleDesc.Quality = 0;
2753 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2754 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
2755 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2756 swapchain_desc.Windowed = TRUE;
2757 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
2758 swapchain_desc.Flags = 0;
2760 memset(&initial_state, 0, sizeof(initial_state));
2761 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
2762 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2763 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2764 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2765 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
2766 "Got unexpected hr %#lx.\n", hr);
2767 if (FAILED(hr))
2769 skip("Could not get output.\n");
2770 goto done;
2772 hr = IDXGIOutput_GetParent(output, &IID_IDXGIAdapter, (void **)&adapter);
2773 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2774 IDXGIOutput_Release(output);
2776 check_swapchain_fullscreen_state(swapchain, &initial_state);
2777 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2778 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
2779 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
2780 "Got unexpected hr %#lx.\n", hr);
2781 if (FAILED(hr))
2783 skip("Could not change fullscreen state.\n");
2784 goto done;
2786 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2787 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2788 refcount = IDXGISwapChain_Release(swapchain);
2789 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2791 DestroyWindow(swapchain_desc.OutputWindow);
2792 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2793 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2794 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2795 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2796 check_swapchain_fullscreen_state(swapchain, &initial_state);
2797 test_swapchain_fullscreen_state(swapchain, adapter, &initial_state);
2798 refcount = IDXGISwapChain_Release(swapchain);
2799 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2801 DestroyWindow(swapchain_desc.OutputWindow);
2802 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2803 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2804 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2805 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2806 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2807 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2808 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2809 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2810 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2811 DestroyWindow(swapchain_desc.OutputWindow);
2812 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2813 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2814 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2815 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2816 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2817 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2818 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#lx.\n", hr);
2819 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2820 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2821 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2822 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2823 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2824 refcount = IDXGISwapChain_Release(swapchain);
2825 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2827 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2828 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2829 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2830 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2831 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2832 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2833 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2834 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2835 ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2836 DestroyWindow(swapchain_desc.OutputWindow);
2837 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2838 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2839 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2840 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2841 ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2842 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2843 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2844 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2845 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2846 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2847 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2848 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#lx.\n", hr);
2849 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2850 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2851 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2852 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2853 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2854 refcount = IDXGISwapChain_Release(swapchain);
2855 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2857 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2858 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2859 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
2860 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2861 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2862 check_swapchain_fullscreen_state(swapchain, &initial_state);
2863 test_swapchain_fullscreen_state(swapchain, adapter, &initial_state);
2865 done:
2866 if (adapter)
2867 IDXGIAdapter_Release(adapter);
2868 refcount = IDXGISwapChain_Release(swapchain);
2869 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2870 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2871 DestroyWindow(swapchain_desc.OutputWindow);
2873 refcount = IDXGIFactory_Release(factory);
2874 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
2877 static void test_default_fullscreen_target_output(IUnknown *device, BOOL is_d3d12)
2879 IDXGIOutput *output, *containing_output, *target;
2880 unsigned int adapter_idx, output_idx;
2881 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2882 DXGI_OUTPUT_DESC output_desc;
2883 unsigned int width, height;
2884 IDXGISwapChain *swapchain;
2885 IDXGIFactory *factory;
2886 IDXGIAdapter *adapter;
2887 BOOL fullscreen, ret;
2888 RECT window_rect;
2889 ULONG refcount;
2890 HRESULT hr;
2892 get_factory(device, is_d3d12, &factory);
2894 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
2895 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
2896 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2897 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
2898 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
2899 swapchain_desc.SampleDesc.Count = 1;
2900 swapchain_desc.SampleDesc.Quality = 0;
2901 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2902 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
2903 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
2904 swapchain_desc.Flags = 0;
2906 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2907 ++adapter_idx)
2909 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
2910 ++output_idx)
2912 /* Windowed swapchain */
2913 swapchain_desc.BufferDesc.Width = 640;
2914 swapchain_desc.BufferDesc.Height = 480;
2915 swapchain_desc.OutputWindow = create_window();
2916 swapchain_desc.Windowed = TRUE;
2917 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2918 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2920 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &containing_output);
2921 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2922 ok(!fullscreen, "Adapter %u output %u: Expected not fullscreen.\n", adapter_idx, output_idx);
2923 ok(!containing_output, "Adapter %u output %u: Expected a null output.\n", adapter_idx, output_idx);
2925 /* Move the OutputWindow to the current output. */
2926 hr = IDXGIOutput_GetDesc(output, &output_desc);
2927 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2928 ret = SetWindowPos(swapchain_desc.OutputWindow, 0,
2929 output_desc.DesktopCoordinates.left, output_desc.DesktopCoordinates.top,
2930 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2931 ok(ret, "Adapter %u output %u: SetWindowPos failed, error %#lx.\n", adapter_idx,
2932 output_idx, GetLastError());
2934 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
2935 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
2936 "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2937 if (hr == DXGI_ERROR_UNSUPPORTED)
2939 win_skip("Adapter %u output %u: GetContainingOutput() not supported.\n",
2940 adapter_idx, output_idx);
2941 IDXGISwapChain_Release(swapchain);
2942 IDXGIOutput_Release(output);
2943 DestroyWindow(swapchain_desc.OutputWindow);
2944 continue;
2947 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2948 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE,
2949 "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2950 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
2952 skip("Adapter %u output %u: Could not change fullscreen state.\n", adapter_idx,
2953 output_idx);
2954 IDXGIOutput_Release(containing_output);
2955 IDXGISwapChain_Release(swapchain);
2956 IDXGIOutput_Release(output);
2957 DestroyWindow(swapchain_desc.OutputWindow);
2958 continue;
2960 GetWindowRect(swapchain_desc.OutputWindow, &window_rect);
2961 ok(EqualRect(&window_rect, &output_desc.DesktopCoordinates),
2962 "Adapter %u output %u: Expect window rect %s, got %s.\n", adapter_idx,
2963 output_idx, wine_dbgstr_rect(&output_desc.DesktopCoordinates),
2964 wine_dbgstr_rect(&window_rect));
2966 target = NULL;
2967 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
2968 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2969 ok(target != containing_output,
2970 "Adapter %u output %u: Got unexpected output %p, expected %p.\n", adapter_idx,
2971 output_idx, target, containing_output);
2972 check_output_equal(target, containing_output);
2974 refcount = IDXGIOutput_Release(containing_output);
2975 ok(!refcount, "Adapter %u output %u: IDXGIOutput has %lu references left.\n",
2976 adapter_idx, output_idx, refcount);
2978 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
2979 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2980 ok(containing_output == target,
2981 "Adapter %u output %u: Got unexpected containing output %p, expected %p.\n",
2982 adapter_idx, output_idx, containing_output, target);
2983 refcount = IDXGIOutput_Release(containing_output);
2984 ok(refcount >= 2, "Adapter %u output %u: Got unexpected refcount %lu.\n", adapter_idx,
2985 output_idx, refcount);
2986 refcount = IDXGIOutput_Release(target);
2987 ok(refcount >= 1, "Adapter %u output %u: Got unexpected refcount %lu.\n", adapter_idx,
2988 output_idx, refcount);
2990 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2991 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2992 refcount = IDXGISwapChain_Release(swapchain);
2993 ok(!refcount, "Adapter %u output %u: IDXGISwapChain has %lu references left.\n",
2994 adapter_idx, output_idx, refcount);
2995 DestroyWindow(swapchain_desc.OutputWindow);
2997 /* Full screen swapchain */
2998 width = output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left;
2999 height = output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top;
3000 swapchain_desc.BufferDesc.Width = width;
3001 swapchain_desc.BufferDesc.Height = height;
3002 swapchain_desc.OutputWindow = create_window();
3003 swapchain_desc.Windowed = FALSE;
3004 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc.DesktopCoordinates.left,
3005 output_desc.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
3006 ok(ret, "Adapter %u output %u: SetWindowPos failed, error %#lx.\n", adapter_idx,
3007 output_idx, GetLastError());
3008 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
3009 if (FAILED(hr))
3011 skip("Adapter %u output %u: CreateSwapChain failed, hr %#lx.\n", adapter_idx,
3012 output_idx, hr);
3013 IDXGIOutput_Release(output);
3014 DestroyWindow(swapchain_desc.OutputWindow);
3015 continue;
3018 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &containing_output);
3019 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
3020 ok(fullscreen, "Adapter %u output %u: Expected fullscreen.\n", adapter_idx, output_idx);
3021 ok(!!containing_output, "Adapter %u output %u: Expected a valid output.\n", adapter_idx, output_idx);
3022 if (containing_output)
3023 IDXGIOutput_Release(containing_output);
3025 ret = GetWindowRect(swapchain_desc.OutputWindow, &window_rect);
3026 ok(ret, "Adapter %u output %u: GetWindowRect failed, error %#lx.\n", adapter_idx,
3027 output_idx, GetLastError());
3028 ok(EqualRect(&window_rect, &output_desc.DesktopCoordinates),
3029 "Adapter %u output %u: Expect window rect %s, got %s.\n", adapter_idx,
3030 output_idx, wine_dbgstr_rect(&output_desc.DesktopCoordinates),
3031 wine_dbgstr_rect(&window_rect));
3033 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
3034 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
3035 ok(containing_output != output,
3036 "Adapter %u output %u: Got unexpected output %p, expected %p.\n", adapter_idx,
3037 output_idx, output, containing_output);
3038 check_output_equal(output, containing_output);
3039 IDXGIOutput_Release(containing_output);
3041 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3042 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
3043 refcount = IDXGISwapChain_Release(swapchain);
3044 ok(!refcount, "Adapter %u output %u: IDXGISwapChain has %lu references left.\n",
3045 adapter_idx, output_idx, refcount);
3046 refcount = IDXGIOutput_Release(output);
3047 ok(!refcount, "Adapter %u output %u: IDXGIOutput has %lu references left.\n",
3048 adapter_idx, output_idx, refcount);
3049 DestroyWindow(swapchain_desc.OutputWindow);
3051 IDXGIAdapter_Release(adapter);
3054 refcount = IDXGIFactory_Release(factory);
3055 ok(refcount == !is_d3d12, "IDXGIFactory has %lu references left.\n", refcount);
3058 static void test_windowed_resize_target(IDXGISwapChain *swapchain, HWND window,
3059 struct swapchain_fullscreen_state *state)
3061 struct swapchain_fullscreen_state expected_state;
3062 struct fullscreen_state *e;
3063 DXGI_MODE_DESC mode;
3064 RECT window_rect;
3065 unsigned int i;
3066 HRESULT hr;
3067 BOOL ret;
3069 static const struct
3071 unsigned int width, height;
3073 sizes[] =
3075 {200, 200},
3076 {400, 200},
3077 {400, 400},
3078 {600, 800},
3079 {1000, 600},
3080 {1600, 100},
3081 {2000, 1000},
3084 check_swapchain_fullscreen_state(swapchain, state);
3085 expected_state = *state;
3086 e = &expected_state.fullscreen_state;
3088 for (i = 0; i < ARRAY_SIZE(sizes); ++i)
3090 SetRect(&e->client_rect, 0, 0, sizes[i].width, sizes[i].height);
3091 e->window_rect = e->client_rect;
3092 ret = AdjustWindowRectEx(&e->window_rect, GetWindowLongW(window, GWL_STYLE),
3093 FALSE, GetWindowLongW(window, GWL_EXSTYLE));
3094 ok(ret, "AdjustWindowRectEx failed.\n");
3095 if (GetMenu(window))
3096 e->client_rect.bottom -= GetSystemMetrics(SM_CYMENU);
3097 SetRect(&e->window_rect, 0, 0,
3098 e->window_rect.right - e->window_rect.left,
3099 e->window_rect.bottom - e->window_rect.top);
3100 GetWindowRect(window, &window_rect);
3101 OffsetRect(&e->window_rect, window_rect.left, window_rect.top);
3102 if (e->window_rect.right >= e->monitor_rect.right
3103 || e->window_rect.bottom >= e->monitor_rect.bottom)
3105 skip("Test %u: Window %s does not fit on screen %s.\n",
3106 i, wine_dbgstr_rect(&e->window_rect), wine_dbgstr_rect(&e->monitor_rect));
3107 continue;
3110 memset(&mode, 0, sizeof(mode));
3111 mode.Width = sizes[i].width;
3112 mode.Height = sizes[i].height;
3113 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
3114 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3115 check_swapchain_fullscreen_state(swapchain, &expected_state);
3118 ret = SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER);
3119 ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
3120 GetWindowRect(window, &e->window_rect);
3121 GetClientRect(window, &e->client_rect);
3122 ret = SetWindowPos(window, 0, 0, 0, 200, 200, SWP_NOMOVE | SWP_NOZORDER);
3123 ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
3125 memset(&mode, 0, sizeof(mode));
3126 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
3127 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3128 check_swapchain_fullscreen_state(swapchain, &expected_state);
3130 GetWindowRect(window, &e->window_rect);
3131 GetClientRect(window, &e->client_rect);
3132 *state = expected_state;
3135 static void test_fullscreen_resize_target(IDXGISwapChain *swapchain,
3136 const struct swapchain_fullscreen_state *initial_state)
3138 struct swapchain_fullscreen_state expected_state;
3139 DXGI_SWAP_CHAIN_DESC swapchain_desc;
3140 DXGI_OUTPUT_DESC output_desc;
3141 unsigned int i, mode_count;
3142 DXGI_MODE_DESC *modes;
3143 IDXGIOutput *target;
3144 HRESULT hr;
3146 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
3147 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3149 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
3150 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3152 hr = IDXGIOutput_GetDisplayModeList(target, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
3153 ok(hr == S_OK || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Win 7 testbot */
3154 "Got unexpected hr %#lx.\n", hr);
3155 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
3157 win_skip("GetDisplayModeList() not supported.\n");
3158 IDXGIOutput_Release(target);
3159 return;
3162 modes = heap_calloc(mode_count, sizeof(*modes));
3163 ok(!!modes, "Failed to allocate memory.\n");
3165 hr = IDXGIOutput_GetDisplayModeList(target, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes);
3166 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3168 expected_state = *initial_state;
3169 for (i = 0; i < min(mode_count, 20); ++i)
3171 /* FIXME: Modes with scaling aren't fully tested. */
3172 if (!(swapchain_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)
3173 && modes[i].Scaling != DXGI_MODE_SCALING_UNSPECIFIED)
3174 continue;
3176 hr = IDXGIOutput_GetDesc(target, &output_desc);
3177 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3179 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
3180 &swapchain_desc, &output_desc.DesktopCoordinates, modes[i].Width, modes[i].Height, NULL);
3182 hr = IDXGISwapChain_ResizeTarget(swapchain, &modes[i]);
3183 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#lx.\n", hr);
3184 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
3186 skip("Failed to change to video mode %u.\n", i);
3187 break;
3189 check_swapchain_fullscreen_state(swapchain, &expected_state);
3191 hr = IDXGIOutput_GetDesc(target, &output_desc);
3192 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3193 ok(EqualRect(&output_desc.DesktopCoordinates, &expected_state.fullscreen_state.monitor_rect),
3194 "Got desktop coordinates %s, expected %s.\n",
3195 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
3196 wine_dbgstr_rect(&expected_state.fullscreen_state.monitor_rect));
3199 heap_free(modes);
3200 IDXGIOutput_Release(target);
3203 static void test_resize_target(IUnknown *device, BOOL is_d3d12)
3205 struct swapchain_fullscreen_state initial_state, expected_state;
3206 unsigned int adapter_idx, output_idx, test_idx;
3207 DXGI_SWAP_CHAIN_DESC swapchain_desc;
3208 DXGI_OUTPUT_DESC output_desc;
3209 IDXGISwapChain *swapchain;
3210 IDXGIFactory *factory;
3211 IDXGIAdapter *adapter;
3212 IDXGIOutput *output;
3213 ULONG refcount;
3214 HRESULT hr;
3216 static const struct
3218 POINT origin;
3219 BOOL fullscreen;
3220 BOOL menu;
3221 unsigned int flags;
3223 tests[] =
3225 {{ 0, 0}, TRUE, FALSE, 0},
3226 {{10, 10}, TRUE, FALSE, 0},
3227 {{ 0, 0}, TRUE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3228 {{10, 10}, TRUE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3229 {{ 0, 0}, FALSE, FALSE, 0},
3230 {{ 0, 0}, FALSE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3231 {{10, 10}, FALSE, FALSE, 0},
3232 {{10, 10}, FALSE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3233 {{ 0, 0}, FALSE, TRUE, 0},
3234 {{ 0, 0}, FALSE, TRUE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3235 {{10, 10}, FALSE, TRUE, 0},
3236 {{10, 10}, FALSE, TRUE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3239 get_factory(device, is_d3d12, &factory);
3241 swapchain_desc.BufferDesc.Width = 800;
3242 swapchain_desc.BufferDesc.Height = 600;
3243 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
3244 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
3245 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
3246 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
3247 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
3248 swapchain_desc.SampleDesc.Count = 1;
3249 swapchain_desc.SampleDesc.Quality = 0;
3250 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3251 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
3252 swapchain_desc.Windowed = TRUE;
3253 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
3254 swapchain_desc.Flags = 0;
3256 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
3257 ++adapter_idx)
3259 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
3260 ++output_idx)
3262 hr = IDXGIOutput_GetDesc(output, &output_desc);
3263 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
3265 for (test_idx = 0; test_idx < ARRAY_SIZE(tests); ++test_idx)
3267 swapchain_desc.Flags = tests[test_idx].flags;
3268 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0,
3269 output_desc.DesktopCoordinates.left + tests[test_idx].origin.x,
3270 output_desc.DesktopCoordinates.top + tests[test_idx].origin.y,
3271 400, 200, 0, 0, 0, 0);
3272 if (tests[test_idx].menu)
3274 HMENU menu_bar = CreateMenu();
3275 HMENU menu = CreateMenu();
3276 AppendMenuA(menu_bar, MF_POPUP, (UINT_PTR)menu, "Menu");
3277 SetMenu(swapchain_desc.OutputWindow, menu_bar);
3280 memset(&initial_state, 0, sizeof(initial_state));
3281 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
3283 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
3284 ok(hr == S_OK, "Adapter %u output %u test %u: Got unexpected hr %#lx.\n",
3285 adapter_idx, output_idx, test_idx, hr);
3286 check_swapchain_fullscreen_state(swapchain, &initial_state);
3288 expected_state = initial_state;
3289 if (tests[test_idx].fullscreen)
3291 expected_state.fullscreen = TRUE;
3292 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
3293 &swapchain_desc, &initial_state.fullscreen_state.monitor_rect, 800, 600, NULL);
3294 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
3295 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
3296 "Adapter %u output %u test %u: Got unexpected hr %#lx.\n",
3297 adapter_idx, output_idx, test_idx, hr);
3298 if (hr == DXGI_ERROR_UNSUPPORTED)
3300 win_skip("Adapter %u output %u test %u: GetContainingOutput() not supported.\n",
3301 adapter_idx, output_idx, test_idx);
3302 IDXGISwapChain_Release(swapchain);
3303 DestroyWindow(swapchain_desc.OutputWindow);
3304 continue;
3307 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
3308 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE,
3309 "Adapter %u output %u test %u: Got unexpected hr %#lx.\n",
3310 adapter_idx, output_idx, test_idx, hr);
3311 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
3313 skip("Adapter %u output %u test %u: Could not change fullscreen state.\n",
3314 adapter_idx, output_idx, test_idx);
3315 IDXGIOutput_Release(expected_state.target);
3316 IDXGISwapChain_Release(swapchain);
3317 DestroyWindow(swapchain_desc.OutputWindow);
3318 continue;
3321 check_swapchain_fullscreen_state(swapchain, &expected_state);
3323 hr = IDXGISwapChain_ResizeTarget(swapchain, NULL);
3324 ok(hr == DXGI_ERROR_INVALID_CALL, "Adapter %u output %u test %u: Got unexpected hr %#lx.\n",
3325 adapter_idx, output_idx, test_idx, hr);
3326 check_swapchain_fullscreen_state(swapchain, &expected_state);
3328 if (tests[test_idx].fullscreen)
3330 test_fullscreen_resize_target(swapchain, &expected_state);
3332 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3333 ok(hr == S_OK, "Adapter %u output %u test %u: Got unexpected hr %#lx.\n",
3334 adapter_idx, output_idx, test_idx, hr);
3335 check_swapchain_fullscreen_state(swapchain, &initial_state);
3336 IDXGIOutput_Release(expected_state.target);
3337 check_swapchain_fullscreen_state(swapchain, &initial_state);
3338 expected_state = initial_state;
3340 else
3342 test_windowed_resize_target(swapchain, swapchain_desc.OutputWindow, &expected_state);
3344 check_swapchain_fullscreen_state(swapchain, &expected_state);
3347 refcount = IDXGISwapChain_Release(swapchain);
3348 ok(!refcount, "Adapter %u output %u test %u: IDXGISwapChain has %lu references left.\n",
3349 adapter_idx, output_idx, test_idx, refcount);
3350 check_window_fullscreen_state(swapchain_desc.OutputWindow, &expected_state.fullscreen_state);
3351 DestroyWindow(swapchain_desc.OutputWindow);
3353 IDXGIOutput_Release(output);
3355 IDXGIAdapter_Release(adapter);
3357 refcount = IDXGIFactory_Release(factory);
3358 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
3361 static LRESULT CALLBACK resize_target_wndproc(HWND hwnd, unsigned int message, WPARAM wparam, LPARAM lparam)
3363 IDXGISwapChain *swapchain = (IDXGISwapChain *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
3364 DXGI_SWAP_CHAIN_DESC desc;
3365 HRESULT hr;
3367 switch (message)
3369 case WM_SIZE:
3370 ok(!!swapchain, "GWLP_USERDATA is NULL.\n");
3371 hr = IDXGISwapChain_GetDesc(swapchain, &desc);
3372 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3373 ok(desc.BufferDesc.Width == 800, "Got unexpected buffer width %u.\n", desc.BufferDesc.Width);
3374 ok(desc.BufferDesc.Height == 600, "Got unexpected buffer height %u.\n", desc.BufferDesc.Height);
3375 return 0;
3377 default:
3378 return DefWindowProcA(hwnd, message, wparam, lparam);
3382 struct window_thread_data
3384 HWND window;
3385 HANDLE window_created;
3386 HANDLE finished;
3389 static DWORD WINAPI window_thread(void *data)
3391 struct window_thread_data *thread_data = data;
3392 unsigned int ret;
3393 WNDCLASSA wc;
3394 MSG msg;
3396 memset(&wc, 0, sizeof(wc));
3397 wc.lpfnWndProc = resize_target_wndproc;
3398 wc.lpszClassName = "dxgi_resize_target_wndproc_wc";
3399 ok(RegisterClassA(&wc), "Failed to register window class.\n");
3401 thread_data->window = CreateWindowA("dxgi_resize_target_wndproc_wc", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
3402 ok(!!thread_data->window, "Failed to create window.\n");
3404 ret = SetEvent(thread_data->window_created);
3405 ok(ret, "Failed to set event, last error %#lx.\n", GetLastError());
3407 for (;;)
3409 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3410 DispatchMessageA(&msg);
3412 ret = WaitForSingleObject(thread_data->finished, 0);
3413 if (ret != WAIT_TIMEOUT)
3414 break;
3416 ok(ret == WAIT_OBJECT_0, "Failed to wait for event, ret %#x, last error %#lx.\n", ret, GetLastError());
3418 DestroyWindow(thread_data->window);
3419 thread_data->window = NULL;
3421 UnregisterClassA("dxgi_test_wndproc_wc", GetModuleHandleA(NULL));
3423 return 0;
3426 static void test_resize_target_wndproc(void)
3428 struct window_thread_data thread_data;
3429 DXGI_SWAP_CHAIN_DESC swapchain_desc;
3430 IDXGISwapChain *swapchain;
3431 IDXGIFactory *factory;
3432 IDXGIAdapter *adapter;
3433 DXGI_MODE_DESC mode;
3434 IDXGIDevice *device;
3435 unsigned int ret;
3436 ULONG refcount;
3437 LONG_PTR data;
3438 HANDLE thread;
3439 HRESULT hr;
3440 RECT rect;
3442 if (!(device = create_device(0)))
3444 skip("Failed to create device.\n");
3445 return;
3448 memset(&thread_data, 0, sizeof(thread_data));
3449 thread_data.window_created = CreateEventA(NULL, FALSE, FALSE, NULL);
3450 ok(!!thread_data.window_created, "Failed to create event, last error %#lx.\n", GetLastError());
3451 thread_data.finished = CreateEventA(NULL, FALSE, FALSE, NULL);
3452 ok(!!thread_data.finished, "Failed to create event, last error %#lx.\n", GetLastError());
3454 thread = CreateThread(NULL, 0, window_thread, &thread_data, 0, NULL);
3455 ok(!!thread, "Failed to create thread, last error %#lx.\n", GetLastError());
3456 ret = WaitForSingleObject(thread_data.window_created, INFINITE);
3457 ok(ret == WAIT_OBJECT_0, "Failed to wait for thread, ret %#x, last error %#lx.\n", ret, GetLastError());
3459 hr = IDXGIDevice_GetAdapter(device, &adapter);
3460 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3461 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
3462 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3464 swapchain_desc.BufferDesc.Width = 800;
3465 swapchain_desc.BufferDesc.Height = 600;
3466 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
3467 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
3468 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
3469 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
3470 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
3471 swapchain_desc.SampleDesc.Count = 1;
3472 swapchain_desc.SampleDesc.Quality = 0;
3473 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3474 swapchain_desc.BufferCount = 1;
3475 swapchain_desc.OutputWindow = thread_data.window;
3476 swapchain_desc.Windowed = TRUE;
3477 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
3478 swapchain_desc.Flags = 0;
3479 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3480 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3482 data = SetWindowLongPtrA(thread_data.window, GWLP_USERDATA, (LONG_PTR)swapchain);
3483 ok(!data, "Got unexpected GWLP_USERDATA %p.\n", (void *)data);
3485 memset(&mode, 0, sizeof(mode));
3486 mode.Width = 600;
3487 mode.Height = 400;
3488 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
3489 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3491 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
3492 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3493 ok(swapchain_desc.BufferDesc.Width == 800,
3494 "Got unexpected buffer width %u.\n", swapchain_desc.BufferDesc.Width);
3495 ok(swapchain_desc.BufferDesc.Height == 600,
3496 "Got unexpected buffer height %u.\n", swapchain_desc.BufferDesc.Height);
3498 ret = GetClientRect(swapchain_desc.OutputWindow, &rect);
3499 ok(ret, "Failed to get client rect.\n");
3500 ok(rect.right == mode.Width && rect.bottom == mode.Height,
3501 "Got unexpected client rect %s.\n", wine_dbgstr_rect(&rect));
3503 refcount = IDXGISwapChain_Release(swapchain);
3504 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
3506 IDXGIAdapter_Release(adapter);
3507 refcount = IDXGIDevice_Release(device);
3508 ok(!refcount, "Device has %lu references left.\n", refcount);
3509 refcount = IDXGIFactory_Release(factory);
3510 ok(!refcount, "Factory has %lu references left.\n", refcount);
3512 ret = SetEvent(thread_data.finished);
3513 ok(ret, "Failed to set event, last error %#lx.\n", GetLastError());
3514 ret = WaitForSingleObject(thread, INFINITE);
3515 ok(ret == WAIT_OBJECT_0, "Failed to wait for thread, ret %#x, last error %#lx.\n", ret, GetLastError());
3516 CloseHandle(thread);
3517 CloseHandle(thread_data.window_created);
3518 CloseHandle(thread_data.finished);
3521 static void test_inexact_modes(void)
3523 struct swapchain_fullscreen_state initial_state, expected_state;
3524 DXGI_SWAP_CHAIN_DESC swapchain_desc, result_desc;
3525 IDXGIOutput *output = NULL;
3526 IDXGISwapChain *swapchain;
3527 IDXGIFactory *factory;
3528 IDXGIAdapter *adapter;
3529 IDXGIDevice *device;
3530 unsigned int i;
3531 ULONG refcount;
3532 HRESULT hr;
3534 static const struct
3536 unsigned int width, height;
3538 sizes[] =
3540 {101, 101},
3541 {203, 204},
3542 {799, 601},
3545 if (!(device = create_device(0)))
3547 skip("Failed to create device.\n");
3548 return;
3551 hr = IDXGIDevice_GetAdapter(device, &adapter);
3552 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3554 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
3555 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3557 swapchain_desc.BufferDesc.Width = 800;
3558 swapchain_desc.BufferDesc.Height = 600;
3559 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
3560 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
3561 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
3562 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
3563 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
3564 swapchain_desc.SampleDesc.Count = 1;
3565 swapchain_desc.SampleDesc.Quality = 0;
3566 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3567 swapchain_desc.BufferCount = 1;
3568 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
3569 swapchain_desc.Windowed = FALSE;
3570 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
3571 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
3573 memset(&initial_state, 0, sizeof(initial_state));
3574 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
3576 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3577 ok(hr == S_OK || hr == DXGI_STATUS_OCCLUDED, "Got unexpected hr %#lx.\n", hr);
3578 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3579 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3580 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3581 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3582 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
3583 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
3584 "Got unexpected hr %#lx.\n", hr);
3585 refcount = IDXGISwapChain_Release(swapchain);
3586 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
3587 if (hr == DXGI_ERROR_UNSUPPORTED)
3589 win_skip("GetContainingOutput() not supported.\n");
3590 goto done;
3592 if (result_desc.Windowed)
3594 win_skip("Fullscreen not supported.\n");
3595 goto done;
3598 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
3600 for (i = 0; i < ARRAY_SIZE(sizes); ++i)
3602 /* Test CreateSwapChain(). */
3603 swapchain_desc.BufferDesc.Width = sizes[i].width;
3604 swapchain_desc.BufferDesc.Height = sizes[i].height;
3605 swapchain_desc.Windowed = FALSE;
3607 expected_state = initial_state;
3608 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
3609 &swapchain_desc, &initial_state.fullscreen_state.monitor_rect,
3610 sizes[i].width, sizes[i].height, output);
3612 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3613 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3615 check_swapchain_fullscreen_state(swapchain, &expected_state);
3616 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3617 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3618 ok(result_desc.BufferDesc.Width == sizes[i].width, "Got width %u, expected %u.\n",
3619 result_desc.BufferDesc.Width, sizes[i].width);
3620 ok(result_desc.BufferDesc.Height == sizes[i].height, "Got height %u, expected %u.\n",
3621 result_desc.BufferDesc.Height, sizes[i].height);
3623 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3624 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3625 check_swapchain_fullscreen_state(swapchain, &initial_state);
3627 refcount = IDXGISwapChain_Release(swapchain);
3628 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
3630 /* Test SetFullscreenState(). */
3631 swapchain_desc.BufferDesc.Width = sizes[i].width;
3632 swapchain_desc.BufferDesc.Height = sizes[i].height;
3633 swapchain_desc.Windowed = TRUE;
3635 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3636 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3638 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
3639 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3641 check_swapchain_fullscreen_state(swapchain, &expected_state);
3642 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3643 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3644 ok(result_desc.BufferDesc.Width == sizes[i].width, "Got width %u, expected %u.\n",
3645 result_desc.BufferDesc.Width, sizes[i].width);
3646 ok(result_desc.BufferDesc.Height == sizes[i].height, "Got height %u, expected %u.\n",
3647 result_desc.BufferDesc.Height, sizes[i].height);
3649 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3650 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3651 check_swapchain_fullscreen_state(swapchain, &initial_state);
3653 refcount = IDXGISwapChain_Release(swapchain);
3654 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
3656 /* Test ResizeTarget(). */
3657 swapchain_desc.BufferDesc.Width = 800;
3658 swapchain_desc.BufferDesc.Height = 600;
3659 swapchain_desc.Windowed = TRUE;
3661 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3662 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3664 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
3665 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3667 swapchain_desc.BufferDesc.Width = sizes[i].width;
3668 swapchain_desc.BufferDesc.Height = sizes[i].height;
3669 hr = IDXGISwapChain_ResizeTarget(swapchain, &swapchain_desc.BufferDesc);
3670 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3672 check_swapchain_fullscreen_state(swapchain, &expected_state);
3673 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3674 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3675 ok(result_desc.BufferDesc.Width == 800, "Got width %u.\n", result_desc.BufferDesc.Width);
3676 ok(result_desc.BufferDesc.Height == 600, "Got height %u.\n", result_desc.BufferDesc.Height);
3678 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3679 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3680 check_swapchain_fullscreen_state(swapchain, &initial_state);
3682 refcount = IDXGISwapChain_Release(swapchain);
3683 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
3686 done:
3687 if (output)
3688 IDXGIOutput_Release(output);
3689 IDXGIAdapter_Release(adapter);
3690 refcount = IDXGIDevice_Release(device);
3691 ok(!refcount, "Device has %lu references left.\n", refcount);
3692 refcount = IDXGIFactory_Release(factory);
3693 ok(!refcount, "Factory has %lu references left.\n", refcount);
3694 DestroyWindow(swapchain_desc.OutputWindow);
3697 static void test_create_factory(void)
3699 IUnknown *iface;
3700 ULONG refcount;
3701 HRESULT hr;
3703 iface = (void *)0xdeadbeef;
3704 hr = CreateDXGIFactory(&IID_IDXGIDevice, (void **)&iface);
3705 ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
3706 ok(!iface, "Got unexpected iface %p.\n", iface);
3708 hr = CreateDXGIFactory(&IID_IUnknown, (void **)&iface);
3709 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3710 IUnknown_Release(iface);
3712 hr = CreateDXGIFactory(&IID_IDXGIObject, (void **)&iface);
3713 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3714 IUnknown_Release(iface);
3716 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&iface);
3717 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3718 check_interface(iface, &IID_IDXGIFactory1, FALSE, FALSE);
3719 IUnknown_Release(iface);
3721 iface = (void *)0xdeadbeef;
3722 hr = CreateDXGIFactory(&IID_IDXGIFactory1, (void **)&iface);
3723 ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
3724 ok(!iface, "Got unexpected iface %p.\n", iface);
3726 iface = NULL;
3727 hr = CreateDXGIFactory(&IID_IDXGIFactory2, (void **)&iface);
3728 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
3729 "Got unexpected hr %#lx.\n", hr);
3730 if (SUCCEEDED(hr))
3732 refcount = IUnknown_Release(iface);
3733 ok(!refcount, "Factory has %lu references left.\n", refcount);
3736 if (!pCreateDXGIFactory1)
3738 win_skip("CreateDXGIFactory1 not available.\n");
3739 return;
3742 iface = (void *)0xdeadbeef;
3743 hr = pCreateDXGIFactory1(&IID_IDXGIDevice, (void **)&iface);
3744 ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
3745 ok(!iface, "Got unexpected iface %p.\n", iface);
3747 hr = pCreateDXGIFactory1(&IID_IUnknown, (void **)&iface);
3748 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3749 IUnknown_Release(iface);
3751 hr = pCreateDXGIFactory1(&IID_IDXGIObject, (void **)&iface);
3752 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3753 IUnknown_Release(iface);
3755 hr = pCreateDXGIFactory1(&IID_IDXGIFactory, (void **)&iface);
3756 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3757 check_interface(iface, &IID_IDXGIFactory1, TRUE, FALSE);
3758 refcount = IUnknown_Release(iface);
3759 ok(!refcount, "Factory has %lu references left.\n", refcount);
3761 hr = pCreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&iface);
3762 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3763 IUnknown_Release(iface);
3765 iface = NULL;
3766 hr = pCreateDXGIFactory1(&IID_IDXGIFactory2, (void **)&iface);
3767 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
3768 "Got unexpected hr %#lx.\n", hr);
3769 if (SUCCEEDED(hr))
3771 refcount = IUnknown_Release(iface);
3772 ok(!refcount, "Factory has %lu references left.\n", refcount);
3775 if (!pCreateDXGIFactory2)
3777 win_skip("CreateDXGIFactory2 not available.\n");
3778 return;
3781 hr = pCreateDXGIFactory2(0, &IID_IDXGIFactory3, (void **)&iface);
3782 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3783 check_interface(iface, &IID_IDXGIFactory, TRUE, FALSE);
3784 check_interface(iface, &IID_IDXGIFactory1, TRUE, FALSE);
3785 check_interface(iface, &IID_IDXGIFactory2, TRUE, FALSE);
3786 check_interface(iface, &IID_IDXGIFactory3, TRUE, FALSE);
3787 /* Not available on all Windows versions. */
3788 check_interface(iface, &IID_IDXGIFactory4, TRUE, TRUE);
3789 check_interface(iface, &IID_IDXGIFactory5, TRUE, TRUE);
3790 refcount = IUnknown_Release(iface);
3791 ok(!refcount, "Factory has %lu references left.\n", refcount);
3793 hr = pCreateDXGIFactory2(0, &IID_IDXGIFactory, (void **)&iface);
3794 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3795 check_interface(iface, &IID_IDXGIFactory, TRUE, FALSE);
3796 check_interface(iface, &IID_IDXGIFactory1, TRUE, FALSE);
3797 check_interface(iface, &IID_IDXGIFactory2, TRUE, FALSE);
3798 check_interface(iface, &IID_IDXGIFactory3, TRUE, FALSE);
3799 refcount = IUnknown_Release(iface);
3800 ok(!refcount, "Factory has %lu references left.\n", refcount);
3803 static void test_private_data(void)
3805 ULONG refcount, expected_refcount;
3806 IDXGIDevice *device;
3807 HRESULT hr;
3808 IDXGIDevice *test_object;
3809 IUnknown *ptr;
3810 static const DWORD data[] = {1, 2, 3, 4};
3811 UINT size;
3812 static const GUID dxgi_private_data_test_guid =
3814 0xfdb37466,
3815 0x428f,
3816 0x4edf,
3817 {0xa3, 0x7f, 0x9b, 0x1d, 0xf4, 0x88, 0xc5, 0xfc}
3819 static const GUID dxgi_private_data_test_guid2 =
3821 0x2e5afac2,
3822 0x87b5,
3823 0x4c10,
3824 {0x9b, 0x4b, 0x89, 0xd7, 0xd1, 0x12, 0xe7, 0x2b}
3827 if (!(device = create_device(0)))
3829 skip("Failed to create device.\n");
3830 return;
3833 test_object = create_device(0);
3835 /* SetPrivateData with a pointer of NULL has the purpose of FreePrivateData in previous
3836 * d3d versions. A successful clear returns S_OK. A redundant clear S_FALSE. Setting a
3837 * NULL interface is not considered a clear but as setting an interface pointer that
3838 * happens to be NULL. */
3839 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 0, NULL);
3840 ok(hr == S_FALSE, "Got unexpected hr %#lx.\n", hr);
3841 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
3842 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3843 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, ~0U, NULL);
3844 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3845 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, ~0U, NULL);
3846 ok(hr == S_FALSE, "Got unexpected hr %#lx.\n", hr);
3848 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
3849 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3850 size = sizeof(ptr) * 2;
3851 ptr = (IUnknown *)0xdeadbeef;
3852 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
3853 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3854 ok(!ptr, "Got unexpected pointer %p.\n", ptr);
3855 ok(size == sizeof(IUnknown *), "Got unexpected size %u.\n", size);
3857 refcount = get_refcount(test_object);
3858 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3859 (IUnknown *)test_object);
3860 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3861 expected_refcount = refcount + 1;
3862 refcount = get_refcount(test_object);
3863 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3864 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3865 (IUnknown *)test_object);
3866 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3867 refcount = get_refcount(test_object);
3868 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3870 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
3871 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3872 expected_refcount--;
3873 refcount = get_refcount(test_object);
3874 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3876 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3877 (IUnknown *)test_object);
3878 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3879 size = sizeof(data);
3880 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, size, data);
3881 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3882 refcount = get_refcount(test_object);
3883 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3884 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 42, NULL);
3885 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3886 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 42, NULL);
3887 ok(hr == S_FALSE, "Got unexpected hr %#lx.\n", hr);
3889 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3890 (IUnknown *)test_object);
3891 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3892 expected_refcount++;
3893 size = 2 * sizeof(ptr);
3894 ptr = NULL;
3895 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
3896 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3897 ok(size == sizeof(test_object), "Got unexpected size %u.\n", size);
3898 expected_refcount++;
3899 refcount = get_refcount(test_object);
3900 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3901 if (ptr)
3902 IUnknown_Release(ptr);
3903 expected_refcount--;
3905 ptr = (IUnknown *)0xdeadbeef;
3906 size = 1;
3907 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, NULL);
3908 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3909 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
3910 size = 2 * sizeof(ptr);
3911 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, NULL);
3912 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3913 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
3914 refcount = get_refcount(test_object);
3915 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3917 size = 1;
3918 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
3919 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#lx.\n", hr);
3920 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
3921 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
3922 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid2, NULL, NULL);
3923 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
3924 size = 0xdeadbabe;
3925 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid2, &size, &ptr);
3926 ok(hr == DXGI_ERROR_NOT_FOUND, "Got unexpected hr %#lx.\n", hr);
3927 ok(size == 0, "Got unexpected size %u.\n", size);
3928 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
3929 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, NULL, &ptr);
3930 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
3931 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
3933 refcount = IDXGIDevice_Release(device);
3934 ok(!refcount, "Device has %lu references left.\n", refcount);
3935 refcount = IDXGIDevice_Release(test_object);
3936 ok(!refcount, "Test object has %lu references left.\n", refcount);
3939 #define check_surface_desc(a, b) check_surface_desc_(__LINE__, a, b)
3940 static void check_surface_desc_(unsigned int line, IDXGISurface *surface,
3941 const DXGI_SWAP_CHAIN_DESC *swapchain_desc)
3943 DXGI_SURFACE_DESC surface_desc;
3944 HRESULT hr;
3946 hr = IDXGISurface_GetDesc(surface, &surface_desc);
3947 ok_(__FILE__, line)(hr == S_OK, "Failed to get surface desc, hr %#lx.\n", hr);
3948 ok_(__FILE__, line)(surface_desc.Width == swapchain_desc->BufferDesc.Width,
3949 "Got Width %u, expected %u.\n", surface_desc.Width, swapchain_desc->BufferDesc.Width);
3950 ok_(__FILE__, line)(surface_desc.Height == swapchain_desc->BufferDesc.Height,
3951 "Got Height %u, expected %u.\n", surface_desc.Height, swapchain_desc->BufferDesc.Height);
3952 ok_(__FILE__, line)(surface_desc.Format == swapchain_desc->BufferDesc.Format,
3953 "Got Format %#x, expected %#x.\n", surface_desc.Format, swapchain_desc->BufferDesc.Format);
3954 ok_(__FILE__, line)(surface_desc.SampleDesc.Count == 1,
3955 "Got unexpected SampleDesc.Count %u.\n", surface_desc.SampleDesc.Count);
3956 ok_(__FILE__, line)(!surface_desc.SampleDesc.Quality,
3957 "Got unexpected SampleDesc.Quality %u.\n", surface_desc.SampleDesc.Quality);
3960 #define check_texture_desc(a, b) check_texture_desc_(__LINE__, a, b)
3961 static void check_texture_desc_(unsigned int line, ID3D10Texture2D *texture,
3962 const DXGI_SWAP_CHAIN_DESC *swapchain_desc)
3964 D3D10_TEXTURE2D_DESC texture_desc;
3966 ID3D10Texture2D_GetDesc(texture, &texture_desc);
3967 ok_(__FILE__, line)(texture_desc.Width == swapchain_desc->BufferDesc.Width,
3968 "Got Width %u, expected %u.\n", texture_desc.Width, swapchain_desc->BufferDesc.Width);
3969 ok_(__FILE__, line)(texture_desc.Height == swapchain_desc->BufferDesc.Height,
3970 "Got Height %u, expected %u.\n", texture_desc.Height, swapchain_desc->BufferDesc.Height);
3971 ok_(__FILE__, line)(texture_desc.MipLevels == 1, "Got unexpected MipLevels %u.\n", texture_desc.MipLevels);
3972 ok_(__FILE__, line)(texture_desc.ArraySize == 1, "Got unexpected ArraySize %u.\n", texture_desc.ArraySize);
3973 ok_(__FILE__, line)(texture_desc.Format == swapchain_desc->BufferDesc.Format,
3974 "Got Format %#x, expected %#x.\n", texture_desc.Format, swapchain_desc->BufferDesc.Format);
3975 ok_(__FILE__, line)(texture_desc.SampleDesc.Count == 1,
3976 "Got unexpected SampleDesc.Count %u.\n", texture_desc.SampleDesc.Count);
3977 ok_(__FILE__, line)(!texture_desc.SampleDesc.Quality,
3978 "Got unexpected SampleDesc.Quality %u.\n", texture_desc.SampleDesc.Quality);
3979 ok_(__FILE__, line)(texture_desc.Usage == D3D10_USAGE_DEFAULT,
3980 "Got unexpected Usage %#x.\n", texture_desc.Usage);
3981 ok_(__FILE__, line)(texture_desc.BindFlags == D3D10_BIND_RENDER_TARGET,
3982 "Got unexpected BindFlags %#x.\n", texture_desc.BindFlags);
3983 ok_(__FILE__, line)(!texture_desc.CPUAccessFlags,
3984 "Got unexpected CPUAccessFlags %#x.\n", texture_desc.CPUAccessFlags);
3985 ok_(__FILE__, line)(!texture_desc.MiscFlags, "Got unexpected MiscFlags %#x.\n", texture_desc.MiscFlags);
3988 #define check_resource_desc(a, b) check_resource_desc_(__LINE__, a, b)
3989 static void check_resource_desc_(unsigned int line, ID3D12Resource *resource,
3990 const DXGI_SWAP_CHAIN_DESC *swapchain_desc)
3992 D3D12_RESOURCE_DESC resource_desc;
3994 resource_desc = ID3D12Resource_GetDesc(resource);
3995 ok_(__FILE__, line)(resource_desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D,
3996 "Got unexpected Dimension %#x.\n", resource_desc.Dimension);
3997 ok_(__FILE__, line)(resource_desc.Width == swapchain_desc->BufferDesc.Width, "Got Width %s, expected %u.\n",
3998 wine_dbgstr_longlong(resource_desc.Width), swapchain_desc->BufferDesc.Width);
3999 ok_(__FILE__, line)(resource_desc.Height == swapchain_desc->BufferDesc.Height,
4000 "Got Height %u, expected %u.\n", resource_desc.Height, swapchain_desc->BufferDesc.Height);
4001 ok_(__FILE__, line)(resource_desc.DepthOrArraySize == 1,
4002 "Got unexpected DepthOrArraySize %u.\n", resource_desc.DepthOrArraySize);
4003 ok_(__FILE__, line)(resource_desc.MipLevels == 1,
4004 "Got unexpected MipLevels %u.\n", resource_desc.MipLevels);
4005 ok_(__FILE__, line)(resource_desc.Format == swapchain_desc->BufferDesc.Format,
4006 "Got Format %#x, expected %#x.\n", resource_desc.Format, swapchain_desc->BufferDesc.Format);
4007 ok_(__FILE__, line)(resource_desc.SampleDesc.Count == 1,
4008 "Got unexpected SampleDesc.Count %u.\n", resource_desc.SampleDesc.Count);
4009 ok_(__FILE__, line)(!resource_desc.SampleDesc.Quality,
4010 "Got unexpected SampleDesc.Quality %u.\n", resource_desc.SampleDesc.Quality);
4011 ok_(__FILE__, line)(resource_desc.Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN,
4012 "Got unexpected Layout %#x.\n", resource_desc.Layout);
4015 static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12)
4017 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4018 DXGI_SWAP_EFFECT swap_effect;
4019 IDXGISwapChain3 *swapchain3;
4020 IUnknown *present_queue[2];
4021 IDXGISwapChain *swapchain;
4022 ID3D12Resource *resource;
4023 ID3D10Texture2D *texture;
4024 HRESULT hr, expected_hr;
4025 IDXGISurface *surface;
4026 IDXGIFactory *factory;
4027 RECT client_rect, r;
4028 UINT node_mask[2];
4029 ULONG refcount;
4030 HWND window;
4031 BOOL ret;
4033 get_factory(device, is_d3d12, &factory);
4035 window = create_window();
4036 ret = GetClientRect(window, &client_rect);
4037 ok(ret, "Failed to get client rect.\n");
4039 swap_effect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
4041 swapchain_desc.BufferDesc.Width = 640;
4042 swapchain_desc.BufferDesc.Height = 480;
4043 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
4044 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
4045 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4046 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
4047 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
4048 swapchain_desc.SampleDesc.Count = 1;
4049 swapchain_desc.SampleDesc.Quality = 0;
4050 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4051 swapchain_desc.BufferCount = 2;
4052 swapchain_desc.OutputWindow = window;
4053 swapchain_desc.Windowed = TRUE;
4054 swapchain_desc.SwapEffect = swap_effect;
4055 swapchain_desc.Flags = 0;
4057 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
4058 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4059 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface);
4060 expected_hr = is_d3d12 ? E_NOINTERFACE : S_OK;
4061 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4062 ok(!surface || hr == S_OK, "Got unexpected pointer %p.\n", surface);
4063 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&texture);
4064 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4065 ok(!texture || hr == S_OK, "Got unexpected pointer %p.\n", texture);
4066 expected_hr = is_d3d12 ? S_OK : E_NOINTERFACE;
4067 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D12Resource, (void **)&resource);
4068 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4069 ok(!resource || hr == S_OK, "Got unexpected pointer %p.\n", resource);
4071 ret = GetClientRect(window, &r);
4072 ok(ret, "Failed to get client rect.\n");
4073 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
4074 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
4076 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4077 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4078 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4079 ok(swapchain_desc.BufferDesc.Width == 640,
4080 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
4081 ok(swapchain_desc.BufferDesc.Height == 480,
4082 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
4083 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4084 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4085 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4086 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4087 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4088 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4089 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM,
4090 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4091 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4092 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4093 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4094 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4095 ok(swapchain_desc.SampleDesc.Count == 1,
4096 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4097 ok(!swapchain_desc.SampleDesc.Quality,
4098 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4099 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4100 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4101 ok(swapchain_desc.BufferCount == 2,
4102 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4103 ok(swapchain_desc.OutputWindow == window,
4104 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4105 ok(swapchain_desc.Windowed,
4106 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4107 ok(swapchain_desc.SwapEffect == swap_effect,
4108 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4109 ok(!swapchain_desc.Flags,
4110 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4112 if (surface)
4113 check_surface_desc(surface, &swapchain_desc);
4114 if (texture)
4115 check_texture_desc(texture, &swapchain_desc);
4116 if (resource)
4117 check_resource_desc(resource, &swapchain_desc);
4119 hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
4120 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4122 ret = GetClientRect(window, &r);
4123 ok(ret, "Failed to get client rect.\n");
4124 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
4125 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
4127 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4128 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4129 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4130 ok(swapchain_desc.BufferDesc.Width == 640,
4131 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
4132 ok(swapchain_desc.BufferDesc.Height == 480,
4133 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
4134 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4135 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4136 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4137 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4138 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4139 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4140 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM,
4141 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4142 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4143 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4144 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4145 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4146 ok(swapchain_desc.SampleDesc.Count == 1,
4147 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4148 ok(!swapchain_desc.SampleDesc.Quality,
4149 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4150 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4151 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4152 ok(swapchain_desc.BufferCount == 2,
4153 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4154 ok(swapchain_desc.OutputWindow == window,
4155 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4156 ok(swapchain_desc.Windowed,
4157 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4158 ok(swapchain_desc.SwapEffect == swap_effect,
4159 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4160 ok(!swapchain_desc.Flags,
4161 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4163 if (surface)
4165 check_surface_desc(surface, &swapchain_desc);
4166 IDXGISurface_Release(surface);
4168 if (texture)
4170 check_texture_desc(texture, &swapchain_desc);
4171 ID3D10Texture2D_Release(texture);
4173 if (resource)
4175 check_resource_desc(resource, &swapchain_desc);
4176 ID3D12Resource_Release(resource);
4179 hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
4180 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4181 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface);
4182 expected_hr = is_d3d12 ? E_NOINTERFACE : S_OK;
4183 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4184 ok(!surface || hr == S_OK, "Got unexpected pointer %p.\n", surface);
4185 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&texture);
4186 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4187 ok(!texture || hr == S_OK, "Got unexpected pointer %p.\n", texture);
4188 expected_hr = is_d3d12 ? S_OK : E_NOINTERFACE;
4189 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D12Resource, (void **)&resource);
4190 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4191 ok(!resource || hr == S_OK, "Got unexpected pointer %p.\n", resource);
4193 ret = GetClientRect(window, &r);
4194 ok(ret, "Failed to get client rect.\n");
4195 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
4196 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
4198 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4199 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4200 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4201 ok(swapchain_desc.BufferDesc.Width == 320,
4202 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
4203 ok(swapchain_desc.BufferDesc.Height == 240,
4204 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
4205 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4206 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4207 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4208 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4209 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4210 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4211 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM,
4212 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4213 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4214 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4215 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4216 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4217 ok(swapchain_desc.SampleDesc.Count == 1,
4218 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4219 ok(!swapchain_desc.SampleDesc.Quality,
4220 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4221 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4222 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4223 ok(swapchain_desc.BufferCount == 2,
4224 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4225 ok(swapchain_desc.OutputWindow == window,
4226 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4227 ok(swapchain_desc.Windowed,
4228 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4229 ok(swapchain_desc.SwapEffect == swap_effect,
4230 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4231 ok(!swapchain_desc.Flags,
4232 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4234 if (surface)
4236 check_surface_desc(surface, &swapchain_desc);
4237 IDXGISurface_Release(surface);
4239 if (texture)
4241 check_texture_desc(texture, &swapchain_desc);
4242 ID3D10Texture2D_Release(texture);
4244 if (resource)
4246 check_resource_desc(resource, &swapchain_desc);
4247 ID3D12Resource_Release(resource);
4250 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4251 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4253 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4254 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4255 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4256 ok(swapchain_desc.BufferDesc.Width == client_rect.right - client_rect.left,
4257 "Got unexpected BufferDesc.Width %u, expected %lu.\n",
4258 swapchain_desc.BufferDesc.Width, client_rect.right - client_rect.left);
4259 ok(swapchain_desc.BufferDesc.Height == client_rect.bottom - client_rect.top,
4260 "Got unexpected bufferDesc.Height %u, expected %lu.\n",
4261 swapchain_desc.BufferDesc.Height, client_rect.bottom - client_rect.top);
4262 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4263 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4264 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4265 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4266 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4267 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4268 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM,
4269 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4270 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4271 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4272 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4273 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4274 ok(swapchain_desc.SampleDesc.Count == 1,
4275 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4276 ok(!swapchain_desc.SampleDesc.Quality,
4277 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4278 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4279 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4280 ok(swapchain_desc.BufferCount == 2,
4281 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4282 ok(swapchain_desc.OutputWindow == window,
4283 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4284 ok(swapchain_desc.Windowed,
4285 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4286 ok(swapchain_desc.SwapEffect == swap_effect,
4287 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4288 ok(!swapchain_desc.Flags,
4289 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4291 node_mask[0] = 1;
4292 node_mask[1] = 1;
4293 present_queue[0] = device;
4294 present_queue[1] = device;
4295 if (IDXGISwapChain_QueryInterface(swapchain, &IID_IDXGISwapChain3, (void **)&swapchain3) == E_NOINTERFACE)
4297 skip("IDXGISwapChain3 is not supported.\n");
4299 else if (!is_d3d12)
4301 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240,
4302 DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4303 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4304 IDXGISwapChain3_Release(swapchain3);
4306 else
4308 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240,
4309 DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4310 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4311 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240,
4312 DXGI_FORMAT_B8G8R8A8_UNORM, 0, NULL, present_queue);
4313 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4314 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, NULL, NULL);
4315 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4316 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 0, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, NULL, NULL);
4317 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4318 node_mask[0] = 2;
4319 node_mask[1] = 2;
4320 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240,
4321 DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4322 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4323 /* Windows validates node masks even when the buffer count is zero.
4324 * It defaults to the current buffer count. NULL queues cause some
4325 * Windows versions to crash. */
4326 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 0, 320, 240,
4327 DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4328 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4329 IDXGISwapChain3_Release(swapchain3);
4332 IDXGISwapChain_Release(swapchain);
4333 DestroyWindow(window);
4334 refcount = IDXGIFactory_Release(factory);
4335 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
4338 static void test_swapchain_parameters(void)
4340 DXGI_USAGE usage, expected_usage, broken_usage;
4341 D3D10_TEXTURE2D_DESC d3d10_texture_desc;
4342 D3D11_TEXTURE2D_DESC d3d11_texture_desc;
4343 unsigned int expected_bind_flags;
4344 ID3D10Texture2D *d3d10_texture;
4345 ID3D11Texture2D *d3d11_texture;
4346 DXGI_SWAP_CHAIN_DESC desc;
4347 IDXGISwapChain *swapchain;
4348 IDXGIResource *resource;
4349 IDXGIAdapter *adapter;
4350 IDXGIFactory *factory;
4351 IDXGIDevice *device;
4352 unsigned int i, j;
4353 ULONG refcount;
4354 IUnknown *obj;
4355 HWND window;
4356 HRESULT hr;
4358 static const struct
4360 BOOL windowed;
4361 UINT buffer_count;
4362 DXGI_SWAP_EFFECT swap_effect;
4363 HRESULT hr, vista_hr;
4364 UINT highest_accessible_buffer;
4366 tests[] =
4368 /* 0 */
4369 {TRUE, 1, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4370 {TRUE, 2, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4371 {TRUE, 1, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 0},
4372 {TRUE, 2, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 1},
4373 {TRUE, 3, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 2},
4374 /* 5 */
4375 {TRUE, 0, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4376 {TRUE, 1, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4377 {TRUE, 2, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4378 {TRUE, 0, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4379 {TRUE, 1, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4380 /* 10 */
4381 {TRUE, 2, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 1},
4382 {TRUE, 3, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 2},
4383 {TRUE, 0, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4384 {TRUE, 1, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4385 {TRUE, 2, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4386 /* 15 */
4387 {TRUE, 0, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4388 {TRUE, 1, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4389 {TRUE, 2, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4390 {TRUE, 16, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4391 {TRUE, 16, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 15},
4392 /* 20 */
4393 {TRUE, 16, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 15},
4394 {TRUE, 16, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4395 {TRUE, 17, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4396 {FALSE, 1, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4397 {FALSE, 2, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4398 /* 25 */
4399 {FALSE, 1, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 0},
4400 {FALSE, 2, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 1},
4401 {FALSE, 3, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 2},
4402 {FALSE, 0, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4403 {FALSE, 1, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4404 /* 30 */
4405 {FALSE, 2, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4406 {FALSE, 0, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4407 {FALSE, 1, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4408 {FALSE, 2, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 1},
4409 {FALSE, 3, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 2},
4410 /* 35 */
4411 {FALSE, 0, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4412 {FALSE, 1, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4413 {FALSE, 2, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4414 {FALSE, 0, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4415 {FALSE, 1, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4416 /* 40 */
4417 {FALSE, 2, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4418 {FALSE, 16, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4419 {FALSE, 16, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 15},
4420 {FALSE, 16, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 15},
4421 {FALSE, 17, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4422 /* 45 */
4423 {FALSE, 17, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4425 /* The following test fails on Nvidia with E_OUTOFMEMORY and leaks device references in the
4426 * process. Disable it for now.
4427 {FALSE, 16, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4430 /* The following tests crash on Win10 1909
4431 {TRUE, 0, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4432 {TRUE, 0, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4433 {TRUE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4434 {TRUE, 17, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4435 {TRUE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4436 {FALSE, 0, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4437 {FALSE, 0, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4438 {FALSE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4439 {FALSE, 17, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4442 static const DXGI_USAGE usage_tests[] =
4445 DXGI_USAGE_BACK_BUFFER,
4446 DXGI_USAGE_SHADER_INPUT,
4447 DXGI_USAGE_RENDER_TARGET_OUTPUT,
4448 DXGI_USAGE_DISCARD_ON_PRESENT,
4449 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER,
4450 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_DISCARD_ON_PRESENT,
4451 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_DISCARD_ON_PRESENT,
4452 DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT,
4453 DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_DISCARD_ON_PRESENT,
4456 if (!(device = create_device(0)))
4458 skip("Failed to create device.\n");
4459 return;
4461 window = create_window();
4463 hr = IDXGIDevice_QueryInterface(device, &IID_IUnknown, (void **)&obj);
4464 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4466 hr = IDXGIDevice_GetAdapter(device, &adapter);
4467 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4468 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
4469 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4470 IDXGIAdapter_Release(adapter);
4472 for (i = 0; i < ARRAY_SIZE(tests); ++i)
4474 memset(&desc, 0, sizeof(desc));
4475 desc.BufferDesc.Width = registry_mode.dmPelsWidth;
4476 desc.BufferDesc.Height = registry_mode.dmPelsHeight;
4477 desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4478 desc.SampleDesc.Count = 1;
4479 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4480 desc.OutputWindow = window;
4482 desc.Windowed = tests[i].windowed;
4483 desc.BufferCount = tests[i].buffer_count;
4484 desc.SwapEffect = tests[i].swap_effect;
4486 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4487 ok(hr == tests[i].hr || broken(hr == tests[i].vista_hr)
4488 || (SUCCEEDED(tests[i].hr) && hr == DXGI_STATUS_OCCLUDED),
4489 "Got unexpected hr %#lx, test %u.\n", hr, i);
4490 if (FAILED(hr))
4491 continue;
4493 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGIResource, (void **)&resource);
4494 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4496 expected_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
4497 hr = IDXGIResource_GetUsage(resource, &usage);
4498 todo_wine
4499 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4500 todo_wine
4501 ok((usage & expected_usage) == expected_usage, "Got usage %x, expected %x, test %u.\n",
4502 usage, expected_usage, i);
4504 IDXGIResource_Release(resource);
4506 hr = IDXGISwapChain_GetDesc(swapchain, &desc);
4507 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4509 for (j = 1; j <= tests[i].highest_accessible_buffer; j++)
4511 hr = IDXGISwapChain_GetBuffer(swapchain, j, &IID_IDXGIResource, (void **)&resource);
4512 ok(hr == S_OK, "Got unexpected hr %#lx, test %u, buffer %u.\n", hr, i, j);
4514 /* Buffers > 0 are supposed to be read only. This is the case except that in
4515 * fullscreen mode on Windows <= 8 the last backbuffer (BufferCount - 1) is
4516 * writable. This is not the case if an unsupported refresh rate is passed
4517 * for some reason, probably because the invalid refresh rate triggers a
4518 * kinda-sorta windowed mode.
4520 * On Windows 10 all buffers > 0 are read-only. Mark the earlier behavior
4521 * broken.
4523 * This last buffer acts as a shadow frontbuffer. Writing to it doesn't show
4524 * the draw on the screen right away (Aero on or off doesn't matter), but
4525 * Present with DXGI_PRESENT_DO_NOT_SEQUENCE will show the modifications.
4527 * Note that if the application doesn't have focus creating a fullscreen
4528 * swapchain returns DXGI_STATUS_OCCLUDED and we get a windowed swapchain,
4529 * so use the Windowed property of the swapchain that was actually created. */
4530 expected_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_READ_ONLY;
4531 broken_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
4533 if (desc.Windowed || j < tests[i].highest_accessible_buffer)
4534 broken_usage |= DXGI_USAGE_READ_ONLY;
4536 hr = IDXGIResource_GetUsage(resource, &usage);
4537 todo_wine
4538 ok(hr == S_OK, "Got unexpected hr %#lx, test %u, buffer %u.\n", hr, i, j);
4539 todo_wine
4540 ok(usage == expected_usage || broken(usage == broken_usage),
4541 "Got usage %x, expected %x, test %u, buffer %u.\n",
4542 usage, expected_usage, i, j);
4544 IDXGIResource_Release(resource);
4547 if (strcmp(winetest_platform, "wine"))
4549 hr = IDXGISwapChain_GetBuffer(swapchain, j, &IID_IDXGIResource, (void **)&resource);
4550 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx, test %u.\n", hr, i);
4553 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
4554 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4556 IDXGISwapChain_Release(swapchain);
4559 for (i = 0; i < ARRAY_SIZE(usage_tests); ++i)
4561 usage = usage_tests[i];
4563 memset(&desc, 0, sizeof(desc));
4564 desc.BufferDesc.Width = registry_mode.dmPelsWidth;
4565 desc.BufferDesc.Height = registry_mode.dmPelsHeight;
4566 desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4567 desc.SampleDesc.Count = 1;
4568 desc.BufferUsage = usage;
4569 desc.BufferCount = 1;
4570 desc.OutputWindow = window;
4571 desc.Windowed = TRUE;
4572 desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
4573 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4574 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4576 hr = IDXGISwapChain_GetDesc(swapchain, &desc);
4577 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4578 todo_wine_if(usage & ~(DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT))
4579 ok(desc.BufferUsage == usage, "Got usage %#x, expected %#x, test %u.\n", desc.BufferUsage, usage, i);
4581 expected_bind_flags = 0;
4582 if (usage & DXGI_USAGE_RENDER_TARGET_OUTPUT)
4583 expected_bind_flags |= D3D11_BIND_RENDER_TARGET;
4584 if (usage & DXGI_USAGE_SHADER_INPUT)
4585 expected_bind_flags |= D3D11_BIND_SHADER_RESOURCE;
4587 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&d3d10_texture);
4588 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4589 ID3D10Texture2D_GetDesc(d3d10_texture, &d3d10_texture_desc);
4590 ok(d3d10_texture_desc.BindFlags == expected_bind_flags,
4591 "Got d3d10 bind flags %#x, expected %#x, test %u.\n",
4592 d3d10_texture_desc.BindFlags, expected_bind_flags, i);
4593 ID3D10Texture2D_Release(d3d10_texture);
4595 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D11Texture2D, (void **)&d3d11_texture);
4596 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Got unexpected hr %#lx, test %u.\n", hr, i);
4597 if (SUCCEEDED(hr))
4599 ID3D11Texture2D_GetDesc(d3d11_texture, &d3d11_texture_desc);
4600 ok(d3d11_texture_desc.BindFlags == expected_bind_flags,
4601 "Got d3d11 bind flags %#x, expected %#x, test %u.\n",
4602 d3d11_texture_desc.BindFlags, expected_bind_flags, i);
4603 ID3D11Texture2D_Release(d3d11_texture);
4606 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGIResource, (void **)&resource);
4607 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4608 expected_usage = usage | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_DISCARD_ON_PRESENT;
4609 hr = IDXGIResource_GetUsage(resource, &usage);
4610 todo_wine
4611 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4612 todo_wine_if(i != 7)
4613 ok(usage == expected_usage, "Got usage %x, expected %x, test %u.\n", usage, expected_usage, i);
4614 IDXGIResource_Release(resource);
4616 IDXGISwapChain_Release(swapchain);
4619 /* multisampling */
4620 memset(&desc, 0, sizeof(desc));
4621 desc.BufferDesc.Width = registry_mode.dmPelsWidth;
4622 desc.BufferDesc.Height = registry_mode.dmPelsHeight;
4623 desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4624 desc.SampleDesc.Count = 4;
4625 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4626 desc.BufferCount = 4;
4627 desc.OutputWindow = window;
4628 desc.Windowed = TRUE;
4629 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
4630 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4631 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4632 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
4633 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4634 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4635 if (check_multisample_quality_levels(device, desc.BufferDesc.Format, desc.SampleDesc.Count))
4637 desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
4638 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4639 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4640 IDXGISwapChain_Release(swapchain);
4641 desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
4642 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4643 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4644 IDXGISwapChain_Release(swapchain);
4646 else
4648 skip("Multisampling not supported for DXGI_FORMAT_R8G8B8A8_UNORM.\n");
4651 IDXGIFactory_Release(factory);
4652 IUnknown_Release(obj);
4653 refcount = IDXGIDevice_Release(device);
4654 ok(!refcount, "Device has %lu references left.\n", refcount);
4655 DestroyWindow(window);
4658 static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
4660 static const DWORD flags[] = {0, DXGI_PRESENT_TEST};
4661 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4662 IDXGISwapChain *swapchain;
4663 IDXGIFactory *factory;
4664 IDXGIOutput *output;
4665 BOOL fullscreen;
4666 unsigned int i;
4667 ULONG refcount;
4668 HRESULT hr;
4670 get_factory(device, is_d3d12, &factory);
4672 swapchain_desc.BufferDesc.Width = 800;
4673 swapchain_desc.BufferDesc.Height = 600;
4674 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
4675 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
4676 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4677 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
4678 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
4679 swapchain_desc.SampleDesc.Count = 1;
4680 swapchain_desc.SampleDesc.Quality = 0;
4681 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4682 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
4683 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
4684 swapchain_desc.Windowed = TRUE;
4685 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
4686 swapchain_desc.Flags = 0;
4688 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
4689 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4691 for (i = 0; i < 10; ++i)
4693 hr = IDXGISwapChain_Present(swapchain, i, 0);
4694 ok(hr == (i <= 4 ? S_OK : DXGI_ERROR_INVALID_CALL),
4695 "Got unexpected hr %#lx for sync interval %u.\n", hr, i);
4697 hr = IDXGISwapChain_Present(swapchain, 0, 0);
4698 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4700 for (i = 0; i < ARRAY_SIZE(flags); ++i)
4702 HWND occluding_window = CreateWindowA("static", "occluding_window",
4703 WS_POPUP | WS_VISIBLE, 0, 0, 400, 200, NULL, NULL, NULL, NULL);
4705 /* Another window covers the swapchain window. Not reported as occluded. */
4706 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4707 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4709 /* Minimised window. */
4710 ShowWindow(swapchain_desc.OutputWindow, SW_MINIMIZE);
4711 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4712 ok(hr == (is_d3d12 ? S_OK : DXGI_STATUS_OCCLUDED), "Test %u: Got unexpected hr %#lx.\n", i, hr);
4713 ShowWindow(swapchain_desc.OutputWindow, SW_NORMAL);
4715 /* Hidden window. */
4716 ShowWindow(swapchain_desc.OutputWindow, SW_HIDE);
4717 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4718 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4719 ShowWindow(swapchain_desc.OutputWindow, SW_SHOW);
4720 DestroyWindow(occluding_window);
4722 /* Test that IDXGIOutput_ReleaseOwnership() makes the swapchain exit
4723 * fullscreen. */
4724 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
4725 /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE on some machines.
4726 * DXGI_ERROR_UNSUPPORTED on the Windows 7 testbot. */
4727 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == DXGI_ERROR_UNSUPPORTED))
4729 skip("Test %u: Could not change fullscreen state.\n", i);
4730 continue;
4732 flush_events();
4733 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4734 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4735 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4736 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4737 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4738 output = NULL;
4739 fullscreen = FALSE;
4740 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
4741 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4742 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4743 ok(!!output, "Test %u: Got unexpected output.\n", i);
4745 if (output)
4746 IDXGIOutput_ReleaseOwnership(output);
4747 /* Still fullscreen. */
4748 fullscreen = FALSE;
4749 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4750 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4751 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4752 /* Calling IDXGISwapChain_Present() will exit fullscreen. */
4753 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4754 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4755 fullscreen = TRUE;
4756 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4757 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4758 /* Now fullscreen mode is exited. */
4759 if (!flags[i] && !is_d3d12)
4760 /* Still fullscreen on vista and 2008. */
4761 todo_wine ok(!fullscreen || broken(fullscreen), "Test %u: Got unexpected fullscreen status.\n", i);
4762 else
4763 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4764 if (output)
4765 IDXGIOutput_Release(output);
4767 /* Test creating a window when swapchain is in fullscreen.
4769 * The window should break the swapchain out of fullscreen mode on
4770 * d3d10/11. D3d12 is different, a new occluding window doesn't break
4771 * the swapchain out of fullscreen because d3d12 fullscreen swapchains
4772 * don't take exclusive ownership over the output, nor do they disable
4773 * compositing. D3d12 fullscreen mode acts just like borderless
4774 * fullscreen window mode. */
4775 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
4776 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4777 fullscreen = FALSE;
4778 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4779 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4780 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4781 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4782 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4783 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4784 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4786 occluding_window = CreateWindowA("static", "occluding_window", WS_POPUP, 0, 0, 400, 200, 0, 0, 0, 0);
4787 /* An invisible window doesn't cause the swapchain to exit fullscreen
4788 * mode. */
4789 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4790 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4791 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4792 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4793 fullscreen = FALSE;
4794 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4795 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4796 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4797 /* A visible, but with bottom z-order window still causes the
4798 * swapchain to exit fullscreen mode. */
4799 SetWindowPos(occluding_window, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
4800 ShowWindow(occluding_window, SW_SHOW);
4801 /* Fullscreen mode takes a while to exit. */
4802 if (!is_d3d12)
4803 wait_fullscreen_state(swapchain, FALSE, TRUE);
4805 /* No longer fullscreen before calling IDXGISwapChain_Present() except
4806 * for d3d12. */
4807 fullscreen = TRUE;
4808 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4809 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4810 todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen,
4811 "Test %u: Got unexpected fullscreen status.\n", i);
4813 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4814 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4815 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4816 todo_wine_if(is_d3d12) ok(hr == (is_d3d12 ? DXGI_STATUS_OCCLUDED : S_OK),
4817 "Test %u: Got unexpected hr %#lx.\n", i, hr);
4819 fullscreen = TRUE;
4820 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4821 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4822 if (flags[i] == DXGI_PRESENT_TEST)
4823 todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen,
4824 "Test %u: Got unexpected fullscreen status.\n", i);
4825 else
4826 todo_wine ok(!fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4828 /* Even though d3d12 doesn't exit fullscreen, a
4829 * IDXGISwapChain_ResizeBuffers() is still needed for subsequent
4830 * IDXGISwapChain_Present() calls to work, otherwise they will return
4831 * DXGI_ERROR_INVALID_CALL */
4832 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4833 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4834 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4835 if (flags[i] == DXGI_PRESENT_TEST)
4836 todo_wine_if(is_d3d12) ok(hr == (is_d3d12 ? DXGI_STATUS_OCCLUDED : S_OK),
4837 "Test %u: Got unexpected hr %#lx.\n", i, hr);
4838 else
4839 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4841 /* Trying to break out of fullscreen mode again. This time, don't call
4842 * IDXGISwapChain_GetFullscreenState() before IDXGISwapChain_Present(). */
4843 ShowWindow(occluding_window, SW_HIDE);
4844 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
4845 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4846 ShowWindow(occluding_window, SW_SHOW);
4848 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4849 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4850 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4851 /* hr == S_OK on vista and 2008 */
4852 todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK),
4853 "Test %u: Got unexpected hr %#lx.\n", i, hr);
4855 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4856 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4857 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4858 if (flags[i] == DXGI_PRESENT_TEST)
4860 todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK),
4861 "Test %u: Got unexpected hr %#lx.\n", i, hr);
4862 /* IDXGISwapChain_Present() without flags refreshes the occlusion
4863 * state. */
4864 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4865 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4866 hr = IDXGISwapChain_Present(swapchain, 0, 0);
4867 todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK),
4868 "Test %u: Got unexpected hr %#lx.\n", i, hr);
4869 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4870 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4871 hr = IDXGISwapChain_Present(swapchain, 0, DXGI_PRESENT_TEST);
4872 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4874 else
4876 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4878 fullscreen = TRUE;
4879 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4880 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4881 todo_wine ok(!fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4883 DestroyWindow(occluding_window);
4884 flush_events();
4885 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4886 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4887 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4888 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4890 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
4891 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4892 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4893 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4896 wait_device_idle(device);
4898 IDXGISwapChain_Release(swapchain);
4899 DestroyWindow(swapchain_desc.OutputWindow);
4900 refcount = IDXGIFactory_Release(factory);
4901 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
4904 static void test_swapchain_backbuffer_index(IUnknown *device, BOOL is_d3d12)
4906 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4907 unsigned int index, expected_index;
4908 IDXGISwapChain3 *swapchain3;
4909 IDXGISwapChain *swapchain;
4910 HRESULT hr, expected_hr;
4911 IDXGIFactory *factory;
4912 unsigned int i, j;
4913 ULONG refcount;
4914 RECT rect;
4915 BOOL ret;
4917 static const DXGI_SWAP_EFFECT swap_effects[] =
4919 DXGI_SWAP_EFFECT_DISCARD,
4920 DXGI_SWAP_EFFECT_SEQUENTIAL,
4921 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
4922 DXGI_SWAP_EFFECT_FLIP_DISCARD,
4925 get_factory(device, is_d3d12, &factory);
4927 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
4928 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
4929 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4930 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
4931 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
4932 swapchain_desc.SampleDesc.Count = 1;
4933 swapchain_desc.SampleDesc.Quality = 0;
4934 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4935 swapchain_desc.BufferCount = 4;
4936 swapchain_desc.OutputWindow = create_window();
4937 swapchain_desc.Windowed = TRUE;
4938 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
4939 swapchain_desc.Flags = 0;
4941 ret = GetClientRect(swapchain_desc.OutputWindow, &rect);
4942 ok(ret, "Failed to get client rect.\n");
4943 swapchain_desc.BufferDesc.Width = rect.right;
4944 swapchain_desc.BufferDesc.Height = rect.bottom;
4946 for (i = 0; i < ARRAY_SIZE(swap_effects); ++i)
4948 swapchain_desc.SwapEffect = swap_effects[i];
4949 expected_hr = is_d3d12 && !is_flip_model(swap_effects[i]) ? DXGI_ERROR_INVALID_CALL : S_OK;
4950 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
4951 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4952 if (FAILED(hr))
4953 continue;
4955 hr = IDXGISwapChain_QueryInterface(swapchain, &IID_IDXGISwapChain3, (void **)&swapchain3);
4956 if (hr == E_NOINTERFACE)
4958 skip("IDXGISwapChain3 is not supported.\n");
4959 IDXGISwapChain_Release(swapchain);
4960 goto done;
4963 for (j = 0; j < 2 * swapchain_desc.BufferCount; ++j)
4965 index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain3);
4966 expected_index = is_d3d12 ? j % swapchain_desc.BufferCount : 0;
4967 ok(index == expected_index, "Got back buffer index %u, expected %u.\n", index, expected_index);
4968 hr = IDXGISwapChain3_Present(swapchain3, 0, 0);
4969 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4972 wait_device_idle(device);
4974 IDXGISwapChain3_Release(swapchain3);
4975 refcount = IDXGISwapChain_Release(swapchain);
4976 ok(!refcount, "Swapchain has %lu references left.\n", refcount);
4979 done:
4980 DestroyWindow(swapchain_desc.OutputWindow);
4981 refcount = IDXGIFactory_Release(factory);
4982 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
4985 static void test_swapchain_formats(IUnknown *device, BOOL is_d3d12)
4987 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4988 IDXGISwapChain *swapchain;
4989 HRESULT hr, expected_hr;
4990 IDXGIFactory *factory;
4991 unsigned int i;
4992 ULONG refcount;
4993 RECT rect;
4994 BOOL ret;
4996 static const struct
4998 DXGI_FORMAT format;
4999 DXGI_SWAP_EFFECT swap_effect;
5000 BOOL supported;
5002 tests[] =
5004 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_DISCARD, FALSE},
5005 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_SEQUENTIAL, FALSE},
5006 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5007 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5008 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5009 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5010 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5011 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5012 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5013 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5014 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5015 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5016 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5017 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5018 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5019 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5020 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5021 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5022 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5023 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5024 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5025 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5026 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5027 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5028 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5029 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5030 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5031 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5032 {DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5033 {DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5036 get_factory(device, is_d3d12, &factory);
5038 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
5039 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
5040 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
5041 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
5042 swapchain_desc.SampleDesc.Count = 1;
5043 swapchain_desc.SampleDesc.Quality = 0;
5044 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5045 swapchain_desc.BufferCount = 4;
5046 swapchain_desc.OutputWindow = create_window();
5047 swapchain_desc.Windowed = TRUE;
5048 swapchain_desc.Flags = 0;
5050 ret = GetClientRect(swapchain_desc.OutputWindow, &rect);
5051 ok(ret, "Failed to get client rect.\n");
5052 swapchain_desc.BufferDesc.Width = rect.right;
5053 swapchain_desc.BufferDesc.Height = rect.bottom;
5055 for (i = 0; i < ARRAY_SIZE(tests); ++i)
5057 if (is_d3d12 && !is_flip_model(tests[i].swap_effect))
5058 continue;
5060 swapchain_desc.BufferDesc.Format = tests[i].format;
5061 swapchain_desc.SwapEffect = tests[i].swap_effect;
5062 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
5063 expected_hr = tests[i].supported ? S_OK : DXGI_ERROR_INVALID_CALL;
5064 if (tests[i].format == DXGI_FORMAT_UNKNOWN && !is_d3d12)
5065 expected_hr = E_INVALIDARG;
5066 ok(hr == expected_hr
5067 /* Flip presentation model not supported. */
5068 || broken(hr == DXGI_ERROR_INVALID_CALL && is_flip_model(tests[i].swap_effect) && !is_d3d12),
5069 "Test %u, d3d12 %#x: Got unexpected hr %#lx, expected %#lx.\n", i, is_d3d12, hr, expected_hr);
5071 if (SUCCEEDED(hr))
5073 refcount = IDXGISwapChain_Release(swapchain);
5074 ok(!refcount, "Swapchain has %lu references left.\n", refcount);
5078 DestroyWindow(swapchain_desc.OutputWindow);
5079 refcount = IDXGIFactory_Release(factory);
5080 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
5083 static void test_maximum_frame_latency(void)
5085 IDXGIDevice1 *device1;
5086 IDXGIDevice *device;
5087 UINT max_latency;
5088 ULONG refcount;
5089 HRESULT hr;
5091 if (!(device = create_device(0)))
5093 skip("Failed to create device.\n");
5094 return;
5097 if (SUCCEEDED(IDXGIDevice_QueryInterface(device, &IID_IDXGIDevice1, (void **)&device1)))
5099 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, NULL);
5100 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
5102 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5103 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5104 ok(max_latency == DEFAULT_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
5106 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, MAX_FRAME_LATENCY);
5107 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5108 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5109 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5110 ok(max_latency == MAX_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
5112 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, MAX_FRAME_LATENCY + 1);
5113 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
5114 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5115 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5116 ok(max_latency == MAX_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
5118 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, 0);
5119 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5120 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5121 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5122 /* 0 does not reset to the default frame latency on all Windows versions. */
5123 ok(max_latency == DEFAULT_FRAME_LATENCY || broken(!max_latency),
5124 "Got unexpected maximum frame latency %u.\n", max_latency);
5126 IDXGIDevice1_Release(device1);
5128 else
5130 win_skip("IDXGIDevice1 is not implemented.\n");
5133 refcount = IDXGIDevice_Release(device);
5134 ok(!refcount, "Device has %lu references left.\n", refcount);
5137 static void test_output_desc(void)
5139 IDXGIAdapter *adapter, *adapter2;
5140 IDXGIOutput *output, *output2;
5141 DXGI_OUTPUT_DESC desc;
5142 IDXGIFactory *factory;
5143 unsigned int i, j;
5144 ULONG refcount;
5145 HRESULT hr;
5147 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory);
5148 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5150 for (i = 0; ; ++i)
5152 hr = IDXGIFactory_EnumAdapters(factory, i, &adapter);
5153 if (hr == DXGI_ERROR_NOT_FOUND)
5154 break;
5155 winetest_push_context("Adapter %u", i);
5156 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5158 hr = IDXGIFactory_EnumAdapters(factory, i, &adapter2);
5159 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5160 ok(adapter != adapter2, "Expected to get new instance of IDXGIAdapter, %p == %p.\n", adapter, adapter2);
5161 refcount = get_refcount(adapter);
5162 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5163 IDXGIAdapter_Release(adapter2);
5165 refcount = get_refcount(factory);
5166 ok(refcount == 2, "Get unexpected refcount %lu.\n", refcount);
5167 refcount = get_refcount(adapter);
5168 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5170 for (j = 0; ; ++j)
5172 MONITORINFOEXW monitor_info;
5173 BOOL ret;
5175 hr = IDXGIAdapter_EnumOutputs(adapter, j, &output);
5176 if (hr == DXGI_ERROR_NOT_FOUND)
5177 break;
5178 winetest_push_context("Output %u", j);
5179 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5181 hr = IDXGIAdapter_EnumOutputs(adapter, j, &output2);
5182 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5183 ok(output != output2, "Expected to get new instance of IDXGIOutput, %p == %p.\n", output, output2);
5184 refcount = get_refcount(output);
5185 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5186 IDXGIOutput_Release(output2);
5188 refcount = get_refcount(factory);
5189 ok(refcount == 2, "Get unexpected refcount %lu.\n", refcount);
5190 refcount = get_refcount(adapter);
5191 ok(refcount == 2, "Get unexpected refcount %lu.\n", refcount);
5192 refcount = get_refcount(output);
5193 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5195 hr = IDXGIOutput_GetDesc(output, &desc);
5196 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5198 monitor_info.cbSize = sizeof(monitor_info);
5199 ret = GetMonitorInfoW(desc.Monitor, (MONITORINFO *)&monitor_info);
5200 ok(ret, "Failed to get monitor info.\n");
5201 ok(!lstrcmpW(desc.DeviceName, monitor_info.szDevice), "Got unexpected device name %s, expected %s.\n",
5202 wine_dbgstr_w(desc.DeviceName), wine_dbgstr_w(monitor_info.szDevice));
5203 ok(EqualRect(&desc.DesktopCoordinates, &monitor_info.rcMonitor),
5204 "Got unexpected desktop coordinates %s, expected %s.\n",
5205 wine_dbgstr_rect(&desc.DesktopCoordinates),
5206 wine_dbgstr_rect(&monitor_info.rcMonitor));
5208 IDXGIOutput_Release(output);
5209 refcount = get_refcount(adapter);
5210 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5212 winetest_pop_context();
5215 IDXGIAdapter_Release(adapter);
5216 refcount = get_refcount(factory);
5217 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5219 winetest_pop_context();
5222 refcount = IDXGIFactory_Release(factory);
5223 ok(!refcount, "IDXGIFactory has %lu references left.\n", refcount);
5226 struct dxgi_factory
5228 IDXGIFactory IDXGIFactory_iface;
5229 IDXGIFactory *wrapped_iface;
5230 unsigned int wrapped_adapter_count;
5233 static inline struct dxgi_factory *impl_from_IDXGIFactory(IDXGIFactory *iface)
5235 return CONTAINING_RECORD(iface, struct dxgi_factory, IDXGIFactory_iface);
5238 static HRESULT STDMETHODCALLTYPE dxgi_factory_QueryInterface(IDXGIFactory *iface, REFIID iid, void **out)
5240 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5242 if (IsEqualGUID(iid, &IID_IDXGIFactory)
5243 || IsEqualGUID(iid, &IID_IDXGIObject)
5244 || IsEqualGUID(iid, &IID_IUnknown))
5246 IDXGIFactory_AddRef(iface);
5247 *out = iface;
5248 return S_OK;
5250 return IDXGIFactory_QueryInterface(factory->wrapped_iface, iid, out);
5253 static ULONG STDMETHODCALLTYPE dxgi_factory_AddRef(IDXGIFactory *iface)
5255 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5256 return IDXGIFactory_AddRef(factory->wrapped_iface);
5259 static ULONG STDMETHODCALLTYPE dxgi_factory_Release(IDXGIFactory *iface)
5261 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5262 return IDXGIFactory_Release(factory->wrapped_iface);
5265 static HRESULT STDMETHODCALLTYPE dxgi_factory_SetPrivateData(IDXGIFactory *iface,
5266 REFGUID guid, UINT data_size, const void *data)
5268 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5269 return IDXGIFactory_SetPrivateData(factory->wrapped_iface, guid, data_size, data);
5272 static HRESULT STDMETHODCALLTYPE dxgi_factory_SetPrivateDataInterface(IDXGIFactory *iface,
5273 REFGUID guid, const IUnknown *object)
5275 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5276 return IDXGIFactory_SetPrivateDataInterface(factory->wrapped_iface, guid, object);
5279 static HRESULT STDMETHODCALLTYPE dxgi_factory_GetPrivateData(IDXGIFactory *iface,
5280 REFGUID guid, UINT *data_size, void *data)
5282 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5283 return IDXGIFactory_GetPrivateData(factory->wrapped_iface, guid, data_size, data);
5286 static HRESULT STDMETHODCALLTYPE dxgi_factory_GetParent(IDXGIFactory *iface, REFIID iid, void **parent)
5288 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5289 return IDXGIFactory_GetParent(factory->wrapped_iface, iid, parent);
5292 static HRESULT STDMETHODCALLTYPE dxgi_factory_EnumAdapters(IDXGIFactory *iface,
5293 UINT adapter_idx, IDXGIAdapter **adapter)
5295 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5296 HRESULT hr;
5298 if (SUCCEEDED(hr = IDXGIFactory_EnumAdapters(factory->wrapped_iface, adapter_idx, adapter)))
5299 ++factory->wrapped_adapter_count;
5300 return hr;
5303 static HRESULT STDMETHODCALLTYPE dxgi_factory_MakeWindowAssociation(IDXGIFactory *iface,
5304 HWND window, UINT flags)
5306 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5307 return IDXGIFactory_MakeWindowAssociation(factory->wrapped_iface, window, flags);
5310 static HRESULT STDMETHODCALLTYPE dxgi_factory_GetWindowAssociation(IDXGIFactory *iface, HWND *window)
5312 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5313 return IDXGIFactory_GetWindowAssociation(factory->wrapped_iface, window);
5316 static HRESULT STDMETHODCALLTYPE dxgi_factory_CreateSwapChain(IDXGIFactory *iface,
5317 IUnknown *device, DXGI_SWAP_CHAIN_DESC *desc, IDXGISwapChain **swapchain)
5319 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5320 return IDXGIFactory_CreateSwapChain(factory->wrapped_iface, device, desc, swapchain);
5323 static HRESULT STDMETHODCALLTYPE dxgi_factory_CreateSoftwareAdapter(IDXGIFactory *iface,
5324 HMODULE swrast, IDXGIAdapter **adapter)
5326 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5327 return IDXGIFactory_CreateSoftwareAdapter(factory->wrapped_iface, swrast, adapter);
5330 static const struct IDXGIFactoryVtbl dxgi_factory_vtbl =
5332 dxgi_factory_QueryInterface,
5333 dxgi_factory_AddRef,
5334 dxgi_factory_Release,
5335 dxgi_factory_SetPrivateData,
5336 dxgi_factory_SetPrivateDataInterface,
5337 dxgi_factory_GetPrivateData,
5338 dxgi_factory_GetParent,
5339 dxgi_factory_EnumAdapters,
5340 dxgi_factory_MakeWindowAssociation,
5341 dxgi_factory_GetWindowAssociation,
5342 dxgi_factory_CreateSwapChain,
5343 dxgi_factory_CreateSoftwareAdapter,
5346 struct dxgi_adapter
5348 IDXGIAdapter IDXGIAdapter_iface;
5349 IDXGIAdapter *wrapped_iface;
5350 struct dxgi_factory factory;
5351 unsigned int wrapped_output_count;
5354 static inline struct dxgi_adapter *impl_from_IDXGIAdapter(IDXGIAdapter *iface)
5356 return CONTAINING_RECORD(iface, struct dxgi_adapter, IDXGIAdapter_iface);
5359 static HRESULT STDMETHODCALLTYPE dxgi_adapter_QueryInterface(IDXGIAdapter *iface, REFIID iid, void **out)
5361 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5363 if (IsEqualGUID(iid, &IID_IDXGIAdapter)
5364 || IsEqualGUID(iid, &IID_IDXGIObject)
5365 || IsEqualGUID(iid, &IID_IUnknown))
5367 IDXGIAdapter_AddRef(adapter->wrapped_iface);
5368 *out = iface;
5369 return S_OK;
5371 return IDXGIAdapter_QueryInterface(adapter->wrapped_iface, iid, out);
5374 static ULONG STDMETHODCALLTYPE dxgi_adapter_AddRef(IDXGIAdapter *iface)
5376 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5377 return IDXGIAdapter_AddRef(adapter->wrapped_iface);
5380 static ULONG STDMETHODCALLTYPE dxgi_adapter_Release(IDXGIAdapter *iface)
5382 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5383 return IDXGIAdapter_Release(adapter->wrapped_iface);
5386 static HRESULT STDMETHODCALLTYPE dxgi_adapter_SetPrivateData(IDXGIAdapter *iface,
5387 REFGUID guid, UINT data_size, const void *data)
5389 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5390 return IDXGIAdapter_SetPrivateData(adapter->wrapped_iface, guid, data_size, data);
5393 static HRESULT STDMETHODCALLTYPE dxgi_adapter_SetPrivateDataInterface(IDXGIAdapter *iface,
5394 REFGUID guid, const IUnknown *object)
5396 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5397 return IDXGIAdapter_SetPrivateDataInterface(adapter->wrapped_iface, guid, object);
5400 static HRESULT STDMETHODCALLTYPE dxgi_adapter_GetPrivateData(IDXGIAdapter *iface,
5401 REFGUID guid, UINT *data_size, void *data)
5403 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5404 return IDXGIAdapter_GetPrivateData(adapter->wrapped_iface, guid, data_size, data);
5407 static HRESULT STDMETHODCALLTYPE dxgi_adapter_GetParent(IDXGIAdapter *iface, REFIID iid, void **parent)
5409 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5410 return IDXGIFactory_QueryInterface(&adapter->factory.IDXGIFactory_iface, iid, parent);
5413 static HRESULT STDMETHODCALLTYPE dxgi_adapter_EnumOutputs(IDXGIAdapter *iface,
5414 UINT output_idx, IDXGIOutput **output)
5416 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5417 HRESULT hr;
5419 if (SUCCEEDED(hr = IDXGIAdapter_EnumOutputs(adapter->wrapped_iface, output_idx, output)))
5420 ++adapter->wrapped_output_count;
5421 return hr;
5424 static HRESULT STDMETHODCALLTYPE dxgi_adapter_GetDesc(IDXGIAdapter *iface, DXGI_ADAPTER_DESC *desc)
5426 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5427 return IDXGIAdapter_GetDesc(adapter->wrapped_iface, desc);
5430 static HRESULT STDMETHODCALLTYPE dxgi_adapter_CheckInterfaceSupport(IDXGIAdapter *iface,
5431 REFGUID guid, LARGE_INTEGER *umd_version)
5433 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5434 return IDXGIAdapter_CheckInterfaceSupport(adapter->wrapped_iface, guid, umd_version);
5437 static const struct IDXGIAdapterVtbl dxgi_adapter_vtbl =
5439 dxgi_adapter_QueryInterface,
5440 dxgi_adapter_AddRef,
5441 dxgi_adapter_Release,
5442 dxgi_adapter_SetPrivateData,
5443 dxgi_adapter_SetPrivateDataInterface,
5444 dxgi_adapter_GetPrivateData,
5445 dxgi_adapter_GetParent,
5446 dxgi_adapter_EnumOutputs,
5447 dxgi_adapter_GetDesc,
5448 dxgi_adapter_CheckInterfaceSupport,
5451 static void test_object_wrapping(void)
5453 struct dxgi_adapter wrapper;
5454 DXGI_ADAPTER_DESC desc;
5455 IDXGIAdapter *adapter;
5456 IDXGIFactory *factory;
5457 ID3D10Device1 *device;
5458 ULONG refcount;
5459 HRESULT hr;
5461 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory);
5462 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5464 hr = IDXGIFactory_EnumAdapters(factory, 0, &adapter);
5465 if (hr == DXGI_ERROR_NOT_FOUND)
5467 skip("Could not enumerate adapters.\n");
5468 IDXGIFactory_Release(factory);
5469 return;
5471 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5473 wrapper.IDXGIAdapter_iface.lpVtbl = &dxgi_adapter_vtbl;
5474 wrapper.wrapped_iface = adapter;
5475 wrapper.factory.IDXGIFactory_iface.lpVtbl = &dxgi_factory_vtbl;
5476 wrapper.factory.wrapped_iface = factory;
5477 wrapper.factory.wrapped_adapter_count = 0;
5478 wrapper.wrapped_output_count = 0;
5480 hr = D3D10CreateDevice1(&wrapper.IDXGIAdapter_iface, D3D10_DRIVER_TYPE_HARDWARE, NULL,
5481 0, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device);
5482 if (SUCCEEDED(hr))
5484 refcount = ID3D10Device1_Release(device);
5485 ok(!refcount, "Device has %lu references left.\n", refcount);
5488 hr = IDXGIAdapter_GetDesc(&wrapper.IDXGIAdapter_iface, &desc);
5489 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5490 ok(!wrapper.factory.wrapped_adapter_count, "Got unexpected wrapped adapter count %u.\n",
5491 wrapper.factory.wrapped_adapter_count);
5492 ok(!wrapper.wrapped_output_count, "Got unexpected wrapped output count %u.\n", wrapper.wrapped_output_count);
5494 refcount = IDXGIAdapter_Release(&wrapper.IDXGIAdapter_iface);
5495 ok(!refcount, "Adapter has %lu references left.\n", refcount);
5496 refcount = IDXGIFactory_Release(factory);
5497 ok(!refcount, "Factory has %lu references left.\n", refcount);
5500 struct adapter_info
5502 const WCHAR *name;
5503 HMONITOR monitor;
5506 static BOOL CALLBACK enum_monitor_proc(HMONITOR monitor, HDC dc, RECT *rect, LPARAM lparam)
5508 struct adapter_info *adapter_info = (struct adapter_info *)lparam;
5509 MONITORINFOEXW monitor_info;
5511 monitor_info.cbSize = sizeof(monitor_info);
5512 if (GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info)
5513 && !lstrcmpiW(adapter_info->name, monitor_info.szDevice))
5515 adapter_info->monitor = monitor;
5516 return FALSE;
5519 return TRUE;
5522 static HMONITOR get_monitor(const WCHAR *adapter_name)
5524 struct adapter_info info = {adapter_name, NULL};
5526 EnumDisplayMonitors(NULL, NULL, enum_monitor_proc, (LPARAM)&info);
5527 return info.monitor;
5530 static void test_multi_adapter(void)
5532 unsigned int output_count = 0, expected_output_count = 0;
5533 unsigned int adapter_index, output_index, device_index;
5534 DXGI_OUTPUT_DESC old_output_desc, output_desc;
5535 DXGI_ADAPTER_DESC1 adapter_desc1;
5536 DXGI_ADAPTER_DESC adapter_desc;
5537 DISPLAY_DEVICEW display_device;
5538 MONITORINFO monitor_info;
5539 DEVMODEW old_mode, mode;
5540 IDXGIAdapter1 *adapter1;
5541 IDXGIFactory *factory;
5542 IDXGIAdapter *adapter;
5543 IDXGIOutput *output;
5544 HMONITOR monitor;
5545 BOOL found;
5546 HRESULT hr;
5547 LONG ret;
5549 if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory)))
5551 skip("Failed to create IDXGIFactory, hr %#lx.\n", hr);
5552 return;
5555 hr = IDXGIFactory_EnumAdapters(factory, 0, NULL);
5556 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
5558 hr = IDXGIFactory_EnumAdapters(factory, 0, &adapter);
5559 if (hr == DXGI_ERROR_NOT_FOUND)
5561 skip("Could not enumerate adapters.\n");
5562 IDXGIFactory_Release(factory);
5563 return;
5565 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5567 for (adapter_index = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_index, &adapter)); ++adapter_index)
5569 for (output_index = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_index, &output)); ++output_index)
5571 hr = IDXGIOutput_GetDesc(output, &output_desc);
5572 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_index,
5573 output_index, hr);
5575 found = FALSE;
5576 display_device.cb = sizeof(display_device);
5577 for (device_index = 0; EnumDisplayDevicesW(NULL, device_index, &display_device, 0); ++device_index)
5579 if (!lstrcmpiW(display_device.DeviceName, output_desc.DeviceName))
5581 found = TRUE;
5582 break;
5585 ok(found, "Adapter %u output %u: Failed to find device %s.\n",
5586 adapter_index, output_index, wine_dbgstr_w(output_desc.DeviceName));
5588 ok(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP,
5589 "Adapter %u output %u: Got unexpected state flags %#lx.\n", adapter_index,
5590 output_index, display_device.StateFlags);
5591 if (!adapter_index && !output_index)
5592 ok(display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE,
5593 "Adapter %u output %u: Got unexpected state flags %#lx.\n", adapter_index,
5594 output_index, display_device.StateFlags);
5595 else
5596 ok(!(display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE),
5597 "Adapter %u output %u: Got unexpected state flags %#lx.\n", adapter_index,
5598 output_index, display_device.StateFlags);
5600 /* Should have the same monitor handle. */
5601 monitor = get_monitor(display_device.DeviceName);
5602 ok(!!monitor, "Adapter %u output %u: Failed to find monitor %s.\n", adapter_index,
5603 output_index, wine_dbgstr_w(display_device.DeviceName));
5604 ok(monitor == output_desc.Monitor,
5605 "Adapter %u output %u: Got unexpected monitor %p, expected %p.\n",
5606 adapter_index, output_index, monitor, output_desc.Monitor);
5608 /* Should have the same monitor rectangle. */
5609 monitor_info.cbSize = sizeof(monitor_info);
5610 ret = GetMonitorInfoA(monitor, &monitor_info);
5611 ok(ret, "Adapter %u output %u: Failed to get monitor info, error %#lx.\n", adapter_index,
5612 output_index, GetLastError());
5613 ok(EqualRect(&monitor_info.rcMonitor, &output_desc.DesktopCoordinates),
5614 "Adapter %u output %u: Got unexpected output rect %s, expected %s.\n",
5615 adapter_index, output_index, wine_dbgstr_rect(&monitor_info.rcMonitor),
5616 wine_dbgstr_rect(&output_desc.DesktopCoordinates));
5618 ++output_count;
5620 /* Test output description after it got detached */
5621 if (display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
5623 IDXGIOutput_Release(output);
5624 continue;
5627 old_output_desc = output_desc;
5629 /* Save current display settings */
5630 memset(&old_mode, 0, sizeof(old_mode));
5631 old_mode.dmSize = sizeof(old_mode);
5632 ret = EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &old_mode);
5633 /* Win10 TestBots may return FALSE but it's actually successful */
5634 ok(ret || broken(!ret),
5635 "Adapter %u output %u: EnumDisplaySettingsW failed for %s, error %#lx.\n",
5636 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName),
5637 GetLastError());
5639 /* Detach */
5640 memset(&mode, 0, sizeof(mode));
5641 mode.dmSize = sizeof(mode);
5642 mode.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
5643 mode.dmPosition = old_mode.dmPosition;
5644 ret = ChangeDisplaySettingsExW(display_device.DeviceName, &mode, NULL,
5645 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
5646 ok(ret == DISP_CHANGE_SUCCESSFUL,
5647 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %ld.\n",
5648 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5649 ret = ChangeDisplaySettingsExW(display_device.DeviceName, NULL, NULL, 0, NULL);
5650 ok(ret == DISP_CHANGE_SUCCESSFUL,
5651 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %ld.\n",
5652 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5654 /* Check if it is really detached */
5655 memset(&mode, 0, sizeof(mode));
5656 mode.dmSize = sizeof(mode);
5657 ret = EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &mode);
5658 /* Win10 TestBots may return FALSE but it's actually successful */
5659 ok(ret || broken(!ret) ,
5660 "Adapter %u output %u: EnumDisplaySettingsW failed for %s, error %#lx.\n",
5661 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName),
5662 GetLastError());
5663 if (mode.dmPelsWidth && mode.dmPelsHeight)
5665 skip("Adapter %u output %u: Failed to detach device %s.\n", adapter_index,
5666 output_index, wine_dbgstr_w(display_device.DeviceName));
5667 IDXGIOutput_Release(output);
5668 continue;
5671 /* Only the AttachedToDesktop field is updated after an output is detached.
5672 * IDXGIAdapter_EnumOutputs() has to be called again to get other fields updated.
5673 * But resolution changes are reflected right away. This weird behaviour is currently
5674 * unimplemented in Wine */
5675 memset(&output_desc, 0, sizeof(output_desc));
5676 hr = IDXGIOutput_GetDesc(output, &output_desc);
5677 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_index,
5678 output_index, hr);
5679 ok(!lstrcmpiW(output_desc.DeviceName, old_output_desc.DeviceName),
5680 "Adapter %u output %u: Expect device name %s, got %s.\n", adapter_index,
5681 output_index, wine_dbgstr_w(old_output_desc.DeviceName),
5682 wine_dbgstr_w(output_desc.DeviceName));
5683 todo_wine
5684 ok(EqualRect(&output_desc.DesktopCoordinates, &old_output_desc.DesktopCoordinates),
5685 "Adapter %u output %u: Expect desktop coordinates %s, got %s.\n",
5686 adapter_index, output_index,
5687 wine_dbgstr_rect(&old_output_desc.DesktopCoordinates),
5688 wine_dbgstr_rect(&output_desc.DesktopCoordinates));
5689 ok(!output_desc.AttachedToDesktop,
5690 "Adapter %u output %u: Expect output not attached to desktop.\n", adapter_index,
5691 output_index);
5692 ok(output_desc.Rotation == old_output_desc.Rotation,
5693 "Adapter %u output %u: Expect rotation %#x, got %#x.\n", adapter_index,
5694 output_index, old_output_desc.Rotation, output_desc.Rotation);
5695 todo_wine
5696 ok(output_desc.Monitor == old_output_desc.Monitor,
5697 "Adapter %u output %u: Expect monitor %p, got %p.\n", adapter_index,
5698 output_index, old_output_desc.Monitor, output_desc.Monitor);
5699 IDXGIOutput_Release(output);
5701 /* Call IDXGIAdapter_EnumOutputs() again to get up-to-date output description */
5702 hr = IDXGIAdapter_EnumOutputs(adapter, output_index, &output);
5703 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_index,
5704 output_index, hr);
5705 memset(&output_desc, 0, sizeof(output_desc));
5706 hr = IDXGIOutput_GetDesc(output, &output_desc);
5707 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_index,
5708 output_index, hr);
5709 ok(!lstrcmpiW(output_desc.DeviceName, display_device.DeviceName),
5710 "Adapter %u output %u: Expect device name %s, got %s.\n", adapter_index,
5711 output_index, wine_dbgstr_w(display_device.DeviceName),
5712 wine_dbgstr_w(output_desc.DeviceName));
5713 ok(IsRectEmpty(&output_desc.DesktopCoordinates),
5714 "Adapter %u output %u: Expect desktop rect empty, got %s.\n", adapter_index,
5715 output_index, wine_dbgstr_rect(&output_desc.DesktopCoordinates));
5716 ok(!output_desc.AttachedToDesktop,
5717 "Adapter %u output %u: Expect output not attached to desktop.\n", adapter_index,
5718 output_index);
5719 ok(output_desc.Rotation == DXGI_MODE_ROTATION_IDENTITY,
5720 "Adapter %u output %u: Expect rotation %#x, got %#x.\n", adapter_index,
5721 output_index, DXGI_MODE_ROTATION_IDENTITY, output_desc.Rotation);
5722 ok(!output_desc.Monitor, "Adapter %u output %u: Expect monitor NULL.\n", adapter_index,
5723 output_index);
5725 /* Restore settings */
5726 ret = ChangeDisplaySettingsExW(display_device.DeviceName, &old_mode, NULL,
5727 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
5728 ok(ret == DISP_CHANGE_SUCCESSFUL,
5729 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %ld.\n",
5730 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5731 ret = ChangeDisplaySettingsExW(display_device.DeviceName, NULL, NULL, 0, NULL);
5732 ok(ret == DISP_CHANGE_SUCCESSFUL,
5733 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %ld.\n",
5734 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5736 IDXGIOutput_Release(output);
5739 IDXGIAdapter_Release(adapter);
5742 /* Windows 8+ always have a WARP adapter present at the end. */
5743 todo_wine ok(adapter_index >= 2 || broken(adapter_index < 2) /* Windows 7 and before */,
5744 "Got unexpected adapter count %u.\n", adapter_index);
5745 if (adapter_index < 2)
5747 todo_wine win_skip("WARP adapter missing, skipping tests.\n");
5748 goto done;
5751 hr = IDXGIFactory_EnumAdapters(factory, adapter_index - 1, &adapter);
5752 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5753 hr = IDXGIAdapter_GetDesc(adapter, &adapter_desc);
5754 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5755 todo_wine ok(!lstrcmpW(adapter_desc.Description, L"Microsoft Basic Render Driver"),
5756 "Got unexpected description %s.\n", wine_dbgstr_w(adapter_desc.Description));
5757 todo_wine ok(adapter_desc.VendorId == 0x1414,
5758 "Got unexpected vendor ID %#x.\n", adapter_desc.VendorId);
5759 todo_wine ok(adapter_desc.DeviceId == 0x008c,
5760 "Got unexpected device ID %#x.\n", adapter_desc.DeviceId);
5761 ok(adapter_desc.SubSysId == 0x0000,
5762 "Got unexpected sub-system ID %#x.\n", adapter_desc.SubSysId);
5763 ok(adapter_desc.Revision == 0x0000,
5764 "Got unexpected revision %#x.\n", adapter_desc.Revision);
5765 todo_wine ok(!adapter_desc.DedicatedVideoMemory,
5766 "Got unexpected DedicatedVideoMemory %#Ix.\n", adapter_desc.DedicatedVideoMemory);
5767 ok(!adapter_desc.DedicatedSystemMemory,
5768 "Got unexpected DedicatedSystemMemory %#Ix.\n", adapter_desc.DedicatedSystemMemory);
5770 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter1, (void **)&adapter1);
5771 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Got unexpected hr %#lx.\n", hr);
5772 if (SUCCEEDED(hr))
5774 hr = IDXGIAdapter1_GetDesc1(adapter1, &adapter_desc1);
5775 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5776 todo_wine ok(adapter_desc1.Flags == DXGI_ADAPTER_FLAG_SOFTWARE,
5777 "Got unexpected flags %#x.\n", adapter_desc1.Flags);
5778 IDXGIAdapter1_Release(adapter1);
5781 IDXGIAdapter_Release(adapter);
5783 done:
5784 IDXGIFactory_Release(factory);
5786 expected_output_count = GetSystemMetrics(SM_CMONITORS);
5787 ok(output_count == expected_output_count, "Expect output count %d, got %d\n",
5788 expected_output_count, output_count);
5791 struct message
5793 unsigned int message;
5794 BOOL check_wparam;
5795 WPARAM expect_wparam;
5798 static BOOL expect_no_messages;
5799 static const struct message *expect_messages;
5800 static const struct message *expect_messages_broken;
5802 static BOOL check_message(const struct message *expected,
5803 HWND hwnd, unsigned int message, WPARAM wparam, LPARAM lparam)
5805 if (expected->message != message)
5806 return FALSE;
5808 if (expected->check_wparam)
5810 ok(wparam == expected->expect_wparam,
5811 "Got unexpected wparam %Ix for message %x, expected %Ix.\n",
5812 wparam, message, expected->expect_wparam);
5815 return TRUE;
5818 static LRESULT CALLBACK test_wndproc(HWND hwnd, unsigned int message, WPARAM wparam, LPARAM lparam)
5820 ok(!expect_no_messages, "Got unexpected message %#x, hwnd %p, wparam %#Ix, lparam %#Ix.\n",
5821 message, hwnd, wparam, lparam);
5823 if (expect_messages)
5825 if (check_message(expect_messages, hwnd, message, wparam, lparam))
5826 ++expect_messages;
5829 if (expect_messages_broken)
5831 if (check_message(expect_messages_broken, hwnd, message, wparam, lparam))
5832 ++expect_messages_broken;
5835 return DefWindowProcA(hwnd, message, wparam, lparam);
5838 static void test_swapchain_window_messages(void)
5840 DXGI_SWAP_CHAIN_DESC swapchain_desc;
5841 IDXGISwapChain *swapchain;
5842 DXGI_MODE_DESC mode_desc;
5843 IDXGIFactory *factory;
5844 IDXGIAdapter *adapter;
5845 IDXGIDevice *device;
5846 ULONG refcount;
5847 WNDCLASSA wc;
5848 HWND window;
5849 HRESULT hr;
5851 static const struct message enter_fullscreen_messages[] =
5853 {WM_STYLECHANGING, TRUE, GWL_STYLE},
5854 {WM_STYLECHANGED, TRUE, GWL_STYLE},
5855 {WM_STYLECHANGING, TRUE, GWL_EXSTYLE},
5856 {WM_STYLECHANGED, TRUE, GWL_EXSTYLE},
5857 {WM_WINDOWPOSCHANGING, FALSE, 0},
5858 {WM_GETMINMAXINFO, FALSE, 0},
5859 {WM_NCCALCSIZE, FALSE, 0},
5860 {WM_WINDOWPOSCHANGED, FALSE, 0},
5861 {WM_MOVE, FALSE, 0},
5862 {WM_SIZE, FALSE, 0},
5863 {0, FALSE, 0},
5865 static const struct message enter_fullscreen_messages_vista[] =
5867 {WM_STYLECHANGING, TRUE, GWL_STYLE},
5868 {WM_STYLECHANGED, TRUE, GWL_STYLE},
5869 {WM_WINDOWPOSCHANGING, FALSE, 0},
5870 {WM_NCCALCSIZE, FALSE, 0},
5871 {WM_WINDOWPOSCHANGED, FALSE, 0},
5872 {WM_MOVE, FALSE, 0},
5873 {WM_SIZE, FALSE, 0},
5874 {WM_STYLECHANGING, TRUE, GWL_EXSTYLE},
5875 {WM_STYLECHANGED, TRUE, GWL_EXSTYLE},
5876 {WM_WINDOWPOSCHANGING, FALSE, 0},
5877 {WM_GETMINMAXINFO, FALSE, 0},
5878 {WM_NCCALCSIZE, FALSE, 0},
5879 {WM_WINDOWPOSCHANGED, FALSE, 0},
5880 {WM_SIZE, FALSE, 0},
5881 {0, FALSE, 0},
5883 static const struct message leave_fullscreen_messages[] =
5885 {WM_STYLECHANGING, TRUE, GWL_STYLE},
5886 {WM_STYLECHANGED, TRUE, GWL_STYLE},
5887 {WM_STYLECHANGING, TRUE, GWL_EXSTYLE},
5888 {WM_STYLECHANGED, TRUE, GWL_EXSTYLE},
5889 {WM_WINDOWPOSCHANGING, FALSE, 0},
5890 {WM_GETMINMAXINFO, FALSE, 0},
5891 {WM_NCCALCSIZE, FALSE, 0},
5892 {WM_WINDOWPOSCHANGED, FALSE, 0},
5893 {WM_MOVE, FALSE, 0},
5894 {WM_SIZE, FALSE, 0},
5895 {0, FALSE, 0},
5897 static const struct message resize_target_messages[] =
5899 {WM_WINDOWPOSCHANGING, FALSE, 0},
5900 {WM_GETMINMAXINFO, FALSE, 0},
5901 {WM_NCCALCSIZE, FALSE, 0},
5902 {WM_WINDOWPOSCHANGED, FALSE, 0},
5903 {WM_SIZE, FALSE, 0},
5904 {0, FALSE, 0},
5907 if (!(device = create_device(0)))
5909 skip("Failed to create device.\n");
5910 return;
5913 memset(&wc, 0, sizeof(wc));
5914 wc.lpfnWndProc = test_wndproc;
5915 wc.lpszClassName = "dxgi_test_wndproc_wc";
5916 ok(RegisterClassA(&wc), "Failed to register window class.\n");
5917 window = CreateWindowA("dxgi_test_wndproc_wc", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
5918 ok(!!window, "Failed to create window.\n");
5920 hr = IDXGIDevice_GetAdapter(device, &adapter);
5921 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5922 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
5923 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5924 IDXGIAdapter_Release(adapter);
5926 swapchain_desc.BufferDesc.Width = 800;
5927 swapchain_desc.BufferDesc.Height = 600;
5928 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
5929 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
5930 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
5931 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
5932 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
5933 swapchain_desc.SampleDesc.Count = 1;
5934 swapchain_desc.SampleDesc.Quality = 0;
5935 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5936 swapchain_desc.BufferCount = 1;
5937 swapchain_desc.OutputWindow = window;
5938 swapchain_desc.Windowed = TRUE;
5939 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
5940 swapchain_desc.Flags = 0;
5942 /* create swapchain */
5943 flush_events();
5944 expect_no_messages = TRUE;
5945 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
5946 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5947 flush_events();
5948 expect_no_messages = FALSE;
5950 /* resize target */
5951 expect_messages = resize_target_messages;
5952 memset(&mode_desc, 0, sizeof(mode_desc));
5953 mode_desc.Width = 800;
5954 mode_desc.Height = 600;
5955 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode_desc);
5956 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5957 flush_events();
5958 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
5960 expect_messages = resize_target_messages;
5961 memset(&mode_desc, 0, sizeof(mode_desc));
5962 mode_desc.Width = 400;
5963 mode_desc.Height = 200;
5964 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode_desc);
5965 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5966 flush_events();
5967 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
5969 /* enter fullscreen */
5970 expect_messages = enter_fullscreen_messages;
5971 expect_messages_broken = enter_fullscreen_messages_vista;
5972 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
5973 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
5974 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
5975 "Got unexpected hr %#lx.\n", hr);
5976 if (FAILED(hr))
5978 skip("Could not change fullscreen state.\n");
5979 goto done;
5981 flush_events();
5982 todo_wine
5983 ok(!expect_messages->message || broken(!expect_messages_broken->message),
5984 "Expected message %#x or %#x.\n",
5985 expect_messages->message, expect_messages_broken->message);
5986 expect_messages_broken = NULL;
5988 /* leave fullscreen */
5989 expect_messages = leave_fullscreen_messages;
5990 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
5991 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5992 flush_events();
5993 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
5994 expect_messages = NULL;
5996 refcount = IDXGISwapChain_Release(swapchain);
5997 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
5999 /* create fullscreen swapchain */
6000 DestroyWindow(window);
6001 window = CreateWindowA("dxgi_test_wndproc_wc", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
6002 ok(!!window, "Failed to create window.\n");
6003 swapchain_desc.OutputWindow = window;
6004 swapchain_desc.Windowed = FALSE;
6005 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
6006 flush_events();
6008 expect_messages = enter_fullscreen_messages;
6009 expect_messages_broken = enter_fullscreen_messages_vista;
6010 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
6011 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6012 flush_events();
6013 todo_wine
6014 ok(!expect_messages->message || broken(!expect_messages_broken->message),
6015 "Expected message %#x or %#x.\n",
6016 expect_messages->message, expect_messages_broken->message);
6017 expect_messages_broken = NULL;
6019 /* leave fullscreen */
6020 expect_messages = leave_fullscreen_messages;
6021 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6022 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6023 flush_events();
6024 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
6025 expect_messages = NULL;
6027 done:
6028 refcount = IDXGISwapChain_Release(swapchain);
6029 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6030 DestroyWindow(window);
6032 refcount = IDXGIDevice_Release(device);
6033 ok(!refcount, "Device has %lu references left.\n", refcount);
6034 refcount = IDXGIFactory_Release(factory);
6035 ok(!refcount, "Factory has %lu references left.\n", refcount);
6037 UnregisterClassA("dxgi_test_wndproc_wc", GetModuleHandleA(NULL));
6040 static void test_swapchain_window_styles(void)
6042 LONG style, exstyle, fullscreen_style, fullscreen_exstyle;
6043 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6044 IDXGISwapChain *swapchain;
6045 IDXGIFactory *factory;
6046 IDXGIAdapter *adapter;
6047 IDXGIDevice *device;
6048 ULONG refcount;
6049 unsigned int i;
6050 HRESULT hr;
6052 static const struct
6054 LONG style, exstyle;
6055 LONG expected_style, expected_exstyle;
6057 tests[] =
6059 {WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0,
6060 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS,
6061 WS_EX_WINDOWEDGE},
6062 {WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE, 0,
6063 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | WS_VISIBLE,
6064 WS_EX_WINDOWEDGE},
6065 {WS_OVERLAPPED | WS_VISIBLE, 0,
6066 WS_OVERLAPPED | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION, WS_EX_WINDOWEDGE},
6067 {WS_OVERLAPPED | WS_MAXIMIZE, 0,
6068 WS_OVERLAPPED | WS_MAXIMIZE | WS_CLIPSIBLINGS | WS_CAPTION, WS_EX_WINDOWEDGE},
6069 {WS_OVERLAPPED | WS_MINIMIZE, 0,
6070 WS_OVERLAPPED | WS_MINIMIZE | WS_CLIPSIBLINGS | WS_CAPTION, WS_EX_WINDOWEDGE},
6071 {WS_CAPTION | WS_DISABLED, WS_EX_TOPMOST,
6072 WS_CAPTION | WS_DISABLED | WS_CLIPSIBLINGS, WS_EX_TOPMOST | WS_EX_WINDOWEDGE},
6073 {WS_CAPTION | WS_DISABLED | WS_VISIBLE, WS_EX_TOPMOST,
6074 WS_CAPTION | WS_DISABLED | WS_VISIBLE | WS_CLIPSIBLINGS, WS_EX_TOPMOST | WS_EX_WINDOWEDGE},
6075 {WS_CAPTION | WS_SYSMENU | WS_VISIBLE, WS_EX_APPWINDOW,
6076 WS_CAPTION | WS_SYSMENU | WS_VISIBLE | WS_CLIPSIBLINGS, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE},
6077 {WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER | WS_DLGFRAME
6078 | WS_VSCROLL | WS_HSCROLL | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
6080 WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER | WS_DLGFRAME
6081 | WS_VSCROLL | WS_HSCROLL | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
6082 WS_EX_WINDOWEDGE},
6085 if (!(device = create_device(0)))
6087 skip("Failed to create device.\n");
6088 return;
6091 hr = IDXGIDevice_GetAdapter(device, &adapter);
6092 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6093 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
6094 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6095 IDXGIAdapter_Release(adapter);
6097 swapchain_desc.BufferDesc.Width = 800;
6098 swapchain_desc.BufferDesc.Height = 600;
6099 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6100 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
6101 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6102 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6103 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6104 swapchain_desc.SampleDesc.Count = 1;
6105 swapchain_desc.SampleDesc.Quality = 0;
6106 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6107 swapchain_desc.BufferCount = 1;
6108 swapchain_desc.Windowed = TRUE;
6109 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
6110 swapchain_desc.Flags = 0;
6112 for (i = 0; i < ARRAY_SIZE(tests); ++i)
6114 winetest_push_context("Test %u", i);
6116 swapchain_desc.OutputWindow = CreateWindowExA(tests[i].exstyle, "static", "dxgi_test",
6117 tests[i].style, 0, 0, 400, 200, 0, 0, 0, 0);
6119 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6120 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6121 ok(style == tests[i].expected_style, "Got unexpected style %#lx, expected %#lx.\n",
6122 style, tests[i].expected_style);
6123 ok(exstyle == tests[i].expected_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6124 exstyle, tests[i].expected_exstyle);
6126 fullscreen_style = tests[i].expected_style & ~(WS_POPUP | WS_MAXIMIZEBOX
6127 | WS_MINIMIZEBOX | WS_THICKFRAME | WS_SYSMENU | WS_DLGFRAME | WS_BORDER);
6128 fullscreen_exstyle = tests[i].expected_exstyle & ~(WS_EX_DLGMODALFRAME
6129 | WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_CONTEXTHELP);
6130 fullscreen_exstyle |= WS_EX_TOPMOST;
6132 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
6133 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6135 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6136 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6137 ok(style == tests[i].expected_style, "Got unexpected style %#lx, expected %#lx.\n",
6138 style, tests[i].expected_style);
6139 ok(exstyle == tests[i].expected_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6140 exstyle, tests[i].expected_exstyle);
6142 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6143 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6144 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6145 "Got unexpected hr %#lx.\n", hr);
6146 if (SUCCEEDED(hr))
6148 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6149 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6150 todo_wine ok(style == fullscreen_style, "Got unexpected style %#lx, expected %#lx.\n",
6151 style, fullscreen_style);
6152 ok(exstyle == fullscreen_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6153 exstyle, fullscreen_exstyle);
6155 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6156 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6158 else
6160 skip("Could not change fullscreen state.\n");
6163 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6164 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6165 ok(style == tests[i].expected_style, "Got unexpected style %#lx, expected %#lx.\n",
6166 style, tests[i].expected_style);
6167 ok(exstyle == tests[i].expected_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6168 exstyle, tests[i].expected_exstyle);
6170 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6171 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6172 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6173 "Got unexpected hr %#lx.\n", hr);
6174 if (SUCCEEDED(hr))
6176 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6177 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6178 todo_wine ok(style == fullscreen_style, "Got unexpected style %#lx, expected %#lx.\n",
6179 style, fullscreen_style);
6180 ok(exstyle == fullscreen_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6181 exstyle, fullscreen_exstyle);
6183 SetWindowLongW(swapchain_desc.OutputWindow, GWL_STYLE, fullscreen_style);
6184 SetWindowLongW(swapchain_desc.OutputWindow, GWL_EXSTYLE, fullscreen_exstyle);
6186 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6187 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6189 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6190 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6191 todo_wine ok(style == tests[i].expected_style, "Got unexpected style %#lx, expected %#lx.\n",
6192 style, tests[i].expected_style);
6193 todo_wine
6194 ok(exstyle == tests[i].expected_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6195 exstyle, tests[i].expected_exstyle);
6197 else
6199 skip("Could not change fullscreen state.\n");
6202 refcount = IDXGISwapChain_Release(swapchain);
6203 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6205 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6206 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6207 todo_wine ok(style == tests[i].expected_style, "Got unexpected style %#lx, expected %#lx.\n",
6208 style, tests[i].expected_style);
6209 todo_wine
6210 ok(exstyle == tests[i].expected_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6211 exstyle, tests[i].expected_exstyle);
6213 DestroyWindow(swapchain_desc.OutputWindow);
6215 winetest_pop_context();
6218 refcount = IDXGIDevice_Release(device);
6219 ok(!refcount, "Device has %lu references left.\n", refcount);
6220 refcount = IDXGIFactory_Release(factory);
6221 ok(!refcount, "Factory has %lu references left.\n", refcount);
6224 static void test_gamma_control(void)
6226 DXGI_GAMMA_CONTROL_CAPABILITIES caps;
6227 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6228 IDXGISwapChain *swapchain;
6229 DXGI_GAMMA_CONTROL gamma;
6230 IDXGIFactory *factory;
6231 IDXGIAdapter *adapter;
6232 IDXGIDevice *device;
6233 IDXGIOutput *output;
6234 unsigned int i;
6235 ULONG refcount;
6236 HRESULT hr;
6238 if (!(device = create_device(0)))
6240 skip("Failed to create device.\n");
6241 return;
6244 hr = IDXGIDevice_GetAdapter(device, &adapter);
6245 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6247 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
6248 if (hr == DXGI_ERROR_NOT_FOUND)
6250 skip("Adapter doesn't have any outputs.\n");
6251 IDXGIAdapter_Release(adapter);
6252 IDXGIDevice_Release(device);
6253 return;
6255 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6257 hr = IDXGIOutput_GetGammaControlCapabilities(output, &caps);
6258 todo_wine
6259 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6260 IDXGIOutput_Release(output);
6262 swapchain_desc.BufferDesc.Width = 640;
6263 swapchain_desc.BufferDesc.Height = 480;
6264 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6265 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
6266 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6267 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6268 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6269 swapchain_desc.SampleDesc.Count = 1;
6270 swapchain_desc.SampleDesc.Quality = 0;
6271 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6272 swapchain_desc.BufferCount = 1;
6273 swapchain_desc.OutputWindow = create_window();
6274 swapchain_desc.Windowed = TRUE;
6275 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
6276 swapchain_desc.Flags = 0;
6278 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
6279 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6281 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
6282 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6283 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6284 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6285 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6286 "Got unexpected hr %#lx.\n", hr);
6287 if (FAILED(hr))
6289 skip("Could not change fullscreen state.\n");
6290 goto done;
6293 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
6294 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6296 memset(&caps, 0, sizeof(caps));
6297 hr = IDXGIOutput_GetGammaControlCapabilities(output, &caps);
6298 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6300 ok(caps.MaxConvertedValue > caps.MinConvertedValue
6301 || broken(caps.MaxConvertedValue == 0.0f && caps.MinConvertedValue == 1.0f) /* WARP */,
6302 "Expected max gamma value (%.8e) to be bigger than min value (%.8e).\n",
6303 caps.MaxConvertedValue, caps.MinConvertedValue);
6305 for (i = 1; i < caps.NumGammaControlPoints; ++i)
6307 ok(caps.ControlPointPositions[i] > caps.ControlPointPositions[i - 1],
6308 "Expected control point positions to be strictly monotonically increasing (%.8e > %.8e).\n",
6309 caps.ControlPointPositions[i], caps.ControlPointPositions[i - 1]);
6312 memset(&gamma, 0, sizeof(gamma));
6313 hr = IDXGIOutput_GetGammaControl(output, &gamma);
6314 todo_wine
6315 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6316 hr = IDXGIOutput_SetGammaControl(output, &gamma);
6317 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6319 IDXGIOutput_Release(output);
6321 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6322 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6324 done:
6325 refcount = IDXGISwapChain_Release(swapchain);
6326 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6327 DestroyWindow(swapchain_desc.OutputWindow);
6329 IDXGIAdapter_Release(adapter);
6330 refcount = IDXGIDevice_Release(device);
6331 ok(!refcount, "Device has %lu references left.\n", refcount);
6332 refcount = IDXGIFactory_Release(factory);
6333 ok(!refcount, "Factory has %lu references left.\n", refcount);
6336 static void test_window_association(IUnknown *device, BOOL is_d3d12)
6338 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6339 LONG_PTR original_wndproc, wndproc;
6340 IDXGIFactory *factory, *factory2;
6341 IDXGISwapChain *swapchain;
6342 IDXGIOutput *output;
6343 HWND hwnd, hwnd2;
6344 BOOL fullscreen;
6345 unsigned int i;
6346 ULONG refcount;
6347 HRESULT hr;
6349 static const struct
6351 UINT flag;
6352 BOOL expect_fullscreen;
6353 BOOL broken_d3d10;
6355 tests[] =
6357 /* There are two reasons why VK_TAB and VK_ESC are not tested here:
6359 * - Posting them to the window doesn't exit fullscreen like
6360 * Alt+Enter does. Alt+Tab and Alt+Esc are handled somewhere else.
6361 * E.g., not calling IDXGISwapChain::Present() will break Alt+Tab
6362 * and Alt+Esc while Alt+Enter will still function.
6364 * - Posting them hangs the posting thread. Another thread that keeps
6365 * sending input is needed to avoid the hang. The hang is not
6366 * because of flush_events(). */
6367 {0, TRUE},
6368 {0, FALSE},
6369 {DXGI_MWA_NO_WINDOW_CHANGES, FALSE},
6370 {DXGI_MWA_NO_WINDOW_CHANGES, FALSE},
6371 {DXGI_MWA_NO_ALT_ENTER, FALSE, TRUE},
6372 {DXGI_MWA_NO_ALT_ENTER, FALSE},
6373 {DXGI_MWA_NO_PRINT_SCREEN, TRUE},
6374 {DXGI_MWA_NO_PRINT_SCREEN, FALSE},
6375 {0, TRUE},
6376 {0, FALSE}
6379 swapchain_desc.BufferDesc.Width = 640;
6380 swapchain_desc.BufferDesc.Height = 480;
6381 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6382 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
6383 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6384 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6385 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6386 swapchain_desc.SampleDesc.Count = 1;
6387 swapchain_desc.SampleDesc.Quality = 0;
6388 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6389 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
6390 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
6391 swapchain_desc.Windowed = TRUE;
6392 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
6393 swapchain_desc.Flags = 0;
6395 original_wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6397 hwnd2 = CreateWindowA("static", "dxgi_test2", 0, 0, 0, 400, 200, 0, 0, 0, 0);
6398 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory2);
6399 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6401 get_factory(device, is_d3d12, &factory);
6403 hr = IDXGIFactory_GetWindowAssociation(factory, NULL);
6404 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6406 for (i = 0; i <= DXGI_MWA_VALID; ++i)
6408 hr = IDXGIFactory_MakeWindowAssociation(factory, NULL, i);
6409 ok(hr == S_OK, "Got unexpected hr %#lx for flags %#x.\n", hr, i);
6411 hr = IDXGIFactory_MakeWindowAssociation(factory, swapchain_desc.OutputWindow, i);
6412 ok(hr == S_OK, "Got unexpected hr %#lx for flags %#x.\n", hr, i);
6414 wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6415 ok(wndproc == original_wndproc, "Got unexpected wndproc %#Ix, expected %#Ix for flags %#x.\n",
6416 wndproc, original_wndproc, i);
6418 hwnd = (HWND)0xdeadbeef;
6419 hr = IDXGIFactory_GetWindowAssociation(factory, &hwnd);
6420 ok(hr == S_OK, "Got unexpected hr %#lx for flags %#x.\n", hr, i);
6421 /* Apparently GetWindowAssociation() always returns NULL, even when
6422 * MakeWindowAssociation() and GetWindowAssociation() are both
6423 * successfully called. */
6424 ok(!hwnd, "Expect null associated window.\n");
6427 hr = IDXGIFactory_MakeWindowAssociation(factory, swapchain_desc.OutputWindow, DXGI_MWA_VALID + 1);
6428 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6430 /* Alt+Enter tests. */
6431 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
6432 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6434 wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6435 ok(wndproc == original_wndproc, "Got unexpected wndproc %#Ix, expected %#Ix.\n", wndproc, original_wndproc);
6437 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6438 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6439 || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Windows 7 testbot */,
6440 "Got unexpected hr %#lx.\n", hr);
6441 if (FAILED(hr))
6443 skip("Could not change fullscreen state.\n");
6445 else
6447 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6448 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6450 for (i = 0; i < ARRAY_SIZE(tests); ++i)
6452 winetest_push_context("Test %u", i);
6454 /* First associate a window with the opposite flags. */
6455 hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd2, ~tests[i].flag & DXGI_MWA_VALID);
6456 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6458 /* Associate the current test window. */
6459 hwnd = tests[i].flag ? swapchain_desc.OutputWindow : NULL;
6460 hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd, tests[i].flag);
6461 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6463 /* Associating a new test window doesn't override the old window. */
6464 hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd2, ~tests[i].flag & DXGI_MWA_VALID);
6465 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6467 /* Associations with a different factory don't affect the existing
6468 * association. */
6469 hr = IDXGIFactory_MakeWindowAssociation(factory2, hwnd, ~tests[i].flag & DXGI_MWA_VALID);
6470 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6472 /* Post synthesized Alt + VK_RETURN WM_SYSKEYDOWN. */
6473 PostMessageA(swapchain_desc.OutputWindow, WM_SYSKEYDOWN, VK_RETURN,
6474 (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x20000001);
6475 flush_events();
6476 output = NULL;
6477 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
6478 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6479 ok(fullscreen == tests[i].expect_fullscreen
6480 || broken(tests[i].broken_d3d10 && fullscreen),
6481 "Got unexpected fullscreen %#x.\n", fullscreen);
6482 ok(fullscreen ? !!output : !output, "Got unexpected output.\n");
6483 if (output)
6484 IDXGIOutput_Release(output);
6486 wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6487 ok(wndproc == original_wndproc, "Got unexpected wndproc %#Ix, expected %#Ix.\n",
6488 wndproc, original_wndproc);
6490 winetest_pop_context();
6494 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6495 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6497 refcount = IDXGIFactory_Release(factory2);
6498 ok(!refcount, "Factory has %lu references left.\n", refcount);
6499 DestroyWindow(hwnd2);
6501 refcount = IDXGISwapChain_Release(swapchain);
6502 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6503 DestroyWindow(swapchain_desc.OutputWindow);
6505 refcount = IDXGIFactory_Release(factory);
6506 ok(refcount == !is_d3d12, "IDXGIFactory has %lu references left.\n", refcount);
6509 static void test_output_ownership(IUnknown *device, BOOL is_d3d12)
6511 D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
6512 D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP check_ownership_desc;
6513 D3DKMT_CLOSEADAPTER close_adapter_desc;
6514 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6515 DXGI_OUTPUT_DESC output_desc;
6516 IDXGISwapChain *swapchain;
6517 IDXGIFactory *factory;
6518 IDXGIAdapter *adapter;
6519 IDXGIOutput *output;
6520 BOOL fullscreen;
6521 NTSTATUS status;
6522 ULONG refcount;
6523 HRESULT hr;
6525 if (!pD3DKMTCheckVidPnExclusiveOwnership
6526 || pD3DKMTCheckVidPnExclusiveOwnership(NULL) == STATUS_PROCEDURE_NOT_FOUND)
6528 win_skip("D3DKMTCheckVidPnExclusiveOwnership() is unavailable.\n");
6529 return;
6532 get_factory(device, is_d3d12, &factory);
6533 adapter = get_adapter(device, is_d3d12);
6534 if (!adapter)
6536 skip("Failed to get adapter on Direct3D %d.\n", is_d3d12 ? 12 : 10);
6537 IDXGIFactory_Release(factory);
6538 return;
6541 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
6542 IDXGIAdapter_Release(adapter);
6543 if (hr == DXGI_ERROR_NOT_FOUND)
6545 skip("Adapter doesn't have any outputs.\n");
6546 IDXGIFactory_Release(factory);
6547 return;
6549 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6551 hr = IDXGIOutput_GetDesc(output, &output_desc);
6552 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6554 lstrcpyW(open_adapter_gdi_desc.DeviceName, output_desc.DeviceName);
6555 status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc);
6556 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
6558 check_ownership_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
6559 check_ownership_desc.VidPnSourceId = open_adapter_gdi_desc.VidPnSourceId;
6560 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6561 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx, expected %#lx.\n", status,
6562 STATUS_SUCCESS);
6564 swapchain_desc.BufferDesc.Width = 800;
6565 swapchain_desc.BufferDesc.Height = 600;
6566 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6567 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
6568 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6569 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6570 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6571 swapchain_desc.SampleDesc.Count = 1;
6572 swapchain_desc.SampleDesc.Quality = 0;
6573 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6574 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
6575 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, NULL, NULL, NULL, NULL);
6576 swapchain_desc.Windowed = TRUE;
6577 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
6578 swapchain_desc.Flags = 0;
6579 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
6580 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6582 /* Swapchain in fullscreen mode. */
6583 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
6584 /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE on some machines.
6585 * DXGI_ERROR_UNSUPPORTED on the Windows 7 testbot. */
6586 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == DXGI_ERROR_UNSUPPORTED))
6588 skip("Failed to change fullscreen state.\n");
6589 goto done;
6591 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6592 fullscreen = FALSE;
6593 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
6594 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6595 ok(fullscreen, "Got unexpected fullscreen state.\n");
6596 /* Win10 1909 doesn't seem to grab output exclusive ownership.
6597 * And all output ownership calls return S_OK on D3D10 and D3D12 with 1909. */
6598 if (is_d3d12)
6600 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6601 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx, expected %#lx.\n", status,
6602 STATUS_SUCCESS);
6604 else
6606 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc,
6607 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6608 todo_wine ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED ||
6609 broken(status == STATUS_SUCCESS), /* Win10 1909 */
6610 "Got unexpected status %#lx, expected %#lx.\n", status,
6611 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6613 hr = IDXGIOutput_TakeOwnership(output, NULL, FALSE);
6614 ok(hr == DXGI_ERROR_INVALID_CALL || broken(hr == S_OK), /* Win10 1909 */
6615 "Got unexpected hr %#lx.\n", hr);
6616 hr = IDXGIOutput_TakeOwnership(output, NULL, TRUE);
6617 ok(hr == DXGI_ERROR_INVALID_CALL || broken(hr == S_OK), /* Win10 1909 */
6618 "Got unexpected hr %#lx.\n", hr);
6619 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6620 if (is_d3d12)
6621 todo_wine ok(hr == E_NOINTERFACE || hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6622 else
6623 todo_wine ok(hr == E_INVALIDARG || broken(hr == S_OK), /* Win10 1909 */
6624 "Got unexpected hr %#lx.\n", hr);
6625 hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
6626 ok(hr == E_NOINTERFACE || hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6627 IDXGIOutput_ReleaseOwnership(output);
6628 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6629 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx, expected %#lx.\n", status,
6630 STATUS_SUCCESS);
6632 /* IDXGIOutput_TakeOwnership always returns E_NOINTERFACE for d3d12. Tests
6633 * finished. */
6634 if (is_d3d12)
6635 goto done;
6637 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6638 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == S_OK), /* Win10 1909 */
6639 "Got unexpected hr %#lx.\n", hr);
6640 IDXGIOutput_ReleaseOwnership(output);
6642 hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
6643 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6644 /* Note that the "exclusive" parameter to IDXGIOutput_TakeOwnership()
6645 * seems to behave opposite to what's described by MSDN. */
6646 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc,
6647 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6648 ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED ||
6649 broken(status == STATUS_SUCCESS), /* Win10 1909 */
6650 "Got unexpected status %#lx, expected %#lx.\n", status, STATUS_GRAPHICS_PRESENT_OCCLUDED);
6651 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6652 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Win10 1909 */, "Got unexpected hr %#lx.\n", hr);
6653 IDXGIOutput_ReleaseOwnership(output);
6655 /* Swapchain in windowed mode. */
6656 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6657 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6658 fullscreen = TRUE;
6659 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
6660 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6661 ok(!fullscreen, "Unexpected fullscreen state.\n");
6662 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6663 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx, expected %#lx.\n", status,
6664 STATUS_SUCCESS);
6666 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6667 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == S_OK), /* Win10 1909 */
6668 "Got unexpected hr %#lx.\n", hr);
6670 hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
6671 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6672 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc,
6673 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6674 ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED || broken(hr == S_OK), /* Win10 1909 */
6675 "Got unexpected status %#lx, expected %#lx.\n", status, STATUS_GRAPHICS_PRESENT_OCCLUDED);
6676 IDXGIOutput_ReleaseOwnership(output);
6677 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6678 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx, expected %#lx.\n", status,
6679 STATUS_SUCCESS);
6681 done:
6682 IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6683 wait_device_idle(device);
6685 IDXGIOutput_Release(output);
6686 IDXGISwapChain_Release(swapchain);
6687 DestroyWindow(swapchain_desc.OutputWindow);
6688 refcount = IDXGIFactory_Release(factory);
6689 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
6691 close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
6692 status = pD3DKMTCloseAdapter(&close_adapter_desc);
6693 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
6696 static void test_cursor_clipping(IUnknown *device, BOOL is_d3d12)
6698 unsigned int adapter_idx, output_idx, mode_idx, mode_count;
6699 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6700 DXGI_OUTPUT_DESC output_desc;
6701 IDXGIAdapter *adapter = NULL;
6702 RECT virtual_rect, clip_rect;
6703 unsigned int width, height;
6704 IDXGISwapChain *swapchain;
6705 DXGI_MODE_DESC *modes;
6706 IDXGIFactory *factory;
6707 IDXGIOutput *output;
6708 ULONG refcount;
6709 HRESULT hr;
6710 BOOL ret;
6712 get_factory(device, is_d3d12, &factory);
6714 swapchain_desc.SampleDesc.Count = 1;
6715 swapchain_desc.SampleDesc.Quality = 0;
6716 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6717 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
6718 swapchain_desc.Windowed = TRUE;
6719 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
6720 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
6722 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
6723 ++adapter_idx)
6725 winetest_push_context("Adapter %u", adapter_idx);
6727 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
6728 ++output_idx)
6730 winetest_push_context("Output %u", output_idx);
6732 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
6733 ok(hr == S_OK || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Win 7 TestBots */
6734 "Got unexpected hr %#lx.\n", hr);
6735 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
6737 win_skip("GetDisplayModeList() not supported.\n");
6738 IDXGIOutput_Release(output);
6739 winetest_pop_context();
6740 continue;
6743 modes = heap_calloc(mode_count, sizeof(*modes));
6744 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes);
6745 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6747 hr = IDXGIOutput_GetDesc(output, &output_desc);
6748 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6749 width = output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left;
6750 height = output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top;
6751 for (mode_idx = 0; mode_idx < mode_count; ++mode_idx)
6753 if (modes[mode_idx].Width != width && modes[mode_idx].Height != height)
6754 break;
6756 ok(modes[mode_idx].Width != width && modes[mode_idx].Height != height,
6757 "Failed to find a different mode than %ux%u.\n", width, height);
6759 ret = ClipCursor(NULL);
6760 ok(ret, "ClipCursor failed, error %#lx.\n", GetLastError());
6761 get_virtual_rect(&virtual_rect);
6762 ret = GetClipCursor(&clip_rect);
6763 ok(ret, "GetClipCursor failed, error %#lx.\n", GetLastError());
6764 ok(EqualRect(&clip_rect, &virtual_rect), "Expect clip rect %s, got %s.\n",
6765 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6767 swapchain_desc.BufferDesc.Width = modes[mode_idx].Width;
6768 swapchain_desc.BufferDesc.Height = modes[mode_idx].Height;
6769 swapchain_desc.BufferDesc.RefreshRate = modes[mode_idx].RefreshRate;
6770 swapchain_desc.BufferDesc.Format = modes[mode_idx].Format;
6771 swapchain_desc.BufferDesc.ScanlineOrdering = modes[mode_idx].ScanlineOrdering;
6772 swapchain_desc.BufferDesc.Scaling = modes[mode_idx].Scaling;
6773 swapchain_desc.OutputWindow = create_window();
6774 heap_free(modes);
6775 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
6776 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6778 flush_events();
6779 get_virtual_rect(&virtual_rect);
6780 ret = GetClipCursor(&clip_rect);
6781 ok(ret, "GetClipCursor failed, error %#lx.\n", GetLastError());
6782 ok(EqualRect(&clip_rect, &virtual_rect), "Expect clip rect %s, got %s.\n",
6783 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6785 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6786 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6787 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6788 "Got unexpected hr %#lx.\n", hr);
6789 if (FAILED(hr))
6791 skip("Could not change fullscreen state, hr %#lx.\n", hr);
6792 IDXGISwapChain_Release(swapchain);
6793 IDXGIOutput_Release(output);
6794 DestroyWindow(swapchain_desc.OutputWindow);
6795 winetest_pop_context();
6796 continue;
6799 flush_events();
6800 get_virtual_rect(&virtual_rect);
6801 ret = GetClipCursor(&clip_rect);
6802 ok(ret, "GetClipCursor failed, error %#lx.\n", GetLastError());
6803 ok(EqualRect(&clip_rect, &virtual_rect), "Expect clip rect %s, got %s.\n",
6804 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6806 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6807 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6808 refcount = IDXGISwapChain_Release(swapchain);
6809 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6810 refcount = IDXGIOutput_Release(output);
6811 ok(!refcount, "IDXGIOutput has %lu references left.\n", refcount);
6812 DestroyWindow(swapchain_desc.OutputWindow);
6814 flush_events();
6815 get_virtual_rect(&virtual_rect);
6816 ret = GetClipCursor(&clip_rect);
6817 ok(ret, "GetClipCursor failed, error %#lx.\n", GetLastError());
6818 ok(EqualRect(&clip_rect, &virtual_rect), "Expect clip rect %s, got %s.\n",
6819 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6821 winetest_pop_context();
6824 IDXGIAdapter_Release(adapter);
6826 winetest_pop_context();
6829 refcount = IDXGIFactory_Release(factory);
6830 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
6833 static void test_factory_check_feature_support(void)
6835 IDXGIFactory5 *factory;
6836 ULONG ref_count;
6837 HRESULT hr;
6838 BOOL data;
6840 if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory5, (void**)&factory)))
6842 win_skip("IDXGIFactory5 is not available.\n");
6843 return;
6846 hr = IDXGIFactory5_CheckFeatureSupport(factory, 0x12345678, (void *)&data, sizeof(data));
6847 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6849 /* Crashes on Windows. */
6850 if (0)
6852 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, NULL, sizeof(data));
6853 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6856 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &data, sizeof(data) - 1);
6857 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6859 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &data, sizeof(data) + 1);
6860 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6862 data = (BOOL)0xdeadbeef;
6863 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &data, sizeof(data));
6864 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6865 ok(data == TRUE || data == FALSE, "Got unexpected data %#x.\n", data);
6867 ref_count = IDXGIFactory5_Release(factory);
6868 ok(!ref_count, "Factory has %lu references left.\n", ref_count);
6871 static void test_frame_latency_event(IUnknown *device, BOOL is_d3d12)
6873 DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
6874 IDXGISwapChain2 *swapchain2;
6875 IDXGISwapChain1 *swapchain1;
6876 IDXGIFactory2 *factory2;
6877 IDXGIFactory *factory;
6878 UINT frame_latency;
6879 DWORD wait_result;
6880 ULONG ref_count;
6881 unsigned int i;
6882 HANDLE event;
6883 HWND window;
6884 HRESULT hr;
6886 get_factory(device, is_d3d12, &factory);
6888 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory2, (void**)&factory2);
6889 IDXGIFactory_Release(factory);
6890 if (FAILED(hr))
6892 win_skip("IDXGIFactory2 not available.\n");
6893 return;
6896 window = create_window();
6898 swapchain_desc.Width = 640;
6899 swapchain_desc.Height = 480;
6900 swapchain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6901 swapchain_desc.Stereo = FALSE;
6902 swapchain_desc.SampleDesc.Count = 1;
6903 swapchain_desc.SampleDesc.Quality = 0;
6904 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6905 swapchain_desc.BufferCount = 2;
6906 swapchain_desc.Scaling = DXGI_SCALING_STRETCH;
6907 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
6908 swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
6909 swapchain_desc.Flags = 0;
6911 hr = IDXGIFactory2_CreateSwapChainForHwnd(factory2, device,
6912 window, &swapchain_desc, NULL, NULL, &swapchain1);
6913 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6915 hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain2, (void**)&swapchain2);
6916 IDXGISwapChain1_Release(swapchain1);
6917 if (FAILED(hr))
6919 win_skip("IDXGISwapChain2 not available.\n");
6920 IDXGIFactory2_Release(factory2);
6921 DestroyWindow(window);
6922 return;
6925 /* test swap chain without waitable object */
6926 frame_latency = 0xdeadbeef;
6927 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6928 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6929 ok(frame_latency == 0xdeadbeef, "Got unexpected frame latency %#x.\n", frame_latency);
6930 hr = IDXGISwapChain2_SetMaximumFrameLatency(swapchain2, 1);
6931 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6932 event = IDXGISwapChain2_GetFrameLatencyWaitableObject(swapchain2);
6933 ok(!event, "Got unexpected event %p.\n", event);
6935 ref_count = IDXGISwapChain2_Release(swapchain2);
6936 ok(!ref_count, "Swap chain has %lu references left.\n", ref_count);
6938 /* test swap chain with waitable object */
6939 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
6941 hr = IDXGIFactory2_CreateSwapChainForHwnd(factory2, device,
6942 window, &swapchain_desc, NULL, NULL, &swapchain1);
6943 ok(hr == S_OK, "Failed to create swap chain, hr %#lx.\n", hr);
6944 hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain2, (void**)&swapchain2);
6945 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6946 IDXGISwapChain1_Release(swapchain1);
6948 event = IDXGISwapChain2_GetFrameLatencyWaitableObject(swapchain2);
6949 ok(!!event, "Got unexpected event %p.\n", event);
6951 /* auto-reset event */
6952 wait_result = WaitForSingleObject(event, 0);
6953 ok(!wait_result, "Got unexpected wait result %#lx.\n", wait_result);
6954 wait_result = WaitForSingleObject(event, 0);
6955 ok(wait_result == WAIT_TIMEOUT, "Got unexpected wait result %#lx.\n", wait_result);
6957 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6958 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6959 ok(frame_latency == 1, "Got unexpected frame latency %#x.\n", frame_latency);
6961 hr = IDXGISwapChain2_SetMaximumFrameLatency(swapchain2, 0);
6962 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6963 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6964 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6965 ok(frame_latency == 1, "Got unexpected frame latency %#x.\n", frame_latency);
6967 hr = IDXGISwapChain2_SetMaximumFrameLatency(swapchain2, 3);
6968 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6969 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6970 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6971 ok(frame_latency == 3, "Got unexpected frame latency %#x.\n", frame_latency);
6973 wait_result = WaitForSingleObject(event, 0);
6974 todo_wine ok(!wait_result, "Got unexpected wait result %#lx.\n", wait_result);
6975 wait_result = WaitForSingleObject(event, 0);
6976 todo_wine ok(!wait_result, "Got unexpected wait result %#lx.\n", wait_result);
6977 wait_result = WaitForSingleObject(event, 100);
6978 ok(wait_result == WAIT_TIMEOUT, "Got unexpected wait result %#lx.\n", wait_result);
6980 for (i = 0; i < 5; i++)
6982 hr = IDXGISwapChain2_Present(swapchain2, 0, 0);
6983 ok(hr == S_OK, "Present %u failed with hr %#lx.\n", i, hr);
6985 wait_result = WaitForSingleObject(event, 100);
6986 ok(!wait_result, "Got unexpected wait result %#lx.\n", wait_result);
6989 wait_result = WaitForSingleObject(event, 100);
6990 ok(wait_result == WAIT_TIMEOUT, "Got unexpected wait result %#lx.\n", wait_result);
6992 ref_count = IDXGISwapChain2_Release(swapchain2);
6993 ok(!ref_count, "Swap chain has %lu references left.\n", ref_count);
6994 DestroyWindow(window);
6995 ref_count = IDXGIFactory2_Release(factory2);
6996 ok(ref_count == !is_d3d12, "Factory has %lu references left.\n", ref_count);
6999 static void test_colour_space_support(IUnknown *device, BOOL is_d3d12)
7001 DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
7002 IDXGISwapChain3 *swapchain3;
7003 IDXGISwapChain1 *swapchain1;
7004 IDXGIFactory2 *factory2;
7005 IDXGIFactory *factory;
7006 ULONG ref_count;
7007 unsigned int i;
7008 UINT support;
7009 HWND window;
7010 HRESULT hr;
7012 static const DXGI_COLOR_SPACE_TYPE colour_spaces[] =
7014 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709,
7015 DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709,
7016 DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709,
7017 DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020,
7018 DXGI_COLOR_SPACE_RESERVED,
7019 DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601,
7020 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601,
7021 DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601,
7022 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709,
7023 DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709,
7024 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020,
7025 DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020,
7026 DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020,
7027 DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020,
7028 DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020,
7029 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020,
7030 DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020,
7031 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020,
7032 DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020,
7033 DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020,
7036 get_factory(device, is_d3d12, &factory);
7038 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory2, (void**)&factory2);
7039 IDXGIFactory_Release(factory);
7040 if (FAILED(hr))
7042 win_skip("IDXGIFactory2 not available.\n");
7043 return;
7046 window = create_window();
7048 swapchain_desc.Width = 640;
7049 swapchain_desc.Height = 480;
7050 swapchain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
7051 swapchain_desc.Stereo = FALSE;
7052 swapchain_desc.SampleDesc.Count = 1;
7053 swapchain_desc.SampleDesc.Quality = 0;
7054 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
7055 swapchain_desc.BufferCount = 2;
7056 swapchain_desc.Scaling = DXGI_SCALING_STRETCH;
7057 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
7058 swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
7059 swapchain_desc.Flags = 0;
7061 hr = IDXGIFactory2_CreateSwapChainForHwnd(factory2, device,
7062 window, &swapchain_desc, NULL, NULL, &swapchain1);
7063 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7065 hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void**)&swapchain3);
7066 IDXGISwapChain1_Release(swapchain1);
7067 if (FAILED(hr))
7069 win_skip("IDXGISwapChain3 not available.\n");
7070 IDXGIFactory2_Release(factory2);
7071 DestroyWindow(window);
7072 return;
7075 for (i = 0; i < ARRAY_SIZE(colour_spaces); ++i)
7077 support = 0xdeadbeef;
7078 hr = IDXGISwapChain3_CheckColorSpaceSupport(swapchain3, colour_spaces[i], &support);
7079 ok(hr == S_OK, "Got unexpected hr %#lx for test %u.\n", hr, i);
7080 ok(!(support & ~DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT),
7081 "Got unexpected support flags %#x for test %u.\n", support, i);
7083 if (colour_spaces[i] == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709)
7085 ok(support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT,
7086 "Required colour space not supported for test %u.\n", i);
7088 else if (colour_spaces[i] == DXGI_COLOR_SPACE_RESERVED)
7090 ok(!support, "Invalid colour space supported for test %u.\n", i);
7093 hr = IDXGISwapChain3_SetColorSpace1(swapchain3, colour_spaces[i]);
7094 ok(hr == (support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) ? S_OK : E_INVALIDARG,
7095 "Got unexpected hr %#lx for text %u.\n", hr, i);
7098 ref_count = IDXGISwapChain3_Release(swapchain3);
7099 ok(!ref_count, "Swap chain has %lu references left.\n", ref_count);
7100 DestroyWindow(window);
7101 ref_count = IDXGIFactory2_Release(factory2);
7102 ok(ref_count == !is_d3d12, "Factory has %lu references left.\n", ref_count);
7105 static void test_mode_change(IUnknown *device, BOOL is_d3d12)
7107 unsigned int user32_width = 0, user32_height = 0, d3d_width = 0, d3d_height = 0;
7108 unsigned int display_count = 0, mode_idx = 0, adapter_idx, output_idx;
7109 DEVMODEW *original_modes = NULL, old_devmode, devmode, devmode2;
7110 DXGI_SWAP_CHAIN_DESC swapchain_desc, swapchain_desc2;
7111 IDXGIOutput *output, *second_output = NULL;
7112 WCHAR second_monitor_name[CCHDEVICENAME];
7113 IDXGISwapChain *swapchain, *swapchain2;
7114 DXGI_OUTPUT_DESC output_desc;
7115 IDXGIAdapter *adapter;
7116 IDXGIFactory *factory;
7117 BOOL fullscreen, ret;
7118 LONG change_ret;
7119 ULONG refcount;
7120 HRESULT hr;
7122 memset(&devmode, 0, sizeof(devmode));
7123 devmode.dmSize = sizeof(devmode);
7124 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
7125 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7126 ok(equal_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
7127 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
7128 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7129 ok(equal_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
7131 while (EnumDisplaySettingsW(NULL, mode_idx++, &devmode))
7133 if (devmode.dmPelsWidth == registry_mode.dmPelsWidth
7134 && devmode.dmPelsHeight == registry_mode.dmPelsHeight)
7135 continue;
7137 if (!d3d_width && !d3d_height)
7139 d3d_width = devmode.dmPelsWidth;
7140 d3d_height = devmode.dmPelsHeight;
7141 continue;
7144 if (devmode.dmPelsWidth == d3d_width && devmode.dmPelsHeight == d3d_height)
7145 continue;
7147 user32_width = devmode.dmPelsWidth;
7148 user32_height = devmode.dmPelsHeight;
7149 break;
7151 if (!user32_width || !user32_height)
7153 skip("Failed to find three different display modes for the primary output.\n");
7154 return;
7157 ret = save_display_modes(&original_modes, &display_count);
7158 ok(ret, "Failed to save original display modes.\n");
7160 get_factory(device, is_d3d12, &factory);
7162 /* Test that no mode restorations if no mode changes actually happened */
7163 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
7164 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
7166 swapchain_desc.BufferDesc.Width = registry_mode.dmPelsWidth;
7167 swapchain_desc.BufferDesc.Height = registry_mode.dmPelsHeight;
7168 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
7169 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
7170 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
7171 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
7172 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
7173 swapchain_desc.SampleDesc.Count = 1;
7174 swapchain_desc.SampleDesc.Quality = 0;
7175 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
7176 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
7177 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
7178 swapchain_desc.Windowed = TRUE;
7179 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
7180 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
7182 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7183 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7184 refcount = IDXGISwapChain_Release(swapchain);
7185 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7187 memset(&devmode2, 0, sizeof(devmode2));
7188 devmode2.dmSize = sizeof(devmode2);
7189 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
7190 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7191 ok(equal_mode_rect(&devmode2, &registry_mode), "Got a different mode.\n");
7192 ret = restore_display_modes(original_modes, display_count);
7193 ok(ret, "Failed to restore display modes.\n");
7195 /* If current display settings are different than the display settings in registry before
7196 * calling SetFullscreenState() */
7197 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
7198 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
7200 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7201 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7202 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7203 ok(hr == DXGI_ERROR_UNSUPPORTED /* Win7 */
7204 || hr == S_OK /* Win8~Win10 1909 */
7205 || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, /* Win10 2004 */
7206 "Got unexpected hr %#lx.\n", hr);
7208 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7209 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7210 refcount = IDXGISwapChain_Release(swapchain);
7211 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7212 ret = restore_display_modes(original_modes, display_count);
7213 ok(ret, "Failed to restore display modes.\n");
7215 /* Test that mode restorations use display settings in the registry with a fullscreen device */
7216 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7217 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7218 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7219 if (FAILED(hr))
7221 skip("SetFullscreenState failed, hr %#lx.\n", hr);
7222 refcount = IDXGISwapChain_Release(swapchain);
7223 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7224 goto done;
7227 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
7228 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
7229 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7230 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7232 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
7233 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7234 ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
7235 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
7236 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7237 ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
7238 refcount = IDXGISwapChain_Release(swapchain);
7239 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7240 ret = restore_display_modes(original_modes, display_count);
7241 ok(ret, "Failed to restore display modes.\n");
7243 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter)); ++adapter_idx)
7245 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output)); ++output_idx)
7247 hr = IDXGIOutput_GetDesc(output, &output_desc);
7248 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
7250 if ((adapter_idx || output_idx) && output_desc.AttachedToDesktop)
7252 second_output = output;
7253 break;
7256 IDXGIOutput_Release(output);
7259 IDXGIAdapter_Release(adapter);
7260 if (second_output)
7261 break;
7264 if (!second_output)
7266 skip("Following tests require two monitors.\n");
7267 goto done;
7269 lstrcpyW(second_monitor_name, output_desc.DeviceName);
7271 memset(&old_devmode, 0, sizeof(old_devmode));
7272 old_devmode.dmSize = sizeof(old_devmode);
7273 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
7274 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7276 mode_idx = 0;
7277 d3d_width = 0;
7278 d3d_height = 0;
7279 user32_width = 0;
7280 user32_height = 0;
7281 while (EnumDisplaySettingsW(second_monitor_name, mode_idx++, &devmode))
7283 if (devmode.dmPelsWidth == old_devmode.dmPelsWidth
7284 && devmode.dmPelsHeight == old_devmode.dmPelsHeight)
7285 continue;
7287 if (!d3d_width && !d3d_height)
7289 d3d_width = devmode.dmPelsWidth;
7290 d3d_height = devmode.dmPelsHeight;
7291 continue;
7294 if (devmode.dmPelsWidth == d3d_width && devmode.dmPelsHeight == d3d_height)
7295 continue;
7297 user32_width = devmode.dmPelsWidth;
7298 user32_height = devmode.dmPelsHeight;
7299 break;
7301 if (!user32_width || !user32_height)
7303 skip("Failed to find three different display modes for the second output.\n");
7304 goto done;
7307 /* Test that mode restorations for non-primary outputs upon fullscreen state changes */
7308 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7309 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7310 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7311 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7313 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
7314 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
7315 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7316 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7317 if (devmode2.dmPelsWidth == old_devmode.dmPelsWidth
7318 && devmode2.dmPelsHeight == old_devmode.dmPelsHeight)
7320 skip("Failed to change display settings of the second monitor.\n");
7321 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7322 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7323 refcount = IDXGISwapChain_Release(swapchain);
7324 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7325 goto done;
7328 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7329 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7331 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7332 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7333 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7334 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
7335 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7336 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7337 hr = IDXGIOutput_GetDesc(second_output, &output_desc);
7338 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7339 ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
7340 old_devmode.dmPelsWidth, "Expected width %lu, got %lu.\n", old_devmode.dmPelsWidth,
7341 output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
7342 ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
7343 old_devmode.dmPelsHeight, "Expected height %lu, got %lu.\n", old_devmode.dmPelsHeight,
7344 output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
7346 refcount = IDXGISwapChain_Release(swapchain);
7347 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7348 ret = restore_display_modes(original_modes, display_count);
7349 ok(ret, "Failed to restore display modes.\n");
7351 /* Test that mode restorations for non-primary outputs use display settings in the registry */
7352 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7353 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7354 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7355 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7357 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
7358 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
7359 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
7360 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7361 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7363 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7364 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7365 ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
7366 "Expected resolution %lux%lu, got %lux%lu.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
7367 devmode2.dmPelsWidth, devmode2.dmPelsHeight);
7368 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
7369 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7370 ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
7371 "Expected resolution %lux%lu, got %lux%lu.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
7372 devmode2.dmPelsWidth, devmode2.dmPelsHeight);
7373 hr = IDXGIOutput_GetDesc(second_output, &output_desc);
7374 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7375 ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
7376 devmode.dmPelsWidth, "Expected width %lu, got %lu.\n", devmode.dmPelsWidth,
7377 output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
7378 ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
7379 devmode.dmPelsHeight, "Expected height %lu, got %lu.\n", devmode.dmPelsHeight,
7380 output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
7382 refcount = IDXGISwapChain_Release(swapchain);
7383 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7384 ret = restore_display_modes(original_modes, display_count);
7385 ok(ret, "Failed to restore display modes.\n");
7387 /* Test that mode restorations for non-primary outputs on fullscreen state changes when there
7388 * are two fullscreen swapchains on different outputs */
7389 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7390 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7392 swapchain_desc2 = swapchain_desc;
7393 swapchain_desc.BufferDesc.Width = d3d_width;
7394 swapchain_desc.BufferDesc.Height = d3d_height;
7395 swapchain_desc2.OutputWindow = CreateWindowA("static", "dxgi_test2", 0,
7396 old_devmode.dmPosition.x, old_devmode.dmPosition.y, 400, 200, 0, 0, 0, 0);
7397 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc2, &swapchain2);
7398 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7399 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7400 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7401 hr = IDXGISwapChain_SetFullscreenState(swapchain2, TRUE, NULL);
7402 if (FAILED(hr))
7404 skip("SetFullscreenState failed, hr %#lx.\n", hr);
7405 refcount = IDXGISwapChain_Release(swapchain2);
7406 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7407 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7408 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7409 refcount = IDXGISwapChain_Release(swapchain);
7410 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7411 goto done;
7414 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7415 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7416 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
7417 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7418 ok(!fullscreen, "Expected swapchain not fullscreen.\n");
7419 hr = IDXGISwapChain_GetFullscreenState(swapchain2, &fullscreen, NULL);
7420 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7421 ok(fullscreen, "Expected swapchain fullscreen.\n");
7423 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7424 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7425 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7426 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
7427 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7428 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7429 hr = IDXGIOutput_GetDesc(second_output, &output_desc);
7430 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7431 ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
7432 old_devmode.dmPelsWidth, "Expected width %lu, got %lu.\n", old_devmode.dmPelsWidth,
7433 output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
7434 ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
7435 old_devmode.dmPelsHeight, "Expected height %lu, got %lu.\n", old_devmode.dmPelsHeight,
7436 output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
7438 hr = IDXGISwapChain_SetFullscreenState(swapchain2, FALSE, NULL);
7439 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7440 refcount = IDXGISwapChain_Release(swapchain2);
7441 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7442 refcount = IDXGISwapChain_Release(swapchain);
7443 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7444 DestroyWindow(swapchain_desc2.OutputWindow);
7445 ret = restore_display_modes(original_modes, display_count);
7446 ok(ret, "Failed to restore display modes.\n");
7448 done:
7449 if (second_output)
7450 IDXGIOutput_Release(second_output);
7451 DestroyWindow(swapchain_desc.OutputWindow);
7452 refcount = IDXGIFactory_Release(factory);
7453 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
7454 ret = restore_display_modes(original_modes, display_count);
7455 ok(ret, "Failed to restore display modes.\n");
7456 heap_free(original_modes);
7459 static void test_swapchain_present_count(IUnknown *device, BOOL is_d3d12)
7461 UINT present_count, expected;
7462 IDXGISwapChain *swapchain;
7463 HWND window;
7464 HRESULT hr;
7466 window = create_window();
7467 swapchain = create_swapchain(device, is_d3d12, window);
7469 present_count = ~0u;
7470 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7471 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7472 ok(!present_count, "Got unexpected present count %u.\n", present_count);
7474 hr = IDXGISwapChain_Present(swapchain, 0, 0);
7475 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7476 expected = present_count + 1;
7477 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7478 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7479 ok(present_count == expected, "Got unexpected present count %u, expected %u.\n", present_count, expected);
7481 hr = IDXGISwapChain_Present(swapchain, 10, 0);
7482 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
7483 expected = present_count;
7484 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7485 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7486 ok(present_count == expected, "Got unexpected present count %u, expected %u.\n", present_count, expected);
7488 hr = IDXGISwapChain_Present(swapchain, 0, DXGI_PRESENT_TEST);
7489 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7490 expected = present_count;
7491 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7492 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7493 ok(present_count == expected, "Got unexpected present count %u, expected %u.\n", present_count, expected);
7495 ShowWindow(window, SW_MINIMIZE);
7496 hr = IDXGISwapChain_Present(swapchain, 0, 0);
7497 ok(hr == (is_d3d12 ? S_OK : DXGI_STATUS_OCCLUDED), "Got unexpected hr %#lx.\n", hr);
7498 expected = present_count + !!is_d3d12;
7499 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7500 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7501 ok(present_count == expected, "Got unexpected present count %u, expected %u.\n", present_count, expected);
7503 ShowWindow(window, SW_NORMAL);
7504 hr = IDXGISwapChain_Present(swapchain, 0, 0);
7505 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7506 expected = present_count + 1;
7507 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7508 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7509 ok(present_count == expected, "Got unexpected present count %u, expected %u.\n", present_count, expected);
7511 IDXGISwapChain_Release(swapchain);
7512 DestroyWindow(window);
7515 static void test_video_memory_budget_notification(void)
7517 DXGI_QUERY_VIDEO_MEMORY_INFO memory_info;
7518 IDXGIAdapter3 *adapter3;
7519 IDXGIAdapter *adapter;
7520 IDXGIDevice *device;
7521 DWORD cookie, ret;
7522 ULONG refcount;
7523 HANDLE event;
7524 HRESULT hr;
7526 if (!(device = create_device(0)))
7528 skip("Failed to create device.\n");
7529 return;
7532 hr = IDXGIDevice_GetAdapter(device, &adapter);
7533 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7534 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter3, (void **)&adapter3);
7535 ok(hr == S_OK || hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
7536 if (hr == E_NOINTERFACE)
7537 goto done;
7539 hr = IDXGIAdapter3_RegisterVideoMemoryBudgetChangeNotificationEvent(adapter3, NULL, &cookie);
7540 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
7542 event = CreateEventW(NULL, FALSE, FALSE, NULL);
7543 hr = IDXGIAdapter3_RegisterVideoMemoryBudgetChangeNotificationEvent(adapter3, event, NULL);
7544 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
7546 hr = IDXGIAdapter3_RegisterVideoMemoryBudgetChangeNotificationEvent(adapter3, event, &cookie);
7547 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7548 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &memory_info);
7549 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7550 if (!memory_info.Budget)
7552 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &memory_info);
7553 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7555 if (memory_info.Budget)
7557 ret = WaitForSingleObject(event, 1000);
7558 ok(ret == WAIT_OBJECT_0, "Expected event fired.\n");
7561 IDXGIAdapter3_UnregisterVideoMemoryBudgetChangeNotification(adapter3, cookie);
7562 IDXGIAdapter3_Release(adapter3);
7563 CloseHandle(event);
7565 done:
7566 IDXGIAdapter_Release(adapter);
7567 refcount = IDXGIDevice_Release(device);
7568 ok(!refcount, "Device has %lu references left.\n", refcount);
7571 static void run_on_d3d10(void (*test_func)(IUnknown *device, BOOL is_d3d12))
7573 IDXGIDevice *device;
7574 ULONG refcount;
7576 if (!(device = create_device(0)))
7578 skip("Failed to create Direct3D 10 device.\n");
7579 return;
7582 test_func((IUnknown *)device, FALSE);
7584 refcount = IDXGIDevice_Release(device);
7585 ok(!refcount, "Device has %lu references left.\n", refcount);
7588 static void run_on_d3d12(void (*test_func)(IUnknown *device, BOOL is_d3d12))
7590 ID3D12CommandQueue *queue;
7591 ID3D12Device *device;
7592 ULONG refcount;
7594 if (!(device = create_d3d12_device()))
7596 skip("Failed to create Direct3D 12 device.\n");
7597 return;
7600 queue = create_d3d12_direct_queue(device);
7602 test_func((IUnknown *)queue, TRUE);
7604 wait_queue_idle(device, queue);
7606 refcount = ID3D12CommandQueue_Release(queue);
7607 ok(!refcount, "Command queue has %lu references left.\n", refcount);
7608 refcount = ID3D12Device_Release(device);
7609 ok(!refcount, "Device has %lu references left.\n", refcount);
7612 START_TEST(dxgi)
7614 HMODULE dxgi_module, d3d11_module, d3d12_module, gdi32_module;
7615 BOOL enable_debug_layer = FALSE;
7616 unsigned int argc, i;
7617 ID3D12Debug *debug;
7618 char **argv;
7620 dxgi_module = GetModuleHandleA("dxgi.dll");
7621 pCreateDXGIFactory1 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory1");
7622 pCreateDXGIFactory2 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory2");
7624 gdi32_module = GetModuleHandleA("gdi32.dll");
7625 pD3DKMTCheckVidPnExclusiveOwnership = (void *)GetProcAddress(gdi32_module, "D3DKMTCheckVidPnExclusiveOwnership");
7626 pD3DKMTCloseAdapter = (void *)GetProcAddress(gdi32_module, "D3DKMTCloseAdapter");
7627 pD3DKMTOpenAdapterFromGdiDisplayName = (void *)GetProcAddress(gdi32_module, "D3DKMTOpenAdapterFromGdiDisplayName");
7629 d3d11_module = LoadLibraryA("d3d11.dll");
7630 pD3D11CreateDevice = (void *)GetProcAddress(d3d11_module, "D3D11CreateDevice");
7632 registry_mode.dmSize = sizeof(registry_mode);
7633 ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &registry_mode), "Failed to get display mode.\n");
7635 use_mt = !getenv("WINETEST_NO_MT_D3D");
7636 /* Some host drivers (MacOS, Mesa radeonsi) never unmap memory even when
7637 * requested. When using the chunk allocator, running the tests with more
7638 * than one thread can exceed the 32-bit virtual address space. */
7639 if (sizeof(void *) == 4 && !strcmp(winetest_platform, "wine"))
7640 use_mt = FALSE;
7642 argc = winetest_get_mainargs(&argv);
7643 for (i = 2; i < argc; ++i)
7645 if (!strcmp(argv[i], "--validate"))
7646 enable_debug_layer = TRUE;
7647 else if (!strcmp(argv[i], "--warp"))
7648 use_warp_adapter = TRUE;
7649 else if (!strcmp(argv[i], "--adapter") && i + 1 < argc)
7650 use_adapter_idx = atoi(argv[++i]);
7651 else if (!strcmp(argv[i], "--single"))
7652 use_mt = FALSE;
7655 queue_test(test_adapter_desc);
7656 queue_test(test_adapter_luid);
7657 queue_test(test_query_video_memory_info);
7658 queue_test(test_check_interface_support);
7659 queue_test(test_create_surface);
7660 queue_test(test_parents);
7661 queue_test(test_output);
7662 queue_test(test_find_closest_matching_mode);
7663 queue_test(test_resize_target_wndproc);
7664 queue_test(test_create_factory);
7665 queue_test(test_private_data);
7666 queue_test(test_maximum_frame_latency);
7667 queue_test(test_output_desc);
7668 queue_test(test_object_wrapping);
7669 queue_test(test_factory_check_feature_support);
7670 queue_test(test_video_memory_budget_notification);
7672 run_queued_tests();
7674 /* These tests use full-screen swapchains, so shouldn't run in parallel. */
7675 test_create_swapchain();
7676 test_inexact_modes();
7677 test_gamma_control();
7678 test_multi_adapter();
7679 test_swapchain_parameters();
7680 test_swapchain_window_messages();
7681 test_swapchain_window_styles();
7682 run_on_d3d10(test_set_fullscreen);
7683 run_on_d3d10(test_resize_target);
7684 run_on_d3d10(test_swapchain_resize);
7685 run_on_d3d10(test_swapchain_present);
7686 run_on_d3d10(test_swapchain_backbuffer_index);
7687 run_on_d3d10(test_swapchain_formats);
7688 run_on_d3d10(test_output_ownership);
7689 run_on_d3d10(test_cursor_clipping);
7690 run_on_d3d10(test_get_containing_output);
7691 run_on_d3d10(test_window_association);
7692 run_on_d3d10(test_default_fullscreen_target_output);
7693 run_on_d3d10(test_mode_change);
7694 run_on_d3d10(test_swapchain_present_count);
7696 if (!(d3d12_module = LoadLibraryA("d3d12.dll")))
7698 skip("Direct3D 12 is not available.\n");
7699 return;
7702 pD3D12CreateDevice = (void *)GetProcAddress(d3d12_module, "D3D12CreateDevice");
7703 pD3D12GetDebugInterface = (void *)GetProcAddress(d3d12_module, "D3D12GetDebugInterface");
7705 if (enable_debug_layer && SUCCEEDED(pD3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug)))
7707 ID3D12Debug_EnableDebugLayer(debug);
7708 ID3D12Debug_Release(debug);
7711 run_on_d3d12(test_set_fullscreen);
7712 run_on_d3d12(test_resize_target);
7713 run_on_d3d12(test_swapchain_resize);
7714 run_on_d3d12(test_swapchain_present);
7715 run_on_d3d12(test_swapchain_backbuffer_index);
7716 run_on_d3d12(test_swapchain_formats);
7717 run_on_d3d12(test_output_ownership);
7718 run_on_d3d12(test_cursor_clipping);
7719 run_on_d3d12(test_frame_latency_event);
7720 run_on_d3d12(test_colour_space_support);
7721 run_on_d3d12(test_get_containing_output);
7722 run_on_d3d12(test_window_association);
7723 run_on_d3d12(test_default_fullscreen_target_output);
7724 run_on_d3d12(test_mode_change);
7725 run_on_d3d12(test_swapchain_present_count);
7727 FreeLibrary(d3d12_module);