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