Release 1.5.29.
[wine] / dlls / ddraw / tests / ddraw1.c
1 /*
2  * Copyright 2011-2012 Henri Verbeet for CodeWeavers
3  * Copyright 2012-2013 Stefan Dösinger for CodeWeavers
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 #define COBJMACROS
20
21 #include "wine/test.h"
22 #include "d3d.h"
23
24 struct create_window_thread_param
25 {
26     HWND window;
27     HANDLE window_created;
28     HANDLE destroy_window;
29     HANDLE thread;
30 };
31
32 static BOOL compare_color(D3DCOLOR c1, D3DCOLOR c2, BYTE max_diff)
33 {
34     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
35     c1 >>= 8; c2 >>= 8;
36     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
37     c1 >>= 8; c2 >>= 8;
38     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
39     c1 >>= 8; c2 >>= 8;
40     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
41     return TRUE;
42 }
43
44 static DWORD WINAPI create_window_thread_proc(void *param)
45 {
46     struct create_window_thread_param *p = param;
47     DWORD res;
48     BOOL ret;
49
50     p->window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
51             0, 0, 640, 480, 0, 0, 0, 0);
52     ret = SetEvent(p->window_created);
53     ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
54
55     for (;;)
56     {
57         MSG msg;
58
59         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
60             DispatchMessage(&msg);
61         res = WaitForSingleObject(p->destroy_window, 100);
62         if (res == WAIT_OBJECT_0)
63             break;
64         if (res != WAIT_TIMEOUT)
65         {
66             ok(0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
67             break;
68         }
69     }
70
71     DestroyWindow(p->window);
72
73     return 0;
74 }
75
76 static void create_window_thread(struct create_window_thread_param *p)
77 {
78     DWORD res, tid;
79
80     p->window_created = CreateEvent(NULL, FALSE, FALSE, NULL);
81     ok(!!p->window_created, "CreateEvent failed, last error %#x.\n", GetLastError());
82     p->destroy_window = CreateEvent(NULL, FALSE, FALSE, NULL);
83     ok(!!p->destroy_window, "CreateEvent failed, last error %#x.\n", GetLastError());
84     p->thread = CreateThread(NULL, 0, create_window_thread_proc, p, 0, &tid);
85     ok(!!p->thread, "Failed to create thread, last error %#x.\n", GetLastError());
86     res = WaitForSingleObject(p->window_created, INFINITE);
87     ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
88 }
89
90 static void destroy_window_thread(struct create_window_thread_param *p)
91 {
92     SetEvent(p->destroy_window);
93     WaitForSingleObject(p->thread, INFINITE);
94     CloseHandle(p->destroy_window);
95     CloseHandle(p->window_created);
96     CloseHandle(p->thread);
97 }
98
99 static D3DCOLOR get_surface_color(IDirectDrawSurface *surface, UINT x, UINT y)
100 {
101     RECT rect = {x, y, x + 1, y + 1};
102     DDSURFACEDESC surface_desc;
103     D3DCOLOR color;
104     HRESULT hr;
105
106     memset(&surface_desc, 0, sizeof(surface_desc));
107     surface_desc.dwSize = sizeof(surface_desc);
108
109     hr = IDirectDrawSurface_Lock(surface, &rect, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
110     ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
111     if (FAILED(hr))
112         return 0xdeadbeef;
113
114     color = *((DWORD *)surface_desc.lpSurface) & 0x00ffffff;
115
116     hr = IDirectDrawSurface_Unlock(surface, NULL);
117     ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
118
119     return color;
120 }
121
122 static void emit_process_vertices(void **ptr, WORD base_idx, DWORD vertex_count)
123 {
124     D3DINSTRUCTION *inst = *ptr;
125     D3DPROCESSVERTICES *pv = (D3DPROCESSVERTICES *)(inst + 1);
126
127     inst->bOpcode = D3DOP_PROCESSVERTICES;
128     inst->bSize = sizeof(*pv);
129     inst->wCount = 1;
130
131     pv->dwFlags = D3DPROCESSVERTICES_COPY;
132     pv->wStart = base_idx;
133     pv->wDest = 0;
134     pv->dwCount = vertex_count;
135     pv->dwReserved = 0;
136
137     *ptr = pv + 1;
138 }
139
140 static void emit_set_rs(void **ptr, D3DRENDERSTATETYPE state, DWORD value)
141 {
142     D3DINSTRUCTION *inst = *ptr;
143     D3DSTATE *rs = (D3DSTATE *)(inst + 1);
144
145     inst->bOpcode = D3DOP_STATERENDER;
146     inst->bSize = sizeof(*rs);
147     inst->wCount = 1;
148
149     U1(*rs).drstRenderStateType = state;
150     U2(*rs).dwArg[0] = value;
151
152     *ptr = rs + 1;
153 }
154
155 static void emit_tquad(void **ptr, WORD base_idx)
156 {
157     D3DINSTRUCTION *inst = *ptr;
158     D3DTRIANGLE *tri = (D3DTRIANGLE *)(inst + 1);
159
160     inst->bOpcode = D3DOP_TRIANGLE;
161     inst->bSize = sizeof(*tri);
162     inst->wCount = 2;
163
164     U1(*tri).v1 = base_idx;
165     U2(*tri).v2 = base_idx + 1;
166     U3(*tri).v3 = base_idx + 2;
167     tri->wFlags = D3DTRIFLAG_START;
168     ++tri;
169
170     U1(*tri).v1 = base_idx + 2;
171     U2(*tri).v2 = base_idx + 1;
172     U3(*tri).v3 = base_idx + 3;
173     tri->wFlags = D3DTRIFLAG_ODD;
174     ++tri;
175
176     *ptr = tri;
177 }
178
179 static void emit_end(void **ptr)
180 {
181     D3DINSTRUCTION *inst = *ptr;
182
183     inst->bOpcode = D3DOP_EXIT;
184     inst->bSize = 0;
185     inst->wCount = 0;
186
187     *ptr = inst + 1;
188 }
189
190 static void set_execute_data(IDirect3DExecuteBuffer *execute_buffer, UINT vertex_count, UINT offset, UINT len)
191 {
192     D3DEXECUTEDATA exec_data;
193     HRESULT hr;
194
195     memset(&exec_data, 0, sizeof(exec_data));
196     exec_data.dwSize = sizeof(exec_data);
197     exec_data.dwVertexCount = vertex_count;
198     exec_data.dwInstructionOffset = offset;
199     exec_data.dwInstructionLength = len;
200     hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
201     ok(SUCCEEDED(hr), "Failed to set execute data, hr %#x.\n", hr);
202 }
203
204 static HRESULT CALLBACK enum_z_fmt(GUID *guid, char *description, char *name,
205         D3DDEVICEDESC *hal_desc, D3DDEVICEDESC *hel_desc, void *ctx)
206 {
207     DWORD *z_depth = ctx;
208
209     if (!IsEqualGUID(&IID_IDirect3DHALDevice, guid))
210         return D3DENUMRET_OK;
211
212     if (hal_desc->dwDeviceZBufferBitDepth & DDBD_32)
213         *z_depth = 32;
214     else if (hal_desc->dwDeviceZBufferBitDepth & DDBD_24)
215         *z_depth = 24;
216     else if (hal_desc->dwDeviceZBufferBitDepth & DDBD_16)
217         *z_depth = 16;
218
219     return DDENUMRET_OK;
220 }
221
222 static IDirectDraw *create_ddraw(void)
223 {
224     IDirectDraw *ddraw;
225
226     if (FAILED(DirectDrawCreate(NULL, &ddraw, NULL)))
227         return NULL;
228
229     return ddraw;
230 }
231
232 static IDirect3DDevice *create_device(IDirectDraw *ddraw, HWND window, DWORD coop_level)
233 {
234     IDirectDrawSurface *surface, *ds;
235     IDirect3DDevice *device = NULL;
236     DDSURFACEDESC surface_desc;
237     DWORD z_depth = 0;
238     IDirect3D *d3d;
239     HRESULT hr;
240
241     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, coop_level);
242     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
243
244     memset(&surface_desc, 0, sizeof(surface_desc));
245     surface_desc.dwSize = sizeof(surface_desc);
246     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
247     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
248     surface_desc.dwWidth = 640;
249     surface_desc.dwHeight = 480;
250
251     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
252     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
253
254     if (coop_level & DDSCL_NORMAL)
255     {
256         IDirectDrawClipper *clipper;
257
258         hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
259         ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
260         hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
261         ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
262         hr = IDirectDrawSurface_SetClipper(surface, clipper);
263         ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#x.\n", hr);
264         IDirectDrawClipper_Release(clipper);
265     }
266
267     hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
268     if (FAILED(hr))
269     {
270         IDirectDrawSurface_Release(surface);
271         return NULL;
272     }
273
274     hr = IDirect3D_EnumDevices(d3d, enum_z_fmt, &z_depth);
275     ok(SUCCEEDED(hr), "Failed to enumerate z-formats, hr %#x.\n", hr);
276     IDirect3D_Release(d3d);
277     if (FAILED(hr) || !z_depth)
278     {
279         IDirectDrawSurface_Release(surface);
280         return NULL;
281     }
282
283     memset(&surface_desc, 0, sizeof(surface_desc));
284     surface_desc.dwSize = sizeof(surface_desc);
285     surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
286     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
287     U2(surface_desc).dwZBufferBitDepth = z_depth;
288     surface_desc.dwWidth = 640;
289     surface_desc.dwHeight = 480;
290     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &ds, NULL);
291     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
292     if (FAILED(hr))
293     {
294         IDirectDrawSurface_Release(surface);
295         return NULL;
296     }
297
298     hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
299     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
300     IDirectDrawSurface_Release(ds);
301     if (FAILED(hr))
302     {
303         IDirectDrawSurface_Release(surface);
304         return NULL;
305     }
306
307     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DHALDevice, (void **)&device);
308     IDirectDrawSurface_Release(surface);
309     if (FAILED(hr))
310         return NULL;
311
312     return device;
313 }
314
315 static IDirect3DViewport *create_viewport(IDirect3DDevice *device, UINT x, UINT y, UINT w, UINT h)
316 {
317     IDirect3DViewport *viewport;
318     D3DVIEWPORT vp;
319     IDirect3D *d3d;
320     HRESULT hr;
321
322     hr = IDirect3DDevice_GetDirect3D(device, &d3d);
323     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
324     hr = IDirect3D_CreateViewport(d3d, &viewport, NULL);
325     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
326     hr = IDirect3DDevice_AddViewport(device, viewport);
327     ok(SUCCEEDED(hr), "Failed to add viewport, hr %#x.\n", hr);
328     memset(&vp, 0, sizeof(vp));
329     vp.dwSize = sizeof(vp);
330     vp.dwX = x;
331     vp.dwY = y;
332     vp.dwWidth = w;
333     vp.dwHeight = h;
334     vp.dvScaleX = (float)w / 2.0f;
335     vp.dvScaleY = (float)h / 2.0f;
336     vp.dvMaxX = 1.0f;
337     vp.dvMaxY = 1.0f;
338     vp.dvMinZ = 0.0f;
339     vp.dvMaxZ = 1.0f;
340     hr = IDirect3DViewport_SetViewport(viewport, &vp);
341     ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#x.\n", hr);
342     IDirect3D_Release(d3d);
343
344     return viewport;
345 }
346
347 static void viewport_set_background(IDirect3DDevice *device, IDirect3DViewport *viewport,
348         IDirect3DMaterial *material)
349 {
350     D3DMATERIALHANDLE material_handle;
351     HRESULT hr;
352
353     hr = IDirect3DMaterial2_GetHandle(material, device, &material_handle);
354     ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
355     hr = IDirect3DViewport2_SetBackground(viewport, material_handle);
356     ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#x.\n", hr);
357 }
358
359 static void destroy_viewport(IDirect3DDevice *device, IDirect3DViewport *viewport)
360 {
361     HRESULT hr;
362
363     hr = IDirect3DDevice_DeleteViewport(device, viewport);
364     ok(SUCCEEDED(hr), "Failed to delete viewport, hr %#x.\n", hr);
365     IDirect3DViewport_Release(viewport);
366 }
367
368 static IDirect3DMaterial *create_diffuse_material(IDirect3DDevice *device, float r, float g, float b, float a)
369 {
370     IDirect3DMaterial *material;
371     D3DMATERIAL mat;
372     IDirect3D *d3d;
373     HRESULT hr;
374
375     hr = IDirect3DDevice_GetDirect3D(device, &d3d);
376     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
377     hr = IDirect3D_CreateMaterial(d3d, &material, NULL);
378     ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
379     memset(&mat, 0, sizeof(mat));
380     mat.dwSize = sizeof(mat);
381     U1(U(mat).diffuse).r = r;
382     U2(U(mat).diffuse).g = g;
383     U3(U(mat).diffuse).b = b;
384     U4(U(mat).diffuse).a = a;
385     hr = IDirect3DMaterial_SetMaterial(material, &mat);
386     ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
387     IDirect3D_Release(d3d);
388
389     return material;
390 }
391
392 static void destroy_material(IDirect3DMaterial *material)
393 {
394     IDirect3DMaterial_Release(material);
395 }
396
397 static const UINT *expect_messages;
398
399 static LRESULT CALLBACK test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
400 {
401     if (expect_messages && message == *expect_messages)
402         ++expect_messages;
403
404     return DefWindowProcA(hwnd, message, wparam, lparam);
405 }
406
407 /* Set the wndproc back to what ddraw expects it to be, and release the ddraw
408  * interface. This prevents subsequent SetCooperativeLevel() calls on a
409  * different window from failing with DDERR_HWNDALREADYSET. */
410 static void fix_wndproc(HWND window, LONG_PTR proc)
411 {
412     IDirectDraw *ddraw;
413     HRESULT hr;
414
415     if (!(ddraw = create_ddraw()))
416         return;
417
418     SetWindowLongPtrA(window, GWLP_WNDPROC, proc);
419     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
420     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
421     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
422     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
423
424     IDirectDraw_Release(ddraw);
425 }
426
427 static HRESULT CALLBACK restore_callback(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
428 {
429     HRESULT hr = IDirectDrawSurface_Restore(surface);
430     ok(SUCCEEDED(hr), "Failed to restore surface, hr %#x.\n", hr);
431     IDirectDrawSurface_Release(surface);
432
433     return DDENUMRET_OK;
434 }
435
436 static HRESULT restore_surfaces(IDirectDraw *ddraw)
437 {
438     return IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_ALL | DDENUMSURFACES_DOESEXIST,
439             NULL, NULL, restore_callback);
440 }
441
442 static void test_coop_level_create_device_window(void)
443 {
444     HWND focus_window, device_window;
445     IDirectDraw *ddraw;
446     HRESULT hr;
447
448     focus_window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
449             0, 0, 640, 480, 0, 0, 0, 0);
450     if (!(ddraw = create_ddraw()))
451     {
452         skip("Failed to create a ddraw object, skipping test.\n");
453         DestroyWindow(focus_window);
454         return;
455     }
456
457     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
458     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
459     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
460     ok(!device_window, "Unexpected device window found.\n");
461     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW);
462     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
463     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
464     ok(!device_window, "Unexpected device window found.\n");
465     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL);
466     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
467     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
468     ok(!device_window, "Unexpected device window found.\n");
469     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL | DDSCL_FULLSCREEN);
470     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
471     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
472     ok(!device_window, "Unexpected device window found.\n");
473     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
474     ok(hr == DDERR_NOFOCUSWINDOW || broken(hr == DDERR_INVALIDPARAMS), "Got unexpected hr %#x.\n", hr);
475     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
476     ok(!device_window, "Unexpected device window found.\n");
477
478     /* Windows versions before 98 / NT5 don't support DDSCL_CREATEDEVICEWINDOW. */
479     if (broken(hr == DDERR_INVALIDPARAMS))
480     {
481         win_skip("DDSCL_CREATEDEVICEWINDOW not supported, skipping test.\n");
482         IDirectDraw_Release(ddraw);
483         DestroyWindow(focus_window);
484         return;
485     }
486
487     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
488     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
489     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
490     ok(!device_window, "Unexpected device window found.\n");
491     hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
492     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
493     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
494     ok(!device_window, "Unexpected device window found.\n");
495
496     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
497     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
498     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
499     ok(!device_window, "Unexpected device window found.\n");
500     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_SETFOCUSWINDOW
501             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
502     ok(hr == DDERR_NOHWND, "Got unexpected hr %#x.\n", hr);
503     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
504     ok(!!device_window, "Device window not found.\n");
505
506     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
507     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
508     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
509     ok(!device_window, "Unexpected device window found.\n");
510     hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW
511             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
512     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
513     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
514     ok(!!device_window, "Device window not found.\n");
515
516     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
517     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
518     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
519     ok(!device_window, "Unexpected device window found.\n");
520     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
521     ok(hr == DDERR_NOFOCUSWINDOW, "Got unexpected hr %#x.\n", hr);
522     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
523     ok(!device_window, "Unexpected device window found.\n");
524     hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW);
525     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
526     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
527     ok(!device_window, "Unexpected device window found.\n");
528     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
529     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
530     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
531     ok(!!device_window, "Device window not found.\n");
532
533     IDirectDraw_Release(ddraw);
534     DestroyWindow(focus_window);
535 }
536
537 static void test_clipper_blt(void)
538 {
539     IDirectDrawSurface *src_surface, *dst_surface;
540     RECT client_rect, src_rect;
541     IDirectDrawClipper *clipper;
542     DDSURFACEDESC surface_desc;
543     unsigned int i, j, x, y;
544     IDirectDraw *ddraw;
545     RGNDATA *rgn_data;
546     D3DCOLOR color;
547     HRGN r1, r2;
548     HWND window;
549     DDBLTFX fx;
550     HRESULT hr;
551     DWORD *ptr;
552     DWORD ret;
553
554     static const DWORD src_data[] =
555     {
556         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
557         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
558         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
559     };
560     static const D3DCOLOR expected1[] =
561     {
562         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
563         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
564         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
565         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
566     };
567     static const D3DCOLOR expected2[] =
568     {
569         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
570         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
571         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
572         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
573     };
574
575     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
576             10, 10, 640, 480, 0, 0, 0, 0);
577     ShowWindow(window, SW_SHOW);
578     if (!(ddraw = create_ddraw()))
579     {
580         skip("Failed to create a ddraw object, skipping test.\n");
581         DestroyWindow(window);
582         return;
583     }
584
585     ret = GetClientRect(window, &client_rect);
586     ok(ret, "Failed to get client rect.\n");
587     ret = MapWindowPoints(window, NULL, (POINT *)&client_rect, 2);
588     ok(ret, "Failed to map client rect.\n");
589
590     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
591     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
592
593     hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
594     ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
595     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
596     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
597     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
598     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
599     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
600     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
601     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
602     hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret);
603     ok(SUCCEEDED(hr), "Failed to get clip list, hr %#x.\n", hr);
604     ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#x.\n", rgn_data->rdh.dwSize);
605     ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#x.\n", rgn_data->rdh.iType);
606     ok(rgn_data->rdh.nCount >= 1, "Got unexpected count %u.\n", rgn_data->rdh.nCount);
607     ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
608             "Got unexpected bounding rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
609             rgn_data->rdh.rcBound.left, rgn_data->rdh.rcBound.top,
610             rgn_data->rdh.rcBound.right, rgn_data->rdh.rcBound.bottom,
611             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
612     HeapFree(GetProcessHeap(), 0, rgn_data);
613
614     r1 = CreateRectRgn(0, 0, 320, 240);
615     ok(!!r1, "Failed to create region.\n");
616     r2 = CreateRectRgn(320, 240, 640, 480);
617     ok(!!r2, "Failed to create region.\n");
618     CombineRgn(r1, r1, r2, RGN_OR);
619     ret = GetRegionData(r1, 0, NULL);
620     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
621     ret = GetRegionData(r1, ret, rgn_data);
622     ok(!!ret, "Failed to get region data.\n");
623
624     DeleteObject(r2);
625     DeleteObject(r1);
626
627     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
628     ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#x.\n", hr);
629     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
630     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
631     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
632     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
633
634     HeapFree(GetProcessHeap(), 0, rgn_data);
635
636     memset(&surface_desc, 0, sizeof(surface_desc));
637     surface_desc.dwSize = sizeof(surface_desc);
638     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
639     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
640     surface_desc.dwWidth = 640;
641     surface_desc.dwHeight = 480;
642     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
643     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
644     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
645     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
646     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
647     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
648
649     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
650     ok(SUCCEEDED(hr), "Failed to create source surface, hr %#x.\n", hr);
651     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
652     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
653
654     memset(&fx, 0, sizeof(fx));
655     fx.dwSize = sizeof(fx);
656     hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
657     ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#x.\n", hr);
658     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
659     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
660
661     hr = IDirectDrawSurface_Lock(src_surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
662     ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#x.\n", hr);
663     ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %u.\n", U1(surface_desc).lPitch);
664     ptr = surface_desc.lpSurface;
665     memcpy(&ptr[   0], &src_data[ 0], 6 * sizeof(DWORD));
666     memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
667     memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
668     hr = IDirectDrawSurface_Unlock(src_surface, NULL);
669     ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#x.\n", hr);
670
671     hr = IDirectDrawSurface_SetClipper(dst_surface, clipper);
672     ok(SUCCEEDED(hr), "Failed to set clipper, hr %#x.\n", hr);
673
674     SetRect(&src_rect, 1, 1, 5, 2);
675     hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
676     ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
677     for (i = 0; i < 4; ++i)
678     {
679         for (j = 0; j < 4; ++j)
680         {
681             x = 80 * ((2 * j) + 1);
682             y = 60 * ((2 * i) + 1);
683             color = get_surface_color(dst_surface, x, y);
684             ok(compare_color(color, expected1[i * 4 + j], 1),
685                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
686         }
687     }
688
689     U5(fx).dwFillColor = 0xff0000ff;
690     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
691     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
692     for (i = 0; i < 4; ++i)
693     {
694         for (j = 0; j < 4; ++j)
695         {
696             x = 80 * ((2 * j) + 1);
697             y = 60 * ((2 * i) + 1);
698             color = get_surface_color(dst_surface, x, y);
699             ok(compare_color(color, expected2[i * 4 + j], 1),
700                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
701         }
702     }
703
704     hr = IDirectDrawSurface_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
705     ok(hr == DDERR_BLTFASTCANTCLIP || broken(hr == E_NOTIMPL /* NT4 */), "Got unexpected hr %#x.\n", hr);
706
707     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
708     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
709     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
710     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
711     DestroyWindow(window);
712     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
713     ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
714     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
715     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
716     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
717     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
718     hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
719     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
720     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
721     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
722     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
723     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
724
725     IDirectDrawSurface_Release(dst_surface);
726     IDirectDrawSurface_Release(src_surface);
727     IDirectDrawClipper_Release(clipper);
728     IDirectDraw_Release(ddraw);
729 }
730
731 static void test_coop_level_d3d_state(void)
732 {
733     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
734     IDirectDrawSurface *rt, *surface;
735     IDirect3DMaterial *background;
736     IDirect3DViewport *viewport;
737     IDirect3DDevice *device;
738     D3DMATERIAL material;
739     IDirectDraw *ddraw;
740     D3DCOLOR color;
741     HWND window;
742     HRESULT hr;
743
744     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
745             0, 0, 640, 480, 0, 0, 0, 0);
746     if (!(ddraw = create_ddraw()))
747     {
748         skip("Failed to create ddraw object, skipping test.\n");
749         DestroyWindow(window);
750         return;
751     }
752     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
753     {
754         skip("Failed to create D3D device, skipping test.\n");
755         IDirectDraw_Release(ddraw);
756         DestroyWindow(window);
757         return;
758     }
759
760     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
761     viewport = create_viewport(device, 0, 0, 640, 480);
762     viewport_set_background(device, viewport, background);
763
764     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
765     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
766     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
767     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
768     color = get_surface_color(rt, 320, 240);
769     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
770
771     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
772     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
773     hr = IDirectDrawSurface_IsLost(rt);
774     ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
775     hr = restore_surfaces(ddraw);
776     ok(SUCCEEDED(hr), "Failed to restore surfaces, hr %#x.\n", hr);
777
778     memset(&material, 0, sizeof(material));
779     material.dwSize = sizeof(material);
780     U1(U(material).diffuse).r = 0.0f;
781     U2(U(material).diffuse).g = 1.0f;
782     U3(U(material).diffuse).b = 0.0f;
783     U4(U(material).diffuse).a = 1.0f;
784     hr = IDirect3DMaterial_SetMaterial(background, &material);
785     ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
786
787     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&surface);
788     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
789     ok(surface == rt, "Got unexpected surface %p.\n", surface);
790     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
791     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
792     color = get_surface_color(rt, 320, 240);
793     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
794
795     destroy_viewport(device, viewport);
796     destroy_material(background);
797     IDirectDrawSurface_Release(surface);
798     IDirectDrawSurface_Release(rt);
799     IDirect3DDevice_Release(device);
800     IDirectDraw_Release(ddraw);
801     DestroyWindow(window);
802 }
803
804 static void test_surface_interface_mismatch(void)
805 {
806     IDirectDraw *ddraw = NULL;
807     IDirect3D *d3d = NULL;
808     IDirectDrawSurface *surface = NULL, *ds;
809     IDirectDrawSurface3 *surface3 = NULL;
810     IDirect3DDevice *device = NULL;
811     IDirect3DViewport *viewport = NULL;
812     IDirect3DMaterial *background = NULL;
813     DDSURFACEDESC surface_desc;
814     DWORD z_depth = 0;
815     ULONG refcount;
816     HRESULT hr;
817     D3DCOLOR color;
818     HWND window;
819     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
820
821     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
822             0, 0, 640, 480, 0, 0, 0, 0);
823
824     if (!(ddraw = create_ddraw()))
825     {
826         skip("Failed to create a ddraw object, skipping test.\n");
827         goto cleanup;
828     }
829
830     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
831     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
832
833     memset(&surface_desc, 0, sizeof(surface_desc));
834     surface_desc.dwSize = sizeof(surface_desc);
835     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
836     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
837     surface_desc.dwWidth = 640;
838     surface_desc.dwHeight = 480;
839
840     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
841     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
842
843     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
844     if (FAILED(hr))
845     {
846         skip("Failed to get the IDirectDrawSurface3 interface, skipping test.\n");
847         goto cleanup;
848     }
849
850     hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
851     if (FAILED(hr))
852     {
853         skip("Failed to get the IDirect3D interface, skipping test.\n");
854         goto cleanup;
855     }
856
857     hr = IDirect3D_EnumDevices(d3d, enum_z_fmt, &z_depth);
858     if (FAILED(hr) || !z_depth)
859     {
860         skip("No depth buffer formats available, skipping test.\n");
861         goto cleanup;
862     }
863
864     memset(&surface_desc, 0, sizeof(surface_desc));
865     surface_desc.dwSize = sizeof(surface_desc);
866     surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
867     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
868     U2(surface_desc).dwZBufferBitDepth = z_depth;
869     surface_desc.dwWidth = 640;
870     surface_desc.dwHeight = 480;
871     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &ds, NULL);
872     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
873     if (FAILED(hr))
874         goto cleanup;
875
876     /* Using a different surface interface version still works */
877     hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
878     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
879     refcount = IDirectDrawSurface_Release(ds);
880     ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
881     if (FAILED(hr))
882         goto cleanup;
883
884     /* Here too */
885     hr = IDirectDrawSurface3_QueryInterface(surface3, &IID_IDirect3DHALDevice, (void **)&device);
886     ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
887     if (FAILED(hr))
888         goto cleanup;
889
890     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
891     viewport = create_viewport(device, 0, 0, 640, 480);
892     viewport_set_background(device, viewport, background);
893
894     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
895     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
896     color = get_surface_color(surface, 320, 240);
897     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
898
899 cleanup:
900     if (viewport)
901         destroy_viewport(device, viewport);
902     if (background)
903         destroy_material(background);
904     if (surface3) IDirectDrawSurface3_Release(surface3);
905     if (surface) IDirectDrawSurface_Release(surface);
906     if (device) IDirect3DDevice_Release(device);
907     if (d3d) IDirect3D_Release(d3d);
908     if (ddraw) IDirectDraw_Release(ddraw);
909     DestroyWindow(window);
910 }
911
912 static void test_coop_level_threaded(void)
913 {
914     struct create_window_thread_param p;
915     IDirectDraw *ddraw;
916     HRESULT hr;
917
918     if (!(ddraw = create_ddraw()))
919     {
920         skip("Failed to create a ddraw object, skipping test.\n");
921         return;
922     }
923     create_window_thread(&p);
924
925     hr = IDirectDraw_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
926     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
927
928     IDirectDraw_Release(ddraw);
929     destroy_window_thread(&p);
930 }
931
932 static ULONG get_refcount(IUnknown *test_iface)
933 {
934     IUnknown_AddRef(test_iface);
935     return IUnknown_Release(test_iface);
936 }
937
938 static void test_viewport(void)
939 {
940     IDirectDraw *ddraw;
941     IDirect3D *d3d;
942     HRESULT hr;
943     ULONG ref;
944     IDirect3DViewport *viewport, *another_vp;
945     IDirect3DViewport2 *viewport2;
946     IDirect3DViewport3 *viewport3;
947     IDirectDrawGammaControl *gamma;
948     IUnknown *unknown;
949     IDirect3DDevice *device;
950     HWND window;
951
952     if (!(ddraw = create_ddraw()))
953     {
954         skip("Failed to create ddraw object, skipping test.\n");
955         return;
956     }
957     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
958             0, 0, 640, 480, 0, 0, 0, 0);
959     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
960     {
961         skip("Failed to create D3D device, skipping test.\n");
962         IDirectDraw_Release(ddraw);
963         DestroyWindow(window);
964         return;
965     }
966
967     hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
968     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
969     ref = get_refcount((IUnknown *) d3d);
970     ok(ref == 2, "IDirect3D refcount is %d\n", ref);
971
972     hr = IDirect3D_CreateViewport(d3d, &viewport, NULL);
973     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
974     ref = get_refcount((IUnknown *)viewport);
975     ok(ref == 1, "Initial IDirect3DViewport refcount is %u\n", ref);
976     ref = get_refcount((IUnknown *)d3d);
977     ok(ref == 2, "IDirect3D refcount is %u\n", ref);
978
979     /* E_FAIL return values are returned by Winetestbot Windows NT machines. While not supporting
980      * newer interfaces is legitimate for old ddraw versions, E_FAIL violates Microsoft's rules
981      * for QueryInterface, hence the broken() */
982     gamma = (IDirectDrawGammaControl *)0xdeadbeef;
983     hr = IDirect3DViewport_QueryInterface(viewport, &IID_IDirectDrawGammaControl, (void **)&gamma);
984     ok(hr == E_NOINTERFACE || broken(hr == E_FAIL), "Got unexpected hr %#x.\n", hr);
985     ok(gamma == NULL, "Interface not set to NULL by failed QI call: %p\n", gamma);
986     if (SUCCEEDED(hr)) IDirectDrawGammaControl_Release(gamma);
987     /* NULL iid: Segfaults */
988
989     hr = IDirect3DViewport_QueryInterface(viewport, &IID_IDirect3DViewport2, (void **)&viewport2);
990     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE || broken(hr == E_FAIL),
991             "Failed to QI IDirect3DViewport2, hr %#x.\n", hr);
992     if (viewport2)
993     {
994         ref = get_refcount((IUnknown *)viewport);
995         ok(ref == 2, "IDirect3DViewport refcount is %u\n", ref);
996         ref = get_refcount((IUnknown *)viewport2);
997         ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
998         IDirect3DViewport2_Release(viewport2);
999         viewport2 = NULL;
1000     }
1001
1002     hr = IDirect3DViewport_QueryInterface(viewport, &IID_IDirect3DViewport3, (void **)&viewport3);
1003     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE || broken(hr == E_FAIL),
1004             "Failed to QI IDirect3DViewport3, hr %#x.\n", hr);
1005     if (viewport3)
1006     {
1007         ref = get_refcount((IUnknown *)viewport);
1008         ok(ref == 2, "IDirect3DViewport refcount is %u\n", ref);
1009         ref = get_refcount((IUnknown *)viewport3);
1010         ok(ref == 2, "IDirect3DViewport3 refcount is %u\n", ref);
1011         IDirect3DViewport3_Release(viewport3);
1012     }
1013
1014     hr = IDirect3DViewport_QueryInterface(viewport, &IID_IUnknown, (void **)&unknown);
1015     ok(SUCCEEDED(hr), "Failed to QI IUnknown, hr %#x.\n", hr);
1016     if (unknown)
1017     {
1018         ref = get_refcount((IUnknown *)viewport);
1019         ok(ref == 2, "IDirect3DViewport refcount is %u\n", ref);
1020         ref = get_refcount(unknown);
1021         ok(ref == 2, "IUnknown refcount is %u\n", ref);
1022         IUnknown_Release(unknown);
1023     }
1024
1025     /* AddViewport(NULL): Segfault */
1026     hr = IDirect3DDevice_DeleteViewport(device, NULL);
1027     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
1028
1029     hr = IDirect3D_CreateViewport(d3d, &another_vp, NULL);
1030     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
1031
1032     hr = IDirect3DDevice_AddViewport(device, viewport);
1033     ok(SUCCEEDED(hr), "Failed to add viewport to device, hr %#x.\n", hr);
1034     ref = get_refcount((IUnknown *) viewport);
1035     ok(ref == 2, "IDirect3DViewport refcount is %d\n", ref);
1036     hr = IDirect3DDevice_AddViewport(device, another_vp);
1037     ok(SUCCEEDED(hr), "Failed to add viewport to device, hr %#x.\n", hr);
1038     ref = get_refcount((IUnknown *) another_vp);
1039     ok(ref == 2, "IDirect3DViewport refcount is %d\n", ref);
1040
1041     hr = IDirect3DDevice_DeleteViewport(device, another_vp);
1042     ok(SUCCEEDED(hr), "Failed to delete viewport from device, hr %#x.\n", hr);
1043     ref = get_refcount((IUnknown *) another_vp);
1044     ok(ref == 1, "IDirect3DViewport refcount is %d\n", ref);
1045
1046     IDirect3DDevice_Release(device);
1047     ref = get_refcount((IUnknown *) viewport);
1048     ok(ref == 1, "IDirect3DViewport refcount is %d\n", ref);
1049
1050     IDirect3DViewport_Release(another_vp);
1051     IDirect3D_Release(d3d);
1052     IDirect3DViewport_Release(viewport);
1053     DestroyWindow(window);
1054     IDirectDraw_Release(ddraw);
1055 }
1056
1057 static void test_zenable(void)
1058 {
1059     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1060     static D3DTLVERTEX tquad[] =
1061     {
1062         {{  0.0f}, {480.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1063         {{  0.0f}, {  0.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1064         {{640.0f}, {480.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1065         {{640.0f}, {  0.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1066     };
1067     IDirect3DExecuteBuffer *execute_buffer;
1068     D3DEXECUTEBUFFERDESC exec_desc;
1069     IDirect3DMaterial *background;
1070     IDirect3DViewport *viewport;
1071     IDirect3DDevice *device;
1072     IDirectDrawSurface *rt;
1073     IDirectDraw *ddraw;
1074     UINT inst_length;
1075     D3DCOLOR color;
1076     HWND window;
1077     HRESULT hr;
1078     UINT x, y;
1079     UINT i, j;
1080     void *ptr;
1081
1082     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1083             0, 0, 640, 480, 0, 0, 0, 0);
1084     if (!(ddraw = create_ddraw()))
1085     {
1086         skip("Failed to create ddraw object, skipping test.\n");
1087         DestroyWindow(window);
1088         return;
1089     }
1090     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1091     {
1092         skip("Failed to create D3D device, skipping test.\n");
1093         IDirectDraw_Release(ddraw);
1094         DestroyWindow(window);
1095         return;
1096     }
1097
1098     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1099     viewport = create_viewport(device, 0, 0, 640, 480);
1100     viewport_set_background(device, viewport, background);
1101
1102     memset(&exec_desc, 0, sizeof(exec_desc));
1103     exec_desc.dwSize = sizeof(exec_desc);
1104     exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
1105     exec_desc.dwBufferSize = 1024;
1106     exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
1107
1108     hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
1109     ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#x.\n", hr);
1110     hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
1111     ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr);
1112     memcpy(exec_desc.lpData, tquad, sizeof(tquad));
1113     ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad);
1114     emit_process_vertices(&ptr, 0, 4);
1115     emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1116     emit_tquad(&ptr, 0);
1117     emit_end(&ptr);
1118     inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
1119     inst_length -= sizeof(tquad);
1120     hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
1121     ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#x.\n", hr);
1122
1123     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1124     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1125     hr = IDirect3DDevice_BeginScene(device);
1126     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1127     set_execute_data(execute_buffer, 4, sizeof(tquad), inst_length);
1128     hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1129     ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
1130     hr = IDirect3DDevice_EndScene(device);
1131     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1132
1133     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
1134     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1135     for (i = 0; i < 4; ++i)
1136     {
1137         for (j = 0; j < 4; ++j)
1138         {
1139             x = 80 * ((2 * j) + 1);
1140             y = 60 * ((2 * i) + 1);
1141             color = get_surface_color(rt, x, y);
1142             ok(compare_color(color, 0x0000ff00, 1),
1143                     "Expected color 0x0000ff00 at %u, %u, got 0x%08x.\n", x, y, color);
1144         }
1145     }
1146     IDirectDrawSurface_Release(rt);
1147
1148     destroy_viewport(device, viewport);
1149     IDirect3DExecuteBuffer_Release(execute_buffer);
1150     destroy_material(background);
1151     IDirect3DDevice_Release(device);
1152     IDirectDraw_Release(ddraw);
1153     DestroyWindow(window);
1154 }
1155
1156 static void test_ck_rgba(void)
1157 {
1158     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1159     static D3DTLVERTEX tquad[] =
1160     {
1161         {{  0.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1162         {{  0.0f}, {  0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1163         {{640.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1164         {{640.0f}, {  0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1165         {{  0.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1166         {{  0.0f}, {  0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1167         {{640.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1168         {{640.0f}, {  0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1169     };
1170     static const struct
1171     {
1172         D3DCOLOR fill_color;
1173         BOOL color_key;
1174         BOOL blend;
1175         D3DCOLOR result1;
1176         D3DCOLOR result2;
1177     }
1178     tests[] =
1179     {
1180         {0xff00ff00, TRUE,  TRUE,  0x00ff0000, 0x000000ff},
1181         {0xff00ff00, TRUE,  FALSE, 0x00ff0000, 0x000000ff},
1182         {0xff00ff00, FALSE, TRUE,  0x0000ff00, 0x0000ff00},
1183         {0xff00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1184         {0x7f00ff00, TRUE,  TRUE,  0x00807f00, 0x00807f00},
1185         {0x7f00ff00, TRUE,  FALSE, 0x0000ff00, 0x0000ff00},
1186         {0x7f00ff00, FALSE, TRUE,  0x00807f00, 0x00807f00},
1187         {0x7f00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1188     };
1189
1190     IDirect3DExecuteBuffer *execute_buffer;
1191     D3DTEXTUREHANDLE texture_handle;
1192     D3DEXECUTEBUFFERDESC exec_desc;
1193     IDirect3DMaterial *background;
1194     IDirectDrawSurface *surface;
1195     IDirect3DViewport *viewport;
1196     DDSURFACEDESC surface_desc;
1197     IDirect3DTexture *texture;
1198     IDirect3DDevice *device;
1199     IDirectDrawSurface *rt;
1200     IDirectDraw *ddraw;
1201     D3DCOLOR color;
1202     HWND window;
1203     DDBLTFX fx;
1204     HRESULT hr;
1205     UINT i;
1206
1207     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1208             0, 0, 640, 480, 0, 0, 0, 0);
1209     if (!(ddraw = create_ddraw()))
1210     {
1211         skip("Failed to create ddraw object, skipping test.\n");
1212         DestroyWindow(window);
1213         return;
1214     }
1215     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1216     {
1217         skip("Failed to create D3D device, skipping test.\n");
1218         IDirectDraw_Release(ddraw);
1219         DestroyWindow(window);
1220         return;
1221     }
1222
1223     background = create_diffuse_material(device, 1.0, 0.0f, 0.0f, 1.0f);
1224     viewport = create_viewport(device, 0, 0, 640, 480);
1225     viewport_set_background(device, viewport, background);
1226
1227     memset(&surface_desc, 0, sizeof(surface_desc));
1228     surface_desc.dwSize = sizeof(surface_desc);
1229     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1230     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1231     surface_desc.dwWidth = 256;
1232     surface_desc.dwHeight = 256;
1233     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1234     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
1235     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1236     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1237     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1238     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1239     U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
1240     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0xff00ff00;
1241     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0xff00ff00;
1242     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1243     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
1244     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture, (void **)&texture);
1245     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1246     hr = IDirect3DTexture_GetHandle(texture, device, &texture_handle);
1247     ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1248     IDirect3DTexture_Release(texture);
1249
1250     memset(&exec_desc, 0, sizeof(exec_desc));
1251     exec_desc.dwSize = sizeof(exec_desc);
1252     exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
1253     exec_desc.dwBufferSize = 1024;
1254     exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
1255     hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
1256     ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#x.\n", hr);
1257
1258     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
1259     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1260
1261     for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
1262     {
1263         UINT draw1_len, draw2_len;
1264         void *ptr;
1265
1266         hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
1267         ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr);
1268         memcpy(exec_desc.lpData, tquad, sizeof(tquad));
1269         ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad);
1270         emit_process_vertices(&ptr, 0, 4);
1271         emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1272         emit_set_rs(&ptr, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
1273         emit_set_rs(&ptr, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
1274         emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, tests[i].color_key);
1275         emit_set_rs(&ptr, D3DRENDERSTATE_ALPHABLENDENABLE, tests[i].blend);
1276         emit_tquad(&ptr, 0);
1277         emit_end(&ptr);
1278         draw1_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - sizeof(tquad);
1279         emit_process_vertices(&ptr, 4, 4);
1280         emit_tquad(&ptr, 0);
1281         emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1282         emit_end(&ptr);
1283         draw2_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw1_len;
1284         hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
1285         ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#x.\n", hr);
1286
1287         memset(&fx, 0, sizeof(fx));
1288         fx.dwSize = sizeof(fx);
1289         U5(fx).dwFillColor = tests[i].fill_color;
1290         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1291         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1292
1293         hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
1294         ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1295         hr = IDirect3DDevice_BeginScene(device);
1296         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1297         set_execute_data(execute_buffer, 8, sizeof(tquad), draw1_len);
1298         hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1299         ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
1300         hr = IDirect3DDevice_EndScene(device);
1301         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1302
1303         color = get_surface_color(rt, 320, 240);
1304         if (i == 2)
1305             todo_wine ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1306                     tests[i].result1, i, color);
1307         else
1308             ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1309                     tests[i].result1, i, color);
1310
1311         U5(fx).dwFillColor = 0xff0000ff;
1312         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1313         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1314
1315         hr = IDirect3DDevice_BeginScene(device);
1316         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1317         set_execute_data(execute_buffer, 8, sizeof(tquad) + draw1_len, draw2_len);
1318         hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1319         ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
1320         hr = IDirect3DDevice_EndScene(device);
1321         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1322
1323         /* This tests that fragments that are masked out by the color key are
1324          * discarded, instead of just fully transparent. */
1325         color = get_surface_color(rt, 320, 240);
1326         if (i == 2)
1327             todo_wine ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1328                     tests[i].result2, i, color);
1329         else
1330             ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1331                     tests[i].result2, i, color);
1332     }
1333
1334     IDirectDrawSurface_Release(rt);
1335     IDirect3DExecuteBuffer_Release(execute_buffer);
1336     IDirectDrawSurface_Release(surface);
1337     destroy_viewport(device, viewport);
1338     destroy_material(background);
1339     IDirect3DDevice_Release(device);
1340     IDirectDraw_Release(ddraw);
1341     DestroyWindow(window);
1342 }
1343
1344 static void test_ck_default(void)
1345 {
1346     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1347     static D3DTLVERTEX tquad[] =
1348     {
1349         {{  0.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1350         {{  0.0f}, {  0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1351         {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1352         {{640.0f}, {  0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1353     };
1354     IDirect3DExecuteBuffer *execute_buffer;
1355     IDirectDrawSurface *surface, *rt;
1356     D3DTEXTUREHANDLE texture_handle;
1357     D3DEXECUTEBUFFERDESC exec_desc;
1358     IDirect3DMaterial *background;
1359     UINT draw1_offset, draw1_len;
1360     UINT draw2_offset, draw2_len;
1361     UINT draw3_offset, draw3_len;
1362     UINT draw4_offset, draw4_len;
1363     IDirect3DViewport *viewport;
1364     DDSURFACEDESC surface_desc;
1365     IDirect3DTexture *texture;
1366     IDirect3DDevice *device;
1367     IDirectDraw *ddraw;
1368     D3DCOLOR color;
1369     HWND window;
1370     DDBLTFX fx;
1371     HRESULT hr;
1372     void *ptr;
1373
1374     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1375             0, 0, 640, 480, 0, 0, 0, 0);
1376
1377     if (!(ddraw = create_ddraw()))
1378     {
1379         skip("Failed to create ddraw object, skipping test.\n");
1380         DestroyWindow(window);
1381         return;
1382     }
1383     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1384     {
1385         skip("Failed to create D3D device, skipping test.\n");
1386         IDirectDraw_Release(ddraw);
1387         DestroyWindow(window);
1388         return;
1389     }
1390
1391     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
1392     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1393
1394     background = create_diffuse_material(device, 0.0, 1.0f, 0.0f, 1.0f);
1395     viewport = create_viewport(device, 0, 0, 640, 480);
1396     viewport_set_background(device, viewport, background);
1397
1398     memset(&surface_desc, 0, sizeof(surface_desc));
1399     surface_desc.dwSize = sizeof(surface_desc);
1400     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1401     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1402     surface_desc.dwWidth = 256;
1403     surface_desc.dwHeight = 256;
1404     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1405     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
1406     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1407     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1408     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1409     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1410     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x000000ff;
1411     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x000000ff;
1412     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1413     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1414     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture, (void **)&texture);
1415     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1416     hr = IDirect3DTexture_GetHandle(texture, device, &texture_handle);
1417     ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1418     IDirect3DTexture_Release(texture);
1419
1420     memset(&fx, 0, sizeof(fx));
1421     fx.dwSize = sizeof(fx);
1422     U5(fx).dwFillColor = 0x000000ff;
1423     hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1424     ok(SUCCEEDED(hr), "Failed to fill surface, hr %#x.\n", hr);
1425
1426     memset(&exec_desc, 0, sizeof(exec_desc));
1427     exec_desc.dwSize = sizeof(exec_desc);
1428     exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
1429     exec_desc.dwBufferSize = 1024;
1430     exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
1431     hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
1432     ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#x.\n", hr);
1433
1434     hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
1435     ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr);
1436     memcpy(exec_desc.lpData, tquad, sizeof(tquad));
1437     ptr = (BYTE *)exec_desc.lpData + sizeof(tquad);
1438     emit_process_vertices(&ptr, 0, 4);
1439     emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1440     emit_tquad(&ptr, 0);
1441     emit_end(&ptr);
1442     draw1_offset = sizeof(tquad);
1443     draw1_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw1_offset;
1444     emit_process_vertices(&ptr, 0, 4);
1445     emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, FALSE);
1446     emit_tquad(&ptr, 0);
1447     emit_end(&ptr);
1448     draw2_offset = draw1_offset + draw1_len;
1449     draw2_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw2_offset;
1450     emit_process_vertices(&ptr, 0, 4);
1451     emit_tquad(&ptr, 0);
1452     emit_end(&ptr);
1453     draw3_offset = draw2_offset + draw2_len;
1454     draw3_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw3_offset;
1455     emit_process_vertices(&ptr, 0, 4);
1456     emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
1457     emit_tquad(&ptr, 0);
1458     emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1459     emit_end(&ptr);
1460     draw4_offset = draw3_offset + draw3_len;
1461     draw4_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw4_offset;
1462     hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
1463     ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#x.\n", hr);
1464
1465     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1466     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1467     hr = IDirect3DDevice_BeginScene(device);
1468     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1469     set_execute_data(execute_buffer, 4, draw1_offset, draw1_len);
1470     hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1471     ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
1472     hr = IDirect3DDevice_EndScene(device);
1473     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1474     color = get_surface_color(rt, 320, 240);
1475     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
1476
1477     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1478     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1479     hr = IDirect3DDevice_BeginScene(device);
1480     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1481     set_execute_data(execute_buffer, 4, draw2_offset, draw2_len);
1482     hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1483     ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
1484     hr = IDirect3DDevice_EndScene(device);
1485     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1486     color = get_surface_color(rt, 320, 240);
1487     ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
1488
1489     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1490     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1491     hr = IDirect3DDevice_BeginScene(device);
1492     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1493     set_execute_data(execute_buffer, 4, draw3_offset, draw3_len);
1494     hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1495     ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
1496     hr = IDirect3DDevice_EndScene(device);
1497     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1498     color = get_surface_color(rt, 320, 240);
1499     ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
1500
1501     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1502     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1503     hr = IDirect3DDevice_BeginScene(device);
1504     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1505     set_execute_data(execute_buffer, 4, draw4_offset, draw4_len);
1506     hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1507     ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
1508     hr = IDirect3DDevice_EndScene(device);
1509     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1510     color = get_surface_color(rt, 320, 240);
1511     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
1512
1513     IDirect3DExecuteBuffer_Release(execute_buffer);
1514     IDirectDrawSurface_Release(surface);
1515     destroy_viewport(device, viewport);
1516     destroy_material(background);
1517     IDirectDrawSurface_Release(rt);
1518     IDirect3DDevice_Release(device);
1519     IDirectDraw_Release(ddraw);
1520     DestroyWindow(window);
1521 }
1522
1523 struct qi_test
1524 {
1525     REFIID iid;
1526     REFIID refcount_iid;
1527     HRESULT hr;
1528 };
1529
1530 static void test_qi(const char *test_name, IUnknown *base_iface,
1531         REFIID refcount_iid, const struct qi_test *tests, UINT entry_count)
1532 {
1533     ULONG refcount, expected_refcount;
1534     IUnknown *iface1, *iface2;
1535     HRESULT hr;
1536     UINT i, j;
1537
1538     for (i = 0; i < entry_count; ++i)
1539     {
1540         hr = IUnknown_QueryInterface(base_iface, tests[i].iid, (void **)&iface1);
1541         ok(hr == tests[i].hr, "Got hr %#x for test \"%s\" %u.\n", hr, test_name, i);
1542         if (SUCCEEDED(hr))
1543         {
1544             for (j = 0; j < entry_count; ++j)
1545             {
1546                 hr = IUnknown_QueryInterface(iface1, tests[j].iid, (void **)&iface2);
1547                 ok(hr == tests[j].hr, "Got hr %#x for test \"%s\" %u, %u.\n", hr, test_name, i, j);
1548                 if (SUCCEEDED(hr))
1549                 {
1550                     expected_refcount = 0;
1551                     if (IsEqualGUID(refcount_iid, tests[j].refcount_iid))
1552                         ++expected_refcount;
1553                     if (IsEqualGUID(tests[i].refcount_iid, tests[j].refcount_iid))
1554                         ++expected_refcount;
1555                     refcount = IUnknown_Release(iface2);
1556                     ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, %u, expected %u.\n",
1557                             refcount, test_name, i, j, expected_refcount);
1558                 }
1559             }
1560
1561             expected_refcount = 0;
1562             if (IsEqualGUID(refcount_iid, tests[i].refcount_iid))
1563                 ++expected_refcount;
1564             refcount = IUnknown_Release(iface1);
1565             ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, expected %u.\n",
1566                     refcount, test_name, i, expected_refcount);
1567         }
1568     }
1569 }
1570
1571 static void test_surface_qi(void)
1572 {
1573     static const struct qi_test tests[] =
1574     {
1575         {&IID_IDirect3DTexture2,        &IID_IDirectDrawSurface,        S_OK         },
1576         {&IID_IDirect3DTexture,         &IID_IDirectDrawSurface,        S_OK         },
1577         {&IID_IDirectDrawGammaControl,  &IID_IDirectDrawGammaControl,   S_OK         },
1578         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1579         {&IID_IDirectDrawSurface7,      &IID_IDirectDrawSurface7,       S_OK         },
1580         {&IID_IDirectDrawSurface4,      &IID_IDirectDrawSurface4,       S_OK         },
1581         {&IID_IDirectDrawSurface3,      &IID_IDirectDrawSurface3,       S_OK         },
1582         {&IID_IDirectDrawSurface2,      &IID_IDirectDrawSurface2,       S_OK         },
1583         {&IID_IDirectDrawSurface,       &IID_IDirectDrawSurface,        S_OK         },
1584         {&IID_IDirect3DDevice7,         NULL,                           E_INVALIDARG },
1585         {&IID_IDirect3DDevice3,         NULL,                           E_INVALIDARG },
1586         {&IID_IDirect3DDevice2,         NULL,                           E_INVALIDARG },
1587         {&IID_IDirect3DDevice,          NULL,                           E_INVALIDARG },
1588         {&IID_IDirect3D7,               NULL,                           E_INVALIDARG },
1589         {&IID_IDirect3D3,               NULL,                           E_INVALIDARG },
1590         {&IID_IDirect3D2,               NULL,                           E_INVALIDARG },
1591         {&IID_IDirect3D,                NULL,                           E_INVALIDARG },
1592         {&IID_IDirectDraw7,             NULL,                           E_INVALIDARG },
1593         {&IID_IDirectDraw4,             NULL,                           E_INVALIDARG },
1594         {&IID_IDirectDraw3,             NULL,                           E_INVALIDARG },
1595         {&IID_IDirectDraw2,             NULL,                           E_INVALIDARG },
1596         {&IID_IDirectDraw,              NULL,                           E_INVALIDARG },
1597         {&IID_IDirect3DLight,           NULL,                           E_INVALIDARG },
1598         {&IID_IDirect3DMaterial,        NULL,                           E_INVALIDARG },
1599         {&IID_IDirect3DMaterial2,       NULL,                           E_INVALIDARG },
1600         {&IID_IDirect3DMaterial3,       NULL,                           E_INVALIDARG },
1601         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_INVALIDARG },
1602         {&IID_IDirect3DViewport,        NULL,                           E_INVALIDARG },
1603         {&IID_IDirect3DViewport2,       NULL,                           E_INVALIDARG },
1604         {&IID_IDirect3DViewport3,       NULL,                           E_INVALIDARG },
1605         {&IID_IDirect3DVertexBuffer,    NULL,                           E_INVALIDARG },
1606         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_INVALIDARG },
1607         {&IID_IDirectDrawPalette,       NULL,                           E_INVALIDARG },
1608         {&IID_IDirectDrawClipper,       NULL,                           E_INVALIDARG },
1609         {&IID_IUnknown,                 &IID_IDirectDrawSurface,        S_OK         },
1610     };
1611
1612     IDirectDrawSurface *surface;
1613     DDSURFACEDESC surface_desc;
1614     IDirect3DDevice *device;
1615     IDirectDraw *ddraw;
1616     HWND window;
1617     HRESULT hr;
1618
1619     if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
1620     {
1621         win_skip("DirectDrawCreateEx not available, skipping test.\n");
1622         return;
1623     }
1624
1625     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1626             0, 0, 640, 480, 0, 0, 0, 0);
1627     if (!(ddraw = create_ddraw()))
1628     {
1629         skip("Failed to create a ddraw object, skipping test.\n");
1630         DestroyWindow(window);
1631         return;
1632     }
1633     /* Try to create a D3D device to see if the ddraw implementation supports
1634      * D3D. 64-bit ddraw in particular doesn't seem to support D3D, and
1635      * doesn't support e.g. the IDirect3DTexture interfaces. */
1636     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1637     {
1638         skip("Failed to create D3D device, skipping test.\n");
1639         IDirectDraw_Release(ddraw);
1640         DestroyWindow(window);
1641         return;
1642     }
1643     IDirect3DDevice_Release(device);
1644
1645     memset(&surface_desc, 0, sizeof(surface_desc));
1646     surface_desc.dwSize = sizeof(surface_desc);
1647     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1648     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1649     surface_desc.dwWidth = 512;
1650     surface_desc.dwHeight = 512;
1651     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1652     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1653
1654     test_qi("surface_qi", (IUnknown *)surface, &IID_IDirectDrawSurface, tests, sizeof(tests) / sizeof(*tests));
1655
1656     IDirectDrawSurface_Release(surface);
1657     IDirectDraw_Release(ddraw);
1658     DestroyWindow(window);
1659 }
1660
1661 static void test_device_qi(void)
1662 {
1663     static const struct qi_test tests[] =
1664     {
1665         {&IID_IDirect3DTexture2,        &IID_IDirectDrawSurface,        S_OK         },
1666         {&IID_IDirect3DTexture,         &IID_IDirectDrawSurface,        S_OK         },
1667         {&IID_IDirectDrawGammaControl,  &IID_IDirectDrawGammaControl,   S_OK         },
1668         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1669         {&IID_IDirectDrawSurface7,      &IID_IDirectDrawSurface7,       S_OK         },
1670         {&IID_IDirectDrawSurface4,      &IID_IDirectDrawSurface4,       S_OK         },
1671         {&IID_IDirectDrawSurface3,      &IID_IDirectDrawSurface3,       S_OK         },
1672         {&IID_IDirectDrawSurface2,      &IID_IDirectDrawSurface2,       S_OK         },
1673         {&IID_IDirectDrawSurface,       &IID_IDirectDrawSurface,        S_OK         },
1674         {&IID_IDirect3DDevice7,         NULL,                           E_INVALIDARG },
1675         {&IID_IDirect3DDevice3,         NULL,                           E_INVALIDARG },
1676         {&IID_IDirect3DDevice2,         NULL,                           E_INVALIDARG },
1677         {&IID_IDirect3DDevice,          NULL,                           E_INVALIDARG },
1678         {&IID_IDirect3DHALDevice,       &IID_IDirectDrawSurface,        S_OK         },
1679         {&IID_IDirect3D7,               NULL,                           E_INVALIDARG },
1680         {&IID_IDirect3D3,               NULL,                           E_INVALIDARG },
1681         {&IID_IDirect3D2,               NULL,                           E_INVALIDARG },
1682         {&IID_IDirect3D,                NULL,                           E_INVALIDARG },
1683         {&IID_IDirectDraw7,             NULL,                           E_INVALIDARG },
1684         {&IID_IDirectDraw4,             NULL,                           E_INVALIDARG },
1685         {&IID_IDirectDraw3,             NULL,                           E_INVALIDARG },
1686         {&IID_IDirectDraw2,             NULL,                           E_INVALIDARG },
1687         {&IID_IDirectDraw,              NULL,                           E_INVALIDARG },
1688         {&IID_IDirect3DLight,           NULL,                           E_INVALIDARG },
1689         {&IID_IDirect3DMaterial,        NULL,                           E_INVALIDARG },
1690         {&IID_IDirect3DMaterial2,       NULL,                           E_INVALIDARG },
1691         {&IID_IDirect3DMaterial3,       NULL,                           E_INVALIDARG },
1692         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_INVALIDARG },
1693         {&IID_IDirect3DViewport,        NULL,                           E_INVALIDARG },
1694         {&IID_IDirect3DViewport2,       NULL,                           E_INVALIDARG },
1695         {&IID_IDirect3DViewport3,       NULL,                           E_INVALIDARG },
1696         {&IID_IDirect3DVertexBuffer,    NULL,                           E_INVALIDARG },
1697         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_INVALIDARG },
1698         {&IID_IDirectDrawPalette,       NULL,                           E_INVALIDARG },
1699         {&IID_IDirectDrawClipper,       NULL,                           E_INVALIDARG },
1700         {&IID_IUnknown,                 &IID_IDirectDrawSurface,        S_OK         },
1701     };
1702
1703
1704     IDirect3DDevice *device;
1705     IDirectDraw *ddraw;
1706     HWND window;
1707
1708     if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
1709     {
1710         win_skip("DirectDrawCreateEx not available, skipping test.\n");
1711         return;
1712     }
1713
1714     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1715             0, 0, 640, 480, 0, 0, 0, 0);
1716     if (!(ddraw = create_ddraw()))
1717     {
1718         skip("Failed to create ddraw object, skipping test.\n");
1719         DestroyWindow(window);
1720         return;
1721     }
1722     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1723     {
1724         skip("Failed to create D3D device, skipping test.\n");
1725         IDirectDraw_Release(ddraw);
1726         DestroyWindow(window);
1727         return;
1728     }
1729
1730     test_qi("device_qi", (IUnknown *)device, &IID_IDirectDrawSurface, tests, sizeof(tests) / sizeof(*tests));
1731
1732     IDirect3DDevice_Release(device);
1733     IDirectDraw_Release(ddraw);
1734     DestroyWindow(window);
1735 }
1736
1737 static void test_wndproc(void)
1738 {
1739     LONG_PTR proc, ddraw_proc;
1740     IDirectDraw *ddraw;
1741     WNDCLASSA wc = {0};
1742     HWND window;
1743     HRESULT hr;
1744     ULONG ref;
1745
1746     static const UINT messages[] =
1747     {
1748         WM_WINDOWPOSCHANGING,
1749         WM_MOVE,
1750         WM_SIZE,
1751         WM_WINDOWPOSCHANGING,
1752         WM_ACTIVATE,
1753         WM_SETFOCUS,
1754         0,
1755     };
1756
1757     /* DDSCL_EXCLUSIVE replaces the window's window proc. */
1758     if (!(ddraw = create_ddraw()))
1759     {
1760         skip("Failed to create IDirectDraw object, skipping tests.\n");
1761         return;
1762     }
1763
1764     wc.lpfnWndProc = test_proc;
1765     wc.lpszClassName = "ddraw_test_wndproc_wc";
1766     ok(RegisterClassA(&wc), "Failed to register window class.\n");
1767
1768     window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test",
1769             WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
1770
1771     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1772     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1773             (LONG_PTR)test_proc, proc);
1774     expect_messages = messages;
1775     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1776     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1777     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
1778     expect_messages = NULL;
1779     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1780     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1781             (LONG_PTR)test_proc, proc);
1782     ref = IDirectDraw_Release(ddraw);
1783     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1784     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1785     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1786             (LONG_PTR)test_proc, proc);
1787
1788     /* DDSCL_NORMAL doesn't. */
1789     ddraw = create_ddraw();
1790     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1791     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1792             (LONG_PTR)test_proc, proc);
1793     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
1794     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1795     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1796     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1797             (LONG_PTR)test_proc, proc);
1798     ref = IDirectDraw_Release(ddraw);
1799     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1800     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1801     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1802             (LONG_PTR)test_proc, proc);
1803
1804     /* The original window proc is only restored by ddraw if the current
1805      * window proc matches the one ddraw set. This also affects switching
1806      * from DDSCL_NORMAL to DDSCL_EXCLUSIVE. */
1807     ddraw = create_ddraw();
1808     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1809     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1810             (LONG_PTR)test_proc, proc);
1811     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1812     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1813     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1814     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1815             (LONG_PTR)test_proc, proc);
1816     ddraw_proc = proc;
1817     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
1818     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1819     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1820     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1821             (LONG_PTR)test_proc, proc);
1822     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1823     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1824     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
1825     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1826             (LONG_PTR)test_proc, proc);
1827     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
1828     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1829     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1830     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
1831             (LONG_PTR)DefWindowProcA, proc);
1832     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1833     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1834     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)ddraw_proc);
1835     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
1836             (LONG_PTR)DefWindowProcA, proc);
1837     ref = IDirectDraw_Release(ddraw);
1838     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1839     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1840     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1841             (LONG_PTR)test_proc, proc);
1842
1843     ddraw = create_ddraw();
1844     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1845     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1846             (LONG_PTR)test_proc, proc);
1847     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1848     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1849     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
1850     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1851             (LONG_PTR)test_proc, proc);
1852     ref = IDirectDraw_Release(ddraw);
1853     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1854     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1855     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
1856             (LONG_PTR)DefWindowProcA, proc);
1857
1858     fix_wndproc(window, (LONG_PTR)test_proc);
1859     expect_messages = NULL;
1860     DestroyWindow(window);
1861     UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
1862 }
1863
1864 static void test_window_style(void)
1865 {
1866     LONG style, exstyle, tmp;
1867     RECT fullscreen_rect, r;
1868     IDirectDraw *ddraw;
1869     HWND window;
1870     HRESULT hr;
1871     ULONG ref;
1872
1873     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1874             0, 0, 100, 100, 0, 0, 0, 0);
1875     if (!(ddraw = create_ddraw()))
1876     {
1877         skip("Failed to create a ddraw object, skipping test.\n");
1878         DestroyWindow(window);
1879         return;
1880     }
1881
1882     style = GetWindowLongA(window, GWL_STYLE);
1883     exstyle = GetWindowLongA(window, GWL_EXSTYLE);
1884     SetRect(&fullscreen_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1885
1886     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1887     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1888
1889     tmp = GetWindowLongA(window, GWL_STYLE);
1890     todo_wine ok(tmp == style, "Expected window style %#x, got %#x.\n", style, tmp);
1891     tmp = GetWindowLongA(window, GWL_EXSTYLE);
1892     todo_wine ok(tmp == exstyle, "Expected window extended style %#x, got %#x.\n", exstyle, tmp);
1893
1894     GetWindowRect(window, &r);
1895     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
1896             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
1897             r.left, r.top, r.right, r.bottom);
1898     GetClientRect(window, &r);
1899     todo_wine ok(!EqualRect(&r, &fullscreen_rect), "Client rect and window rect are equal.\n");
1900
1901     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
1902     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1903
1904     tmp = GetWindowLongA(window, GWL_STYLE);
1905     todo_wine ok(tmp == style, "Expected window style %#x, got %#x.\n", style, tmp);
1906     tmp = GetWindowLongA(window, GWL_EXSTYLE);
1907     todo_wine ok(tmp == exstyle, "Expected window extended style %#x, got %#x.\n", exstyle, tmp);
1908
1909     ref = IDirectDraw_Release(ddraw);
1910     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1911
1912     DestroyWindow(window);
1913 }
1914
1915 static void test_redundant_mode_set(void)
1916 {
1917     DDSURFACEDESC surface_desc = {0};
1918     IDirectDraw *ddraw;
1919     HWND window;
1920     HRESULT hr;
1921     RECT r, s;
1922     ULONG ref;
1923
1924     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1925             0, 0, 100, 100, 0, 0, 0, 0);
1926     if (!(ddraw = create_ddraw()))
1927     {
1928         skip("Failed to create a ddraw object, skipping test.\n");
1929         DestroyWindow(window);
1930         return;
1931     }
1932
1933     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1934     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1935
1936     surface_desc.dwSize = sizeof(surface_desc);
1937     hr = IDirectDraw_GetDisplayMode(ddraw, &surface_desc);
1938     ok(SUCCEEDED(hr), "GetDipslayMode failed, hr %#x.\n", hr);
1939
1940     hr = IDirectDraw_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
1941             U1(surface_desc.ddpfPixelFormat).dwRGBBitCount);
1942     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
1943
1944     GetWindowRect(window, &r);
1945     r.right /= 2;
1946     r.bottom /= 2;
1947     SetWindowPos(window, HWND_TOP, r.left, r.top, r.right, r.bottom, 0);
1948     GetWindowRect(window, &s);
1949     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
1950             r.left, r.top, r.right, r.bottom,
1951             s.left, s.top, s.right, s.bottom);
1952
1953     hr = IDirectDraw_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
1954             U1(surface_desc.ddpfPixelFormat).dwRGBBitCount);
1955     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
1956
1957     GetWindowRect(window, &s);
1958     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
1959             r.left, r.top, r.right, r.bottom,
1960             s.left, s.top, s.right, s.bottom);
1961
1962     ref = IDirectDraw_Release(ddraw);
1963     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1964
1965     DestroyWindow(window);
1966 }
1967
1968 static SIZE screen_size;
1969
1970 static LRESULT CALLBACK mode_set_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1971 {
1972     if (message == WM_SIZE)
1973     {
1974         screen_size.cx = GetSystemMetrics(SM_CXSCREEN);
1975         screen_size.cy = GetSystemMetrics(SM_CYSCREEN);
1976     }
1977
1978     return test_proc(hwnd, message, wparam, lparam);
1979 }
1980
1981 static void test_coop_level_mode_set(void)
1982 {
1983     IDirectDrawSurface *primary;
1984     RECT fullscreen_rect, r, s;
1985     IDirectDraw *ddraw;
1986     DDSURFACEDESC ddsd;
1987     WNDCLASSA wc = {0};
1988     HWND window;
1989     HRESULT hr;
1990     ULONG ref;
1991
1992     static const UINT exclusive_messages[] =
1993     {
1994         WM_WINDOWPOSCHANGING,
1995         WM_WINDOWPOSCHANGED,
1996         WM_SIZE,
1997         WM_DISPLAYCHANGE,
1998         0,
1999     };
2000
2001     static const UINT normal_messages[] =
2002     {
2003         WM_DISPLAYCHANGE,
2004         0,
2005     };
2006
2007     if (!(ddraw = create_ddraw()))
2008     {
2009         skip("Failed to create a ddraw object, skipping test.\n");
2010         return;
2011     }
2012
2013     wc.lpfnWndProc = mode_set_proc;
2014     wc.lpszClassName = "ddraw_test_wndproc_wc";
2015     ok(RegisterClassA(&wc), "Failed to register window class.\n");
2016
2017     window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test", WS_OVERLAPPEDWINDOW,
2018             0, 0, 100, 100, 0, 0, 0, 0);
2019
2020     SetRect(&fullscreen_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2021     SetRect(&s, 0, 0, 640, 480);
2022
2023     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2024     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2025
2026     GetWindowRect(window, &r);
2027     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2028             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2029             r.left, r.top, r.right, r.bottom);
2030
2031     memset(&ddsd, 0, sizeof(ddsd));
2032     ddsd.dwSize = sizeof(ddsd);
2033     ddsd.dwFlags = DDSD_CAPS;
2034     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2035
2036     hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
2037     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2038     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2039     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2040     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2041             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2042     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2043             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2044
2045     GetWindowRect(window, &r);
2046     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2047             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2048             r.left, r.top, r.right, r.bottom);
2049
2050     expect_messages = exclusive_messages;
2051     screen_size.cx = 0;
2052     screen_size.cy = 0;
2053
2054     hr = IDirectDraw_SetDisplayMode(ddraw, 640, 480, 32);
2055     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2056
2057     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2058     expect_messages = NULL;
2059     ok(screen_size.cx == s.right && screen_size.cy == s.bottom,
2060             "Expected screen size %ux%u, got %ux%u.\n",
2061             s.right, s.bottom, screen_size.cx, screen_size.cy);
2062
2063     GetWindowRect(window, &r);
2064     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2065             s.left, s.top, s.right, s.bottom,
2066             r.left, r.top, r.right, r.bottom);
2067
2068     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2069     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2070     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2071             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2072     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2073             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2074     IDirectDrawSurface_Release(primary);
2075
2076     memset(&ddsd, 0, sizeof(ddsd));
2077     ddsd.dwSize = sizeof(ddsd);
2078     ddsd.dwFlags = DDSD_CAPS;
2079     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2080
2081     hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
2082     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2083     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2084     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2085     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2086             s.right - s.left, ddsd.dwWidth);
2087     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2088             s.bottom - s.top, ddsd.dwHeight);
2089
2090     GetWindowRect(window, &r);
2091     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2092             s.left, s.top, s.right, s.bottom,
2093             r.left, r.top, r.right, r.bottom);
2094
2095     expect_messages = exclusive_messages;
2096     screen_size.cx = 0;
2097     screen_size.cy = 0;
2098
2099     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2100     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2101
2102     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2103     expect_messages = NULL;
2104     ok(screen_size.cx == fullscreen_rect.right && screen_size.cy == fullscreen_rect.bottom,
2105             "Expected screen size %ux%u, got %ux%u.\n",
2106             fullscreen_rect.right, fullscreen_rect.bottom, screen_size.cx, screen_size.cy);
2107
2108     GetWindowRect(window, &r);
2109     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2110             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2111             r.left, r.top, r.right, r.bottom);
2112
2113     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2114     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2115     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2116             s.right - s.left, ddsd.dwWidth);
2117     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2118             s.bottom - s.top, ddsd.dwHeight);
2119     IDirectDrawSurface_Release(primary);
2120
2121     memset(&ddsd, 0, sizeof(ddsd));
2122     ddsd.dwSize = sizeof(ddsd);
2123     ddsd.dwFlags = DDSD_CAPS;
2124     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2125
2126     hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
2127     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2128     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2129     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2130     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2131             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2132     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2133             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2134
2135     GetWindowRect(window, &r);
2136     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2137             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2138             r.left, r.top, r.right, r.bottom);
2139
2140     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2141     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2142
2143     GetWindowRect(window, &r);
2144     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2145             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2146             r.left, r.top, r.right, r.bottom);
2147
2148     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2149     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2150     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2151             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2152     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2153             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2154     IDirectDrawSurface_Release(primary);
2155
2156     memset(&ddsd, 0, sizeof(ddsd));
2157     ddsd.dwSize = sizeof(ddsd);
2158     ddsd.dwFlags = DDSD_CAPS;
2159     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2160
2161     hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
2162     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2163     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2164     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2165     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2166             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2167     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2168             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2169
2170     GetWindowRect(window, &r);
2171     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2172             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2173             r.left, r.top, r.right, r.bottom);
2174
2175     expect_messages = normal_messages;
2176     screen_size.cx = 0;
2177     screen_size.cy = 0;
2178
2179     hr = IDirectDraw_SetDisplayMode(ddraw, 640, 480, 32);
2180     ok(SUCCEEDED(hr) || broken(hr == DDERR_NOEXCLUSIVEMODE) /* NT4 testbot */,
2181             "SetDipslayMode failed, hr %#x.\n", hr);
2182     if (hr == DDERR_NOEXCLUSIVEMODE)
2183     {
2184         win_skip("Broken SetDisplayMode(), skipping remaining tests.\n");
2185         IDirectDrawSurface_Release(primary);
2186         IDirectDraw_Release(ddraw);
2187         goto done;
2188     }
2189
2190     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2191     expect_messages = NULL;
2192     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2193
2194     GetWindowRect(window, &r);
2195     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2196             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2197             r.left, r.top, r.right, r.bottom);
2198
2199     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2200     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2201     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2202             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2203     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2204             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2205     IDirectDrawSurface_Release(primary);
2206
2207     memset(&ddsd, 0, sizeof(ddsd));
2208     ddsd.dwSize = sizeof(ddsd);
2209     ddsd.dwFlags = DDSD_CAPS;
2210     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2211
2212     hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
2213     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2214     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2215     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2216     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2217             s.right - s.left, ddsd.dwWidth);
2218     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2219             s.bottom - s.top, ddsd.dwHeight);
2220
2221     GetWindowRect(window, &r);
2222     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2223             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2224             r.left, r.top, r.right, r.bottom);
2225
2226     expect_messages = normal_messages;
2227     screen_size.cx = 0;
2228     screen_size.cy = 0;
2229
2230     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2231     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2232
2233     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2234     expect_messages = NULL;
2235     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2236
2237     GetWindowRect(window, &r);
2238     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2239             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2240             r.left, r.top, r.right, r.bottom);
2241
2242     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2243     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2244     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2245             s.right - s.left, ddsd.dwWidth);
2246     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2247             s.bottom - s.top, ddsd.dwHeight);
2248     IDirectDrawSurface_Release(primary);
2249
2250     memset(&ddsd, 0, sizeof(ddsd));
2251     ddsd.dwSize = sizeof(ddsd);
2252     ddsd.dwFlags = DDSD_CAPS;
2253     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2254
2255     hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
2256     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2257     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2258     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2259     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2260             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2261     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2262             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2263
2264     GetWindowRect(window, &r);
2265     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2266             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2267             r.left, r.top, r.right, r.bottom);
2268
2269     /* DDSCL_NORMAL | DDSCL_FULLSCREEN behaves the same as just DDSCL_NORMAL.
2270      * Resizing the window on mode changes is a property of DDSCL_EXCLUSIVE,
2271      * not DDSCL_FULLSCREEN. */
2272     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
2273     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2274
2275     GetWindowRect(window, &r);
2276     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2277             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2278             r.left, r.top, r.right, r.bottom);
2279
2280     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2281     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2282     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2283             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2284     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2285             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2286     IDirectDrawSurface_Release(primary);
2287
2288     memset(&ddsd, 0, sizeof(ddsd));
2289     ddsd.dwSize = sizeof(ddsd);
2290     ddsd.dwFlags = DDSD_CAPS;
2291     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2292
2293     hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
2294     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2295     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2296     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2297     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2298             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2299     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2300             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2301
2302     GetWindowRect(window, &r);
2303     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2304             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2305             r.left, r.top, r.right, r.bottom);
2306
2307     expect_messages = normal_messages;
2308     screen_size.cx = 0;
2309     screen_size.cy = 0;
2310
2311     hr = IDirectDraw_SetDisplayMode(ddraw, 640, 480, 32);
2312     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2313
2314     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2315     expect_messages = NULL;
2316     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2317
2318     GetWindowRect(window, &r);
2319     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2320             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2321             r.left, r.top, r.right, r.bottom);
2322
2323     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2324     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2325     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2326             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2327     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2328             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2329     IDirectDrawSurface_Release(primary);
2330
2331     memset(&ddsd, 0, sizeof(ddsd));
2332     ddsd.dwSize = sizeof(ddsd);
2333     ddsd.dwFlags = DDSD_CAPS;
2334     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2335
2336     hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
2337     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2338     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2339     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2340     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2341             s.right - s.left, ddsd.dwWidth);
2342     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2343             s.bottom - s.top, ddsd.dwHeight);
2344
2345     GetWindowRect(window, &r);
2346     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2347             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2348             r.left, r.top, r.right, r.bottom);
2349
2350     expect_messages = normal_messages;
2351     screen_size.cx = 0;
2352     screen_size.cy = 0;
2353
2354     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2355     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2356
2357     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2358     expect_messages = NULL;
2359     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2360
2361     GetWindowRect(window, &r);
2362     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2363             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2364             r.left, r.top, r.right, r.bottom);
2365
2366     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2367     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2368     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2369             s.right - s.left, ddsd.dwWidth);
2370     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2371             s.bottom - s.top, ddsd.dwHeight);
2372     IDirectDrawSurface_Release(primary);
2373
2374     memset(&ddsd, 0, sizeof(ddsd));
2375     ddsd.dwSize = sizeof(ddsd);
2376     ddsd.dwFlags = DDSD_CAPS;
2377     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2378
2379     hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
2380     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2381     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2382     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2383     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2384             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2385     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2386             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2387     IDirectDrawSurface_Release(primary);
2388
2389     GetWindowRect(window, &r);
2390     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2391             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2392             r.left, r.top, r.right, r.bottom);
2393
2394     ref = IDirectDraw_Release(ddraw);
2395     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2396
2397     GetWindowRect(window, &r);
2398     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2399             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2400             r.left, r.top, r.right, r.bottom);
2401
2402 done:
2403     expect_messages = NULL;
2404     DestroyWindow(window);
2405     UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
2406 }
2407
2408 static void test_coop_level_mode_set_multi(void)
2409 {
2410     IDirectDraw *ddraw1, *ddraw2;
2411     UINT orig_w, orig_h, w, h;
2412     HWND window;
2413     HRESULT hr;
2414     ULONG ref;
2415
2416     if (!(ddraw1 = create_ddraw()))
2417     {
2418         skip("Failed to create a ddraw object, skipping test.\n");
2419         return;
2420     }
2421
2422     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2423             0, 0, 100, 100, 0, 0, 0, 0);
2424
2425     orig_w = GetSystemMetrics(SM_CXSCREEN);
2426     orig_h = GetSystemMetrics(SM_CYSCREEN);
2427
2428     /* With just a single ddraw object, the display mode is restored on
2429      * release. */
2430     hr = IDirectDraw_SetDisplayMode(ddraw1, 800, 600, 32);
2431     ok(SUCCEEDED(hr) || broken(hr == DDERR_NOEXCLUSIVEMODE) /* NT4 testbot */,
2432             "SetDipslayMode failed, hr %#x.\n", hr);
2433     if (hr == DDERR_NOEXCLUSIVEMODE)
2434     {
2435         win_skip("Broken SetDisplayMode(), skipping test.\n");
2436         IDirectDraw_Release(ddraw1);
2437         DestroyWindow(window);
2438         return;
2439     }
2440     w = GetSystemMetrics(SM_CXSCREEN);
2441     ok(w == 800, "Got unexpected screen width %u.\n", w);
2442     h = GetSystemMetrics(SM_CYSCREEN);
2443     ok(h == 600, "Got unexpected screen height %u.\n", h);
2444
2445     ref = IDirectDraw_Release(ddraw1);
2446     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2447     w = GetSystemMetrics(SM_CXSCREEN);
2448     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2449     h = GetSystemMetrics(SM_CYSCREEN);
2450     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2451
2452     /* When there are multiple ddraw objects, the display mode is restored to
2453      * the initial mode, before the first SetDisplayMode() call. */
2454     ddraw1 = create_ddraw();
2455     hr = IDirectDraw_SetDisplayMode(ddraw1, 800, 600, 32);
2456     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2457     w = GetSystemMetrics(SM_CXSCREEN);
2458     ok(w == 800, "Got unexpected screen width %u.\n", w);
2459     h = GetSystemMetrics(SM_CYSCREEN);
2460     ok(h == 600, "Got unexpected screen height %u.\n", h);
2461
2462     ddraw2 = create_ddraw();
2463     hr = IDirectDraw_SetDisplayMode(ddraw2, 640, 480, 32);
2464     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2465     w = GetSystemMetrics(SM_CXSCREEN);
2466     ok(w == 640, "Got unexpected screen width %u.\n", w);
2467     h = GetSystemMetrics(SM_CYSCREEN);
2468     ok(h == 480, "Got unexpected screen height %u.\n", h);
2469
2470     ref = IDirectDraw_Release(ddraw2);
2471     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2472     w = GetSystemMetrics(SM_CXSCREEN);
2473     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2474     h = GetSystemMetrics(SM_CYSCREEN);
2475     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2476
2477     ref = IDirectDraw_Release(ddraw1);
2478     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2479     w = GetSystemMetrics(SM_CXSCREEN);
2480     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2481     h = GetSystemMetrics(SM_CYSCREEN);
2482     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2483
2484     /* Regardless of release ordering. */
2485     ddraw1 = create_ddraw();
2486     hr = IDirectDraw_SetDisplayMode(ddraw1, 800, 600, 32);
2487     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2488     w = GetSystemMetrics(SM_CXSCREEN);
2489     ok(w == 800, "Got unexpected screen width %u.\n", w);
2490     h = GetSystemMetrics(SM_CYSCREEN);
2491     ok(h == 600, "Got unexpected screen height %u.\n", h);
2492
2493     ddraw2 = create_ddraw();
2494     hr = IDirectDraw_SetDisplayMode(ddraw2, 640, 480, 32);
2495     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2496     w = GetSystemMetrics(SM_CXSCREEN);
2497     ok(w == 640, "Got unexpected screen width %u.\n", w);
2498     h = GetSystemMetrics(SM_CYSCREEN);
2499     ok(h == 480, "Got unexpected screen height %u.\n", h);
2500
2501     ref = IDirectDraw_Release(ddraw1);
2502     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2503     w = GetSystemMetrics(SM_CXSCREEN);
2504     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2505     h = GetSystemMetrics(SM_CYSCREEN);
2506     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2507
2508     ref = IDirectDraw_Release(ddraw2);
2509     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2510     w = GetSystemMetrics(SM_CXSCREEN);
2511     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2512     h = GetSystemMetrics(SM_CYSCREEN);
2513     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2514
2515     /* But only for ddraw objects that called SetDisplayMode(). */
2516     ddraw1 = create_ddraw();
2517     ddraw2 = create_ddraw();
2518     hr = IDirectDraw_SetDisplayMode(ddraw2, 640, 480, 32);
2519     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2520     w = GetSystemMetrics(SM_CXSCREEN);
2521     ok(w == 640, "Got unexpected screen width %u.\n", w);
2522     h = GetSystemMetrics(SM_CYSCREEN);
2523     ok(h == 480, "Got unexpected screen height %u.\n", h);
2524
2525     ref = IDirectDraw_Release(ddraw1);
2526     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2527     w = GetSystemMetrics(SM_CXSCREEN);
2528     ok(w == 640, "Got unexpected screen width %u.\n", w);
2529     h = GetSystemMetrics(SM_CYSCREEN);
2530     ok(h == 480, "Got unexpected screen height %u.\n", h);
2531
2532     ref = IDirectDraw_Release(ddraw2);
2533     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2534     w = GetSystemMetrics(SM_CXSCREEN);
2535     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2536     h = GetSystemMetrics(SM_CYSCREEN);
2537     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2538
2539     /* If there's a ddraw object that's currently in exclusive mode, it blocks
2540      * restoring the display mode. */
2541     ddraw1 = create_ddraw();
2542     hr = IDirectDraw_SetDisplayMode(ddraw1, 800, 600, 32);
2543     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2544     w = GetSystemMetrics(SM_CXSCREEN);
2545     ok(w == 800, "Got unexpected screen width %u.\n", w);
2546     h = GetSystemMetrics(SM_CYSCREEN);
2547     ok(h == 600, "Got unexpected screen height %u.\n", h);
2548
2549     ddraw2 = create_ddraw();
2550     hr = IDirectDraw_SetDisplayMode(ddraw2, 640, 480, 32);
2551     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2552     w = GetSystemMetrics(SM_CXSCREEN);
2553     ok(w == 640, "Got unexpected screen width %u.\n", w);
2554     h = GetSystemMetrics(SM_CYSCREEN);
2555     ok(h == 480, "Got unexpected screen height %u.\n", h);
2556
2557     hr = IDirectDraw_SetCooperativeLevel(ddraw2, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2558     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2559
2560     ref = IDirectDraw_Release(ddraw1);
2561     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2562     w = GetSystemMetrics(SM_CXSCREEN);
2563     ok(w == 640, "Got unexpected screen width %u.\n", w);
2564     h = GetSystemMetrics(SM_CYSCREEN);
2565     ok(h == 480, "Got unexpected screen height %u.\n", h);
2566
2567     ref = IDirectDraw_Release(ddraw2);
2568     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2569     w = GetSystemMetrics(SM_CXSCREEN);
2570     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2571     h = GetSystemMetrics(SM_CYSCREEN);
2572     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2573
2574     /* Exclusive mode blocks mode setting on other ddraw objects in general. */
2575     ddraw1 = create_ddraw();
2576     hr = IDirectDraw_SetDisplayMode(ddraw1, 800, 600, 32);
2577     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2578     w = GetSystemMetrics(SM_CXSCREEN);
2579     ok(w == 800, "Got unexpected screen width %u.\n", w);
2580     h = GetSystemMetrics(SM_CYSCREEN);
2581     ok(h == 600, "Got unexpected screen height %u.\n", h);
2582
2583     hr = IDirectDraw_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2584     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2585
2586     ddraw2 = create_ddraw();
2587     hr = IDirectDraw_SetDisplayMode(ddraw2, 640, 480, 32);
2588     ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#x.\n", hr);
2589
2590     ref = IDirectDraw_Release(ddraw1);
2591     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2592     w = GetSystemMetrics(SM_CXSCREEN);
2593     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2594     h = GetSystemMetrics(SM_CYSCREEN);
2595     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2596
2597     ref = IDirectDraw_Release(ddraw2);
2598     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2599     w = GetSystemMetrics(SM_CXSCREEN);
2600     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2601     h = GetSystemMetrics(SM_CYSCREEN);
2602     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2603
2604     DestroyWindow(window);
2605 }
2606
2607 static void test_initialize(void)
2608 {
2609     IDirectDraw *ddraw;
2610     IDirect3D *d3d;
2611     HRESULT hr;
2612
2613     if (!(ddraw = create_ddraw()))
2614     {
2615         skip("Failed to create a ddraw object, skipping test.\n");
2616         return;
2617     }
2618
2619     hr = IDirectDraw_Initialize(ddraw, NULL);
2620     ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x.\n", hr);
2621     IDirectDraw_Release(ddraw);
2622
2623     CoInitialize(NULL);
2624     hr = CoCreateInstance(&CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectDraw, (void **)&ddraw);
2625     ok(SUCCEEDED(hr), "Failed to create IDirectDraw instance, hr %#x.\n", hr);
2626     hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
2627     if (SUCCEEDED(hr))
2628     {
2629         /* IDirect3D_Initialize() just returns DDERR_ALREADYINITIALIZED. */
2630         hr = IDirect3D_Initialize(d3d, NULL);
2631         ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x, expected DDERR_ALREADYINITIALIZED.\n", hr);
2632         IDirect3D_Release(d3d);
2633     }
2634     else skip("Failed to query IDirect3D interface, skipping tests.\n");
2635     hr = IDirectDraw_Initialize(ddraw, NULL);
2636     ok(hr == DD_OK, "Initialize returned hr %#x, expected DD_OK.\n", hr);
2637     hr = IDirectDraw_Initialize(ddraw, NULL);
2638     ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x, expected DDERR_ALREADYINITIALIZED.\n", hr);
2639     IDirectDraw_Release(ddraw);
2640     CoUninitialize();
2641
2642     if (0) /* This crashes on the W2KPROSP4 testbot. */
2643     {
2644         CoInitialize(NULL);
2645         hr = CoCreateInstance(&CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER, &IID_IDirect3D, (void **)&d3d);
2646         ok(hr == E_NOINTERFACE, "CoCreateInstance returned hr %#x, expected E_NOINTERFACE.\n", hr);
2647         CoUninitialize();
2648     }
2649 }
2650
2651 static void test_coop_level_surf_create(void)
2652 {
2653     IDirectDrawSurface *surface;
2654     IDirectDraw *ddraw;
2655     DDSURFACEDESC ddsd;
2656     HRESULT hr;
2657
2658     if (!(ddraw = create_ddraw()))
2659     {
2660         skip("Failed to create a ddraw object, skipping test.\n");
2661         return;
2662     }
2663
2664     memset(&ddsd, 0, sizeof(ddsd));
2665     ddsd.dwSize = sizeof(ddsd);
2666     ddsd.dwFlags = DDSD_CAPS;
2667     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2668     hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
2669     ok(hr == DDERR_NOCOOPERATIVELEVELSET, "Surface creation returned hr %#x.\n", hr);
2670
2671     IDirectDraw_Release(ddraw);
2672 }
2673
2674 static void test_coop_level_multi_window(void)
2675 {
2676     HWND window1, window2;
2677     IDirectDraw *ddraw;
2678     HRESULT hr;
2679
2680     window1 = CreateWindowA("static", "ddraw_test1", WS_OVERLAPPEDWINDOW,
2681             0, 0, 640, 480, 0, 0, 0, 0);
2682     window2 = CreateWindowA("static", "ddraw_test2", WS_OVERLAPPEDWINDOW,
2683             0, 0, 640, 480, 0, 0, 0, 0);
2684     if (!(ddraw = create_ddraw()))
2685     {
2686         skip("Failed to create a ddraw object, skipping test.\n");
2687         DestroyWindow(window2);
2688         DestroyWindow(window1);
2689         return;
2690     }
2691
2692     hr = IDirectDraw_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
2693     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
2694     hr = IDirectDraw_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL);
2695     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
2696     ok(IsWindow(window1), "Window 1 was destroyed.\n");
2697     ok(IsWindow(window2), "Window 2 was destroyed.\n");
2698
2699     IDirectDraw_Release(ddraw);
2700     DestroyWindow(window2);
2701     DestroyWindow(window1);
2702 }
2703
2704 static void test_clear_rect_count(void)
2705 {
2706     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
2707     IDirect3DMaterial *white, *red, *green, *blue;
2708     IDirect3DViewport *viewport;
2709     IDirect3DDevice *device;
2710     IDirectDrawSurface *rt;
2711     IDirectDraw *ddraw;
2712     D3DCOLOR color;
2713     HWND window;
2714     HRESULT hr;
2715
2716     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2717             0, 0, 640, 480, 0, 0, 0, 0);
2718     if (!(ddraw = create_ddraw()))
2719     {
2720         skip("Failed to create ddraw object, skipping test.\n");
2721         DestroyWindow(window);
2722         return;
2723     }
2724     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
2725     {
2726         skip("Failed to create D3D device, skipping test.\n");
2727         IDirectDraw_Release(ddraw);
2728         DestroyWindow(window);
2729         return;
2730     }
2731
2732     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
2733     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
2734
2735     white = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
2736     red   = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
2737     green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 1.0f);
2738     blue  = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
2739     viewport = create_viewport(device, 0, 0, 640, 480);
2740
2741     viewport_set_background(device, viewport, white);
2742     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
2743     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
2744     viewport_set_background(device, viewport, red);
2745     hr = IDirect3DViewport_Clear(viewport, 0, &clear_rect, D3DCLEAR_TARGET);
2746     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
2747     viewport_set_background(device, viewport, green);
2748     hr = IDirect3DViewport_Clear(viewport, 0, NULL, D3DCLEAR_TARGET);
2749     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
2750     viewport_set_background(device, viewport, blue);
2751     hr = IDirect3DViewport_Clear(viewport, 1, NULL, D3DCLEAR_TARGET);
2752     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
2753
2754     color = get_surface_color(rt, 320, 240);
2755     ok(compare_color(color, 0x00ffffff, 1), "Got unexpected color 0x%08x.\n", color);
2756
2757     IDirectDrawSurface_Release(rt);
2758     destroy_viewport(device, viewport);
2759     destroy_material(white);
2760     destroy_material(red);
2761     destroy_material(green);
2762     destroy_material(blue);
2763     IDirect3DDevice_Release(device);
2764     IDirectDraw_Release(ddraw);
2765     DestroyWindow(window);
2766 }
2767
2768 START_TEST(ddraw1)
2769 {
2770     test_coop_level_create_device_window();
2771     test_clipper_blt();
2772     test_coop_level_d3d_state();
2773     test_surface_interface_mismatch();
2774     test_coop_level_threaded();
2775     test_viewport();
2776     test_zenable();
2777     test_ck_rgba();
2778     test_ck_default();
2779     test_surface_qi();
2780     test_device_qi();
2781     test_wndproc();
2782     test_window_style();
2783     test_redundant_mode_set();
2784     test_coop_level_mode_set();
2785     test_coop_level_mode_set_multi();
2786     test_initialize();
2787     test_coop_level_surf_create();
2788     test_coop_level_multi_window();
2789     test_clear_rect_count();
2790 }