dxgi: Implement dxgi_output_FindClosestMatchingMode().
[wine.git] / dlls / dxgi / tests / device.c
blob8ec65e25f817ffe9d249b860f407ba8a92c4dcc3
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 #define COBJMACROS
21 #include "initguid.h"
22 #include "d3d11.h"
23 #include "wine/test.h"
25 enum frame_latency
27 DEFAULT_FRAME_LATENCY = 3,
28 MAX_FRAME_LATENCY = 16,
31 static DEVMODEW registry_mode;
33 static HRESULT (WINAPI *pCreateDXGIFactory1)(REFIID iid, void **factory);
35 static ULONG get_refcount(IUnknown *iface)
37 IUnknown_AddRef(iface);
38 return IUnknown_Release(iface);
41 #define check_output_desc(a, b) check_output_desc_(__LINE__, a, b)
42 static void check_output_desc_(unsigned int line, const DXGI_OUTPUT_DESC *desc,
43 const struct DXGI_OUTPUT_DESC *expected_desc)
45 ok_(__FILE__, line)(!lstrcmpW(desc->DeviceName, expected_desc->DeviceName),
46 "Got unexpected device name %s, expected %s.\n",
47 wine_dbgstr_w(desc->DeviceName), wine_dbgstr_w(expected_desc->DeviceName));
48 ok_(__FILE__, line)(EqualRect(&desc->DesktopCoordinates, &expected_desc->DesktopCoordinates),
49 "Got unexpected desktop coordinates %s, expected %s.\n",
50 wine_dbgstr_rect(&desc->DesktopCoordinates),
51 wine_dbgstr_rect(&expected_desc->DesktopCoordinates));
54 #define check_output_equal(a, b) check_output_equal_(__LINE__, a, b)
55 static void check_output_equal_(unsigned int line, IDXGIOutput *output1, IDXGIOutput *output2)
57 DXGI_OUTPUT_DESC desc1, desc2;
58 HRESULT hr;
60 hr = IDXGIOutput_GetDesc(output1, &desc1);
61 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
62 hr = IDXGIOutput_GetDesc(output2, &desc2);
63 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
64 check_output_desc_(line, &desc1, &desc2);
67 static BOOL output_belongs_to_adapter(IDXGIOutput *output, IDXGIAdapter *adapter)
69 DXGI_OUTPUT_DESC output_desc, desc;
70 unsigned int output_idx;
71 IDXGIOutput *o;
72 HRESULT hr;
74 hr = IDXGIOutput_GetDesc(output, &output_desc);
75 ok(SUCCEEDED(hr), "Failed to get output desc, hr %#x.\n", hr);
77 for (output_idx = 0; IDXGIAdapter_EnumOutputs(adapter, output_idx, &o) != DXGI_ERROR_NOT_FOUND; ++output_idx)
79 hr = IDXGIOutput_GetDesc(o, &desc);
80 ok(SUCCEEDED(hr), "Failed to get output desc, hr %#x.\n", hr);
81 IDXGIOutput_Release(o);
83 if (!lstrcmpW(desc.DeviceName, output_desc.DeviceName)
84 && EqualRect(&desc.DesktopCoordinates, &output_desc.DesktopCoordinates))
85 return TRUE;
88 return FALSE;
91 struct fullscreen_state
93 RECT window_rect;
94 RECT client_rect;
95 HMONITOR monitor;
96 RECT monitor_rect;
99 struct swapchain_fullscreen_state
101 struct fullscreen_state fullscreen_state;
102 BOOL fullscreen;
103 IDXGIOutput *target;
106 #define capture_fullscreen_state(a, b) capture_fullscreen_state_(__LINE__, a, b)
107 static void capture_fullscreen_state_(unsigned int line, struct fullscreen_state *state, HWND window)
109 MONITORINFOEXW monitor_info;
110 BOOL ret;
112 ret = GetWindowRect(window, &state->window_rect);
113 ok_(__FILE__, line)(ret, "GetWindowRect failed.\n");
114 ret = GetClientRect(window, &state->client_rect);
115 ok_(__FILE__, line)(ret, "GetClientRect failed.\n");
117 state->monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
118 ok_(__FILE__, line)(!!state->monitor, "Failed to get monitor from window.\n");
120 monitor_info.cbSize = sizeof(monitor_info);
121 ret = GetMonitorInfoW(state->monitor, (MONITORINFO *)&monitor_info);
122 ok_(__FILE__, line)(ret, "Failed to get monitor info.\n");
123 state->monitor_rect = monitor_info.rcMonitor;
126 #define check_fullscreen_state(a, b) check_fullscreen_state_(__LINE__, a, b)
127 static void check_fullscreen_state_(unsigned int line, const struct fullscreen_state *state,
128 const struct fullscreen_state *expected_state)
130 ok_(__FILE__, line)(EqualRect(&state->window_rect, &expected_state->window_rect),
131 "Got window rect %s, expected %s.\n",
132 wine_dbgstr_rect(&state->window_rect), wine_dbgstr_rect(&expected_state->window_rect));
133 ok_(__FILE__, line)(EqualRect(&state->client_rect, &expected_state->client_rect),
134 "Got client rect %s, expected %s.\n",
135 wine_dbgstr_rect(&state->client_rect), wine_dbgstr_rect(&expected_state->client_rect));
136 ok_(__FILE__, line)(state->monitor == expected_state->monitor,
137 "Got monitor %p, expected %p.\n",
138 state->monitor, expected_state->monitor);
139 ok_(__FILE__, line)(EqualRect(&state->monitor_rect, &expected_state->monitor_rect),
140 "Got monitor rect %s, expected %s.\n",
141 wine_dbgstr_rect(&state->monitor_rect), wine_dbgstr_rect(&expected_state->monitor_rect));
144 #define check_window_fullscreen_state(a, b) check_window_fullscreen_state_(__LINE__, a, b)
145 static void check_window_fullscreen_state_(unsigned int line, HWND window,
146 const struct fullscreen_state *expected_state)
148 struct fullscreen_state current_state;
149 capture_fullscreen_state_(line, &current_state, window);
150 check_fullscreen_state_(line, &current_state, expected_state);
153 #define check_swapchain_fullscreen_state(a, b) check_swapchain_fullscreen_state_(__LINE__, a, b)
154 static void check_swapchain_fullscreen_state_(unsigned int line, IDXGISwapChain *swapchain,
155 const struct swapchain_fullscreen_state *expected_state)
157 IDXGIOutput *containing_output, *target;
158 DXGI_SWAP_CHAIN_DESC swapchain_desc;
159 BOOL fullscreen;
160 HRESULT hr;
162 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
163 ok_(__FILE__, line)(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
164 check_window_fullscreen_state_(line, swapchain_desc.OutputWindow, &expected_state->fullscreen_state);
166 ok_(__FILE__, line)(swapchain_desc.Windowed == !expected_state->fullscreen,
167 "Got windowed %#x, expected %#x.\n",
168 swapchain_desc.Windowed, !expected_state->fullscreen);
170 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
171 ok_(__FILE__, line)(SUCCEEDED(hr), "GetFullscreenState failed, hr %#x.\n", hr);
172 ok_(__FILE__, line)(fullscreen == expected_state->fullscreen, "Got fullscreen %#x, expected %#x.\n",
173 fullscreen, expected_state->fullscreen);
175 if (!swapchain_desc.Windowed && expected_state->fullscreen)
177 IDXGIAdapter *adapter;
178 IDXGIDevice *device;
180 hr = IDXGISwapChain_GetDevice(swapchain, &IID_IDXGIDevice, (void **)&device);
181 ok_(__FILE__, line)(SUCCEEDED(hr), "GetDevice failed, hr %#x.\n", hr);
182 hr = IDXGIDevice_GetAdapter(device, &adapter);
183 ok_(__FILE__, line)(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
184 IDXGIDevice_Release(device);
186 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
187 ok_(__FILE__, line)(SUCCEEDED(hr), "GetContainingOutput failed, hr %#x.\n", hr);
189 check_output_equal_(line, target, expected_state->target);
190 ok_(__FILE__, line)(target == containing_output, "Got target %p, expected %p.\n",
191 target, containing_output);
192 ok_(__FILE__, line)(output_belongs_to_adapter(target, adapter),
193 "Output %p doesn't belong to adapter %p.\n",
194 target, adapter);
196 IDXGIOutput_Release(target);
197 IDXGIOutput_Release(containing_output);
198 IDXGIAdapter_Release(adapter);
200 else
202 ok_(__FILE__, line)(!target, "Got unexpected target %p.\n", target);
206 #define compute_expected_swapchain_fullscreen_state_after_fullscreen_change(a, b, c, d, e, f) \
207 compute_expected_swapchain_fullscreen_state_after_fullscreen_change_(__LINE__, a, b, c, d, e, f)
208 static void compute_expected_swapchain_fullscreen_state_after_fullscreen_change_(unsigned int line,
209 struct swapchain_fullscreen_state *state, const DXGI_SWAP_CHAIN_DESC *swapchain_desc,
210 const RECT *old_monitor_rect, unsigned int new_width, unsigned int new_height, IDXGIOutput *target)
212 if (!new_width && !new_height)
214 RECT client_rect;
215 GetClientRect(swapchain_desc->OutputWindow, &client_rect);
216 new_width = client_rect.right - client_rect.left;
217 new_height = client_rect.bottom - client_rect.top;
220 if (target)
222 DXGI_MODE_DESC mode_desc = swapchain_desc->BufferDesc;
223 HRESULT hr;
225 mode_desc.Width = new_width;
226 mode_desc.Height = new_height;
227 hr = IDXGIOutput_FindClosestMatchingMode(target, &mode_desc, &mode_desc, NULL);
228 ok_(__FILE__, line)(SUCCEEDED(hr), "FindClosestMatchingMode failed, hr %#x.\n", hr);
229 new_width = mode_desc.Width;
230 new_height = mode_desc.Height;
233 state->fullscreen = TRUE;
234 if (swapchain_desc->Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)
236 unsigned int new_x = (old_monitor_rect->left >= 0)
237 ? old_monitor_rect->left : old_monitor_rect->right - new_width;
238 unsigned new_y = (old_monitor_rect->top >= 0)
239 ? old_monitor_rect->top : old_monitor_rect->bottom - new_height;
240 RECT new_monitor_rect = {0, 0, new_width, new_height};
241 OffsetRect(&new_monitor_rect, new_x, new_y);
243 SetRect(&state->fullscreen_state.client_rect, 0, 0, new_width, new_height);
244 state->fullscreen_state.monitor_rect = new_monitor_rect;
245 state->fullscreen_state.window_rect = new_monitor_rect;
247 if (target)
248 state->target = target;
250 else
252 state->fullscreen_state.window_rect = *old_monitor_rect;
253 SetRect(&state->fullscreen_state.client_rect, 0, 0,
254 old_monitor_rect->right - old_monitor_rect->left,
255 old_monitor_rect->bottom - old_monitor_rect->top);
259 static IDXGIDevice *create_device(void)
261 IDXGIDevice *dxgi_device;
262 ID3D10Device *device;
263 HRESULT hr;
265 if (SUCCEEDED(D3D10CreateDevice(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &device)))
266 goto success;
267 if (SUCCEEDED(D3D10CreateDevice(NULL, D3D10_DRIVER_TYPE_WARP, NULL, 0, D3D10_SDK_VERSION, &device)))
268 goto success;
269 if (SUCCEEDED(D3D10CreateDevice(NULL, D3D10_DRIVER_TYPE_REFERENCE, NULL, 0, D3D10_SDK_VERSION, &device)))
270 goto success;
272 return NULL;
274 success:
275 hr = ID3D10Device_QueryInterface(device, &IID_IDXGIDevice, (void **)&dxgi_device);
276 ok(SUCCEEDED(hr), "Created device does not implement IDXGIDevice\n");
277 ID3D10Device_Release(device);
279 return dxgi_device;
282 static void test_adapter_desc(void)
284 DXGI_ADAPTER_DESC1 desc1;
285 IDXGIAdapter1 *adapter1;
286 DXGI_ADAPTER_DESC desc;
287 IDXGIAdapter *adapter;
288 IDXGIDevice *device;
289 ULONG refcount;
290 HRESULT hr;
292 if (!(device = create_device()))
294 skip("Failed to create device, skipping tests.\n");
295 return;
298 hr = IDXGIDevice_GetAdapter(device, &adapter);
299 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
301 hr = IDXGIAdapter_GetDesc(adapter, NULL);
302 ok(hr == E_INVALIDARG, "GetDesc returned %#x, expected %#x.\n",
303 hr, E_INVALIDARG);
305 hr = IDXGIAdapter_GetDesc(adapter, &desc);
306 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
308 trace("%s.\n", wine_dbgstr_w(desc.Description));
309 trace("%04x: %04x:%04x (rev %02x).\n",
310 desc.SubSysId, desc.VendorId, desc.DeviceId, desc.Revision);
311 trace("Dedicated video memory: %lu (%lu MB).\n",
312 desc.DedicatedVideoMemory, desc.DedicatedVideoMemory / (1024 * 1024));
313 trace("Dedicated system memory: %lu (%lu MB).\n",
314 desc.DedicatedSystemMemory, desc.DedicatedSystemMemory / (1024 * 1024));
315 trace("Shared system memory: %lu (%lu MB).\n",
316 desc.SharedSystemMemory, desc.SharedSystemMemory / (1024 * 1024));
317 trace("LUID: %08x:%08x.\n", desc.AdapterLuid.HighPart, desc.AdapterLuid.LowPart);
319 hr = IDXGIAdapter_QueryInterface(adapter, &IID_IDXGIAdapter1, (void **)&adapter1);
320 ok(SUCCEEDED(hr) || broken(hr == E_NOINTERFACE), "Got unexpected hr %#x.\n", hr);
321 if (hr == E_NOINTERFACE)
322 goto done;
324 hr = IDXGIAdapter1_GetDesc1(adapter1, &desc1);
325 ok(SUCCEEDED(hr), "GetDesc1 failed, hr %#x.\n", hr);
327 ok(!lstrcmpW(desc.Description, desc1.Description),
328 "Got unexpected description %s.\n", wine_dbgstr_w(desc1.Description));
329 ok(desc1.VendorId == desc.VendorId, "Got unexpected vendor ID %04x.\n", desc1.VendorId);
330 ok(desc1.DeviceId == desc.DeviceId, "Got unexpected device ID %04x.\n", desc1.DeviceId);
331 ok(desc1.SubSysId == desc.SubSysId, "Got unexpected sub system ID %04x.\n", desc1.SubSysId);
332 ok(desc1.Revision == desc.Revision, "Got unexpected revision %02x.\n", desc1.Revision);
333 ok(desc1.DedicatedVideoMemory == desc.DedicatedVideoMemory,
334 "Got unexpected dedicated video memory %lu.\n", desc1.DedicatedVideoMemory);
335 ok(desc1.DedicatedSystemMemory == desc.DedicatedSystemMemory,
336 "Got unexpected dedicated system memory %lu.\n", desc1.DedicatedSystemMemory);
337 ok(desc1.SharedSystemMemory == desc.SharedSystemMemory,
338 "Got unexpected shared system memory %lu.\n", desc1.SharedSystemMemory);
339 ok(!memcmp(&desc.AdapterLuid, &desc1.AdapterLuid, sizeof(desc.AdapterLuid)),
340 "Got unexpected adapter LUID %08x:%08x.\n", desc1.AdapterLuid.HighPart, desc1.AdapterLuid.LowPart);
341 trace("Flags: %08x.\n", desc1.Flags);
343 IDXGIAdapter1_Release(adapter1);
345 done:
346 IDXGIAdapter_Release(adapter);
347 refcount = IDXGIDevice_Release(device);
348 ok(!refcount, "Device has %u references left.\n", refcount);
351 static void test_check_interface_support(void)
353 LARGE_INTEGER driver_version;
354 IDXGIAdapter *adapter;
355 IDXGIDevice *device;
356 IUnknown *iface;
357 ULONG refcount;
358 HRESULT hr;
360 if (!(device = create_device()))
362 skip("Failed to create device.\n");
363 return;
366 hr = IDXGIDevice_GetAdapter(device, &adapter);
367 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
369 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device, NULL);
370 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
371 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device, &driver_version);
372 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
374 trace("UMD version: %u.%u.%u.%u.\n",
375 HIWORD(U(driver_version).HighPart), LOWORD(U(driver_version).HighPart),
376 HIWORD(U(driver_version).LowPart), LOWORD(U(driver_version).LowPart));
378 hr = IDXGIDevice_QueryInterface(device, &IID_ID3D10Device1, (void **)&iface);
379 if (SUCCEEDED(hr))
381 IUnknown_Release(iface);
382 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device1, NULL);
383 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
384 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D10Device1, &driver_version);
385 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
387 else
389 win_skip("D3D10.1 is not supported.\n");
392 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D11Device, NULL);
393 ok(hr == DXGI_ERROR_UNSUPPORTED, "Got unexpected hr %#x.\n", hr);
394 driver_version.HighPart = driver_version.LowPart = 0xdeadbeef;
395 hr = IDXGIAdapter_CheckInterfaceSupport(adapter, &IID_ID3D11Device, &driver_version);
396 ok(hr == DXGI_ERROR_UNSUPPORTED, "Got unexpected hr %#x.\n", hr);
397 ok(driver_version.HighPart == 0xdeadbeef, "Got unexpected driver version %#x.\n", driver_version.HighPart);
398 ok(driver_version.LowPart == 0xdeadbeef, "Got unexpected driver version %#x.\n", driver_version.LowPart);
400 IDXGIAdapter_Release(adapter);
401 refcount = IDXGIDevice_Release(device);
402 ok(!refcount, "Device has %u references left.\n", refcount);
405 static void test_create_surface(void)
407 DXGI_SURFACE_DESC desc;
408 IDXGISurface *surface;
409 IDXGIDevice *device;
410 IUnknown *surface1;
411 IUnknown *texture;
412 ULONG refcount;
413 HRESULT hr;
415 if (!(device = create_device()))
417 skip("Failed to create device, skipping tests.\n");
418 return;
421 desc.Width = 512;
422 desc.Height = 512;
423 desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
424 desc.SampleDesc.Count = 1;
425 desc.SampleDesc.Quality = 0;
427 hr = IDXGIDevice_CreateSurface(device, &desc, 1, DXGI_USAGE_RENDER_TARGET_OUTPUT, NULL, &surface);
428 ok(SUCCEEDED(hr), "Failed to create a dxgi surface, hr %#x\n", hr);
430 hr = IDXGISurface_QueryInterface(surface, &IID_ID3D10Texture2D, (void **)&texture);
431 ok(SUCCEEDED(hr), "Surface should implement ID3D10Texture2D\n");
432 IUnknown_Release(texture);
434 hr = IDXGISurface_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture);
435 ok(SUCCEEDED(hr) || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
436 "Surface should implement ID3D11Texture2D.\n");
437 if (SUCCEEDED(hr)) IUnknown_Release(texture);
439 hr = IDXGISurface_QueryInterface(surface, &IID_IDXGISurface1, (void **)&surface1);
440 ok(SUCCEEDED(hr) || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
441 "Surface should implement IDXGISurface1.\n");
442 if (SUCCEEDED(hr)) IUnknown_Release(surface1);
444 IDXGISurface_Release(surface);
445 refcount = IDXGIDevice_Release(device);
446 ok(!refcount, "Device has %u references left.\n", refcount);
449 static void test_parents(void)
451 DXGI_SURFACE_DESC surface_desc;
452 IDXGISurface *surface;
453 IDXGIFactory *factory;
454 IDXGIAdapter *adapter;
455 IDXGIDevice *device;
456 IDXGIOutput *output;
457 IUnknown *parent;
458 ULONG refcount;
459 HRESULT hr;
461 if (!(device = create_device()))
463 skip("Failed to create device, skipping tests.\n");
464 return;
467 surface_desc.Width = 512;
468 surface_desc.Height = 512;
469 surface_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
470 surface_desc.SampleDesc.Count = 1;
471 surface_desc.SampleDesc.Quality = 0;
473 hr = IDXGIDevice_CreateSurface(device, &surface_desc, 1, DXGI_USAGE_RENDER_TARGET_OUTPUT, NULL, &surface);
474 ok(SUCCEEDED(hr), "Failed to create a dxgi surface, hr %#x\n", hr);
476 hr = IDXGISurface_GetParent(surface, &IID_IDXGIDevice, (void **)&parent);
477 IDXGISurface_Release(surface);
478 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
479 ok(parent == (IUnknown *)device, "Got parent %p, expected %p.\n", parent, device);
480 IUnknown_Release(parent);
482 hr = IDXGIDevice_GetAdapter(device, &adapter);
483 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
485 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
486 if (hr == DXGI_ERROR_NOT_FOUND)
488 skip("Adapter has not outputs, skipping output tests.\n");
490 else
492 ok(SUCCEEDED(hr), "EnumOutputs failed, hr %#x.\n", hr);
494 hr = IDXGIOutput_GetParent(output, &IID_IDXGIAdapter, (void **)&parent);
495 IDXGIOutput_Release(output);
496 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
497 ok(parent == (IUnknown *)adapter, "Got parent %p, expected %p.\n", parent, adapter);
498 IUnknown_Release(parent);
501 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
502 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
504 hr = IDXGIFactory_GetParent(factory, &IID_IUnknown, (void **)&parent);
505 ok(hr == E_NOINTERFACE, "GetParent returned %#x, expected %#x.\n", hr, E_NOINTERFACE);
506 ok(parent == NULL, "Got parent %p, expected %p.\n", parent, NULL);
507 IDXGIFactory_Release(factory);
509 hr = IDXGIDevice_GetParent(device, &IID_IDXGIAdapter, (void **)&parent);
510 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
511 ok(parent == (IUnknown *)adapter, "Got parent %p, expected %p.\n", parent, adapter);
512 IUnknown_Release(parent);
514 IDXGIAdapter_Release(adapter);
515 refcount = IDXGIDevice_Release(device);
516 ok(!refcount, "Device has %u references left.\n", refcount);
519 static void test_output(void)
521 IDXGIAdapter *adapter;
522 IDXGIDevice *device;
523 HRESULT hr;
524 IDXGIOutput *output;
525 ULONG refcount;
526 UINT mode_count, mode_count_comp, i;
527 DXGI_MODE_DESC *modes;
529 if (!(device = create_device()))
531 skip("Failed to create device, skipping tests.\n");
532 return;
535 hr = IDXGIDevice_GetAdapter(device, &adapter);
536 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
538 hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
539 if (hr == DXGI_ERROR_NOT_FOUND)
541 skip("Adapter doesn't have any outputs, skipping tests.\n");
542 IDXGIAdapter_Release(adapter);
543 IDXGIDevice_Release(device);
544 return;
546 ok(SUCCEEDED(hr), "EnumOutputs failed, hr %#x.\n", hr);
548 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, NULL, NULL);
549 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
551 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
552 ok(SUCCEEDED(hr)
553 || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Remote Desktop Services / Win 7 testbot */
554 "Failed to list modes, hr %#x.\n", hr);
555 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
557 win_skip("GetDisplayModeList() not supported.\n");
558 IDXGIOutput_Release(output);
559 IDXGIAdapter_Release(adapter);
560 IDXGIDevice_Release(device);
561 return;
563 mode_count_comp = mode_count;
565 hr = IDXGIOutput_GetDisplayModeList(output, 0, 0, &mode_count, NULL);
566 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
567 ok(!mode_count, "Got unexpected mode_count %u.\n", mode_count);
569 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
570 DXGI_ENUM_MODES_SCALING, &mode_count, NULL);
571 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
572 ok(mode_count >= mode_count_comp, "Got unexpected mode_count %u, expected >= %u.\n", mode_count, mode_count_comp);
573 mode_count_comp = mode_count;
575 modes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*modes) * (mode_count + 10));
577 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
578 DXGI_ENUM_MODES_SCALING, NULL, modes);
579 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
580 ok(!modes[0].Height, "No output was expected.\n");
582 mode_count = 0;
583 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
584 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
585 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#x.\n", hr);
586 ok(!modes[0].Height, "No output was expected.\n");
588 mode_count = mode_count_comp;
589 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
590 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
591 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
592 ok(mode_count == mode_count_comp, "Got unexpected mode_count %u, expected %u.\n", mode_count, mode_count_comp);
594 for (i = 0; i < mode_count; i++)
596 ok(modes[i].Height && modes[i].Width, "Proper mode was expected\n");
599 mode_count += 5;
600 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
601 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
602 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
603 ok(mode_count == mode_count_comp, "Got unexpected mode_count %u, expected %u.\n", mode_count, mode_count_comp);
605 if (mode_count_comp)
607 mode_count = mode_count_comp - 1;
608 hr = IDXGIOutput_GetDisplayModeList(output, DXGI_FORMAT_R8G8B8A8_UNORM,
609 DXGI_ENUM_MODES_SCALING, &mode_count, modes);
610 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#x.\n", hr);
611 ok(mode_count == mode_count_comp - 1, "Got unexpected mode_count %u, expected %u.\n",
612 mode_count, mode_count_comp - 1);
614 else
616 skip("Not enough modes for test, skipping.\n");
619 HeapFree(GetProcessHeap(), 0, modes);
620 IDXGIOutput_Release(output);
621 IDXGIAdapter_Release(adapter);
622 refcount = IDXGIDevice_Release(device);
623 ok(!refcount, "Device has %u references left.\n", refcount);
626 struct refresh_rates
628 UINT numerator;
629 UINT denominator;
630 BOOL numerator_should_pass;
631 BOOL denominator_should_pass;
634 static void test_create_swapchain(void)
636 struct swapchain_fullscreen_state initial_state, expected_state;
637 unsigned int i, expected_width, expected_height;
638 DXGI_SWAP_CHAIN_DESC creation_desc, result_desc;
639 ULONG refcount, expected_refcount;
640 RECT *expected_client_rect;
641 IDXGISwapChain *swapchain;
642 IUnknown *obj, *parent;
643 IDXGIAdapter *adapter;
644 IDXGIFactory *factory;
645 IDXGIDevice *device;
646 IDXGIOutput *target;
647 BOOL fullscreen;
648 HRESULT hr;
650 const struct refresh_rates refresh_list[] =
652 {60, 60, FALSE, FALSE},
653 {60, 0, TRUE, FALSE},
654 {60, 1, TRUE, TRUE},
655 { 0, 60, TRUE, FALSE},
656 { 0, 0, TRUE, FALSE},
659 if (!(device = create_device()))
661 skip("Failed to create device, skipping tests.\n");
662 return;
665 creation_desc.OutputWindow = 0;
666 creation_desc.BufferDesc.Width = 800;
667 creation_desc.BufferDesc.Height = 600;
668 creation_desc.BufferDesc.RefreshRate.Numerator = 60;
669 creation_desc.BufferDesc.RefreshRate.Denominator = 60;
670 creation_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
671 creation_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
672 creation_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
673 creation_desc.SampleDesc.Count = 1;
674 creation_desc.SampleDesc.Quality = 0;
675 creation_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
676 creation_desc.BufferCount = 1;
677 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 0, 0, 0, 0, 0, 0);
678 creation_desc.Windowed = TRUE;
679 creation_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
680 creation_desc.Flags = 0;
682 memset(&initial_state, 0, sizeof(initial_state));
683 capture_fullscreen_state(&initial_state.fullscreen_state, creation_desc.OutputWindow);
685 hr = IDXGIDevice_QueryInterface(device, &IID_IUnknown, (void **)&obj);
686 ok(SUCCEEDED(hr), "IDXGIDevice does not implement IUnknown.\n");
688 hr = IDXGIDevice_GetAdapter(device, &adapter);
689 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
691 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
692 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
694 expected_refcount = get_refcount((IUnknown *)adapter);
695 refcount = get_refcount((IUnknown *)factory);
696 ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
697 refcount = get_refcount((IUnknown *)device);
698 ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
700 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
701 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
703 refcount = get_refcount((IUnknown *)adapter);
704 ok(refcount == expected_refcount, "Got refcount %u, expected %u.\n", refcount, expected_refcount);
705 refcount = get_refcount((IUnknown *)factory);
706 todo_wine ok(refcount == 4, "Got unexpected refcount %u.\n", refcount);
707 refcount = get_refcount((IUnknown *)device);
708 ok(refcount == 3, "Got unexpected refcount %u.\n", refcount);
710 hr = IDXGISwapChain_GetDesc(swapchain, NULL);
711 ok(hr == E_INVALIDARG, "GetDesc unexpectedly returned %#x.\n", hr);
713 hr = IDXGISwapChain_GetParent(swapchain, &IID_IUnknown, (void **)&parent);
714 ok(SUCCEEDED(hr), "GetParent failed %#x.\n", hr);
715 ok(parent == (IUnknown *)factory, "Got unexpected parent interface pointer %p.\n", parent);
716 refcount = IUnknown_Release(parent);
717 todo_wine ok(refcount == 4, "Got unexpected refcount %u.\n", refcount);
719 hr = IDXGISwapChain_GetParent(swapchain, &IID_IDXGIFactory, (void **)&parent);
720 ok(SUCCEEDED(hr), "GetParent failed %#x.\n", hr);
721 ok(parent == (IUnknown *)factory, "Got unexpected parent interface pointer %p.\n", parent);
722 refcount = IUnknown_Release(parent);
723 todo_wine ok(refcount == 4, "Got unexpected refcount %u.\n", refcount);
725 IDXGISwapChain_Release(swapchain);
727 refcount = get_refcount((IUnknown *)factory);
728 ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
730 for (i = 0; i < sizeof(refresh_list) / sizeof(*refresh_list); ++i)
732 creation_desc.BufferDesc.RefreshRate.Numerator = refresh_list[i].numerator;
733 creation_desc.BufferDesc.RefreshRate.Denominator = refresh_list[i].denominator;
735 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
736 ok(SUCCEEDED(hr), "Test %u: CreateSwapChain failed, hr %#x.\n", i, hr);
738 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
739 ok(SUCCEEDED(hr), "Test %u: GetDesc failed, hr %#x.\n", i, hr);
741 ok(result_desc.Windowed == creation_desc.Windowed, "Test %u: Got unexpected windowed %#x.\n",
742 i, result_desc.Windowed);
744 todo_wine_if (!refresh_list[i].numerator_should_pass)
745 ok(result_desc.BufferDesc.RefreshRate.Numerator == refresh_list[i].numerator,
746 "Numerator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Numerator);
748 todo_wine_if (!refresh_list[i].denominator_should_pass)
749 ok(result_desc.BufferDesc.RefreshRate.Denominator == refresh_list[i].denominator,
750 "Denominator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Denominator);
752 fullscreen = 0xdeadbeef;
753 target = (void *)0xdeadbeef;
754 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
755 ok(hr == S_OK, "Test %u: GetFullscreenState failed, hr %#x.\n", i, hr);
756 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
757 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
759 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, NULL);
760 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
761 fullscreen = 0xdeadbeef;
762 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
763 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
764 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
765 target = (void *)0xdeadbeef;
766 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
767 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
768 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
770 check_swapchain_fullscreen_state(swapchain, &initial_state);
771 IDXGISwapChain_Release(swapchain);
774 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
776 creation_desc.Windowed = FALSE;
778 for (i = 0; i < sizeof(refresh_list) / sizeof(*refresh_list); ++i)
780 creation_desc.BufferDesc.RefreshRate.Numerator = refresh_list[i].numerator;
781 creation_desc.BufferDesc.RefreshRate.Denominator = refresh_list[i].denominator;
783 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
784 ok(SUCCEEDED(hr), "Test %u: CreateSwapChain failed, hr %#x.\n", i, hr);
786 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
787 ok(SUCCEEDED(hr), "Test %u: GetDesc failed, hr %#x.\n", i, hr);
789 /* When numerator is non-zero and denominator is zero, the windowed mode is used.
790 * Additionally, some versions of WARP seem to always fail to change fullscreen state. */
791 if (result_desc.Windowed != creation_desc.Windowed)
792 trace("Test %u: Failed to change fullscreen state.\n", i);
794 todo_wine_if (!refresh_list[i].numerator_should_pass)
795 ok(result_desc.BufferDesc.RefreshRate.Numerator == refresh_list[i].numerator,
796 "Numerator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Numerator);
798 todo_wine_if (!refresh_list[i].denominator_should_pass)
799 ok(result_desc.BufferDesc.RefreshRate.Denominator == refresh_list[i].denominator,
800 "Denominator %u is %u.\n", i, result_desc.BufferDesc.RefreshRate.Denominator);
802 fullscreen = FALSE;
803 target = NULL;
804 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
805 ok(hr == S_OK, "Test %u: GetFullscreenState failed, hr %#x.\n", i, hr);
806 ok(fullscreen == !result_desc.Windowed, "Test %u: Got fullscreen %#x, expected %#x.\n",
807 i, fullscreen, result_desc.Windowed);
808 ok(result_desc.Windowed ? !target : !!target, "Test %u: Got unexpected target %p.\n", i, target);
809 if (!result_desc.Windowed)
811 IDXGIOutput *containing_output;
812 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
813 ok(SUCCEEDED(hr), "Test %u: GetContainingOutput failed, hr %#x.\n", i, hr);
814 ok(containing_output == target, "Test %u: Got unexpected containing output pointer %p.\n",
815 i, containing_output);
816 IDXGIOutput_Release(containing_output);
818 ok(output_belongs_to_adapter(target, adapter),
819 "Test %u: Output %p doesn't belong to adapter %p.\n",
820 i, target, adapter);
821 IDXGIOutput_Release(target);
823 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, NULL);
824 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
825 fullscreen = FALSE;
826 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
827 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
828 ok(fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
829 target = NULL;
830 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
831 ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
832 ok(!!target, "Test %u: Got unexpected target %p.\n", i, target);
833 IDXGIOutput_Release(target);
836 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
837 ok(SUCCEEDED(hr), "Test %u: SetFullscreenState failed, hr %#x.\n", i, hr);
839 fullscreen = 0xdeadbeef;
840 target = (void *)0xdeadbeef;
841 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &target);
842 ok(hr == S_OK, "Test %u: GetFullscreenState failed, hr %#x.\n", i, hr);
843 ok(!fullscreen, "Test %u: Got unexpected fullscreen %#x.\n", i, fullscreen);
844 ok(!target, "Test %u: Got unexpected target %p.\n", i, target);
846 check_swapchain_fullscreen_state(swapchain, &initial_state);
847 IDXGISwapChain_Release(swapchain);
850 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
852 /* Test swapchain creation with backbuffer width and height equal to 0. */
853 expected_state = initial_state;
854 expected_client_rect = &expected_state.fullscreen_state.client_rect;
856 /* Windowed */
857 expected_width = expected_client_rect->right;
858 expected_height = expected_client_rect->bottom;
860 creation_desc.BufferDesc.Width = 0;
861 creation_desc.BufferDesc.Height = 0;
862 creation_desc.Windowed = TRUE;
863 creation_desc.Flags = 0;
864 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
865 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
866 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
867 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
868 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
869 result_desc.BufferDesc.Width, expected_width);
870 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
871 result_desc.BufferDesc.Height, expected_height);
872 check_swapchain_fullscreen_state(swapchain, &expected_state);
873 IDXGISwapChain_Release(swapchain);
875 DestroyWindow(creation_desc.OutputWindow);
876 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
877 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
878 0, 0, 222, 222, 0, 0, 0, 0);
879 SetRect(&expected_state.fullscreen_state.window_rect, 0, 0, 222, 222);
880 GetClientRect(creation_desc.OutputWindow, expected_client_rect);
881 expected_width = expected_client_rect->right;
882 expected_height = expected_client_rect->bottom;
884 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
885 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
886 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
887 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
888 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
889 result_desc.BufferDesc.Width, expected_width);
890 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
891 result_desc.BufferDesc.Height, expected_height);
892 check_swapchain_fullscreen_state(swapchain, &expected_state);
893 IDXGISwapChain_Release(swapchain);
895 DestroyWindow(creation_desc.OutputWindow);
896 creation_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 0, 0, 0, 0, 0, 0);
897 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
899 /* Fullscreen */
900 creation_desc.Windowed = FALSE;
901 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
902 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
903 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
904 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
905 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
906 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
907 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
908 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
909 "GetContainingOutput failed, hr %#x.\n", hr);
910 check_swapchain_fullscreen_state(swapchain, &initial_state);
911 IDXGISwapChain_Release(swapchain);
912 if (hr == DXGI_ERROR_UNSUPPORTED)
914 win_skip("GetContainingOutput() not supported.\n");
915 goto done;
917 if (result_desc.Windowed)
919 win_skip("Fullscreen not supported.\n");
920 IDXGIOutput_Release(expected_state.target);
921 goto done;
924 creation_desc.BufferDesc.Width = 0;
925 creation_desc.BufferDesc.Height = 0;
926 creation_desc.Windowed = FALSE;
927 creation_desc.Flags = 0;
928 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
929 &creation_desc, &initial_state.fullscreen_state.monitor_rect, 0, 0, expected_state.target);
930 expected_width = expected_client_rect->right - expected_client_rect->left;
931 expected_height = expected_client_rect->bottom - expected_client_rect->top;
933 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
934 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
935 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
936 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
937 todo_wine ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
938 result_desc.BufferDesc.Width, expected_width);
939 todo_wine ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
940 result_desc.BufferDesc.Height, expected_height);
941 check_swapchain_fullscreen_state(swapchain, &expected_state);
942 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
943 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
944 check_swapchain_fullscreen_state(swapchain, &initial_state);
945 IDXGISwapChain_Release(swapchain);
947 /* Fullscreen and DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH */
948 creation_desc.BufferDesc.Width = 0;
949 creation_desc.BufferDesc.Height = 0;
950 creation_desc.Windowed = FALSE;
951 creation_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
952 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
953 &creation_desc, &initial_state.fullscreen_state.monitor_rect, 0, 0, expected_state.target);
954 expected_width = expected_client_rect->right - expected_client_rect->left;
955 expected_height = expected_client_rect->bottom - expected_client_rect->top;
957 hr = IDXGIFactory_CreateSwapChain(factory, obj, &creation_desc, &swapchain);
958 todo_wine ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
959 if (SUCCEEDED(hr))
961 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
962 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
963 ok(result_desc.BufferDesc.Width == expected_width, "Got width %u, expected %u.\n",
964 result_desc.BufferDesc.Width, expected_width);
965 ok(result_desc.BufferDesc.Height == expected_height, "Got height %u, expected %u.\n",
966 result_desc.BufferDesc.Height, expected_height);
967 check_swapchain_fullscreen_state(swapchain, &expected_state);
968 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
969 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
970 check_swapchain_fullscreen_state(swapchain, &initial_state);
971 IDXGISwapChain_Release(swapchain);
974 IDXGIOutput_Release(expected_state.target);
976 done:
977 IUnknown_Release(obj);
978 refcount = IDXGIDevice_Release(device);
979 ok(!refcount, "Device has %u references left.\n", refcount);
980 refcount = IDXGIAdapter_Release(adapter);
981 ok(!refcount, "Adapter has %u references left.\n", refcount);
982 refcount = IDXGIFactory_Release(factory);
983 ok(!refcount, "Factory has %u references left.\n", refcount);
984 check_window_fullscreen_state(creation_desc.OutputWindow, &initial_state.fullscreen_state);
985 DestroyWindow(creation_desc.OutputWindow);
988 static void test_get_containing_output(void)
990 unsigned int output_count, output_idx;
991 DXGI_SWAP_CHAIN_DESC swapchain_desc;
992 IDXGIOutput *output, *output2;
993 DXGI_OUTPUT_DESC output_desc;
994 MONITORINFOEXW monitor_info;
995 IDXGISwapChain *swapchain;
996 IDXGIFactory *factory;
997 IDXGIAdapter *adapter;
998 POINT points[4 * 16];
999 IDXGIDevice *device;
1000 unsigned int i, j;
1001 HMONITOR monitor;
1002 ULONG refcount;
1003 HRESULT hr;
1004 BOOL ret;
1006 if (!(device = create_device()))
1008 skip("Failed to create device.\n");
1009 return;
1012 hr = IDXGIDevice_GetAdapter(device, &adapter);
1013 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
1015 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1016 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
1018 swapchain_desc.BufferDesc.Width = 100;
1019 swapchain_desc.BufferDesc.Height = 100;
1020 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
1021 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
1022 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1023 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1024 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
1025 swapchain_desc.SampleDesc.Count = 1;
1026 swapchain_desc.SampleDesc.Quality = 0;
1027 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1028 swapchain_desc.BufferCount = 1;
1029 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
1030 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 100, 100, 0, 0, 0, 0);
1031 swapchain_desc.Windowed = TRUE;
1032 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
1033 swapchain_desc.Flags = 0;
1035 output_count = 0;
1036 while (IDXGIAdapter_EnumOutputs(adapter, output_count, &output) != DXGI_ERROR_NOT_FOUND)
1038 ok(SUCCEEDED(hr), "Failed to enumarate output %u, hr %#x.\n", output_count, hr);
1039 IDXGIOutput_Release(output);
1040 ++output_count;
1043 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
1044 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
1046 monitor = MonitorFromWindow(swapchain_desc.OutputWindow, 0);
1047 ok(!!monitor, "MonitorFromWindow failed.\n");
1049 monitor_info.cbSize = sizeof(monitor_info);
1050 ret = GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info);
1051 ok(ret, "Failed to get monitor info.\n");
1053 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
1054 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
1055 "GetContainingOutput failed, hr %#x.\n", hr);
1056 if (hr == DXGI_ERROR_UNSUPPORTED)
1058 win_skip("GetContainingOutput() not supported.\n");
1059 IDXGISwapChain_Release(swapchain);
1060 goto done;
1063 hr = IDXGIOutput_GetDesc(output, &output_desc);
1064 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1066 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
1067 ok(SUCCEEDED(hr), "GetContainingOutput failed, hr %#x.\n", hr);
1068 ok(output != output2, "Got unexpected output pointers %p, %p.\n", output, output2);
1069 check_output_equal(output, output2);
1071 refcount = IDXGIOutput_Release(output);
1072 ok(!refcount, "IDXGIOutput has %u references left.\n", refcount);
1073 refcount = IDXGIOutput_Release(output2);
1074 ok(!refcount, "IDXGIOutput has %u references left.\n", refcount);
1076 ok(!lstrcmpW(output_desc.DeviceName, monitor_info.szDevice),
1077 "Got unexpected device name %s, expected %s.\n",
1078 wine_dbgstr_w(output_desc.DeviceName), wine_dbgstr_w(monitor_info.szDevice));
1079 ok(EqualRect(&output_desc.DesktopCoordinates, &monitor_info.rcMonitor),
1080 "Got unexpected desktop coordinates %s, expected %s.\n",
1081 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
1082 wine_dbgstr_rect(&monitor_info.rcMonitor));
1084 output_idx = 0;
1085 while ((hr = IDXGIAdapter_EnumOutputs(adapter, output_idx, &output)) != DXGI_ERROR_NOT_FOUND)
1087 ok(SUCCEEDED(hr), "Failed to enumarate output %u, hr %#x.\n", output_idx, hr);
1089 hr = IDXGIOutput_GetDesc(output, &output_desc);
1090 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1092 /* Move the OutputWindow to the current output. */
1093 ret = SetWindowPos(swapchain_desc.OutputWindow, 0,
1094 output_desc.DesktopCoordinates.left, output_desc.DesktopCoordinates.top,
1095 0, 0, SWP_NOSIZE | SWP_NOZORDER);
1096 ok(ret, "SetWindowPos failed.\n");
1098 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
1099 ok(SUCCEEDED(hr), "GetContainingOutput failed, hr %#x.\n", hr);
1101 check_output_equal(output, output2);
1103 refcount = IDXGIOutput_Release(output2);
1104 ok(!refcount, "IDXGIOutput has %u references left.\n", refcount);
1105 refcount = IDXGIOutput_Release(output);
1106 ok(!refcount, "IDXGIOutput has %u references left.\n", refcount);
1107 ++output_idx;
1109 /* Move the OutputWindow around the corners of the current output desktop coordinates. */
1110 for (i = 0; i < 4; ++i)
1112 static const POINT offsets[] =
1114 { 0, 0},
1115 {-49, 0}, {-50, 0}, {-51, 0},
1116 { 0, -49}, { 0, -50}, { 0, -51},
1117 {-49, -49}, {-50, -49}, {-51, -49},
1118 {-49, -50}, {-50, -50}, {-51, -50},
1119 {-49, -51}, {-50, -51}, {-51, -51},
1121 unsigned int x, y;
1123 switch (i)
1125 case 0:
1126 x = output_desc.DesktopCoordinates.left;
1127 y = output_desc.DesktopCoordinates.top;
1128 break;
1129 case 1:
1130 x = output_desc.DesktopCoordinates.right;
1131 y = output_desc.DesktopCoordinates.top;
1132 break;
1133 case 2:
1134 x = output_desc.DesktopCoordinates.right;
1135 y = output_desc.DesktopCoordinates.bottom;
1136 break;
1137 case 3:
1138 x = output_desc.DesktopCoordinates.left;
1139 y = output_desc.DesktopCoordinates.bottom;
1140 break;
1143 for (j = 0; j < sizeof(offsets) / sizeof(*offsets); ++j)
1145 unsigned int idx = (sizeof(offsets) / sizeof(*offsets)) * i + j;
1146 assert(idx < sizeof(points) / sizeof(*points));
1147 points[idx].x = x + offsets[j].x;
1148 points[idx].y = y + offsets[j].y;
1152 for (i = 0; i < sizeof(points) / sizeof(*points); ++i)
1154 ret = SetWindowPos(swapchain_desc.OutputWindow, 0, points[i].x, points[i].y,
1155 0, 0, SWP_NOSIZE | SWP_NOZORDER);
1156 ok(ret, "SetWindowPos failed.\n");
1158 monitor = MonitorFromWindow(swapchain_desc.OutputWindow, MONITOR_DEFAULTTONEAREST);
1159 ok(!!monitor, "MonitorFromWindow failed.\n");
1161 monitor_info.cbSize = sizeof(monitor_info);
1162 ret = GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info);
1163 ok(ret, "Failed to get monitor info.\n");
1165 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
1166 ok(SUCCEEDED(hr), "GetContainingOutput failed, hr %#x.\n", hr);
1167 ok(!!output, "Got unexpected containing output %p.\n", output);
1168 hr = IDXGIOutput_GetDesc(output, &output_desc);
1169 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1170 refcount = IDXGIOutput_Release(output);
1171 ok(!refcount, "IDXGIOutput has %u references left.\n", refcount);
1173 ok(!lstrcmpW(output_desc.DeviceName, monitor_info.szDevice),
1174 "Got unexpected device name %s, expected %s.\n",
1175 wine_dbgstr_w(output_desc.DeviceName), wine_dbgstr_w(monitor_info.szDevice));
1176 ok(EqualRect(&output_desc.DesktopCoordinates, &monitor_info.rcMonitor),
1177 "Got unexpected desktop coordinates %s, expected %s.\n",
1178 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
1179 wine_dbgstr_rect(&monitor_info.rcMonitor));
1183 refcount = IDXGISwapChain_Release(swapchain);
1184 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
1186 done:
1187 refcount = IDXGIDevice_Release(device);
1188 ok(!refcount, "Device has %u references left.\n", refcount);
1189 refcount = IDXGIAdapter_Release(adapter);
1190 ok(!refcount, "Adapter has %u references left.\n", refcount);
1191 refcount = IDXGIFactory_Release(factory);
1192 ok(!refcount, "Factory has %u references left.\n", refcount);
1193 DestroyWindow(swapchain_desc.OutputWindow);
1196 static void test_swapchain_fullscreen_state(IDXGISwapChain *swapchain,
1197 IDXGIAdapter *adapter, const struct swapchain_fullscreen_state *initial_state)
1199 MONITORINFOEXW monitor_info, *output_monitor_info;
1200 struct swapchain_fullscreen_state expected_state;
1201 DXGI_SWAP_CHAIN_DESC swapchain_desc;
1202 DXGI_OUTPUT_DESC output_desc;
1203 unsigned int i, output_count;
1204 IDXGIOutput *output;
1205 HRESULT hr;
1206 BOOL ret;
1208 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
1209 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1211 check_swapchain_fullscreen_state(swapchain, initial_state);
1213 expected_state = *initial_state;
1214 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
1215 &swapchain_desc, &initial_state->fullscreen_state.monitor_rect, 800, 600, NULL);
1216 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
1217 ok(SUCCEEDED(hr), "GetContainingOutput failed, hr %#x.\n", hr);
1219 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
1220 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
1221 check_swapchain_fullscreen_state(swapchain, &expected_state);
1223 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
1224 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1225 check_swapchain_fullscreen_state(swapchain, &expected_state);
1227 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1228 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
1229 check_swapchain_fullscreen_state(swapchain, initial_state);
1231 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1232 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1233 check_swapchain_fullscreen_state(swapchain, initial_state);
1235 IDXGIOutput_Release(expected_state.target);
1236 expected_state.target = NULL;
1238 output_count = 0;
1239 while (IDXGIAdapter_EnumOutputs(adapter, output_count, &output) != DXGI_ERROR_NOT_FOUND)
1241 IDXGIOutput_Release(output);
1242 ++output_count;
1245 output_monitor_info = HeapAlloc(GetProcessHeap(), 0, output_count * sizeof(*output_monitor_info));
1246 ok(!!output_monitor_info, "Failed to allocate memory.\n");
1247 for (i = 0; i < output_count; ++i)
1249 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
1250 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1252 hr = IDXGIOutput_GetDesc(output, &output_desc);
1253 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1255 output_monitor_info[i].cbSize = sizeof(*output_monitor_info);
1256 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&output_monitor_info[i]);
1257 ok(ret, "Failed to get monitor info.\n");
1259 IDXGIOutput_Release(output);
1262 for (i = 0; i < output_count; ++i)
1264 RECT orig_monitor_rect = output_monitor_info[i].rcMonitor;
1265 IDXGIOutput *target;
1266 BOOL fullscreen;
1268 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
1269 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1270 hr = IDXGIOutput_GetDesc(output, &output_desc);
1271 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1273 expected_state = *initial_state;
1274 expected_state.target = output;
1275 expected_state.fullscreen_state.monitor = output_desc.Monitor;
1276 expected_state.fullscreen_state.monitor_rect = orig_monitor_rect;
1277 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
1278 &swapchain_desc, &orig_monitor_rect, 800, 600, NULL);
1280 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
1281 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1282 check_swapchain_fullscreen_state(swapchain, &expected_state);
1284 target = NULL;
1285 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
1286 ok(SUCCEEDED(hr), "GetFullscreenState failed, hr %#x.\n", hr);
1287 ok(target == output, "Got target pointer %p, expected %p.\n", target, output);
1288 IDXGIOutput_Release(target);
1289 fullscreen = FALSE;
1290 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
1291 ok(SUCCEEDED(hr), "GetFullscreenState failed, hr %#x.\n", hr);
1292 ok(fullscreen, "Got unexpected fullscreen %#x.\n", hr);
1294 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
1295 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1296 check_swapchain_fullscreen_state(swapchain, &expected_state);
1297 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, output);
1298 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1299 check_swapchain_fullscreen_state(swapchain, &expected_state);
1300 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1301 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1302 check_swapchain_fullscreen_state(swapchain, initial_state);
1304 fullscreen = TRUE;
1305 hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
1306 ok(SUCCEEDED(hr), "GetFullscreenState failed, hr %#x.\n", hr);
1307 ok(!fullscreen, "Got unexpected fullscreen %#x.\n", hr);
1309 check_swapchain_fullscreen_state(swapchain, initial_state);
1310 monitor_info.cbSize = sizeof(monitor_info);
1311 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&monitor_info);
1312 ok(ret, "Failed to get monitor info.\n");
1313 ok(EqualRect(&monitor_info.rcMonitor, &orig_monitor_rect), "Got monitor rect %s, expected %s.\n",
1314 wine_dbgstr_rect(&monitor_info.rcMonitor), wine_dbgstr_rect(&orig_monitor_rect));
1316 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
1317 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1319 IDXGIOutput_Release(output);
1322 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1323 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1324 check_swapchain_fullscreen_state(swapchain, initial_state);
1326 for (i = 0; i < output_count; ++i)
1328 hr = IDXGIAdapter_EnumOutputs(adapter, i, &output);
1329 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1331 hr = IDXGIOutput_GetDesc(output, &output_desc);
1332 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1334 monitor_info.cbSize = sizeof(monitor_info);
1335 ret = GetMonitorInfoW(output_desc.Monitor, (MONITORINFO *)&monitor_info);
1336 ok(ret, "Failed to get monitor info.\n");
1338 ok(EqualRect(&monitor_info.rcMonitor, &output_monitor_info[i].rcMonitor),
1339 "Got monitor rect %s, expected %s.\n",
1340 wine_dbgstr_rect(&monitor_info.rcMonitor),
1341 wine_dbgstr_rect(&output_monitor_info[i].rcMonitor));
1343 IDXGIOutput_Release(output);
1346 HeapFree(GetProcessHeap(), 0, output_monitor_info);
1349 static void test_set_fullscreen(void)
1351 struct swapchain_fullscreen_state initial_state;
1352 DXGI_SWAP_CHAIN_DESC swapchain_desc;
1353 IDXGISwapChain *swapchain;
1354 IDXGIFactory *factory;
1355 IDXGIAdapter *adapter;
1356 IDXGIDevice *device;
1357 ULONG refcount;
1358 HRESULT hr;
1360 if (!(device = create_device()))
1362 skip("Failed to create device.\n");
1363 return;
1366 hr = IDXGIDevice_GetAdapter(device, &adapter);
1367 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
1369 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1370 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
1372 swapchain_desc.BufferDesc.Width = 800;
1373 swapchain_desc.BufferDesc.Height = 600;
1374 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
1375 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
1376 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1377 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1378 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
1379 swapchain_desc.SampleDesc.Count = 1;
1380 swapchain_desc.SampleDesc.Quality = 0;
1381 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1382 swapchain_desc.BufferCount = 1;
1383 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
1384 swapchain_desc.Windowed = TRUE;
1385 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
1386 swapchain_desc.Flags = 0;
1388 memset(&initial_state, 0, sizeof(initial_state));
1389 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
1390 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
1391 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
1392 check_swapchain_fullscreen_state(swapchain, &initial_state);
1393 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
1394 ok(SUCCEEDED(hr) || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "SetFullscreenState failed, hr %#x.\n", hr);
1395 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
1397 skip("Could not change fullscreen state.\n");
1398 goto done;
1400 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1401 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1402 refcount = IDXGISwapChain_Release(swapchain);
1403 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
1405 DestroyWindow(swapchain_desc.OutputWindow);
1406 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
1407 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
1408 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
1409 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
1410 check_swapchain_fullscreen_state(swapchain, &initial_state);
1411 test_swapchain_fullscreen_state(swapchain, adapter, &initial_state);
1412 refcount = IDXGISwapChain_Release(swapchain);
1413 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
1415 DestroyWindow(swapchain_desc.OutputWindow);
1416 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
1417 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
1418 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
1419 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
1420 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
1421 check_swapchain_fullscreen_state(swapchain, &initial_state);
1422 test_swapchain_fullscreen_state(swapchain, adapter, &initial_state);
1424 done:
1425 refcount = IDXGISwapChain_Release(swapchain);
1426 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
1427 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
1428 DestroyWindow(swapchain_desc.OutputWindow);
1430 IDXGIAdapter_Release(adapter);
1431 refcount = IDXGIDevice_Release(device);
1432 ok(!refcount, "Device has %u references left.\n", refcount);
1433 refcount = IDXGIFactory_Release(factory);
1434 ok(!refcount, "Factory has %u references left.\n", refcount);
1437 static void test_default_fullscreen_target_output(void)
1439 IDXGIOutput *output, *containing_output, *target;
1440 DXGI_SWAP_CHAIN_DESC swapchain_desc;
1441 DXGI_OUTPUT_DESC output_desc;
1442 IDXGISwapChain *swapchain;
1443 unsigned int output_idx;
1444 IDXGIFactory *factory;
1445 IDXGIAdapter *adapter;
1446 IDXGIDevice *device;
1447 ULONG refcount;
1448 HRESULT hr;
1449 BOOL ret;
1451 if (!(device = create_device()))
1453 skip("Failed to create device.\n");
1454 return;
1457 hr = IDXGIDevice_GetAdapter(device, &adapter);
1458 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
1460 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1461 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
1463 swapchain_desc.BufferDesc.Width = 100;
1464 swapchain_desc.BufferDesc.Height = 100;
1465 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
1466 swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
1467 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1468 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1469 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
1470 swapchain_desc.SampleDesc.Count = 1;
1471 swapchain_desc.SampleDesc.Quality = 0;
1472 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1473 swapchain_desc.BufferCount = 1;
1474 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test",
1475 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 100, 100, 0, 0, 0, 0);
1476 swapchain_desc.Windowed = TRUE;
1477 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
1478 swapchain_desc.Flags = 0;
1480 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
1481 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
1483 output_idx = 0;
1484 while ((hr = IDXGIAdapter_EnumOutputs(adapter, output_idx, &output)) != DXGI_ERROR_NOT_FOUND)
1486 ok(SUCCEEDED(hr), "Failed to enumarate output %u, hr %#x.\n", output_idx, hr);
1488 hr = IDXGIOutput_GetDesc(output, &output_desc);
1489 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1491 /* Move the OutputWindow to the current output. */
1492 ret = SetWindowPos(swapchain_desc.OutputWindow, 0,
1493 output_desc.DesktopCoordinates.left, output_desc.DesktopCoordinates.top,
1494 0, 0, SWP_NOSIZE | SWP_NOZORDER);
1495 ok(ret, "SetWindowPos failed.\n");
1497 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
1498 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
1499 "GetContainingOutput failed, hr %#x.\n", hr);
1500 if (hr == DXGI_ERROR_UNSUPPORTED)
1502 win_skip("GetContainingOutput() not supported.\n");
1503 IDXGIOutput_Release(output);
1504 goto done;
1507 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
1508 ok(SUCCEEDED(hr) || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE,
1509 "SetFullscreenState failed, hr %#x.\n", hr);
1510 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
1512 skip("Could not change fullscreen state.\n");
1513 IDXGIOutput_Release(containing_output);
1514 IDXGIOutput_Release(output);
1515 goto done;
1518 target = NULL;
1519 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
1520 ok(SUCCEEDED(hr), "GetFullscreenState failed, hr %#x.\n", hr);
1521 ok(target != containing_output, "Got unexpected output pointers %p, %p.\n",
1522 target, containing_output);
1523 check_output_equal(target, containing_output);
1525 refcount = IDXGIOutput_Release(containing_output);
1526 ok(!refcount, "IDXGIOutput has %u references left.\n", refcount);
1528 hr = IDXGISwapChain_GetContainingOutput(swapchain, &containing_output);
1529 ok(SUCCEEDED(hr), "GetContainingOutput failed, hr %#x.\n", hr);
1530 ok(containing_output == target, "Got unexpected containing output %p, expected %p.\n",
1531 containing_output, target);
1532 refcount = IDXGIOutput_Release(containing_output);
1533 ok(refcount >= 2, "Got unexpected refcount %u.\n", refcount);
1534 refcount = IDXGIOutput_Release(target);
1535 ok(refcount >= 1, "Got unexpected refcount %u.\n", refcount);
1537 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1538 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
1540 IDXGIOutput_Release(output);
1541 ++output_idx;
1544 done:
1545 refcount = IDXGISwapChain_Release(swapchain);
1546 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
1548 refcount = IDXGIDevice_Release(device);
1549 ok(!refcount, "Device has %u references left.\n", refcount);
1550 refcount = IDXGIAdapter_Release(adapter);
1551 ok(!refcount, "Adapter has %u references left.\n", refcount);
1552 refcount = IDXGIFactory_Release(factory);
1553 ok(!refcount, "Factory has %u references left.\n", refcount);
1554 DestroyWindow(swapchain_desc.OutputWindow);
1557 static void test_windowed_resize_target(IDXGISwapChain *swapchain, HWND window,
1558 struct swapchain_fullscreen_state *state)
1560 struct swapchain_fullscreen_state expected_state;
1561 struct fullscreen_state *e;
1562 DXGI_MODE_DESC mode;
1563 RECT window_rect;
1564 unsigned int i;
1565 HRESULT hr;
1566 BOOL ret;
1568 static const struct
1570 unsigned int width, height;
1572 sizes[] =
1574 {200, 200},
1575 {400, 200},
1576 {400, 400},
1577 {600, 800},
1578 {1000, 600},
1579 {1600, 100},
1580 {2000, 1000},
1583 check_swapchain_fullscreen_state(swapchain, state);
1584 expected_state = *state;
1585 e = &expected_state.fullscreen_state;
1587 for (i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i)
1589 SetRect(&e->client_rect, 0, 0, sizes[i].width, sizes[i].height);
1590 e->window_rect = e->client_rect;
1591 ret = AdjustWindowRectEx(&e->window_rect, GetWindowLongW(window, GWL_STYLE),
1592 FALSE, GetWindowLongW(window, GWL_EXSTYLE));
1593 ok(ret, "AdjustWindowRectEx failed.\n");
1594 if (GetMenu(window))
1595 e->client_rect.bottom -= GetSystemMetrics(SM_CYMENU);
1596 SetRect(&e->window_rect, 0, 0,
1597 e->window_rect.right - e->window_rect.left,
1598 e->window_rect.bottom - e->window_rect.top);
1599 GetWindowRect(window, &window_rect);
1600 OffsetRect(&e->window_rect, window_rect.left, window_rect.top);
1601 if (e->window_rect.right >= e->monitor_rect.right
1602 || e->window_rect.bottom >= e->monitor_rect.bottom)
1604 skip("Test %u: Window %s does not fit on screen %s.\n",
1605 i, wine_dbgstr_rect(&e->window_rect), wine_dbgstr_rect(&e->monitor_rect));
1606 continue;
1609 memset(&mode, 0, sizeof(mode));
1610 mode.Width = sizes[i].width;
1611 mode.Height = sizes[i].height;
1612 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
1613 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1614 check_swapchain_fullscreen_state(swapchain, &expected_state);
1617 ret = MoveWindow(window, 0, 0, 0, 0, TRUE);
1618 ok(ret, "MoveWindow failed.\n");
1619 GetWindowRect(window, &e->window_rect);
1620 GetClientRect(window, &e->client_rect);
1621 ret = MoveWindow(window, 0, 0, 200, 200, TRUE);
1623 memset(&mode, 0, sizeof(mode));
1624 hr = IDXGISwapChain_ResizeTarget(swapchain, &mode);
1625 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1626 check_swapchain_fullscreen_state(swapchain, &expected_state);
1628 GetWindowRect(window, &e->window_rect);
1629 GetClientRect(window, &e->client_rect);
1630 *state = expected_state;
1633 static void test_fullscreen_resize_target(IDXGISwapChain *swapchain,
1634 const struct swapchain_fullscreen_state *initial_state)
1636 struct swapchain_fullscreen_state expected_state;
1637 DXGI_SWAP_CHAIN_DESC swapchain_desc;
1638 DXGI_OUTPUT_DESC output_desc;
1639 unsigned int i, mode_count;
1640 DXGI_MODE_DESC *modes;
1641 IDXGIOutput *target;
1642 HRESULT hr;
1644 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
1645 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1647 hr = IDXGISwapChain_GetFullscreenState(swapchain, NULL, &target);
1648 ok(SUCCEEDED(hr), "GetFullscreenState failed, hr %#x.\n", hr);
1650 hr = IDXGIOutput_GetDisplayModeList(target, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, NULL);
1651 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), /* Win 7 testbot */
1652 "Failed to list modes, hr %#x.\n", hr);
1653 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
1655 win_skip("GetDisplayModeList() not supported.\n");
1656 IDXGIOutput_Release(target);
1657 return;
1660 modes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*modes) * mode_count);
1661 ok(!!modes, "Failed to allocate memory.\n");
1663 hr = IDXGIOutput_GetDisplayModeList(target, DXGI_FORMAT_R8G8B8A8_UNORM, 0, &mode_count, modes);
1664 ok(SUCCEEDED(hr), "Failed to list modes, hr %#x.\n", hr);
1666 expected_state = *initial_state;
1667 for (i = 0; i < min(mode_count, 20); ++i)
1669 /* FIXME: Modes with scaling aren't fully tested. */
1670 if (!(swapchain_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)
1671 && modes[i].Scaling != DXGI_MODE_SCALING_UNSPECIFIED)
1672 continue;
1674 hr = IDXGIOutput_GetDesc(target, &output_desc);
1675 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1677 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
1678 &swapchain_desc, &output_desc.DesktopCoordinates, modes[i].Width, modes[i].Height, NULL);
1680 hr = IDXGISwapChain_ResizeTarget(swapchain, &modes[i]);
1681 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
1682 check_swapchain_fullscreen_state(swapchain, &expected_state);
1684 hr = IDXGIOutput_GetDesc(target, &output_desc);
1685 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1686 ok(EqualRect(&output_desc.DesktopCoordinates, &expected_state.fullscreen_state.monitor_rect),
1687 "Got desktop coordinates %s, expected %s.\n",
1688 wine_dbgstr_rect(&output_desc.DesktopCoordinates),
1689 wine_dbgstr_rect(&expected_state.fullscreen_state.monitor_rect));
1692 HeapFree(GetProcessHeap(), 0, modes);
1693 IDXGIOutput_Release(target);
1696 static void test_resize_target(void)
1698 struct swapchain_fullscreen_state initial_state, expected_state;
1699 DXGI_SWAP_CHAIN_DESC swapchain_desc;
1700 IDXGISwapChain *swapchain;
1701 IDXGIFactory *factory;
1702 IDXGIAdapter *adapter;
1703 IDXGIDevice *device;
1704 unsigned int i;
1705 ULONG refcount;
1706 HRESULT hr;
1708 static const struct
1710 POINT origin;
1711 BOOL fullscreen;
1712 BOOL menu;
1713 unsigned int flags;
1715 tests[] =
1717 {{ 0, 0}, TRUE, FALSE, 0},
1718 {{10, 10}, TRUE, FALSE, 0},
1719 {{ 0, 0}, TRUE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
1720 {{10, 10}, TRUE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
1721 {{ 0, 0}, FALSE, FALSE, 0},
1722 {{ 0, 0}, FALSE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
1723 {{10, 10}, FALSE, FALSE, 0},
1724 {{10, 10}, FALSE, FALSE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
1725 {{ 0, 0}, FALSE, TRUE, 0},
1726 {{ 0, 0}, FALSE, TRUE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
1727 {{10, 10}, FALSE, TRUE, 0},
1728 {{10, 10}, FALSE, TRUE, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH},
1731 if (!(device = create_device()))
1733 skip("Failed to create device.\n");
1734 return;
1737 hr = IDXGIDevice_GetAdapter(device, &adapter);
1738 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
1740 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1741 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
1743 swapchain_desc.BufferDesc.Width = 800;
1744 swapchain_desc.BufferDesc.Height = 600;
1745 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
1746 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
1747 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1748 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1749 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
1750 swapchain_desc.SampleDesc.Count = 1;
1751 swapchain_desc.SampleDesc.Quality = 0;
1752 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1753 swapchain_desc.BufferCount = 1;
1754 swapchain_desc.Windowed = TRUE;
1755 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
1756 swapchain_desc.Flags = 0;
1758 for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
1760 swapchain_desc.Flags = tests[i].flags;
1761 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0,
1762 tests[i].origin.x, tests[i].origin.y, 400, 200, 0, 0, 0, 0);
1763 if (tests[i].menu)
1765 HMENU menu_bar = CreateMenu();
1766 HMENU menu = CreateMenu();
1767 AppendMenuA(menu_bar, MF_POPUP, (UINT_PTR)menu, "Menu");
1768 SetMenu(swapchain_desc.OutputWindow, menu_bar);
1771 memset(&initial_state, 0, sizeof(initial_state));
1772 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
1774 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
1775 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
1776 check_swapchain_fullscreen_state(swapchain, &initial_state);
1778 expected_state = initial_state;
1779 if (tests[i].fullscreen)
1781 expected_state.fullscreen = TRUE;
1782 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
1783 &swapchain_desc, &initial_state.fullscreen_state.monitor_rect, 800, 600, NULL);
1784 hr = IDXGISwapChain_GetContainingOutput(swapchain, &expected_state.target);
1785 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
1786 "GetContainingOutput failed, hr %#x.\n", hr);
1787 if (hr == DXGI_ERROR_UNSUPPORTED)
1789 win_skip("GetContainingOutput() not supported.\n");
1790 IDXGISwapChain_Release(swapchain);
1791 DestroyWindow(swapchain_desc.OutputWindow);
1792 continue;
1795 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
1796 ok(SUCCEEDED(hr) || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE,
1797 "SetFullscreenState failed, hr %#x.\n", hr);
1798 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
1800 skip("Could not change fullscreen state.\n");
1801 IDXGIOutput_Release(expected_state.target);
1802 IDXGISwapChain_Release(swapchain);
1803 DestroyWindow(swapchain_desc.OutputWindow);
1804 continue;
1807 check_swapchain_fullscreen_state(swapchain, &expected_state);
1809 hr = IDXGISwapChain_ResizeTarget(swapchain, NULL);
1810 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
1811 check_swapchain_fullscreen_state(swapchain, &expected_state);
1813 if (tests[i].fullscreen)
1815 test_fullscreen_resize_target(swapchain, &expected_state);
1817 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1818 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
1819 check_swapchain_fullscreen_state(swapchain, &initial_state);
1820 IDXGIOutput_Release(expected_state.target);
1821 check_swapchain_fullscreen_state(swapchain, &initial_state);
1822 expected_state = initial_state;
1824 else
1826 test_windowed_resize_target(swapchain, swapchain_desc.OutputWindow, &expected_state);
1828 check_swapchain_fullscreen_state(swapchain, &expected_state);
1831 refcount = IDXGISwapChain_Release(swapchain);
1832 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
1833 check_window_fullscreen_state(swapchain_desc.OutputWindow, &expected_state.fullscreen_state);
1834 DestroyWindow(swapchain_desc.OutputWindow);
1837 IDXGIAdapter_Release(adapter);
1838 refcount = IDXGIDevice_Release(device);
1839 ok(!refcount, "Device has %u references left.\n", refcount);
1840 refcount = IDXGIFactory_Release(factory);
1841 ok(!refcount, "Factory has %u references left.\n", refcount);
1844 static void test_inexact_modes(void)
1846 struct swapchain_fullscreen_state initial_state, expected_state;
1847 DXGI_SWAP_CHAIN_DESC swapchain_desc, result_desc;
1848 IDXGIOutput *output = NULL;
1849 IDXGISwapChain *swapchain;
1850 IDXGIFactory *factory;
1851 IDXGIAdapter *adapter;
1852 IDXGIDevice *device;
1853 unsigned int i;
1854 ULONG refcount;
1855 HRESULT hr;
1857 static const struct
1859 unsigned int width, height;
1861 sizes[] =
1863 {101, 101},
1864 {203, 204},
1865 {799, 601},
1868 if (!(device = create_device()))
1870 skip("Failed to create device.\n");
1871 return;
1874 hr = IDXGIDevice_GetAdapter(device, &adapter);
1875 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
1877 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
1878 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
1880 swapchain_desc.BufferDesc.Width = 800;
1881 swapchain_desc.BufferDesc.Height = 600;
1882 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
1883 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
1884 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1885 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1886 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
1887 swapchain_desc.SampleDesc.Count = 1;
1888 swapchain_desc.SampleDesc.Quality = 0;
1889 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1890 swapchain_desc.BufferCount = 1;
1891 swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
1892 swapchain_desc.Windowed = FALSE;
1893 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
1894 swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
1896 memset(&initial_state, 0, sizeof(initial_state));
1897 capture_fullscreen_state(&initial_state.fullscreen_state, swapchain_desc.OutputWindow);
1899 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
1900 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
1901 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
1902 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1903 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1904 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
1905 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output);
1906 ok(SUCCEEDED(hr) || broken(hr == DXGI_ERROR_UNSUPPORTED) /* Win 7 testbot */,
1907 "GetContainingOutput failed, hr %#x.\n", hr);
1908 refcount = IDXGISwapChain_Release(swapchain);
1909 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
1910 if (hr == DXGI_ERROR_UNSUPPORTED)
1912 win_skip("GetContainingOutput() not supported.\n");
1913 goto done;
1915 if (result_desc.Windowed)
1917 win_skip("Fullscreen not supported.\n");
1918 goto done;
1921 check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
1923 for (i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i)
1925 /* Test CreateSwapChain(). */
1926 swapchain_desc.BufferDesc.Width = sizes[i].width;
1927 swapchain_desc.BufferDesc.Height = sizes[i].height;
1928 swapchain_desc.Windowed = FALSE;
1930 expected_state = initial_state;
1931 compute_expected_swapchain_fullscreen_state_after_fullscreen_change(&expected_state,
1932 &swapchain_desc, &initial_state.fullscreen_state.monitor_rect,
1933 sizes[i].width, sizes[i].height, output);
1935 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
1936 todo_wine ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
1938 if (SUCCEEDED(hr))
1940 check_swapchain_fullscreen_state(swapchain, &expected_state);
1941 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
1942 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1943 ok(result_desc.BufferDesc.Width == sizes[i].width, "Got width %u, expected %u.\n",
1944 result_desc.BufferDesc.Width, sizes[i].width);
1945 ok(result_desc.BufferDesc.Height == sizes[i].height, "Got height %u, expected %u.\n",
1946 result_desc.BufferDesc.Height, sizes[i].height);
1948 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1949 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
1950 check_swapchain_fullscreen_state(swapchain, &initial_state);
1952 refcount = IDXGISwapChain_Release(swapchain);
1953 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
1956 /* Test SetFullscreenState(). */
1957 swapchain_desc.BufferDesc.Width = sizes[i].width;
1958 swapchain_desc.BufferDesc.Height = sizes[i].height;
1959 swapchain_desc.Windowed = TRUE;
1961 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
1962 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
1964 todo_wine hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
1965 todo_wine ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
1967 if (SUCCEEDED(hr))
1968 check_swapchain_fullscreen_state(swapchain, &expected_state);
1969 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
1970 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
1971 ok(result_desc.BufferDesc.Width == sizes[i].width, "Got width %u, expected %u.\n",
1972 result_desc.BufferDesc.Width, sizes[i].width);
1973 ok(result_desc.BufferDesc.Height == sizes[i].height, "Got height %u, expected %u.\n",
1974 result_desc.BufferDesc.Height, sizes[i].height);
1976 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
1977 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
1978 check_swapchain_fullscreen_state(swapchain, &initial_state);
1980 refcount = IDXGISwapChain_Release(swapchain);
1981 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
1983 /* Test ResizeTarget(). */
1984 swapchain_desc.BufferDesc.Width = 800;
1985 swapchain_desc.BufferDesc.Height = 600;
1986 swapchain_desc.Windowed = TRUE;
1988 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
1989 ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
1991 hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
1992 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
1994 swapchain_desc.BufferDesc.Width = sizes[i].width;
1995 swapchain_desc.BufferDesc.Height = sizes[i].height;
1996 hr = IDXGISwapChain_ResizeTarget(swapchain, &swapchain_desc.BufferDesc);
1997 todo_wine ok(SUCCEEDED(hr), "ResizeTarget failed, hr %#x.\n", hr);
1999 if (SUCCEEDED(hr))
2000 check_swapchain_fullscreen_state(swapchain, &expected_state);
2001 hr = IDXGISwapChain_GetDesc(swapchain, &result_desc);
2002 ok(SUCCEEDED(hr), "GetDesc failed, hr %#x.\n", hr);
2003 ok(result_desc.BufferDesc.Width == 800, "Got width %u.\n", result_desc.BufferDesc.Width);
2004 ok(result_desc.BufferDesc.Height == 600, "Got height %u.\n", result_desc.BufferDesc.Height);
2006 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2007 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
2008 check_swapchain_fullscreen_state(swapchain, &initial_state);
2010 refcount = IDXGISwapChain_Release(swapchain);
2011 ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
2014 done:
2015 if (output)
2016 IDXGIOutput_Release(output);
2017 IDXGIAdapter_Release(adapter);
2018 refcount = IDXGIDevice_Release(device);
2019 ok(!refcount, "Device has %u references left.\n", refcount);
2020 refcount = IDXGIFactory_Release(factory);
2021 ok(!refcount, "Factory has %u references left.\n", refcount);
2024 static void test_create_factory(void)
2026 IDXGIFactory1 *factory;
2027 IUnknown *iface;
2028 HRESULT hr;
2030 iface = (void *)0xdeadbeef;
2031 hr = CreateDXGIFactory(&IID_IDXGIDevice, (void **)&iface);
2032 ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
2033 ok(!iface, "Got unexpected iface %p.\n", iface);
2035 hr = CreateDXGIFactory(&IID_IUnknown, (void **)&iface);
2036 ok(SUCCEEDED(hr), "Failed to create factory with IID_IUnknown, hr %#x.\n", hr);
2037 IUnknown_Release(iface);
2039 hr = CreateDXGIFactory(&IID_IDXGIObject, (void **)&iface);
2040 ok(SUCCEEDED(hr), "Failed to create factory with IID_IDXGIObject, hr %#x.\n", hr);
2041 IUnknown_Release(iface);
2043 factory = (void *)0xdeadbeef;
2044 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&iface);
2045 ok(SUCCEEDED(hr), "Failed to create factory with IID_IDXGIFactory, hr %#x.\n", hr);
2046 hr = IUnknown_QueryInterface(iface, &IID_IDXGIFactory1, (void **)&factory);
2047 ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
2048 ok(!factory, "Got unexpected factory %p.\n", factory);
2049 IUnknown_Release(iface);
2051 iface = (void *)0xdeadbeef;
2052 hr = CreateDXGIFactory(&IID_IDXGIFactory1, (void **)&iface);
2053 ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
2054 ok(!iface, "Got unexpected iface %p.\n", iface);
2056 if (!pCreateDXGIFactory1)
2058 win_skip("CreateDXGIFactory1 not available, skipping tests.\n");
2059 return;
2062 iface = (void *)0xdeadbeef;
2063 hr = pCreateDXGIFactory1(&IID_IDXGIDevice, (void **)&iface);
2064 ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
2065 ok(!iface, "Got unexpected iface %p.\n", iface);
2067 hr = pCreateDXGIFactory1(&IID_IUnknown, (void **)&iface);
2068 ok(SUCCEEDED(hr), "Failed to create factory with IID_IUnknown, hr %#x.\n", hr);
2069 IUnknown_Release(iface);
2071 hr = pCreateDXGIFactory1(&IID_IDXGIObject, (void **)&iface);
2072 ok(SUCCEEDED(hr), "Failed to create factory with IID_IDXGIObject, hr %#x.\n", hr);
2073 IUnknown_Release(iface);
2075 hr = pCreateDXGIFactory1(&IID_IDXGIFactory, (void **)&iface);
2076 ok(SUCCEEDED(hr), "Failed to create factory with IID_IDXGIFactory, hr %#x.\n", hr);
2077 hr = IUnknown_QueryInterface(iface, &IID_IDXGIFactory1, (void **)&factory);
2078 ok(SUCCEEDED(hr), "Failed to query IDXGIFactory1 interface, hr %#x.\n", hr);
2079 IDXGIFactory1_Release(factory);
2080 IUnknown_Release(iface);
2082 hr = pCreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&iface);
2083 ok(SUCCEEDED(hr), "Failed to create factory with IID_IDXGIFactory1, hr %#x.\n", hr);
2084 IUnknown_Release(iface);
2087 static void test_private_data(void)
2089 ULONG refcount, expected_refcount;
2090 IDXGIDevice *device;
2091 HRESULT hr;
2092 IDXGIDevice *test_object;
2093 IUnknown *ptr;
2094 static const DWORD data[] = {1, 2, 3, 4};
2095 UINT size;
2096 static const GUID dxgi_private_data_test_guid =
2098 0xfdb37466,
2099 0x428f,
2100 0x4edf,
2101 {0xa3, 0x7f, 0x9b, 0x1d, 0xf4, 0x88, 0xc5, 0xfc}
2103 static const GUID dxgi_private_data_test_guid2 =
2105 0x2e5afac2,
2106 0x87b5,
2107 0x4c10,
2108 {0x9b, 0x4b, 0x89, 0xd7, 0xd1, 0x12, 0xe7, 0x2b}
2111 if (!(device = create_device()))
2113 skip("Failed to create device, skipping tests.\n");
2114 return;
2117 test_object = create_device();
2119 /* SetPrivateData with a pointer of NULL has the purpose of FreePrivateData in previous
2120 * d3d versions. A successful clear returns S_OK. A redundant clear S_FALSE. Setting a
2121 * NULL interface is not considered a clear but as setting an interface pointer that
2122 * happens to be NULL. */
2123 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 0, NULL);
2124 ok(hr == S_FALSE, "Got unexpected hr %#x.\n", hr);
2125 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
2126 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2127 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, ~0U, NULL);
2128 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2129 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, ~0U, NULL);
2130 ok(hr == S_FALSE, "Got unexpected hr %#x.\n", hr);
2132 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
2133 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2134 size = sizeof(ptr) * 2;
2135 ptr = (IUnknown *)0xdeadbeef;
2136 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
2137 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2138 ok(!ptr, "Got unexpected pointer %p.\n", ptr);
2139 ok(size == sizeof(IUnknown *), "Got unexpected size %u.\n", size);
2141 refcount = get_refcount((IUnknown *)test_object);
2142 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
2143 (IUnknown *)test_object);
2144 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2145 expected_refcount = refcount + 1;
2146 refcount = get_refcount((IUnknown *)test_object);
2147 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
2148 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
2149 (IUnknown *)test_object);
2150 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2151 refcount = get_refcount((IUnknown *)test_object);
2152 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
2154 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid, NULL);
2155 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2156 expected_refcount--;
2157 refcount = get_refcount((IUnknown *)test_object);
2158 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
2160 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
2161 (IUnknown *)test_object);
2162 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2163 size = sizeof(data);
2164 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, size, data);
2165 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2166 refcount = get_refcount((IUnknown *)test_object);
2167 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
2168 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 42, NULL);
2169 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2170 hr = IDXGIDevice_SetPrivateData(device, &dxgi_private_data_test_guid, 42, NULL);
2171 ok(hr == S_FALSE, "Got unexpected hr %#x.\n", hr);
2173 hr = IDXGIDevice_SetPrivateDataInterface(device, &dxgi_private_data_test_guid,
2174 (IUnknown *)test_object);
2175 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2176 expected_refcount++;
2177 size = 2 * sizeof(ptr);
2178 ptr = NULL;
2179 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
2180 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2181 ok(size == sizeof(test_object), "Got unexpected size %u.\n", size);
2182 expected_refcount++;
2183 refcount = get_refcount((IUnknown *)test_object);
2184 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
2185 if (ptr)
2186 IUnknown_Release(ptr);
2187 expected_refcount--;
2189 ptr = (IUnknown *)0xdeadbeef;
2190 size = 1;
2191 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, NULL);
2192 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2193 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
2194 size = 2 * sizeof(ptr);
2195 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, NULL);
2196 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2197 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
2198 refcount = get_refcount((IUnknown *)test_object);
2199 ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
2201 size = 1;
2202 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, &size, &ptr);
2203 ok(hr == DXGI_ERROR_MORE_DATA, "Got unexpected hr %#x.\n", hr);
2204 ok(size == sizeof(device), "Got unexpected size %u.\n", size);
2205 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
2206 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid2, NULL, NULL);
2207 ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
2208 size = 0xdeadbabe;
2209 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid2, &size, &ptr);
2210 ok(hr == DXGI_ERROR_NOT_FOUND, "Got unexpected hr %#x.\n", hr);
2211 ok(size == 0, "Got unexpected size %u.\n", size);
2212 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
2213 hr = IDXGIDevice_GetPrivateData(device, &dxgi_private_data_test_guid, NULL, &ptr);
2214 ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
2215 ok(ptr == (IUnknown *)0xdeadbeef, "Got unexpected pointer %p.\n", ptr);
2217 refcount = IDXGIDevice_Release(device);
2218 ok(!refcount, "Device has %u references left.\n", refcount);
2219 refcount = IDXGIDevice_Release(test_object);
2220 ok(!refcount, "Test object has %u references left.\n", refcount);
2223 static void test_swapchain_resize(void)
2225 DXGI_SWAP_CHAIN_DESC swapchain_desc;
2226 D3D10_TEXTURE2D_DESC texture_desc;
2227 DXGI_SURFACE_DESC surface_desc;
2228 IDXGISwapChain *swapchain;
2229 ID3D10Texture2D *texture;
2230 IDXGISurface *surface;
2231 IDXGIAdapter *adapter;
2232 IDXGIFactory *factory;
2233 IDXGIDevice *device;
2234 RECT client_rect, r;
2235 ULONG refcount;
2236 HWND window;
2237 HRESULT hr;
2238 BOOL ret;
2240 if (!(device = create_device()))
2242 skip("Failed to create device, skipping tests.\n");
2243 return;
2245 window = CreateWindowA("static", "dxgi_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2246 0, 0, 640, 480, NULL, NULL, NULL, NULL);
2247 ret = GetClientRect(window, &client_rect);
2248 ok(ret, "Failed to get client rect.\n");
2250 hr = IDXGIDevice_GetAdapter(device, &adapter);
2251 ok(SUCCEEDED(hr), "Failed to get adapter, hr %#x.\n", hr);
2252 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
2253 ok(SUCCEEDED(hr), "Failed to get factory, hr %#x.\n", hr);
2254 IDXGIAdapter_Release(adapter);
2256 swapchain_desc.BufferDesc.Width = 640;
2257 swapchain_desc.BufferDesc.Height = 480;
2258 swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
2259 swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
2260 swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2261 swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
2262 swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
2263 swapchain_desc.SampleDesc.Count = 1;
2264 swapchain_desc.SampleDesc.Quality = 0;
2265 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2266 swapchain_desc.BufferCount = 1;
2267 swapchain_desc.OutputWindow = window;
2268 swapchain_desc.Windowed = TRUE;
2269 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
2270 swapchain_desc.Flags = 0;
2272 hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
2273 ok(SUCCEEDED(hr), "Failed to create swapchain, hr %#x.\n", hr);
2274 IDXGIFactory_Release(factory);
2275 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface);
2276 ok(SUCCEEDED(hr), "Failed to get buffer, hr %#x.\n", hr);
2277 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&texture);
2278 ok(SUCCEEDED(hr), "Failed to get buffer, hr %#x.\n", hr);
2280 ret = GetClientRect(window, &r);
2281 ok(ret, "Failed to get client rect.\n");
2282 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
2283 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
2285 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
2286 ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
2287 ok(swapchain_desc.BufferDesc.Width == 640,
2288 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
2289 ok(swapchain_desc.BufferDesc.Height == 480,
2290 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
2291 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
2292 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
2293 swapchain_desc.BufferDesc.RefreshRate.Numerator);
2294 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
2295 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
2296 swapchain_desc.BufferDesc.RefreshRate.Denominator);
2297 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM,
2298 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
2299 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
2300 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
2301 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
2302 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
2303 ok(swapchain_desc.SampleDesc.Count == 1,
2304 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
2305 ok(!swapchain_desc.SampleDesc.Quality,
2306 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
2307 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
2308 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
2309 ok(swapchain_desc.BufferCount == 1,
2310 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
2311 ok(swapchain_desc.OutputWindow == window,
2312 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
2313 ok(swapchain_desc.Windowed,
2314 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
2315 ok(swapchain_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD,
2316 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
2317 ok(!swapchain_desc.Flags,
2318 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
2320 hr = IDXGISurface_GetDesc(surface, &surface_desc);
2321 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2322 ok(surface_desc.Width == 640, "Got unexpected Width %u.\n", surface_desc.Width);
2323 ok(surface_desc.Height == 480, "Got unexpected Height %u.\n", surface_desc.Height);
2324 ok(surface_desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Got unexpected Format %#x.\n", surface_desc.Format);
2325 ok(surface_desc.SampleDesc.Count == 1, "Got unexpected SampleDesc.Count %u.\n", surface_desc.SampleDesc.Count);
2326 ok(!surface_desc.SampleDesc.Quality, "Got unexpected SampleDesc.Quality %u.\n", surface_desc.SampleDesc.Quality);
2328 ID3D10Texture2D_GetDesc(texture, &texture_desc);
2329 ok(texture_desc.Width == 640, "Got unexpected Width %u.\n", texture_desc.Width);
2330 ok(texture_desc.Height == 480, "Got unexpected Height %u.\n", texture_desc.Height);
2331 ok(texture_desc.MipLevels == 1, "Got unexpected MipLevels %u.\n", texture_desc.MipLevels);
2332 ok(texture_desc.ArraySize == 1, "Got unexpected ArraySize %u.\n", texture_desc.ArraySize);
2333 ok(texture_desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Got unexpected Format %#x.\n", texture_desc.Format);
2334 ok(texture_desc.SampleDesc.Count == 1, "Got unexpected SampleDesc.Count %u.\n", texture_desc.SampleDesc.Count);
2335 ok(!texture_desc.SampleDesc.Quality, "Got unexpected SampleDesc.Quality %u.\n", texture_desc.SampleDesc.Quality);
2336 ok(texture_desc.Usage == D3D10_USAGE_DEFAULT, "Got unexpected Usage %#x.\n", texture_desc.Usage);
2337 ok(texture_desc.BindFlags == D3D10_BIND_RENDER_TARGET, "Got unexpected BindFlags %#x.\n", texture_desc.BindFlags);
2338 ok(!texture_desc.CPUAccessFlags, "Got unexpected CPUAccessFlags %#x.\n", texture_desc.CPUAccessFlags);
2339 ok(!texture_desc.MiscFlags, "Got unexpected MiscFlags %#x.\n", texture_desc.MiscFlags);
2341 hr = IDXGISwapChain_ResizeBuffers(swapchain, 1, 320, 240, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 0);
2342 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
2344 ret = GetClientRect(window, &r);
2345 ok(ret, "Failed to get client rect.\n");
2346 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
2347 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
2349 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
2350 ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
2351 ok(swapchain_desc.BufferDesc.Width == 640,
2352 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
2353 ok(swapchain_desc.BufferDesc.Height == 480,
2354 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
2355 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
2356 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
2357 swapchain_desc.BufferDesc.RefreshRate.Numerator);
2358 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
2359 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
2360 swapchain_desc.BufferDesc.RefreshRate.Denominator);
2361 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM,
2362 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
2363 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
2364 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
2365 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
2366 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
2367 ok(swapchain_desc.SampleDesc.Count == 1,
2368 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
2369 ok(!swapchain_desc.SampleDesc.Quality,
2370 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
2371 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
2372 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
2373 ok(swapchain_desc.BufferCount == 1,
2374 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
2375 ok(swapchain_desc.OutputWindow == window,
2376 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
2377 ok(swapchain_desc.Windowed,
2378 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
2379 ok(swapchain_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD,
2380 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
2381 ok(!swapchain_desc.Flags,
2382 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
2384 hr = IDXGISurface_GetDesc(surface, &surface_desc);
2385 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2386 ok(surface_desc.Width == 640, "Got unexpected Width %u.\n", surface_desc.Width);
2387 ok(surface_desc.Height == 480, "Got unexpected Height %u.\n", surface_desc.Height);
2388 ok(surface_desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Got unexpected Format %#x.\n", surface_desc.Format);
2389 ok(surface_desc.SampleDesc.Count == 1, "Got unexpected SampleDesc.Count %u.\n", surface_desc.SampleDesc.Count);
2390 ok(!surface_desc.SampleDesc.Quality, "Got unexpected SampleDesc.Quality %u.\n", surface_desc.SampleDesc.Quality);
2392 ID3D10Texture2D_GetDesc(texture, &texture_desc);
2393 ok(texture_desc.Width == 640, "Got unexpected Width %u.\n", texture_desc.Width);
2394 ok(texture_desc.Height == 480, "Got unexpected Height %u.\n", texture_desc.Height);
2395 ok(texture_desc.MipLevels == 1, "Got unexpected MipLevels %u.\n", texture_desc.MipLevels);
2396 ok(texture_desc.ArraySize == 1, "Got unexpected ArraySize %u.\n", texture_desc.ArraySize);
2397 ok(texture_desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Got unexpected Format %#x.\n", texture_desc.Format);
2398 ok(texture_desc.SampleDesc.Count == 1, "Got unexpected SampleDesc.Count %u.\n", texture_desc.SampleDesc.Count);
2399 ok(!texture_desc.SampleDesc.Quality, "Got unexpected SampleDesc.Quality %u.\n", texture_desc.SampleDesc.Quality);
2400 ok(texture_desc.Usage == D3D10_USAGE_DEFAULT, "Got unexpected Usage %#x.\n", texture_desc.Usage);
2401 ok(texture_desc.BindFlags == D3D10_BIND_RENDER_TARGET, "Got unexpected BindFlags %#x.\n", texture_desc.BindFlags);
2402 ok(!texture_desc.CPUAccessFlags, "Got unexpected CPUAccessFlags %#x.\n", texture_desc.CPUAccessFlags);
2403 ok(!texture_desc.MiscFlags, "Got unexpected MiscFlags %#x.\n", texture_desc.MiscFlags);
2405 ID3D10Texture2D_Release(texture);
2406 IDXGISurface_Release(surface);
2407 hr = IDXGISwapChain_ResizeBuffers(swapchain, 1, 320, 240, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 0);
2408 ok(SUCCEEDED(hr), "Failed to resize buffers, hr %#x.\n", hr);
2409 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface);
2410 ok(SUCCEEDED(hr), "Failed to get buffer, hr %#x.\n", hr);
2411 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_ID3D10Texture2D, (void **)&texture);
2412 ok(SUCCEEDED(hr), "Failed to get buffer, hr %#x.\n", hr);
2414 ret = GetClientRect(window, &r);
2415 ok(ret, "Failed to get client rect.\n");
2416 ok(EqualRect(&r, &client_rect), "Got unexpected rect %s, expected %s.\n",
2417 wine_dbgstr_rect(&r), wine_dbgstr_rect(&client_rect));
2419 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
2420 ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
2421 ok(swapchain_desc.BufferDesc.Width == 320,
2422 "Got unexpected BufferDesc.Width %u.\n", swapchain_desc.BufferDesc.Width);
2423 ok(swapchain_desc.BufferDesc.Height == 240,
2424 "Got unexpected bufferDesc.Height %u.\n", swapchain_desc.BufferDesc.Height);
2425 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
2426 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
2427 swapchain_desc.BufferDesc.RefreshRate.Numerator);
2428 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
2429 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
2430 swapchain_desc.BufferDesc.RefreshRate.Denominator);
2431 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
2432 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
2433 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
2434 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
2435 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
2436 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
2437 ok(swapchain_desc.SampleDesc.Count == 1,
2438 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
2439 ok(!swapchain_desc.SampleDesc.Quality,
2440 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
2441 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
2442 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
2443 ok(swapchain_desc.BufferCount == 1,
2444 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
2445 ok(swapchain_desc.OutputWindow == window,
2446 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
2447 ok(swapchain_desc.Windowed,
2448 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
2449 ok(swapchain_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD,
2450 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
2451 ok(!swapchain_desc.Flags,
2452 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
2454 hr = IDXGISurface_GetDesc(surface, &surface_desc);
2455 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2456 ok(surface_desc.Width == 320, "Got unexpected Width %u.\n", surface_desc.Width);
2457 ok(surface_desc.Height == 240, "Got unexpected Height %u.\n", surface_desc.Height);
2458 ok(surface_desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, "Got unexpected Format %#x.\n", surface_desc.Format);
2459 ok(surface_desc.SampleDesc.Count == 1, "Got unexpected SampleDesc.Count %u.\n", surface_desc.SampleDesc.Count);
2460 ok(!surface_desc.SampleDesc.Quality, "Got unexpected SampleDesc.Quality %u.\n", surface_desc.SampleDesc.Quality);
2462 ID3D10Texture2D_GetDesc(texture, &texture_desc);
2463 ok(texture_desc.Width == 320, "Got unexpected Width %u.\n", texture_desc.Width);
2464 ok(texture_desc.Height == 240, "Got unexpected Height %u.\n", texture_desc.Height);
2465 ok(texture_desc.MipLevels == 1, "Got unexpected MipLevels %u.\n", texture_desc.MipLevels);
2466 ok(texture_desc.ArraySize == 1, "Got unexpected ArraySize %u.\n", texture_desc.ArraySize);
2467 ok(texture_desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, "Got unexpected Format %#x.\n", texture_desc.Format);
2468 ok(texture_desc.SampleDesc.Count == 1, "Got unexpected SampleDesc.Count %u.\n", texture_desc.SampleDesc.Count);
2469 ok(!texture_desc.SampleDesc.Quality, "Got unexpected SampleDesc.Quality %u.\n", texture_desc.SampleDesc.Quality);
2470 ok(texture_desc.Usage == D3D10_USAGE_DEFAULT, "Got unexpected Usage %#x.\n", texture_desc.Usage);
2471 ok(texture_desc.BindFlags == D3D10_BIND_RENDER_TARGET, "Got unexpected BindFlags %#x.\n", texture_desc.BindFlags);
2472 ok(!texture_desc.CPUAccessFlags, "Got unexpected CPUAccessFlags %#x.\n", texture_desc.CPUAccessFlags);
2473 ok(!texture_desc.MiscFlags, "Got unexpected MiscFlags %#x.\n", texture_desc.MiscFlags);
2475 ID3D10Texture2D_Release(texture);
2476 IDXGISurface_Release(surface);
2478 hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
2479 ok(SUCCEEDED(hr), "Failed to resize buffers, hr %#x.\n", hr);
2481 hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
2482 ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
2483 ok(swapchain_desc.BufferDesc.Width == client_rect.right - client_rect.left,
2484 "Got unexpected BufferDesc.Width %u, expected %u.\n",
2485 swapchain_desc.BufferDesc.Width, client_rect.right - client_rect.left);
2486 ok(swapchain_desc.BufferDesc.Height == client_rect.bottom - client_rect.top,
2487 "Got unexpected bufferDesc.Height %u, expected %u.\n",
2488 swapchain_desc.BufferDesc.Height, client_rect.bottom - client_rect.top);
2489 ok(swapchain_desc.BufferDesc.RefreshRate.Numerator == 60,
2490 "Got unexpected BufferDesc.RefreshRate.Numerator %u.\n",
2491 swapchain_desc.BufferDesc.RefreshRate.Numerator);
2492 ok(swapchain_desc.BufferDesc.RefreshRate.Denominator == 1,
2493 "Got unexpected BufferDesc.RefreshRate.Denominator %u.\n",
2494 swapchain_desc.BufferDesc.RefreshRate.Denominator);
2495 ok(swapchain_desc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
2496 "Got unexpected BufferDesc.Format %#x.\n", swapchain_desc.BufferDesc.Format);
2497 ok(swapchain_desc.BufferDesc.ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
2498 "Got unexpected BufferDesc.ScanlineOrdering %#x.\n", swapchain_desc.BufferDesc.ScanlineOrdering);
2499 ok(swapchain_desc.BufferDesc.Scaling == DXGI_MODE_SCALING_UNSPECIFIED,
2500 "Got unexpected BufferDesc.Scaling %#x.\n", swapchain_desc.BufferDesc.Scaling);
2501 ok(swapchain_desc.SampleDesc.Count == 1,
2502 "Got unexpected SampleDesc.Count %u.\n", swapchain_desc.SampleDesc.Count);
2503 ok(!swapchain_desc.SampleDesc.Quality,
2504 "Got unexpected SampleDesc.Quality %u.\n", swapchain_desc.SampleDesc.Quality);
2505 ok(swapchain_desc.BufferUsage == DXGI_USAGE_RENDER_TARGET_OUTPUT,
2506 "Got unexpected BufferUsage %#x.\n", swapchain_desc.BufferUsage);
2507 ok(swapchain_desc.BufferCount == 1,
2508 "Got unexpected BufferCount %u.\n", swapchain_desc.BufferCount);
2509 ok(swapchain_desc.OutputWindow == window,
2510 "Got unexpected OutputWindow %p, expected %p.\n", swapchain_desc.OutputWindow, window);
2511 ok(swapchain_desc.Windowed,
2512 "Got unexpected Windowed %#x.\n", swapchain_desc.Windowed);
2513 ok(swapchain_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD,
2514 "Got unexpected SwapEffect %#x.\n", swapchain_desc.SwapEffect);
2515 ok(!swapchain_desc.Flags,
2516 "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
2518 IDXGISwapChain_Release(swapchain);
2519 refcount = IDXGIDevice_Release(device);
2520 ok(!refcount, "Device has %u references left.\n", refcount);
2521 DestroyWindow(window);
2524 static void test_swapchain_parameters(void)
2526 IDXGISwapChain *swapchain;
2527 IUnknown *obj;
2528 IDXGIAdapter *adapter;
2529 IDXGIFactory *factory;
2530 IDXGIDevice *device;
2531 IDXGIResource *resource;
2532 DXGI_SWAP_CHAIN_DESC desc;
2533 HRESULT hr;
2534 unsigned int i, j;
2535 ULONG refcount;
2536 DXGI_USAGE usage, expected_usage, broken_usage;
2537 HWND window;
2538 static const struct
2540 BOOL windowed;
2541 UINT buffer_count;
2542 DXGI_SWAP_EFFECT swap_effect;
2543 HRESULT hr, vista_hr;
2544 UINT highest_accessible_buffer;
2546 tests[] =
2548 {TRUE, 0, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2549 {TRUE, 1, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
2550 {TRUE, 2, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
2551 {TRUE, 0, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2552 {TRUE, 1, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 0},
2553 {TRUE, 2, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 1},
2554 {TRUE, 3, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 2},
2555 {TRUE, 0, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2556 {TRUE, 1, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2557 {TRUE, 2, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2558 {TRUE, 0, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2559 {TRUE, 1, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2560 {TRUE, 2, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 1},
2561 {TRUE, 3, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 2},
2562 {TRUE, 0, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2563 {TRUE, 1, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2564 {TRUE, 2, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
2565 {TRUE, 0, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2566 {TRUE, 1, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2567 {TRUE, 2, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2568 {TRUE, 16, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
2569 {TRUE, 16, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 15},
2570 {TRUE, 16, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 15},
2571 {TRUE, 16, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
2572 {TRUE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2573 {TRUE, 17, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2574 {TRUE, 17, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2575 {TRUE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2577 {FALSE, 0, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2578 {FALSE, 1, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
2579 {FALSE, 2, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
2580 {FALSE, 0, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2581 {FALSE, 1, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 0},
2582 {FALSE, 2, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 1},
2583 {FALSE, 3, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 2},
2584 {FALSE, 0, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2585 {FALSE, 1, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2586 {FALSE, 2, 2 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2587 {FALSE, 0, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2588 {FALSE, 1, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2589 {FALSE, 2, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 1},
2590 {FALSE, 3, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 2},
2591 {FALSE, 0, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2592 {FALSE, 1, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2593 {FALSE, 2, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
2594 {FALSE, 0, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2595 {FALSE, 1, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2596 {FALSE, 2, 5 /* undefined */, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2597 {FALSE, 16, DXGI_SWAP_EFFECT_DISCARD, S_OK, S_OK, 0},
2598 {FALSE, 16, DXGI_SWAP_EFFECT_SEQUENTIAL, S_OK, S_OK, 15},
2599 {FALSE, 16, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK, DXGI_ERROR_INVALID_CALL, 15},
2600 /* The following test fails on Nvidia with E_OUTOFMEMORY and leaks device references in the
2601 * process. Disable it for now.
2602 {FALSE, 16, DXGI_SWAP_EFFECT_FLIP_DISCARD, S_OK, DXGI_ERROR_INVALID_CALL, 0},
2604 {FALSE, 17, DXGI_SWAP_EFFECT_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2605 {FALSE, 17, DXGI_SWAP_EFFECT_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2606 {FALSE, 17, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2607 {FALSE, 17, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL, 0},
2610 if (!(device = create_device()))
2612 skip("Failed to create device, skipping tests.\n");
2613 return;
2615 window = CreateWindowA("static", "dxgi_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2616 0, 0, 640, 480, 0, 0, 0, 0);
2618 hr = IDXGIDevice_QueryInterface(device, &IID_IUnknown, (void **)&obj);
2619 ok(SUCCEEDED(hr), "IDXGIDevice does not implement IUnknown\n");
2621 hr = IDXGIDevice_GetAdapter(device, &adapter);
2622 ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
2624 hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
2625 ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
2627 for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
2629 memset(&desc, 0, sizeof(desc));
2630 desc.BufferDesc.Width = registry_mode.dmPelsWidth;
2631 desc.BufferDesc.Height = registry_mode.dmPelsHeight;
2632 desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2633 desc.SampleDesc.Count = 1;
2634 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2635 desc.OutputWindow = window;
2637 desc.Windowed = tests[i].windowed;
2638 desc.BufferCount = tests[i].buffer_count;
2639 desc.SwapEffect = tests[i].swap_effect;
2641 hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
2642 ok(hr == tests[i].hr || broken(hr == tests[i].vista_hr)
2643 || (SUCCEEDED(tests[i].hr) && hr == DXGI_STATUS_OCCLUDED),
2644 "Got unexpected hr %#x, test %u.\n", hr, i);
2645 if (FAILED(hr))
2646 continue;
2648 hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGIResource, (void **)&resource);
2649 todo_wine ok(SUCCEEDED(hr), "GetBuffer(0) failed, hr %#x, test %u.\n", hr, i);
2650 if (FAILED(hr))
2652 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2653 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
2655 IDXGISwapChain_Release(swapchain);
2656 continue;
2659 expected_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
2660 if (tests[i].swap_effect == DXGI_SWAP_EFFECT_DISCARD)
2661 expected_usage |= DXGI_USAGE_DISCARD_ON_PRESENT;
2662 hr = IDXGIResource_GetUsage(resource, &usage);
2663 ok(SUCCEEDED(hr), "Failed to get resource usage, hr %#x, test %u.\n", hr, i);
2664 ok(usage == expected_usage, "Got usage %x, expected %x, test %u.\n", usage, expected_usage, i);
2666 IDXGIResource_Release(resource);
2668 hr = IDXGISwapChain_GetDesc(swapchain, &desc);
2669 ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
2671 for (j = 1; j <= tests[i].highest_accessible_buffer; j++)
2673 hr = IDXGISwapChain_GetBuffer(swapchain, j, &IID_IDXGIResource, (void **)&resource);
2674 ok(SUCCEEDED(hr), "GetBuffer(%u) failed, hr %#x, test %u.\n", hr, i, j);
2676 /* Buffers > 0 are supposed to be read only. This is the case except that in
2677 * fullscreen mode on Windows <= 8 the last backbuffer (BufferCount - 1) is
2678 * writable. This is not the case if an unsupported refresh rate is passed
2679 * for some reason, probably because the invalid refresh rate triggers a
2680 * kinda-sorta windowed mode.
2682 * On Windows 10 all buffers > 0 are read-only. Mark the earlier behavior
2683 * broken.
2685 * This last buffer acts as a shadow frontbuffer. Writing to it doesn't show
2686 * the draw on the screen right away (Aero on or off doesn't matter), but
2687 * Present with DXGI_PRESENT_DO_NOT_SEQUENCE will show the modifications.
2689 * Note that if the application doesn't have focused creating a fullscreen
2690 * swapchain returns DXGI_STATUS_OCCLUDED and we get a windowed swapchain,
2691 * so use the Windowed property of the swapchain that was actually created. */
2692 expected_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_READ_ONLY;
2693 broken_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
2695 if (desc.Windowed || j < tests[i].highest_accessible_buffer)
2696 broken_usage |= DXGI_USAGE_READ_ONLY;
2698 hr = IDXGIResource_GetUsage(resource, &usage);
2699 ok(SUCCEEDED(hr), "Failed to get resource usage, hr %#x, test %u, buffer %u.\n", hr, i, j);
2700 ok(usage == expected_usage || broken(usage == broken_usage),
2701 "Got usage %x, expected %x, test %u, buffer %u.\n",
2702 usage, expected_usage, i, j);
2704 IDXGIResource_Release(resource);
2706 hr = IDXGISwapChain_GetBuffer(swapchain, j, &IID_IDXGIResource, (void **)&resource);
2707 ok(hr == DXGI_ERROR_INVALID_CALL, "GetBuffer(%u) returned unexpected hr %#x, test %u.\n", j, hr, i);
2709 hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
2710 ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
2712 IDXGISwapChain_Release(swapchain);
2715 IDXGIFactory_Release(factory);
2716 IDXGIAdapter_Release(adapter);
2717 IUnknown_Release(obj);
2718 refcount = IDXGIDevice_Release(device);
2719 ok(!refcount, "Device has %u references left.\n", refcount);
2720 DestroyWindow(window);
2723 static void test_maximum_frame_latency(void)
2725 IDXGIDevice1 *device1;
2726 IDXGIDevice *device;
2727 UINT max_latency;
2728 ULONG refcount;
2729 HRESULT hr;
2731 if (!(device = create_device()))
2733 skip("Failed to create device.\n");
2734 return;
2737 if (SUCCEEDED(IDXGIDevice_QueryInterface(device, &IID_IDXGIDevice1, (void **)&device1)))
2739 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
2740 todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2741 ok(max_latency == DEFAULT_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
2743 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, MAX_FRAME_LATENCY);
2744 todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2745 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
2746 todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2747 todo_wine ok(max_latency == MAX_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
2749 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, MAX_FRAME_LATENCY + 1);
2750 ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#x.\n", hr);
2751 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
2752 todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2753 todo_wine ok(max_latency == MAX_FRAME_LATENCY, "Got unexpected maximum frame latency %u.\n", max_latency);
2755 hr = IDXGIDevice1_SetMaximumFrameLatency(device1, 0);
2756 todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2757 hr = IDXGIDevice1_GetMaximumFrameLatency(device1, &max_latency);
2758 todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
2759 /* 0 does not reset to the default frame latency on all Windows versions. */
2760 ok(max_latency == DEFAULT_FRAME_LATENCY || broken(!max_latency),
2761 "Got unexpected maximum frame latency %u.\n", max_latency);
2763 IDXGIDevice1_Release(device1);
2765 else
2767 win_skip("IDXGIDevice1 is not implemented.\n");
2770 refcount = IDXGIDevice_Release(device);
2771 ok(!refcount, "Device has %u references left.\n", refcount);
2774 static void test_output_desc(void)
2776 IDXGIAdapter *adapter, *adapter2;
2777 IDXGIOutput *output, *output2;
2778 DXGI_OUTPUT_DESC desc;
2779 IDXGIFactory *factory;
2780 unsigned int i, j;
2781 ULONG refcount;
2782 HRESULT hr;
2784 hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory);
2785 ok(SUCCEEDED(hr), "Failed to create DXGI factory, hr %#x.\n", hr);
2787 for (i = 0; ; ++i)
2789 hr = IDXGIFactory_EnumAdapters(factory, i, &adapter);
2790 if (hr == DXGI_ERROR_NOT_FOUND)
2791 break;
2792 ok(SUCCEEDED(hr), "Failed to enumerate adapter %u, hr %#x.\n", i, hr);
2794 hr = IDXGIFactory_EnumAdapters(factory, i, &adapter2);
2795 ok(SUCCEEDED(hr), "Failed to enumerate adapter %u, hr %#x.\n", i, hr);
2796 ok(adapter != adapter2, "Expected to get new instance of IDXGIAdapter, %p == %p.\n", adapter, adapter2);
2797 refcount = get_refcount((IUnknown *)adapter);
2798 ok(refcount == 1, "Get unexpected refcount %u for adapter %u.\n", refcount, i);
2799 IDXGIAdapter_Release(adapter2);
2801 refcount = get_refcount((IUnknown *)factory);
2802 ok(refcount == 2, "Get unexpected refcount %u.\n", refcount);
2803 refcount = get_refcount((IUnknown *)adapter);
2804 ok(refcount == 1, "Get unexpected refcount %u for adapter %u.\n", refcount, i);
2806 for (j = 0; ; ++j)
2808 MONITORINFOEXW monitor_info;
2809 BOOL ret;
2811 hr = IDXGIAdapter_EnumOutputs(adapter, j, &output);
2812 if (hr == DXGI_ERROR_NOT_FOUND)
2813 break;
2814 ok(SUCCEEDED(hr), "Failed to enumerate output %u on adapter %u, hr %#x.\n", j, i, hr);
2816 hr = IDXGIAdapter_EnumOutputs(adapter, j, &output2);
2817 ok(SUCCEEDED(hr), "Failed to enumerate output %u on adapter %u, hr %#x.\n", j, i, hr);
2818 ok(output != output2, "Expected to get new instance of IDXGIOutput, %p == %p.\n", output, output2);
2819 refcount = get_refcount((IUnknown *)output);
2820 ok(refcount == 1, "Get unexpected refcount %u for output %u, adapter %u.\n", refcount, j, i);
2821 IDXGIOutput_Release(output2);
2823 refcount = get_refcount((IUnknown *)factory);
2824 ok(refcount == 2, "Get unexpected refcount %u.\n", refcount);
2825 refcount = get_refcount((IUnknown *)adapter);
2826 ok(refcount == 2, "Get unexpected refcount %u for adapter %u.\n", refcount, i);
2827 refcount = get_refcount((IUnknown *)output);
2828 ok(refcount == 1, "Get unexpected refcount %u for output %u, adapter %u.\n", refcount, j, i);
2830 hr = IDXGIOutput_GetDesc(output, NULL);
2831 ok(hr == E_INVALIDARG, "Got unexpected hr %#x for output %u on adapter %u.\n", hr, j, i);
2832 hr = IDXGIOutput_GetDesc(output, &desc);
2833 ok(SUCCEEDED(hr), "Failed to get desc for output %u on adapter %u, hr %#x.\n", j, i, hr);
2835 monitor_info.cbSize = sizeof(monitor_info);
2836 ret = GetMonitorInfoW(desc.Monitor, (MONITORINFO *)&monitor_info);
2837 ok(ret, "Failed to get monitor info.\n");
2838 ok(!lstrcmpW(desc.DeviceName, monitor_info.szDevice), "Got unexpected device name %s, expected %s.\n",
2839 wine_dbgstr_w(desc.DeviceName), wine_dbgstr_w(monitor_info.szDevice));
2840 ok(EqualRect(&desc.DesktopCoordinates, &monitor_info.rcMonitor),
2841 "Got unexpected desktop coordinates %s, expected %s.\n",
2842 wine_dbgstr_rect(&desc.DesktopCoordinates),
2843 wine_dbgstr_rect(&monitor_info.rcMonitor));
2845 IDXGIOutput_Release(output);
2846 refcount = get_refcount((IUnknown *)adapter);
2847 ok(refcount == 1, "Get unexpected refcount %u for adapter %u.\n", refcount, i);
2850 IDXGIAdapter_Release(adapter);
2851 refcount = get_refcount((IUnknown *)factory);
2852 ok(refcount == 1, "Get unexpected refcount %u.\n", refcount);
2855 refcount = IDXGIFactory_Release(factory);
2856 ok(!refcount, "IDXGIFactory has %u references left.\n", refcount);
2859 START_TEST(device)
2861 pCreateDXGIFactory1 = (void *)GetProcAddress(GetModuleHandleA("dxgi.dll"), "CreateDXGIFactory1");
2863 registry_mode.dmSize = sizeof(registry_mode);
2864 ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &registry_mode), "Failed to get display mode.\n");
2866 test_adapter_desc();
2867 test_check_interface_support();
2868 test_create_surface();
2869 test_parents();
2870 test_output();
2871 test_create_swapchain();
2872 test_get_containing_output();
2873 test_set_fullscreen();
2874 test_default_fullscreen_target_output();
2875 test_resize_target();
2876 test_inexact_modes();
2877 test_create_factory();
2878 test_private_data();
2879 test_swapchain_resize();
2880 test_swapchain_parameters();
2881 test_maximum_frame_latency();
2882 test_output_desc();