ddraw/tests: Add tests for z-clipping with D3DRENDERSTATE_ZENABLE disabled.
[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
20 #include "wine/test.h"
21 #include <limits.h>
22 #include "d3d.h"
23
24 static HRESULT (WINAPI *pDirectDrawCreateEx)(GUID *guid, void **ddraw, REFIID iid, IUnknown *outer_unknown);
25
26 struct vec3
27 {
28     float x, y, z;
29 };
30
31 struct vec4
32 {
33     float x, y, z, w;
34 };
35
36 struct create_window_thread_param
37 {
38     HWND window;
39     HANDLE window_created;
40     HANDLE destroy_window;
41     HANDLE thread;
42 };
43
44 static BOOL compare_float(float f, float g, unsigned int ulps)
45 {
46     int x = *(int *)&f;
47     int y = *(int *)&g;
48
49     if (x < 0)
50         x = INT_MIN - x;
51     if (y < 0)
52         y = INT_MIN - y;
53
54     if (abs(x - y) > ulps)
55         return FALSE;
56
57     return TRUE;
58 }
59
60 static BOOL compare_vec3(struct vec3 *vec, float x, float y, float z, unsigned int ulps)
61 {
62     return compare_float(vec->x, x, ulps)
63             && compare_float(vec->y, y, ulps)
64             && compare_float(vec->z, z, ulps);
65 }
66
67 static BOOL compare_vec4(struct vec4 *vec, float x, float y, float z, float w, unsigned int ulps)
68 {
69     return compare_float(vec->x, x, ulps)
70             && compare_float(vec->y, y, ulps)
71             && compare_float(vec->z, z, ulps)
72             && compare_float(vec->w, w, ulps);
73 }
74
75 static BOOL compare_color(D3DCOLOR c1, D3DCOLOR c2, BYTE max_diff)
76 {
77     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
78     c1 >>= 8; c2 >>= 8;
79     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
80     c1 >>= 8; c2 >>= 8;
81     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
82     c1 >>= 8; c2 >>= 8;
83     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
84     return TRUE;
85 }
86
87 static DWORD WINAPI create_window_thread_proc(void *param)
88 {
89     struct create_window_thread_param *p = param;
90     DWORD res;
91     BOOL ret;
92
93     p->window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
94             0, 0, 640, 480, 0, 0, 0, 0);
95     ret = SetEvent(p->window_created);
96     ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
97
98     for (;;)
99     {
100         MSG msg;
101
102         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
103             DispatchMessage(&msg);
104         res = WaitForSingleObject(p->destroy_window, 100);
105         if (res == WAIT_OBJECT_0)
106             break;
107         if (res != WAIT_TIMEOUT)
108         {
109             ok(0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
110             break;
111         }
112     }
113
114     DestroyWindow(p->window);
115
116     return 0;
117 }
118
119 static void create_window_thread(struct create_window_thread_param *p)
120 {
121     DWORD res, tid;
122
123     p->window_created = CreateEvent(NULL, FALSE, FALSE, NULL);
124     ok(!!p->window_created, "CreateEvent failed, last error %#x.\n", GetLastError());
125     p->destroy_window = CreateEvent(NULL, FALSE, FALSE, NULL);
126     ok(!!p->destroy_window, "CreateEvent failed, last error %#x.\n", GetLastError());
127     p->thread = CreateThread(NULL, 0, create_window_thread_proc, p, 0, &tid);
128     ok(!!p->thread, "Failed to create thread, last error %#x.\n", GetLastError());
129     res = WaitForSingleObject(p->window_created, INFINITE);
130     ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
131 }
132
133 static void destroy_window_thread(struct create_window_thread_param *p)
134 {
135     SetEvent(p->destroy_window);
136     WaitForSingleObject(p->thread, INFINITE);
137     CloseHandle(p->destroy_window);
138     CloseHandle(p->window_created);
139     CloseHandle(p->thread);
140 }
141
142 static IDirectDrawSurface7 *get_depth_stencil(IDirect3DDevice7 *device)
143 {
144     IDirectDrawSurface7 *rt, *ret;
145     DDSCAPS2 caps = {DDSCAPS_ZBUFFER, 0, 0, 0};
146     HRESULT hr;
147
148     hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
149     ok(SUCCEEDED(hr), "Failed to get the render target, hr %#x.\n", hr);
150     hr = IDirectDrawSurface7_GetAttachedSurface(rt, &caps, &ret);
151     ok(SUCCEEDED(hr) || hr == DDERR_NOTFOUND, "Failed to get the z buffer, hr %#x.\n", hr);
152     IDirectDrawSurface7_Release(rt);
153     return ret;
154 }
155
156 static D3DCOLOR get_surface_color(IDirectDrawSurface7 *surface, UINT x, UINT y)
157 {
158     RECT rect = {x, y, x + 1, y + 1};
159     DDSURFACEDESC2 surface_desc;
160     D3DCOLOR color;
161     HRESULT hr;
162
163     memset(&surface_desc, 0, sizeof(surface_desc));
164     surface_desc.dwSize = sizeof(surface_desc);
165
166     hr = IDirectDrawSurface7_Lock(surface, &rect, &surface_desc, DDLOCK_READONLY, NULL);
167     ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
168     if (FAILED(hr))
169         return 0xdeadbeef;
170
171     color = *((DWORD *)surface_desc.lpSurface) & 0x00ffffff;
172
173     hr = IDirectDrawSurface7_Unlock(surface, &rect);
174     ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
175
176     return color;
177 }
178
179 static HRESULT CALLBACK enum_z_fmt(DDPIXELFORMAT *format, void *ctx)
180 {
181     DDPIXELFORMAT *z_fmt = ctx;
182
183     if (U1(*format).dwZBufferBitDepth > U1(*z_fmt).dwZBufferBitDepth)
184         *z_fmt = *format;
185
186     return DDENUMRET_OK;
187 }
188
189 static IDirectDraw7 *create_ddraw(void)
190 {
191     IDirectDraw7 *ddraw;
192
193     if (FAILED(pDirectDrawCreateEx(NULL, (void **)&ddraw, &IID_IDirectDraw7, NULL)))
194         return NULL;
195
196     return ddraw;
197 }
198
199 static IDirect3DDevice7 *create_device(HWND window, DWORD coop_level)
200 {
201     IDirectDrawSurface7 *surface, *ds;
202     IDirect3DDevice7 *device = NULL;
203     DDSURFACEDESC2 surface_desc;
204     DDPIXELFORMAT z_fmt;
205     IDirectDraw7 *ddraw;
206     IDirect3D7 *d3d7;
207     HRESULT hr;
208
209     if (!(ddraw = create_ddraw()))
210         return NULL;
211
212     hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, coop_level);
213     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
214
215     memset(&surface_desc, 0, sizeof(surface_desc));
216     surface_desc.dwSize = sizeof(surface_desc);
217     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
218     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
219     surface_desc.dwWidth = 640;
220     surface_desc.dwHeight = 480;
221
222     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface, NULL);
223     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
224
225     if (coop_level & DDSCL_NORMAL)
226     {
227         IDirectDrawClipper *clipper;
228
229         hr = IDirectDraw7_CreateClipper(ddraw, 0, &clipper, NULL);
230         ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
231         hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
232         ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
233         hr = IDirectDrawSurface7_SetClipper(surface, clipper);
234         ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#x.\n", hr);
235         IDirectDrawClipper_Release(clipper);
236     }
237
238     hr = IDirectDraw7_QueryInterface(ddraw, &IID_IDirect3D7, (void **)&d3d7);
239     IDirectDraw7_Release(ddraw);
240     if (FAILED(hr))
241     {
242         IDirectDrawSurface7_Release(surface);
243         return NULL;
244     }
245
246     memset(&z_fmt, 0, sizeof(z_fmt));
247     hr = IDirect3D7_EnumZBufferFormats(d3d7, &IID_IDirect3DTnLHalDevice, enum_z_fmt, &z_fmt);
248     if (FAILED(hr) || !z_fmt.dwSize)
249     {
250         IDirect3D7_Release(d3d7);
251         IDirectDrawSurface7_Release(surface);
252         return NULL;
253     }
254
255     memset(&surface_desc, 0, sizeof(surface_desc));
256     surface_desc.dwSize = sizeof(surface_desc);
257     surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
258     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
259     U4(surface_desc).ddpfPixelFormat = z_fmt;
260     surface_desc.dwWidth = 640;
261     surface_desc.dwHeight = 480;
262     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &ds, NULL);
263     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
264     if (FAILED(hr))
265     {
266         IDirect3D7_Release(d3d7);
267         IDirectDrawSurface7_Release(surface);
268         return NULL;
269     }
270
271     hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
272     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
273     IDirectDrawSurface7_Release(ds);
274     if (FAILED(hr))
275     {
276         IDirect3D7_Release(d3d7);
277         IDirectDrawSurface7_Release(surface);
278         return NULL;
279     }
280
281     hr = IDirect3D7_CreateDevice(d3d7, &IID_IDirect3DTnLHalDevice, surface, &device);
282     IDirect3D7_Release(d3d7);
283     IDirectDrawSurface7_Release(surface);
284     if (FAILED(hr))
285         return NULL;
286
287     return device;
288 }
289
290 static void test_process_vertices(void)
291 {
292     IDirect3DVertexBuffer7 *src_vb, *dst_vb1, *dst_vb2;
293     D3DVERTEXBUFFERDESC vb_desc;
294     IDirect3DDevice7 *device;
295     struct vec4 *dst_data;
296     struct vec3 *dst_data2;
297     struct vec3 *src_data;
298     IDirect3D7 *d3d7;
299     D3DVIEWPORT7 vp;
300     HWND window;
301     HRESULT hr;
302
303     static D3DMATRIX world =
304     {
305         0.0f,  1.0f, 0.0f, 0.0f,
306         1.0f,  0.0f, 0.0f, 0.0f,
307         0.0f,  0.0f, 0.0f, 1.0f,
308         0.0f,  1.0f, 1.0f, 1.0f,
309     };
310     static D3DMATRIX view =
311     {
312         2.0f,  0.0f, 0.0f, 0.0f,
313         0.0f, -1.0f, 0.0f, 0.0f,
314         0.0f,  0.0f, 1.0f, 0.0f,
315         0.0f,  0.0f, 0.0f, 3.0f,
316     };
317     static D3DMATRIX proj =
318     {
319         1.0f,  0.0f, 0.0f, 1.0f,
320         0.0f,  1.0f, 1.0f, 0.0f,
321         0.0f,  1.0f, 1.0f, 0.0f,
322         1.0f,  0.0f, 0.0f, 1.0f,
323     };
324
325     window = CreateWindowA("static", "d3d7_test", WS_OVERLAPPEDWINDOW,
326             0, 0, 640, 480, 0, 0, 0, 0);
327     if (!(device = create_device(window, DDSCL_NORMAL)))
328     {
329         skip("Failed to create a ddraw object, skipping test.\n");
330         DestroyWindow(window);
331         return;
332     }
333
334     hr = IDirect3DDevice7_GetDirect3D(device, &d3d7);
335     ok(SUCCEEDED(hr), "Failed to get Direct3D7 interface, hr %#x.\n", hr);
336
337     memset(&vb_desc, 0, sizeof(vb_desc));
338     vb_desc.dwSize = sizeof(vb_desc);
339     vb_desc.dwFVF = D3DFVF_XYZ;
340     vb_desc.dwNumVertices = 4;
341     hr = IDirect3D7_CreateVertexBuffer(d3d7, &vb_desc, &src_vb, 0);
342     ok(SUCCEEDED(hr), "Failed to create source vertex buffer, hr %#x.\n", hr);
343
344     hr = IDirect3DVertexBuffer7_Lock(src_vb, 0, (void **)&src_data, NULL);
345     ok(SUCCEEDED(hr), "Failed to lock source vertex buffer, hr %#x.\n", hr);
346     src_data[0].x = 0.0f;
347     src_data[0].y = 0.0f;
348     src_data[0].z = 0.0f;
349     src_data[1].x = 1.0f;
350     src_data[1].y = 1.0f;
351     src_data[1].z = 1.0f;
352     src_data[2].x = -1.0f;
353     src_data[2].y = -1.0f;
354     src_data[2].z = 0.5f;
355     src_data[3].x = 0.5f;
356     src_data[3].y = -0.5f;
357     src_data[3].z = 0.25f;
358     hr = IDirect3DVertexBuffer7_Unlock(src_vb);
359     ok(SUCCEEDED(hr), "Failed to unlock source vertex buffer, hr %#x.\n", hr);
360
361     memset(&vb_desc, 0, sizeof(vb_desc));
362     vb_desc.dwSize = sizeof(vb_desc);
363     vb_desc.dwFVF = D3DFVF_XYZRHW;
364     vb_desc.dwNumVertices = 4;
365     /* MSDN says that the last parameter must be 0 - check that. */
366     hr = IDirect3D7_CreateVertexBuffer(d3d7, &vb_desc, &dst_vb1, 4);
367     ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
368
369     memset(&vb_desc, 0, sizeof(vb_desc));
370     vb_desc.dwSize = sizeof(vb_desc);
371     vb_desc.dwFVF = D3DFVF_XYZ;
372     vb_desc.dwNumVertices = 5;
373     /* MSDN says that the last parameter must be 0 - check that. */
374     hr = IDirect3D7_CreateVertexBuffer(d3d7, &vb_desc, &dst_vb2, 12345678);
375     ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
376
377     memset(&vp, 0, sizeof(vp));
378     vp.dwX = 64;
379     vp.dwY = 64;
380     vp.dwWidth = 128;
381     vp.dwHeight = 128;
382     vp.dvMinZ = 0.0f;
383     vp.dvMaxZ = 1.0f;
384     hr = IDirect3DDevice7_SetViewport(device, &vp);
385     ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
386
387     hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb1, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0);
388     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
389     hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb2, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0);
390     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
391
392     hr = IDirect3DVertexBuffer7_Lock(dst_vb1, 0, (void **)&dst_data, NULL);
393     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
394     ok(compare_vec4(&dst_data[0], +1.280e+2f, +1.280e+2f, +0.000e+0f, +1.000e+0f, 4096),
395             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
396             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
397     ok(compare_vec4(&dst_data[1], +1.920e+2f, +6.400e+1f, +1.000e+0f, +1.000e+0f, 4096),
398             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
399             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
400     ok(compare_vec4(&dst_data[2], +6.400e+1f, +1.920e+2f, +5.000e-1f, +1.000e+0f, 4096),
401             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
402             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
403     ok(compare_vec4(&dst_data[3], +1.600e+2f, +1.600e+2f, +2.500e-1f, +1.000e+0f, 4096),
404             "Got unexpected vertex 3 {%.8e, %.8e, %.8e, %.8e}.\n",
405             dst_data[3].x, dst_data[3].y, dst_data[3].z, dst_data[3].w);
406     hr = IDirect3DVertexBuffer7_Unlock(dst_vb1);
407     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
408
409     hr = IDirect3DVertexBuffer7_Lock(dst_vb2, 0, (void **)&dst_data2, NULL);
410     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
411     /* Small thing without much practical meaning, but I stumbled upon it,
412      * so let's check for it: If the output vertex buffer has no RHW value,
413      * the RHW value of the last vertex is written into the next vertex. */
414     ok(compare_vec3(&dst_data2[4], +1.000e+0f, +0.000e+0f, +0.000e+0f, 4096),
415             "Got unexpected vertex 4 {%.8e, %.8e, %.8e}.\n",
416             dst_data2[4].x, dst_data2[4].y, dst_data2[4].z);
417     hr = IDirect3DVertexBuffer7_Unlock(dst_vb2);
418     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
419
420     /* Try a more complicated viewport, same vertices. */
421     memset(&vp, 0, sizeof(vp));
422     vp.dwX = 10;
423     vp.dwY = 5;
424     vp.dwWidth = 246;
425     vp.dwHeight = 130;
426     vp.dvMinZ = -2.0f;
427     vp.dvMaxZ = 4.0f;
428     hr = IDirect3DDevice7_SetViewport(device, &vp);
429     ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
430
431     hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb1, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0);
432     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
433
434     hr = IDirect3DVertexBuffer7_Lock(dst_vb1, 0, (void **)&dst_data, NULL);
435     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
436     ok(compare_vec4(&dst_data[0], +1.330e+2f, +7.000e+1f, -2.000e+0f, +1.000e+0f, 4096),
437             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
438             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
439     ok(compare_vec4(&dst_data[1], +2.560e+2f, +5.000e+0f, +4.000e+0f, +1.000e+0f, 4096),
440             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
441             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
442     ok(compare_vec4(&dst_data[2], +1.000e+1f, +1.350e+2f, +1.000e+0f, +1.000e+0f, 4096),
443             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
444             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
445     ok(compare_vec4(&dst_data[3], +1.945e+2f, +1.025e+2f, -5.000e-1f, +1.000e+0f, 4096),
446             "Got unexpected vertex 3 {%.8e, %.8e, %.8e, %.8e}.\n",
447             dst_data[3].x, dst_data[3].y, dst_data[3].z, dst_data[3].w);
448     hr = IDirect3DVertexBuffer7_Unlock(dst_vb1);
449     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
450
451     hr = IDirect3DDevice7_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &world);
452     ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr);
453     hr = IDirect3DDevice7_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &view);
454     ok(SUCCEEDED(hr), "Failed to set view transform, hr %#x.\n", hr);
455     hr = IDirect3DDevice7_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &proj);
456     ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#x.\n", hr);
457
458     hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb1, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0);
459     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
460
461     hr = IDirect3DVertexBuffer7_Lock(dst_vb1, 0, (void **)&dst_data, NULL);
462     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
463     ok(compare_vec4(&dst_data[0], +2.560e+2f, +7.000e+1f, -2.000e+0f, +3.333e-1f, 4096),
464             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
465             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
466     ok(compare_vec4(&dst_data[1], +2.560e+2f, +7.813e+1f, -2.750e+0f, +1.250e-1f, 4096),
467             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
468             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
469     ok(compare_vec4(&dst_data[2], +2.560e+2f, +4.400e+1f, +4.000e-1f, +4.000e-1f, 4096),
470             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
471             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
472     ok(compare_vec4(&dst_data[3], +2.560e+2f, +8.182e+1f, -3.091e+0f, +3.636e-1f, 4096),
473             "Got unexpected vertex 3 {%.8e, %.8e, %.8e, %.8e}.\n",
474             dst_data[3].x, dst_data[3].y, dst_data[3].z, dst_data[3].w);
475     hr = IDirect3DVertexBuffer7_Unlock(dst_vb1);
476     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
477
478     IDirect3DVertexBuffer7_Release(dst_vb2);
479     IDirect3DVertexBuffer7_Release(dst_vb1);
480     IDirect3DVertexBuffer7_Release(src_vb);
481     IDirect3D7_Release(d3d7);
482     IDirect3DDevice7_Release(device);
483     DestroyWindow(window);
484 }
485
486 static void test_coop_level_create_device_window(void)
487 {
488     HWND focus_window, device_window;
489     IDirectDraw7 *ddraw;
490     HRESULT hr;
491
492     focus_window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
493             0, 0, 640, 480, 0, 0, 0, 0);
494     if (!(ddraw = create_ddraw()))
495     {
496         skip("Failed to create a 3D device, skipping test.\n");
497         DestroyWindow(focus_window);
498         return;
499     }
500
501     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
502     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
503     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
504     ok(!device_window, "Unexpected device window found.\n");
505     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW);
506     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
507     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
508     ok(!device_window, "Unexpected device window found.\n");
509     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL);
510     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
511     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
512     ok(!device_window, "Unexpected device window found.\n");
513     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL | DDSCL_FULLSCREEN);
514     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
515     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
516     ok(!device_window, "Unexpected device window found.\n");
517     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
518     ok(hr == DDERR_NOFOCUSWINDOW || broken(hr == DDERR_INVALIDPARAMS), "Got unexpected hr %#x.\n", hr);
519     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
520     ok(!device_window, "Unexpected device window found.\n");
521
522     /* Windows versions before 98 / NT5 don't support DDSCL_CREATEDEVICEWINDOW. */
523     if (broken(hr == DDERR_INVALIDPARAMS))
524     {
525         win_skip("DDSCL_CREATEDEVICEWINDOW not supported, skipping test.\n");
526         IDirectDraw7_Release(ddraw);
527         DestroyWindow(focus_window);
528         return;
529     }
530
531     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
532     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
533     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
534     ok(!device_window, "Unexpected device window found.\n");
535     hr = IDirectDraw7_SetCooperativeLevel(ddraw, focus_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
536     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
537     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
538     ok(!device_window, "Unexpected device window found.\n");
539
540     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
541     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
542     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
543     ok(!device_window, "Unexpected device window found.\n");
544     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_SETFOCUSWINDOW
545             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
546     ok(hr == DDERR_NOHWND, "Got unexpected hr %#x.\n", hr);
547     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
548     ok(!!device_window, "Device window not found.\n");
549
550     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
551     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
552     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
553     ok(!device_window, "Unexpected device window found.\n");
554     hr = IDirectDraw7_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW
555             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
556     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
557     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
558     ok(!!device_window, "Device window not found.\n");
559
560     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
561     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
562     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
563     ok(!device_window, "Unexpected device window found.\n");
564     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
565     ok(hr == DDERR_NOFOCUSWINDOW, "Got unexpected hr %#x.\n", hr);
566     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
567     ok(!device_window, "Unexpected device window found.\n");
568     hr = IDirectDraw7_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW);
569     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
570     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
571     ok(!device_window, "Unexpected device window found.\n");
572     hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
573     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
574     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
575     ok(!!device_window, "Device window not found.\n");
576
577     IDirectDraw7_Release(ddraw);
578     DestroyWindow(focus_window);
579 }
580
581 static void test_clipper_blt(void)
582 {
583     IDirectDrawSurface7 *src_surface, *dst_surface;
584     RECT client_rect, src_rect, *rect;
585     IDirectDrawClipper *clipper;
586     DDSURFACEDESC2 surface_desc;
587     unsigned int i, j, x, y;
588     IDirectDraw7 *ddraw;
589     RGNDATA *rgn_data;
590     D3DCOLOR color;
591     HRGN r1, r2;
592     HWND window;
593     DDBLTFX fx;
594     HRESULT hr;
595     DWORD *ptr;
596     DWORD ret;
597
598     static const DWORD src_data[] =
599     {
600         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
601         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
602         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
603     };
604     static const D3DCOLOR expected1[] =
605     {
606         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
607         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
608         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
609         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
610     };
611     static const D3DCOLOR expected2[] =
612     {
613         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
614         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
615         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
616         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
617     };
618
619     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
620             10, 10, 640, 480, 0, 0, 0, 0);
621     ShowWindow(window, SW_SHOW);
622     if (!(ddraw = create_ddraw()))
623     {
624         skip("Failed to create a ddraw object, skipping test.\n");
625         DestroyWindow(window);
626         return;
627     }
628
629     ret = GetClientRect(window, &client_rect);
630     ok(ret, "Failed to get client rect.\n");
631     ret = MapWindowPoints(window, NULL, (POINT *)&client_rect, 2);
632     ok(ret, "Failed to map client rect.\n");
633
634     hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
635     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
636
637     hr = IDirectDraw7_CreateClipper(ddraw, 0, &clipper, NULL);
638     ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
639     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
640     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
641     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
642     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
643     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
644     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
645     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
646     hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret);
647     ok(SUCCEEDED(hr), "Failed to get clip list, hr %#x.\n", hr);
648     ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#x.\n", rgn_data->rdh.dwSize);
649     ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#x.\n", rgn_data->rdh.iType);
650     ok(rgn_data->rdh.nCount == 1, "Got unexpected count %u.\n", rgn_data->rdh.nCount);
651     ok(rgn_data->rdh.nRgnSize == 16, "Got unexpected region size %u.\n", rgn_data->rdh.nRgnSize);
652     ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
653             "Got unexpected bounding rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
654             rgn_data->rdh.rcBound.left, rgn_data->rdh.rcBound.top,
655             rgn_data->rdh.rcBound.right, rgn_data->rdh.rcBound.bottom,
656             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
657     rect = (RECT *)&rgn_data->Buffer[0];
658     ok(EqualRect(rect, &client_rect),
659             "Got unexpected clip rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
660             rect->left, rect->top, rect->right, rect->bottom,
661             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
662     HeapFree(GetProcessHeap(), 0, rgn_data);
663
664     r1 = CreateRectRgn(0, 0, 320, 240);
665     ok(!!r1, "Failed to create region.\n");
666     r2 = CreateRectRgn(320, 240, 640, 480);
667     ok(!!r2, "Failed to create region.\n");
668     CombineRgn(r1, r1, r2, RGN_OR);
669     ret = GetRegionData(r1, 0, NULL);
670     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
671     ret = GetRegionData(r1, ret, rgn_data);
672     ok(!!ret, "Failed to get region data.\n");
673
674     DeleteObject(r2);
675     DeleteObject(r1);
676
677     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
678     ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#x.\n", hr);
679     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
680     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
681     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
682     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
683
684     HeapFree(GetProcessHeap(), 0, rgn_data);
685
686     memset(&surface_desc, 0, sizeof(surface_desc));
687     surface_desc.dwSize = sizeof(surface_desc);
688     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
689     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
690     surface_desc.dwWidth = 640;
691     surface_desc.dwHeight = 480;
692     U4(surface_desc).ddpfPixelFormat.dwSize = sizeof(U4(surface_desc).ddpfPixelFormat);
693     U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB;
694     U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount = 32;
695     U2(U4(surface_desc).ddpfPixelFormat).dwRBitMask = 0x00ff0000;
696     U3(U4(surface_desc).ddpfPixelFormat).dwGBitMask = 0x0000ff00;
697     U4(U4(surface_desc).ddpfPixelFormat).dwBBitMask = 0x000000ff;
698
699     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
700     ok(SUCCEEDED(hr), "Failed to create source surface, hr %#x.\n", hr);
701     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
702     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
703
704     memset(&fx, 0, sizeof(fx));
705     fx.dwSize = sizeof(fx);
706     hr = IDirectDrawSurface7_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
707     ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#x.\n", hr);
708     hr = IDirectDrawSurface7_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
709     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
710
711     hr = IDirectDrawSurface7_Lock(src_surface, NULL, &surface_desc, 0, NULL);
712     ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#x.\n", hr);
713     ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %u.\n", U1(surface_desc).lPitch);
714     ptr = surface_desc.lpSurface;
715     memcpy(&ptr[   0], &src_data[ 0], 6 * sizeof(DWORD));
716     memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
717     memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
718     hr = IDirectDrawSurface7_Unlock(src_surface, NULL);
719     ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#x.\n", hr);
720
721     hr = IDirectDrawSurface7_SetClipper(dst_surface, clipper);
722     ok(SUCCEEDED(hr), "Failed to set clipper, hr %#x.\n", hr);
723
724     SetRect(&src_rect, 1, 1, 5, 2);
725     hr = IDirectDrawSurface7_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
726     ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
727     for (i = 0; i < 4; ++i)
728     {
729         for (j = 0; j < 4; ++j)
730         {
731             x = 80 * ((2 * j) + 1);
732             y = 60 * ((2 * i) + 1);
733             color = get_surface_color(dst_surface, x, y);
734             ok(compare_color(color, expected1[i * 4 + j], 1),
735                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
736         }
737     }
738
739     U5(fx).dwFillColor = 0xff0000ff;
740     hr = IDirectDrawSurface7_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
741     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
742     for (i = 0; i < 4; ++i)
743     {
744         for (j = 0; j < 4; ++j)
745         {
746             x = 80 * ((2 * j) + 1);
747             y = 60 * ((2 * i) + 1);
748             color = get_surface_color(dst_surface, x, y);
749             ok(compare_color(color, expected2[i * 4 + j], 1),
750                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
751         }
752     }
753
754     hr = IDirectDrawSurface7_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
755     ok(hr == DDERR_BLTFASTCANTCLIP, "Got unexpected hr %#x.\n", hr);
756
757     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
758     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
759     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
760     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
761     DestroyWindow(window);
762     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
763     ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
764     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
765     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
766     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
767     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
768     hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
769     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
770     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
771     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
772     hr = IDirectDrawSurface7_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
773     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
774
775     IDirectDrawSurface7_Release(dst_surface);
776     IDirectDrawSurface7_Release(src_surface);
777     IDirectDrawClipper_Release(clipper);
778     IDirectDraw7_Release(ddraw);
779 }
780
781 static void test_coop_level_d3d_state(void)
782 {
783     IDirectDrawSurface7 *rt, *surface;
784     IDirect3DDevice7 *device;
785     IDirectDraw7 *ddraw;
786     IDirect3D7 *d3d;
787     D3DCOLOR color;
788     DWORD value;
789     HWND window;
790     HRESULT hr;
791
792     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
793             0, 0, 640, 480, 0, 0, 0, 0);
794     if (!(device = create_device(window, DDSCL_NORMAL)))
795     {
796         skip("Failed to create D3D device, skipping test.\n");
797         DestroyWindow(window);
798         return;
799     }
800
801     hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
802     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
803     hr = IDirect3DDevice7_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
804     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
805     ok(!!value, "Got unexpected z-enable state %#x.\n", value);
806     hr = IDirect3DDevice7_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
807     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
808     ok(!value, "Got unexpected alpha blend enable state %#x.\n", value);
809     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
810     ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
811     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffff0000, 0.0f, 0);
812     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
813     color = get_surface_color(rt, 320, 240);
814     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
815
816     hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
817     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
818     hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw);
819     ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr);
820     IDirect3D7_Release(d3d);
821     hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
822     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
823     hr = IDirectDrawSurface7_IsLost(rt);
824     ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
825     hr = IDirectDraw7_RestoreAllSurfaces(ddraw);
826     ok(SUCCEEDED(hr), "Failed to restore surfaces, hr %#x.\n", hr);
827     IDirectDraw7_Release(ddraw);
828
829     hr = IDirect3DDevice7_GetRenderTarget(device, &surface);
830     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
831     ok(surface == rt, "Got unexpected surface %p.\n", surface);
832     hr = IDirect3DDevice7_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
833     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
834     ok(!!value, "Got unexpected z-enable state %#x.\n", value);
835     hr = IDirect3DDevice7_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
836     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
837     ok(!!value, "Got unexpected alpha blend enable state %#x.\n", value);
838     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff00ff00, 0.0f, 0);
839     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
840     color = get_surface_color(rt, 320, 240);
841     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
842
843     IDirectDrawSurface7_Release(surface);
844     IDirectDrawSurface7_Release(rt);
845     IDirect3DDevice7_Release(device);
846     DestroyWindow(window);
847 }
848
849 static void test_surface_interface_mismatch(void)
850 {
851     IDirectDraw7 *ddraw = NULL;
852     IDirect3D7 *d3d = NULL;
853     IDirectDrawSurface7 *surface = NULL, *ds;
854     IDirectDrawSurface3 *surface3 = NULL;
855     IDirect3DDevice7 *device = NULL;
856     DDSURFACEDESC2 surface_desc;
857     DDPIXELFORMAT z_fmt;
858     ULONG refcount;
859     HRESULT hr;
860     D3DCOLOR color;
861     HWND window;
862
863     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
864             0, 0, 640, 480, 0, 0, 0, 0);
865
866     if (!(ddraw = create_ddraw()))
867     {
868         skip("Failed to create a ddraw object, skipping test.\n");
869         goto cleanup;
870     }
871
872     hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
873     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
874
875     memset(&surface_desc, 0, sizeof(surface_desc));
876     surface_desc.dwSize = sizeof(surface_desc);
877     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
878     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
879     surface_desc.dwWidth = 640;
880     surface_desc.dwHeight = 480;
881
882     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface, NULL);
883     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
884
885     hr = IDirectDrawSurface7_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
886     ok(SUCCEEDED(hr), "Failed to QI IDirectDrawSurface3, hr %#x.\n", hr);
887
888     hr = IDirectDraw7_QueryInterface(ddraw, &IID_IDirect3D7, (void **)&d3d);
889     if (FAILED(hr))
890     {
891         skip("Failed to get the IDirect3D7 interface, skipping test.\n");
892         goto cleanup;
893     }
894
895     memset(&z_fmt, 0, sizeof(z_fmt));
896     hr = IDirect3D7_EnumZBufferFormats(d3d, &IID_IDirect3DTnLHalDevice, enum_z_fmt, &z_fmt);
897     if (FAILED(hr) || !z_fmt.dwSize)
898     {
899         skip("No depth buffer formats available, skipping test.\n");
900         goto cleanup;
901     }
902
903     memset(&surface_desc, 0, sizeof(surface_desc));
904     surface_desc.dwSize = sizeof(surface_desc);
905     surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
906     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
907     U4(surface_desc).ddpfPixelFormat = z_fmt;
908     surface_desc.dwWidth = 640;
909     surface_desc.dwHeight = 480;
910     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &ds, NULL);
911     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
912     if (FAILED(hr))
913         goto cleanup;
914
915     /* Using a different surface interface version still works */
916     hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
917     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
918     refcount = IDirectDrawSurface7_Release(ds);
919     ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
920     if (FAILED(hr))
921         goto cleanup;
922
923     /* Here too */
924     hr = IDirect3D7_CreateDevice(d3d, &IID_IDirect3DTnLHalDevice, (IDirectDrawSurface7 *)surface3, &device);
925     ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
926     if (FAILED(hr))
927         goto cleanup;
928
929     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffff0000, 0.0f, 0);
930     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
931     color = get_surface_color(surface, 320, 240);
932     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
933
934 cleanup:
935     if (surface3) IDirectDrawSurface3_Release(surface3);
936     if (surface) IDirectDrawSurface7_Release(surface);
937     if (device) IDirect3DDevice7_Release(device);
938     if (d3d) IDirect3D7_Release(d3d);
939     if (ddraw) IDirectDraw7_Release(ddraw);
940     DestroyWindow(window);
941 }
942
943 static void test_coop_level_threaded(void)
944 {
945     struct create_window_thread_param p;
946     IDirectDraw7 *ddraw;
947     HRESULT hr;
948
949     if (!(ddraw = create_ddraw()))
950     {
951         skip("Failed to create a ddraw object, skipping test.\n");
952         return;
953     }
954     create_window_thread(&p);
955
956     hr = IDirectDraw7_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
957     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
958
959     IDirectDraw7_Release(ddraw);
960     destroy_window_thread(&p);
961 }
962
963 static void test_depth_blit(void)
964 {
965     IDirect3DDevice7 *device;
966     static struct
967     {
968         float x, y, z;
969         DWORD color;
970     }
971     quad1[] =
972     {
973         { -1.0,  1.0, 0.50f, 0xff00ff00},
974         {  1.0,  1.0, 0.50f, 0xff00ff00},
975         { -1.0, -1.0, 0.50f, 0xff00ff00},
976         {  1.0, -1.0, 0.50f, 0xff00ff00},
977     };
978     static const D3DCOLOR expected_colors[4][4] =
979     {
980         {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
981         {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
982         {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
983         {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
984     };
985     DDSURFACEDESC2 ddsd_new, ddsd_existing;
986
987     IDirectDrawSurface7 *ds1, *ds2, *ds3, *rt;
988     RECT src_rect, dst_rect;
989     unsigned int i, j;
990     D3DCOLOR color;
991     HRESULT hr;
992     IDirect3D7 *d3d;
993     IDirectDraw7 *ddraw;
994     DDBLTFX fx;
995     HWND window;
996
997     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
998             0, 0, 640, 480, 0, 0, 0, 0);
999     if (!(device = create_device(window, DDSCL_NORMAL)))
1000     {
1001         skip("Failed to create D3D device, skipping test.\n");
1002         DestroyWindow(window);
1003         return;
1004     }
1005
1006     hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
1007     ok(SUCCEEDED(hr), "Failed to get Direct3D7 interface, hr %#x.\n", hr);
1008     hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw);
1009     ok(SUCCEEDED(hr), "Failed to get DirectDraw7 interface, hr %#x.\n", hr);
1010     IDirect3D7_Release(d3d);
1011
1012     ds1 = get_depth_stencil(device);
1013
1014     memset(&ddsd_new, 0, sizeof(ddsd_new));
1015     ddsd_new.dwSize = sizeof(ddsd_new);
1016     memset(&ddsd_existing, 0, sizeof(ddsd_existing));
1017     ddsd_existing.dwSize = sizeof(ddsd_existing);
1018     hr = IDirectDrawSurface7_GetSurfaceDesc(ds1, &ddsd_existing);
1019     ddsd_new.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
1020     ddsd_new.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
1021     ddsd_new.dwWidth = ddsd_existing.dwWidth;
1022     ddsd_new.dwHeight = ddsd_existing.dwHeight;
1023     U4(ddsd_new).ddpfPixelFormat = U4(ddsd_existing).ddpfPixelFormat;
1024     hr = IDirectDraw7_CreateSurface(ddraw, &ddsd_new, &ds2, NULL);
1025     ok(SUCCEEDED(hr), "Failed to create a z buffer, hr %#x.\n", hr);
1026     hr = IDirectDraw7_CreateSurface(ddraw, &ddsd_new, &ds3, NULL);
1027     ok(SUCCEEDED(hr), "Failed to create a z buffer, hr %#x.\n", hr);
1028     IDirectDraw7_Release(ddraw);
1029
1030     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_TRUE);
1031     ok(SUCCEEDED(hr), "Failed to enable z testing, hr %#x.\n", hr);
1032     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
1033     ok(SUCCEEDED(hr), "Failed to set the z function, hr %#x.\n", hr);
1034     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
1035     ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr);
1036
1037     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_ZBUFFER, 0, 0.0f, 0);
1038     ok(SUCCEEDED(hr), "Failed to clear the z buffer, hr %#x.\n", hr);
1039
1040     /* Partial blit. */
1041     SetRect(&src_rect, 0, 0, 320, 240);
1042     SetRect(&dst_rect, 0, 0, 320, 240);
1043     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1044     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1045     /* Different locations. */
1046     SetRect(&src_rect, 0, 0, 320, 240);
1047     SetRect(&dst_rect, 320, 240, 640, 480);
1048     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1049     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1050     /* Streched. */
1051     SetRect(&src_rect, 0, 0, 320, 240);
1052     SetRect(&dst_rect, 0, 0, 640, 480);
1053     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1054     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1055     /* Flipped. */
1056     SetRect(&src_rect, 0, 480, 640, 0);
1057     SetRect(&dst_rect, 0, 0, 640, 480);
1058     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1059     ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
1060     SetRect(&src_rect, 0, 0, 640, 480);
1061     SetRect(&dst_rect, 0, 480, 640, 0);
1062     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1063     ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
1064     /* Full, explicit. */
1065     SetRect(&src_rect, 0, 0, 640, 480);
1066     SetRect(&dst_rect, 0, 0, 640, 480);
1067     hr = IDirectDrawSurface7_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1068     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1069     /* Depth -> color blit: Succeeds on Win7 + Radeon HD 5700, fails on WinXP + Radeon X1600 */
1070
1071     /* Depth blit inside a BeginScene / EndScene pair */
1072     hr = IDirect3DDevice7_BeginScene(device);
1073     ok(SUCCEEDED(hr), "Failed to start scene, hr %#x.\n", hr);
1074     /* From the current depth stencil */
1075     hr = IDirectDrawSurface7_Blt(ds2, NULL, ds1, NULL, DDBLT_WAIT, NULL);
1076     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1077     /* To the current depth stencil */
1078     hr = IDirectDrawSurface7_Blt(ds1, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1079     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1080     /* Between unbound surfaces */
1081     hr = IDirectDrawSurface7_Blt(ds3, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1082     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1083     hr = IDirect3DDevice7_EndScene(device);
1084     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1085
1086     /* Avoid changing the depth stencil, it doesn't work properly on Windows.
1087      * Instead use DDBLT_DEPTHFILL to clear the depth stencil. Unfortunately
1088      * drivers disagree on the meaning of dwFillDepth. Only 0 seems to produce
1089      * a reliable result(z = 0.0) */
1090     memset(&fx, 0, sizeof(fx));
1091     fx.dwSize = sizeof(fx);
1092     hr = IDirectDrawSurface7_Blt(ds2, NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
1093     ok(SUCCEEDED(hr), "Failed to clear the source z buffer, hr %#x.\n", hr);
1094
1095     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET, 0xffff0000, 1.0f, 0);
1096     ok(SUCCEEDED(hr), "Failed to clear the color and z buffers, hr %#x.\n", hr);
1097     SetRect(&dst_rect, 0, 0, 320, 240);
1098     hr = IDirectDrawSurface7_Blt(ds1, &dst_rect, ds2, NULL, DDBLT_WAIT, NULL);
1099     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1100     IDirectDrawSurface7_Release(ds3);
1101     IDirectDrawSurface7_Release(ds2);
1102     IDirectDrawSurface7_Release(ds1);
1103
1104     hr = IDirect3DDevice7_BeginScene(device);
1105     ok(SUCCEEDED(hr), "Failed to start scene, hr %#x.\n", hr);
1106     hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ | D3DFVF_DIFFUSE,
1107             quad1, 4, 0);
1108     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1109     hr = IDirect3DDevice7_EndScene(device);
1110     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1111
1112     hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
1113     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1114     for (i = 0; i < 4; ++i)
1115     {
1116         for (j = 0; j < 4; ++j)
1117         {
1118             unsigned int x = 80 * ((2 * j) + 1);
1119             unsigned int y = 60 * ((2 * i) + 1);
1120             color = get_surface_color(rt, x, y);
1121             ok(compare_color(color, expected_colors[i][j], 1),
1122                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected_colors[i][j], x, y, color);
1123         }
1124     }
1125
1126     IDirectDrawSurface7_Release(rt);
1127     IDirect3DDevice7_Release(device);
1128     DestroyWindow(window);
1129 }
1130
1131 static void test_texture_load_ckey(void)
1132 {
1133     HWND window;
1134     IDirect3DDevice7 *device;
1135     IDirectDraw7 *ddraw;
1136     IDirectDrawSurface7 *src;
1137     IDirectDrawSurface7 *dst;
1138     DDSURFACEDESC2 ddsd;
1139     HRESULT hr;
1140     DDCOLORKEY ckey;
1141     IDirect3D7 *d3d;
1142
1143     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1144             0, 0, 640, 480, 0, 0, 0, 0);
1145     if (!(device = create_device(window, DDSCL_NORMAL)))
1146     {
1147         skip("Failed to create D3D device, skipping test.\n");
1148         DestroyWindow(window);
1149         return;
1150     }
1151
1152     hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
1153     ok(SUCCEEDED(hr), "Failed to get Direct3D7 interface, hr %#x.\n", hr);
1154     hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw);
1155     ok(SUCCEEDED(hr), "Failed to get DirectDraw7 interface, hr %#x.\n", hr);
1156     IDirect3D7_Release(d3d);
1157
1158     memset(&ddsd, 0, sizeof(ddsd));
1159     ddsd.dwSize = sizeof(ddsd);
1160     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1161     ddsd.dwHeight = 128;
1162     ddsd.dwWidth = 128;
1163     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
1164     hr = IDirectDraw7_CreateSurface(ddraw, &ddsd, &src, NULL);
1165     ok(SUCCEEDED(hr), "Failed to create source texture, hr %#x.\n", hr);
1166     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1167     hr = IDirectDraw7_CreateSurface(ddraw, &ddsd, &dst, NULL);
1168     ok(SUCCEEDED(hr), "Failed to create destination texture, hr %#x.\n", hr);
1169
1170     /* No surface has a color key */
1171     hr = IDirect3DDevice7_Load(device, dst, NULL, src, NULL, 0);
1172     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1173     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0xdeadbeef;
1174     hr = IDirectDrawSurface7_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1175     ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1176     ok(ckey.dwColorSpaceLowValue == 0xdeadbeef, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1177     ok(ckey.dwColorSpaceHighValue == 0xdeadbeef, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1178
1179     /* Source surface has a color key */
1180     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
1181     hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
1182     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1183     hr = IDirect3DDevice7_Load(device, dst, NULL, src, NULL, 0);
1184     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1185     hr = IDirectDrawSurface7_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1186     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1187     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1188     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1189
1190     /* Both surfaces have a color key: Dest ckey is overwritten */
1191     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x000000ff;
1192     hr = IDirectDrawSurface7_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1193     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1194     hr = IDirect3DDevice7_Load(device, dst, NULL, src, NULL, 0);
1195     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1196     hr = IDirectDrawSurface7_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1197     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1198     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1199     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1200
1201     /* Only the destination has a color key: It is deleted. This behavior differs from
1202      * IDirect3DTexture(2)::Load */
1203     hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_SRCBLT, NULL);
1204     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1205     hr = IDirectDrawSurface7_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
1206     ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1207     hr = IDirect3DDevice7_Load(device, dst, NULL, src, NULL, 0);
1208     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1209     hr = IDirectDrawSurface7_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1210     todo_wine ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1211
1212     IDirectDrawSurface7_Release(dst);
1213     IDirectDrawSurface7_Release(src);
1214     IDirectDraw7_Release(ddraw);
1215     IDirect3DDevice7_Release(device);
1216 }
1217
1218 static void test_zenable(void)
1219 {
1220     static struct
1221     {
1222         struct vec4 position;
1223         D3DCOLOR diffuse;
1224     }
1225     tquad[] =
1226     {
1227         {{  0.0f, 480.0f, -0.5f, 1.0f}, 0xff00ff00},
1228         {{  0.0f,   0.0f, -0.5f, 1.0f}, 0xff00ff00},
1229         {{640.0f, 480.0f,  1.5f, 1.0f}, 0xff00ff00},
1230         {{640.0f,   0.0f,  1.5f, 1.0f}, 0xff00ff00},
1231     };
1232     IDirect3DDevice7 *device;
1233     IDirectDrawSurface7 *rt;
1234     D3DCOLOR color;
1235     HWND window;
1236     HRESULT hr;
1237     UINT x, y;
1238     UINT i, j;
1239
1240     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1241             0, 0, 640, 480, 0, 0, 0, 0);
1242     if (!(device = create_device(window, DDSCL_NORMAL)))
1243     {
1244         skip("Failed to create D3D device, skipping test.\n");
1245         DestroyWindow(window);
1246         return;
1247     }
1248
1249     hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1250     ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#x.\n", hr);
1251
1252     hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffff0000, 0.0f, 0);
1253     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
1254     hr = IDirect3DDevice7_BeginScene(device);
1255     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1256     hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_DIFFUSE, tquad, 4, 0);
1257     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1258     hr = IDirect3DDevice7_EndScene(device);
1259     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1260
1261     hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
1262     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1263     for (i = 0; i < 4; ++i)
1264     {
1265         for (j = 0; j < 4; ++j)
1266         {
1267             x = 80 * ((2 * j) + 1);
1268             y = 60 * ((2 * i) + 1);
1269             color = get_surface_color(rt, x, y);
1270             ok(compare_color(color, 0x0000ff00, 1),
1271                     "Expected color 0x0000ff00 at %u, %u, got 0x%08x.\n", x, y, color);
1272         }
1273     }
1274     IDirectDrawSurface7_Release(rt);
1275
1276     IDirect3DDevice7_Release(device);
1277     DestroyWindow(window);
1278 }
1279
1280 START_TEST(ddraw7)
1281 {
1282     HMODULE module = GetModuleHandleA("ddraw.dll");
1283
1284     if (!(pDirectDrawCreateEx = (void *)GetProcAddress(module, "DirectDrawCreateEx")))
1285     {
1286         win_skip("DirectDrawCreateEx not available, skipping tests.\n");
1287         return;
1288     }
1289
1290     test_process_vertices();
1291     test_coop_level_create_device_window();
1292     test_clipper_blt();
1293     test_coop_level_d3d_state();
1294     test_surface_interface_mismatch();
1295     test_coop_level_threaded();
1296     test_depth_blit();
1297     test_texture_load_ckey();
1298     test_zenable();
1299 }