d3drm: Implement IDirect3DRMMesh_AddGroup.
[wine] / dlls / ddraw / tests / ddraw7.c
1 /*
2  * Copyright 2006 Stefan Dösinger for CodeWeavers
3  * Copyright 2011 Henri Verbeet 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 static HRESULT (WINAPI *pDirectDrawCreateEx)(GUID *guid, void **ddraw, REFIID iid, IUnknown *outer_unknown);
26
27 struct vec2
28 {
29     float x, y;
30 };
31
32 struct vec3
33 {
34     float x, y, z;
35 };
36
37 struct vec4
38 {
39     float x, y, z, w;
40 };
41
42 struct create_window_thread_param
43 {
44     HWND window;
45     HANDLE window_created;
46     HANDLE destroy_window;
47     HANDLE thread;
48 };
49
50 static BOOL compare_float(float f, float g, unsigned int ulps)
51 {
52     int x = *(int *)&f;
53     int y = *(int *)&g;
54
55     if (x < 0)
56         x = INT_MIN - x;
57     if (y < 0)
58         y = INT_MIN - y;
59
60     if (abs(x - y) > ulps)
61         return FALSE;
62
63     return TRUE;
64 }
65
66 static BOOL compare_vec3(struct vec3 *vec, float x, float y, float z, unsigned int ulps)
67 {
68     return compare_float(vec->x, x, ulps)
69             && compare_float(vec->y, y, ulps)
70             && compare_float(vec->z, z, ulps);
71 }
72
73 static BOOL compare_vec4(struct vec4 *vec, float x, float y, float z, float w, unsigned int ulps)
74 {
75     return compare_float(vec->x, x, ulps)
76             && compare_float(vec->y, y, ulps)
77             && compare_float(vec->z, z, ulps)
78             && compare_float(vec->w, w, ulps);
79 }
80
81 static BOOL compare_color(D3DCOLOR c1, D3DCOLOR c2, BYTE max_diff)
82 {
83     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
84     c1 >>= 8; c2 >>= 8;
85     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
86     c1 >>= 8; c2 >>= 8;
87     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
88     c1 >>= 8; c2 >>= 8;
89     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
90     return TRUE;
91 }
92
93 static DWORD WINAPI create_window_thread_proc(void *param)
94 {
95     struct create_window_thread_param *p = param;
96     DWORD res;
97     BOOL ret;
98
99     p->window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
100             0, 0, 640, 480, 0, 0, 0, 0);
101     ret = SetEvent(p->window_created);
102     ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
103
104     for (;;)
105     {
106         MSG msg;
107
108         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
109             DispatchMessage(&msg);
110         res = WaitForSingleObject(p->destroy_window, 100);
111         if (res == WAIT_OBJECT_0)
112             break;
113         if (res != WAIT_TIMEOUT)
114         {
115             ok(0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
116             break;
117         }
118     }
119
120     DestroyWindow(p->window);
121
122     return 0;
123 }
124
125 static void create_window_thread(struct create_window_thread_param *p)
126 {
127     DWORD res, tid;
128
129     p->window_created = CreateEvent(NULL, FALSE, FALSE, NULL);
130     ok(!!p->window_created, "CreateEvent failed, last error %#x.\n", GetLastError());
131     p->destroy_window = CreateEvent(NULL, FALSE, FALSE, NULL);
132     ok(!!p->destroy_window, "CreateEvent failed, last error %#x.\n", GetLastError());
133     p->thread = CreateThread(NULL, 0, create_window_thread_proc, p, 0, &tid);
134     ok(!!p->thread, "Failed to create thread, last error %#x.\n", GetLastError());
135     res = WaitForSingleObject(p->window_created, INFINITE);
136     ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
137 }
138
139 static void destroy_window_thread(struct create_window_thread_param *p)
140 {
141     SetEvent(p->destroy_window);
142     WaitForSingleObject(p->thread, INFINITE);
143     CloseHandle(p->destroy_window);
144     CloseHandle(p->window_created);
145     CloseHandle(p->thread);
146 }
147
148 static IDirectDrawSurface7 *get_depth_stencil(IDirect3DDevice7 *device)
149 {
150     IDirectDrawSurface7 *rt, *ret;
151     DDSCAPS2 caps = {DDSCAPS_ZBUFFER, 0, 0, 0};
152     HRESULT hr;
153
154     hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
155     ok(SUCCEEDED(hr), "Failed to get the render target, hr %#x.\n", hr);
156     hr = IDirectDrawSurface7_GetAttachedSurface(rt, &caps, &ret);
157     ok(SUCCEEDED(hr) || hr == DDERR_NOTFOUND, "Failed to get the z buffer, hr %#x.\n", hr);
158     IDirectDrawSurface7_Release(rt);
159     return ret;
160 }
161
162 static D3DCOLOR get_surface_color(IDirectDrawSurface7 *surface, UINT x, UINT y)
163 {
164     RECT rect = {x, y, x + 1, y + 1};
165     DDSURFACEDESC2 surface_desc;
166     D3DCOLOR color;
167     HRESULT hr;
168
169     memset(&surface_desc, 0, sizeof(surface_desc));
170     surface_desc.dwSize = sizeof(surface_desc);
171
172     hr = IDirectDrawSurface7_Lock(surface, &rect, &surface_desc, DDLOCK_READONLY, NULL);
173     ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
174     if (FAILED(hr))
175         return 0xdeadbeef;
176
177     color = *((DWORD *)surface_desc.lpSurface) & 0x00ffffff;
178
179     hr = IDirectDrawSurface7_Unlock(surface, &rect);
180     ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
181
182     return color;
183 }
184
185 static HRESULT CALLBACK enum_z_fmt(DDPIXELFORMAT *format, void *ctx)
186 {
187     DDPIXELFORMAT *z_fmt = ctx;
188
189     if (U1(*format).dwZBufferBitDepth > U1(*z_fmt).dwZBufferBitDepth)
190         *z_fmt = *format;
191
192     return DDENUMRET_OK;
193 }
194
195 static IDirectDraw7 *create_ddraw(void)
196 {
197     IDirectDraw7 *ddraw;
198
199     if (FAILED(pDirectDrawCreateEx(NULL, (void **)&ddraw, &IID_IDirectDraw7, NULL)))
200         return NULL;
201
202     return ddraw;
203 }
204
205 static IDirect3DDevice7 *create_device(HWND window, DWORD coop_level)
206 {
207     IDirectDrawSurface7 *surface, *ds;
208     IDirect3DDevice7 *device = NULL;
209     DDSURFACEDESC2 surface_desc;
210     DDPIXELFORMAT z_fmt;
211     IDirectDraw7 *ddraw;
212     IDirect3D7 *d3d7;
213     HRESULT hr;
214
215     if (!(ddraw = create_ddraw()))
216         return NULL;
217
218     hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, coop_level);
219     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
220
221     memset(&surface_desc, 0, sizeof(surface_desc));
222     surface_desc.dwSize = sizeof(surface_desc);
223     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
224     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
225     surface_desc.dwWidth = 640;
226     surface_desc.dwHeight = 480;
227
228     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface, NULL);
229     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
230
231     if (coop_level & DDSCL_NORMAL)
232     {
233         IDirectDrawClipper *clipper;
234
235         hr = IDirectDraw7_CreateClipper(ddraw, 0, &clipper, NULL);
236         ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
237         hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
238         ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
239         hr = IDirectDrawSurface7_SetClipper(surface, clipper);
240         ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#x.\n", hr);
241         IDirectDrawClipper_Release(clipper);
242     }
243
244     hr = IDirectDraw7_QueryInterface(ddraw, &IID_IDirect3D7, (void **)&d3d7);
245     IDirectDraw7_Release(ddraw);
246     if (FAILED(hr))
247     {
248         IDirectDrawSurface7_Release(surface);
249         return NULL;
250     }
251
252     memset(&z_fmt, 0, sizeof(z_fmt));
253     hr = IDirect3D7_EnumZBufferFormats(d3d7, &IID_IDirect3DTnLHalDevice, enum_z_fmt, &z_fmt);
254     if (FAILED(hr) || !z_fmt.dwSize)
255     {
256         IDirect3D7_Release(d3d7);
257         IDirectDrawSurface7_Release(surface);
258         return NULL;
259     }
260
261     memset(&surface_desc, 0, sizeof(surface_desc));
262     surface_desc.dwSize = sizeof(surface_desc);
263     surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
264     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
265     U4(surface_desc).ddpfPixelFormat = z_fmt;
266     surface_desc.dwWidth = 640;
267     surface_desc.dwHeight = 480;
268     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &ds, NULL);
269     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
270     if (FAILED(hr))
271     {
272         IDirect3D7_Release(d3d7);
273         IDirectDrawSurface7_Release(surface);
274         return NULL;
275     }
276
277     hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
278     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
279     IDirectDrawSurface7_Release(ds);
280     if (FAILED(hr))
281     {
282         IDirect3D7_Release(d3d7);
283         IDirectDrawSurface7_Release(surface);
284         return NULL;
285     }
286
287     hr = IDirect3D7_CreateDevice(d3d7, &IID_IDirect3DTnLHalDevice, surface, &device);
288     IDirect3D7_Release(d3d7);
289     IDirectDrawSurface7_Release(surface);
290     if (FAILED(hr))
291         return NULL;
292
293     return device;
294 }
295
296 static void test_process_vertices(void)
297 {
298     IDirect3DVertexBuffer7 *src_vb, *dst_vb1, *dst_vb2;
299     D3DVERTEXBUFFERDESC vb_desc;
300     IDirect3DDevice7 *device;
301     struct vec4 *dst_data;
302     struct vec3 *dst_data2;
303     struct vec3 *src_data;
304     IDirect3D7 *d3d7;
305     D3DVIEWPORT7 vp;
306     HWND window;
307     HRESULT hr;
308
309     static D3DMATRIX world =
310     {
311         0.0f,  1.0f, 0.0f, 0.0f,
312         1.0f,  0.0f, 0.0f, 0.0f,
313         0.0f,  0.0f, 0.0f, 1.0f,
314         0.0f,  1.0f, 1.0f, 1.0f,
315     };
316     static D3DMATRIX view =
317     {
318         2.0f,  0.0f, 0.0f, 0.0f,
319         0.0f, -1.0f, 0.0f, 0.0f,
320         0.0f,  0.0f, 1.0f, 0.0f,
321         0.0f,  0.0f, 0.0f, 3.0f,
322     };
323     static D3DMATRIX proj =
324     {
325         1.0f,  0.0f, 0.0f, 1.0f,
326         0.0f,  1.0f, 1.0f, 0.0f,
327         0.0f,  1.0f, 1.0f, 0.0f,
328         1.0f,  0.0f, 0.0f, 1.0f,
329     };
330
331     window = CreateWindowA("static", "d3d7_test", WS_OVERLAPPEDWINDOW,
332             0, 0, 640, 480, 0, 0, 0, 0);
333     if (!(device = create_device(window, DDSCL_NORMAL)))
334     {
335         skip("Failed to create a ddraw object, skipping test.\n");
336         DestroyWindow(window);
337         return;
338     }
339
340     hr = IDirect3DDevice7_GetDirect3D(device, &d3d7);
341     ok(SUCCEEDED(hr), "Failed to get Direct3D7 interface, hr %#x.\n", hr);
342
343     memset(&vb_desc, 0, sizeof(vb_desc));
344     vb_desc.dwSize = sizeof(vb_desc);
345     vb_desc.dwFVF = D3DFVF_XYZ;
346     vb_desc.dwNumVertices = 4;
347     hr = IDirect3D7_CreateVertexBuffer(d3d7, &vb_desc, &src_vb, 0);
348     ok(SUCCEEDED(hr), "Failed to create source vertex buffer, hr %#x.\n", hr);
349
350     hr = IDirect3DVertexBuffer7_Lock(src_vb, 0, (void **)&src_data, NULL);
351     ok(SUCCEEDED(hr), "Failed to lock source vertex buffer, hr %#x.\n", hr);
352     src_data[0].x = 0.0f;
353     src_data[0].y = 0.0f;
354     src_data[0].z = 0.0f;
355     src_data[1].x = 1.0f;
356     src_data[1].y = 1.0f;
357     src_data[1].z = 1.0f;
358     src_data[2].x = -1.0f;
359     src_data[2].y = -1.0f;
360     src_data[2].z = 0.5f;
361     src_data[3].x = 0.5f;
362     src_data[3].y = -0.5f;
363     src_data[3].z = 0.25f;
364     hr = IDirect3DVertexBuffer7_Unlock(src_vb);
365     ok(SUCCEEDED(hr), "Failed to unlock source vertex buffer, hr %#x.\n", hr);
366
367     memset(&vb_desc, 0, sizeof(vb_desc));
368     vb_desc.dwSize = sizeof(vb_desc);
369     vb_desc.dwFVF = D3DFVF_XYZRHW;
370     vb_desc.dwNumVertices = 4;
371     /* MSDN says that the last parameter must be 0 - check that. */
372     hr = IDirect3D7_CreateVertexBuffer(d3d7, &vb_desc, &dst_vb1, 4);
373     ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
374
375     memset(&vb_desc, 0, sizeof(vb_desc));
376     vb_desc.dwSize = sizeof(vb_desc);
377     vb_desc.dwFVF = D3DFVF_XYZ;
378     vb_desc.dwNumVertices = 5;
379     /* MSDN says that the last parameter must be 0 - check that. */
380     hr = IDirect3D7_CreateVertexBuffer(d3d7, &vb_desc, &dst_vb2, 12345678);
381     ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
382
383     memset(&vp, 0, sizeof(vp));
384     vp.dwX = 64;
385     vp.dwY = 64;
386     vp.dwWidth = 128;
387     vp.dwHeight = 128;
388     vp.dvMinZ = 0.0f;
389     vp.dvMaxZ = 1.0f;
390     hr = IDirect3DDevice7_SetViewport(device, &vp);
391     ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
392
393     hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb1, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0);
394     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
395     hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb2, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0);
396     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
397
398     hr = IDirect3DVertexBuffer7_Lock(dst_vb1, 0, (void **)&dst_data, NULL);
399     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
400     ok(compare_vec4(&dst_data[0], +1.280e+2f, +1.280e+2f, +0.000e+0f, +1.000e+0f, 4096),
401             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
402             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
403     ok(compare_vec4(&dst_data[1], +1.920e+2f, +6.400e+1f, +1.000e+0f, +1.000e+0f, 4096),
404             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
405             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
406     ok(compare_vec4(&dst_data[2], +6.400e+1f, +1.920e+2f, +5.000e-1f, +1.000e+0f, 4096),
407             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
408             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
409     ok(compare_vec4(&dst_data[3], +1.600e+2f, +1.600e+2f, +2.500e-1f, +1.000e+0f, 4096),
410             "Got unexpected vertex 3 {%.8e, %.8e, %.8e, %.8e}.\n",
411             dst_data[3].x, dst_data[3].y, dst_data[3].z, dst_data[3].w);
412     hr = IDirect3DVertexBuffer7_Unlock(dst_vb1);
413     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
414
415     hr = IDirect3DVertexBuffer7_Lock(dst_vb2, 0, (void **)&dst_data2, NULL);
416     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
417     /* Small thing without much practical meaning, but I stumbled upon it,
418      * so let's check for it: If the output vertex buffer has no RHW value,
419      * the RHW value of the last vertex is written into the next vertex. */
420     ok(compare_vec3(&dst_data2[4], +1.000e+0f, +0.000e+0f, +0.000e+0f, 4096),
421             "Got unexpected vertex 4 {%.8e, %.8e, %.8e}.\n",
422             dst_data2[4].x, dst_data2[4].y, dst_data2[4].z);
423     hr = IDirect3DVertexBuffer7_Unlock(dst_vb2);
424     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
425
426     /* Try a more complicated viewport, same vertices. */
427     memset(&vp, 0, sizeof(vp));
428     vp.dwX = 10;
429     vp.dwY = 5;
430     vp.dwWidth = 246;
431     vp.dwHeight = 130;
432     vp.dvMinZ = -2.0f;
433     vp.dvMaxZ = 4.0f;
434     hr = IDirect3DDevice7_SetViewport(device, &vp);
435     ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
436
437     hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb1, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0);
438     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
439
440     hr = IDirect3DVertexBuffer7_Lock(dst_vb1, 0, (void **)&dst_data, NULL);
441     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
442     ok(compare_vec4(&dst_data[0], +1.330e+2f, +7.000e+1f, -2.000e+0f, +1.000e+0f, 4096),
443             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
444             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
445     ok(compare_vec4(&dst_data[1], +2.560e+2f, +5.000e+0f, +4.000e+0f, +1.000e+0f, 4096),
446             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
447             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
448     ok(compare_vec4(&dst_data[2], +1.000e+1f, +1.350e+2f, +1.000e+0f, +1.000e+0f, 4096),
449             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
450             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
451     ok(compare_vec4(&dst_data[3], +1.945e+2f, +1.025e+2f, -5.000e-1f, +1.000e+0f, 4096),
452             "Got unexpected vertex 3 {%.8e, %.8e, %.8e, %.8e}.\n",
453             dst_data[3].x, dst_data[3].y, dst_data[3].z, dst_data[3].w);
454     hr = IDirect3DVertexBuffer7_Unlock(dst_vb1);
455     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
456
457     hr = IDirect3DDevice7_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &world);
458     ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr);
459     hr = IDirect3DDevice7_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &view);
460     ok(SUCCEEDED(hr), "Failed to set view transform, hr %#x.\n", hr);
461     hr = IDirect3DDevice7_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &proj);
462     ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#x.\n", hr);
463
464     hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb1, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0);
465     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
466
467     hr = IDirect3DVertexBuffer7_Lock(dst_vb1, 0, (void **)&dst_data, NULL);
468     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
469     ok(compare_vec4(&dst_data[0], +2.560e+2f, +7.000e+1f, -2.000e+0f, +3.333e-1f, 4096),
470             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
471             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
472     ok(compare_vec4(&dst_data[1], +2.560e+2f, +7.813e+1f, -2.750e+0f, +1.250e-1f, 4096),
473             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
474             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
475     ok(compare_vec4(&dst_data[2], +2.560e+2f, +4.400e+1f, +4.000e-1f, +4.000e-1f, 4096),
476             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
477             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
478     ok(compare_vec4(&dst_data[3], +2.560e+2f, +8.182e+1f, -3.091e+0f, +3.636e-1f, 4096),
479             "Got unexpected vertex 3 {%.8e, %.8e, %.8e, %.8e}.\n",
480             dst_data[3].x, dst_data[3].y, dst_data[3].z, dst_data[3].w);
481     hr = IDirect3DVertexBuffer7_Unlock(dst_vb1);
482     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
483
484     IDirect3DVertexBuffer7_Release(dst_vb2);
485     IDirect3DVertexBuffer7_Release(dst_vb1);
486     IDirect3DVertexBuffer7_Release(src_vb);
487     IDirect3D7_Release(d3d7);
488     IDirect3DDevice7_Release(device);
489     DestroyWindow(window);
490 }
491
492 static void test_coop_level_create_device_window(void)
493 {
494     HWND focus_window, device_window;
495     IDirectDraw7 *ddraw;
496     HRESULT hr;
497
498     focus_window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
499             0, 0, 640, 480, 0, 0, 0, 0);
500     if (!(ddraw = create_ddraw()))
501     {
502         skip("Failed to create a 3D device, skipping test.\n");
503         DestroyWindow(focus_window);
504         return;
505     }
506
507     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
508     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
509     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
510     ok(!device_window, "Unexpected device window found.\n");
511     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW);
512     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
513     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
514     ok(!device_window, "Unexpected device window found.\n");
515     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL);
516     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
517     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
518     ok(!device_window, "Unexpected device window found.\n");
519     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL | DDSCL_FULLSCREEN);
520     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
521     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
522     ok(!device_window, "Unexpected device window found.\n");
523     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
524     ok(hr == DDERR_NOFOCUSWINDOW || broken(hr == DDERR_INVALIDPARAMS), "Got unexpected hr %#x.\n", hr);
525     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
526     ok(!device_window, "Unexpected device window found.\n");
527
528     /* Windows versions before 98 / NT5 don't support DDSCL_CREATEDEVICEWINDOW. */
529     if (broken(hr == DDERR_INVALIDPARAMS))
530     {
531         win_skip("DDSCL_CREATEDEVICEWINDOW not supported, skipping test.\n");
532         IDirectDraw7_Release(ddraw);
533         DestroyWindow(focus_window);
534         return;
535     }
536
537     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
538     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
539     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
540     ok(!device_window, "Unexpected device window found.\n");
541     hr = IDirectDraw7_SetCooperativeLevel(ddraw, focus_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
542     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
543     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
544     ok(!device_window, "Unexpected device window found.\n");
545
546     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
547     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
548     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
549     ok(!device_window, "Unexpected device window found.\n");
550     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_SETFOCUSWINDOW
551             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
552     ok(hr == DDERR_NOHWND, "Got unexpected hr %#x.\n", hr);
553     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
554     ok(!!device_window, "Device window not found.\n");
555
556     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
557     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
558     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
559     ok(!device_window, "Unexpected device window found.\n");
560     hr = IDirectDraw7_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW
561             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
562     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
563     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
564     ok(!!device_window, "Device window not found.\n");
565
566     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
567     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
568     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
569     ok(!device_window, "Unexpected device window found.\n");
570     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
571     ok(hr == DDERR_NOFOCUSWINDOW, "Got unexpected hr %#x.\n", hr);
572     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
573     ok(!device_window, "Unexpected device window found.\n");
574     hr = IDirectDraw7_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW);
575     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
576     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
577     ok(!device_window, "Unexpected device window found.\n");
578     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
579     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
580     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
581     ok(!!device_window, "Device window not found.\n");
582
583     IDirectDraw7_Release(ddraw);
584     DestroyWindow(focus_window);
585 }
586
587 static void test_clipper_blt(void)
588 {
589     IDirectDrawSurface7 *src_surface, *dst_surface;
590     RECT client_rect, src_rect, *rect;
591     IDirectDrawClipper *clipper;
592     DDSURFACEDESC2 surface_desc;
593     unsigned int i, j, x, y;
594     IDirectDraw7 *ddraw;
595     RGNDATA *rgn_data;
596     D3DCOLOR color;
597     HRGN r1, r2;
598     HWND window;
599     DDBLTFX fx;
600     HRESULT hr;
601     DWORD *ptr;
602     DWORD ret;
603
604     static const DWORD src_data[] =
605     {
606         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
607         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
608         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
609     };
610     static const D3DCOLOR expected1[] =
611     {
612         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
613         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
614         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
615         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
616     };
617     static const D3DCOLOR expected2[] =
618     {
619         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
620         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
621         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
622         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
623     };
624
625     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
626             10, 10, 640, 480, 0, 0, 0, 0);
627     ShowWindow(window, SW_SHOW);
628     if (!(ddraw = create_ddraw()))
629     {
630         skip("Failed to create a ddraw object, skipping test.\n");
631         DestroyWindow(window);
632         return;
633     }
634
635     ret = GetClientRect(window, &client_rect);
636     ok(ret, "Failed to get client rect.\n");
637     ret = MapWindowPoints(window, NULL, (POINT *)&client_rect, 2);
638     ok(ret, "Failed to map client rect.\n");
639
640     hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
641     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
642
643     hr = IDirectDraw7_CreateClipper(ddraw, 0, &clipper, NULL);
644     ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
645     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
646     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
647     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
648     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
649     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
650     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
651     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
652     hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret);
653     ok(SUCCEEDED(hr), "Failed to get clip list, hr %#x.\n", hr);
654     ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#x.\n", rgn_data->rdh.dwSize);
655     ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#x.\n", rgn_data->rdh.iType);
656     ok(rgn_data->rdh.nCount == 1, "Got unexpected count %u.\n", rgn_data->rdh.nCount);
657     ok(rgn_data->rdh.nRgnSize == 16, "Got unexpected region size %u.\n", rgn_data->rdh.nRgnSize);
658     ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
659             "Got unexpected bounding rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
660             rgn_data->rdh.rcBound.left, rgn_data->rdh.rcBound.top,
661             rgn_data->rdh.rcBound.right, rgn_data->rdh.rcBound.bottom,
662             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
663     rect = (RECT *)&rgn_data->Buffer[0];
664     ok(EqualRect(rect, &client_rect),
665             "Got unexpected clip rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
666             rect->left, rect->top, rect->right, rect->bottom,
667             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
668     HeapFree(GetProcessHeap(), 0, rgn_data);
669
670     r1 = CreateRectRgn(0, 0, 320, 240);
671     ok(!!r1, "Failed to create region.\n");
672     r2 = CreateRectRgn(320, 240, 640, 480);
673     ok(!!r2, "Failed to create region.\n");
674     CombineRgn(r1, r1, r2, RGN_OR);
675     ret = GetRegionData(r1, 0, NULL);
676     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
677     ret = GetRegionData(r1, ret, rgn_data);
678     ok(!!ret, "Failed to get region data.\n");
679
680     DeleteObject(r2);
681     DeleteObject(r1);
682
683     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
684     ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#x.\n", hr);
685     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
686     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
687     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
688     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
689
690     HeapFree(GetProcessHeap(), 0, rgn_data);
691
692     memset(&surface_desc, 0, sizeof(surface_desc));
693     surface_desc.dwSize = sizeof(surface_desc);
694     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
695     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
696     surface_desc.dwWidth = 640;
697     surface_desc.dwHeight = 480;
698     U4(surface_desc).ddpfPixelFormat.dwSize = sizeof(U4(surface_desc).ddpfPixelFormat);
699     U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB;
700     U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount = 32;
701     U2(U4(surface_desc).ddpfPixelFormat).dwRBitMask = 0x00ff0000;
702     U3(U4(surface_desc).ddpfPixelFormat).dwGBitMask = 0x0000ff00;
703     U4(U4(surface_desc).ddpfPixelFormat).dwBBitMask = 0x000000ff;
704
705     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
706     ok(SUCCEEDED(hr), "Failed to create source surface, hr %#x.\n", hr);
707     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
708     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
709
710     memset(&fx, 0, sizeof(fx));
711     fx.dwSize = sizeof(fx);
712     hr = IDirectDrawSurface7_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
713     ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#x.\n", hr);
714     hr = IDirectDrawSurface7_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
715     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
716
717     hr = IDirectDrawSurface7_Lock(src_surface, NULL, &surface_desc, 0, NULL);
718     ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#x.\n", hr);
719     ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %u.\n", U1(surface_desc).lPitch);
720     ptr = surface_desc.lpSurface;
721     memcpy(&ptr[   0], &src_data[ 0], 6 * sizeof(DWORD));
722     memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
723     memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
724     hr = IDirectDrawSurface7_Unlock(src_surface, NULL);
725     ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#x.\n", hr);
726
727     hr = IDirectDrawSurface7_SetClipper(dst_surface, clipper);
728     ok(SUCCEEDED(hr), "Failed to set clipper, hr %#x.\n", hr);
729
730     SetRect(&src_rect, 1, 1, 5, 2);
731     hr = IDirectDrawSurface7_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
732     ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
733     for (i = 0; i < 4; ++i)
734     {
735         for (j = 0; j < 4; ++j)
736         {
737             x = 80 * ((2 * j) + 1);
738             y = 60 * ((2 * i) + 1);
739             color = get_surface_color(dst_surface, x, y);
740             ok(compare_color(color, expected1[i * 4 + j], 1),
741                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
742         }
743     }
744
745     U5(fx).dwFillColor = 0xff0000ff;
746     hr = IDirectDrawSurface7_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
747     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
748     for (i = 0; i < 4; ++i)
749     {
750         for (j = 0; j < 4; ++j)
751         {
752             x = 80 * ((2 * j) + 1);
753             y = 60 * ((2 * i) + 1);
754             color = get_surface_color(dst_surface, x, y);
755             ok(compare_color(color, expected2[i * 4 + j], 1),
756                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
757         }
758     }
759
760     hr = IDirectDrawSurface7_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
761     ok(hr == DDERR_BLTFASTCANTCLIP, "Got unexpected hr %#x.\n", hr);
762
763     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
764     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
765     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
766     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
767     DestroyWindow(window);
768     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
769     ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
770     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
771     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
772     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
773     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
774     hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
775     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
776     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
777     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
778     hr = IDirectDrawSurface7_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
779     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
780
781     IDirectDrawSurface7_Release(dst_surface);
782     IDirectDrawSurface7_Release(src_surface);
783     IDirectDrawClipper_Release(clipper);
784     IDirectDraw7_Release(ddraw);
785 }
786
787 static void test_coop_level_d3d_state(void)
788 {
789     IDirectDrawSurface7 *rt, *surface;
790     IDirect3DDevice7 *device;
791     IDirectDraw7 *ddraw;
792     IDirect3D7 *d3d;
793     D3DCOLOR color;
794     DWORD value;
795     HWND window;
796     HRESULT hr;
797
798     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
799             0, 0, 640, 480, 0, 0, 0, 0);
800     if (!(device = create_device(window, DDSCL_NORMAL)))
801     {
802         skip("Failed to create D3D device, skipping test.\n");
803         DestroyWindow(window);
804         return;
805     }
806
807     hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
808     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
809     hr = IDirect3DDevice7_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
810     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
811     ok(!!value, "Got unexpected z-enable state %#x.\n", value);
812     hr = IDirect3DDevice7_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
813     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
814     ok(!value, "Got unexpected alpha blend enable state %#x.\n", value);
815     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
816     ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
817     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffff0000, 0.0f, 0);
818     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
819     color = get_surface_color(rt, 320, 240);
820     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
821
822     hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
823     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
824     hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw);
825     ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr);
826     IDirect3D7_Release(d3d);
827     hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
828     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
829     hr = IDirectDrawSurface7_IsLost(rt);
830     ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
831     hr = IDirectDraw7_RestoreAllSurfaces(ddraw);
832     ok(SUCCEEDED(hr), "Failed to restore surfaces, hr %#x.\n", hr);
833     IDirectDraw7_Release(ddraw);
834
835     hr = IDirect3DDevice7_GetRenderTarget(device, &surface);
836     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
837     ok(surface == rt, "Got unexpected surface %p.\n", surface);
838     hr = IDirect3DDevice7_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
839     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
840     ok(!!value, "Got unexpected z-enable state %#x.\n", value);
841     hr = IDirect3DDevice7_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
842     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
843     ok(!!value, "Got unexpected alpha blend enable state %#x.\n", value);
844     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff00ff00, 0.0f, 0);
845     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
846     color = get_surface_color(rt, 320, 240);
847     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
848
849     IDirectDrawSurface7_Release(surface);
850     IDirectDrawSurface7_Release(rt);
851     IDirect3DDevice7_Release(device);
852     DestroyWindow(window);
853 }
854
855 static void test_surface_interface_mismatch(void)
856 {
857     IDirectDraw7 *ddraw = NULL;
858     IDirect3D7 *d3d = NULL;
859     IDirectDrawSurface7 *surface = NULL, *ds;
860     IDirectDrawSurface3 *surface3 = NULL;
861     IDirect3DDevice7 *device = NULL;
862     DDSURFACEDESC2 surface_desc;
863     DDPIXELFORMAT z_fmt;
864     ULONG refcount;
865     HRESULT hr;
866     D3DCOLOR color;
867     HWND window;
868
869     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
870             0, 0, 640, 480, 0, 0, 0, 0);
871
872     if (!(ddraw = create_ddraw()))
873     {
874         skip("Failed to create a ddraw object, skipping test.\n");
875         goto cleanup;
876     }
877
878     hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
879     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
880
881     memset(&surface_desc, 0, sizeof(surface_desc));
882     surface_desc.dwSize = sizeof(surface_desc);
883     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
884     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
885     surface_desc.dwWidth = 640;
886     surface_desc.dwHeight = 480;
887
888     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface, NULL);
889     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
890
891     hr = IDirectDrawSurface7_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
892     ok(SUCCEEDED(hr), "Failed to QI IDirectDrawSurface3, hr %#x.\n", hr);
893
894     hr = IDirectDraw7_QueryInterface(ddraw, &IID_IDirect3D7, (void **)&d3d);
895     if (FAILED(hr))
896     {
897         skip("Failed to get the IDirect3D7 interface, skipping test.\n");
898         goto cleanup;
899     }
900
901     memset(&z_fmt, 0, sizeof(z_fmt));
902     hr = IDirect3D7_EnumZBufferFormats(d3d, &IID_IDirect3DTnLHalDevice, enum_z_fmt, &z_fmt);
903     if (FAILED(hr) || !z_fmt.dwSize)
904     {
905         skip("No depth buffer formats available, skipping test.\n");
906         goto cleanup;
907     }
908
909     memset(&surface_desc, 0, sizeof(surface_desc));
910     surface_desc.dwSize = sizeof(surface_desc);
911     surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
912     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
913     U4(surface_desc).ddpfPixelFormat = z_fmt;
914     surface_desc.dwWidth = 640;
915     surface_desc.dwHeight = 480;
916     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &ds, NULL);
917     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
918     if (FAILED(hr))
919         goto cleanup;
920
921     /* Using a different surface interface version still works */
922     hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
923     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
924     refcount = IDirectDrawSurface7_Release(ds);
925     ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
926     if (FAILED(hr))
927         goto cleanup;
928
929     /* Here too */
930     hr = IDirect3D7_CreateDevice(d3d, &IID_IDirect3DTnLHalDevice, (IDirectDrawSurface7 *)surface3, &device);
931     ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
932     if (FAILED(hr))
933         goto cleanup;
934
935     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffff0000, 0.0f, 0);
936     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
937     color = get_surface_color(surface, 320, 240);
938     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
939
940 cleanup:
941     if (surface3) IDirectDrawSurface3_Release(surface3);
942     if (surface) IDirectDrawSurface7_Release(surface);
943     if (device) IDirect3DDevice7_Release(device);
944     if (d3d) IDirect3D7_Release(d3d);
945     if (ddraw) IDirectDraw7_Release(ddraw);
946     DestroyWindow(window);
947 }
948
949 static void test_coop_level_threaded(void)
950 {
951     struct create_window_thread_param p;
952     IDirectDraw7 *ddraw;
953     HRESULT hr;
954
955     if (!(ddraw = create_ddraw()))
956     {
957         skip("Failed to create a ddraw object, skipping test.\n");
958         return;
959     }
960     create_window_thread(&p);
961
962     hr = IDirectDraw7_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
963     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
964
965     IDirectDraw7_Release(ddraw);
966     destroy_window_thread(&p);
967 }
968
969 static void test_depth_blit(void)
970 {
971     IDirect3DDevice7 *device;
972     static struct
973     {
974         float x, y, z;
975         DWORD color;
976     }
977     quad1[] =
978     {
979         { -1.0,  1.0, 0.50f, 0xff00ff00},
980         {  1.0,  1.0, 0.50f, 0xff00ff00},
981         { -1.0, -1.0, 0.50f, 0xff00ff00},
982         {  1.0, -1.0, 0.50f, 0xff00ff00},
983     };
984     static const D3DCOLOR expected_colors[4][4] =
985     {
986         {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
987         {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
988         {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
989         {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
990     };
991     DDSURFACEDESC2 ddsd_new, ddsd_existing;
992
993     IDirectDrawSurface7 *ds1, *ds2, *ds3, *rt;
994     RECT src_rect, dst_rect;
995     unsigned int i, j;
996     D3DCOLOR color;
997     HRESULT hr;
998     IDirect3D7 *d3d;
999     IDirectDraw7 *ddraw;
1000     DDBLTFX fx;
1001     HWND window;
1002
1003     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1004             0, 0, 640, 480, 0, 0, 0, 0);
1005     if (!(device = create_device(window, DDSCL_NORMAL)))
1006     {
1007         skip("Failed to create D3D device, skipping test.\n");
1008         DestroyWindow(window);
1009         return;
1010     }
1011
1012     hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
1013     ok(SUCCEEDED(hr), "Failed to get Direct3D7 interface, hr %#x.\n", hr);
1014     hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw);
1015     ok(SUCCEEDED(hr), "Failed to get DirectDraw7 interface, hr %#x.\n", hr);
1016     IDirect3D7_Release(d3d);
1017
1018     ds1 = get_depth_stencil(device);
1019
1020     memset(&ddsd_new, 0, sizeof(ddsd_new));
1021     ddsd_new.dwSize = sizeof(ddsd_new);
1022     memset(&ddsd_existing, 0, sizeof(ddsd_existing));
1023     ddsd_existing.dwSize = sizeof(ddsd_existing);
1024     hr = IDirectDrawSurface7_GetSurfaceDesc(ds1, &ddsd_existing);
1025     ddsd_new.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
1026     ddsd_new.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
1027     ddsd_new.dwWidth = ddsd_existing.dwWidth;
1028     ddsd_new.dwHeight = ddsd_existing.dwHeight;
1029     U4(ddsd_new).ddpfPixelFormat = U4(ddsd_existing).ddpfPixelFormat;
1030     hr = IDirectDraw7_CreateSurface(ddraw, &ddsd_new, &ds2, NULL);
1031     ok(SUCCEEDED(hr), "Failed to create a z buffer, hr %#x.\n", hr);
1032     hr = IDirectDraw7_CreateSurface(ddraw, &ddsd_new, &ds3, NULL);
1033     ok(SUCCEEDED(hr), "Failed to create a z buffer, hr %#x.\n", hr);
1034     IDirectDraw7_Release(ddraw);
1035
1036     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_TRUE);
1037     ok(SUCCEEDED(hr), "Failed to enable z testing, hr %#x.\n", hr);
1038     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
1039     ok(SUCCEEDED(hr), "Failed to set the z function, hr %#x.\n", hr);
1040     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
1041     ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr);
1042
1043     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_ZBUFFER, 0, 0.0f, 0);
1044     ok(SUCCEEDED(hr), "Failed to clear the z buffer, hr %#x.\n", hr);
1045
1046     /* Partial blit. */
1047     SetRect(&src_rect, 0, 0, 320, 240);
1048     SetRect(&dst_rect, 0, 0, 320, 240);
1049     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1050     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1051     /* Different locations. */
1052     SetRect(&src_rect, 0, 0, 320, 240);
1053     SetRect(&dst_rect, 320, 240, 640, 480);
1054     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1055     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1056     /* Streched. */
1057     SetRect(&src_rect, 0, 0, 320, 240);
1058     SetRect(&dst_rect, 0, 0, 640, 480);
1059     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1060     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1061     /* Flipped. */
1062     SetRect(&src_rect, 0, 480, 640, 0);
1063     SetRect(&dst_rect, 0, 0, 640, 480);
1064     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1065     ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
1066     SetRect(&src_rect, 0, 0, 640, 480);
1067     SetRect(&dst_rect, 0, 480, 640, 0);
1068     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1069     ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
1070     /* Full, explicit. */
1071     SetRect(&src_rect, 0, 0, 640, 480);
1072     SetRect(&dst_rect, 0, 0, 640, 480);
1073     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1074     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1075     /* Depth -> color blit: Succeeds on Win7 + Radeon HD 5700, fails on WinXP + Radeon X1600 */
1076
1077     /* Depth blit inside a BeginScene / EndScene pair */
1078     hr = IDirect3DDevice7_BeginScene(device);
1079     ok(SUCCEEDED(hr), "Failed to start scene, hr %#x.\n", hr);
1080     /* From the current depth stencil */
1081     hr = IDirectDrawSurface7_Blt(ds2, NULL, ds1, NULL, DDBLT_WAIT, NULL);
1082     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1083     /* To the current depth stencil */
1084     hr = IDirectDrawSurface7_Blt(ds1, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1085     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1086     /* Between unbound surfaces */
1087     hr = IDirectDrawSurface7_Blt(ds3, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1088     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1089     hr = IDirect3DDevice7_EndScene(device);
1090     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1091
1092     /* Avoid changing the depth stencil, it doesn't work properly on Windows.
1093      * Instead use DDBLT_DEPTHFILL to clear the depth stencil. Unfortunately
1094      * drivers disagree on the meaning of dwFillDepth. Only 0 seems to produce
1095      * a reliable result(z = 0.0) */
1096     memset(&fx, 0, sizeof(fx));
1097     fx.dwSize = sizeof(fx);
1098     hr = IDirectDrawSurface7_Blt(ds2, NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
1099     ok(SUCCEEDED(hr), "Failed to clear the source z buffer, hr %#x.\n", hr);
1100
1101     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET, 0xffff0000, 1.0f, 0);
1102     ok(SUCCEEDED(hr), "Failed to clear the color and z buffers, hr %#x.\n", hr);
1103     SetRect(&dst_rect, 0, 0, 320, 240);
1104     hr = IDirectDrawSurface7_Blt(ds1, &dst_rect, ds2, NULL, DDBLT_WAIT, NULL);
1105     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1106     IDirectDrawSurface7_Release(ds3);
1107     IDirectDrawSurface7_Release(ds2);
1108     IDirectDrawSurface7_Release(ds1);
1109
1110     hr = IDirect3DDevice7_BeginScene(device);
1111     ok(SUCCEEDED(hr), "Failed to start scene, hr %#x.\n", hr);
1112     hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ | D3DFVF_DIFFUSE,
1113             quad1, 4, 0);
1114     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1115     hr = IDirect3DDevice7_EndScene(device);
1116     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1117
1118     hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
1119     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1120     for (i = 0; i < 4; ++i)
1121     {
1122         for (j = 0; j < 4; ++j)
1123         {
1124             unsigned int x = 80 * ((2 * j) + 1);
1125             unsigned int y = 60 * ((2 * i) + 1);
1126             color = get_surface_color(rt, x, y);
1127             ok(compare_color(color, expected_colors[i][j], 1),
1128                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected_colors[i][j], x, y, color);
1129         }
1130     }
1131
1132     IDirectDrawSurface7_Release(rt);
1133     IDirect3DDevice7_Release(device);
1134     DestroyWindow(window);
1135 }
1136
1137 static void test_texture_load_ckey(void)
1138 {
1139     HWND window;
1140     IDirect3DDevice7 *device;
1141     IDirectDraw7 *ddraw;
1142     IDirectDrawSurface7 *src;
1143     IDirectDrawSurface7 *dst;
1144     DDSURFACEDESC2 ddsd;
1145     HRESULT hr;
1146     DDCOLORKEY ckey;
1147     IDirect3D7 *d3d;
1148
1149     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1150             0, 0, 640, 480, 0, 0, 0, 0);
1151     if (!(device = create_device(window, DDSCL_NORMAL)))
1152     {
1153         skip("Failed to create D3D device, skipping test.\n");
1154         DestroyWindow(window);
1155         return;
1156     }
1157
1158     hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
1159     ok(SUCCEEDED(hr), "Failed to get Direct3D7 interface, hr %#x.\n", hr);
1160     hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw);
1161     ok(SUCCEEDED(hr), "Failed to get DirectDraw7 interface, hr %#x.\n", hr);
1162     IDirect3D7_Release(d3d);
1163
1164     memset(&ddsd, 0, sizeof(ddsd));
1165     ddsd.dwSize = sizeof(ddsd);
1166     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1167     ddsd.dwHeight = 128;
1168     ddsd.dwWidth = 128;
1169     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
1170     hr = IDirectDraw7_CreateSurface(ddraw, &ddsd, &src, NULL);
1171     ok(SUCCEEDED(hr), "Failed to create source texture, hr %#x.\n", hr);
1172     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1173     hr = IDirectDraw7_CreateSurface(ddraw, &ddsd, &dst, NULL);
1174     ok(SUCCEEDED(hr), "Failed to create destination texture, hr %#x.\n", hr);
1175
1176     /* No surface has a color key */
1177     hr = IDirect3DDevice7_Load(device, dst, NULL, src, NULL, 0);
1178     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1179     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0xdeadbeef;
1180     hr = IDirectDrawSurface7_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1181     ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1182     ok(ckey.dwColorSpaceLowValue == 0xdeadbeef, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1183     ok(ckey.dwColorSpaceHighValue == 0xdeadbeef, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1184
1185     /* Source surface has a color key */
1186     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
1187     hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
1188     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1189     hr = IDirect3DDevice7_Load(device, dst, NULL, src, NULL, 0);
1190     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1191     hr = IDirectDrawSurface7_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1192     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1193     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1194     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1195
1196     /* Both surfaces have a color key: Dest ckey is overwritten */
1197     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x000000ff;
1198     hr = IDirectDrawSurface7_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1199     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1200     hr = IDirect3DDevice7_Load(device, dst, NULL, src, NULL, 0);
1201     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1202     hr = IDirectDrawSurface7_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1203     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1204     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1205     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1206
1207     /* Only the destination has a color key: It is deleted. This behavior differs from
1208      * IDirect3DTexture(2)::Load */
1209     hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_SRCBLT, NULL);
1210     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1211     hr = IDirectDrawSurface7_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
1212     ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1213     hr = IDirect3DDevice7_Load(device, dst, NULL, src, NULL, 0);
1214     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1215     hr = IDirectDrawSurface7_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1216     todo_wine ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1217
1218     IDirectDrawSurface7_Release(dst);
1219     IDirectDrawSurface7_Release(src);
1220     IDirectDraw7_Release(ddraw);
1221     IDirect3DDevice7_Release(device);
1222 }
1223
1224 static void test_zenable(void)
1225 {
1226     static struct
1227     {
1228         struct vec4 position;
1229         D3DCOLOR diffuse;
1230     }
1231     tquad[] =
1232     {
1233         {{  0.0f, 480.0f, -0.5f, 1.0f}, 0xff00ff00},
1234         {{  0.0f,   0.0f, -0.5f, 1.0f}, 0xff00ff00},
1235         {{640.0f, 480.0f,  1.5f, 1.0f}, 0xff00ff00},
1236         {{640.0f,   0.0f,  1.5f, 1.0f}, 0xff00ff00},
1237     };
1238     IDirect3DDevice7 *device;
1239     IDirectDrawSurface7 *rt;
1240     D3DCOLOR color;
1241     HWND window;
1242     HRESULT hr;
1243     UINT x, y;
1244     UINT i, j;
1245
1246     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1247             0, 0, 640, 480, 0, 0, 0, 0);
1248     if (!(device = create_device(window, DDSCL_NORMAL)))
1249     {
1250         skip("Failed to create D3D device, skipping test.\n");
1251         DestroyWindow(window);
1252         return;
1253     }
1254
1255     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1256     ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#x.\n", hr);
1257
1258     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffff0000, 0.0f, 0);
1259     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
1260     hr = IDirect3DDevice7_BeginScene(device);
1261     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1262     hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_DIFFUSE, tquad, 4, 0);
1263     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1264     hr = IDirect3DDevice7_EndScene(device);
1265     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1266
1267     hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
1268     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1269     for (i = 0; i < 4; ++i)
1270     {
1271         for (j = 0; j < 4; ++j)
1272         {
1273             x = 80 * ((2 * j) + 1);
1274             y = 60 * ((2 * i) + 1);
1275             color = get_surface_color(rt, x, y);
1276             ok(compare_color(color, 0x0000ff00, 1),
1277                     "Expected color 0x0000ff00 at %u, %u, got 0x%08x.\n", x, y, color);
1278         }
1279     }
1280     IDirectDrawSurface7_Release(rt);
1281
1282     IDirect3DDevice7_Release(device);
1283     DestroyWindow(window);
1284 }
1285
1286 static void test_ck_rgba(void)
1287 {
1288     static struct
1289     {
1290         struct vec4 position;
1291         struct vec2 texcoord;
1292     }
1293     tquad[] =
1294     {
1295         {{  0.0f, 480.0f, 0.25f, 1.0f}, {0.0f, 0.0f}},
1296         {{  0.0f,   0.0f, 0.25f, 1.0f}, {0.0f, 1.0f}},
1297         {{640.0f, 480.0f, 0.25f, 1.0f}, {1.0f, 0.0f}},
1298         {{640.0f,   0.0f, 0.25f, 1.0f}, {1.0f, 1.0f}},
1299         {{  0.0f, 480.0f, 0.75f, 1.0f}, {0.0f, 0.0f}},
1300         {{  0.0f,   0.0f, 0.75f, 1.0f}, {0.0f, 1.0f}},
1301         {{640.0f, 480.0f, 0.75f, 1.0f}, {1.0f, 0.0f}},
1302         {{640.0f,   0.0f, 0.75f, 1.0f}, {1.0f, 1.0f}},
1303     };
1304     static const struct
1305     {
1306         D3DCOLOR fill_color;
1307         BOOL color_key;
1308         BOOL blend;
1309         D3DCOLOR result1;
1310         D3DCOLOR result2;
1311     }
1312     tests[] =
1313     {
1314         {0xff00ff00, TRUE,  TRUE,  0x00ff0000, 0x000000ff},
1315         {0xff00ff00, TRUE,  FALSE, 0x00ff0000, 0x000000ff},
1316         {0xff00ff00, FALSE, TRUE,  0x0000ff00, 0x0000ff00},
1317         {0xff00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1318         {0x7f00ff00, TRUE,  TRUE,  0x00807f00, 0x00807f00},
1319         {0x7f00ff00, TRUE,  FALSE, 0x0000ff00, 0x0000ff00},
1320         {0x7f00ff00, FALSE, TRUE,  0x00807f00, 0x00807f00},
1321         {0x7f00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1322     };
1323
1324     IDirectDrawSurface7 *texture;
1325     DDSURFACEDESC2 surface_desc;
1326     IDirect3DDevice7 *device;
1327     IDirectDrawSurface7 *rt;
1328     IDirectDraw7 *ddraw;
1329     IDirect3D7 *d3d;
1330     D3DCOLOR color;
1331     HWND window;
1332     DDBLTFX fx;
1333     HRESULT hr;
1334     UINT i;
1335
1336     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1337             0, 0, 640, 480, 0, 0, 0, 0);
1338     if (!(device = create_device(window, DDSCL_NORMAL)))
1339     {
1340         skip("Failed to create D3D device, skipping test.\n");
1341         DestroyWindow(window);
1342         return;
1343     }
1344
1345     hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
1346     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
1347     hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw);
1348     ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr);
1349     IDirect3D7_Release(d3d);
1350
1351     memset(&surface_desc, 0, sizeof(surface_desc));
1352     surface_desc.dwSize = sizeof(surface_desc);
1353     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1354     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1355     surface_desc.dwWidth = 256;
1356     surface_desc.dwHeight = 256;
1357     U4(surface_desc).ddpfPixelFormat.dwSize = sizeof(U4(surface_desc).ddpfPixelFormat);
1358     U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
1359     U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount = 32;
1360     U2(U4(surface_desc).ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1361     U3(U4(surface_desc).ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1362     U4(U4(surface_desc).ddpfPixelFormat).dwBBitMask = 0x000000ff;
1363     U5(U4(surface_desc).ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
1364     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0xff00ff00;
1365     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0xff00ff00;
1366     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &texture, NULL);
1367     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
1368
1369     hr = IDirect3DDevice7_SetTexture(device, 0, texture);
1370     ok(SUCCEEDED(hr), "Failed to set texture, hr %#x.\n", hr);
1371     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
1372     ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1373     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
1374     ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1375
1376     hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
1377     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1378
1379     for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
1380     {
1381         hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, tests[i].color_key);
1382         ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1383         hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, tests[i].blend);
1384         ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1385
1386         memset(&fx, 0, sizeof(fx));
1387         fx.dwSize = sizeof(fx);
1388         U5(fx).dwFillColor = tests[i].fill_color;
1389         hr = IDirectDrawSurface7_Blt(texture, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1390         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1391
1392         hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffff0000, 1.0f, 0);
1393         ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
1394         hr = IDirect3DDevice7_BeginScene(device);
1395         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1396         hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_TEX1, &tquad[0], 4, 0);
1397         ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1398         hr = IDirect3DDevice7_EndScene(device);
1399         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1400
1401         color = get_surface_color(rt, 320, 240);
1402         if (i == 2)
1403             todo_wine ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1404                     tests[i].result1, i, color);
1405         else
1406             ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1407                     tests[i].result1, i, color);
1408
1409         U5(fx).dwFillColor = 0xff0000ff;
1410         hr = IDirectDrawSurface7_Blt(texture, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1411         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1412
1413         hr = IDirect3DDevice7_BeginScene(device);
1414         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1415         hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_TEX1, &tquad[4], 4, 0);
1416         ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1417         hr = IDirect3DDevice7_EndScene(device);
1418         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1419
1420         /* This tests that fragments that are masked out by the color key are
1421          * discarded, instead of just fully transparent. */
1422         color = get_surface_color(rt, 320, 240);
1423         if (i == 2)
1424             todo_wine ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1425                     tests[i].result2, i, color);
1426         else
1427             ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1428                     tests[i].result2, i, color);
1429     }
1430
1431     IDirectDrawSurface7_Release(rt);
1432     IDirectDrawSurface7_Release(texture);
1433     IDirectDraw7_Release(ddraw);
1434     IDirect3DDevice7_Release(device);
1435     DestroyWindow(window);
1436 }
1437
1438 struct qi_test
1439 {
1440     REFIID iid;
1441     REFIID refcount_iid;
1442     HRESULT hr;
1443 };
1444
1445 static void test_qi(const char *test_name, IUnknown *base_iface,
1446         REFIID refcount_iid, const struct qi_test *tests, UINT entry_count)
1447 {
1448     ULONG refcount, expected_refcount;
1449     IUnknown *iface1, *iface2;
1450     HRESULT hr;
1451     UINT i, j;
1452
1453     for (i = 0; i < entry_count; ++i)
1454     {
1455         hr = IUnknown_QueryInterface(base_iface, tests[i].iid, (void **)&iface1);
1456         ok(hr == tests[i].hr, "Got hr %#x for test \"%s\" %u.\n", hr, test_name, i);
1457         if (SUCCEEDED(hr))
1458         {
1459             for (j = 0; j < entry_count; ++j)
1460             {
1461                 hr = IUnknown_QueryInterface(iface1, tests[j].iid, (void **)&iface2);
1462                 ok(hr == tests[j].hr, "Got hr %#x for test \"%s\" %u, %u.\n", hr, test_name, i, j);
1463                 if (SUCCEEDED(hr))
1464                 {
1465                     expected_refcount = 0;
1466                     if (IsEqualGUID(refcount_iid, tests[j].refcount_iid))
1467                         ++expected_refcount;
1468                     if (IsEqualGUID(tests[i].refcount_iid, tests[j].refcount_iid))
1469                         ++expected_refcount;
1470                     refcount = IUnknown_Release(iface2);
1471                     ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, %u, expected %u.\n",
1472                             refcount, test_name, i, j, expected_refcount);
1473                 }
1474             }
1475
1476             expected_refcount = 0;
1477             if (IsEqualGUID(refcount_iid, tests[i].refcount_iid))
1478                 ++expected_refcount;
1479             refcount = IUnknown_Release(iface1);
1480             ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, expected %u.\n",
1481                     refcount, test_name, i, expected_refcount);
1482         }
1483     }
1484 }
1485
1486 static void test_surface_qi(void)
1487 {
1488     static const struct qi_test tests[] =
1489     {
1490         {&IID_IDirect3DTexture2,        NULL,                           E_NOINTERFACE},
1491         {&IID_IDirect3DTexture,         NULL,                           E_NOINTERFACE},
1492         {&IID_IDirectDrawGammaControl,  &IID_IDirectDrawGammaControl,   S_OK         },
1493         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1494         {&IID_IDirectDrawSurface7,      &IID_IDirectDrawSurface7,       S_OK         },
1495         {&IID_IDirectDrawSurface4,      &IID_IDirectDrawSurface4,       S_OK         },
1496         {&IID_IDirectDrawSurface3,      &IID_IDirectDrawSurface3,       S_OK         },
1497         {&IID_IDirectDrawSurface2,      &IID_IDirectDrawSurface2,       S_OK         },
1498         {&IID_IDirectDrawSurface,       &IID_IDirectDrawSurface,        S_OK         },
1499         {&IID_IDirect3DDevice7,         NULL,                           E_NOINTERFACE},
1500         {&IID_IDirect3DDevice3,         NULL,                           E_NOINTERFACE},
1501         {&IID_IDirect3DDevice2,         NULL,                           E_NOINTERFACE},
1502         {&IID_IDirect3DDevice,          NULL,                           E_NOINTERFACE},
1503         {&IID_IDirect3DRampDevice,      NULL,                           E_NOINTERFACE},
1504         {&IID_IDirect3DRGBDevice,       NULL,                           E_NOINTERFACE},
1505         {&IID_IDirect3DHALDevice,       NULL,                           E_NOINTERFACE},
1506         {&IID_IDirect3DMMXDevice,       NULL,                           E_NOINTERFACE},
1507         {&IID_IDirect3DRefDevice,       NULL,                           E_NOINTERFACE},
1508         {&IID_IDirect3DTnLHalDevice,    NULL,                           E_NOINTERFACE},
1509         {&IID_IDirect3DNullDevice,      NULL,                           E_NOINTERFACE},
1510         {&IID_IDirect3D7,               NULL,                           E_NOINTERFACE},
1511         {&IID_IDirect3D3,               NULL,                           E_NOINTERFACE},
1512         {&IID_IDirect3D2,               NULL,                           E_NOINTERFACE},
1513         {&IID_IDirect3D,                NULL,                           E_NOINTERFACE},
1514         {&IID_IDirectDraw7,             NULL,                           E_NOINTERFACE},
1515         {&IID_IDirectDraw4,             NULL,                           E_NOINTERFACE},
1516         {&IID_IDirectDraw3,             NULL,                           E_NOINTERFACE},
1517         {&IID_IDirectDraw2,             NULL,                           E_NOINTERFACE},
1518         {&IID_IDirectDraw,              NULL,                           E_NOINTERFACE},
1519         {&IID_IDirect3DLight,           NULL,                           E_NOINTERFACE},
1520         {&IID_IDirect3DMaterial,        NULL,                           E_NOINTERFACE},
1521         {&IID_IDirect3DMaterial2,       NULL,                           E_NOINTERFACE},
1522         {&IID_IDirect3DMaterial3,       NULL,                           E_NOINTERFACE},
1523         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_NOINTERFACE},
1524         {&IID_IDirect3DViewport,        NULL,                           E_NOINTERFACE},
1525         {&IID_IDirect3DViewport2,       NULL,                           E_NOINTERFACE},
1526         {&IID_IDirect3DViewport3,       NULL,                           E_NOINTERFACE},
1527         {&IID_IDirect3DVertexBuffer,    NULL,                           E_NOINTERFACE},
1528         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_NOINTERFACE},
1529         {&IID_IDirectDrawPalette,       NULL,                           E_NOINTERFACE},
1530         {&IID_IDirectDrawClipper,       NULL,                           E_NOINTERFACE},
1531         {&IID_IUnknown,                 &IID_IDirectDrawSurface,        S_OK         },
1532     };
1533
1534     IDirectDrawSurface7 *surface;
1535     DDSURFACEDESC2 surface_desc;
1536     IDirect3DDevice7 *device;
1537     IDirectDraw7 *ddraw;
1538     HWND window;
1539     HRESULT hr;
1540
1541     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1542             0, 0, 640, 480, 0, 0, 0, 0);
1543     /* Try to create a D3D device to see if the ddraw implementation supports
1544      * D3D. 64-bit ddraw in particular doesn't seem to support D3D, and
1545      * doesn't support e.g. the IDirect3DTexture interfaces. */
1546     if (!(device = create_device(window, DDSCL_NORMAL)))
1547     {
1548         skip("Failed to create D3D device, skipping test.\n");
1549         DestroyWindow(window);
1550         return;
1551     }
1552     IDirect3DDevice_Release(device);
1553     if (!(ddraw = create_ddraw()))
1554     {
1555         skip("Failed to create a ddraw object, skipping test.\n");
1556         DestroyWindow(window);
1557         return;
1558     }
1559     hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
1560     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
1561
1562     memset(&surface_desc, 0, sizeof(surface_desc));
1563     surface_desc.dwSize = sizeof(surface_desc);
1564     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1565     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1566     surface_desc.dwWidth = 512;
1567     surface_desc.dwHeight = 512;
1568     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1569     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1570
1571     test_qi("surface_qi", (IUnknown *)surface, &IID_IDirectDrawSurface7, tests, sizeof(tests) / sizeof(*tests));
1572
1573     IDirectDrawSurface7_Release(surface);
1574     IDirectDraw7_Release(ddraw);
1575     DestroyWindow(window);
1576 }
1577
1578 static void test_device_qi(void)
1579 {
1580     static const struct qi_test tests[] =
1581     {
1582         {&IID_IDirect3DTexture2,        NULL,                           E_NOINTERFACE},
1583         {&IID_IDirect3DTexture,         NULL,                           E_NOINTERFACE},
1584         {&IID_IDirectDrawGammaControl,  NULL,                           E_NOINTERFACE},
1585         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1586         {&IID_IDirectDrawSurface7,      NULL,                           E_NOINTERFACE},
1587         {&IID_IDirectDrawSurface4,      NULL,                           E_NOINTERFACE},
1588         {&IID_IDirectDrawSurface3,      NULL,                           E_NOINTERFACE},
1589         {&IID_IDirectDrawSurface2,      NULL,                           E_NOINTERFACE},
1590         {&IID_IDirectDrawSurface,       NULL,                           E_NOINTERFACE},
1591         {&IID_IDirect3DDevice7,         &IID_IDirect3DDevice7,          S_OK         },
1592         {&IID_IDirect3DDevice3,         NULL,                           E_NOINTERFACE},
1593         {&IID_IDirect3DDevice2,         NULL,                           E_NOINTERFACE},
1594         {&IID_IDirect3DDevice,          NULL,                           E_NOINTERFACE},
1595         {&IID_IDirect3DRampDevice,      NULL,                           E_NOINTERFACE},
1596         {&IID_IDirect3DRGBDevice,       NULL,                           E_NOINTERFACE},
1597         {&IID_IDirect3DHALDevice,       NULL,                           E_NOINTERFACE},
1598         {&IID_IDirect3DMMXDevice,       NULL,                           E_NOINTERFACE},
1599         {&IID_IDirect3DRefDevice,       NULL,                           E_NOINTERFACE},
1600         {&IID_IDirect3DTnLHalDevice,    NULL,                           E_NOINTERFACE},
1601         {&IID_IDirect3DNullDevice,      NULL,                           E_NOINTERFACE},
1602         {&IID_IDirect3D7,               NULL,                           E_NOINTERFACE},
1603         {&IID_IDirect3D3,               NULL,                           E_NOINTERFACE},
1604         {&IID_IDirect3D2,               NULL,                           E_NOINTERFACE},
1605         {&IID_IDirect3D,                NULL,                           E_NOINTERFACE},
1606         {&IID_IDirectDraw7,             NULL,                           E_NOINTERFACE},
1607         {&IID_IDirectDraw4,             NULL,                           E_NOINTERFACE},
1608         {&IID_IDirectDraw3,             NULL,                           E_NOINTERFACE},
1609         {&IID_IDirectDraw2,             NULL,                           E_NOINTERFACE},
1610         {&IID_IDirectDraw,              NULL,                           E_NOINTERFACE},
1611         {&IID_IDirect3DLight,           NULL,                           E_NOINTERFACE},
1612         {&IID_IDirect3DMaterial,        NULL,                           E_NOINTERFACE},
1613         {&IID_IDirect3DMaterial2,       NULL,                           E_NOINTERFACE},
1614         {&IID_IDirect3DMaterial3,       NULL,                           E_NOINTERFACE},
1615         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_NOINTERFACE},
1616         {&IID_IDirect3DViewport,        NULL,                           E_NOINTERFACE},
1617         {&IID_IDirect3DViewport2,       NULL,                           E_NOINTERFACE},
1618         {&IID_IDirect3DViewport3,       NULL,                           E_NOINTERFACE},
1619         {&IID_IDirect3DVertexBuffer,    NULL,                           E_NOINTERFACE},
1620         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_NOINTERFACE},
1621         {&IID_IDirectDrawPalette,       NULL,                           E_NOINTERFACE},
1622         {&IID_IDirectDrawClipper,       NULL,                           E_NOINTERFACE},
1623         {&IID_IUnknown,                 &IID_IDirect3DDevice7,          S_OK         },
1624     };
1625
1626     IDirect3DDevice7 *device;
1627     HWND window;
1628
1629     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1630             0, 0, 640, 480, 0, 0, 0, 0);
1631     if (!(device = create_device(window, DDSCL_NORMAL)))
1632     {
1633         skip("Failed to create D3D device, skipping test.\n");
1634         DestroyWindow(window);
1635         return;
1636     }
1637
1638     test_qi("device_qi", (IUnknown *)device, &IID_IDirect3DDevice7, tests, sizeof(tests) / sizeof(*tests));
1639
1640     IDirect3DDevice7_Release(device);
1641     DestroyWindow(window);
1642 }
1643
1644 START_TEST(ddraw7)
1645 {
1646     HMODULE module = GetModuleHandleA("ddraw.dll");
1647
1648     if (!(pDirectDrawCreateEx = (void *)GetProcAddress(module, "DirectDrawCreateEx")))
1649     {
1650         win_skip("DirectDrawCreateEx not available, skipping tests.\n");
1651         return;
1652     }
1653
1654     test_process_vertices();
1655     test_coop_level_create_device_window();
1656     test_clipper_blt();
1657     test_coop_level_d3d_state();
1658     test_surface_interface_mismatch();
1659     test_coop_level_threaded();
1660     test_depth_blit();
1661     test_texture_load_ckey();
1662     test_zenable();
1663     test_ck_rgba();
1664     test_surface_qi();
1665     test_device_qi();
1666 }