2 * Unit tests for DirectDraw overlay functions
4 * Copyright (C) 2008,2011 Stefan Dösinger for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/test.h"
26 static HRESULT (WINAPI
*pDirectDrawCreateEx
)(LPGUID
,LPVOID
*,REFIID
,LPUNKNOWN
);
28 static IDirectDraw7
*ddraw
= NULL
;
29 static IDirectDrawSurface7
*primary
= NULL
;
31 static IDirectDrawSurface7
*create_overlay(DWORD width
, DWORD height
, DWORD format
) {
34 IDirectDrawSurface7
*ret
;
36 memset(&ddsd
, 0, sizeof(ddsd
));
37 ddsd
.dwSize
= sizeof(ddsd
);
38 ddsd
.dwFlags
= DDSD_CAPS
| DDSD_HEIGHT
| DDSD_WIDTH
| DDSD_PIXELFORMAT
;
40 ddsd
.dwHeight
= height
;
41 ddsd
.ddsCaps
.dwCaps
= DDSCAPS_OVERLAY
;
42 U4(ddsd
).ddpfPixelFormat
.dwSize
= sizeof(U4(ddsd
).ddpfPixelFormat
);
43 U4(ddsd
).ddpfPixelFormat
.dwFlags
= DDPF_FOURCC
;
44 U4(ddsd
).ddpfPixelFormat
.dwFourCC
= format
;
45 hr
= IDirectDraw7_CreateSurface(ddraw
, &ddsd
, &ret
, NULL
);
46 if(FAILED(hr
)) return NULL
;
50 static BOOL
CreateDirectDraw(void)
54 IDirectDrawSurface7
*overlay
= NULL
;
55 HMODULE hmod
= GetModuleHandleA("ddraw.dll");
57 pDirectDrawCreateEx
= (void*)GetProcAddress(hmod
, "DirectDrawCreateEx");
58 if (!pDirectDrawCreateEx
) {
59 win_skip("DirectDrawCreateEx is not available\n");
63 hr
= pDirectDrawCreateEx(NULL
, (void**)&ddraw
, &IID_IDirectDraw7
, NULL
);
64 ok(hr
== DD_OK
|| hr
== DDERR_NODIRECTDRAWSUPPORT
, "DirectDrawCreateEx returned: %x\n", hr
);
66 trace("DirectDrawCreateEx() failed with an error %x\n", hr
);
70 hr
= IDirectDraw_SetCooperativeLevel(ddraw
, NULL
, DDSCL_NORMAL
);
71 ok(hr
== DD_OK
, "SetCooperativeLevel returned: %x\n", hr
);
73 memset(&ddsd
, 0, sizeof(ddsd
));
74 ddsd
.dwSize
= sizeof(ddsd
);
75 ddsd
.dwFlags
= DDSD_CAPS
;
76 ddsd
.ddsCaps
.dwCaps
= DDSCAPS_PRIMARYSURFACE
;
77 hr
= IDirectDraw7_CreateSurface(ddraw
, &ddsd
, &primary
, NULL
);
79 IDirectDraw7_Release(ddraw
);
80 trace("IDirectDraw7_CreateSurface() failed with an error %x\n", hr
);
84 overlay
= create_overlay(64, 64, MAKEFOURCC('U','Y','V','Y'));
86 IDirectDrawSurface7_Release(primary
);
87 IDirectDraw7_Release(ddraw
);
88 skip("Failed to create an overlay - assuming not supported\n");
91 IDirectDraw7_Release(overlay
);
96 static void rectangle_settings(void) {
97 IDirectDrawSurface7
*overlay
= create_overlay(64, 64, MAKEFOURCC('U','Y','V','Y'));
99 RECT rect
= {0, 0, 64, 64};
102 /* The dx sdk sort of implies that rect must be set when DDOVER_SHOW is used. This is not true
103 * in Windows Vista and earlier, but changed in Win7 */
104 hr
= IDirectDrawSurface7_UpdateOverlay(overlay
, NULL
, primary
, &rect
, DDOVER_SHOW
, NULL
);
105 ok(hr
== DD_OK
, "IDirectDrawSurface7_UpdateOverlay failed with hr=0x%08x\n", hr
);
106 hr
= IDirectDrawSurface7_UpdateOverlay(overlay
, NULL
, primary
, NULL
, DDOVER_HIDE
, NULL
);
107 ok(hr
== DD_OK
, "IDirectDrawSurface7_UpdateOverlay failed with hr=0x%08x\n", hr
);
108 hr
= IDirectDrawSurface7_UpdateOverlay(overlay
, NULL
, primary
, NULL
, DDOVER_SHOW
, NULL
);
109 ok(hr
== DD_OK
|| hr
== DDERR_INVALIDPARAMS
, "IDirectDrawSurface7_UpdateOverlay failed with hr=0x%08x\n", hr
);
111 /* Show that the overlay position is the (top, left) coordinate of the dest rectangle */
116 hr
= IDirectDrawSurface7_UpdateOverlay(overlay
, NULL
, primary
, &rect
, DDOVER_SHOW
, NULL
);
117 ok(hr
== DD_OK
, "IDirectDrawSurface7_UpdateOverlay failed with hr=0x%08x\n", hr
);
118 posx
= -1; posy
= -1;
119 hr
= IDirectDrawSurface7_GetOverlayPosition(overlay
, &posx
, &posy
);
120 ok(hr
== DD_OK
, "IDirectDrawSurface7_GetOverlayPosition failed with hr=0x%08x\n", hr
);
121 ok(posx
== rect
.left
&& posy
== rect
.top
, "Overlay position is (%d, %d), expected (%d, %d)\n",
122 posx
, posy
, rect
.left
, rect
.top
);
124 /* Passing a NULL dest rect sets the position to 0/0 . Visually it can be seen that the overlay overlays the whole primary(==screen)*/
125 hr2
= IDirectDrawSurface7_UpdateOverlay(overlay
, NULL
, primary
, NULL
, 0, NULL
);
126 ok(hr2
== DD_OK
|| hr2
== DDERR_INVALIDPARAMS
127 || hr2
== DDERR_OUTOFCAPS
, "IDirectDrawSurface7_UpdateOverlay failed with hr=0x%08x\n", hr2
);
128 hr
= IDirectDrawSurface7_GetOverlayPosition(overlay
, &posx
, &posy
);
129 ok(hr
== DD_OK
, "IDirectDrawSurface7_GetOverlayPosition failed with hr=0x%08x\n", hr
);
132 ok(posx
== 0 && posy
== 0, "Overlay position is (%d, %d), expected (%d, %d)\n",
137 /* Otherwise the position remains untouched */
138 ok(posx
== 32 && posy
== 16, "Overlay position is (%d, %d), expected (%d, %d)\n",
141 /* The position cannot be retrieved when the overlay is not shown */
142 hr
= IDirectDrawSurface7_UpdateOverlay(overlay
, NULL
, primary
, &rect
, DDOVER_HIDE
, NULL
);
143 ok(hr
== DD_OK
, "IDirectDrawSurface7_UpdateOverlay failed with hr=0x%08x\n", hr
);
144 posx
= -1; posy
= -1;
145 hr
= IDirectDrawSurface7_GetOverlayPosition(overlay
, &posx
, &posy
);
146 ok(hr
== DDERR_OVERLAYNOTVISIBLE
, "IDirectDrawSurface7_GetOverlayPosition failed with hr=0x%08x\n", hr
);
147 ok(posx
== 0 && posy
== 0, "Overlay position is (%d, %d), expected (%d, %d)\n",
150 IDirectDrawSurface7_Release(overlay
);
153 static void offscreen_test(void) {
154 IDirectDrawSurface7
*overlay
= create_overlay(64, 64, MAKEFOURCC('U','Y','V','Y')), *offscreen
= NULL
;
158 /* Try to overlay a NULL surface */
159 hr
= IDirectDrawSurface7_UpdateOverlay(overlay
, NULL
, NULL
, NULL
, DDOVER_SHOW
, NULL
);
160 ok(hr
== DDERR_INVALIDPARAMS
, "IDirectDrawSurface7_UpdateOverlay failed with hr=0x%08x\n", hr
);
161 hr
= IDirectDrawSurface7_UpdateOverlay(overlay
, NULL
, NULL
, NULL
, DDOVER_HIDE
, NULL
);
162 ok(hr
== DDERR_INVALIDPARAMS
, "IDirectDrawSurface7_UpdateOverlay failed with hr=0x%08x\n", hr
);
164 /* Try to overlay an offscreen surface */
165 memset(&ddsd
, 0, sizeof(ddsd
));
166 ddsd
.dwSize
= sizeof(ddsd
);
167 ddsd
.dwFlags
= DDSD_CAPS
| DDSD_HEIGHT
| DDSD_WIDTH
| DDSD_PIXELFORMAT
;
170 U4(ddsd
).ddpfPixelFormat
.dwSize
= sizeof(U4(ddsd
).ddpfPixelFormat
);
171 U4(ddsd
).ddpfPixelFormat
.dwFlags
= DDPF_RGB
;
172 U4(ddsd
).ddpfPixelFormat
.dwFourCC
= 0;
173 U1(U4(ddsd
).ddpfPixelFormat
).dwRGBBitCount
= 16;
174 U2(U4(ddsd
).ddpfPixelFormat
).dwRBitMask
= 0xF800;
175 U3(U4(ddsd
).ddpfPixelFormat
).dwGBitMask
= 0x07e0;
176 U4(U4(ddsd
).ddpfPixelFormat
).dwBBitMask
= 0x001F;
177 ddsd
.ddsCaps
.dwCaps
= DDSCAPS_OFFSCREENPLAIN
;
178 hr
= IDirectDraw7_CreateSurface(ddraw
, &ddsd
, &offscreen
, NULL
);
179 ok(hr
== DD_OK
, "IDirectDraw7_CreateSurface failed with hr=0x%08x\n", hr
);
181 hr
= IDirectDrawSurface7_UpdateOverlay(overlay
, NULL
, offscreen
, NULL
, DDOVER_SHOW
, NULL
);
182 ok(hr
== DD_OK
|| broken(hr
== E_NOTIMPL
),
183 "IDirectDrawSurface7_UpdateOverlay failed with hr=0x%08x\n", hr
);
185 /* Try to overlay the primary with a non-overlay surface */
186 hr
= IDirectDrawSurface7_UpdateOverlay(offscreen
, NULL
, primary
, NULL
, DDOVER_SHOW
, NULL
);
187 ok(hr
== DDERR_NOTAOVERLAYSURFACE
, "IDirectDrawSurface7_UpdateOverlay failed with hr=0x%08x\n", hr
);
189 IDirectDrawSurface7_Release(offscreen
);
190 IDirectDrawSurface7_Release(overlay
);
193 static void yv12_test(void)
197 IDirectDrawSurface7
*surface
, *dst
;
199 RECT rect
= {13, 17, 14, 18};
200 unsigned int offset
, y
;
202 surface
= create_overlay(256, 256, MAKEFOURCC('Y','V','1','2'));
204 skip("YV12 surfaces not available\n");
208 memset(&desc
, 0, sizeof(desc
));
209 desc
.dwSize
= sizeof(desc
);
210 hr
= IDirectDrawSurface7_Lock(surface
, NULL
, &desc
, 0, NULL
);
211 ok(hr
== DD_OK
, "IDirectDrawSurface7_Lock returned 0x%08x, expected DD_OK\n", hr
);
213 ok(desc
.dwFlags
== (DDSD_WIDTH
| DDSD_HEIGHT
| DDSD_PIXELFORMAT
| DDSD_CAPS
| DDSD_PITCH
),
214 "Unexpected desc.dwFlags 0x%08x\n", desc
.dwFlags
);
215 ok(desc
.ddsCaps
.dwCaps
== (DDSCAPS_OVERLAY
| DDSCAPS_VIDEOMEMORY
| DDSCAPS_LOCALVIDMEM
) ||
216 desc
.ddsCaps
.dwCaps
== (DDSCAPS_OVERLAY
| DDSCAPS_VIDEOMEMORY
| DDSCAPS_LOCALVIDMEM
| DDSCAPS_HWCODEC
),
217 "Unexpected desc.ddsCaps.dwCaps 0x%08x\n", desc
.ddsCaps
.dwCaps
);
218 ok(desc
.dwWidth
== 256 && desc
.dwHeight
== 256, "Expected size 256x256, got %ux%u\n",
219 desc
.dwWidth
, desc
.dwHeight
);
220 /* The overlay pitch seems to have 256 byte alignment */
221 ok((U1(desc
).lPitch
& 0xff) == 0, "Expected 256 byte aligned pitch, got %u\n", U1(desc
).lPitch
);
223 /* Fill the surface with some data for the blit test */
224 base
= desc
.lpSurface
;
226 for (y
= 0; y
< desc
.dwHeight
; y
++)
228 memset(base
+ U1(desc
).lPitch
* y
, 0x10, desc
.dwWidth
);
231 for (; y
< desc
.dwHeight
+ desc
.dwHeight
/ 4; y
++)
233 memset(base
+ U1(desc
).lPitch
* y
, 0x20, desc
.dwWidth
);
236 for (; y
< desc
.dwHeight
+ desc
.dwHeight
/ 2; y
++)
238 memset(base
+ U1(desc
).lPitch
* y
, 0x30, desc
.dwWidth
);
241 hr
= IDirectDrawSurface7_Unlock(surface
, NULL
);
242 ok(hr
== DD_OK
, "IDirectDrawSurface7_Unlock returned 0x%08x, expected DD_OK\n", hr
);
244 /* YV12 uses 2x2 blocks with 6 bytes per block(4*Y, 1*U, 1*V). Unlike other block-based formats like DXT
245 * the entire Y channel is stored in one big chunk of memory, followed by the chroma channels. So
246 * partial locks do not really make sense. Show that they are allowed nevertheless and the offset points
247 * into the luminance data */
248 hr
= IDirectDrawSurface7_Lock(surface
, &rect
, &desc
, 0, NULL
);
249 ok(hr
== DD_OK
, "Partial lock of a YV12 surface returned 0x%08x, expected DD_OK\n", hr
);
250 offset
= ((const char *) desc
.lpSurface
- base
);
251 ok(offset
== rect
.top
* U1(desc
).lPitch
+ rect
.left
, "Expected %u byte offset from partial lock, got %u\n",
252 rect
.top
* U1(desc
).lPitch
+ rect
.left
, offset
);
253 hr
= IDirectDrawSurface7_Unlock(surface
, NULL
);
254 ok(hr
== DD_OK
, "IDirectDrawSurface7_Unlock returned 0x%08x, expected DD_OK\n", hr
);
256 dst
= create_overlay(256, 256, MAKEFOURCC('Y','V','1','2'));
259 /* Windows XP with a Radeon X1600 GPU refuses to create a second overlay surface,
260 * DDERR_NOOVERLAYHW, making the blit tests moot */
261 skip("Could not create a second YV12 surface, skipping blit test\n");
265 hr
= IDirectDrawSurface7_Blt(dst
, NULL
, surface
, NULL
, 0, NULL
);
266 /* VMware rejects YV12 blits. This behavior has not been seen on real hardware yet, so mark it broken */
267 ok(hr
== DD_OK
|| broken(hr
== E_NOTIMPL
),
268 "IDirectDrawSurface7_Blt returned 0x%08x, expected DD_OK\n", hr
);
272 memset(&desc
, 0, sizeof(desc
));
273 desc
.dwSize
= sizeof(desc
);
274 hr
= IDirectDrawSurface7_Lock(dst
, NULL
, &desc
, 0, NULL
);
275 ok(hr
== DD_OK
, "IDirectDrawSurface7_Lock returned 0x%08x, expected DD_OK\n", hr
);
277 base
= desc
.lpSurface
;
278 ok(base
[0] == 0x10, "Y data is 0x%02x, expected 0x10\n", base
[0]);
279 base
+= desc
.dwHeight
* U1(desc
).lPitch
;
280 todo_wine
ok(base
[0] == 0x20, "V data is 0x%02x, expected 0x20\n", base
[0]);
281 base
+= desc
.dwHeight
/ 4 * U1(desc
).lPitch
;
282 todo_wine
ok(base
[0] == 0x30, "U data is 0x%02x, expected 0x30\n", base
[0]);
284 hr
= IDirectDrawSurface7_Unlock(dst
, NULL
);
285 ok(hr
== DD_OK
, "IDirectDrawSurface7_Unlock returned 0x%08x, expected DD_OK\n", hr
);
288 IDirectDrawSurface7_Release(dst
);
290 IDirectDrawSurface7_Release(surface
);
295 if(CreateDirectDraw() == FALSE
) {
296 skip("Failed to initialize ddraw\n");
300 rectangle_settings();
304 if(primary
) IDirectDrawSurface7_Release(primary
);
305 if(ddraw
) IDirectDraw7_Release(ddraw
);