ntdll: Fix SMT CPU flag reporting.
[wine/zf.git] / dlls / dxgi / tests / dxgi.c
blobe6c8e0eb8c4d1017cd6ad4dc84d643cd8790789a
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 hr %#x, expected %#x.\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, "Failed to query ID3D10Device, hr %#x.\n", hr);
270 hr = ID3D10Device_CheckMultisampleQualityLevels(device, format, sample_count, &levels);
271 ok(hr == S_OK, "Failed to check multisample quality levels, hr %#x.\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 %lu, expected %lu.\n",
357 desc->DedicatedVideoMemory, expected_desc->DedicatedVideoMemory);
358 ok_(__FILE__, line)(desc->DedicatedSystemMemory == expected_desc->DedicatedSystemMemory,
359 "Got dedicated system memory %lu, expected %lu.\n",
360 desc->DedicatedSystemMemory, expected_desc->DedicatedSystemMemory);
361 ok_(__FILE__, line)(desc->SharedSystemMemory == expected_desc->SharedSystemMemory,
362 "Got shared system memory %lu, expected %lu.\n",
363 desc->SharedSystemMemory, expected_desc->SharedSystemMemory);
364 ok_(__FILE__, line)(equal_luid(desc->AdapterLuid, expected_desc->AdapterLuid),
365 "Got LUID %08x:%08x, expected %08x:%08x.\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(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
391 hr = IDXGIOutput_GetDesc(output2, &desc2);
392 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\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(SUCCEEDED(hr), "Failed to get output desc, hr %#x.\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(SUCCEEDED(hr), "Failed to get output desc, hr %#x.\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 %#x, expected %#x.\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 %#x, expected %#x.\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 %#x.\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 %#x.\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 %#x.\n", hr);
523 hr = IDXGIOutput_GetParent(containing_output, &IID_IDXGIAdapter, (void **)&adapter);
524 ok_(__FILE__, line)(hr == S_OK, "Failed to get parent, hr %#x.\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 %#x.\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 %#x.\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 %#x.\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 %#x.\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 %#x.\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, "Failed to create command queue, hr %#x.\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 %#x.\n", hr);
828 hr = ID3D12CommandQueue_Signal(queue, fence, 1);
829 ok_(__FILE__, line)(hr == S_OK, "Failed to signal fence, hr %#x.\n", hr);
830 hr = wait_for_fence(fence, 1);
831 ok_(__FILE__, line)(hr == S_OK, "Failed to wait for fence, hr %#x.\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 %#x.\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 %#x.\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 %#x.\n", hr);
873 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)factory);
874 ok_(__FILE__, line)(hr == S_OK, "Failed to get parent, hr %#x.\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 %#x.\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 %#x.\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 %#x.\n", hr);
908 return adapter;
911 static void test_adapter_desc(void)
913 DXGI_ADAPTER_DESC1 desc1;
914 IDXGIAdapter1 *adapter1;
915 DXGI_ADAPTER_DESC desc;
916 IDXGIAdapter *adapter;
917 IDXGIDevice *device;
918 ULONG refcount;
919 HRESULT hr;
921 if (!(device = create_device(0)))
923 skip("Failed to create device.\n");
924 return;
927 hr = IDXGIDevice_GetAdapter(device, &adapter);
928 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
930 hr = IDXGIAdapter_GetDesc(adapter, NULL);
931 ok(hr == E_INVALIDARG, "GetDesc returned %#x, expected %#x.\n",
932 hr, E_INVALIDARG);
934 hr = IDXGIAdapter_GetDesc(adapter, &desc);
935 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
937 trace("%s.\n", wine_dbgstr_w(desc.Description));
938 trace("%04x: %04x:%04x (rev %02x).\n",
939 desc.SubSysId, desc.VendorId, desc.DeviceId, desc.Revision);
940 trace("Dedicated video memory: %lu (%lu MB).\n",
941 desc.DedicatedVideoMemory, desc.DedicatedVideoMemory / (1024 * 1024));
942 trace("Dedicated system memory: %lu (%lu MB).\n",
943 desc.DedicatedSystemMemory, desc.DedicatedSystemMemory / (1024 * 1024));
944 trace("Shared system memory: %lu (%lu MB).\n",
945 desc.SharedSystemMemory, desc.SharedSystemMemory / (1024 * 1024));
946 trace("LUID: %08x:%08x.\n", desc.AdapterLuid.HighPart, desc.AdapterLuid.LowPart);
948 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter1, (void **)&adapter1);
949 ok(SUCCEEDED(hr) || broken(hr == E_NOINTERFACE), "Got unexpected hr %#x.\n", hr);
950 if (hr == E_NOINTERFACE)
951 goto done;
953 hr = IDXGIAdapter1_GetDesc1(adapter1, &desc1);
954 ok(SUCCEEDED(hr), "GetDesc1 failed, hr %#x.\n", hr);
956 ok(!lstrcmpW(desc.Description, desc1.Description),
957 "Got unexpected description %s.\n", wine_dbgstr_w(desc1.Description));
958 ok(desc1.VendorId == desc.VendorId, "Got unexpected vendor ID %04x.\n", desc1.VendorId);
959 ok(desc1.DeviceId == desc.DeviceId, "Got unexpected device ID %04x.\n", desc1.DeviceId);
960 ok(desc1.SubSysId == desc.SubSysId, "Got unexpected sub system ID %04x.\n", desc1.SubSysId);
961 ok(desc1.Revision == desc.Revision, "Got unexpected revision %02x.\n", desc1.Revision);
962 ok(desc1.DedicatedVideoMemory == desc.DedicatedVideoMemory,
963 "Got unexpected dedicated video memory %lu.\n", desc1.DedicatedVideoMemory);
964 ok(desc1.DedicatedSystemMemory == desc.DedicatedSystemMemory,
965 "Got unexpected dedicated system memory %lu.\n", desc1.DedicatedSystemMemory);
966 ok(desc1.SharedSystemMemory == desc.SharedSystemMemory,
967 "Got unexpected shared system memory %lu.\n", desc1.SharedSystemMemory);
968 ok(equal_luid(desc1.AdapterLuid, desc.AdapterLuid),
969 "Got unexpected adapter LUID %08x:%08x.\n", desc1.AdapterLuid.HighPart, desc1.AdapterLuid.LowPart);
970 trace("Flags: %08x.\n", desc1.Flags);
972 IDXGIAdapter1_Release(adapter1);
974 done:
975 IDXGIAdapter_Release(adapter);
976 refcount = IDXGIDevice_Release(device);
977 ok(!refcount, "Device has %u references left.\n", refcount);
980 static void test_adapter_luid(void)
982 DXGI_ADAPTER_DESC device_adapter_desc, desc, desc2;
983 static const LUID luid = {0xdeadbeef, 0xdeadbeef};
984 IDXGIAdapter *adapter, *adapter2;
985 unsigned int found_adapter_count;
986 unsigned int adapter_index;
987 BOOL is_null_luid_adapter;
988 IDXGIFactory4 *factory4;
989 IDXGIFactory *factory;
990 BOOL have_unique_luid;
991 IDXGIDevice *device;
992 ULONG refcount;
993 HRESULT hr;
995 if (!(device = create_device(0)))
997 skip("Failed to create device.\n");
998 return;
1001 hr = IDXGIDevice_GetAdapter(device, &adapter);
1002 ok(hr == S_OK, "Failed to get adapter, hr %#x.\n", hr);
1003 hr = IDXGIAdapter_GetDesc(adapter, &device_adapter_desc);
1004 ok(hr == S_OK, "Failed to get adapter desc, hr %#x.\n", hr);
1005 IDXGIAdapter_Release(adapter);
1006 refcount = IDXGIDevice_Release(device);
1007 ok(!refcount, "Device has %u references left.\n", refcount);
1009 is_null_luid_adapter = !device_adapter_desc.AdapterLuid.LowPart
1010 && !device_adapter_desc.SubSysId && !device_adapter_desc.Revision
1011 && !device_adapter_desc.VendorId && !device_adapter_desc.DeviceId;
1013 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory);
1014 ok(hr == S_OK, "Failed to create DXGI factory, hr %#x.\n", hr);
1016 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void **)&factory4);
1017 ok(hr == S_OK || hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
1019 have_unique_luid = TRUE;
1020 found_adapter_count = 0;
1021 adapter_index = 0;
1022 while ((hr = IDXGIFactory_EnumAdapters(factory, adapter_index, &adapter)) == S_OK)
1024 hr = IDXGIAdapter_GetDesc(adapter, &desc);
1025 ok(hr == S_OK, "Failed to get adapter desc, hr %#x.\n", hr);
1027 if (equal_luid(desc.AdapterLuid, device_adapter_desc.AdapterLuid))
1029 check_adapter_desc(&desc, &device_adapter_desc);
1030 ++found_adapter_count;
1033 if (equal_luid(desc.AdapterLuid, luid))
1034 have_unique_luid = FALSE;
1036 if (factory4)
1038 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, desc.AdapterLuid,
1039 &IID_IDXGIAdapter, (void **)&adapter2);
1040 ok(hr == S_OK, "Failed to enum adapter by LUID, hr %#x.\n", hr);
1041 hr = IDXGIAdapter_GetDesc(adapter2, &desc2);
1042 ok(hr == S_OK, "Failed to get adapter desc, hr %#x.\n", hr);
1043 check_adapter_desc(&desc2, &desc);
1044 ok(adapter2 != adapter, "Expected to get new instance of IDXGIAdapter.\n");
1045 refcount = IDXGIAdapter_Release(adapter2);
1046 ok(!refcount, "Adapter has %u references left.\n", refcount);
1049 refcount = IDXGIAdapter_Release(adapter);
1050 ok(!refcount, "Adapter has %u references left.\n", refcount);
1052 ++adapter_index;
1054 ok(hr == DXGI_ERROR_NOT_FOUND, "Got unexpected hr %#x.\n", hr);
1056 /* Older versions of WARP aren't enumerated by IDXGIFactory_EnumAdapters(). */
1057 ok(found_adapter_count == 1 || broken(is_null_luid_adapter),
1058 "Found %u adapters for LUID %08x:%08x.\n",
1059 found_adapter_count, device_adapter_desc.AdapterLuid.HighPart,
1060 device_adapter_desc.AdapterLuid.LowPart);
1062 if (factory4)
1063 IDXGIFactory4_Release(factory4);
1064 refcount = IDXGIFactory_Release(factory);
1065 ok(!refcount, "Factory has %u references left.\n", refcount);
1067 if (!pCreateDXGIFactory2
1068 || FAILED(hr = pCreateDXGIFactory2(0, &IID_IDXGIFactory4, (void **)&factory4)))
1070 skip("DXGI 1.4 is not available.\n");
1071 return;
1074 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, device_adapter_desc.AdapterLuid,
1075 &IID_IDXGIAdapter, NULL);
1076 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1078 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, device_adapter_desc.AdapterLuid,
1079 &IID_IDXGIAdapter, (void **)&adapter);
1080 ok(hr == S_OK, "Failed to enum adapter by LUID, hr %#x.\n", hr);
1081 if (SUCCEEDED(hr))
1083 hr = IDXGIAdapter_GetDesc(adapter, &desc);
1084 ok(hr == S_OK, "Failed to get adapter desc, hr %#x.\n", hr);
1085 check_adapter_desc(&desc, &device_adapter_desc);
1086 refcount = IDXGIAdapter_Release(adapter);
1087 ok(!refcount, "Adapter has %u references left.\n", refcount);
1090 if (have_unique_luid)
1092 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, luid, &IID_IDXGIAdapter, (void **)&adapter);
1093 ok(hr == DXGI_ERROR_NOT_FOUND, "Got unexpected hr %#x.\n", hr);
1095 else
1097 skip("Our LUID is not unique.\n");
1100 refcount = IDXGIFactory4_Release(factory4);
1101 ok(!refcount, "Factory has %u references left.\n", refcount);
1104 static void test_query_video_memory_info(void)
1106 DXGI_QUERY_VIDEO_MEMORY_INFO memory_info;
1107 IDXGIAdapter3 *adapter3;
1108 IDXGIAdapter *adapter;
1109 IDXGIDevice *device;
1110 ULONG refcount;
1111 HRESULT hr;
1113 if (!(device = create_device(0)))
1115 skip("Failed to create device.\n");
1116 return;
1119 hr = IDXGIDevice_GetAdapter(device, &adapter);
1120 ok(hr == S_OK, "Failed to get adapter, hr %#x.\n", hr);
1121 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter3, (void **)&adapter3);
1122 ok(hr == S_OK || hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
1123 if (hr == E_NOINTERFACE)
1124 goto done;
1126 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &memory_info);
1127 ok(hr == S_OK, "Failed to query video memory info, hr %#x.\n", hr);
1128 ok(memory_info.Budget >= memory_info.AvailableForReservation,
1129 "Available for reservation 0x%s is greater than budget 0x%s.\n",
1130 wine_dbgstr_longlong(memory_info.AvailableForReservation),
1131 wine_dbgstr_longlong(memory_info.Budget));
1132 ok(!memory_info.CurrentReservation, "Got unexpected current reservation 0x%s.\n",
1133 wine_dbgstr_longlong(memory_info.CurrentReservation));
1135 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &memory_info);
1136 ok(hr == S_OK, "Failed to query video memory info, hr %#x.\n", hr);
1137 ok(memory_info.Budget >= memory_info.AvailableForReservation,
1138 "Available for reservation 0x%s is greater than budget 0x%s.\n",
1139 wine_dbgstr_longlong(memory_info.AvailableForReservation),
1140 wine_dbgstr_longlong(memory_info.Budget));
1141 ok(!memory_info.CurrentReservation, "Got unexpected current reservation 0x%s.\n",
1142 wine_dbgstr_longlong(memory_info.CurrentReservation));
1144 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL + 1, &memory_info);
1145 ok(hr == E_INVALIDARG, "Failed to query video memory info, hr %#x.\n", hr);
1147 IDXGIAdapter3_Release(adapter3);
1149 done:
1150 IDXGIAdapter_Release(adapter);
1151 refcount = IDXGIDevice_Release(device);
1152 ok(!refcount, "Device has %u references left.\n", refcount);
1155 static void test_check_interface_support(void)
1157 LARGE_INTEGER driver_version;
1158 IDXGIAdapter *adapter;
1159 IDXGIDevice *device;
1160 IUnknown *iface;
1161 ULONG refcount;
1162 HRESULT hr;
1164 if (!(device = create_device(0)))
1166 skip("Failed to create device.\n");
1167 return;
1170 hr = IDXGIDevice_GetAdapter(device, &adapter);
1171 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
1173 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_IDXGIDevice, NULL);
1174 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1175 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_IDXGIDevice, &driver_version);
1176 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1177 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device, NULL);
1178 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1179 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device, &driver_version);
1180 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1182 trace("UMD version: %u.%u.%u.%u.\n",
1183 HIWORD(U(driver_version).HighPart), LOWORD(U(driver_version).HighPart),
1184 HIWORD(U(driver_version).LowPart), LOWORD(U(driver_version).LowPart));
1186 hr = IDXGIDevice_QueryInterface(device, &IID_ID3D10Device1, (void **)&iface);
1187 if (SUCCEEDED(hr))
1189 IUnknown_Release(iface);
1190 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device1, NULL);
1191 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1192 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device1, &driver_version);
1193 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1195 else
1197 win_skip("D3D10.1 is not supported.\n");
1200 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D11Device, NULL);
1201 ok(hr == DXGI_ERROR_UNSUPPORTED, "Got unexpected hr %#x.\n", hr);
1202 driver_version.LowPart = driver_version.HighPart = 0xdeadbeef;
1203 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D11Device, &driver_version);
1204 ok(hr == DXGI_ERROR_UNSUPPORTED, "Got unexpected hr %#x.\n", hr);
1205 ok(driver_version.HighPart == 0xdeadbeef, "Got unexpected driver version %#x.\n", driver_version.HighPart);
1206 ok(driver_version.LowPart == 0xdeadbeef, "Got unexpected driver version %#x.\n", driver_version.LowPart);
1208 IDXGIAdapter_Release(adapter);
1209 refcount = IDXGIDevice_Release(device);
1210 ok(!refcount, "Device has %u references left.\n", refcount);
1213 static void test_create_surface(void)
1215 ID3D11Texture2D *texture2d;
1216 DXGI_SURFACE_DESC desc;
1217 IDXGISurface *surface;
1218 IDXGIDevice *device;
1219 ULONG refcount;
1220 HRESULT hr;
1222 if (!(device = create_device(0)))
1224 skip("Failed to create device.\n");
1225 return;
1228 desc.Width = 512;
1229 desc.Height = 512;
1230 desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1231 desc.SampleDesc.Count = 1;
1232 desc.SampleDesc.Quality = 0;
1234 hr = IDXGIDevice_CreateSurface(device, &desc, 1, DXGI_USAGE_RENDER_TARGET_OUTPUT, NULL, &surface);
1235 ok(SUCCEEDED(hr), "Failed to create a dxgi surface, hr %#x\n", hr);
1237 check_interface(surface, &IID_ID3D10Texture2D, TRUE, FALSE);
1238 /* Not available on all Windows versions. */
1239 check_interface(surface, &IID_ID3D11Texture2D, TRUE, TRUE);
1240 /* Not available on all Windows versions. */
1241 check_interface(surface, &IID_IDXGISurface1, TRUE, TRUE);
1243 IDXGISurface_Release(surface);
1244 refcount = IDXGIDevice_Release(device);
1245 ok(!refcount, "Device has %u references left.\n", refcount);
1247 /* DXGI_USAGE_UNORDERED_ACCESS */
1248 if (!(device = create_d3d11_device()))
1250 skip("Failed to create D3D11 device.\n");
1251 return;
1254 surface = NULL;
1255 hr = IDXGIDevice_CreateSurface(device, &desc, 1, DXGI_USAGE_UNORDERED_ACCESS, NULL, &surface);
1256 ok(SUCCEEDED(hr), "Failed to create a dxgi surface, hr %#x\n", hr);
1258 if (surface)
1260 ID3D11UnorderedAccessView *uav;
1261 ID3D11Device *d3d_device;
1263 hr = IDXGISurface_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture2d);
1264 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1266 ID3D11Texture2D_GetDevice(texture2d, &d3d_device);
1268 hr = ID3D11Device_CreateUnorderedAccessView(d3d_device, (ID3D11Resource *)texture2d, NULL, &uav);
1269 ok(SUCCEEDED(hr), "Failed to create unordered access view, hr %#x.\n", hr);
1270 ID3D11UnorderedAccessView_Release(uav);
1272 ID3D11Device_Release(d3d_device);
1273 ID3D11Texture2D_Release(texture2d);
1275 IDXGISurface_Release(surface);
1278 refcount = IDXGIDevice_Release(device);
1279 ok(!refcount, "Device has %u references left.\n", refcount);
1282 static void test_parents(void)
1284 DXGI_SURFACE_DESC surface_desc;
1285 IDXGISurface *surface;
1286 IDXGIFactory *factory;
1287 IDXGIAdapter *adapter;
1288 IDXGIDevice *device;
1289 IDXGIOutput *output;
1290 IUnknown *parent;
1291 ULONG refcount;
1292 HRESULT hr;
1294 if (!(device = create_device(0)))
1296 skip("Failed to create device.\n");
1297 return;
1300 surface_desc.Width = 512;
1301 surface_desc.Height = 512;
1302 surface_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1303 surface_desc.SampleDesc.Count = 1;
1304 surface_desc.SampleDesc.Quality = 0;
1306 hr = IDXGIDevice_CreateSurface(device, &surface_desc, 1, DXGI_USAGE_RENDER_TARGET_OUTPUT, NULL, &surface);
1307 ok(SUCCEEDED(hr), "Failed to create a dxgi surface, hr %#x\n", hr);
1309 hr = IDXGISurface_GetParent(surface, &IID_IDXGIDevice, (void **)&parent);
1310 IDXGISurface_Release(surface);
1311 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
1312 ok(parent == (IUnknown *)device, "Got parent %p, expected %p.\n", parent, device);
1313 IUnknown_Release(parent);
1315 hr = IDXGIDevice_GetAdapter(device, &adapter);
1316 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
1318 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
1319 if (hr == DXGI_ERROR_NOT_FOUND)
1321 skip("Adapter has not outputs.\n");
1323 else
1325 ok(SUCCEEDED(hr), "EnumOutputs failed, hr %#x.\n", hr);
1327 hr = IDXGIOutput_GetParent(output, &IID_IDXGIAdapter, (void **)&parent);
1328 IDXGIOutput_Release(output);
1329 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
1330 ok(parent == (IUnknown *)adapter, "Got parent %p, expected %p.\n", parent, adapter);
1331 IUnknown_Release(parent);
1334 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1335 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
1337 hr = IDXGIFactory_GetParent(factory, &IID_IUnknown, (void **)&parent);
1338 ok(hr == E_NOINTERFACE, "GetParent returned %#x, expected %#x.\n", hr, E_NOINTERFACE);
1339 ok(parent == NULL, "Got parent %p, expected %p.\n", parent, NULL);
1340 IDXGIFactory_Release(factory);
1342 hr = IDXGIDevice_GetParent(device, &IID_IDXGIAdapter, (void **)&parent);
1343 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
1344 ok(parent == (IUnknown *)adapter, "Got parent %p, expected %p.\n", parent, adapter);
1345 IUnknown_Release(parent);
1347 IDXGIAdapter_Release(adapter);
1348 refcount = IDXGIDevice_Release(device);
1349 ok(!refcount, "Device has %u references left.\n", refcount);
1352 static void test_output(void)
1354 unsigned int mode_count, mode_count_comp, i, last_height, last_width;
1355 double last_refresh_rate;
1356 IDXGIAdapter *adapter;
1357 IDXGIDevice *device;
1358 HRESULT hr;
1359 IDXGIOutput *output;
1360 ULONG refcount;
1361 DXGI_MODE_DESC *modes;
1363 if (!(device = create_device(0)))
1365 skip("Failed to create device.\n");
1366 return;
1369 hr = IDXGIDevice_GetAdapter(device, &adapter);
1370 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
1372 hr = IDXGIAdapter_EnumOutputs(adapter, 0, NULL);
1373 ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
1375 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
1376 if (hr == DXGI_ERROR_NOT_FOUND)
1378 skip("Adapter doesn't have any outputs.\n");
1379 IDXGIAdapter_Release(adapter);
1380 IDXGIDevice_Release(device);
1381 return;
1383 ok(SUCCEEDED(hr), "EnumOutputs failed, hr %#x.\n", hr);
1385 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, NULL, NULL);
1386 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1388 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
1389 ok(SUCCEEDED(hr)
1390 || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Remote Desktop Services / Win 7 testbot */
1391 "Failed to list modes, hr %#x.\n", hr);
1392 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
1394 win_skip("GetDisplayModeList() not supported.\n");
1395 IDXGIOutput_Release(output);
1396 IDXGIAdapter_Release(adapter);
1397 IDXGIDevice_Release(device);
1398 return;
1400 mode_count_comp = mode_count;
1402 hr = IDXGIOutput_GetDisplayModeList(output, 0, 0, &mode_count, NULL);
1403 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
1404 ok(!mode_count, "Got unexpected mode_count %u.\n", mode_count);
1406 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1407 DXGI_ENUM_MODES_SCALING, &mode_count, NULL);
1408 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
1409 ok(mode_count >= mode_count_comp, "Got unexpected mode_count %u, expected >= %u.\n", mode_count, mode_count_comp);
1410 mode_count_comp = mode_count;
1412 modes = heap_calloc(mode_count + 10, sizeof(*modes));
1413 ok(!!modes, "Failed to allocate memory.\n");
1415 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1416 DXGI_ENUM_MODES_SCALING, NULL, modes);
1417 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1418 ok(!modes[0].Height, "No output was expected.\n");
1420 mode_count = 0;
1421 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1422 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1423 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#x.\n", hr);
1424 ok(!modes[0].Height, "No output was expected.\n");
1426 mode_count = mode_count_comp;
1427 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1428 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1429 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
1430 ok(mode_count == mode_count_comp, "Got unexpected mode_count %u, expected %u.\n", mode_count, mode_count_comp);
1432 last_width = last_height = 0;
1433 last_refresh_rate = 0.;
1434 for (i = 0; i < mode_count; i++)
1436 double refresh_rate = modes[i].RefreshRate.Numerator / (double)modes[i].RefreshRate.Denominator;
1438 ok(modes[i].Width && modes[i].Height, "Mode %u: Invalid dimensions %ux%u.\n",
1439 i, modes[i].Width, modes[i].Height);
1441 ok(modes[i].Width >= last_width,
1442 "Mode %u: Modes should have been sorted, width %u < %u.\n", i, modes[i].Width, last_width);
1443 if (modes[i].Width != last_width)
1445 last_width = modes[i].Width;
1446 last_height = 0;
1447 last_refresh_rate = 0.;
1448 continue;
1451 ok(modes[i].Height >= last_height,
1452 "Mode %u: Modes should have been sorted, height %u < %u.\n", i, modes[i].Height, last_height);
1453 if (modes[i].Height != last_height)
1455 last_height = modes[i].Height;
1456 last_refresh_rate = 0.;
1457 continue;
1460 ok(refresh_rate >= last_refresh_rate,
1461 "Mode %u: Modes should have been sorted, refresh rate %f < %f.\n", i, refresh_rate, last_refresh_rate);
1462 if (refresh_rate != last_refresh_rate)
1463 last_refresh_rate = refresh_rate;
1466 mode_count += 5;
1467 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1468 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1469 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
1470 ok(mode_count == mode_count_comp, "Got unexpected mode_count %u, expected %u.\n", mode_count, mode_count_comp);
1472 if (mode_count_comp)
1474 mode_count = mode_count_comp - 1;
1475 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1476 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1477 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#x.\n", hr);
1478 ok(mode_count == mode_count_comp - 1, "Got unexpected mode_count %u, expected %u.\n",
1479 mode_count, mode_count_comp - 1);
1481 else
1483 skip("Not enough modes for test.\n");
1486 heap_free(modes);
1487 IDXGIOutput_Release(output);
1488 IDXGIAdapter_Release(adapter);
1489 refcount = IDXGIDevice_Release(device);
1490 ok(!refcount, "Device has %u references left.\n", refcount);
1493 static void test_find_closest_matching_mode(void)
1495 static const DXGI_MODE_SCALING scaling_tests[] =
1497 DXGI_MODE_SCALING_CENTERED,
1498 DXGI_MODE_SCALING_STRETCHED
1500 DXGI_MODE_DESC *modes, mode, matching_mode;
1501 unsigned int i, j, mode_count;
1502 IDXGIAdapter *adapter;
1503 IDXGIDevice *device;
1504 IDXGIOutput *output;
1505 ULONG refcount;
1506 HRESULT hr;
1508 if (!(device = create_device(0)))
1510 skip("Failed to create device.\n");
1511 return;
1514 hr = IDXGIDevice_GetAdapter(device, &adapter);
1515 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
1517 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
1518 if (hr == DXGI_ERROR_NOT_FOUND)
1520 win_skip("Adapter doesn't have any outputs.\n");
1521 IDXGIAdapter_Release(adapter);
1522 IDXGIDevice_Release(device);
1523 return;
1525 ok(SUCCEEDED(hr), "EnumOutputs failed, hr %#x.\n", hr);
1527 memset(&mode, 0, sizeof(mode));
1528 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1529 ok(hr == DXGI_ERROR_INVALID_CALL || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Win 7 testbot */
1530 "Got unexpected hr %#x.\n", hr);
1531 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
1533 win_skip("FindClosestMatchingMode() not supported.\n");
1534 goto done;
1537 memset(&mode, 0, sizeof(mode));
1538 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, (IUnknown *)device);
1539 todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1541 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
1542 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
1544 modes = heap_calloc(mode_count, sizeof(*modes));
1545 ok(!!modes, "Failed to allocate memory.\n");
1547 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes);
1548 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
1550 for (i = 0; i < mode_count; ++i)
1552 mode = modes[i];
1553 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1554 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1555 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING);
1557 mode.Format = DXGI_FORMAT_UNKNOWN;
1558 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1559 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1561 mode = modes[i];
1562 mode.Width = 0;
1563 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1564 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1566 mode = modes[i];
1567 mode.Height = 0;
1568 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1569 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1571 mode = modes[i];
1572 mode.Width = mode.Height = 0;
1573 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1574 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1575 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING | MODE_DESC_IGNORE_RESOLUTION);
1576 ok(matching_mode.Width > 0 && matching_mode.Height > 0, "Got unexpected resolution %ux%u.\n",
1577 matching_mode.Width, matching_mode.Height);
1579 mode = modes[i];
1580 mode.RefreshRate.Numerator = mode.RefreshRate.Denominator = 0;
1581 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1582 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1583 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING | MODE_DESC_IGNORE_REFRESH_RATE);
1584 ok(matching_mode.RefreshRate.Numerator > 0 && matching_mode.RefreshRate.Denominator > 0,
1585 "Got unexpected refresh rate %u / %u.\n",
1586 matching_mode.RefreshRate.Numerator, matching_mode.RefreshRate.Denominator);
1588 mode = modes[i];
1589 mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1590 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1591 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1592 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING | MODE_DESC_IGNORE_SCANLINE_ORDERING);
1593 ok(matching_mode.ScanlineOrdering, "Got unexpected scanline ordering %#x.\n",
1594 matching_mode.ScanlineOrdering);
1596 memset(&mode, 0, sizeof(mode));
1597 mode.Width = modes[i].Width;
1598 mode.Height = modes[i].Height;
1599 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1600 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1601 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1602 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1604 memset(&mode, 0, sizeof(mode));
1605 mode.Width = modes[i].Width - 1;
1606 mode.Height = modes[i].Height - 1;
1607 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1608 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1609 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1610 check_mode_desc(&matching_mode, &modes[i],
1611 (MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT) | MODE_DESC_IGNORE_EXACT_RESOLUTION);
1613 memset(&mode, 0, sizeof(mode));
1614 mode.Width = modes[i].Width + 1;
1615 mode.Height = modes[i].Height + 1;
1616 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1617 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1618 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1619 check_mode_desc(&matching_mode, &modes[i],
1620 (MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT) | MODE_DESC_IGNORE_EXACT_RESOLUTION);
1623 memset(&mode, 0, sizeof(mode));
1624 mode.Width = mode.Height = 10;
1625 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1626 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1627 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1628 /* Find mode for the lowest resolution. */
1629 mode = modes[0];
1630 for (i = 0; i < mode_count; ++i)
1632 if (mode.Width >= modes[i].Width && mode.Height >= modes[i].Height)
1633 mode = modes[i];
1635 check_mode_desc(&matching_mode, &mode, MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1637 memset(&mode, 0, sizeof(mode));
1638 mode.Width = modes[0].Width;
1639 mode.Height = modes[0].Height;
1640 mode.Format = modes[0].Format;
1641 mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST;
1642 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1643 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1644 check_mode_desc(&matching_mode, &modes[0], MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1646 memset(&mode, 0, sizeof(mode));
1647 mode.Width = modes[0].Width;
1648 mode.Height = modes[0].Height;
1649 mode.Format = modes[0].Format;
1650 mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST;
1651 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1652 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1653 check_mode_desc(&matching_mode, &modes[0], MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1655 for (i = 0; i < ARRAY_SIZE(scaling_tests); ++i)
1657 for (j = 0; j < mode_count; ++j)
1659 if (modes[j].Scaling != scaling_tests[i])
1660 continue;
1662 memset(&mode, 0, sizeof(mode));
1663 mode.Width = modes[j].Width;
1664 mode.Height = modes[j].Height;
1665 mode.Format = modes[j].Format;
1666 mode.Scaling = modes[j].Scaling;
1667 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1668 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
1669 check_mode_desc(&matching_mode, &modes[j],
1670 MODE_DESC_IGNORE_REFRESH_RATE | MODE_DESC_IGNORE_SCANLINE_ORDERING);
1671 break;
1675 heap_free(modes);
1677 done:
1678 IDXGIOutput_Release(output);
1679 IDXGIAdapter_Release(adapter);
1680 refcount = IDXGIDevice_Release(device);
1681 ok(!refcount, "Device has %u references left.\n", refcount);
1684 struct refresh_rates
1686 UINT numerator;
1687 UINT denominator;
1688 BOOL numerator_should_pass;
1689 BOOL denominator_should_pass;
1692 static void test_create_swapchain(void)
1694 struct swapchain_fullscreen_state initial_state, expected_state;
1695 unsigned int i, expected_width, expected_height;
1696 DXGI_SWAP_CHAIN_DESC creation_desc, result_desc;
1697 DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc;
1698 DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
1699 IDXGIDevice *device, *bgra_device;
1700 ULONG refcount, expected_refcount;
1701 IUnknown *obj, *obj2, *parent;
1702 IDXGISwapChain1 *swapchain1;
1703 RECT *expected_client_rect;
1704 IDXGISwapChain *swapchain;
1705 IDXGISurface1 *surface;
1706 IDXGIAdapter *adapter;
1707 IDXGIFactory *factory;
1708 IDXGIOutput *target;
1709 BOOL fullscreen;
1710 HWND window;
1711 HRESULT hr;
1713 const struct refresh_rates refresh_list[] =
1715 {60, 60, FALSE, FALSE},
1716 {60, 0, TRUE, FALSE},
1717 {60, 1, TRUE, TRUE},
1718 { 0, 60, TRUE, FALSE},
1719 { 0, 0, TRUE, FALSE},
1722 if (!(device = create_device(0)))
1724 skip("Failed to create device.\n");
1725 return;
1728 creation_desc.BufferDesc.Width = 800;
1729 creation_desc.BufferDesc.Height = 600;
1730 creation_desc.BufferDesc.RefreshRate.Numerator = 60;
1731 creation_desc.BufferDesc.RefreshRate.Denominator = 60;
1732 creation_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1733 creation_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1734 creation_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
1735 creation_desc.SampleDesc.Count = 1;
1736 creation_desc.SampleDesc.Quality = 0;
1737 creation_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1738 creation_desc.BufferCount = 1;
1739 creation_desc.OutputWindow = NULL;
1740 creation_desc.Windowed = TRUE;
1741 creation_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
1742 creation_desc.Flags = 0;
1744 hr = IDXGIDevice_QueryInterface(device, &IID_IUnknown, (void **)&obj);
1745 ok(hr == S_OK, "IDXGIDevice does not implement IUnknown.\n");
1747 hr = IDXGIDevice_GetAdapter(device, &adapter);
1748 ok(hr == S_OK, "Failed to get adapter, hr %#x.\n", hr);
1750 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1751 ok(hr == S_OK, "Failed to get parent, hr %#x.\n", hr);
1753 expected_refcount = get_refcount(adapter);
1754 refcount = get_refcount(factory);
1755 ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
1756 refcount = get_refcount(device);
1757 ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
1759 creation_desc.OutputWindow = NULL;
1760 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1761 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1763 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 0, 0, 0, 0, 0, 0);
1764 memset(&initial_state, 0, sizeof(initial_state));
1765 capture_fullscreen_state(&initial_state.fullscreen_state, creation_desc.OutputWindow);
1767 hr = IDXGIFactory_CreateSwapChain(factory, NULL, &creation_desc, &swapchain);
1768 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1769 hr = IDXGIFactory_CreateSwapChain(factory, obj, NULL, &swapchain);
1770 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1771 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, NULL);
1772 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1773 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1774 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
1776 refcount = get_refcount(adapter);
1777 ok(refcount >= expected_refcount, "Got refcount %u, expected >= %u.\n", refcount, expected_refcount);
1778 refcount = get_refcount(factory);
1779 todo_wine ok(refcount == 4, "Got unexpected refcount %u.\n", refcount);
1780 refcount = get_refcount(device);
1781 ok(refcount == 3, "Got unexpected refcount %u.\n", refcount);
1783 hr = IDXGISwapChain_GetDesc(swapchain, NULL);
1784 ok(hr == E_INVALIDARG, "GetDesc unexpectedly returned %#x.\n", hr);
1786 hr = IDXGISwapChain_GetParent(swapchain, &IID_IUnknown, (void **)&parent);
1787 ok(hr == S_OK, "Failed to get parent,%#x.\n", hr);
1788 ok(parent == (IUnknown *)factory, "Got unexpected parent interface pointer %p.\n", parent);
1789 refcount = IUnknown_Release(parent);
1790 todo_wine ok(refcount == 4, "Got unexpected refcount %u.\n", refcount);
1792 hr = IDXGISwapChain_GetParent(swapchain, &IID_IDXGIFactory, (void **)&parent);
1793 ok(hr == S_OK, "Failed to get parent,%#x.\n", hr);
1794 ok(parent == (IUnknown *)factory, "Got unexpected parent interface pointer %p.\n", parent);
1795 refcount = IUnknown_Release(parent);
1796 todo_wine ok(refcount == 4, "Got unexpected refcount %u.\n", refcount);
1798 hr = IDXGISwapChain_QueryInterface(swapchain, &IID_IDXGISwapChain1, (void **)&swapchain1);
1799 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
1800 "Failed to query IDXGISwapChain1 interface, hr %#x.\n", hr);
1801 if (SUCCEEDED(hr))
1803 hr = IDXGISwapChain1_GetDesc1(swapchain1, NULL);
1804 ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
1805 hr = IDXGISwapChain1_GetDesc1(swapchain1, &swapchain_desc);
1806 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1807 ok(!swapchain_desc.Stereo, "Got unexpected stereo %#x.\n", swapchain_desc.Stereo);
1808 ok(swapchain_desc.Scaling == DXGI_SCALING_STRETCH,
1809 "Got unexpected scaling %#x.\n", swapchain_desc.Scaling);
1810 ok(swapchain_desc.AlphaMode == DXGI_ALPHA_MODE_IGNORE,
1811 "Got unexpected alpha mode %#x.\n", swapchain_desc.AlphaMode);
1812 hr = IDXGISwapChain1_GetFullscreenDesc(swapchain1, NULL);
1813 ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
1814 hr = IDXGISwapChain1_GetFullscreenDesc(swapchain1, &fullscreen_desc);
1815 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1816 ok(fullscreen_desc.Windowed == creation_desc.Windowed,
1817 "Got unexpected windowed %#x.\n", fullscreen_desc.Windowed);
1818 hr = IDXGISwapChain1_GetHwnd(swapchain1, &window);
1819 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1820 ok(window == creation_desc.OutputWindow, "Got unexpected window %p.\n", window);
1821 IDXGISwapChain1_Release(swapchain1);
1824 refcount = IDXGISwapChain_Release(swapchain);
1825 ok(!refcount, "Swapchain has %u references left.\n", refcount);
1827 refcount = get_refcount(factory);
1828 ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
1830 for (i = 0; i < ARRAY_SIZE(refresh_list); ++i)
1832 creation_desc.BufferDesc.RefreshRate.Numerator = refresh_list[i].numerator;
1833 creation_desc.BufferDesc.RefreshRate.Denominator = refresh_list[i].denominator;
1835 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1836 ok(hr == S_OK, "Test %u: Failed to create swapchain, hr %#x.\n", i, hr);
1838 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
1839 ok(hr == S_OK, "Test %u: Failed to get swapchain desc, hr %#x.\n", i, hr);
1841 ok(result_desc.Windowed == creation_desc.Windowed, "Test %u: Got unexpected windowed %#x.\n",
1842 i, result_desc.Windowed);
1844 todo_wine_if (!refresh_list[i].numerator_should_pass)
1845 ok(result_desc.BufferDesc.RefreshRate.Numerator == refresh_list[i].numerator,
1846 "Numerator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Numerator);
1848 todo_wine_if (!refresh_list[i].denominator_should_pass)
1849 ok(result_desc.BufferDesc.RefreshRate.Denominator == refresh_list[i].denominator,
1850 "Denominator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Denominator);
1852 fullscreen = 0xdeadbeef;
1853 target = (void *)0xdeadbeef;
1854 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
1855 ok(hr == S_OK, "Test %u: Failed to get fullscreen state, hr %#x.\n", i, hr);
1856 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
1857 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
1859 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, NULL);
1860 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
1861 fullscreen = 0xdeadbeef;
1862 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
1863 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
1864 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
1865 target = (void *)0xdeadbeef;
1866 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
1867 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
1868 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
1870 check_swapchain_fullscreen_state(swapchain, &initial_state);
1871 IDXGISwapChain_Release(swapchain);
1874 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
1876 /* Test GDI-compatible swapchain */
1877 bgra_device = create_device(D3D10_CREATE_DEVICE_BGRA_SUPPORT);
1878 ok(!!bgra_device, "Failed to create BGRA capable device.\n");
1880 hr = IDXGIDevice_QueryInterface(bgra_device, &IID_IUnknown, (void **)&obj2);
1881 ok(hr == S_OK, "IDXGIDevice does not implement IUnknown.\n");
1883 hr = IDXGIFactory_CreateSwapChain(factory, obj2, &creation_desc, &swapchain);
1884 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
1886 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface1, (void **)&surface);
1887 if (SUCCEEDED(hr))
1889 HDC hdc;
1891 hr = IDXGISurface1_GetDC(surface, FALSE, &hdc);
1892 ok(FAILED(hr), "Expected GetDC() to fail, %#x\n", hr);
1894 IDXGISurface1_Release(surface);
1895 IDXGISwapChain_Release(swapchain);
1897 creation_desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
1898 creation_desc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
1900 hr = IDXGIFactory_CreateSwapChain(factory, obj2, &creation_desc, &swapchain);
1901 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
1903 creation_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1904 creation_desc.Flags = 0;
1906 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface1, (void **)&surface);
1907 ok(hr == S_OK, "Failed to get front buffer, hr %#x.\n", hr);
1909 hr = IDXGISurface1_GetDC(surface, FALSE, &hdc);
1910 ok(hr == S_OK, "Expected GetDC() to succeed, %#x\n", hr);
1911 IDXGISurface1_ReleaseDC(surface, NULL);
1913 IDXGISurface1_Release(surface);
1914 IDXGISwapChain_Release(swapchain);
1916 else
1918 win_skip("IDXGISurface1 is not supported, skipping GetDC() tests.\n");
1919 IDXGISwapChain_Release(swapchain);
1921 IUnknown_Release(obj2);
1922 IDXGIDevice_Release(bgra_device);
1924 creation_desc.Windowed = FALSE;
1926 for (i = 0; i < ARRAY_SIZE(refresh_list); ++i)
1928 creation_desc.BufferDesc.RefreshRate.Numerator = refresh_list[i].numerator;
1929 creation_desc.BufferDesc.RefreshRate.Denominator = refresh_list[i].denominator;
1931 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1932 ok(SUCCEEDED(hr), "Test %u: Failed to create swapchain, hr %#x.\n", i, hr);
1934 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
1935 ok(hr == S_OK, "Test %u: Failed to get swapchain desc, hr %#x.\n", i, hr);
1937 /* When numerator is non-zero and denominator is zero, the windowed mode is used.
1938 * Additionally, some versions of WARP seem to always fail to change fullscreen state. */
1939 if (result_desc.Windowed != creation_desc.Windowed)
1940 trace("Test %u: Failed to change fullscreen state.\n", i);
1942 todo_wine_if (!refresh_list[i].numerator_should_pass)
1943 ok(result_desc.BufferDesc.RefreshRate.Numerator == refresh_list[i].numerator,
1944 "Numerator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Numerator);
1946 todo_wine_if (!refresh_list[i].denominator_should_pass)
1947 ok(result_desc.BufferDesc.RefreshRate.Denominator == refresh_list[i].denominator,
1948 "Denominator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Denominator);
1950 fullscreen = FALSE;
1951 target = NULL;
1952 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
1953 ok(hr == S_OK, "Test %u: Failed to get fullscreen state, hr %#x.\n", i, hr);
1954 ok(fullscreen == !result_desc.Windowed, "Test %u: Got fullscreen %#x, expected %#x.\n",
1955 i, fullscreen, result_desc.Windowed);
1956 ok(result_desc.Windowed ? !target : !!target, "Test %u: Got unexpected target %p.\n", i, target);
1957 if (!result_desc.Windowed)
1959 IDXGIOutput *containing_output;
1960 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
1961 ok(hr == S_OK, "Test %u: Failed to get containing output, hr %#x.\n", i, hr);
1962 ok(containing_output == target, "Test %u: Got unexpected containing output pointer %p.\n",
1963 i, containing_output);
1964 IDXGIOutput_Release(containing_output);
1966 ok(output_belongs_to_adapter(target, adapter),
1967 "Test %u: Output %p doesn't belong to adapter %p.\n",
1968 i, target, adapter);
1969 IDXGIOutput_Release(target);
1971 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, NULL);
1972 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
1973 fullscreen = FALSE;
1974 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
1975 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
1976 ok(fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
1977 target = NULL;
1978 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
1979 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
1980 ok(!!target, "Test %u: Got unexpected target %p.\n", i, target);
1981 IDXGIOutput_Release(target);
1984 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1985 ok(hr == S_OK, "Test %u: Failed to set fullscreen state, hr %#x.\n", i, hr);
1987 fullscreen = 0xdeadbeef;
1988 target = (void *)0xdeadbeef;
1989 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
1990 ok(hr == S_OK, "Test %u: Failed to get fullscreen state, hr %#x.\n", i, hr);
1991 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
1992 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
1994 check_swapchain_fullscreen_state(swapchain, &initial_state);
1995 IDXGISwapChain_Release(swapchain);
1998 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2000 /* Test swapchain creation with DXGI_FORMAT_UNKNOWN. */
2001 creation_desc.BufferDesc.Format = DXGI_FORMAT_UNKNOWN;
2002 creation_desc.Windowed = TRUE;
2003 creation_desc.Flags = 0;
2004 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2005 ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
2007 creation_desc.Windowed = FALSE;
2008 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2009 ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
2011 creation_desc.BufferCount = 2;
2012 creation_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
2013 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2014 ok(hr == E_INVALIDARG || hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
2015 creation_desc.BufferCount = 1;
2016 creation_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
2018 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2020 /* Test swapchain creation with backbuffer width and height equal to 0. */
2021 expected_state = initial_state;
2022 expected_client_rect = &expected_state.fullscreen_state.client_rect;
2024 /* Windowed */
2025 expected_width = expected_client_rect->right;
2026 expected_height = expected_client_rect->bottom;
2028 creation_desc.BufferDesc.Width = 0;
2029 creation_desc.BufferDesc.Height = 0;
2030 creation_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2031 creation_desc.Windowed = TRUE;
2032 creation_desc.Flags = 0;
2033 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2034 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
2035 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2036 ok(hr == S_OK, "Failed to get swapchain desc, hr %#x.\n", hr);
2037 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2038 result_desc.BufferDesc.Width, expected_width);
2039 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2040 result_desc.BufferDesc.Height, expected_height);
2041 check_swapchain_fullscreen_state(swapchain, &expected_state);
2042 IDXGISwapChain_Release(swapchain);
2044 DestroyWindow(creation_desc.OutputWindow);
2045 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
2046 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
2047 0, 0, 222, 222, 0, 0, 0, 0);
2048 expected_state.fullscreen_state.style = WS_CLIPSIBLINGS | WS_CAPTION
2049 | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
2050 SetRect(&expected_state.fullscreen_state.window_rect, 0, 0, 222, 222);
2051 GetClientRect(creation_desc.OutputWindow, expected_client_rect);
2052 expected_width = expected_client_rect->right;
2053 expected_height = expected_client_rect->bottom;
2055 creation_desc.BufferDesc.Width = 0;
2056 creation_desc.BufferDesc.Height = 0;
2057 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2058 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
2059 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2060 ok(hr == S_OK, "Failed to get swapchain desc, hr %#x.\n", hr);
2061 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2062 result_desc.BufferDesc.Width, expected_width);
2063 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2064 result_desc.BufferDesc.Height, expected_height);
2065 check_swapchain_fullscreen_state(swapchain, &expected_state);
2066 IDXGISwapChain_Release(swapchain);
2068 DestroyWindow(creation_desc.OutputWindow);
2069 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
2070 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
2071 1, 1, 0, 0, 0, 0, 0, 0);
2072 expected_state.fullscreen_state.style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
2073 expected_state.fullscreen_state.exstyle = 0;
2074 SetRect(&expected_state.fullscreen_state.window_rect, 1, 1, 1, 1);
2075 SetRectEmpty(expected_client_rect);
2076 expected_width = expected_height = 8;
2078 creation_desc.BufferDesc.Width = 0;
2079 creation_desc.BufferDesc.Height = 0;
2080 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2081 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
2082 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2083 ok(hr == S_OK, "Failed to get swapchain desc, hr %#x.\n", hr);
2084 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2085 result_desc.BufferDesc.Width, expected_width);
2086 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2087 result_desc.BufferDesc.Height, expected_height);
2088 check_swapchain_fullscreen_state(swapchain, &expected_state);
2089 IDXGISwapChain_Release(swapchain);
2091 DestroyWindow(creation_desc.OutputWindow);
2092 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 0, 0, 0, 0, 0, 0);
2093 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2095 /* Fullscreen */
2096 creation_desc.Windowed = FALSE;
2097 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2098 ok(SUCCEEDED(hr), "Failed to create swapchain, hr %#x.\n", hr);
2099 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2100 ok(hr == S_OK, "Failed to get swapchain desc, hr %#x.\n", hr);
2101 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2102 ok(hr == S_OK, "Failed to set fullscreen state, hr %#x.\n", hr);
2103 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
2104 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
2105 "Failed to get containing output, hr %#x.\n", hr);
2106 check_swapchain_fullscreen_state(swapchain, &initial_state);
2107 IDXGISwapChain_Release(swapchain);
2108 if (hr == DXGI_ERROR_UNSUPPORTED)
2110 win_skip("GetContainingOutput() not supported.\n");
2111 goto done;
2113 if (result_desc.Windowed)
2115 win_skip("Fullscreen not supported.\n");
2116 IDXGIOutput_Release(expected_state.target);
2117 goto done;
2120 creation_desc.BufferDesc.Width = 0;
2121 creation_desc.BufferDesc.Height = 0;
2122 creation_desc.Windowed = FALSE;
2123 creation_desc.Flags = 0;
2124 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2125 &creation_desc, &initial_state.fullscreen_state.monitor_rect, 0, 0, expected_state.target);
2126 expected_width = expected_client_rect->right - expected_client_rect->left;
2127 expected_height = expected_client_rect->bottom - expected_client_rect->top;
2129 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2130 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
2131 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2132 ok(hr == S_OK, "Failed to get swapchain desc, hr %#x.\n", hr);
2133 todo_wine ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2134 result_desc.BufferDesc.Width, expected_width);
2135 todo_wine ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2136 result_desc.BufferDesc.Height, expected_height);
2137 check_swapchain_fullscreen_state(swapchain, &expected_state);
2138 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2139 ok(hr == S_OK, "Failed to set fullscreen state, hr %#x.\n", hr);
2140 check_swapchain_fullscreen_state(swapchain, &initial_state);
2141 IDXGISwapChain_Release(swapchain);
2143 /* Fullscreen and DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH */
2144 creation_desc.BufferDesc.Width = 0;
2145 creation_desc.BufferDesc.Height = 0;
2146 creation_desc.Windowed = FALSE;
2147 creation_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
2148 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2149 &creation_desc, &initial_state.fullscreen_state.monitor_rect, 0, 0, expected_state.target);
2150 expected_width = expected_client_rect->right - expected_client_rect->left;
2151 expected_height = expected_client_rect->bottom - expected_client_rect->top;
2153 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2154 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
2155 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2156 ok(hr == S_OK, "Failed to get swapchain desc, hr %#x.\n", hr);
2157 todo_wine ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2158 result_desc.BufferDesc.Width, expected_width);
2159 todo_wine ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2160 result_desc.BufferDesc.Height, expected_height);
2161 check_swapchain_fullscreen_state(swapchain, &expected_state);
2162 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2163 ok(hr == S_OK, "Failed to set fullscreen state, hr %#x.\n", hr);
2164 check_swapchain_fullscreen_state(swapchain, &initial_state);
2165 IDXGISwapChain_Release(swapchain);
2167 IDXGIOutput_Release(expected_state.target);
2169 done:
2170 IUnknown_Release(obj);
2171 refcount = IDXGIDevice_Release(device);
2172 ok(!refcount, "Device has %u references left.\n", refcount);
2173 refcount = IDXGIAdapter_Release(adapter);
2174 ok(!refcount, "Adapter has %u references left.\n", refcount);
2175 refcount = IDXGIFactory_Release(factory);
2176 ok(!refcount, "Factory has %u references left.\n", refcount);
2177 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2178 DestroyWindow(creation_desc.OutputWindow);
2181 static HMONITOR get_primary_if_right_side_secondary(const DXGI_OUTPUT_DESC *output_desc)
2183 HMONITOR primary, secondary;
2184 MONITORINFO mi;
2185 POINT pt = {0, 0};
2187 primary = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
2188 pt.x = output_desc->DesktopCoordinates.right;
2189 secondary = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
2190 mi.cbSize = sizeof(mi);
2191 if (secondary && secondary != primary
2192 && GetMonitorInfoW(primary, &mi) && (mi.dwFlags & MONITORINFOF_PRIMARY))
2193 return primary;
2194 return NULL;
2197 static void test_get_containing_output(IUnknown *device, BOOL is_d3d12)
2199 unsigned int adapter_idx, output_idx, output_count;
2200 DXGI_OUTPUT_DESC output_desc, output_desc2;
2201 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2202 IDXGIOutput *output, *output2;
2203 MONITORINFOEXW monitor_info;
2204 IDXGISwapChain *swapchain;
2205 IDXGIFactory *factory;
2206 IDXGIAdapter *adapter;
2207 POINT points[4 * 16];
2208 unsigned int i, j;
2209 HMONITOR monitor;
2210 HMONITOR primary;
2211 BOOL fullscreen;
2212 ULONG refcount;
2213 HRESULT hr;
2214 BOOL ret;
2216 adapter = get_adapter(device, is_d3d12);
2217 if (!adapter)
2219 skip("Failed to get adapter on Direct3D %d.\n", is_d3d12 ? 12 : 10);
2220 return;
2223 output_count = 0;
2224 while ((hr = IDXGIAdapter_EnumOutputs(adapter, output_count, &output)) != DXGI_ERROR_NOT_FOUND)
2226 ok(SUCCEEDED(hr), "Failed to enumerate output %u, hr %#x.\n", output_count, hr);
2227 IDXGIOutput_Release(output);
2228 ++output_count;
2230 IDXGIAdapter_Release(adapter);
2232 swapchain_desc.BufferDesc.Width = 100;
2233 swapchain_desc.BufferDesc.Height = 100;
2234 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
2235 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
2236 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2237 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
2238 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
2239 swapchain_desc.SampleDesc.Count = 1;
2240 swapchain_desc.SampleDesc.Quality = 0;
2241 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2242 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
2243 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
2244 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 100, 100, 0, 0, 0, 0);
2245 swapchain_desc.Windowed = TRUE;
2246 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
2247 swapchain_desc.Flags = 0;
2249 get_factory(device, is_d3d12, &factory);
2250 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2251 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
2253 monitor = MonitorFromWindow(swapchain_desc.OutputWindow, 0);
2254 ok(!!monitor, "MonitorFromWindow failed.\n");
2256 monitor_info.cbSize = sizeof(monitor_info);
2257 ret = GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info);
2258 ok(ret, "Failed to get monitor info.\n");
2260 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2261 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
2262 "GetContainingOutput failed, hr %#x.\n", hr);
2263 if (hr == DXGI_ERROR_UNSUPPORTED)
2265 win_skip("GetContainingOutput() not supported.\n");
2266 goto done;
2269 hr = IDXGIOutput_GetDesc(output, &output_desc);
2270 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
2272 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2273 ok(SUCCEEDED(hr), "GetContainingOutput failed, hr %#x.\n", hr);
2274 ok(output != output2, "Got unexpected output pointers %p, %p.\n", output, output2);
2275 check_output_equal(output, output2);
2277 refcount = IDXGIOutput_Release(output);
2278 ok(!refcount, "IDXGIOutput has %u references left.\n", refcount);
2279 refcount = IDXGIOutput_Release(output2);
2280 ok(!refcount, "IDXGIOutput has %u references left.\n", refcount);
2282 ok(!lstrcmpW(output_desc.DeviceName, monitor_info.szDevice),
2283 "Got unexpected device name %s, expected %s.\n",
2284 wine_dbgstr_w(output_desc.DeviceName), wine_dbgstr_w(monitor_info.szDevice));
2285 ok(EqualRect(&output_desc.DesktopCoordinates, &monitor_info.rcMonitor),
2286 "Got unexpected desktop coordinates %s, expected %s.\n",
2287 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
2288 wine_dbgstr_rect(&monitor_info.rcMonitor));
2290 primary = get_primary_if_right_side_secondary(&output_desc);
2292 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2293 ++adapter_idx)
2295 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
2296 ++output_idx)
2298 hr = IDXGIOutput_GetDesc(output, &output_desc);
2299 ok(SUCCEEDED(hr), "Adapter %u output %u: GetDesc failed, hr %#x.\n", adapter_idx,
2300 output_idx, hr);
2302 /* Move the OutputWindow to the current output. */
2303 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc.DesktopCoordinates.left,
2304 output_desc.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2305 ok(ret, "Adapter %u output %u: SetWindowPos failed.\n", adapter_idx, output_idx);
2307 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2308 if (FAILED(hr))
2310 win_skip("Adapter %u output %u: GetContainingOutput failed, hr %#x.\n",
2311 adapter_idx, output_idx, hr);
2312 IDXGIOutput_Release(output);
2313 continue;
2316 check_output_equal(output, output2);
2318 refcount = IDXGIOutput_Release(output2);
2319 ok(!refcount, "Adapter %u output %u: IDXGIOutput has %u references left.\n",
2320 adapter_idx, output_idx, refcount);
2322 /* Move the OutputWindow around the corners of the current output desktop coordinates. */
2323 for (i = 0; i < 4; ++i)
2325 static const POINT offsets[] =
2327 { 0, 0},
2328 {-49, 0}, {-50, 0}, {-51, 0},
2329 { 0, -49}, { 0, -50}, { 0, -51},
2330 {-49, -49}, {-50, -49}, {-51, -49},
2331 {-49, -50}, {-50, -50}, {-51, -50},
2332 {-49, -51}, {-50, -51}, {-51, -51},
2334 unsigned int x = 0, y = 0;
2336 switch (i)
2338 case 0:
2339 x = output_desc.DesktopCoordinates.left;
2340 y = output_desc.DesktopCoordinates.top;
2341 break;
2342 case 1:
2343 x = output_desc.DesktopCoordinates.right;
2344 y = output_desc.DesktopCoordinates.top;
2345 break;
2346 case 2:
2347 x = output_desc.DesktopCoordinates.right;
2348 y = output_desc.DesktopCoordinates.bottom;
2349 break;
2350 case 3:
2351 x = output_desc.DesktopCoordinates.left;
2352 y = output_desc.DesktopCoordinates.bottom;
2353 break;
2356 for (j = 0; j < ARRAY_SIZE(offsets); ++j)
2358 unsigned int idx = ARRAY_SIZE(offsets) * i + j;
2359 assert(idx < ARRAY_SIZE(points));
2360 points[idx].x = x + offsets[j].x;
2361 points[idx].y = y + offsets[j].y;
2365 for (i = 0; i < ARRAY_SIZE(points); ++i)
2367 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, points[i].x, points[i].y,
2368 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2369 ok(ret, "Adapter %u output %u point %u: Failed to set window position.\n",
2370 adapter_idx, output_idx, i);
2372 monitor = MonitorFromWindow(swapchain_desc.OutputWindow, MONITOR_DEFAULTTONEAREST);
2373 ok(!!monitor, "Adapter %u output %u point %u: Failed to get monitor from window.\n",
2374 adapter_idx, output_idx, i);
2376 monitor_info.cbSize = sizeof(monitor_info);
2377 ret = GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info);
2378 ok(ret, "Adapter %u output %u point %u: Failed to get monitor info.\n", adapter_idx,
2379 output_idx, i);
2381 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2382 /* Hack to prevent test failures with secondary on the right until multi-monitor support is improved. */
2383 todo_wine_if(primary && monitor != primary)
2384 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED),
2385 "Adapter %u output %u point %u: Failed to get containing output, hr %#x.\n",
2386 adapter_idx, output_idx, i, hr);
2387 if (hr != S_OK)
2388 continue;
2389 ok(!!output2, "Adapter %u output %u point %u: Got unexpected containing output %p.\n",
2390 adapter_idx, output_idx, i, output2);
2391 hr = IDXGIOutput_GetDesc(output2, &output_desc);
2392 ok(hr == S_OK, "Adapter %u output %u point %u: Failed to get output desc, hr %#x.\n",
2393 adapter_idx, output_idx, i, hr);
2394 refcount = IDXGIOutput_Release(output2);
2395 ok(!refcount, "Adapter %u output %u point %u: IDXGIOutput has %u references left.\n",
2396 adapter_idx, output_idx, i, refcount);
2398 ok(!lstrcmpW(output_desc.DeviceName, monitor_info.szDevice),
2399 "Adapter %u output %u point %u: Got unexpected device name %s, expected %s.\n",
2400 adapter_idx, output_idx, i, wine_dbgstr_w(output_desc.DeviceName),
2401 wine_dbgstr_w(monitor_info.szDevice));
2402 ok(EqualRect(&output_desc.DesktopCoordinates, &monitor_info.rcMonitor),
2403 "Adapter %u output %u point %u: Expect desktop coordinates %s, got %s.\n",
2404 adapter_idx, output_idx, i,
2405 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
2406 wine_dbgstr_rect(&monitor_info.rcMonitor));
2408 IDXGIOutput_Release(output);
2410 IDXGIAdapter_Release(adapter);
2413 /* Test GetContainingOutput with a full screen swapchain. The containing output should stay
2414 * the same even if the device window is moved */
2415 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2416 if (FAILED(hr))
2418 skip("SetFullscreenState failed, hr %#x.\n", hr);
2419 goto done;
2422 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2423 if (FAILED(hr))
2425 win_skip("GetContainingOutput failed, hr %#x.\n", hr);
2426 IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2427 goto done;
2430 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2431 ++adapter_idx)
2433 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
2434 ++output_idx)
2436 hr = IDXGIOutput_GetDesc(output, &output_desc);
2437 ok(hr == S_OK, "Adapter %u output %u: GetDesc failed, hr %#x.\n", adapter_idx,
2438 output_idx, hr);
2439 IDXGIOutput_Release(output);
2441 /* Move the OutputWindow to the current output. */
2442 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc.DesktopCoordinates.left,
2443 output_desc.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2444 ok(ret, "Adapter %u output %u: SetWindowPos failed.\n", adapter_idx, output_idx);
2446 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
2447 ok(hr == S_OK, "Adapter %u output %u: GetFullscreenState failed, hr %#x.\n",
2448 adapter_idx, output_idx, hr);
2449 ok(fullscreen, "Adapter %u output %u: Expect swapchain full screen.\n", adapter_idx,
2450 output_idx);
2451 ok(output == output2, "Adapter %u output %u: Expect output %p, got %p.\n",
2452 adapter_idx, output_idx, output2, output);
2453 IDXGIOutput_Release(output);
2455 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2456 ok(hr == S_OK, "Adapter %u output %u: GetContainingOutput failed, hr %#x.\n",
2457 adapter_idx, output_idx, hr);
2458 ok(output == output2, "Adapter %u output %u: Expect output %p, got %p.\n",
2459 adapter_idx, output_idx, output2, output);
2460 IDXGIOutput_Release(output);
2462 IDXGIAdapter_Release(adapter);
2465 IDXGIOutput_Release(output2);
2466 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2467 ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
2469 /* Test GetContainingOutput after a full screen swapchain is made windowed by pressing
2470 * Alt+Enter, then move it to another output and use Alt+Enter to enter full screen */
2471 output = NULL;
2472 output2 = NULL;
2473 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2474 ++adapter_idx)
2476 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx,
2477 output ? &output2 : &output)); ++output_idx)
2479 if (output2)
2480 break;
2483 IDXGIAdapter_Release(adapter);
2484 if (output2)
2485 break;
2488 if (output && output2)
2490 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2491 IDXGIOutput_Release(output);
2492 if (FAILED(hr))
2494 skip("SetFullscreenState failed, hr %#x.\n", hr);
2495 IDXGIOutput_Release(output2);
2496 goto done;
2499 /* Post an Alt + VK_RETURN WM_SYSKEYDOWN to leave full screen on the first output */
2500 PostMessageA(swapchain_desc.OutputWindow, WM_SYSKEYDOWN, VK_RETURN,
2501 (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x20000001);
2502 flush_events();
2503 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2504 ok(hr == S_OK, "GetFullscreenState failed, hr %#x.\n", hr);
2505 ok(!fullscreen, "Expect swapchain not full screen.\n");
2507 /* Move the swapchain output window to the second output */
2508 hr = IDXGIOutput_GetDesc(output2, &output_desc2);
2509 ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
2510 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc2.DesktopCoordinates.left,
2511 output_desc2.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2512 ok(ret, "SetWindowPos failed.\n");
2514 /* Post an Alt + VK_RETURN WM_SYSKEYDOWN to enter full screen on the second output */
2515 PostMessageA(swapchain_desc.OutputWindow, WM_SYSKEYDOWN, VK_RETURN,
2516 (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x20000001);
2517 flush_events();
2518 output = NULL;
2519 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
2520 ok(hr == S_OK, "GetFullscreenState failed, hr %#x.\n", hr);
2521 ok(fullscreen, "Expect swapchain full screen.\n");
2522 ok(!!output, "Expect output not NULL.\n");
2523 hr = IDXGIOutput_GetDesc(output, &output_desc);
2524 ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
2525 hr = IDXGIOutput_GetDesc(output2, &output_desc2);
2526 ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
2527 ok(!lstrcmpW(output_desc.DeviceName, output_desc2.DeviceName),
2528 "Expect device name %s, got %s.\n", wine_dbgstr_w(output_desc2.DeviceName),
2529 wine_dbgstr_w(output_desc.DeviceName));
2530 IDXGIOutput_Release(output);
2532 output = NULL;
2533 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2534 ok(hr == S_OK, "GetContainingOutput failed, hr %#x.\n", hr);
2535 hr = IDXGIOutput_GetDesc(output, &output_desc);
2536 ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
2537 hr = IDXGIOutput_GetDesc(output2, &output_desc2);
2538 ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
2539 ok(!lstrcmpW(output_desc.DeviceName, output_desc2.DeviceName),
2540 "Expect device name %s, got %s.\n", wine_dbgstr_w(output_desc2.DeviceName),
2541 wine_dbgstr_w(output_desc.DeviceName));
2543 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2544 ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
2546 else
2548 skip("This test requires two outputs.\n");
2551 if (output)
2552 IDXGIOutput_Release(output);
2553 if (output2)
2554 IDXGIOutput_Release(output2);
2556 done:
2557 refcount = IDXGISwapChain_Release(swapchain);
2558 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
2559 refcount = IDXGIFactory_Release(factory);
2560 ok(refcount == !is_d3d12, "IDXGIFactory has %u references left.\n", refcount);
2561 DestroyWindow(swapchain_desc.OutputWindow);
2564 static void test_swapchain_fullscreen_state(IDXGISwapChain *swapchain,
2565 IDXGIAdapter *adapter, const struct swapchain_fullscreen_state *initial_state)
2567 MONITORINFOEXW monitor_info, *output_monitor_info;
2568 struct swapchain_fullscreen_state expected_state;
2569 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2570 DXGI_OUTPUT_DESC output_desc;
2571 unsigned int i, output_count;
2572 IDXGIOutput *output;
2573 HRESULT hr;
2574 BOOL ret;
2576 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
2577 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
2579 check_swapchain_fullscreen_state(swapchain, initial_state);
2581 expected_state = *initial_state;
2582 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2583 &swapchain_desc, &initial_state->fullscreen_state.monitor_rect, 800, 600, NULL);
2584 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
2585 ok(SUCCEEDED(hr), "GetContainingOutput failed, hr %#x.\n", hr);
2587 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2588 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#x.\n", hr);
2589 if (FAILED(hr))
2591 skip("Could not change fullscreen state.\n");
2592 IDXGIOutput_Release(expected_state.target);
2593 return;
2595 check_swapchain_fullscreen_state(swapchain, &expected_state);
2597 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2598 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2599 check_swapchain_fullscreen_state(swapchain, &expected_state);
2601 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2602 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
2603 check_swapchain_fullscreen_state(swapchain, initial_state);
2605 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2606 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2607 check_swapchain_fullscreen_state(swapchain, initial_state);
2609 IDXGIOutput_Release(expected_state.target);
2610 expected_state.target = NULL;
2612 output_count = 0;
2613 while (IDXGIAdapter_EnumOutputs(adapter, output_count, &output) != DXGI_ERROR_NOT_FOUND)
2615 IDXGIOutput_Release(output);
2616 ++output_count;
2619 output_monitor_info = heap_calloc(output_count, sizeof(*output_monitor_info));
2620 ok(!!output_monitor_info, "Failed to allocate memory.\n");
2621 for (i = 0; i < output_count; ++i)
2623 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
2624 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2626 hr = IDXGIOutput_GetDesc(output, &output_desc);
2627 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
2629 output_monitor_info[i].cbSize = sizeof(*output_monitor_info);
2630 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&output_monitor_info[i]);
2631 ok(ret, "Failed to get monitor info.\n");
2633 IDXGIOutput_Release(output);
2636 for (i = 0; i < output_count; ++i)
2638 RECT orig_monitor_rect = output_monitor_info[i].rcMonitor;
2639 IDXGIOutput *target;
2640 BOOL fullscreen;
2642 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
2643 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2644 hr = IDXGIOutput_GetDesc(output, &output_desc);
2645 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
2647 expected_state = *initial_state;
2648 expected_state.target = output;
2649 expected_state.fullscreen_state.monitor = output_desc.Monitor;
2650 expected_state.fullscreen_state.monitor_rect = orig_monitor_rect;
2651 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2652 &swapchain_desc, &orig_monitor_rect, 800, 600, NULL);
2654 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2655 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2656 check_swapchain_fullscreen_state(swapchain, &expected_state);
2658 target = NULL;
2659 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
2660 ok(SUCCEEDED(hr), "GetFullscreenState failed, hr %#x.\n", hr);
2661 ok(target == output, "Got target pointer %p, expected %p.\n", target, output);
2662 IDXGIOutput_Release(target);
2663 fullscreen = FALSE;
2664 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2665 ok(SUCCEEDED(hr), "GetFullscreenState failed, hr %#x.\n", hr);
2666 ok(fullscreen, "Got unexpected fullscreen %#x.\n", hr);
2668 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2669 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2670 check_swapchain_fullscreen_state(swapchain, &expected_state);
2671 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, output);
2672 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
2673 check_swapchain_fullscreen_state(swapchain, &expected_state);
2674 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2675 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2676 check_swapchain_fullscreen_state(swapchain, initial_state);
2678 fullscreen = TRUE;
2679 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2680 ok(SUCCEEDED(hr), "GetFullscreenState failed, hr %#x.\n", hr);
2681 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", hr);
2683 check_swapchain_fullscreen_state(swapchain, initial_state);
2684 monitor_info.cbSize = sizeof(monitor_info);
2685 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&monitor_info);
2686 ok(ret, "Failed to get monitor info.\n");
2687 ok(EqualRect(&monitor_info.rcMonitor, &orig_monitor_rect), "Got monitor rect %s, expected %s.\n",
2688 wine_dbgstr_rect(&monitor_info.rcMonitor), wine_dbgstr_rect(&orig_monitor_rect));
2690 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2691 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2693 IDXGIOutput_Release(output);
2696 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2697 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2698 check_swapchain_fullscreen_state(swapchain, initial_state);
2700 for (i = 0; i < output_count; ++i)
2702 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
2703 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2705 hr = IDXGIOutput_GetDesc(output, &output_desc);
2706 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
2708 monitor_info.cbSize = sizeof(monitor_info);
2709 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&monitor_info);
2710 ok(ret, "Failed to get monitor info.\n");
2712 ok(EqualRect(&monitor_info.rcMonitor, &output_monitor_info[i].rcMonitor),
2713 "Got monitor rect %s, expected %s.\n",
2714 wine_dbgstr_rect(&monitor_info.rcMonitor),
2715 wine_dbgstr_rect(&output_monitor_info[i].rcMonitor));
2717 IDXGIOutput_Release(output);
2720 heap_free(output_monitor_info);
2723 static void test_set_fullscreen(IUnknown *device, BOOL is_d3d12)
2725 struct swapchain_fullscreen_state initial_state;
2726 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2727 IDXGIAdapter *adapter = NULL;
2728 IDXGISwapChain *swapchain;
2729 IDXGIFactory *factory;
2730 IDXGIOutput *output;
2731 BOOL fullscreen;
2732 ULONG refcount;
2733 HRESULT hr;
2735 get_factory(device, is_d3d12, &factory);
2737 swapchain_desc.BufferDesc.Width = 800;
2738 swapchain_desc.BufferDesc.Height = 600;
2739 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
2740 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
2741 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2742 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
2743 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
2744 swapchain_desc.SampleDesc.Count = 1;
2745 swapchain_desc.SampleDesc.Quality = 0;
2746 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2747 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
2748 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2749 swapchain_desc.Windowed = TRUE;
2750 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
2751 swapchain_desc.Flags = 0;
2753 memset(&initial_state, 0, sizeof(initial_state));
2754 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
2755 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2756 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
2757 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2758 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
2759 "Failed to get containing output, hr %#x.\n", hr);
2760 if (FAILED(hr))
2762 skip("Could not get output.\n");
2763 goto done;
2765 hr = IDXGIOutput_GetParent(output, &IID_IDXGIAdapter, (void **)&adapter);
2766 ok(hr == S_OK, "Failed to get parent, hr %#x.\n", hr);
2767 IDXGIOutput_Release(output);
2769 check_swapchain_fullscreen_state(swapchain, &initial_state);
2770 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2771 ok(SUCCEEDED(hr) || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
2772 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
2773 "SetFullscreenState failed, hr %#x.\n", hr);
2774 if (FAILED(hr))
2776 skip("Could not change fullscreen state.\n");
2777 goto done;
2779 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2780 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2781 refcount = IDXGISwapChain_Release(swapchain);
2782 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
2784 DestroyWindow(swapchain_desc.OutputWindow);
2785 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2786 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2787 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2788 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
2789 check_swapchain_fullscreen_state(swapchain, &initial_state);
2790 test_swapchain_fullscreen_state(swapchain, adapter, &initial_state);
2791 refcount = IDXGISwapChain_Release(swapchain);
2792 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
2794 DestroyWindow(swapchain_desc.OutputWindow);
2795 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2796 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2797 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2798 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2799 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2800 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2801 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2802 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2803 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2804 DestroyWindow(swapchain_desc.OutputWindow);
2805 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2806 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2807 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2808 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2809 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2810 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2811 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#x.\n", hr);
2812 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2813 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2814 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2815 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2816 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2817 refcount = IDXGISwapChain_Release(swapchain);
2818 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
2820 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2821 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2822 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2823 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2824 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2825 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2826 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2827 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2828 ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2829 DestroyWindow(swapchain_desc.OutputWindow);
2830 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2831 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2832 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2833 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2834 ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2835 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2836 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2837 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2838 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2839 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2840 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2841 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#x.\n", hr);
2842 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2843 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2844 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2845 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2846 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2847 refcount = IDXGISwapChain_Release(swapchain);
2848 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
2850 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2851 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2852 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
2853 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2854 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
2855 check_swapchain_fullscreen_state(swapchain, &initial_state);
2856 test_swapchain_fullscreen_state(swapchain, adapter, &initial_state);
2858 done:
2859 if (adapter)
2860 IDXGIAdapter_Release(adapter);
2861 refcount = IDXGISwapChain_Release(swapchain);
2862 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
2863 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2864 DestroyWindow(swapchain_desc.OutputWindow);
2866 refcount = IDXGIFactory_Release(factory);
2867 ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
2870 static void test_default_fullscreen_target_output(IUnknown *device, BOOL is_d3d12)
2872 IDXGIOutput *output, *containing_output, *target;
2873 unsigned int adapter_idx, output_idx;
2874 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2875 DXGI_OUTPUT_DESC output_desc;
2876 unsigned int width, height;
2877 IDXGISwapChain *swapchain;
2878 IDXGIFactory *factory;
2879 IDXGIAdapter *adapter;
2880 BOOL fullscreen, ret;
2881 RECT window_rect;
2882 ULONG refcount;
2883 HRESULT hr;
2885 get_factory(device, is_d3d12, &factory);
2887 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
2888 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
2889 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2890 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
2891 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
2892 swapchain_desc.SampleDesc.Count = 1;
2893 swapchain_desc.SampleDesc.Quality = 0;
2894 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2895 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
2896 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
2897 swapchain_desc.Flags = 0;
2899 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2900 ++adapter_idx)
2902 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
2903 ++output_idx)
2905 /* Windowed swapchain */
2906 swapchain_desc.BufferDesc.Width = 640;
2907 swapchain_desc.BufferDesc.Height = 480;
2908 swapchain_desc.OutputWindow = create_window();
2909 swapchain_desc.Windowed = TRUE;
2910 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc,
2911 &swapchain);
2912 ok(SUCCEEDED(hr), "Adapter %u output %u: CreateSwapChain failed, hr %#x.\n",
2913 adapter_idx, output_idx, hr);
2915 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &containing_output);
2916 ok(SUCCEEDED(hr), "Adapter %u output %u: GetFullscreenState failed, hr %#x.\n",
2917 adapter_idx, output_idx, hr);
2918 ok(!fullscreen, "Adapter %u output %u: Expected not fullscreen.\n", adapter_idx,
2919 output_idx);
2920 ok(!containing_output, "Adapter %u output %u: Expected a null output.\n", adapter_idx,
2921 output_idx);
2923 /* Move the OutputWindow to the current output. */
2924 hr = IDXGIOutput_GetDesc(output, &output_desc);
2925 ok(SUCCEEDED(hr), "Adapter %u output %u: GetDesc failed, hr %#x.\n", adapter_idx,
2926 output_idx, hr);
2927 ret = SetWindowPos(swapchain_desc.OutputWindow, 0,
2928 output_desc.DesktopCoordinates.left, output_desc.DesktopCoordinates.top,
2929 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2930 ok(ret, "Adapter %u output %u: SetWindowPos failed, error %#x.\n", adapter_idx,
2931 output_idx, GetLastError());
2933 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
2934 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
2935 "Adapter %u output %u: GetContainingOutput failed, hr %#x.\n", adapter_idx,
2936 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(SUCCEEDED(hr) || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE,
2949 "Adapter %u output %u: SetFullscreenState failed, hr %#x.\n", adapter_idx,
2950 output_idx, hr);
2951 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
2953 skip("Adapter %u output %u: Could not change fullscreen state.\n", adapter_idx,
2954 output_idx);
2955 IDXGIOutput_Release(containing_output);
2956 IDXGISwapChain_Release(swapchain);
2957 IDXGIOutput_Release(output);
2958 DestroyWindow(swapchain_desc.OutputWindow);
2959 continue;
2961 GetWindowRect(swapchain_desc.OutputWindow, &window_rect);
2962 ok(EqualRect(&window_rect, &output_desc.DesktopCoordinates),
2963 "Adapter %u output %u: Expect window rect %s, got %s.\n", adapter_idx,
2964 output_idx, wine_dbgstr_rect(&output_desc.DesktopCoordinates),
2965 wine_dbgstr_rect(&window_rect));
2967 target = NULL;
2968 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
2969 ok(SUCCEEDED(hr), "Adapter %u output %u: GetFullscreenState failed, hr %#x.\n",
2970 adapter_idx, output_idx, hr);
2971 ok(target != containing_output,
2972 "Adapter %u output %u: Got unexpected output %p, expected %p.\n", adapter_idx,
2973 output_idx, target, containing_output);
2974 check_output_equal(target, containing_output);
2976 refcount = IDXGIOutput_Release(containing_output);
2977 ok(!refcount, "Adapter %u output %u: IDXGIOutput has %u references left.\n",
2978 adapter_idx, output_idx, refcount);
2980 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
2981 ok(SUCCEEDED(hr), "Adapter %u output %u: GetContainingOutput failed, hr %#x.\n",
2982 adapter_idx, output_idx, hr);
2983 ok(containing_output == target,
2984 "Adapter %u output %u: Got unexpected containing output %p, expected %p.\n",
2985 adapter_idx, output_idx, containing_output, target);
2986 refcount = IDXGIOutput_Release(containing_output);
2987 ok(refcount >= 2, "Adapter %u output %u: Got unexpected refcount %u.\n", adapter_idx,
2988 output_idx, refcount);
2989 refcount = IDXGIOutput_Release(target);
2990 ok(refcount >= 1, "Adapter %u output %u: Got unexpected refcount %u.\n", adapter_idx,
2991 output_idx, refcount);
2993 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2994 ok(SUCCEEDED(hr), "Adapter %u output %u: SetFullscreenState failed, hr %#x.\n",
2995 adapter_idx, output_idx, hr);
2996 refcount = IDXGISwapChain_Release(swapchain);
2997 ok(!refcount, "Adapter %u output %u: IDXGISwapChain has %u references left.\n",
2998 adapter_idx, output_idx, refcount);
2999 DestroyWindow(swapchain_desc.OutputWindow);
3001 /* Full screen swapchain */
3002 width = output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left;
3003 height = output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top;
3004 swapchain_desc.BufferDesc.Width = width;
3005 swapchain_desc.BufferDesc.Height = height;
3006 swapchain_desc.OutputWindow = create_window();
3007 swapchain_desc.Windowed = FALSE;
3008 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc.DesktopCoordinates.left,
3009 output_desc.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
3010 ok(ret, "Adapter %u output %u: SetWindowPos failed, error %#x.\n", adapter_idx,
3011 output_idx, GetLastError());
3012 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc,
3013 &swapchain);
3014 if (FAILED(hr))
3016 skip("Adapter %u output %u: CreateSwapChain failed, hr %#x.\n", adapter_idx,
3017 output_idx, hr);
3018 IDXGIOutput_Release(output);
3019 DestroyWindow(swapchain_desc.OutputWindow);
3020 continue;
3023 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &containing_output);
3024 ok(SUCCEEDED(hr), "Adapter %u output %u: GetFullscreenState failed, hr %#x.\n",
3025 adapter_idx, output_idx, hr);
3026 ok(fullscreen, "Adapter %u output %u: Expected fullscreen.\n", adapter_idx, output_idx);
3027 ok(!!containing_output, "Adapter %u output %u: Expected a valid output.\n", adapter_idx,
3028 output_idx);
3029 if (containing_output)
3030 IDXGIOutput_Release(containing_output);
3032 ret = GetWindowRect(swapchain_desc.OutputWindow, &window_rect);
3033 ok(ret, "Adapter %u output %u: GetWindowRect failed, error %#x.\n", adapter_idx,
3034 output_idx, GetLastError());
3035 ok(EqualRect(&window_rect, &output_desc.DesktopCoordinates),
3036 "Adapter %u output %u: Expect window rect %s, got %s.\n", adapter_idx,
3037 output_idx, wine_dbgstr_rect(&output_desc.DesktopCoordinates),
3038 wine_dbgstr_rect(&window_rect));
3040 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
3041 ok(hr == S_OK, "Adapter %u output %u: GetContainingOutput failed, hr %#x.\n",
3042 adapter_idx, output_idx, hr);
3043 ok(containing_output != output,
3044 "Adapter %u output %u: Got unexpected output %p, expected %p.\n", adapter_idx,
3045 output_idx, output, containing_output);
3046 check_output_equal(output, containing_output);
3047 IDXGIOutput_Release(containing_output);
3049 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3050 ok(hr == S_OK, "Adapter %u output %u: SetFullscreenState failed, hr %#x.\n",
3051 adapter_idx, output_idx, hr);
3052 refcount = IDXGISwapChain_Release(swapchain);
3053 ok(!refcount, "Adapter %u output %u: IDXGISwapChain has %u references left.\n",
3054 adapter_idx, output_idx, refcount);
3055 refcount = IDXGIOutput_Release(output);
3056 ok(!refcount, "Adapter %u output %u: IDXGIOutput has %u references left.\n",
3057 adapter_idx, output_idx, refcount);
3058 DestroyWindow(swapchain_desc.OutputWindow);
3060 IDXGIAdapter_Release(adapter);
3063 refcount = IDXGIFactory_Release(factory);
3064 ok(refcount == !is_d3d12, "IDXGIFactory has %u references left.\n", refcount);
3067 static void test_windowed_resize_target(IDXGISwapChain *swapchain, HWND window,
3068 struct swapchain_fullscreen_state *state)
3070 struct swapchain_fullscreen_state expected_state;
3071 struct fullscreen_state *e;
3072 DXGI_MODE_DESC mode;
3073 RECT window_rect;
3074 unsigned int i;
3075 HRESULT hr;
3076 BOOL ret;
3078 static const struct
3080 unsigned int width, height;
3082 sizes[] =
3084 {200, 200},
3085 {400, 200},
3086 {400, 400},
3087 {600, 800},
3088 {1000, 600},
3089 {1600, 100},
3090 {2000, 1000},
3093 check_swapchain_fullscreen_state(swapchain, state);
3094 expected_state = *state;
3095 e = &expected_state.fullscreen_state;
3097 for (i = 0; i < ARRAY_SIZE(sizes); ++i)
3099 SetRect(&e->client_rect, 0, 0, sizes[i].width, sizes[i].height);
3100 e->window_rect = e->client_rect;
3101 ret = AdjustWindowRectEx(&e->window_rect, GetWindowLongW(window, GWL_STYLE),
3102 FALSE, GetWindowLongW(window, GWL_EXSTYLE));
3103 ok(ret, "AdjustWindowRectEx failed.\n");
3104 if (GetMenu(window))
3105 e->client_rect.bottom -= GetSystemMetrics(SM_CYMENU);
3106 SetRect(&e->window_rect, 0, 0,
3107 e->window_rect.right - e->window_rect.left,
3108 e->window_rect.bottom - e->window_rect.top);
3109 GetWindowRect(window, &window_rect);
3110 OffsetRect(&e->window_rect, window_rect.left, window_rect.top);
3111 if (e->window_rect.right >= e->monitor_rect.right
3112 || e->window_rect.bottom >= e->monitor_rect.bottom)
3114 skip("Test %u: Window %s does not fit on screen %s.\n",
3115 i, wine_dbgstr_rect(&e->window_rect), wine_dbgstr_rect(&e->monitor_rect));
3116 continue;
3119 memset(&mode, 0, sizeof(mode));
3120 mode.Width = sizes[i].width;
3121 mode.Height = sizes[i].height;
3122 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
3123 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3124 check_swapchain_fullscreen_state(swapchain, &expected_state);
3127 ret = SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER);
3128 ok(ret, "SetWindowPos failed, error %#x.\n", GetLastError());
3129 GetWindowRect(window, &e->window_rect);
3130 GetClientRect(window, &e->client_rect);
3131 ret = SetWindowPos(window, 0, 0, 0, 200, 200, SWP_NOMOVE | SWP_NOZORDER);
3132 ok(ret, "SetWindowPos failed, error %#x.\n", GetLastError());
3134 memset(&mode, 0, sizeof(mode));
3135 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
3136 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3137 check_swapchain_fullscreen_state(swapchain, &expected_state);
3139 GetWindowRect(window, &e->window_rect);
3140 GetClientRect(window, &e->client_rect);
3141 *state = expected_state;
3144 static void test_fullscreen_resize_target(IDXGISwapChain *swapchain,
3145 const struct swapchain_fullscreen_state *initial_state)
3147 struct swapchain_fullscreen_state expected_state;
3148 DXGI_SWAP_CHAIN_DESC swapchain_desc;
3149 DXGI_OUTPUT_DESC output_desc;
3150 unsigned int i, mode_count;
3151 DXGI_MODE_DESC *modes;
3152 IDXGIOutput *target;
3153 HRESULT hr;
3155 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
3156 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
3158 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
3159 ok(SUCCEEDED(hr), "GetFullscreenState failed, hr %#x.\n", hr);
3161 hr = IDXGIOutput_GetDisplayModeList(target, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
3162 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Win 7 testbot */
3163 "Failed to list modes, hr %#x.\n", hr);
3164 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
3166 win_skip("GetDisplayModeList() not supported.\n");
3167 IDXGIOutput_Release(target);
3168 return;
3171 modes = heap_calloc(mode_count, sizeof(*modes));
3172 ok(!!modes, "Failed to allocate memory.\n");
3174 hr = IDXGIOutput_GetDisplayModeList(target, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes);
3175 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
3177 expected_state = *initial_state;
3178 for (i = 0; i < min(mode_count, 20); ++i)
3180 /* FIXME: Modes with scaling aren't fully tested. */
3181 if (!(swapchain_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)
3182 && modes[i].Scaling != DXGI_MODE_SCALING_UNSPECIFIED)
3183 continue;
3185 hr = IDXGIOutput_GetDesc(target, &output_desc);
3186 ok(hr == S_OK, "Failed to get desc, hr %#x.\n", hr);
3188 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
3189 &swapchain_desc, &output_desc.DesktopCoordinates, modes[i].Width, modes[i].Height, NULL);
3191 hr = IDXGISwapChain_ResizeTarget(swapchain, &modes[i]);
3192 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#x.\n", hr);
3193 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
3195 skip("Failed to change to video mode %u.\n", i);
3196 break;
3198 check_swapchain_fullscreen_state(swapchain, &expected_state);
3200 hr = IDXGIOutput_GetDesc(target, &output_desc);
3201 ok(hr == S_OK, "Failed to get desc, hr %#x.\n", hr);
3202 ok(EqualRect(&output_desc.DesktopCoordinates, &expected_state.fullscreen_state.monitor_rect),
3203 "Got desktop coordinates %s, expected %s.\n",
3204 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
3205 wine_dbgstr_rect(&expected_state.fullscreen_state.monitor_rect));
3208 heap_free(modes);
3209 IDXGIOutput_Release(target);
3212 static void test_resize_target(IUnknown *device, BOOL is_d3d12)
3214 struct swapchain_fullscreen_state initial_state, expected_state;
3215 unsigned int adapter_idx, output_idx, test_idx;
3216 DXGI_SWAP_CHAIN_DESC swapchain_desc;
3217 DXGI_OUTPUT_DESC output_desc;
3218 IDXGISwapChain *swapchain;
3219 IDXGIFactory *factory;
3220 IDXGIAdapter *adapter;
3221 IDXGIOutput *output;
3222 ULONG refcount;
3223 HRESULT hr;
3225 static const struct
3227 POINT origin;
3228 BOOL fullscreen;
3229 BOOL menu;
3230 unsigned int flags;
3232 tests[] =
3234 {{ 0, 0}, TRUE, FALSE, 0},
3235 {{10, 10}, TRUE, FALSE, 0},
3236 {{ 0, 0}, TRUE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3237 {{10, 10}, TRUE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3238 {{ 0, 0}, FALSE, FALSE, 0},
3239 {{ 0, 0}, FALSE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3240 {{10, 10}, FALSE, FALSE, 0},
3241 {{10, 10}, FALSE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3242 {{ 0, 0}, FALSE, TRUE, 0},
3243 {{ 0, 0}, FALSE, TRUE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3244 {{10, 10}, FALSE, TRUE, 0},
3245 {{10, 10}, FALSE, TRUE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3248 get_factory(device, is_d3d12, &factory);
3250 swapchain_desc.BufferDesc.Width = 800;
3251 swapchain_desc.BufferDesc.Height = 600;
3252 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
3253 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
3254 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
3255 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
3256 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
3257 swapchain_desc.SampleDesc.Count = 1;
3258 swapchain_desc.SampleDesc.Quality = 0;
3259 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3260 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
3261 swapchain_desc.Windowed = TRUE;
3262 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
3263 swapchain_desc.Flags = 0;
3265 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
3266 ++adapter_idx)
3268 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
3269 ++output_idx)
3271 hr = IDXGIOutput_GetDesc(output, &output_desc);
3272 ok(hr == S_OK, "Adapter %u output %u: GetDesc failed, hr %#x.\n", adapter_idx,
3273 output_idx, hr);
3275 for (test_idx = 0; test_idx < ARRAY_SIZE(tests); ++test_idx)
3277 swapchain_desc.Flags = tests[test_idx].flags;
3278 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0,
3279 output_desc.DesktopCoordinates.left + tests[test_idx].origin.x,
3280 output_desc.DesktopCoordinates.top + tests[test_idx].origin.y,
3281 400, 200, 0, 0, 0, 0);
3282 if (tests[test_idx].menu)
3284 HMENU menu_bar = CreateMenu();
3285 HMENU menu = CreateMenu();
3286 AppendMenuA(menu_bar, MF_POPUP, (UINT_PTR)menu, "Menu");
3287 SetMenu(swapchain_desc.OutputWindow, menu_bar);
3290 memset(&initial_state, 0, sizeof(initial_state));
3291 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
3293 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
3294 ok(SUCCEEDED(hr), "Adapter %u output %u test %u: CreateSwapChain failed, hr %#x.\n",
3295 adapter_idx, output_idx, test_idx, hr);
3296 check_swapchain_fullscreen_state(swapchain, &initial_state);
3298 expected_state = initial_state;
3299 if (tests[test_idx].fullscreen)
3301 expected_state.fullscreen = TRUE;
3302 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
3303 &swapchain_desc, &initial_state.fullscreen_state.monitor_rect, 800, 600, NULL);
3304 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
3305 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
3306 "Adapter %u output %u test %u: GetContainingOutput failed, hr %#x.\n",
3307 adapter_idx, output_idx, test_idx, hr);
3308 if (hr == DXGI_ERROR_UNSUPPORTED)
3310 win_skip("Adapter %u output %u test %u: GetContainingOutput() not supported.\n",
3311 adapter_idx, output_idx, test_idx);
3312 IDXGISwapChain_Release(swapchain);
3313 DestroyWindow(swapchain_desc.OutputWindow);
3314 continue;
3317 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
3318 ok(SUCCEEDED(hr) || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE,
3319 "Adapter %u output %u test %u: SetFullscreenState failed, hr %#x.\n",
3320 adapter_idx, output_idx, test_idx, hr);
3321 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
3323 skip("Adapter %u output %u test %u: Could not change fullscreen state.\n",
3324 adapter_idx, output_idx, test_idx);
3325 IDXGIOutput_Release(expected_state.target);
3326 IDXGISwapChain_Release(swapchain);
3327 DestroyWindow(swapchain_desc.OutputWindow);
3328 continue;
3331 check_swapchain_fullscreen_state(swapchain, &expected_state);
3333 hr = IDXGISwapChain_ResizeTarget(swapchain, NULL);
3334 ok(hr == DXGI_ERROR_INVALID_CALL, "Adapter %u output %u test %u: Got unexpected hr %#x.\n",
3335 adapter_idx, output_idx, test_idx, hr);
3336 check_swapchain_fullscreen_state(swapchain, &expected_state);
3338 if (tests[test_idx].fullscreen)
3340 test_fullscreen_resize_target(swapchain, &expected_state);
3342 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3343 ok(SUCCEEDED(hr), "Adapter %u output %u test %u: SetFullscreenState failed, hr %#x.\n",
3344 adapter_idx, output_idx, test_idx, hr);
3345 check_swapchain_fullscreen_state(swapchain, &initial_state);
3346 IDXGIOutput_Release(expected_state.target);
3347 check_swapchain_fullscreen_state(swapchain, &initial_state);
3348 expected_state = initial_state;
3350 else
3352 test_windowed_resize_target(swapchain, swapchain_desc.OutputWindow, &expected_state);
3354 check_swapchain_fullscreen_state(swapchain, &expected_state);
3357 refcount = IDXGISwapChain_Release(swapchain);
3358 ok(!refcount, "Adapter %u output %u test %u: IDXGISwapChain has %u references left.\n",
3359 adapter_idx, output_idx, test_idx, refcount);
3360 check_window_fullscreen_state(swapchain_desc.OutputWindow, &expected_state.fullscreen_state);
3361 DestroyWindow(swapchain_desc.OutputWindow);
3363 IDXGIOutput_Release(output);
3365 IDXGIAdapter_Release(adapter);
3367 refcount = IDXGIFactory_Release(factory);
3368 ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
3371 static LRESULT CALLBACK resize_target_wndproc(HWND hwnd, unsigned int message, WPARAM wparam, LPARAM lparam)
3373 IDXGISwapChain *swapchain = (IDXGISwapChain *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
3374 DXGI_SWAP_CHAIN_DESC desc;
3375 HRESULT hr;
3377 switch (message)
3379 case WM_SIZE:
3380 ok(!!swapchain, "GWLP_USERDATA is NULL.\n");
3381 hr = IDXGISwapChain_GetDesc(swapchain, &desc);
3382 ok(hr == S_OK, "Failed to get desc, hr %#x.\n", hr);
3383 ok(desc.BufferDesc.Width == 800, "Got unexpected buffer width %u.\n", desc.BufferDesc.Width);
3384 ok(desc.BufferDesc.Height == 600, "Got unexpected buffer height %u.\n", desc.BufferDesc.Height);
3385 return 0;
3387 default:
3388 return DefWindowProcA(hwnd, message, wparam, lparam);
3392 struct window_thread_data
3394 HWND window;
3395 HANDLE window_created;
3396 HANDLE finished;
3399 static DWORD WINAPI window_thread(void *data)
3401 struct window_thread_data *thread_data = data;
3402 unsigned int ret;
3403 WNDCLASSA wc;
3404 MSG msg;
3406 memset(&wc, 0, sizeof(wc));
3407 wc.lpfnWndProc = resize_target_wndproc;
3408 wc.lpszClassName = "dxgi_resize_target_wndproc_wc";
3409 ok(RegisterClassA(&wc), "Failed to register window class.\n");
3411 thread_data->window = CreateWindowA("dxgi_resize_target_wndproc_wc", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
3412 ok(!!thread_data->window, "Failed to create window.\n");
3414 ret = SetEvent(thread_data->window_created);
3415 ok(ret, "Failed to set event, last error %#x.\n", GetLastError());
3417 for (;;)
3419 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3420 DispatchMessageA(&msg);
3422 ret = WaitForSingleObject(thread_data->finished, 0);
3423 if (ret != WAIT_TIMEOUT)
3424 break;
3426 ok(ret == WAIT_OBJECT_0, "Failed to wait for event, ret %#x, last error %#x.\n", ret, GetLastError());
3428 DestroyWindow(thread_data->window);
3429 thread_data->window = NULL;
3431 UnregisterClassA("dxgi_test_wndproc_wc", GetModuleHandleA(NULL));
3433 return 0;
3436 static void test_resize_target_wndproc(void)
3438 struct window_thread_data thread_data;
3439 DXGI_SWAP_CHAIN_DESC swapchain_desc;
3440 IDXGISwapChain *swapchain;
3441 IDXGIFactory *factory;
3442 IDXGIAdapter *adapter;
3443 DXGI_MODE_DESC mode;
3444 IDXGIDevice *device;
3445 unsigned int ret;
3446 ULONG refcount;
3447 LONG_PTR data;
3448 HANDLE thread;
3449 HRESULT hr;
3450 RECT rect;
3452 if (!(device = create_device(0)))
3454 skip("Failed to create device.\n");
3455 return;
3458 memset(&thread_data, 0, sizeof(thread_data));
3459 thread_data.window_created = CreateEventA(NULL, FALSE, FALSE, NULL);
3460 ok(!!thread_data.window_created, "Failed to create event, last error %#x.\n", GetLastError());
3461 thread_data.finished = CreateEventA(NULL, FALSE, FALSE, NULL);
3462 ok(!!thread_data.finished, "Failed to create event, last error %#x.\n", GetLastError());
3464 thread = CreateThread(NULL, 0, window_thread, &thread_data, 0, NULL);
3465 ok(!!thread, "Failed to create thread, last error %#x.\n", GetLastError());
3466 ret = WaitForSingleObject(thread_data.window_created, INFINITE);
3467 ok(ret == WAIT_OBJECT_0, "Failed to wait for thread, ret %#x, last error %#x.\n", ret, GetLastError());
3469 hr = IDXGIDevice_GetAdapter(device, &adapter);
3470 ok(hr == S_OK, "Failed to get adapter, hr %#x.\n", hr);
3471 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
3472 ok(hr == S_OK, "Failed to get parent, hr %#x.\n", hr);
3474 swapchain_desc.BufferDesc.Width = 800;
3475 swapchain_desc.BufferDesc.Height = 600;
3476 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
3477 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
3478 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
3479 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
3480 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
3481 swapchain_desc.SampleDesc.Count = 1;
3482 swapchain_desc.SampleDesc.Quality = 0;
3483 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3484 swapchain_desc.BufferCount = 1;
3485 swapchain_desc.OutputWindow = thread_data.window;
3486 swapchain_desc.Windowed = TRUE;
3487 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
3488 swapchain_desc.Flags = 0;
3489 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3490 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
3492 data = SetWindowLongPtrA(thread_data.window, GWLP_USERDATA, (LONG_PTR)swapchain);
3493 ok(!data, "Got unexpected GWLP_USERDATA %p.\n", (void *)data);
3495 memset(&mode, 0, sizeof(mode));
3496 mode.Width = 600;
3497 mode.Height = 400;
3498 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
3499 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3501 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
3502 ok(hr == S_OK, "Getswapchain_desc failed, hr %#x.\n", hr);
3503 ok(swapchain_desc.BufferDesc.Width == 800,
3504 "Got unexpected buffer width %u.\n", swapchain_desc.BufferDesc.Width);
3505 ok(swapchain_desc.BufferDesc.Height == 600,
3506 "Got unexpected buffer height %u.\n", swapchain_desc.BufferDesc.Height);
3508 ret = GetClientRect(swapchain_desc.OutputWindow, &rect);
3509 ok(ret, "Failed to get client rect.\n");
3510 ok(rect.right == mode.Width && rect.bottom == mode.Height,
3511 "Got unexpected client rect %s.\n", wine_dbgstr_rect(&rect));
3513 refcount = IDXGISwapChain_Release(swapchain);
3514 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
3516 IDXGIAdapter_Release(adapter);
3517 refcount = IDXGIDevice_Release(device);
3518 ok(!refcount, "Device has %u references left.\n", refcount);
3519 refcount = IDXGIFactory_Release(factory);
3520 ok(!refcount, "Factory has %u references left.\n", refcount);
3522 ret = SetEvent(thread_data.finished);
3523 ok(ret, "Failed to set event, last error %#x.\n", GetLastError());
3524 ret = WaitForSingleObject(thread, INFINITE);
3525 ok(ret == WAIT_OBJECT_0, "Failed to wait for thread, ret %#x, last error %#x.\n", ret, GetLastError());
3526 CloseHandle(thread);
3527 CloseHandle(thread_data.window_created);
3528 CloseHandle(thread_data.finished);
3531 static void test_inexact_modes(void)
3533 struct swapchain_fullscreen_state initial_state, expected_state;
3534 DXGI_SWAP_CHAIN_DESC swapchain_desc, result_desc;
3535 IDXGIOutput *output = NULL;
3536 IDXGISwapChain *swapchain;
3537 IDXGIFactory *factory;
3538 IDXGIAdapter *adapter;
3539 IDXGIDevice *device;
3540 unsigned int i;
3541 ULONG refcount;
3542 HRESULT hr;
3544 static const struct
3546 unsigned int width, height;
3548 sizes[] =
3550 {101, 101},
3551 {203, 204},
3552 {799, 601},
3555 if (!(device = create_device(0)))
3557 skip("Failed to create device.\n");
3558 return;
3561 hr = IDXGIDevice_GetAdapter(device, &adapter);
3562 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
3564 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
3565 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
3567 swapchain_desc.BufferDesc.Width = 800;
3568 swapchain_desc.BufferDesc.Height = 600;
3569 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
3570 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
3571 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
3572 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
3573 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
3574 swapchain_desc.SampleDesc.Count = 1;
3575 swapchain_desc.SampleDesc.Quality = 0;
3576 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3577 swapchain_desc.BufferCount = 1;
3578 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
3579 swapchain_desc.Windowed = FALSE;
3580 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
3581 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
3583 memset(&initial_state, 0, sizeof(initial_state));
3584 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
3586 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3587 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
3588 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3589 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
3590 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3591 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
3592 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
3593 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
3594 "GetContainingOutput failed, hr %#x.\n", hr);
3595 refcount = IDXGISwapChain_Release(swapchain);
3596 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
3597 if (hr == DXGI_ERROR_UNSUPPORTED)
3599 win_skip("GetContainingOutput() not supported.\n");
3600 goto done;
3602 if (result_desc.Windowed)
3604 win_skip("Fullscreen not supported.\n");
3605 goto done;
3608 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
3610 for (i = 0; i < ARRAY_SIZE(sizes); ++i)
3612 /* Test CreateSwapChain(). */
3613 swapchain_desc.BufferDesc.Width = sizes[i].width;
3614 swapchain_desc.BufferDesc.Height = sizes[i].height;
3615 swapchain_desc.Windowed = FALSE;
3617 expected_state = initial_state;
3618 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
3619 &swapchain_desc, &initial_state.fullscreen_state.monitor_rect,
3620 sizes[i].width, sizes[i].height, output);
3622 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3623 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
3625 check_swapchain_fullscreen_state(swapchain, &expected_state);
3626 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3627 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
3628 ok(result_desc.BufferDesc.Width == sizes[i].width, "Got width %u, expected %u.\n",
3629 result_desc.BufferDesc.Width, sizes[i].width);
3630 ok(result_desc.BufferDesc.Height == sizes[i].height, "Got height %u, expected %u.\n",
3631 result_desc.BufferDesc.Height, sizes[i].height);
3633 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3634 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
3635 check_swapchain_fullscreen_state(swapchain, &initial_state);
3637 refcount = IDXGISwapChain_Release(swapchain);
3638 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
3640 /* Test SetFullscreenState(). */
3641 swapchain_desc.BufferDesc.Width = sizes[i].width;
3642 swapchain_desc.BufferDesc.Height = sizes[i].height;
3643 swapchain_desc.Windowed = TRUE;
3645 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3646 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
3648 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
3649 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
3651 check_swapchain_fullscreen_state(swapchain, &expected_state);
3652 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3653 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
3654 ok(result_desc.BufferDesc.Width == sizes[i].width, "Got width %u, expected %u.\n",
3655 result_desc.BufferDesc.Width, sizes[i].width);
3656 ok(result_desc.BufferDesc.Height == sizes[i].height, "Got height %u, expected %u.\n",
3657 result_desc.BufferDesc.Height, sizes[i].height);
3659 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3660 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
3661 check_swapchain_fullscreen_state(swapchain, &initial_state);
3663 refcount = IDXGISwapChain_Release(swapchain);
3664 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
3666 /* Test ResizeTarget(). */
3667 swapchain_desc.BufferDesc.Width = 800;
3668 swapchain_desc.BufferDesc.Height = 600;
3669 swapchain_desc.Windowed = TRUE;
3671 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3672 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
3674 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
3675 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
3677 swapchain_desc.BufferDesc.Width = sizes[i].width;
3678 swapchain_desc.BufferDesc.Height = sizes[i].height;
3679 hr = IDXGISwapChain_ResizeTarget(swapchain, &swapchain_desc.BufferDesc);
3680 ok(SUCCEEDED(hr), "ResizeTarget failed, hr %#x.\n", hr);
3682 check_swapchain_fullscreen_state(swapchain, &expected_state);
3683 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3684 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
3685 ok(result_desc.BufferDesc.Width == 800, "Got width %u.\n", result_desc.BufferDesc.Width);
3686 ok(result_desc.BufferDesc.Height == 600, "Got height %u.\n", result_desc.BufferDesc.Height);
3688 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3689 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
3690 check_swapchain_fullscreen_state(swapchain, &initial_state);
3692 refcount = IDXGISwapChain_Release(swapchain);
3693 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
3696 done:
3697 if (output)
3698 IDXGIOutput_Release(output);
3699 IDXGIAdapter_Release(adapter);
3700 refcount = IDXGIDevice_Release(device);
3701 ok(!refcount, "Device has %u references left.\n", refcount);
3702 refcount = IDXGIFactory_Release(factory);
3703 ok(!refcount, "Factory has %u references left.\n", refcount);
3704 DestroyWindow(swapchain_desc.OutputWindow);
3707 static void test_create_factory(void)
3709 IUnknown *iface;
3710 ULONG refcount;
3711 HRESULT hr;
3713 iface = (void *)0xdeadbeef;
3714 hr = CreateDXGIFactory(&IID_IDXGIDevice, (void **)&iface);
3715 ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
3716 ok(!iface, "Got unexpected iface %p.\n", iface);
3718 hr = CreateDXGIFactory(&IID_IUnknown, (void **)&iface);
3719 ok(SUCCEEDED(hr), "Failed to create factory with IID_IUnknown, hr %#x.\n", hr);
3720 IUnknown_Release(iface);
3722 hr = CreateDXGIFactory(&IID_IDXGIObject, (void **)&iface);
3723 ok(SUCCEEDED(hr), "Failed to create factory with IID_IDXGIObject, hr %#x.\n", hr);
3724 IUnknown_Release(iface);
3726 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&iface);
3727 ok(SUCCEEDED(hr), "Failed to create factory with IID_IDXGIFactory, hr %#x.\n", hr);
3728 check_interface(iface, &IID_IDXGIFactory1, FALSE, FALSE);
3729 IUnknown_Release(iface);
3731 iface = (void *)0xdeadbeef;
3732 hr = CreateDXGIFactory(&IID_IDXGIFactory1, (void **)&iface);
3733 ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
3734 ok(!iface, "Got unexpected iface %p.\n", iface);
3736 iface = NULL;
3737 hr = CreateDXGIFactory(&IID_IDXGIFactory2, (void **)&iface);
3738 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
3739 "Got unexpected hr %#x.\n", hr);
3740 if (SUCCEEDED(hr))
3742 refcount = IUnknown_Release(iface);
3743 ok(!refcount, "Factory has %u references left.\n", refcount);
3746 if (!pCreateDXGIFactory1)
3748 win_skip("CreateDXGIFactory1 not available.\n");
3749 return;
3752 iface = (void *)0xdeadbeef;
3753 hr = pCreateDXGIFactory1(&IID_IDXGIDevice, (void **)&iface);
3754 ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
3755 ok(!iface, "Got unexpected iface %p.\n", iface);
3757 hr = pCreateDXGIFactory1(&IID_IUnknown, (void **)&iface);
3758 ok(SUCCEEDED(hr), "Failed to create factory with IID_IUnknown, hr %#x.\n", hr);
3759 IUnknown_Release(iface);
3761 hr = pCreateDXGIFactory1(&IID_IDXGIObject, (void **)&iface);
3762 ok(SUCCEEDED(hr), "Failed to create factory with IID_IDXGIObject, hr %#x.\n", hr);
3763 IUnknown_Release(iface);
3765 hr = pCreateDXGIFactory1(&IID_IDXGIFactory, (void **)&iface);
3766 ok(SUCCEEDED(hr), "Failed to create factory with IID_IDXGIFactory, hr %#x.\n", hr);
3767 check_interface(iface, &IID_IDXGIFactory1, TRUE, FALSE);
3768 refcount = IUnknown_Release(iface);
3769 ok(!refcount, "Factory has %u references left.\n", refcount);
3771 hr = pCreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&iface);
3772 ok(SUCCEEDED(hr), "Failed to create factory with IID_IDXGIFactory1, hr %#x.\n", hr);
3773 IUnknown_Release(iface);
3775 iface = NULL;
3776 hr = pCreateDXGIFactory1(&IID_IDXGIFactory2, (void **)&iface);
3777 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
3778 "Got unexpected hr %#x.\n", hr);
3779 if (SUCCEEDED(hr))
3781 refcount = IUnknown_Release(iface);
3782 ok(!refcount, "Factory has %u references left.\n", refcount);
3785 if (!pCreateDXGIFactory2)
3787 win_skip("CreateDXGIFactory2 not available.\n");
3788 return;
3791 hr = pCreateDXGIFactory2(0, &IID_IDXGIFactory3, (void **)&iface);
3792 ok(hr == S_OK, "Failed to create factory, hr %#x.\n", hr);
3793 check_interface(iface, &IID_IDXGIFactory, TRUE, FALSE);
3794 check_interface(iface, &IID_IDXGIFactory1, TRUE, FALSE);
3795 check_interface(iface, &IID_IDXGIFactory2, TRUE, FALSE);
3796 check_interface(iface, &IID_IDXGIFactory3, TRUE, FALSE);
3797 /* Not available on all Windows versions. */
3798 check_interface(iface, &IID_IDXGIFactory4, TRUE, TRUE);
3799 check_interface(iface, &IID_IDXGIFactory5, TRUE, TRUE);
3800 refcount = IUnknown_Release(iface);
3801 ok(!refcount, "Factory has %u references left.\n", refcount);
3803 hr = pCreateDXGIFactory2(0, &IID_IDXGIFactory, (void **)&iface);
3804 ok(hr == S_OK, "Failed to create factory, hr %#x.\n", hr);
3805 check_interface(iface, &IID_IDXGIFactory, TRUE, FALSE);
3806 check_interface(iface, &IID_IDXGIFactory1, TRUE, FALSE);
3807 check_interface(iface, &IID_IDXGIFactory2, TRUE, FALSE);
3808 check_interface(iface, &IID_IDXGIFactory3, TRUE, FALSE);
3809 refcount = IUnknown_Release(iface);
3810 ok(!refcount, "Factory has %u references left.\n", refcount);
3813 static void test_private_data(void)
3815 ULONG refcount, expected_refcount;
3816 IDXGIDevice *device;
3817 HRESULT hr;
3818 IDXGIDevice *test_object;
3819 IUnknown *ptr;
3820 static const DWORD data[] = {1, 2, 3, 4};
3821 UINT size;
3822 static const GUID dxgi_private_data_test_guid =
3824 0xfdb37466,
3825 0x428f,
3826 0x4edf,
3827 {0xa3, 0x7f, 0x9b, 0x1d, 0xf4, 0x88, 0xc5, 0xfc}
3829 static const GUID dxgi_private_data_test_guid2 =
3831 0x2e5afac2,
3832 0x87b5,
3833 0x4c10,
3834 {0x9b, 0x4b, 0x89, 0xd7, 0xd1, 0x12, 0xe7, 0x2b}
3837 if (!(device = create_device(0)))
3839 skip("Failed to create device.\n");
3840 return;
3843 test_object = create_device(0);
3845 /* SetPrivateData with a pointer of NULL has the purpose of FreePrivateData in previous
3846 * d3d versions. A successful clear returns S_OK. A redundant clear S_FALSE. Setting a
3847 * NULL interface is not considered a clear but as setting an interface pointer that
3848 * happens to be NULL. */
3849 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 0, NULL);
3850 ok(hr == S_FALSE, "Got unexpected hr %#x.\n", hr);
3851 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
3852 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3853 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, ~0U, NULL);
3854 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3855 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, ~0U, NULL);
3856 ok(hr == S_FALSE, "Got unexpected hr %#x.\n", hr);
3858 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
3859 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3860 size = sizeof(ptr) * 2;
3861 ptr = (IUnknown *)0xdeadbeef;
3862 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
3863 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3864 ok(!ptr, "Got unexpected pointer %p.\n", ptr);
3865 ok(size == sizeof(IUnknown *), "Got unexpected size %u.\n", size);
3867 refcount = get_refcount(test_object);
3868 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3869 (IUnknown *)test_object);
3870 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3871 expected_refcount = refcount + 1;
3872 refcount = get_refcount(test_object);
3873 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
3874 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3875 (IUnknown *)test_object);
3876 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3877 refcount = get_refcount(test_object);
3878 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
3880 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
3881 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3882 expected_refcount--;
3883 refcount = get_refcount(test_object);
3884 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
3886 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3887 (IUnknown *)test_object);
3888 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3889 size = sizeof(data);
3890 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, size, data);
3891 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3892 refcount = get_refcount(test_object);
3893 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
3894 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 42, NULL);
3895 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3896 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 42, NULL);
3897 ok(hr == S_FALSE, "Got unexpected hr %#x.\n", hr);
3899 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3900 (IUnknown *)test_object);
3901 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3902 expected_refcount++;
3903 size = 2 * sizeof(ptr);
3904 ptr = NULL;
3905 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
3906 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3907 ok(size == sizeof(test_object), "Got unexpected size %u.\n", size);
3908 expected_refcount++;
3909 refcount = get_refcount(test_object);
3910 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
3911 if (ptr)
3912 IUnknown_Release(ptr);
3913 expected_refcount--;
3915 ptr = (IUnknown *)0xdeadbeef;
3916 size = 1;
3917 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, NULL);
3918 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3919 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
3920 size = 2 * sizeof(ptr);
3921 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, NULL);
3922 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
3923 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
3924 refcount = get_refcount(test_object);
3925 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
3927 size = 1;
3928 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
3929 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#x.\n", hr);
3930 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
3931 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
3932 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid2, NULL, NULL);
3933 ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
3934 size = 0xdeadbabe;
3935 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid2, &size, &ptr);
3936 ok(hr == DXGI_ERROR_NOT_FOUND, "Got unexpected hr %#x.\n", hr);
3937 ok(size == 0, "Got unexpected size %u.\n", size);
3938 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
3939 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, NULL, &ptr);
3940 ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
3941 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
3943 refcount = IDXGIDevice_Release(device);
3944 ok(!refcount, "Device has %u references left.\n", refcount);
3945 refcount = IDXGIDevice_Release(test_object);
3946 ok(!refcount, "Test object has %u references left.\n", refcount);
3949 #define check_surface_desc(a, b) check_surface_desc_(__LINE__, a, b)
3950 static void check_surface_desc_(unsigned int line, IDXGISurface *surface,
3951 const DXGI_SWAP_CHAIN_DESC *swapchain_desc)
3953 DXGI_SURFACE_DESC surface_desc;
3954 HRESULT hr;
3956 hr = IDXGISurface_GetDesc(surface, &surface_desc);
3957 ok_(__FILE__, line)(hr == S_OK, "Failed to get surface desc, hr %#x.\n", hr);
3958 ok_(__FILE__, line)(surface_desc.Width == swapchain_desc->BufferDesc.Width,
3959 "Got Width %u, expected %u.\n", surface_desc.Width, swapchain_desc->BufferDesc.Width);
3960 ok_(__FILE__, line)(surface_desc.Height == swapchain_desc->BufferDesc.Height,
3961 "Got Height %u, expected %u.\n", surface_desc.Height, swapchain_desc->BufferDesc.Height);
3962 ok_(__FILE__, line)(surface_desc.Format == swapchain_desc->BufferDesc.Format,
3963 "Got Format %#x, expected %#x.\n", surface_desc.Format, swapchain_desc->BufferDesc.Format);
3964 ok_(__FILE__, line)(surface_desc.SampleDesc.Count == 1,
3965 "Got unexpected SampleDesc.Count %u.\n", surface_desc.SampleDesc.Count);
3966 ok_(__FILE__, line)(!surface_desc.SampleDesc.Quality,
3967 "Got unexpected SampleDesc.Quality %u.\n", surface_desc.SampleDesc.Quality);
3970 #define check_texture_desc(a, b) check_texture_desc_(__LINE__, a, b)
3971 static void check_texture_desc_(unsigned int line, ID3D10Texture2D *texture,
3972 const DXGI_SWAP_CHAIN_DESC *swapchain_desc)
3974 D3D10_TEXTURE2D_DESC texture_desc;
3976 ID3D10Texture2D_GetDesc(texture, &texture_desc);
3977 ok_(__FILE__, line)(texture_desc.Width == swapchain_desc->BufferDesc.Width,
3978 "Got Width %u, expected %u.\n", texture_desc.Width, swapchain_desc->BufferDesc.Width);
3979 ok_(__FILE__, line)(texture_desc.Height == swapchain_desc->BufferDesc.Height,
3980 "Got Height %u, expected %u.\n", texture_desc.Height, swapchain_desc->BufferDesc.Height);
3981 ok_(__FILE__, line)(texture_desc.MipLevels == 1, "Got unexpected MipLevels %u.\n", texture_desc.MipLevels);
3982 ok_(__FILE__, line)(texture_desc.ArraySize == 1, "Got unexpected ArraySize %u.\n", texture_desc.ArraySize);
3983 ok_(__FILE__, line)(texture_desc.Format == swapchain_desc->BufferDesc.Format,
3984 "Got Format %#x, expected %#x.\n", texture_desc.Format, swapchain_desc->BufferDesc.Format);
3985 ok_(__FILE__, line)(texture_desc.SampleDesc.Count == 1,
3986 "Got unexpected SampleDesc.Count %u.\n", texture_desc.SampleDesc.Count);
3987 ok_(__FILE__, line)(!texture_desc.SampleDesc.Quality,
3988 "Got unexpected SampleDesc.Quality %u.\n", texture_desc.SampleDesc.Quality);
3989 ok_(__FILE__, line)(texture_desc.Usage == D3D10_USAGE_DEFAULT,
3990 "Got unexpected Usage %#x.\n", texture_desc.Usage);
3991 ok_(__FILE__, line)(texture_desc.BindFlags == D3D10_BIND_RENDER_TARGET,
3992 "Got unexpected BindFlags %#x.\n", texture_desc.BindFlags);
3993 ok_(__FILE__, line)(!texture_desc.CPUAccessFlags,
3994 "Got unexpected CPUAccessFlags %#x.\n", texture_desc.CPUAccessFlags);
3995 ok_(__FILE__, line)(!texture_desc.MiscFlags, "Got unexpected MiscFlags %#x.\n", texture_desc.MiscFlags);
3998 #define check_resource_desc(a, b) check_resource_desc_(__LINE__, a, b)
3999 static void check_resource_desc_(unsigned int line, ID3D12Resource *resource,
4000 const DXGI_SWAP_CHAIN_DESC *swapchain_desc)
4002 D3D12_RESOURCE_DESC resource_desc;
4004 resource_desc = ID3D12Resource_GetDesc(resource);
4005 ok_(__FILE__, line)(resource_desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D,
4006 "Got unexpected Dimension %#x.\n", resource_desc.Dimension);
4007 ok_(__FILE__, line)(resource_desc.Width == swapchain_desc->BufferDesc.Width, "Got Width %s, expected %u.\n",
4008 wine_dbgstr_longlong(resource_desc.Width), swapchain_desc->BufferDesc.Width);
4009 ok_(__FILE__, line)(resource_desc.Height == swapchain_desc->BufferDesc.Height,
4010 "Got Height %u, expected %u.\n", resource_desc.Height, swapchain_desc->BufferDesc.Height);
4011 ok_(__FILE__, line)(resource_desc.DepthOrArraySize == 1,
4012 "Got unexpected DepthOrArraySize %u.\n", resource_desc.DepthOrArraySize);
4013 ok_(__FILE__, line)(resource_desc.MipLevels == 1,
4014 "Got unexpected MipLevels %u.\n", resource_desc.MipLevels);
4015 ok_(__FILE__, line)(resource_desc.Format == swapchain_desc->BufferDesc.Format,
4016 "Got Format %#x, expected %#x.\n", resource_desc.Format, swapchain_desc->BufferDesc.Format);
4017 ok_(__FILE__, line)(resource_desc.SampleDesc.Count == 1,
4018 "Got unexpected SampleDesc.Count %u.\n", resource_desc.SampleDesc.Count);
4019 ok_(__FILE__, line)(!resource_desc.SampleDesc.Quality,
4020 "Got unexpected SampleDesc.Quality %u.\n", resource_desc.SampleDesc.Quality);
4021 ok_(__FILE__, line)(resource_desc.Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN,
4022 "Got unexpected Layout %#x.\n", resource_desc.Layout);
4025 static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12)
4027 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4028 DXGI_SWAP_EFFECT swap_effect;
4029 IDXGISwapChain3 *swapchain3;
4030 IUnknown *present_queue[2];
4031 IDXGISwapChain *swapchain;
4032 ID3D12Resource *resource;
4033 ID3D10Texture2D *texture;
4034 HRESULT hr, expected_hr;
4035 IDXGISurface *surface;
4036 IDXGIFactory *factory;
4037 RECT client_rect, r;
4038 UINT node_mask[2];
4039 ULONG refcount;
4040 HWND window;
4041 BOOL ret;
4043 get_factory(device, is_d3d12, &factory);
4045 window = create_window();
4046 ret = GetClientRect(window, &client_rect);
4047 ok(ret, "Failed to get client rect.\n");
4049 swap_effect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
4051 swapchain_desc.BufferDesc.Width = 640;
4052 swapchain_desc.BufferDesc.Height = 480;
4053 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
4054 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
4055 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4056 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
4057 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
4058 swapchain_desc.SampleDesc.Count = 1;
4059 swapchain_desc.SampleDesc.Quality = 0;
4060 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4061 swapchain_desc.BufferCount = 2;
4062 swapchain_desc.OutputWindow = window;
4063 swapchain_desc.Windowed = TRUE;
4064 swapchain_desc.SwapEffect = swap_effect;
4065 swapchain_desc.Flags = 0;
4067 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
4068 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
4069 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface);
4070 expected_hr = is_d3d12 ? E_NOINTERFACE : S_OK;
4071 ok(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
4072 ok(!surface || hr == S_OK, "Got unexpected pointer %p.\n", surface);
4073 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&texture);
4074 ok(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
4075 ok(!texture || hr == S_OK, "Got unexpected pointer %p.\n", texture);
4076 expected_hr = is_d3d12 ? S_OK : E_NOINTERFACE;
4077 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D12Resource, (void **)&resource);
4078 ok(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
4079 ok(!resource || hr == S_OK, "Got unexpected pointer %p.\n", resource);
4081 ret = GetClientRect(window, &r);
4082 ok(ret, "Failed to get client rect.\n");
4083 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
4084 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
4086 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4087 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4088 ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
4089 ok(swapchain_desc.BufferDesc.Width == 640,
4090 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
4091 ok(swapchain_desc.BufferDesc.Height == 480,
4092 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
4093 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4094 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4095 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4096 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4097 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4098 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4099 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM,
4100 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4101 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4102 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4103 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4104 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4105 ok(swapchain_desc.SampleDesc.Count == 1,
4106 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4107 ok(!swapchain_desc.SampleDesc.Quality,
4108 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4109 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4110 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4111 ok(swapchain_desc.BufferCount == 2,
4112 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4113 ok(swapchain_desc.OutputWindow == window,
4114 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4115 ok(swapchain_desc.Windowed,
4116 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4117 ok(swapchain_desc.SwapEffect == swap_effect,
4118 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4119 ok(!swapchain_desc.Flags,
4120 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4122 if (surface)
4123 check_surface_desc(surface, &swapchain_desc);
4124 if (texture)
4125 check_texture_desc(texture, &swapchain_desc);
4126 if (resource)
4127 check_resource_desc(resource, &swapchain_desc);
4129 hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
4130 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
4132 ret = GetClientRect(window, &r);
4133 ok(ret, "Failed to get client rect.\n");
4134 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
4135 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
4137 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4138 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4139 ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
4140 ok(swapchain_desc.BufferDesc.Width == 640,
4141 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
4142 ok(swapchain_desc.BufferDesc.Height == 480,
4143 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
4144 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4145 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4146 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4147 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4148 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4149 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4150 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM,
4151 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4152 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4153 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4154 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4155 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4156 ok(swapchain_desc.SampleDesc.Count == 1,
4157 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4158 ok(!swapchain_desc.SampleDesc.Quality,
4159 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4160 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4161 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4162 ok(swapchain_desc.BufferCount == 2,
4163 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4164 ok(swapchain_desc.OutputWindow == window,
4165 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4166 ok(swapchain_desc.Windowed,
4167 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4168 ok(swapchain_desc.SwapEffect == swap_effect,
4169 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4170 ok(!swapchain_desc.Flags,
4171 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4173 if (surface)
4175 check_surface_desc(surface, &swapchain_desc);
4176 IDXGISurface_Release(surface);
4178 if (texture)
4180 check_texture_desc(texture, &swapchain_desc);
4181 ID3D10Texture2D_Release(texture);
4183 if (resource)
4185 check_resource_desc(resource, &swapchain_desc);
4186 ID3D12Resource_Release(resource);
4189 hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
4190 ok(hr == S_OK, "Failed to resize buffers, hr %#x.\n", hr);
4191 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface);
4192 expected_hr = is_d3d12 ? E_NOINTERFACE : S_OK;
4193 ok(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
4194 ok(!surface || hr == S_OK, "Got unexpected pointer %p.\n", surface);
4195 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&texture);
4196 ok(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
4197 ok(!texture || hr == S_OK, "Got unexpected pointer %p.\n", texture);
4198 expected_hr = is_d3d12 ? S_OK : E_NOINTERFACE;
4199 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D12Resource, (void **)&resource);
4200 ok(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
4201 ok(!resource || hr == S_OK, "Got unexpected pointer %p.\n", resource);
4203 ret = GetClientRect(window, &r);
4204 ok(ret, "Failed to get client rect.\n");
4205 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
4206 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
4208 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4209 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4210 ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
4211 ok(swapchain_desc.BufferDesc.Width == 320,
4212 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
4213 ok(swapchain_desc.BufferDesc.Height == 240,
4214 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
4215 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4216 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4217 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4218 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4219 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4220 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4221 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM,
4222 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4223 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4224 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4225 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4226 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4227 ok(swapchain_desc.SampleDesc.Count == 1,
4228 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4229 ok(!swapchain_desc.SampleDesc.Quality,
4230 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4231 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4232 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4233 ok(swapchain_desc.BufferCount == 2,
4234 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4235 ok(swapchain_desc.OutputWindow == window,
4236 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4237 ok(swapchain_desc.Windowed,
4238 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4239 ok(swapchain_desc.SwapEffect == swap_effect,
4240 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4241 ok(!swapchain_desc.Flags,
4242 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4244 if (surface)
4246 check_surface_desc(surface, &swapchain_desc);
4247 IDXGISurface_Release(surface);
4249 if (texture)
4251 check_texture_desc(texture, &swapchain_desc);
4252 ID3D10Texture2D_Release(texture);
4254 if (resource)
4256 check_resource_desc(resource, &swapchain_desc);
4257 ID3D12Resource_Release(resource);
4260 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4261 ok(hr == S_OK, "Failed to resize buffers, hr %#x.\n", hr);
4263 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4264 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4265 ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
4266 ok(swapchain_desc.BufferDesc.Width == client_rect.right - client_rect.left,
4267 "Got unexpected BufferDesc.Width %u, expected %u.\n",
4268 swapchain_desc.BufferDesc.Width, client_rect.right - client_rect.left);
4269 ok(swapchain_desc.BufferDesc.Height == client_rect.bottom - client_rect.top,
4270 "Got unexpected bufferDesc.Height %u, expected %u.\n",
4271 swapchain_desc.BufferDesc.Height, client_rect.bottom - client_rect.top);
4272 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4273 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4274 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4275 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4276 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4277 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4278 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM,
4279 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4280 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4281 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4282 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4283 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4284 ok(swapchain_desc.SampleDesc.Count == 1,
4285 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4286 ok(!swapchain_desc.SampleDesc.Quality,
4287 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4288 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4289 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4290 ok(swapchain_desc.BufferCount == 2,
4291 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4292 ok(swapchain_desc.OutputWindow == window,
4293 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4294 ok(swapchain_desc.Windowed,
4295 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4296 ok(swapchain_desc.SwapEffect == swap_effect,
4297 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4298 ok(!swapchain_desc.Flags,
4299 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4301 node_mask[0] = 1;
4302 node_mask[1] = 1;
4303 present_queue[0] = device;
4304 present_queue[1] = device;
4305 if (IDXGISwapChain_QueryInterface(swapchain, &IID_IDXGISwapChain3, (void **)&swapchain3) == E_NOINTERFACE)
4307 skip("IDXGISwapChain3 is not supported.\n");
4309 else if (!is_d3d12)
4311 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4312 ok(hr == DXGI_ERROR_INVALID_CALL, "Expected DXGI_ERROR_INVALID_CALL, got hr %#x.\n", hr);
4313 IDXGISwapChain3_Release(swapchain3);
4315 else
4317 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4318 ok(hr == S_OK, "Failed to resize buffers, hr %#x.\n", hr);
4319 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, NULL, present_queue);
4320 ok(hr == DXGI_ERROR_INVALID_CALL, "Expected DXGI_ERROR_INVALID_CALL, got hr %#x.\n", hr);
4321 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, NULL, NULL);
4322 ok(hr == DXGI_ERROR_INVALID_CALL, "Expected DXGI_ERROR_INVALID_CALL, got hr %#x.\n", hr);
4323 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 0, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, NULL, NULL);
4324 ok(hr == DXGI_ERROR_INVALID_CALL, "Expected DXGI_ERROR_INVALID_CALL, got hr %#x.\n", hr);
4325 node_mask[0] = 2;
4326 node_mask[1] = 2;
4327 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4328 ok(hr == DXGI_ERROR_INVALID_CALL, "Expected DXGI_ERROR_INVALID_CALL, got hr %#x.\n", hr);
4329 /* Windows validates node masks even when the buffer count is zero. It defaults to the current buffer count.
4330 * NULL queues cause some Windows versions to crash. */
4331 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 0, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4332 ok(hr == DXGI_ERROR_INVALID_CALL, "Expected DXGI_ERROR_INVALID_CALL, got hr %#x.\n", hr);
4333 IDXGISwapChain3_Release(swapchain3);
4336 IDXGISwapChain_Release(swapchain);
4337 DestroyWindow(window);
4338 refcount = IDXGIFactory_Release(factory);
4339 ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
4342 static void test_swapchain_parameters(void)
4344 DXGI_USAGE usage, expected_usage, broken_usage;
4345 D3D10_TEXTURE2D_DESC d3d10_texture_desc;
4346 D3D11_TEXTURE2D_DESC d3d11_texture_desc;
4347 unsigned int expected_bind_flags;
4348 ID3D10Texture2D *d3d10_texture;
4349 ID3D11Texture2D *d3d11_texture;
4350 DXGI_SWAP_CHAIN_DESC desc;
4351 IDXGISwapChain *swapchain;
4352 IDXGIResource *resource;
4353 IDXGIAdapter *adapter;
4354 IDXGIFactory *factory;
4355 IDXGIDevice *device;
4356 unsigned int i, j;
4357 ULONG refcount;
4358 IUnknown *obj;
4359 HWND window;
4360 HRESULT hr;
4362 static const struct
4364 BOOL windowed;
4365 UINT buffer_count;
4366 DXGI_SWAP_EFFECT swap_effect;
4367 HRESULT hr, vista_hr;
4368 UINT highest_accessible_buffer;
4370 tests[] =
4372 /* 0 */
4373 {TRUE, 1, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4374 {TRUE, 2, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4375 {TRUE, 1, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 0},
4376 {TRUE, 2, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 1},
4377 {TRUE, 3, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 2},
4378 /* 5 */
4379 {TRUE, 0, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4380 {TRUE, 1, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4381 {TRUE, 2, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4382 {TRUE, 0, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4383 {TRUE, 1, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4384 /* 10 */
4385 {TRUE, 2, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 1},
4386 {TRUE, 3, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 2},
4387 {TRUE, 0, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4388 {TRUE, 1, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4389 {TRUE, 2, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4390 /* 15 */
4391 {TRUE, 0, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4392 {TRUE, 1, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4393 {TRUE, 2, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4394 {TRUE, 16, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4395 {TRUE, 16, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 15},
4396 /* 20 */
4397 {TRUE, 16, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 15},
4398 {TRUE, 16, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4399 {TRUE, 17, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4400 {FALSE, 1, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4401 {FALSE, 2, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4402 /* 25 */
4403 {FALSE, 1, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 0},
4404 {FALSE, 2, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 1},
4405 {FALSE, 3, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 2},
4406 {FALSE, 0, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4407 {FALSE, 1, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4408 /* 30 */
4409 {FALSE, 2, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4410 {FALSE, 0, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4411 {FALSE, 1, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4412 {FALSE, 2, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 1},
4413 {FALSE, 3, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 2},
4414 /* 35 */
4415 {FALSE, 0, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4416 {FALSE, 1, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4417 {FALSE, 2, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4418 {FALSE, 0, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4419 {FALSE, 1, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4420 /* 40 */
4421 {FALSE, 2, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4422 {FALSE, 16, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4423 {FALSE, 16, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 15},
4424 {FALSE, 16, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 15},
4425 {FALSE, 17, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4426 /* 45 */
4427 {FALSE, 17, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4429 /* The following test fails on Nvidia with E_OUTOFMEMORY and leaks device references in the
4430 * process. Disable it for now.
4431 {FALSE, 16, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4434 /* The following tests crash on Win10 1909
4435 {TRUE, 0, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4436 {TRUE, 0, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4437 {TRUE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4438 {TRUE, 17, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4439 {TRUE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4440 {FALSE, 0, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4441 {FALSE, 0, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4442 {FALSE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4443 {FALSE, 17, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4446 static const DXGI_USAGE usage_tests[] =
4449 DXGI_USAGE_BACK_BUFFER,
4450 DXGI_USAGE_SHADER_INPUT,
4451 DXGI_USAGE_RENDER_TARGET_OUTPUT,
4452 DXGI_USAGE_DISCARD_ON_PRESENT,
4453 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER,
4454 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_DISCARD_ON_PRESENT,
4455 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_DISCARD_ON_PRESENT,
4456 DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT,
4457 DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_DISCARD_ON_PRESENT,
4460 if (!(device = create_device(0)))
4462 skip("Failed to create device.\n");
4463 return;
4465 window = create_window();
4467 hr = IDXGIDevice_QueryInterface(device, &IID_IUnknown, (void **)&obj);
4468 ok(hr == S_OK, "IDXGIDevice does not implement IUnknown.\n");
4470 hr = IDXGIDevice_GetAdapter(device, &adapter);
4471 ok(hr == S_OK, "Failed to get adapter, hr %#x.\n", hr);
4472 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
4473 ok(hr == S_OK, "Failed to get parent, hr %#x.\n", hr);
4474 IDXGIAdapter_Release(adapter);
4476 for (i = 0; i < ARRAY_SIZE(tests); ++i)
4478 memset(&desc, 0, sizeof(desc));
4479 desc.BufferDesc.Width = registry_mode.dmPelsWidth;
4480 desc.BufferDesc.Height = registry_mode.dmPelsHeight;
4481 desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4482 desc.SampleDesc.Count = 1;
4483 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4484 desc.OutputWindow = window;
4486 desc.Windowed = tests[i].windowed;
4487 desc.BufferCount = tests[i].buffer_count;
4488 desc.SwapEffect = tests[i].swap_effect;
4490 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4491 ok(hr == tests[i].hr || broken(hr == tests[i].vista_hr)
4492 || (SUCCEEDED(tests[i].hr) && hr == DXGI_STATUS_OCCLUDED),
4493 "Got unexpected hr %#x, test %u.\n", hr, i);
4494 if (FAILED(hr))
4495 continue;
4497 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGIResource, (void **)&resource);
4498 todo_wine ok(SUCCEEDED(hr), "GetBuffer(0) failed, hr %#x, test %u.\n", hr, i);
4499 if (FAILED(hr))
4501 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
4502 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
4504 IDXGISwapChain_Release(swapchain);
4505 continue;
4508 expected_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
4509 hr = IDXGIResource_GetUsage(resource, &usage);
4510 ok(SUCCEEDED(hr), "Failed to get resource usage, hr %#x, test %u.\n", hr, i);
4511 ok((usage & expected_usage) == expected_usage, "Got usage %x, expected %x, test %u.\n",
4512 usage, expected_usage, i);
4514 IDXGIResource_Release(resource);
4516 hr = IDXGISwapChain_GetDesc(swapchain, &desc);
4517 ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
4519 for (j = 1; j <= tests[i].highest_accessible_buffer; j++)
4521 hr = IDXGISwapChain_GetBuffer(swapchain, j, &IID_IDXGIResource, (void **)&resource);
4522 ok(SUCCEEDED(hr), "GetBuffer(%u) failed, hr %#x, test %u.\n", hr, i, j);
4524 /* Buffers > 0 are supposed to be read only. This is the case except that in
4525 * fullscreen mode on Windows <= 8 the last backbuffer (BufferCount - 1) is
4526 * writable. This is not the case if an unsupported refresh rate is passed
4527 * for some reason, probably because the invalid refresh rate triggers a
4528 * kinda-sorta windowed mode.
4530 * On Windows 10 all buffers > 0 are read-only. Mark the earlier behavior
4531 * broken.
4533 * This last buffer acts as a shadow frontbuffer. Writing to it doesn't show
4534 * the draw on the screen right away (Aero on or off doesn't matter), but
4535 * Present with DXGI_PRESENT_DO_NOT_SEQUENCE will show the modifications.
4537 * Note that if the application doesn't have focused creating a fullscreen
4538 * swapchain returns DXGI_STATUS_OCCLUDED and we get a windowed swapchain,
4539 * so use the Windowed property of the swapchain that was actually created. */
4540 expected_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_READ_ONLY;
4541 broken_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
4543 if (desc.Windowed || j < tests[i].highest_accessible_buffer)
4544 broken_usage |= DXGI_USAGE_READ_ONLY;
4546 hr = IDXGIResource_GetUsage(resource, &usage);
4547 ok(SUCCEEDED(hr), "Failed to get resource usage, hr %#x, test %u, buffer %u.\n", hr, i, j);
4548 ok(usage == expected_usage || broken(usage == broken_usage),
4549 "Got usage %x, expected %x, test %u, buffer %u.\n",
4550 usage, expected_usage, i, j);
4552 IDXGIResource_Release(resource);
4554 hr = IDXGISwapChain_GetBuffer(swapchain, j, &IID_IDXGIResource, (void **)&resource);
4555 ok(hr == DXGI_ERROR_INVALID_CALL, "GetBuffer(%u) returned unexpected hr %#x, test %u.\n", j, hr, i);
4557 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
4558 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
4560 IDXGISwapChain_Release(swapchain);
4563 for (i = 0; i < ARRAY_SIZE(usage_tests); ++i)
4565 usage = usage_tests[i];
4567 memset(&desc, 0, sizeof(desc));
4568 desc.BufferDesc.Width = registry_mode.dmPelsWidth;
4569 desc.BufferDesc.Height = registry_mode.dmPelsHeight;
4570 desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4571 desc.SampleDesc.Count = 1;
4572 desc.BufferUsage = usage;
4573 desc.BufferCount = 1;
4574 desc.OutputWindow = window;
4575 desc.Windowed = TRUE;
4576 desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
4577 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4578 ok(hr == S_OK, "Got unexpected hr %#x, test %u.\n", hr, i);
4580 hr = IDXGISwapChain_GetDesc(swapchain, &desc);
4581 ok(hr == S_OK, "Failed to get swapchain desc, hr %#x, test %u.\n", hr, i);
4582 todo_wine_if(usage & ~(DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT))
4583 ok(desc.BufferUsage == usage, "Got usage %#x, expected %#x, test %u.\n", desc.BufferUsage, usage, i);
4585 expected_bind_flags = 0;
4586 if (usage & DXGI_USAGE_RENDER_TARGET_OUTPUT)
4587 expected_bind_flags |= D3D11_BIND_RENDER_TARGET;
4588 if (usage & DXGI_USAGE_SHADER_INPUT)
4589 expected_bind_flags |= D3D11_BIND_SHADER_RESOURCE;
4591 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&d3d10_texture);
4592 ok(hr == S_OK, "Failed to get d3d10 texture, hr %#x, test %u.\n", hr, i);
4593 ID3D10Texture2D_GetDesc(d3d10_texture, &d3d10_texture_desc);
4594 ok(d3d10_texture_desc.BindFlags == expected_bind_flags,
4595 "Got d3d10 bind flags %#x, expected %#x, test %u.\n",
4596 d3d10_texture_desc.BindFlags, expected_bind_flags, i);
4597 ID3D10Texture2D_Release(d3d10_texture);
4599 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D11Texture2D, (void **)&d3d11_texture);
4600 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Failed to get d3d11 texture, hr %#x, test %u.\n", hr, i);
4601 if (SUCCEEDED(hr))
4603 ID3D11Texture2D_GetDesc(d3d11_texture, &d3d11_texture_desc);
4604 ok(d3d11_texture_desc.BindFlags == expected_bind_flags,
4605 "Got d3d11 bind flags %#x, expected %#x, test %u.\n",
4606 d3d11_texture_desc.BindFlags, expected_bind_flags, i);
4607 ID3D11Texture2D_Release(d3d11_texture);
4610 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGIResource, (void **)&resource);
4611 todo_wine ok(hr == S_OK, "Failed to get buffer, hr %#x, test %u.\n", hr, i);
4612 if (FAILED(hr))
4614 IDXGISwapChain_Release(swapchain);
4615 continue;
4617 expected_usage = usage | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_DISCARD_ON_PRESENT;
4618 hr = IDXGIResource_GetUsage(resource, &usage);
4619 ok(hr == S_OK, "Failed to get resource usage, hr %#x, test %u.\n", hr, i);
4620 ok(usage == expected_usage, "Got usage %x, expected %x, test %u.\n", usage, expected_usage, i);
4621 IDXGIResource_Release(resource);
4623 IDXGISwapChain_Release(swapchain);
4626 /* multisampling */
4627 memset(&desc, 0, sizeof(desc));
4628 desc.BufferDesc.Width = registry_mode.dmPelsWidth;
4629 desc.BufferDesc.Height = registry_mode.dmPelsHeight;
4630 desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4631 desc.SampleDesc.Count = 4;
4632 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4633 desc.BufferCount = 4;
4634 desc.OutputWindow = window;
4635 desc.Windowed = TRUE;
4636 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
4637 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4638 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
4639 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
4640 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4641 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
4642 if (check_multisample_quality_levels(device, desc.BufferDesc.Format, desc.SampleDesc.Count))
4644 desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
4645 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4646 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
4647 IDXGISwapChain_Release(swapchain);
4648 desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
4649 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4650 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
4651 IDXGISwapChain_Release(swapchain);
4653 else
4655 skip("Multisampling not supported for DXGI_FORMAT_R8G8B8A8_UNORM.\n");
4658 IDXGIFactory_Release(factory);
4659 IUnknown_Release(obj);
4660 refcount = IDXGIDevice_Release(device);
4661 ok(!refcount, "Device has %u references left.\n", refcount);
4662 DestroyWindow(window);
4665 static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
4667 static const DWORD flags[] = {0, DXGI_PRESENT_TEST};
4668 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4669 IDXGISwapChain *swapchain;
4670 IDXGIFactory *factory;
4671 IDXGIOutput *output;
4672 BOOL fullscreen;
4673 unsigned int i;
4674 ULONG refcount;
4675 HRESULT hr;
4677 get_factory(device, is_d3d12, &factory);
4679 swapchain_desc.BufferDesc.Width = 800;
4680 swapchain_desc.BufferDesc.Height = 600;
4681 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
4682 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
4683 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4684 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
4685 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
4686 swapchain_desc.SampleDesc.Count = 1;
4687 swapchain_desc.SampleDesc.Quality = 0;
4688 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4689 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
4690 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
4691 swapchain_desc.Windowed = TRUE;
4692 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
4693 swapchain_desc.Flags = 0;
4695 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
4696 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
4698 for (i = 0; i < 10; ++i)
4700 hr = IDXGISwapChain_Present(swapchain, i, 0);
4701 ok(hr == (i <= 4 ? S_OK : DXGI_ERROR_INVALID_CALL),
4702 "Got unexpected hr %#x for sync interval %u.\n", hr, i);
4704 hr = IDXGISwapChain_Present(swapchain, 0, 0);
4705 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
4707 for (i = 0; i < ARRAY_SIZE(flags); ++i)
4709 HWND occluding_window = CreateWindowA("static", "occluding_window",
4710 WS_POPUP | WS_VISIBLE, 0, 0, 400, 200, NULL, NULL, NULL, NULL);
4712 /* Another window covers the swapchain window. Not reported as occluded. */
4713 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4714 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4716 /* Minimised window. */
4717 ShowWindow(swapchain_desc.OutputWindow, SW_MINIMIZE);
4718 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4719 ok(hr == (is_d3d12 ? S_OK : DXGI_STATUS_OCCLUDED), "Test %u: Got unexpected hr %#x.\n", i, hr);
4720 ShowWindow(swapchain_desc.OutputWindow, SW_NORMAL);
4722 /* Hidden window. */
4723 ShowWindow(swapchain_desc.OutputWindow, SW_HIDE);
4724 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4725 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4726 ShowWindow(swapchain_desc.OutputWindow, SW_SHOW);
4727 DestroyWindow(occluding_window);
4729 /* Test that IDXGIOutput_ReleaseOwnership() makes the swapchain exit
4730 * fullscreen. */
4731 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
4732 /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE on some machines.
4733 * DXGI_ERROR_UNSUPPORTED on the Windows 7 testbot. */
4734 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == DXGI_ERROR_UNSUPPORTED))
4736 skip("Test %u: Could not change fullscreen state.\n", i);
4737 continue;
4739 flush_events();
4740 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4741 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4742 todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4743 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4744 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4745 output = NULL;
4746 fullscreen = FALSE;
4747 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
4748 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4749 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4750 ok(!!output, "Test %u: Got unexpected output.\n", i);
4752 if (output)
4753 IDXGIOutput_ReleaseOwnership(output);
4754 /* Still fullscreen. */
4755 fullscreen = FALSE;
4756 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4757 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4758 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4759 /* Calling IDXGISwapChain_Present() will exit fullscreen. */
4760 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4761 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4762 fullscreen = TRUE;
4763 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4764 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4765 /* Now fullscreen mode is exited. */
4766 if (!flags[i] && !is_d3d12)
4767 /* Still fullscreen on vista and 2008. */
4768 todo_wine ok(!fullscreen || broken(fullscreen), "Test %u: Got unexpected fullscreen status.\n", i);
4769 else
4770 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4771 if (output)
4772 IDXGIOutput_Release(output);
4774 /* Test creating a window when swapchain is in fullscreen.
4776 * The window should break the swapchain out of fullscreen mode on
4777 * d3d10/11. D3d12 is different, a new occluding window doesn't break
4778 * the swapchain out of fullscreen because d3d12 fullscreen swapchains
4779 * don't take exclusive ownership over the output, nor do they disable
4780 * compositing. D3d12 fullscreen mode acts just like borderless
4781 * fullscreen window mode. */
4782 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
4783 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4784 fullscreen = FALSE;
4785 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4786 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4787 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4788 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4789 todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4790 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4791 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4793 occluding_window = CreateWindowA("static", "occluding_window", WS_POPUP, 0, 0, 400, 200, 0, 0, 0, 0);
4794 /* An invisible window doesn't cause the swapchain to exit fullscreen
4795 * mode. */
4796 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4797 todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4798 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4799 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4800 fullscreen = FALSE;
4801 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4802 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4803 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4804 /* A visible, but with bottom z-order window still causes the
4805 * swapchain to exit fullscreen mode. */
4806 SetWindowPos(occluding_window, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
4807 ShowWindow(occluding_window, SW_SHOW);
4808 /* Fullscreen mode takes a while to exit. */
4809 if (!is_d3d12)
4810 wait_fullscreen_state(swapchain, FALSE, TRUE);
4812 /* No longer fullscreen before calling IDXGISwapChain_Present() except
4813 * for d3d12. */
4814 fullscreen = TRUE;
4815 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4816 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4817 todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen,
4818 "Test %u: Got unexpected fullscreen status.\n", i);
4820 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4821 todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4822 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4823 todo_wine_if(is_d3d12) ok(hr == (is_d3d12 ? DXGI_STATUS_OCCLUDED : S_OK),
4824 "Test %u: Got unexpected hr %#x.\n", i, hr);
4826 fullscreen = TRUE;
4827 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4828 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4829 if (flags[i] == DXGI_PRESENT_TEST)
4830 todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen,
4831 "Test %u: Got unexpected fullscreen status.\n", i);
4832 else
4833 todo_wine ok(!fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4835 /* Even though d3d12 doesn't exit fullscreen, a
4836 * IDXGISwapChain_ResizeBuffers() is still needed for subsequent
4837 * IDXGISwapChain_Present() calls to work, otherwise they will return
4838 * DXGI_ERROR_INVALID_CALL */
4839 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4840 todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4841 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4842 if (flags[i] == DXGI_PRESENT_TEST)
4843 todo_wine_if(is_d3d12) ok(hr == (is_d3d12 ? DXGI_STATUS_OCCLUDED : S_OK),
4844 "Test %u: Got unexpected hr %#x.\n", i, hr);
4845 else
4846 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4848 /* Trying to break out of fullscreen mode again. This time, don't call
4849 * IDXGISwapChain_GetFullscreenState() before IDXGISwapChain_Present(). */
4850 ShowWindow(occluding_window, SW_HIDE);
4851 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
4852 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4853 ShowWindow(occluding_window, SW_SHOW);
4855 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4856 todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4857 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4858 /* hr == S_OK on vista and 2008 */
4859 todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK),
4860 "Test %u: Got unexpected hr %#x.\n", i, hr);
4862 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4863 todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4864 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4865 if (flags[i] == DXGI_PRESENT_TEST)
4867 todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK),
4868 "Test %u: Got unexpected hr %#x.\n", i, hr);
4869 /* IDXGISwapChain_Present() without flags refreshes the occlusion
4870 * state. */
4871 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4872 todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4873 hr = IDXGISwapChain_Present(swapchain, 0, 0);
4874 todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK),
4875 "Test %u: Got unexpected hr %#x.\n", i, hr);
4876 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4877 todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4878 hr = IDXGISwapChain_Present(swapchain, 0, DXGI_PRESENT_TEST);
4879 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4881 else
4883 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4885 fullscreen = TRUE;
4886 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4887 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4888 todo_wine ok(!fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4890 DestroyWindow(occluding_window);
4891 flush_events();
4892 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4893 todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4894 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4895 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4897 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
4898 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4899 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4900 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
4903 wait_device_idle(device);
4905 IDXGISwapChain_Release(swapchain);
4906 DestroyWindow(swapchain_desc.OutputWindow);
4907 refcount = IDXGIFactory_Release(factory);
4908 ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
4911 static void test_swapchain_backbuffer_index(IUnknown *device, BOOL is_d3d12)
4913 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4914 unsigned int index, expected_index;
4915 IDXGISwapChain3 *swapchain3;
4916 IDXGISwapChain *swapchain;
4917 HRESULT hr, expected_hr;
4918 IDXGIFactory *factory;
4919 unsigned int i, j;
4920 ULONG refcount;
4921 RECT rect;
4922 BOOL ret;
4924 static const DXGI_SWAP_EFFECT swap_effects[] =
4926 DXGI_SWAP_EFFECT_DISCARD,
4927 DXGI_SWAP_EFFECT_SEQUENTIAL,
4928 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
4929 DXGI_SWAP_EFFECT_FLIP_DISCARD,
4932 get_factory(device, is_d3d12, &factory);
4934 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
4935 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
4936 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4937 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
4938 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
4939 swapchain_desc.SampleDesc.Count = 1;
4940 swapchain_desc.SampleDesc.Quality = 0;
4941 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4942 swapchain_desc.BufferCount = 4;
4943 swapchain_desc.OutputWindow = create_window();
4944 swapchain_desc.Windowed = TRUE;
4945 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
4946 swapchain_desc.Flags = 0;
4948 ret = GetClientRect(swapchain_desc.OutputWindow, &rect);
4949 ok(ret, "Failed to get client rect.\n");
4950 swapchain_desc.BufferDesc.Width = rect.right;
4951 swapchain_desc.BufferDesc.Height = rect.bottom;
4953 for (i = 0; i < ARRAY_SIZE(swap_effects); ++i)
4955 swapchain_desc.SwapEffect = swap_effects[i];
4956 expected_hr = is_d3d12 && !is_flip_model(swap_effects[i]) ? DXGI_ERROR_INVALID_CALL : S_OK;
4957 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
4958 ok(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
4959 if (FAILED(hr))
4960 continue;
4962 hr = IDXGISwapChain_QueryInterface(swapchain, &IID_IDXGISwapChain3, (void **)&swapchain3);
4963 if (hr == E_NOINTERFACE)
4965 skip("IDXGISwapChain3 is not supported.\n");
4966 IDXGISwapChain_Release(swapchain);
4967 goto done;
4970 for (j = 0; j < 2 * swapchain_desc.BufferCount; ++j)
4972 index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain3);
4973 expected_index = is_d3d12 ? j % swapchain_desc.BufferCount : 0;
4974 ok(index == expected_index, "Got back buffer index %u, expected %u.\n", index, expected_index);
4975 hr = IDXGISwapChain3_Present(swapchain3, 0, 0);
4976 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
4979 wait_device_idle(device);
4981 IDXGISwapChain3_Release(swapchain3);
4982 refcount = IDXGISwapChain_Release(swapchain);
4983 ok(!refcount, "Swapchain has %u references left.\n", refcount);
4986 done:
4987 DestroyWindow(swapchain_desc.OutputWindow);
4988 refcount = IDXGIFactory_Release(factory);
4989 ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
4992 static void test_swapchain_formats(IUnknown *device, BOOL is_d3d12)
4994 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4995 IDXGISwapChain *swapchain;
4996 HRESULT hr, expected_hr;
4997 IDXGIFactory *factory;
4998 unsigned int i;
4999 ULONG refcount;
5000 RECT rect;
5001 BOOL ret;
5003 static const struct
5005 DXGI_FORMAT format;
5006 DXGI_SWAP_EFFECT swap_effect;
5007 BOOL supported;
5009 tests[] =
5011 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_DISCARD, FALSE},
5012 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_SEQUENTIAL, FALSE},
5013 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5014 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5015 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5016 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5017 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5018 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5019 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5020 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5021 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5022 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5023 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5024 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5025 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5026 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5027 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5028 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5029 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5030 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5031 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5032 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5033 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5034 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5035 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5036 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5037 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5038 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5039 {DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5040 {DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5043 get_factory(device, is_d3d12, &factory);
5045 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
5046 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
5047 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
5048 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
5049 swapchain_desc.SampleDesc.Count = 1;
5050 swapchain_desc.SampleDesc.Quality = 0;
5051 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5052 swapchain_desc.BufferCount = 4;
5053 swapchain_desc.OutputWindow = create_window();
5054 swapchain_desc.Windowed = TRUE;
5055 swapchain_desc.Flags = 0;
5057 ret = GetClientRect(swapchain_desc.OutputWindow, &rect);
5058 ok(ret, "Failed to get client rect.\n");
5059 swapchain_desc.BufferDesc.Width = rect.right;
5060 swapchain_desc.BufferDesc.Height = rect.bottom;
5062 for (i = 0; i < ARRAY_SIZE(tests); ++i)
5064 if (is_d3d12 && !is_flip_model(tests[i].swap_effect))
5065 continue;
5067 swapchain_desc.BufferDesc.Format = tests[i].format;
5068 swapchain_desc.SwapEffect = tests[i].swap_effect;
5069 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
5070 expected_hr = tests[i].supported ? S_OK : DXGI_ERROR_INVALID_CALL;
5071 if (tests[i].format == DXGI_FORMAT_UNKNOWN && !is_d3d12)
5072 expected_hr = E_INVALIDARG;
5073 ok(hr == expected_hr
5074 /* Flip presentation model not supported. */
5075 || broken(hr == DXGI_ERROR_INVALID_CALL && is_flip_model(tests[i].swap_effect) && !is_d3d12),
5076 "Test %u, d3d12 %#x: Got hr %#x, expected %#x.\n", i, is_d3d12, hr, expected_hr);
5078 if (SUCCEEDED(hr))
5080 refcount = IDXGISwapChain_Release(swapchain);
5081 ok(!refcount, "Swapchain has %u references left.\n", refcount);
5085 DestroyWindow(swapchain_desc.OutputWindow);
5086 refcount = IDXGIFactory_Release(factory);
5087 ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
5090 static void test_maximum_frame_latency(void)
5092 IDXGIDevice1 *device1;
5093 IDXGIDevice *device;
5094 UINT max_latency;
5095 ULONG refcount;
5096 HRESULT hr;
5098 if (!(device = create_device(0)))
5100 skip("Failed to create device.\n");
5101 return;
5104 if (SUCCEEDED(IDXGIDevice_QueryInterface(device, &IID_IDXGIDevice1, (void **)&device1)))
5106 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, NULL);
5107 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
5109 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5110 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5111 ok(max_latency == DEFAULT_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
5113 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, MAX_FRAME_LATENCY);
5114 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5115 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5116 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5117 ok(max_latency == MAX_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
5119 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, MAX_FRAME_LATENCY + 1);
5120 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
5121 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5122 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5123 ok(max_latency == MAX_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
5125 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, 0);
5126 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5127 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5128 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5129 /* 0 does not reset to the default frame latency on all Windows versions. */
5130 ok(max_latency == DEFAULT_FRAME_LATENCY || broken(!max_latency),
5131 "Got unexpected maximum frame latency %u.\n", max_latency);
5133 IDXGIDevice1_Release(device1);
5135 else
5137 win_skip("IDXGIDevice1 is not implemented.\n");
5140 refcount = IDXGIDevice_Release(device);
5141 ok(!refcount, "Device has %u references left.\n", refcount);
5144 static void test_output_desc(void)
5146 IDXGIAdapter *adapter, *adapter2;
5147 IDXGIOutput *output, *output2;
5148 DXGI_OUTPUT_DESC desc;
5149 IDXGIFactory *factory;
5150 unsigned int i, j;
5151 ULONG refcount;
5152 HRESULT hr;
5154 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory);
5155 ok(SUCCEEDED(hr), "Failed to create DXGI factory, hr %#x.\n", hr);
5157 for (i = 0; ; ++i)
5159 hr = IDXGIFactory_EnumAdapters(factory, i, &adapter);
5160 if (hr == DXGI_ERROR_NOT_FOUND)
5161 break;
5162 ok(SUCCEEDED(hr), "Failed to enumerate adapter %u, hr %#x.\n", i, hr);
5164 hr = IDXGIFactory_EnumAdapters(factory, i, &adapter2);
5165 ok(SUCCEEDED(hr), "Failed to enumerate adapter %u, hr %#x.\n", i, hr);
5166 ok(adapter != adapter2, "Expected to get new instance of IDXGIAdapter, %p == %p.\n", adapter, adapter2);
5167 refcount = get_refcount(adapter);
5168 ok(refcount == 1, "Get unexpected refcount %u for adapter %u.\n", refcount, i);
5169 IDXGIAdapter_Release(adapter2);
5171 refcount = get_refcount(factory);
5172 ok(refcount == 2, "Get unexpected refcount %u.\n", refcount);
5173 refcount = get_refcount(adapter);
5174 ok(refcount == 1, "Get unexpected refcount %u for adapter %u.\n", refcount, i);
5176 for (j = 0; ; ++j)
5178 MONITORINFOEXW monitor_info;
5179 BOOL ret;
5181 hr = IDXGIAdapter_EnumOutputs(adapter, j, &output);
5182 if (hr == DXGI_ERROR_NOT_FOUND)
5183 break;
5184 ok(SUCCEEDED(hr), "Failed to enumerate output %u on adapter %u, hr %#x.\n", j, i, hr);
5186 hr = IDXGIAdapter_EnumOutputs(adapter, j, &output2);
5187 ok(SUCCEEDED(hr), "Failed to enumerate output %u on adapter %u, hr %#x.\n", j, i, hr);
5188 ok(output != output2, "Expected to get new instance of IDXGIOutput, %p == %p.\n", output, output2);
5189 refcount = get_refcount(output);
5190 ok(refcount == 1, "Get unexpected refcount %u for output %u, adapter %u.\n", refcount, j, i);
5191 IDXGIOutput_Release(output2);
5193 refcount = get_refcount(factory);
5194 ok(refcount == 2, "Get unexpected refcount %u.\n", refcount);
5195 refcount = get_refcount(adapter);
5196 ok(refcount == 2, "Get unexpected refcount %u for adapter %u.\n", refcount, i);
5197 refcount = get_refcount(output);
5198 ok(refcount == 1, "Get unexpected refcount %u for output %u, adapter %u.\n", refcount, j, i);
5200 hr = IDXGIOutput_GetDesc(output, &desc);
5201 ok(SUCCEEDED(hr), "Failed to get desc for output %u on adapter %u, hr %#x.\n", j, i, hr);
5203 monitor_info.cbSize = sizeof(monitor_info);
5204 ret = GetMonitorInfoW(desc.Monitor, (MONITORINFO *)&monitor_info);
5205 ok(ret, "Failed to get monitor info.\n");
5206 ok(!lstrcmpW(desc.DeviceName, monitor_info.szDevice), "Got unexpected device name %s, expected %s.\n",
5207 wine_dbgstr_w(desc.DeviceName), wine_dbgstr_w(monitor_info.szDevice));
5208 ok(EqualRect(&desc.DesktopCoordinates, &monitor_info.rcMonitor),
5209 "Got unexpected desktop coordinates %s, expected %s.\n",
5210 wine_dbgstr_rect(&desc.DesktopCoordinates),
5211 wine_dbgstr_rect(&monitor_info.rcMonitor));
5213 IDXGIOutput_Release(output);
5214 refcount = get_refcount(adapter);
5215 ok(refcount == 1, "Get unexpected refcount %u for adapter %u.\n", refcount, i);
5218 IDXGIAdapter_Release(adapter);
5219 refcount = get_refcount(factory);
5220 ok(refcount == 1, "Get unexpected refcount %u.\n", refcount);
5223 refcount = IDXGIFactory_Release(factory);
5224 ok(!refcount, "IDXGIFactory has %u references left.\n", refcount);
5227 struct dxgi_adapter
5229 IDXGIAdapter IDXGIAdapter_iface;
5230 IDXGIAdapter *wrapped_iface;
5233 static inline struct dxgi_adapter *impl_from_IDXGIAdapter(IDXGIAdapter *iface)
5235 return CONTAINING_RECORD(iface, struct dxgi_adapter, IDXGIAdapter_iface);
5238 static HRESULT STDMETHODCALLTYPE dxgi_adapter_QueryInterface(IDXGIAdapter *iface, REFIID iid, void **out)
5240 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5242 if (IsEqualGUID(iid, &IID_IDXGIAdapter)
5243 || IsEqualGUID(iid, &IID_IDXGIObject)
5244 || IsEqualGUID(iid, &IID_IUnknown))
5246 IDXGIAdapter_AddRef(adapter->wrapped_iface);
5247 *out = iface;
5248 return S_OK;
5250 return IDXGIAdapter_QueryInterface(adapter->wrapped_iface, iid, out);
5253 static ULONG STDMETHODCALLTYPE dxgi_adapter_AddRef(IDXGIAdapter *iface)
5255 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5256 return IDXGIAdapter_AddRef(adapter->wrapped_iface);
5259 static ULONG STDMETHODCALLTYPE dxgi_adapter_Release(IDXGIAdapter *iface)
5261 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5262 return IDXGIAdapter_Release(adapter->wrapped_iface);
5265 static HRESULT STDMETHODCALLTYPE dxgi_adapter_SetPrivateData(IDXGIAdapter *iface,
5266 REFGUID guid, UINT data_size, const void *data)
5268 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5269 return IDXGIAdapter_SetPrivateData(adapter->wrapped_iface, guid, data_size, data);
5272 static HRESULT STDMETHODCALLTYPE dxgi_adapter_SetPrivateDataInterface(IDXGIAdapter *iface,
5273 REFGUID guid, const IUnknown *object)
5275 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5276 return IDXGIAdapter_SetPrivateDataInterface(adapter->wrapped_iface, guid, object);
5279 static HRESULT STDMETHODCALLTYPE dxgi_adapter_GetPrivateData(IDXGIAdapter *iface,
5280 REFGUID guid, UINT *data_size, void *data)
5282 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5283 return IDXGIAdapter_GetPrivateData(adapter->wrapped_iface, guid, data_size, data);
5286 static HRESULT STDMETHODCALLTYPE dxgi_adapter_GetParent(IDXGIAdapter *iface, REFIID iid, void **parent)
5288 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5289 return IDXGIAdapter_GetParent(adapter->wrapped_iface, iid, parent);
5292 static HRESULT STDMETHODCALLTYPE dxgi_adapter_EnumOutputs(IDXGIAdapter *iface,
5293 UINT output_idx, IDXGIOutput **output)
5295 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5296 return IDXGIAdapter_EnumOutputs(adapter->wrapped_iface, output_idx, output);
5299 static HRESULT STDMETHODCALLTYPE dxgi_adapter_GetDesc(IDXGIAdapter *iface, DXGI_ADAPTER_DESC *desc)
5301 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5302 return IDXGIAdapter_GetDesc(adapter->wrapped_iface, desc);
5305 static HRESULT STDMETHODCALLTYPE dxgi_adapter_CheckInterfaceSupport(IDXGIAdapter *iface,
5306 REFGUID guid, LARGE_INTEGER *umd_version)
5308 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5309 return IDXGIAdapter_CheckInterfaceSupport(adapter->wrapped_iface, guid, umd_version);
5312 static const struct IDXGIAdapterVtbl dxgi_adapter_vtbl =
5314 dxgi_adapter_QueryInterface,
5315 dxgi_adapter_AddRef,
5316 dxgi_adapter_Release,
5317 dxgi_adapter_SetPrivateData,
5318 dxgi_adapter_SetPrivateDataInterface,
5319 dxgi_adapter_GetPrivateData,
5320 dxgi_adapter_GetParent,
5321 dxgi_adapter_EnumOutputs,
5322 dxgi_adapter_GetDesc,
5323 dxgi_adapter_CheckInterfaceSupport,
5326 static void test_object_wrapping(void)
5328 struct dxgi_adapter wrapper;
5329 DXGI_ADAPTER_DESC desc;
5330 IDXGIAdapter *adapter;
5331 IDXGIFactory *factory;
5332 ID3D10Device1 *device;
5333 ULONG refcount;
5334 HRESULT hr;
5336 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory);
5337 ok(hr == S_OK, "Failed to create DXGI factory, hr %#x.\n", hr);
5339 hr = IDXGIFactory_EnumAdapters(factory, 0, &adapter);
5340 if (hr == DXGI_ERROR_NOT_FOUND)
5342 skip("Could not enumerate adapters.\n");
5343 IDXGIFactory_Release(factory);
5344 return;
5346 ok(hr == S_OK, "Failed to enumerate adapter, hr %#x.\n", hr);
5348 wrapper.IDXGIAdapter_iface.lpVtbl = &dxgi_adapter_vtbl;
5349 wrapper.wrapped_iface = adapter;
5351 hr = D3D10CreateDevice1(&wrapper.IDXGIAdapter_iface, D3D10_DRIVER_TYPE_HARDWARE, NULL,
5352 0, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device);
5353 if (SUCCEEDED(hr))
5355 refcount = ID3D10Device1_Release(device);
5356 ok(!refcount, "Device has %u references left.\n", refcount);
5359 hr = IDXGIAdapter_GetDesc(&wrapper.IDXGIAdapter_iface, &desc);
5360 ok(hr == S_OK, "Failed to get adapter desc, hr %#x.\n", hr);
5362 refcount = IDXGIAdapter_Release(&wrapper.IDXGIAdapter_iface);
5363 ok(!refcount, "Adapter has %u references left.\n", refcount);
5364 refcount = IDXGIFactory_Release(factory);
5365 ok(!refcount, "Factory has %u references left.\n", refcount);
5368 struct adapter_info
5370 const WCHAR *name;
5371 HMONITOR monitor;
5374 static BOOL CALLBACK enum_monitor_proc(HMONITOR monitor, HDC dc, RECT *rect, LPARAM lparam)
5376 struct adapter_info *adapter_info = (struct adapter_info *)lparam;
5377 MONITORINFOEXW monitor_info;
5379 monitor_info.cbSize = sizeof(monitor_info);
5380 if (GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info)
5381 && !lstrcmpiW(adapter_info->name, monitor_info.szDevice))
5383 adapter_info->monitor = monitor;
5384 return FALSE;
5387 return TRUE;
5390 static HMONITOR get_monitor(const WCHAR *adapter_name)
5392 struct adapter_info info = {adapter_name, NULL};
5394 EnumDisplayMonitors(NULL, NULL, enum_monitor_proc, (LPARAM)&info);
5395 return info.monitor;
5398 static void test_multi_adapter(void)
5400 unsigned int output_count = 0, expected_output_count = 0;
5401 unsigned int adapter_index, output_index, device_index;
5402 DXGI_OUTPUT_DESC old_output_desc, output_desc;
5403 DXGI_ADAPTER_DESC1 adapter_desc1;
5404 DXGI_ADAPTER_DESC adapter_desc;
5405 DISPLAY_DEVICEW display_device;
5406 MONITORINFO monitor_info;
5407 DEVMODEW old_mode, mode;
5408 IDXGIAdapter1 *adapter1;
5409 IDXGIFactory *factory;
5410 IDXGIAdapter *adapter;
5411 IDXGIOutput *output;
5412 HMONITOR monitor;
5413 BOOL found;
5414 HRESULT hr;
5415 LONG ret;
5417 if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory)))
5419 skip("Failed to create IDXGIFactory, hr %#x.\n", hr);
5420 return;
5423 hr = IDXGIFactory_EnumAdapters(factory, 0, NULL);
5424 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
5426 hr = IDXGIFactory_EnumAdapters(factory, 0, &adapter);
5427 if (hr == DXGI_ERROR_NOT_FOUND)
5429 skip("Could not enumerate adapters.\n");
5430 IDXGIFactory_Release(factory);
5431 return;
5433 ok(hr == S_OK, "Failed to enumerate adapter, hr %#x.\n", hr);
5435 for (adapter_index = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_index, &adapter)); ++adapter_index)
5437 for (output_index = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_index, &output)); ++output_index)
5439 hr = IDXGIOutput_GetDesc(output, &output_desc);
5440 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#x.\n", adapter_index,
5441 output_index, hr);
5443 found = FALSE;
5444 display_device.cb = sizeof(display_device);
5445 for (device_index = 0; EnumDisplayDevicesW(NULL, device_index, &display_device, 0); ++device_index)
5447 if (!lstrcmpiW(display_device.DeviceName, output_desc.DeviceName))
5449 found = TRUE;
5450 break;
5453 ok(found, "Adapter %u output %u: Failed to find device %s.\n",
5454 adapter_index, output_index, wine_dbgstr_w(output_desc.DeviceName));
5456 ok(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP,
5457 "Adapter %u output %u: Got unexpected state flags %#x.\n", adapter_index,
5458 output_index, display_device.StateFlags);
5459 if (!adapter_index && !output_index)
5460 ok(display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE,
5461 "Adapter %u output %u: Got unexpected state flags %#x.\n", adapter_index,
5462 output_index, display_device.StateFlags);
5463 else
5464 ok(!(display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE),
5465 "Adapter %u output %u: Got unexpected state flags %#x.\n", adapter_index,
5466 output_index, display_device.StateFlags);
5468 /* Should have the same monitor handle. */
5469 monitor = get_monitor(display_device.DeviceName);
5470 ok(!!monitor, "Adapter %u output %u: Failed to find monitor %s.\n", adapter_index,
5471 output_index, wine_dbgstr_w(display_device.DeviceName));
5472 ok(monitor == output_desc.Monitor,
5473 "Adapter %u output %u: Got unexpected monitor %p, expected %p.\n",
5474 adapter_index, output_index, monitor, output_desc.Monitor);
5476 /* Should have the same monitor rectangle. */
5477 monitor_info.cbSize = sizeof(monitor_info);
5478 ok(GetMonitorInfoA(monitor, &monitor_info),
5479 "Adapter %u output %u: Failed to get monitor info, error %#x.\n", adapter_index,
5480 output_index, GetLastError());
5481 ok(EqualRect(&monitor_info.rcMonitor, &output_desc.DesktopCoordinates),
5482 "Adapter %u output %u: Got unexpected output rect %s, expected %s.\n",
5483 adapter_index, output_index, wine_dbgstr_rect(&monitor_info.rcMonitor),
5484 wine_dbgstr_rect(&output_desc.DesktopCoordinates));
5486 ++output_count;
5488 /* Test output description after it got detached */
5489 if (display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
5491 IDXGIOutput_Release(output);
5492 continue;
5495 old_output_desc = output_desc;
5497 /* Save current display settings */
5498 memset(&old_mode, 0, sizeof(old_mode));
5499 old_mode.dmSize = sizeof(old_mode);
5500 ret = EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &old_mode);
5501 /* Win10 TestBots may return FALSE but it's actually successful */
5502 ok(ret || broken(!ret),
5503 "Adapter %u output %u: EnumDisplaySettingsW failed for %s, error %#x.\n",
5504 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName),
5505 GetLastError());
5507 /* Detach */
5508 memset(&mode, 0, sizeof(mode));
5509 mode.dmSize = sizeof(mode);
5510 mode.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
5511 mode.dmPosition = old_mode.dmPosition;
5512 ret = ChangeDisplaySettingsExW(display_device.DeviceName, &mode, NULL,
5513 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
5514 ok(ret == DISP_CHANGE_SUCCESSFUL,
5515 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %d.\n",
5516 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5517 ret = ChangeDisplaySettingsExW(display_device.DeviceName, NULL, NULL, 0, NULL);
5518 ok(ret == DISP_CHANGE_SUCCESSFUL,
5519 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %d.\n",
5520 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5522 /* Check if it is really detached */
5523 memset(&mode, 0, sizeof(mode));
5524 mode.dmSize = sizeof(mode);
5525 ret = EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &mode);
5526 /* Win10 TestBots may return FALSE but it's actually successful */
5527 ok(ret || broken(!ret) ,
5528 "Adapter %u output %u: EnumDisplaySettingsW failed for %s, error %#x.\n",
5529 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName),
5530 GetLastError());
5531 if (mode.dmPelsWidth && mode.dmPelsHeight)
5533 skip("Adapter %u output %u: Failed to detach device %s.\n", adapter_index,
5534 output_index, wine_dbgstr_w(display_device.DeviceName));
5535 IDXGIOutput_Release(output);
5536 continue;
5539 /* Only the AttachedToDesktop field is updated after an output is detached.
5540 * IDXGIAdapter_EnumOutputs() has to be called again to get other fields updated.
5541 * But resolution changes are reflected right away. This weird behaviour is currently
5542 * unimplemented in Wine */
5543 memset(&output_desc, 0, sizeof(output_desc));
5544 hr = IDXGIOutput_GetDesc(output, &output_desc);
5545 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#x.\n", adapter_index,
5546 output_index, hr);
5547 ok(!lstrcmpiW(output_desc.DeviceName, old_output_desc.DeviceName),
5548 "Adapter %u output %u: Expect device name %s, got %s.\n", adapter_index,
5549 output_index, wine_dbgstr_w(old_output_desc.DeviceName),
5550 wine_dbgstr_w(output_desc.DeviceName));
5551 todo_wine
5552 ok(EqualRect(&output_desc.DesktopCoordinates, &old_output_desc.DesktopCoordinates),
5553 "Adapter %u output %u: Expect desktop coordinates %s, got %s.\n",
5554 adapter_index, output_index,
5555 wine_dbgstr_rect(&old_output_desc.DesktopCoordinates),
5556 wine_dbgstr_rect(&output_desc.DesktopCoordinates));
5557 ok(!output_desc.AttachedToDesktop,
5558 "Adapter %u output %u: Expect output not attached to desktop.\n", adapter_index,
5559 output_index);
5560 ok(output_desc.Rotation == old_output_desc.Rotation,
5561 "Adapter %u output %u: Expect rotation %#x, got %#x.\n", adapter_index,
5562 output_index, old_output_desc.Rotation, output_desc.Rotation);
5563 todo_wine
5564 ok(output_desc.Monitor == old_output_desc.Monitor,
5565 "Adapter %u output %u: Expect monitor %p, got %p.\n", adapter_index,
5566 output_index, old_output_desc.Monitor, output_desc.Monitor);
5567 IDXGIOutput_Release(output);
5569 /* Call IDXGIAdapter_EnumOutputs() again to get up-to-date output description */
5570 hr = IDXGIAdapter_EnumOutputs(adapter, output_index, &output);
5571 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#x.\n", adapter_index,
5572 output_index, hr);
5573 memset(&output_desc, 0, sizeof(output_desc));
5574 hr = IDXGIOutput_GetDesc(output, &output_desc);
5575 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#x.\n", adapter_index,
5576 output_index, hr);
5577 ok(!lstrcmpiW(output_desc.DeviceName, display_device.DeviceName),
5578 "Adapter %u output %u: Expect device name %s, got %s.\n", adapter_index,
5579 output_index, wine_dbgstr_w(display_device.DeviceName),
5580 wine_dbgstr_w(output_desc.DeviceName));
5581 ok(IsRectEmpty(&output_desc.DesktopCoordinates),
5582 "Adapter %u output %u: Expect desktop rect empty, got %s.\n", adapter_index,
5583 output_index, wine_dbgstr_rect(&output_desc.DesktopCoordinates));
5584 ok(!output_desc.AttachedToDesktop,
5585 "Adapter %u output %u: Expect output not attached to desktop.\n", adapter_index,
5586 output_index);
5587 ok(output_desc.Rotation == DXGI_MODE_ROTATION_IDENTITY,
5588 "Adapter %u output %u: Expect rotation %#x, got %#x.\n", adapter_index,
5589 output_index, DXGI_MODE_ROTATION_IDENTITY, output_desc.Rotation);
5590 ok(!output_desc.Monitor, "Adapter %u output %u: Expect monitor NULL.\n", adapter_index,
5591 output_index);
5593 /* Restore settings */
5594 ret = ChangeDisplaySettingsExW(display_device.DeviceName, &old_mode, NULL,
5595 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
5596 ok(ret == DISP_CHANGE_SUCCESSFUL,
5597 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %d.\n",
5598 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5599 ret = ChangeDisplaySettingsExW(display_device.DeviceName, NULL, NULL, 0, NULL);
5600 ok(ret == DISP_CHANGE_SUCCESSFUL,
5601 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %d.\n",
5602 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5604 IDXGIOutput_Release(output);
5607 IDXGIAdapter_Release(adapter);
5610 /* Windows 8+ always have a WARP adapter present at the end. */
5611 todo_wine ok(adapter_index >= 2 || broken(adapter_index < 2) /* Windows 7 and before */,
5612 "Got unexpected adapter count %u.\n", adapter_index);
5613 if (adapter_index < 2)
5615 todo_wine win_skip("WARP adapter missing, skipping tests.\n");
5616 goto done;
5619 hr = IDXGIFactory_EnumAdapters(factory, adapter_index - 1, &adapter);
5620 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5621 hr = IDXGIAdapter_GetDesc(adapter, &adapter_desc);
5622 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5623 todo_wine ok(!lstrcmpW(adapter_desc.Description, L"Microsoft Basic Render Driver"),
5624 "Got unexpected description %s.\n", wine_dbgstr_w(adapter_desc.Description));
5625 todo_wine ok(adapter_desc.VendorId == 0x1414,
5626 "Got unexpected vendor ID %#x.\n", adapter_desc.VendorId);
5627 todo_wine ok(adapter_desc.DeviceId == 0x008c,
5628 "Got unexpected device ID %#x.\n", adapter_desc.DeviceId);
5629 ok(adapter_desc.SubSysId == 0x0000,
5630 "Got unexpected sub-system ID %#x.\n", adapter_desc.SubSysId);
5631 ok(adapter_desc.Revision == 0x0000,
5632 "Got unexpected revision %#x.\n", adapter_desc.Revision);
5633 todo_wine ok(!adapter_desc.DedicatedVideoMemory,
5634 "Got unexpected DedicatedVideoMemory %#lx.\n", adapter_desc.DedicatedVideoMemory);
5635 ok(!adapter_desc.DedicatedSystemMemory,
5636 "Got unexpected DedicatedSystemMemory %#lx.\n", adapter_desc.DedicatedSystemMemory);
5638 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter1, (void **)&adapter1);
5639 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Got unexpected hr %#x.\n", hr);
5640 if (SUCCEEDED(hr))
5642 hr = IDXGIAdapter1_GetDesc1(adapter1, &adapter_desc1);
5643 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5644 todo_wine ok(adapter_desc1.Flags == DXGI_ADAPTER_FLAG_SOFTWARE,
5645 "Got unexpected flags %#x.\n", adapter_desc1.Flags);
5646 IDXGIAdapter1_Release(adapter1);
5649 IDXGIAdapter_Release(adapter);
5651 done:
5652 IDXGIFactory_Release(factory);
5654 expected_output_count = GetSystemMetrics(SM_CMONITORS);
5655 todo_wine_if(expected_output_count > 1)
5656 ok(output_count == expected_output_count, "Expect output count %d, got %d\n",
5657 expected_output_count, output_count);
5660 struct message
5662 unsigned int message;
5663 BOOL check_wparam;
5664 WPARAM expect_wparam;
5667 static BOOL expect_no_messages;
5668 static const struct message *expect_messages;
5669 static const struct message *expect_messages_broken;
5671 static BOOL check_message(const struct message *expected,
5672 HWND hwnd, unsigned int message, WPARAM wparam, LPARAM lparam)
5674 if (expected->message != message)
5675 return FALSE;
5677 if (expected->check_wparam)
5679 ok(wparam == expected->expect_wparam,
5680 "Got unexpected wparam %lx for message %x, expected %lx.\n",
5681 wparam, message, expected->expect_wparam);
5684 return TRUE;
5687 static LRESULT CALLBACK test_wndproc(HWND hwnd, unsigned int message, WPARAM wparam, LPARAM lparam)
5689 ok(!expect_no_messages, "Got unexpected message %#x, hwnd %p, wparam %#lx, lparam %#lx.\n",
5690 message, hwnd, wparam, lparam);
5692 if (expect_messages)
5694 if (check_message(expect_messages, hwnd, message, wparam, lparam))
5695 ++expect_messages;
5698 if (expect_messages_broken)
5700 if (check_message(expect_messages_broken, hwnd, message, wparam, lparam))
5701 ++expect_messages_broken;
5704 return DefWindowProcA(hwnd, message, wparam, lparam);
5707 static void test_swapchain_window_messages(void)
5709 DXGI_SWAP_CHAIN_DESC swapchain_desc;
5710 IDXGISwapChain *swapchain;
5711 DXGI_MODE_DESC mode_desc;
5712 IDXGIFactory *factory;
5713 IDXGIAdapter *adapter;
5714 IDXGIDevice *device;
5715 ULONG refcount;
5716 WNDCLASSA wc;
5717 HWND window;
5718 HRESULT hr;
5720 static const struct message enter_fullscreen_messages[] =
5722 {WM_STYLECHANGING, TRUE, GWL_STYLE},
5723 {WM_STYLECHANGED, TRUE, GWL_STYLE},
5724 {WM_STYLECHANGING, TRUE, GWL_EXSTYLE},
5725 {WM_STYLECHANGED, TRUE, GWL_EXSTYLE},
5726 {WM_WINDOWPOSCHANGING, FALSE, 0},
5727 {WM_GETMINMAXINFO, FALSE, 0},
5728 {WM_NCCALCSIZE, FALSE, 0},
5729 {WM_WINDOWPOSCHANGED, FALSE, 0},
5730 {WM_MOVE, FALSE, 0},
5731 {WM_SIZE, FALSE, 0},
5732 {0, FALSE, 0},
5734 static const struct message enter_fullscreen_messages_vista[] =
5736 {WM_STYLECHANGING, TRUE, GWL_STYLE},
5737 {WM_STYLECHANGED, TRUE, GWL_STYLE},
5738 {WM_WINDOWPOSCHANGING, FALSE, 0},
5739 {WM_NCCALCSIZE, FALSE, 0},
5740 {WM_WINDOWPOSCHANGED, FALSE, 0},
5741 {WM_MOVE, FALSE, 0},
5742 {WM_SIZE, FALSE, 0},
5743 {WM_STYLECHANGING, TRUE, GWL_EXSTYLE},
5744 {WM_STYLECHANGED, TRUE, GWL_EXSTYLE},
5745 {WM_WINDOWPOSCHANGING, FALSE, 0},
5746 {WM_GETMINMAXINFO, FALSE, 0},
5747 {WM_NCCALCSIZE, FALSE, 0},
5748 {WM_WINDOWPOSCHANGED, FALSE, 0},
5749 {WM_SIZE, FALSE, 0},
5750 {0, FALSE, 0},
5752 static const struct message leave_fullscreen_messages[] =
5754 {WM_STYLECHANGING, TRUE, GWL_STYLE},
5755 {WM_STYLECHANGED, TRUE, GWL_STYLE},
5756 {WM_STYLECHANGING, TRUE, GWL_EXSTYLE},
5757 {WM_STYLECHANGED, TRUE, GWL_EXSTYLE},
5758 {WM_WINDOWPOSCHANGING, FALSE, 0},
5759 {WM_GETMINMAXINFO, FALSE, 0},
5760 {WM_NCCALCSIZE, FALSE, 0},
5761 {WM_WINDOWPOSCHANGED, FALSE, 0},
5762 {WM_MOVE, FALSE, 0},
5763 {WM_SIZE, FALSE, 0},
5764 {0, FALSE, 0},
5766 static const struct message resize_target_messages[] =
5768 {WM_WINDOWPOSCHANGING, FALSE, 0},
5769 {WM_GETMINMAXINFO, FALSE, 0},
5770 {WM_NCCALCSIZE, FALSE, 0},
5771 {WM_WINDOWPOSCHANGED, FALSE, 0},
5772 {WM_SIZE, FALSE, 0},
5773 {0, FALSE, 0},
5776 if (!(device = create_device(0)))
5778 skip("Failed to create device.\n");
5779 return;
5782 memset(&wc, 0, sizeof(wc));
5783 wc.lpfnWndProc = test_wndproc;
5784 wc.lpszClassName = "dxgi_test_wndproc_wc";
5785 ok(RegisterClassA(&wc), "Failed to register window class.\n");
5786 window = CreateWindowA("dxgi_test_wndproc_wc", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
5787 ok(!!window, "Failed to create window.\n");
5789 hr = IDXGIDevice_GetAdapter(device, &adapter);
5790 ok(hr == S_OK, "Failed to get adapter, hr %#x.\n", hr);
5791 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
5792 ok(hr == S_OK, "Failed to get parent, hr %#x.\n", hr);
5793 IDXGIAdapter_Release(adapter);
5795 swapchain_desc.BufferDesc.Width = 800;
5796 swapchain_desc.BufferDesc.Height = 600;
5797 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
5798 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
5799 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
5800 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
5801 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
5802 swapchain_desc.SampleDesc.Count = 1;
5803 swapchain_desc.SampleDesc.Quality = 0;
5804 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5805 swapchain_desc.BufferCount = 1;
5806 swapchain_desc.OutputWindow = window;
5807 swapchain_desc.Windowed = TRUE;
5808 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
5809 swapchain_desc.Flags = 0;
5811 /* create swapchain */
5812 flush_events();
5813 expect_no_messages = TRUE;
5814 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
5815 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
5816 flush_events();
5817 expect_no_messages = FALSE;
5819 /* resize target */
5820 expect_messages = resize_target_messages;
5821 memset(&mode_desc, 0, sizeof(mode_desc));
5822 mode_desc.Width = 800;
5823 mode_desc.Height = 600;
5824 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode_desc);
5825 ok(hr == S_OK, "Failed to resize target, hr %#x.\n", hr);
5826 flush_events();
5827 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
5829 expect_messages = resize_target_messages;
5830 memset(&mode_desc, 0, sizeof(mode_desc));
5831 mode_desc.Width = 400;
5832 mode_desc.Height = 200;
5833 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode_desc);
5834 ok(hr == S_OK, "Failed to resize target, hr %#x.\n", hr);
5835 flush_events();
5836 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
5838 /* enter fullscreen */
5839 expect_messages = enter_fullscreen_messages;
5840 expect_messages_broken = enter_fullscreen_messages_vista;
5841 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
5842 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
5843 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
5844 "Failed to enter fullscreen, hr %#x.\n", hr);
5845 if (FAILED(hr))
5847 skip("Could not change fullscreen state.\n");
5848 goto done;
5850 flush_events();
5851 todo_wine
5852 ok(!expect_messages->message || broken(!expect_messages_broken->message),
5853 "Expected message %#x or %#x.\n",
5854 expect_messages->message, expect_messages_broken->message);
5855 expect_messages_broken = NULL;
5857 /* leave fullscreen */
5858 expect_messages = leave_fullscreen_messages;
5859 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
5860 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5861 flush_events();
5862 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
5863 expect_messages = NULL;
5865 refcount = IDXGISwapChain_Release(swapchain);
5866 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
5868 /* create fullscreen swapchain */
5869 DestroyWindow(window);
5870 window = CreateWindowA("dxgi_test_wndproc_wc", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
5871 ok(!!window, "Failed to create window.\n");
5872 swapchain_desc.OutputWindow = window;
5873 swapchain_desc.Windowed = FALSE;
5874 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
5875 flush_events();
5877 expect_messages = enter_fullscreen_messages;
5878 expect_messages_broken = enter_fullscreen_messages_vista;
5879 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
5880 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
5881 flush_events();
5882 todo_wine
5883 ok(!expect_messages->message || broken(!expect_messages_broken->message),
5884 "Expected message %#x or %#x.\n",
5885 expect_messages->message, expect_messages_broken->message);
5886 expect_messages_broken = NULL;
5888 /* leave fullscreen */
5889 expect_messages = leave_fullscreen_messages;
5890 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
5891 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
5892 flush_events();
5893 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
5894 expect_messages = NULL;
5896 done:
5897 refcount = IDXGISwapChain_Release(swapchain);
5898 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
5899 DestroyWindow(window);
5901 refcount = IDXGIDevice_Release(device);
5902 ok(!refcount, "Device has %u references left.\n", refcount);
5903 refcount = IDXGIFactory_Release(factory);
5904 ok(!refcount, "Factory has %u references left.\n", refcount);
5906 UnregisterClassA("dxgi_test_wndproc_wc", GetModuleHandleA(NULL));
5909 static void test_swapchain_window_styles(void)
5911 LONG style, exstyle, fullscreen_style, fullscreen_exstyle;
5912 DXGI_SWAP_CHAIN_DESC swapchain_desc;
5913 IDXGISwapChain *swapchain;
5914 IDXGIFactory *factory;
5915 IDXGIAdapter *adapter;
5916 IDXGIDevice *device;
5917 ULONG refcount;
5918 unsigned int i;
5919 HRESULT hr;
5921 static const struct
5923 LONG style, exstyle;
5924 LONG expected_style, expected_exstyle;
5926 tests[] =
5928 {WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0,
5929 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS,
5930 WS_EX_WINDOWEDGE},
5931 {WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE, 0,
5932 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | WS_VISIBLE,
5933 WS_EX_WINDOWEDGE},
5934 {WS_OVERLAPPED | WS_VISIBLE, 0,
5935 WS_OVERLAPPED | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION, WS_EX_WINDOWEDGE},
5936 {WS_OVERLAPPED | WS_MAXIMIZE, 0,
5937 WS_OVERLAPPED | WS_MAXIMIZE | WS_CLIPSIBLINGS | WS_CAPTION, WS_EX_WINDOWEDGE},
5938 {WS_OVERLAPPED | WS_MINIMIZE, 0,
5939 WS_OVERLAPPED | WS_MINIMIZE | WS_CLIPSIBLINGS | WS_CAPTION, WS_EX_WINDOWEDGE},
5940 {WS_CAPTION | WS_DISABLED, WS_EX_TOPMOST,
5941 WS_CAPTION | WS_DISABLED | WS_CLIPSIBLINGS, WS_EX_TOPMOST | WS_EX_WINDOWEDGE},
5942 {WS_CAPTION | WS_DISABLED | WS_VISIBLE, WS_EX_TOPMOST,
5943 WS_CAPTION | WS_DISABLED | WS_VISIBLE | WS_CLIPSIBLINGS, WS_EX_TOPMOST | WS_EX_WINDOWEDGE},
5944 {WS_CAPTION | WS_SYSMENU | WS_VISIBLE, WS_EX_APPWINDOW,
5945 WS_CAPTION | WS_SYSMENU | WS_VISIBLE | WS_CLIPSIBLINGS, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE},
5946 {WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER | WS_DLGFRAME
5947 | WS_VSCROLL | WS_HSCROLL | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
5949 WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER | WS_DLGFRAME
5950 | WS_VSCROLL | WS_HSCROLL | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
5951 WS_EX_WINDOWEDGE},
5954 if (!(device = create_device(0)))
5956 skip("Failed to create device.\n");
5957 return;
5960 hr = IDXGIDevice_GetAdapter(device, &adapter);
5961 ok(hr == S_OK, "Failed to get adapter, hr %#x.\n", hr);
5962 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
5963 ok(hr == S_OK, "Failed to get parent, hr %#x.\n", hr);
5964 IDXGIAdapter_Release(adapter);
5966 swapchain_desc.BufferDesc.Width = 800;
5967 swapchain_desc.BufferDesc.Height = 600;
5968 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
5969 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
5970 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
5971 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
5972 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
5973 swapchain_desc.SampleDesc.Count = 1;
5974 swapchain_desc.SampleDesc.Quality = 0;
5975 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5976 swapchain_desc.BufferCount = 1;
5977 swapchain_desc.Windowed = TRUE;
5978 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
5979 swapchain_desc.Flags = 0;
5981 for (i = 0; i < ARRAY_SIZE(tests); ++i)
5983 swapchain_desc.OutputWindow = CreateWindowExA(tests[i].exstyle, "static", "dxgi_test",
5984 tests[i].style, 0, 0, 400, 200, 0, 0, 0, 0);
5986 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
5987 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
5988 ok(style == tests[i].expected_style, "Test %u: Got style %#x, expected %#x.\n",
5989 i, style, tests[i].expected_style);
5990 ok(exstyle == tests[i].expected_exstyle, "Test %u: Got exstyle %#x, expected %#x.\n",
5991 i, exstyle, tests[i].expected_exstyle);
5993 fullscreen_style = tests[i].expected_style & ~(WS_POPUP | WS_MAXIMIZEBOX
5994 | WS_MINIMIZEBOX | WS_THICKFRAME | WS_SYSMENU | WS_DLGFRAME | WS_BORDER);
5995 fullscreen_exstyle = tests[i].expected_exstyle & ~(WS_EX_DLGMODALFRAME
5996 | WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_CONTEXTHELP);
5997 fullscreen_exstyle |= WS_EX_TOPMOST;
5999 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
6000 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
6002 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6003 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6004 ok(style == tests[i].expected_style, "Test %u: Got style %#x, expected %#x.\n",
6005 i, style, tests[i].expected_style);
6006 ok(exstyle == tests[i].expected_exstyle, "Test %u: Got exstyle %#x, expected %#x.\n",
6007 i, exstyle, tests[i].expected_exstyle);
6009 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6010 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6011 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6012 "Failed to set fullscreen state, hr %#x.\n", hr);
6013 if (SUCCEEDED(hr))
6015 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6016 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6017 todo_wine
6018 ok(style == fullscreen_style, "Test %u: Got style %#x, expected %#x.\n",
6019 i, style, fullscreen_style);
6020 ok(exstyle == fullscreen_exstyle, "Test %u: Got exstyle %#x, expected %#x.\n",
6021 i, exstyle, fullscreen_exstyle);
6023 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6024 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6026 else
6028 skip("Test %u: Could not change fullscreen state.\n", i);
6031 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6032 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6033 ok(style == tests[i].expected_style, "Test %u: Got style %#x, expected %#x.\n",
6034 i, style, tests[i].expected_style);
6035 ok(exstyle == tests[i].expected_exstyle, "Test %u: Got exstyle %#x, expected %#x.\n",
6036 i, exstyle, tests[i].expected_exstyle);
6038 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6039 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6040 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6041 "Failed to set fullscreen state, hr %#x.\n", hr);
6042 if (SUCCEEDED(hr))
6044 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6045 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6046 todo_wine
6047 ok(style == fullscreen_style, "Test %u: Got style %#x, expected %#x.\n",
6048 i, style, fullscreen_style);
6049 ok(exstyle == fullscreen_exstyle, "Test %u: Got exstyle %#x, expected %#x.\n",
6050 i, exstyle, fullscreen_exstyle);
6052 SetWindowLongW(swapchain_desc.OutputWindow, GWL_STYLE, fullscreen_style);
6053 SetWindowLongW(swapchain_desc.OutputWindow, GWL_EXSTYLE, fullscreen_exstyle);
6055 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6056 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6058 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6059 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6060 todo_wine
6061 ok(style == tests[i].expected_style, "Test %u: Got style %#x, expected %#x.\n",
6062 i, style, tests[i].expected_style);
6063 todo_wine
6064 ok(exstyle == tests[i].expected_exstyle, "Test %u: Got exstyle %#x, expected %#x.\n",
6065 i, exstyle, tests[i].expected_exstyle);
6067 else
6069 skip("Test %u: Could not change fullscreen state.\n", i);
6072 refcount = IDXGISwapChain_Release(swapchain);
6073 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
6075 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6076 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6077 todo_wine
6078 ok(style == tests[i].expected_style, "Test %u: Got style %#x, expected %#x.\n",
6079 i, style, tests[i].expected_style);
6080 todo_wine
6081 ok(exstyle == tests[i].expected_exstyle, "Test %u: Got exstyle %#x, expected %#x.\n",
6082 i, exstyle, tests[i].expected_exstyle);
6084 DestroyWindow(swapchain_desc.OutputWindow);
6087 refcount = IDXGIDevice_Release(device);
6088 ok(!refcount, "Device has %u references left.\n", refcount);
6089 refcount = IDXGIFactory_Release(factory);
6090 ok(!refcount, "Factory has %u references left.\n", refcount);
6093 static void test_gamma_control(void)
6095 DXGI_GAMMA_CONTROL_CAPABILITIES caps;
6096 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6097 IDXGISwapChain *swapchain;
6098 DXGI_GAMMA_CONTROL gamma;
6099 IDXGIFactory *factory;
6100 IDXGIAdapter *adapter;
6101 IDXGIDevice *device;
6102 IDXGIOutput *output;
6103 unsigned int i;
6104 ULONG refcount;
6105 HRESULT hr;
6107 if (!(device = create_device(0)))
6109 skip("Failed to create device.\n");
6110 return;
6113 hr = IDXGIDevice_GetAdapter(device, &adapter);
6114 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6116 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
6117 if (hr == DXGI_ERROR_NOT_FOUND)
6119 skip("Adapter doesn't have any outputs.\n");
6120 IDXGIAdapter_Release(adapter);
6121 IDXGIDevice_Release(device);
6122 return;
6124 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6126 hr = IDXGIOutput_GetGammaControlCapabilities(output, &caps);
6127 todo_wine
6128 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6129 IDXGIOutput_Release(output);
6131 swapchain_desc.BufferDesc.Width = 640;
6132 swapchain_desc.BufferDesc.Height = 480;
6133 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6134 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
6135 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6136 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6137 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6138 swapchain_desc.SampleDesc.Count = 1;
6139 swapchain_desc.SampleDesc.Quality = 0;
6140 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6141 swapchain_desc.BufferCount = 1;
6142 swapchain_desc.OutputWindow = create_window();
6143 swapchain_desc.Windowed = TRUE;
6144 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
6145 swapchain_desc.Flags = 0;
6147 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
6148 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6150 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
6151 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
6152 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6153 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6154 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6155 "Failed to enter fullscreen, hr %#x.\n", hr);
6156 if (FAILED(hr))
6158 skip("Could not change fullscreen state.\n");
6159 goto done;
6162 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
6163 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6165 memset(&caps, 0, sizeof(caps));
6166 hr = IDXGIOutput_GetGammaControlCapabilities(output, &caps);
6167 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6169 ok(caps.MaxConvertedValue > caps.MinConvertedValue
6170 || broken(caps.MaxConvertedValue == 0.0f && caps.MinConvertedValue == 1.0f) /* WARP */,
6171 "Expected max gamma value (%.8e) to be bigger than min value (%.8e).\n",
6172 caps.MaxConvertedValue, caps.MinConvertedValue);
6174 for (i = 1; i < caps.NumGammaControlPoints; ++i)
6176 ok(caps.ControlPointPositions[i] > caps.ControlPointPositions[i - 1],
6177 "Expected control point positions to be strictly monotonically increasing (%.8e > %.8e).\n",
6178 caps.ControlPointPositions[i], caps.ControlPointPositions[i - 1]);
6181 memset(&gamma, 0, sizeof(gamma));
6182 hr = IDXGIOutput_GetGammaControl(output, &gamma);
6183 todo_wine
6184 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6185 hr = IDXGIOutput_SetGammaControl(output, &gamma);
6186 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6188 IDXGIOutput_Release(output);
6190 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6191 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6193 done:
6194 refcount = IDXGISwapChain_Release(swapchain);
6195 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
6196 DestroyWindow(swapchain_desc.OutputWindow);
6198 IDXGIAdapter_Release(adapter);
6199 refcount = IDXGIDevice_Release(device);
6200 ok(!refcount, "Device has %u references left.\n", refcount);
6201 refcount = IDXGIFactory_Release(factory);
6202 ok(!refcount, "Factory has %u references left.\n", refcount);
6205 static void test_window_association(IUnknown *device, BOOL is_d3d12)
6207 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6208 LONG_PTR original_wndproc, wndproc;
6209 IDXGIFactory *factory, *factory2;
6210 IDXGISwapChain *swapchain;
6211 IDXGIOutput *output;
6212 HWND hwnd, hwnd2;
6213 BOOL fullscreen;
6214 unsigned int i;
6215 ULONG refcount;
6216 HRESULT hr;
6218 static const struct
6220 UINT flag;
6221 BOOL expect_fullscreen;
6222 BOOL broken_d3d10;
6224 tests[] =
6226 /* There are two reasons why VK_TAB and VK_ESC are not tested here:
6228 * - Posting them to the window doesn't exit fullscreen like
6229 * Alt+Enter does. Alt+Tab and Alt+Esc are handled somewhere else.
6230 * E.g., not calling IDXGISwapChain::Present() will break Alt+Tab
6231 * and Alt+Esc while Alt+Enter will still function.
6233 * - Posting them hangs the posting thread. Another thread that keeps
6234 * sending input is needed to avoid the hang. The hang is not
6235 * because of flush_events(). */
6236 {0, TRUE},
6237 {0, FALSE},
6238 {DXGI_MWA_NO_WINDOW_CHANGES, FALSE},
6239 {DXGI_MWA_NO_WINDOW_CHANGES, FALSE},
6240 {DXGI_MWA_NO_ALT_ENTER, FALSE, TRUE},
6241 {DXGI_MWA_NO_ALT_ENTER, FALSE},
6242 {DXGI_MWA_NO_PRINT_SCREEN, TRUE},
6243 {DXGI_MWA_NO_PRINT_SCREEN, FALSE},
6244 {0, TRUE},
6245 {0, FALSE}
6248 swapchain_desc.BufferDesc.Width = 640;
6249 swapchain_desc.BufferDesc.Height = 480;
6250 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6251 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
6252 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6253 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6254 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6255 swapchain_desc.SampleDesc.Count = 1;
6256 swapchain_desc.SampleDesc.Quality = 0;
6257 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6258 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
6259 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
6260 swapchain_desc.Windowed = TRUE;
6261 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
6262 swapchain_desc.Flags = 0;
6264 original_wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6266 hwnd2 = CreateWindowA("static", "dxgi_test2", 0, 0, 0, 400, 200, 0, 0, 0, 0);
6267 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory2);
6268 ok(hr == S_OK, "Failed to create DXGI factory, hr %#x.\n", hr);
6270 get_factory(device, is_d3d12, &factory);
6272 hr = IDXGIFactory_GetWindowAssociation(factory, NULL);
6273 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6275 for (i = 0; i <= DXGI_MWA_VALID; ++i)
6277 hr = IDXGIFactory_MakeWindowAssociation(factory, NULL, i);
6278 ok(hr == S_OK, "Got unexpected hr %#x for flags %#x.\n", hr, i);
6280 hr = IDXGIFactory_MakeWindowAssociation(factory, swapchain_desc.OutputWindow, i);
6281 ok(hr == S_OK, "Got unexpected hr %#x for flags %#x.\n", hr, i);
6283 wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6284 ok(wndproc == original_wndproc, "Got unexpected wndproc %#lx, expected %#lx for flags %#x.\n",
6285 wndproc, original_wndproc, i);
6287 hwnd = (HWND)0xdeadbeef;
6288 hr = IDXGIFactory_GetWindowAssociation(factory, &hwnd);
6289 ok(hr == S_OK, "Got unexpected hr %#x for flags %#x.\n", hr, i);
6290 /* Apparently GetWindowAssociation() always returns NULL, even when
6291 * MakeWindowAssociation() and GetWindowAssociation() are both
6292 * successfully called. */
6293 ok(!hwnd, "Expect null associated window.\n");
6296 hr = IDXGIFactory_MakeWindowAssociation(factory, swapchain_desc.OutputWindow, DXGI_MWA_VALID + 1);
6297 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6299 /* Alt+Enter tests. */
6300 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
6301 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6303 wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6304 ok(wndproc == original_wndproc, "Got unexpected wndproc %#lx, expected %#lx.\n", wndproc, original_wndproc);
6306 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6307 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6308 || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Windows 7 testbot */,
6309 "Got unexpected hr %#x.\n", hr);
6310 if (FAILED(hr))
6312 skip("Could not change fullscreen state.\n");
6314 else
6316 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6317 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6319 for (i = 0; i < ARRAY_SIZE(tests); ++i)
6321 /* First associate a window with the opposite flags. */
6322 hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd2, ~tests[i].flag & DXGI_MWA_VALID);
6323 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
6325 /* Associate the current test window. */
6326 hwnd = tests[i].flag ? swapchain_desc.OutputWindow : NULL;
6327 hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd, tests[i].flag);
6328 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
6330 /* Associating a new test window doesn't override the old window. */
6331 hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd2, ~tests[i].flag & DXGI_MWA_VALID);
6332 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
6334 /* Associations with a different factory don't affect the existing
6335 * association. */
6336 hr = IDXGIFactory_MakeWindowAssociation(factory2, hwnd, ~tests[i].flag & DXGI_MWA_VALID);
6337 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
6339 /* Post synthesized Alt + VK_RETURN WM_SYSKEYDOWN. */
6340 PostMessageA(swapchain_desc.OutputWindow, WM_SYSKEYDOWN, VK_RETURN,
6341 (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x20000001);
6342 flush_events();
6343 output = NULL;
6344 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
6345 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
6346 ok(fullscreen == tests[i].expect_fullscreen
6347 || broken(tests[i].broken_d3d10 && fullscreen),
6348 "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
6349 ok(fullscreen ? !!output : !output, "Test %u: Got wrong output.\n", i);
6350 if (output)
6351 IDXGIOutput_Release(output);
6353 wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6354 ok(wndproc == original_wndproc, "Test %u: Got unexpected wndproc %#lx, expected %#lx.\n",
6355 i, wndproc, original_wndproc);
6359 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6360 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6362 refcount = IDXGIFactory_Release(factory2);
6363 ok(!refcount, "Factory has %u references left.\n", refcount);
6364 DestroyWindow(hwnd2);
6366 refcount = IDXGISwapChain_Release(swapchain);
6367 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
6368 DestroyWindow(swapchain_desc.OutputWindow);
6370 refcount = IDXGIFactory_Release(factory);
6371 ok(refcount == !is_d3d12, "IDXGIFactory has %u references left.\n", refcount);
6374 static void test_output_ownership(IUnknown *device, BOOL is_d3d12)
6376 D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
6377 D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP check_ownership_desc;
6378 D3DKMT_CLOSEADAPTER close_adapter_desc;
6379 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6380 DXGI_OUTPUT_DESC output_desc;
6381 IDXGISwapChain *swapchain;
6382 IDXGIFactory *factory;
6383 IDXGIAdapter *adapter;
6384 IDXGIOutput *output;
6385 BOOL fullscreen;
6386 NTSTATUS status;
6387 ULONG refcount;
6388 HRESULT hr;
6390 if (!pD3DKMTCheckVidPnExclusiveOwnership
6391 || pD3DKMTCheckVidPnExclusiveOwnership(NULL) == STATUS_PROCEDURE_NOT_FOUND)
6393 win_skip("D3DKMTCheckVidPnExclusiveOwnership() is unavailable.\n");
6394 return;
6397 get_factory(device, is_d3d12, &factory);
6398 adapter = get_adapter(device, is_d3d12);
6399 if (!adapter)
6401 skip("Failed to get adapter on Direct3D %d.\n", is_d3d12 ? 12 : 10);
6402 IDXGIFactory_Release(factory);
6403 return;
6406 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
6407 IDXGIAdapter_Release(adapter);
6408 if (hr == DXGI_ERROR_NOT_FOUND)
6410 skip("Adapter doesn't have any outputs.\n");
6411 IDXGIFactory_Release(factory);
6412 return;
6414 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6416 hr = IDXGIOutput_GetDesc(output, &output_desc);
6417 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6419 lstrcpyW(open_adapter_gdi_desc.DeviceName, output_desc.DeviceName);
6420 status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc);
6421 ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
6423 check_ownership_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
6424 check_ownership_desc.VidPnSourceId = open_adapter_gdi_desc.VidPnSourceId;
6425 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6426 ok(status == STATUS_SUCCESS, "Got unexpected status %#x, expected %#x.\n", status,
6427 STATUS_SUCCESS);
6429 swapchain_desc.BufferDesc.Width = 800;
6430 swapchain_desc.BufferDesc.Height = 600;
6431 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6432 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
6433 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6434 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6435 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6436 swapchain_desc.SampleDesc.Count = 1;
6437 swapchain_desc.SampleDesc.Quality = 0;
6438 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6439 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
6440 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, NULL, NULL, NULL, NULL);
6441 swapchain_desc.Windowed = TRUE;
6442 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
6443 swapchain_desc.Flags = 0;
6444 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
6445 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6447 /* Swapchain in fullscreen mode. */
6448 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
6449 /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE on some machines.
6450 * DXGI_ERROR_UNSUPPORTED on the Windows 7 testbot. */
6451 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == DXGI_ERROR_UNSUPPORTED))
6453 skip("Failed to change fullscreen state.\n");
6454 goto done;
6456 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6457 fullscreen = FALSE;
6458 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
6459 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6460 ok(fullscreen, "Got unexpected fullscreen state.\n");
6461 /* Win10 1909 doesn't seem to grab output exclusive ownership.
6462 * And all output ownership calls return S_OK on D3D10 and D3D12 with 1909. */
6463 if (is_d3d12)
6465 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6466 ok(status == STATUS_SUCCESS, "Got unexpected status %#x, expected %#x.\n", status,
6467 STATUS_SUCCESS);
6469 else
6471 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc,
6472 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6473 todo_wine ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED ||
6474 broken(status == STATUS_SUCCESS), /* Win10 1909 */
6475 "Got unexpected status %#x, expected %#x.\n", status,
6476 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6478 hr = IDXGIOutput_TakeOwnership(output, NULL, FALSE);
6479 ok(hr == DXGI_ERROR_INVALID_CALL || broken(hr == S_OK), /* Win10 1909 */
6480 "Got unexpected hr %#x.\n", hr);
6481 hr = IDXGIOutput_TakeOwnership(output, NULL, TRUE);
6482 ok(hr == DXGI_ERROR_INVALID_CALL || broken(hr == S_OK), /* Win10 1909 */
6483 "Got unexpected hr %#x.\n", hr);
6484 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6485 if (is_d3d12)
6486 todo_wine ok(hr == E_NOINTERFACE || hr == S_OK, "Got unexpected hr %#x.\n", hr);
6487 else
6488 todo_wine ok(hr == E_INVALIDARG || broken(hr == S_OK), /* Win10 1909 */
6489 "Got unexpected hr %#x.\n", hr);
6490 hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
6491 ok(hr == E_NOINTERFACE || hr == S_OK, "Got unexpected hr %#x.\n", hr);
6492 IDXGIOutput_ReleaseOwnership(output);
6493 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6494 ok(status == STATUS_SUCCESS, "Got unexpected status %#x, expected %#x.\n", status,
6495 STATUS_SUCCESS);
6497 /* IDXGIOutput_TakeOwnership always returns E_NOINTERFACE for d3d12. Tests
6498 * finished. */
6499 if (is_d3d12)
6500 goto done;
6502 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6503 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == S_OK), /* Win10 1909 */
6504 "Got unexpected hr %#x.\n", hr);
6505 IDXGIOutput_ReleaseOwnership(output);
6507 hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
6508 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6509 /* Note that the "exclusive" parameter to IDXGIOutput_TakeOwnership()
6510 * seems to behave opposite to what's described by MSDN. */
6511 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc,
6512 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6513 ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED ||
6514 broken(status == STATUS_SUCCESS), /* Win10 1909 */
6515 "Got unexpected status %#x, expected %#x.\n", status, STATUS_GRAPHICS_PRESENT_OCCLUDED);
6516 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6517 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Win10 1909 */, "Got unexpected hr %#x.\n", hr);
6518 IDXGIOutput_ReleaseOwnership(output);
6520 /* Swapchain in windowed mode. */
6521 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6522 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6523 fullscreen = TRUE;
6524 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
6525 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6526 ok(!fullscreen, "Unexpected fullscreen state.\n");
6527 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6528 ok(status == STATUS_SUCCESS, "Got unexpected status %#x, expected %#x.\n", status,
6529 STATUS_SUCCESS);
6531 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6532 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == S_OK), /* Win10 1909 */
6533 "Got unexpected hr %#x.\n", hr);
6535 hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
6536 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6537 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc,
6538 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6539 ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED || broken(hr == S_OK), /* Win10 1909 */
6540 "Got unexpected status %#x, expected %#x.\n", status, STATUS_GRAPHICS_PRESENT_OCCLUDED);
6541 IDXGIOutput_ReleaseOwnership(output);
6542 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6543 ok(status == STATUS_SUCCESS, "Got unexpected status %#x, expected %#x.\n", status,
6544 STATUS_SUCCESS);
6546 done:
6547 IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6548 wait_device_idle(device);
6550 IDXGIOutput_Release(output);
6551 IDXGISwapChain_Release(swapchain);
6552 DestroyWindow(swapchain_desc.OutputWindow);
6553 refcount = IDXGIFactory_Release(factory);
6554 ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
6556 close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
6557 status = pD3DKMTCloseAdapter(&close_adapter_desc);
6558 ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
6561 static void test_cursor_clipping(IUnknown *device, BOOL is_d3d12)
6563 unsigned int adapter_idx, output_idx, mode_idx, mode_count;
6564 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6565 DXGI_OUTPUT_DESC output_desc;
6566 IDXGIAdapter *adapter = NULL;
6567 RECT virtual_rect, clip_rect;
6568 unsigned int width, height;
6569 IDXGISwapChain *swapchain;
6570 DXGI_MODE_DESC *modes;
6571 IDXGIFactory *factory;
6572 IDXGIOutput *output;
6573 ULONG refcount;
6574 HRESULT hr;
6576 get_factory(device, is_d3d12, &factory);
6578 swapchain_desc.SampleDesc.Count = 1;
6579 swapchain_desc.SampleDesc.Quality = 0;
6580 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6581 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
6582 swapchain_desc.Windowed = TRUE;
6583 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
6584 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
6586 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
6587 ++adapter_idx)
6589 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
6590 ++output_idx)
6592 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count,
6593 NULL);
6594 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Win 7 TestBots */
6595 "Adapter %u output %u: GetDisplayModeList failed, hr %#x.\n", adapter_idx,
6596 output_idx, hr);
6597 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
6599 win_skip("Adapter %u output %u: GetDisplayModeList() not supported.\n", adapter_idx,
6600 output_idx);
6601 IDXGIOutput_Release(output);
6602 continue;
6605 modes = heap_calloc(mode_count, sizeof(*modes));
6606 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count,
6607 modes);
6608 ok(hr == S_OK, "Adapter %u output %u: GetDisplayModeList failed, hr %#x.\n",
6609 adapter_idx, output_idx, hr);
6611 hr = IDXGIOutput_GetDesc(output, &output_desc);
6612 ok(hr == S_OK, "Adapter %u output %u: GetDesc failed, hr %#x.\n", adapter_idx,
6613 output_idx, hr);
6614 width = output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left;
6615 height = output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top;
6616 for (mode_idx = 0; mode_idx < mode_count; ++mode_idx)
6618 if (modes[mode_idx].Width != width && modes[mode_idx].Height != height)
6619 break;
6621 ok(modes[mode_idx].Width != width && modes[mode_idx].Height != height,
6622 "Adapter %u output %u: Failed to find a different mode than %ux%u.\n",
6623 adapter_idx, output_idx, width, height);
6625 ok(ClipCursor(NULL), "Adapter %u output %u: ClipCursor failed, error %#x.\n",
6626 adapter_idx, output_idx, GetLastError());
6627 get_virtual_rect(&virtual_rect);
6628 ok(GetClipCursor(&clip_rect),
6629 "Adapter %u output %u: GetClipCursor failed, error %#x.\n", adapter_idx,
6630 output_idx, GetLastError());
6631 ok(EqualRect(&clip_rect, &virtual_rect),
6632 "Adapter %u output %u: Expect clip rect %s, got %s.\n", adapter_idx, output_idx,
6633 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6635 swapchain_desc.BufferDesc.Width = modes[mode_idx].Width;
6636 swapchain_desc.BufferDesc.Height = modes[mode_idx].Height;
6637 swapchain_desc.BufferDesc.RefreshRate = modes[mode_idx].RefreshRate;
6638 swapchain_desc.BufferDesc.Format = modes[mode_idx].Format;
6639 swapchain_desc.BufferDesc.ScanlineOrdering = modes[mode_idx].ScanlineOrdering;
6640 swapchain_desc.BufferDesc.Scaling = modes[mode_idx].Scaling;
6641 swapchain_desc.OutputWindow = create_window();
6642 heap_free(modes);
6643 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc,
6644 &swapchain);
6645 ok(hr == S_OK, "Adapter %u output %u: CreateSwapChain failed, hr %#x.\n",
6646 adapter_idx, output_idx, hr);
6648 flush_events();
6649 get_virtual_rect(&virtual_rect);
6650 ok(GetClipCursor(&clip_rect),
6651 "Adapter %u output %u: GetClipCursor failed, error %#x.\n", adapter_idx,
6652 output_idx, GetLastError());
6653 ok(EqualRect(&clip_rect, &virtual_rect),
6654 "Adapter %u output %u: Expect clip rect %s, got %s.\n", adapter_idx, output_idx,
6655 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6657 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6658 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE ||
6659 broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6660 "Adapter %u output %u: SetFullscreenState failed, hr %#x.\n", adapter_idx,
6661 output_idx, hr);
6662 if (FAILED(hr))
6664 skip("Adapter %u output %u: Could not change fullscreen state, hr %#x.\n",
6665 adapter_idx, output_idx, hr);
6666 IDXGISwapChain_Release(swapchain);
6667 IDXGIOutput_Release(output);
6668 DestroyWindow(swapchain_desc.OutputWindow);
6669 continue;
6672 flush_events();
6673 get_virtual_rect(&virtual_rect);
6674 ok(GetClipCursor(&clip_rect),
6675 "Adapter %u output %u: GetClipCursor failed, error %#x.\n", adapter_idx,
6676 output_idx, GetLastError());
6677 ok(EqualRect(&clip_rect, &virtual_rect),
6678 "Adapter %u output %u: Expect clip rect %s, got %s.\n", adapter_idx, output_idx,
6679 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6681 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6682 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#x.\n", adapter_idx,
6683 output_idx, hr);
6684 refcount = IDXGISwapChain_Release(swapchain);
6685 ok(!refcount, "Adapter %u output %u: IDXGISwapChain has %u references left.\n",
6686 adapter_idx, output_idx, refcount);
6687 refcount = IDXGIOutput_Release(output);
6688 ok(!refcount, "Adapter %u output %u: IDXGIOutput has %u references left.\n",
6689 adapter_idx, output_idx, refcount);
6690 DestroyWindow(swapchain_desc.OutputWindow);
6692 flush_events();
6693 get_virtual_rect(&virtual_rect);
6694 ok(GetClipCursor(&clip_rect),
6695 "Adapter %u output %u: GetClipCursor failed, error %#x.\n", adapter_idx,
6696 output_idx, GetLastError());
6697 ok(EqualRect(&clip_rect, &virtual_rect),
6698 "Adapter %u output %u: Expect clip rect %s, got %s.\n", adapter_idx, output_idx,
6699 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6702 IDXGIAdapter_Release(adapter);
6705 refcount = IDXGIFactory_Release(factory);
6706 ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
6709 static void test_factory_check_feature_support(void)
6711 IDXGIFactory5 *factory;
6712 ULONG ref_count;
6713 HRESULT hr;
6714 BOOL data;
6716 if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory5, (void**)&factory)))
6718 win_skip("IDXGIFactory5 is not available.\n");
6719 return;
6722 hr = IDXGIFactory5_CheckFeatureSupport(factory, 0x12345678, (void *)&data, sizeof(data));
6723 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6725 /* Crashes on Windows. */
6726 if (0)
6728 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, NULL, sizeof(data));
6729 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6732 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &data, sizeof(data) - 1);
6733 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6735 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &data, sizeof(data) + 1);
6736 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6738 data = (BOOL)0xdeadbeef;
6739 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &data, sizeof(data));
6740 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6741 ok(data == TRUE || data == FALSE, "Got unexpected data %#x.\n", data);
6743 ref_count = IDXGIFactory5_Release(factory);
6744 ok(!ref_count, "Factory has %u references left.\n", ref_count);
6747 static void test_frame_latency_event(IUnknown *device, BOOL is_d3d12)
6749 DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
6750 IDXGISwapChain2 *swapchain2;
6751 IDXGISwapChain1 *swapchain1;
6752 IDXGIFactory2 *factory2;
6753 IDXGIFactory *factory;
6754 UINT frame_latency;
6755 DWORD wait_result;
6756 ULONG ref_count;
6757 unsigned int i;
6758 HANDLE event;
6759 HWND window;
6760 HRESULT hr;
6762 get_factory(device, is_d3d12, &factory);
6764 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory2, (void**)&factory2);
6765 IDXGIFactory_Release(factory);
6766 if (FAILED(hr))
6768 win_skip("IDXGIFactory2 not available.\n");
6769 return;
6772 window = create_window();
6774 swapchain_desc.Width = 640;
6775 swapchain_desc.Height = 480;
6776 swapchain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6777 swapchain_desc.Stereo = FALSE;
6778 swapchain_desc.SampleDesc.Count = 1;
6779 swapchain_desc.SampleDesc.Quality = 0;
6780 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6781 swapchain_desc.BufferCount = 2;
6782 swapchain_desc.Scaling = DXGI_SCALING_STRETCH;
6783 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
6784 swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
6785 swapchain_desc.Flags = 0;
6787 hr = IDXGIFactory2_CreateSwapChainForHwnd(factory2, device,
6788 window, &swapchain_desc, NULL, NULL, &swapchain1);
6789 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6791 hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain2, (void**)&swapchain2);
6792 IDXGISwapChain1_Release(swapchain1);
6793 if (FAILED(hr))
6795 win_skip("IDXGISwapChain2 not available.\n");
6796 IDXGIFactory2_Release(factory2);
6797 DestroyWindow(window);
6798 return;
6801 /* test swap chain without waitable object */
6802 frame_latency = 0xdeadbeef;
6803 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6804 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6805 ok(frame_latency == 0xdeadbeef, "Got unexpected frame latency %#x.\n", frame_latency);
6806 hr = IDXGISwapChain2_SetMaximumFrameLatency(swapchain2, 1);
6807 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6808 event = IDXGISwapChain2_GetFrameLatencyWaitableObject(swapchain2);
6809 ok(!event, "Got unexpected event %p.\n", event);
6811 ref_count = IDXGISwapChain2_Release(swapchain2);
6812 ok(!ref_count, "Swap chain has %u references left.\n", ref_count);
6814 /* test swap chain with waitable object */
6815 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
6817 hr = IDXGIFactory2_CreateSwapChainForHwnd(factory2, device,
6818 window, &swapchain_desc, NULL, NULL, &swapchain1);
6819 ok(hr == S_OK, "Failed to create swap chain, hr %#x.\n", hr);
6820 hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain2, (void**)&swapchain2);
6821 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6822 IDXGISwapChain1_Release(swapchain1);
6824 event = IDXGISwapChain2_GetFrameLatencyWaitableObject(swapchain2);
6825 ok(!!event, "Got unexpected event %p.\n", event);
6827 /* auto-reset event */
6828 wait_result = WaitForSingleObject(event, 0);
6829 ok(!wait_result, "Got unexpected wait result %#x.\n", wait_result);
6830 wait_result = WaitForSingleObject(event, 0);
6831 ok(wait_result == WAIT_TIMEOUT, "Got unexpected wait result %#x.\n", wait_result);
6833 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6834 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6835 ok(frame_latency == 1, "Got unexpected frame latency %#x.\n", frame_latency);
6837 hr = IDXGISwapChain2_SetMaximumFrameLatency(swapchain2, 0);
6838 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
6839 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6840 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6841 ok(frame_latency == 1, "Got unexpected frame latency %#x.\n", frame_latency);
6843 hr = IDXGISwapChain2_SetMaximumFrameLatency(swapchain2, 2);
6844 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6845 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6846 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6847 ok(frame_latency == 2, "Got unexpected frame latency %#x.\n", frame_latency);
6849 for (i = 0; i < 5; i++)
6851 hr = IDXGISwapChain2_Present(swapchain2, 0, 0);
6852 ok(hr == S_OK, "Present %u failed with hr %#x.\n", i, hr);
6855 wait_result = WaitForSingleObject(event, 1000);
6856 ok(!wait_result, "Got unexpected wait result %#x.\n", wait_result);
6858 ref_count = IDXGISwapChain2_Release(swapchain2);
6859 ok(!ref_count, "Swap chain has %u references left.\n", ref_count);
6860 DestroyWindow(window);
6861 ref_count = IDXGIFactory2_Release(factory2);
6862 ok(ref_count == !is_d3d12, "Factory has %u references left.\n", ref_count);
6865 static void test_colour_space_support(IUnknown *device, BOOL is_d3d12)
6867 DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
6868 IDXGISwapChain3 *swapchain3;
6869 IDXGISwapChain1 *swapchain1;
6870 IDXGIFactory2 *factory2;
6871 IDXGIFactory *factory;
6872 ULONG ref_count;
6873 unsigned int i;
6874 UINT support;
6875 HWND window;
6876 HRESULT hr;
6878 static const DXGI_COLOR_SPACE_TYPE colour_spaces[] =
6880 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709,
6881 DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709,
6882 DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709,
6883 DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020,
6884 DXGI_COLOR_SPACE_RESERVED,
6885 DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601,
6886 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601,
6887 DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601,
6888 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709,
6889 DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709,
6890 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020,
6891 DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020,
6892 DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020,
6893 DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020,
6894 DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020,
6895 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020,
6896 DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020,
6897 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020,
6898 DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020,
6899 DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020,
6902 get_factory(device, is_d3d12, &factory);
6904 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory2, (void**)&factory2);
6905 IDXGIFactory_Release(factory);
6906 if (FAILED(hr))
6908 win_skip("IDXGIFactory2 not available.\n");
6909 return;
6912 window = create_window();
6914 swapchain_desc.Width = 640;
6915 swapchain_desc.Height = 480;
6916 swapchain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6917 swapchain_desc.Stereo = FALSE;
6918 swapchain_desc.SampleDesc.Count = 1;
6919 swapchain_desc.SampleDesc.Quality = 0;
6920 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6921 swapchain_desc.BufferCount = 2;
6922 swapchain_desc.Scaling = DXGI_SCALING_STRETCH;
6923 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
6924 swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
6925 swapchain_desc.Flags = 0;
6927 hr = IDXGIFactory2_CreateSwapChainForHwnd(factory2, device,
6928 window, &swapchain_desc, NULL, NULL, &swapchain1);
6929 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
6931 hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void**)&swapchain3);
6932 IDXGISwapChain1_Release(swapchain1);
6933 if (FAILED(hr))
6935 win_skip("IDXGISwapChain3 not available.\n");
6936 IDXGIFactory2_Release(factory2);
6937 DestroyWindow(window);
6938 return;
6941 for (i = 0; i < ARRAY_SIZE(colour_spaces); ++i)
6943 support = 0xdeadbeef;
6944 hr = IDXGISwapChain3_CheckColorSpaceSupport(swapchain3, colour_spaces[i], &support);
6945 ok(hr == S_OK, "Got unexpected hr %#x for test %u.\n", hr, i);
6946 ok(!(support & ~DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT),
6947 "Got unexpected support flags %#x for test %u.\n", support, i);
6949 if (colour_spaces[i] == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709)
6951 ok(support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT,
6952 "Required colour space not supported for test %u.\n", i);
6954 else if (colour_spaces[i] == DXGI_COLOR_SPACE_RESERVED)
6956 ok(!support, "Invalid colour space supported for test %u.\n", i);
6959 hr = IDXGISwapChain3_SetColorSpace1(swapchain3, colour_spaces[i]);
6960 ok(hr == (support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) ? S_OK : E_INVALIDARG,
6961 "Got unexpected hr %#x for text %u.\n", hr, i);
6964 ref_count = IDXGISwapChain3_Release(swapchain3);
6965 ok(!ref_count, "Swap chain has %u references left.\n", ref_count);
6966 DestroyWindow(window);
6967 ref_count = IDXGIFactory2_Release(factory2);
6968 ok(ref_count == !is_d3d12, "Factory has %u references left.\n", ref_count);
6971 static void test_mode_change(IUnknown *device, BOOL is_d3d12)
6973 unsigned int user32_width = 0, user32_height = 0, d3d_width = 0, d3d_height = 0;
6974 unsigned int display_count = 0, mode_idx = 0, adapter_idx, output_idx;
6975 DEVMODEW *original_modes = NULL, old_devmode, devmode, devmode2;
6976 DXGI_SWAP_CHAIN_DESC swapchain_desc, swapchain_desc2;
6977 IDXGIOutput *output, *second_output = NULL;
6978 WCHAR second_monitor_name[CCHDEVICENAME];
6979 IDXGISwapChain *swapchain, *swapchain2;
6980 DXGI_OUTPUT_DESC output_desc;
6981 IDXGIAdapter *adapter;
6982 IDXGIFactory *factory;
6983 BOOL fullscreen, ret;
6984 LONG change_ret;
6985 ULONG refcount;
6986 HRESULT hr;
6988 memset(&devmode, 0, sizeof(devmode));
6989 devmode.dmSize = sizeof(devmode);
6990 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
6991 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
6992 ok(equal_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
6993 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
6994 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
6995 ok(equal_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
6997 while (EnumDisplaySettingsW(NULL, mode_idx++, &devmode))
6999 if (devmode.dmPelsWidth == registry_mode.dmPelsWidth
7000 && devmode.dmPelsHeight == registry_mode.dmPelsHeight)
7001 continue;
7003 if (!d3d_width && !d3d_height)
7005 d3d_width = devmode.dmPelsWidth;
7006 d3d_height = devmode.dmPelsHeight;
7007 continue;
7010 if (devmode.dmPelsWidth == d3d_width && devmode.dmPelsHeight == d3d_height)
7011 continue;
7013 user32_width = devmode.dmPelsWidth;
7014 user32_height = devmode.dmPelsHeight;
7015 break;
7017 if (!user32_width || !user32_height)
7019 skip("Failed to find three different display modes for the primary output.\n");
7020 return;
7023 ret = save_display_modes(&original_modes, &display_count);
7024 ok(ret, "Failed to save original display modes.\n");
7026 get_factory(device, is_d3d12, &factory);
7028 /* Test that no mode restorations if no mode changes actually happened */
7029 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
7030 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
7032 swapchain_desc.BufferDesc.Width = registry_mode.dmPelsWidth;
7033 swapchain_desc.BufferDesc.Height = registry_mode.dmPelsHeight;
7034 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
7035 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
7036 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
7037 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
7038 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
7039 swapchain_desc.SampleDesc.Count = 1;
7040 swapchain_desc.SampleDesc.Quality = 0;
7041 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
7042 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
7043 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
7044 swapchain_desc.Windowed = TRUE;
7045 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
7046 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
7048 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7049 ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
7050 refcount = IDXGISwapChain_Release(swapchain);
7051 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7053 memset(&devmode2, 0, sizeof(devmode2));
7054 devmode2.dmSize = sizeof(devmode2);
7055 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
7056 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7057 ok(equal_mode_rect(&devmode2, &registry_mode), "Got a different mode.\n");
7058 ret = restore_display_modes(original_modes, display_count);
7059 ok(ret, "Failed to restore display modes.\n");
7061 /* If current display settings are different than the display settings in registry before
7062 * calling SetFullscreenState() */
7063 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
7064 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
7066 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7067 ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
7068 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7069 ok(hr == DXGI_ERROR_UNSUPPORTED /* Win7 */
7070 || hr == S_OK /* Win8~Win10 1909 */
7071 || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, /* Win10 2004 */
7072 "Got unexpected hr %#x.\n", hr);
7074 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7075 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
7076 refcount = IDXGISwapChain_Release(swapchain);
7077 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7078 ret = restore_display_modes(original_modes, display_count);
7079 ok(ret, "Failed to restore display modes.\n");
7081 /* Test that mode restorations use display settings in the registry with a fullscreen device */
7082 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7083 ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
7084 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7085 if (FAILED(hr))
7087 skip("SetFullscreenState failed, hr %#x.\n", hr);
7088 refcount = IDXGISwapChain_Release(swapchain);
7089 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7090 goto done;
7093 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
7094 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
7095 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7096 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
7098 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
7099 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7100 ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
7101 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
7102 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7103 ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
7104 refcount = IDXGISwapChain_Release(swapchain);
7105 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7106 ret = restore_display_modes(original_modes, display_count);
7107 ok(ret, "Failed to restore display modes.\n");
7109 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter)); ++adapter_idx)
7111 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output)); ++output_idx)
7113 hr = IDXGIOutput_GetDesc(output, &output_desc);
7114 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#x.\n", adapter_idx, output_idx, hr);
7116 if ((adapter_idx || output_idx) && output_desc.AttachedToDesktop)
7118 second_output = output;
7119 break;
7122 IDXGIOutput_Release(output);
7125 IDXGIAdapter_Release(adapter);
7126 if (second_output)
7127 break;
7130 if (!second_output)
7132 skip("Following tests require two monitors.\n");
7133 goto done;
7135 lstrcpyW(second_monitor_name, output_desc.DeviceName);
7137 memset(&old_devmode, 0, sizeof(old_devmode));
7138 old_devmode.dmSize = sizeof(old_devmode);
7139 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
7140 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7142 mode_idx = 0;
7143 d3d_width = 0;
7144 d3d_height = 0;
7145 user32_width = 0;
7146 user32_height = 0;
7147 while (EnumDisplaySettingsW(second_monitor_name, mode_idx++, &devmode))
7149 if (devmode.dmPelsWidth == old_devmode.dmPelsWidth
7150 && devmode.dmPelsHeight == old_devmode.dmPelsHeight)
7151 continue;
7153 if (!d3d_width && !d3d_height)
7155 d3d_width = devmode.dmPelsWidth;
7156 d3d_height = devmode.dmPelsHeight;
7157 continue;
7160 if (devmode.dmPelsWidth == d3d_width && devmode.dmPelsHeight == d3d_height)
7161 continue;
7163 user32_width = devmode.dmPelsWidth;
7164 user32_height = devmode.dmPelsHeight;
7165 break;
7167 if (!user32_width || !user32_height)
7169 skip("Failed to find three different display modes for the second output.\n");
7170 goto done;
7173 /* Test that mode restorations for non-primary outputs upon fullscreen state changes */
7174 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7175 ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
7176 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7177 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
7179 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
7180 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
7181 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7182 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7183 if (devmode2.dmPelsWidth == old_devmode.dmPelsWidth
7184 && devmode2.dmPelsHeight == old_devmode.dmPelsHeight)
7186 skip("Failed to change display settings of the second monitor.\n");
7187 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7188 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
7189 refcount = IDXGISwapChain_Release(swapchain);
7190 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7191 goto done;
7194 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7195 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
7197 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7198 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7199 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7200 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
7201 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7202 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7203 hr = IDXGIOutput_GetDesc(second_output, &output_desc);
7204 ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
7205 ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
7206 old_devmode.dmPelsWidth, "Expected width %u, got %u.\n", old_devmode.dmPelsWidth,
7207 output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
7208 ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
7209 old_devmode.dmPelsHeight, "Expected height %u, got %u.\n", old_devmode.dmPelsHeight,
7210 output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
7212 refcount = IDXGISwapChain_Release(swapchain);
7213 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7214 ret = restore_display_modes(original_modes, display_count);
7215 ok(ret, "Failed to restore display modes.\n");
7217 /* Test that mode restorations for non-primary outputs use display settings in the registry */
7218 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7219 ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
7220 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7221 ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
7223 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
7224 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
7225 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
7226 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7227 ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
7229 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7230 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7231 ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
7232 "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
7233 devmode2.dmPelsWidth, devmode2.dmPelsHeight);
7234 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
7235 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7236 ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
7237 "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
7238 devmode2.dmPelsWidth, devmode2.dmPelsHeight);
7239 hr = IDXGIOutput_GetDesc(second_output, &output_desc);
7240 ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
7241 ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
7242 devmode.dmPelsWidth, "Expected width %u, got %u.\n", devmode.dmPelsWidth,
7243 output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
7244 ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
7245 devmode.dmPelsHeight, "Expected height %u, got %u.\n", devmode.dmPelsHeight,
7246 output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
7248 refcount = IDXGISwapChain_Release(swapchain);
7249 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7250 ret = restore_display_modes(original_modes, display_count);
7251 ok(ret, "Failed to restore display modes.\n");
7253 /* Test that mode restorations for non-primary outputs on fullscreen state changes when there
7254 * are two fullscreen swapchains on different outputs */
7255 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7256 ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
7258 swapchain_desc2 = swapchain_desc;
7259 swapchain_desc.BufferDesc.Width = d3d_width;
7260 swapchain_desc.BufferDesc.Height = d3d_height;
7261 swapchain_desc2.OutputWindow = CreateWindowA("static", "dxgi_test2", 0,
7262 old_devmode.dmPosition.x, old_devmode.dmPosition.y, 400, 200, 0, 0, 0, 0);
7263 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc2, &swapchain2);
7264 ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
7265 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7266 ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
7267 hr = IDXGISwapChain_SetFullscreenState(swapchain2, TRUE, NULL);
7268 if (FAILED(hr))
7270 skip("SetFullscreenState failed, hr %#x.\n", hr);
7271 refcount = IDXGISwapChain_Release(swapchain2);
7272 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7273 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7274 ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
7275 refcount = IDXGISwapChain_Release(swapchain);
7276 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7277 goto done;
7280 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7281 ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
7282 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
7283 ok(hr == S_OK, "GetFullscreenState failed, hr %#x.\n", hr);
7284 ok(!fullscreen, "Expected swapchain not fullscreen.\n");
7285 hr = IDXGISwapChain_GetFullscreenState(swapchain2, &fullscreen, NULL);
7286 ok(hr == S_OK, "GetFullscreenState failed, hr %#x.\n", hr);
7287 ok(fullscreen, "Expected swapchain fullscreen.\n");
7289 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7290 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7291 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7292 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
7293 ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
7294 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7295 hr = IDXGIOutput_GetDesc(second_output, &output_desc);
7296 ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
7297 ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
7298 old_devmode.dmPelsWidth, "Expected width %u, got %u.\n", old_devmode.dmPelsWidth,
7299 output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
7300 ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
7301 old_devmode.dmPelsHeight, "Expected height %u, got %u.\n", old_devmode.dmPelsHeight,
7302 output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
7304 hr = IDXGISwapChain_SetFullscreenState(swapchain2, FALSE, NULL);
7305 ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
7306 refcount = IDXGISwapChain_Release(swapchain2);
7307 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7308 refcount = IDXGISwapChain_Release(swapchain);
7309 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
7310 DestroyWindow(swapchain_desc2.OutputWindow);
7311 ret = restore_display_modes(original_modes, display_count);
7312 ok(ret, "Failed to restore display modes.\n");
7314 done:
7315 if (second_output)
7316 IDXGIOutput_Release(second_output);
7317 DestroyWindow(swapchain_desc.OutputWindow);
7318 refcount = IDXGIFactory_Release(factory);
7319 ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
7320 ret = restore_display_modes(original_modes, display_count);
7321 ok(ret, "Failed to restore display modes.\n");
7322 heap_free(original_modes);
7325 static void run_on_d3d10(void (*test_func)(IUnknown *device, BOOL is_d3d12))
7327 IDXGIDevice *device;
7328 ULONG refcount;
7330 if (!(device = create_device(0)))
7332 skip("Failed to create Direct3D 10 device.\n");
7333 return;
7336 test_func((IUnknown *)device, FALSE);
7338 refcount = IDXGIDevice_Release(device);
7339 ok(!refcount, "Device has %u references left.\n", refcount);
7342 static void run_on_d3d12(void (*test_func)(IUnknown *device, BOOL is_d3d12))
7344 ID3D12CommandQueue *queue;
7345 ID3D12Device *device;
7346 ULONG refcount;
7348 if (!(device = create_d3d12_device()))
7350 skip("Failed to create Direct3D 12 device.\n");
7351 return;
7354 queue = create_d3d12_direct_queue(device);
7356 test_func((IUnknown *)queue, TRUE);
7358 wait_queue_idle(device, queue);
7360 refcount = ID3D12CommandQueue_Release(queue);
7361 ok(!refcount, "Command queue has %u references left.\n", refcount);
7362 refcount = ID3D12Device_Release(device);
7363 ok(!refcount, "Device has %u references left.\n", refcount);
7366 START_TEST(dxgi)
7368 HMODULE dxgi_module, d3d11_module, d3d12_module, gdi32_module;
7369 BOOL enable_debug_layer = FALSE;
7370 unsigned int argc, i;
7371 ID3D12Debug *debug;
7372 char **argv;
7374 dxgi_module = GetModuleHandleA("dxgi.dll");
7375 pCreateDXGIFactory1 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory1");
7376 pCreateDXGIFactory2 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory2");
7378 gdi32_module = GetModuleHandleA("gdi32.dll");
7379 pD3DKMTCheckVidPnExclusiveOwnership = (void *)GetProcAddress(gdi32_module, "D3DKMTCheckVidPnExclusiveOwnership");
7380 pD3DKMTCloseAdapter = (void *)GetProcAddress(gdi32_module, "D3DKMTCloseAdapter");
7381 pD3DKMTOpenAdapterFromGdiDisplayName = (void *)GetProcAddress(gdi32_module, "D3DKMTOpenAdapterFromGdiDisplayName");
7383 d3d11_module = LoadLibraryA("d3d11.dll");
7384 pD3D11CreateDevice = (void *)GetProcAddress(d3d11_module, "D3D11CreateDevice");
7386 registry_mode.dmSize = sizeof(registry_mode);
7387 ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &registry_mode), "Failed to get display mode.\n");
7389 use_mt = !getenv("WINETEST_NO_MT_D3D");
7391 argc = winetest_get_mainargs(&argv);
7392 for (i = 2; i < argc; ++i)
7394 if (!strcmp(argv[i], "--validate"))
7395 enable_debug_layer = TRUE;
7396 else if (!strcmp(argv[i], "--warp"))
7397 use_warp_adapter = TRUE;
7398 else if (!strcmp(argv[i], "--adapter") && i + 1 < argc)
7399 use_adapter_idx = atoi(argv[++i]);
7400 else if (!strcmp(argv[i], "--single"))
7401 use_mt = FALSE;
7404 queue_test(test_adapter_desc);
7405 queue_test(test_adapter_luid);
7406 queue_test(test_query_video_memory_info);
7407 queue_test(test_check_interface_support);
7408 queue_test(test_create_surface);
7409 queue_test(test_parents);
7410 queue_test(test_output);
7411 queue_test(test_find_closest_matching_mode);
7412 queue_test(test_resize_target_wndproc);
7413 queue_test(test_create_factory);
7414 queue_test(test_private_data);
7415 queue_test(test_maximum_frame_latency);
7416 queue_test(test_output_desc);
7417 queue_test(test_object_wrapping);
7418 queue_test(test_factory_check_feature_support);
7420 run_queued_tests();
7422 /* These tests use full-screen swapchains, so shouldn't run in parallel. */
7423 test_create_swapchain();
7424 test_inexact_modes();
7425 test_gamma_control();
7426 test_multi_adapter();
7427 test_swapchain_parameters();
7428 test_swapchain_window_messages();
7429 test_swapchain_window_styles();
7430 run_on_d3d10(test_set_fullscreen);
7431 run_on_d3d10(test_resize_target);
7432 run_on_d3d10(test_swapchain_resize);
7433 run_on_d3d10(test_swapchain_present);
7434 run_on_d3d10(test_swapchain_backbuffer_index);
7435 run_on_d3d10(test_swapchain_formats);
7436 run_on_d3d10(test_output_ownership);
7437 run_on_d3d10(test_cursor_clipping);
7438 run_on_d3d10(test_get_containing_output);
7439 run_on_d3d10(test_window_association);
7440 run_on_d3d10(test_default_fullscreen_target_output);
7441 run_on_d3d10(test_mode_change);
7443 if (!(d3d12_module = LoadLibraryA("d3d12.dll")))
7445 skip("Direct3D 12 is not available.\n");
7446 return;
7449 pD3D12CreateDevice = (void *)GetProcAddress(d3d12_module, "D3D12CreateDevice");
7450 pD3D12GetDebugInterface = (void *)GetProcAddress(d3d12_module, "D3D12GetDebugInterface");
7452 if (enable_debug_layer && SUCCEEDED(pD3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug)))
7454 ID3D12Debug_EnableDebugLayer(debug);
7455 ID3D12Debug_Release(debug);
7458 run_on_d3d12(test_set_fullscreen);
7459 run_on_d3d12(test_resize_target);
7460 run_on_d3d12(test_swapchain_resize);
7461 run_on_d3d12(test_swapchain_present);
7462 run_on_d3d12(test_swapchain_backbuffer_index);
7463 run_on_d3d12(test_swapchain_formats);
7464 run_on_d3d12(test_output_ownership);
7465 run_on_d3d12(test_cursor_clipping);
7466 run_on_d3d12(test_frame_latency_event);
7467 run_on_d3d12(test_colour_space_support);
7468 run_on_d3d12(test_get_containing_output);
7469 run_on_d3d12(test_window_association);
7470 run_on_d3d12(test_default_fullscreen_target_output);
7471 run_on_d3d12(test_mode_change);
7473 FreeLibrary(d3d12_module);