fltlib: Add a stub dll.
[wine] / dlls / ddraw / tests / ddrawmodes.c
1 /*
2  * Unit tests for ddraw functions
3  *
4  *
5  * Part of this test involves changing the screen resolution. But this is
6  * really disrupting if the user is doing something else and is not very nice
7  * to CRT screens. Plus, ideally it needs someone watching it to check that
8  * each mode displays correctly.
9  * So this is only done if the test is being run in interactive mode.
10  *
11  * Copyright (C) 2003 Sami Aario
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27
28 #include <assert.h>
29 #include "wine/test.h"
30 #include "ddraw.h"
31
32 static LPDIRECTDRAW lpDD = NULL;
33 static LPDIRECTDRAWSURFACE lpDDSPrimary = NULL;
34 static LPDIRECTDRAWSURFACE lpDDSBack = NULL;
35 static WNDCLASS wc;
36 static HWND hwnd;
37 static int modes_cnt;
38 static int modes_size;
39 static LPDDSURFACEDESC modes;
40
41 static void createwindow(void)
42 {
43     wc.style = CS_HREDRAW | CS_VREDRAW;
44     wc.lpfnWndProc = DefWindowProcA;
45     wc.cbClsExtra = 0;
46     wc.cbWndExtra = 0;
47     wc.hInstance = GetModuleHandleA(0);
48     wc.hIcon = LoadIconA(wc.hInstance, IDI_APPLICATION);
49     wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
50     wc.hbrBackground = GetStockObject(BLACK_BRUSH);
51     wc.lpszMenuName = NULL;
52     wc.lpszClassName = "TestWindowClass";
53     if(!RegisterClassA(&wc))
54         assert(0);
55
56     hwnd = CreateWindowExA(0, "TestWindowClass", "TestWindowClass",
57         WS_POPUP, 0, 0,
58         GetSystemMetrics(SM_CXSCREEN),
59         GetSystemMetrics(SM_CYSCREEN),
60         NULL, NULL, GetModuleHandleA(0), NULL);
61     assert(hwnd != NULL);
62
63     ShowWindow(hwnd, SW_HIDE);
64     UpdateWindow(hwnd);
65     SetFocus(hwnd);
66 }
67
68 static BOOL createdirectdraw(void)
69 {
70     HRESULT rc;
71
72     rc = DirectDrawCreate(NULL, &lpDD, NULL);
73     ok(rc==DD_OK || rc==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreateEx returned: %x\n", rc);
74     if (!lpDD) {
75         trace("DirectDrawCreateEx() failed with an error %x\n", rc);
76         return FALSE;
77     }
78     return TRUE;
79 }
80
81
82 static void releasedirectdraw(void)
83 {
84         if( lpDD != NULL )
85         {
86                 IDirectDraw_Release(lpDD);
87                 lpDD = NULL;
88         }
89 }
90
91 static void adddisplaymode(LPDDSURFACEDESC lpddsd)
92 {
93     if (!modes)
94         modes = HeapAlloc(GetProcessHeap(), 0, (modes_size = 2) * sizeof(DDSURFACEDESC));
95     if (modes_cnt == modes_size)
96         modes = HeapReAlloc(GetProcessHeap(), 0, modes, (modes_size *= 2) * sizeof(DDSURFACEDESC));
97     assert(modes);
98     modes[modes_cnt++] = *lpddsd;
99 }
100
101 static void flushdisplaymodes(void)
102 {
103     HeapFree(GetProcessHeap(), 0, modes);
104     modes = 0;
105     modes_cnt = modes_size = 0;
106 }
107
108 static HRESULT WINAPI enummodescallback(LPDDSURFACEDESC lpddsd, LPVOID lpContext)
109 {
110     trace("Width = %i, Height = %i, Refresh Rate = %i, Pitch = %i, flags =%02X\r\n",
111         lpddsd->dwWidth, lpddsd->dwHeight,
112           U2(*lpddsd).dwRefreshRate, U1(*lpddsd).lPitch, lpddsd->dwFlags);
113
114     /* Check that the pitch is valid if applicable */
115     if(lpddsd->dwFlags & DDSD_PITCH)
116     {
117         ok(U1(*lpddsd).lPitch != 0, "EnumDisplayModes callback with bad pitch\n");
118     }
119
120     /* Check that frequency is valid if applicable
121      *
122      * This fails on some Windows drivers or Windows versions, so it isn't important
123      * apparently
124     if(lpddsd->dwFlags & DDSD_REFRESHRATE)
125     {
126         ok(U2(*lpddsd).dwRefreshRate != 0, "EnumDisplayModes callback with bad refresh rate\n");
127     }
128      */
129
130     adddisplaymode(lpddsd);
131
132     return DDENUMRET_OK;
133 }
134
135 static void enumdisplaymodes(void)
136 {
137     DDSURFACEDESC ddsd;
138     HRESULT rc;
139
140     ZeroMemory(&ddsd, sizeof(DDSURFACEDESC));
141     ddsd.dwSize = sizeof(DDSURFACEDESC);
142     ddsd.dwFlags = DDSD_CAPS;
143     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
144
145     rc = IDirectDraw_EnumDisplayModes(lpDD,
146         DDEDM_STANDARDVGAMODES, &ddsd, 0, enummodescallback);
147     ok(rc==DD_OK || rc==E_INVALIDARG,"EnumDisplayModes returned: %x\n",rc);
148 }
149
150 static void setdisplaymode(int i)
151 {
152     HRESULT rc;
153
154     rc = IDirectDraw_SetCooperativeLevel(lpDD,
155         hwnd, DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
156     ok(rc==DD_OK,"SetCooperativeLevel returned: %x\n",rc);
157     if (modes[i].dwFlags & DDSD_PIXELFORMAT)
158     {
159         if (modes[i].ddpfPixelFormat.dwFlags & DDPF_RGB)
160         {
161             rc = IDirectDraw_SetDisplayMode(lpDD,
162                 modes[i].dwWidth, modes[i].dwHeight,
163                 U1(modes[i].ddpfPixelFormat).dwRGBBitCount);
164             ok(DD_OK==rc || DDERR_UNSUPPORTED==rc,"SetDisplayMode returned: %x\n",rc);
165             if (rc == DD_OK)
166             {
167                 RECT r, scrn, virt;
168
169                 SetRect(&virt, 0, 0, GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN));
170                 OffsetRect(&virt, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN));
171                 SetRect(&scrn, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
172                 trace("Mode (%dx%d) [%dx%d] (%d %d)x(%d %d)\n", modes[i].dwWidth, modes[i].dwHeight,
173                       scrn.right, scrn.bottom, virt.left, virt.top, virt.right, virt.bottom);
174
175                 ok(GetClipCursor(&r), "GetClipCursor() failed\n");
176                 /* ddraw sets clip rect here to the screen size, even for
177                    multiple monitors */
178                 ok(EqualRect(&r, &scrn), "Invalid clip rect: (%d %d) x (%d %d)\n",
179                    r.left, r.top, r.right, r.bottom);
180
181                 ok(ClipCursor(NULL), "ClipCursor() failed\n");
182                 ok(GetClipCursor(&r), "GetClipCursor() failed\n");
183                 ok(EqualRect(&r, &virt), "Invalid clip rect: (%d %d) x (%d %d)\n",
184                    r.left, r.top, r.right, r.bottom);
185
186                 rc = IDirectDraw_RestoreDisplayMode(lpDD);
187                 ok(DD_OK==rc,"RestoreDisplayMode returned: %x\n",rc);
188             }
189         }
190     }
191 }
192
193 static void createsurface(void)
194 {
195     DDSURFACEDESC ddsd;
196     DDSCAPS ddscaps;
197     HRESULT rc;
198
199     ddsd.dwSize = sizeof(ddsd);
200     ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
201     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
202         DDSCAPS_FLIP |
203         DDSCAPS_COMPLEX;
204     ddsd.dwBackBufferCount = 1;
205     rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDDSPrimary, NULL );
206     ok(rc==DD_OK,"CreateSurface returned: %x\n",rc);
207     ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
208     rc = IDirectDrawSurface_GetAttachedSurface(lpDDSPrimary, &ddscaps, &lpDDSBack);
209     ok(rc==DD_OK,"GetAttachedSurface returned: %x\n",rc);
210 }
211
212 static void destroysurface(void)
213 {
214     if( lpDDSPrimary != NULL )
215     {
216         IDirectDrawSurface_Release(lpDDSPrimary);
217         lpDDSPrimary = NULL;
218     }
219 }
220
221 static void testsurface(void)
222 {
223     const char* testMsg = "ddraw device context test";
224     HDC hdc;
225     HRESULT rc;
226
227     rc = IDirectDrawSurface_GetDC(lpDDSBack, &hdc);
228     ok(rc==DD_OK, "IDirectDrawSurface_GetDC returned: %x\n",rc);
229     SetBkColor(hdc, RGB(0, 0, 255));
230     SetTextColor(hdc, RGB(255, 255, 0));
231     TextOut(hdc, 0, 0, testMsg, lstrlen(testMsg));
232     IDirectDrawSurface_ReleaseDC(lpDDSBack, hdc);
233     ok(rc==DD_OK, "IDirectDrawSurface_ReleaseDC returned: %x\n",rc);
234
235     while (1)
236     {
237         rc = IDirectDrawSurface_Flip(lpDDSPrimary, NULL, DDFLIP_WAIT);
238         ok(rc==DD_OK || rc==DDERR_SURFACELOST, "IDirectDrawSurface_BltFast returned: %x\n",rc);
239
240         if (rc == DD_OK)
241         {
242             break;
243         }
244         else if (rc == DDERR_SURFACELOST)
245         {
246             rc = IDirectDrawSurface_Restore(lpDDSPrimary);
247             ok(rc==DD_OK, "IDirectDrawSurface_Restore returned: %x\n",rc);
248         }
249     }
250 }
251
252 static void testdisplaymodes(void)
253 {
254     int i;
255
256     for (i = 0; i < modes_cnt; ++i)
257     {
258         setdisplaymode(i);
259         createsurface();
260         testsurface();
261         destroysurface();
262     }
263 }
264
265 static void testcooperativelevels_normal(void)
266 {
267     HRESULT rc;
268     DDSURFACEDESC surfacedesc;
269     IDirectDrawSurface *surface = (IDirectDrawSurface *) 0xdeadbeef;
270
271     memset(&surfacedesc, 0, sizeof(surfacedesc));
272     surfacedesc.dwSize = sizeof(surfacedesc);
273     surfacedesc.ddpfPixelFormat.dwSize = sizeof(surfacedesc.ddpfPixelFormat);
274     surfacedesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
275     surfacedesc.dwBackBufferCount = 1;
276     surfacedesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
277
278     /* Do some tests with DDSCL_NORMAL mode */
279
280     rc = IDirectDraw_SetCooperativeLevel(lpDD,
281         hwnd, DDSCL_NORMAL);
282     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NORMAL) returned: %x\n",rc);
283
284     /* Try creating a double buffered primary in normal mode */
285     rc = IDirectDraw_CreateSurface(lpDD, &surfacedesc, &surface, NULL);
286     if (rc == DDERR_UNSUPPORTEDMODE)
287         skip("Unsupported mode\n");
288     else
289     {
290         ok(rc == DDERR_NOEXCLUSIVEMODE, "IDirectDraw_CreateSurface returned %08x\n", rc);
291         ok(surface == NULL, "Returned surface pointer is %p\n", surface);
292     }
293     if(surface && surface != (IDirectDrawSurface *)0xdeadbeef) IDirectDrawSurface_Release(surface);
294
295     /* Set the focus window */
296     rc = IDirectDraw_SetCooperativeLevel(lpDD,
297         hwnd, DDSCL_SETFOCUSWINDOW);
298
299     if (rc == DDERR_INVALIDPARAMS)
300     {
301         win_skip("NT4/Win95 do not support cooperative levels DDSCL_SETDEVICEWINDOW and DDSCL_SETFOCUSWINDOW\n");
302         return;
303     }
304
305     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
306
307     /* Set the focus window a second time*/
308     rc = IDirectDraw_SetCooperativeLevel(lpDD,
309         hwnd, DDSCL_SETFOCUSWINDOW);
310     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) the second time returned: %x\n",rc);
311
312     /* Test DDSCL_SETFOCUSWINDOW with the other flags. They should all fail, except of DDSCL_NOWINDOWCHANGES */
313     rc = IDirectDraw_SetCooperativeLevel(lpDD,
314         hwnd, DDSCL_NORMAL | DDSCL_SETFOCUSWINDOW);
315     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
316
317     rc = IDirectDraw_SetCooperativeLevel(lpDD,
318         hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETFOCUSWINDOW);
319     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
320
321     /* This one succeeds */
322     rc = IDirectDraw_SetCooperativeLevel(lpDD,
323         hwnd, DDSCL_NOWINDOWCHANGES | DDSCL_SETFOCUSWINDOW);
324     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NOWINDOWCHANGES | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
325
326     rc = IDirectDraw_SetCooperativeLevel(lpDD,
327         hwnd, DDSCL_MULTITHREADED | DDSCL_SETFOCUSWINDOW);
328     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_MULTITHREADED | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
329
330     rc = IDirectDraw_SetCooperativeLevel(lpDD,
331         hwnd, DDSCL_FPUSETUP | DDSCL_SETFOCUSWINDOW);
332     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FPUSETUP | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
333
334     rc = IDirectDraw_SetCooperativeLevel(lpDD,
335         hwnd, DDSCL_FPUPRESERVE | DDSCL_SETFOCUSWINDOW);
336     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FPUPRESERVE | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
337
338     rc = IDirectDraw_SetCooperativeLevel(lpDD,
339         hwnd, DDSCL_ALLOWREBOOT | DDSCL_SETFOCUSWINDOW);
340     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_ALLOWREBOOT | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
341
342     rc = IDirectDraw_SetCooperativeLevel(lpDD,
343         hwnd, DDSCL_ALLOWMODEX | DDSCL_SETFOCUSWINDOW);
344     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_ALLOWMODEX | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
345
346     /* Set the device window without any other flags. Should give an error */
347     rc = IDirectDraw_SetCooperativeLevel(lpDD,
348         hwnd, DDSCL_SETDEVICEWINDOW);
349     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_SETDEVICEWINDOW) returned: %x\n",rc);
350
351     /* Set device window with DDSCL_NORMAL */
352     rc = IDirectDraw_SetCooperativeLevel(lpDD,
353         hwnd, DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW);
354     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW) returned: %x\n",rc);
355
356     /* Also set the focus window. Should give an error */
357     rc = IDirectDraw_SetCooperativeLevel(lpDD,
358         hwnd, DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETDEVICEWINDOW | DDSCL_SETFOCUSWINDOW);
359     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
360
361     /* All done */
362 }
363
364 static void testcooperativelevels_exclusive(void)
365 {
366     HRESULT rc;
367
368     /* Do some tests with DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN mode */
369
370     /* Try to set exclusive mode only */
371     rc = IDirectDraw_SetCooperativeLevel(lpDD,
372         hwnd, DDSCL_EXCLUSIVE);
373     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_EXCLUSIVE) returned: %x\n",rc);
374
375     /* Full screen mode only */
376     rc = IDirectDraw_SetCooperativeLevel(lpDD,
377         hwnd, DDSCL_FULLSCREEN);
378     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FULLSCREEN) returned: %x\n",rc);
379
380     /* Full screen mode + exclusive mode */
381     rc = IDirectDraw_SetCooperativeLevel(lpDD,
382         hwnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
383     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) returned: %x\n",rc);
384
385     /* Set the focus window. Should fail */
386     rc = IDirectDraw_SetCooperativeLevel(lpDD,
387         hwnd, DDSCL_SETFOCUSWINDOW);
388     ok(rc==DDERR_HWNDALREADYSET ||
389        broken(rc==DDERR_INVALIDPARAMS) /* NT4/Win95 */,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
390
391
392     /* All done */
393 }
394
395 static void testddraw3(void)
396 {
397     const GUID My_IID_IDirectDraw3 = {
398         0x618f8ad4,
399         0x8b7a,
400         0x11d0,
401         { 0x8f,0xcc,0x0,0xc0,0x4f,0xd9,0x18,0x9d }
402     };
403     IDirectDraw3 *dd3;
404     HRESULT hr;
405     hr = IDirectDraw_QueryInterface(lpDD, &My_IID_IDirectDraw3, (void **) &dd3);
406     ok(hr == E_NOINTERFACE, "QueryInterface for IID_IDirectDraw3 returned 0x%08x, expected E_NOINTERFACE\n", hr);
407     if(SUCCEEDED(hr) && dd3) IDirectDraw3_Release(dd3);
408 }
409
410 START_TEST(ddrawmodes)
411 {
412     createwindow();
413     if (!createdirectdraw())
414         return;
415     enumdisplaymodes();
416     if (winetest_interactive)
417         testdisplaymodes();
418     flushdisplaymodes();
419     testddraw3();
420     releasedirectdraw();
421
422     createdirectdraw();
423     testcooperativelevels_normal();
424     releasedirectdraw();
425
426     createdirectdraw();
427     testcooperativelevels_exclusive();
428     releasedirectdraw();
429 }