d3dx9: Add support for luminance pixel formats.
[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         IDirectDraw2_Release(ddraw);
1377         DestroyWindow(window);
1378         return;
1379     }
1380
1381     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1382     viewport = create_viewport(device, 0, 0, 640, 480);
1383     viewport_set_background(device, viewport, background);
1384     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1385     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1386
1387     memset(&surface_desc, 0, sizeof(surface_desc));
1388     surface_desc.dwSize = sizeof(surface_desc);
1389     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1390     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1391     surface_desc.dwWidth = 256;
1392     surface_desc.dwHeight = 256;
1393     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1394     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
1395     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1396     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1397     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1398     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1399     U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
1400     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0xff00ff00;
1401     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0xff00ff00;
1402     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1403     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
1404     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
1405     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1406     hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
1407     ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1408     IDirect3DTexture2_Release(texture);
1409
1410     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1411     ok(SUCCEEDED(hr), "Failed to set texture, hr %#x.\n", hr);
1412     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
1413     ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1414     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
1415     ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1416
1417     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1418     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1419
1420     for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
1421     {
1422         hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, tests[i].color_key);
1423         ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1424         hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, tests[i].blend);
1425         ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1426
1427         memset(&fx, 0, sizeof(fx));
1428         fx.dwSize = sizeof(fx);
1429         U5(fx).dwFillColor = tests[i].fill_color;
1430         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1431         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1432
1433         hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
1434         ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1435         hr = IDirect3DDevice2_BeginScene(device);
1436         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1437         hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1438         ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1439         hr = IDirect3DDevice2_EndScene(device);
1440         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1441
1442         color = get_surface_color(rt, 320, 240);
1443         if (i == 2)
1444             todo_wine ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1445                     tests[i].result1, i, color);
1446         else
1447             ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1448                     tests[i].result1, i, color);
1449
1450         U5(fx).dwFillColor = 0xff0000ff;
1451         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1452         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1453
1454         hr = IDirect3DDevice2_BeginScene(device);
1455         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1456         hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[4], 4, 0);
1457         ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1458         hr = IDirect3DDevice2_EndScene(device);
1459         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1460
1461         /* This tests that fragments that are masked out by the color key are
1462          * discarded, instead of just fully transparent. */
1463         color = get_surface_color(rt, 320, 240);
1464         if (i == 2)
1465             todo_wine ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1466                     tests[i].result2, i, color);
1467         else
1468             ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1469                     tests[i].result2, i, color);
1470     }
1471
1472     IDirectDrawSurface_Release(rt);
1473     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1474     ok(SUCCEEDED(hr), "Failed to unset texture, hr %#x.\n", hr);
1475     IDirectDrawSurface_Release(surface);
1476     destroy_viewport(device, viewport);
1477     destroy_material(background);
1478     IDirect3DDevice2_Release(device);
1479     IDirectDraw2_Release(ddraw);
1480     DestroyWindow(window);
1481 }
1482
1483 static void test_ck_default(void)
1484 {
1485     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1486     static D3DTLVERTEX tquad[] =
1487     {
1488         {{  0.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1489         {{  0.0f}, {  0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1490         {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1491         {{640.0f}, {  0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1492     };
1493     IDirectDrawSurface *surface, *rt;
1494     D3DTEXTUREHANDLE texture_handle;
1495     IDirect3DMaterial2 *background;
1496     IDirect3DViewport2 *viewport;
1497     DDSURFACEDESC surface_desc;
1498     IDirect3DTexture2 *texture;
1499     IDirect3DDevice2 *device;
1500     IDirectDraw2 *ddraw;
1501     D3DCOLOR color;
1502     DWORD value;
1503     HWND window;
1504     DDBLTFX fx;
1505     HRESULT hr;
1506
1507     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1508             0, 0, 640, 480, 0, 0, 0, 0);
1509
1510     if (!(ddraw = create_ddraw()))
1511     {
1512         skip("Failed to create ddraw object, skipping test.\n");
1513         DestroyWindow(window);
1514         return;
1515     }
1516     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1517     {
1518         skip("Failed to create D3D device, skipping test.\n");
1519         IDirectDraw2_Release(ddraw);
1520         DestroyWindow(window);
1521         return;
1522     }
1523
1524     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1525     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1526
1527     background = create_diffuse_material(device, 0.0, 1.0f, 0.0f, 1.0f);
1528     viewport = create_viewport(device, 0, 0, 640, 480);
1529     viewport_set_background(device, viewport, background);
1530     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1531     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1532
1533     memset(&surface_desc, 0, sizeof(surface_desc));
1534     surface_desc.dwSize = sizeof(surface_desc);
1535     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1536     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1537     surface_desc.dwWidth = 256;
1538     surface_desc.dwHeight = 256;
1539     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1540     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
1541     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1542     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1543     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1544     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1545     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x000000ff;
1546     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x000000ff;
1547     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1548     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1549     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
1550     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1551     hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
1552     ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1553     IDirect3DTexture_Release(texture);
1554
1555     memset(&fx, 0, sizeof(fx));
1556     fx.dwSize = sizeof(fx);
1557     U5(fx).dwFillColor = 0x000000ff;
1558     hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1559     ok(SUCCEEDED(hr), "Failed to fill surface, hr %#x.\n", hr);
1560
1561     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1562     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1563     hr = IDirect3DDevice2_BeginScene(device);
1564     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1565     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1566     ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#x.\n", hr);
1567     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
1568     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
1569     ok(!value, "Got unexpected color keying state %#x.\n", value);
1570     hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1571     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1572     hr = IDirect3DDevice2_EndScene(device);
1573     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1574     color = get_surface_color(rt, 320, 240);
1575     ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
1576
1577     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1578     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1579     hr = IDirect3DDevice2_BeginScene(device);
1580     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1581     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
1582     ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1583     hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1584     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1585     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
1586     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
1587     ok(!!value, "Got unexpected color keying state %#x.\n", value);
1588     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1589     ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#x.\n", hr);
1590     hr = IDirect3DDevice2_EndScene(device);
1591     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1592     color = get_surface_color(rt, 320, 240);
1593     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
1594
1595     IDirectDrawSurface_Release(surface);
1596     destroy_viewport(device, viewport);
1597     destroy_material(background);
1598     IDirectDrawSurface_Release(rt);
1599     IDirect3DDevice2_Release(device);
1600     IDirectDraw2_Release(ddraw);
1601     DestroyWindow(window);
1602 }
1603
1604 struct qi_test
1605 {
1606     REFIID iid;
1607     REFIID refcount_iid;
1608     HRESULT hr;
1609 };
1610
1611 static void test_qi(const char *test_name, IUnknown *base_iface,
1612         REFIID refcount_iid, const struct qi_test *tests, UINT entry_count)
1613 {
1614     ULONG refcount, expected_refcount;
1615     IUnknown *iface1, *iface2;
1616     HRESULT hr;
1617     UINT i, j;
1618
1619     for (i = 0; i < entry_count; ++i)
1620     {
1621         hr = IUnknown_QueryInterface(base_iface, tests[i].iid, (void **)&iface1);
1622         ok(hr == tests[i].hr, "Got hr %#x for test \"%s\" %u.\n", hr, test_name, i);
1623         if (SUCCEEDED(hr))
1624         {
1625             for (j = 0; j < entry_count; ++j)
1626             {
1627                 hr = IUnknown_QueryInterface(iface1, tests[j].iid, (void **)&iface2);
1628                 ok(hr == tests[j].hr, "Got hr %#x for test \"%s\" %u, %u.\n", hr, test_name, i, j);
1629                 if (SUCCEEDED(hr))
1630                 {
1631                     expected_refcount = 0;
1632                     if (IsEqualGUID(refcount_iid, tests[j].refcount_iid))
1633                         ++expected_refcount;
1634                     if (IsEqualGUID(tests[i].refcount_iid, tests[j].refcount_iid))
1635                         ++expected_refcount;
1636                     refcount = IUnknown_Release(iface2);
1637                     ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, %u, expected %u.\n",
1638                             refcount, test_name, i, j, expected_refcount);
1639                 }
1640             }
1641
1642             expected_refcount = 0;
1643             if (IsEqualGUID(refcount_iid, tests[i].refcount_iid))
1644                 ++expected_refcount;
1645             refcount = IUnknown_Release(iface1);
1646             ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, expected %u.\n",
1647                     refcount, test_name, i, expected_refcount);
1648         }
1649     }
1650 }
1651
1652 static void test_surface_qi(void)
1653 {
1654     static const struct qi_test tests[] =
1655     {
1656         {&IID_IDirect3DTexture2,        &IID_IDirectDrawSurface,        S_OK         },
1657         {&IID_IDirect3DTexture,         &IID_IDirectDrawSurface,        S_OK         },
1658         {&IID_IDirectDrawGammaControl,  &IID_IDirectDrawGammaControl,   S_OK         },
1659         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1660         {&IID_IDirectDrawSurface7,      &IID_IDirectDrawSurface7,       S_OK         },
1661         {&IID_IDirectDrawSurface4,      &IID_IDirectDrawSurface4,       S_OK         },
1662         {&IID_IDirectDrawSurface3,      &IID_IDirectDrawSurface3,       S_OK         },
1663         {&IID_IDirectDrawSurface2,      &IID_IDirectDrawSurface2,       S_OK         },
1664         {&IID_IDirectDrawSurface,       &IID_IDirectDrawSurface,        S_OK         },
1665         {&IID_IDirect3DDevice7,         NULL,                           E_INVALIDARG },
1666         {&IID_IDirect3DDevice3,         NULL,                           E_INVALIDARG },
1667         {&IID_IDirect3DDevice2,         NULL,                           E_INVALIDARG },
1668         {&IID_IDirect3DDevice,          NULL,                           E_INVALIDARG },
1669         {&IID_IDirect3D7,               NULL,                           E_INVALIDARG },
1670         {&IID_IDirect3D3,               NULL,                           E_INVALIDARG },
1671         {&IID_IDirect3D2,               NULL,                           E_INVALIDARG },
1672         {&IID_IDirect3D,                NULL,                           E_INVALIDARG },
1673         {&IID_IDirectDraw7,             NULL,                           E_INVALIDARG },
1674         {&IID_IDirectDraw4,             NULL,                           E_INVALIDARG },
1675         {&IID_IDirectDraw3,             NULL,                           E_INVALIDARG },
1676         {&IID_IDirectDraw2,             NULL,                           E_INVALIDARG },
1677         {&IID_IDirectDraw,              NULL,                           E_INVALIDARG },
1678         {&IID_IDirect3DLight,           NULL,                           E_INVALIDARG },
1679         {&IID_IDirect3DMaterial,        NULL,                           E_INVALIDARG },
1680         {&IID_IDirect3DMaterial2,       NULL,                           E_INVALIDARG },
1681         {&IID_IDirect3DMaterial3,       NULL,                           E_INVALIDARG },
1682         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_INVALIDARG },
1683         {&IID_IDirect3DViewport,        NULL,                           E_INVALIDARG },
1684         {&IID_IDirect3DViewport2,       NULL,                           E_INVALIDARG },
1685         {&IID_IDirect3DViewport3,       NULL,                           E_INVALIDARG },
1686         {&IID_IDirect3DVertexBuffer,    NULL,                           E_INVALIDARG },
1687         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_INVALIDARG },
1688         {&IID_IDirectDrawPalette,       NULL,                           E_INVALIDARG },
1689         {&IID_IDirectDrawClipper,       NULL,                           E_INVALIDARG },
1690         {&IID_IUnknown,                 &IID_IDirectDrawSurface,        S_OK         },
1691     };
1692
1693     IDirectDrawSurface *surface;
1694     DDSURFACEDESC surface_desc;
1695     IDirect3DDevice2 *device;
1696     IDirectDraw2 *ddraw;
1697     HWND window;
1698     HRESULT hr;
1699
1700     if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
1701     {
1702         win_skip("DirectDrawCreateEx not available, skipping test.\n");
1703         return;
1704     }
1705
1706     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1707             0, 0, 640, 480, 0, 0, 0, 0);
1708     if (!(ddraw = create_ddraw()))
1709     {
1710         skip("Failed to create a ddraw object, skipping test.\n");
1711         DestroyWindow(window);
1712         return;
1713     }
1714     /* Try to create a D3D device to see if the ddraw implementation supports
1715      * D3D. 64-bit ddraw in particular doesn't seem to support D3D, and
1716      * doesn't support e.g. the IDirect3DTexture interfaces. */
1717     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1718     {
1719         skip("Failed to create D3D device, skipping test.\n");
1720         IDirectDraw2_Release(ddraw);
1721         DestroyWindow(window);
1722         return;
1723     }
1724     IDirect3DDevice_Release(device);
1725
1726     memset(&surface_desc, 0, sizeof(surface_desc));
1727     surface_desc.dwSize = sizeof(surface_desc);
1728     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1729     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1730     surface_desc.dwWidth = 512;
1731     surface_desc.dwHeight = 512;
1732     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1733     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1734
1735     test_qi("surface_qi", (IUnknown *)surface, &IID_IDirectDrawSurface, tests, sizeof(tests) / sizeof(*tests));
1736
1737     IDirectDrawSurface_Release(surface);
1738     IDirectDraw2_Release(ddraw);
1739     DestroyWindow(window);
1740 }
1741
1742 static void test_device_qi(void)
1743 {
1744     static const struct qi_test tests[] =
1745     {
1746         {&IID_IDirect3DTexture2,        NULL,                           E_NOINTERFACE},
1747         {&IID_IDirect3DTexture,         NULL,                           E_NOINTERFACE},
1748         {&IID_IDirectDrawGammaControl,  NULL,                           E_NOINTERFACE},
1749         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1750         {&IID_IDirectDrawSurface7,      NULL,                           E_NOINTERFACE},
1751         {&IID_IDirectDrawSurface4,      NULL,                           E_NOINTERFACE},
1752         {&IID_IDirectDrawSurface3,      NULL,                           E_NOINTERFACE},
1753         {&IID_IDirectDrawSurface2,      NULL,                           E_NOINTERFACE},
1754         {&IID_IDirectDrawSurface,       NULL,                           E_NOINTERFACE},
1755         {&IID_IDirect3DDevice7,         NULL,                           E_NOINTERFACE},
1756         {&IID_IDirect3DDevice3,         NULL,                           E_NOINTERFACE},
1757         {&IID_IDirect3DDevice2,         &IID_IDirect3DDevice2,          S_OK         },
1758         {&IID_IDirect3DDevice,          &IID_IDirect3DDevice2,          S_OK         },
1759         {&IID_IDirect3DRampDevice,      NULL,                           E_NOINTERFACE},
1760         {&IID_IDirect3DRGBDevice,       NULL,                           E_NOINTERFACE},
1761         {&IID_IDirect3DHALDevice,       NULL,                           E_NOINTERFACE},
1762         {&IID_IDirect3DMMXDevice,       NULL,                           E_NOINTERFACE},
1763         {&IID_IDirect3DRefDevice,       NULL,                           E_NOINTERFACE},
1764         {&IID_IDirect3DTnLHalDevice,    NULL,                           E_NOINTERFACE},
1765         {&IID_IDirect3DNullDevice,      NULL,                           E_NOINTERFACE},
1766         {&IID_IDirect3D7,               NULL,                           E_NOINTERFACE},
1767         {&IID_IDirect3D3,               NULL,                           E_NOINTERFACE},
1768         {&IID_IDirect3D2,               NULL,                           E_NOINTERFACE},
1769         {&IID_IDirect3D,                NULL,                           E_NOINTERFACE},
1770         {&IID_IDirectDraw7,             NULL,                           E_NOINTERFACE},
1771         {&IID_IDirectDraw4,             NULL,                           E_NOINTERFACE},
1772         {&IID_IDirectDraw3,             NULL,                           E_NOINTERFACE},
1773         {&IID_IDirectDraw2,             NULL,                           E_NOINTERFACE},
1774         {&IID_IDirectDraw,              NULL,                           E_NOINTERFACE},
1775         {&IID_IDirect3DLight,           NULL,                           E_NOINTERFACE},
1776         {&IID_IDirect3DMaterial,        NULL,                           E_NOINTERFACE},
1777         {&IID_IDirect3DMaterial2,       NULL,                           E_NOINTERFACE},
1778         {&IID_IDirect3DMaterial3,       NULL,                           E_NOINTERFACE},
1779         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_NOINTERFACE},
1780         {&IID_IDirect3DViewport,        NULL,                           E_NOINTERFACE},
1781         {&IID_IDirect3DViewport2,       NULL,                           E_NOINTERFACE},
1782         {&IID_IDirect3DViewport3,       NULL,                           E_NOINTERFACE},
1783         {&IID_IDirect3DVertexBuffer,    NULL,                           E_NOINTERFACE},
1784         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_NOINTERFACE},
1785         {&IID_IDirectDrawPalette,       NULL,                           E_NOINTERFACE},
1786         {&IID_IDirectDrawClipper,       NULL,                           E_NOINTERFACE},
1787         {&IID_IUnknown,                 &IID_IDirect3DDevice2,          S_OK         },
1788     };
1789
1790     IDirect3DDevice2 *device;
1791     IDirectDraw2 *ddraw;
1792     HWND window;
1793
1794     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1795             0, 0, 640, 480, 0, 0, 0, 0);
1796     if (!(ddraw = create_ddraw()))
1797     {
1798         skip("Failed to create ddraw object, skipping test.\n");
1799         DestroyWindow(window);
1800         return;
1801     }
1802     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1803     {
1804         skip("Failed to create D3D device, skipping test.\n");
1805         IDirectDraw2_Release(ddraw);
1806         DestroyWindow(window);
1807         return;
1808     }
1809
1810     test_qi("device_qi", (IUnknown *)device, &IID_IDirect3DDevice2, tests, sizeof(tests) / sizeof(*tests));
1811
1812     IDirect3DDevice2_Release(device);
1813     IDirectDraw2_Release(ddraw);
1814     DestroyWindow(window);
1815 }
1816
1817 START_TEST(ddraw2)
1818 {
1819     test_coop_level_create_device_window();
1820     test_clipper_blt();
1821     test_coop_level_d3d_state();
1822     test_surface_interface_mismatch();
1823     test_coop_level_threaded();
1824     test_depth_blit();
1825     test_texture_load_ckey();
1826     test_viewport_interfaces();
1827     test_zenable();
1828     test_ck_rgba();
1829     test_ck_default();
1830     test_surface_qi();
1831     test_device_qi();
1832 }