comctl32/imagelist: Use proper color format for merged image lists.
[wine] / dlls / ddraw / tests / ddraw4.c
1 /*
2  * Copyright 2011-2012 Henri Verbeet for CodeWeavers
3  * Copyright 2012-2013 Stefan Dösinger for CodeWeavers
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 #define COBJMACROS
20
21 #include "wine/test.h"
22 #include <limits.h>
23 #include "d3d.h"
24
25 struct vec2
26 {
27     float x, y;
28 };
29
30 struct vec3
31 {
32     float x, y, z;
33 };
34
35 struct vec4
36 {
37     float x, y, z, w;
38 };
39
40 struct create_window_thread_param
41 {
42     HWND window;
43     HANDLE window_created;
44     HANDLE destroy_window;
45     HANDLE thread;
46 };
47
48 static BOOL compare_float(float f, float g, unsigned int ulps)
49 {
50     int x = *(int *)&f;
51     int y = *(int *)&g;
52
53     if (x < 0)
54         x = INT_MIN - x;
55     if (y < 0)
56         y = INT_MIN - y;
57
58     if (abs(x - y) > ulps)
59         return FALSE;
60
61     return TRUE;
62 }
63
64 static BOOL compare_vec4(struct vec4 *vec, float x, float y, float z, float w, unsigned int ulps)
65 {
66     return compare_float(vec->x, x, ulps)
67             && compare_float(vec->y, y, ulps)
68             && compare_float(vec->z, z, ulps)
69             && compare_float(vec->w, w, ulps);
70 }
71
72 static BOOL compare_color(D3DCOLOR c1, D3DCOLOR c2, BYTE max_diff)
73 {
74     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
75     c1 >>= 8; c2 >>= 8;
76     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
77     c1 >>= 8; c2 >>= 8;
78     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
79     c1 >>= 8; c2 >>= 8;
80     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
81     return TRUE;
82 }
83
84 static DWORD WINAPI create_window_thread_proc(void *param)
85 {
86     struct create_window_thread_param *p = param;
87     DWORD res;
88     BOOL ret;
89
90     p->window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
91             0, 0, 640, 480, 0, 0, 0, 0);
92     ret = SetEvent(p->window_created);
93     ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
94
95     for (;;)
96     {
97         MSG msg;
98
99         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
100             DispatchMessage(&msg);
101         res = WaitForSingleObject(p->destroy_window, 100);
102         if (res == WAIT_OBJECT_0)
103             break;
104         if (res != WAIT_TIMEOUT)
105         {
106             ok(0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
107             break;
108         }
109     }
110
111     DestroyWindow(p->window);
112
113     return 0;
114 }
115
116 static void create_window_thread(struct create_window_thread_param *p)
117 {
118     DWORD res, tid;
119
120     p->window_created = CreateEvent(NULL, FALSE, FALSE, NULL);
121     ok(!!p->window_created, "CreateEvent failed, last error %#x.\n", GetLastError());
122     p->destroy_window = CreateEvent(NULL, FALSE, FALSE, NULL);
123     ok(!!p->destroy_window, "CreateEvent failed, last error %#x.\n", GetLastError());
124     p->thread = CreateThread(NULL, 0, create_window_thread_proc, p, 0, &tid);
125     ok(!!p->thread, "Failed to create thread, last error %#x.\n", GetLastError());
126     res = WaitForSingleObject(p->window_created, INFINITE);
127     ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
128 }
129
130 static void destroy_window_thread(struct create_window_thread_param *p)
131 {
132     SetEvent(p->destroy_window);
133     WaitForSingleObject(p->thread, INFINITE);
134     CloseHandle(p->destroy_window);
135     CloseHandle(p->window_created);
136     CloseHandle(p->thread);
137 }
138
139 static IDirectDrawSurface4 *get_depth_stencil(IDirect3DDevice3 *device)
140 {
141     IDirectDrawSurface4 *rt, *ret;
142     DDSCAPS2 caps = {DDSCAPS_ZBUFFER, 0, 0, 0};
143     HRESULT hr;
144
145     hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
146     ok(SUCCEEDED(hr), "Failed to get the render target, hr %#x.\n", hr);
147     hr = IDirectDrawSurface4_GetAttachedSurface(rt, &caps, &ret);
148     ok(SUCCEEDED(hr) || hr == DDERR_NOTFOUND, "Failed to get the z buffer, hr %#x.\n", hr);
149     IDirectDrawSurface4_Release(rt);
150     return ret;
151 }
152
153 static D3DCOLOR get_surface_color(IDirectDrawSurface4 *surface, UINT x, UINT y)
154 {
155     RECT rect = {x, y, x + 1, y + 1};
156     DDSURFACEDESC2 surface_desc;
157     D3DCOLOR color;
158     HRESULT hr;
159
160     memset(&surface_desc, 0, sizeof(surface_desc));
161     surface_desc.dwSize = sizeof(surface_desc);
162
163     hr = IDirectDrawSurface4_Lock(surface, &rect, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
164     ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
165     if (FAILED(hr))
166         return 0xdeadbeef;
167
168     color = *((DWORD *)surface_desc.lpSurface) & 0x00ffffff;
169
170     hr = IDirectDrawSurface4_Unlock(surface, &rect);
171     ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
172
173     return color;
174 }
175
176 static HRESULT CALLBACK enum_z_fmt(DDPIXELFORMAT *format, void *ctx)
177 {
178     DDPIXELFORMAT *z_fmt = ctx;
179
180     if (U1(*format).dwZBufferBitDepth > U1(*z_fmt).dwZBufferBitDepth)
181         *z_fmt = *format;
182
183     return DDENUMRET_OK;
184 }
185
186 static IDirectDraw4 *create_ddraw(void)
187 {
188     IDirectDraw4 *ddraw4;
189     IDirectDraw *ddraw1;
190     HRESULT hr;
191
192     if (FAILED(DirectDrawCreate(NULL, &ddraw1, NULL)))
193         return NULL;
194
195     hr = IDirectDraw_QueryInterface(ddraw1, &IID_IDirectDraw4, (void **)&ddraw4);
196     IDirectDraw_Release(ddraw1);
197     if (FAILED(hr))
198         return NULL;
199
200     return ddraw4;
201 }
202
203 static IDirect3DDevice3 *create_device(HWND window, DWORD coop_level)
204 {
205     IDirectDrawSurface4 *surface, *ds;
206     IDirect3DDevice3 *device = NULL;
207     DDSURFACEDESC2 surface_desc;
208     IDirectDraw4 *ddraw4;
209     DDPIXELFORMAT z_fmt;
210     IDirect3D3 *d3d3;
211     HRESULT hr;
212
213     if (!(ddraw4 = create_ddraw()))
214         return NULL;
215
216     hr = IDirectDraw4_SetCooperativeLevel(ddraw4, window, coop_level);
217     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
218
219     memset(&surface_desc, 0, sizeof(surface_desc));
220     surface_desc.dwSize = sizeof(surface_desc);
221     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
222     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
223     surface_desc.dwWidth = 640;
224     surface_desc.dwHeight = 480;
225
226     hr = IDirectDraw4_CreateSurface(ddraw4, &surface_desc, &surface, NULL);
227     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
228
229     if (coop_level & DDSCL_NORMAL)
230     {
231         IDirectDrawClipper *clipper;
232
233         hr = IDirectDraw4_CreateClipper(ddraw4, 0, &clipper, NULL);
234         ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
235         hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
236         ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
237         hr = IDirectDrawSurface4_SetClipper(surface, clipper);
238         ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#x.\n", hr);
239         IDirectDrawClipper_Release(clipper);
240     }
241
242     hr = IDirectDraw4_QueryInterface(ddraw4, &IID_IDirect3D3, (void **)&d3d3);
243     IDirectDraw4_Release(ddraw4);
244     if (FAILED(hr))
245     {
246         IDirectDrawSurface4_Release(surface);
247         return NULL;
248     }
249
250     memset(&z_fmt, 0, sizeof(z_fmt));
251     hr = IDirect3D3_EnumZBufferFormats(d3d3, &IID_IDirect3DHALDevice, enum_z_fmt, &z_fmt);
252     if (FAILED(hr) || !z_fmt.dwSize)
253     {
254         IDirect3D3_Release(d3d3);
255         IDirectDrawSurface4_Release(surface);
256         return NULL;
257     }
258
259     memset(&surface_desc, 0, sizeof(surface_desc));
260     surface_desc.dwSize = sizeof(surface_desc);
261     surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
262     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
263     U4(surface_desc).ddpfPixelFormat = z_fmt;
264     surface_desc.dwWidth = 640;
265     surface_desc.dwHeight = 480;
266     hr = IDirectDraw4_CreateSurface(ddraw4, &surface_desc, &ds, NULL);
267     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
268     if (FAILED(hr))
269     {
270         IDirect3D3_Release(d3d3);
271         IDirectDrawSurface4_Release(surface);
272         return NULL;
273     }
274
275     hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
276     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
277     IDirectDrawSurface4_Release(ds);
278     if (FAILED(hr))
279     {
280         IDirect3D3_Release(d3d3);
281         IDirectDrawSurface4_Release(surface);
282         return NULL;
283     }
284
285     hr = IDirect3D3_CreateDevice(d3d3, &IID_IDirect3DHALDevice, surface, &device, NULL);
286     IDirect3D3_Release(d3d3);
287     IDirectDrawSurface4_Release(surface);
288     if (FAILED(hr))
289         return NULL;
290
291     return device;
292 }
293
294 static IDirect3DViewport3 *create_viewport(IDirect3DDevice3 *device, UINT x, UINT y, UINT w, UINT h)
295 {
296     IDirect3DViewport3 *viewport;
297     D3DVIEWPORT2 vp;
298     IDirect3D3 *d3d;
299     HRESULT hr;
300
301     hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
302     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
303     hr = IDirect3D3_CreateViewport(d3d, &viewport, NULL);
304     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
305     hr = IDirect3DDevice3_AddViewport(device, viewport);
306     ok(SUCCEEDED(hr), "Failed to add viewport, hr %#x.\n", hr);
307     memset(&vp, 0, sizeof(vp));
308     vp.dwSize = sizeof(vp);
309     vp.dwX = x;
310     vp.dwY = y;
311     vp.dwWidth = w;
312     vp.dwHeight = h;
313     vp.dvClipX = -1.0f;
314     vp.dvClipY =  1.0f;
315     vp.dvClipWidth = 2.0f;
316     vp.dvClipHeight = 2.0f;
317     vp.dvMinZ = 0.0f;
318     vp.dvMaxZ = 1.0f;
319     hr = IDirect3DViewport3_SetViewport2(viewport, &vp);
320     ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#x.\n", hr);
321     IDirect3D3_Release(d3d);
322
323     return viewport;
324 }
325
326 static void destroy_viewport(IDirect3DDevice3 *device, IDirect3DViewport3 *viewport)
327 {
328     HRESULT hr;
329
330     hr = IDirect3DDevice3_DeleteViewport(device, viewport);
331     ok(SUCCEEDED(hr), "Failed to delete viewport, hr %#x.\n", hr);
332     IDirect3DViewport3_Release(viewport);
333 }
334
335 static const UINT *expect_messages;
336
337 static LRESULT CALLBACK test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
338 {
339     if (expect_messages && message == *expect_messages)
340         ++expect_messages;
341
342     return DefWindowProcA(hwnd, message, wparam, lparam);
343 }
344
345 /* Set the wndproc back to what ddraw expects it to be, and release the ddraw
346  * interface. This prevents subsequent SetCooperativeLevel() calls on a
347  * different window from failing with DDERR_HWNDALREADYSET. */
348 static void fix_wndproc(HWND window, LONG_PTR proc)
349 {
350     IDirectDraw4 *ddraw;
351     HRESULT hr;
352
353     if (!(ddraw = create_ddraw()))
354         return;
355
356     SetWindowLongPtrA(window, GWLP_WNDPROC, proc);
357     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
358     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
359     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
360     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
361
362     IDirectDraw4_Release(ddraw);
363 }
364
365 static void test_process_vertices(void)
366 {
367     IDirect3DVertexBuffer *src_vb, *dst_vb;
368     IDirect3DViewport3 *viewport;
369     D3DVERTEXBUFFERDESC vb_desc;
370     IDirect3DDevice3 *device;
371     struct vec3 *src_data;
372     struct vec4 *dst_data;
373     IDirect3D3 *d3d3;
374     D3DVIEWPORT2 vp2;
375     D3DVIEWPORT vp1;
376     HWND window;
377     HRESULT hr;
378
379     static D3DMATRIX identity =
380     {
381         1.0f, 0.0f, 0.0f, 0.0f,
382         0.0f, 1.0f, 0.0f, 0.0f,
383         0.0f, 0.0f, 1.0f, 0.0f,
384         0.0f, 0.0f, 0.0f, 1.0f,
385     };
386     static D3DMATRIX projection =
387     {
388         1.0f, 0.0f, 0.0f, 0.0f,
389         0.0f, 1.0f, 0.0f, 0.0f,
390         0.0f, 0.0f, 1.0f, 0.0f,
391         6.0f, 7.0f, 8.0f, 1.0f,
392     };
393
394     window = CreateWindowA("static", "d3d7_test", WS_OVERLAPPEDWINDOW,
395             0, 0, 640, 480, 0, 0, 0, 0);
396     if (!(device = create_device(window, DDSCL_NORMAL)))
397     {
398         skip("Failed to create a 3D device, skipping test.\n");
399         DestroyWindow(window);
400         return;
401     }
402
403     hr = IDirect3DDevice3_GetDirect3D(device, &d3d3);
404     ok(SUCCEEDED(hr), "Failed to get Direct3D3 interface, hr %#x.\n", hr);
405
406     memset(&vb_desc, 0, sizeof(vb_desc));
407     vb_desc.dwSize = sizeof(vb_desc);
408     vb_desc.dwFVF = D3DFVF_XYZ;
409     vb_desc.dwNumVertices = 3;
410     hr = IDirect3D3_CreateVertexBuffer(d3d3, &vb_desc, &src_vb, 0, NULL);
411     ok(SUCCEEDED(hr), "Failed to create source vertex buffer, hr %#x.\n", hr);
412
413     hr = IDirect3DVertexBuffer_Lock(src_vb, DDLOCK_WRITEONLY, (void **)&src_data, NULL);
414     ok(SUCCEEDED(hr), "Failed to lock source vertex buffer, hr %#x.\n", hr);
415     src_data[0].x = -1.0f;
416     src_data[0].y = -1.0f;
417     src_data[0].z = -1.0f;
418     src_data[1].x = 0.0f;
419     src_data[1].y = 0.0f;
420     src_data[1].z = 0.0f;
421     src_data[2].x = 1.0f;
422     src_data[2].y = 1.0f;
423     src_data[2].z = 1.0f;
424     hr = IDirect3DVertexBuffer_Unlock(src_vb);
425     ok(SUCCEEDED(hr), "Failed to unlock source vertex buffer, hr %#x.\n", hr);
426
427     memset(&vb_desc, 0, sizeof(vb_desc));
428     vb_desc.dwSize = sizeof(vb_desc);
429     vb_desc.dwFVF = D3DFVF_XYZRHW;
430     vb_desc.dwNumVertices = 3;
431     hr = IDirect3D3_CreateVertexBuffer(d3d3, &vb_desc, &dst_vb, 0, NULL);
432     ok(SUCCEEDED(hr), "Failed to create destination vertex buffer, hr %#x.\n", hr);
433
434     hr = IDirect3D3_CreateViewport(d3d3, &viewport, NULL);
435     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
436     hr = IDirect3DDevice3_AddViewport(device, viewport);
437     ok(SUCCEEDED(hr), "Failed to add viewport, hr %#x.\n", hr);
438     vp2.dwSize = sizeof(vp2);
439     vp2.dwX = 10;
440     vp2.dwY = 20;
441     vp2.dwWidth = 100;
442     vp2.dwHeight = 200;
443     vp2.dvClipX = 2.0f;
444     vp2.dvClipY = 3.0f;
445     vp2.dvClipWidth = 4.0f;
446     vp2.dvClipHeight = 5.0f;
447     vp2.dvMinZ = -2.0f;
448     vp2.dvMaxZ = 3.0f;
449     hr = IDirect3DViewport3_SetViewport2(viewport, &vp2);
450     ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#x.\n", hr);
451     hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
452     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
453
454     hr = IDirect3DDevice3_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &identity);
455     ok(SUCCEEDED(hr), "Failed to set world transformation, hr %#x.\n", hr);
456     hr = IDirect3DDevice3_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &identity);
457     ok(SUCCEEDED(hr), "Failed to set view transformation, hr %#x.\n", hr);
458     hr = IDirect3DDevice3_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &identity);
459     ok(SUCCEEDED(hr), "Failed to set projection transformation, hr %#x.\n", hr);
460
461     hr = IDirect3DVertexBuffer_ProcessVertices(dst_vb, D3DVOP_TRANSFORM, 0, 3, src_vb, 0, device, 0);
462     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
463
464     hr = IDirect3DVertexBuffer_Lock(dst_vb, DDLOCK_READONLY, (void **)&dst_data, NULL);
465     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
466     ok(compare_vec4(&dst_data[0], -6.500e+1f, +1.800e+2f, +2.000e-1f, +1.000e+0f, 4096),
467             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
468             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
469     ok(compare_vec4(&dst_data[1], -4.000e+1f, +1.400e+2f, +4.000e-1f, +1.000e+0f, 4096),
470             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
471             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
472     ok(compare_vec4(&dst_data[2], -1.500e+1f, +1.000e+2f, +6.000e-1f, +1.000e+0f, 4096),
473             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
474             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
475     hr = IDirect3DVertexBuffer_Unlock(dst_vb);
476     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
477
478     hr = IDirect3DDevice3_MultiplyTransform(device, D3DTRANSFORMSTATE_PROJECTION, &projection);
479     ok(SUCCEEDED(hr), "Failed to set projection transformation, hr %#x.\n", hr);
480
481     hr = IDirect3DVertexBuffer_ProcessVertices(dst_vb, D3DVOP_TRANSFORM, 0, 3, src_vb, 0, device, 0);
482     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
483
484     hr = IDirect3DVertexBuffer_Lock(dst_vb, DDLOCK_READONLY, (void **)&dst_data, NULL);
485     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
486     ok(compare_vec4(&dst_data[0], +8.500e+1f, -1.000e+2f, +1.800e+0f, +1.000e+0f, 4096),
487             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
488             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
489     ok(compare_vec4(&dst_data[1], +1.100e+2f, -1.400e+2f, +2.000e+0f, +1.000e+0f, 4096),
490             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
491             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
492     ok(compare_vec4(&dst_data[2], +1.350e+2f, -1.800e+2f, +2.200e+0f, +1.000e+0f, 4096),
493             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
494             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
495     hr = IDirect3DVertexBuffer_Unlock(dst_vb);
496     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
497
498     vp2.dwSize = sizeof(vp2);
499     vp2.dwX = 30;
500     vp2.dwY = 40;
501     vp2.dwWidth = 90;
502     vp2.dwHeight = 80;
503     vp2.dvClipX = 4.0f;
504     vp2.dvClipY = 6.0f;
505     vp2.dvClipWidth = 2.0f;
506     vp2.dvClipHeight = 4.0f;
507     vp2.dvMinZ = 3.0f;
508     vp2.dvMaxZ = -2.0f;
509     hr = IDirect3DViewport3_SetViewport2(viewport, &vp2);
510     ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#x.\n", hr);
511
512     hr = IDirect3DVertexBuffer_ProcessVertices(dst_vb, D3DVOP_TRANSFORM, 0, 3, src_vb, 0, device, 0);
513     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
514
515     hr = IDirect3DVertexBuffer_Lock(dst_vb, DDLOCK_READONLY, (void **)&dst_data, NULL);
516     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
517     ok(compare_vec4(&dst_data[0], +7.500e+1f, +4.000e+1f, -8.000e-1f, +1.000e+0f, 4096),
518             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
519             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
520     ok(compare_vec4(&dst_data[1], +1.200e+2f, +2.000e+1f, -1.000e+0f, +1.000e+0f, 4096),
521             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
522             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
523     ok(compare_vec4(&dst_data[2], +1.650e+2f, +0.000e+0f, -1.200e+0f, +1.000e+0f, 4096),
524             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
525             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
526     hr = IDirect3DVertexBuffer_Unlock(dst_vb);
527     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
528
529     vp1.dwSize = sizeof(vp1);
530     vp1.dwX = 30;
531     vp1.dwY = 40;
532     vp1.dwWidth = 90;
533     vp1.dwHeight = 80;
534     vp1.dvScaleX = 7.0f;
535     vp1.dvScaleY = 2.0f;
536     vp1.dvMaxX = 6.0f;
537     vp1.dvMaxY = 10.0f;
538     vp1.dvMinZ = -2.0f;
539     vp1.dvMaxZ = 3.0f;
540     hr = IDirect3DViewport3_SetViewport(viewport, &vp1);
541     ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#x.\n", hr);
542
543     hr = IDirect3DVertexBuffer_ProcessVertices(dst_vb, D3DVOP_TRANSFORM, 0, 3, src_vb, 0, device, 0);
544     ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr);
545
546     hr = IDirect3DVertexBuffer_Lock(dst_vb, DDLOCK_READONLY, (void **)&dst_data, NULL);
547     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
548     ok(compare_vec4(&dst_data[0], +1.100e+2f, +6.800e+1f, +7.000e+0f, +1.000e+0f, 4096),
549             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
550             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
551     ok(compare_vec4(&dst_data[1], +1.170e+2f, +6.600e+1f, +8.000e+0f, +1.000e+0f, 4096),
552             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
553             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
554     ok(compare_vec4(&dst_data[2], +1.240e+2f, +6.400e+1f, +9.000e+0f, +1.000e+0f, 4096),
555             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
556             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
557     hr = IDirect3DVertexBuffer_Unlock(dst_vb);
558     ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr);
559
560     hr = IDirect3DDevice3_DeleteViewport(device, viewport);
561     ok(SUCCEEDED(hr), "Failed to delete viewport, hr %#x.\n", hr);
562
563     IDirect3DVertexBuffer_Release(dst_vb);
564     IDirect3DVertexBuffer_Release(src_vb);
565     IDirect3DViewport3_Release(viewport);
566     IDirect3D3_Release(d3d3);
567     IDirect3DDevice3_Release(device);
568     DestroyWindow(window);
569 }
570
571 static void test_coop_level_create_device_window(void)
572 {
573     HWND focus_window, device_window;
574     IDirectDraw4 *ddraw;
575     HRESULT hr;
576
577     focus_window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
578             0, 0, 640, 480, 0, 0, 0, 0);
579     if (!(ddraw = create_ddraw()))
580     {
581         skip("Failed to create a ddraw object, skipping test.\n");
582         DestroyWindow(focus_window);
583         return;
584     }
585
586     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
587     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
588     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
589     ok(!device_window, "Unexpected device window found.\n");
590     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW);
591     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
592     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
593     ok(!device_window, "Unexpected device window found.\n");
594     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL);
595     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
596     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
597     ok(!device_window, "Unexpected device window found.\n");
598     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL | DDSCL_FULLSCREEN);
599     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
600     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
601     ok(!device_window, "Unexpected device window found.\n");
602     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
603     ok(hr == DDERR_NOFOCUSWINDOW || broken(hr == DDERR_INVALIDPARAMS), "Got unexpected hr %#x.\n", hr);
604     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
605     ok(!device_window, "Unexpected device window found.\n");
606
607     /* Windows versions before 98 / NT5 don't support DDSCL_CREATEDEVICEWINDOW. */
608     if (broken(hr == DDERR_INVALIDPARAMS))
609     {
610         win_skip("DDSCL_CREATEDEVICEWINDOW not supported, skipping test.\n");
611         IDirectDraw4_Release(ddraw);
612         DestroyWindow(focus_window);
613         return;
614     }
615
616     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
617     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
618     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
619     ok(!device_window, "Unexpected device window found.\n");
620     hr = IDirectDraw4_SetCooperativeLevel(ddraw, focus_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
621     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
622     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
623     ok(!device_window, "Unexpected device window found.\n");
624
625     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
626     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
627     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
628     ok(!device_window, "Unexpected device window found.\n");
629     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_SETFOCUSWINDOW
630             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
631     ok(hr == DDERR_NOHWND, "Got unexpected hr %#x.\n", hr);
632     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
633     ok(!!device_window, "Device window not found.\n");
634
635     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
636     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
637     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
638     ok(!device_window, "Unexpected device window found.\n");
639     hr = IDirectDraw4_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW
640             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
641     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
642     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
643     ok(!!device_window, "Device window not found.\n");
644
645     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
646     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
647     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
648     ok(!device_window, "Unexpected device window found.\n");
649     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
650     ok(hr == DDERR_NOFOCUSWINDOW, "Got unexpected hr %#x.\n", hr);
651     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
652     ok(!device_window, "Unexpected device window found.\n");
653     hr = IDirectDraw4_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW);
654     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
655     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
656     ok(!device_window, "Unexpected device window found.\n");
657     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
658     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
659     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
660     ok(!!device_window, "Device window not found.\n");
661
662     IDirectDraw4_Release(ddraw);
663     DestroyWindow(focus_window);
664 }
665
666 static void test_clipper_blt(void)
667 {
668     IDirectDrawSurface4 *src_surface, *dst_surface;
669     RECT client_rect, src_rect;
670     IDirectDrawClipper *clipper;
671     DDSURFACEDESC2 surface_desc;
672     unsigned int i, j, x, y;
673     IDirectDraw4 *ddraw;
674     RGNDATA *rgn_data;
675     D3DCOLOR color;
676     HRGN r1, r2;
677     HWND window;
678     DDBLTFX fx;
679     HRESULT hr;
680     DWORD *ptr;
681     DWORD ret;
682
683     static const DWORD src_data[] =
684     {
685         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
686         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
687         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
688     };
689     static const D3DCOLOR expected1[] =
690     {
691         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
692         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
693         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
694         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
695     };
696     static const D3DCOLOR expected2[] =
697     {
698         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
699         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
700         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
701         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
702     };
703
704     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
705             10, 10, 640, 480, 0, 0, 0, 0);
706     ShowWindow(window, SW_SHOW);
707     if (!(ddraw = create_ddraw()))
708     {
709         skip("Failed to create a ddraw object, skipping test.\n");
710         DestroyWindow(window);
711         return;
712     }
713
714     ret = GetClientRect(window, &client_rect);
715     ok(ret, "Failed to get client rect.\n");
716     ret = MapWindowPoints(window, NULL, (POINT *)&client_rect, 2);
717     ok(ret, "Failed to map client rect.\n");
718
719     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
720     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
721
722     hr = IDirectDraw4_CreateClipper(ddraw, 0, &clipper, NULL);
723     ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
724     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
725     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
726     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
727     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
728     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
729     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
730     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
731     hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret);
732     ok(SUCCEEDED(hr), "Failed to get clip list, hr %#x.\n", hr);
733     ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#x.\n", rgn_data->rdh.dwSize);
734     ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#x.\n", rgn_data->rdh.iType);
735     ok(rgn_data->rdh.nCount >= 1, "Got unexpected count %u.\n", rgn_data->rdh.nCount);
736     ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
737             "Got unexpected bounding rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
738             rgn_data->rdh.rcBound.left, rgn_data->rdh.rcBound.top,
739             rgn_data->rdh.rcBound.right, rgn_data->rdh.rcBound.bottom,
740             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
741     HeapFree(GetProcessHeap(), 0, rgn_data);
742
743     r1 = CreateRectRgn(0, 0, 320, 240);
744     ok(!!r1, "Failed to create region.\n");
745     r2 = CreateRectRgn(320, 240, 640, 480);
746     ok(!!r2, "Failed to create region.\n");
747     CombineRgn(r1, r1, r2, RGN_OR);
748     ret = GetRegionData(r1, 0, NULL);
749     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
750     ret = GetRegionData(r1, ret, rgn_data);
751     ok(!!ret, "Failed to get region data.\n");
752
753     DeleteObject(r2);
754     DeleteObject(r1);
755
756     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
757     ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#x.\n", hr);
758     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
759     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
760     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
761     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
762
763     HeapFree(GetProcessHeap(), 0, rgn_data);
764
765     memset(&surface_desc, 0, sizeof(surface_desc));
766     surface_desc.dwSize = sizeof(surface_desc);
767     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
768     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
769     surface_desc.dwWidth = 640;
770     surface_desc.dwHeight = 480;
771     U4(surface_desc).ddpfPixelFormat.dwSize = sizeof(U4(surface_desc).ddpfPixelFormat);
772     U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB;
773     U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount = 32;
774     U2(U4(surface_desc).ddpfPixelFormat).dwRBitMask = 0x00ff0000;
775     U3(U4(surface_desc).ddpfPixelFormat).dwGBitMask = 0x0000ff00;
776     U4(U4(surface_desc).ddpfPixelFormat).dwBBitMask = 0x000000ff;
777
778     hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
779     ok(SUCCEEDED(hr), "Failed to create source surface, hr %#x.\n", hr);
780     hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
781     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
782
783     memset(&fx, 0, sizeof(fx));
784     fx.dwSize = sizeof(fx);
785     hr = IDirectDrawSurface4_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
786     ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#x.\n", hr);
787     hr = IDirectDrawSurface4_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
788     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
789
790     hr = IDirectDrawSurface4_Lock(src_surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
791     ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#x.\n", hr);
792     ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %u.\n", U1(surface_desc).lPitch);
793     ptr = surface_desc.lpSurface;
794     memcpy(&ptr[   0], &src_data[ 0], 6 * sizeof(DWORD));
795     memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
796     memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
797     hr = IDirectDrawSurface4_Unlock(src_surface, NULL);
798     ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#x.\n", hr);
799
800     hr = IDirectDrawSurface4_SetClipper(dst_surface, clipper);
801     ok(SUCCEEDED(hr), "Failed to set clipper, hr %#x.\n", hr);
802
803     SetRect(&src_rect, 1, 1, 5, 2);
804     hr = IDirectDrawSurface4_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
805     ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
806     for (i = 0; i < 4; ++i)
807     {
808         for (j = 0; j < 4; ++j)
809         {
810             x = 80 * ((2 * j) + 1);
811             y = 60 * ((2 * i) + 1);
812             color = get_surface_color(dst_surface, x, y);
813             ok(compare_color(color, expected1[i * 4 + j], 1),
814                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
815         }
816     }
817
818     U5(fx).dwFillColor = 0xff0000ff;
819     hr = IDirectDrawSurface4_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
820     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
821     for (i = 0; i < 4; ++i)
822     {
823         for (j = 0; j < 4; ++j)
824         {
825             x = 80 * ((2 * j) + 1);
826             y = 60 * ((2 * i) + 1);
827             color = get_surface_color(dst_surface, x, y);
828             ok(compare_color(color, expected2[i * 4 + j], 1),
829                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
830         }
831     }
832
833     hr = IDirectDrawSurface4_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
834     ok(hr == DDERR_BLTFASTCANTCLIP, "Got unexpected hr %#x.\n", hr);
835
836     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
837     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
838     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
839     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
840     DestroyWindow(window);
841     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
842     ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
843     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
844     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
845     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
846     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
847     hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
848     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
849     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
850     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
851     hr = IDirectDrawSurface4_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
852     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
853
854     IDirectDrawSurface4_Release(dst_surface);
855     IDirectDrawSurface4_Release(src_surface);
856     IDirectDrawClipper_Release(clipper);
857     IDirectDraw4_Release(ddraw);
858 }
859
860 static void test_coop_level_d3d_state(void)
861 {
862     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
863     IDirectDrawSurface4 *rt, *surface;
864     IDirect3DViewport3 *viewport;
865     IDirect3DDevice3 *device;
866     IDirectDraw4 *ddraw;
867     IDirect3D3 *d3d;
868     D3DCOLOR color;
869     DWORD value;
870     HWND window;
871     HRESULT hr;
872
873     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
874             0, 0, 640, 480, 0, 0, 0, 0);
875     if (!(device = create_device(window, DDSCL_NORMAL)))
876     {
877         skip("Failed to create D3D device, skipping test.\n");
878         DestroyWindow(window);
879         return;
880     }
881
882     viewport = create_viewport(device, 0, 0, 640, 480);
883
884     hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
885     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
886     hr = IDirect3DDevice3_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
887     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
888     ok(!!value, "Got unexpected z-enable state %#x.\n", value);
889     hr = IDirect3DDevice3_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
890     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
891     ok(!value, "Got unexpected alpha blend enable state %#x.\n", value);
892     hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
893     ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
894     hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0xffff0000, 0.0f, 0);
895     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
896     color = get_surface_color(rt, 320, 240);
897     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
898
899     hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
900     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
901     hr = IDirect3D3_QueryInterface(d3d, &IID_IDirectDraw4, (void **)&ddraw);
902     ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr);
903     IDirect3D3_Release(d3d);
904     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
905     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
906     hr = IDirectDrawSurface4_IsLost(rt);
907     ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
908     hr = IDirectDraw4_RestoreAllSurfaces(ddraw);
909     ok(SUCCEEDED(hr), "Failed to restore surfaces, hr %#x.\n", hr);
910     IDirectDraw4_Release(ddraw);
911
912     hr = IDirect3DDevice3_GetRenderTarget(device, &surface);
913     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
914     ok(surface == rt, "Got unexpected surface %p.\n", surface);
915     hr = IDirect3DDevice3_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
916     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
917     ok(!!value, "Got unexpected z-enable state %#x.\n", value);
918     hr = IDirect3DDevice3_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
919     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
920     ok(!!value, "Got unexpected alpha blend enable state %#x.\n", value);
921     hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0xff00ff00, 0.0f, 0);
922     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
923     color = get_surface_color(rt, 320, 240);
924     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
925
926     destroy_viewport(device, viewport);
927     IDirectDrawSurface4_Release(surface);
928     IDirectDrawSurface4_Release(rt);
929     IDirect3DDevice3_Release(device);
930     DestroyWindow(window);
931 }
932
933 static void test_surface_interface_mismatch(void)
934 {
935     IDirectDraw4 *ddraw = NULL;
936     IDirect3D3 *d3d = NULL;
937     IDirectDrawSurface4 *surface = NULL, *ds;
938     IDirectDrawSurface3 *surface3 = NULL;
939     IDirect3DDevice3 *device = NULL;
940     IDirect3DViewport3 *viewport = NULL;
941     DDSURFACEDESC2 surface_desc;
942     DDPIXELFORMAT z_fmt;
943     ULONG refcount;
944     HRESULT hr;
945     D3DCOLOR color;
946     HWND window;
947     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
948
949     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
950             0, 0, 640, 480, 0, 0, 0, 0);
951
952     if (!(ddraw = create_ddraw()))
953     {
954         skip("Failed to create a ddraw object, skipping test.\n");
955         goto cleanup;
956     }
957
958     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
959     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
960
961     memset(&surface_desc, 0, sizeof(surface_desc));
962     surface_desc.dwSize = sizeof(surface_desc);
963     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
964     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
965     surface_desc.dwWidth = 640;
966     surface_desc.dwHeight = 480;
967
968     hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface, NULL);
969     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
970
971     hr = IDirectDrawSurface4_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
972     ok(SUCCEEDED(hr), "Failed to QI IDirectDrawSurface3, hr %#x.\n", hr);
973
974     hr = IDirectDraw4_QueryInterface(ddraw, &IID_IDirect3D3, (void **)&d3d);
975     if (FAILED(hr))
976     {
977         skip("Failed to get the IDirect3D7 interface, skipping test.\n");
978         goto cleanup;
979     }
980
981     memset(&z_fmt, 0, sizeof(z_fmt));
982     hr = IDirect3D3_EnumZBufferFormats(d3d, &IID_IDirect3DHALDevice, enum_z_fmt, &z_fmt);
983     if (FAILED(hr) || !z_fmt.dwSize)
984     {
985         skip("No depth buffer formats available, skipping test.\n");
986         goto cleanup;
987     }
988
989     memset(&surface_desc, 0, sizeof(surface_desc));
990     surface_desc.dwSize = sizeof(surface_desc);
991     surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
992     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
993     U4(surface_desc).ddpfPixelFormat = z_fmt;
994     surface_desc.dwWidth = 640;
995     surface_desc.dwHeight = 480;
996     hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &ds, NULL);
997     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
998     if (FAILED(hr))
999         goto cleanup;
1000
1001     /* Using a different surface interface version still works */
1002     hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
1003     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
1004     refcount = IDirectDrawSurface4_Release(ds);
1005     ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
1006     if (FAILED(hr))
1007         goto cleanup;
1008
1009     /* Here too */
1010     hr = IDirect3D3_CreateDevice(d3d, &IID_IDirect3DHALDevice, (IDirectDrawSurface4 *)surface3, &device, NULL);
1011     ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
1012     if (FAILED(hr))
1013         goto cleanup;
1014
1015     viewport = create_viewport(device, 0, 0, 640, 480);
1016
1017     hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0xffff0000, 0.0f, 0);
1018     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1019     color = get_surface_color(surface, 320, 240);
1020     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
1021
1022 cleanup:
1023     if (viewport)
1024         destroy_viewport(device, viewport);
1025     if (surface3) IDirectDrawSurface3_Release(surface3);
1026     if (surface) IDirectDrawSurface4_Release(surface);
1027     if (device) IDirect3DDevice3_Release(device);
1028     if (d3d) IDirect3D3_Release(d3d);
1029     if (ddraw) IDirectDraw4_Release(ddraw);
1030     DestroyWindow(window);
1031 }
1032
1033 static void test_coop_level_threaded(void)
1034 {
1035     struct create_window_thread_param p;
1036     IDirectDraw4 *ddraw;
1037     HRESULT hr;
1038
1039     if (!(ddraw = create_ddraw()))
1040     {
1041         skip("Failed to create a ddraw object, skipping test.\n");
1042         return;
1043     }
1044     create_window_thread(&p);
1045
1046     hr = IDirectDraw4_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1047     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
1048
1049     IDirectDraw4_Release(ddraw);
1050     destroy_window_thread(&p);
1051 }
1052
1053 static void test_depth_blit(void)
1054 {
1055     static struct
1056     {
1057         float x, y, z;
1058         DWORD color;
1059     }
1060     quad1[] =
1061     {
1062         { -1.0,  1.0, 0.50f, 0xff00ff00},
1063         {  1.0,  1.0, 0.50f, 0xff00ff00},
1064         { -1.0, -1.0, 0.50f, 0xff00ff00},
1065         {  1.0, -1.0, 0.50f, 0xff00ff00},
1066     };
1067     static const D3DCOLOR expected_colors[4][4] =
1068     {
1069         {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
1070         {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
1071         {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1072         {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1073     };
1074     DDSURFACEDESC2 ddsd_new, ddsd_existing;
1075
1076     IDirect3DDevice3 *device;
1077     IDirectDrawSurface4 *ds1, *ds2, *ds3, *rt;
1078     IDirect3DViewport3 *viewport;
1079     RECT src_rect, dst_rect;
1080     unsigned int i, j;
1081     D3DCOLOR color;
1082     HRESULT hr;
1083     IDirect3D3 *d3d;
1084     IDirectDraw4 *ddraw;
1085     DDBLTFX fx;
1086     HWND window;
1087     D3DRECT d3drect;
1088
1089     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1090             0, 0, 640, 480, 0, 0, 0, 0);
1091     if (!(device = create_device(window, DDSCL_NORMAL)))
1092     {
1093         skip("Failed to create D3D device, skipping test.\n");
1094         DestroyWindow(window);
1095         return;
1096     }
1097
1098     hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
1099     ok(SUCCEEDED(hr), "Failed to get Direct3D3 interface, hr %#x.\n", hr);
1100     hr = IDirect3D3_QueryInterface(d3d, &IID_IDirectDraw4, (void **)&ddraw);
1101     ok(SUCCEEDED(hr), "Failed to get DirectDraw4 interface, hr %#x.\n", hr);
1102     IDirect3D3_Release(d3d);
1103
1104     ds1 = get_depth_stencil(device);
1105
1106     memset(&ddsd_new, 0, sizeof(ddsd_new));
1107     ddsd_new.dwSize = sizeof(ddsd_new);
1108     memset(&ddsd_existing, 0, sizeof(ddsd_existing));
1109     ddsd_existing.dwSize = sizeof(ddsd_existing);
1110     hr = IDirectDrawSurface4_GetSurfaceDesc(ds1, &ddsd_existing);
1111     ddsd_new.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
1112     ddsd_new.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
1113     ddsd_new.dwWidth = ddsd_existing.dwWidth;
1114     ddsd_new.dwHeight = ddsd_existing.dwHeight;
1115     U4(ddsd_new).ddpfPixelFormat = U4(ddsd_existing).ddpfPixelFormat;
1116     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd_new, &ds2, NULL);
1117     ok(SUCCEEDED(hr), "Failed to create a surface, hr %#x.\n", hr);
1118     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd_new, &ds3, NULL);
1119     ok(SUCCEEDED(hr), "Failed to create a surface, hr %#x.\n", hr);
1120     IDirectDraw4_Release(ddraw);
1121
1122     viewport = create_viewport(device, 0, 0, ddsd_existing.dwWidth, ddsd_existing.dwHeight);
1123     hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
1124     ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
1125
1126     hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_TRUE);
1127     ok(SUCCEEDED(hr), "Failed to enable z testing, hr %#x.\n", hr);
1128     hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
1129     ok(SUCCEEDED(hr), "Failed to set the z function, hr %#x.\n", hr);
1130     hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
1131     ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr);
1132
1133     U1(d3drect).x1 = U2(d3drect).y1 = 0;
1134     U3(d3drect).x2 = ddsd_existing.dwWidth; U4(d3drect).y2 = ddsd_existing.dwHeight;
1135     hr = IDirect3DViewport3_Clear2(viewport, 1, &d3drect, D3DCLEAR_ZBUFFER, 0, 0.0f, 0);
1136     ok(SUCCEEDED(hr), "Failed to clear the z buffer, hr %#x.\n", hr);
1137
1138     /* Partial blit. */
1139     SetRect(&src_rect, 0, 0, 320, 240);
1140     SetRect(&dst_rect, 0, 0, 320, 240);
1141     hr = IDirectDrawSurface4_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1142     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1143     /* Different locations. */
1144     SetRect(&src_rect, 0, 0, 320, 240);
1145     SetRect(&dst_rect, 320, 240, 640, 480);
1146     hr = IDirectDrawSurface4_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1147     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1148     /* Streched. */
1149     SetRect(&src_rect, 0, 0, 320, 240);
1150     SetRect(&dst_rect, 0, 0, 640, 480);
1151     hr = IDirectDrawSurface4_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1152     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1153     /* Flipped. */
1154     SetRect(&src_rect, 0, 480, 640, 0);
1155     SetRect(&dst_rect, 0, 0, 640, 480);
1156     hr = IDirectDrawSurface4_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1157     ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
1158     SetRect(&src_rect, 0, 0, 640, 480);
1159     SetRect(&dst_rect, 0, 480, 640, 0);
1160     hr = IDirectDrawSurface4_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1161     ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
1162     /* Full, explicit. */
1163     SetRect(&src_rect, 0, 0, 640, 480);
1164     SetRect(&dst_rect, 0, 0, 640, 480);
1165     hr = IDirectDrawSurface4_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1166     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1167     /* Depth -> color blit: Succeeds on Win7 + Radeon HD 5700, fails on WinXP + Radeon X1600 */
1168
1169     /* Depth blit inside a BeginScene / EndScene pair */
1170     hr = IDirect3DDevice3_BeginScene(device);
1171     ok(SUCCEEDED(hr), "Failed to start a scene, hr %#x.\n", hr);
1172     /* From the current depth stencil */
1173     hr = IDirectDrawSurface4_Blt(ds2, NULL, ds1, NULL, DDBLT_WAIT, NULL);
1174     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1175     /* To the current depth stencil */
1176     hr = IDirectDrawSurface4_Blt(ds1, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1177     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1178     /* Between unbound surfaces */
1179     hr = IDirectDrawSurface4_Blt(ds3, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1180     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1181     hr = IDirect3DDevice3_EndScene(device);
1182     ok(SUCCEEDED(hr), "Failed to end a scene, hr %#x.\n", hr);
1183
1184     /* Avoid changing the depth stencil, it doesn't work properly on Windows.
1185      * Instead use DDBLT_DEPTHFILL to clear the depth stencil. Unfortunately
1186      * drivers disagree on the meaning of dwFillDepth. Only 0 seems to produce
1187      * a reliable result(z = 0.0) */
1188     memset(&fx, 0, sizeof(fx));
1189     fx.dwSize = sizeof(fx);
1190     hr = IDirectDrawSurface4_Blt(ds2, NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
1191     ok(SUCCEEDED(hr), "Failed to clear the source z buffer, hr %#x.\n", hr);
1192
1193     hr = IDirect3DViewport3_Clear2(viewport, 1, &d3drect, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET, 0xffff0000, 1.0f, 0);
1194     ok(SUCCEEDED(hr), "Failed to clear the color and z buffers, hr %#x.\n", hr);
1195     SetRect(&dst_rect, 0, 0, 320, 240);
1196     hr = IDirectDrawSurface4_Blt(ds1, &dst_rect, ds2, NULL, DDBLT_WAIT, NULL);
1197     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1198     IDirectDrawSurface4_Release(ds3);
1199     IDirectDrawSurface4_Release(ds2);
1200     IDirectDrawSurface4_Release(ds1);
1201
1202     hr = IDirect3DDevice3_BeginScene(device);
1203     ok(SUCCEEDED(hr), "Failed to start a scene, hr %#x.\n", hr);
1204     hr = IDirect3DDevice3_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ | D3DFVF_DIFFUSE,
1205             quad1, 4, 0);
1206     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1207     hr = IDirect3DDevice3_EndScene(device);
1208     ok(SUCCEEDED(hr), "Failed to end a scene, hr %#x.\n", hr);
1209
1210     hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
1211     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1212     for (i = 0; i < 4; ++i)
1213     {
1214         for (j = 0; j < 4; ++j)
1215         {
1216             unsigned int x = 80 * ((2 * j) + 1);
1217             unsigned int y = 60 * ((2 * i) + 1);
1218             color = get_surface_color(rt, x, y);
1219             ok(compare_color(color, expected_colors[i][j], 1),
1220                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected_colors[i][j], x, y, color);
1221         }
1222     }
1223     IDirectDrawSurface4_Release(rt);
1224
1225     destroy_viewport(device, viewport);
1226     IDirect3DDevice3_Release(device);
1227     DestroyWindow(window);
1228 }
1229
1230 static void test_texture_load_ckey(void)
1231 {
1232     IDirectDraw4 *ddraw;
1233     IDirectDrawSurface4 *src;
1234     IDirectDrawSurface4 *dst;
1235     IDirect3DTexture2 *src_tex;
1236     IDirect3DTexture2 *dst_tex;
1237     DDSURFACEDESC2 ddsd;
1238     HRESULT hr;
1239     DDCOLORKEY ckey;
1240
1241     if (!(ddraw = create_ddraw()))
1242     {
1243         skip("Failed to create ddraw object, skipping test.\n");
1244         return;
1245     }
1246     hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
1247     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
1248
1249     memset(&ddsd, 0, sizeof(ddsd));
1250     ddsd.dwSize = sizeof(ddsd);
1251     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1252     ddsd.dwHeight = 128;
1253     ddsd.dwWidth = 128;
1254     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
1255     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &src, NULL);
1256     ok(SUCCEEDED(hr), "Failed to create source texture, hr %#x.\n", hr);
1257     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1258     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &dst, NULL);
1259     ok(SUCCEEDED(hr), "Failed to create destination texture, hr %#x.\n", hr);
1260
1261     hr = IDirectDrawSurface4_QueryInterface(src, &IID_IDirect3DTexture2, (void **)&src_tex);
1262     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to get Direct3DTexture2 interface, hr %#x.\n", hr);
1263     if (FAILED(hr))
1264     {
1265         /* 64 bit ddraw does not support d3d */
1266         skip("Could not get Direct3DTexture2 interface, skipping texture::Load color keying tests.\n");
1267         IDirectDrawSurface4_Release(dst);
1268         IDirectDrawSurface4_Release(src);
1269         IDirectDraw4_Release(ddraw);
1270         return;
1271     }
1272     hr = IDirectDrawSurface4_QueryInterface(dst, &IID_IDirect3DTexture2, (void **)&dst_tex);
1273     ok(SUCCEEDED(hr), "Failed to get Direct3DTexture2 interface, hr %#x.\n", hr);
1274
1275     /* No surface has a color key */
1276     hr = IDirect3DTexture2_Load(dst_tex, src_tex);
1277     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1278     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0xdeadbeef;
1279     hr = IDirectDrawSurface4_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1280     ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1281     ok(ckey.dwColorSpaceLowValue == 0xdeadbeef, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1282     ok(ckey.dwColorSpaceHighValue == 0xdeadbeef, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1283
1284     /* Source surface has a color key */
1285     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
1286     hr = IDirectDrawSurface4_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
1287     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1288     hr = IDirect3DTexture2_Load(dst_tex, src_tex);
1289     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1290     hr = IDirectDrawSurface4_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1291     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1292     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1293     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1294
1295     /* Both surfaces have a color key: Dest ckey is overwritten */
1296     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x000000ff;
1297     hr = IDirectDrawSurface4_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1298     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1299     hr = IDirect3DTexture2_Load(dst_tex, src_tex);
1300     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1301     hr = IDirectDrawSurface4_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1302     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1303     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1304     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1305
1306     /* Only the destination has a color key: It is not deleted */
1307     hr = IDirectDrawSurface4_SetColorKey(src, DDCKEY_SRCBLT, NULL);
1308     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1309     hr = IDirectDrawSurface4_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
1310     ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1311     hr = IDirect3DTexture2_Load(dst_tex, src_tex);
1312     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1313     hr = IDirectDrawSurface4_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1314     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1315     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1316     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1317
1318     IDirect3DTexture2_Release(dst_tex);
1319     IDirect3DTexture2_Release(src_tex);
1320     IDirectDrawSurface4_Release(dst);
1321     IDirectDrawSurface4_Release(src);
1322     IDirectDraw4_Release(ddraw);
1323 }
1324
1325 static ULONG get_refcount(IUnknown *test_iface)
1326 {
1327     IUnknown_AddRef(test_iface);
1328     return IUnknown_Release(test_iface);
1329 }
1330
1331 static void test_viewport(void)
1332 {
1333     IDirectDraw4 *ddraw;
1334     IDirect3D3 *d3d;
1335     HRESULT hr, old_d3d_ref;
1336     ULONG ref;
1337     IDirect3DViewport *viewport;
1338     IDirect3DViewport2 *viewport2;
1339     IDirect3DViewport3 *viewport3, *another_vp, *test_vp;
1340     IDirectDrawGammaControl *gamma;
1341     IUnknown *unknown;
1342     HWND window;
1343     IDirect3DDevice3 *device;
1344
1345     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1346             0, 0, 640, 480, 0, 0, 0, 0);
1347     if (!(device = create_device(window, DDSCL_NORMAL)))
1348     {
1349         skip("Failed to create D3D device, skipping test.\n");
1350         DestroyWindow(window);
1351         return;
1352     }
1353     hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
1354     ok(SUCCEEDED(hr), "Failed to get Direct3D3 interface, hr %#x.\n", hr);
1355     hr = IDirect3D3_QueryInterface(d3d, &IID_IDirectDraw4, (void **)&ddraw);
1356     ok(SUCCEEDED(hr), "Failed to get DirectDraw4 interface, hr %#x.\n", hr);
1357     old_d3d_ref = get_refcount((IUnknown *) d3d);
1358
1359     hr = IDirect3D3_CreateViewport(d3d, &viewport3, NULL);
1360     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
1361     ref = get_refcount((IUnknown *)viewport3);
1362     ok(ref == 1, "Initial IDirect3DViewport3 refcount is %u\n", ref);
1363     ref = get_refcount((IUnknown *)d3d);
1364     ok(ref == old_d3d_ref, "IDirect3D3 refcount is %u\n", ref);
1365
1366     gamma = (IDirectDrawGammaControl *)0xdeadbeef;
1367     hr = IDirect3DViewport2_QueryInterface(viewport3, &IID_IDirectDrawGammaControl, (void **)&gamma);
1368     ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
1369     ok(gamma == NULL, "Interface not set to NULL by failed QI call: %p\n", gamma);
1370     if (SUCCEEDED(hr)) IDirectDrawGammaControl_Release(gamma);
1371     /* NULL iid: Segfaults */
1372
1373     hr = IDirect3DViewport3_QueryInterface(viewport3, &IID_IDirect3DViewport, (void **)&viewport);
1374     ok(SUCCEEDED(hr), "Failed to QI IDirect3DViewport, hr %#x.\n", hr);
1375     if (viewport)
1376     {
1377         ref = get_refcount((IUnknown *)viewport);
1378         ok(ref == 2, "IDirect3DViewport refcount is %u\n", ref);
1379         ref = get_refcount((IUnknown *)viewport3);
1380         ok(ref == 2, "IDirect3DViewport3 refcount is %u\n", ref);
1381         IDirect3DViewport_Release(viewport);
1382         viewport = NULL;
1383     }
1384
1385     hr = IDirect3DViewport3_QueryInterface(viewport3, &IID_IDirect3DViewport3, (void **)&viewport2);
1386     ok(SUCCEEDED(hr), "Failed to QI IDirect3DViewport3, hr %#x.\n", hr);
1387     if (viewport2)
1388     {
1389         ref = get_refcount((IUnknown *)viewport2);
1390         ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
1391         ref = get_refcount((IUnknown *)viewport3);
1392         ok(ref == 2, "IDirect3DViewport3 refcount is %u\n", ref);
1393         IDirect3DViewport3_Release(viewport2);
1394     }
1395
1396     hr = IDirect3DViewport3_QueryInterface(viewport3, &IID_IUnknown, (void **)&unknown);
1397     ok(SUCCEEDED(hr), "Failed to QI IUnknown, hr %#x.\n", hr);
1398     if (unknown)
1399     {
1400         ref = get_refcount((IUnknown *)viewport3);
1401         ok(ref == 2, "IDirect3DViewport3 refcount is %u\n", ref);
1402         ref = get_refcount(unknown);
1403         ok(ref == 2, "IUnknown refcount is %u\n", ref);
1404         IUnknown_Release(unknown);
1405     }
1406
1407     /* AddViewport(NULL): Segfault */
1408     hr = IDirect3DDevice3_DeleteViewport(device, NULL);
1409     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
1410     hr = IDirect3DDevice3_GetCurrentViewport(device, NULL);
1411     ok(hr == D3DERR_NOCURRENTVIEWPORT, "Got unexpected hr %#x.\n", hr);
1412
1413     hr = IDirect3D3_CreateViewport(d3d, &another_vp, NULL);
1414     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
1415
1416     /* Setting a viewport not in the viewport list fails */
1417     hr = IDirect3DDevice3_SetCurrentViewport(device, another_vp);
1418     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
1419
1420     hr = IDirect3DDevice3_AddViewport(device, viewport3);
1421     ok(SUCCEEDED(hr), "Failed to add viewport to device, hr %#x.\n", hr);
1422     ref = get_refcount((IUnknown *) viewport3);
1423     ok(ref == 2, "viewport3 refcount is %d\n", ref);
1424     hr = IDirect3DDevice3_AddViewport(device, another_vp);
1425     ok(SUCCEEDED(hr), "Failed to add viewport to device, hr %#x.\n", hr);
1426     ref = get_refcount((IUnknown *) another_vp);
1427     ok(ref == 2, "another_vp refcount is %d\n", ref);
1428
1429     test_vp = (IDirect3DViewport3 *) 0xbaadc0de;
1430     hr = IDirect3DDevice3_GetCurrentViewport(device, &test_vp);
1431     ok(hr == D3DERR_NOCURRENTVIEWPORT, "Got unexpected hr %#x.\n", hr);
1432     ok(test_vp == (IDirect3DViewport3 *) 0xbaadc0de, "Got unexpected pointer %p\n", test_vp);
1433
1434     hr = IDirect3DDevice3_SetCurrentViewport(device, viewport3);
1435     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1436     ref = get_refcount((IUnknown *) viewport3);
1437     ok(ref == 3, "viewport3 refcount is %d\n", ref);
1438     ref = get_refcount((IUnknown *) device);
1439     ok(ref == 1, "device refcount is %d\n", ref);
1440
1441     test_vp = NULL;
1442     hr = IDirect3DDevice3_GetCurrentViewport(device, &test_vp);
1443     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
1444     ok(test_vp == viewport3, "Got unexpected viewport %p\n", test_vp);
1445     ref = get_refcount((IUnknown *) viewport3);
1446     ok(ref == 4, "viewport3 refcount is %d\n", ref);
1447     if(test_vp) IDirect3DViewport3_Release(test_vp);
1448
1449     /* GetCurrentViewport with a viewport set and NULL input param: Segfault */
1450
1451     /* Cannot set the viewport to NULL */
1452     hr = IDirect3DDevice3_SetCurrentViewport(device, NULL);
1453     ok(hr == DDERR_INVALIDPARAMS, "Failed to set viewport to NULL, hr %#x.\n", hr);
1454     test_vp = NULL;
1455     hr = IDirect3DDevice3_GetCurrentViewport(device, &test_vp);
1456     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
1457     ok(test_vp == viewport3, "Got unexpected viewport %p\n", test_vp);
1458     if(test_vp) IDirect3DViewport3_Release(test_vp);
1459
1460     /* SetCurrentViewport properly releases the old viewport's reference */
1461     hr = IDirect3DDevice3_SetCurrentViewport(device, another_vp);
1462     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1463     ref = get_refcount((IUnknown *) viewport3);
1464     ok(ref == 2, "viewport3 refcount is %d\n", ref);
1465     ref = get_refcount((IUnknown *) another_vp);
1466     ok(ref == 3, "another_vp refcount is %d\n", ref);
1467
1468     /* Unlike device2::DeleteViewport, device3::DeleteViewport releases the
1469      * reference held by SetCurrentViewport */
1470     hr = IDirect3DDevice3_DeleteViewport(device, another_vp);
1471     ok(SUCCEEDED(hr), "Failed to delete viewport from device, hr %#x.\n", hr);
1472     ref = get_refcount((IUnknown *) another_vp);
1473     ok(ref == 1, "another_vp refcount is %d\n", ref);
1474
1475     /* GetCurrentViewport still fails */
1476     test_vp = NULL;
1477     hr = IDirect3DDevice3_GetCurrentViewport(device, &test_vp);
1478     ok(hr == D3DERR_NOCURRENTVIEWPORT, "Got unexpected hr %#x.\n", hr);
1479     ok(test_vp == NULL, "Got unexpected viewport %p\n", test_vp);
1480     if(test_vp) IDirect3DViewport3_Release(test_vp);
1481
1482     /* Setting a different viewport doesn't have any surprises now */
1483     hr = IDirect3DDevice3_SetCurrentViewport(device, viewport3);
1484     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1485     ref = get_refcount((IUnknown *) viewport3);
1486     ok(ref == 3, "viewport3 refcount is %d\n", ref);
1487     ref = get_refcount((IUnknown *) another_vp);
1488     ok(ref == 1, "another_vp refcount is %d\n", ref);
1489
1490     /* Destroying the device removes the viewport and releases the reference */
1491     IDirect3DDevice3_Release(device);
1492     ref = get_refcount((IUnknown *) viewport3);
1493     ok(ref == 1, "viewport3 refcount is %d\n", ref);
1494
1495     ref = IDirect3DViewport3_Release(another_vp);
1496     ok(ref == 0, "Got unexpected ref %d\n", ref);
1497     ref = IDirect3DViewport3_Release(viewport3);
1498     ok(ref == 0, "Got unexpected ref %d\n", ref);
1499     IDirect3D3_Release(d3d);
1500     DestroyWindow(window);
1501     IDirectDraw4_Release(ddraw);
1502 }
1503
1504 static void test_zenable(void)
1505 {
1506     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1507     static struct
1508     {
1509         struct vec4 position;
1510         D3DCOLOR diffuse;
1511     }
1512     tquad[] =
1513     {
1514         {{  0.0f, 480.0f, -0.5f, 1.0f}, 0xff00ff00},
1515         {{  0.0f,   0.0f, -0.5f, 1.0f}, 0xff00ff00},
1516         {{640.0f, 480.0f,  1.5f, 1.0f}, 0xff00ff00},
1517         {{640.0f,   0.0f,  1.5f, 1.0f}, 0xff00ff00},
1518     };
1519     IDirect3DViewport3 *viewport;
1520     IDirect3DDevice3 *device;
1521     IDirectDrawSurface4 *rt;
1522     D3DCOLOR color;
1523     HWND window;
1524     HRESULT hr;
1525     UINT x, y;
1526     UINT i, j;
1527
1528     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1529             0, 0, 640, 480, 0, 0, 0, 0);
1530     if (!(device = create_device(window, DDSCL_NORMAL)))
1531     {
1532         skip("Failed to create D3D device, skipping test.\n");
1533         DestroyWindow(window);
1534         return;
1535     }
1536
1537     viewport = create_viewport(device, 0, 0, 640, 480);
1538     hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
1539     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1540
1541     hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1542     ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#x.\n", hr);
1543
1544     hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffff0000, 0.0f, 0);
1545     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1546     hr = IDirect3DDevice3_BeginScene(device);
1547     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1548     hr = IDirect3DDevice3_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_DIFFUSE, tquad, 4, 0);
1549     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1550     hr = IDirect3DDevice3_EndScene(device);
1551     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1552
1553     hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
1554     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1555     for (i = 0; i < 4; ++i)
1556     {
1557         for (j = 0; j < 4; ++j)
1558         {
1559             x = 80 * ((2 * j) + 1);
1560             y = 60 * ((2 * i) + 1);
1561             color = get_surface_color(rt, x, y);
1562             ok(compare_color(color, 0x0000ff00, 1),
1563                     "Expected color 0x0000ff00 at %u, %u, got 0x%08x.\n", x, y, color);
1564         }
1565     }
1566     IDirectDrawSurface4_Release(rt);
1567
1568     destroy_viewport(device, viewport);
1569     IDirect3DDevice3_Release(device);
1570     DestroyWindow(window);
1571 }
1572
1573 static void test_ck_rgba(void)
1574 {
1575     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1576     static struct
1577     {
1578         struct vec4 position;
1579         struct vec2 texcoord;
1580     }
1581     tquad[] =
1582     {
1583         {{  0.0f, 480.0f, 0.25f, 1.0f}, {0.0f, 0.0f}},
1584         {{  0.0f,   0.0f, 0.25f, 1.0f}, {0.0f, 1.0f}},
1585         {{640.0f, 480.0f, 0.25f, 1.0f}, {1.0f, 0.0f}},
1586         {{640.0f,   0.0f, 0.25f, 1.0f}, {1.0f, 1.0f}},
1587         {{  0.0f, 480.0f, 0.75f, 1.0f}, {0.0f, 0.0f}},
1588         {{  0.0f,   0.0f, 0.75f, 1.0f}, {0.0f, 1.0f}},
1589         {{640.0f, 480.0f, 0.75f, 1.0f}, {1.0f, 0.0f}},
1590         {{640.0f,   0.0f, 0.75f, 1.0f}, {1.0f, 1.0f}},
1591     };
1592     static const struct
1593     {
1594         D3DCOLOR fill_color;
1595         BOOL color_key;
1596         BOOL blend;
1597         D3DCOLOR result1;
1598         D3DCOLOR result2;
1599     }
1600     tests[] =
1601     {
1602         {0xff00ff00, TRUE,  TRUE,  0x00ff0000, 0x000000ff},
1603         {0xff00ff00, TRUE,  FALSE, 0x00ff0000, 0x000000ff},
1604         {0xff00ff00, FALSE, TRUE,  0x0000ff00, 0x0000ff00},
1605         {0xff00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1606         {0x7f00ff00, TRUE,  TRUE,  0x00807f00, 0x00807f00},
1607         {0x7f00ff00, TRUE,  FALSE, 0x0000ff00, 0x0000ff00},
1608         {0x7f00ff00, FALSE, TRUE,  0x00807f00, 0x00807f00},
1609         {0x7f00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1610     };
1611
1612     IDirectDrawSurface4 *surface;
1613     IDirect3DViewport3 *viewport;
1614     DDSURFACEDESC2 surface_desc;
1615     IDirect3DTexture2 *texture;
1616     IDirect3DDevice3 *device;
1617     IDirectDrawSurface4 *rt;
1618     IDirectDraw4 *ddraw;
1619     IDirect3D3 *d3d;
1620     D3DCOLOR color;
1621     HWND window;
1622     DDBLTFX fx;
1623     HRESULT hr;
1624     UINT i;
1625
1626     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1627             0, 0, 640, 480, 0, 0, 0, 0);
1628     if (!(device = create_device(window, DDSCL_NORMAL)))
1629     {
1630         skip("Failed to create D3D device, skipping test.\n");
1631         DestroyWindow(window);
1632         return;
1633     }
1634
1635     viewport = create_viewport(device, 0, 0, 640, 480);
1636     hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
1637     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1638
1639     hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
1640     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
1641     hr = IDirect3D3_QueryInterface(d3d, &IID_IDirectDraw4, (void **)&ddraw);
1642     ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr);
1643     IDirect3D3_Release(d3d);
1644
1645     memset(&surface_desc, 0, sizeof(surface_desc));
1646     surface_desc.dwSize = sizeof(surface_desc);
1647     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1648     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1649     surface_desc.dwWidth = 256;
1650     surface_desc.dwHeight = 256;
1651     U4(surface_desc).ddpfPixelFormat.dwSize = sizeof(U4(surface_desc).ddpfPixelFormat);
1652     U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
1653     U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount = 32;
1654     U2(U4(surface_desc).ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1655     U3(U4(surface_desc).ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1656     U4(U4(surface_desc).ddpfPixelFormat).dwBBitMask = 0x000000ff;
1657     U5(U4(surface_desc).ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
1658     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0xff00ff00;
1659     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0xff00ff00;
1660     hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1661     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
1662     hr = IDirectDrawSurface4_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
1663     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1664
1665     hr = IDirect3DDevice3_SetTexture(device, 0, texture);
1666     ok(SUCCEEDED(hr), "Failed to set texture, hr %#x.\n", hr);
1667     hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
1668     ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1669     hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
1670     ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1671
1672     hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
1673     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1674
1675     for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
1676     {
1677         hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, tests[i].color_key);
1678         ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1679         hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, tests[i].blend);
1680         ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1681
1682         memset(&fx, 0, sizeof(fx));
1683         fx.dwSize = sizeof(fx);
1684         U5(fx).dwFillColor = tests[i].fill_color;
1685         hr = IDirectDrawSurface4_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1686         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1687
1688         hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect,
1689                 D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffff0000, 1.0f, 0);
1690         ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1691         hr = IDirect3DDevice3_BeginScene(device);
1692         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1693         hr = IDirect3DDevice3_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_TEX1, &tquad[0], 4, 0);
1694         ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1695         hr = IDirect3DDevice3_EndScene(device);
1696         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1697
1698         color = get_surface_color(rt, 320, 240);
1699         if (i == 2)
1700             todo_wine ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1701                     tests[i].result1, i, color);
1702         else
1703             ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1704                     tests[i].result1, i, color);
1705
1706         U5(fx).dwFillColor = 0xff0000ff;
1707         hr = IDirectDrawSurface4_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1708         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1709
1710         hr = IDirect3DDevice3_BeginScene(device);
1711         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1712         hr = IDirect3DDevice3_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_TEX1, &tquad[4], 4, 0);
1713         ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1714         hr = IDirect3DDevice3_EndScene(device);
1715         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1716
1717         /* This tests that fragments that are masked out by the color key are
1718          * discarded, instead of just fully transparent. */
1719         color = get_surface_color(rt, 320, 240);
1720         if (i == 2)
1721             todo_wine ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1722                     tests[i].result2, i, color);
1723         else
1724             ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1725                     tests[i].result2, i, color);
1726     }
1727
1728     IDirectDrawSurface4_Release(rt);
1729     IDirect3DTexture2_Release(texture);
1730     IDirectDrawSurface4_Release(surface);
1731     destroy_viewport(device, viewport);
1732     IDirectDraw4_Release(ddraw);
1733     IDirect3DDevice3_Release(device);
1734     DestroyWindow(window);
1735 }
1736
1737 static void test_ck_default(void)
1738 {
1739     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1740     static struct
1741     {
1742         struct vec4 position;
1743         struct vec2 texcoord;
1744     }
1745     tquad[] =
1746     {
1747         {{  0.0f, 480.0f, 0.0f, 1.0f}, {0.0f, 0.0f}},
1748         {{  0.0f,   0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}},
1749         {{640.0f, 480.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
1750         {{640.0f,   0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
1751     };
1752     IDirectDrawSurface4 *surface, *rt;
1753     IDirect3DViewport3 *viewport;
1754     DDSURFACEDESC2 surface_desc;
1755     IDirect3DTexture2 *texture;
1756     IDirect3DDevice3 *device;
1757     IDirectDraw4 *ddraw;
1758     IDirect3D3 *d3d;
1759     D3DCOLOR color;
1760     DWORD value;
1761     HWND window;
1762     DDBLTFX fx;
1763     HRESULT hr;
1764
1765     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1766             0, 0, 640, 480, 0, 0, 0, 0);
1767
1768     if (!(device = create_device(window, DDSCL_NORMAL)))
1769     {
1770         skip("Failed to create D3D device, skipping test.\n");
1771         DestroyWindow(window);
1772         return;
1773     }
1774
1775     hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
1776     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
1777     hr = IDirect3D3_QueryInterface(d3d, &IID_IDirectDraw4, (void **)&ddraw);
1778     ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr);
1779     IDirect3D3_Release(d3d);
1780
1781     hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
1782     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1783
1784     viewport = create_viewport(device, 0, 0, 640, 480);
1785     hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
1786     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1787
1788     memset(&surface_desc, 0, sizeof(surface_desc));
1789     surface_desc.dwSize = sizeof(surface_desc);
1790     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1791     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1792     surface_desc.dwWidth = 256;
1793     surface_desc.dwHeight = 256;
1794     U4(surface_desc).ddpfPixelFormat.dwSize = sizeof(U4(surface_desc).ddpfPixelFormat);
1795     U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB;
1796     U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount = 32;
1797     U2(U4(surface_desc).ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1798     U3(U4(surface_desc).ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1799     U4(U4(surface_desc).ddpfPixelFormat).dwBBitMask = 0x000000ff;
1800     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x000000ff;
1801     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x000000ff;
1802     hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1803     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1804     hr = IDirectDrawSurface4_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
1805     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1806     hr = IDirect3DDevice3_SetTexture(device, 0, texture);
1807     ok(SUCCEEDED(hr), "Failed to set texture, hr %#x.\n", hr);
1808
1809     memset(&fx, 0, sizeof(fx));
1810     fx.dwSize = sizeof(fx);
1811     U5(fx).dwFillColor = 0x000000ff;
1812     hr = IDirectDrawSurface4_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1813     ok(SUCCEEDED(hr), "Failed to fill surface, hr %#x.\n", hr);
1814
1815     hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0xff00ff00, 1.0f, 0);
1816     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1817     hr = IDirect3DDevice3_BeginScene(device);
1818     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1819     hr = IDirect3DDevice3_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
1820     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
1821     ok(!value, "Got unexpected color keying state %#x.\n", value);
1822     hr = IDirect3DDevice3_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_TEX1, &tquad[0], 4, 0);
1823     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1824     hr = IDirect3DDevice3_EndScene(device);
1825     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1826     color = get_surface_color(rt, 320, 240);
1827     ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
1828
1829     hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0xff00ff00, 1.0f, 0);
1830     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1831     hr = IDirect3DDevice3_BeginScene(device);
1832     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1833     hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
1834     ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1835     hr = IDirect3DDevice3_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_TEX1, &tquad[0], 4, 0);
1836     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1837     hr = IDirect3DDevice3_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
1838     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
1839     ok(!!value, "Got unexpected color keying state %#x.\n", value);
1840     hr = IDirect3DDevice3_EndScene(device);
1841     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1842     color = get_surface_color(rt, 320, 240);
1843     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
1844
1845     IDirect3DTexture_Release(texture);
1846     IDirectDrawSurface4_Release(surface);
1847     destroy_viewport(device, viewport);
1848     IDirectDrawSurface4_Release(rt);
1849     IDirect3DDevice3_Release(device);
1850     IDirectDraw4_Release(ddraw);
1851     DestroyWindow(window);
1852 }
1853
1854 struct qi_test
1855 {
1856     REFIID iid;
1857     REFIID refcount_iid;
1858     HRESULT hr;
1859 };
1860
1861 static void test_qi(const char *test_name, IUnknown *base_iface,
1862         REFIID refcount_iid, const struct qi_test *tests, UINT entry_count)
1863 {
1864     ULONG refcount, expected_refcount;
1865     IUnknown *iface1, *iface2;
1866     HRESULT hr;
1867     UINT i, j;
1868
1869     for (i = 0; i < entry_count; ++i)
1870     {
1871         hr = IUnknown_QueryInterface(base_iface, tests[i].iid, (void **)&iface1);
1872         ok(hr == tests[i].hr, "Got hr %#x for test \"%s\" %u.\n", hr, test_name, i);
1873         if (SUCCEEDED(hr))
1874         {
1875             for (j = 0; j < entry_count; ++j)
1876             {
1877                 hr = IUnknown_QueryInterface(iface1, tests[j].iid, (void **)&iface2);
1878                 ok(hr == tests[j].hr, "Got hr %#x for test \"%s\" %u, %u.\n", hr, test_name, i, j);
1879                 if (SUCCEEDED(hr))
1880                 {
1881                     expected_refcount = 0;
1882                     if (IsEqualGUID(refcount_iid, tests[j].refcount_iid))
1883                         ++expected_refcount;
1884                     if (IsEqualGUID(tests[i].refcount_iid, tests[j].refcount_iid))
1885                         ++expected_refcount;
1886                     refcount = IUnknown_Release(iface2);
1887                     ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, %u, expected %u.\n",
1888                             refcount, test_name, i, j, expected_refcount);
1889                 }
1890             }
1891
1892             expected_refcount = 0;
1893             if (IsEqualGUID(refcount_iid, tests[i].refcount_iid))
1894                 ++expected_refcount;
1895             refcount = IUnknown_Release(iface1);
1896             ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, expected %u.\n",
1897                     refcount, test_name, i, expected_refcount);
1898         }
1899     }
1900 }
1901
1902 static void test_surface_qi(void)
1903 {
1904     static const struct qi_test tests[] =
1905     {
1906         {&IID_IDirect3DTexture2,        &IID_IDirectDrawSurface4,       S_OK         },
1907         {&IID_IDirect3DTexture,         &IID_IDirectDrawSurface4,       S_OK         },
1908         {&IID_IDirectDrawGammaControl,  &IID_IDirectDrawGammaControl,   S_OK         },
1909         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1910         {&IID_IDirectDrawSurface7,      &IID_IDirectDrawSurface7,       S_OK         },
1911         {&IID_IDirectDrawSurface4,      &IID_IDirectDrawSurface4,       S_OK         },
1912         {&IID_IDirectDrawSurface3,      &IID_IDirectDrawSurface3,       S_OK         },
1913         {&IID_IDirectDrawSurface2,      &IID_IDirectDrawSurface2,       S_OK         },
1914         {&IID_IDirectDrawSurface,       &IID_IDirectDrawSurface,        S_OK         },
1915         {&IID_IDirect3DDevice7,         NULL,                           E_INVALIDARG },
1916         {&IID_IDirect3DDevice3,         NULL,                           E_INVALIDARG },
1917         {&IID_IDirect3DDevice2,         NULL,                           E_INVALIDARG },
1918         {&IID_IDirect3DDevice,          NULL,                           E_INVALIDARG },
1919         {&IID_IDirect3D7,               NULL,                           E_INVALIDARG },
1920         {&IID_IDirect3D3,               NULL,                           E_INVALIDARG },
1921         {&IID_IDirect3D2,               NULL,                           E_INVALIDARG },
1922         {&IID_IDirect3D,                NULL,                           E_INVALIDARG },
1923         {&IID_IDirectDraw7,             NULL,                           E_INVALIDARG },
1924         {&IID_IDirectDraw4,             NULL,                           E_INVALIDARG },
1925         {&IID_IDirectDraw3,             NULL,                           E_INVALIDARG },
1926         {&IID_IDirectDraw2,             NULL,                           E_INVALIDARG },
1927         {&IID_IDirectDraw,              NULL,                           E_INVALIDARG },
1928         {&IID_IDirect3DLight,           NULL,                           E_INVALIDARG },
1929         {&IID_IDirect3DMaterial,        NULL,                           E_INVALIDARG },
1930         {&IID_IDirect3DMaterial2,       NULL,                           E_INVALIDARG },
1931         {&IID_IDirect3DMaterial3,       NULL,                           E_INVALIDARG },
1932         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_INVALIDARG },
1933         {&IID_IDirect3DViewport,        NULL,                           E_INVALIDARG },
1934         {&IID_IDirect3DViewport2,       NULL,                           E_INVALIDARG },
1935         {&IID_IDirect3DViewport3,       NULL,                           E_INVALIDARG },
1936         {&IID_IDirect3DVertexBuffer,    NULL,                           E_INVALIDARG },
1937         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_INVALIDARG },
1938         {&IID_IDirectDrawPalette,       NULL,                           E_INVALIDARG },
1939         {&IID_IDirectDrawClipper,       NULL,                           E_INVALIDARG },
1940         {&IID_IUnknown,                 &IID_IDirectDrawSurface,        S_OK         },
1941     };
1942
1943     IDirectDrawSurface4 *surface;
1944     DDSURFACEDESC2 surface_desc;
1945     IDirect3DDevice3 *device;
1946     IDirectDraw4 *ddraw;
1947     HWND window;
1948     HRESULT hr;
1949
1950     if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
1951     {
1952         win_skip("DirectDrawCreateEx not available, skipping test.\n");
1953         return;
1954     }
1955
1956     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1957             0, 0, 640, 480, 0, 0, 0, 0);
1958     /* Try to create a D3D device to see if the ddraw implementation supports
1959      * D3D. 64-bit ddraw in particular doesn't seem to support D3D, and
1960      * doesn't support e.g. the IDirect3DTexture interfaces. */
1961     if (!(device = create_device(window, DDSCL_NORMAL)))
1962     {
1963         skip("Failed to create D3D device, skipping test.\n");
1964         DestroyWindow(window);
1965         return;
1966     }
1967     IDirect3DDevice_Release(device);
1968     if (!(ddraw = create_ddraw()))
1969     {
1970         skip("Failed to create a ddraw object, skipping test.\n");
1971         DestroyWindow(window);
1972         return;
1973     }
1974     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
1975     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
1976
1977     memset(&surface_desc, 0, sizeof(surface_desc));
1978     surface_desc.dwSize = sizeof(surface_desc);
1979     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1980     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1981     surface_desc.dwWidth = 512;
1982     surface_desc.dwHeight = 512;
1983     hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1984     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1985
1986     test_qi("surface_qi", (IUnknown *)surface, &IID_IDirectDrawSurface4, tests, sizeof(tests) / sizeof(*tests));
1987
1988     IDirectDrawSurface4_Release(surface);
1989     IDirectDraw4_Release(ddraw);
1990     DestroyWindow(window);
1991 }
1992
1993 static void test_device_qi(void)
1994 {
1995     static const struct qi_test tests[] =
1996     {
1997         {&IID_IDirect3DTexture2,        NULL,                           E_NOINTERFACE},
1998         {&IID_IDirect3DTexture,         NULL,                           E_NOINTERFACE},
1999         {&IID_IDirectDrawGammaControl,  NULL,                           E_NOINTERFACE},
2000         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
2001         {&IID_IDirectDrawSurface7,      NULL,                           E_NOINTERFACE},
2002         {&IID_IDirectDrawSurface4,      NULL,                           E_NOINTERFACE},
2003         {&IID_IDirectDrawSurface3,      NULL,                           E_NOINTERFACE},
2004         {&IID_IDirectDrawSurface2,      NULL,                           E_NOINTERFACE},
2005         {&IID_IDirectDrawSurface,       NULL,                           E_NOINTERFACE},
2006         {&IID_IDirect3DDevice7,         NULL,                           E_NOINTERFACE},
2007         {&IID_IDirect3DDevice3,         &IID_IDirect3DDevice3,          S_OK         },
2008         {&IID_IDirect3DDevice2,         &IID_IDirect3DDevice3,          S_OK         },
2009         {&IID_IDirect3DDevice,          &IID_IDirect3DDevice3,          S_OK         },
2010         {&IID_IDirect3DRampDevice,      NULL,                           E_NOINTERFACE},
2011         {&IID_IDirect3DRGBDevice,       NULL,                           E_NOINTERFACE},
2012         {&IID_IDirect3DHALDevice,       NULL,                           E_NOINTERFACE},
2013         {&IID_IDirect3DMMXDevice,       NULL,                           E_NOINTERFACE},
2014         {&IID_IDirect3DRefDevice,       NULL,                           E_NOINTERFACE},
2015         {&IID_IDirect3DTnLHalDevice,    NULL,                           E_NOINTERFACE},
2016         {&IID_IDirect3DNullDevice,      NULL,                           E_NOINTERFACE},
2017         {&IID_IDirect3D7,               NULL,                           E_NOINTERFACE},
2018         {&IID_IDirect3D3,               NULL,                           E_NOINTERFACE},
2019         {&IID_IDirect3D2,               NULL,                           E_NOINTERFACE},
2020         {&IID_IDirect3D,                NULL,                           E_NOINTERFACE},
2021         {&IID_IDirectDraw7,             NULL,                           E_NOINTERFACE},
2022         {&IID_IDirectDraw4,             NULL,                           E_NOINTERFACE},
2023         {&IID_IDirectDraw3,             NULL,                           E_NOINTERFACE},
2024         {&IID_IDirectDraw2,             NULL,                           E_NOINTERFACE},
2025         {&IID_IDirectDraw,              NULL,                           E_NOINTERFACE},
2026         {&IID_IDirect3DLight,           NULL,                           E_NOINTERFACE},
2027         {&IID_IDirect3DMaterial,        NULL,                           E_NOINTERFACE},
2028         {&IID_IDirect3DMaterial2,       NULL,                           E_NOINTERFACE},
2029         {&IID_IDirect3DMaterial3,       NULL,                           E_NOINTERFACE},
2030         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_NOINTERFACE},
2031         {&IID_IDirect3DViewport,        NULL,                           E_NOINTERFACE},
2032         {&IID_IDirect3DViewport2,       NULL,                           E_NOINTERFACE},
2033         {&IID_IDirect3DViewport3,       NULL,                           E_NOINTERFACE},
2034         {&IID_IDirect3DVertexBuffer,    NULL,                           E_NOINTERFACE},
2035         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_NOINTERFACE},
2036         {&IID_IDirectDrawPalette,       NULL,                           E_NOINTERFACE},
2037         {&IID_IDirectDrawClipper,       NULL,                           E_NOINTERFACE},
2038         {&IID_IUnknown,                 &IID_IDirect3DDevice3,          S_OK         },
2039     };
2040
2041     IDirect3DDevice3 *device;
2042     HWND window;
2043
2044     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2045             0, 0, 640, 480, 0, 0, 0, 0);
2046     if (!(device = create_device(window, DDSCL_NORMAL)))
2047     {
2048         skip("Failed to create D3D device, skipping test.\n");
2049         DestroyWindow(window);
2050         return;
2051     }
2052
2053     test_qi("device_qi", (IUnknown *)device, &IID_IDirect3DDevice3, tests, sizeof(tests) / sizeof(*tests));
2054
2055     IDirect3DDevice3_Release(device);
2056     DestroyWindow(window);
2057 }
2058
2059 static void test_wndproc(void)
2060 {
2061     LONG_PTR proc, ddraw_proc;
2062     IDirectDraw4 *ddraw;
2063     WNDCLASSA wc = {0};
2064     HWND window;
2065     HRESULT hr;
2066     ULONG ref;
2067
2068     static const UINT messages[] =
2069     {
2070         WM_WINDOWPOSCHANGING,
2071         WM_MOVE,
2072         WM_SIZE,
2073         WM_WINDOWPOSCHANGING,
2074         WM_ACTIVATE,
2075         WM_SETFOCUS,
2076         0,
2077     };
2078
2079     /* DDSCL_EXCLUSIVE replaces the window's window proc. */
2080     if (!(ddraw = create_ddraw()))
2081     {
2082         skip("Failed to create IDirectDraw4 object, skipping tests.\n");
2083         return;
2084     }
2085
2086     wc.lpfnWndProc = test_proc;
2087     wc.lpszClassName = "ddraw_test_wndproc_wc";
2088     ok(RegisterClassA(&wc), "Failed to register window class.\n");
2089
2090     window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test",
2091             WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
2092
2093     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2094     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2095             (LONG_PTR)test_proc, proc);
2096     expect_messages = messages;
2097     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2098     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2099     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2100     expect_messages = NULL;
2101     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2102     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
2103             (LONG_PTR)test_proc, proc);
2104     ref = IDirectDraw4_Release(ddraw);
2105     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2106     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2107     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2108             (LONG_PTR)test_proc, proc);
2109
2110     /* DDSCL_NORMAL doesn't. */
2111     ddraw = create_ddraw();
2112     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2113     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2114             (LONG_PTR)test_proc, proc);
2115     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
2116     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2117     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2118     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2119             (LONG_PTR)test_proc, proc);
2120     ref = IDirectDraw4_Release(ddraw);
2121     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2122     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2123     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2124             (LONG_PTR)test_proc, proc);
2125
2126     /* The original window proc is only restored by ddraw if the current
2127      * window proc matches the one ddraw set. This also affects switching
2128      * from DDSCL_NORMAL to DDSCL_EXCLUSIVE. */
2129     ddraw = create_ddraw();
2130     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2131     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2132             (LONG_PTR)test_proc, proc);
2133     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2134     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2135     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2136     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
2137             (LONG_PTR)test_proc, proc);
2138     ddraw_proc = proc;
2139     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2140     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2141     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2142     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2143             (LONG_PTR)test_proc, proc);
2144     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2145     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2146     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
2147     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
2148             (LONG_PTR)test_proc, proc);
2149     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2150     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2151     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2152     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
2153             (LONG_PTR)DefWindowProcA, proc);
2154     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2155     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2156     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)ddraw_proc);
2157     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
2158             (LONG_PTR)DefWindowProcA, proc);
2159     ref = IDirectDraw4_Release(ddraw);
2160     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2161     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2162     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2163             (LONG_PTR)test_proc, proc);
2164
2165     ddraw = create_ddraw();
2166     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2167     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2168             (LONG_PTR)test_proc, proc);
2169     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2170     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2171     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
2172     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
2173             (LONG_PTR)test_proc, proc);
2174     ref = IDirectDraw4_Release(ddraw);
2175     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2176     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2177     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
2178             (LONG_PTR)DefWindowProcA, proc);
2179
2180     fix_wndproc(window, (LONG_PTR)test_proc);
2181     expect_messages = NULL;
2182     DestroyWindow(window);
2183     UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
2184 }
2185
2186 static void test_window_style(void)
2187 {
2188     LONG style, exstyle, tmp;
2189     RECT fullscreen_rect, r;
2190     IDirectDraw4 *ddraw;
2191     HWND window;
2192     HRESULT hr;
2193     ULONG ref;
2194
2195     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2196             0, 0, 100, 100, 0, 0, 0, 0);
2197     if (!(ddraw = create_ddraw()))
2198     {
2199         skip("Failed to create a ddraw object, skipping test.\n");
2200         DestroyWindow(window);
2201         return;
2202     }
2203
2204     style = GetWindowLongA(window, GWL_STYLE);
2205     exstyle = GetWindowLongA(window, GWL_EXSTYLE);
2206     SetRect(&fullscreen_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2207
2208     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2209     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2210
2211     tmp = GetWindowLongA(window, GWL_STYLE);
2212     todo_wine ok(tmp == style, "Expected window style %#x, got %#x.\n", style, tmp);
2213     tmp = GetWindowLongA(window, GWL_EXSTYLE);
2214     todo_wine ok(tmp == exstyle, "Expected window extended style %#x, got %#x.\n", exstyle, tmp);
2215
2216     GetWindowRect(window, &r);
2217     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2218             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2219             r.left, r.top, r.right, r.bottom);
2220     GetClientRect(window, &r);
2221     todo_wine ok(!EqualRect(&r, &fullscreen_rect), "Client rect and window rect are equal.\n");
2222
2223     ref = IDirectDraw4_Release(ddraw);
2224     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2225
2226     DestroyWindow(window);
2227 }
2228
2229 static void test_redundant_mode_set(void)
2230 {
2231     DDSURFACEDESC2 surface_desc = {0};
2232     IDirectDraw4 *ddraw;
2233     HWND window;
2234     HRESULT hr;
2235     RECT r, s;
2236     ULONG ref;
2237
2238     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2239             0, 0, 100, 100, 0, 0, 0, 0);
2240     if (!(ddraw = create_ddraw()))
2241     {
2242         skip("Failed to create a ddraw object, skipping test.\n");
2243         DestroyWindow(window);
2244         return;
2245     }
2246
2247     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2248     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2249
2250     surface_desc.dwSize = sizeof(surface_desc);
2251     hr = IDirectDraw4_GetDisplayMode(ddraw, &surface_desc);
2252     ok(SUCCEEDED(hr), "GetDipslayMode failed, hr %#x.\n", hr);
2253
2254     hr = IDirectDraw4_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2255             U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount, 0, 0);
2256     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2257
2258     GetWindowRect(window, &r);
2259     r.right /= 2;
2260     r.bottom /= 2;
2261     SetWindowPos(window, HWND_TOP, r.left, r.top, r.right, r.bottom, 0);
2262     GetWindowRect(window, &s);
2263     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2264             r.left, r.top, r.right, r.bottom,
2265             s.left, s.top, s.right, s.bottom);
2266
2267     hr = IDirectDraw4_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2268             U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount, 0, 0);
2269     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2270
2271     GetWindowRect(window, &s);
2272     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2273             r.left, r.top, r.right, r.bottom,
2274             s.left, s.top, s.right, s.bottom);
2275
2276     ref = IDirectDraw4_Release(ddraw);
2277     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2278
2279     DestroyWindow(window);
2280 }
2281
2282 static SIZE screen_size;
2283
2284 static LRESULT CALLBACK mode_set_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2285 {
2286     if (message == WM_SIZE)
2287     {
2288         screen_size.cx = GetSystemMetrics(SM_CXSCREEN);
2289         screen_size.cy = GetSystemMetrics(SM_CYSCREEN);
2290     }
2291
2292     return test_proc(hwnd, message, wparam, lparam);
2293 }
2294
2295 static void test_coop_level_mode_set(void)
2296 {
2297     IDirectDrawSurface4 *primary;
2298     RECT fullscreen_rect, r, s;
2299     IDirectDraw4 *ddraw;
2300     DDSURFACEDESC2 ddsd;
2301     WNDCLASSA wc = {0};
2302     HWND window;
2303     HRESULT hr;
2304     ULONG ref;
2305
2306     static const UINT exclusive_messages[] =
2307     {
2308         WM_WINDOWPOSCHANGING,
2309         WM_WINDOWPOSCHANGED,
2310         WM_SIZE,
2311         WM_DISPLAYCHANGE,
2312         0,
2313     };
2314
2315     static const UINT normal_messages[] =
2316     {
2317         WM_DISPLAYCHANGE,
2318         0,
2319     };
2320
2321     if (!(ddraw = create_ddraw()))
2322     {
2323         skip("Failed to create a ddraw object, skipping test.\n");
2324         return;
2325     }
2326
2327     wc.lpfnWndProc = mode_set_proc;
2328     wc.lpszClassName = "ddraw_test_wndproc_wc";
2329     ok(RegisterClassA(&wc), "Failed to register window class.\n");
2330
2331     window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test", WS_OVERLAPPEDWINDOW,
2332             0, 0, 100, 100, 0, 0, 0, 0);
2333
2334     SetRect(&fullscreen_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2335     SetRect(&s, 0, 0, 640, 480);
2336
2337     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2338     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2339
2340     GetWindowRect(window, &r);
2341     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2342             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2343             r.left, r.top, r.right, r.bottom);
2344
2345     memset(&ddsd, 0, sizeof(ddsd));
2346     ddsd.dwSize = sizeof(ddsd);
2347     ddsd.dwFlags = DDSD_CAPS;
2348     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2349
2350     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &primary, NULL);
2351     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2352     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2353     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2354     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2355             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2356     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2357             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2358
2359     GetWindowRect(window, &r);
2360     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2361             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2362             r.left, r.top, r.right, r.bottom);
2363
2364     expect_messages = exclusive_messages;
2365     screen_size.cx = 0;
2366     screen_size.cy = 0;
2367
2368     hr = IDirectDraw4_SetDisplayMode(ddraw, 640, 480, 32, 0, 0);
2369     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2370
2371     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2372     expect_messages = NULL;
2373     ok(screen_size.cx == s.right && screen_size.cy == s.bottom,
2374             "Expected screen size %ux%u, got %ux%u.\n",
2375             s.right, s.bottom, screen_size.cx, screen_size.cy);
2376
2377     GetWindowRect(window, &r);
2378     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2379             s.left, s.top, s.right, s.bottom,
2380             r.left, r.top, r.right, r.bottom);
2381
2382     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2383     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2384     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2385             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2386     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2387             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2388     IDirectDrawSurface4_Release(primary);
2389
2390     memset(&ddsd, 0, sizeof(ddsd));
2391     ddsd.dwSize = sizeof(ddsd);
2392     ddsd.dwFlags = DDSD_CAPS;
2393     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2394
2395     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &primary, NULL);
2396     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2397     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2398     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2399     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2400             s.right - s.left, ddsd.dwWidth);
2401     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2402             s.bottom - s.top, ddsd.dwHeight);
2403
2404     GetWindowRect(window, &r);
2405     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2406             s.left, s.top, s.right, s.bottom,
2407             r.left, r.top, r.right, r.bottom);
2408
2409     expect_messages = exclusive_messages;
2410     screen_size.cx = 0;
2411     screen_size.cy = 0;
2412
2413     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2414     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2415
2416     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2417     expect_messages = NULL;
2418     ok(screen_size.cx == fullscreen_rect.right && screen_size.cy == fullscreen_rect.bottom,
2419             "Expected screen size %ux%u, got %ux%u.\n",
2420             fullscreen_rect.right, fullscreen_rect.bottom, screen_size.cx, screen_size.cy);
2421
2422     GetWindowRect(window, &r);
2423     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2424             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2425             r.left, r.top, r.right, r.bottom);
2426
2427     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2428     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2429     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2430             s.right - s.left, ddsd.dwWidth);
2431     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2432             s.bottom - s.top, ddsd.dwHeight);
2433     IDirectDrawSurface4_Release(primary);
2434
2435     memset(&ddsd, 0, sizeof(ddsd));
2436     ddsd.dwSize = sizeof(ddsd);
2437     ddsd.dwFlags = DDSD_CAPS;
2438     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2439
2440     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &primary, NULL);
2441     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2442     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2443     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2444     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2445             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2446     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2447             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2448
2449     GetWindowRect(window, &r);
2450     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2451             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2452             r.left, r.top, r.right, r.bottom);
2453
2454     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2455     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2456
2457     GetWindowRect(window, &r);
2458     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2459             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2460             r.left, r.top, r.right, r.bottom);
2461
2462     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2463     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2464     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2465             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2466     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2467             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2468     IDirectDrawSurface4_Release(primary);
2469
2470     memset(&ddsd, 0, sizeof(ddsd));
2471     ddsd.dwSize = sizeof(ddsd);
2472     ddsd.dwFlags = DDSD_CAPS;
2473     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2474
2475     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &primary, NULL);
2476     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2477     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2478     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2479     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2480             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2481     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2482             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2483
2484     GetWindowRect(window, &r);
2485     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2486             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2487             r.left, r.top, r.right, r.bottom);
2488
2489     expect_messages = normal_messages;
2490     screen_size.cx = 0;
2491     screen_size.cy = 0;
2492
2493     hr = IDirectDraw4_SetDisplayMode(ddraw, 640, 480, 32, 0, 0);
2494     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2495
2496     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2497     expect_messages = NULL;
2498     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2499
2500     GetWindowRect(window, &r);
2501     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2502             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2503             r.left, r.top, r.right, r.bottom);
2504
2505     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2506     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2507     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2508             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2509     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2510             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2511     IDirectDrawSurface4_Release(primary);
2512
2513     memset(&ddsd, 0, sizeof(ddsd));
2514     ddsd.dwSize = sizeof(ddsd);
2515     ddsd.dwFlags = DDSD_CAPS;
2516     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2517
2518     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &primary, NULL);
2519     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2520     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2521     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2522     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2523             s.right - s.left, ddsd.dwWidth);
2524     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2525             s.bottom - s.top, ddsd.dwHeight);
2526
2527     GetWindowRect(window, &r);
2528     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2529             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2530             r.left, r.top, r.right, r.bottom);
2531
2532     expect_messages = normal_messages;
2533     screen_size.cx = 0;
2534     screen_size.cy = 0;
2535
2536     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2537     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2538
2539     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2540     expect_messages = NULL;
2541     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2542
2543     GetWindowRect(window, &r);
2544     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2545             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2546             r.left, r.top, r.right, r.bottom);
2547
2548     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2549     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2550     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2551             s.right - s.left, ddsd.dwWidth);
2552     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2553             s.bottom - s.top, ddsd.dwHeight);
2554     IDirectDrawSurface4_Release(primary);
2555
2556     memset(&ddsd, 0, sizeof(ddsd));
2557     ddsd.dwSize = sizeof(ddsd);
2558     ddsd.dwFlags = DDSD_CAPS;
2559     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2560
2561     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &primary, NULL);
2562     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2563     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2564     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2565     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2566             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2567     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2568             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2569
2570     GetWindowRect(window, &r);
2571     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2572             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2573             r.left, r.top, r.right, r.bottom);
2574
2575     /* DDSCL_NORMAL | DDSCL_FULLSCREEN behaves the same as just DDSCL_NORMAL.
2576      * Resizing the window on mode changes is a property of DDSCL_EXCLUSIVE,
2577      * not DDSCL_FULLSCREEN. */
2578     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
2579     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2580
2581     GetWindowRect(window, &r);
2582     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2583             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2584             r.left, r.top, r.right, r.bottom);
2585
2586     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2587     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2588     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2589             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2590     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2591             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2592     IDirectDrawSurface4_Release(primary);
2593
2594     memset(&ddsd, 0, sizeof(ddsd));
2595     ddsd.dwSize = sizeof(ddsd);
2596     ddsd.dwFlags = DDSD_CAPS;
2597     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2598
2599     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &primary, NULL);
2600     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2601     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2602     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2603     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2604             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2605     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2606             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2607
2608     GetWindowRect(window, &r);
2609     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2610             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2611             r.left, r.top, r.right, r.bottom);
2612
2613     expect_messages = normal_messages;
2614     screen_size.cx = 0;
2615     screen_size.cy = 0;
2616
2617     hr = IDirectDraw4_SetDisplayMode(ddraw, 640, 480, 32, 0, 0);
2618     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2619
2620     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2621     expect_messages = NULL;
2622     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2623
2624     GetWindowRect(window, &r);
2625     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2626             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2627             r.left, r.top, r.right, r.bottom);
2628
2629     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2630     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2631     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2632             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2633     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2634             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2635     IDirectDrawSurface4_Release(primary);
2636
2637     memset(&ddsd, 0, sizeof(ddsd));
2638     ddsd.dwSize = sizeof(ddsd);
2639     ddsd.dwFlags = DDSD_CAPS;
2640     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2641
2642     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &primary, NULL);
2643     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2644     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2645     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2646     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2647             s.right - s.left, ddsd.dwWidth);
2648     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2649             s.bottom - s.top, ddsd.dwHeight);
2650
2651     GetWindowRect(window, &r);
2652     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2653             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2654             r.left, r.top, r.right, r.bottom);
2655
2656     expect_messages = normal_messages;
2657     screen_size.cx = 0;
2658     screen_size.cy = 0;
2659
2660     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2661     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2662
2663     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2664     expect_messages = NULL;
2665     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2666
2667     GetWindowRect(window, &r);
2668     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2669             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2670             r.left, r.top, r.right, r.bottom);
2671
2672     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2673     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2674     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2675             s.right - s.left, ddsd.dwWidth);
2676     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2677             s.bottom - s.top, ddsd.dwHeight);
2678     IDirectDrawSurface4_Release(primary);
2679
2680     memset(&ddsd, 0, sizeof(ddsd));
2681     ddsd.dwSize = sizeof(ddsd);
2682     ddsd.dwFlags = DDSD_CAPS;
2683     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2684
2685     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &primary, NULL);
2686     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2687     hr = IDirectDrawSurface4_GetSurfaceDesc(primary, &ddsd);
2688     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2689     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2690             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2691     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2692             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2693     IDirectDrawSurface4_Release(primary);
2694
2695     GetWindowRect(window, &r);
2696     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2697             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2698             r.left, r.top, r.right, r.bottom);
2699
2700     ref = IDirectDraw4_Release(ddraw);
2701     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2702
2703     GetWindowRect(window, &r);
2704     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2705             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2706             r.left, r.top, r.right, r.bottom);
2707
2708     expect_messages = NULL;
2709     DestroyWindow(window);
2710     UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
2711 }
2712
2713 static void test_coop_level_mode_set_multi(void)
2714 {
2715     IDirectDraw4 *ddraw1, *ddraw2;
2716     UINT orig_w, orig_h, w, h;
2717     HWND window;
2718     HRESULT hr;
2719     ULONG ref;
2720
2721     if (!(ddraw1 = create_ddraw()))
2722     {
2723         skip("Failed to create a ddraw object, skipping test.\n");
2724         return;
2725     }
2726
2727     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2728             0, 0, 100, 100, 0, 0, 0, 0);
2729
2730     orig_w = GetSystemMetrics(SM_CXSCREEN);
2731     orig_h = GetSystemMetrics(SM_CYSCREEN);
2732
2733     /* With just a single ddraw object, the display mode is restored on
2734      * release. */
2735     hr = IDirectDraw4_SetDisplayMode(ddraw1, 800, 600, 32, 0, 0);
2736     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2737     w = GetSystemMetrics(SM_CXSCREEN);
2738     ok(w == 800, "Got unexpected screen width %u.\n", w);
2739     h = GetSystemMetrics(SM_CYSCREEN);
2740     ok(h == 600, "Got unexpected screen height %u.\n", h);
2741
2742     ref = IDirectDraw4_Release(ddraw1);
2743     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2744     w = GetSystemMetrics(SM_CXSCREEN);
2745     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2746     h = GetSystemMetrics(SM_CYSCREEN);
2747     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2748
2749     /* When there are multiple ddraw objects, the display mode is restored to
2750      * the initial mode, before the first SetDisplayMode() call. */
2751     ddraw1 = create_ddraw();
2752     hr = IDirectDraw4_SetDisplayMode(ddraw1, 800, 600, 32, 0, 0);
2753     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2754     w = GetSystemMetrics(SM_CXSCREEN);
2755     ok(w == 800, "Got unexpected screen width %u.\n", w);
2756     h = GetSystemMetrics(SM_CYSCREEN);
2757     ok(h == 600, "Got unexpected screen height %u.\n", h);
2758
2759     ddraw2 = create_ddraw();
2760     hr = IDirectDraw4_SetDisplayMode(ddraw2, 640, 480, 32, 0, 0);
2761     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2762     w = GetSystemMetrics(SM_CXSCREEN);
2763     ok(w == 640, "Got unexpected screen width %u.\n", w);
2764     h = GetSystemMetrics(SM_CYSCREEN);
2765     ok(h == 480, "Got unexpected screen height %u.\n", h);
2766
2767     ref = IDirectDraw4_Release(ddraw2);
2768     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2769     w = GetSystemMetrics(SM_CXSCREEN);
2770     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2771     h = GetSystemMetrics(SM_CYSCREEN);
2772     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2773
2774     ref = IDirectDraw4_Release(ddraw1);
2775     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2776     w = GetSystemMetrics(SM_CXSCREEN);
2777     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2778     h = GetSystemMetrics(SM_CYSCREEN);
2779     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2780
2781     /* Regardless of release ordering. */
2782     ddraw1 = create_ddraw();
2783     hr = IDirectDraw4_SetDisplayMode(ddraw1, 800, 600, 32, 0, 0);
2784     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2785     w = GetSystemMetrics(SM_CXSCREEN);
2786     ok(w == 800, "Got unexpected screen width %u.\n", w);
2787     h = GetSystemMetrics(SM_CYSCREEN);
2788     ok(h == 600, "Got unexpected screen height %u.\n", h);
2789
2790     ddraw2 = create_ddraw();
2791     hr = IDirectDraw4_SetDisplayMode(ddraw2, 640, 480, 32, 0, 0);
2792     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2793     w = GetSystemMetrics(SM_CXSCREEN);
2794     ok(w == 640, "Got unexpected screen width %u.\n", w);
2795     h = GetSystemMetrics(SM_CYSCREEN);
2796     ok(h == 480, "Got unexpected screen height %u.\n", h);
2797
2798     ref = IDirectDraw4_Release(ddraw1);
2799     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2800     w = GetSystemMetrics(SM_CXSCREEN);
2801     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2802     h = GetSystemMetrics(SM_CYSCREEN);
2803     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2804
2805     ref = IDirectDraw4_Release(ddraw2);
2806     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2807     w = GetSystemMetrics(SM_CXSCREEN);
2808     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2809     h = GetSystemMetrics(SM_CYSCREEN);
2810     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2811
2812     /* But only for ddraw objects that called SetDisplayMode(). */
2813     ddraw1 = create_ddraw();
2814     ddraw2 = create_ddraw();
2815     hr = IDirectDraw4_SetDisplayMode(ddraw2, 640, 480, 32, 0, 0);
2816     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2817     w = GetSystemMetrics(SM_CXSCREEN);
2818     ok(w == 640, "Got unexpected screen width %u.\n", w);
2819     h = GetSystemMetrics(SM_CYSCREEN);
2820     ok(h == 480, "Got unexpected screen height %u.\n", h);
2821
2822     ref = IDirectDraw4_Release(ddraw1);
2823     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2824     w = GetSystemMetrics(SM_CXSCREEN);
2825     ok(w == 640, "Got unexpected screen width %u.\n", w);
2826     h = GetSystemMetrics(SM_CYSCREEN);
2827     ok(h == 480, "Got unexpected screen height %u.\n", h);
2828
2829     ref = IDirectDraw4_Release(ddraw2);
2830     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2831     w = GetSystemMetrics(SM_CXSCREEN);
2832     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2833     h = GetSystemMetrics(SM_CYSCREEN);
2834     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2835
2836     /* If there's a ddraw object that's currently in exclusive mode, it blocks
2837      * restoring the display mode. */
2838     ddraw1 = create_ddraw();
2839     hr = IDirectDraw4_SetDisplayMode(ddraw1, 800, 600, 32, 0, 0);
2840     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2841     w = GetSystemMetrics(SM_CXSCREEN);
2842     ok(w == 800, "Got unexpected screen width %u.\n", w);
2843     h = GetSystemMetrics(SM_CYSCREEN);
2844     ok(h == 600, "Got unexpected screen height %u.\n", h);
2845
2846     ddraw2 = create_ddraw();
2847     hr = IDirectDraw4_SetDisplayMode(ddraw2, 640, 480, 32, 0, 0);
2848     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2849     w = GetSystemMetrics(SM_CXSCREEN);
2850     ok(w == 640, "Got unexpected screen width %u.\n", w);
2851     h = GetSystemMetrics(SM_CYSCREEN);
2852     ok(h == 480, "Got unexpected screen height %u.\n", h);
2853
2854     hr = IDirectDraw4_SetCooperativeLevel(ddraw2, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2855     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2856
2857     ref = IDirectDraw4_Release(ddraw1);
2858     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2859     w = GetSystemMetrics(SM_CXSCREEN);
2860     ok(w == 640, "Got unexpected screen width %u.\n", w);
2861     h = GetSystemMetrics(SM_CYSCREEN);
2862     ok(h == 480, "Got unexpected screen height %u.\n", h);
2863
2864     ref = IDirectDraw4_Release(ddraw2);
2865     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2866     w = GetSystemMetrics(SM_CXSCREEN);
2867     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2868     h = GetSystemMetrics(SM_CYSCREEN);
2869     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2870
2871     /* Exclusive mode blocks mode setting on other ddraw objects in general. */
2872     ddraw1 = create_ddraw();
2873     hr = IDirectDraw4_SetDisplayMode(ddraw1, 800, 600, 32, 0, 0);
2874     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2875     w = GetSystemMetrics(SM_CXSCREEN);
2876     ok(w == 800, "Got unexpected screen width %u.\n", w);
2877     h = GetSystemMetrics(SM_CYSCREEN);
2878     ok(h == 600, "Got unexpected screen height %u.\n", h);
2879
2880     hr = IDirectDraw4_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2881     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2882
2883     ddraw2 = create_ddraw();
2884     hr = IDirectDraw4_SetDisplayMode(ddraw2, 640, 480, 32, 0, 0);
2885     ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#x.\n", hr);
2886
2887     ref = IDirectDraw4_Release(ddraw1);
2888     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2889     w = GetSystemMetrics(SM_CXSCREEN);
2890     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2891     h = GetSystemMetrics(SM_CYSCREEN);
2892     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2893
2894     ref = IDirectDraw4_Release(ddraw2);
2895     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2896     w = GetSystemMetrics(SM_CXSCREEN);
2897     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2898     h = GetSystemMetrics(SM_CYSCREEN);
2899     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2900
2901     DestroyWindow(window);
2902 }
2903
2904 static void test_initialize(void)
2905 {
2906     IDirectDraw4 *ddraw;
2907     HRESULT hr;
2908
2909     if (!(ddraw = create_ddraw()))
2910     {
2911         skip("Failed to create a ddraw object, skipping test.\n");
2912         return;
2913     }
2914
2915     hr = IDirectDraw4_Initialize(ddraw, NULL);
2916     ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x.\n", hr);
2917     IDirectDraw4_Release(ddraw);
2918
2919     CoInitialize(NULL);
2920     hr = CoCreateInstance(&CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectDraw4, (void **)&ddraw);
2921     ok(SUCCEEDED(hr), "Failed to create IDirectDraw4 instance, hr %#x.\n", hr);
2922     hr = IDirectDraw4_Initialize(ddraw, NULL);
2923     ok(hr == DD_OK, "Initialize returned hr %#x, expected DD_OK.\n", hr);
2924     hr = IDirectDraw4_Initialize(ddraw, NULL);
2925     ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x, expected DDERR_ALREADYINITIALIZED.\n", hr);
2926     IDirectDraw4_Release(ddraw);
2927     CoUninitialize();
2928 }
2929
2930 static void test_coop_level_surf_create(void)
2931 {
2932     IDirectDrawSurface4 *surface;
2933     IDirectDraw4 *ddraw;
2934     DDSURFACEDESC2 ddsd;
2935     HRESULT hr;
2936
2937     if (!(ddraw = create_ddraw()))
2938     {
2939         skip("Failed to create a ddraw object, skipping test.\n");
2940         return;
2941     }
2942
2943     memset(&ddsd, 0, sizeof(ddsd));
2944     ddsd.dwSize = sizeof(ddsd);
2945     ddsd.dwFlags = DDSD_CAPS;
2946     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2947     hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &surface, NULL);
2948     ok(hr == DDERR_NOCOOPERATIVELEVELSET, "Surface creation returned hr %#x.\n", hr);
2949
2950     IDirectDraw4_Release(ddraw);
2951 }
2952
2953 static void test_vb_discard(void)
2954 {
2955     static const struct vec4 quad[] =
2956     {
2957         {  0.0f, 480.0f, 0.0f, 1.0f},
2958         {  0.0f,   0.0f, 0.0f, 1.0f},
2959         {640.0f, 480.0f, 0.0f, 1.0f},
2960         {640.0f,   0.0f, 0.0f, 1.0f},
2961     };
2962
2963     IDirect3DDevice3 *device;
2964     IDirect3D3 *d3d;
2965     IDirect3DVertexBuffer *buffer;
2966     HWND window;
2967     HRESULT hr;
2968     D3DVERTEXBUFFERDESC desc;
2969     BYTE *data;
2970     static const unsigned int vbsize = 16;
2971     unsigned int i;
2972
2973     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2974             0, 0, 640, 480, 0, 0, 0, 0);
2975
2976     if (!(device = create_device(window, DDSCL_NORMAL)))
2977     {
2978         skip("Failed to create D3D device, skipping test.\n");
2979         DestroyWindow(window);
2980         return;
2981     }
2982
2983     hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
2984     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
2985
2986     memset(&desc, 0, sizeof(desc));
2987     desc.dwSize = sizeof(desc);
2988     desc.dwCaps = D3DVBCAPS_WRITEONLY;
2989     desc.dwFVF = D3DFVF_XYZRHW;
2990     desc.dwNumVertices = vbsize;
2991     hr = IDirect3D3_CreateVertexBuffer(d3d, &desc, &buffer, 0, NULL);
2992     ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
2993
2994     hr = IDirect3DVertexBuffer_Lock(buffer, DDLOCK_DISCARDCONTENTS, (void **)&data, NULL);
2995     ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr);
2996     memcpy(data, quad, sizeof(quad));
2997     hr = IDirect3DVertexBuffer_Unlock(buffer);
2998     ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr);
2999
3000     hr = IDirect3DDevice3_BeginScene(device);
3001     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
3002     hr = IDirect3DDevice3_DrawPrimitiveVB(device, D3DPT_TRIANGLESTRIP, buffer, 0, 4, 0);
3003     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
3004     hr = IDirect3DDevice3_EndScene(device);
3005     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
3006
3007     hr = IDirect3DVertexBuffer_Lock(buffer, DDLOCK_DISCARDCONTENTS, (void **)&data, NULL);
3008     ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr);
3009     memset(data, 0xaa, sizeof(struct vec4) * vbsize);
3010     hr = IDirect3DVertexBuffer_Unlock(buffer);
3011     ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr);
3012
3013     hr = IDirect3DVertexBuffer_Lock(buffer, DDLOCK_DISCARDCONTENTS, (void **)&data, NULL);
3014     ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr);
3015     for (i = 0; i < sizeof(struct vec4) * vbsize; i++)
3016     {
3017         if (data[i] != 0xaa)
3018         {
3019             ok(FALSE, "Vertex buffer data byte %u is 0x%02x, expected 0xaa\n", i, data[i]);
3020             break;
3021         }
3022     }
3023     hr = IDirect3DVertexBuffer_Unlock(buffer);
3024     ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr);
3025
3026     IDirect3DVertexBuffer_Release(buffer);
3027     IDirect3D3_Release(d3d);
3028     IDirect3DDevice3_Release(device);
3029     DestroyWindow(window);
3030 }
3031
3032 static void test_coop_level_multi_window(void)
3033 {
3034     HWND window1, window2;
3035     IDirectDraw4 *ddraw;
3036     HRESULT hr;
3037
3038     window1 = CreateWindowA("static", "ddraw_test1", WS_OVERLAPPEDWINDOW,
3039             0, 0, 640, 480, 0, 0, 0, 0);
3040     window2 = CreateWindowA("static", "ddraw_test2", WS_OVERLAPPEDWINDOW,
3041             0, 0, 640, 480, 0, 0, 0, 0);
3042     if (!(ddraw = create_ddraw()))
3043     {
3044         skip("Failed to create a ddraw object, skipping test.\n");
3045         DestroyWindow(window2);
3046         DestroyWindow(window1);
3047         return;
3048     }
3049
3050     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
3051     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3052     hr = IDirectDraw4_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL);
3053     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3054     ok(IsWindow(window1), "Window 1 was destroyed.\n");
3055     ok(IsWindow(window2), "Window 2 was destroyed.\n");
3056
3057     IDirectDraw4_Release(ddraw);
3058     DestroyWindow(window2);
3059     DestroyWindow(window1);
3060 }
3061
3062 static void test_draw_strided(void)
3063 {
3064     static struct vec3 position[] =
3065     {
3066         {-1.0,   -1.0,   0.0},
3067         {-1.0,    1.0,   0.0},
3068         { 1.0,    1.0,   0.0},
3069         { 1.0,   -1.0,   0.0},
3070     };
3071     static DWORD diffuse[] =
3072     {
3073         0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00,
3074     };
3075     static WORD indices[] =
3076     {
3077         0, 1, 2, 2, 3, 0
3078     };
3079
3080     IDirectDrawSurface4 *rt;
3081     IDirect3DDevice3 *device;
3082     D3DCOLOR color;
3083     HWND window;
3084     HRESULT hr;
3085     D3DDRAWPRIMITIVESTRIDEDDATA strided;
3086     IDirect3DViewport3 *viewport;
3087     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
3088
3089     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
3090             0, 0, 640, 480, 0, 0, 0, 0);
3091
3092     if (!(device = create_device(window, DDSCL_NORMAL)))
3093     {
3094         skip("Failed to create D3D device, skipping test.\n");
3095         DestroyWindow(window);
3096         return;
3097     }
3098
3099     hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
3100     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
3101     viewport = create_viewport(device, 0, 0, 640, 480);
3102     hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
3103     ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
3104     hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0x00000000, 0.0f, 0);
3105     ok(SUCCEEDED(hr), "Failed to clear the viewport, hr %#x.\n", hr);
3106
3107     hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
3108     ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr);
3109     hr = IDirect3DDevice3_BeginScene(device);
3110     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
3111
3112     memset(&strided, 0x55, sizeof(strided));
3113     strided.position.lpvData = position;
3114     strided.position.dwStride = sizeof(*position);
3115     strided.diffuse.lpvData = diffuse;
3116     strided.diffuse.dwStride = sizeof(*diffuse);
3117     hr = IDirect3DDevice3_DrawIndexedPrimitiveStrided(device, D3DPT_TRIANGLELIST, D3DFVF_XYZ | D3DFVF_DIFFUSE,
3118             &strided, 4, indices, 6, 0);
3119     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
3120
3121     hr = IDirect3DDevice3_EndScene(device);
3122     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
3123
3124     color = get_surface_color(rt, 320, 240);
3125     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
3126
3127     IDirect3DViewport3_Release(viewport);
3128     IDirectDrawSurface4_Release(rt);
3129     IDirect3DDevice3_Release(device);
3130     DestroyWindow(window);
3131 }
3132
3133 static void test_clear_rect_count(void)
3134 {
3135     IDirectDrawSurface4 *rt;
3136     IDirect3DDevice3 *device;
3137     D3DCOLOR color;
3138     HWND window;
3139     HRESULT hr;
3140     IDirect3DViewport3 *viewport;
3141     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
3142
3143     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
3144             0, 0, 640, 480, 0, 0, 0, 0);
3145     if (!(device = create_device(window, DDSCL_NORMAL)))
3146     {
3147         skip("Failed to create D3D device, skipping test.\n");
3148         DestroyWindow(window);
3149         return;
3150     }
3151
3152     hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
3153     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
3154
3155     viewport = create_viewport(device, 0, 0, 640, 480);
3156     hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
3157     ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
3158     hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0x00ffffff, 0.0f, 0);
3159     ok(SUCCEEDED(hr), "Failed to clear the viewport, hr %#x.\n", hr);
3160     hr = IDirect3DViewport3_Clear2(viewport, 0, &clear_rect, D3DCLEAR_TARGET, 0x00ff0000, 0.0f, 0);
3161     ok(SUCCEEDED(hr), "Failed to clear the viewport, hr %#x.\n", hr);
3162     hr = IDirect3DViewport3_Clear2(viewport, 0, NULL, D3DCLEAR_TARGET, 0x0000ff00, 0.0f, 0);
3163     ok(SUCCEEDED(hr), "Failed to clear the viewport, hr %#x.\n", hr);
3164     hr = IDirect3DViewport3_Clear2(viewport, 1, NULL, D3DCLEAR_TARGET, 0x000000ff, 0.0f, 0);
3165     ok(SUCCEEDED(hr), "Failed to clear the viewport, hr %#x.\n", hr);
3166
3167     color = get_surface_color(rt, 320, 240);
3168     ok(compare_color(color, 0x00ffffff, 1), "Got unexpected color 0x%08x.\n", color);
3169
3170     IDirect3DViewport3_Release(viewport);
3171     IDirectDrawSurface4_Release(rt);
3172     IDirect3DDevice3_Release(device);
3173     DestroyWindow(window);
3174 }
3175
3176 START_TEST(ddraw4)
3177 {
3178     test_process_vertices();
3179     test_coop_level_create_device_window();
3180     test_clipper_blt();
3181     test_coop_level_d3d_state();
3182     test_surface_interface_mismatch();
3183     test_coop_level_threaded();
3184     test_depth_blit();
3185     test_texture_load_ckey();
3186     test_viewport();
3187     test_zenable();
3188     test_ck_rgba();
3189     test_ck_default();
3190     test_surface_qi();
3191     test_device_qi();
3192     test_wndproc();
3193     test_window_style();
3194     test_redundant_mode_set();
3195     test_coop_level_mode_set();
3196     test_coop_level_mode_set_multi();
3197     test_initialize();
3198     test_coop_level_surf_create();
3199     test_vb_discard();
3200     test_coop_level_multi_window();
3201     test_draw_strided();
3202     test_clear_rect_count();
3203 }