d3drm: Implement IDirect3DRMMesh_AddGroup.
[wine] / dlls / ddraw / tests / ddraw1.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 D3DCOLOR get_surface_color(IDirectDrawSurface *surface, UINT x, UINT y)
99 {
100     RECT rect = {x, y, x + 1, y + 1};
101     DDSURFACEDESC surface_desc;
102     D3DCOLOR color;
103     HRESULT hr;
104
105     memset(&surface_desc, 0, sizeof(surface_desc));
106     surface_desc.dwSize = sizeof(surface_desc);
107
108     hr = IDirectDrawSurface_Lock(surface, &rect, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
109     ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
110     if (FAILED(hr))
111         return 0xdeadbeef;
112
113     color = *((DWORD *)surface_desc.lpSurface) & 0x00ffffff;
114
115     hr = IDirectDrawSurface_Unlock(surface, NULL);
116     ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
117
118     return color;
119 }
120
121 static void emit_process_vertices(void **ptr, WORD base_idx, DWORD vertex_count)
122 {
123     D3DINSTRUCTION *inst = *ptr;
124     D3DPROCESSVERTICES *pv = (D3DPROCESSVERTICES *)(inst + 1);
125
126     inst->bOpcode = D3DOP_PROCESSVERTICES;
127     inst->bSize = sizeof(*pv);
128     inst->wCount = 1;
129
130     pv->dwFlags = D3DPROCESSVERTICES_COPY;
131     pv->wStart = base_idx;
132     pv->wDest = 0;
133     pv->dwCount = vertex_count;
134     pv->dwReserved = 0;
135
136     *ptr = pv + 1;
137 }
138
139 static void emit_set_rs(void **ptr, D3DRENDERSTATETYPE state, DWORD value)
140 {
141     D3DINSTRUCTION *inst = *ptr;
142     D3DSTATE *rs = (D3DSTATE *)(inst + 1);
143
144     inst->bOpcode = D3DOP_STATERENDER;
145     inst->bSize = sizeof(*rs);
146     inst->wCount = 1;
147
148     U1(*rs).drstRenderStateType = state;
149     U2(*rs).dwArg[0] = value;
150
151     *ptr = rs + 1;
152 }
153
154 static void emit_tquad(void **ptr, WORD base_idx)
155 {
156     D3DINSTRUCTION *inst = *ptr;
157     D3DTRIANGLE *tri = (D3DTRIANGLE *)(inst + 1);
158
159     inst->bOpcode = D3DOP_TRIANGLE;
160     inst->bSize = sizeof(*tri);
161     inst->wCount = 2;
162
163     U1(*tri).v1 = base_idx;
164     U2(*tri).v2 = base_idx + 1;
165     U3(*tri).v3 = base_idx + 2;
166     tri->wFlags = D3DTRIFLAG_START;
167     ++tri;
168
169     U1(*tri).v1 = base_idx + 2;
170     U2(*tri).v2 = base_idx + 1;
171     U3(*tri).v3 = base_idx + 3;
172     tri->wFlags = D3DTRIFLAG_ODD;
173     ++tri;
174
175     *ptr = tri;
176 }
177
178 static void emit_end(void **ptr)
179 {
180     D3DINSTRUCTION *inst = *ptr;
181
182     inst->bOpcode = D3DOP_EXIT;
183     inst->bSize = 0;
184     inst->wCount = 0;
185
186     *ptr = inst + 1;
187 }
188
189 static HRESULT CALLBACK enum_z_fmt(GUID *guid, char *description, char *name,
190         D3DDEVICEDESC *hal_desc, D3DDEVICEDESC *hel_desc, void *ctx)
191 {
192     DWORD *z_depth = ctx;
193
194     if (!IsEqualGUID(&IID_IDirect3DHALDevice, guid))
195         return D3DENUMRET_OK;
196
197     if (hal_desc->dwDeviceZBufferBitDepth & DDBD_32)
198         *z_depth = 32;
199     else if (hal_desc->dwDeviceZBufferBitDepth & DDBD_24)
200         *z_depth = 24;
201     else if (hal_desc->dwDeviceZBufferBitDepth & DDBD_16)
202         *z_depth = 16;
203
204     return DDENUMRET_OK;
205 }
206
207 static IDirectDraw *create_ddraw(void)
208 {
209     IDirectDraw *ddraw;
210
211     if (FAILED(DirectDrawCreate(NULL, &ddraw, NULL)))
212         return NULL;
213
214     return ddraw;
215 }
216
217 static IDirect3DDevice *create_device(IDirectDraw *ddraw, HWND window, DWORD coop_level)
218 {
219     IDirectDrawSurface *surface, *ds;
220     IDirect3DDevice *device = NULL;
221     DDSURFACEDESC surface_desc;
222     DWORD z_depth = 0;
223     IDirect3D *d3d;
224     HRESULT hr;
225
226     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, coop_level);
227     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
228
229     memset(&surface_desc, 0, sizeof(surface_desc));
230     surface_desc.dwSize = sizeof(surface_desc);
231     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
232     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
233     surface_desc.dwWidth = 640;
234     surface_desc.dwHeight = 480;
235
236     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
237     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
238
239     if (coop_level & DDSCL_NORMAL)
240     {
241         IDirectDrawClipper *clipper;
242
243         hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
244         ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
245         hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
246         ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
247         hr = IDirectDrawSurface_SetClipper(surface, clipper);
248         ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#x.\n", hr);
249         IDirectDrawClipper_Release(clipper);
250     }
251
252     hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
253     if (FAILED(hr))
254     {
255         IDirectDrawSurface_Release(surface);
256         return NULL;
257     }
258
259     hr = IDirect3D_EnumDevices(d3d, enum_z_fmt, &z_depth);
260     ok(SUCCEEDED(hr), "Failed to enumerate z-formats, hr %#x.\n", hr);
261     IDirect3D_Release(d3d);
262     if (FAILED(hr) || !z_depth)
263     {
264         IDirectDrawSurface_Release(surface);
265         return NULL;
266     }
267
268     memset(&surface_desc, 0, sizeof(surface_desc));
269     surface_desc.dwSize = sizeof(surface_desc);
270     surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
271     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
272     U2(surface_desc).dwZBufferBitDepth = z_depth;
273     surface_desc.dwWidth = 640;
274     surface_desc.dwHeight = 480;
275     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &ds, NULL);
276     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
277     if (FAILED(hr))
278     {
279         IDirectDrawSurface_Release(surface);
280         return NULL;
281     }
282
283     hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
284     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
285     IDirectDrawSurface_Release(ds);
286     if (FAILED(hr))
287     {
288         IDirectDrawSurface_Release(surface);
289         return NULL;
290     }
291
292     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DHALDevice, (void **)&device);
293     IDirectDrawSurface_Release(surface);
294     if (FAILED(hr))
295         return NULL;
296
297     return device;
298 }
299
300 static IDirect3DViewport *create_viewport(IDirect3DDevice *device, UINT x, UINT y, UINT w, UINT h)
301 {
302     IDirect3DViewport *viewport;
303     D3DVIEWPORT vp;
304     IDirect3D *d3d;
305     HRESULT hr;
306
307     hr = IDirect3DDevice_GetDirect3D(device, &d3d);
308     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
309     hr = IDirect3D_CreateViewport(d3d, &viewport, NULL);
310     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
311     hr = IDirect3DDevice_AddViewport(device, viewport);
312     ok(SUCCEEDED(hr), "Failed to add viewport, hr %#x.\n", hr);
313     memset(&vp, 0, sizeof(vp));
314     vp.dwSize = sizeof(vp);
315     vp.dwX = x;
316     vp.dwY = y;
317     vp.dwWidth = w;
318     vp.dwHeight = h;
319     vp.dvScaleX = (float)w / 2.0f;
320     vp.dvScaleY = (float)h / 2.0f;
321     vp.dvMaxX = 1.0f;
322     vp.dvMaxY = 1.0f;
323     vp.dvMinZ = 0.0f;
324     vp.dvMaxZ = 1.0f;
325     hr = IDirect3DViewport_SetViewport(viewport, &vp);
326     ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#x.\n", hr);
327     IDirect3D_Release(d3d);
328
329     return viewport;
330 }
331
332 static void viewport_set_background(IDirect3DDevice *device, IDirect3DViewport *viewport,
333         IDirect3DMaterial *material)
334 {
335     D3DMATERIALHANDLE material_handle;
336     HRESULT hr;
337
338     hr = IDirect3DMaterial2_GetHandle(material, device, &material_handle);
339     ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
340     hr = IDirect3DViewport2_SetBackground(viewport, material_handle);
341     ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#x.\n", hr);
342 }
343
344 static void destroy_viewport(IDirect3DDevice *device, IDirect3DViewport *viewport)
345 {
346     HRESULT hr;
347
348     hr = IDirect3DDevice_DeleteViewport(device, viewport);
349     ok(SUCCEEDED(hr), "Failed to delete viewport, hr %#x.\n", hr);
350     IDirect3DViewport_Release(viewport);
351 }
352
353 static IDirect3DMaterial *create_diffuse_material(IDirect3DDevice *device, float r, float g, float b, float a)
354 {
355     IDirect3DMaterial *material;
356     D3DMATERIAL mat;
357     IDirect3D *d3d;
358     HRESULT hr;
359
360     hr = IDirect3DDevice_GetDirect3D(device, &d3d);
361     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
362     hr = IDirect3D_CreateMaterial(d3d, &material, NULL);
363     ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
364     memset(&mat, 0, sizeof(mat));
365     mat.dwSize = sizeof(mat);
366     U1(U(mat).diffuse).r = r;
367     U2(U(mat).diffuse).g = g;
368     U3(U(mat).diffuse).b = b;
369     U4(U(mat).diffuse).a = a;
370     hr = IDirect3DMaterial_SetMaterial(material, &mat);
371     ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
372     IDirect3D_Release(d3d);
373
374     return material;
375 }
376
377 static void destroy_material(IDirect3DMaterial *material)
378 {
379     IDirect3DMaterial_Release(material);
380 }
381
382 static HRESULT CALLBACK restore_callback(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
383 {
384     HRESULT hr = IDirectDrawSurface_Restore(surface);
385     ok(SUCCEEDED(hr), "Failed to restore surface, hr %#x.\n", hr);
386     IDirectDrawSurface_Release(surface);
387
388     return DDENUMRET_OK;
389 }
390
391 static HRESULT restore_surfaces(IDirectDraw *ddraw)
392 {
393     return IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_ALL | DDENUMSURFACES_DOESEXIST,
394             NULL, NULL, restore_callback);
395 }
396
397 static void test_coop_level_create_device_window(void)
398 {
399     HWND focus_window, device_window;
400     IDirectDraw *ddraw;
401     HRESULT hr;
402
403     focus_window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
404             0, 0, 640, 480, 0, 0, 0, 0);
405     if (!(ddraw = create_ddraw()))
406     {
407         skip("Failed to create a ddraw object, skipping test.\n");
408         DestroyWindow(focus_window);
409         return;
410     }
411
412     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
413     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
414     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
415     ok(!device_window, "Unexpected device window found.\n");
416     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW);
417     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
418     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
419     ok(!device_window, "Unexpected device window found.\n");
420     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL);
421     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
422     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
423     ok(!device_window, "Unexpected device window found.\n");
424     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL | DDSCL_FULLSCREEN);
425     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
426     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
427     ok(!device_window, "Unexpected device window found.\n");
428     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
429     ok(hr == DDERR_NOFOCUSWINDOW || broken(hr == DDERR_INVALIDPARAMS), "Got unexpected hr %#x.\n", hr);
430     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
431     ok(!device_window, "Unexpected device window found.\n");
432
433     /* Windows versions before 98 / NT5 don't support DDSCL_CREATEDEVICEWINDOW. */
434     if (broken(hr == DDERR_INVALIDPARAMS))
435     {
436         win_skip("DDSCL_CREATEDEVICEWINDOW not supported, skipping test.\n");
437         IDirectDraw_Release(ddraw);
438         DestroyWindow(focus_window);
439         return;
440     }
441
442     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
443     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
444     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
445     ok(!device_window, "Unexpected device window found.\n");
446     hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
447     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
448     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
449     ok(!device_window, "Unexpected device window found.\n");
450
451     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
452     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
453     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
454     ok(!device_window, "Unexpected device window found.\n");
455     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_SETFOCUSWINDOW
456             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
457     ok(hr == DDERR_NOHWND, "Got unexpected hr %#x.\n", hr);
458     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
459     ok(!!device_window, "Device window not found.\n");
460
461     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
462     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
463     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
464     ok(!device_window, "Unexpected device window found.\n");
465     hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW
466             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
467     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
468     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
469     ok(!!device_window, "Device window not found.\n");
470
471     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
472     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
473     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
474     ok(!device_window, "Unexpected device window found.\n");
475     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
476     ok(hr == DDERR_NOFOCUSWINDOW, "Got unexpected hr %#x.\n", hr);
477     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
478     ok(!device_window, "Unexpected device window found.\n");
479     hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW);
480     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
481     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
482     ok(!device_window, "Unexpected device window found.\n");
483     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
484     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
485     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
486     ok(!!device_window, "Device window not found.\n");
487
488     IDirectDraw_Release(ddraw);
489     DestroyWindow(focus_window);
490 }
491
492 static void test_clipper_blt(void)
493 {
494     IDirectDrawSurface *src_surface, *dst_surface;
495     RECT client_rect, src_rect, *rect;
496     IDirectDrawClipper *clipper;
497     DDSURFACEDESC surface_desc;
498     unsigned int i, j, x, y;
499     IDirectDraw *ddraw;
500     RGNDATA *rgn_data;
501     D3DCOLOR color;
502     HRGN r1, r2;
503     HWND window;
504     DDBLTFX fx;
505     HRESULT hr;
506     DWORD *ptr;
507     DWORD ret;
508
509     static const DWORD src_data[] =
510     {
511         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
512         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
513         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
514     };
515     static const D3DCOLOR expected1[] =
516     {
517         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
518         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
519         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
520         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
521     };
522     static const D3DCOLOR expected2[] =
523     {
524         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
525         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
526         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
527         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
528     };
529
530     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
531             10, 10, 640, 480, 0, 0, 0, 0);
532     ShowWindow(window, SW_SHOW);
533     if (!(ddraw = create_ddraw()))
534     {
535         skip("Failed to create a ddraw object, skipping test.\n");
536         DestroyWindow(window);
537         return;
538     }
539
540     ret = GetClientRect(window, &client_rect);
541     ok(ret, "Failed to get client rect.\n");
542     ret = MapWindowPoints(window, NULL, (POINT *)&client_rect, 2);
543     ok(ret, "Failed to map client rect.\n");
544
545     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
546     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
547
548     hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
549     ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
550     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
551     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
552     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
553     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
554     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
555     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
556     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
557     hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret);
558     ok(SUCCEEDED(hr), "Failed to get clip list, hr %#x.\n", hr);
559     ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#x.\n", rgn_data->rdh.dwSize);
560     ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#x.\n", rgn_data->rdh.iType);
561     ok(rgn_data->rdh.nCount == 1, "Got unexpected count %u.\n", rgn_data->rdh.nCount);
562     ok(rgn_data->rdh.nRgnSize == 16 || broken(rgn_data->rdh.nRgnSize == 168 /* NT4 */),
563             "Got unexpected region size %u.\n", rgn_data->rdh.nRgnSize);
564     ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
565             "Got unexpected bounding rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
566             rgn_data->rdh.rcBound.left, rgn_data->rdh.rcBound.top,
567             rgn_data->rdh.rcBound.right, rgn_data->rdh.rcBound.bottom,
568             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
569     rect = (RECT *)&rgn_data->Buffer[0];
570     ok(EqualRect(rect, &client_rect),
571             "Got unexpected clip rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
572             rect->left, rect->top, rect->right, rect->bottom,
573             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
574     HeapFree(GetProcessHeap(), 0, rgn_data);
575
576     r1 = CreateRectRgn(0, 0, 320, 240);
577     ok(!!r1, "Failed to create region.\n");
578     r2 = CreateRectRgn(320, 240, 640, 480);
579     ok(!!r2, "Failed to create region.\n");
580     CombineRgn(r1, r1, r2, RGN_OR);
581     ret = GetRegionData(r1, 0, NULL);
582     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
583     ret = GetRegionData(r1, ret, rgn_data);
584     ok(!!ret, "Failed to get region data.\n");
585
586     DeleteObject(r2);
587     DeleteObject(r1);
588
589     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
590     ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#x.\n", hr);
591     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
592     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
593     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
594     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
595
596     HeapFree(GetProcessHeap(), 0, rgn_data);
597
598     memset(&surface_desc, 0, sizeof(surface_desc));
599     surface_desc.dwSize = sizeof(surface_desc);
600     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
601     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
602     surface_desc.dwWidth = 640;
603     surface_desc.dwHeight = 480;
604     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
605     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
606     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
607     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
608     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
609     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
610
611     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
612     ok(SUCCEEDED(hr), "Failed to create source surface, hr %#x.\n", hr);
613     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
614     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
615
616     memset(&fx, 0, sizeof(fx));
617     fx.dwSize = sizeof(fx);
618     hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
619     ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#x.\n", hr);
620     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
621     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
622
623     hr = IDirectDrawSurface_Lock(src_surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
624     ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#x.\n", hr);
625     ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %u.\n", U1(surface_desc).lPitch);
626     ptr = surface_desc.lpSurface;
627     memcpy(&ptr[   0], &src_data[ 0], 6 * sizeof(DWORD));
628     memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
629     memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
630     hr = IDirectDrawSurface_Unlock(src_surface, NULL);
631     ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#x.\n", hr);
632
633     hr = IDirectDrawSurface_SetClipper(dst_surface, clipper);
634     ok(SUCCEEDED(hr), "Failed to set clipper, hr %#x.\n", hr);
635
636     SetRect(&src_rect, 1, 1, 5, 2);
637     hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
638     ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
639     for (i = 0; i < 4; ++i)
640     {
641         for (j = 0; j < 4; ++j)
642         {
643             x = 80 * ((2 * j) + 1);
644             y = 60 * ((2 * i) + 1);
645             color = get_surface_color(dst_surface, x, y);
646             ok(compare_color(color, expected1[i * 4 + j], 1),
647                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
648         }
649     }
650
651     U5(fx).dwFillColor = 0xff0000ff;
652     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
653     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
654     for (i = 0; i < 4; ++i)
655     {
656         for (j = 0; j < 4; ++j)
657         {
658             x = 80 * ((2 * j) + 1);
659             y = 60 * ((2 * i) + 1);
660             color = get_surface_color(dst_surface, x, y);
661             ok(compare_color(color, expected2[i * 4 + j], 1),
662                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
663         }
664     }
665
666     hr = IDirectDrawSurface_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
667     ok(hr == DDERR_BLTFASTCANTCLIP || broken(hr == E_NOTIMPL /* NT4 */), "Got unexpected hr %#x.\n", hr);
668
669     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
670     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
671     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
672     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
673     DestroyWindow(window);
674     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
675     ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
676     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
677     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
678     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
679     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
680     hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
681     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
682     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
683     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
684     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
685     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
686
687     IDirectDrawSurface_Release(dst_surface);
688     IDirectDrawSurface_Release(src_surface);
689     IDirectDrawClipper_Release(clipper);
690     IDirectDraw_Release(ddraw);
691 }
692
693 static void test_coop_level_d3d_state(void)
694 {
695     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
696     IDirectDrawSurface *rt, *surface;
697     IDirect3DMaterial *background;
698     IDirect3DViewport *viewport;
699     IDirect3DDevice *device;
700     D3DMATERIAL material;
701     IDirectDraw *ddraw;
702     D3DCOLOR color;
703     HWND window;
704     HRESULT hr;
705
706     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
707             0, 0, 640, 480, 0, 0, 0, 0);
708     if (!(ddraw = create_ddraw()))
709     {
710         skip("Failed to create ddraw object, skipping test.\n");
711         DestroyWindow(window);
712         return;
713     }
714     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
715     {
716         skip("Failed to create D3D device, skipping test.\n");
717         IDirectDraw_Release(ddraw);
718         DestroyWindow(window);
719         return;
720     }
721
722     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
723     viewport = create_viewport(device, 0, 0, 640, 480);
724     viewport_set_background(device, viewport, background);
725
726     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
727     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
728     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
729     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
730     color = get_surface_color(rt, 320, 240);
731     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
732
733     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
734     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
735     hr = IDirectDrawSurface_IsLost(rt);
736     ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
737     hr = restore_surfaces(ddraw);
738     ok(SUCCEEDED(hr), "Failed to restore surfaces, hr %#x.\n", hr);
739
740     memset(&material, 0, sizeof(material));
741     material.dwSize = sizeof(material);
742     U1(U(material).diffuse).r = 0.0f;
743     U2(U(material).diffuse).g = 1.0f;
744     U3(U(material).diffuse).b = 0.0f;
745     U4(U(material).diffuse).a = 1.0f;
746     hr = IDirect3DMaterial_SetMaterial(background, &material);
747     ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
748
749     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&surface);
750     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
751     ok(surface == rt, "Got unexpected surface %p.\n", surface);
752     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
753     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
754     color = get_surface_color(rt, 320, 240);
755     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
756
757     destroy_viewport(device, viewport);
758     destroy_material(background);
759     IDirectDrawSurface_Release(surface);
760     IDirectDrawSurface_Release(rt);
761     IDirect3DDevice_Release(device);
762     IDirectDraw_Release(ddraw);
763     DestroyWindow(window);
764 }
765
766 static void test_surface_interface_mismatch(void)
767 {
768     IDirectDraw *ddraw = NULL;
769     IDirect3D *d3d = NULL;
770     IDirectDrawSurface *surface = NULL, *ds;
771     IDirectDrawSurface3 *surface3 = NULL;
772     IDirect3DDevice *device = NULL;
773     IDirect3DViewport *viewport = NULL;
774     IDirect3DMaterial *background = NULL;
775     DDSURFACEDESC surface_desc;
776     DWORD z_depth = 0;
777     ULONG refcount;
778     HRESULT hr;
779     D3DCOLOR color;
780     HWND window;
781     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
782
783     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
784             0, 0, 640, 480, 0, 0, 0, 0);
785
786     if (!(ddraw = create_ddraw()))
787     {
788         skip("Failed to create a ddraw object, skipping test.\n");
789         goto cleanup;
790     }
791
792     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
793     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
794
795     memset(&surface_desc, 0, sizeof(surface_desc));
796     surface_desc.dwSize = sizeof(surface_desc);
797     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
798     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
799     surface_desc.dwWidth = 640;
800     surface_desc.dwHeight = 480;
801
802     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
803     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
804
805     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
806     if (FAILED(hr))
807     {
808         skip("Failed to get the IDirectDrawSurface3 interface, skipping test.\n");
809         goto cleanup;
810     }
811
812     hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
813     if (FAILED(hr))
814     {
815         skip("Failed to get the IDirect3D interface, skipping test.\n");
816         goto cleanup;
817     }
818
819     hr = IDirect3D_EnumDevices(d3d, enum_z_fmt, &z_depth);
820     if (FAILED(hr) || !z_depth)
821     {
822         skip("No depth buffer formats available, skipping test.\n");
823         goto cleanup;
824     }
825
826     memset(&surface_desc, 0, sizeof(surface_desc));
827     surface_desc.dwSize = sizeof(surface_desc);
828     surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
829     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
830     U2(surface_desc).dwZBufferBitDepth = z_depth;
831     surface_desc.dwWidth = 640;
832     surface_desc.dwHeight = 480;
833     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &ds, NULL);
834     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
835     if (FAILED(hr))
836         goto cleanup;
837
838     /* Using a different surface interface version still works */
839     hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
840     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
841     refcount = IDirectDrawSurface_Release(ds);
842     ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
843     if (FAILED(hr))
844         goto cleanup;
845
846     /* Here too */
847     hr = IDirectDrawSurface3_QueryInterface(surface3, &IID_IDirect3DHALDevice, (void **)&device);
848     ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
849     if (FAILED(hr))
850         goto cleanup;
851
852     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
853     viewport = create_viewport(device, 0, 0, 640, 480);
854     viewport_set_background(device, viewport, background);
855
856     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
857     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
858     color = get_surface_color(surface, 320, 240);
859     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
860
861 cleanup:
862     if (viewport)
863         destroy_viewport(device, viewport);
864     if (background)
865         destroy_material(background);
866     if (surface3) IDirectDrawSurface3_Release(surface3);
867     if (surface) IDirectDrawSurface_Release(surface);
868     if (device) IDirect3DDevice_Release(device);
869     if (d3d) IDirect3D_Release(d3d);
870     if (ddraw) IDirectDraw_Release(ddraw);
871     DestroyWindow(window);
872 }
873
874 static void test_coop_level_threaded(void)
875 {
876     struct create_window_thread_param p;
877     IDirectDraw *ddraw;
878     HRESULT hr;
879
880     if (!(ddraw = create_ddraw()))
881     {
882         skip("Failed to create a ddraw object, skipping test.\n");
883         return;
884     }
885     create_window_thread(&p);
886
887     hr = IDirectDraw_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
888     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
889
890     IDirectDraw_Release(ddraw);
891     destroy_window_thread(&p);
892 }
893
894 static ULONG get_refcount(IUnknown *test_iface)
895 {
896     IUnknown_AddRef(test_iface);
897     return IUnknown_Release(test_iface);
898 }
899
900 static void test_viewport_interfaces(void)
901 {
902     IDirectDraw *ddraw;
903     IDirect3D *d3d;
904     HRESULT hr;
905     ULONG ref;
906     IDirect3DViewport *viewport;
907     IDirect3DViewport2 *viewport2;
908     IDirect3DViewport3 *viewport3;
909     IDirectDrawGammaControl *gamma;
910     IUnknown *unknown;
911
912     if (!(ddraw = create_ddraw()))
913     {
914         skip("Failed to create ddraw object, skipping test.\n");
915         return;
916     }
917     hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
918     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to get d3d interface, hr %#x.\n", hr);
919     if (FAILED(hr))
920     {
921         skip("Direct3D not available, skipping tests\n");
922         IDirectDraw_Release(ddraw);
923         return;
924     }
925     ref = get_refcount((IUnknown *)d3d);
926     ok(ref == 2, "IDirect3D refcount is %d\n", ref);
927
928     hr = IDirect3D_CreateViewport(d3d, &viewport, NULL);
929     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
930     ref = get_refcount((IUnknown *)viewport);
931     ok(ref == 1, "Initial IDirect3DViewport refcount is %u\n", ref);
932     ref = get_refcount((IUnknown *)d3d);
933     ok(ref == 2, "IDirect3D refcount is %u\n", ref);
934
935     /* E_FAIL return values are returned by Winetestbot Windows NT machines. While not supporting
936      * newer interfaces is legitimate for old ddraw versions, E_FAIL violates Microsoft's rules
937      * for QueryInterface, hence the broken() */
938     gamma = (IDirectDrawGammaControl *)0xdeadbeef;
939     hr = IDirect3DViewport_QueryInterface(viewport, &IID_IDirectDrawGammaControl, (void **)&gamma);
940     ok(hr == E_NOINTERFACE || broken(hr == E_FAIL), "Got unexpected hr %#x.\n", hr);
941     ok(gamma == NULL, "Interface not set to NULL by failed QI call: %p\n", gamma);
942     if (SUCCEEDED(hr)) IDirectDrawGammaControl_Release(gamma);
943     /* NULL iid: Segfaults */
944
945     hr = IDirect3DViewport_QueryInterface(viewport, &IID_IDirect3DViewport2, (void **)&viewport2);
946     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE || broken(hr == E_FAIL),
947             "Failed to QI IDirect3DViewport2, hr %#x.\n", hr);
948     if (viewport2)
949     {
950         ref = get_refcount((IUnknown *)viewport);
951         ok(ref == 2, "IDirect3DViewport refcount is %u\n", ref);
952         ref = get_refcount((IUnknown *)viewport2);
953         ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
954         IDirect3DViewport2_Release(viewport2);
955         viewport2 = NULL;
956     }
957
958     hr = IDirect3DViewport_QueryInterface(viewport, &IID_IDirect3DViewport3, (void **)&viewport3);
959     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE || broken(hr == E_FAIL),
960             "Failed to QI IDirect3DViewport3, hr %#x.\n", hr);
961     if (viewport3)
962     {
963         ref = get_refcount((IUnknown *)viewport);
964         ok(ref == 2, "IDirect3DViewport refcount is %u\n", ref);
965         ref = get_refcount((IUnknown *)viewport3);
966         ok(ref == 2, "IDirect3DViewport3 refcount is %u\n", ref);
967         IDirect3DViewport3_Release(viewport3);
968     }
969
970     hr = IDirect3DViewport_QueryInterface(viewport, &IID_IUnknown, (void **)&unknown);
971     ok(SUCCEEDED(hr), "Failed to QI IUnknown, hr %#x.\n", hr);
972     if (unknown)
973     {
974         ref = get_refcount((IUnknown *)viewport);
975         ok(ref == 2, "IDirect3DViewport refcount is %u\n", ref);
976         ref = get_refcount(unknown);
977         ok(ref == 2, "IUnknown refcount is %u\n", ref);
978         IUnknown_Release(unknown);
979     }
980
981     IDirect3DViewport_Release(viewport);
982     IDirect3D_Release(d3d);
983     IDirectDraw_Release(ddraw);
984 }
985
986 static void test_zenable(void)
987 {
988     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
989     static D3DTLVERTEX tquad[] =
990     {
991         {{  0.0f}, {480.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
992         {{  0.0f}, {  0.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
993         {{640.0f}, {480.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
994         {{640.0f}, {  0.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
995     };
996     IDirect3DExecuteBuffer *execute_buffer;
997     D3DEXECUTEBUFFERDESC exec_desc;
998     IDirect3DMaterial *background;
999     IDirect3DViewport *viewport;
1000     D3DEXECUTEDATA exec_data;
1001     IDirect3DDevice *device;
1002     IDirectDrawSurface *rt;
1003     IDirectDraw *ddraw;
1004     UINT inst_length;
1005     D3DCOLOR color;
1006     HWND window;
1007     HRESULT hr;
1008     UINT x, y;
1009     UINT i, j;
1010     void *ptr;
1011
1012     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1013             0, 0, 640, 480, 0, 0, 0, 0);
1014     if (!(ddraw = create_ddraw()))
1015     {
1016         skip("Failed to create ddraw object, skipping test.\n");
1017         DestroyWindow(window);
1018         return;
1019     }
1020     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1021     {
1022         skip("Failed to create D3D device, skipping test.\n");
1023         IDirectDraw_Release(ddraw);
1024         DestroyWindow(window);
1025         return;
1026     }
1027
1028     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1029     viewport = create_viewport(device, 0, 0, 640, 480);
1030     viewport_set_background(device, viewport, background);
1031
1032     memset(&exec_desc, 0, sizeof(exec_desc));
1033     exec_desc.dwSize = sizeof(exec_desc);
1034     exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
1035     exec_desc.dwBufferSize = 1024;
1036     exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
1037
1038     hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
1039     ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#x.\n", hr);
1040     hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
1041     ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr);
1042     memcpy(exec_desc.lpData, tquad, sizeof(tquad));
1043     ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad);
1044     emit_process_vertices(&ptr, 0, 4);
1045     emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1046     emit_tquad(&ptr, 0);
1047     emit_end(&ptr);
1048     inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
1049     inst_length -= sizeof(tquad);
1050     hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
1051     ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#x.\n", hr);
1052
1053     memset(&exec_data, 0, sizeof(exec_data));
1054     exec_data.dwSize = sizeof(exec_data);
1055     exec_data.dwVertexCount = 4;
1056     exec_data.dwInstructionOffset = sizeof(tquad);
1057     exec_data.dwInstructionLength = inst_length;
1058     hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
1059     ok(SUCCEEDED(hr), "Failed to set execute data, hr %#x.\n", hr);
1060
1061     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1062     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1063     hr = IDirect3DDevice_BeginScene(device);
1064     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1065     hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1066     ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
1067     hr = IDirect3DDevice_EndScene(device);
1068     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1069
1070     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
1071     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1072     for (i = 0; i < 4; ++i)
1073     {
1074         for (j = 0; j < 4; ++j)
1075         {
1076             x = 80 * ((2 * j) + 1);
1077             y = 60 * ((2 * i) + 1);
1078             color = get_surface_color(rt, x, y);
1079             ok(compare_color(color, 0x0000ff00, 1),
1080                     "Expected color 0x0000ff00 at %u, %u, got 0x%08x.\n", x, y, color);
1081         }
1082     }
1083     IDirectDrawSurface_Release(rt);
1084
1085     destroy_viewport(device, viewport);
1086     IDirect3DExecuteBuffer_Release(execute_buffer);
1087     destroy_material(background);
1088     IDirect3DDevice_Release(device);
1089     IDirectDraw_Release(ddraw);
1090     DestroyWindow(window);
1091 }
1092
1093 static void test_ck_rgba(void)
1094 {
1095     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1096     static D3DTLVERTEX tquad[] =
1097     {
1098         {{  0.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1099         {{  0.0f}, {  0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1100         {{640.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1101         {{640.0f}, {  0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1102         {{  0.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1103         {{  0.0f}, {  0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1104         {{640.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1105         {{640.0f}, {  0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1106     };
1107     static const struct
1108     {
1109         D3DCOLOR fill_color;
1110         BOOL color_key;
1111         BOOL blend;
1112         D3DCOLOR result1;
1113         D3DCOLOR result2;
1114     }
1115     tests[] =
1116     {
1117         {0xff00ff00, TRUE,  TRUE,  0x00ff0000, 0x000000ff},
1118         {0xff00ff00, TRUE,  FALSE, 0x00ff0000, 0x000000ff},
1119         {0xff00ff00, FALSE, TRUE,  0x0000ff00, 0x0000ff00},
1120         {0xff00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1121         {0x7f00ff00, TRUE,  TRUE,  0x00807f00, 0x00807f00},
1122         {0x7f00ff00, TRUE,  FALSE, 0x0000ff00, 0x0000ff00},
1123         {0x7f00ff00, FALSE, TRUE,  0x00807f00, 0x00807f00},
1124         {0x7f00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1125     };
1126
1127     IDirect3DExecuteBuffer *execute_buffer;
1128     D3DTEXTUREHANDLE texture_handle;
1129     D3DEXECUTEBUFFERDESC exec_desc;
1130     IDirect3DMaterial *background;
1131     IDirectDrawSurface *surface;
1132     IDirect3DViewport *viewport;
1133     DDSURFACEDESC surface_desc;
1134     IDirect3DTexture *texture;
1135     IDirect3DDevice *device;
1136     IDirectDrawSurface *rt;
1137     IDirectDraw *ddraw;
1138     D3DCOLOR color;
1139     HWND window;
1140     DDBLTFX fx;
1141     HRESULT hr;
1142     UINT i;
1143
1144     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1145             0, 0, 640, 480, 0, 0, 0, 0);
1146     if (!(ddraw = create_ddraw()))
1147     {
1148         skip("Failed to create ddraw object, skipping test.\n");
1149         DestroyWindow(window);
1150         return;
1151     }
1152     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1153     {
1154         skip("Failed to create D3D device, skipping test.\n");
1155         DestroyWindow(window);
1156         return;
1157     }
1158
1159     background = create_diffuse_material(device, 1.0, 0.0f, 0.0f, 1.0f);
1160     viewport = create_viewport(device, 0, 0, 640, 480);
1161     viewport_set_background(device, viewport, background);
1162
1163     memset(&surface_desc, 0, sizeof(surface_desc));
1164     surface_desc.dwSize = sizeof(surface_desc);
1165     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1166     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1167     surface_desc.dwWidth = 256;
1168     surface_desc.dwHeight = 256;
1169     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1170     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
1171     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1172     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1173     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1174     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1175     U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
1176     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0xff00ff00;
1177     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0xff00ff00;
1178     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1179     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
1180     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture, (void **)&texture);
1181     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1182     hr = IDirect3DTexture_GetHandle(texture, device, &texture_handle);
1183     ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1184     IDirect3DTexture_Release(texture);
1185
1186     memset(&exec_desc, 0, sizeof(exec_desc));
1187     exec_desc.dwSize = sizeof(exec_desc);
1188     exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
1189     exec_desc.dwBufferSize = 1024;
1190     exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
1191     hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
1192     ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#x.\n", hr);
1193
1194     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
1195     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1196
1197     for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
1198     {
1199         UINT draw1_len, draw2_len;
1200         D3DEXECUTEDATA exec_data;
1201         void *ptr;
1202
1203         hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
1204         ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr);
1205         memcpy(exec_desc.lpData, tquad, sizeof(tquad));
1206         ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad);
1207         emit_process_vertices(&ptr, 0, 4);
1208         emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1209         emit_set_rs(&ptr, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
1210         emit_set_rs(&ptr, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
1211         emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, tests[i].color_key);
1212         emit_set_rs(&ptr, D3DRENDERSTATE_ALPHABLENDENABLE, tests[i].blend);
1213         emit_tquad(&ptr, 0);
1214         emit_end(&ptr);
1215         draw1_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - sizeof(tquad);
1216         emit_process_vertices(&ptr, 4, 4);
1217         emit_tquad(&ptr, 0);
1218         emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1219         emit_end(&ptr);
1220         draw2_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw1_len;
1221         hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
1222         ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#x.\n", hr);
1223
1224         memset(&fx, 0, sizeof(fx));
1225         fx.dwSize = sizeof(fx);
1226         U5(fx).dwFillColor = tests[i].fill_color;
1227         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1228         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1229
1230         memset(&exec_data, 0, sizeof(exec_data));
1231         exec_data.dwSize = sizeof(exec_data);
1232         exec_data.dwVertexCount = 8;
1233         exec_data.dwInstructionOffset = sizeof(tquad);
1234         exec_data.dwInstructionLength = draw1_len;
1235         hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
1236         ok(SUCCEEDED(hr), "Failed to set execute data, hr %#x.\n", hr);
1237
1238         hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
1239         ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1240         hr = IDirect3DDevice_BeginScene(device);
1241         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1242         hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1243         ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
1244         hr = IDirect3DDevice_EndScene(device);
1245         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1246
1247         color = get_surface_color(rt, 320, 240);
1248         if (i == 2 || i == 3)
1249             todo_wine ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1250                     tests[i].result1, i, color);
1251         else
1252             ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1253                     tests[i].result1, i, color);
1254
1255         U5(fx).dwFillColor = 0xff0000ff;
1256         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1257         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1258
1259         exec_data.dwInstructionOffset = sizeof(tquad) + draw1_len;
1260         exec_data.dwInstructionLength = draw2_len;
1261         hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
1262         ok(SUCCEEDED(hr), "Failed to set execute data, hr %#x.\n", hr);
1263
1264         hr = IDirect3DDevice_BeginScene(device);
1265         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1266         hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1267         ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
1268         hr = IDirect3DDevice_EndScene(device);
1269         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1270
1271         /* This tests that fragments that are masked out by the color key are
1272          * discarded, instead of just fully transparent. */
1273         color = get_surface_color(rt, 320, 240);
1274         if (i == 2 || i == 3)
1275             todo_wine ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1276                     tests[i].result2, i, color);
1277         else
1278             ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1279                     tests[i].result2, i, color);
1280     }
1281
1282     IDirectDrawSurface_Release(rt);
1283     IDirect3DExecuteBuffer_Release(execute_buffer);
1284     IDirectDrawSurface_Release(surface);
1285     destroy_viewport(device, viewport);
1286     destroy_material(background);
1287     IDirect3DDevice_Release(device);
1288     IDirectDraw_Release(ddraw);
1289     DestroyWindow(window);
1290 }
1291
1292 struct qi_test
1293 {
1294     REFIID iid;
1295     REFIID refcount_iid;
1296     HRESULT hr;
1297 };
1298
1299 static void test_qi(const char *test_name, IUnknown *base_iface,
1300         REFIID refcount_iid, const struct qi_test *tests, UINT entry_count)
1301 {
1302     ULONG refcount, expected_refcount;
1303     IUnknown *iface1, *iface2;
1304     HRESULT hr;
1305     UINT i, j;
1306
1307     for (i = 0; i < entry_count; ++i)
1308     {
1309         hr = IUnknown_QueryInterface(base_iface, tests[i].iid, (void **)&iface1);
1310         ok(hr == tests[i].hr, "Got hr %#x for test \"%s\" %u.\n", hr, test_name, i);
1311         if (SUCCEEDED(hr))
1312         {
1313             for (j = 0; j < entry_count; ++j)
1314             {
1315                 hr = IUnknown_QueryInterface(iface1, tests[j].iid, (void **)&iface2);
1316                 ok(hr == tests[j].hr, "Got hr %#x for test \"%s\" %u, %u.\n", hr, test_name, i, j);
1317                 if (SUCCEEDED(hr))
1318                 {
1319                     expected_refcount = 0;
1320                     if (IsEqualGUID(refcount_iid, tests[j].refcount_iid))
1321                         ++expected_refcount;
1322                     if (IsEqualGUID(tests[i].refcount_iid, tests[j].refcount_iid))
1323                         ++expected_refcount;
1324                     refcount = IUnknown_Release(iface2);
1325                     ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, %u, expected %u.\n",
1326                             refcount, test_name, i, j, expected_refcount);
1327                 }
1328             }
1329
1330             expected_refcount = 0;
1331             if (IsEqualGUID(refcount_iid, tests[i].refcount_iid))
1332                 ++expected_refcount;
1333             refcount = IUnknown_Release(iface1);
1334             ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, expected %u.\n",
1335                     refcount, test_name, i, expected_refcount);
1336         }
1337     }
1338 }
1339
1340 static void test_surface_qi(void)
1341 {
1342     static const struct qi_test tests[] =
1343     {
1344         {&IID_IDirect3DTexture2,        &IID_IDirectDrawSurface,        S_OK         },
1345         {&IID_IDirect3DTexture,         &IID_IDirectDrawSurface,        S_OK         },
1346         {&IID_IDirectDrawGammaControl,  &IID_IDirectDrawGammaControl,   S_OK         },
1347         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1348         {&IID_IDirectDrawSurface7,      &IID_IDirectDrawSurface7,       S_OK         },
1349         {&IID_IDirectDrawSurface4,      &IID_IDirectDrawSurface4,       S_OK         },
1350         {&IID_IDirectDrawSurface3,      &IID_IDirectDrawSurface3,       S_OK         },
1351         {&IID_IDirectDrawSurface2,      &IID_IDirectDrawSurface2,       S_OK         },
1352         {&IID_IDirectDrawSurface,       &IID_IDirectDrawSurface,        S_OK         },
1353         {&IID_IDirect3DDevice7,         NULL,                           E_INVALIDARG },
1354         {&IID_IDirect3DDevice3,         NULL,                           E_INVALIDARG },
1355         {&IID_IDirect3DDevice2,         NULL,                           E_INVALIDARG },
1356         {&IID_IDirect3DDevice,          NULL,                           E_INVALIDARG },
1357         {&IID_IDirect3D7,               NULL,                           E_INVALIDARG },
1358         {&IID_IDirect3D3,               NULL,                           E_INVALIDARG },
1359         {&IID_IDirect3D2,               NULL,                           E_INVALIDARG },
1360         {&IID_IDirect3D,                NULL,                           E_INVALIDARG },
1361         {&IID_IDirectDraw7,             NULL,                           E_INVALIDARG },
1362         {&IID_IDirectDraw4,             NULL,                           E_INVALIDARG },
1363         {&IID_IDirectDraw3,             NULL,                           E_INVALIDARG },
1364         {&IID_IDirectDraw2,             NULL,                           E_INVALIDARG },
1365         {&IID_IDirectDraw,              NULL,                           E_INVALIDARG },
1366         {&IID_IDirect3DLight,           NULL,                           E_INVALIDARG },
1367         {&IID_IDirect3DMaterial,        NULL,                           E_INVALIDARG },
1368         {&IID_IDirect3DMaterial2,       NULL,                           E_INVALIDARG },
1369         {&IID_IDirect3DMaterial3,       NULL,                           E_INVALIDARG },
1370         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_INVALIDARG },
1371         {&IID_IDirect3DViewport,        NULL,                           E_INVALIDARG },
1372         {&IID_IDirect3DViewport2,       NULL,                           E_INVALIDARG },
1373         {&IID_IDirect3DViewport3,       NULL,                           E_INVALIDARG },
1374         {&IID_IDirect3DVertexBuffer,    NULL,                           E_INVALIDARG },
1375         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_INVALIDARG },
1376         {&IID_IDirectDrawPalette,       NULL,                           E_INVALIDARG },
1377         {&IID_IDirectDrawClipper,       NULL,                           E_INVALIDARG },
1378         {&IID_IUnknown,                 &IID_IDirectDrawSurface,        S_OK         },
1379     };
1380
1381     IDirectDrawSurface *surface;
1382     DDSURFACEDESC surface_desc;
1383     IDirect3DDevice *device;
1384     IDirectDraw *ddraw;
1385     HWND window;
1386     HRESULT hr;
1387
1388     if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
1389     {
1390         win_skip("DirectDrawCreateEx not available, skipping test.\n");
1391         return;
1392     }
1393
1394     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1395             0, 0, 640, 480, 0, 0, 0, 0);
1396     if (!(ddraw = create_ddraw()))
1397     {
1398         skip("Failed to create a ddraw object, skipping test.\n");
1399         return;
1400     }
1401     /* Try to create a D3D device to see if the ddraw implementation supports
1402      * D3D. 64-bit ddraw in particular doesn't seem to support D3D, and
1403      * doesn't support e.g. the IDirect3DTexture interfaces. */
1404     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1405     {
1406         skip("Failed to create D3D device, skipping test.\n");
1407         DestroyWindow(window);
1408         return;
1409     }
1410     IDirect3DDevice_Release(device);
1411
1412     memset(&surface_desc, 0, sizeof(surface_desc));
1413     surface_desc.dwSize = sizeof(surface_desc);
1414     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1415     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1416     surface_desc.dwWidth = 512;
1417     surface_desc.dwHeight = 512;
1418     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1419     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1420
1421     test_qi("surface_qi", (IUnknown *)surface, &IID_IDirectDrawSurface, tests, sizeof(tests) / sizeof(*tests));
1422
1423     IDirectDrawSurface_Release(surface);
1424     IDirectDraw_Release(ddraw);
1425     DestroyWindow(window);
1426 }
1427
1428 static void test_device_qi(void)
1429 {
1430     static const struct qi_test tests[] =
1431     {
1432         {&IID_IDirect3DTexture2,        &IID_IDirectDrawSurface,        S_OK         },
1433         {&IID_IDirect3DTexture,         &IID_IDirectDrawSurface,        S_OK         },
1434         {&IID_IDirectDrawGammaControl,  &IID_IDirectDrawGammaControl,   S_OK         },
1435         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1436         {&IID_IDirectDrawSurface7,      &IID_IDirectDrawSurface7,       S_OK         },
1437         {&IID_IDirectDrawSurface4,      &IID_IDirectDrawSurface4,       S_OK         },
1438         {&IID_IDirectDrawSurface3,      &IID_IDirectDrawSurface3,       S_OK         },
1439         {&IID_IDirectDrawSurface2,      &IID_IDirectDrawSurface2,       S_OK         },
1440         {&IID_IDirectDrawSurface,       &IID_IDirectDrawSurface,        S_OK         },
1441         {&IID_IDirect3DDevice7,         NULL,                           E_INVALIDARG },
1442         {&IID_IDirect3DDevice3,         NULL,                           E_INVALIDARG },
1443         {&IID_IDirect3DDevice2,         NULL,                           E_INVALIDARG },
1444         {&IID_IDirect3DDevice,          NULL,                           E_INVALIDARG },
1445         {&IID_IDirect3DHALDevice,       &IID_IDirectDrawSurface,        S_OK         },
1446         {&IID_IDirect3D7,               NULL,                           E_INVALIDARG },
1447         {&IID_IDirect3D3,               NULL,                           E_INVALIDARG },
1448         {&IID_IDirect3D2,               NULL,                           E_INVALIDARG },
1449         {&IID_IDirect3D,                NULL,                           E_INVALIDARG },
1450         {&IID_IDirectDraw7,             NULL,                           E_INVALIDARG },
1451         {&IID_IDirectDraw4,             NULL,                           E_INVALIDARG },
1452         {&IID_IDirectDraw3,             NULL,                           E_INVALIDARG },
1453         {&IID_IDirectDraw2,             NULL,                           E_INVALIDARG },
1454         {&IID_IDirectDraw,              NULL,                           E_INVALIDARG },
1455         {&IID_IDirect3DLight,           NULL,                           E_INVALIDARG },
1456         {&IID_IDirect3DMaterial,        NULL,                           E_INVALIDARG },
1457         {&IID_IDirect3DMaterial2,       NULL,                           E_INVALIDARG },
1458         {&IID_IDirect3DMaterial3,       NULL,                           E_INVALIDARG },
1459         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_INVALIDARG },
1460         {&IID_IDirect3DViewport,        NULL,                           E_INVALIDARG },
1461         {&IID_IDirect3DViewport2,       NULL,                           E_INVALIDARG },
1462         {&IID_IDirect3DViewport3,       NULL,                           E_INVALIDARG },
1463         {&IID_IDirect3DVertexBuffer,    NULL,                           E_INVALIDARG },
1464         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_INVALIDARG },
1465         {&IID_IDirectDrawPalette,       NULL,                           E_INVALIDARG },
1466         {&IID_IDirectDrawClipper,       NULL,                           E_INVALIDARG },
1467         {&IID_IUnknown,                 &IID_IDirectDrawSurface,        S_OK         },
1468     };
1469
1470
1471     IDirect3DDevice *device;
1472     IDirectDraw *ddraw;
1473     HWND window;
1474
1475     if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
1476     {
1477         win_skip("DirectDrawCreateEx not available, skipping test.\n");
1478         return;
1479     }
1480
1481     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1482             0, 0, 640, 480, 0, 0, 0, 0);
1483     if (!(ddraw = create_ddraw()))
1484     {
1485         skip("Failed to create ddraw object, skipping test.\n");
1486         DestroyWindow(window);
1487         return;
1488     }
1489     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1490     {
1491         skip("Failed to create D3D device, skipping test.\n");
1492         DestroyWindow(window);
1493         return;
1494     }
1495
1496     test_qi("device_qi", (IUnknown *)device, &IID_IDirectDrawSurface, tests, sizeof(tests) / sizeof(*tests));
1497
1498     IDirect3DDevice_Release(device);
1499     IDirectDraw_Release(ddraw);
1500     DestroyWindow(window);
1501 }
1502
1503 START_TEST(ddraw1)
1504 {
1505     test_coop_level_create_device_window();
1506     test_clipper_blt();
1507     test_coop_level_d3d_state();
1508     test_surface_interface_mismatch();
1509     test_coop_level_threaded();
1510     test_viewport_interfaces();
1511     test_zenable();
1512     test_ck_rgba();
1513     test_surface_qi();
1514     test_device_qi();
1515 }