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