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