dxgi/tests: Accept DXGI_STATUS_OCCLUDED as result when creating fullscreen swapchains.
[wine.git] / dlls / dxgi / tests / dxgi.c
bloba199ba486ba80441aeecb1b7185681ca653a9035
1 /*
2 * Copyright 2008 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <assert.h>
20 #include "ntstatus.h"
21 #define WIN32_NO_STATUS
22 #define COBJMACROS
23 #include "initguid.h"
24 #include "dxgi1_6.h"
25 #include "d3d11.h"
26 #include "d3d12.h"
27 #include "d3d12sdklayers.h"
28 #include "winternl.h"
29 #include "ddk/d3dkmthk.h"
30 #include "wine/heap.h"
31 #include "wine/test.h"
33 enum frame_latency
35 DEFAULT_FRAME_LATENCY = 3,
36 MAX_FRAME_LATENCY = 16,
39 static DEVMODEW registry_mode;
41 static HRESULT (WINAPI *pCreateDXGIFactory1)(REFIID iid, void **factory);
42 static HRESULT (WINAPI *pCreateDXGIFactory2)(UINT flags, REFIID iid, void **factory);
44 static NTSTATUS (WINAPI *pD3DKMTCheckVidPnExclusiveOwnership)(const D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP *desc);
45 static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER *desc);
46 static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *desc);
48 static HRESULT (WINAPI *pD3D11CreateDevice)(IDXGIAdapter *adapter, D3D_DRIVER_TYPE driver_type, HMODULE swrast, UINT flags,
49 const D3D_FEATURE_LEVEL *feature_levels, UINT levels, UINT sdk_version, ID3D11Device **device_out,
50 D3D_FEATURE_LEVEL *obtained_feature_level, ID3D11DeviceContext **immediate_context);
52 static PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice;
53 static PFN_D3D12_GET_DEBUG_INTERFACE pD3D12GetDebugInterface;
55 static unsigned int use_adapter_idx;
56 static BOOL use_warp_adapter;
57 static BOOL use_mt = TRUE;
59 static struct test_entry
61 void (*test)(void);
62 } *mt_tests;
63 size_t mt_tests_size, mt_test_count;
65 static void queue_test(void (*test)(void))
67 if (mt_test_count >= mt_tests_size)
69 mt_tests_size = max(16, mt_tests_size * 2);
70 mt_tests = heap_realloc(mt_tests, mt_tests_size * sizeof(*mt_tests));
72 mt_tests[mt_test_count++].test = test;
75 static DWORD WINAPI thread_func(void *ctx)
77 LONG *i = ctx, j;
79 while (*i < mt_test_count)
81 j = *i;
82 if (InterlockedCompareExchange(i, j + 1, j) == j)
83 mt_tests[j].test();
86 return 0;
89 static void run_queued_tests(void)
91 unsigned int thread_count, i;
92 HANDLE *threads;
93 SYSTEM_INFO si;
94 LONG test_idx;
96 if (!use_mt)
98 for (i = 0; i < mt_test_count; ++i)
100 mt_tests[i].test();
103 return;
106 GetSystemInfo(&si);
107 thread_count = si.dwNumberOfProcessors;
108 threads = heap_calloc(thread_count, sizeof(*threads));
109 for (i = 0, test_idx = 0; i < thread_count; ++i)
111 threads[i] = CreateThread(NULL, 0, thread_func, &test_idx, 0, NULL);
112 ok(!!threads[i], "Failed to create thread %u.\n", i);
114 WaitForMultipleObjects(thread_count, threads, TRUE, INFINITE);
115 for (i = 0; i < thread_count; ++i)
117 CloseHandle(threads[i]);
119 heap_free(threads);
122 static ULONG get_refcount(void *iface)
124 IUnknown *unknown = iface;
125 IUnknown_AddRef(unknown);
126 return IUnknown_Release(unknown);
129 static void get_virtual_rect(RECT *rect)
131 rect->left = GetSystemMetrics(SM_XVIRTUALSCREEN);
132 rect->top = GetSystemMetrics(SM_YVIRTUALSCREEN);
133 rect->right = rect->left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
134 rect->bottom = rect->top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
137 static BOOL equal_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
139 return mode1->dmPosition.x == mode2->dmPosition.x
140 && mode1->dmPosition.y == mode2->dmPosition.y
141 && mode1->dmPelsWidth == mode2->dmPelsWidth
142 && mode1->dmPelsHeight == mode2->dmPelsHeight;
145 /* Free original_modes after finished using it */
146 static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
148 unsigned int number, size = 2, count = 0, index = 0;
149 DISPLAY_DEVICEW display_device;
150 DEVMODEW *modes, *tmp;
152 if (!(modes = heap_alloc(size * sizeof(*modes))))
153 return FALSE;
155 display_device.cb = sizeof(display_device);
156 while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
158 /* Skip software devices */
159 if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
160 continue;
162 if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
163 continue;
165 if (count >= size)
167 size *= 2;
168 if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
170 heap_free(modes);
171 return FALSE;
173 modes = tmp;
176 memset(&modes[count], 0, sizeof(modes[count]));
177 modes[count].dmSize = sizeof(modes[count]);
178 if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
180 heap_free(modes);
181 return FALSE;
184 lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
187 *original_modes = modes;
188 *display_count = count;
189 return TRUE;
192 static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
194 unsigned int index;
195 LONG ret;
197 for (index = 0; index < count; ++index)
199 ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
200 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
201 if (ret != DISP_CHANGE_SUCCESSFUL)
202 return FALSE;
204 ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
205 return ret == DISP_CHANGE_SUCCESSFUL;
208 /* try to make sure pending X events have been processed before continuing */
209 static void flush_events(void)
211 int diff = 200;
212 DWORD time;
213 MSG msg;
215 time = GetTickCount() + diff;
216 while (diff > 0)
218 if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT)
219 break;
220 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
221 DispatchMessageA(&msg);
222 diff = time - GetTickCount();
226 #define check_interface(a, b, c, d) check_interface_(__LINE__, a, b, c, d)
227 static HRESULT check_interface_(unsigned int line, void *iface, REFIID iid,
228 BOOL supported, BOOL is_broken)
230 HRESULT hr, expected_hr, broken_hr;
231 IUnknown *unknown = iface, *out;
233 if (supported)
235 expected_hr = S_OK;
236 broken_hr = E_NOINTERFACE;
238 else
240 expected_hr = E_NOINTERFACE;
241 broken_hr = S_OK;
244 out = (IUnknown *)0xdeadbeef;
245 hr = IUnknown_QueryInterface(unknown, iid, (void **)&out);
246 ok_(__FILE__, line)(hr == expected_hr || broken(is_broken && hr == broken_hr),
247 "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
248 if (SUCCEEDED(hr))
249 IUnknown_Release(out);
250 else
251 ok_(__FILE__, line)(!out, "Got unexpected pointer %p.\n", out);
252 return hr;
255 static BOOL is_flip_model(DXGI_SWAP_EFFECT swap_effect)
257 return swap_effect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
258 || swap_effect == DXGI_SWAP_EFFECT_FLIP_DISCARD;
261 static unsigned int check_multisample_quality_levels(IDXGIDevice *dxgi_device,
262 DXGI_FORMAT format, unsigned int sample_count)
264 ID3D10Device *device;
265 unsigned int levels;
266 HRESULT hr;
268 hr = IDXGIDevice_QueryInterface(dxgi_device, &IID_ID3D10Device, (void **)&device);
269 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
270 hr = ID3D10Device_CheckMultisampleQualityLevels(device, format, sample_count, &levels);
271 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
272 ID3D10Device_Release(device);
274 return levels;
277 #define MODE_DESC_IGNORE_RESOLUTION 0x00000001u
278 #define MODE_DESC_IGNORE_REFRESH_RATE 0x00000002u
279 #define MODE_DESC_IGNORE_FORMAT 0x00000004u
280 #define MODE_DESC_IGNORE_SCANLINE_ORDERING 0x00000008u
281 #define MODE_DESC_IGNORE_SCALING 0x00000010u
282 #define MODE_DESC_IGNORE_EXACT_RESOLUTION 0x00000020u
284 #define MODE_DESC_CHECK_RESOLUTION (~MODE_DESC_IGNORE_RESOLUTION & ~MODE_DESC_IGNORE_EXACT_RESOLUTION)
285 #define MODE_DESC_CHECK_FORMAT (~MODE_DESC_IGNORE_FORMAT)
287 #define check_mode_desc(a, b, c) check_mode_desc_(__LINE__, a, b, c)
288 static void check_mode_desc_(unsigned int line, const DXGI_MODE_DESC *desc,
289 const DXGI_MODE_DESC *expected_desc, unsigned int ignore_flags)
291 if (!(ignore_flags & MODE_DESC_IGNORE_RESOLUTION))
293 if (ignore_flags & MODE_DESC_IGNORE_EXACT_RESOLUTION)
294 ok_(__FILE__, line)(desc->Width * desc->Height ==
295 expected_desc->Width * expected_desc->Height,
296 "Got resolution %ux%u, expected %ux%u.\n",
297 desc->Width, desc->Height, expected_desc->Width, expected_desc->Height);
298 else
299 ok_(__FILE__, line)(desc->Width == expected_desc->Width &&
300 desc->Height == expected_desc->Height,
301 "Got resolution %ux%u, expected %ux%u.\n",
302 desc->Width, desc->Height, expected_desc->Width, expected_desc->Height);
304 if (!(ignore_flags & MODE_DESC_IGNORE_REFRESH_RATE))
306 ok_(__FILE__, line)(desc->RefreshRate.Numerator == expected_desc->RefreshRate.Numerator
307 && desc->RefreshRate.Denominator == expected_desc->RefreshRate.Denominator,
308 "Got refresh rate %u / %u, expected %u / %u.\n",
309 desc->RefreshRate.Numerator, desc->RefreshRate.Denominator,
310 expected_desc->RefreshRate.Denominator, expected_desc->RefreshRate.Denominator);
312 if (!(ignore_flags & MODE_DESC_IGNORE_FORMAT))
314 ok_(__FILE__, line)(desc->Format == expected_desc->Format,
315 "Got format %#x, expected %#x.\n", desc->Format, expected_desc->Format);
317 if (!(ignore_flags & MODE_DESC_IGNORE_SCANLINE_ORDERING))
319 ok_(__FILE__, line)(desc->ScanlineOrdering == expected_desc->ScanlineOrdering,
320 "Got scanline ordering %#x, expected %#x.\n",
321 desc->ScanlineOrdering, expected_desc->ScanlineOrdering);
323 if (!(ignore_flags & MODE_DESC_IGNORE_SCALING))
325 ok_(__FILE__, line)(desc->Scaling == expected_desc->Scaling,
326 "Got scaling %#x, expected %#x.\n",
327 desc->Scaling, expected_desc->Scaling);
331 static BOOL equal_luid(LUID a, LUID b)
333 return a.LowPart == b.LowPart && a.HighPart == b.HighPart;
336 #define check_adapter_desc(a, b) check_adapter_desc_(__LINE__, a, b)
337 static void check_adapter_desc_(unsigned int line, const DXGI_ADAPTER_DESC *desc,
338 const struct DXGI_ADAPTER_DESC *expected_desc)
340 ok_(__FILE__, line)(!lstrcmpW(desc->Description, expected_desc->Description),
341 "Got description %s, expected %s.\n",
342 wine_dbgstr_w(desc->Description), wine_dbgstr_w(expected_desc->Description));
343 ok_(__FILE__, line)(desc->VendorId == expected_desc->VendorId,
344 "Got vendor id %04x, expected %04x.\n",
345 desc->VendorId, expected_desc->VendorId);
346 ok_(__FILE__, line)(desc->DeviceId == expected_desc->DeviceId,
347 "Got device id %04x, expected %04x.\n",
348 desc->DeviceId, expected_desc->DeviceId);
349 ok_(__FILE__, line)(desc->SubSysId == expected_desc->SubSysId,
350 "Got subsys id %04x, expected %04x.\n",
351 desc->SubSysId, expected_desc->SubSysId);
352 ok_(__FILE__, line)(desc->Revision == expected_desc->Revision,
353 "Got revision %02x, expected %02x.\n",
354 desc->Revision, expected_desc->Revision);
355 ok_(__FILE__, line)(desc->DedicatedVideoMemory == expected_desc->DedicatedVideoMemory,
356 "Got dedicated video memory %Iu, expected %Iu.\n",
357 desc->DedicatedVideoMemory, expected_desc->DedicatedVideoMemory);
358 ok_(__FILE__, line)(desc->DedicatedSystemMemory == expected_desc->DedicatedSystemMemory,
359 "Got dedicated system memory %Iu, expected %Iu.\n",
360 desc->DedicatedSystemMemory, expected_desc->DedicatedSystemMemory);
361 ok_(__FILE__, line)(desc->SharedSystemMemory == expected_desc->SharedSystemMemory,
362 "Got shared system memory %Iu, expected %Iu.\n",
363 desc->SharedSystemMemory, expected_desc->SharedSystemMemory);
364 ok_(__FILE__, line)(equal_luid(desc->AdapterLuid, expected_desc->AdapterLuid),
365 "Got LUID %08lx:%08lx, expected %08lx:%08lx.\n",
366 desc->AdapterLuid.HighPart, desc->AdapterLuid.LowPart,
367 expected_desc->AdapterLuid.HighPart, expected_desc->AdapterLuid.LowPart);
370 #define check_output_desc(a, b) check_output_desc_(__LINE__, a, b)
371 static void check_output_desc_(unsigned int line, const DXGI_OUTPUT_DESC *desc,
372 const struct DXGI_OUTPUT_DESC *expected_desc)
374 ok_(__FILE__, line)(!lstrcmpW(desc->DeviceName, expected_desc->DeviceName),
375 "Got unexpected device name %s, expected %s.\n",
376 wine_dbgstr_w(desc->DeviceName), wine_dbgstr_w(expected_desc->DeviceName));
377 ok_(__FILE__, line)(EqualRect(&desc->DesktopCoordinates, &expected_desc->DesktopCoordinates),
378 "Got unexpected desktop coordinates %s, expected %s.\n",
379 wine_dbgstr_rect(&desc->DesktopCoordinates),
380 wine_dbgstr_rect(&expected_desc->DesktopCoordinates));
383 #define check_output_equal(a, b) check_output_equal_(__LINE__, a, b)
384 static void check_output_equal_(unsigned int line, IDXGIOutput *output1, IDXGIOutput *output2)
386 DXGI_OUTPUT_DESC desc1, desc2;
387 HRESULT hr;
389 hr = IDXGIOutput_GetDesc(output1, &desc1);
390 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
391 hr = IDXGIOutput_GetDesc(output2, &desc2);
392 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
393 check_output_desc_(line, &desc1, &desc2);
396 static BOOL output_belongs_to_adapter(IDXGIOutput *output, IDXGIAdapter *adapter)
398 DXGI_OUTPUT_DESC output_desc, desc;
399 unsigned int output_idx;
400 IDXGIOutput *o;
401 HRESULT hr;
403 hr = IDXGIOutput_GetDesc(output, &output_desc);
404 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
406 for (output_idx = 0; IDXGIAdapter_EnumOutputs(adapter, output_idx, &o) != DXGI_ERROR_NOT_FOUND; ++output_idx)
408 hr = IDXGIOutput_GetDesc(o, &desc);
409 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
410 IDXGIOutput_Release(o);
412 if (!lstrcmpW(desc.DeviceName, output_desc.DeviceName)
413 && EqualRect(&desc.DesktopCoordinates, &output_desc.DesktopCoordinates))
414 return TRUE;
417 return FALSE;
420 struct fullscreen_state
422 DWORD style;
423 DWORD exstyle;
424 RECT window_rect;
425 RECT client_rect;
426 HMONITOR monitor;
427 RECT monitor_rect;
430 struct swapchain_fullscreen_state
432 struct fullscreen_state fullscreen_state;
433 BOOL fullscreen;
434 IDXGIOutput *target;
437 #define capture_fullscreen_state(a, b) capture_fullscreen_state_(__LINE__, a, b)
438 static void capture_fullscreen_state_(unsigned int line, struct fullscreen_state *state, HWND window)
440 MONITORINFOEXW monitor_info;
441 BOOL ret;
443 state->style = GetWindowLongA(window, GWL_STYLE);
444 state->exstyle = GetWindowLongA(window, GWL_EXSTYLE);
446 ret = GetWindowRect(window, &state->window_rect);
447 ok_(__FILE__, line)(ret, "GetWindowRect failed.\n");
448 ret = GetClientRect(window, &state->client_rect);
449 ok_(__FILE__, line)(ret, "GetClientRect failed.\n");
451 state->monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
452 ok_(__FILE__, line)(!!state->monitor, "Failed to get monitor from window.\n");
454 monitor_info.cbSize = sizeof(monitor_info);
455 ret = GetMonitorInfoW(state->monitor, (MONITORINFO *)&monitor_info);
456 ok_(__FILE__, line)(ret, "Failed to get monitor info.\n");
457 state->monitor_rect = monitor_info.rcMonitor;
460 static void check_fullscreen_state_(unsigned int line, const struct fullscreen_state *state,
461 const struct fullscreen_state *expected_state, BOOL windowed)
463 todo_wine_if(!windowed)
464 ok_(__FILE__, line)((state->style & ~WS_VISIBLE) == (expected_state->style & ~WS_VISIBLE),
465 "Got style %#lx, expected %#lx.\n",
466 state->style & ~(DWORD)WS_VISIBLE, expected_state->style & ~(DWORD)WS_VISIBLE);
467 ok_(__FILE__, line)((state->exstyle & ~WS_EX_TOPMOST) == (expected_state->exstyle & ~WS_EX_TOPMOST),
468 "Got exstyle %#lx, expected %#lx.\n",
469 state->exstyle & ~(DWORD)WS_EX_TOPMOST, expected_state->exstyle & ~(DWORD)WS_EX_TOPMOST);
470 ok_(__FILE__, line)(EqualRect(&state->window_rect, &expected_state->window_rect),
471 "Got window rect %s, expected %s.\n",
472 wine_dbgstr_rect(&state->window_rect), wine_dbgstr_rect(&expected_state->window_rect));
473 ok_(__FILE__, line)(EqualRect(&state->client_rect, &expected_state->client_rect),
474 "Got client rect %s, expected %s.\n",
475 wine_dbgstr_rect(&state->client_rect), wine_dbgstr_rect(&expected_state->client_rect));
476 ok_(__FILE__, line)(state->monitor == expected_state->monitor,
477 "Got monitor %p, expected %p.\n",
478 state->monitor, expected_state->monitor);
479 ok_(__FILE__, line)(EqualRect(&state->monitor_rect, &expected_state->monitor_rect),
480 "Got monitor rect %s, expected %s.\n",
481 wine_dbgstr_rect(&state->monitor_rect), wine_dbgstr_rect(&expected_state->monitor_rect));
484 #define check_window_fullscreen_state(a, b) check_window_fullscreen_state_(__LINE__, a, b, TRUE)
485 static void check_window_fullscreen_state_(unsigned int line, HWND window,
486 const struct fullscreen_state *expected_state, BOOL windowed)
488 struct fullscreen_state current_state;
489 capture_fullscreen_state_(line, &current_state, window);
490 check_fullscreen_state_(line, &current_state, expected_state, windowed);
493 #define check_swapchain_fullscreen_state(a, b) check_swapchain_fullscreen_state_(__LINE__, a, b)
494 static void check_swapchain_fullscreen_state_(unsigned int line, IDXGISwapChain *swapchain,
495 const struct swapchain_fullscreen_state *expected_state)
497 IDXGIOutput *containing_output, *target;
498 DXGI_SWAP_CHAIN_DESC swapchain_desc;
499 BOOL fullscreen;
500 HRESULT hr;
502 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
503 ok_(__FILE__, line)(hr == S_OK, "Failed to get swapchain desc, hr %#lx.\n", hr);
504 check_window_fullscreen_state_(line, swapchain_desc.OutputWindow,
505 &expected_state->fullscreen_state, swapchain_desc.Windowed);
507 ok_(__FILE__, line)(swapchain_desc.Windowed == !expected_state->fullscreen,
508 "Got windowed %#x, expected %#x.\n",
509 swapchain_desc.Windowed, !expected_state->fullscreen);
511 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
512 ok_(__FILE__, line)(hr == S_OK, "Failed to get fullscreen state, hr %#lx.\n", hr);
513 ok_(__FILE__, line)(fullscreen == expected_state->fullscreen, "Got fullscreen %#x, expected %#x.\n",
514 fullscreen, expected_state->fullscreen);
516 if (!swapchain_desc.Windowed && expected_state->fullscreen)
518 IDXGIAdapter *adapter;
520 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
521 ok_(__FILE__, line)(hr == S_OK, "Failed to get containing output, hr %#lx.\n", hr);
523 hr = IDXGIOutput_GetParent(containing_output, &IID_IDXGIAdapter, (void **)&adapter);
524 ok_(__FILE__, line)(hr == S_OK, "Failed to get parent, hr %#lx.\n", hr);
526 check_output_equal_(line, target, expected_state->target);
527 ok_(__FILE__, line)(target == containing_output, "Got target %p, expected %p.\n",
528 target, containing_output);
529 ok_(__FILE__, line)(output_belongs_to_adapter(target, adapter),
530 "Output %p doesn't belong to adapter %p.\n",
531 target, adapter);
533 IDXGIOutput_Release(target);
534 IDXGIOutput_Release(containing_output);
535 IDXGIAdapter_Release(adapter);
537 else
539 ok_(__FILE__, line)(!target, "Got unexpected target %p.\n", target);
543 #define compute_expected_swapchain_fullscreen_state_after_fullscreen_change(a, b, c, d, e, f) \
544 compute_expected_swapchain_fullscreen_state_after_fullscreen_change_(__LINE__, a, b, c, d, e, f)
545 static void compute_expected_swapchain_fullscreen_state_after_fullscreen_change_(unsigned int line,
546 struct swapchain_fullscreen_state *state, const DXGI_SWAP_CHAIN_DESC *swapchain_desc,
547 const RECT *old_monitor_rect, unsigned int new_width, unsigned int new_height, IDXGIOutput *target)
549 if (!new_width && !new_height)
551 RECT client_rect;
552 GetClientRect(swapchain_desc->OutputWindow, &client_rect);
553 new_width = client_rect.right - client_rect.left;
554 new_height = client_rect.bottom - client_rect.top;
557 if (target)
559 DXGI_MODE_DESC mode_desc = swapchain_desc->BufferDesc;
560 HRESULT hr;
562 mode_desc.Width = new_width;
563 mode_desc.Height = new_height;
564 hr = IDXGIOutput_FindClosestMatchingMode(target, &mode_desc, &mode_desc, NULL);
565 ok_(__FILE__, line)(SUCCEEDED(hr), "FindClosestMatchingMode failed, hr %#lx.\n", hr);
566 new_width = mode_desc.Width;
567 new_height = mode_desc.Height;
570 state->fullscreen_state.style &= WS_VISIBLE | WS_CLIPSIBLINGS;
571 state->fullscreen_state.exstyle &= WS_EX_TOPMOST;
573 state->fullscreen = TRUE;
574 if (swapchain_desc->Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)
576 unsigned int new_x = (old_monitor_rect->left >= 0)
577 ? old_monitor_rect->left : old_monitor_rect->right - new_width;
578 unsigned new_y = (old_monitor_rect->top >= 0)
579 ? old_monitor_rect->top : old_monitor_rect->bottom - new_height;
580 RECT new_monitor_rect = {0, 0, new_width, new_height};
581 OffsetRect(&new_monitor_rect, new_x, new_y);
583 SetRect(&state->fullscreen_state.client_rect, 0, 0, new_width, new_height);
584 state->fullscreen_state.monitor_rect = new_monitor_rect;
585 state->fullscreen_state.window_rect = new_monitor_rect;
587 if (target)
588 state->target = target;
590 else
592 state->fullscreen_state.window_rect = *old_monitor_rect;
593 SetRect(&state->fullscreen_state.client_rect, 0, 0,
594 old_monitor_rect->right - old_monitor_rect->left,
595 old_monitor_rect->bottom - old_monitor_rect->top);
599 #define wait_fullscreen_state(a, b, c) wait_fullscreen_state_(__LINE__, a, b, c)
600 static void wait_fullscreen_state_(unsigned int line, IDXGISwapChain *swapchain, BOOL expected, BOOL todo)
602 static const unsigned int wait_timeout = 2000;
603 static const unsigned int wait_step = 100;
604 unsigned int total_time = 0;
605 HRESULT hr;
606 BOOL state;
608 while (total_time < wait_timeout)
610 state = !expected;
611 if (FAILED(hr = IDXGISwapChain_GetFullscreenState(swapchain, &state, NULL)))
612 break;
613 if (state == expected)
614 break;
615 Sleep(wait_step);
616 total_time += wait_step;
618 ok_(__FILE__, line)(hr == S_OK, "Failed to get fullscreen state, hr %#lx.\n", hr);
619 todo_wine_if(todo) ok_(__FILE__, line)(state == expected,
620 "Got unexpected state %#x, expected %#x.\n", state, expected);
623 /* VidPN exclusive ownership doesn't change immediately.
624 * This helper is used to wait for the expected status */
625 #define get_expected_vidpn_exclusive_ownership(a, b) \
626 get_expected_vidpn_exclusive_ownership_(__LINE__, a, b)
627 static NTSTATUS get_expected_vidpn_exclusive_ownership_(unsigned int line,
628 const D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP *desc, NTSTATUS expected)
630 static const unsigned int wait_timeout = 2000;
631 static const unsigned int wait_step = 100;
632 unsigned int total_time = 0;
633 NTSTATUS status;
635 while (total_time < wait_timeout)
637 status = pD3DKMTCheckVidPnExclusiveOwnership(desc);
638 if (status == expected)
639 break;
640 Sleep(wait_step);
641 total_time += wait_step;
643 return status;
646 static HWND create_window(void)
648 RECT r = {0, 0, 640, 480};
650 AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE);
652 return CreateWindowA("static", "dxgi_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
653 0, 0, r.right - r.left, r.bottom - r.top, NULL, NULL, NULL, NULL);
656 static IDXGIAdapter *create_adapter(void)
658 IDXGIFactory4 *factory4;
659 IDXGIFactory *factory;
660 IDXGIAdapter *adapter;
661 HRESULT hr;
663 if (!use_warp_adapter && !use_adapter_idx)
664 return NULL;
666 if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory)))
668 trace("Failed to create IDXGIFactory, hr %#lx.\n", hr);
669 return NULL;
672 adapter = NULL;
673 if (use_warp_adapter)
675 if (SUCCEEDED(hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void **)&factory4)))
677 hr = IDXGIFactory4_EnumWarpAdapter(factory4, &IID_IDXGIAdapter, (void **)&adapter);
678 IDXGIFactory4_Release(factory4);
680 else
682 trace("Failed to get IDXGIFactory4, hr %#lx.\n", hr);
685 else
687 hr = IDXGIFactory_EnumAdapters(factory, use_adapter_idx, &adapter);
689 IDXGIFactory_Release(factory);
690 if (FAILED(hr))
691 trace("Failed to get adapter, hr %#lx.\n", hr);
692 return adapter;
695 static IDXGIDevice *create_device(unsigned int flags)
697 IDXGIDevice *dxgi_device;
698 ID3D10Device1 *device;
699 IDXGIAdapter *adapter;
700 HRESULT hr;
702 adapter = create_adapter();
703 hr = D3D10CreateDevice1(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL,
704 flags, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device);
705 if (adapter)
706 IDXGIAdapter_Release(adapter);
707 if (SUCCEEDED(hr))
708 goto success;
710 if (SUCCEEDED(D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_WARP, NULL,
711 flags, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device)))
712 goto success;
713 if (SUCCEEDED(D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_REFERENCE, NULL,
714 flags, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device)))
715 goto success;
717 return NULL;
719 success:
720 hr = ID3D10Device1_QueryInterface(device, &IID_IDXGIDevice, (void **)&dxgi_device);
721 ok(SUCCEEDED(hr), "Created device does not implement IDXGIDevice\n");
722 ID3D10Device1_Release(device);
724 return dxgi_device;
727 static IDXGIDevice *create_d3d11_device(void)
729 static const D3D_FEATURE_LEVEL feature_level[] =
731 D3D_FEATURE_LEVEL_11_0,
733 unsigned int feature_level_count = ARRAY_SIZE(feature_level);
734 IDXGIDevice *device = NULL;
735 ID3D11Device *d3d_device;
736 HRESULT hr;
738 if (!pD3D11CreateDevice)
739 return NULL;
741 hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, feature_level, feature_level_count,
742 D3D11_SDK_VERSION, &d3d_device, NULL, NULL);
743 if (FAILED(hr))
744 hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_WARP, NULL, 0, feature_level, feature_level_count,
745 D3D11_SDK_VERSION, &d3d_device, NULL, NULL);
746 if (FAILED(hr))
747 hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, 0, feature_level, feature_level_count,
748 D3D11_SDK_VERSION, &d3d_device, NULL, NULL);
750 if (SUCCEEDED(hr))
752 hr = ID3D11Device_QueryInterface(d3d_device, &IID_IDXGIDevice, (void **)&device);
753 ok(SUCCEEDED(hr), "Created device does not implement IDXGIDevice.\n");
754 ID3D11Device_Release(d3d_device);
757 return device;
760 static ID3D12Device *create_d3d12_device(void)
762 IDXGIAdapter *adapter;
763 ID3D12Device *device;
764 HRESULT hr;
766 if (!pD3D12CreateDevice)
767 return NULL;
769 adapter = create_adapter();
770 hr = pD3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&device);
771 if (adapter)
772 IDXGIAdapter_Release(adapter);
773 if (FAILED(hr))
774 return NULL;
776 return device;
779 static ID3D12CommandQueue *create_d3d12_direct_queue(ID3D12Device *device)
781 D3D12_COMMAND_QUEUE_DESC command_queue_desc;
782 ID3D12CommandQueue *queue;
783 HRESULT hr;
785 command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
786 command_queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
787 command_queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
788 command_queue_desc.NodeMask = 0;
789 hr = ID3D12Device_CreateCommandQueue(device, &command_queue_desc,
790 &IID_ID3D12CommandQueue, (void **)&queue);
791 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
792 return queue;
795 static HRESULT wait_for_fence(ID3D12Fence *fence, UINT64 value)
797 HANDLE event;
798 HRESULT hr;
799 DWORD ret;
801 if (ID3D12Fence_GetCompletedValue(fence) >= value)
802 return S_OK;
804 if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL)))
805 return E_FAIL;
807 if (FAILED(hr = ID3D12Fence_SetEventOnCompletion(fence, value, event)))
809 CloseHandle(event);
810 return hr;
813 ret = WaitForSingleObject(event, INFINITE);
814 CloseHandle(event);
815 return ret == WAIT_OBJECT_0 ? S_OK : E_FAIL;
818 #define wait_queue_idle(a, b) wait_queue_idle_(__LINE__, a, b)
819 static void wait_queue_idle_(unsigned int line, ID3D12Device *device, ID3D12CommandQueue *queue)
821 ID3D12Fence *fence;
822 HRESULT hr;
824 hr = ID3D12Device_CreateFence(device, 0, D3D12_FENCE_FLAG_NONE,
825 &IID_ID3D12Fence, (void **)&fence);
826 ok_(__FILE__, line)(hr == S_OK, "Failed to create fence, hr %#lx.\n", hr);
828 hr = ID3D12CommandQueue_Signal(queue, fence, 1);
829 ok_(__FILE__, line)(hr == S_OK, "Failed to signal fence, hr %#lx.\n", hr);
830 hr = wait_for_fence(fence, 1);
831 ok_(__FILE__, line)(hr == S_OK, "Failed to wait for fence, hr %#lx.\n", hr);
833 ID3D12Fence_Release(fence);
836 #define wait_device_idle(a) wait_device_idle_(__LINE__, a)
837 static void wait_device_idle_(unsigned int line, IUnknown *device)
839 ID3D12Device *d3d12_device;
840 ID3D12CommandQueue *queue;
841 HRESULT hr;
843 hr = IUnknown_QueryInterface(device, &IID_ID3D12CommandQueue, (void **)&queue);
844 if (hr != S_OK)
845 return;
847 hr = ID3D12CommandQueue_GetDevice(queue, &IID_ID3D12Device, (void **)&d3d12_device);
848 ok_(__FILE__, line)(hr == S_OK, "Failed to get d3d12 device, hr %#lx.\n", hr);
850 wait_queue_idle_(line, d3d12_device, queue);
852 ID3D12CommandQueue_Release(queue);
853 ID3D12Device_Release(d3d12_device);
856 #define get_factory(a, b, c) get_factory_(__LINE__, a, b, c)
857 static void get_factory_(unsigned int line, IUnknown *device, BOOL is_d3d12, IDXGIFactory **factory)
859 IDXGIDevice *dxgi_device;
860 IDXGIAdapter *adapter;
861 HRESULT hr;
863 if (is_d3d12)
865 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)factory);
866 ok_(__FILE__, line)(hr == S_OK, "Failed to create factory, hr %#lx.\n", hr);
868 else
870 dxgi_device = (IDXGIDevice *)device;
871 hr = IDXGIDevice_GetAdapter(dxgi_device, &adapter);
872 ok_(__FILE__, line)(hr == S_OK, "Failed to get adapter, hr %#lx.\n", hr);
873 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)factory);
874 ok_(__FILE__, line)(hr == S_OK, "Failed to get parent, hr %#lx.\n", hr);
875 IDXGIAdapter_Release(adapter);
879 #define get_adapter(a, b) get_adapter_(__LINE__, a, b)
880 static IDXGIAdapter *get_adapter_(unsigned int line, IUnknown *device, BOOL is_d3d12)
882 IDXGIAdapter *adapter = NULL;
883 ID3D12Device *d3d12_device;
884 IDXGIFactory4 *factory4;
885 IDXGIFactory *factory;
886 HRESULT hr;
887 LUID luid;
889 if (is_d3d12)
891 get_factory_(line, device, is_d3d12, &factory);
892 hr = ID3D12CommandQueue_GetDevice((ID3D12CommandQueue *)device, &IID_ID3D12Device, (void **)&d3d12_device);
893 ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
894 luid = ID3D12Device_GetAdapterLuid(d3d12_device);
895 ID3D12Device_Release(d3d12_device);
896 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void **)&factory4);
897 ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
898 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, luid, &IID_IDXGIAdapter, (void **)&adapter);
899 IDXGIFactory4_Release(factory4);
900 IDXGIFactory_Release(factory);
902 else
904 hr = IDXGIDevice_GetAdapter((IDXGIDevice *)device, &adapter);
905 ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
908 return adapter;
911 #define create_swapchain(a, b, c) create_swapchain_(__LINE__, a, b, c)
912 static IDXGISwapChain *create_swapchain_(unsigned int line, IUnknown *device, BOOL is_d3d12, HWND window)
914 DXGI_SWAP_CHAIN_DESC desc;
915 IDXGISwapChain *swapchain;
916 IDXGIFactory *factory;
917 HRESULT hr;
919 desc.BufferDesc.Width = 640;
920 desc.BufferDesc.Height = 480;
921 desc.BufferDesc.RefreshRate.Numerator = 60;
922 desc.BufferDesc.RefreshRate.Denominator = 1;
923 desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
924 desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
925 desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
926 desc.SampleDesc.Count = 1;
927 desc.SampleDesc.Quality = 0;
928 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
929 desc.BufferCount = is_d3d12 ? 2 : 1;
930 desc.OutputWindow = window;
931 desc.Windowed = TRUE;
932 desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
933 desc.Flags = 0;
935 get_factory(device, is_d3d12, &factory);
936 hr = IDXGIFactory_CreateSwapChain(factory, device, &desc, &swapchain);
937 ok_(__FILE__, line)(hr == S_OK, "Failed to create swapchain, hr %#lx.\n", hr);
938 IDXGIFactory_Release(factory);
940 return swapchain;
943 static void test_adapter_desc(void)
945 DXGI_ADAPTER_DESC1 desc1;
946 IDXGIAdapter1 *adapter1;
947 DXGI_ADAPTER_DESC desc;
948 IDXGIAdapter *adapter;
949 IDXGIDevice *device;
950 ULONG refcount;
951 HRESULT hr;
953 if (!(device = create_device(0)))
955 skip("Failed to create device.\n");
956 return;
959 hr = IDXGIDevice_GetAdapter(device, &adapter);
960 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
962 hr = IDXGIAdapter_GetDesc(adapter, NULL);
963 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
965 hr = IDXGIAdapter_GetDesc(adapter, &desc);
966 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
968 trace("%s.\n", wine_dbgstr_w(desc.Description));
969 trace("%04x: %04x:%04x (rev %02x).\n",
970 desc.SubSysId, desc.VendorId, desc.DeviceId, desc.Revision);
971 trace("Dedicated video memory: %Iu (%Iu MB).\n",
972 desc.DedicatedVideoMemory, desc.DedicatedVideoMemory / (1024 * 1024));
973 trace("Dedicated system memory: %Iu (%Iu MB).\n",
974 desc.DedicatedSystemMemory, desc.DedicatedSystemMemory / (1024 * 1024));
975 trace("Shared system memory: %Iu (%Iu MB).\n",
976 desc.SharedSystemMemory, desc.SharedSystemMemory / (1024 * 1024));
977 trace("LUID: %08lx:%08lx.\n", desc.AdapterLuid.HighPart, desc.AdapterLuid.LowPart);
979 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter1, (void **)&adapter1);
980 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Got unexpected hr %#lx.\n", hr);
981 if (hr == E_NOINTERFACE)
982 goto done;
984 hr = IDXGIAdapter1_GetDesc1(adapter1, &desc1);
985 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
987 ok(!lstrcmpW(desc.Description, desc1.Description),
988 "Got unexpected description %s.\n", wine_dbgstr_w(desc1.Description));
989 ok(desc1.VendorId == desc.VendorId, "Got unexpected vendor ID %04x.\n", desc1.VendorId);
990 ok(desc1.DeviceId == desc.DeviceId, "Got unexpected device ID %04x.\n", desc1.DeviceId);
991 ok(desc1.SubSysId == desc.SubSysId, "Got unexpected sub system ID %04x.\n", desc1.SubSysId);
992 ok(desc1.Revision == desc.Revision, "Got unexpected revision %02x.\n", desc1.Revision);
993 ok(desc1.DedicatedVideoMemory == desc.DedicatedVideoMemory,
994 "Got unexpected dedicated video memory %Iu.\n", desc1.DedicatedVideoMemory);
995 ok(desc1.DedicatedSystemMemory == desc.DedicatedSystemMemory,
996 "Got unexpected dedicated system memory %Iu.\n", desc1.DedicatedSystemMemory);
997 ok(desc1.SharedSystemMemory == desc.SharedSystemMemory,
998 "Got unexpected shared system memory %Iu.\n", desc1.SharedSystemMemory);
999 ok(equal_luid(desc1.AdapterLuid, desc.AdapterLuid),
1000 "Got unexpected adapter LUID %08lx:%08lx.\n", desc1.AdapterLuid.HighPart, desc1.AdapterLuid.LowPart);
1001 trace("Flags: %08x.\n", desc1.Flags);
1003 IDXGIAdapter1_Release(adapter1);
1005 done:
1006 IDXGIAdapter_Release(adapter);
1007 refcount = IDXGIDevice_Release(device);
1008 ok(!refcount, "Device has %lu references left.\n", refcount);
1011 static void test_adapter_luid(void)
1013 DXGI_ADAPTER_DESC device_adapter_desc, desc, desc2;
1014 static const LUID luid = {0xdeadbeef, 0xdeadbeef};
1015 IDXGIAdapter *adapter, *adapter2;
1016 unsigned int found_adapter_count;
1017 unsigned int adapter_index;
1018 BOOL is_null_luid_adapter;
1019 IDXGIFactory4 *factory4;
1020 IDXGIFactory *factory;
1021 BOOL have_unique_luid;
1022 IDXGIDevice *device;
1023 ULONG refcount;
1024 HRESULT hr;
1026 if (!(device = create_device(0)))
1028 skip("Failed to create device.\n");
1029 return;
1032 hr = IDXGIDevice_GetAdapter(device, &adapter);
1033 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1034 hr = IDXGIAdapter_GetDesc(adapter, &device_adapter_desc);
1035 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1036 IDXGIAdapter_Release(adapter);
1037 refcount = IDXGIDevice_Release(device);
1038 ok(!refcount, "Device has %lu references left.\n", refcount);
1040 is_null_luid_adapter = !device_adapter_desc.AdapterLuid.LowPart
1041 && !device_adapter_desc.SubSysId && !device_adapter_desc.Revision
1042 && !device_adapter_desc.VendorId && !device_adapter_desc.DeviceId;
1044 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory);
1045 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1047 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void **)&factory4);
1048 ok(hr == S_OK || hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
1050 have_unique_luid = TRUE;
1051 found_adapter_count = 0;
1052 adapter_index = 0;
1053 while ((hr = IDXGIFactory_EnumAdapters(factory, adapter_index, &adapter)) == S_OK)
1055 hr = IDXGIAdapter_GetDesc(adapter, &desc);
1056 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1058 if (equal_luid(desc.AdapterLuid, device_adapter_desc.AdapterLuid))
1060 check_adapter_desc(&desc, &device_adapter_desc);
1061 ++found_adapter_count;
1064 if (equal_luid(desc.AdapterLuid, luid))
1065 have_unique_luid = FALSE;
1067 if (factory4)
1069 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, desc.AdapterLuid,
1070 &IID_IDXGIAdapter, (void **)&adapter2);
1071 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1072 hr = IDXGIAdapter_GetDesc(adapter2, &desc2);
1073 ok(hr == S_OK, "Failed to get adapter desc, hr %#lx.\n", hr);
1074 check_adapter_desc(&desc2, &desc);
1075 ok(adapter2 != adapter, "Expected to get new instance of IDXGIAdapter.\n");
1076 refcount = IDXGIAdapter_Release(adapter2);
1077 ok(!refcount, "Adapter has %lu references left.\n", refcount);
1080 refcount = IDXGIAdapter_Release(adapter);
1081 ok(!refcount, "Adapter has %lu references left.\n", refcount);
1083 ++adapter_index;
1085 ok(hr == DXGI_ERROR_NOT_FOUND, "Got unexpected hr %#lx.\n", hr);
1087 /* Older versions of WARP aren't enumerated by IDXGIFactory_EnumAdapters(). */
1088 ok(found_adapter_count == 1 || broken(is_null_luid_adapter),
1089 "Found %u adapters for LUID %08lx:%08lx.\n",
1090 found_adapter_count, device_adapter_desc.AdapterLuid.HighPart,
1091 device_adapter_desc.AdapterLuid.LowPart);
1093 if (factory4)
1094 IDXGIFactory4_Release(factory4);
1095 refcount = IDXGIFactory_Release(factory);
1096 ok(!refcount, "Factory has %lu references left.\n", refcount);
1098 if (!pCreateDXGIFactory2
1099 || FAILED(hr = pCreateDXGIFactory2(0, &IID_IDXGIFactory4, (void **)&factory4)))
1101 skip("DXGI 1.4 is not available.\n");
1102 return;
1105 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, device_adapter_desc.AdapterLuid,
1106 &IID_IDXGIAdapter, NULL);
1107 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1109 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, device_adapter_desc.AdapterLuid,
1110 &IID_IDXGIAdapter, (void **)&adapter);
1111 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1112 if (SUCCEEDED(hr))
1114 hr = IDXGIAdapter_GetDesc(adapter, &desc);
1115 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1116 check_adapter_desc(&desc, &device_adapter_desc);
1117 refcount = IDXGIAdapter_Release(adapter);
1118 ok(!refcount, "Adapter has %lu references left.\n", refcount);
1121 if (have_unique_luid)
1123 hr = IDXGIFactory4_EnumAdapterByLuid(factory4, luid, &IID_IDXGIAdapter, (void **)&adapter);
1124 ok(hr == DXGI_ERROR_NOT_FOUND, "Got unexpected hr %#lx.\n", hr);
1126 else
1128 skip("Our LUID is not unique.\n");
1131 refcount = IDXGIFactory4_Release(factory4);
1132 ok(!refcount, "Factory has %lu references left.\n", refcount);
1135 static void test_query_video_memory_info(void)
1137 DXGI_QUERY_VIDEO_MEMORY_INFO memory_info;
1138 IDXGIAdapter3 *adapter3;
1139 IDXGIAdapter *adapter;
1140 IDXGIDevice *device;
1141 ULONG refcount;
1142 HRESULT hr;
1144 if (!(device = create_device(0)))
1146 skip("Failed to create device.\n");
1147 return;
1150 hr = IDXGIDevice_GetAdapter(device, &adapter);
1151 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1152 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter3, (void **)&adapter3);
1153 ok(hr == S_OK || hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
1154 if (hr == E_NOINTERFACE)
1155 goto done;
1157 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &memory_info);
1158 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1159 ok(memory_info.Budget >= memory_info.AvailableForReservation,
1160 "Available for reservation 0x%s is greater than budget 0x%s.\n",
1161 wine_dbgstr_longlong(memory_info.AvailableForReservation),
1162 wine_dbgstr_longlong(memory_info.Budget));
1163 ok(!memory_info.CurrentReservation, "Got unexpected current reservation 0x%s.\n",
1164 wine_dbgstr_longlong(memory_info.CurrentReservation));
1166 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &memory_info);
1167 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1168 ok(memory_info.Budget >= memory_info.AvailableForReservation,
1169 "Available for reservation 0x%s is greater than budget 0x%s.\n",
1170 wine_dbgstr_longlong(memory_info.AvailableForReservation),
1171 wine_dbgstr_longlong(memory_info.Budget));
1172 ok(!memory_info.CurrentReservation, "Got unexpected current reservation 0x%s.\n",
1173 wine_dbgstr_longlong(memory_info.CurrentReservation));
1175 hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL + 1, &memory_info);
1176 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
1178 IDXGIAdapter3_Release(adapter3);
1180 done:
1181 IDXGIAdapter_Release(adapter);
1182 refcount = IDXGIDevice_Release(device);
1183 ok(!refcount, "Device has %lu references left.\n", refcount);
1186 static void test_check_interface_support(void)
1188 LARGE_INTEGER driver_version;
1189 IDXGIAdapter *adapter;
1190 IDXGIDevice *device;
1191 IUnknown *iface;
1192 ULONG refcount;
1193 HRESULT hr;
1195 if (!(device = create_device(0)))
1197 skip("Failed to create device.\n");
1198 return;
1201 hr = IDXGIDevice_GetAdapter(device, &adapter);
1202 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1204 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_IDXGIDevice, NULL);
1205 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1206 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_IDXGIDevice, &driver_version);
1207 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1208 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device, NULL);
1209 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1210 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device, &driver_version);
1211 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1213 trace("UMD version: %u.%u.%u.%u.\n",
1214 HIWORD(U(driver_version).HighPart), LOWORD(U(driver_version).HighPart),
1215 HIWORD(U(driver_version).LowPart), LOWORD(U(driver_version).LowPart));
1217 hr = IDXGIDevice_QueryInterface(device, &IID_ID3D10Device1, (void **)&iface);
1218 if (SUCCEEDED(hr))
1220 IUnknown_Release(iface);
1221 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device1, NULL);
1222 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1223 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device1, &driver_version);
1224 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1226 else
1228 win_skip("D3D10.1 is not supported.\n");
1231 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D11Device, NULL);
1232 ok(hr == DXGI_ERROR_UNSUPPORTED, "Got unexpected hr %#lx.\n", hr);
1233 driver_version.LowPart = driver_version.HighPart = 0xdeadbeef;
1234 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D11Device, &driver_version);
1235 ok(hr == DXGI_ERROR_UNSUPPORTED, "Got unexpected hr %#lx.\n", hr);
1236 ok(driver_version.HighPart == 0xdeadbeef, "Got unexpected driver version %#lx.\n", driver_version.HighPart);
1237 ok(driver_version.LowPart == 0xdeadbeef, "Got unexpected driver version %#lx.\n", driver_version.LowPart);
1239 IDXGIAdapter_Release(adapter);
1240 refcount = IDXGIDevice_Release(device);
1241 ok(!refcount, "Device has %lu references left.\n", refcount);
1244 static void test_create_surface(void)
1246 ID3D11Texture2D *texture2d;
1247 DXGI_SURFACE_DESC desc;
1248 IDXGISurface *surface;
1249 IDXGIDevice *device;
1250 ULONG refcount;
1251 HRESULT hr;
1253 if (!(device = create_device(0)))
1255 skip("Failed to create device.\n");
1256 return;
1259 desc.Width = 512;
1260 desc.Height = 512;
1261 desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1262 desc.SampleDesc.Count = 1;
1263 desc.SampleDesc.Quality = 0;
1265 hr = IDXGIDevice_CreateSurface(device, &desc, 1, DXGI_USAGE_RENDER_TARGET_OUTPUT, NULL, &surface);
1266 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1268 check_interface(surface, &IID_ID3D10Texture2D, TRUE, FALSE);
1269 /* Not available on all Windows versions. */
1270 check_interface(surface, &IID_ID3D11Texture2D, TRUE, TRUE);
1271 /* Not available on all Windows versions. */
1272 check_interface(surface, &IID_IDXGISurface1, TRUE, TRUE);
1274 IDXGISurface_Release(surface);
1275 refcount = IDXGIDevice_Release(device);
1276 ok(!refcount, "Device has %lu references left.\n", refcount);
1278 /* DXGI_USAGE_UNORDERED_ACCESS */
1279 if (!(device = create_d3d11_device()))
1281 skip("Failed to create D3D11 device.\n");
1282 return;
1285 surface = NULL;
1286 hr = IDXGIDevice_CreateSurface(device, &desc, 1, DXGI_USAGE_UNORDERED_ACCESS, NULL, &surface);
1287 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1289 if (surface)
1291 ID3D11UnorderedAccessView *uav;
1292 ID3D11Device *d3d_device;
1294 hr = IDXGISurface_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture2d);
1295 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1297 ID3D11Texture2D_GetDevice(texture2d, &d3d_device);
1299 hr = ID3D11Device_CreateUnorderedAccessView(d3d_device, (ID3D11Resource *)texture2d, NULL, &uav);
1300 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1301 ID3D11UnorderedAccessView_Release(uav);
1303 ID3D11Device_Release(d3d_device);
1304 ID3D11Texture2D_Release(texture2d);
1306 IDXGISurface_Release(surface);
1309 refcount = IDXGIDevice_Release(device);
1310 ok(!refcount, "Device has %lu references left.\n", refcount);
1313 static void test_parents(void)
1315 DXGI_SURFACE_DESC surface_desc;
1316 IDXGISurface *surface;
1317 IDXGIFactory *factory;
1318 IDXGIAdapter *adapter;
1319 IDXGIDevice *device;
1320 IDXGIOutput *output;
1321 IUnknown *parent;
1322 ULONG refcount;
1323 HRESULT hr;
1325 if (!(device = create_device(0)))
1327 skip("Failed to create device.\n");
1328 return;
1331 surface_desc.Width = 512;
1332 surface_desc.Height = 512;
1333 surface_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1334 surface_desc.SampleDesc.Count = 1;
1335 surface_desc.SampleDesc.Quality = 0;
1337 hr = IDXGIDevice_CreateSurface(device, &surface_desc, 1, DXGI_USAGE_RENDER_TARGET_OUTPUT, NULL, &surface);
1338 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1340 hr = IDXGISurface_GetParent(surface, &IID_IDXGIDevice, (void **)&parent);
1341 IDXGISurface_Release(surface);
1342 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1343 ok(parent == (IUnknown *)device, "Got parent %p, expected %p.\n", parent, device);
1344 IUnknown_Release(parent);
1346 hr = IDXGIDevice_GetAdapter(device, &adapter);
1347 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1349 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
1350 if (hr == DXGI_ERROR_NOT_FOUND)
1352 skip("Adapter has not outputs.\n");
1354 else
1356 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1358 hr = IDXGIOutput_GetParent(output, &IID_IDXGIAdapter, (void **)&parent);
1359 IDXGIOutput_Release(output);
1360 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1361 ok(parent == (IUnknown *)adapter, "Got parent %p, expected %p.\n", parent, adapter);
1362 IUnknown_Release(parent);
1365 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1366 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1368 hr = IDXGIFactory_GetParent(factory, &IID_IUnknown, (void **)&parent);
1369 ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
1370 ok(parent == NULL, "Got parent %p, expected %p.\n", parent, NULL);
1371 IDXGIFactory_Release(factory);
1373 hr = IDXGIDevice_GetParent(device, &IID_IDXGIAdapter, (void **)&parent);
1374 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1375 ok(parent == (IUnknown *)adapter, "Got parent %p, expected %p.\n", parent, adapter);
1376 IUnknown_Release(parent);
1378 IDXGIAdapter_Release(adapter);
1379 refcount = IDXGIDevice_Release(device);
1380 ok(!refcount, "Device has %lu references left.\n", refcount);
1383 static void test_output(void)
1385 unsigned int mode_count, mode_count_comp, i, last_height, last_width;
1386 double last_refresh_rate;
1387 IDXGIAdapter *adapter;
1388 IDXGIDevice *device;
1389 HRESULT hr;
1390 IDXGIOutput *output;
1391 ULONG refcount;
1392 DXGI_MODE_DESC *modes;
1394 if (!(device = create_device(0)))
1396 skip("Failed to create device.\n");
1397 return;
1400 hr = IDXGIDevice_GetAdapter(device, &adapter);
1401 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1403 hr = IDXGIAdapter_EnumOutputs(adapter, 0, NULL);
1404 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
1406 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
1407 if (hr == DXGI_ERROR_NOT_FOUND)
1409 skip("Adapter doesn't have any outputs.\n");
1410 IDXGIAdapter_Release(adapter);
1411 IDXGIDevice_Release(device);
1412 return;
1414 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1416 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, NULL, NULL);
1417 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1419 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
1420 ok(hr == S_OK|| broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Remote Desktop Services / Win 7 testbot */
1421 "Got unexpected hr %#lx.\n", hr);
1422 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
1424 win_skip("GetDisplayModeList() not supported.\n");
1425 IDXGIOutput_Release(output);
1426 IDXGIAdapter_Release(adapter);
1427 IDXGIDevice_Release(device);
1428 return;
1430 mode_count_comp = mode_count;
1432 hr = IDXGIOutput_GetDisplayModeList(output, 0, 0, &mode_count, NULL);
1433 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1434 ok(!mode_count, "Got unexpected mode_count %u.\n", mode_count);
1436 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1437 DXGI_ENUM_MODES_SCALING, &mode_count, NULL);
1438 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1439 ok(mode_count >= mode_count_comp, "Got unexpected mode_count %u, expected >= %u.\n", mode_count, mode_count_comp);
1440 mode_count_comp = mode_count;
1442 modes = heap_calloc(mode_count + 10, sizeof(*modes));
1443 ok(!!modes, "Failed to allocate memory.\n");
1445 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1446 DXGI_ENUM_MODES_SCALING, NULL, modes);
1447 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1448 ok(!modes[0].Height, "No output was expected.\n");
1450 mode_count = 0;
1451 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1452 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1453 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#lx.\n", hr);
1454 ok(!modes[0].Height, "No output was expected.\n");
1456 mode_count = mode_count_comp;
1457 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1458 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1459 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1460 ok(mode_count == mode_count_comp, "Got unexpected mode_count %u, expected %u.\n", mode_count, mode_count_comp);
1462 last_width = last_height = 0;
1463 last_refresh_rate = 0.;
1464 for (i = 0; i < mode_count; i++)
1466 double refresh_rate = modes[i].RefreshRate.Numerator / (double)modes[i].RefreshRate.Denominator;
1468 ok(modes[i].Width && modes[i].Height, "Mode %u: Invalid dimensions %ux%u.\n",
1469 i, modes[i].Width, modes[i].Height);
1471 ok(modes[i].Width >= last_width,
1472 "Mode %u: Modes should have been sorted, width %u < %u.\n", i, modes[i].Width, last_width);
1473 if (modes[i].Width != last_width)
1475 last_width = modes[i].Width;
1476 last_height = 0;
1477 last_refresh_rate = 0.;
1478 continue;
1481 ok(modes[i].Height >= last_height,
1482 "Mode %u: Modes should have been sorted, height %u < %u.\n", i, modes[i].Height, last_height);
1483 if (modes[i].Height != last_height)
1485 last_height = modes[i].Height;
1486 last_refresh_rate = 0.;
1487 continue;
1490 ok(refresh_rate >= last_refresh_rate,
1491 "Mode %u: Modes should have been sorted, refresh rate %f < %f.\n", i, refresh_rate, last_refresh_rate);
1492 if (refresh_rate != last_refresh_rate)
1493 last_refresh_rate = refresh_rate;
1496 mode_count += 5;
1497 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1498 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1499 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1500 ok(mode_count == mode_count_comp, "Got unexpected mode_count %u, expected %u.\n", mode_count, mode_count_comp);
1502 if (mode_count_comp)
1504 mode_count = mode_count_comp - 1;
1505 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
1506 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
1507 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#lx.\n", hr);
1508 ok(mode_count == mode_count_comp - 1, "Got unexpected mode_count %u, expected %u.\n",
1509 mode_count, mode_count_comp - 1);
1511 else
1513 skip("Not enough modes for test.\n");
1516 heap_free(modes);
1517 IDXGIOutput_Release(output);
1518 IDXGIAdapter_Release(adapter);
1519 refcount = IDXGIDevice_Release(device);
1520 ok(!refcount, "Device has %lu references left.\n", refcount);
1523 static void test_find_closest_matching_mode(void)
1525 static const DXGI_MODE_SCALING scaling_tests[] =
1527 DXGI_MODE_SCALING_CENTERED,
1528 DXGI_MODE_SCALING_STRETCHED
1530 DXGI_MODE_DESC *modes, mode, matching_mode;
1531 unsigned int i, j, mode_count;
1532 IDXGIAdapter *adapter;
1533 IDXGIDevice *device;
1534 IDXGIOutput *output;
1535 ULONG refcount;
1536 HRESULT hr;
1538 if (!(device = create_device(0)))
1540 skip("Failed to create device.\n");
1541 return;
1544 hr = IDXGIDevice_GetAdapter(device, &adapter);
1545 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1547 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
1548 if (hr == DXGI_ERROR_NOT_FOUND)
1550 win_skip("Adapter doesn't have any outputs.\n");
1551 IDXGIAdapter_Release(adapter);
1552 IDXGIDevice_Release(device);
1553 return;
1555 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1557 memset(&mode, 0, sizeof(mode));
1558 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1559 ok(hr == DXGI_ERROR_INVALID_CALL || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Win 7 testbot */
1560 "Got unexpected hr %#lx.\n", hr);
1561 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
1563 win_skip("FindClosestMatchingMode() not supported.\n");
1564 goto done;
1567 memset(&mode, 0, sizeof(mode));
1568 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, (IUnknown *)device);
1569 todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1571 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
1572 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1574 modes = heap_calloc(mode_count, sizeof(*modes));
1575 ok(!!modes, "Failed to allocate memory.\n");
1577 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes);
1578 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1580 for (i = 0; i < mode_count; ++i)
1582 mode = modes[i];
1583 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1584 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1585 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING);
1587 mode.Format = DXGI_FORMAT_UNKNOWN;
1588 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1589 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1591 mode = modes[i];
1592 mode.Width = 0;
1593 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1594 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1596 mode = modes[i];
1597 mode.Height = 0;
1598 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1599 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1601 mode = modes[i];
1602 mode.Width = mode.Height = 0;
1603 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1604 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1605 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING | MODE_DESC_IGNORE_RESOLUTION);
1606 ok(matching_mode.Width > 0 && matching_mode.Height > 0, "Got unexpected resolution %ux%u.\n",
1607 matching_mode.Width, matching_mode.Height);
1609 mode = modes[i];
1610 mode.RefreshRate.Numerator = mode.RefreshRate.Denominator = 0;
1611 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1612 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1613 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING | MODE_DESC_IGNORE_REFRESH_RATE);
1614 ok(matching_mode.RefreshRate.Numerator > 0 && matching_mode.RefreshRate.Denominator > 0,
1615 "Got unexpected refresh rate %u / %u.\n",
1616 matching_mode.RefreshRate.Numerator, matching_mode.RefreshRate.Denominator);
1618 mode = modes[i];
1619 mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1620 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1621 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1622 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_IGNORE_SCALING | MODE_DESC_IGNORE_SCANLINE_ORDERING);
1623 ok(matching_mode.ScanlineOrdering, "Got unexpected scanline ordering %#x.\n",
1624 matching_mode.ScanlineOrdering);
1626 memset(&mode, 0, sizeof(mode));
1627 mode.Width = modes[i].Width;
1628 mode.Height = modes[i].Height;
1629 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1630 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1631 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1632 check_mode_desc(&matching_mode, &modes[i], MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1634 memset(&mode, 0, sizeof(mode));
1635 mode.Width = modes[i].Width - 1;
1636 mode.Height = modes[i].Height - 1;
1637 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1638 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1639 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1640 check_mode_desc(&matching_mode, &modes[i],
1641 (MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT) | MODE_DESC_IGNORE_EXACT_RESOLUTION);
1643 memset(&mode, 0, sizeof(mode));
1644 mode.Width = modes[i].Width + 1;
1645 mode.Height = modes[i].Height + 1;
1646 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1647 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1648 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1649 check_mode_desc(&matching_mode, &modes[i],
1650 (MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT) | MODE_DESC_IGNORE_EXACT_RESOLUTION);
1653 memset(&mode, 0, sizeof(mode));
1654 mode.Width = mode.Height = 10;
1655 mode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1656 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1657 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1658 /* Find mode for the lowest resolution. */
1659 mode = modes[0];
1660 for (i = 0; i < mode_count; ++i)
1662 if (mode.Width >= modes[i].Width && mode.Height >= modes[i].Height)
1663 mode = modes[i];
1665 check_mode_desc(&matching_mode, &mode, MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1667 memset(&mode, 0, sizeof(mode));
1668 mode.Width = modes[0].Width;
1669 mode.Height = modes[0].Height;
1670 mode.Format = modes[0].Format;
1671 mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST;
1672 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1673 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1674 check_mode_desc(&matching_mode, &modes[0], MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1676 memset(&mode, 0, sizeof(mode));
1677 mode.Width = modes[0].Width;
1678 mode.Height = modes[0].Height;
1679 mode.Format = modes[0].Format;
1680 mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST;
1681 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1682 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1683 check_mode_desc(&matching_mode, &modes[0], MODE_DESC_CHECK_RESOLUTION & MODE_DESC_CHECK_FORMAT);
1685 for (i = 0; i < ARRAY_SIZE(scaling_tests); ++i)
1687 for (j = 0; j < mode_count; ++j)
1689 if (modes[j].Scaling != scaling_tests[i])
1690 continue;
1692 memset(&mode, 0, sizeof(mode));
1693 mode.Width = modes[j].Width;
1694 mode.Height = modes[j].Height;
1695 mode.Format = modes[j].Format;
1696 mode.Scaling = modes[j].Scaling;
1697 hr = IDXGIOutput_FindClosestMatchingMode(output, &mode, &matching_mode, NULL);
1698 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1699 check_mode_desc(&matching_mode, &modes[j],
1700 MODE_DESC_IGNORE_REFRESH_RATE | MODE_DESC_IGNORE_SCANLINE_ORDERING);
1701 break;
1705 heap_free(modes);
1707 done:
1708 IDXGIOutput_Release(output);
1709 IDXGIAdapter_Release(adapter);
1710 refcount = IDXGIDevice_Release(device);
1711 ok(!refcount, "Device has %lu references left.\n", refcount);
1714 struct refresh_rates
1716 UINT numerator;
1717 UINT denominator;
1718 BOOL numerator_should_pass;
1719 BOOL denominator_should_pass;
1722 static void test_create_swapchain(void)
1724 struct swapchain_fullscreen_state initial_state, expected_state;
1725 unsigned int i, expected_width, expected_height;
1726 DXGI_SWAP_CHAIN_DESC creation_desc, result_desc;
1727 DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc;
1728 DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
1729 IDXGIDevice *device, *bgra_device;
1730 ULONG refcount, expected_refcount;
1731 IUnknown *obj, *obj2, *parent;
1732 IDXGISwapChain1 *swapchain1;
1733 RECT *expected_client_rect;
1734 IDXGISwapChain *swapchain;
1735 IDXGISurface1 *surface;
1736 IDXGIAdapter *adapter;
1737 IDXGIFactory *factory;
1738 IDXGIOutput *target;
1739 BOOL fullscreen;
1740 HWND window;
1741 HRESULT hr;
1743 const struct refresh_rates refresh_list[] =
1745 {60, 60, FALSE, FALSE},
1746 {60, 0, TRUE, FALSE},
1747 {60, 1, TRUE, TRUE},
1748 { 0, 60, TRUE, FALSE},
1749 { 0, 0, TRUE, FALSE},
1752 if (!(device = create_device(0)))
1754 skip("Failed to create device.\n");
1755 return;
1758 creation_desc.BufferDesc.Width = 800;
1759 creation_desc.BufferDesc.Height = 600;
1760 creation_desc.BufferDesc.RefreshRate.Numerator = 60;
1761 creation_desc.BufferDesc.RefreshRate.Denominator = 60;
1762 creation_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1763 creation_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1764 creation_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
1765 creation_desc.SampleDesc.Count = 1;
1766 creation_desc.SampleDesc.Quality = 0;
1767 creation_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1768 creation_desc.BufferCount = 1;
1769 creation_desc.OutputWindow = NULL;
1770 creation_desc.Windowed = TRUE;
1771 creation_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
1772 creation_desc.Flags = 0;
1774 hr = IDXGIDevice_QueryInterface(device, &IID_IUnknown, (void **)&obj);
1775 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1777 hr = IDXGIDevice_GetAdapter(device, &adapter);
1778 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1780 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1781 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1783 expected_refcount = get_refcount(adapter);
1784 refcount = get_refcount(factory);
1785 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
1786 refcount = get_refcount(device);
1787 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
1789 creation_desc.OutputWindow = NULL;
1790 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1791 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1793 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 0, 0, 0, 0, 0, 0);
1794 memset(&initial_state, 0, sizeof(initial_state));
1795 capture_fullscreen_state(&initial_state.fullscreen_state, creation_desc.OutputWindow);
1797 hr = IDXGIFactory_CreateSwapChain(factory, NULL, &creation_desc, &swapchain);
1798 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1799 hr = IDXGIFactory_CreateSwapChain(factory, obj, NULL, &swapchain);
1800 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1801 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, NULL);
1802 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
1803 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1804 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1806 refcount = get_refcount(adapter);
1807 ok(refcount >= expected_refcount, "Got refcount %lu, expected >= %lu.\n", refcount, expected_refcount);
1808 refcount = get_refcount(factory);
1809 todo_wine ok(refcount == 4, "Got unexpected refcount %lu.\n", refcount);
1810 refcount = get_refcount(device);
1811 ok(refcount == 3, "Got unexpected refcount %lu.\n", refcount);
1813 hr = IDXGISwapChain_GetDesc(swapchain, NULL);
1814 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
1816 hr = IDXGISwapChain_GetParent(swapchain, &IID_IUnknown, (void **)&parent);
1817 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1818 ok(parent == (IUnknown *)factory, "Got unexpected parent interface pointer %p.\n", parent);
1819 refcount = IUnknown_Release(parent);
1820 todo_wine ok(refcount == 4, "Got unexpected refcount %lu.\n", refcount);
1822 hr = IDXGISwapChain_GetParent(swapchain, &IID_IDXGIFactory, (void **)&parent);
1823 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1824 ok(parent == (IUnknown *)factory, "Got unexpected parent interface pointer %p.\n", parent);
1825 refcount = IUnknown_Release(parent);
1826 todo_wine ok(refcount == 4, "Got unexpected refcount %lu.\n", refcount);
1828 hr = IDXGISwapChain_QueryInterface(swapchain, &IID_IDXGISwapChain1, (void **)&swapchain1);
1829 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
1830 "Got unexpected hr %#lx.\n", hr);
1831 if (SUCCEEDED(hr))
1833 hr = IDXGISwapChain1_GetDesc1(swapchain1, NULL);
1834 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
1835 hr = IDXGISwapChain1_GetDesc1(swapchain1, &swapchain_desc);
1836 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1837 ok(!swapchain_desc.Stereo, "Got unexpected stereo %#x.\n", swapchain_desc.Stereo);
1838 ok(swapchain_desc.Scaling == DXGI_SCALING_STRETCH,
1839 "Got unexpected scaling %#x.\n", swapchain_desc.Scaling);
1840 ok(swapchain_desc.AlphaMode == DXGI_ALPHA_MODE_IGNORE,
1841 "Got unexpected alpha mode %#x.\n", swapchain_desc.AlphaMode);
1842 hr = IDXGISwapChain1_GetFullscreenDesc(swapchain1, NULL);
1843 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
1844 hr = IDXGISwapChain1_GetFullscreenDesc(swapchain1, &fullscreen_desc);
1845 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1846 ok(fullscreen_desc.Windowed == creation_desc.Windowed,
1847 "Got unexpected windowed %#x.\n", fullscreen_desc.Windowed);
1848 hr = IDXGISwapChain1_GetHwnd(swapchain1, &window);
1849 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1850 ok(window == creation_desc.OutputWindow, "Got unexpected window %p.\n", window);
1851 IDXGISwapChain1_Release(swapchain1);
1854 refcount = IDXGISwapChain_Release(swapchain);
1855 ok(!refcount, "Swapchain has %lu references left.\n", refcount);
1857 refcount = get_refcount(factory);
1858 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
1860 for (i = 0; i < ARRAY_SIZE(refresh_list); ++i)
1862 creation_desc.BufferDesc.RefreshRate.Numerator = refresh_list[i].numerator;
1863 creation_desc.BufferDesc.RefreshRate.Denominator = refresh_list[i].denominator;
1865 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1866 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1868 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
1869 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1871 ok(result_desc.Windowed == creation_desc.Windowed, "Test %u: Got unexpected windowed %#x.\n",
1872 i, result_desc.Windowed);
1874 todo_wine_if (!refresh_list[i].numerator_should_pass)
1875 ok(result_desc.BufferDesc.RefreshRate.Numerator == refresh_list[i].numerator,
1876 "Numerator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Numerator);
1878 todo_wine_if (!refresh_list[i].denominator_should_pass)
1879 ok(result_desc.BufferDesc.RefreshRate.Denominator == refresh_list[i].denominator,
1880 "Denominator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Denominator);
1882 fullscreen = 0xdeadbeef;
1883 target = (void *)0xdeadbeef;
1884 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
1885 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1886 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
1887 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
1889 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, NULL);
1890 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1891 fullscreen = 0xdeadbeef;
1892 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
1893 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1894 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
1895 target = (void *)0xdeadbeef;
1896 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
1897 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1898 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
1900 check_swapchain_fullscreen_state(swapchain, &initial_state);
1901 IDXGISwapChain_Release(swapchain);
1904 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
1906 /* Test GDI-compatible swapchain */
1907 bgra_device = create_device(D3D10_CREATE_DEVICE_BGRA_SUPPORT);
1908 ok(!!bgra_device, "Failed to create BGRA capable device.\n");
1910 hr = IDXGIDevice_QueryInterface(bgra_device, &IID_IUnknown, (void **)&obj2);
1911 ok(hr == S_OK, "IDXGIDevice does not implement IUnknown.\n");
1913 hr = IDXGIFactory_CreateSwapChain(factory, obj2, &creation_desc, &swapchain);
1914 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1916 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface1, (void **)&surface);
1917 if (SUCCEEDED(hr))
1919 HDC hdc;
1921 hr = IDXGISurface1_GetDC(surface, FALSE, &hdc);
1922 ok(FAILED(hr), "Got unexpected hr %#lx.\n", hr);
1924 IDXGISurface1_Release(surface);
1925 IDXGISwapChain_Release(swapchain);
1927 creation_desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
1928 creation_desc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
1930 hr = IDXGIFactory_CreateSwapChain(factory, obj2, &creation_desc, &swapchain);
1931 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1933 creation_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1934 creation_desc.Flags = 0;
1936 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface1, (void **)&surface);
1937 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1939 hr = IDXGISurface1_GetDC(surface, FALSE, &hdc);
1940 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
1941 IDXGISurface1_ReleaseDC(surface, NULL);
1943 IDXGISurface1_Release(surface);
1944 IDXGISwapChain_Release(swapchain);
1946 else
1948 win_skip("IDXGISurface1 is not supported, skipping GetDC() tests.\n");
1949 IDXGISwapChain_Release(swapchain);
1951 IUnknown_Release(obj2);
1952 IDXGIDevice_Release(bgra_device);
1954 creation_desc.Windowed = FALSE;
1956 for (i = 0; i < ARRAY_SIZE(refresh_list); ++i)
1958 creation_desc.BufferDesc.RefreshRate.Numerator = refresh_list[i].numerator;
1959 creation_desc.BufferDesc.RefreshRate.Denominator = refresh_list[i].denominator;
1961 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
1962 ok(hr == S_OK || hr == DXGI_STATUS_OCCLUDED, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1964 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
1965 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1967 /* When numerator is non-zero and denominator is zero, the windowed mode is used.
1968 * Additionally, some versions of WARP seem to always fail to change fullscreen state. */
1969 if (result_desc.Windowed != creation_desc.Windowed)
1970 trace("Test %u: Failed to change fullscreen state.\n", i);
1972 todo_wine_if (!refresh_list[i].numerator_should_pass)
1973 ok(result_desc.BufferDesc.RefreshRate.Numerator == refresh_list[i].numerator,
1974 "Numerator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Numerator);
1976 todo_wine_if (!refresh_list[i].denominator_should_pass)
1977 ok(result_desc.BufferDesc.RefreshRate.Denominator == refresh_list[i].denominator,
1978 "Denominator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Denominator);
1980 fullscreen = FALSE;
1981 target = NULL;
1982 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
1983 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1984 ok(fullscreen == !result_desc.Windowed, "Test %u: Got fullscreen %#x, expected %#x.\n",
1985 i, fullscreen, result_desc.Windowed);
1986 ok(result_desc.Windowed ? !target : !!target, "Test %u: Got unexpected target %p.\n", i, target);
1987 if (!result_desc.Windowed)
1989 IDXGIOutput *containing_output;
1990 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
1991 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
1992 ok(containing_output == target, "Test %u: Got unexpected containing output pointer %p.\n",
1993 i, containing_output);
1994 IDXGIOutput_Release(containing_output);
1996 ok(output_belongs_to_adapter(target, adapter),
1997 "Test %u: Output %p doesn't belong to adapter %p.\n",
1998 i, target, adapter);
1999 IDXGIOutput_Release(target);
2001 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, NULL);
2002 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
2003 fullscreen = FALSE;
2004 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2005 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
2006 ok(fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
2007 target = NULL;
2008 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
2009 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
2010 ok(!!target, "Test %u: Got unexpected target %p.\n", i, target);
2011 IDXGIOutput_Release(target);
2014 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2015 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
2017 fullscreen = 0xdeadbeef;
2018 target = (void *)0xdeadbeef;
2019 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
2020 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
2021 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
2022 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
2024 check_swapchain_fullscreen_state(swapchain, &initial_state);
2025 IDXGISwapChain_Release(swapchain);
2028 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2030 /* Test swapchain creation with DXGI_FORMAT_UNKNOWN. */
2031 creation_desc.BufferDesc.Format = DXGI_FORMAT_UNKNOWN;
2032 creation_desc.Windowed = TRUE;
2033 creation_desc.Flags = 0;
2034 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2035 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2037 creation_desc.Windowed = FALSE;
2038 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2039 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2041 creation_desc.BufferCount = 2;
2042 creation_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
2043 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2044 ok(hr == E_INVALIDARG || hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
2045 creation_desc.BufferCount = 1;
2046 creation_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
2048 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2050 /* Test swapchain creation with backbuffer width and height equal to 0. */
2051 expected_state = initial_state;
2052 expected_client_rect = &expected_state.fullscreen_state.client_rect;
2054 /* Windowed */
2055 expected_width = expected_client_rect->right;
2056 expected_height = expected_client_rect->bottom;
2058 creation_desc.BufferDesc.Width = 0;
2059 creation_desc.BufferDesc.Height = 0;
2060 creation_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2061 creation_desc.Windowed = TRUE;
2062 creation_desc.Flags = 0;
2063 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2064 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2065 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2066 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2067 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2068 result_desc.BufferDesc.Width, expected_width);
2069 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2070 result_desc.BufferDesc.Height, expected_height);
2071 check_swapchain_fullscreen_state(swapchain, &expected_state);
2072 IDXGISwapChain_Release(swapchain);
2074 DestroyWindow(creation_desc.OutputWindow);
2075 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
2076 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
2077 0, 0, 222, 222, 0, 0, 0, 0);
2078 expected_state.fullscreen_state.style = WS_CLIPSIBLINGS | WS_CAPTION
2079 | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
2080 SetRect(&expected_state.fullscreen_state.window_rect, 0, 0, 222, 222);
2081 GetClientRect(creation_desc.OutputWindow, expected_client_rect);
2082 expected_width = expected_client_rect->right;
2083 expected_height = expected_client_rect->bottom;
2085 creation_desc.BufferDesc.Width = 0;
2086 creation_desc.BufferDesc.Height = 0;
2087 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2088 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2089 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2090 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2091 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2092 result_desc.BufferDesc.Width, expected_width);
2093 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2094 result_desc.BufferDesc.Height, expected_height);
2095 check_swapchain_fullscreen_state(swapchain, &expected_state);
2096 IDXGISwapChain_Release(swapchain);
2098 DestroyWindow(creation_desc.OutputWindow);
2099 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
2100 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
2101 1, 1, 0, 0, 0, 0, 0, 0);
2102 expected_state.fullscreen_state.style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
2103 expected_state.fullscreen_state.exstyle = 0;
2104 SetRect(&expected_state.fullscreen_state.window_rect, 1, 1, 1, 1);
2105 SetRectEmpty(expected_client_rect);
2106 expected_width = expected_height = 8;
2108 creation_desc.BufferDesc.Width = 0;
2109 creation_desc.BufferDesc.Height = 0;
2110 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2111 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2112 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2113 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2114 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2115 result_desc.BufferDesc.Width, expected_width);
2116 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2117 result_desc.BufferDesc.Height, expected_height);
2118 check_swapchain_fullscreen_state(swapchain, &expected_state);
2119 IDXGISwapChain_Release(swapchain);
2121 DestroyWindow(creation_desc.OutputWindow);
2122 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 0, 0, 0, 0, 0, 0);
2123 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2125 /* Fullscreen */
2126 creation_desc.Windowed = FALSE;
2127 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2128 ok(hr == S_OK || hr == DXGI_STATUS_OCCLUDED, "Got unexpected hr %#lx.\n", hr);
2129 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2130 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2131 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2132 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2133 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
2134 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
2135 "Got unexpected hr %#lx.\n", hr);
2136 check_swapchain_fullscreen_state(swapchain, &initial_state);
2137 IDXGISwapChain_Release(swapchain);
2138 if (hr == DXGI_ERROR_UNSUPPORTED)
2140 win_skip("GetContainingOutput() not supported.\n");
2141 goto done;
2143 if (result_desc.Windowed)
2145 win_skip("Fullscreen not supported.\n");
2146 IDXGIOutput_Release(expected_state.target);
2147 goto done;
2150 creation_desc.BufferDesc.Width = 0;
2151 creation_desc.BufferDesc.Height = 0;
2152 creation_desc.Windowed = FALSE;
2153 creation_desc.Flags = 0;
2154 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2155 &creation_desc, &initial_state.fullscreen_state.monitor_rect, 0, 0, expected_state.target);
2156 expected_width = expected_client_rect->right - expected_client_rect->left;
2157 expected_height = expected_client_rect->bottom - expected_client_rect->top;
2159 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2160 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2161 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2162 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2163 todo_wine ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2164 result_desc.BufferDesc.Width, expected_width);
2165 todo_wine ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2166 result_desc.BufferDesc.Height, expected_height);
2167 check_swapchain_fullscreen_state(swapchain, &expected_state);
2168 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2169 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2170 check_swapchain_fullscreen_state(swapchain, &initial_state);
2171 IDXGISwapChain_Release(swapchain);
2173 /* Fullscreen and DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH */
2174 creation_desc.BufferDesc.Width = 0;
2175 creation_desc.BufferDesc.Height = 0;
2176 creation_desc.Windowed = FALSE;
2177 creation_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
2178 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2179 &creation_desc, &initial_state.fullscreen_state.monitor_rect, 0, 0, expected_state.target);
2180 expected_width = expected_client_rect->right - expected_client_rect->left;
2181 expected_height = expected_client_rect->bottom - expected_client_rect->top;
2183 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
2184 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2185 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2186 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2187 todo_wine ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
2188 result_desc.BufferDesc.Width, expected_width);
2189 todo_wine ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
2190 result_desc.BufferDesc.Height, expected_height);
2191 check_swapchain_fullscreen_state(swapchain, &expected_state);
2192 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2193 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2194 check_swapchain_fullscreen_state(swapchain, &initial_state);
2195 IDXGISwapChain_Release(swapchain);
2197 IDXGIOutput_Release(expected_state.target);
2199 done:
2200 IUnknown_Release(obj);
2201 refcount = IDXGIDevice_Release(device);
2202 ok(!refcount, "Device has %lu references left.\n", refcount);
2203 refcount = IDXGIAdapter_Release(adapter);
2204 ok(!refcount, "Adapter has %lu references left.\n", refcount);
2205 refcount = IDXGIFactory_Release(factory);
2206 ok(!refcount, "Factory has %lu references left.\n", refcount);
2207 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
2208 DestroyWindow(creation_desc.OutputWindow);
2211 static void test_get_containing_output(IUnknown *device, BOOL is_d3d12)
2213 unsigned int adapter_idx, output_idx, output_count;
2214 DXGI_OUTPUT_DESC output_desc, output_desc2;
2215 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2216 IDXGIOutput *output, *output2;
2217 MONITORINFOEXW monitor_info;
2218 IDXGISwapChain *swapchain;
2219 IDXGIFactory *factory;
2220 IDXGIAdapter *adapter;
2221 POINT points[4 * 16];
2222 unsigned int i, j;
2223 HMONITOR monitor;
2224 BOOL fullscreen;
2225 ULONG refcount;
2226 HRESULT hr;
2227 BOOL ret;
2229 adapter = get_adapter(device, is_d3d12);
2230 if (!adapter)
2232 skip("Failed to get adapter on Direct3D %d.\n", is_d3d12 ? 12 : 10);
2233 return;
2236 output_count = 0;
2237 while ((hr = IDXGIAdapter_EnumOutputs(adapter, output_count, &output)) != DXGI_ERROR_NOT_FOUND)
2239 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2240 IDXGIOutput_Release(output);
2241 ++output_count;
2243 IDXGIAdapter_Release(adapter);
2245 swapchain_desc.BufferDesc.Width = 100;
2246 swapchain_desc.BufferDesc.Height = 100;
2247 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
2248 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
2249 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2250 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
2251 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
2252 swapchain_desc.SampleDesc.Count = 1;
2253 swapchain_desc.SampleDesc.Quality = 0;
2254 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2255 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
2256 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
2257 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 100, 100, 0, 0, 0, 0);
2258 swapchain_desc.Windowed = TRUE;
2259 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
2260 swapchain_desc.Flags = 0;
2262 get_factory(device, is_d3d12, &factory);
2263 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2264 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2266 monitor = MonitorFromWindow(swapchain_desc.OutputWindow, 0);
2267 ok(!!monitor, "MonitorFromWindow failed.\n");
2269 monitor_info.cbSize = sizeof(monitor_info);
2270 ret = GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info);
2271 ok(ret, "Failed to get monitor info.\n");
2273 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2274 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
2275 "Got unexpected hr %#lx.\n", hr);
2276 if (hr == DXGI_ERROR_UNSUPPORTED)
2278 win_skip("GetContainingOutput() not supported.\n");
2279 goto done;
2282 hr = IDXGIOutput_GetDesc(output, &output_desc);
2283 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2285 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2286 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2287 ok(output != output2, "Got unexpected output pointers %p, %p.\n", output, output2);
2288 check_output_equal(output, output2);
2290 refcount = IDXGIOutput_Release(output);
2291 ok(!refcount, "IDXGIOutput has %lu references left.\n", refcount);
2292 refcount = IDXGIOutput_Release(output2);
2293 ok(!refcount, "IDXGIOutput has %lu references left.\n", refcount);
2295 ok(!lstrcmpW(output_desc.DeviceName, monitor_info.szDevice),
2296 "Got unexpected device name %s, expected %s.\n",
2297 wine_dbgstr_w(output_desc.DeviceName), wine_dbgstr_w(monitor_info.szDevice));
2298 ok(EqualRect(&output_desc.DesktopCoordinates, &monitor_info.rcMonitor),
2299 "Got unexpected desktop coordinates %s, expected %s.\n",
2300 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
2301 wine_dbgstr_rect(&monitor_info.rcMonitor));
2303 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2304 ++adapter_idx)
2306 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
2307 ++output_idx)
2309 hr = IDXGIOutput_GetDesc(output, &output_desc);
2310 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx,
2311 output_idx, hr);
2313 /* Move the OutputWindow to the current output. */
2314 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc.DesktopCoordinates.left,
2315 output_desc.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2316 ok(ret, "Adapter %u output %u: SetWindowPos failed.\n", adapter_idx, output_idx);
2318 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2319 if (FAILED(hr))
2321 win_skip("Adapter %u output %u: GetContainingOutput failed, hr %#lx.\n",
2322 adapter_idx, output_idx, hr);
2323 IDXGIOutput_Release(output);
2324 continue;
2327 check_output_equal(output, output2);
2329 refcount = IDXGIOutput_Release(output2);
2330 ok(!refcount, "Adapter %u output %u: IDXGIOutput has %lu references left.\n",
2331 adapter_idx, output_idx, refcount);
2333 /* Move the OutputWindow around the corners of the current output desktop coordinates. */
2334 for (i = 0; i < 4; ++i)
2336 static const POINT offsets[] =
2338 { 0, 0},
2339 {-49, 0}, {-50, 0}, {-51, 0},
2340 { 0, -49}, { 0, -50}, { 0, -51},
2341 {-49, -49}, {-50, -49}, {-51, -49},
2342 {-49, -50}, {-50, -50}, {-51, -50},
2343 {-49, -51}, {-50, -51}, {-51, -51},
2345 unsigned int x = 0, y = 0;
2347 switch (i)
2349 case 0:
2350 x = output_desc.DesktopCoordinates.left;
2351 y = output_desc.DesktopCoordinates.top;
2352 break;
2353 case 1:
2354 x = output_desc.DesktopCoordinates.right;
2355 y = output_desc.DesktopCoordinates.top;
2356 break;
2357 case 2:
2358 x = output_desc.DesktopCoordinates.right;
2359 y = output_desc.DesktopCoordinates.bottom;
2360 break;
2361 case 3:
2362 x = output_desc.DesktopCoordinates.left;
2363 y = output_desc.DesktopCoordinates.bottom;
2364 break;
2367 for (j = 0; j < ARRAY_SIZE(offsets); ++j)
2369 unsigned int idx = ARRAY_SIZE(offsets) * i + j;
2370 assert(idx < ARRAY_SIZE(points));
2371 points[idx].x = x + offsets[j].x;
2372 points[idx].y = y + offsets[j].y;
2376 for (i = 0; i < ARRAY_SIZE(points); ++i)
2378 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, points[i].x, points[i].y,
2379 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2380 ok(ret, "Adapter %u output %u point %u: Failed to set window position.\n",
2381 adapter_idx, output_idx, i);
2383 monitor = MonitorFromWindow(swapchain_desc.OutputWindow, MONITOR_DEFAULTTONEAREST);
2384 ok(!!monitor, "Adapter %u output %u point %u: Failed to get monitor from window.\n",
2385 adapter_idx, output_idx, i);
2387 monitor_info.cbSize = sizeof(monitor_info);
2388 ret = GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info);
2389 ok(ret, "Adapter %u output %u point %u: Failed to get monitor info.\n", adapter_idx,
2390 output_idx, i);
2392 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2393 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED),
2394 "Adapter %u output %u point %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, i, hr);
2395 if (hr != S_OK)
2396 continue;
2397 ok(!!output2, "Adapter %u output %u point %u: Got unexpected containing output %p.\n",
2398 adapter_idx, output_idx, i, output2);
2399 hr = IDXGIOutput_GetDesc(output2, &output_desc);
2400 ok(hr == S_OK, "Adapter %u output %u point %u: Got unexpected hr %#lx.\n",
2401 adapter_idx, output_idx, i, hr);
2402 refcount = IDXGIOutput_Release(output2);
2403 ok(!refcount, "Adapter %u output %u point %u: IDXGIOutput has %lu references left.\n",
2404 adapter_idx, output_idx, i, refcount);
2406 ok(!lstrcmpW(output_desc.DeviceName, monitor_info.szDevice),
2407 "Adapter %u output %u point %u: Got unexpected device name %s, expected %s.\n",
2408 adapter_idx, output_idx, i, wine_dbgstr_w(output_desc.DeviceName),
2409 wine_dbgstr_w(monitor_info.szDevice));
2410 ok(EqualRect(&output_desc.DesktopCoordinates, &monitor_info.rcMonitor),
2411 "Adapter %u output %u point %u: Expect desktop coordinates %s, got %s.\n",
2412 adapter_idx, output_idx, i,
2413 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
2414 wine_dbgstr_rect(&monitor_info.rcMonitor));
2416 IDXGIOutput_Release(output);
2418 IDXGIAdapter_Release(adapter);
2421 /* Test GetContainingOutput with a full screen swapchain. The containing output should stay
2422 * the same even if the device window is moved */
2423 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2424 if (FAILED(hr))
2426 skip("SetFullscreenState failed, hr %#lx.\n", hr);
2427 goto done;
2430 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
2431 if (FAILED(hr))
2433 win_skip("GetContainingOutput failed, hr %#lx.\n", hr);
2434 IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2435 goto done;
2438 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2439 ++adapter_idx)
2441 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
2442 ++output_idx)
2444 hr = IDXGIOutput_GetDesc(output, &output_desc);
2445 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2446 IDXGIOutput_Release(output);
2448 /* Move the OutputWindow to the current output. */
2449 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc.DesktopCoordinates.left,
2450 output_desc.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2451 ok(ret, "Adapter %u output %u: SetWindowPos failed.\n", adapter_idx, output_idx);
2453 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
2454 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n",
2455 adapter_idx, output_idx, hr);
2456 ok(fullscreen, "Adapter %u output %u: Expect swapchain full screen.\n", adapter_idx,
2457 output_idx);
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 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2463 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2464 ok(output == output2, "Adapter %u output %u: Expect output %p, got %p.\n",
2465 adapter_idx, output_idx, output2, output);
2466 IDXGIOutput_Release(output);
2468 IDXGIAdapter_Release(adapter);
2471 IDXGIOutput_Release(output2);
2472 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2473 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2475 /* Test GetContainingOutput after a full screen swapchain is made windowed by pressing
2476 * Alt+Enter, then move it to another output and use Alt+Enter to enter full screen */
2477 output = NULL;
2478 output2 = NULL;
2479 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2480 ++adapter_idx)
2482 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx,
2483 output ? &output2 : &output)); ++output_idx)
2485 if (output2)
2486 break;
2489 IDXGIAdapter_Release(adapter);
2490 if (output2)
2491 break;
2494 if (output && output2)
2496 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2497 IDXGIOutput_Release(output);
2498 if (FAILED(hr))
2500 skip("SetFullscreenState failed, hr %#lx.\n", hr);
2501 IDXGIOutput_Release(output2);
2502 goto done;
2505 /* Post an Alt + VK_RETURN WM_SYSKEYDOWN to leave full screen on the first output */
2506 PostMessageA(swapchain_desc.OutputWindow, WM_SYSKEYDOWN, VK_RETURN,
2507 (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x20000001);
2508 flush_events();
2509 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2510 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2511 ok(!fullscreen, "Expect swapchain not full screen.\n");
2513 /* Move the swapchain output window to the second output */
2514 hr = IDXGIOutput_GetDesc(output2, &output_desc2);
2515 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2516 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc2.DesktopCoordinates.left,
2517 output_desc2.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2518 ok(ret, "SetWindowPos failed.\n");
2520 /* Post an Alt + VK_RETURN WM_SYSKEYDOWN to enter full screen on the second output */
2521 PostMessageA(swapchain_desc.OutputWindow, WM_SYSKEYDOWN, VK_RETURN,
2522 (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x20000001);
2523 flush_events();
2524 output = NULL;
2525 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
2526 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2527 ok(fullscreen, "Expect swapchain full screen.\n");
2528 ok(!!output, "Expect output not NULL.\n");
2529 hr = IDXGIOutput_GetDesc(output, &output_desc);
2530 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2531 hr = IDXGIOutput_GetDesc(output2, &output_desc2);
2532 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2533 ok(!lstrcmpW(output_desc.DeviceName, output_desc2.DeviceName),
2534 "Expect device name %s, got %s.\n", wine_dbgstr_w(output_desc2.DeviceName),
2535 wine_dbgstr_w(output_desc.DeviceName));
2536 IDXGIOutput_Release(output);
2538 output = NULL;
2539 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2540 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2541 hr = IDXGIOutput_GetDesc(output, &output_desc);
2542 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2543 hr = IDXGIOutput_GetDesc(output2, &output_desc2);
2544 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2545 ok(!lstrcmpW(output_desc.DeviceName, output_desc2.DeviceName),
2546 "Expect device name %s, got %s.\n", wine_dbgstr_w(output_desc2.DeviceName),
2547 wine_dbgstr_w(output_desc.DeviceName));
2549 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2550 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2552 else
2554 skip("This test requires two outputs.\n");
2557 if (output)
2558 IDXGIOutput_Release(output);
2559 if (output2)
2560 IDXGIOutput_Release(output2);
2562 done:
2563 refcount = IDXGISwapChain_Release(swapchain);
2564 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2565 refcount = IDXGIFactory_Release(factory);
2566 ok(refcount == !is_d3d12, "IDXGIFactory has %lu references left.\n", refcount);
2567 DestroyWindow(swapchain_desc.OutputWindow);
2570 static void test_swapchain_fullscreen_state(IDXGISwapChain *swapchain,
2571 IDXGIAdapter *adapter, const struct swapchain_fullscreen_state *initial_state)
2573 MONITORINFOEXW monitor_info, *output_monitor_info;
2574 struct swapchain_fullscreen_state expected_state;
2575 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2576 DXGI_OUTPUT_DESC output_desc;
2577 unsigned int i, output_count;
2578 IDXGIOutput *output;
2579 HRESULT hr;
2580 BOOL ret;
2582 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
2583 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2585 check_swapchain_fullscreen_state(swapchain, initial_state);
2587 expected_state = *initial_state;
2588 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2589 &swapchain_desc, &initial_state->fullscreen_state.monitor_rect, 800, 600, NULL);
2590 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
2591 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2593 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2594 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#lx.\n", hr);
2595 if (FAILED(hr))
2597 skip("Could not change fullscreen state.\n");
2598 IDXGIOutput_Release(expected_state.target);
2599 return;
2601 check_swapchain_fullscreen_state(swapchain, &expected_state);
2603 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2604 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2605 check_swapchain_fullscreen_state(swapchain, &expected_state);
2607 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2608 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2609 check_swapchain_fullscreen_state(swapchain, initial_state);
2611 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2612 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2613 check_swapchain_fullscreen_state(swapchain, initial_state);
2615 IDXGIOutput_Release(expected_state.target);
2616 expected_state.target = NULL;
2618 output_count = 0;
2619 while (IDXGIAdapter_EnumOutputs(adapter, output_count, &output) != DXGI_ERROR_NOT_FOUND)
2621 IDXGIOutput_Release(output);
2622 ++output_count;
2625 output_monitor_info = heap_calloc(output_count, sizeof(*output_monitor_info));
2626 ok(!!output_monitor_info, "Failed to allocate memory.\n");
2627 for (i = 0; i < output_count; ++i)
2629 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
2630 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2632 hr = IDXGIOutput_GetDesc(output, &output_desc);
2633 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2635 output_monitor_info[i].cbSize = sizeof(*output_monitor_info);
2636 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&output_monitor_info[i]);
2637 ok(ret, "Failed to get monitor info.\n");
2639 IDXGIOutput_Release(output);
2642 for (i = 0; i < output_count; ++i)
2644 RECT orig_monitor_rect = output_monitor_info[i].rcMonitor;
2645 IDXGIOutput *target;
2646 BOOL fullscreen;
2648 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
2649 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2650 hr = IDXGIOutput_GetDesc(output, &output_desc);
2651 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2653 expected_state = *initial_state;
2654 expected_state.target = output;
2655 expected_state.fullscreen_state.monitor = output_desc.Monitor;
2656 expected_state.fullscreen_state.monitor_rect = orig_monitor_rect;
2657 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
2658 &swapchain_desc, &orig_monitor_rect, 800, 600, NULL);
2660 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2661 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2662 check_swapchain_fullscreen_state(swapchain, &expected_state);
2664 target = NULL;
2665 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
2666 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2667 ok(target == output, "Got target pointer %p, expected %p.\n", target, output);
2668 IDXGIOutput_Release(target);
2669 fullscreen = FALSE;
2670 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2671 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2672 ok(fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2674 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2675 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2676 check_swapchain_fullscreen_state(swapchain, &expected_state);
2677 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, output);
2678 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
2679 check_swapchain_fullscreen_state(swapchain, &expected_state);
2680 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2681 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2682 check_swapchain_fullscreen_state(swapchain, initial_state);
2684 fullscreen = TRUE;
2685 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2686 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2687 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2689 check_swapchain_fullscreen_state(swapchain, initial_state);
2690 monitor_info.cbSize = sizeof(monitor_info);
2691 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&monitor_info);
2692 ok(ret, "Failed to get monitor info.\n");
2693 ok(EqualRect(&monitor_info.rcMonitor, &orig_monitor_rect), "Got monitor rect %s, expected %s.\n",
2694 wine_dbgstr_rect(&monitor_info.rcMonitor), wine_dbgstr_rect(&orig_monitor_rect));
2696 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
2697 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2699 IDXGIOutput_Release(output);
2702 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2703 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2704 check_swapchain_fullscreen_state(swapchain, initial_state);
2706 for (i = 0; i < output_count; ++i)
2708 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
2709 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2711 hr = IDXGIOutput_GetDesc(output, &output_desc);
2712 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2714 monitor_info.cbSize = sizeof(monitor_info);
2715 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&monitor_info);
2716 ok(ret, "Failed to get monitor info.\n");
2718 ok(EqualRect(&monitor_info.rcMonitor, &output_monitor_info[i].rcMonitor),
2719 "Got monitor rect %s, expected %s.\n",
2720 wine_dbgstr_rect(&monitor_info.rcMonitor),
2721 wine_dbgstr_rect(&output_monitor_info[i].rcMonitor));
2723 IDXGIOutput_Release(output);
2726 heap_free(output_monitor_info);
2729 static void test_set_fullscreen(IUnknown *device, BOOL is_d3d12)
2731 struct swapchain_fullscreen_state initial_state;
2732 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2733 IDXGIAdapter *adapter = NULL;
2734 IDXGISwapChain *swapchain;
2735 IDXGIFactory *factory;
2736 IDXGIOutput *output;
2737 BOOL fullscreen;
2738 ULONG refcount;
2739 HRESULT hr;
2741 get_factory(device, is_d3d12, &factory);
2743 swapchain_desc.BufferDesc.Width = 800;
2744 swapchain_desc.BufferDesc.Height = 600;
2745 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
2746 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
2747 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2748 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
2749 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
2750 swapchain_desc.SampleDesc.Count = 1;
2751 swapchain_desc.SampleDesc.Quality = 0;
2752 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2753 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
2754 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2755 swapchain_desc.Windowed = TRUE;
2756 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
2757 swapchain_desc.Flags = 0;
2759 memset(&initial_state, 0, sizeof(initial_state));
2760 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
2761 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2762 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2763 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
2764 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
2765 "Got unexpected hr %#lx.\n", hr);
2766 if (FAILED(hr))
2768 skip("Could not get output.\n");
2769 goto done;
2771 hr = IDXGIOutput_GetParent(output, &IID_IDXGIAdapter, (void **)&adapter);
2772 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2773 IDXGIOutput_Release(output);
2775 check_swapchain_fullscreen_state(swapchain, &initial_state);
2776 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2777 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
2778 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
2779 "Got unexpected hr %#lx.\n", hr);
2780 if (FAILED(hr))
2782 skip("Could not change fullscreen state.\n");
2783 goto done;
2785 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2786 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2787 refcount = IDXGISwapChain_Release(swapchain);
2788 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2790 DestroyWindow(swapchain_desc.OutputWindow);
2791 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2792 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2793 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2794 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2795 check_swapchain_fullscreen_state(swapchain, &initial_state);
2796 test_swapchain_fullscreen_state(swapchain, adapter, &initial_state);
2797 refcount = IDXGISwapChain_Release(swapchain);
2798 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2800 DestroyWindow(swapchain_desc.OutputWindow);
2801 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2802 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2803 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2804 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2805 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2806 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2807 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2808 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2809 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2810 DestroyWindow(swapchain_desc.OutputWindow);
2811 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2812 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2813 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2814 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2815 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2816 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2817 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#lx.\n", hr);
2818 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2819 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2820 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2821 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2822 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2823 refcount = IDXGISwapChain_Release(swapchain);
2824 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2826 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2827 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2828 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2829 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2830 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2831 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2832 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2833 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2834 ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2835 DestroyWindow(swapchain_desc.OutputWindow);
2836 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2837 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2838 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2839 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2840 ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2841 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2842 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2843 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2844 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2845 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2846 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2847 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#lx.\n", hr);
2848 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
2849 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2850 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
2851 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2852 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2853 refcount = IDXGISwapChain_Release(swapchain);
2854 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2856 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
2857 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2858 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
2859 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2860 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2861 check_swapchain_fullscreen_state(swapchain, &initial_state);
2862 test_swapchain_fullscreen_state(swapchain, adapter, &initial_state);
2864 done:
2865 if (adapter)
2866 IDXGIAdapter_Release(adapter);
2867 refcount = IDXGISwapChain_Release(swapchain);
2868 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
2869 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
2870 DestroyWindow(swapchain_desc.OutputWindow);
2872 refcount = IDXGIFactory_Release(factory);
2873 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
2876 static void test_default_fullscreen_target_output(IUnknown *device, BOOL is_d3d12)
2878 IDXGIOutput *output, *containing_output, *target;
2879 unsigned int adapter_idx, output_idx;
2880 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2881 DXGI_OUTPUT_DESC output_desc;
2882 unsigned int width, height;
2883 IDXGISwapChain *swapchain;
2884 IDXGIFactory *factory;
2885 IDXGIAdapter *adapter;
2886 BOOL fullscreen, ret;
2887 RECT window_rect;
2888 ULONG refcount;
2889 HRESULT hr;
2891 get_factory(device, is_d3d12, &factory);
2893 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
2894 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
2895 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2896 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
2897 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
2898 swapchain_desc.SampleDesc.Count = 1;
2899 swapchain_desc.SampleDesc.Quality = 0;
2900 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2901 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
2902 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
2903 swapchain_desc.Flags = 0;
2905 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
2906 ++adapter_idx)
2908 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
2909 ++output_idx)
2911 /* Windowed swapchain */
2912 swapchain_desc.BufferDesc.Width = 640;
2913 swapchain_desc.BufferDesc.Height = 480;
2914 swapchain_desc.OutputWindow = create_window();
2915 swapchain_desc.Windowed = TRUE;
2916 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
2917 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2919 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &containing_output);
2920 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2921 ok(!fullscreen, "Adapter %u output %u: Expected not fullscreen.\n", adapter_idx, output_idx);
2922 ok(!containing_output, "Adapter %u output %u: Expected a null output.\n", adapter_idx, output_idx);
2924 /* Move the OutputWindow to the current output. */
2925 hr = IDXGIOutput_GetDesc(output, &output_desc);
2926 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, 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 %#lx.\n", adapter_idx,
2931 output_idx, GetLastError());
2933 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
2934 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
2935 "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2936 if (hr == DXGI_ERROR_UNSUPPORTED)
2938 win_skip("Adapter %u output %u: GetContainingOutput() not supported.\n",
2939 adapter_idx, output_idx);
2940 IDXGISwapChain_Release(swapchain);
2941 IDXGIOutput_Release(output);
2942 DestroyWindow(swapchain_desc.OutputWindow);
2943 continue;
2946 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
2947 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE,
2948 "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2949 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
2951 skip("Adapter %u output %u: Could not change fullscreen state.\n", adapter_idx,
2952 output_idx);
2953 IDXGIOutput_Release(containing_output);
2954 IDXGISwapChain_Release(swapchain);
2955 IDXGIOutput_Release(output);
2956 DestroyWindow(swapchain_desc.OutputWindow);
2957 continue;
2959 GetWindowRect(swapchain_desc.OutputWindow, &window_rect);
2960 ok(EqualRect(&window_rect, &output_desc.DesktopCoordinates),
2961 "Adapter %u output %u: Expect window rect %s, got %s.\n", adapter_idx,
2962 output_idx, wine_dbgstr_rect(&output_desc.DesktopCoordinates),
2963 wine_dbgstr_rect(&window_rect));
2965 target = NULL;
2966 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
2967 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2968 ok(target != containing_output,
2969 "Adapter %u output %u: Got unexpected output %p, expected %p.\n", adapter_idx,
2970 output_idx, target, containing_output);
2971 check_output_equal(target, containing_output);
2973 refcount = IDXGIOutput_Release(containing_output);
2974 ok(!refcount, "Adapter %u output %u: IDXGIOutput has %lu references left.\n",
2975 adapter_idx, output_idx, refcount);
2977 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
2978 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2979 ok(containing_output == target,
2980 "Adapter %u output %u: Got unexpected containing output %p, expected %p.\n",
2981 adapter_idx, output_idx, containing_output, target);
2982 refcount = IDXGIOutput_Release(containing_output);
2983 ok(refcount >= 2, "Adapter %u output %u: Got unexpected refcount %lu.\n", adapter_idx,
2984 output_idx, refcount);
2985 refcount = IDXGIOutput_Release(target);
2986 ok(refcount >= 1, "Adapter %u output %u: Got unexpected refcount %lu.\n", adapter_idx,
2987 output_idx, refcount);
2989 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2990 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
2991 refcount = IDXGISwapChain_Release(swapchain);
2992 ok(!refcount, "Adapter %u output %u: IDXGISwapChain has %lu references left.\n",
2993 adapter_idx, output_idx, refcount);
2994 DestroyWindow(swapchain_desc.OutputWindow);
2996 /* Full screen swapchain */
2997 width = output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left;
2998 height = output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top;
2999 swapchain_desc.BufferDesc.Width = width;
3000 swapchain_desc.BufferDesc.Height = height;
3001 swapchain_desc.OutputWindow = create_window();
3002 swapchain_desc.Windowed = FALSE;
3003 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, output_desc.DesktopCoordinates.left,
3004 output_desc.DesktopCoordinates.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
3005 ok(ret, "Adapter %u output %u: SetWindowPos failed, error %#lx.\n", adapter_idx,
3006 output_idx, GetLastError());
3007 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
3008 if (FAILED(hr))
3010 skip("Adapter %u output %u: CreateSwapChain failed, hr %#lx.\n", adapter_idx,
3011 output_idx, hr);
3012 IDXGIOutput_Release(output);
3013 DestroyWindow(swapchain_desc.OutputWindow);
3014 continue;
3017 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &containing_output);
3018 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
3019 ok(fullscreen, "Adapter %u output %u: Expected fullscreen.\n", adapter_idx, output_idx);
3020 ok(!!containing_output, "Adapter %u output %u: Expected a valid output.\n", adapter_idx, output_idx);
3021 if (containing_output)
3022 IDXGIOutput_Release(containing_output);
3024 ret = GetWindowRect(swapchain_desc.OutputWindow, &window_rect);
3025 ok(ret, "Adapter %u output %u: GetWindowRect failed, error %#lx.\n", adapter_idx,
3026 output_idx, GetLastError());
3027 ok(EqualRect(&window_rect, &output_desc.DesktopCoordinates),
3028 "Adapter %u output %u: Expect window rect %s, got %s.\n", adapter_idx,
3029 output_idx, wine_dbgstr_rect(&output_desc.DesktopCoordinates),
3030 wine_dbgstr_rect(&window_rect));
3032 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
3033 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
3034 ok(containing_output != output,
3035 "Adapter %u output %u: Got unexpected output %p, expected %p.\n", adapter_idx,
3036 output_idx, output, containing_output);
3037 check_output_equal(output, containing_output);
3038 IDXGIOutput_Release(containing_output);
3040 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3041 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
3042 refcount = IDXGISwapChain_Release(swapchain);
3043 ok(!refcount, "Adapter %u output %u: IDXGISwapChain has %lu references left.\n",
3044 adapter_idx, output_idx, refcount);
3045 refcount = IDXGIOutput_Release(output);
3046 ok(!refcount, "Adapter %u output %u: IDXGIOutput has %lu references left.\n",
3047 adapter_idx, output_idx, refcount);
3048 DestroyWindow(swapchain_desc.OutputWindow);
3050 IDXGIAdapter_Release(adapter);
3053 refcount = IDXGIFactory_Release(factory);
3054 ok(refcount == !is_d3d12, "IDXGIFactory has %lu references left.\n", refcount);
3057 static void test_windowed_resize_target(IDXGISwapChain *swapchain, HWND window,
3058 struct swapchain_fullscreen_state *state)
3060 struct swapchain_fullscreen_state expected_state;
3061 struct fullscreen_state *e;
3062 DXGI_MODE_DESC mode;
3063 RECT window_rect;
3064 unsigned int i;
3065 HRESULT hr;
3066 BOOL ret;
3068 static const struct
3070 unsigned int width, height;
3072 sizes[] =
3074 {200, 200},
3075 {400, 200},
3076 {400, 400},
3077 {600, 800},
3078 {1000, 600},
3079 {1600, 100},
3080 {2000, 1000},
3083 check_swapchain_fullscreen_state(swapchain, state);
3084 expected_state = *state;
3085 e = &expected_state.fullscreen_state;
3087 for (i = 0; i < ARRAY_SIZE(sizes); ++i)
3089 SetRect(&e->client_rect, 0, 0, sizes[i].width, sizes[i].height);
3090 e->window_rect = e->client_rect;
3091 ret = AdjustWindowRectEx(&e->window_rect, GetWindowLongW(window, GWL_STYLE),
3092 FALSE, GetWindowLongW(window, GWL_EXSTYLE));
3093 ok(ret, "AdjustWindowRectEx failed.\n");
3094 if (GetMenu(window))
3095 e->client_rect.bottom -= GetSystemMetrics(SM_CYMENU);
3096 SetRect(&e->window_rect, 0, 0,
3097 e->window_rect.right - e->window_rect.left,
3098 e->window_rect.bottom - e->window_rect.top);
3099 GetWindowRect(window, &window_rect);
3100 OffsetRect(&e->window_rect, window_rect.left, window_rect.top);
3101 if (e->window_rect.right >= e->monitor_rect.right
3102 || e->window_rect.bottom >= e->monitor_rect.bottom)
3104 skip("Test %u: Window %s does not fit on screen %s.\n",
3105 i, wine_dbgstr_rect(&e->window_rect), wine_dbgstr_rect(&e->monitor_rect));
3106 continue;
3109 memset(&mode, 0, sizeof(mode));
3110 mode.Width = sizes[i].width;
3111 mode.Height = sizes[i].height;
3112 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
3113 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3114 check_swapchain_fullscreen_state(swapchain, &expected_state);
3117 ret = SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER);
3118 ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
3119 GetWindowRect(window, &e->window_rect);
3120 GetClientRect(window, &e->client_rect);
3121 ret = SetWindowPos(window, 0, 0, 0, 200, 200, SWP_NOMOVE | SWP_NOZORDER);
3122 ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
3124 memset(&mode, 0, sizeof(mode));
3125 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
3126 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3127 check_swapchain_fullscreen_state(swapchain, &expected_state);
3129 GetWindowRect(window, &e->window_rect);
3130 GetClientRect(window, &e->client_rect);
3131 *state = expected_state;
3134 static void test_fullscreen_resize_target(IDXGISwapChain *swapchain,
3135 const struct swapchain_fullscreen_state *initial_state)
3137 struct swapchain_fullscreen_state expected_state;
3138 DXGI_SWAP_CHAIN_DESC swapchain_desc;
3139 DXGI_OUTPUT_DESC output_desc;
3140 unsigned int i, mode_count;
3141 DXGI_MODE_DESC *modes;
3142 IDXGIOutput *target;
3143 HRESULT hr;
3145 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
3146 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3148 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
3149 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3151 hr = IDXGIOutput_GetDisplayModeList(target, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
3152 ok(hr == S_OK || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Win 7 testbot */
3153 "Got unexpected hr %#lx.\n", hr);
3154 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
3156 win_skip("GetDisplayModeList() not supported.\n");
3157 IDXGIOutput_Release(target);
3158 return;
3161 modes = heap_calloc(mode_count, sizeof(*modes));
3162 ok(!!modes, "Failed to allocate memory.\n");
3164 hr = IDXGIOutput_GetDisplayModeList(target, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes);
3165 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3167 expected_state = *initial_state;
3168 for (i = 0; i < min(mode_count, 20); ++i)
3170 /* FIXME: Modes with scaling aren't fully tested. */
3171 if (!(swapchain_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)
3172 && modes[i].Scaling != DXGI_MODE_SCALING_UNSPECIFIED)
3173 continue;
3175 hr = IDXGIOutput_GetDesc(target, &output_desc);
3176 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3178 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
3179 &swapchain_desc, &output_desc.DesktopCoordinates, modes[i].Width, modes[i].Height, NULL);
3181 hr = IDXGISwapChain_ResizeTarget(swapchain, &modes[i]);
3182 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#lx.\n", hr);
3183 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
3185 skip("Failed to change to video mode %u.\n", i);
3186 break;
3188 check_swapchain_fullscreen_state(swapchain, &expected_state);
3190 hr = IDXGIOutput_GetDesc(target, &output_desc);
3191 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3192 ok(EqualRect(&output_desc.DesktopCoordinates, &expected_state.fullscreen_state.monitor_rect),
3193 "Got desktop coordinates %s, expected %s.\n",
3194 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
3195 wine_dbgstr_rect(&expected_state.fullscreen_state.monitor_rect));
3198 heap_free(modes);
3199 IDXGIOutput_Release(target);
3202 static void test_resize_target(IUnknown *device, BOOL is_d3d12)
3204 struct swapchain_fullscreen_state initial_state, expected_state;
3205 unsigned int adapter_idx, output_idx, test_idx;
3206 DXGI_SWAP_CHAIN_DESC swapchain_desc;
3207 DXGI_OUTPUT_DESC output_desc;
3208 IDXGISwapChain *swapchain;
3209 IDXGIFactory *factory;
3210 IDXGIAdapter *adapter;
3211 IDXGIOutput *output;
3212 ULONG refcount;
3213 HRESULT hr;
3215 static const struct
3217 POINT origin;
3218 BOOL fullscreen;
3219 BOOL menu;
3220 unsigned int flags;
3222 tests[] =
3224 {{ 0, 0}, TRUE, FALSE, 0},
3225 {{10, 10}, TRUE, FALSE, 0},
3226 {{ 0, 0}, TRUE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3227 {{10, 10}, TRUE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3228 {{ 0, 0}, FALSE, FALSE, 0},
3229 {{ 0, 0}, FALSE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3230 {{10, 10}, FALSE, FALSE, 0},
3231 {{10, 10}, FALSE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3232 {{ 0, 0}, FALSE, TRUE, 0},
3233 {{ 0, 0}, FALSE, TRUE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3234 {{10, 10}, FALSE, TRUE, 0},
3235 {{10, 10}, FALSE, TRUE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
3238 get_factory(device, is_d3d12, &factory);
3240 swapchain_desc.BufferDesc.Width = 800;
3241 swapchain_desc.BufferDesc.Height = 600;
3242 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
3243 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
3244 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
3245 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
3246 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
3247 swapchain_desc.SampleDesc.Count = 1;
3248 swapchain_desc.SampleDesc.Quality = 0;
3249 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3250 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
3251 swapchain_desc.Windowed = TRUE;
3252 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
3253 swapchain_desc.Flags = 0;
3255 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
3256 ++adapter_idx)
3258 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
3259 ++output_idx)
3261 hr = IDXGIOutput_GetDesc(output, &output_desc);
3262 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
3264 for (test_idx = 0; test_idx < ARRAY_SIZE(tests); ++test_idx)
3266 swapchain_desc.Flags = tests[test_idx].flags;
3267 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0,
3268 output_desc.DesktopCoordinates.left + tests[test_idx].origin.x,
3269 output_desc.DesktopCoordinates.top + tests[test_idx].origin.y,
3270 400, 200, 0, 0, 0, 0);
3271 if (tests[test_idx].menu)
3273 HMENU menu_bar = CreateMenu();
3274 HMENU menu = CreateMenu();
3275 AppendMenuA(menu_bar, MF_POPUP, (UINT_PTR)menu, "Menu");
3276 SetMenu(swapchain_desc.OutputWindow, menu_bar);
3279 memset(&initial_state, 0, sizeof(initial_state));
3280 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
3282 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
3283 ok(hr == S_OK, "Adapter %u output %u test %u: Got unexpected hr %#lx.\n",
3284 adapter_idx, output_idx, test_idx, hr);
3285 check_swapchain_fullscreen_state(swapchain, &initial_state);
3287 expected_state = initial_state;
3288 if (tests[test_idx].fullscreen)
3290 expected_state.fullscreen = TRUE;
3291 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
3292 &swapchain_desc, &initial_state.fullscreen_state.monitor_rect, 800, 600, NULL);
3293 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
3294 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
3295 "Adapter %u output %u test %u: Got unexpected hr %#lx.\n",
3296 adapter_idx, output_idx, test_idx, hr);
3297 if (hr == DXGI_ERROR_UNSUPPORTED)
3299 win_skip("Adapter %u output %u test %u: GetContainingOutput() not supported.\n",
3300 adapter_idx, output_idx, test_idx);
3301 IDXGISwapChain_Release(swapchain);
3302 DestroyWindow(swapchain_desc.OutputWindow);
3303 continue;
3306 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
3307 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE,
3308 "Adapter %u output %u test %u: Got unexpected hr %#lx.\n",
3309 adapter_idx, output_idx, test_idx, hr);
3310 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
3312 skip("Adapter %u output %u test %u: Could not change fullscreen state.\n",
3313 adapter_idx, output_idx, test_idx);
3314 IDXGIOutput_Release(expected_state.target);
3315 IDXGISwapChain_Release(swapchain);
3316 DestroyWindow(swapchain_desc.OutputWindow);
3317 continue;
3320 check_swapchain_fullscreen_state(swapchain, &expected_state);
3322 hr = IDXGISwapChain_ResizeTarget(swapchain, NULL);
3323 ok(hr == DXGI_ERROR_INVALID_CALL, "Adapter %u output %u test %u: Got unexpected hr %#lx.\n",
3324 adapter_idx, output_idx, test_idx, hr);
3325 check_swapchain_fullscreen_state(swapchain, &expected_state);
3327 if (tests[test_idx].fullscreen)
3329 test_fullscreen_resize_target(swapchain, &expected_state);
3331 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3332 ok(hr == S_OK, "Adapter %u output %u test %u: Got unexpected hr %#lx.\n",
3333 adapter_idx, output_idx, test_idx, hr);
3334 check_swapchain_fullscreen_state(swapchain, &initial_state);
3335 IDXGIOutput_Release(expected_state.target);
3336 check_swapchain_fullscreen_state(swapchain, &initial_state);
3337 expected_state = initial_state;
3339 else
3341 test_windowed_resize_target(swapchain, swapchain_desc.OutputWindow, &expected_state);
3343 check_swapchain_fullscreen_state(swapchain, &expected_state);
3346 refcount = IDXGISwapChain_Release(swapchain);
3347 ok(!refcount, "Adapter %u output %u test %u: IDXGISwapChain has %lu references left.\n",
3348 adapter_idx, output_idx, test_idx, refcount);
3349 check_window_fullscreen_state(swapchain_desc.OutputWindow, &expected_state.fullscreen_state);
3350 DestroyWindow(swapchain_desc.OutputWindow);
3352 IDXGIOutput_Release(output);
3354 IDXGIAdapter_Release(adapter);
3356 refcount = IDXGIFactory_Release(factory);
3357 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
3360 static LRESULT CALLBACK resize_target_wndproc(HWND hwnd, unsigned int message, WPARAM wparam, LPARAM lparam)
3362 IDXGISwapChain *swapchain = (IDXGISwapChain *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
3363 DXGI_SWAP_CHAIN_DESC desc;
3364 HRESULT hr;
3366 switch (message)
3368 case WM_SIZE:
3369 ok(!!swapchain, "GWLP_USERDATA is NULL.\n");
3370 hr = IDXGISwapChain_GetDesc(swapchain, &desc);
3371 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3372 ok(desc.BufferDesc.Width == 800, "Got unexpected buffer width %u.\n", desc.BufferDesc.Width);
3373 ok(desc.BufferDesc.Height == 600, "Got unexpected buffer height %u.\n", desc.BufferDesc.Height);
3374 return 0;
3376 default:
3377 return DefWindowProcA(hwnd, message, wparam, lparam);
3381 struct window_thread_data
3383 HWND window;
3384 HANDLE window_created;
3385 HANDLE finished;
3388 static DWORD WINAPI window_thread(void *data)
3390 struct window_thread_data *thread_data = data;
3391 unsigned int ret;
3392 WNDCLASSA wc;
3393 MSG msg;
3395 memset(&wc, 0, sizeof(wc));
3396 wc.lpfnWndProc = resize_target_wndproc;
3397 wc.lpszClassName = "dxgi_resize_target_wndproc_wc";
3398 ok(RegisterClassA(&wc), "Failed to register window class.\n");
3400 thread_data->window = CreateWindowA("dxgi_resize_target_wndproc_wc", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
3401 ok(!!thread_data->window, "Failed to create window.\n");
3403 ret = SetEvent(thread_data->window_created);
3404 ok(ret, "Failed to set event, last error %#lx.\n", GetLastError());
3406 for (;;)
3408 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3409 DispatchMessageA(&msg);
3411 ret = WaitForSingleObject(thread_data->finished, 0);
3412 if (ret != WAIT_TIMEOUT)
3413 break;
3415 ok(ret == WAIT_OBJECT_0, "Failed to wait for event, ret %#x, last error %#lx.\n", ret, GetLastError());
3417 DestroyWindow(thread_data->window);
3418 thread_data->window = NULL;
3420 UnregisterClassA("dxgi_test_wndproc_wc", GetModuleHandleA(NULL));
3422 return 0;
3425 static void test_resize_target_wndproc(void)
3427 struct window_thread_data thread_data;
3428 DXGI_SWAP_CHAIN_DESC swapchain_desc;
3429 IDXGISwapChain *swapchain;
3430 IDXGIFactory *factory;
3431 IDXGIAdapter *adapter;
3432 DXGI_MODE_DESC mode;
3433 IDXGIDevice *device;
3434 unsigned int ret;
3435 ULONG refcount;
3436 LONG_PTR data;
3437 HANDLE thread;
3438 HRESULT hr;
3439 RECT rect;
3441 if (!(device = create_device(0)))
3443 skip("Failed to create device.\n");
3444 return;
3447 memset(&thread_data, 0, sizeof(thread_data));
3448 thread_data.window_created = CreateEventA(NULL, FALSE, FALSE, NULL);
3449 ok(!!thread_data.window_created, "Failed to create event, last error %#lx.\n", GetLastError());
3450 thread_data.finished = CreateEventA(NULL, FALSE, FALSE, NULL);
3451 ok(!!thread_data.finished, "Failed to create event, last error %#lx.\n", GetLastError());
3453 thread = CreateThread(NULL, 0, window_thread, &thread_data, 0, NULL);
3454 ok(!!thread, "Failed to create thread, last error %#lx.\n", GetLastError());
3455 ret = WaitForSingleObject(thread_data.window_created, INFINITE);
3456 ok(ret == WAIT_OBJECT_0, "Failed to wait for thread, ret %#x, last error %#lx.\n", ret, GetLastError());
3458 hr = IDXGIDevice_GetAdapter(device, &adapter);
3459 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3460 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
3461 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3463 swapchain_desc.BufferDesc.Width = 800;
3464 swapchain_desc.BufferDesc.Height = 600;
3465 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
3466 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
3467 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
3468 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
3469 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
3470 swapchain_desc.SampleDesc.Count = 1;
3471 swapchain_desc.SampleDesc.Quality = 0;
3472 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3473 swapchain_desc.BufferCount = 1;
3474 swapchain_desc.OutputWindow = thread_data.window;
3475 swapchain_desc.Windowed = TRUE;
3476 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
3477 swapchain_desc.Flags = 0;
3478 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3479 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3481 data = SetWindowLongPtrA(thread_data.window, GWLP_USERDATA, (LONG_PTR)swapchain);
3482 ok(!data, "Got unexpected GWLP_USERDATA %p.\n", (void *)data);
3484 memset(&mode, 0, sizeof(mode));
3485 mode.Width = 600;
3486 mode.Height = 400;
3487 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
3488 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3490 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
3491 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3492 ok(swapchain_desc.BufferDesc.Width == 800,
3493 "Got unexpected buffer width %u.\n", swapchain_desc.BufferDesc.Width);
3494 ok(swapchain_desc.BufferDesc.Height == 600,
3495 "Got unexpected buffer height %u.\n", swapchain_desc.BufferDesc.Height);
3497 ret = GetClientRect(swapchain_desc.OutputWindow, &rect);
3498 ok(ret, "Failed to get client rect.\n");
3499 ok(rect.right == mode.Width && rect.bottom == mode.Height,
3500 "Got unexpected client rect %s.\n", wine_dbgstr_rect(&rect));
3502 refcount = IDXGISwapChain_Release(swapchain);
3503 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
3505 IDXGIAdapter_Release(adapter);
3506 refcount = IDXGIDevice_Release(device);
3507 ok(!refcount, "Device has %lu references left.\n", refcount);
3508 refcount = IDXGIFactory_Release(factory);
3509 ok(!refcount, "Factory has %lu references left.\n", refcount);
3511 ret = SetEvent(thread_data.finished);
3512 ok(ret, "Failed to set event, last error %#lx.\n", GetLastError());
3513 ret = WaitForSingleObject(thread, INFINITE);
3514 ok(ret == WAIT_OBJECT_0, "Failed to wait for thread, ret %#x, last error %#lx.\n", ret, GetLastError());
3515 CloseHandle(thread);
3516 CloseHandle(thread_data.window_created);
3517 CloseHandle(thread_data.finished);
3520 static void test_inexact_modes(void)
3522 struct swapchain_fullscreen_state initial_state, expected_state;
3523 DXGI_SWAP_CHAIN_DESC swapchain_desc, result_desc;
3524 IDXGIOutput *output = NULL;
3525 IDXGISwapChain *swapchain;
3526 IDXGIFactory *factory;
3527 IDXGIAdapter *adapter;
3528 IDXGIDevice *device;
3529 unsigned int i;
3530 ULONG refcount;
3531 HRESULT hr;
3533 static const struct
3535 unsigned int width, height;
3537 sizes[] =
3539 {101, 101},
3540 {203, 204},
3541 {799, 601},
3544 if (!(device = create_device(0)))
3546 skip("Failed to create device.\n");
3547 return;
3550 hr = IDXGIDevice_GetAdapter(device, &adapter);
3551 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3553 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
3554 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3556 swapchain_desc.BufferDesc.Width = 800;
3557 swapchain_desc.BufferDesc.Height = 600;
3558 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
3559 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
3560 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
3561 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
3562 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
3563 swapchain_desc.SampleDesc.Count = 1;
3564 swapchain_desc.SampleDesc.Quality = 0;
3565 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3566 swapchain_desc.BufferCount = 1;
3567 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
3568 swapchain_desc.Windowed = FALSE;
3569 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
3570 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
3572 memset(&initial_state, 0, sizeof(initial_state));
3573 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
3575 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3576 ok(hr == S_OK || hr == DXGI_STATUS_OCCLUDED, "Got unexpected hr %#lx.\n", hr);
3577 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3578 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3579 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3580 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3581 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
3582 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
3583 "Got unexpected hr %#lx.\n", hr);
3584 refcount = IDXGISwapChain_Release(swapchain);
3585 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
3586 if (hr == DXGI_ERROR_UNSUPPORTED)
3588 win_skip("GetContainingOutput() not supported.\n");
3589 goto done;
3591 if (result_desc.Windowed)
3593 win_skip("Fullscreen not supported.\n");
3594 goto done;
3597 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
3599 for (i = 0; i < ARRAY_SIZE(sizes); ++i)
3601 /* Test CreateSwapChain(). */
3602 swapchain_desc.BufferDesc.Width = sizes[i].width;
3603 swapchain_desc.BufferDesc.Height = sizes[i].height;
3604 swapchain_desc.Windowed = FALSE;
3606 expected_state = initial_state;
3607 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
3608 &swapchain_desc, &initial_state.fullscreen_state.monitor_rect,
3609 sizes[i].width, sizes[i].height, output);
3611 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3612 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3614 check_swapchain_fullscreen_state(swapchain, &expected_state);
3615 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3616 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3617 ok(result_desc.BufferDesc.Width == sizes[i].width, "Got width %u, expected %u.\n",
3618 result_desc.BufferDesc.Width, sizes[i].width);
3619 ok(result_desc.BufferDesc.Height == sizes[i].height, "Got height %u, expected %u.\n",
3620 result_desc.BufferDesc.Height, sizes[i].height);
3622 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3623 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3624 check_swapchain_fullscreen_state(swapchain, &initial_state);
3626 refcount = IDXGISwapChain_Release(swapchain);
3627 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
3629 /* Test SetFullscreenState(). */
3630 swapchain_desc.BufferDesc.Width = sizes[i].width;
3631 swapchain_desc.BufferDesc.Height = sizes[i].height;
3632 swapchain_desc.Windowed = TRUE;
3634 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3635 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3637 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
3638 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3640 check_swapchain_fullscreen_state(swapchain, &expected_state);
3641 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3642 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3643 ok(result_desc.BufferDesc.Width == sizes[i].width, "Got width %u, expected %u.\n",
3644 result_desc.BufferDesc.Width, sizes[i].width);
3645 ok(result_desc.BufferDesc.Height == sizes[i].height, "Got height %u, expected %u.\n",
3646 result_desc.BufferDesc.Height, sizes[i].height);
3648 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3649 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3650 check_swapchain_fullscreen_state(swapchain, &initial_state);
3652 refcount = IDXGISwapChain_Release(swapchain);
3653 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
3655 /* Test ResizeTarget(). */
3656 swapchain_desc.BufferDesc.Width = 800;
3657 swapchain_desc.BufferDesc.Height = 600;
3658 swapchain_desc.Windowed = TRUE;
3660 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
3661 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3663 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
3664 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3666 swapchain_desc.BufferDesc.Width = sizes[i].width;
3667 swapchain_desc.BufferDesc.Height = sizes[i].height;
3668 hr = IDXGISwapChain_ResizeTarget(swapchain, &swapchain_desc.BufferDesc);
3669 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3671 check_swapchain_fullscreen_state(swapchain, &expected_state);
3672 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
3673 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3674 ok(result_desc.BufferDesc.Width == 800, "Got width %u.\n", result_desc.BufferDesc.Width);
3675 ok(result_desc.BufferDesc.Height == 600, "Got height %u.\n", result_desc.BufferDesc.Height);
3677 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
3678 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3679 check_swapchain_fullscreen_state(swapchain, &initial_state);
3681 refcount = IDXGISwapChain_Release(swapchain);
3682 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
3685 done:
3686 if (output)
3687 IDXGIOutput_Release(output);
3688 IDXGIAdapter_Release(adapter);
3689 refcount = IDXGIDevice_Release(device);
3690 ok(!refcount, "Device has %lu references left.\n", refcount);
3691 refcount = IDXGIFactory_Release(factory);
3692 ok(!refcount, "Factory has %lu references left.\n", refcount);
3693 DestroyWindow(swapchain_desc.OutputWindow);
3696 static void test_create_factory(void)
3698 IUnknown *iface;
3699 ULONG refcount;
3700 HRESULT hr;
3702 iface = (void *)0xdeadbeef;
3703 hr = CreateDXGIFactory(&IID_IDXGIDevice, (void **)&iface);
3704 ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
3705 ok(!iface, "Got unexpected iface %p.\n", iface);
3707 hr = CreateDXGIFactory(&IID_IUnknown, (void **)&iface);
3708 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3709 IUnknown_Release(iface);
3711 hr = CreateDXGIFactory(&IID_IDXGIObject, (void **)&iface);
3712 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3713 IUnknown_Release(iface);
3715 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&iface);
3716 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3717 check_interface(iface, &IID_IDXGIFactory1, FALSE, FALSE);
3718 IUnknown_Release(iface);
3720 iface = (void *)0xdeadbeef;
3721 hr = CreateDXGIFactory(&IID_IDXGIFactory1, (void **)&iface);
3722 ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
3723 ok(!iface, "Got unexpected iface %p.\n", iface);
3725 iface = NULL;
3726 hr = CreateDXGIFactory(&IID_IDXGIFactory2, (void **)&iface);
3727 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
3728 "Got unexpected hr %#lx.\n", hr);
3729 if (SUCCEEDED(hr))
3731 refcount = IUnknown_Release(iface);
3732 ok(!refcount, "Factory has %lu references left.\n", refcount);
3735 if (!pCreateDXGIFactory1)
3737 win_skip("CreateDXGIFactory1 not available.\n");
3738 return;
3741 iface = (void *)0xdeadbeef;
3742 hr = pCreateDXGIFactory1(&IID_IDXGIDevice, (void **)&iface);
3743 ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
3744 ok(!iface, "Got unexpected iface %p.\n", iface);
3746 hr = pCreateDXGIFactory1(&IID_IUnknown, (void **)&iface);
3747 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3748 IUnknown_Release(iface);
3750 hr = pCreateDXGIFactory1(&IID_IDXGIObject, (void **)&iface);
3751 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3752 IUnknown_Release(iface);
3754 hr = pCreateDXGIFactory1(&IID_IDXGIFactory, (void **)&iface);
3755 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3756 check_interface(iface, &IID_IDXGIFactory1, TRUE, FALSE);
3757 refcount = IUnknown_Release(iface);
3758 ok(!refcount, "Factory has %lu references left.\n", refcount);
3760 hr = pCreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&iface);
3761 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3762 IUnknown_Release(iface);
3764 iface = NULL;
3765 hr = pCreateDXGIFactory1(&IID_IDXGIFactory2, (void **)&iface);
3766 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
3767 "Got unexpected hr %#lx.\n", hr);
3768 if (SUCCEEDED(hr))
3770 refcount = IUnknown_Release(iface);
3771 ok(!refcount, "Factory has %lu references left.\n", refcount);
3774 if (!pCreateDXGIFactory2)
3776 win_skip("CreateDXGIFactory2 not available.\n");
3777 return;
3780 hr = pCreateDXGIFactory2(0, &IID_IDXGIFactory3, (void **)&iface);
3781 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3782 check_interface(iface, &IID_IDXGIFactory, TRUE, FALSE);
3783 check_interface(iface, &IID_IDXGIFactory1, TRUE, FALSE);
3784 check_interface(iface, &IID_IDXGIFactory2, TRUE, FALSE);
3785 check_interface(iface, &IID_IDXGIFactory3, TRUE, FALSE);
3786 /* Not available on all Windows versions. */
3787 check_interface(iface, &IID_IDXGIFactory4, TRUE, TRUE);
3788 check_interface(iface, &IID_IDXGIFactory5, TRUE, TRUE);
3789 refcount = IUnknown_Release(iface);
3790 ok(!refcount, "Factory has %lu references left.\n", refcount);
3792 hr = pCreateDXGIFactory2(0, &IID_IDXGIFactory, (void **)&iface);
3793 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3794 check_interface(iface, &IID_IDXGIFactory, TRUE, FALSE);
3795 check_interface(iface, &IID_IDXGIFactory1, TRUE, FALSE);
3796 check_interface(iface, &IID_IDXGIFactory2, TRUE, FALSE);
3797 check_interface(iface, &IID_IDXGIFactory3, TRUE, FALSE);
3798 refcount = IUnknown_Release(iface);
3799 ok(!refcount, "Factory has %lu references left.\n", refcount);
3802 static void test_private_data(void)
3804 ULONG refcount, expected_refcount;
3805 IDXGIDevice *device;
3806 HRESULT hr;
3807 IDXGIDevice *test_object;
3808 IUnknown *ptr;
3809 static const DWORD data[] = {1, 2, 3, 4};
3810 UINT size;
3811 static const GUID dxgi_private_data_test_guid =
3813 0xfdb37466,
3814 0x428f,
3815 0x4edf,
3816 {0xa3, 0x7f, 0x9b, 0x1d, 0xf4, 0x88, 0xc5, 0xfc}
3818 static const GUID dxgi_private_data_test_guid2 =
3820 0x2e5afac2,
3821 0x87b5,
3822 0x4c10,
3823 {0x9b, 0x4b, 0x89, 0xd7, 0xd1, 0x12, 0xe7, 0x2b}
3826 if (!(device = create_device(0)))
3828 skip("Failed to create device.\n");
3829 return;
3832 test_object = create_device(0);
3834 /* SetPrivateData with a pointer of NULL has the purpose of FreePrivateData in previous
3835 * d3d versions. A successful clear returns S_OK. A redundant clear S_FALSE. Setting a
3836 * NULL interface is not considered a clear but as setting an interface pointer that
3837 * happens to be NULL. */
3838 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 0, NULL);
3839 ok(hr == S_FALSE, "Got unexpected hr %#lx.\n", hr);
3840 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
3841 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3842 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, ~0U, NULL);
3843 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3844 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, ~0U, NULL);
3845 ok(hr == S_FALSE, "Got unexpected hr %#lx.\n", hr);
3847 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
3848 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3849 size = sizeof(ptr) * 2;
3850 ptr = (IUnknown *)0xdeadbeef;
3851 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
3852 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3853 ok(!ptr, "Got unexpected pointer %p.\n", ptr);
3854 ok(size == sizeof(IUnknown *), "Got unexpected size %u.\n", size);
3856 refcount = get_refcount(test_object);
3857 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3858 (IUnknown *)test_object);
3859 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3860 expected_refcount = refcount + 1;
3861 refcount = get_refcount(test_object);
3862 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3863 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3864 (IUnknown *)test_object);
3865 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3866 refcount = get_refcount(test_object);
3867 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3869 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
3870 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3871 expected_refcount--;
3872 refcount = get_refcount(test_object);
3873 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3875 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3876 (IUnknown *)test_object);
3877 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3878 size = sizeof(data);
3879 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, size, data);
3880 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3881 refcount = get_refcount(test_object);
3882 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3883 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 42, NULL);
3884 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3885 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 42, NULL);
3886 ok(hr == S_FALSE, "Got unexpected hr %#lx.\n", hr);
3888 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
3889 (IUnknown *)test_object);
3890 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3891 expected_refcount++;
3892 size = 2 * sizeof(ptr);
3893 ptr = NULL;
3894 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
3895 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3896 ok(size == sizeof(test_object), "Got unexpected size %u.\n", size);
3897 expected_refcount++;
3898 refcount = get_refcount(test_object);
3899 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3900 if (ptr)
3901 IUnknown_Release(ptr);
3902 expected_refcount--;
3904 ptr = (IUnknown *)0xdeadbeef;
3905 size = 1;
3906 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, NULL);
3907 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3908 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
3909 size = 2 * sizeof(ptr);
3910 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, NULL);
3911 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
3912 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
3913 refcount = get_refcount(test_object);
3914 ok(refcount == expected_refcount, "Got unexpected refcount %lu, expected %lu.\n", refcount, expected_refcount);
3916 size = 1;
3917 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
3918 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#lx.\n", hr);
3919 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
3920 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
3921 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid2, NULL, NULL);
3922 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
3923 size = 0xdeadbabe;
3924 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid2, &size, &ptr);
3925 ok(hr == DXGI_ERROR_NOT_FOUND, "Got unexpected hr %#lx.\n", hr);
3926 ok(size == 0, "Got unexpected size %u.\n", size);
3927 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
3928 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, NULL, &ptr);
3929 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
3930 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
3932 refcount = IDXGIDevice_Release(device);
3933 ok(!refcount, "Device has %lu references left.\n", refcount);
3934 refcount = IDXGIDevice_Release(test_object);
3935 ok(!refcount, "Test object has %lu references left.\n", refcount);
3938 #define check_surface_desc(a, b) check_surface_desc_(__LINE__, a, b)
3939 static void check_surface_desc_(unsigned int line, IDXGISurface *surface,
3940 const DXGI_SWAP_CHAIN_DESC *swapchain_desc)
3942 DXGI_SURFACE_DESC surface_desc;
3943 HRESULT hr;
3945 hr = IDXGISurface_GetDesc(surface, &surface_desc);
3946 ok_(__FILE__, line)(hr == S_OK, "Failed to get surface desc, hr %#lx.\n", hr);
3947 ok_(__FILE__, line)(surface_desc.Width == swapchain_desc->BufferDesc.Width,
3948 "Got Width %u, expected %u.\n", surface_desc.Width, swapchain_desc->BufferDesc.Width);
3949 ok_(__FILE__, line)(surface_desc.Height == swapchain_desc->BufferDesc.Height,
3950 "Got Height %u, expected %u.\n", surface_desc.Height, swapchain_desc->BufferDesc.Height);
3951 ok_(__FILE__, line)(surface_desc.Format == swapchain_desc->BufferDesc.Format,
3952 "Got Format %#x, expected %#x.\n", surface_desc.Format, swapchain_desc->BufferDesc.Format);
3953 ok_(__FILE__, line)(surface_desc.SampleDesc.Count == 1,
3954 "Got unexpected SampleDesc.Count %u.\n", surface_desc.SampleDesc.Count);
3955 ok_(__FILE__, line)(!surface_desc.SampleDesc.Quality,
3956 "Got unexpected SampleDesc.Quality %u.\n", surface_desc.SampleDesc.Quality);
3959 #define check_texture_desc(a, b) check_texture_desc_(__LINE__, a, b)
3960 static void check_texture_desc_(unsigned int line, ID3D10Texture2D *texture,
3961 const DXGI_SWAP_CHAIN_DESC *swapchain_desc)
3963 D3D10_TEXTURE2D_DESC texture_desc;
3965 ID3D10Texture2D_GetDesc(texture, &texture_desc);
3966 ok_(__FILE__, line)(texture_desc.Width == swapchain_desc->BufferDesc.Width,
3967 "Got Width %u, expected %u.\n", texture_desc.Width, swapchain_desc->BufferDesc.Width);
3968 ok_(__FILE__, line)(texture_desc.Height == swapchain_desc->BufferDesc.Height,
3969 "Got Height %u, expected %u.\n", texture_desc.Height, swapchain_desc->BufferDesc.Height);
3970 ok_(__FILE__, line)(texture_desc.MipLevels == 1, "Got unexpected MipLevels %u.\n", texture_desc.MipLevels);
3971 ok_(__FILE__, line)(texture_desc.ArraySize == 1, "Got unexpected ArraySize %u.\n", texture_desc.ArraySize);
3972 ok_(__FILE__, line)(texture_desc.Format == swapchain_desc->BufferDesc.Format,
3973 "Got Format %#x, expected %#x.\n", texture_desc.Format, swapchain_desc->BufferDesc.Format);
3974 ok_(__FILE__, line)(texture_desc.SampleDesc.Count == 1,
3975 "Got unexpected SampleDesc.Count %u.\n", texture_desc.SampleDesc.Count);
3976 ok_(__FILE__, line)(!texture_desc.SampleDesc.Quality,
3977 "Got unexpected SampleDesc.Quality %u.\n", texture_desc.SampleDesc.Quality);
3978 ok_(__FILE__, line)(texture_desc.Usage == D3D10_USAGE_DEFAULT,
3979 "Got unexpected Usage %#x.\n", texture_desc.Usage);
3980 ok_(__FILE__, line)(texture_desc.BindFlags == D3D10_BIND_RENDER_TARGET,
3981 "Got unexpected BindFlags %#x.\n", texture_desc.BindFlags);
3982 ok_(__FILE__, line)(!texture_desc.CPUAccessFlags,
3983 "Got unexpected CPUAccessFlags %#x.\n", texture_desc.CPUAccessFlags);
3984 ok_(__FILE__, line)(!texture_desc.MiscFlags, "Got unexpected MiscFlags %#x.\n", texture_desc.MiscFlags);
3987 #define check_resource_desc(a, b) check_resource_desc_(__LINE__, a, b)
3988 static void check_resource_desc_(unsigned int line, ID3D12Resource *resource,
3989 const DXGI_SWAP_CHAIN_DESC *swapchain_desc)
3991 D3D12_RESOURCE_DESC resource_desc;
3993 resource_desc = ID3D12Resource_GetDesc(resource);
3994 ok_(__FILE__, line)(resource_desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D,
3995 "Got unexpected Dimension %#x.\n", resource_desc.Dimension);
3996 ok_(__FILE__, line)(resource_desc.Width == swapchain_desc->BufferDesc.Width, "Got Width %s, expected %u.\n",
3997 wine_dbgstr_longlong(resource_desc.Width), swapchain_desc->BufferDesc.Width);
3998 ok_(__FILE__, line)(resource_desc.Height == swapchain_desc->BufferDesc.Height,
3999 "Got Height %u, expected %u.\n", resource_desc.Height, swapchain_desc->BufferDesc.Height);
4000 ok_(__FILE__, line)(resource_desc.DepthOrArraySize == 1,
4001 "Got unexpected DepthOrArraySize %u.\n", resource_desc.DepthOrArraySize);
4002 ok_(__FILE__, line)(resource_desc.MipLevels == 1,
4003 "Got unexpected MipLevels %u.\n", resource_desc.MipLevels);
4004 ok_(__FILE__, line)(resource_desc.Format == swapchain_desc->BufferDesc.Format,
4005 "Got Format %#x, expected %#x.\n", resource_desc.Format, swapchain_desc->BufferDesc.Format);
4006 ok_(__FILE__, line)(resource_desc.SampleDesc.Count == 1,
4007 "Got unexpected SampleDesc.Count %u.\n", resource_desc.SampleDesc.Count);
4008 ok_(__FILE__, line)(!resource_desc.SampleDesc.Quality,
4009 "Got unexpected SampleDesc.Quality %u.\n", resource_desc.SampleDesc.Quality);
4010 ok_(__FILE__, line)(resource_desc.Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN,
4011 "Got unexpected Layout %#x.\n", resource_desc.Layout);
4014 static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12)
4016 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4017 DXGI_SWAP_EFFECT swap_effect;
4018 IDXGISwapChain3 *swapchain3;
4019 IUnknown *present_queue[2];
4020 IDXGISwapChain *swapchain;
4021 ID3D12Resource *resource;
4022 ID3D10Texture2D *texture;
4023 HRESULT hr, expected_hr;
4024 IDXGISurface *surface;
4025 IDXGIFactory *factory;
4026 RECT client_rect, r;
4027 UINT node_mask[2];
4028 ULONG refcount;
4029 HWND window;
4030 BOOL ret;
4032 get_factory(device, is_d3d12, &factory);
4034 window = create_window();
4035 ret = GetClientRect(window, &client_rect);
4036 ok(ret, "Failed to get client rect.\n");
4038 swap_effect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
4040 swapchain_desc.BufferDesc.Width = 640;
4041 swapchain_desc.BufferDesc.Height = 480;
4042 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
4043 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
4044 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4045 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
4046 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
4047 swapchain_desc.SampleDesc.Count = 1;
4048 swapchain_desc.SampleDesc.Quality = 0;
4049 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4050 swapchain_desc.BufferCount = 2;
4051 swapchain_desc.OutputWindow = window;
4052 swapchain_desc.Windowed = TRUE;
4053 swapchain_desc.SwapEffect = swap_effect;
4054 swapchain_desc.Flags = 0;
4056 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
4057 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4058 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface);
4059 expected_hr = is_d3d12 ? E_NOINTERFACE : S_OK;
4060 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4061 ok(!surface || hr == S_OK, "Got unexpected pointer %p.\n", surface);
4062 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&texture);
4063 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4064 ok(!texture || hr == S_OK, "Got unexpected pointer %p.\n", texture);
4065 expected_hr = is_d3d12 ? S_OK : E_NOINTERFACE;
4066 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D12Resource, (void **)&resource);
4067 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4068 ok(!resource || hr == S_OK, "Got unexpected pointer %p.\n", resource);
4070 ret = GetClientRect(window, &r);
4071 ok(ret, "Failed to get client rect.\n");
4072 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
4073 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
4075 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4076 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4077 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4078 ok(swapchain_desc.BufferDesc.Width == 640,
4079 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
4080 ok(swapchain_desc.BufferDesc.Height == 480,
4081 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
4082 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4083 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4084 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4085 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4086 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4087 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4088 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM,
4089 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4090 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4091 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4092 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4093 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4094 ok(swapchain_desc.SampleDesc.Count == 1,
4095 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4096 ok(!swapchain_desc.SampleDesc.Quality,
4097 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4098 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4099 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4100 ok(swapchain_desc.BufferCount == 2,
4101 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4102 ok(swapchain_desc.OutputWindow == window,
4103 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4104 ok(swapchain_desc.Windowed,
4105 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4106 ok(swapchain_desc.SwapEffect == swap_effect,
4107 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4108 ok(!swapchain_desc.Flags,
4109 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4111 if (surface)
4112 check_surface_desc(surface, &swapchain_desc);
4113 if (texture)
4114 check_texture_desc(texture, &swapchain_desc);
4115 if (resource)
4116 check_resource_desc(resource, &swapchain_desc);
4118 hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
4119 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4121 ret = GetClientRect(window, &r);
4122 ok(ret, "Failed to get client rect.\n");
4123 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
4124 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
4126 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4127 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4128 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4129 ok(swapchain_desc.BufferDesc.Width == 640,
4130 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
4131 ok(swapchain_desc.BufferDesc.Height == 480,
4132 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
4133 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4134 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4135 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4136 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4137 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4138 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4139 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM,
4140 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4141 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4142 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4143 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4144 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4145 ok(swapchain_desc.SampleDesc.Count == 1,
4146 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4147 ok(!swapchain_desc.SampleDesc.Quality,
4148 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4149 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4150 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4151 ok(swapchain_desc.BufferCount == 2,
4152 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4153 ok(swapchain_desc.OutputWindow == window,
4154 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4155 ok(swapchain_desc.Windowed,
4156 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4157 ok(swapchain_desc.SwapEffect == swap_effect,
4158 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4159 ok(!swapchain_desc.Flags,
4160 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4162 if (surface)
4164 check_surface_desc(surface, &swapchain_desc);
4165 IDXGISurface_Release(surface);
4167 if (texture)
4169 check_texture_desc(texture, &swapchain_desc);
4170 ID3D10Texture2D_Release(texture);
4172 if (resource)
4174 check_resource_desc(resource, &swapchain_desc);
4175 ID3D12Resource_Release(resource);
4178 hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
4179 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4180 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface);
4181 expected_hr = is_d3d12 ? E_NOINTERFACE : S_OK;
4182 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4183 ok(!surface || hr == S_OK, "Got unexpected pointer %p.\n", surface);
4184 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&texture);
4185 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4186 ok(!texture || hr == S_OK, "Got unexpected pointer %p.\n", texture);
4187 expected_hr = is_d3d12 ? S_OK : E_NOINTERFACE;
4188 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D12Resource, (void **)&resource);
4189 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4190 ok(!resource || hr == S_OK, "Got unexpected pointer %p.\n", resource);
4192 ret = GetClientRect(window, &r);
4193 ok(ret, "Failed to get client rect.\n");
4194 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
4195 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
4197 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4198 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4199 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4200 ok(swapchain_desc.BufferDesc.Width == 320,
4201 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
4202 ok(swapchain_desc.BufferDesc.Height == 240,
4203 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
4204 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4205 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4206 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4207 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4208 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4209 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4210 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM,
4211 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4212 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4213 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4214 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4215 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4216 ok(swapchain_desc.SampleDesc.Count == 1,
4217 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4218 ok(!swapchain_desc.SampleDesc.Quality,
4219 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4220 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4221 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4222 ok(swapchain_desc.BufferCount == 2,
4223 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4224 ok(swapchain_desc.OutputWindow == window,
4225 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4226 ok(swapchain_desc.Windowed,
4227 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4228 ok(swapchain_desc.SwapEffect == swap_effect,
4229 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4230 ok(!swapchain_desc.Flags,
4231 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4233 if (surface)
4235 check_surface_desc(surface, &swapchain_desc);
4236 IDXGISurface_Release(surface);
4238 if (texture)
4240 check_texture_desc(texture, &swapchain_desc);
4241 ID3D10Texture2D_Release(texture);
4243 if (resource)
4245 check_resource_desc(resource, &swapchain_desc);
4246 ID3D12Resource_Release(resource);
4249 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4250 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4252 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
4253 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
4254 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4255 ok(swapchain_desc.BufferDesc.Width == client_rect.right - client_rect.left,
4256 "Got unexpected BufferDesc.Width %u, expected %lu.\n",
4257 swapchain_desc.BufferDesc.Width, client_rect.right - client_rect.left);
4258 ok(swapchain_desc.BufferDesc.Height == client_rect.bottom - client_rect.top,
4259 "Got unexpected bufferDesc.Height %u, expected %lu.\n",
4260 swapchain_desc.BufferDesc.Height, client_rect.bottom - client_rect.top);
4261 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
4262 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
4263 swapchain_desc.BufferDesc.RefreshRate.Numerator);
4264 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
4265 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
4266 swapchain_desc.BufferDesc.RefreshRate.Denominator);
4267 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM,
4268 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
4269 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
4270 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
4271 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
4272 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
4273 ok(swapchain_desc.SampleDesc.Count == 1,
4274 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
4275 ok(!swapchain_desc.SampleDesc.Quality,
4276 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
4277 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
4278 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
4279 ok(swapchain_desc.BufferCount == 2,
4280 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
4281 ok(swapchain_desc.OutputWindow == window,
4282 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
4283 ok(swapchain_desc.Windowed,
4284 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
4285 ok(swapchain_desc.SwapEffect == swap_effect,
4286 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
4287 ok(!swapchain_desc.Flags,
4288 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
4290 node_mask[0] = 1;
4291 node_mask[1] = 1;
4292 present_queue[0] = device;
4293 present_queue[1] = device;
4294 if (IDXGISwapChain_QueryInterface(swapchain, &IID_IDXGISwapChain3, (void **)&swapchain3) == E_NOINTERFACE)
4296 skip("IDXGISwapChain3 is not supported.\n");
4298 else if (!is_d3d12)
4300 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240,
4301 DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4302 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4303 IDXGISwapChain3_Release(swapchain3);
4305 else
4307 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240,
4308 DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4309 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4310 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240,
4311 DXGI_FORMAT_B8G8R8A8_UNORM, 0, NULL, present_queue);
4312 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4313 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, NULL, NULL);
4314 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4315 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 0, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0, NULL, NULL);
4316 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4317 node_mask[0] = 2;
4318 node_mask[1] = 2;
4319 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240,
4320 DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4321 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4322 /* Windows validates node masks even when the buffer count is zero.
4323 * It defaults to the current buffer count. NULL queues cause some
4324 * Windows versions to crash. */
4325 hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 0, 320, 240,
4326 DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
4327 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4328 IDXGISwapChain3_Release(swapchain3);
4331 IDXGISwapChain_Release(swapchain);
4332 DestroyWindow(window);
4333 refcount = IDXGIFactory_Release(factory);
4334 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
4337 static void test_swapchain_parameters(void)
4339 DXGI_USAGE usage, expected_usage, broken_usage;
4340 D3D10_TEXTURE2D_DESC d3d10_texture_desc;
4341 D3D11_TEXTURE2D_DESC d3d11_texture_desc;
4342 unsigned int expected_bind_flags;
4343 ID3D10Texture2D *d3d10_texture;
4344 ID3D11Texture2D *d3d11_texture;
4345 DXGI_SWAP_CHAIN_DESC desc;
4346 IDXGISwapChain *swapchain;
4347 IDXGIResource *resource;
4348 IDXGIAdapter *adapter;
4349 IDXGIFactory *factory;
4350 IDXGIDevice *device;
4351 unsigned int i, j;
4352 ULONG refcount;
4353 IUnknown *obj;
4354 HWND window;
4355 HRESULT hr;
4357 static const struct
4359 BOOL windowed;
4360 UINT buffer_count;
4361 DXGI_SWAP_EFFECT swap_effect;
4362 HRESULT hr, vista_hr;
4363 UINT highest_accessible_buffer;
4365 tests[] =
4367 /* 0 */
4368 {TRUE, 1, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4369 {TRUE, 2, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4370 {TRUE, 1, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 0},
4371 {TRUE, 2, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 1},
4372 {TRUE, 3, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 2},
4373 /* 5 */
4374 {TRUE, 0, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4375 {TRUE, 1, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4376 {TRUE, 2, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4377 {TRUE, 0, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4378 {TRUE, 1, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4379 /* 10 */
4380 {TRUE, 2, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 1},
4381 {TRUE, 3, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 2},
4382 {TRUE, 0, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4383 {TRUE, 1, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4384 {TRUE, 2, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4385 /* 15 */
4386 {TRUE, 0, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4387 {TRUE, 1, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4388 {TRUE, 2, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4389 {TRUE, 16, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4390 {TRUE, 16, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 15},
4391 /* 20 */
4392 {TRUE, 16, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 15},
4393 {TRUE, 16, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4394 {TRUE, 17, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4395 {FALSE, 1, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4396 {FALSE, 2, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4397 /* 25 */
4398 {FALSE, 1, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 0},
4399 {FALSE, 2, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 1},
4400 {FALSE, 3, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 2},
4401 {FALSE, 0, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4402 {FALSE, 1, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4403 /* 30 */
4404 {FALSE, 2, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4405 {FALSE, 0, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4406 {FALSE, 1, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4407 {FALSE, 2, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 1},
4408 {FALSE, 3, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 2},
4409 /* 35 */
4410 {FALSE, 0, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4411 {FALSE, 1, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4412 {FALSE, 2, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4413 {FALSE, 0, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4414 {FALSE, 1, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4415 /* 40 */
4416 {FALSE, 2, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4417 {FALSE, 16, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
4418 {FALSE, 16, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 15},
4419 {FALSE, 16, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 15},
4420 {FALSE, 17, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4421 /* 45 */
4422 {FALSE, 17, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4424 /* The following test fails on Nvidia with E_OUTOFMEMORY and leaks device references in the
4425 * process. Disable it for now.
4426 {FALSE, 16, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
4429 /* The following tests crash on Win10 1909
4430 {TRUE, 0, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4431 {TRUE, 0, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4432 {TRUE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4433 {TRUE, 17, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4434 {TRUE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4435 {FALSE, 0, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4436 {FALSE, 0, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4437 {FALSE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4438 {FALSE, 17, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
4441 static const DXGI_USAGE usage_tests[] =
4444 DXGI_USAGE_BACK_BUFFER,
4445 DXGI_USAGE_SHADER_INPUT,
4446 DXGI_USAGE_RENDER_TARGET_OUTPUT,
4447 DXGI_USAGE_DISCARD_ON_PRESENT,
4448 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER,
4449 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_DISCARD_ON_PRESENT,
4450 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_DISCARD_ON_PRESENT,
4451 DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT,
4452 DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_DISCARD_ON_PRESENT,
4455 if (!(device = create_device(0)))
4457 skip("Failed to create device.\n");
4458 return;
4460 window = create_window();
4462 hr = IDXGIDevice_QueryInterface(device, &IID_IUnknown, (void **)&obj);
4463 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4465 hr = IDXGIDevice_GetAdapter(device, &adapter);
4466 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4467 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
4468 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4469 IDXGIAdapter_Release(adapter);
4471 for (i = 0; i < ARRAY_SIZE(tests); ++i)
4473 memset(&desc, 0, sizeof(desc));
4474 desc.BufferDesc.Width = registry_mode.dmPelsWidth;
4475 desc.BufferDesc.Height = registry_mode.dmPelsHeight;
4476 desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4477 desc.SampleDesc.Count = 1;
4478 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4479 desc.OutputWindow = window;
4481 desc.Windowed = tests[i].windowed;
4482 desc.BufferCount = tests[i].buffer_count;
4483 desc.SwapEffect = tests[i].swap_effect;
4485 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4486 ok(hr == tests[i].hr || broken(hr == tests[i].vista_hr)
4487 || (SUCCEEDED(tests[i].hr) && hr == DXGI_STATUS_OCCLUDED),
4488 "Got unexpected hr %#lx, test %u.\n", hr, i);
4489 if (FAILED(hr))
4490 continue;
4492 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGIResource, (void **)&resource);
4493 todo_wine ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4494 if (FAILED(hr))
4496 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
4497 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4499 IDXGISwapChain_Release(swapchain);
4500 continue;
4503 expected_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
4504 hr = IDXGIResource_GetUsage(resource, &usage);
4505 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4506 ok((usage & expected_usage) == expected_usage, "Got usage %x, expected %x, test %u.\n",
4507 usage, expected_usage, i);
4509 IDXGIResource_Release(resource);
4511 hr = IDXGISwapChain_GetDesc(swapchain, &desc);
4512 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4514 for (j = 1; j <= tests[i].highest_accessible_buffer; j++)
4516 hr = IDXGISwapChain_GetBuffer(swapchain, j, &IID_IDXGIResource, (void **)&resource);
4517 ok(hr == S_OK, "Got unexpected hr %#lx, test %u, buffer %u.\n", hr, i, j);
4519 /* Buffers > 0 are supposed to be read only. This is the case except that in
4520 * fullscreen mode on Windows <= 8 the last backbuffer (BufferCount - 1) is
4521 * writable. This is not the case if an unsupported refresh rate is passed
4522 * for some reason, probably because the invalid refresh rate triggers a
4523 * kinda-sorta windowed mode.
4525 * On Windows 10 all buffers > 0 are read-only. Mark the earlier behavior
4526 * broken.
4528 * This last buffer acts as a shadow frontbuffer. Writing to it doesn't show
4529 * the draw on the screen right away (Aero on or off doesn't matter), but
4530 * Present with DXGI_PRESENT_DO_NOT_SEQUENCE will show the modifications.
4532 * Note that if the application doesn't have focus creating a fullscreen
4533 * swapchain returns DXGI_STATUS_OCCLUDED and we get a windowed swapchain,
4534 * so use the Windowed property of the swapchain that was actually created. */
4535 expected_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_READ_ONLY;
4536 broken_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
4538 if (desc.Windowed || j < tests[i].highest_accessible_buffer)
4539 broken_usage |= DXGI_USAGE_READ_ONLY;
4541 hr = IDXGIResource_GetUsage(resource, &usage);
4542 ok(hr == S_OK, "Got unexpected hr %#lx, test %u, buffer %u.\n", hr, i, j);
4543 ok(usage == expected_usage || broken(usage == broken_usage),
4544 "Got usage %x, expected %x, test %u, buffer %u.\n",
4545 usage, expected_usage, i, j);
4547 IDXGIResource_Release(resource);
4549 hr = IDXGISwapChain_GetBuffer(swapchain, j, &IID_IDXGIResource, (void **)&resource);
4550 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx, test %u.\n", hr, i);
4552 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
4553 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4555 IDXGISwapChain_Release(swapchain);
4558 for (i = 0; i < ARRAY_SIZE(usage_tests); ++i)
4560 usage = usage_tests[i];
4562 memset(&desc, 0, sizeof(desc));
4563 desc.BufferDesc.Width = registry_mode.dmPelsWidth;
4564 desc.BufferDesc.Height = registry_mode.dmPelsHeight;
4565 desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4566 desc.SampleDesc.Count = 1;
4567 desc.BufferUsage = usage;
4568 desc.BufferCount = 1;
4569 desc.OutputWindow = window;
4570 desc.Windowed = TRUE;
4571 desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
4572 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4573 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4575 hr = IDXGISwapChain_GetDesc(swapchain, &desc);
4576 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4577 todo_wine_if(usage & ~(DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT))
4578 ok(desc.BufferUsage == usage, "Got usage %#x, expected %#x, test %u.\n", desc.BufferUsage, usage, i);
4580 expected_bind_flags = 0;
4581 if (usage & DXGI_USAGE_RENDER_TARGET_OUTPUT)
4582 expected_bind_flags |= D3D11_BIND_RENDER_TARGET;
4583 if (usage & DXGI_USAGE_SHADER_INPUT)
4584 expected_bind_flags |= D3D11_BIND_SHADER_RESOURCE;
4586 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&d3d10_texture);
4587 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4588 ID3D10Texture2D_GetDesc(d3d10_texture, &d3d10_texture_desc);
4589 ok(d3d10_texture_desc.BindFlags == expected_bind_flags,
4590 "Got d3d10 bind flags %#x, expected %#x, test %u.\n",
4591 d3d10_texture_desc.BindFlags, expected_bind_flags, i);
4592 ID3D10Texture2D_Release(d3d10_texture);
4594 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D11Texture2D, (void **)&d3d11_texture);
4595 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Got unexpected hr %#lx, test %u.\n", hr, i);
4596 if (SUCCEEDED(hr))
4598 ID3D11Texture2D_GetDesc(d3d11_texture, &d3d11_texture_desc);
4599 ok(d3d11_texture_desc.BindFlags == expected_bind_flags,
4600 "Got d3d11 bind flags %#x, expected %#x, test %u.\n",
4601 d3d11_texture_desc.BindFlags, expected_bind_flags, i);
4602 ID3D11Texture2D_Release(d3d11_texture);
4605 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGIResource, (void **)&resource);
4606 todo_wine ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4607 if (FAILED(hr))
4609 IDXGISwapChain_Release(swapchain);
4610 continue;
4612 expected_usage = usage | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_DISCARD_ON_PRESENT;
4613 hr = IDXGIResource_GetUsage(resource, &usage);
4614 ok(hr == S_OK, "Got unexpected hr %#lx, test %u.\n", hr, i);
4615 ok(usage == expected_usage, "Got usage %x, expected %x, test %u.\n", usage, expected_usage, i);
4616 IDXGIResource_Release(resource);
4618 IDXGISwapChain_Release(swapchain);
4621 /* multisampling */
4622 memset(&desc, 0, sizeof(desc));
4623 desc.BufferDesc.Width = registry_mode.dmPelsWidth;
4624 desc.BufferDesc.Height = registry_mode.dmPelsHeight;
4625 desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4626 desc.SampleDesc.Count = 4;
4627 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4628 desc.BufferCount = 4;
4629 desc.OutputWindow = window;
4630 desc.Windowed = TRUE;
4631 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
4632 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4633 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4634 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
4635 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4636 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
4637 if (check_multisample_quality_levels(device, desc.BufferDesc.Format, desc.SampleDesc.Count))
4639 desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
4640 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4641 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4642 IDXGISwapChain_Release(swapchain);
4643 desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
4644 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
4645 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4646 IDXGISwapChain_Release(swapchain);
4648 else
4650 skip("Multisampling not supported for DXGI_FORMAT_R8G8B8A8_UNORM.\n");
4653 IDXGIFactory_Release(factory);
4654 IUnknown_Release(obj);
4655 refcount = IDXGIDevice_Release(device);
4656 ok(!refcount, "Device has %lu references left.\n", refcount);
4657 DestroyWindow(window);
4660 static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
4662 static const DWORD flags[] = {0, DXGI_PRESENT_TEST};
4663 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4664 IDXGISwapChain *swapchain;
4665 IDXGIFactory *factory;
4666 IDXGIOutput *output;
4667 BOOL fullscreen;
4668 unsigned int i;
4669 ULONG refcount;
4670 HRESULT hr;
4672 get_factory(device, is_d3d12, &factory);
4674 swapchain_desc.BufferDesc.Width = 800;
4675 swapchain_desc.BufferDesc.Height = 600;
4676 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
4677 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
4678 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4679 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
4680 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
4681 swapchain_desc.SampleDesc.Count = 1;
4682 swapchain_desc.SampleDesc.Quality = 0;
4683 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4684 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
4685 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
4686 swapchain_desc.Windowed = TRUE;
4687 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
4688 swapchain_desc.Flags = 0;
4690 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
4691 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4693 for (i = 0; i < 10; ++i)
4695 hr = IDXGISwapChain_Present(swapchain, i, 0);
4696 ok(hr == (i <= 4 ? S_OK : DXGI_ERROR_INVALID_CALL),
4697 "Got unexpected hr %#lx for sync interval %u.\n", hr, i);
4699 hr = IDXGISwapChain_Present(swapchain, 0, 0);
4700 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4702 for (i = 0; i < ARRAY_SIZE(flags); ++i)
4704 HWND occluding_window = CreateWindowA("static", "occluding_window",
4705 WS_POPUP | WS_VISIBLE, 0, 0, 400, 200, NULL, NULL, NULL, NULL);
4707 /* Another window covers the swapchain window. Not reported as occluded. */
4708 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4709 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4711 /* Minimised window. */
4712 ShowWindow(swapchain_desc.OutputWindow, SW_MINIMIZE);
4713 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4714 ok(hr == (is_d3d12 ? S_OK : DXGI_STATUS_OCCLUDED), "Test %u: Got unexpected hr %#lx.\n", i, hr);
4715 ShowWindow(swapchain_desc.OutputWindow, SW_NORMAL);
4717 /* Hidden window. */
4718 ShowWindow(swapchain_desc.OutputWindow, SW_HIDE);
4719 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4720 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4721 ShowWindow(swapchain_desc.OutputWindow, SW_SHOW);
4722 DestroyWindow(occluding_window);
4724 /* Test that IDXGIOutput_ReleaseOwnership() makes the swapchain exit
4725 * fullscreen. */
4726 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
4727 /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE on some machines.
4728 * DXGI_ERROR_UNSUPPORTED on the Windows 7 testbot. */
4729 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == DXGI_ERROR_UNSUPPORTED))
4731 skip("Test %u: Could not change fullscreen state.\n", i);
4732 continue;
4734 flush_events();
4735 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4736 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4737 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4738 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4739 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4740 output = NULL;
4741 fullscreen = FALSE;
4742 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
4743 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4744 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4745 ok(!!output, "Test %u: Got unexpected output.\n", i);
4747 if (output)
4748 IDXGIOutput_ReleaseOwnership(output);
4749 /* Still fullscreen. */
4750 fullscreen = FALSE;
4751 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4752 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4753 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4754 /* Calling IDXGISwapChain_Present() will exit fullscreen. */
4755 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4756 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4757 fullscreen = TRUE;
4758 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4759 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4760 /* Now fullscreen mode is exited. */
4761 if (!flags[i] && !is_d3d12)
4762 /* Still fullscreen on vista and 2008. */
4763 todo_wine ok(!fullscreen || broken(fullscreen), "Test %u: Got unexpected fullscreen status.\n", i);
4764 else
4765 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4766 if (output)
4767 IDXGIOutput_Release(output);
4769 /* Test creating a window when swapchain is in fullscreen.
4771 * The window should break the swapchain out of fullscreen mode on
4772 * d3d10/11. D3d12 is different, a new occluding window doesn't break
4773 * the swapchain out of fullscreen because d3d12 fullscreen swapchains
4774 * don't take exclusive ownership over the output, nor do they disable
4775 * compositing. D3d12 fullscreen mode acts just like borderless
4776 * fullscreen window mode. */
4777 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
4778 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4779 fullscreen = FALSE;
4780 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4781 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4782 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4783 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4784 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4785 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4786 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4788 occluding_window = CreateWindowA("static", "occluding_window", WS_POPUP, 0, 0, 400, 200, 0, 0, 0, 0);
4789 /* An invisible window doesn't cause the swapchain to exit fullscreen
4790 * mode. */
4791 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4792 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4793 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4794 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4795 fullscreen = FALSE;
4796 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4797 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4798 ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4799 /* A visible, but with bottom z-order window still causes the
4800 * swapchain to exit fullscreen mode. */
4801 SetWindowPos(occluding_window, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
4802 ShowWindow(occluding_window, SW_SHOW);
4803 /* Fullscreen mode takes a while to exit. */
4804 if (!is_d3d12)
4805 wait_fullscreen_state(swapchain, FALSE, TRUE);
4807 /* No longer fullscreen before calling IDXGISwapChain_Present() except
4808 * for d3d12. */
4809 fullscreen = TRUE;
4810 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4811 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4812 todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen,
4813 "Test %u: Got unexpected fullscreen status.\n", i);
4815 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4816 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4817 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4818 todo_wine_if(is_d3d12) ok(hr == (is_d3d12 ? DXGI_STATUS_OCCLUDED : S_OK),
4819 "Test %u: Got unexpected hr %#lx.\n", i, hr);
4821 fullscreen = TRUE;
4822 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4823 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4824 if (flags[i] == DXGI_PRESENT_TEST)
4825 todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen,
4826 "Test %u: Got unexpected fullscreen status.\n", i);
4827 else
4828 todo_wine ok(!fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4830 /* Even though d3d12 doesn't exit fullscreen, a
4831 * IDXGISwapChain_ResizeBuffers() is still needed for subsequent
4832 * IDXGISwapChain_Present() calls to work, otherwise they will return
4833 * DXGI_ERROR_INVALID_CALL */
4834 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4835 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4836 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4837 if (flags[i] == DXGI_PRESENT_TEST)
4838 todo_wine_if(is_d3d12) ok(hr == (is_d3d12 ? DXGI_STATUS_OCCLUDED : S_OK),
4839 "Test %u: Got unexpected hr %#lx.\n", i, hr);
4840 else
4841 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4843 /* Trying to break out of fullscreen mode again. This time, don't call
4844 * IDXGISwapChain_GetFullscreenState() before IDXGISwapChain_Present(). */
4845 ShowWindow(occluding_window, SW_HIDE);
4846 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
4847 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4848 ShowWindow(occluding_window, SW_SHOW);
4850 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4851 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4852 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4853 /* hr == S_OK on vista and 2008 */
4854 todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK),
4855 "Test %u: Got unexpected hr %#lx.\n", i, hr);
4857 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4858 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4859 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4860 if (flags[i] == DXGI_PRESENT_TEST)
4862 todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK),
4863 "Test %u: Got unexpected hr %#lx.\n", i, hr);
4864 /* IDXGISwapChain_Present() without flags refreshes the occlusion
4865 * state. */
4866 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4867 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4868 hr = IDXGISwapChain_Present(swapchain, 0, 0);
4869 todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK),
4870 "Test %u: Got unexpected hr %#lx.\n", i, hr);
4871 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4872 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4873 hr = IDXGISwapChain_Present(swapchain, 0, DXGI_PRESENT_TEST);
4874 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4876 else
4878 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4880 fullscreen = TRUE;
4881 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
4882 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4883 todo_wine ok(!fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
4885 DestroyWindow(occluding_window);
4886 flush_events();
4887 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4888 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4889 hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
4890 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4892 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
4893 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4894 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
4895 ok(hr == S_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr);
4898 wait_device_idle(device);
4900 IDXGISwapChain_Release(swapchain);
4901 DestroyWindow(swapchain_desc.OutputWindow);
4902 refcount = IDXGIFactory_Release(factory);
4903 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
4906 static void test_swapchain_backbuffer_index(IUnknown *device, BOOL is_d3d12)
4908 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4909 unsigned int index, expected_index;
4910 IDXGISwapChain3 *swapchain3;
4911 IDXGISwapChain *swapchain;
4912 HRESULT hr, expected_hr;
4913 IDXGIFactory *factory;
4914 unsigned int i, j;
4915 ULONG refcount;
4916 RECT rect;
4917 BOOL ret;
4919 static const DXGI_SWAP_EFFECT swap_effects[] =
4921 DXGI_SWAP_EFFECT_DISCARD,
4922 DXGI_SWAP_EFFECT_SEQUENTIAL,
4923 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
4924 DXGI_SWAP_EFFECT_FLIP_DISCARD,
4927 get_factory(device, is_d3d12, &factory);
4929 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
4930 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
4931 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
4932 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
4933 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
4934 swapchain_desc.SampleDesc.Count = 1;
4935 swapchain_desc.SampleDesc.Quality = 0;
4936 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
4937 swapchain_desc.BufferCount = 4;
4938 swapchain_desc.OutputWindow = create_window();
4939 swapchain_desc.Windowed = TRUE;
4940 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
4941 swapchain_desc.Flags = 0;
4943 ret = GetClientRect(swapchain_desc.OutputWindow, &rect);
4944 ok(ret, "Failed to get client rect.\n");
4945 swapchain_desc.BufferDesc.Width = rect.right;
4946 swapchain_desc.BufferDesc.Height = rect.bottom;
4948 for (i = 0; i < ARRAY_SIZE(swap_effects); ++i)
4950 swapchain_desc.SwapEffect = swap_effects[i];
4951 expected_hr = is_d3d12 && !is_flip_model(swap_effects[i]) ? DXGI_ERROR_INVALID_CALL : S_OK;
4952 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
4953 ok(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr);
4954 if (FAILED(hr))
4955 continue;
4957 hr = IDXGISwapChain_QueryInterface(swapchain, &IID_IDXGISwapChain3, (void **)&swapchain3);
4958 if (hr == E_NOINTERFACE)
4960 skip("IDXGISwapChain3 is not supported.\n");
4961 IDXGISwapChain_Release(swapchain);
4962 goto done;
4965 for (j = 0; j < 2 * swapchain_desc.BufferCount; ++j)
4967 index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain3);
4968 expected_index = is_d3d12 ? j % swapchain_desc.BufferCount : 0;
4969 ok(index == expected_index, "Got back buffer index %u, expected %u.\n", index, expected_index);
4970 hr = IDXGISwapChain3_Present(swapchain3, 0, 0);
4971 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
4974 wait_device_idle(device);
4976 IDXGISwapChain3_Release(swapchain3);
4977 refcount = IDXGISwapChain_Release(swapchain);
4978 ok(!refcount, "Swapchain has %lu references left.\n", refcount);
4981 done:
4982 DestroyWindow(swapchain_desc.OutputWindow);
4983 refcount = IDXGIFactory_Release(factory);
4984 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
4987 static void test_swapchain_formats(IUnknown *device, BOOL is_d3d12)
4989 DXGI_SWAP_CHAIN_DESC swapchain_desc;
4990 IDXGISwapChain *swapchain;
4991 HRESULT hr, expected_hr;
4992 IDXGIFactory *factory;
4993 unsigned int i;
4994 ULONG refcount;
4995 RECT rect;
4996 BOOL ret;
4998 static const struct
5000 DXGI_FORMAT format;
5001 DXGI_SWAP_EFFECT swap_effect;
5002 BOOL supported;
5004 tests[] =
5006 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_DISCARD, FALSE},
5007 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_SEQUENTIAL, FALSE},
5008 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5009 {DXGI_FORMAT_UNKNOWN, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5010 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5011 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5012 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5013 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5014 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5015 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5016 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5017 {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5018 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5019 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5020 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5021 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5022 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5023 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5024 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5025 {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5026 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5027 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5028 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5029 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5030 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_DISCARD, TRUE},
5031 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_SEQUENTIAL, TRUE},
5032 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_FLIP_DISCARD, TRUE},
5033 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, TRUE},
5034 {DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, DXGI_SWAP_EFFECT_FLIP_DISCARD, FALSE},
5035 {DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, FALSE},
5038 get_factory(device, is_d3d12, &factory);
5040 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
5041 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
5042 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
5043 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
5044 swapchain_desc.SampleDesc.Count = 1;
5045 swapchain_desc.SampleDesc.Quality = 0;
5046 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5047 swapchain_desc.BufferCount = 4;
5048 swapchain_desc.OutputWindow = create_window();
5049 swapchain_desc.Windowed = TRUE;
5050 swapchain_desc.Flags = 0;
5052 ret = GetClientRect(swapchain_desc.OutputWindow, &rect);
5053 ok(ret, "Failed to get client rect.\n");
5054 swapchain_desc.BufferDesc.Width = rect.right;
5055 swapchain_desc.BufferDesc.Height = rect.bottom;
5057 for (i = 0; i < ARRAY_SIZE(tests); ++i)
5059 if (is_d3d12 && !is_flip_model(tests[i].swap_effect))
5060 continue;
5062 swapchain_desc.BufferDesc.Format = tests[i].format;
5063 swapchain_desc.SwapEffect = tests[i].swap_effect;
5064 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
5065 expected_hr = tests[i].supported ? S_OK : DXGI_ERROR_INVALID_CALL;
5066 if (tests[i].format == DXGI_FORMAT_UNKNOWN && !is_d3d12)
5067 expected_hr = E_INVALIDARG;
5068 ok(hr == expected_hr
5069 /* Flip presentation model not supported. */
5070 || broken(hr == DXGI_ERROR_INVALID_CALL && is_flip_model(tests[i].swap_effect) && !is_d3d12),
5071 "Test %u, d3d12 %#x: Got unexpected hr %#lx, expected %#lx.\n", i, is_d3d12, hr, expected_hr);
5073 if (SUCCEEDED(hr))
5075 refcount = IDXGISwapChain_Release(swapchain);
5076 ok(!refcount, "Swapchain has %lu references left.\n", refcount);
5080 DestroyWindow(swapchain_desc.OutputWindow);
5081 refcount = IDXGIFactory_Release(factory);
5082 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
5085 static void test_maximum_frame_latency(void)
5087 IDXGIDevice1 *device1;
5088 IDXGIDevice *device;
5089 UINT max_latency;
5090 ULONG refcount;
5091 HRESULT hr;
5093 if (!(device = create_device(0)))
5095 skip("Failed to create device.\n");
5096 return;
5099 if (SUCCEEDED(IDXGIDevice_QueryInterface(device, &IID_IDXGIDevice1, (void **)&device1)))
5101 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, NULL);
5102 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
5104 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5105 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5106 ok(max_latency == DEFAULT_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
5108 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, MAX_FRAME_LATENCY);
5109 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5110 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5111 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5112 ok(max_latency == MAX_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
5114 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, MAX_FRAME_LATENCY + 1);
5115 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
5116 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5117 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5118 ok(max_latency == MAX_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
5120 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, 0);
5121 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5122 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
5123 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5124 /* 0 does not reset to the default frame latency on all Windows versions. */
5125 ok(max_latency == DEFAULT_FRAME_LATENCY || broken(!max_latency),
5126 "Got unexpected maximum frame latency %u.\n", max_latency);
5128 IDXGIDevice1_Release(device1);
5130 else
5132 win_skip("IDXGIDevice1 is not implemented.\n");
5135 refcount = IDXGIDevice_Release(device);
5136 ok(!refcount, "Device has %lu references left.\n", refcount);
5139 static void test_output_desc(void)
5141 IDXGIAdapter *adapter, *adapter2;
5142 IDXGIOutput *output, *output2;
5143 DXGI_OUTPUT_DESC desc;
5144 IDXGIFactory *factory;
5145 unsigned int i, j;
5146 ULONG refcount;
5147 HRESULT hr;
5149 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory);
5150 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5152 for (i = 0; ; ++i)
5154 hr = IDXGIFactory_EnumAdapters(factory, i, &adapter);
5155 if (hr == DXGI_ERROR_NOT_FOUND)
5156 break;
5157 winetest_push_context("Adapter %u", i);
5158 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5160 hr = IDXGIFactory_EnumAdapters(factory, i, &adapter2);
5161 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5162 ok(adapter != adapter2, "Expected to get new instance of IDXGIAdapter, %p == %p.\n", adapter, adapter2);
5163 refcount = get_refcount(adapter);
5164 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5165 IDXGIAdapter_Release(adapter2);
5167 refcount = get_refcount(factory);
5168 ok(refcount == 2, "Get unexpected refcount %lu.\n", refcount);
5169 refcount = get_refcount(adapter);
5170 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5172 for (j = 0; ; ++j)
5174 MONITORINFOEXW monitor_info;
5175 BOOL ret;
5177 hr = IDXGIAdapter_EnumOutputs(adapter, j, &output);
5178 if (hr == DXGI_ERROR_NOT_FOUND)
5179 break;
5180 winetest_push_context("Output %u", j);
5181 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5183 hr = IDXGIAdapter_EnumOutputs(adapter, j, &output2);
5184 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5185 ok(output != output2, "Expected to get new instance of IDXGIOutput, %p == %p.\n", output, output2);
5186 refcount = get_refcount(output);
5187 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5188 IDXGIOutput_Release(output2);
5190 refcount = get_refcount(factory);
5191 ok(refcount == 2, "Get unexpected refcount %lu.\n", refcount);
5192 refcount = get_refcount(adapter);
5193 ok(refcount == 2, "Get unexpected refcount %lu.\n", refcount);
5194 refcount = get_refcount(output);
5195 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5197 hr = IDXGIOutput_GetDesc(output, &desc);
5198 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5200 monitor_info.cbSize = sizeof(monitor_info);
5201 ret = GetMonitorInfoW(desc.Monitor, (MONITORINFO *)&monitor_info);
5202 ok(ret, "Failed to get monitor info.\n");
5203 ok(!lstrcmpW(desc.DeviceName, monitor_info.szDevice), "Got unexpected device name %s, expected %s.\n",
5204 wine_dbgstr_w(desc.DeviceName), wine_dbgstr_w(monitor_info.szDevice));
5205 ok(EqualRect(&desc.DesktopCoordinates, &monitor_info.rcMonitor),
5206 "Got unexpected desktop coordinates %s, expected %s.\n",
5207 wine_dbgstr_rect(&desc.DesktopCoordinates),
5208 wine_dbgstr_rect(&monitor_info.rcMonitor));
5210 IDXGIOutput_Release(output);
5211 refcount = get_refcount(adapter);
5212 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5214 winetest_pop_context();
5217 IDXGIAdapter_Release(adapter);
5218 refcount = get_refcount(factory);
5219 ok(refcount == 1, "Get unexpected refcount %lu.\n", refcount);
5221 winetest_pop_context();
5224 refcount = IDXGIFactory_Release(factory);
5225 ok(!refcount, "IDXGIFactory has %lu references left.\n", refcount);
5228 struct dxgi_factory
5230 IDXGIFactory IDXGIFactory_iface;
5231 IDXGIFactory *wrapped_iface;
5232 unsigned int wrapped_adapter_count;
5235 static inline struct dxgi_factory *impl_from_IDXGIFactory(IDXGIFactory *iface)
5237 return CONTAINING_RECORD(iface, struct dxgi_factory, IDXGIFactory_iface);
5240 static HRESULT STDMETHODCALLTYPE dxgi_factory_QueryInterface(IDXGIFactory *iface, REFIID iid, void **out)
5242 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5244 if (IsEqualGUID(iid, &IID_IDXGIFactory)
5245 || IsEqualGUID(iid, &IID_IDXGIObject)
5246 || IsEqualGUID(iid, &IID_IUnknown))
5248 IDXGIFactory_AddRef(iface);
5249 *out = iface;
5250 return S_OK;
5252 return IDXGIFactory_QueryInterface(factory->wrapped_iface, iid, out);
5255 static ULONG STDMETHODCALLTYPE dxgi_factory_AddRef(IDXGIFactory *iface)
5257 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5258 return IDXGIFactory_AddRef(factory->wrapped_iface);
5261 static ULONG STDMETHODCALLTYPE dxgi_factory_Release(IDXGIFactory *iface)
5263 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5264 return IDXGIFactory_Release(factory->wrapped_iface);
5267 static HRESULT STDMETHODCALLTYPE dxgi_factory_SetPrivateData(IDXGIFactory *iface,
5268 REFGUID guid, UINT data_size, const void *data)
5270 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5271 return IDXGIFactory_SetPrivateData(factory->wrapped_iface, guid, data_size, data);
5274 static HRESULT STDMETHODCALLTYPE dxgi_factory_SetPrivateDataInterface(IDXGIFactory *iface,
5275 REFGUID guid, const IUnknown *object)
5277 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5278 return IDXGIFactory_SetPrivateDataInterface(factory->wrapped_iface, guid, object);
5281 static HRESULT STDMETHODCALLTYPE dxgi_factory_GetPrivateData(IDXGIFactory *iface,
5282 REFGUID guid, UINT *data_size, void *data)
5284 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5285 return IDXGIFactory_GetPrivateData(factory->wrapped_iface, guid, data_size, data);
5288 static HRESULT STDMETHODCALLTYPE dxgi_factory_GetParent(IDXGIFactory *iface, REFIID iid, void **parent)
5290 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5291 return IDXGIFactory_GetParent(factory->wrapped_iface, iid, parent);
5294 static HRESULT STDMETHODCALLTYPE dxgi_factory_EnumAdapters(IDXGIFactory *iface,
5295 UINT adapter_idx, IDXGIAdapter **adapter)
5297 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5298 HRESULT hr;
5300 if (SUCCEEDED(hr = IDXGIFactory_EnumAdapters(factory->wrapped_iface, adapter_idx, adapter)))
5301 ++factory->wrapped_adapter_count;
5302 return hr;
5305 static HRESULT STDMETHODCALLTYPE dxgi_factory_MakeWindowAssociation(IDXGIFactory *iface,
5306 HWND window, UINT flags)
5308 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5309 return IDXGIFactory_MakeWindowAssociation(factory->wrapped_iface, window, flags);
5312 static HRESULT STDMETHODCALLTYPE dxgi_factory_GetWindowAssociation(IDXGIFactory *iface, HWND *window)
5314 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5315 return IDXGIFactory_GetWindowAssociation(factory->wrapped_iface, window);
5318 static HRESULT STDMETHODCALLTYPE dxgi_factory_CreateSwapChain(IDXGIFactory *iface,
5319 IUnknown *device, DXGI_SWAP_CHAIN_DESC *desc, IDXGISwapChain **swapchain)
5321 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5322 return IDXGIFactory_CreateSwapChain(factory->wrapped_iface, device, desc, swapchain);
5325 static HRESULT STDMETHODCALLTYPE dxgi_factory_CreateSoftwareAdapter(IDXGIFactory *iface,
5326 HMODULE swrast, IDXGIAdapter **adapter)
5328 struct dxgi_factory *factory = impl_from_IDXGIFactory(iface);
5329 return IDXGIFactory_CreateSoftwareAdapter(factory->wrapped_iface, swrast, adapter);
5332 static const struct IDXGIFactoryVtbl dxgi_factory_vtbl =
5334 dxgi_factory_QueryInterface,
5335 dxgi_factory_AddRef,
5336 dxgi_factory_Release,
5337 dxgi_factory_SetPrivateData,
5338 dxgi_factory_SetPrivateDataInterface,
5339 dxgi_factory_GetPrivateData,
5340 dxgi_factory_GetParent,
5341 dxgi_factory_EnumAdapters,
5342 dxgi_factory_MakeWindowAssociation,
5343 dxgi_factory_GetWindowAssociation,
5344 dxgi_factory_CreateSwapChain,
5345 dxgi_factory_CreateSoftwareAdapter,
5348 struct dxgi_adapter
5350 IDXGIAdapter IDXGIAdapter_iface;
5351 IDXGIAdapter *wrapped_iface;
5352 struct dxgi_factory factory;
5353 unsigned int wrapped_output_count;
5356 static inline struct dxgi_adapter *impl_from_IDXGIAdapter(IDXGIAdapter *iface)
5358 return CONTAINING_RECORD(iface, struct dxgi_adapter, IDXGIAdapter_iface);
5361 static HRESULT STDMETHODCALLTYPE dxgi_adapter_QueryInterface(IDXGIAdapter *iface, REFIID iid, void **out)
5363 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5365 if (IsEqualGUID(iid, &IID_IDXGIAdapter)
5366 || IsEqualGUID(iid, &IID_IDXGIObject)
5367 || IsEqualGUID(iid, &IID_IUnknown))
5369 IDXGIAdapter_AddRef(adapter->wrapped_iface);
5370 *out = iface;
5371 return S_OK;
5373 return IDXGIAdapter_QueryInterface(adapter->wrapped_iface, iid, out);
5376 static ULONG STDMETHODCALLTYPE dxgi_adapter_AddRef(IDXGIAdapter *iface)
5378 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5379 return IDXGIAdapter_AddRef(adapter->wrapped_iface);
5382 static ULONG STDMETHODCALLTYPE dxgi_adapter_Release(IDXGIAdapter *iface)
5384 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5385 return IDXGIAdapter_Release(adapter->wrapped_iface);
5388 static HRESULT STDMETHODCALLTYPE dxgi_adapter_SetPrivateData(IDXGIAdapter *iface,
5389 REFGUID guid, UINT data_size, const void *data)
5391 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5392 return IDXGIAdapter_SetPrivateData(adapter->wrapped_iface, guid, data_size, data);
5395 static HRESULT STDMETHODCALLTYPE dxgi_adapter_SetPrivateDataInterface(IDXGIAdapter *iface,
5396 REFGUID guid, const IUnknown *object)
5398 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5399 return IDXGIAdapter_SetPrivateDataInterface(adapter->wrapped_iface, guid, object);
5402 static HRESULT STDMETHODCALLTYPE dxgi_adapter_GetPrivateData(IDXGIAdapter *iface,
5403 REFGUID guid, UINT *data_size, void *data)
5405 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5406 return IDXGIAdapter_GetPrivateData(adapter->wrapped_iface, guid, data_size, data);
5409 static HRESULT STDMETHODCALLTYPE dxgi_adapter_GetParent(IDXGIAdapter *iface, REFIID iid, void **parent)
5411 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5412 return IDXGIFactory_QueryInterface(&adapter->factory.IDXGIFactory_iface, iid, parent);
5415 static HRESULT STDMETHODCALLTYPE dxgi_adapter_EnumOutputs(IDXGIAdapter *iface,
5416 UINT output_idx, IDXGIOutput **output)
5418 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5419 HRESULT hr;
5421 if (SUCCEEDED(hr = IDXGIAdapter_EnumOutputs(adapter->wrapped_iface, output_idx, output)))
5422 ++adapter->wrapped_output_count;
5423 return hr;
5426 static HRESULT STDMETHODCALLTYPE dxgi_adapter_GetDesc(IDXGIAdapter *iface, DXGI_ADAPTER_DESC *desc)
5428 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5429 return IDXGIAdapter_GetDesc(adapter->wrapped_iface, desc);
5432 static HRESULT STDMETHODCALLTYPE dxgi_adapter_CheckInterfaceSupport(IDXGIAdapter *iface,
5433 REFGUID guid, LARGE_INTEGER *umd_version)
5435 struct dxgi_adapter *adapter = impl_from_IDXGIAdapter(iface);
5436 return IDXGIAdapter_CheckInterfaceSupport(adapter->wrapped_iface, guid, umd_version);
5439 static const struct IDXGIAdapterVtbl dxgi_adapter_vtbl =
5441 dxgi_adapter_QueryInterface,
5442 dxgi_adapter_AddRef,
5443 dxgi_adapter_Release,
5444 dxgi_adapter_SetPrivateData,
5445 dxgi_adapter_SetPrivateDataInterface,
5446 dxgi_adapter_GetPrivateData,
5447 dxgi_adapter_GetParent,
5448 dxgi_adapter_EnumOutputs,
5449 dxgi_adapter_GetDesc,
5450 dxgi_adapter_CheckInterfaceSupport,
5453 static void test_object_wrapping(void)
5455 struct dxgi_adapter wrapper;
5456 DXGI_ADAPTER_DESC desc;
5457 IDXGIAdapter *adapter;
5458 IDXGIFactory *factory;
5459 ID3D10Device1 *device;
5460 ULONG refcount;
5461 HRESULT hr;
5463 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory);
5464 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5466 hr = IDXGIFactory_EnumAdapters(factory, 0, &adapter);
5467 if (hr == DXGI_ERROR_NOT_FOUND)
5469 skip("Could not enumerate adapters.\n");
5470 IDXGIFactory_Release(factory);
5471 return;
5473 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5475 wrapper.IDXGIAdapter_iface.lpVtbl = &dxgi_adapter_vtbl;
5476 wrapper.wrapped_iface = adapter;
5477 wrapper.factory.IDXGIFactory_iface.lpVtbl = &dxgi_factory_vtbl;
5478 wrapper.factory.wrapped_iface = factory;
5479 wrapper.factory.wrapped_adapter_count = 0;
5480 wrapper.wrapped_output_count = 0;
5482 hr = D3D10CreateDevice1(&wrapper.IDXGIAdapter_iface, D3D10_DRIVER_TYPE_HARDWARE, NULL,
5483 0, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &device);
5484 if (SUCCEEDED(hr))
5486 refcount = ID3D10Device1_Release(device);
5487 ok(!refcount, "Device has %lu references left.\n", refcount);
5490 hr = IDXGIAdapter_GetDesc(&wrapper.IDXGIAdapter_iface, &desc);
5491 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5492 ok(!wrapper.factory.wrapped_adapter_count, "Got unexpected wrapped adapter count %u.\n",
5493 wrapper.factory.wrapped_adapter_count);
5494 ok(!wrapper.wrapped_output_count, "Got unexpected wrapped output count %u.\n", wrapper.wrapped_output_count);
5496 refcount = IDXGIAdapter_Release(&wrapper.IDXGIAdapter_iface);
5497 ok(!refcount, "Adapter has %lu references left.\n", refcount);
5498 refcount = IDXGIFactory_Release(factory);
5499 ok(!refcount, "Factory has %lu references left.\n", refcount);
5502 struct adapter_info
5504 const WCHAR *name;
5505 HMONITOR monitor;
5508 static BOOL CALLBACK enum_monitor_proc(HMONITOR monitor, HDC dc, RECT *rect, LPARAM lparam)
5510 struct adapter_info *adapter_info = (struct adapter_info *)lparam;
5511 MONITORINFOEXW monitor_info;
5513 monitor_info.cbSize = sizeof(monitor_info);
5514 if (GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info)
5515 && !lstrcmpiW(adapter_info->name, monitor_info.szDevice))
5517 adapter_info->monitor = monitor;
5518 return FALSE;
5521 return TRUE;
5524 static HMONITOR get_monitor(const WCHAR *adapter_name)
5526 struct adapter_info info = {adapter_name, NULL};
5528 EnumDisplayMonitors(NULL, NULL, enum_monitor_proc, (LPARAM)&info);
5529 return info.monitor;
5532 static void test_multi_adapter(void)
5534 unsigned int output_count = 0, expected_output_count = 0;
5535 unsigned int adapter_index, output_index, device_index;
5536 DXGI_OUTPUT_DESC old_output_desc, output_desc;
5537 DXGI_ADAPTER_DESC1 adapter_desc1;
5538 DXGI_ADAPTER_DESC adapter_desc;
5539 DISPLAY_DEVICEW display_device;
5540 MONITORINFO monitor_info;
5541 DEVMODEW old_mode, mode;
5542 IDXGIAdapter1 *adapter1;
5543 IDXGIFactory *factory;
5544 IDXGIAdapter *adapter;
5545 IDXGIOutput *output;
5546 HMONITOR monitor;
5547 BOOL found;
5548 HRESULT hr;
5549 LONG ret;
5551 if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory)))
5553 skip("Failed to create IDXGIFactory, hr %#lx.\n", hr);
5554 return;
5557 hr = IDXGIFactory_EnumAdapters(factory, 0, NULL);
5558 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
5560 hr = IDXGIFactory_EnumAdapters(factory, 0, &adapter);
5561 if (hr == DXGI_ERROR_NOT_FOUND)
5563 skip("Could not enumerate adapters.\n");
5564 IDXGIFactory_Release(factory);
5565 return;
5567 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5569 for (adapter_index = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_index, &adapter)); ++adapter_index)
5571 for (output_index = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_index, &output)); ++output_index)
5573 hr = IDXGIOutput_GetDesc(output, &output_desc);
5574 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_index,
5575 output_index, hr);
5577 found = FALSE;
5578 display_device.cb = sizeof(display_device);
5579 for (device_index = 0; EnumDisplayDevicesW(NULL, device_index, &display_device, 0); ++device_index)
5581 if (!lstrcmpiW(display_device.DeviceName, output_desc.DeviceName))
5583 found = TRUE;
5584 break;
5587 ok(found, "Adapter %u output %u: Failed to find device %s.\n",
5588 adapter_index, output_index, wine_dbgstr_w(output_desc.DeviceName));
5590 ok(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP,
5591 "Adapter %u output %u: Got unexpected state flags %#lx.\n", adapter_index,
5592 output_index, display_device.StateFlags);
5593 if (!adapter_index && !output_index)
5594 ok(display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE,
5595 "Adapter %u output %u: Got unexpected state flags %#lx.\n", adapter_index,
5596 output_index, display_device.StateFlags);
5597 else
5598 ok(!(display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE),
5599 "Adapter %u output %u: Got unexpected state flags %#lx.\n", adapter_index,
5600 output_index, display_device.StateFlags);
5602 /* Should have the same monitor handle. */
5603 monitor = get_monitor(display_device.DeviceName);
5604 ok(!!monitor, "Adapter %u output %u: Failed to find monitor %s.\n", adapter_index,
5605 output_index, wine_dbgstr_w(display_device.DeviceName));
5606 ok(monitor == output_desc.Monitor,
5607 "Adapter %u output %u: Got unexpected monitor %p, expected %p.\n",
5608 adapter_index, output_index, monitor, output_desc.Monitor);
5610 /* Should have the same monitor rectangle. */
5611 monitor_info.cbSize = sizeof(monitor_info);
5612 ret = GetMonitorInfoA(monitor, &monitor_info);
5613 ok(ret, "Adapter %u output %u: Failed to get monitor info, error %#lx.\n", adapter_index,
5614 output_index, GetLastError());
5615 ok(EqualRect(&monitor_info.rcMonitor, &output_desc.DesktopCoordinates),
5616 "Adapter %u output %u: Got unexpected output rect %s, expected %s.\n",
5617 adapter_index, output_index, wine_dbgstr_rect(&monitor_info.rcMonitor),
5618 wine_dbgstr_rect(&output_desc.DesktopCoordinates));
5620 ++output_count;
5622 /* Test output description after it got detached */
5623 if (display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
5625 IDXGIOutput_Release(output);
5626 continue;
5629 old_output_desc = output_desc;
5631 /* Save current display settings */
5632 memset(&old_mode, 0, sizeof(old_mode));
5633 old_mode.dmSize = sizeof(old_mode);
5634 ret = EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &old_mode);
5635 /* Win10 TestBots may return FALSE but it's actually successful */
5636 ok(ret || broken(!ret),
5637 "Adapter %u output %u: EnumDisplaySettingsW failed for %s, error %#lx.\n",
5638 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName),
5639 GetLastError());
5641 /* Detach */
5642 memset(&mode, 0, sizeof(mode));
5643 mode.dmSize = sizeof(mode);
5644 mode.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
5645 mode.dmPosition = old_mode.dmPosition;
5646 ret = ChangeDisplaySettingsExW(display_device.DeviceName, &mode, NULL,
5647 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
5648 ok(ret == DISP_CHANGE_SUCCESSFUL,
5649 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %ld.\n",
5650 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5651 ret = ChangeDisplaySettingsExW(display_device.DeviceName, NULL, NULL, 0, NULL);
5652 ok(ret == DISP_CHANGE_SUCCESSFUL,
5653 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %ld.\n",
5654 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5656 /* Check if it is really detached */
5657 memset(&mode, 0, sizeof(mode));
5658 mode.dmSize = sizeof(mode);
5659 ret = EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &mode);
5660 /* Win10 TestBots may return FALSE but it's actually successful */
5661 ok(ret || broken(!ret) ,
5662 "Adapter %u output %u: EnumDisplaySettingsW failed for %s, error %#lx.\n",
5663 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName),
5664 GetLastError());
5665 if (mode.dmPelsWidth && mode.dmPelsHeight)
5667 skip("Adapter %u output %u: Failed to detach device %s.\n", adapter_index,
5668 output_index, wine_dbgstr_w(display_device.DeviceName));
5669 IDXGIOutput_Release(output);
5670 continue;
5673 /* Only the AttachedToDesktop field is updated after an output is detached.
5674 * IDXGIAdapter_EnumOutputs() has to be called again to get other fields updated.
5675 * But resolution changes are reflected right away. This weird behaviour is currently
5676 * unimplemented in Wine */
5677 memset(&output_desc, 0, sizeof(output_desc));
5678 hr = IDXGIOutput_GetDesc(output, &output_desc);
5679 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_index,
5680 output_index, hr);
5681 ok(!lstrcmpiW(output_desc.DeviceName, old_output_desc.DeviceName),
5682 "Adapter %u output %u: Expect device name %s, got %s.\n", adapter_index,
5683 output_index, wine_dbgstr_w(old_output_desc.DeviceName),
5684 wine_dbgstr_w(output_desc.DeviceName));
5685 todo_wine
5686 ok(EqualRect(&output_desc.DesktopCoordinates, &old_output_desc.DesktopCoordinates),
5687 "Adapter %u output %u: Expect desktop coordinates %s, got %s.\n",
5688 adapter_index, output_index,
5689 wine_dbgstr_rect(&old_output_desc.DesktopCoordinates),
5690 wine_dbgstr_rect(&output_desc.DesktopCoordinates));
5691 ok(!output_desc.AttachedToDesktop,
5692 "Adapter %u output %u: Expect output not attached to desktop.\n", adapter_index,
5693 output_index);
5694 ok(output_desc.Rotation == old_output_desc.Rotation,
5695 "Adapter %u output %u: Expect rotation %#x, got %#x.\n", adapter_index,
5696 output_index, old_output_desc.Rotation, output_desc.Rotation);
5697 todo_wine
5698 ok(output_desc.Monitor == old_output_desc.Monitor,
5699 "Adapter %u output %u: Expect monitor %p, got %p.\n", adapter_index,
5700 output_index, old_output_desc.Monitor, output_desc.Monitor);
5701 IDXGIOutput_Release(output);
5703 /* Call IDXGIAdapter_EnumOutputs() again to get up-to-date output description */
5704 hr = IDXGIAdapter_EnumOutputs(adapter, output_index, &output);
5705 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_index,
5706 output_index, hr);
5707 memset(&output_desc, 0, sizeof(output_desc));
5708 hr = IDXGIOutput_GetDesc(output, &output_desc);
5709 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_index,
5710 output_index, hr);
5711 ok(!lstrcmpiW(output_desc.DeviceName, display_device.DeviceName),
5712 "Adapter %u output %u: Expect device name %s, got %s.\n", adapter_index,
5713 output_index, wine_dbgstr_w(display_device.DeviceName),
5714 wine_dbgstr_w(output_desc.DeviceName));
5715 ok(IsRectEmpty(&output_desc.DesktopCoordinates),
5716 "Adapter %u output %u: Expect desktop rect empty, got %s.\n", adapter_index,
5717 output_index, wine_dbgstr_rect(&output_desc.DesktopCoordinates));
5718 ok(!output_desc.AttachedToDesktop,
5719 "Adapter %u output %u: Expect output not attached to desktop.\n", adapter_index,
5720 output_index);
5721 ok(output_desc.Rotation == DXGI_MODE_ROTATION_IDENTITY,
5722 "Adapter %u output %u: Expect rotation %#x, got %#x.\n", adapter_index,
5723 output_index, DXGI_MODE_ROTATION_IDENTITY, output_desc.Rotation);
5724 ok(!output_desc.Monitor, "Adapter %u output %u: Expect monitor NULL.\n", adapter_index,
5725 output_index);
5727 /* Restore settings */
5728 ret = ChangeDisplaySettingsExW(display_device.DeviceName, &old_mode, NULL,
5729 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
5730 ok(ret == DISP_CHANGE_SUCCESSFUL,
5731 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %ld.\n",
5732 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5733 ret = ChangeDisplaySettingsExW(display_device.DeviceName, NULL, NULL, 0, NULL);
5734 ok(ret == DISP_CHANGE_SUCCESSFUL,
5735 "Adapter %u output %u: ChangeDisplaySettingsExW %s returned unexpected %ld.\n",
5736 adapter_index, output_index, wine_dbgstr_w(display_device.DeviceName), ret);
5738 IDXGIOutput_Release(output);
5741 IDXGIAdapter_Release(adapter);
5744 /* Windows 8+ always have a WARP adapter present at the end. */
5745 todo_wine ok(adapter_index >= 2 || broken(adapter_index < 2) /* Windows 7 and before */,
5746 "Got unexpected adapter count %u.\n", adapter_index);
5747 if (adapter_index < 2)
5749 todo_wine win_skip("WARP adapter missing, skipping tests.\n");
5750 goto done;
5753 hr = IDXGIFactory_EnumAdapters(factory, adapter_index - 1, &adapter);
5754 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5755 hr = IDXGIAdapter_GetDesc(adapter, &adapter_desc);
5756 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5757 todo_wine ok(!lstrcmpW(adapter_desc.Description, L"Microsoft Basic Render Driver"),
5758 "Got unexpected description %s.\n", wine_dbgstr_w(adapter_desc.Description));
5759 todo_wine ok(adapter_desc.VendorId == 0x1414,
5760 "Got unexpected vendor ID %#x.\n", adapter_desc.VendorId);
5761 todo_wine ok(adapter_desc.DeviceId == 0x008c,
5762 "Got unexpected device ID %#x.\n", adapter_desc.DeviceId);
5763 ok(adapter_desc.SubSysId == 0x0000,
5764 "Got unexpected sub-system ID %#x.\n", adapter_desc.SubSysId);
5765 ok(adapter_desc.Revision == 0x0000,
5766 "Got unexpected revision %#x.\n", adapter_desc.Revision);
5767 todo_wine ok(!adapter_desc.DedicatedVideoMemory,
5768 "Got unexpected DedicatedVideoMemory %#Ix.\n", adapter_desc.DedicatedVideoMemory);
5769 ok(!adapter_desc.DedicatedSystemMemory,
5770 "Got unexpected DedicatedSystemMemory %#Ix.\n", adapter_desc.DedicatedSystemMemory);
5772 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter1, (void **)&adapter1);
5773 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Got unexpected hr %#lx.\n", hr);
5774 if (SUCCEEDED(hr))
5776 hr = IDXGIAdapter1_GetDesc1(adapter1, &adapter_desc1);
5777 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5778 todo_wine ok(adapter_desc1.Flags == DXGI_ADAPTER_FLAG_SOFTWARE,
5779 "Got unexpected flags %#x.\n", adapter_desc1.Flags);
5780 IDXGIAdapter1_Release(adapter1);
5783 IDXGIAdapter_Release(adapter);
5785 done:
5786 IDXGIFactory_Release(factory);
5788 expected_output_count = GetSystemMetrics(SM_CMONITORS);
5789 ok(output_count == expected_output_count, "Expect output count %d, got %d\n",
5790 expected_output_count, output_count);
5793 struct message
5795 unsigned int message;
5796 BOOL check_wparam;
5797 WPARAM expect_wparam;
5800 static BOOL expect_no_messages;
5801 static const struct message *expect_messages;
5802 static const struct message *expect_messages_broken;
5804 static BOOL check_message(const struct message *expected,
5805 HWND hwnd, unsigned int message, WPARAM wparam, LPARAM lparam)
5807 if (expected->message != message)
5808 return FALSE;
5810 if (expected->check_wparam)
5812 ok(wparam == expected->expect_wparam,
5813 "Got unexpected wparam %Ix for message %x, expected %Ix.\n",
5814 wparam, message, expected->expect_wparam);
5817 return TRUE;
5820 static LRESULT CALLBACK test_wndproc(HWND hwnd, unsigned int message, WPARAM wparam, LPARAM lparam)
5822 ok(!expect_no_messages, "Got unexpected message %#x, hwnd %p, wparam %#Ix, lparam %#Ix.\n",
5823 message, hwnd, wparam, lparam);
5825 if (expect_messages)
5827 if (check_message(expect_messages, hwnd, message, wparam, lparam))
5828 ++expect_messages;
5831 if (expect_messages_broken)
5833 if (check_message(expect_messages_broken, hwnd, message, wparam, lparam))
5834 ++expect_messages_broken;
5837 return DefWindowProcA(hwnd, message, wparam, lparam);
5840 static void test_swapchain_window_messages(void)
5842 DXGI_SWAP_CHAIN_DESC swapchain_desc;
5843 IDXGISwapChain *swapchain;
5844 DXGI_MODE_DESC mode_desc;
5845 IDXGIFactory *factory;
5846 IDXGIAdapter *adapter;
5847 IDXGIDevice *device;
5848 ULONG refcount;
5849 WNDCLASSA wc;
5850 HWND window;
5851 HRESULT hr;
5853 static const struct message enter_fullscreen_messages[] =
5855 {WM_STYLECHANGING, TRUE, GWL_STYLE},
5856 {WM_STYLECHANGED, TRUE, GWL_STYLE},
5857 {WM_STYLECHANGING, TRUE, GWL_EXSTYLE},
5858 {WM_STYLECHANGED, TRUE, GWL_EXSTYLE},
5859 {WM_WINDOWPOSCHANGING, FALSE, 0},
5860 {WM_GETMINMAXINFO, FALSE, 0},
5861 {WM_NCCALCSIZE, FALSE, 0},
5862 {WM_WINDOWPOSCHANGED, FALSE, 0},
5863 {WM_MOVE, FALSE, 0},
5864 {WM_SIZE, FALSE, 0},
5865 {0, FALSE, 0},
5867 static const struct message enter_fullscreen_messages_vista[] =
5869 {WM_STYLECHANGING, TRUE, GWL_STYLE},
5870 {WM_STYLECHANGED, TRUE, GWL_STYLE},
5871 {WM_WINDOWPOSCHANGING, FALSE, 0},
5872 {WM_NCCALCSIZE, FALSE, 0},
5873 {WM_WINDOWPOSCHANGED, FALSE, 0},
5874 {WM_MOVE, FALSE, 0},
5875 {WM_SIZE, FALSE, 0},
5876 {WM_STYLECHANGING, TRUE, GWL_EXSTYLE},
5877 {WM_STYLECHANGED, TRUE, GWL_EXSTYLE},
5878 {WM_WINDOWPOSCHANGING, FALSE, 0},
5879 {WM_GETMINMAXINFO, FALSE, 0},
5880 {WM_NCCALCSIZE, FALSE, 0},
5881 {WM_WINDOWPOSCHANGED, FALSE, 0},
5882 {WM_SIZE, FALSE, 0},
5883 {0, FALSE, 0},
5885 static const struct message leave_fullscreen_messages[] =
5887 {WM_STYLECHANGING, TRUE, GWL_STYLE},
5888 {WM_STYLECHANGED, TRUE, GWL_STYLE},
5889 {WM_STYLECHANGING, TRUE, GWL_EXSTYLE},
5890 {WM_STYLECHANGED, TRUE, GWL_EXSTYLE},
5891 {WM_WINDOWPOSCHANGING, FALSE, 0},
5892 {WM_GETMINMAXINFO, FALSE, 0},
5893 {WM_NCCALCSIZE, FALSE, 0},
5894 {WM_WINDOWPOSCHANGED, FALSE, 0},
5895 {WM_MOVE, FALSE, 0},
5896 {WM_SIZE, FALSE, 0},
5897 {0, FALSE, 0},
5899 static const struct message resize_target_messages[] =
5901 {WM_WINDOWPOSCHANGING, FALSE, 0},
5902 {WM_GETMINMAXINFO, FALSE, 0},
5903 {WM_NCCALCSIZE, FALSE, 0},
5904 {WM_WINDOWPOSCHANGED, FALSE, 0},
5905 {WM_SIZE, FALSE, 0},
5906 {0, FALSE, 0},
5909 if (!(device = create_device(0)))
5911 skip("Failed to create device.\n");
5912 return;
5915 memset(&wc, 0, sizeof(wc));
5916 wc.lpfnWndProc = test_wndproc;
5917 wc.lpszClassName = "dxgi_test_wndproc_wc";
5918 ok(RegisterClassA(&wc), "Failed to register window class.\n");
5919 window = CreateWindowA("dxgi_test_wndproc_wc", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
5920 ok(!!window, "Failed to create window.\n");
5922 hr = IDXGIDevice_GetAdapter(device, &adapter);
5923 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5924 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
5925 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5926 IDXGIAdapter_Release(adapter);
5928 swapchain_desc.BufferDesc.Width = 800;
5929 swapchain_desc.BufferDesc.Height = 600;
5930 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
5931 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
5932 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
5933 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
5934 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
5935 swapchain_desc.SampleDesc.Count = 1;
5936 swapchain_desc.SampleDesc.Quality = 0;
5937 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5938 swapchain_desc.BufferCount = 1;
5939 swapchain_desc.OutputWindow = window;
5940 swapchain_desc.Windowed = TRUE;
5941 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
5942 swapchain_desc.Flags = 0;
5944 /* create swapchain */
5945 flush_events();
5946 expect_no_messages = TRUE;
5947 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
5948 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5949 flush_events();
5950 expect_no_messages = FALSE;
5952 /* resize target */
5953 expect_messages = resize_target_messages;
5954 memset(&mode_desc, 0, sizeof(mode_desc));
5955 mode_desc.Width = 800;
5956 mode_desc.Height = 600;
5957 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode_desc);
5958 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5959 flush_events();
5960 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
5962 expect_messages = resize_target_messages;
5963 memset(&mode_desc, 0, sizeof(mode_desc));
5964 mode_desc.Width = 400;
5965 mode_desc.Height = 200;
5966 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode_desc);
5967 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5968 flush_events();
5969 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
5971 /* enter fullscreen */
5972 expect_messages = enter_fullscreen_messages;
5973 expect_messages_broken = enter_fullscreen_messages_vista;
5974 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
5975 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
5976 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
5977 "Got unexpected hr %#lx.\n", hr);
5978 if (FAILED(hr))
5980 skip("Could not change fullscreen state.\n");
5981 goto done;
5983 flush_events();
5984 todo_wine
5985 ok(!expect_messages->message || broken(!expect_messages_broken->message),
5986 "Expected message %#x or %#x.\n",
5987 expect_messages->message, expect_messages_broken->message);
5988 expect_messages_broken = NULL;
5990 /* leave fullscreen */
5991 expect_messages = leave_fullscreen_messages;
5992 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
5993 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
5994 flush_events();
5995 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
5996 expect_messages = NULL;
5998 refcount = IDXGISwapChain_Release(swapchain);
5999 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6001 /* create fullscreen swapchain */
6002 DestroyWindow(window);
6003 window = CreateWindowA("dxgi_test_wndproc_wc", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
6004 ok(!!window, "Failed to create window.\n");
6005 swapchain_desc.OutputWindow = window;
6006 swapchain_desc.Windowed = FALSE;
6007 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
6008 flush_events();
6010 expect_messages = enter_fullscreen_messages;
6011 expect_messages_broken = enter_fullscreen_messages_vista;
6012 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
6013 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6014 flush_events();
6015 todo_wine
6016 ok(!expect_messages->message || broken(!expect_messages_broken->message),
6017 "Expected message %#x or %#x.\n",
6018 expect_messages->message, expect_messages_broken->message);
6019 expect_messages_broken = NULL;
6021 /* leave fullscreen */
6022 expect_messages = leave_fullscreen_messages;
6023 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6024 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6025 flush_events();
6026 ok(!expect_messages->message, "Expected message %#x.\n", expect_messages->message);
6027 expect_messages = NULL;
6029 done:
6030 refcount = IDXGISwapChain_Release(swapchain);
6031 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6032 DestroyWindow(window);
6034 refcount = IDXGIDevice_Release(device);
6035 ok(!refcount, "Device has %lu references left.\n", refcount);
6036 refcount = IDXGIFactory_Release(factory);
6037 ok(!refcount, "Factory has %lu references left.\n", refcount);
6039 UnregisterClassA("dxgi_test_wndproc_wc", GetModuleHandleA(NULL));
6042 static void test_swapchain_window_styles(void)
6044 LONG style, exstyle, fullscreen_style, fullscreen_exstyle;
6045 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6046 IDXGISwapChain *swapchain;
6047 IDXGIFactory *factory;
6048 IDXGIAdapter *adapter;
6049 IDXGIDevice *device;
6050 ULONG refcount;
6051 unsigned int i;
6052 HRESULT hr;
6054 static const struct
6056 LONG style, exstyle;
6057 LONG expected_style, expected_exstyle;
6059 tests[] =
6061 {WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0,
6062 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS,
6063 WS_EX_WINDOWEDGE},
6064 {WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE, 0,
6065 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | WS_VISIBLE,
6066 WS_EX_WINDOWEDGE},
6067 {WS_OVERLAPPED | WS_VISIBLE, 0,
6068 WS_OVERLAPPED | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION, WS_EX_WINDOWEDGE},
6069 {WS_OVERLAPPED | WS_MAXIMIZE, 0,
6070 WS_OVERLAPPED | WS_MAXIMIZE | WS_CLIPSIBLINGS | WS_CAPTION, WS_EX_WINDOWEDGE},
6071 {WS_OVERLAPPED | WS_MINIMIZE, 0,
6072 WS_OVERLAPPED | WS_MINIMIZE | WS_CLIPSIBLINGS | WS_CAPTION, WS_EX_WINDOWEDGE},
6073 {WS_CAPTION | WS_DISABLED, WS_EX_TOPMOST,
6074 WS_CAPTION | WS_DISABLED | WS_CLIPSIBLINGS, WS_EX_TOPMOST | WS_EX_WINDOWEDGE},
6075 {WS_CAPTION | WS_DISABLED | WS_VISIBLE, WS_EX_TOPMOST,
6076 WS_CAPTION | WS_DISABLED | WS_VISIBLE | WS_CLIPSIBLINGS, WS_EX_TOPMOST | WS_EX_WINDOWEDGE},
6077 {WS_CAPTION | WS_SYSMENU | WS_VISIBLE, WS_EX_APPWINDOW,
6078 WS_CAPTION | WS_SYSMENU | WS_VISIBLE | WS_CLIPSIBLINGS, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE},
6079 {WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER | WS_DLGFRAME
6080 | WS_VSCROLL | WS_HSCROLL | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
6082 WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER | WS_DLGFRAME
6083 | WS_VSCROLL | WS_HSCROLL | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
6084 WS_EX_WINDOWEDGE},
6087 if (!(device = create_device(0)))
6089 skip("Failed to create device.\n");
6090 return;
6093 hr = IDXGIDevice_GetAdapter(device, &adapter);
6094 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6095 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
6096 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6097 IDXGIAdapter_Release(adapter);
6099 swapchain_desc.BufferDesc.Width = 800;
6100 swapchain_desc.BufferDesc.Height = 600;
6101 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6102 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
6103 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6104 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6105 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6106 swapchain_desc.SampleDesc.Count = 1;
6107 swapchain_desc.SampleDesc.Quality = 0;
6108 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6109 swapchain_desc.BufferCount = 1;
6110 swapchain_desc.Windowed = TRUE;
6111 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
6112 swapchain_desc.Flags = 0;
6114 for (i = 0; i < ARRAY_SIZE(tests); ++i)
6116 winetest_push_context("Test %u", i);
6118 swapchain_desc.OutputWindow = CreateWindowExA(tests[i].exstyle, "static", "dxgi_test",
6119 tests[i].style, 0, 0, 400, 200, 0, 0, 0, 0);
6121 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6122 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6123 ok(style == tests[i].expected_style, "Got unexpected style %#lx, expected %#lx.\n",
6124 style, tests[i].expected_style);
6125 ok(exstyle == tests[i].expected_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6126 exstyle, tests[i].expected_exstyle);
6128 fullscreen_style = tests[i].expected_style & ~(WS_POPUP | WS_MAXIMIZEBOX
6129 | WS_MINIMIZEBOX | WS_THICKFRAME | WS_SYSMENU | WS_DLGFRAME | WS_BORDER);
6130 fullscreen_exstyle = tests[i].expected_exstyle & ~(WS_EX_DLGMODALFRAME
6131 | WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_CONTEXTHELP);
6132 fullscreen_exstyle |= WS_EX_TOPMOST;
6134 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
6135 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6137 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6138 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6139 ok(style == tests[i].expected_style, "Got unexpected style %#lx, expected %#lx.\n",
6140 style, tests[i].expected_style);
6141 ok(exstyle == tests[i].expected_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6142 exstyle, tests[i].expected_exstyle);
6144 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6145 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6146 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6147 "Got unexpected hr %#lx.\n", hr);
6148 if (SUCCEEDED(hr))
6150 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6151 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6152 todo_wine ok(style == fullscreen_style, "Got unexpected style %#lx, expected %#lx.\n",
6153 style, fullscreen_style);
6154 ok(exstyle == fullscreen_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6155 exstyle, fullscreen_exstyle);
6157 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6158 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6160 else
6162 skip("Could not change fullscreen state.\n");
6165 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6166 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6167 ok(style == tests[i].expected_style, "Got unexpected style %#lx, expected %#lx.\n",
6168 style, tests[i].expected_style);
6169 ok(exstyle == tests[i].expected_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6170 exstyle, tests[i].expected_exstyle);
6172 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6173 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6174 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6175 "Got unexpected hr %#lx.\n", hr);
6176 if (SUCCEEDED(hr))
6178 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6179 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6180 todo_wine ok(style == fullscreen_style, "Got unexpected style %#lx, expected %#lx.\n",
6181 style, fullscreen_style);
6182 ok(exstyle == fullscreen_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6183 exstyle, fullscreen_exstyle);
6185 SetWindowLongW(swapchain_desc.OutputWindow, GWL_STYLE, fullscreen_style);
6186 SetWindowLongW(swapchain_desc.OutputWindow, GWL_EXSTYLE, fullscreen_exstyle);
6188 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6189 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6191 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6192 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6193 todo_wine ok(style == tests[i].expected_style, "Got unexpected style %#lx, expected %#lx.\n",
6194 style, tests[i].expected_style);
6195 todo_wine
6196 ok(exstyle == tests[i].expected_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6197 exstyle, tests[i].expected_exstyle);
6199 else
6201 skip("Could not change fullscreen state.\n");
6204 refcount = IDXGISwapChain_Release(swapchain);
6205 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6207 style = GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE);
6208 exstyle = GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE);
6209 todo_wine ok(style == tests[i].expected_style, "Got unexpected style %#lx, expected %#lx.\n",
6210 style, tests[i].expected_style);
6211 todo_wine
6212 ok(exstyle == tests[i].expected_exstyle, "Got unexpected exstyle %#lx, expected %#lx.\n",
6213 exstyle, tests[i].expected_exstyle);
6215 DestroyWindow(swapchain_desc.OutputWindow);
6217 winetest_pop_context();
6220 refcount = IDXGIDevice_Release(device);
6221 ok(!refcount, "Device has %lu references left.\n", refcount);
6222 refcount = IDXGIFactory_Release(factory);
6223 ok(!refcount, "Factory has %lu references left.\n", refcount);
6226 static void test_gamma_control(void)
6228 DXGI_GAMMA_CONTROL_CAPABILITIES caps;
6229 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6230 IDXGISwapChain *swapchain;
6231 DXGI_GAMMA_CONTROL gamma;
6232 IDXGIFactory *factory;
6233 IDXGIAdapter *adapter;
6234 IDXGIDevice *device;
6235 IDXGIOutput *output;
6236 unsigned int i;
6237 ULONG refcount;
6238 HRESULT hr;
6240 if (!(device = create_device(0)))
6242 skip("Failed to create device.\n");
6243 return;
6246 hr = IDXGIDevice_GetAdapter(device, &adapter);
6247 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6249 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
6250 if (hr == DXGI_ERROR_NOT_FOUND)
6252 skip("Adapter doesn't have any outputs.\n");
6253 IDXGIAdapter_Release(adapter);
6254 IDXGIDevice_Release(device);
6255 return;
6257 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6259 hr = IDXGIOutput_GetGammaControlCapabilities(output, &caps);
6260 todo_wine
6261 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6262 IDXGIOutput_Release(output);
6264 swapchain_desc.BufferDesc.Width = 640;
6265 swapchain_desc.BufferDesc.Height = 480;
6266 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6267 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
6268 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6269 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6270 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6271 swapchain_desc.SampleDesc.Count = 1;
6272 swapchain_desc.SampleDesc.Quality = 0;
6273 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6274 swapchain_desc.BufferCount = 1;
6275 swapchain_desc.OutputWindow = create_window();
6276 swapchain_desc.Windowed = TRUE;
6277 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
6278 swapchain_desc.Flags = 0;
6280 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
6281 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6283 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
6284 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6285 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6286 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6287 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6288 "Got unexpected hr %#lx.\n", hr);
6289 if (FAILED(hr))
6291 skip("Could not change fullscreen state.\n");
6292 goto done;
6295 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
6296 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6298 memset(&caps, 0, sizeof(caps));
6299 hr = IDXGIOutput_GetGammaControlCapabilities(output, &caps);
6300 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6302 ok(caps.MaxConvertedValue > caps.MinConvertedValue
6303 || broken(caps.MaxConvertedValue == 0.0f && caps.MinConvertedValue == 1.0f) /* WARP */,
6304 "Expected max gamma value (%.8e) to be bigger than min value (%.8e).\n",
6305 caps.MaxConvertedValue, caps.MinConvertedValue);
6307 for (i = 1; i < caps.NumGammaControlPoints; ++i)
6309 ok(caps.ControlPointPositions[i] > caps.ControlPointPositions[i - 1],
6310 "Expected control point positions to be strictly monotonically increasing (%.8e > %.8e).\n",
6311 caps.ControlPointPositions[i], caps.ControlPointPositions[i - 1]);
6314 memset(&gamma, 0, sizeof(gamma));
6315 hr = IDXGIOutput_GetGammaControl(output, &gamma);
6316 todo_wine
6317 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6318 hr = IDXGIOutput_SetGammaControl(output, &gamma);
6319 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6321 IDXGIOutput_Release(output);
6323 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6324 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6326 done:
6327 refcount = IDXGISwapChain_Release(swapchain);
6328 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6329 DestroyWindow(swapchain_desc.OutputWindow);
6331 IDXGIAdapter_Release(adapter);
6332 refcount = IDXGIDevice_Release(device);
6333 ok(!refcount, "Device has %lu references left.\n", refcount);
6334 refcount = IDXGIFactory_Release(factory);
6335 ok(!refcount, "Factory has %lu references left.\n", refcount);
6338 static void test_window_association(IUnknown *device, BOOL is_d3d12)
6340 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6341 LONG_PTR original_wndproc, wndproc;
6342 IDXGIFactory *factory, *factory2;
6343 IDXGISwapChain *swapchain;
6344 IDXGIOutput *output;
6345 HWND hwnd, hwnd2;
6346 BOOL fullscreen;
6347 unsigned int i;
6348 ULONG refcount;
6349 HRESULT hr;
6351 static const struct
6353 UINT flag;
6354 BOOL expect_fullscreen;
6355 BOOL broken_d3d10;
6357 tests[] =
6359 /* There are two reasons why VK_TAB and VK_ESC are not tested here:
6361 * - Posting them to the window doesn't exit fullscreen like
6362 * Alt+Enter does. Alt+Tab and Alt+Esc are handled somewhere else.
6363 * E.g., not calling IDXGISwapChain::Present() will break Alt+Tab
6364 * and Alt+Esc while Alt+Enter will still function.
6366 * - Posting them hangs the posting thread. Another thread that keeps
6367 * sending input is needed to avoid the hang. The hang is not
6368 * because of flush_events(). */
6369 {0, TRUE},
6370 {0, FALSE},
6371 {DXGI_MWA_NO_WINDOW_CHANGES, FALSE},
6372 {DXGI_MWA_NO_WINDOW_CHANGES, FALSE},
6373 {DXGI_MWA_NO_ALT_ENTER, FALSE, TRUE},
6374 {DXGI_MWA_NO_ALT_ENTER, FALSE},
6375 {DXGI_MWA_NO_PRINT_SCREEN, TRUE},
6376 {DXGI_MWA_NO_PRINT_SCREEN, FALSE},
6377 {0, TRUE},
6378 {0, FALSE}
6381 swapchain_desc.BufferDesc.Width = 640;
6382 swapchain_desc.BufferDesc.Height = 480;
6383 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6384 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
6385 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6386 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6387 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6388 swapchain_desc.SampleDesc.Count = 1;
6389 swapchain_desc.SampleDesc.Quality = 0;
6390 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6391 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
6392 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
6393 swapchain_desc.Windowed = TRUE;
6394 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
6395 swapchain_desc.Flags = 0;
6397 original_wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6399 hwnd2 = CreateWindowA("static", "dxgi_test2", 0, 0, 0, 400, 200, 0, 0, 0, 0);
6400 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory2);
6401 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6403 get_factory(device, is_d3d12, &factory);
6405 hr = IDXGIFactory_GetWindowAssociation(factory, NULL);
6406 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6408 for (i = 0; i <= DXGI_MWA_VALID; ++i)
6410 hr = IDXGIFactory_MakeWindowAssociation(factory, NULL, i);
6411 ok(hr == S_OK, "Got unexpected hr %#lx for flags %#x.\n", hr, i);
6413 hr = IDXGIFactory_MakeWindowAssociation(factory, swapchain_desc.OutputWindow, i);
6414 ok(hr == S_OK, "Got unexpected hr %#lx for flags %#x.\n", hr, i);
6416 wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6417 ok(wndproc == original_wndproc, "Got unexpected wndproc %#Ix, expected %#Ix for flags %#x.\n",
6418 wndproc, original_wndproc, i);
6420 hwnd = (HWND)0xdeadbeef;
6421 hr = IDXGIFactory_GetWindowAssociation(factory, &hwnd);
6422 ok(hr == S_OK, "Got unexpected hr %#lx for flags %#x.\n", hr, i);
6423 /* Apparently GetWindowAssociation() always returns NULL, even when
6424 * MakeWindowAssociation() and GetWindowAssociation() are both
6425 * successfully called. */
6426 ok(!hwnd, "Expect null associated window.\n");
6429 hr = IDXGIFactory_MakeWindowAssociation(factory, swapchain_desc.OutputWindow, DXGI_MWA_VALID + 1);
6430 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6432 /* Alt+Enter tests. */
6433 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
6434 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6436 wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6437 ok(wndproc == original_wndproc, "Got unexpected wndproc %#Ix, expected %#Ix.\n", wndproc, original_wndproc);
6439 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6440 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6441 || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Windows 7 testbot */,
6442 "Got unexpected hr %#lx.\n", hr);
6443 if (FAILED(hr))
6445 skip("Could not change fullscreen state.\n");
6447 else
6449 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6450 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6452 for (i = 0; i < ARRAY_SIZE(tests); ++i)
6454 winetest_push_context("Test %u", i);
6456 /* First associate a window with the opposite flags. */
6457 hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd2, ~tests[i].flag & DXGI_MWA_VALID);
6458 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6460 /* Associate the current test window. */
6461 hwnd = tests[i].flag ? swapchain_desc.OutputWindow : NULL;
6462 hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd, tests[i].flag);
6463 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6465 /* Associating a new test window doesn't override the old window. */
6466 hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd2, ~tests[i].flag & DXGI_MWA_VALID);
6467 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6469 /* Associations with a different factory don't affect the existing
6470 * association. */
6471 hr = IDXGIFactory_MakeWindowAssociation(factory2, hwnd, ~tests[i].flag & DXGI_MWA_VALID);
6472 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6474 /* Post synthesized Alt + VK_RETURN WM_SYSKEYDOWN. */
6475 PostMessageA(swapchain_desc.OutputWindow, WM_SYSKEYDOWN, VK_RETURN,
6476 (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x20000001);
6477 flush_events();
6478 output = NULL;
6479 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
6480 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6481 ok(fullscreen == tests[i].expect_fullscreen
6482 || broken(tests[i].broken_d3d10 && fullscreen),
6483 "Got unexpected fullscreen %#x.\n", fullscreen);
6484 ok(fullscreen ? !!output : !output, "Got unexpected output.\n");
6485 if (output)
6486 IDXGIOutput_Release(output);
6488 wndproc = GetWindowLongPtrW(swapchain_desc.OutputWindow, GWLP_WNDPROC);
6489 ok(wndproc == original_wndproc, "Got unexpected wndproc %#Ix, expected %#Ix.\n",
6490 wndproc, original_wndproc);
6492 winetest_pop_context();
6496 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6497 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6499 refcount = IDXGIFactory_Release(factory2);
6500 ok(!refcount, "Factory has %lu references left.\n", refcount);
6501 DestroyWindow(hwnd2);
6503 refcount = IDXGISwapChain_Release(swapchain);
6504 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6505 DestroyWindow(swapchain_desc.OutputWindow);
6507 refcount = IDXGIFactory_Release(factory);
6508 ok(refcount == !is_d3d12, "IDXGIFactory has %lu references left.\n", refcount);
6511 static void test_output_ownership(IUnknown *device, BOOL is_d3d12)
6513 D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
6514 D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP check_ownership_desc;
6515 D3DKMT_CLOSEADAPTER close_adapter_desc;
6516 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6517 DXGI_OUTPUT_DESC output_desc;
6518 IDXGISwapChain *swapchain;
6519 IDXGIFactory *factory;
6520 IDXGIAdapter *adapter;
6521 IDXGIOutput *output;
6522 BOOL fullscreen;
6523 NTSTATUS status;
6524 ULONG refcount;
6525 HRESULT hr;
6527 if (!pD3DKMTCheckVidPnExclusiveOwnership
6528 || pD3DKMTCheckVidPnExclusiveOwnership(NULL) == STATUS_PROCEDURE_NOT_FOUND)
6530 win_skip("D3DKMTCheckVidPnExclusiveOwnership() is unavailable.\n");
6531 return;
6534 get_factory(device, is_d3d12, &factory);
6535 adapter = get_adapter(device, is_d3d12);
6536 if (!adapter)
6538 skip("Failed to get adapter on Direct3D %d.\n", is_d3d12 ? 12 : 10);
6539 IDXGIFactory_Release(factory);
6540 return;
6543 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
6544 IDXGIAdapter_Release(adapter);
6545 if (hr == DXGI_ERROR_NOT_FOUND)
6547 skip("Adapter doesn't have any outputs.\n");
6548 IDXGIFactory_Release(factory);
6549 return;
6551 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6553 hr = IDXGIOutput_GetDesc(output, &output_desc);
6554 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6556 lstrcpyW(open_adapter_gdi_desc.DeviceName, output_desc.DeviceName);
6557 status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc);
6558 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
6560 check_ownership_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
6561 check_ownership_desc.VidPnSourceId = open_adapter_gdi_desc.VidPnSourceId;
6562 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6563 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx, expected %#lx.\n", status,
6564 STATUS_SUCCESS);
6566 swapchain_desc.BufferDesc.Width = 800;
6567 swapchain_desc.BufferDesc.Height = 600;
6568 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
6569 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
6570 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6571 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
6572 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
6573 swapchain_desc.SampleDesc.Count = 1;
6574 swapchain_desc.SampleDesc.Quality = 0;
6575 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6576 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
6577 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, NULL, NULL, NULL, NULL);
6578 swapchain_desc.Windowed = TRUE;
6579 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
6580 swapchain_desc.Flags = 0;
6581 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
6582 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6584 /* Swapchain in fullscreen mode. */
6585 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
6586 /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE on some machines.
6587 * DXGI_ERROR_UNSUPPORTED on the Windows 7 testbot. */
6588 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == DXGI_ERROR_UNSUPPORTED))
6590 skip("Failed to change fullscreen state.\n");
6591 goto done;
6593 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6594 fullscreen = FALSE;
6595 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
6596 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6597 ok(fullscreen, "Got unexpected fullscreen state.\n");
6598 /* Win10 1909 doesn't seem to grab output exclusive ownership.
6599 * And all output ownership calls return S_OK on D3D10 and D3D12 with 1909. */
6600 if (is_d3d12)
6602 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6603 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx, expected %#lx.\n", status,
6604 STATUS_SUCCESS);
6606 else
6608 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc,
6609 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6610 todo_wine ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED ||
6611 broken(status == STATUS_SUCCESS), /* Win10 1909 */
6612 "Got unexpected status %#lx, expected %#lx.\n", status,
6613 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6615 hr = IDXGIOutput_TakeOwnership(output, NULL, FALSE);
6616 ok(hr == DXGI_ERROR_INVALID_CALL || broken(hr == S_OK), /* Win10 1909 */
6617 "Got unexpected hr %#lx.\n", hr);
6618 hr = IDXGIOutput_TakeOwnership(output, NULL, TRUE);
6619 ok(hr == DXGI_ERROR_INVALID_CALL || broken(hr == S_OK), /* Win10 1909 */
6620 "Got unexpected hr %#lx.\n", hr);
6621 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6622 if (is_d3d12)
6623 todo_wine ok(hr == E_NOINTERFACE || hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6624 else
6625 todo_wine ok(hr == E_INVALIDARG || broken(hr == S_OK), /* Win10 1909 */
6626 "Got unexpected hr %#lx.\n", hr);
6627 hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
6628 ok(hr == E_NOINTERFACE || hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6629 IDXGIOutput_ReleaseOwnership(output);
6630 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6631 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx, expected %#lx.\n", status,
6632 STATUS_SUCCESS);
6634 /* IDXGIOutput_TakeOwnership always returns E_NOINTERFACE for d3d12. Tests
6635 * finished. */
6636 if (is_d3d12)
6637 goto done;
6639 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6640 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == S_OK), /* Win10 1909 */
6641 "Got unexpected hr %#lx.\n", hr);
6642 IDXGIOutput_ReleaseOwnership(output);
6644 hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
6645 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6646 /* Note that the "exclusive" parameter to IDXGIOutput_TakeOwnership()
6647 * seems to behave opposite to what's described by MSDN. */
6648 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc,
6649 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6650 ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED ||
6651 broken(status == STATUS_SUCCESS), /* Win10 1909 */
6652 "Got unexpected status %#lx, expected %#lx.\n", status, STATUS_GRAPHICS_PRESENT_OCCLUDED);
6653 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6654 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Win10 1909 */, "Got unexpected hr %#lx.\n", hr);
6655 IDXGIOutput_ReleaseOwnership(output);
6657 /* Swapchain in windowed mode. */
6658 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6659 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6660 fullscreen = TRUE;
6661 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
6662 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6663 ok(!fullscreen, "Unexpected fullscreen state.\n");
6664 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6665 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx, expected %#lx.\n", status,
6666 STATUS_SUCCESS);
6668 hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
6669 ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == S_OK), /* Win10 1909 */
6670 "Got unexpected hr %#lx.\n", hr);
6672 hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
6673 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6674 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc,
6675 STATUS_GRAPHICS_PRESENT_OCCLUDED);
6676 ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED || broken(hr == S_OK), /* Win10 1909 */
6677 "Got unexpected status %#lx, expected %#lx.\n", status, STATUS_GRAPHICS_PRESENT_OCCLUDED);
6678 IDXGIOutput_ReleaseOwnership(output);
6679 status = get_expected_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS);
6680 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx, expected %#lx.\n", status,
6681 STATUS_SUCCESS);
6683 done:
6684 IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6685 wait_device_idle(device);
6687 IDXGIOutput_Release(output);
6688 IDXGISwapChain_Release(swapchain);
6689 DestroyWindow(swapchain_desc.OutputWindow);
6690 refcount = IDXGIFactory_Release(factory);
6691 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
6693 close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
6694 status = pD3DKMTCloseAdapter(&close_adapter_desc);
6695 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
6698 static void test_cursor_clipping(IUnknown *device, BOOL is_d3d12)
6700 unsigned int adapter_idx, output_idx, mode_idx, mode_count;
6701 DXGI_SWAP_CHAIN_DESC swapchain_desc;
6702 DXGI_OUTPUT_DESC output_desc;
6703 IDXGIAdapter *adapter = NULL;
6704 RECT virtual_rect, clip_rect;
6705 unsigned int width, height;
6706 IDXGISwapChain *swapchain;
6707 DXGI_MODE_DESC *modes;
6708 IDXGIFactory *factory;
6709 IDXGIOutput *output;
6710 ULONG refcount;
6711 HRESULT hr;
6712 BOOL ret;
6714 get_factory(device, is_d3d12, &factory);
6716 swapchain_desc.SampleDesc.Count = 1;
6717 swapchain_desc.SampleDesc.Quality = 0;
6718 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6719 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
6720 swapchain_desc.Windowed = TRUE;
6721 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
6722 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
6724 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
6725 ++adapter_idx)
6727 winetest_push_context("Adapter %u", adapter_idx);
6729 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output));
6730 ++output_idx)
6732 winetest_push_context("Output %u", output_idx);
6734 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
6735 ok(hr == S_OK || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Win 7 TestBots */
6736 "Got unexpected hr %#lx.\n", hr);
6737 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
6739 win_skip("GetDisplayModeList() not supported.\n");
6740 IDXGIOutput_Release(output);
6741 winetest_pop_context();
6742 continue;
6745 modes = heap_calloc(mode_count, sizeof(*modes));
6746 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes);
6747 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6749 hr = IDXGIOutput_GetDesc(output, &output_desc);
6750 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6751 width = output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left;
6752 height = output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top;
6753 for (mode_idx = 0; mode_idx < mode_count; ++mode_idx)
6755 if (modes[mode_idx].Width != width && modes[mode_idx].Height != height)
6756 break;
6758 ok(modes[mode_idx].Width != width && modes[mode_idx].Height != height,
6759 "Failed to find a different mode than %ux%u.\n", width, height);
6761 ret = ClipCursor(NULL);
6762 ok(ret, "ClipCursor failed, error %#lx.\n", GetLastError());
6763 get_virtual_rect(&virtual_rect);
6764 ret = GetClipCursor(&clip_rect);
6765 ok(ret, "GetClipCursor failed, error %#lx.\n", GetLastError());
6766 ok(EqualRect(&clip_rect, &virtual_rect), "Expect clip rect %s, got %s.\n",
6767 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6769 swapchain_desc.BufferDesc.Width = modes[mode_idx].Width;
6770 swapchain_desc.BufferDesc.Height = modes[mode_idx].Height;
6771 swapchain_desc.BufferDesc.RefreshRate = modes[mode_idx].RefreshRate;
6772 swapchain_desc.BufferDesc.Format = modes[mode_idx].Format;
6773 swapchain_desc.BufferDesc.ScanlineOrdering = modes[mode_idx].ScanlineOrdering;
6774 swapchain_desc.BufferDesc.Scaling = modes[mode_idx].Scaling;
6775 swapchain_desc.OutputWindow = create_window();
6776 heap_free(modes);
6777 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
6778 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6780 flush_events();
6781 get_virtual_rect(&virtual_rect);
6782 ret = GetClipCursor(&clip_rect);
6783 ok(ret, "GetClipCursor failed, error %#lx.\n", GetLastError());
6784 ok(EqualRect(&clip_rect, &virtual_rect), "Expect clip rect %s, got %s.\n",
6785 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6787 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
6788 ok(hr == S_OK || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
6789 || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
6790 "Got unexpected hr %#lx.\n", hr);
6791 if (FAILED(hr))
6793 skip("Could not change fullscreen state, hr %#lx.\n", hr);
6794 IDXGISwapChain_Release(swapchain);
6795 IDXGIOutput_Release(output);
6796 DestroyWindow(swapchain_desc.OutputWindow);
6797 winetest_pop_context();
6798 continue;
6801 flush_events();
6802 get_virtual_rect(&virtual_rect);
6803 ret = GetClipCursor(&clip_rect);
6804 ok(ret, "GetClipCursor failed, error %#lx.\n", GetLastError());
6805 ok(EqualRect(&clip_rect, &virtual_rect), "Expect clip rect %s, got %s.\n",
6806 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6808 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
6809 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6810 refcount = IDXGISwapChain_Release(swapchain);
6811 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
6812 refcount = IDXGIOutput_Release(output);
6813 ok(!refcount, "IDXGIOutput has %lu references left.\n", refcount);
6814 DestroyWindow(swapchain_desc.OutputWindow);
6816 flush_events();
6817 get_virtual_rect(&virtual_rect);
6818 ret = GetClipCursor(&clip_rect);
6819 ok(ret, "GetClipCursor failed, error %#lx.\n", GetLastError());
6820 ok(EqualRect(&clip_rect, &virtual_rect), "Expect clip rect %s, got %s.\n",
6821 wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&clip_rect));
6823 winetest_pop_context();
6826 IDXGIAdapter_Release(adapter);
6828 winetest_pop_context();
6831 refcount = IDXGIFactory_Release(factory);
6832 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
6835 static void test_factory_check_feature_support(void)
6837 IDXGIFactory5 *factory;
6838 ULONG ref_count;
6839 HRESULT hr;
6840 BOOL data;
6842 if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory5, (void**)&factory)))
6844 win_skip("IDXGIFactory5 is not available.\n");
6845 return;
6848 hr = IDXGIFactory5_CheckFeatureSupport(factory, 0x12345678, (void *)&data, sizeof(data));
6849 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6851 /* Crashes on Windows. */
6852 if (0)
6854 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, NULL, sizeof(data));
6855 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6858 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &data, sizeof(data) - 1);
6859 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6861 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &data, sizeof(data) + 1);
6862 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6864 data = (BOOL)0xdeadbeef;
6865 hr = IDXGIFactory5_CheckFeatureSupport(factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &data, sizeof(data));
6866 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6867 ok(data == TRUE || data == FALSE, "Got unexpected data %#x.\n", data);
6869 ref_count = IDXGIFactory5_Release(factory);
6870 ok(!ref_count, "Factory has %lu references left.\n", ref_count);
6873 static void test_frame_latency_event(IUnknown *device, BOOL is_d3d12)
6875 DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
6876 IDXGISwapChain2 *swapchain2;
6877 IDXGISwapChain1 *swapchain1;
6878 IDXGIFactory2 *factory2;
6879 IDXGIFactory *factory;
6880 UINT frame_latency;
6881 DWORD wait_result;
6882 ULONG ref_count;
6883 unsigned int i;
6884 HANDLE event;
6885 HWND window;
6886 HRESULT hr;
6888 get_factory(device, is_d3d12, &factory);
6890 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory2, (void**)&factory2);
6891 IDXGIFactory_Release(factory);
6892 if (FAILED(hr))
6894 win_skip("IDXGIFactory2 not available.\n");
6895 return;
6898 window = create_window();
6900 swapchain_desc.Width = 640;
6901 swapchain_desc.Height = 480;
6902 swapchain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
6903 swapchain_desc.Stereo = FALSE;
6904 swapchain_desc.SampleDesc.Count = 1;
6905 swapchain_desc.SampleDesc.Quality = 0;
6906 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6907 swapchain_desc.BufferCount = 2;
6908 swapchain_desc.Scaling = DXGI_SCALING_STRETCH;
6909 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
6910 swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
6911 swapchain_desc.Flags = 0;
6913 hr = IDXGIFactory2_CreateSwapChainForHwnd(factory2, device,
6914 window, &swapchain_desc, NULL, NULL, &swapchain1);
6915 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6917 hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain2, (void**)&swapchain2);
6918 IDXGISwapChain1_Release(swapchain1);
6919 if (FAILED(hr))
6921 win_skip("IDXGISwapChain2 not available.\n");
6922 IDXGIFactory2_Release(factory2);
6923 DestroyWindow(window);
6924 return;
6927 /* test swap chain without waitable object */
6928 frame_latency = 0xdeadbeef;
6929 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6930 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6931 ok(frame_latency == 0xdeadbeef, "Got unexpected frame latency %#x.\n", frame_latency);
6932 hr = IDXGISwapChain2_SetMaximumFrameLatency(swapchain2, 1);
6933 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6934 event = IDXGISwapChain2_GetFrameLatencyWaitableObject(swapchain2);
6935 ok(!event, "Got unexpected event %p.\n", event);
6937 ref_count = IDXGISwapChain2_Release(swapchain2);
6938 ok(!ref_count, "Swap chain has %lu references left.\n", ref_count);
6940 /* test swap chain with waitable object */
6941 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
6943 hr = IDXGIFactory2_CreateSwapChainForHwnd(factory2, device,
6944 window, &swapchain_desc, NULL, NULL, &swapchain1);
6945 ok(hr == S_OK, "Failed to create swap chain, hr %#lx.\n", hr);
6946 hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain2, (void**)&swapchain2);
6947 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6948 IDXGISwapChain1_Release(swapchain1);
6950 event = IDXGISwapChain2_GetFrameLatencyWaitableObject(swapchain2);
6951 ok(!!event, "Got unexpected event %p.\n", event);
6953 /* auto-reset event */
6954 wait_result = WaitForSingleObject(event, 0);
6955 ok(!wait_result, "Got unexpected wait result %#lx.\n", wait_result);
6956 wait_result = WaitForSingleObject(event, 0);
6957 ok(wait_result == WAIT_TIMEOUT, "Got unexpected wait result %#lx.\n", wait_result);
6959 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6960 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6961 ok(frame_latency == 1, "Got unexpected frame latency %#x.\n", frame_latency);
6963 hr = IDXGISwapChain2_SetMaximumFrameLatency(swapchain2, 0);
6964 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
6965 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6966 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6967 ok(frame_latency == 1, "Got unexpected frame latency %#x.\n", frame_latency);
6969 hr = IDXGISwapChain2_SetMaximumFrameLatency(swapchain2, 3);
6970 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6971 hr = IDXGISwapChain2_GetMaximumFrameLatency(swapchain2, &frame_latency);
6972 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
6973 ok(frame_latency == 3, "Got unexpected frame latency %#x.\n", frame_latency);
6975 wait_result = WaitForSingleObject(event, 0);
6976 todo_wine ok(!wait_result, "Got unexpected wait result %#lx.\n", wait_result);
6977 wait_result = WaitForSingleObject(event, 0);
6978 todo_wine ok(!wait_result, "Got unexpected wait result %#lx.\n", wait_result);
6979 wait_result = WaitForSingleObject(event, 100);
6980 ok(wait_result == WAIT_TIMEOUT, "Got unexpected wait result %#lx.\n", wait_result);
6982 for (i = 0; i < 5; i++)
6984 hr = IDXGISwapChain2_Present(swapchain2, 0, 0);
6985 ok(hr == S_OK, "Present %u failed with hr %#lx.\n", i, hr);
6987 wait_result = WaitForSingleObject(event, 100);
6988 ok(!wait_result, "Got unexpected wait result %#lx.\n", wait_result);
6991 wait_result = WaitForSingleObject(event, 100);
6992 ok(wait_result == WAIT_TIMEOUT, "Got unexpected wait result %#lx.\n", wait_result);
6994 ref_count = IDXGISwapChain2_Release(swapchain2);
6995 ok(!ref_count, "Swap chain has %lu references left.\n", ref_count);
6996 DestroyWindow(window);
6997 ref_count = IDXGIFactory2_Release(factory2);
6998 ok(ref_count == !is_d3d12, "Factory has %lu references left.\n", ref_count);
7001 static void test_colour_space_support(IUnknown *device, BOOL is_d3d12)
7003 DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
7004 IDXGISwapChain3 *swapchain3;
7005 IDXGISwapChain1 *swapchain1;
7006 IDXGIFactory2 *factory2;
7007 IDXGIFactory *factory;
7008 ULONG ref_count;
7009 unsigned int i;
7010 UINT support;
7011 HWND window;
7012 HRESULT hr;
7014 static const DXGI_COLOR_SPACE_TYPE colour_spaces[] =
7016 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709,
7017 DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709,
7018 DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709,
7019 DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020,
7020 DXGI_COLOR_SPACE_RESERVED,
7021 DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601,
7022 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601,
7023 DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601,
7024 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709,
7025 DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709,
7026 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020,
7027 DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020,
7028 DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020,
7029 DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020,
7030 DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020,
7031 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020,
7032 DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020,
7033 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020,
7034 DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020,
7035 DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020,
7038 get_factory(device, is_d3d12, &factory);
7040 hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory2, (void**)&factory2);
7041 IDXGIFactory_Release(factory);
7042 if (FAILED(hr))
7044 win_skip("IDXGIFactory2 not available.\n");
7045 return;
7048 window = create_window();
7050 swapchain_desc.Width = 640;
7051 swapchain_desc.Height = 480;
7052 swapchain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
7053 swapchain_desc.Stereo = FALSE;
7054 swapchain_desc.SampleDesc.Count = 1;
7055 swapchain_desc.SampleDesc.Quality = 0;
7056 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
7057 swapchain_desc.BufferCount = 2;
7058 swapchain_desc.Scaling = DXGI_SCALING_STRETCH;
7059 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
7060 swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
7061 swapchain_desc.Flags = 0;
7063 hr = IDXGIFactory2_CreateSwapChainForHwnd(factory2, device,
7064 window, &swapchain_desc, NULL, NULL, &swapchain1);
7065 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7067 hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void**)&swapchain3);
7068 IDXGISwapChain1_Release(swapchain1);
7069 if (FAILED(hr))
7071 win_skip("IDXGISwapChain3 not available.\n");
7072 IDXGIFactory2_Release(factory2);
7073 DestroyWindow(window);
7074 return;
7077 for (i = 0; i < ARRAY_SIZE(colour_spaces); ++i)
7079 support = 0xdeadbeef;
7080 hr = IDXGISwapChain3_CheckColorSpaceSupport(swapchain3, colour_spaces[i], &support);
7081 ok(hr == S_OK, "Got unexpected hr %#lx for test %u.\n", hr, i);
7082 ok(!(support & ~DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT),
7083 "Got unexpected support flags %#x for test %u.\n", support, i);
7085 if (colour_spaces[i] == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709)
7087 ok(support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT,
7088 "Required colour space not supported for test %u.\n", i);
7090 else if (colour_spaces[i] == DXGI_COLOR_SPACE_RESERVED)
7092 ok(!support, "Invalid colour space supported for test %u.\n", i);
7095 hr = IDXGISwapChain3_SetColorSpace1(swapchain3, colour_spaces[i]);
7096 ok(hr == (support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) ? S_OK : E_INVALIDARG,
7097 "Got unexpected hr %#lx for text %u.\n", hr, i);
7100 ref_count = IDXGISwapChain3_Release(swapchain3);
7101 ok(!ref_count, "Swap chain has %lu references left.\n", ref_count);
7102 DestroyWindow(window);
7103 ref_count = IDXGIFactory2_Release(factory2);
7104 ok(ref_count == !is_d3d12, "Factory has %lu references left.\n", ref_count);
7107 static void test_mode_change(IUnknown *device, BOOL is_d3d12)
7109 unsigned int user32_width = 0, user32_height = 0, d3d_width = 0, d3d_height = 0;
7110 unsigned int display_count = 0, mode_idx = 0, adapter_idx, output_idx;
7111 DEVMODEW *original_modes = NULL, old_devmode, devmode, devmode2;
7112 DXGI_SWAP_CHAIN_DESC swapchain_desc, swapchain_desc2;
7113 IDXGIOutput *output, *second_output = NULL;
7114 WCHAR second_monitor_name[CCHDEVICENAME];
7115 IDXGISwapChain *swapchain, *swapchain2;
7116 DXGI_OUTPUT_DESC output_desc;
7117 IDXGIAdapter *adapter;
7118 IDXGIFactory *factory;
7119 BOOL fullscreen, ret;
7120 LONG change_ret;
7121 ULONG refcount;
7122 HRESULT hr;
7124 memset(&devmode, 0, sizeof(devmode));
7125 devmode.dmSize = sizeof(devmode);
7126 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
7127 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7128 ok(equal_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
7129 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
7130 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7131 ok(equal_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
7133 while (EnumDisplaySettingsW(NULL, mode_idx++, &devmode))
7135 if (devmode.dmPelsWidth == registry_mode.dmPelsWidth
7136 && devmode.dmPelsHeight == registry_mode.dmPelsHeight)
7137 continue;
7139 if (!d3d_width && !d3d_height)
7141 d3d_width = devmode.dmPelsWidth;
7142 d3d_height = devmode.dmPelsHeight;
7143 continue;
7146 if (devmode.dmPelsWidth == d3d_width && devmode.dmPelsHeight == d3d_height)
7147 continue;
7149 user32_width = devmode.dmPelsWidth;
7150 user32_height = devmode.dmPelsHeight;
7151 break;
7153 if (!user32_width || !user32_height)
7155 skip("Failed to find three different display modes for the primary output.\n");
7156 return;
7159 ret = save_display_modes(&original_modes, &display_count);
7160 ok(ret, "Failed to save original display modes.\n");
7162 get_factory(device, is_d3d12, &factory);
7164 /* Test that no mode restorations if no mode changes actually happened */
7165 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
7166 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
7168 swapchain_desc.BufferDesc.Width = registry_mode.dmPelsWidth;
7169 swapchain_desc.BufferDesc.Height = registry_mode.dmPelsHeight;
7170 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
7171 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
7172 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
7173 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
7174 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
7175 swapchain_desc.SampleDesc.Count = 1;
7176 swapchain_desc.SampleDesc.Quality = 0;
7177 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
7178 swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
7179 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
7180 swapchain_desc.Windowed = TRUE;
7181 swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
7182 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
7184 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7185 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7186 refcount = IDXGISwapChain_Release(swapchain);
7187 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7189 memset(&devmode2, 0, sizeof(devmode2));
7190 devmode2.dmSize = sizeof(devmode2);
7191 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
7192 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7193 ok(equal_mode_rect(&devmode2, &registry_mode), "Got a different mode.\n");
7194 ret = restore_display_modes(original_modes, display_count);
7195 ok(ret, "Failed to restore display modes.\n");
7197 /* If current display settings are different than the display settings in registry before
7198 * calling SetFullscreenState() */
7199 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
7200 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
7202 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7203 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7204 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7205 ok(hr == DXGI_ERROR_UNSUPPORTED /* Win7 */
7206 || hr == S_OK /* Win8~Win10 1909 */
7207 || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, /* Win10 2004 */
7208 "Got unexpected hr %#lx.\n", hr);
7210 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7211 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7212 refcount = IDXGISwapChain_Release(swapchain);
7213 ok(!refcount, "IDXGISwapChain has %lu 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 use display settings in the registry with a fullscreen device */
7218 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7219 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7220 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7221 if (FAILED(hr))
7223 skip("SetFullscreenState failed, hr %#lx.\n", hr);
7224 refcount = IDXGISwapChain_Release(swapchain);
7225 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7226 goto done;
7229 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
7230 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
7231 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7232 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7234 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
7235 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7236 ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
7237 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
7238 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7239 ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
7240 refcount = IDXGISwapChain_Release(swapchain);
7241 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7242 ret = restore_display_modes(original_modes, display_count);
7243 ok(ret, "Failed to restore display modes.\n");
7245 for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter)); ++adapter_idx)
7247 for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output)); ++output_idx)
7249 hr = IDXGIOutput_GetDesc(output, &output_desc);
7250 ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#lx.\n", adapter_idx, output_idx, hr);
7252 if ((adapter_idx || output_idx) && output_desc.AttachedToDesktop)
7254 second_output = output;
7255 break;
7258 IDXGIOutput_Release(output);
7261 IDXGIAdapter_Release(adapter);
7262 if (second_output)
7263 break;
7266 if (!second_output)
7268 skip("Following tests require two monitors.\n");
7269 goto done;
7271 lstrcpyW(second_monitor_name, output_desc.DeviceName);
7273 memset(&old_devmode, 0, sizeof(old_devmode));
7274 old_devmode.dmSize = sizeof(old_devmode);
7275 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
7276 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7278 mode_idx = 0;
7279 d3d_width = 0;
7280 d3d_height = 0;
7281 user32_width = 0;
7282 user32_height = 0;
7283 while (EnumDisplaySettingsW(second_monitor_name, mode_idx++, &devmode))
7285 if (devmode.dmPelsWidth == old_devmode.dmPelsWidth
7286 && devmode.dmPelsHeight == old_devmode.dmPelsHeight)
7287 continue;
7289 if (!d3d_width && !d3d_height)
7291 d3d_width = devmode.dmPelsWidth;
7292 d3d_height = devmode.dmPelsHeight;
7293 continue;
7296 if (devmode.dmPelsWidth == d3d_width && devmode.dmPelsHeight == d3d_height)
7297 continue;
7299 user32_width = devmode.dmPelsWidth;
7300 user32_height = devmode.dmPelsHeight;
7301 break;
7303 if (!user32_width || !user32_height)
7305 skip("Failed to find three different display modes for the second output.\n");
7306 goto done;
7309 /* Test that mode restorations for non-primary outputs upon fullscreen state changes */
7310 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7311 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7312 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7313 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7315 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
7316 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
7317 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7318 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7319 if (devmode2.dmPelsWidth == old_devmode.dmPelsWidth
7320 && devmode2.dmPelsHeight == old_devmode.dmPelsHeight)
7322 skip("Failed to change display settings of the second monitor.\n");
7323 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7324 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7325 refcount = IDXGISwapChain_Release(swapchain);
7326 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7327 goto done;
7330 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7331 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7333 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7334 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7335 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7336 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
7337 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7338 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7339 hr = IDXGIOutput_GetDesc(second_output, &output_desc);
7340 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7341 ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
7342 old_devmode.dmPelsWidth, "Expected width %lu, got %lu.\n", old_devmode.dmPelsWidth,
7343 output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
7344 ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
7345 old_devmode.dmPelsHeight, "Expected height %lu, got %lu.\n", old_devmode.dmPelsHeight,
7346 output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
7348 refcount = IDXGISwapChain_Release(swapchain);
7349 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7350 ret = restore_display_modes(original_modes, display_count);
7351 ok(ret, "Failed to restore display modes.\n");
7353 /* Test that mode restorations for non-primary outputs use display settings in the registry */
7354 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7355 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7356 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7357 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7359 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
7360 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
7361 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
7362 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7363 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7365 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7366 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7367 ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
7368 "Expected resolution %lux%lu, got %lux%lu.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
7369 devmode2.dmPelsWidth, devmode2.dmPelsHeight);
7370 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
7371 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7372 ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
7373 "Expected resolution %lux%lu, got %lux%lu.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
7374 devmode2.dmPelsWidth, devmode2.dmPelsHeight);
7375 hr = IDXGIOutput_GetDesc(second_output, &output_desc);
7376 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7377 ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
7378 devmode.dmPelsWidth, "Expected width %lu, got %lu.\n", devmode.dmPelsWidth,
7379 output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
7380 ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
7381 devmode.dmPelsHeight, "Expected height %lu, got %lu.\n", devmode.dmPelsHeight,
7382 output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
7384 refcount = IDXGISwapChain_Release(swapchain);
7385 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7386 ret = restore_display_modes(original_modes, display_count);
7387 ok(ret, "Failed to restore display modes.\n");
7389 /* Test that mode restorations for non-primary outputs on fullscreen state changes when there
7390 * are two fullscreen swapchains on different outputs */
7391 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
7392 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7394 swapchain_desc2 = swapchain_desc;
7395 swapchain_desc.BufferDesc.Width = d3d_width;
7396 swapchain_desc.BufferDesc.Height = d3d_height;
7397 swapchain_desc2.OutputWindow = CreateWindowA("static", "dxgi_test2", 0,
7398 old_devmode.dmPosition.x, old_devmode.dmPosition.y, 400, 200, 0, 0, 0, 0);
7399 hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc2, &swapchain2);
7400 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7401 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
7402 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7403 hr = IDXGISwapChain_SetFullscreenState(swapchain2, TRUE, NULL);
7404 if (FAILED(hr))
7406 skip("SetFullscreenState failed, hr %#lx.\n", hr);
7407 refcount = IDXGISwapChain_Release(swapchain2);
7408 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7409 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7410 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7411 refcount = IDXGISwapChain_Release(swapchain);
7412 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7413 goto done;
7416 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
7417 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7418 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
7419 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7420 ok(!fullscreen, "Expected swapchain not fullscreen.\n");
7421 hr = IDXGISwapChain_GetFullscreenState(swapchain2, &fullscreen, NULL);
7422 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7423 ok(fullscreen, "Expected swapchain fullscreen.\n");
7425 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
7426 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7427 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7428 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
7429 ok(ret, "EnumDisplaySettingsW failed, error %#lx.\n", GetLastError());
7430 ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
7431 hr = IDXGIOutput_GetDesc(second_output, &output_desc);
7432 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7433 ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
7434 old_devmode.dmPelsWidth, "Expected width %lu, got %lu.\n", old_devmode.dmPelsWidth,
7435 output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
7436 ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
7437 old_devmode.dmPelsHeight, "Expected height %lu, got %lu.\n", old_devmode.dmPelsHeight,
7438 output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
7440 hr = IDXGISwapChain_SetFullscreenState(swapchain2, FALSE, NULL);
7441 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7442 refcount = IDXGISwapChain_Release(swapchain2);
7443 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7444 refcount = IDXGISwapChain_Release(swapchain);
7445 ok(!refcount, "IDXGISwapChain has %lu references left.\n", refcount);
7446 DestroyWindow(swapchain_desc2.OutputWindow);
7447 ret = restore_display_modes(original_modes, display_count);
7448 ok(ret, "Failed to restore display modes.\n");
7450 done:
7451 if (second_output)
7452 IDXGIOutput_Release(second_output);
7453 DestroyWindow(swapchain_desc.OutputWindow);
7454 refcount = IDXGIFactory_Release(factory);
7455 ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
7456 ret = restore_display_modes(original_modes, display_count);
7457 ok(ret, "Failed to restore display modes.\n");
7458 heap_free(original_modes);
7461 static void test_swapchain_present_count(IUnknown *device, BOOL is_d3d12)
7463 UINT present_count, expected;
7464 IDXGISwapChain *swapchain;
7465 HWND window;
7466 HRESULT hr;
7468 window = create_window();
7469 swapchain = create_swapchain(device, is_d3d12, window);
7471 present_count = ~0u;
7472 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7473 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7474 ok(!present_count, "Got unexpected present count %u.\n", present_count);
7476 hr = IDXGISwapChain_Present(swapchain, 0, 0);
7477 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7478 expected = present_count + 1;
7479 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7480 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7481 ok(present_count == expected, "Got unexpected present count %u, expected %u.\n", present_count, expected);
7483 hr = IDXGISwapChain_Present(swapchain, 10, 0);
7484 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
7485 expected = present_count;
7486 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7487 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7488 ok(present_count == expected, "Got unexpected present count %u, expected %u.\n", present_count, expected);
7490 hr = IDXGISwapChain_Present(swapchain, 0, DXGI_PRESENT_TEST);
7491 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7492 expected = present_count;
7493 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7494 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7495 ok(present_count == expected, "Got unexpected present count %u, expected %u.\n", present_count, expected);
7497 ShowWindow(window, SW_MINIMIZE);
7498 hr = IDXGISwapChain_Present(swapchain, 0, 0);
7499 ok(hr == (is_d3d12 ? S_OK : DXGI_STATUS_OCCLUDED), "Got unexpected hr %#lx.\n", hr);
7500 expected = present_count + !!is_d3d12;
7501 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7502 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7503 ok(present_count == expected, "Got unexpected present count %u, expected %u.\n", present_count, expected);
7505 ShowWindow(window, SW_NORMAL);
7506 hr = IDXGISwapChain_Present(swapchain, 0, 0);
7507 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7508 expected = present_count + 1;
7509 hr = IDXGISwapChain_GetLastPresentCount(swapchain, &present_count);
7510 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
7511 ok(present_count == expected, "Got unexpected present count %u, expected %u.\n", present_count, expected);
7513 IDXGISwapChain_Release(swapchain);
7514 DestroyWindow(window);
7517 static void run_on_d3d10(void (*test_func)(IUnknown *device, BOOL is_d3d12))
7519 IDXGIDevice *device;
7520 ULONG refcount;
7522 if (!(device = create_device(0)))
7524 skip("Failed to create Direct3D 10 device.\n");
7525 return;
7528 test_func((IUnknown *)device, FALSE);
7530 refcount = IDXGIDevice_Release(device);
7531 ok(!refcount, "Device has %lu references left.\n", refcount);
7534 static void run_on_d3d12(void (*test_func)(IUnknown *device, BOOL is_d3d12))
7536 ID3D12CommandQueue *queue;
7537 ID3D12Device *device;
7538 ULONG refcount;
7540 if (!(device = create_d3d12_device()))
7542 skip("Failed to create Direct3D 12 device.\n");
7543 return;
7546 queue = create_d3d12_direct_queue(device);
7548 test_func((IUnknown *)queue, TRUE);
7550 wait_queue_idle(device, queue);
7552 refcount = ID3D12CommandQueue_Release(queue);
7553 ok(!refcount, "Command queue has %lu references left.\n", refcount);
7554 refcount = ID3D12Device_Release(device);
7555 ok(!refcount, "Device has %lu references left.\n", refcount);
7558 START_TEST(dxgi)
7560 HMODULE dxgi_module, d3d11_module, d3d12_module, gdi32_module;
7561 BOOL enable_debug_layer = FALSE;
7562 unsigned int argc, i;
7563 ID3D12Debug *debug;
7564 char **argv;
7566 dxgi_module = GetModuleHandleA("dxgi.dll");
7567 pCreateDXGIFactory1 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory1");
7568 pCreateDXGIFactory2 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory2");
7570 gdi32_module = GetModuleHandleA("gdi32.dll");
7571 pD3DKMTCheckVidPnExclusiveOwnership = (void *)GetProcAddress(gdi32_module, "D3DKMTCheckVidPnExclusiveOwnership");
7572 pD3DKMTCloseAdapter = (void *)GetProcAddress(gdi32_module, "D3DKMTCloseAdapter");
7573 pD3DKMTOpenAdapterFromGdiDisplayName = (void *)GetProcAddress(gdi32_module, "D3DKMTOpenAdapterFromGdiDisplayName");
7575 d3d11_module = LoadLibraryA("d3d11.dll");
7576 pD3D11CreateDevice = (void *)GetProcAddress(d3d11_module, "D3D11CreateDevice");
7578 registry_mode.dmSize = sizeof(registry_mode);
7579 ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &registry_mode), "Failed to get display mode.\n");
7581 use_mt = !getenv("WINETEST_NO_MT_D3D");
7582 /* Some host drivers (MacOS, Mesa radeonsi) never unmap memory even when
7583 * requested. When using the chunk allocator, running the tests with more
7584 * than one thread can exceed the 32-bit virtual address space. */
7585 if (sizeof(void *) == 4 && !strcmp(winetest_platform, "wine"))
7586 use_mt = FALSE;
7588 argc = winetest_get_mainargs(&argv);
7589 for (i = 2; i < argc; ++i)
7591 if (!strcmp(argv[i], "--validate"))
7592 enable_debug_layer = TRUE;
7593 else if (!strcmp(argv[i], "--warp"))
7594 use_warp_adapter = TRUE;
7595 else if (!strcmp(argv[i], "--adapter") && i + 1 < argc)
7596 use_adapter_idx = atoi(argv[++i]);
7597 else if (!strcmp(argv[i], "--single"))
7598 use_mt = FALSE;
7601 queue_test(test_adapter_desc);
7602 queue_test(test_adapter_luid);
7603 queue_test(test_query_video_memory_info);
7604 queue_test(test_check_interface_support);
7605 queue_test(test_create_surface);
7606 queue_test(test_parents);
7607 queue_test(test_output);
7608 queue_test(test_find_closest_matching_mode);
7609 queue_test(test_resize_target_wndproc);
7610 queue_test(test_create_factory);
7611 queue_test(test_private_data);
7612 queue_test(test_maximum_frame_latency);
7613 queue_test(test_output_desc);
7614 queue_test(test_object_wrapping);
7615 queue_test(test_factory_check_feature_support);
7617 run_queued_tests();
7619 /* These tests use full-screen swapchains, so shouldn't run in parallel. */
7620 test_create_swapchain();
7621 test_inexact_modes();
7622 test_gamma_control();
7623 test_multi_adapter();
7624 test_swapchain_parameters();
7625 test_swapchain_window_messages();
7626 test_swapchain_window_styles();
7627 run_on_d3d10(test_set_fullscreen);
7628 run_on_d3d10(test_resize_target);
7629 run_on_d3d10(test_swapchain_resize);
7630 run_on_d3d10(test_swapchain_present);
7631 run_on_d3d10(test_swapchain_backbuffer_index);
7632 run_on_d3d10(test_swapchain_formats);
7633 run_on_d3d10(test_output_ownership);
7634 run_on_d3d10(test_cursor_clipping);
7635 run_on_d3d10(test_get_containing_output);
7636 run_on_d3d10(test_window_association);
7637 run_on_d3d10(test_default_fullscreen_target_output);
7638 run_on_d3d10(test_mode_change);
7639 run_on_d3d10(test_swapchain_present_count);
7641 if (!(d3d12_module = LoadLibraryA("d3d12.dll")))
7643 skip("Direct3D 12 is not available.\n");
7644 return;
7647 pD3D12CreateDevice = (void *)GetProcAddress(d3d12_module, "D3D12CreateDevice");
7648 pD3D12GetDebugInterface = (void *)GetProcAddress(d3d12_module, "D3D12GetDebugInterface");
7650 if (enable_debug_layer && SUCCEEDED(pD3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug)))
7652 ID3D12Debug_EnableDebugLayer(debug);
7653 ID3D12Debug_Release(debug);
7656 run_on_d3d12(test_set_fullscreen);
7657 run_on_d3d12(test_resize_target);
7658 run_on_d3d12(test_swapchain_resize);
7659 run_on_d3d12(test_swapchain_present);
7660 run_on_d3d12(test_swapchain_backbuffer_index);
7661 run_on_d3d12(test_swapchain_formats);
7662 run_on_d3d12(test_output_ownership);
7663 run_on_d3d12(test_cursor_clipping);
7664 run_on_d3d12(test_frame_latency_event);
7665 run_on_d3d12(test_colour_space_support);
7666 run_on_d3d12(test_get_containing_output);
7667 run_on_d3d12(test_window_association);
7668 run_on_d3d12(test_default_fullscreen_target_output);
7669 run_on_d3d12(test_mode_change);
7670 run_on_d3d12(test_swapchain_present_count);
7672 FreeLibrary(d3d12_module);