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