ddraw: AddAttachedSurface() just references whatever we pass it.
[wine] / dlls / ddraw / tests / ddraw1.c
1 /*
2  * Copyright 2011 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
19 #include "wine/test.h"
20 #include "d3d.h"
21
22 struct create_window_thread_param
23 {
24     HWND window;
25     HANDLE window_created;
26     HANDLE destroy_window;
27     HANDLE thread;
28 };
29
30 static BOOL compare_color(D3DCOLOR c1, D3DCOLOR c2, BYTE max_diff)
31 {
32     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
33     c1 >>= 8; c2 >>= 8;
34     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
35     c1 >>= 8; c2 >>= 8;
36     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
37     c1 >>= 8; c2 >>= 8;
38     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
39     return TRUE;
40 }
41
42 static DWORD WINAPI create_window_thread_proc(void *param)
43 {
44     struct create_window_thread_param *p = param;
45     DWORD res;
46     BOOL ret;
47
48     p->window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
49             0, 0, 640, 480, 0, 0, 0, 0);
50     ret = SetEvent(p->window_created);
51     ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
52
53     for (;;)
54     {
55         MSG msg;
56
57         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
58             DispatchMessage(&msg);
59         res = WaitForSingleObject(p->destroy_window, 100);
60         if (res == WAIT_OBJECT_0)
61             break;
62         if (res != WAIT_TIMEOUT)
63         {
64             ok(0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
65             break;
66         }
67     }
68
69     DestroyWindow(p->window);
70
71     return 0;
72 }
73
74 static void create_window_thread(struct create_window_thread_param *p)
75 {
76     DWORD res, tid;
77
78     p->window_created = CreateEvent(NULL, FALSE, FALSE, NULL);
79     ok(!!p->window_created, "CreateEvent failed, last error %#x.\n", GetLastError());
80     p->destroy_window = CreateEvent(NULL, FALSE, FALSE, NULL);
81     ok(!!p->destroy_window, "CreateEvent failed, last error %#x.\n", GetLastError());
82     p->thread = CreateThread(NULL, 0, create_window_thread_proc, p, 0, &tid);
83     ok(!!p->thread, "Failed to create thread, last error %#x.\n", GetLastError());
84     res = WaitForSingleObject(p->window_created, INFINITE);
85     ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
86 }
87
88 static void destroy_window_thread(struct create_window_thread_param *p)
89 {
90     SetEvent(p->destroy_window);
91     WaitForSingleObject(p->thread, INFINITE);
92     CloseHandle(p->destroy_window);
93     CloseHandle(p->window_created);
94     CloseHandle(p->thread);
95 }
96
97 static D3DCOLOR get_surface_color(IDirectDrawSurface *surface, UINT x, UINT y)
98 {
99     RECT rect = {x, y, x + 1, y + 1};
100     DDSURFACEDESC surface_desc;
101     D3DCOLOR color;
102     HRESULT hr;
103
104     memset(&surface_desc, 0, sizeof(surface_desc));
105     surface_desc.dwSize = sizeof(surface_desc);
106
107     hr = IDirectDrawSurface_Lock(surface, &rect, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
108     ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
109     if (FAILED(hr))
110         return 0xdeadbeef;
111
112     color = *((DWORD *)surface_desc.lpSurface) & 0x00ffffff;
113
114     hr = IDirectDrawSurface_Unlock(surface, NULL);
115     ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
116
117     return color;
118 }
119
120 static HRESULT CALLBACK enum_z_fmt(GUID *guid, char *description, char *name,
121         D3DDEVICEDESC *hal_desc, D3DDEVICEDESC *hel_desc, void *ctx)
122 {
123     DWORD *z_depth = ctx;
124
125     if (!IsEqualGUID(&IID_IDirect3DHALDevice, guid))
126         return D3DENUMRET_OK;
127
128     if (hal_desc->dwDeviceZBufferBitDepth & DDBD_32)
129         *z_depth = 32;
130     else if (hal_desc->dwDeviceZBufferBitDepth & DDBD_24)
131         *z_depth = 24;
132     else if (hal_desc->dwDeviceZBufferBitDepth & DDBD_16)
133         *z_depth = 16;
134
135     return DDENUMRET_OK;
136 }
137
138 static IDirectDraw *create_ddraw(void)
139 {
140     IDirectDraw *ddraw;
141
142     if (FAILED(DirectDrawCreate(NULL, &ddraw, NULL)))
143         return NULL;
144
145     return ddraw;
146 }
147
148 static IDirect3DDevice *create_device(IDirectDraw *ddraw, HWND window, DWORD coop_level)
149 {
150     IDirectDrawSurface *surface, *ds;
151     IDirect3DDevice *device = NULL;
152     DDSURFACEDESC surface_desc;
153     DWORD z_depth = 0;
154     IDirect3D *d3d;
155     HRESULT hr;
156
157     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, coop_level);
158     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
159
160     memset(&surface_desc, 0, sizeof(surface_desc));
161     surface_desc.dwSize = sizeof(surface_desc);
162     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
163     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
164     surface_desc.dwWidth = 640;
165     surface_desc.dwHeight = 480;
166
167     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
168     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
169
170     if (coop_level & DDSCL_NORMAL)
171     {
172         IDirectDrawClipper *clipper;
173
174         hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
175         ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
176         hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
177         ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
178         hr = IDirectDrawSurface_SetClipper(surface, clipper);
179         ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#x.\n", hr);
180         IDirectDrawClipper_Release(clipper);
181     }
182
183     hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
184     if (FAILED(hr))
185     {
186         IDirectDrawSurface_Release(surface);
187         return NULL;
188     }
189
190     hr = IDirect3D_EnumDevices(d3d, enum_z_fmt, &z_depth);
191     ok(SUCCEEDED(hr), "Failed to enumerate z-formats, hr %#x.\n", hr);
192     IDirect3D_Release(d3d);
193     if (FAILED(hr) || !z_depth)
194     {
195         IDirectDrawSurface_Release(surface);
196         return NULL;
197     }
198
199     memset(&surface_desc, 0, sizeof(surface_desc));
200     surface_desc.dwSize = sizeof(surface_desc);
201     surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
202     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
203     U2(surface_desc).dwZBufferBitDepth = z_depth;
204     surface_desc.dwWidth = 640;
205     surface_desc.dwHeight = 480;
206     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &ds, NULL);
207     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
208     if (FAILED(hr))
209     {
210         IDirectDrawSurface_Release(surface);
211         return NULL;
212     }
213
214     hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
215     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
216     IDirectDrawSurface_Release(ds);
217     if (FAILED(hr))
218     {
219         IDirectDrawSurface_Release(surface);
220         return NULL;
221     }
222
223     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DHALDevice, (void **)&device);
224     IDirectDrawSurface_Release(surface);
225     if (FAILED(hr))
226         return NULL;
227
228     return device;
229 }
230
231 static HRESULT CALLBACK restore_callback(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
232 {
233     HRESULT hr = IDirectDrawSurface_Restore(surface);
234     ok(SUCCEEDED(hr), "Failed to restore surface, hr %#x.\n", hr);
235     IDirectDrawSurface_Release(surface);
236
237     return DDENUMRET_OK;
238 }
239
240 static HRESULT restore_surfaces(IDirectDraw *ddraw)
241 {
242     return IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_ALL | DDENUMSURFACES_DOESEXIST,
243             NULL, NULL, restore_callback);
244 }
245
246 static void test_coop_level_create_device_window(void)
247 {
248     HWND focus_window, device_window;
249     IDirectDraw *ddraw;
250     HRESULT hr;
251
252     focus_window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
253             0, 0, 640, 480, 0, 0, 0, 0);
254     if (!(ddraw = create_ddraw()))
255     {
256         skip("Failed to create a ddraw object, skipping test.\n");
257         DestroyWindow(focus_window);
258         return;
259     }
260
261     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
262     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
263     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
264     ok(!device_window, "Unexpected device window found.\n");
265     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW);
266     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
267     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
268     ok(!device_window, "Unexpected device window found.\n");
269     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL);
270     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
271     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
272     ok(!device_window, "Unexpected device window found.\n");
273     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL | DDSCL_FULLSCREEN);
274     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
275     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
276     ok(!device_window, "Unexpected device window found.\n");
277     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
278     ok(hr == DDERR_NOFOCUSWINDOW || broken(hr == DDERR_INVALIDPARAMS), "Got unexpected hr %#x.\n", hr);
279     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
280     ok(!device_window, "Unexpected device window found.\n");
281
282     /* Windows versions before 98 / NT5 don't support DDSCL_CREATEDEVICEWINDOW. */
283     if (broken(hr == DDERR_INVALIDPARAMS))
284     {
285         win_skip("DDSCL_CREATEDEVICEWINDOW not supported, skipping test.\n");
286         IDirectDraw_Release(ddraw);
287         DestroyWindow(focus_window);
288         return;
289     }
290
291     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
292     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
293     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
294     ok(!device_window, "Unexpected device window found.\n");
295     hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
296     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
297     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
298     ok(!device_window, "Unexpected device window found.\n");
299
300     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
301     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
302     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
303     ok(!device_window, "Unexpected device window found.\n");
304     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_SETFOCUSWINDOW
305             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
306     ok(hr == DDERR_NOHWND, "Got unexpected hr %#x.\n", hr);
307     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
308     ok(!!device_window, "Device window not found.\n");
309
310     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
311     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
312     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
313     ok(!device_window, "Unexpected device window found.\n");
314     hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW
315             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
316     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
317     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
318     ok(!!device_window, "Device window not found.\n");
319
320     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
321     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
322     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
323     ok(!device_window, "Unexpected device window found.\n");
324     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
325     ok(hr == DDERR_NOFOCUSWINDOW, "Got unexpected hr %#x.\n", hr);
326     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
327     ok(!device_window, "Unexpected device window found.\n");
328     hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW);
329     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
330     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
331     ok(!device_window, "Unexpected device window found.\n");
332     hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
333     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
334     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
335     ok(!!device_window, "Device window not found.\n");
336
337     IDirectDraw_Release(ddraw);
338     DestroyWindow(focus_window);
339 }
340
341 static void test_clipper_blt(void)
342 {
343     IDirectDrawSurface *src_surface, *dst_surface;
344     RECT client_rect, src_rect, *rect;
345     IDirectDrawClipper *clipper;
346     DDSURFACEDESC surface_desc;
347     unsigned int i, j, x, y;
348     IDirectDraw *ddraw;
349     RGNDATA *rgn_data;
350     D3DCOLOR color;
351     HRGN r1, r2;
352     HWND window;
353     DDBLTFX fx;
354     HRESULT hr;
355     DWORD *ptr;
356     DWORD ret;
357
358     static const DWORD src_data[] =
359     {
360         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
361         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
362         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
363     };
364     static const D3DCOLOR expected1[] =
365     {
366         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
367         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
368         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
369         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
370     };
371     static const D3DCOLOR expected2[] =
372     {
373         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
374         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
375         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
376         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
377     };
378
379     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
380             10, 10, 640, 480, 0, 0, 0, 0);
381     ShowWindow(window, SW_SHOW);
382     if (!(ddraw = create_ddraw()))
383     {
384         skip("Failed to create a ddraw object, skipping test.\n");
385         DestroyWindow(window);
386         return;
387     }
388
389     ret = GetClientRect(window, &client_rect);
390     ok(ret, "Failed to get client rect.\n");
391     ret = MapWindowPoints(window, NULL, (POINT *)&client_rect, 2);
392     ok(ret, "Failed to map client rect.\n");
393
394     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
395     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
396
397     hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
398     ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
399     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
400     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
401     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
402     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
403     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
404     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
405     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
406     hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret);
407     ok(SUCCEEDED(hr), "Failed to get clip list, hr %#x.\n", hr);
408     ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#x.\n", rgn_data->rdh.dwSize);
409     ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#x.\n", rgn_data->rdh.iType);
410     ok(rgn_data->rdh.nCount == 1, "Got unexpected count %u.\n", rgn_data->rdh.nCount);
411     ok(rgn_data->rdh.nRgnSize == 16 || broken(rgn_data->rdh.nRgnSize == 168 /* NT4 */),
412             "Got unexpected region size %u.\n", rgn_data->rdh.nRgnSize);
413     ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
414             "Got unexpected bounding rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
415             rgn_data->rdh.rcBound.left, rgn_data->rdh.rcBound.top,
416             rgn_data->rdh.rcBound.right, rgn_data->rdh.rcBound.bottom,
417             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
418     rect = (RECT *)&rgn_data->Buffer[0];
419     ok(EqualRect(rect, &client_rect),
420             "Got unexpected clip rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
421             rect->left, rect->top, rect->right, rect->bottom,
422             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
423     HeapFree(GetProcessHeap(), 0, rgn_data);
424
425     r1 = CreateRectRgn(0, 0, 320, 240);
426     ok(!!r1, "Failed to create region.\n");
427     r2 = CreateRectRgn(320, 240, 640, 480);
428     ok(!!r2, "Failed to create region.\n");
429     CombineRgn(r1, r1, r2, RGN_OR);
430     ret = GetRegionData(r1, 0, NULL);
431     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
432     ret = GetRegionData(r1, ret, rgn_data);
433     ok(!!ret, "Failed to get region data.\n");
434
435     DeleteObject(r2);
436     DeleteObject(r1);
437
438     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
439     ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#x.\n", hr);
440     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
441     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
442     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
443     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
444
445     HeapFree(GetProcessHeap(), 0, rgn_data);
446
447     memset(&surface_desc, 0, sizeof(surface_desc));
448     surface_desc.dwSize = sizeof(surface_desc);
449     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
450     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
451     surface_desc.dwWidth = 640;
452     surface_desc.dwHeight = 480;
453     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
454     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
455     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
456     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
457     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
458     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
459
460     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
461     ok(SUCCEEDED(hr), "Failed to create source surface, hr %#x.\n", hr);
462     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
463     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
464
465     memset(&fx, 0, sizeof(fx));
466     fx.dwSize = sizeof(fx);
467     hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
468     ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#x.\n", hr);
469     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
470     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
471
472     hr = IDirectDrawSurface_Lock(src_surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
473     ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#x.\n", hr);
474     ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %u.\n", U1(surface_desc).lPitch);
475     ptr = surface_desc.lpSurface;
476     memcpy(&ptr[   0], &src_data[ 0], 6 * sizeof(DWORD));
477     memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
478     memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
479     hr = IDirectDrawSurface_Unlock(src_surface, NULL);
480     ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#x.\n", hr);
481
482     hr = IDirectDrawSurface_SetClipper(dst_surface, clipper);
483     ok(SUCCEEDED(hr), "Failed to set clipper, hr %#x.\n", hr);
484
485     SetRect(&src_rect, 1, 1, 5, 2);
486     hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
487     ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
488     for (i = 0; i < 4; ++i)
489     {
490         for (j = 0; j < 4; ++j)
491         {
492             x = 80 * ((2 * j) + 1);
493             y = 60 * ((2 * i) + 1);
494             color = get_surface_color(dst_surface, x, y);
495             ok(compare_color(color, expected1[i * 4 + j], 1),
496                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
497         }
498     }
499
500     U5(fx).dwFillColor = 0xff0000ff;
501     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
502     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
503     for (i = 0; i < 4; ++i)
504     {
505         for (j = 0; j < 4; ++j)
506         {
507             x = 80 * ((2 * j) + 1);
508             y = 60 * ((2 * i) + 1);
509             color = get_surface_color(dst_surface, x, y);
510             ok(compare_color(color, expected2[i * 4 + j], 1),
511                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
512         }
513     }
514
515     hr = IDirectDrawSurface_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
516     ok(hr == DDERR_BLTFASTCANTCLIP || broken(hr == E_NOTIMPL /* NT4 */), "Got unexpected hr %#x.\n", hr);
517
518     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
519     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
520     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
521     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
522     DestroyWindow(window);
523     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
524     ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
525     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
526     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
527     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
528     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
529     hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
530     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
531     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
532     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
533     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
534     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
535
536     IDirectDrawSurface_Release(dst_surface);
537     IDirectDrawSurface_Release(src_surface);
538     IDirectDrawClipper_Release(clipper);
539     IDirectDraw_Release(ddraw);
540 }
541
542 static void test_coop_level_d3d_state(void)
543 {
544     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
545     D3DMATERIALHANDLE background_handle;
546     IDirectDrawSurface *rt, *surface;
547     IDirect3DMaterial *background;
548     IDirect3DViewport *viewport;
549     IDirect3DDevice *device;
550     D3DMATERIAL material;
551     IDirectDraw *ddraw;
552     D3DVIEWPORT vp;
553     IDirect3D *d3d;
554     D3DCOLOR color;
555     HWND window;
556     HRESULT hr;
557
558     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
559             0, 0, 640, 480, 0, 0, 0, 0);
560     if (!(ddraw = create_ddraw()))
561     {
562         skip("Failed to create ddraw object, skipping test.\n");
563         DestroyWindow(window);
564         return;
565     }
566     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
567     {
568         skip("Failed to create D3D device, skipping test.\n");
569         IDirectDraw_Release(ddraw);
570         DestroyWindow(window);
571         return;
572     }
573
574     hr = IDirect3DDevice_GetDirect3D(device, &d3d);
575     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
576     hr = IDirect3D_CreateViewport(d3d, &viewport, NULL);
577     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
578     hr = IDirect3D_CreateMaterial(d3d, &background, NULL);
579     ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
580     IDirect3D_Release(d3d);
581
582     hr = IDirect3DDevice_AddViewport(device, viewport);
583     ok(SUCCEEDED(hr), "Failed to add viewport, hr %#x.\n", hr);
584     memset(&vp, 0, sizeof(vp));
585     vp.dwSize = sizeof(vp);
586     vp.dwX = 0;
587     vp.dwY = 0;
588     vp.dwWidth = 640;
589     vp.dwHeight = 480;
590     vp.dvScaleX = 320.0f;
591     vp.dvScaleY = 240.0f;
592     vp.dvMaxX = 1.0f;
593     vp.dvMaxY = 1.0f;
594     vp.dvMinZ = 0.0f;
595     vp.dvMaxZ = 1.0f;
596     hr = IDirect3DViewport_SetViewport(viewport, &vp);
597     ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#x.\n", hr);
598
599     memset(&material, 0, sizeof(material));
600     material.dwSize = sizeof(material);
601     U1(U(material).diffuse).r = 1.0f;
602     U2(U(material).diffuse).g = 0.0f;
603     U3(U(material).diffuse).b = 0.0f;
604     U4(U(material).diffuse).a = 1.0f;
605     hr = IDirect3DMaterial_SetMaterial(background, &material);
606     ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
607     hr = IDirect3DMaterial_GetHandle(background, device, &background_handle);
608     ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
609     hr = IDirect3DViewport_SetBackground(viewport, background_handle);
610     ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#x.\n", hr);
611
612     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
613     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
614     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
615     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
616     color = get_surface_color(rt, 320, 240);
617     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
618
619     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
620     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
621     hr = IDirectDrawSurface_IsLost(rt);
622     ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
623     hr = restore_surfaces(ddraw);
624     ok(SUCCEEDED(hr), "Failed to restore surfaces, hr %#x.\n", hr);
625
626     memset(&material, 0, sizeof(material));
627     material.dwSize = sizeof(material);
628     U1(U(material).diffuse).r = 0.0f;
629     U2(U(material).diffuse).g = 1.0f;
630     U3(U(material).diffuse).b = 0.0f;
631     U4(U(material).diffuse).a = 1.0f;
632     hr = IDirect3DMaterial_SetMaterial(background, &material);
633     ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
634
635     hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&surface);
636     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
637     ok(surface == rt, "Got unexpected surface %p.\n", surface);
638     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
639     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
640     color = get_surface_color(rt, 320, 240);
641     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
642
643     hr = IDirect3DDevice_DeleteViewport(device, viewport);
644     ok(SUCCEEDED(hr), "Failed to delete viewport, hr %#x.\n", hr);
645     IDirect3DMaterial_Release(background);
646     IDirect3DViewport_Release(viewport);
647     IDirectDrawSurface_Release(surface);
648     IDirectDrawSurface_Release(rt);
649     IDirect3DDevice_Release(device);
650     IDirectDraw_Release(ddraw);
651     DestroyWindow(window);
652 }
653
654 static void test_surface_interface_mismatch(void)
655 {
656     IDirectDraw *ddraw = NULL;
657     IDirect3D *d3d = NULL;
658     IDirectDrawSurface *surface = NULL, *ds;
659     IDirectDrawSurface3 *surface3 = NULL;
660     IDirect3DDevice *device = NULL;
661     IDirect3DViewport *viewport = NULL;
662     IDirect3DMaterial *background = NULL;
663     DDSURFACEDESC surface_desc;
664     DWORD z_depth = 0;
665     ULONG refcount;
666     HRESULT hr;
667     D3DCOLOR color;
668     HWND window;
669     D3DVIEWPORT vp;
670     D3DMATERIAL material;
671     D3DMATERIALHANDLE background_handle;
672     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
673
674     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
675             0, 0, 640, 480, 0, 0, 0, 0);
676
677     if (!(ddraw = create_ddraw()))
678     {
679         skip("Failed to create a ddraw object, skipping test.\n");
680         goto cleanup;
681     }
682
683     hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
684     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
685
686     memset(&surface_desc, 0, sizeof(surface_desc));
687     surface_desc.dwSize = sizeof(surface_desc);
688     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
689     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
690     surface_desc.dwWidth = 640;
691     surface_desc.dwHeight = 480;
692
693     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
694     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
695
696     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
697     if (FAILED(hr))
698     {
699         skip("Failed to get the IDirectDrawSurface3 interface, skipping test.\n");
700         goto cleanup;
701     }
702
703     hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
704     if (FAILED(hr))
705     {
706         skip("Failed to get the IDirect3D interface, skipping test.\n");
707         goto cleanup;
708     }
709
710     hr = IDirect3D_EnumDevices(d3d, enum_z_fmt, &z_depth);
711     if (FAILED(hr) || !z_depth)
712     {
713         skip("No depth buffer formats available, skipping test.\n");
714         goto cleanup;
715     }
716
717     memset(&surface_desc, 0, sizeof(surface_desc));
718     surface_desc.dwSize = sizeof(surface_desc);
719     surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
720     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
721     surface_desc.dwZBufferBitDepth = z_depth;
722     surface_desc.dwWidth = 640;
723     surface_desc.dwHeight = 480;
724     hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &ds, NULL);
725     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
726     if (FAILED(hr))
727         goto cleanup;
728
729     /* Using a different surface interface version still works */
730     hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
731     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
732     refcount = IDirectDrawSurface_Release(ds);
733     ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
734     if (FAILED(hr))
735         goto cleanup;
736
737     /* Here too */
738     hr = IDirectDrawSurface3_QueryInterface(surface3, &IID_IDirect3DHALDevice, (void **)&device);
739     ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
740     if (FAILED(hr))
741         goto cleanup;
742
743     hr = IDirect3D_CreateViewport(d3d, &viewport, NULL);
744     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
745     hr = IDirect3D_CreateMaterial(d3d, &background, NULL);
746     ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
747
748     hr = IDirect3DDevice_AddViewport(device, viewport);
749     ok(SUCCEEDED(hr), "Failed to add viewport, hr %#x.\n", hr);
750     memset(&vp, 0, sizeof(vp));
751     vp.dwSize = sizeof(vp);
752     vp.dwX = 0;
753     vp.dwY = 0;
754     vp.dwWidth = 640;
755     vp.dwHeight = 480;
756     vp.dvScaleX = 320.0f;
757     vp.dvScaleY = 240.0f;
758     vp.dvMaxX = 1.0f;
759     vp.dvMaxY = 1.0f;
760     vp.dvMinZ = 0.0f;
761     vp.dvMaxZ = 1.0f;
762     hr = IDirect3DViewport_SetViewport(viewport, &vp);
763     ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#x.\n", hr);
764
765     memset(&material, 0, sizeof(material));
766     material.dwSize = sizeof(material);
767     U1(U(material).diffuse).r = 1.0f;
768     U2(U(material).diffuse).g = 0.0f;
769     U3(U(material).diffuse).b = 0.0f;
770     U4(U(material).diffuse).a = 1.0f;
771     hr = IDirect3DMaterial_SetMaterial(background, &material);
772     ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
773     hr = IDirect3DMaterial_GetHandle(background, device, &background_handle);
774     ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
775     hr = IDirect3DViewport_SetBackground(viewport, background_handle);
776     ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#x.\n", hr);
777
778     hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
779     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
780     color = get_surface_color(surface, 320, 240);
781     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
782
783 cleanup:
784     if (viewport)
785     {
786         IDirect3DDevice2_DeleteViewport(device, viewport);
787         IDirect3DViewport2_Release(viewport);
788     }
789     if (background) IDirect3DMaterial2_Release(background);
790     if (surface3) IDirectDrawSurface3_Release(surface3);
791     if (surface) IDirectDrawSurface7_Release(surface);
792     if (device) IDirect3DDevice2_Release(device);
793     if (d3d) IDirect3D7_Release(d3d);
794     if (ddraw) IDirectDraw7_Release(ddraw);
795     DestroyWindow(window);
796 }
797
798 static void test_coop_level_threaded(void)
799 {
800     struct create_window_thread_param p;
801     IDirectDraw *ddraw;
802     HRESULT hr;
803
804     if (!(ddraw = create_ddraw()))
805     {
806         skip("Failed to create a ddraw object, skipping test.\n");
807         return;
808     }
809     create_window_thread(&p);
810
811     hr = IDirectDraw_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
812     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
813
814     IDirectDraw_Release(ddraw);
815     destroy_window_thread(&p);
816 }
817
818 START_TEST(ddraw1)
819 {
820     test_coop_level_create_device_window();
821     test_clipper_blt();
822     test_coop_level_d3d_state();
823     test_surface_interface_mismatch();
824     test_coop_level_threaded();
825 }