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