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