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