ddraw/tests: Test d3d2 and 3 drawing with non-standard viewports.
[wine.git] / dlls / ddraw / tests / ddraw2.c
blob65376b3a2c854eac0323b9cb43168d04c7242af1
1 /*
2 * Copyright 2005 Antoine Chavasse (a.chavasse@gmail.com)
3 * Copyright 2008, 2011, 2012-2014 Stefan Dösinger for CodeWeavers
4 * Copyright 2011-2014 Henri Verbeet 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
21 #include <math.h>
23 #define COBJMACROS
24 #include "wine/test.h"
25 #include <limits.h>
26 #include "d3d.h"
28 static BOOL is_ddraw64 = sizeof(DWORD) != sizeof(DWORD *);
29 static DEVMODEW registry_mode;
31 static HRESULT (WINAPI *pDwmIsCompositionEnabled)(BOOL *);
33 #ifndef ARRAY_SIZE
34 #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
35 #endif
37 struct vec4
39 float x, y, z, w;
42 struct create_window_thread_param
44 HWND window;
45 HANDLE window_created;
46 HANDLE destroy_window;
47 HANDLE thread;
50 static BOOL compare_color(D3DCOLOR c1, D3DCOLOR c2, BYTE max_diff)
52 if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
53 c1 >>= 8; c2 >>= 8;
54 if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
55 c1 >>= 8; c2 >>= 8;
56 if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
57 c1 >>= 8; c2 >>= 8;
58 if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
59 return TRUE;
62 static BOOL compare_float(float f, float g, unsigned int ulps)
64 int x = *(int *)&f;
65 int y = *(int *)&g;
67 if (x < 0)
68 x = INT_MIN - x;
69 if (y < 0)
70 y = INT_MIN - y;
72 if (abs(x - y) > ulps)
73 return FALSE;
75 return TRUE;
78 static BOOL compare_vec4(const struct vec4 *vec, float x, float y, float z, float w, unsigned int ulps)
80 return compare_float(vec->x, x, ulps)
81 && compare_float(vec->y, y, ulps)
82 && compare_float(vec->z, z, ulps)
83 && compare_float(vec->w, w, ulps);
86 static IDirectDrawSurface *create_overlay(IDirectDraw2 *ddraw,
87 unsigned int width, unsigned int height, DWORD format)
89 IDirectDrawSurface *surface;
90 DDSURFACEDESC desc;
92 memset(&desc, 0, sizeof(desc));
93 desc.dwSize = sizeof(desc);
94 desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
95 desc.dwWidth = width;
96 desc.dwHeight = height;
97 desc.ddsCaps.dwCaps = DDSCAPS_OVERLAY;
98 desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
99 desc.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
100 desc.ddpfPixelFormat.dwFourCC = format;
102 if (FAILED(IDirectDraw2_CreateSurface(ddraw, &desc, &surface, NULL)))
103 return NULL;
104 return surface;
107 static DWORD WINAPI create_window_thread_proc(void *param)
109 struct create_window_thread_param *p = param;
110 DWORD res;
111 BOOL ret;
113 p->window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
114 0, 0, 640, 480, 0, 0, 0, 0);
115 ret = SetEvent(p->window_created);
116 ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
118 for (;;)
120 MSG msg;
122 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
123 DispatchMessageA(&msg);
124 res = WaitForSingleObject(p->destroy_window, 100);
125 if (res == WAIT_OBJECT_0)
126 break;
127 if (res != WAIT_TIMEOUT)
129 ok(0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
130 break;
134 DestroyWindow(p->window);
136 return 0;
139 static void create_window_thread(struct create_window_thread_param *p)
141 DWORD res, tid;
143 p->window_created = CreateEventA(NULL, FALSE, FALSE, NULL);
144 ok(!!p->window_created, "CreateEvent failed, last error %#x.\n", GetLastError());
145 p->destroy_window = CreateEventA(NULL, FALSE, FALSE, NULL);
146 ok(!!p->destroy_window, "CreateEvent failed, last error %#x.\n", GetLastError());
147 p->thread = CreateThread(NULL, 0, create_window_thread_proc, p, 0, &tid);
148 ok(!!p->thread, "Failed to create thread, last error %#x.\n", GetLastError());
149 res = WaitForSingleObject(p->window_created, INFINITE);
150 ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
153 static void destroy_window_thread(struct create_window_thread_param *p)
155 SetEvent(p->destroy_window);
156 WaitForSingleObject(p->thread, INFINITE);
157 CloseHandle(p->destroy_window);
158 CloseHandle(p->window_created);
159 CloseHandle(p->thread);
162 static IDirectDrawSurface *get_depth_stencil(IDirect3DDevice2 *device)
164 IDirectDrawSurface *rt, *ret;
165 DDSCAPS caps = {DDSCAPS_ZBUFFER};
166 HRESULT hr;
168 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
169 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
170 hr = IDirectDrawSurface_GetAttachedSurface(rt, &caps, &ret);
171 ok(SUCCEEDED(hr) || hr == DDERR_NOTFOUND, "Failed to get the z buffer, hr %#x.\n", hr);
172 IDirectDrawSurface_Release(rt);
173 return ret;
176 static HRESULT set_display_mode(IDirectDraw2 *ddraw, DWORD width, DWORD height)
178 if (SUCCEEDED(IDirectDraw2_SetDisplayMode(ddraw, width, height, 32, 0, 0)))
179 return DD_OK;
180 return IDirectDraw2_SetDisplayMode(ddraw, width, height, 24, 0, 0);
183 static D3DCOLOR get_surface_color(IDirectDrawSurface *surface, UINT x, UINT y)
185 RECT rect = {x, y, x + 1, y + 1};
186 DDSURFACEDESC surface_desc;
187 D3DCOLOR color;
188 HRESULT hr;
190 memset(&surface_desc, 0, sizeof(surface_desc));
191 surface_desc.dwSize = sizeof(surface_desc);
193 hr = IDirectDrawSurface_Lock(surface, &rect, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
194 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
195 if (FAILED(hr))
196 return 0xdeadbeef;
198 color = *((DWORD *)surface_desc.lpSurface) & 0x00ffffff;
200 hr = IDirectDrawSurface_Unlock(surface, NULL);
201 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
203 return color;
206 static DWORD get_device_z_depth(IDirect3DDevice2 *device)
208 DDSCAPS caps = {DDSCAPS_ZBUFFER};
209 IDirectDrawSurface *ds, *rt;
210 DDSURFACEDESC desc;
211 HRESULT hr;
213 if (FAILED(IDirect3DDevice2_GetRenderTarget(device, &rt)))
214 return 0;
216 hr = IDirectDrawSurface_GetAttachedSurface(rt, &caps, &ds);
217 IDirectDrawSurface_Release(rt);
218 if (FAILED(hr))
219 return 0;
221 desc.dwSize = sizeof(desc);
222 hr = IDirectDrawSurface_GetSurfaceDesc(ds, &desc);
223 IDirectDrawSurface_Release(ds);
224 if (FAILED(hr))
225 return 0;
227 return U2(desc).dwZBufferBitDepth;
230 static IDirectDraw2 *create_ddraw(void)
232 IDirectDraw2 *ddraw2;
233 IDirectDraw *ddraw1;
234 HRESULT hr;
236 if (FAILED(DirectDrawCreate(NULL, &ddraw1, NULL)))
237 return NULL;
239 hr = IDirectDraw_QueryInterface(ddraw1, &IID_IDirectDraw2, (void **)&ddraw2);
240 IDirectDraw_Release(ddraw1);
241 if (FAILED(hr))
242 return NULL;
244 return ddraw2;
247 static IDirect3DDevice2 *create_device(IDirectDraw2 *ddraw, HWND window, DWORD coop_level)
249 static const DWORD z_depths[] = {32, 24, 16};
250 IDirectDrawSurface *surface, *ds;
251 IDirect3DDevice2 *device = NULL;
252 DDSURFACEDESC surface_desc;
253 IDirect3D2 *d3d;
254 unsigned int i;
255 HRESULT hr;
257 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, coop_level);
258 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
260 memset(&surface_desc, 0, sizeof(surface_desc));
261 surface_desc.dwSize = sizeof(surface_desc);
262 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
263 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
264 surface_desc.dwWidth = 640;
265 surface_desc.dwHeight = 480;
267 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
268 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
270 if (coop_level & DDSCL_NORMAL)
272 IDirectDrawClipper *clipper;
274 hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL);
275 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
276 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
277 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
278 hr = IDirectDrawSurface_SetClipper(surface, clipper);
279 ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#x.\n", hr);
280 IDirectDrawClipper_Release(clipper);
283 hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
284 if (FAILED(hr))
286 IDirectDrawSurface_Release(surface);
287 return NULL;
290 /* We used to use EnumDevices() for this, but it seems
291 * D3DDEVICEDESC.dwDeviceZBufferBitDepth only has a very casual
292 * relationship with reality. */
293 for (i = 0; i < sizeof(z_depths) / sizeof(*z_depths); ++i)
295 memset(&surface_desc, 0, sizeof(surface_desc));
296 surface_desc.dwSize = sizeof(surface_desc);
297 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
298 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
299 U2(surface_desc).dwZBufferBitDepth = z_depths[i];
300 surface_desc.dwWidth = 640;
301 surface_desc.dwHeight = 480;
302 if (FAILED(IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL)))
303 continue;
305 hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
306 ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
307 IDirectDrawSurface_Release(ds);
308 if (FAILED(hr))
309 continue;
311 if (SUCCEEDED(IDirect3D2_CreateDevice(d3d, &IID_IDirect3DHALDevice, surface, &device)))
312 break;
314 IDirectDrawSurface_DeleteAttachedSurface(surface, 0, ds);
317 IDirect3D2_Release(d3d);
318 IDirectDrawSurface_Release(surface);
319 return device;
322 static IDirect3DViewport2 *create_viewport(IDirect3DDevice2 *device, UINT x, UINT y, UINT w, UINT h)
324 IDirect3DViewport2 *viewport;
325 D3DVIEWPORT2 vp;
326 IDirect3D2 *d3d;
327 HRESULT hr;
329 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
330 ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
331 hr = IDirect3D2_CreateViewport(d3d, &viewport, NULL);
332 ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
333 hr = IDirect3DDevice2_AddViewport(device, viewport);
334 ok(SUCCEEDED(hr), "Failed to add viewport, hr %#x.\n", hr);
335 memset(&vp, 0, sizeof(vp));
336 vp.dwSize = sizeof(vp);
337 vp.dwX = x;
338 vp.dwY = y;
339 vp.dwWidth = w;
340 vp.dwHeight = h;
341 vp.dvClipX = -1.0f;
342 vp.dvClipY = 1.0f;
343 vp.dvClipWidth = 2.0f;
344 vp.dvClipHeight = 2.0f;
345 vp.dvMinZ = 0.0f;
346 vp.dvMaxZ = 1.0f;
347 hr = IDirect3DViewport2_SetViewport2(viewport, &vp);
348 ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#x.\n", hr);
349 IDirect3D2_Release(d3d);
351 return viewport;
354 static void viewport_set_background(IDirect3DDevice2 *device, IDirect3DViewport2 *viewport,
355 IDirect3DMaterial2 *material)
357 D3DMATERIALHANDLE material_handle;
358 HRESULT hr;
360 hr = IDirect3DMaterial2_GetHandle(material, device, &material_handle);
361 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
362 hr = IDirect3DViewport2_SetBackground(viewport, material_handle);
363 ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#x.\n", hr);
366 static void destroy_viewport(IDirect3DDevice2 *device, IDirect3DViewport2 *viewport)
368 HRESULT hr;
370 hr = IDirect3DDevice2_DeleteViewport(device, viewport);
371 ok(SUCCEEDED(hr), "Failed to delete viewport, hr %#x.\n", hr);
372 IDirect3DViewport2_Release(viewport);
375 static IDirect3DMaterial2 *create_material(IDirect3DDevice2 *device, D3DMATERIAL *mat)
377 IDirect3DMaterial2 *material;
378 IDirect3D2 *d3d;
379 HRESULT hr;
381 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
382 ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
383 hr = IDirect3D2_CreateMaterial(d3d, &material, NULL);
384 ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
385 hr = IDirect3DMaterial2_SetMaterial(material, mat);
386 ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
387 IDirect3D2_Release(d3d);
389 return material;
392 static IDirect3DMaterial2 *create_diffuse_material(IDirect3DDevice2 *device, float r, float g, float b, float a)
394 D3DMATERIAL mat;
396 memset(&mat, 0, sizeof(mat));
397 mat.dwSize = sizeof(mat);
398 U1(U(mat).diffuse).r = r;
399 U2(U(mat).diffuse).g = g;
400 U3(U(mat).diffuse).b = b;
401 U4(U(mat).diffuse).a = a;
403 return create_material(device, &mat);
406 static IDirect3DMaterial2 *create_specular_material(IDirect3DDevice2 *device,
407 float r, float g, float b, float a, float power)
409 D3DMATERIAL mat;
411 memset(&mat, 0, sizeof(mat));
412 mat.dwSize = sizeof(mat);
413 U1(U2(mat).specular).r = r;
414 U2(U2(mat).specular).g = g;
415 U3(U2(mat).specular).b = b;
416 U4(U2(mat).specular).a = a;
417 U4(mat).power = power;
419 return create_material(device, &mat);
422 static IDirect3DMaterial2 *create_emissive_material(IDirect3DDevice2 *device, float r, float g, float b, float a)
424 D3DMATERIAL mat;
426 memset(&mat, 0, sizeof(mat));
427 mat.dwSize = sizeof(mat);
428 U1(U3(mat).emissive).r = r;
429 U2(U3(mat).emissive).g = g;
430 U3(U3(mat).emissive).b = b;
431 U4(U3(mat).emissive).a = a;
433 return create_material(device, &mat);
436 static void destroy_material(IDirect3DMaterial2 *material)
438 IDirect3DMaterial2_Release(material);
441 struct message
443 UINT message;
444 BOOL check_wparam;
445 WPARAM expect_wparam;
448 static const struct message *expect_messages;
450 static LRESULT CALLBACK test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
452 if (expect_messages && message == expect_messages->message)
454 if (expect_messages->check_wparam)
455 ok (wparam == expect_messages->expect_wparam,
456 "Got unexpected wparam %lx for message %x, expected %lx.\n",
457 wparam, message, expect_messages->expect_wparam);
459 ++expect_messages;
462 return DefWindowProcA(hwnd, message, wparam, lparam);
465 /* Set the wndproc back to what ddraw expects it to be, and release the ddraw
466 * interface. This prevents subsequent SetCooperativeLevel() calls on a
467 * different window from failing with DDERR_HWNDALREADYSET. */
468 static void fix_wndproc(HWND window, LONG_PTR proc)
470 IDirectDraw2 *ddraw;
471 HRESULT hr;
473 if (!(ddraw = create_ddraw()))
474 return;
476 SetWindowLongPtrA(window, GWLP_WNDPROC, proc);
477 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
478 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
479 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
480 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
482 IDirectDraw2_Release(ddraw);
485 static HRESULT CALLBACK restore_callback(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
487 HRESULT hr = IDirectDrawSurface_Restore(surface);
488 ok(SUCCEEDED(hr) || hr == DDERR_IMPLICITLYCREATED, "Failed to restore surface, hr %#x.\n", hr);
489 IDirectDrawSurface_Release(surface);
491 return DDENUMRET_OK;
494 static HRESULT restore_surfaces(IDirectDraw2 *ddraw)
496 return IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_ALL | DDENUMSURFACES_DOESEXIST,
497 NULL, NULL, restore_callback);
500 static void test_coop_level_create_device_window(void)
502 HWND focus_window, device_window;
503 IDirectDraw2 *ddraw;
504 HRESULT hr;
506 focus_window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
507 0, 0, 640, 480, 0, 0, 0, 0);
508 ddraw = create_ddraw();
509 ok(!!ddraw, "Failed to create a ddraw object.\n");
511 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
512 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
513 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
514 ok(!device_window, "Unexpected device window found.\n");
515 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW);
516 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
517 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
518 ok(!device_window, "Unexpected device window found.\n");
519 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL);
520 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
521 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
522 ok(!device_window, "Unexpected device window found.\n");
523 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL | DDSCL_FULLSCREEN);
524 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
525 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
526 ok(!device_window, "Unexpected device window found.\n");
527 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
528 ok(hr == DDERR_NOFOCUSWINDOW || broken(hr == DDERR_INVALIDPARAMS), "Got unexpected hr %#x.\n", hr);
529 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
530 ok(!device_window, "Unexpected device window found.\n");
532 /* Windows versions before 98 / NT5 don't support DDSCL_CREATEDEVICEWINDOW. */
533 if (broken(hr == DDERR_INVALIDPARAMS))
535 win_skip("DDSCL_CREATEDEVICEWINDOW not supported, skipping test.\n");
536 IDirectDraw2_Release(ddraw);
537 DestroyWindow(focus_window);
538 return;
541 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
542 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
543 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
544 ok(!device_window, "Unexpected device window found.\n");
545 hr = IDirectDraw2_SetCooperativeLevel(ddraw, focus_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
546 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
547 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
548 ok(!device_window, "Unexpected device window found.\n");
550 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
551 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
552 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
553 ok(!device_window, "Unexpected device window found.\n");
554 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_SETFOCUSWINDOW
555 | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
556 ok(hr == DDERR_NOHWND, "Got unexpected hr %#x.\n", hr);
557 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
558 ok(!!device_window, "Device window not found.\n");
560 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
561 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
562 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
563 ok(!device_window, "Unexpected device window found.\n");
564 hr = IDirectDraw2_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW
565 | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
566 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
567 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
568 ok(!!device_window, "Device window not found.\n");
570 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
571 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
572 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
573 ok(!device_window, "Unexpected device window found.\n");
574 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
575 ok(hr == DDERR_NOFOCUSWINDOW, "Got unexpected hr %#x.\n", hr);
576 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
577 ok(!device_window, "Unexpected device window found.\n");
578 hr = IDirectDraw2_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW);
579 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
580 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
581 ok(!device_window, "Unexpected device window found.\n");
582 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
583 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
584 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
585 ok(!!device_window, "Device window not found.\n");
587 IDirectDraw2_Release(ddraw);
588 DestroyWindow(focus_window);
591 static void test_clipper_blt(void)
593 IDirectDrawSurface *src_surface, *dst_surface;
594 RECT client_rect, src_rect;
595 IDirectDrawClipper *clipper;
596 DDSURFACEDESC surface_desc;
597 unsigned int i, j, x, y;
598 IDirectDraw2 *ddraw;
599 RGNDATA *rgn_data;
600 D3DCOLOR color;
601 ULONG refcount;
602 HRGN r1, r2;
603 HWND window;
604 DDBLTFX fx;
605 HRESULT hr;
606 DWORD *ptr;
607 DWORD ret;
609 static const DWORD src_data[] =
611 0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
612 0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
613 0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
615 static const D3DCOLOR expected1[] =
617 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
618 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
619 0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
620 0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
622 /* Nvidia on Windows seems to have an off-by-one error
623 * when processing source rectangles. Our left = 1 and
624 * right = 5 input reads from x = {1, 2, 3}. x = 4 is
625 * read as well, but only for the edge pixels on the
626 * output image. The bug happens on the y axis as well,
627 * but we only read one row there, and all source rows
628 * contain the same data. This bug is not dependent on
629 * the presence of a clipper. */
630 static const D3DCOLOR expected1_broken[] =
632 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
633 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
634 0x00000000, 0x00000000, 0x00ff0000, 0x00ff0000,
635 0x00000000, 0x00000000, 0x0000ff00, 0x00ff0000,
637 static const D3DCOLOR expected2[] =
639 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
640 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
641 0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
642 0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
645 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
646 10, 10, 640, 480, 0, 0, 0, 0);
647 ShowWindow(window, SW_SHOW);
648 ddraw = create_ddraw();
649 ok(!!ddraw, "Failed to create a ddraw object.\n");
651 ret = GetClientRect(window, &client_rect);
652 ok(ret, "Failed to get client rect.\n");
653 ret = MapWindowPoints(window, NULL, (POINT *)&client_rect, 2);
654 ok(ret, "Failed to map client rect.\n");
656 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
657 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
659 hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL);
660 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
661 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
662 ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
663 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
664 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
665 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
666 ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
667 rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
668 hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret);
669 ok(SUCCEEDED(hr), "Failed to get clip list, hr %#x.\n", hr);
670 ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#x.\n", rgn_data->rdh.dwSize);
671 ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#x.\n", rgn_data->rdh.iType);
672 ok(rgn_data->rdh.nCount >= 1, "Got unexpected count %u.\n", rgn_data->rdh.nCount);
673 ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
674 "Got unexpected bounding rect %s, expected %s.\n",
675 wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&client_rect));
676 HeapFree(GetProcessHeap(), 0, rgn_data);
678 r1 = CreateRectRgn(0, 0, 320, 240);
679 ok(!!r1, "Failed to create region.\n");
680 r2 = CreateRectRgn(320, 240, 640, 480);
681 ok(!!r2, "Failed to create region.\n");
682 CombineRgn(r1, r1, r2, RGN_OR);
683 ret = GetRegionData(r1, 0, NULL);
684 rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
685 ret = GetRegionData(r1, ret, rgn_data);
686 ok(!!ret, "Failed to get region data.\n");
688 DeleteObject(r2);
689 DeleteObject(r1);
691 hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
692 ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#x.\n", hr);
693 hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
694 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
695 hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
696 ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
698 HeapFree(GetProcessHeap(), 0, rgn_data);
700 memset(&surface_desc, 0, sizeof(surface_desc));
701 surface_desc.dwSize = sizeof(surface_desc);
702 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
703 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
704 surface_desc.dwWidth = 640;
705 surface_desc.dwHeight = 480;
706 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
707 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
708 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
709 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
710 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
711 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
713 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
714 ok(SUCCEEDED(hr), "Failed to create source surface, hr %#x.\n", hr);
715 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
716 ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
718 memset(&fx, 0, sizeof(fx));
719 fx.dwSize = sizeof(fx);
720 hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
721 ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#x.\n", hr);
722 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
723 ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
725 hr = IDirectDrawSurface_Lock(src_surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
726 ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#x.\n", hr);
727 ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %u.\n", U1(surface_desc).lPitch);
728 ptr = surface_desc.lpSurface;
729 memcpy(&ptr[ 0], &src_data[ 0], 6 * sizeof(DWORD));
730 memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
731 memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
732 hr = IDirectDrawSurface_Unlock(src_surface, NULL);
733 ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#x.\n", hr);
735 hr = IDirectDrawSurface_SetClipper(dst_surface, clipper);
736 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#x.\n", hr);
738 SetRect(&src_rect, 1, 1, 5, 2);
739 hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
740 ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
741 for (i = 0; i < 4; ++i)
743 for (j = 0; j < 4; ++j)
745 x = 80 * ((2 * j) + 1);
746 y = 60 * ((2 * i) + 1);
747 color = get_surface_color(dst_surface, x, y);
748 ok(compare_color(color, expected1[i * 4 + j], 1)
749 || broken(compare_color(color, expected1_broken[i * 4 + j], 1)),
750 "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
754 U5(fx).dwFillColor = 0xff0000ff;
755 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
756 ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
757 for (i = 0; i < 4; ++i)
759 for (j = 0; j < 4; ++j)
761 x = 80 * ((2 * j) + 1);
762 y = 60 * ((2 * i) + 1);
763 color = get_surface_color(dst_surface, x, y);
764 ok(compare_color(color, expected2[i * 4 + j], 1),
765 "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
769 hr = IDirectDrawSurface_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
770 ok(hr == DDERR_BLTFASTCANTCLIP || broken(hr == E_NOTIMPL /* NT4 */), "Got unexpected hr %#x.\n", hr);
772 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
773 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
774 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
775 ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
776 DestroyWindow(window);
777 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
778 ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
779 hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
780 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
781 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
782 ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
783 hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
784 ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
785 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
786 ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
787 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
788 ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
790 IDirectDrawSurface_Release(dst_surface);
791 IDirectDrawSurface_Release(src_surface);
792 refcount = IDirectDrawClipper_Release(clipper);
793 ok(!refcount, "Clipper has %u references left.\n", refcount);
794 IDirectDraw2_Release(ddraw);
797 static void test_coop_level_d3d_state(void)
799 D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
800 IDirectDrawSurface *rt, *surface;
801 IDirect3DMaterial2 *background;
802 IDirect3DViewport2 *viewport;
803 IDirect3DDevice2 *device;
804 D3DMATERIAL material;
805 IDirectDraw2 *ddraw;
806 D3DCOLOR color;
807 DWORD value;
808 HWND window;
809 HRESULT hr;
811 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
812 0, 0, 640, 480, 0, 0, 0, 0);
813 ddraw = create_ddraw();
814 ok(!!ddraw, "Failed to create a ddraw object.\n");
815 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
817 skip("Failed to create a 3D device, skipping test.\n");
818 IDirectDraw2_Release(ddraw);
819 DestroyWindow(window);
820 return;
823 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
824 viewport = create_viewport(device, 0, 0, 640, 480);
825 viewport_set_background(device, viewport, background);
827 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
828 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
829 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
830 ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
831 ok(!!value, "Got unexpected z-enable state %#x.\n", value);
832 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
833 ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
834 ok(!value, "Got unexpected alpha blend enable state %#x.\n", value);
835 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
836 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
837 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
838 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
839 color = get_surface_color(rt, 320, 240);
840 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
842 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
843 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
844 hr = IDirectDrawSurface_IsLost(rt);
845 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
846 hr = restore_surfaces(ddraw);
847 ok(SUCCEEDED(hr), "Failed to restore surfaces, hr %#x.\n", hr);
849 memset(&material, 0, sizeof(material));
850 material.dwSize = sizeof(material);
851 U1(U(material).diffuse).r = 0.0f;
852 U2(U(material).diffuse).g = 1.0f;
853 U3(U(material).diffuse).b = 0.0f;
854 U4(U(material).diffuse).a = 1.0f;
855 hr = IDirect3DMaterial2_SetMaterial(background, &material);
856 ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
858 hr = IDirect3DDevice2_GetRenderTarget(device, &surface);
859 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
860 ok(surface == rt, "Got unexpected surface %p.\n", surface);
861 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
862 ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
863 ok(!!value, "Got unexpected z-enable state %#x.\n", value);
864 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
865 ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
866 ok(!!value, "Got unexpected alpha blend enable state %#x.\n", value);
867 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
868 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
869 color = get_surface_color(rt, 320, 240);
870 ok(compare_color(color, 0x0000ff00, 1) || broken(compare_color(color, 0x00000000, 1)),
871 "Got unexpected color 0x%08x.\n", color);
873 destroy_viewport(device, viewport);
874 destroy_material(background);
875 IDirectDrawSurface_Release(surface);
876 IDirectDrawSurface_Release(rt);
877 IDirect3DDevice2_Release(device);
878 IDirectDraw2_Release(ddraw);
879 DestroyWindow(window);
882 static void test_surface_interface_mismatch(void)
884 IDirectDraw2 *ddraw = NULL;
885 IDirect3D2 *d3d = NULL;
886 IDirectDrawSurface *surface = NULL, *ds;
887 IDirectDrawSurface3 *surface3 = NULL;
888 IDirect3DDevice2 *device = NULL;
889 IDirect3DViewport2 *viewport = NULL;
890 IDirect3DMaterial2 *background = NULL;
891 DDSURFACEDESC surface_desc;
892 DWORD z_depth = 0;
893 ULONG refcount;
894 HRESULT hr;
895 D3DCOLOR color;
896 HWND window;
897 D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
899 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
900 0, 0, 640, 480, 0, 0, 0, 0);
901 ddraw = create_ddraw();
902 ok(!!ddraw, "Failed to create a ddraw object.\n");
903 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
905 skip("Failed to create a 3D device, skipping test.\n");
906 IDirectDraw2_Release(ddraw);
907 DestroyWindow(window);
908 return;
910 z_depth = get_device_z_depth(device);
911 ok(!!z_depth, "Failed to get device z depth.\n");
912 IDirect3DDevice2_Release(device);
913 device = NULL;
915 memset(&surface_desc, 0, sizeof(surface_desc));
916 surface_desc.dwSize = sizeof(surface_desc);
917 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
918 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
919 surface_desc.dwWidth = 640;
920 surface_desc.dwHeight = 480;
922 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
923 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
925 hr = IDirectDrawSurface2_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
926 if (FAILED(hr))
928 skip("Failed to get the IDirectDrawSurface3 interface, skipping test.\n");
929 goto cleanup;
932 if (FAILED(IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d)))
934 skip("D3D interface is not available, skipping test.\n");
935 goto cleanup;
938 memset(&surface_desc, 0, sizeof(surface_desc));
939 surface_desc.dwSize = sizeof(surface_desc);
940 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
941 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
942 U2(surface_desc).dwZBufferBitDepth = z_depth;
943 surface_desc.dwWidth = 640;
944 surface_desc.dwHeight = 480;
945 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL);
946 ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
947 if (FAILED(hr))
948 goto cleanup;
950 /* Using a different surface interface version still works */
951 hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
952 ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
953 refcount = IDirectDrawSurface_Release(ds);
954 ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
955 if (FAILED(hr))
956 goto cleanup;
958 /* Here too */
959 hr = IDirect3D2_CreateDevice(d3d, &IID_IDirect3DHALDevice, (IDirectDrawSurface *)surface3, &device);
960 ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
961 if (FAILED(hr))
962 goto cleanup;
964 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
965 viewport = create_viewport(device, 0, 0, 640, 480);
966 viewport_set_background(device, viewport, background);
968 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
969 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
970 color = get_surface_color(surface, 320, 240);
971 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
973 cleanup:
974 if (viewport)
975 destroy_viewport(device, viewport);
976 if (background)
977 destroy_material(background);
978 if (surface3) IDirectDrawSurface3_Release(surface3);
979 if (surface) IDirectDrawSurface_Release(surface);
980 if (device) IDirect3DDevice2_Release(device);
981 if (d3d) IDirect3D2_Release(d3d);
982 if (ddraw) IDirectDraw2_Release(ddraw);
983 DestroyWindow(window);
986 static void test_coop_level_threaded(void)
988 struct create_window_thread_param p;
989 IDirectDraw2 *ddraw;
990 HRESULT hr;
992 ddraw = create_ddraw();
993 ok(!!ddraw, "Failed to create a ddraw object.\n");
994 create_window_thread(&p);
996 hr = IDirectDraw2_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
997 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
999 IDirectDraw2_Release(ddraw);
1000 destroy_window_thread(&p);
1003 static void test_depth_blit(void)
1005 static D3DLVERTEX quad1[] =
1007 {{-1.0}, { 1.0}, {0.50f}, 0, {0xff00ff00}},
1008 {{ 1.0}, { 1.0}, {0.50f}, 0, {0xff00ff00}},
1009 {{-1.0}, {-1.0}, {0.50f}, 0, {0xff00ff00}},
1010 {{ 1.0}, {-1.0}, {0.50f}, 0, {0xff00ff00}},
1012 static const D3DCOLOR expected_colors[4][4] =
1014 {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
1015 {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
1016 {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1017 {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1019 DDSURFACEDESC ddsd_new, ddsd_existing;
1021 IDirect3DDevice2 *device;
1022 IDirectDrawSurface *ds1, *ds2, *ds3, *rt;
1023 IDirect3DViewport2 *viewport;
1024 RECT src_rect, dst_rect;
1025 unsigned int i, j;
1026 D3DCOLOR color;
1027 HRESULT hr;
1028 IDirectDraw2 *ddraw;
1029 DDBLTFX fx;
1030 HWND window;
1031 D3DRECT d3drect;
1032 IDirect3DMaterial2 *background;
1034 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1035 0, 0, 640, 480, 0, 0, 0, 0);
1036 ddraw = create_ddraw();
1037 ok(!!ddraw, "Failed to create a ddraw object.\n");
1038 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1040 skip("Failed to create a 3D device, skipping test.\n");
1041 IDirectDraw2_Release(ddraw);
1042 DestroyWindow(window);
1043 return;
1046 ds1 = get_depth_stencil(device);
1048 memset(&ddsd_new, 0, sizeof(ddsd_new));
1049 ddsd_new.dwSize = sizeof(ddsd_new);
1050 memset(&ddsd_existing, 0, sizeof(ddsd_existing));
1051 ddsd_existing.dwSize = sizeof(ddsd_existing);
1052 hr = IDirectDrawSurface_GetSurfaceDesc(ds1, &ddsd_existing);
1053 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
1054 ddsd_new.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
1055 ddsd_new.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
1056 ddsd_new.dwWidth = ddsd_existing.dwWidth;
1057 ddsd_new.dwHeight = ddsd_existing.dwHeight;
1058 ddsd_new.ddpfPixelFormat = ddsd_existing.ddpfPixelFormat;
1059 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd_new, &ds2, NULL);
1060 ok(SUCCEEDED(hr), "Failed to create a surface, hr %#x.\n", hr);
1061 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd_new, &ds3, NULL);
1062 ok(SUCCEEDED(hr), "Failed to create a surface, hr %#x.\n", hr);
1064 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1065 viewport = create_viewport(device, 0, 0, ddsd_existing.dwWidth, ddsd_existing.dwHeight);
1066 viewport_set_background(device, viewport, background);
1067 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1068 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
1070 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_TRUE);
1071 ok(SUCCEEDED(hr), "Failed to enable z testing, hr %#x.\n", hr);
1072 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
1073 ok(SUCCEEDED(hr), "Failed to set the z function, hr %#x.\n", hr);
1075 U1(d3drect).x1 = U2(d3drect).y1 = 0;
1076 U3(d3drect).x2 = ddsd_existing.dwWidth; U4(d3drect).y2 = ddsd_existing.dwHeight;
1077 hr = IDirect3DViewport2_Clear(viewport, 1, &d3drect, D3DCLEAR_ZBUFFER);
1078 ok(SUCCEEDED(hr), "Failed to clear the z buffer, hr %#x.\n", hr);
1080 /* Partial blit. */
1081 SetRect(&src_rect, 0, 0, 320, 240);
1082 SetRect(&dst_rect, 0, 0, 320, 240);
1083 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1084 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1085 /* Different locations. */
1086 SetRect(&src_rect, 0, 0, 320, 240);
1087 SetRect(&dst_rect, 320, 240, 640, 480);
1088 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1089 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1090 /* Streched. */
1091 SetRect(&src_rect, 0, 0, 320, 240);
1092 SetRect(&dst_rect, 0, 0, 640, 480);
1093 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1094 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1095 /* Flipped. */
1096 SetRect(&src_rect, 0, 480, 640, 0);
1097 SetRect(&dst_rect, 0, 0, 640, 480);
1098 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1099 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
1100 SetRect(&src_rect, 0, 0, 640, 480);
1101 SetRect(&dst_rect, 0, 480, 640, 0);
1102 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1103 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
1104 /* Full, explicit. */
1105 SetRect(&src_rect, 0, 0, 640, 480);
1106 SetRect(&dst_rect, 0, 0, 640, 480);
1107 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1108 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1109 /* Depth -> color blit: Succeeds on Win7 + Radeon HD 5700, fails on WinXP + Radeon X1600 */
1111 /* Depth blit inside a BeginScene / EndScene pair */
1112 hr = IDirect3DDevice2_BeginScene(device);
1113 ok(SUCCEEDED(hr), "Failed to start a scene, hr %#x.\n", hr);
1114 /* From the current depth stencil */
1115 hr = IDirectDrawSurface_Blt(ds2, NULL, ds1, NULL, DDBLT_WAIT, NULL);
1116 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1117 /* To the current depth stencil */
1118 hr = IDirectDrawSurface_Blt(ds1, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1119 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1120 /* Between unbound surfaces */
1121 hr = IDirectDrawSurface_Blt(ds3, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1122 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1123 hr = IDirect3DDevice2_EndScene(device);
1124 ok(SUCCEEDED(hr), "Failed to end a scene, hr %#x.\n", hr);
1126 /* Avoid changing the depth stencil, it doesn't work properly on Windows.
1127 * Instead use DDBLT_DEPTHFILL to clear the depth stencil. Unfortunately
1128 * drivers disagree on the meaning of dwFillDepth. Only 0 seems to produce
1129 * a reliable result(z = 0.0) */
1130 memset(&fx, 0, sizeof(fx));
1131 fx.dwSize = sizeof(fx);
1132 U5(fx).dwFillDepth = 0;
1133 hr = IDirectDrawSurface_Blt(ds2, NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
1134 ok(SUCCEEDED(hr), "Failed to clear the source z buffer, hr %#x.\n", hr);
1136 /* This clears the Z buffer with 1.0 */
1137 hr = IDirect3DViewport2_Clear(viewport, 1, &d3drect, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET);
1138 ok(SUCCEEDED(hr), "Failed to clear the color and z buffers, hr %#x.\n", hr);
1140 SetRect(&dst_rect, 0, 0, 320, 240);
1141 hr = IDirectDrawSurface_Blt(ds1, &dst_rect, ds2, NULL, DDBLT_WAIT, NULL);
1142 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1143 IDirectDrawSurface_Release(ds3);
1144 IDirectDrawSurface_Release(ds2);
1145 IDirectDrawSurface_Release(ds1);
1147 hr = IDirect3DDevice2_BeginScene(device);
1148 ok(SUCCEEDED(hr), "Failed to start a scene, hr %#x.\n", hr);
1149 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad1, 4, 0);
1150 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1151 hr = IDirect3DDevice2_EndScene(device);
1152 ok(SUCCEEDED(hr), "Failed to end a scene, hr %#x.\n", hr);
1154 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1155 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1156 for (i = 0; i < 4; ++i)
1158 for (j = 0; j < 4; ++j)
1160 unsigned int x = 80 * ((2 * j) + 1);
1161 unsigned int y = 60 * ((2 * i) + 1);
1162 color = get_surface_color(rt, x, y);
1163 ok(compare_color(color, expected_colors[i][j], 1),
1164 "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected_colors[i][j], x, y, color);
1167 IDirectDrawSurface_Release(rt);
1169 destroy_viewport(device, viewport);
1170 destroy_material(background);
1171 IDirect3DDevice2_Release(device);
1172 IDirectDraw2_Release(ddraw);
1173 DestroyWindow(window);
1176 static void test_texture_load_ckey(void)
1178 IDirectDraw2 *ddraw = NULL;
1179 IDirectDrawSurface *src = NULL;
1180 IDirectDrawSurface *dst = NULL;
1181 IDirect3DTexture *src_tex = NULL;
1182 IDirect3DTexture *dst_tex = NULL;
1183 DDSURFACEDESC ddsd;
1184 HRESULT hr;
1185 DDCOLORKEY ckey;
1187 ddraw = create_ddraw();
1188 ok(!!ddraw, "Failed to create a ddraw object.\n");
1189 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
1190 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
1192 memset(&ddsd, 0, sizeof(ddsd));
1193 ddsd.dwSize = sizeof(ddsd);
1194 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1195 ddsd.dwHeight = 128;
1196 ddsd.dwWidth = 128;
1197 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
1198 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &src, NULL);
1199 ok(SUCCEEDED(hr), "Failed to create source texture, hr %#x.\n", hr);
1200 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1201 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &dst, NULL);
1202 ok(SUCCEEDED(hr), "Failed to create destination texture, hr %#x.\n", hr);
1204 hr = IDirectDrawSurface_QueryInterface(src, &IID_IDirect3DTexture, (void **)&src_tex);
1205 ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to get Direct3DTexture interface, hr %#x.\n", hr);
1206 if (FAILED(hr))
1208 /* 64 bit ddraw does not support d3d */
1209 skip("Could not get Direct3DTexture interface, skipping texture::Load color keying tests.\n");
1210 goto done;
1212 hr = IDirectDrawSurface_QueryInterface(dst, &IID_IDirect3DTexture, (void **)&dst_tex);
1213 ok(SUCCEEDED(hr), "Failed to get Direct3DTexture interface, hr %#x.\n", hr);
1215 /* No surface has a color key */
1216 hr = IDirect3DTexture_Load(dst_tex, src_tex);
1217 ok(SUCCEEDED(hr) || broken(hr == DDERR_INVALIDCAPS), "Got unexpected hr %#x.\n", hr);
1218 if (FAILED(hr))
1220 /* Testbot Windows NT VMs */
1221 skip("IDirect3DTexture::Load does not work, skipping color keying tests.\n");
1222 goto done;
1225 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0xdeadbeef;
1226 hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1227 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1228 ok(ckey.dwColorSpaceLowValue == 0xdeadbeef, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1229 ok(ckey.dwColorSpaceHighValue == 0xdeadbeef, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1231 /* Source surface has a color key */
1232 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
1233 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
1234 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1235 hr = IDirect3DTexture_Load(dst_tex, src_tex);
1236 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1237 hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1238 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1239 ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1240 ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1242 /* Both surfaces have a color key: Dest ckey is overwritten */
1243 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x000000ff;
1244 hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1245 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1246 hr = IDirect3DTexture_Load(dst_tex, src_tex);
1247 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1248 hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1249 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1250 ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1251 ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1253 /* Only the destination has a color key: It is not deleted */
1254 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, NULL);
1255 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1256 hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
1257 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1258 hr = IDirect3DTexture_Load(dst_tex, src_tex);
1259 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1260 hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1261 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1262 ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1263 ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1265 done:
1266 if (dst_tex) IDirect3DTexture_Release(dst_tex);
1267 if (src_tex) IDirect3DTexture_Release(src_tex);
1268 if (dst) IDirectDrawSurface_Release(dst);
1269 if (src) IDirectDrawSurface_Release(src);
1270 if (ddraw) IDirectDraw2_Release(ddraw);
1273 static ULONG get_refcount(IUnknown *test_iface)
1275 IUnknown_AddRef(test_iface);
1276 return IUnknown_Release(test_iface);
1279 static void test_viewport(void)
1281 IDirectDraw2 *ddraw;
1282 IDirect3D2 *d3d;
1283 HRESULT hr;
1284 ULONG ref, old_d3d_ref;
1285 IDirect3DViewport *viewport;
1286 IDirect3DViewport2 *viewport2, *another_vp, *test_vp;
1287 IDirect3DViewport3 *viewport3;
1288 IDirectDrawGammaControl *gamma;
1289 IUnknown *unknown;
1290 IDirect3DDevice2 *device;
1291 HWND window;
1293 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1294 0, 0, 640, 480, 0, 0, 0, 0);
1295 ddraw = create_ddraw();
1296 ok(!!ddraw, "Failed to create a ddraw object.\n");
1297 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1299 skip("Failed to create a 3D device, skipping test.\n");
1300 IDirectDraw_Release(ddraw);
1301 DestroyWindow(window);
1302 return;
1305 hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
1306 ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to get d3d interface, hr %#x.\n", hr);
1307 if (FAILED(hr))
1309 skip("D3D interface is not available, skipping test.\n");
1310 IDirectDraw2_Release(ddraw);
1311 return;
1313 old_d3d_ref = get_refcount((IUnknown *)d3d);
1315 hr = IDirect3D2_CreateViewport(d3d, &viewport2, NULL);
1316 ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
1317 ref = get_refcount((IUnknown *)viewport2);
1318 ok(ref == 1, "Initial IDirect3DViewport2 refcount is %u\n", ref);
1319 ref = get_refcount((IUnknown *)d3d);
1320 ok(ref == old_d3d_ref, "IDirect3D2 refcount is %u\n", ref);
1322 gamma = (IDirectDrawGammaControl *)0xdeadbeef;
1323 hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirectDrawGammaControl, (void **)&gamma);
1324 ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
1325 ok(gamma == NULL, "Interface not set to NULL by failed QI call: %p\n", gamma);
1326 if (SUCCEEDED(hr)) IDirectDrawGammaControl_Release(gamma);
1327 /* NULL iid: Segfaults */
1329 hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirect3DViewport, (void **)&viewport);
1330 ok(SUCCEEDED(hr), "Failed to QI IDirect3DViewport, hr %#x.\n", hr);
1331 if (viewport)
1333 ref = get_refcount((IUnknown *)viewport);
1334 ok(ref == 2, "IDirect3DViewport refcount is %u\n", ref);
1335 ref = get_refcount((IUnknown *)viewport2);
1336 ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
1337 IDirect3DViewport_Release(viewport);
1338 viewport = NULL;
1341 hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirect3DViewport3, (void **)&viewport3);
1342 ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to QI IDirect3DViewport3, hr %#x.\n", hr);
1343 if (viewport3)
1345 ref = get_refcount((IUnknown *)viewport2);
1346 ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
1347 ref = get_refcount((IUnknown *)viewport3);
1348 ok(ref == 2, "IDirect3DViewport3 refcount is %u\n", ref);
1349 IDirect3DViewport3_Release(viewport3);
1352 hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IUnknown, (void **)&unknown);
1353 ok(SUCCEEDED(hr), "Failed to QI IUnknown, hr %#x.\n", hr);
1354 if (unknown)
1356 ref = get_refcount((IUnknown *)viewport2);
1357 ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
1358 ref = get_refcount(unknown);
1359 ok(ref == 2, "IUnknown refcount is %u\n", ref);
1360 IUnknown_Release(unknown);
1363 /* AddViewport(NULL): Segfault */
1364 hr = IDirect3DDevice2_DeleteViewport(device, NULL);
1365 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
1366 hr = IDirect3DDevice2_GetCurrentViewport(device, NULL);
1367 ok(hr == D3DERR_NOCURRENTVIEWPORT, "Got unexpected hr %#x.\n", hr);
1369 hr = IDirect3D2_CreateViewport(d3d, &another_vp, NULL);
1370 ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
1372 /* Setting a viewport not in the viewport list fails */
1373 hr = IDirect3DDevice2_SetCurrentViewport(device, another_vp);
1374 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
1376 hr = IDirect3DDevice2_AddViewport(device, viewport2);
1377 ok(SUCCEEDED(hr), "Failed to add viewport to device, hr %#x.\n", hr);
1378 ref = get_refcount((IUnknown *) viewport2);
1379 ok(ref == 2, "viewport2 refcount is %d\n", ref);
1380 hr = IDirect3DDevice2_AddViewport(device, another_vp);
1381 ok(SUCCEEDED(hr), "Failed to add viewport to device, hr %#x.\n", hr);
1382 ref = get_refcount((IUnknown *) another_vp);
1383 ok(ref == 2, "another_vp refcount is %d\n", ref);
1385 test_vp = (IDirect3DViewport2 *) 0xbaadc0de;
1386 hr = IDirect3DDevice2_GetCurrentViewport(device, &test_vp);
1387 ok(hr == D3DERR_NOCURRENTVIEWPORT, "Got unexpected hr %#x.\n", hr);
1388 ok(test_vp == (IDirect3DViewport2 *) 0xbaadc0de, "Got unexpected pointer %p\n", test_vp);
1390 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport2);
1391 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1392 ref = get_refcount((IUnknown *) viewport2);
1393 ok(ref == 3, "viewport2 refcount is %d\n", ref);
1394 ref = get_refcount((IUnknown *) device);
1395 ok(ref == 1, "device refcount is %d\n", ref);
1397 test_vp = NULL;
1398 hr = IDirect3DDevice2_GetCurrentViewport(device, &test_vp);
1399 ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
1400 ok(test_vp == viewport2, "Got unexpected viewport %p\n", test_vp);
1401 ref = get_refcount((IUnknown *) viewport2);
1402 ok(ref == 4, "viewport2 refcount is %d\n", ref);
1403 if(test_vp) IDirect3DViewport2_Release(test_vp);
1405 /* GetCurrentViewport with a viewport set and NULL input param: Segfault */
1407 /* Cannot set the viewport to NULL */
1408 hr = IDirect3DDevice2_SetCurrentViewport(device, NULL);
1409 ok(hr == DDERR_INVALIDPARAMS, "Failed to set viewport to NULL, hr %#x.\n", hr);
1410 test_vp = NULL;
1411 hr = IDirect3DDevice2_GetCurrentViewport(device, &test_vp);
1412 ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
1413 ok(test_vp == viewport2, "Got unexpected viewport %p\n", test_vp);
1414 if(test_vp) IDirect3DViewport2_Release(test_vp);
1416 /* SetCurrentViewport properly releases the old viewport's reference */
1417 hr = IDirect3DDevice2_SetCurrentViewport(device, another_vp);
1418 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1419 ref = get_refcount((IUnknown *) viewport2);
1420 ok(ref == 2, "viewport2 refcount is %d\n", ref);
1421 ref = get_refcount((IUnknown *) another_vp);
1422 ok(ref == 3, "another_vp refcount is %d\n", ref);
1424 /* Deleting the viewport removes the reference added by AddViewport, but not
1425 * the one added by SetCurrentViewport. */
1426 hr = IDirect3DDevice2_DeleteViewport(device, another_vp);
1427 ok(SUCCEEDED(hr), "Failed to delete viewport from device, hr %#x.\n", hr);
1428 ref = get_refcount((IUnknown *) another_vp);
1429 todo_wine ok(ref == 2, "IDirect3DViewport2 refcount is %d\n", ref);
1431 /* GetCurrentViewport fails though */
1432 test_vp = NULL;
1433 hr = IDirect3DDevice2_GetCurrentViewport(device, &test_vp);
1434 ok(hr == D3DERR_NOCURRENTVIEWPORT, "Got unexpected hr %#x.\n", hr);
1435 ok(test_vp == NULL, "Got unexpected viewport %p\n", test_vp);
1436 if(test_vp) IDirect3DViewport2_Release(test_vp);
1438 /* Setting a different viewport does not free the leaked reference. How
1439 * do I get rid of it? Leak the viewport for now. */
1440 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport2);
1441 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1442 ref = get_refcount((IUnknown *) viewport2);
1443 ok(ref == 3, "viewport2 refcount is %d\n", ref);
1444 ref = get_refcount((IUnknown *) another_vp);
1445 todo_wine ok(ref == 2, "another_vp refcount is %d\n", ref);
1447 /* Destroying the device removes the viewport, but does not free the reference
1448 * added by SetCurrentViewport. */
1449 IDirect3DDevice2_Release(device);
1450 ref = get_refcount((IUnknown *) viewport2);
1451 todo_wine ok(ref == 2, "viewport2 refcount is %d\n", ref);
1453 IDirect3DViewport2_Release(another_vp);
1454 IDirect3DViewport2_Release(viewport2);
1455 IDirect3D2_Release(d3d);
1456 DestroyWindow(window);
1457 IDirectDraw2_Release(ddraw);
1460 static void test_zenable(void)
1462 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1463 static D3DTLVERTEX tquad[] =
1465 {{ 0.0f}, {480.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1466 {{ 0.0f}, { 0.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1467 {{640.0f}, {480.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1468 {{640.0f}, { 0.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1470 IDirect3DMaterial2 *background;
1471 IDirect3DViewport2 *viewport;
1472 IDirect3DDevice2 *device;
1473 IDirectDrawSurface *rt;
1474 IDirectDraw2 *ddraw;
1475 D3DCOLOR color;
1476 HWND window;
1477 HRESULT hr;
1478 UINT x, y;
1479 UINT i, j;
1481 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1482 0, 0, 640, 480, 0, 0, 0, 0);
1483 ddraw = create_ddraw();
1484 ok(!!ddraw, "Failed to create a ddraw object.\n");
1485 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1487 skip("Failed to create a 3D device, skipping test.\n");
1488 IDirectDraw2_Release(ddraw);
1489 DestroyWindow(window);
1490 return;
1493 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1494 viewport = create_viewport(device, 0, 0, 640, 480);
1495 viewport_set_background(device, viewport, background);
1496 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1497 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1499 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1500 ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#x.\n", hr);
1502 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1503 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1504 hr = IDirect3DDevice2_BeginScene(device);
1505 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1506 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, tquad, 4, 0);
1507 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1508 hr = IDirect3DDevice2_EndScene(device);
1509 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1511 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1512 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1513 for (i = 0; i < 4; ++i)
1515 for (j = 0; j < 4; ++j)
1517 x = 80 * ((2 * j) + 1);
1518 y = 60 * ((2 * i) + 1);
1519 color = get_surface_color(rt, x, y);
1520 ok(compare_color(color, 0x0000ff00, 1),
1521 "Expected color 0x0000ff00 at %u, %u, got 0x%08x.\n", x, y, color);
1524 IDirectDrawSurface_Release(rt);
1526 destroy_viewport(device, viewport);
1527 destroy_material(background);
1528 IDirect3DDevice2_Release(device);
1529 IDirectDraw2_Release(ddraw);
1530 DestroyWindow(window);
1533 static void test_ck_rgba(void)
1535 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1536 static D3DTLVERTEX tquad[] =
1538 {{ 0.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1539 {{ 0.0f}, { 0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1540 {{640.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1541 {{640.0f}, { 0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1542 {{ 0.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1543 {{ 0.0f}, { 0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1544 {{640.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1545 {{640.0f}, { 0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1547 static const struct
1549 D3DCOLOR fill_color;
1550 BOOL color_key;
1551 BOOL blend;
1552 D3DCOLOR result1, result1_broken;
1553 D3DCOLOR result2, result2_broken;
1555 tests[] =
1557 /* r200 on Windows doesn't check the alpha component when applying the color
1558 * key, so the key matches on every texel. */
1559 {0xff00ff00, TRUE, TRUE, 0x00ff0000, 0x00ff0000, 0x000000ff, 0x000000ff},
1560 {0xff00ff00, TRUE, FALSE, 0x00ff0000, 0x00ff0000, 0x000000ff, 0x000000ff},
1561 {0xff00ff00, FALSE, TRUE, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1562 {0xff00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1563 {0x7f00ff00, TRUE, TRUE, 0x00807f00, 0x00ff0000, 0x00807f00, 0x000000ff},
1564 {0x7f00ff00, TRUE, FALSE, 0x0000ff00, 0x00ff0000, 0x0000ff00, 0x000000ff},
1565 {0x7f00ff00, FALSE, TRUE, 0x00807f00, 0x00807f00, 0x00807f00, 0x00807f00},
1566 {0x7f00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1569 D3DTEXTUREHANDLE texture_handle;
1570 IDirect3DMaterial2 *background;
1571 IDirectDrawSurface *surface;
1572 IDirect3DViewport2 *viewport;
1573 IDirect3DTexture2 *texture;
1574 DDSURFACEDESC surface_desc;
1575 IDirect3DDevice2 *device;
1576 IDirectDrawSurface *rt;
1577 IDirectDraw2 *ddraw;
1578 D3DCOLOR color;
1579 HWND window;
1580 DDBLTFX fx;
1581 HRESULT hr;
1582 UINT i;
1584 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1585 0, 0, 640, 480, 0, 0, 0, 0);
1586 ddraw = create_ddraw();
1587 ok(!!ddraw, "Failed to create a ddraw object.\n");
1588 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1590 skip("Failed to create a 3D device, skipping test.\n");
1591 IDirectDraw2_Release(ddraw);
1592 DestroyWindow(window);
1593 return;
1596 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1597 viewport = create_viewport(device, 0, 0, 640, 480);
1598 viewport_set_background(device, viewport, background);
1599 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1600 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1602 memset(&surface_desc, 0, sizeof(surface_desc));
1603 surface_desc.dwSize = sizeof(surface_desc);
1604 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1605 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1606 surface_desc.dwWidth = 256;
1607 surface_desc.dwHeight = 256;
1608 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1609 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
1610 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1611 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1612 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1613 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1614 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
1615 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0xff00ff00;
1616 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0xff00ff00;
1617 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1618 ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
1619 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
1620 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1621 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
1622 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1623 IDirect3DTexture2_Release(texture);
1625 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1626 ok(SUCCEEDED(hr), "Failed to set texture, hr %#x.\n", hr);
1627 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
1628 ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1629 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
1630 ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1632 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1633 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1635 for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
1637 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, tests[i].color_key);
1638 ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1639 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, tests[i].blend);
1640 ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1642 memset(&fx, 0, sizeof(fx));
1643 fx.dwSize = sizeof(fx);
1644 U5(fx).dwFillColor = tests[i].fill_color;
1645 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1646 ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1648 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
1649 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1650 hr = IDirect3DDevice2_BeginScene(device);
1651 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1652 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1653 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1654 hr = IDirect3DDevice2_EndScene(device);
1655 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1657 color = get_surface_color(rt, 320, 240);
1658 ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
1659 "Expected color 0x%08x for test %u, got 0x%08x.\n",
1660 tests[i].result1, i, color);
1662 U5(fx).dwFillColor = 0xff0000ff;
1663 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1664 ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1666 hr = IDirect3DDevice2_BeginScene(device);
1667 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1668 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[4], 4, 0);
1669 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1670 hr = IDirect3DDevice2_EndScene(device);
1671 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1673 /* This tests that fragments that are masked out by the color key are
1674 * discarded, instead of just fully transparent. */
1675 color = get_surface_color(rt, 320, 240);
1676 ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
1677 "Expected color 0x%08x for test %u, got 0x%08x.\n",
1678 tests[i].result2, i, color);
1681 IDirectDrawSurface_Release(rt);
1682 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1683 ok(SUCCEEDED(hr), "Failed to unset texture, hr %#x.\n", hr);
1684 IDirectDrawSurface_Release(surface);
1685 destroy_viewport(device, viewport);
1686 destroy_material(background);
1687 IDirect3DDevice2_Release(device);
1688 IDirectDraw2_Release(ddraw);
1689 DestroyWindow(window);
1692 static void test_ck_default(void)
1694 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1695 static D3DTLVERTEX tquad[] =
1697 {{ 0.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1698 {{ 0.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1699 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1700 {{640.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1702 IDirectDrawSurface *surface, *rt;
1703 D3DTEXTUREHANDLE texture_handle;
1704 IDirect3DMaterial2 *background;
1705 IDirect3DViewport2 *viewport;
1706 DDSURFACEDESC surface_desc;
1707 IDirect3DTexture2 *texture;
1708 IDirect3DDevice2 *device;
1709 IDirectDraw2 *ddraw;
1710 D3DCOLOR color;
1711 DWORD value;
1712 HWND window;
1713 DDBLTFX fx;
1714 HRESULT hr;
1716 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1717 0, 0, 640, 480, 0, 0, 0, 0);
1718 ddraw = create_ddraw();
1719 ok(!!ddraw, "Failed to create a ddraw object.\n");
1720 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1722 skip("Failed to create a 3D device, skipping test.\n");
1723 IDirectDraw2_Release(ddraw);
1724 DestroyWindow(window);
1725 return;
1728 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1729 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1731 background = create_diffuse_material(device, 0.0, 1.0f, 0.0f, 1.0f);
1732 viewport = create_viewport(device, 0, 0, 640, 480);
1733 viewport_set_background(device, viewport, background);
1734 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1735 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1737 memset(&surface_desc, 0, sizeof(surface_desc));
1738 surface_desc.dwSize = sizeof(surface_desc);
1739 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1740 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1741 surface_desc.dwWidth = 256;
1742 surface_desc.dwHeight = 256;
1743 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1744 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
1745 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1746 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1747 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1748 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1749 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x000000ff;
1750 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x000000ff;
1751 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1752 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1753 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
1754 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1755 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
1756 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1757 IDirect3DTexture_Release(texture);
1759 memset(&fx, 0, sizeof(fx));
1760 fx.dwSize = sizeof(fx);
1761 U5(fx).dwFillColor = 0x000000ff;
1762 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1763 ok(SUCCEEDED(hr), "Failed to fill surface, hr %#x.\n", hr);
1765 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1766 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1767 hr = IDirect3DDevice2_BeginScene(device);
1768 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1769 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1770 ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#x.\n", hr);
1771 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
1772 ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
1773 ok(!value, "Got unexpected color keying state %#x.\n", value);
1774 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1775 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1776 hr = IDirect3DDevice2_EndScene(device);
1777 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1778 color = get_surface_color(rt, 320, 240);
1779 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
1781 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1782 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1783 hr = IDirect3DDevice2_BeginScene(device);
1784 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1785 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
1786 ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1787 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1788 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1789 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
1790 ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
1791 ok(!!value, "Got unexpected color keying state %#x.\n", value);
1792 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1793 ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#x.\n", hr);
1794 hr = IDirect3DDevice2_EndScene(device);
1795 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1796 color = get_surface_color(rt, 320, 240);
1797 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
1799 IDirectDrawSurface_Release(surface);
1800 destroy_viewport(device, viewport);
1801 destroy_material(background);
1802 IDirectDrawSurface_Release(rt);
1803 IDirect3DDevice2_Release(device);
1804 IDirectDraw2_Release(ddraw);
1805 DestroyWindow(window);
1808 static void test_ck_complex(void)
1810 IDirectDrawSurface *surface, *mipmap, *tmp;
1811 DDSCAPS caps = {DDSCAPS_COMPLEX};
1812 DDSURFACEDESC surface_desc;
1813 IDirect3DDevice2 *device;
1814 DDCOLORKEY color_key;
1815 IDirectDraw2 *ddraw;
1816 unsigned int i;
1817 ULONG refcount;
1818 HWND window;
1819 HRESULT hr;
1821 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1822 0, 0, 640, 480, 0, 0, 0, 0);
1823 ddraw = create_ddraw();
1824 ok(!!ddraw, "Failed to create a ddraw object.\n");
1825 if (!(device = create_device(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN)))
1827 skip("Failed to create a 3D device, skipping test.\n");
1828 DestroyWindow(window);
1829 IDirectDraw2_Release(ddraw);
1830 return;
1832 IDirect3DDevice2_Release(device);
1834 memset(&surface_desc, 0, sizeof(surface_desc));
1835 surface_desc.dwSize = sizeof(surface_desc);
1836 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1837 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
1838 surface_desc.dwWidth = 128;
1839 surface_desc.dwHeight = 128;
1840 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1841 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1843 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
1844 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1845 color_key.dwColorSpaceLowValue = 0x0000ff00;
1846 color_key.dwColorSpaceHighValue = 0x0000ff00;
1847 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &color_key);
1848 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1849 memset(&color_key, 0, sizeof(color_key));
1850 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
1851 ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
1852 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08x.\n",
1853 color_key.dwColorSpaceLowValue);
1854 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08x.\n",
1855 color_key.dwColorSpaceHighValue);
1857 mipmap = surface;
1858 IDirectDrawSurface_AddRef(mipmap);
1859 for (i = 0; i < 7; ++i)
1861 hr = IDirectDrawSurface_GetAttachedSurface(mipmap, &caps, &tmp);
1862 ok(SUCCEEDED(hr), "Failed to get attached surface, i %u, hr %#x.\n", i, hr);
1864 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
1865 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x, i %u.\n", hr, i);
1866 color_key.dwColorSpaceLowValue = 0x000000ff;
1867 color_key.dwColorSpaceHighValue = 0x000000ff;
1868 hr = IDirectDrawSurface_SetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
1869 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x, i %u.\n", hr, i);
1870 memset(&color_key, 0, sizeof(color_key));
1871 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
1872 ok(SUCCEEDED(hr), "Failed to get color key, hr %#x, i %u.\n", hr, i);
1873 ok(color_key.dwColorSpaceLowValue == 0x000000ff, "Got unexpected value 0x%08x, i %u.\n",
1874 color_key.dwColorSpaceLowValue, i);
1875 ok(color_key.dwColorSpaceHighValue == 0x000000ff, "Got unexpected value 0x%08x, i %u.\n",
1876 color_key.dwColorSpaceHighValue, i);
1878 IDirectDrawSurface_Release(mipmap);
1879 mipmap = tmp;
1882 memset(&color_key, 0, sizeof(color_key));
1883 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
1884 ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
1885 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08x.\n",
1886 color_key.dwColorSpaceLowValue);
1887 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08x.\n",
1888 color_key.dwColorSpaceHighValue);
1890 hr = IDirectDrawSurface_GetAttachedSurface(mipmap, &caps, &tmp);
1891 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#x.\n", hr);
1892 IDirectDrawSurface_Release(mipmap);
1893 refcount = IDirectDrawSurface_Release(surface);
1894 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
1896 memset(&surface_desc, 0, sizeof(surface_desc));
1897 surface_desc.dwSize = sizeof(surface_desc);
1898 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
1899 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
1900 surface_desc.dwBackBufferCount = 1;
1901 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1902 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1904 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
1905 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1906 color_key.dwColorSpaceLowValue = 0x0000ff00;
1907 color_key.dwColorSpaceHighValue = 0x0000ff00;
1908 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &color_key);
1909 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1910 memset(&color_key, 0, sizeof(color_key));
1911 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
1912 ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
1913 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08x.\n",
1914 color_key.dwColorSpaceLowValue);
1915 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08x.\n",
1916 color_key.dwColorSpaceHighValue);
1918 hr = IDirectDrawSurface_GetAttachedSurface(surface, &caps, &tmp);
1919 ok(SUCCEEDED(hr), "Failed to get attached surface, hr %#x.\n", hr);
1921 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
1922 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x, i %u.\n", hr, i);
1923 color_key.dwColorSpaceLowValue = 0x0000ff00;
1924 color_key.dwColorSpaceHighValue = 0x0000ff00;
1925 hr = IDirectDrawSurface_SetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
1926 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1927 memset(&color_key, 0, sizeof(color_key));
1928 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
1929 ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
1930 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08x.\n",
1931 color_key.dwColorSpaceLowValue);
1932 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08x.\n",
1933 color_key.dwColorSpaceHighValue);
1935 IDirectDrawSurface_Release(tmp);
1937 refcount = IDirectDrawSurface_Release(surface);
1938 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
1939 refcount = IDirectDraw2_Release(ddraw);
1940 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
1941 DestroyWindow(window);
1944 struct qi_test
1946 REFIID iid;
1947 REFIID refcount_iid;
1948 HRESULT hr;
1951 static void test_qi(const char *test_name, IUnknown *base_iface,
1952 REFIID refcount_iid, const struct qi_test *tests, UINT entry_count)
1954 ULONG refcount, expected_refcount;
1955 IUnknown *iface1, *iface2;
1956 HRESULT hr;
1957 UINT i, j;
1959 for (i = 0; i < entry_count; ++i)
1961 hr = IUnknown_QueryInterface(base_iface, tests[i].iid, (void **)&iface1);
1962 ok(hr == tests[i].hr, "Got hr %#x for test \"%s\" %u.\n", hr, test_name, i);
1963 if (SUCCEEDED(hr))
1965 for (j = 0; j < entry_count; ++j)
1967 hr = IUnknown_QueryInterface(iface1, tests[j].iid, (void **)&iface2);
1968 ok(hr == tests[j].hr, "Got hr %#x for test \"%s\" %u, %u.\n", hr, test_name, i, j);
1969 if (SUCCEEDED(hr))
1971 expected_refcount = 0;
1972 if (IsEqualGUID(refcount_iid, tests[j].refcount_iid))
1973 ++expected_refcount;
1974 if (IsEqualGUID(tests[i].refcount_iid, tests[j].refcount_iid))
1975 ++expected_refcount;
1976 refcount = IUnknown_Release(iface2);
1977 ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, %u, expected %u.\n",
1978 refcount, test_name, i, j, expected_refcount);
1982 expected_refcount = 0;
1983 if (IsEqualGUID(refcount_iid, tests[i].refcount_iid))
1984 ++expected_refcount;
1985 refcount = IUnknown_Release(iface1);
1986 ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, expected %u.\n",
1987 refcount, test_name, i, expected_refcount);
1992 static void test_surface_qi(void)
1994 static const struct qi_test tests[] =
1996 {&IID_IDirect3DTexture2, &IID_IDirectDrawSurface, S_OK },
1997 {&IID_IDirect3DTexture, &IID_IDirectDrawSurface, S_OK },
1998 {&IID_IDirectDrawGammaControl, &IID_IDirectDrawGammaControl, S_OK },
1999 {&IID_IDirectDrawColorControl, NULL, E_NOINTERFACE},
2000 {&IID_IDirectDrawSurface7, &IID_IDirectDrawSurface7, S_OK },
2001 {&IID_IDirectDrawSurface4, &IID_IDirectDrawSurface4, S_OK },
2002 {&IID_IDirectDrawSurface3, &IID_IDirectDrawSurface3, S_OK },
2003 {&IID_IDirectDrawSurface2, &IID_IDirectDrawSurface2, S_OK },
2004 {&IID_IDirectDrawSurface, &IID_IDirectDrawSurface, S_OK },
2005 {&IID_IDirect3DDevice7, NULL, E_INVALIDARG },
2006 {&IID_IDirect3DDevice3, NULL, E_INVALIDARG },
2007 {&IID_IDirect3DDevice2, NULL, E_INVALIDARG },
2008 {&IID_IDirect3DDevice, NULL, E_INVALIDARG },
2009 {&IID_IDirect3D7, NULL, E_INVALIDARG },
2010 {&IID_IDirect3D3, NULL, E_INVALIDARG },
2011 {&IID_IDirect3D2, NULL, E_INVALIDARG },
2012 {&IID_IDirect3D, NULL, E_INVALIDARG },
2013 {&IID_IDirectDraw7, NULL, E_INVALIDARG },
2014 {&IID_IDirectDraw4, NULL, E_INVALIDARG },
2015 {&IID_IDirectDraw3, NULL, E_INVALIDARG },
2016 {&IID_IDirectDraw2, NULL, E_INVALIDARG },
2017 {&IID_IDirectDraw, NULL, E_INVALIDARG },
2018 {&IID_IDirect3DLight, NULL, E_INVALIDARG },
2019 {&IID_IDirect3DMaterial, NULL, E_INVALIDARG },
2020 {&IID_IDirect3DMaterial2, NULL, E_INVALIDARG },
2021 {&IID_IDirect3DMaterial3, NULL, E_INVALIDARG },
2022 {&IID_IDirect3DExecuteBuffer, NULL, E_INVALIDARG },
2023 {&IID_IDirect3DViewport, NULL, E_INVALIDARG },
2024 {&IID_IDirect3DViewport2, NULL, E_INVALIDARG },
2025 {&IID_IDirect3DViewport3, NULL, E_INVALIDARG },
2026 {&IID_IDirect3DVertexBuffer, NULL, E_INVALIDARG },
2027 {&IID_IDirect3DVertexBuffer7, NULL, E_INVALIDARG },
2028 {&IID_IDirectDrawPalette, NULL, E_INVALIDARG },
2029 {&IID_IDirectDrawClipper, NULL, E_INVALIDARG },
2030 {&IID_IUnknown, &IID_IDirectDrawSurface, S_OK },
2033 IDirectDrawSurface *surface;
2034 DDSURFACEDESC surface_desc;
2035 IDirect3DDevice2 *device;
2036 IDirectDraw2 *ddraw;
2037 HWND window;
2038 HRESULT hr;
2040 if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
2042 win_skip("DirectDrawCreateEx not available, skipping test.\n");
2043 return;
2046 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2047 0, 0, 640, 480, 0, 0, 0, 0);
2048 ddraw = create_ddraw();
2049 ok(!!ddraw, "Failed to create a ddraw object.\n");
2050 /* Try to create a D3D device to see if the ddraw implementation supports
2051 * D3D. 64-bit ddraw in particular doesn't seem to support D3D, and
2052 * doesn't support e.g. the IDirect3DTexture interfaces. */
2053 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
2055 skip("Failed to create a 3D device, skipping test.\n");
2056 IDirectDraw2_Release(ddraw);
2057 DestroyWindow(window);
2058 return;
2060 IDirect3DDevice_Release(device);
2062 memset(&surface_desc, 0, sizeof(surface_desc));
2063 surface_desc.dwSize = sizeof(surface_desc);
2064 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2065 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
2066 surface_desc.dwWidth = 512;
2067 surface_desc.dwHeight = 512;
2068 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
2069 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
2071 test_qi("surface_qi", (IUnknown *)surface, &IID_IDirectDrawSurface, tests, sizeof(tests) / sizeof(*tests));
2073 IDirectDrawSurface_Release(surface);
2074 IDirectDraw2_Release(ddraw);
2075 DestroyWindow(window);
2078 static void test_device_qi(void)
2080 static const struct qi_test tests[] =
2082 {&IID_IDirect3DTexture2, NULL, E_NOINTERFACE},
2083 {&IID_IDirect3DTexture, NULL, E_NOINTERFACE},
2084 {&IID_IDirectDrawGammaControl, NULL, E_NOINTERFACE},
2085 {&IID_IDirectDrawColorControl, NULL, E_NOINTERFACE},
2086 {&IID_IDirectDrawSurface7, NULL, E_NOINTERFACE},
2087 {&IID_IDirectDrawSurface4, NULL, E_NOINTERFACE},
2088 {&IID_IDirectDrawSurface3, NULL, E_NOINTERFACE},
2089 {&IID_IDirectDrawSurface2, NULL, E_NOINTERFACE},
2090 {&IID_IDirectDrawSurface, NULL, E_NOINTERFACE},
2091 {&IID_IDirect3DDevice7, NULL, E_NOINTERFACE},
2092 {&IID_IDirect3DDevice3, NULL, E_NOINTERFACE},
2093 {&IID_IDirect3DDevice2, &IID_IDirect3DDevice2, S_OK },
2094 {&IID_IDirect3DDevice, &IID_IDirect3DDevice2, S_OK },
2095 {&IID_IDirect3DRampDevice, NULL, E_NOINTERFACE},
2096 {&IID_IDirect3DRGBDevice, NULL, E_NOINTERFACE},
2097 {&IID_IDirect3DHALDevice, NULL, E_NOINTERFACE},
2098 {&IID_IDirect3DMMXDevice, NULL, E_NOINTERFACE},
2099 {&IID_IDirect3DRefDevice, NULL, E_NOINTERFACE},
2100 {&IID_IDirect3DTnLHalDevice, NULL, E_NOINTERFACE},
2101 {&IID_IDirect3DNullDevice, NULL, E_NOINTERFACE},
2102 {&IID_IDirect3D7, NULL, E_NOINTERFACE},
2103 {&IID_IDirect3D3, NULL, E_NOINTERFACE},
2104 {&IID_IDirect3D2, NULL, E_NOINTERFACE},
2105 {&IID_IDirect3D, NULL, E_NOINTERFACE},
2106 {&IID_IDirectDraw7, NULL, E_NOINTERFACE},
2107 {&IID_IDirectDraw4, NULL, E_NOINTERFACE},
2108 {&IID_IDirectDraw3, NULL, E_NOINTERFACE},
2109 {&IID_IDirectDraw2, NULL, E_NOINTERFACE},
2110 {&IID_IDirectDraw, NULL, E_NOINTERFACE},
2111 {&IID_IDirect3DLight, NULL, E_NOINTERFACE},
2112 {&IID_IDirect3DMaterial, NULL, E_NOINTERFACE},
2113 {&IID_IDirect3DMaterial2, NULL, E_NOINTERFACE},
2114 {&IID_IDirect3DMaterial3, NULL, E_NOINTERFACE},
2115 {&IID_IDirect3DExecuteBuffer, NULL, E_NOINTERFACE},
2116 {&IID_IDirect3DViewport, NULL, E_NOINTERFACE},
2117 {&IID_IDirect3DViewport2, NULL, E_NOINTERFACE},
2118 {&IID_IDirect3DViewport3, NULL, E_NOINTERFACE},
2119 {&IID_IDirect3DVertexBuffer, NULL, E_NOINTERFACE},
2120 {&IID_IDirect3DVertexBuffer7, NULL, E_NOINTERFACE},
2121 {&IID_IDirectDrawPalette, NULL, E_NOINTERFACE},
2122 {&IID_IDirectDrawClipper, NULL, E_NOINTERFACE},
2123 {&IID_IUnknown, &IID_IDirect3DDevice2, S_OK },
2126 IDirect3DDevice2 *device;
2127 IDirectDraw2 *ddraw;
2128 HWND window;
2130 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2131 0, 0, 640, 480, 0, 0, 0, 0);
2132 ddraw = create_ddraw();
2133 ok(!!ddraw, "Failed to create a ddraw object.\n");
2134 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
2136 skip("Failed to create a 3D device, skipping test.\n");
2137 IDirectDraw2_Release(ddraw);
2138 DestroyWindow(window);
2139 return;
2142 test_qi("device_qi", (IUnknown *)device, &IID_IDirect3DDevice2, tests, sizeof(tests) / sizeof(*tests));
2144 IDirect3DDevice2_Release(device);
2145 IDirectDraw2_Release(ddraw);
2146 DestroyWindow(window);
2149 static void test_wndproc(void)
2151 LONG_PTR proc, ddraw_proc;
2152 IDirectDraw2 *ddraw;
2153 WNDCLASSA wc = {0};
2154 HWND window;
2155 HRESULT hr;
2156 ULONG ref;
2158 static struct message messages[] =
2160 {WM_WINDOWPOSCHANGING, FALSE, 0},
2161 {WM_MOVE, FALSE, 0},
2162 {WM_SIZE, FALSE, 0},
2163 {WM_WINDOWPOSCHANGING, FALSE, 0},
2164 {WM_ACTIVATE, FALSE, 0},
2165 {WM_SETFOCUS, FALSE, 0},
2166 {0, FALSE, 0},
2169 /* DDSCL_EXCLUSIVE replaces the window's window proc. */
2170 ddraw = create_ddraw();
2171 ok(!!ddraw, "Failed to create a ddraw object.\n");
2173 wc.lpfnWndProc = test_proc;
2174 wc.lpszClassName = "ddraw_test_wndproc_wc";
2175 ok(RegisterClassA(&wc), "Failed to register window class.\n");
2177 window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test",
2178 WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
2180 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2181 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2182 (LONG_PTR)test_proc, proc);
2183 expect_messages = messages;
2184 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2185 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2186 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2187 expect_messages = NULL;
2188 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2189 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
2190 (LONG_PTR)test_proc, proc);
2191 ref = IDirectDraw2_Release(ddraw);
2192 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2193 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2194 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2195 (LONG_PTR)test_proc, proc);
2197 /* DDSCL_NORMAL doesn't. */
2198 ddraw = create_ddraw();
2199 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2200 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2201 (LONG_PTR)test_proc, proc);
2202 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
2203 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2204 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2205 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2206 (LONG_PTR)test_proc, proc);
2207 ref = IDirectDraw2_Release(ddraw);
2208 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2209 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2210 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2211 (LONG_PTR)test_proc, proc);
2213 /* The original window proc is only restored by ddraw if the current
2214 * window proc matches the one ddraw set. This also affects switching
2215 * from DDSCL_NORMAL to DDSCL_EXCLUSIVE. */
2216 ddraw = create_ddraw();
2217 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2218 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2219 (LONG_PTR)test_proc, proc);
2220 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2221 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2222 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2223 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
2224 (LONG_PTR)test_proc, proc);
2225 ddraw_proc = proc;
2226 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2227 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2228 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2229 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2230 (LONG_PTR)test_proc, proc);
2231 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2232 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2233 proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
2234 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
2235 (LONG_PTR)test_proc, proc);
2236 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2237 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2238 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2239 ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
2240 (LONG_PTR)DefWindowProcA, proc);
2241 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2242 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2243 proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)ddraw_proc);
2244 ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
2245 (LONG_PTR)DefWindowProcA, proc);
2246 ref = IDirectDraw2_Release(ddraw);
2247 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2248 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2249 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2250 (LONG_PTR)test_proc, proc);
2252 ddraw = create_ddraw();
2253 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2254 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
2255 (LONG_PTR)test_proc, proc);
2256 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2257 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2258 proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
2259 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
2260 (LONG_PTR)test_proc, proc);
2261 ref = IDirectDraw2_Release(ddraw);
2262 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2263 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2264 ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
2265 (LONG_PTR)DefWindowProcA, proc);
2267 fix_wndproc(window, (LONG_PTR)test_proc);
2268 expect_messages = NULL;
2269 DestroyWindow(window);
2270 UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
2273 static void test_window_style(void)
2275 LONG style, exstyle, tmp, expected_style;
2276 RECT fullscreen_rect, r;
2277 IDirectDraw2 *ddraw;
2278 HWND window;
2279 HRESULT hr;
2280 ULONG ref;
2281 BOOL ret;
2283 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2284 0, 0, 100, 100, 0, 0, 0, 0);
2285 ddraw = create_ddraw();
2286 ok(!!ddraw, "Failed to create a ddraw object.\n");
2288 style = GetWindowLongA(window, GWL_STYLE);
2289 exstyle = GetWindowLongA(window, GWL_EXSTYLE);
2290 SetRect(&fullscreen_rect, 0, 0, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
2292 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2293 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2295 tmp = GetWindowLongA(window, GWL_STYLE);
2296 todo_wine ok(tmp == style, "Expected window style %#x, got %#x.\n", style, tmp);
2297 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2298 todo_wine ok(tmp == exstyle, "Expected window extended style %#x, got %#x.\n", exstyle, tmp);
2300 GetWindowRect(window, &r);
2301 ok(EqualRect(&r, &fullscreen_rect), "Expected %s, got %s.\n",
2302 wine_dbgstr_rect(&fullscreen_rect), wine_dbgstr_rect(&r));
2303 GetClientRect(window, &r);
2304 todo_wine ok(!EqualRect(&r, &fullscreen_rect), "Client rect and window rect are equal.\n");
2306 ret = SetForegroundWindow(GetDesktopWindow());
2307 ok(ret, "Failed to set foreground window.\n");
2309 tmp = GetWindowLongA(window, GWL_STYLE);
2310 todo_wine ok(tmp == style, "Expected window style %#x, got %#x.\n", style, tmp);
2311 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2312 todo_wine ok(tmp == exstyle, "Expected window extended style %#x, got %#x.\n", exstyle, tmp);
2314 ret = SetForegroundWindow(window);
2315 ok(ret, "Failed to set foreground window.\n");
2316 /* Windows 7 (but not Vista and XP) shows the window when it receives focus. Hide it again,
2317 * the next tests expect this. */
2318 ShowWindow(window, SW_HIDE);
2320 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2321 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2323 tmp = GetWindowLongA(window, GWL_STYLE);
2324 todo_wine ok(tmp == style, "Expected window style %#x, got %#x.\n", style, tmp);
2325 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2326 todo_wine ok(tmp == exstyle, "Expected window extended style %#x, got %#x.\n", exstyle, tmp);
2328 ShowWindow(window, SW_SHOW);
2329 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2330 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2332 tmp = GetWindowLongA(window, GWL_STYLE);
2333 expected_style = style | WS_VISIBLE;
2334 todo_wine ok(tmp == expected_style, "Expected window style %#x, got %#x.\n", expected_style, tmp);
2335 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2336 expected_style = exstyle | WS_EX_TOPMOST;
2337 todo_wine ok(tmp == expected_style, "Expected window extended style %#x, got %#x.\n", expected_style, tmp);
2339 ret = SetForegroundWindow(GetDesktopWindow());
2340 ok(ret, "Failed to set foreground window.\n");
2341 tmp = GetWindowLongA(window, GWL_STYLE);
2342 expected_style = style | WS_VISIBLE | WS_MINIMIZE;
2343 todo_wine ok(tmp == expected_style, "Expected window style %#x, got %#x.\n", expected_style, tmp);
2344 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2345 expected_style = exstyle | WS_EX_TOPMOST;
2346 todo_wine ok(tmp == expected_style, "Expected window extended style %#x, got %#x.\n", expected_style, tmp);
2348 ref = IDirectDraw2_Release(ddraw);
2349 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2351 DestroyWindow(window);
2354 static void test_redundant_mode_set(void)
2356 DDSURFACEDESC surface_desc = {0};
2357 IDirectDraw2 *ddraw;
2358 HWND window;
2359 HRESULT hr;
2360 RECT r, s;
2361 ULONG ref;
2363 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2364 0, 0, 100, 100, 0, 0, 0, 0);
2365 ddraw = create_ddraw();
2366 ok(!!ddraw, "Failed to create a ddraw object.\n");
2368 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2369 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2371 surface_desc.dwSize = sizeof(surface_desc);
2372 hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
2373 ok(SUCCEEDED(hr), "GetDisplayMode failed, hr %#x.\n", hr);
2375 hr = IDirectDraw2_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2376 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, 0, 0);
2377 ok(SUCCEEDED(hr), "SetDisplayMode failed, hr %#x.\n", hr);
2379 GetWindowRect(window, &r);
2380 r.right /= 2;
2381 r.bottom /= 2;
2382 SetWindowPos(window, HWND_TOP, r.left, r.top, r.right, r.bottom, 0);
2383 GetWindowRect(window, &s);
2384 ok(EqualRect(&r, &s), "Expected %s, got %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&s));
2386 hr = IDirectDraw2_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2387 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, 0, 0);
2388 ok(SUCCEEDED(hr), "SetDisplayMode failed, hr %#x.\n", hr);
2390 GetWindowRect(window, &s);
2391 ok(EqualRect(&r, &s), "Expected %s, got %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&s));
2393 ref = IDirectDraw2_Release(ddraw);
2394 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2396 DestroyWindow(window);
2399 static SIZE screen_size, screen_size2;
2401 static LRESULT CALLBACK mode_set_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2403 if (message == WM_SIZE)
2405 screen_size.cx = GetSystemMetrics(SM_CXSCREEN);
2406 screen_size.cy = GetSystemMetrics(SM_CYSCREEN);
2409 return test_proc(hwnd, message, wparam, lparam);
2412 static LRESULT CALLBACK mode_set_proc2(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2414 if (message == WM_SIZE)
2416 screen_size2.cx = GetSystemMetrics(SM_CXSCREEN);
2417 screen_size2.cy = GetSystemMetrics(SM_CYSCREEN);
2420 return test_proc(hwnd, message, wparam, lparam);
2423 struct test_coop_level_mode_set_enum_param
2425 DWORD ddraw_width, ddraw_height, user32_width, user32_height;
2428 static HRESULT CALLBACK test_coop_level_mode_set_enum_cb(DDSURFACEDESC *surface_desc, void *context)
2430 struct test_coop_level_mode_set_enum_param *param = context;
2432 if (U1(surface_desc->ddpfPixelFormat).dwRGBBitCount != registry_mode.dmBitsPerPel)
2433 return DDENUMRET_OK;
2434 if (surface_desc->dwWidth == registry_mode.dmPelsWidth
2435 && surface_desc->dwHeight == registry_mode.dmPelsHeight)
2436 return DDENUMRET_OK;
2438 if (!param->ddraw_width)
2440 param->ddraw_width = surface_desc->dwWidth;
2441 param->ddraw_height = surface_desc->dwHeight;
2442 return DDENUMRET_OK;
2444 if (surface_desc->dwWidth == param->ddraw_width && surface_desc->dwHeight == param->ddraw_height)
2445 return DDENUMRET_OK;
2447 param->user32_width = surface_desc->dwWidth;
2448 param->user32_height = surface_desc->dwHeight;
2449 return DDENUMRET_CANCEL;
2452 static void test_coop_level_mode_set(void)
2454 IDirectDrawSurface *primary;
2455 RECT registry_rect, ddraw_rect, user32_rect, r;
2456 IDirectDraw2 *ddraw;
2457 DDSURFACEDESC ddsd;
2458 WNDCLASSA wc = {0};
2459 HWND window, window2;
2460 HRESULT hr;
2461 ULONG ref;
2462 MSG msg;
2463 struct test_coop_level_mode_set_enum_param param;
2464 DEVMODEW devmode;
2465 BOOL ret;
2466 LONG change_ret;
2468 static const struct message exclusive_messages[] =
2470 {WM_WINDOWPOSCHANGING, FALSE, 0},
2471 {WM_WINDOWPOSCHANGED, FALSE, 0},
2472 {WM_SIZE, FALSE, 0},
2473 {WM_DISPLAYCHANGE, FALSE, 0},
2474 {0, FALSE, 0},
2476 static const struct message exclusive_focus_loss_messages[] =
2478 {WM_ACTIVATE, TRUE, WA_INACTIVE},
2479 {WM_DISPLAYCHANGE, FALSE, 0},
2480 {WM_WINDOWPOSCHANGING, FALSE, 0},
2481 /* Like d3d8 and d3d9 ddraw seems to use SW_SHOWMINIMIZED instead of
2482 * SW_MINIMIZED, causing a recursive window activation that does not
2483 * produce the same result in Wine yet. Ignore the difference for now.
2484 * {WM_ACTIVATE, TRUE, 0x200000 | WA_ACTIVE}, */
2485 {WM_WINDOWPOSCHANGED, FALSE, 0},
2486 {WM_MOVE, FALSE, 0},
2487 {WM_SIZE, TRUE, SIZE_MINIMIZED},
2488 {WM_ACTIVATEAPP, TRUE, FALSE},
2489 {0, FALSE, 0},
2491 static const struct message exclusive_focus_restore_messages[] =
2493 {WM_WINDOWPOSCHANGING, FALSE, 0}, /* From the ShowWindow(SW_RESTORE). */
2494 {WM_WINDOWPOSCHANGING, FALSE, 0}, /* Generated by ddraw, matches d3d9 behavior. */
2495 {WM_WINDOWPOSCHANGED, FALSE, 0}, /* Matching previous message. */
2496 {WM_SIZE, FALSE, 0}, /* DefWindowProc. */
2497 {WM_DISPLAYCHANGE, FALSE, 0}, /* Ddraw restores mode. */
2498 /* Native redundantly sets the window size here. */
2499 {WM_ACTIVATEAPP, TRUE, TRUE}, /* End of ddraw's hooks. */
2500 {WM_WINDOWPOSCHANGED, FALSE, 0}, /* Matching the one from ShowWindow. */
2501 {WM_MOVE, FALSE, 0}, /* DefWindowProc. */
2502 {WM_SIZE, TRUE, SIZE_RESTORED}, /* DefWindowProc. */
2503 {0, FALSE, 0},
2505 static const struct message sc_restore_messages[] =
2507 {WM_SYSCOMMAND, TRUE, SC_RESTORE},
2508 {WM_WINDOWPOSCHANGING, FALSE, 0},
2509 {WM_WINDOWPOSCHANGED, FALSE, 0},
2510 {WM_SIZE, TRUE, SIZE_RESTORED},
2511 {0, FALSE, 0},
2513 static const struct message sc_minimize_messages[] =
2515 {WM_SYSCOMMAND, TRUE, SC_MINIMIZE},
2516 {WM_WINDOWPOSCHANGING, FALSE, 0},
2517 {WM_WINDOWPOSCHANGED, FALSE, 0},
2518 {WM_SIZE, TRUE, SIZE_MINIMIZED},
2519 {0, FALSE, 0},
2521 static const struct message sc_maximize_messages[] =
2523 {WM_SYSCOMMAND, TRUE, SC_MAXIMIZE},
2524 {WM_WINDOWPOSCHANGING, FALSE, 0},
2525 {WM_WINDOWPOSCHANGED, FALSE, 0},
2526 {WM_SIZE, TRUE, SIZE_MAXIMIZED},
2527 {0, FALSE, 0},
2530 static const struct message normal_messages[] =
2532 {WM_DISPLAYCHANGE, FALSE, 0},
2533 {0, FALSE, 0},
2536 ddraw = create_ddraw();
2537 ok(!!ddraw, "Failed to create a ddraw object.\n");
2539 memset(&param, 0, sizeof(param));
2540 hr = IDirectDraw2_EnumDisplayModes(ddraw, 0, NULL, &param, test_coop_level_mode_set_enum_cb);
2541 ok(SUCCEEDED(hr), "Failed to enumerate display mode, hr %#x.\n", hr);
2542 ref = IDirectDraw2_Release(ddraw);
2543 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2545 if (!param.user32_height)
2547 skip("Fewer than 3 different modes supported, skipping mode restore test.\n");
2548 return;
2551 SetRect(&registry_rect, 0, 0, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
2552 SetRect(&ddraw_rect, 0, 0, param.ddraw_width, param.ddraw_height);
2553 SetRect(&user32_rect, 0, 0, param.user32_width, param.user32_height);
2555 memset(&devmode, 0, sizeof(devmode));
2556 devmode.dmSize = sizeof(devmode);
2557 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
2558 devmode.dmPelsWidth = param.user32_width;
2559 devmode.dmPelsHeight = param.user32_height;
2560 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
2561 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#x.\n", change_ret);
2563 ddraw = create_ddraw();
2564 ok(!!ddraw, "Failed to create a ddraw object.\n");
2566 wc.lpfnWndProc = mode_set_proc;
2567 wc.lpszClassName = "ddraw_test_wndproc_wc";
2568 ok(RegisterClassA(&wc), "Failed to register window class.\n");
2569 wc.lpfnWndProc = mode_set_proc2;
2570 wc.lpszClassName = "ddraw_test_wndproc_wc2";
2571 ok(RegisterClassA(&wc), "Failed to register window class.\n");
2573 window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test", WS_OVERLAPPEDWINDOW,
2574 0, 0, 100, 100, 0, 0, 0, 0);
2575 window2 = CreateWindowA("ddraw_test_wndproc_wc2", "ddraw_test", WS_OVERLAPPEDWINDOW,
2576 0, 0, 100, 100, 0, 0, 0, 0);
2578 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2579 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2581 GetWindowRect(window, &r);
2582 ok(EqualRect(&r, &user32_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&user32_rect),
2583 wine_dbgstr_rect(&r));
2585 memset(&ddsd, 0, sizeof(ddsd));
2586 ddsd.dwSize = sizeof(ddsd);
2587 ddsd.dwFlags = DDSD_CAPS;
2588 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2590 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2591 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2592 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2593 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2594 ok(ddsd.dwWidth == param.user32_width, "Expected surface width %u, got %u.\n",
2595 param.user32_width, ddsd.dwWidth);
2596 ok(ddsd.dwHeight == param.user32_height, "Expected surface height %u, got %u.\n",
2597 param.user32_height, ddsd.dwHeight);
2599 GetWindowRect(window, &r);
2600 ok(EqualRect(&r, &user32_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&user32_rect),
2601 wine_dbgstr_rect(&r));
2603 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
2604 expect_messages = exclusive_messages;
2605 screen_size.cx = 0;
2606 screen_size.cy = 0;
2608 hr = IDirectDrawSurface_IsLost(primary);
2609 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
2610 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
2611 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
2612 hr = IDirectDrawSurface_IsLost(primary);
2613 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
2615 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2616 expect_messages = NULL;
2617 ok(screen_size.cx == param.ddraw_width && screen_size.cy == param.ddraw_height,
2618 "Expected screen size %ux%u, got %ux%u.\n",
2619 param.ddraw_width, param.ddraw_height, screen_size.cx, screen_size.cy);
2621 GetWindowRect(window, &r);
2622 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
2623 wine_dbgstr_rect(&r));
2625 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2626 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2627 ok(ddsd.dwWidth == param.user32_width, "Expected surface width %u, got %u.\n",
2628 param.user32_width, ddsd.dwWidth);
2629 ok(ddsd.dwHeight == param.user32_height, "Expected surface height %u, got %u.\n",
2630 param.user32_height, ddsd.dwHeight);
2631 IDirectDrawSurface_Release(primary);
2633 memset(&ddsd, 0, sizeof(ddsd));
2634 ddsd.dwSize = sizeof(ddsd);
2635 ddsd.dwFlags = DDSD_CAPS;
2636 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2638 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2639 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2640 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2641 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2642 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %u, got %u.\n",
2643 param.ddraw_width, ddsd.dwWidth);
2644 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %u, got %u.\n",
2645 param.ddraw_height, ddsd.dwHeight);
2647 GetWindowRect(window, &r);
2648 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
2649 wine_dbgstr_rect(&r));
2651 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
2652 expect_messages = exclusive_messages;
2653 screen_size.cx = 0;
2654 screen_size.cy = 0;
2656 hr = IDirectDrawSurface_IsLost(primary);
2657 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
2658 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
2659 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#x.\n", change_ret);
2660 hr = IDirectDrawSurface_IsLost(primary);
2661 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
2663 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2664 expect_messages = NULL;
2665 ok(screen_size.cx == param.user32_width && screen_size.cy == param.user32_height,
2666 "Expected screen size %ux%u, got %ux%u.\n",
2667 param.user32_width, param.user32_height, screen_size.cx, screen_size.cy);
2669 GetWindowRect(window, &r);
2670 ok(EqualRect(&r, &user32_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&user32_rect),
2671 wine_dbgstr_rect(&r));
2673 expect_messages = exclusive_focus_loss_messages;
2674 ret = SetForegroundWindow(GetDesktopWindow());
2675 ok(ret, "Failed to set foreground window.\n");
2676 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2677 memset(&devmode, 0, sizeof(devmode));
2678 devmode.dmSize = sizeof(devmode);
2679 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
2680 ok(ret, "Failed to get display mode.\n");
2681 ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
2682 && devmode.dmPelsHeight == registry_mode.dmPelsHeight, "Got unexpect screen size %ux%u.\n",
2683 devmode.dmPelsWidth, devmode.dmPelsHeight);
2685 expect_messages = exclusive_focus_restore_messages;
2686 ShowWindow(window, SW_RESTORE);
2687 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2689 GetWindowRect(window, &r);
2690 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
2691 wine_dbgstr_rect(&r));
2692 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
2693 ok(ret, "Failed to get display mode.\n");
2694 ok(devmode.dmPelsWidth == param.ddraw_width
2695 && devmode.dmPelsHeight == param.ddraw_height, "Got unexpect screen size %ux%u.\n",
2696 devmode.dmPelsWidth, devmode.dmPelsHeight);
2698 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2699 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2700 /* Normally the primary should be restored here. Unfortunately this causes the
2701 * GetSurfaceDesc call after the next display mode change to crash on the Windows 8
2702 * testbot. Another Restore call would presumably avoid the crash, but it also moots
2703 * the point of the GetSurfaceDesc call. */
2705 expect_messages = sc_minimize_messages;
2706 SendMessageA(window, WM_SYSCOMMAND, SC_MINIMIZE, 0);
2707 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2708 expect_messages = NULL;
2710 expect_messages = sc_restore_messages;
2711 SendMessageA(window, WM_SYSCOMMAND, SC_RESTORE, 0);
2712 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2713 expect_messages = NULL;
2715 expect_messages = sc_maximize_messages;
2716 SendMessageA(window, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
2717 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2718 expect_messages = NULL;
2720 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2721 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2723 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
2724 expect_messages = exclusive_messages;
2725 screen_size.cx = 0;
2726 screen_size.cy = 0;
2728 hr = IDirectDrawSurface_IsLost(primary);
2729 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
2730 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
2731 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2732 hr = IDirectDrawSurface_IsLost(primary);
2733 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
2735 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2736 expect_messages = NULL;
2737 ok(screen_size.cx == registry_mode.dmPelsWidth
2738 && screen_size.cy == registry_mode.dmPelsHeight,
2739 "Expected screen size %ux%u, got %ux%u.\n",
2740 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight, screen_size.cx, screen_size.cy);
2742 GetWindowRect(window, &r);
2743 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2744 wine_dbgstr_rect(&r));
2746 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2747 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2748 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %u, got %u.\n",
2749 param.ddraw_width, ddsd.dwWidth);
2750 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %u, got %u.\n",
2751 param.ddraw_height, ddsd.dwHeight);
2752 IDirectDrawSurface_Release(primary);
2754 /* For Wine. */
2755 change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
2756 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#x.\n", change_ret);
2758 memset(&ddsd, 0, sizeof(ddsd));
2759 ddsd.dwSize = sizeof(ddsd);
2760 ddsd.dwFlags = DDSD_CAPS;
2761 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2763 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2764 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2765 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2766 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2767 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
2768 registry_mode.dmPelsWidth, ddsd.dwWidth);
2769 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
2770 registry_mode.dmPelsHeight, ddsd.dwHeight);
2772 GetWindowRect(window, &r);
2773 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2774 wine_dbgstr_rect(&r));
2776 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2777 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2779 GetWindowRect(window, &r);
2780 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2781 wine_dbgstr_rect(&r));
2783 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2784 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2785 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
2786 registry_mode.dmPelsWidth, ddsd.dwWidth);
2787 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
2788 registry_mode.dmPelsHeight, ddsd.dwHeight);
2789 IDirectDrawSurface_Release(primary);
2791 memset(&ddsd, 0, sizeof(ddsd));
2792 ddsd.dwSize = sizeof(ddsd);
2793 ddsd.dwFlags = DDSD_CAPS;
2794 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2796 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2797 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2798 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2799 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2800 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
2801 registry_mode.dmPelsWidth, ddsd.dwWidth);
2802 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
2803 registry_mode.dmPelsHeight, ddsd.dwHeight);
2805 GetWindowRect(window, &r);
2806 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2807 wine_dbgstr_rect(&r));
2809 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
2810 expect_messages = normal_messages;
2811 screen_size.cx = 0;
2812 screen_size.cy = 0;
2814 hr = IDirectDrawSurface_IsLost(primary);
2815 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
2816 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
2817 devmode.dmPelsWidth = param.user32_width;
2818 devmode.dmPelsHeight = param.user32_height;
2819 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
2820 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#x.\n", change_ret);
2821 hr = IDirectDrawSurface_IsLost(primary);
2822 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
2824 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2825 expect_messages = NULL;
2826 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2828 GetWindowRect(window, &r);
2829 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2830 wine_dbgstr_rect(&r));
2832 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
2833 expect_messages = normal_messages;
2834 screen_size.cx = 0;
2835 screen_size.cy = 0;
2837 hr = IDirectDrawSurface_Restore(primary);
2838 todo_wine ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#x.\n", hr);
2839 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
2840 if (hr == DDERR_NOEXCLUSIVEMODE /* NT4 testbot */)
2842 win_skip("Broken SetDisplayMode(), skipping remaining tests.\n");
2843 IDirectDrawSurface_Release(primary);
2844 IDirectDraw2_Release(ddraw);
2845 goto done;
2847 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
2848 hr = IDirectDrawSurface_Restore(primary);
2849 todo_wine ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#x.\n", hr);
2850 hr = IDirectDrawSurface_IsLost(primary);
2851 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
2853 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2854 expect_messages = NULL;
2855 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2857 GetWindowRect(window, &r);
2858 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2859 wine_dbgstr_rect(&r));
2861 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2862 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2863 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
2864 registry_mode.dmPelsWidth, ddsd.dwWidth);
2865 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
2866 registry_mode.dmPelsHeight, ddsd.dwHeight);
2867 IDirectDrawSurface_Release(primary);
2869 memset(&ddsd, 0, sizeof(ddsd));
2870 ddsd.dwSize = sizeof(ddsd);
2871 ddsd.dwFlags = DDSD_CAPS;
2872 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2874 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2875 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2876 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2877 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2878 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %u, got %u.\n",
2879 param.ddraw_width, ddsd.dwWidth);
2880 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %u, got %u.\n",
2881 param.ddraw_height, ddsd.dwHeight);
2883 GetWindowRect(window, &r);
2884 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2885 wine_dbgstr_rect(&r));
2887 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
2888 expect_messages = normal_messages;
2889 screen_size.cx = 0;
2890 screen_size.cy = 0;
2892 hr = IDirectDrawSurface_IsLost(primary);
2893 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
2894 hr = IDirectDraw_RestoreDisplayMode(ddraw);
2895 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2896 hr = IDirectDrawSurface_IsLost(primary);
2897 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
2899 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2900 expect_messages = NULL;
2901 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2903 GetWindowRect(window, &r);
2904 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2905 wine_dbgstr_rect(&r));
2907 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2908 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2909 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %u, got %u.\n",
2910 param.ddraw_width, ddsd.dwWidth);
2911 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %u, got %u.\n",
2912 param.ddraw_height, ddsd.dwHeight);
2913 IDirectDrawSurface_Release(primary);
2915 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
2916 ok(ret, "Failed to get display mode.\n");
2917 ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
2918 && devmode.dmPelsHeight == registry_mode.dmPelsHeight,
2919 "Expected resolution %ux%u, got %ux%u.\n",
2920 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight,
2921 devmode.dmPelsWidth, devmode.dmPelsHeight);
2922 change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
2923 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#x.\n", change_ret);
2925 memset(&ddsd, 0, sizeof(ddsd));
2926 ddsd.dwSize = sizeof(ddsd);
2927 ddsd.dwFlags = DDSD_CAPS;
2928 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2930 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2931 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2932 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2933 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2934 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
2935 registry_mode.dmPelsWidth, ddsd.dwWidth);
2936 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
2937 registry_mode.dmPelsHeight, ddsd.dwHeight);
2939 GetWindowRect(window, &r);
2940 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2941 wine_dbgstr_rect(&r));
2943 /* DDSCL_NORMAL | DDSCL_FULLSCREEN behaves the same as just DDSCL_NORMAL.
2944 * Resizing the window on mode changes is a property of DDSCL_EXCLUSIVE,
2945 * not DDSCL_FULLSCREEN. */
2946 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
2947 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2949 GetWindowRect(window, &r);
2950 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2951 wine_dbgstr_rect(&r));
2953 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2954 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2955 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
2956 registry_mode.dmPelsWidth, ddsd.dwWidth);
2957 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
2958 registry_mode.dmPelsHeight, ddsd.dwHeight);
2959 IDirectDrawSurface_Release(primary);
2961 memset(&ddsd, 0, sizeof(ddsd));
2962 ddsd.dwSize = sizeof(ddsd);
2963 ddsd.dwFlags = DDSD_CAPS;
2964 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2966 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2967 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2968 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2969 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2970 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
2971 registry_mode.dmPelsWidth, ddsd.dwWidth);
2972 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
2973 registry_mode.dmPelsHeight, ddsd.dwHeight);
2975 GetWindowRect(window, &r);
2976 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
2977 wine_dbgstr_rect(&r));
2979 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
2980 expect_messages = normal_messages;
2981 screen_size.cx = 0;
2982 screen_size.cy = 0;
2984 hr = IDirectDrawSurface_IsLost(primary);
2985 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
2986 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
2987 devmode.dmPelsWidth = param.user32_width;
2988 devmode.dmPelsHeight = param.user32_height;
2989 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
2990 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#x.\n", change_ret);
2991 hr = IDirectDrawSurface_IsLost(primary);
2992 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
2994 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2995 expect_messages = NULL;
2996 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2998 GetWindowRect(window, &r);
2999 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3000 wine_dbgstr_rect(&r));
3002 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3003 expect_messages = normal_messages;
3004 screen_size.cx = 0;
3005 screen_size.cy = 0;
3007 hr = IDirectDrawSurface_Restore(primary);
3008 todo_wine ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#x.\n", hr);
3009 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3010 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3011 hr = IDirectDrawSurface_Restore(primary);
3012 todo_wine ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#x.\n", hr);
3013 hr = IDirectDrawSurface_IsLost(primary);
3014 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
3016 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3017 expect_messages = NULL;
3018 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
3020 GetWindowRect(window, &r);
3021 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3022 wine_dbgstr_rect(&r));
3024 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3025 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
3026 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
3027 registry_mode.dmPelsWidth, ddsd.dwWidth);
3028 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
3029 registry_mode.dmPelsHeight, ddsd.dwHeight);
3030 IDirectDrawSurface_Release(primary);
3032 memset(&ddsd, 0, sizeof(ddsd));
3033 ddsd.dwSize = sizeof(ddsd);
3034 ddsd.dwFlags = DDSD_CAPS;
3035 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3037 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3038 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
3039 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3040 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
3041 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %u, got %u.\n",
3042 param.ddraw_width, ddsd.dwWidth);
3043 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %u, got %u.\n",
3044 param.ddraw_height, ddsd.dwHeight);
3046 GetWindowRect(window, &r);
3047 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3048 wine_dbgstr_rect(&r));
3050 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3051 expect_messages = normal_messages;
3052 screen_size.cx = 0;
3053 screen_size.cy = 0;
3055 hr = IDirectDrawSurface_IsLost(primary);
3056 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
3057 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
3058 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
3059 hr = IDirectDrawSurface_IsLost(primary);
3060 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
3062 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3063 expect_messages = NULL;
3064 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
3066 GetWindowRect(window, &r);
3067 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3068 wine_dbgstr_rect(&r));
3070 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3071 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
3072 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %u, got %u.\n",
3073 param.ddraw_width, ddsd.dwWidth);
3074 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %u, got %u.\n",
3075 param.ddraw_height, ddsd.dwHeight);
3076 IDirectDrawSurface_Release(primary);
3078 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3079 ok(ret, "Failed to get display mode.\n");
3080 ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
3081 && devmode.dmPelsHeight == registry_mode.dmPelsHeight,
3082 "Expected resolution %ux%u, got %ux%u.\n",
3083 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight,
3084 devmode.dmPelsWidth, devmode.dmPelsHeight);
3085 change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
3086 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#x.\n", change_ret);
3088 memset(&ddsd, 0, sizeof(ddsd));
3089 ddsd.dwSize = sizeof(ddsd);
3090 ddsd.dwFlags = DDSD_CAPS;
3091 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3093 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3094 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
3095 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3096 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
3097 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
3098 registry_mode.dmPelsWidth, ddsd.dwWidth);
3099 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
3100 registry_mode.dmPelsHeight, ddsd.dwHeight);
3101 IDirectDrawSurface_Release(primary);
3103 GetWindowRect(window, &r);
3104 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3105 wine_dbgstr_rect(&r));
3107 /* Changing the coop level from EXCLUSIVE to NORMAL restores the screen resolution */
3108 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3109 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3110 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3111 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3113 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3114 expect_messages = exclusive_messages;
3115 screen_size.cx = 0;
3116 screen_size.cy = 0;
3118 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3119 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3121 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3122 expect_messages = NULL;
3123 ok(screen_size.cx == registry_mode.dmPelsWidth
3124 && screen_size.cy == registry_mode.dmPelsHeight,
3125 "Expected screen size %ux%u, got %ux%u.\n",
3126 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight,
3127 screen_size.cx, screen_size.cy);
3129 GetWindowRect(window, &r);
3130 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3131 wine_dbgstr_rect(&r));
3133 memset(&ddsd, 0, sizeof(ddsd));
3134 ddsd.dwSize = sizeof(ddsd);
3135 ddsd.dwFlags = DDSD_CAPS;
3136 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3138 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3139 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
3140 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3141 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
3142 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
3143 registry_mode.dmPelsWidth, ddsd.dwWidth);
3144 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
3145 registry_mode.dmPelsHeight, ddsd.dwHeight);
3146 IDirectDrawSurface_Release(primary);
3148 /* The screen restore is a property of DDSCL_EXCLUSIVE */
3149 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
3150 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3151 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3152 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3154 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3155 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3157 memset(&ddsd, 0, sizeof(ddsd));
3158 ddsd.dwSize = sizeof(ddsd);
3159 ddsd.dwFlags = DDSD_CAPS;
3160 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3162 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3163 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
3164 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3165 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
3166 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %u, got %u.\n",
3167 param.ddraw_width, ddsd.dwWidth);
3168 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %u, got %u.\n",
3169 param.ddraw_height, ddsd.dwHeight);
3170 IDirectDrawSurface_Release(primary);
3172 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
3173 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
3175 /* If the window is changed at the same time, messages are sent to the new window. */
3176 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3177 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3178 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3179 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3181 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3182 expect_messages = exclusive_messages;
3183 screen_size.cx = 0;
3184 screen_size.cy = 0;
3185 screen_size2.cx = 0;
3186 screen_size2.cy = 0;
3188 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL);
3189 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3191 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3192 expect_messages = NULL;
3193 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %ux%u.\n",
3194 screen_size.cx, screen_size.cy);
3195 ok(screen_size2.cx == registry_mode.dmPelsWidth && screen_size2.cy == registry_mode.dmPelsHeight,
3196 "Expected screen size 2 %ux%u, got %ux%u.\n",
3197 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight, screen_size2.cx, screen_size2.cy);
3199 GetWindowRect(window, &r);
3200 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3201 wine_dbgstr_rect(&r));
3202 GetWindowRect(window2, &r);
3203 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3204 wine_dbgstr_rect(&r));
3206 memset(&ddsd, 0, sizeof(ddsd));
3207 ddsd.dwSize = sizeof(ddsd);
3208 ddsd.dwFlags = DDSD_CAPS;
3209 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3211 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3212 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
3213 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3214 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
3215 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %u, got %u.\n",
3216 registry_mode.dmPelsWidth, ddsd.dwWidth);
3217 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %u, got %u.\n",
3218 registry_mode.dmPelsHeight, ddsd.dwHeight);
3219 IDirectDrawSurface_Release(primary);
3221 ref = IDirectDraw2_Release(ddraw);
3222 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3224 GetWindowRect(window, &r);
3225 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3226 wine_dbgstr_rect(&r));
3228 done:
3229 expect_messages = NULL;
3230 DestroyWindow(window);
3231 DestroyWindow(window2);
3232 UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
3233 UnregisterClassA("ddraw_test_wndproc_wc2", GetModuleHandleA(NULL));
3236 static void test_coop_level_mode_set_multi(void)
3238 IDirectDraw2 *ddraw1, *ddraw2;
3239 UINT w, h;
3240 HWND window;
3241 HRESULT hr;
3242 ULONG ref;
3244 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
3245 0, 0, 100, 100, 0, 0, 0, 0);
3246 ddraw1 = create_ddraw();
3247 ok(!!ddraw1, "Failed to create a ddraw object.\n");
3249 /* With just a single ddraw object, the display mode is restored on
3250 * release. */
3251 hr = set_display_mode(ddraw1, 800, 600);
3252 if (hr == DDERR_NOEXCLUSIVEMODE /* NT4 testbot */)
3254 win_skip("Broken SetDisplayMode(), skipping test.\n");
3255 IDirectDraw2_Release(ddraw1);
3256 DestroyWindow(window);
3257 return;
3259 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3260 w = GetSystemMetrics(SM_CXSCREEN);
3261 ok(w == 800, "Got unexpected screen width %u.\n", w);
3262 h = GetSystemMetrics(SM_CYSCREEN);
3263 ok(h == 600, "Got unexpected screen height %u.\n", h);
3265 ref = IDirectDraw2_Release(ddraw1);
3266 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3267 w = GetSystemMetrics(SM_CXSCREEN);
3268 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3269 h = GetSystemMetrics(SM_CYSCREEN);
3270 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3272 /* When there are multiple ddraw objects, the display mode is restored to
3273 * the initial mode, before the first SetDisplayMode() call. */
3274 ddraw1 = create_ddraw();
3275 hr = set_display_mode(ddraw1, 800, 600);
3276 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3277 w = GetSystemMetrics(SM_CXSCREEN);
3278 ok(w == 800, "Got unexpected screen width %u.\n", w);
3279 h = GetSystemMetrics(SM_CYSCREEN);
3280 ok(h == 600, "Got unexpected screen height %u.\n", h);
3282 ddraw2 = create_ddraw();
3283 hr = set_display_mode(ddraw2, 640, 480);
3284 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3285 w = GetSystemMetrics(SM_CXSCREEN);
3286 ok(w == 640, "Got unexpected screen width %u.\n", w);
3287 h = GetSystemMetrics(SM_CYSCREEN);
3288 ok(h == 480, "Got unexpected screen height %u.\n", h);
3290 ref = IDirectDraw2_Release(ddraw2);
3291 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3292 w = GetSystemMetrics(SM_CXSCREEN);
3293 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3294 h = GetSystemMetrics(SM_CYSCREEN);
3295 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3297 ref = IDirectDraw2_Release(ddraw1);
3298 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3299 w = GetSystemMetrics(SM_CXSCREEN);
3300 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3301 h = GetSystemMetrics(SM_CYSCREEN);
3302 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3304 /* Regardless of release ordering. */
3305 ddraw1 = create_ddraw();
3306 hr = set_display_mode(ddraw1, 800, 600);
3307 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3308 w = GetSystemMetrics(SM_CXSCREEN);
3309 ok(w == 800, "Got unexpected screen width %u.\n", w);
3310 h = GetSystemMetrics(SM_CYSCREEN);
3311 ok(h == 600, "Got unexpected screen height %u.\n", h);
3313 ddraw2 = create_ddraw();
3314 hr = set_display_mode(ddraw2, 640, 480);
3315 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3316 w = GetSystemMetrics(SM_CXSCREEN);
3317 ok(w == 640, "Got unexpected screen width %u.\n", w);
3318 h = GetSystemMetrics(SM_CYSCREEN);
3319 ok(h == 480, "Got unexpected screen height %u.\n", h);
3321 ref = IDirectDraw2_Release(ddraw1);
3322 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3323 w = GetSystemMetrics(SM_CXSCREEN);
3324 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3325 h = GetSystemMetrics(SM_CYSCREEN);
3326 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3328 ref = IDirectDraw2_Release(ddraw2);
3329 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3330 w = GetSystemMetrics(SM_CXSCREEN);
3331 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3332 h = GetSystemMetrics(SM_CYSCREEN);
3333 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3335 /* But only for ddraw objects that called SetDisplayMode(). */
3336 ddraw1 = create_ddraw();
3337 ddraw2 = create_ddraw();
3338 hr = set_display_mode(ddraw2, 640, 480);
3339 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3340 w = GetSystemMetrics(SM_CXSCREEN);
3341 ok(w == 640, "Got unexpected screen width %u.\n", w);
3342 h = GetSystemMetrics(SM_CYSCREEN);
3343 ok(h == 480, "Got unexpected screen height %u.\n", h);
3345 ref = IDirectDraw2_Release(ddraw1);
3346 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3347 w = GetSystemMetrics(SM_CXSCREEN);
3348 ok(w == 640, "Got unexpected screen width %u.\n", w);
3349 h = GetSystemMetrics(SM_CYSCREEN);
3350 ok(h == 480, "Got unexpected screen height %u.\n", h);
3352 ref = IDirectDraw2_Release(ddraw2);
3353 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3354 w = GetSystemMetrics(SM_CXSCREEN);
3355 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3356 h = GetSystemMetrics(SM_CYSCREEN);
3357 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3359 /* If there's a ddraw object that's currently in exclusive mode, it blocks
3360 * restoring the display mode. */
3361 ddraw1 = create_ddraw();
3362 hr = set_display_mode(ddraw1, 800, 600);
3363 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3364 w = GetSystemMetrics(SM_CXSCREEN);
3365 ok(w == 800, "Got unexpected screen width %u.\n", w);
3366 h = GetSystemMetrics(SM_CYSCREEN);
3367 ok(h == 600, "Got unexpected screen height %u.\n", h);
3369 ddraw2 = create_ddraw();
3370 hr = set_display_mode(ddraw2, 640, 480);
3371 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3372 w = GetSystemMetrics(SM_CXSCREEN);
3373 ok(w == 640, "Got unexpected screen width %u.\n", w);
3374 h = GetSystemMetrics(SM_CYSCREEN);
3375 ok(h == 480, "Got unexpected screen height %u.\n", h);
3377 hr = IDirectDraw2_SetCooperativeLevel(ddraw2, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3378 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3380 ref = IDirectDraw2_Release(ddraw1);
3381 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3382 w = GetSystemMetrics(SM_CXSCREEN);
3383 ok(w == 640, "Got unexpected screen width %u.\n", w);
3384 h = GetSystemMetrics(SM_CYSCREEN);
3385 ok(h == 480, "Got unexpected screen height %u.\n", h);
3387 ref = IDirectDraw2_Release(ddraw2);
3388 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3389 w = GetSystemMetrics(SM_CXSCREEN);
3390 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3391 h = GetSystemMetrics(SM_CYSCREEN);
3392 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3394 /* Exclusive mode blocks mode setting on other ddraw objects in general. */
3395 ddraw1 = create_ddraw();
3396 hr = set_display_mode(ddraw1, 800, 600);
3397 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3398 w = GetSystemMetrics(SM_CXSCREEN);
3399 ok(w == 800, "Got unexpected screen width %u.\n", w);
3400 h = GetSystemMetrics(SM_CYSCREEN);
3401 ok(h == 600, "Got unexpected screen height %u.\n", h);
3403 hr = IDirectDraw2_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3404 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3406 ddraw2 = create_ddraw();
3407 hr = set_display_mode(ddraw2, 640, 480);
3408 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#x.\n", hr);
3410 ref = IDirectDraw2_Release(ddraw1);
3411 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3412 w = GetSystemMetrics(SM_CXSCREEN);
3413 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3414 h = GetSystemMetrics(SM_CYSCREEN);
3415 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3417 ref = IDirectDraw2_Release(ddraw2);
3418 ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3419 w = GetSystemMetrics(SM_CXSCREEN);
3420 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3421 h = GetSystemMetrics(SM_CYSCREEN);
3422 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3424 DestroyWindow(window);
3427 static void test_initialize(void)
3429 IDirectDraw2 *ddraw;
3430 HRESULT hr;
3432 ddraw = create_ddraw();
3433 ok(!!ddraw, "Failed to create a ddraw object.\n");
3435 hr = IDirectDraw2_Initialize(ddraw, NULL);
3436 ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x.\n", hr);
3437 IDirectDraw2_Release(ddraw);
3439 CoInitialize(NULL);
3440 hr = CoCreateInstance(&CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectDraw2, (void **)&ddraw);
3441 ok(SUCCEEDED(hr), "Failed to create IDirectDraw2 instance, hr %#x.\n", hr);
3442 hr = IDirectDraw2_Initialize(ddraw, NULL);
3443 ok(hr == DD_OK, "Initialize returned hr %#x, expected DD_OK.\n", hr);
3444 hr = IDirectDraw2_Initialize(ddraw, NULL);
3445 ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x, expected DDERR_ALREADYINITIALIZED.\n", hr);
3446 IDirectDraw2_Release(ddraw);
3447 CoUninitialize();
3450 static void test_coop_level_surf_create(void)
3452 IDirectDrawSurface *surface;
3453 IDirectDraw2 *ddraw;
3454 DDSURFACEDESC ddsd;
3455 HRESULT hr;
3457 ddraw = create_ddraw();
3458 ok(!!ddraw, "Failed to create a ddraw object.\n");
3460 memset(&ddsd, 0, sizeof(ddsd));
3461 ddsd.dwSize = sizeof(ddsd);
3462 ddsd.dwFlags = DDSD_CAPS;
3463 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3464 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
3465 ok(hr == DDERR_NOCOOPERATIVELEVELSET, "Surface creation returned hr %#x.\n", hr);
3467 IDirectDraw2_Release(ddraw);
3470 static void test_coop_level_multi_window(void)
3472 HWND window1, window2;
3473 IDirectDraw2 *ddraw;
3474 HRESULT hr;
3476 window1 = CreateWindowA("static", "ddraw_test1", WS_OVERLAPPEDWINDOW,
3477 0, 0, 640, 480, 0, 0, 0, 0);
3478 window2 = CreateWindowA("static", "ddraw_test2", WS_OVERLAPPEDWINDOW,
3479 0, 0, 640, 480, 0, 0, 0, 0);
3480 ddraw = create_ddraw();
3481 ok(!!ddraw, "Failed to create a ddraw object.\n");
3483 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
3484 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3485 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL);
3486 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3487 ok(IsWindow(window1), "Window 1 was destroyed.\n");
3488 ok(IsWindow(window2), "Window 2 was destroyed.\n");
3490 IDirectDraw2_Release(ddraw);
3491 DestroyWindow(window2);
3492 DestroyWindow(window1);
3495 static void test_clear_rect_count(void)
3497 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
3498 IDirect3DMaterial2 *white, *red, *green, *blue;
3499 IDirect3DViewport2 *viewport;
3500 IDirect3DDevice2 *device;
3501 IDirectDrawSurface *rt;
3502 IDirectDraw2 *ddraw;
3503 D3DCOLOR color;
3504 HWND window;
3505 HRESULT hr;
3507 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
3508 0, 0, 640, 480, 0, 0, 0, 0);
3509 ddraw = create_ddraw();
3510 ok(!!ddraw, "Failed to create a ddraw object.\n");
3511 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
3513 skip("Failed to create a 3D device, skipping test.\n");
3514 IDirectDraw2_Release(ddraw);
3515 DestroyWindow(window);
3516 return;
3519 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
3520 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
3522 white = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
3523 red = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
3524 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 1.0f);
3525 blue = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
3527 viewport = create_viewport(device, 0, 0, 640, 480);
3528 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
3529 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
3531 viewport_set_background(device, viewport, white);
3532 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
3533 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
3534 viewport_set_background(device, viewport, red);
3535 hr = IDirect3DViewport2_Clear(viewport, 0, &clear_rect, D3DCLEAR_TARGET);
3536 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
3537 viewport_set_background(device, viewport, green);
3538 hr = IDirect3DViewport2_Clear(viewport, 0, NULL, D3DCLEAR_TARGET);
3539 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
3540 viewport_set_background(device, viewport, blue);
3541 hr = IDirect3DViewport2_Clear(viewport, 0, &clear_rect, D3DCLEAR_TARGET);
3542 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
3544 color = get_surface_color(rt, 320, 240);
3545 ok(compare_color(color, 0x00ffffff, 1) || broken(compare_color(color, 0x000000ff, 1)),
3546 "Got unexpected color 0x%08x.\n", color);
3548 IDirectDrawSurface_Release(rt);
3549 destroy_viewport(device, viewport);
3550 destroy_material(white);
3551 destroy_material(red);
3552 destroy_material(green);
3553 destroy_material(blue);
3554 IDirect3DDevice2_Release(device);
3555 IDirectDraw2_Release(ddraw);
3556 DestroyWindow(window);
3559 static BOOL test_mode_restored(IDirectDraw2 *ddraw, HWND window)
3561 DDSURFACEDESC ddsd1, ddsd2;
3562 HRESULT hr;
3564 memset(&ddsd1, 0, sizeof(ddsd1));
3565 ddsd1.dwSize = sizeof(ddsd1);
3566 hr = IDirectDraw2_GetDisplayMode(ddraw, &ddsd1);
3567 ok(SUCCEEDED(hr), "GetDisplayMode failed, hr %#x.\n", hr);
3569 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3570 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3571 hr = set_display_mode(ddraw, 640, 480);
3572 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
3573 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3574 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3576 memset(&ddsd2, 0, sizeof(ddsd2));
3577 ddsd2.dwSize = sizeof(ddsd2);
3578 hr = IDirectDraw2_GetDisplayMode(ddraw, &ddsd2);
3579 ok(SUCCEEDED(hr), "GetDisplayMode failed, hr %#x.\n", hr);
3580 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
3581 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
3583 return ddsd1.dwWidth == ddsd2.dwWidth && ddsd1.dwHeight == ddsd2.dwHeight;
3586 static void test_coop_level_versions(void)
3588 HWND window;
3589 IDirectDraw *ddraw;
3590 HRESULT hr;
3591 BOOL restored;
3592 IDirectDrawSurface *surface;
3593 IDirectDraw2 *ddraw2;
3594 DDSURFACEDESC ddsd;
3596 window = CreateWindowA("static", "ddraw_test1", WS_OVERLAPPEDWINDOW,
3597 0, 0, 640, 480, 0, 0, 0, 0);
3599 ddraw2 = create_ddraw();
3600 ok(!!ddraw2, "Failed to create a ddraw object.\n");
3601 /* Newly created ddraw objects restore the mode on ddraw2+::SetCooperativeLevel(NORMAL) */
3602 restored = test_mode_restored(ddraw2, window);
3603 ok(restored, "Display mode not restored in new ddraw object\n");
3605 /* A failing ddraw1::SetCooperativeLevel call does not have an effect */
3606 hr = IDirectDraw2_QueryInterface(ddraw2, &IID_IDirectDraw, (void **)&ddraw);
3607 ok(SUCCEEDED(hr), "QueryInterface failed, hr %#x.\n", hr);
3609 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
3610 ok(FAILED(hr), "SetCooperativeLevel returned %#x, expected failure.\n", hr);
3611 restored = test_mode_restored(ddraw2, window);
3612 ok(restored, "Display mode not restored after bad ddraw1::SetCooperativeLevel call\n");
3614 /* A successful one does */
3615 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
3616 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3617 restored = test_mode_restored(ddraw2, window);
3618 ok(!restored, "Display mode restored after good ddraw1::SetCooperativeLevel call\n");
3620 IDirectDraw_Release(ddraw);
3621 IDirectDraw2_Release(ddraw2);
3623 ddraw2 = create_ddraw();
3624 ok(!!ddraw2, "Failed to create a ddraw object.\n");
3625 hr = IDirectDraw2_QueryInterface(ddraw2, &IID_IDirectDraw, (void **)&ddraw);
3626 ok(SUCCEEDED(hr), "QueryInterface failed, hr %#x.\n", hr);
3628 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_SETFOCUSWINDOW);
3629 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3630 restored = test_mode_restored(ddraw2, window);
3631 ok(!restored, "Display mode restored after ddraw1::SetCooperativeLevel(SETFOCUSWINDOW) call\n");
3633 IDirectDraw_Release(ddraw);
3634 IDirectDraw2_Release(ddraw2);
3636 /* A failing call does not restore the ddraw2+ behavior */
3637 ddraw2 = create_ddraw();
3638 ok(!!ddraw2, "Failed to create a ddraw object.\n");
3639 hr = IDirectDraw2_QueryInterface(ddraw2, &IID_IDirectDraw, (void **)&ddraw);
3640 ok(SUCCEEDED(hr), "QueryInterface failed, hr %#x.\n", hr);
3642 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
3643 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3644 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
3645 ok(FAILED(hr), "SetCooperativeLevel returned %#x, expected failure.\n", hr);
3646 restored = test_mode_restored(ddraw2, window);
3647 ok(!restored, "Display mode restored after good-bad ddraw1::SetCooperativeLevel() call sequence\n");
3649 IDirectDraw_Release(ddraw);
3650 IDirectDraw2_Release(ddraw2);
3652 /* Neither does a sequence of successful calls with the new interface */
3653 ddraw2 = create_ddraw();
3654 ok(!!ddraw2, "Failed to create a ddraw object.\n");
3655 hr = IDirectDraw2_QueryInterface(ddraw2, &IID_IDirectDraw, (void **)&ddraw);
3656 ok(SUCCEEDED(hr), "QueryInterface failed, hr %#x.\n", hr);
3658 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
3659 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3660 hr = IDirectDraw2_SetCooperativeLevel(ddraw2, window, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
3661 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3662 hr = IDirectDraw2_SetCooperativeLevel(ddraw2, window, DDSCL_NORMAL);
3663 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3665 restored = test_mode_restored(ddraw2, window);
3666 ok(!restored, "Display mode restored after ddraw1-ddraw2 SetCooperativeLevel() call sequence\n");
3667 IDirectDraw_Release(ddraw);
3668 IDirectDraw2_Release(ddraw2);
3670 /* ddraw1::CreateSurface does not triger the ddraw1 behavior */
3671 ddraw2 = create_ddraw();
3672 ok(!!ddraw2, "Failed to create a ddraw object.\n");
3673 hr = IDirectDraw2_QueryInterface(ddraw2, &IID_IDirectDraw, (void **)&ddraw);
3674 ok(SUCCEEDED(hr), "QueryInterface failed, hr %#x.\n", hr);
3676 hr = IDirectDraw2_SetCooperativeLevel(ddraw2, window, DDSCL_NORMAL);
3677 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3679 memset(&ddsd, 0, sizeof(ddsd));
3680 ddsd.dwSize = sizeof(ddsd);
3681 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
3682 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
3683 ddsd.dwWidth = ddsd.dwHeight = 8;
3684 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
3685 ok(SUCCEEDED(hr), "CreateSurface failed, hr %#x.\n", hr);
3686 IDirectDrawSurface_Release(surface);
3687 restored = test_mode_restored(ddraw2, window);
3688 ok(restored, "Display mode not restored after ddraw1::CreateSurface() call\n");
3690 IDirectDraw_Release(ddraw);
3691 IDirectDraw2_Release(ddraw2);
3692 DestroyWindow(window);
3695 static void test_lighting_interface_versions(void)
3697 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
3698 IDirect3DMaterial2 *emissive, *background;
3699 IDirect3DViewport2 *viewport;
3700 IDirect3DDevice2 *device;
3701 IDirectDrawSurface *rt;
3702 IDirectDraw2 *ddraw;
3703 D3DCOLOR color;
3704 HWND window;
3705 HRESULT hr;
3706 D3DMATERIALHANDLE mat_handle;
3707 DWORD rs;
3708 unsigned int i;
3709 ULONG ref;
3710 static D3DVERTEX quad[] =
3712 {{-1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
3713 {{ 1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
3714 {{-1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
3715 {{ 1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
3717 static D3DLVERTEX lquad[] =
3719 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xffff0000}, {0xff808080}},
3720 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xffff0000}, {0xff808080}},
3721 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xffff0000}, {0xff808080}},
3722 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xffff0000}, {0xff808080}},
3724 static D3DTLVERTEX tlquad[] =
3726 {{ 0.0f}, { 480.0f}, {0.0f}, {1.0f}, {0xff0000ff}, {0xff808080}},
3727 {{ 0.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xff0000ff}, {0xff808080}},
3728 {{ 640.0f}, { 480.0f}, {0.0f}, {1.0f}, {0xff0000ff}, {0xff808080}},
3729 {{ 640.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xff0000ff}, {0xff808080}},
3731 static const struct
3733 D3DVERTEXTYPE vertextype;
3734 void *data;
3735 DWORD d3drs_lighting, d3drs_specular;
3736 DWORD draw_flags;
3737 D3DCOLOR color;
3739 tests[] =
3741 /* Lighting is enabled when D3DVT_VERTEX is used and D3DDP_DONOTLIGHT is not
3742 * set. D3DVT_VERTEX has diffuse = 0xffffffff and specular = 0x00000000, as
3743 * in later d3d versions */
3744 { D3DVT_VERTEX, quad, FALSE, FALSE, 0, 0x0000ff00},
3745 { D3DVT_VERTEX, quad, TRUE, FALSE, 0, 0x0000ff00},
3746 { D3DVT_VERTEX, quad, FALSE, FALSE, D3DDP_DONOTLIGHT, 0x00ffffff},
3747 { D3DVT_VERTEX, quad, TRUE, FALSE, D3DDP_DONOTLIGHT, 0x00ffffff},
3748 { D3DVT_VERTEX, quad, FALSE, TRUE, 0, 0x0000ff00},
3749 { D3DVT_VERTEX, quad, TRUE, TRUE, 0, 0x0000ff00},
3750 { D3DVT_VERTEX, quad, FALSE, TRUE, D3DDP_DONOTLIGHT, 0x00ffffff},
3751 { D3DVT_VERTEX, quad, TRUE, TRUE, D3DDP_DONOTLIGHT, 0x00ffffff},
3753 { D3DVT_LVERTEX, lquad, FALSE, FALSE, 0, 0x00ff0000},
3754 { D3DVT_LVERTEX, lquad, TRUE, FALSE, 0, 0x00ff0000},
3755 { D3DVT_LVERTEX, lquad, FALSE, FALSE, D3DDP_DONOTLIGHT, 0x00ff0000},
3756 { D3DVT_LVERTEX, lquad, TRUE, FALSE, D3DDP_DONOTLIGHT, 0x00ff0000},
3757 { D3DVT_LVERTEX, lquad, FALSE, TRUE, 0, 0x00ff8080},
3758 { D3DVT_LVERTEX, lquad, TRUE, TRUE, 0, 0x00ff8080},
3759 { D3DVT_LVERTEX, lquad, FALSE, TRUE, D3DDP_DONOTLIGHT, 0x00ff8080},
3760 { D3DVT_LVERTEX, lquad, TRUE, TRUE, D3DDP_DONOTLIGHT, 0x00ff8080},
3762 { D3DVT_TLVERTEX, tlquad, FALSE, FALSE, 0, 0x000000ff},
3763 { D3DVT_TLVERTEX, tlquad, TRUE, FALSE, 0, 0x000000ff},
3764 { D3DVT_TLVERTEX, tlquad, FALSE, FALSE, D3DDP_DONOTLIGHT, 0x000000ff},
3765 { D3DVT_TLVERTEX, tlquad, TRUE, FALSE, D3DDP_DONOTLIGHT, 0x000000ff},
3766 { D3DVT_TLVERTEX, tlquad, FALSE, TRUE, 0, 0x008080ff},
3767 { D3DVT_TLVERTEX, tlquad, TRUE, TRUE, 0, 0x008080ff},
3768 { D3DVT_TLVERTEX, tlquad, FALSE, TRUE, D3DDP_DONOTLIGHT, 0x008080ff},
3769 { D3DVT_TLVERTEX, tlquad, TRUE, TRUE, D3DDP_DONOTLIGHT, 0x008080ff},
3772 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
3773 0, 0, 640, 480, 0, 0, 0, 0);
3774 ddraw = create_ddraw();
3775 ok(!!ddraw, "Failed to create a ddraw object.\n");
3776 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
3778 skip("Failed to create a 3D device, skipping test.\n");
3779 IDirectDraw2_Release(ddraw);
3780 DestroyWindow(window);
3781 return;
3784 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
3785 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
3787 viewport = create_viewport(device, 0, 0, 640, 480);
3788 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
3789 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
3791 emissive = create_emissive_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
3792 hr = IDirect3DMaterial2_GetHandle(emissive, device, &mat_handle);
3793 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
3794 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
3795 ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
3796 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
3797 ok(SUCCEEDED(hr), "Failed to disable z test, hr %#x.\n", hr);
3799 background = create_diffuse_material(device, 0.1f, 0.1f, 0.1f, 0.1f);
3800 viewport_set_background(device, viewport, background);
3802 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_SPECULARENABLE, &rs);
3803 ok(SUCCEEDED(hr), "Failed to get specularenable render state, hr %#x.\n", hr);
3804 ok(rs == TRUE, "Initial D3DRENDERSTATE_SPECULARENABLE is %#x, expected TRUE.\n", rs);
3806 for (i = 0; i < sizeof(tests) / sizeof(*tests); i++)
3808 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
3809 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
3811 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, tests[i].d3drs_lighting);
3812 ok(SUCCEEDED(hr), "Failed to set lighting render state, hr %#x.\n", hr);
3813 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SPECULARENABLE,
3814 tests[i].d3drs_specular);
3815 ok(SUCCEEDED(hr), "Failed to set specularenable render state, hr %#x.\n", hr);
3817 hr = IDirect3DDevice2_BeginScene(device);
3818 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
3819 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP,
3820 tests[i].vertextype, tests[i].data, 4, tests[i].draw_flags | D3DDP_WAIT);
3821 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
3822 hr = IDirect3DDevice2_EndScene(device);
3823 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
3825 color = get_surface_color(rt, 320, 240);
3826 ok(compare_color(color, tests[i].color, 1),
3827 "Got unexpected color 0x%08x, expected 0x%08x, test %u.\n",
3828 color, tests[i].color, i);
3831 destroy_material(background);
3832 destroy_material(emissive);
3833 IDirectDrawSurface_Release(rt);
3834 IDirect3DDevice2_Release(device);
3835 ref = IDirectDraw2_Release(ddraw);
3836 ok(ref == 0, "Ddraw object not properly released, refcount %u.\n", ref);
3837 DestroyWindow(window);
3840 static struct
3842 BOOL received;
3843 IDirectDraw2 *ddraw;
3844 HWND window;
3845 DWORD coop_level;
3846 } activateapp_testdata;
3848 static LRESULT CALLBACK activateapp_test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
3850 if (message == WM_ACTIVATEAPP)
3852 if (activateapp_testdata.ddraw)
3854 HRESULT hr;
3855 activateapp_testdata.received = FALSE;
3856 hr = IDirectDraw2_SetCooperativeLevel(activateapp_testdata.ddraw,
3857 activateapp_testdata.window, activateapp_testdata.coop_level);
3858 ok(SUCCEEDED(hr), "Recursive SetCooperativeLevel call failed, hr %#x.\n", hr);
3859 ok(!activateapp_testdata.received, "Received WM_ACTIVATEAPP during recursive SetCooperativeLevel call.\n");
3861 activateapp_testdata.received = TRUE;
3864 return DefWindowProcA(hwnd, message, wparam, lparam);
3867 static void test_coop_level_activateapp(void)
3869 IDirectDraw2 *ddraw;
3870 HRESULT hr;
3871 HWND window;
3872 WNDCLASSA wc = {0};
3873 DDSURFACEDESC ddsd;
3874 IDirectDrawSurface *surface;
3876 ddraw = create_ddraw();
3877 ok(!!ddraw, "Failed to create a ddraw object.\n");
3879 wc.lpfnWndProc = activateapp_test_proc;
3880 wc.lpszClassName = "ddraw_test_wndproc_wc";
3881 ok(RegisterClassA(&wc), "Failed to register window class.\n");
3883 window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test",
3884 WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
3886 /* Exclusive with window already active. */
3887 SetForegroundWindow(window);
3888 activateapp_testdata.received = FALSE;
3889 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3890 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3891 ok(!activateapp_testdata.received, "Received WM_ACTIVATEAPP although window was already active.\n");
3892 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
3893 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3895 /* Exclusive with window not active. */
3896 SetForegroundWindow(GetDesktopWindow());
3897 activateapp_testdata.received = FALSE;
3898 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3899 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3900 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
3901 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
3902 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3904 /* Normal with window not active, then exclusive with the same window. */
3905 SetForegroundWindow(GetDesktopWindow());
3906 activateapp_testdata.received = FALSE;
3907 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3908 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3909 ok(!activateapp_testdata.received, "Received WM_ACTIVATEAPP when setting DDSCL_NORMAL.\n");
3910 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3911 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3912 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
3913 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
3914 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3916 /* Recursive set of DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN. */
3917 SetForegroundWindow(GetDesktopWindow());
3918 activateapp_testdata.received = FALSE;
3919 activateapp_testdata.ddraw = ddraw;
3920 activateapp_testdata.window = window;
3921 activateapp_testdata.coop_level = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
3922 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3923 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3924 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
3925 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
3926 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3928 /* The recursive call seems to have some bad effect on native ddraw, despite (apparently)
3929 * succeeding. Another switch to exclusive and back to normal is needed to release the
3930 * window properly. Without doing this, SetCooperativeLevel(EXCLUSIVE) will not send
3931 * WM_ACTIVATEAPP messages. */
3932 activateapp_testdata.ddraw = NULL;
3933 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3934 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3935 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
3936 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3938 /* Setting DDSCL_NORMAL with recursive invocation. */
3939 SetForegroundWindow(GetDesktopWindow());
3940 activateapp_testdata.received = FALSE;
3941 activateapp_testdata.ddraw = ddraw;
3942 activateapp_testdata.window = window;
3943 activateapp_testdata.coop_level = DDSCL_NORMAL;
3944 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3945 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3946 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
3948 /* DDraw is in exlusive mode now. */
3949 memset(&ddsd, 0, sizeof(ddsd));
3950 ddsd.dwSize = sizeof(ddsd);
3951 ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
3952 ddsd.dwBackBufferCount = 1;
3953 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
3954 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
3955 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
3956 IDirectDrawSurface_Release(surface);
3958 /* Recover again, just to be sure. */
3959 activateapp_testdata.ddraw = NULL;
3960 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3961 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3962 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
3963 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
3965 DestroyWindow(window);
3966 UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
3967 IDirectDraw2_Release(ddraw);
3970 struct format_support_check
3972 const DDPIXELFORMAT *format;
3973 BOOL supported;
3976 static HRESULT WINAPI test_unsupported_formats_cb(DDSURFACEDESC *desc, void *ctx)
3978 struct format_support_check *format = ctx;
3980 if (!memcmp(format->format, &desc->ddpfPixelFormat, sizeof(*format->format)))
3982 format->supported = TRUE;
3983 return DDENUMRET_CANCEL;
3986 return DDENUMRET_OK;
3989 static void test_unsupported_formats(void)
3991 HRESULT hr;
3992 BOOL expect_success;
3993 HWND window;
3994 IDirectDraw2 *ddraw;
3995 IDirect3DDevice2 *device;
3996 IDirectDrawSurface *surface;
3997 DDSURFACEDESC ddsd;
3998 unsigned int i, j;
3999 DWORD expected_caps;
4000 static const struct
4002 const char *name;
4003 DDPIXELFORMAT fmt;
4005 formats[] =
4008 "D3DFMT_A8R8G8B8",
4010 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
4011 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
4015 "D3DFMT_P8",
4017 sizeof(DDPIXELFORMAT), DDPF_PALETTEINDEXED8 | DDPF_RGB, 0,
4018 {8 }, {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}
4022 static const DWORD caps[] = {0, DDSCAPS_SYSTEMMEMORY, DDSCAPS_VIDEOMEMORY};
4024 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
4025 0, 0, 640, 480, 0, 0, 0, 0);
4026 ddraw = create_ddraw();
4027 ok(!!ddraw, "Failed to create a ddraw object.\n");
4028 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
4030 skip("Failed to create a 3D device, skipping test.\n");
4031 IDirectDraw2_Release(ddraw);
4032 DestroyWindow(window);
4033 return;
4036 for (i = 0; i < sizeof(formats) / sizeof(*formats); i++)
4038 struct format_support_check check = {&formats[i].fmt, FALSE};
4039 hr = IDirect3DDevice2_EnumTextureFormats(device, test_unsupported_formats_cb, &check);
4040 ok(SUCCEEDED(hr), "Failed to enumerate texture formats %#x.\n", hr);
4042 for (j = 0; j < sizeof(caps) / sizeof(*caps); j++)
4044 memset(&ddsd, 0, sizeof(ddsd));
4045 ddsd.dwSize = sizeof(ddsd);
4046 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
4047 ddsd.ddpfPixelFormat = formats[i].fmt;
4048 ddsd.dwWidth = 4;
4049 ddsd.dwHeight = 4;
4050 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | caps[j];
4052 if (caps[j] & DDSCAPS_VIDEOMEMORY && !check.supported)
4053 expect_success = FALSE;
4054 else
4055 expect_success = TRUE;
4057 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
4058 ok(SUCCEEDED(hr) == expect_success,
4059 "Got unexpected hr %#x for format %s, caps %#x, expected %s.\n",
4060 hr, formats[i].name, caps[j], expect_success ? "success" : "failure");
4061 if (FAILED(hr))
4062 continue;
4064 memset(&ddsd, 0, sizeof(ddsd));
4065 ddsd.dwSize = sizeof(ddsd);
4066 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &ddsd);
4067 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
4069 if (caps[j] & DDSCAPS_VIDEOMEMORY)
4070 expected_caps = DDSCAPS_VIDEOMEMORY;
4071 else if (caps[j] & DDSCAPS_SYSTEMMEMORY)
4072 expected_caps = DDSCAPS_SYSTEMMEMORY;
4073 else if (check.supported)
4074 expected_caps = DDSCAPS_VIDEOMEMORY;
4075 else
4076 expected_caps = DDSCAPS_SYSTEMMEMORY;
4078 ok(ddsd.ddsCaps.dwCaps & expected_caps,
4079 "Expected capability %#x, format %s, input cap %#x.\n",
4080 expected_caps, formats[i].name, caps[j]);
4082 IDirectDrawSurface_Release(surface);
4086 IDirect3DDevice2_Release(device);
4087 IDirectDraw2_Release(ddraw);
4088 DestroyWindow(window);
4091 static void test_rt_caps(void)
4093 PALETTEENTRY palette_entries[256];
4094 IDirectDrawPalette *palette;
4095 IDirect3DDevice2 *device;
4096 IDirectDraw2 *ddraw;
4097 DWORD z_depth = 0;
4098 IDirect3D2 *d3d;
4099 unsigned int i;
4100 ULONG refcount;
4101 HWND window;
4102 HRESULT hr;
4104 static const DDPIXELFORMAT p8_fmt =
4106 sizeof(DDPIXELFORMAT), DDPF_PALETTEINDEXED8 | DDPF_RGB, 0,
4107 {8}, {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000},
4110 static const struct
4112 const DDPIXELFORMAT *pf;
4113 DWORD caps_in;
4114 DWORD caps_out;
4115 HRESULT create_device_hr;
4116 HRESULT set_rt_hr;
4117 HRESULT alternative_set_rt_hr;
4118 BOOL create_may_fail;
4120 test_data[] =
4123 NULL,
4124 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY,
4125 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM,
4126 D3D_OK,
4127 D3D_OK,
4128 D3D_OK,
4129 FALSE,
4132 NULL,
4133 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE,
4134 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM,
4135 D3D_OK,
4136 D3D_OK,
4137 D3D_OK,
4138 FALSE,
4141 NULL,
4142 DDSCAPS_OFFSCREENPLAIN,
4143 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM,
4144 DDERR_INVALIDCAPS,
4145 DDERR_INVALIDCAPS,
4146 DDERR_INVALIDCAPS,
4147 FALSE,
4150 NULL,
4151 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
4152 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
4153 D3DERR_SURFACENOTINVIDMEM,
4154 D3D_OK,
4155 D3D_OK,
4156 FALSE,
4159 NULL,
4160 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
4161 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
4162 DDERR_INVALIDCAPS,
4163 DDERR_INVALIDCAPS,
4164 DDERR_INVALIDCAPS,
4165 FALSE,
4168 NULL,
4169 DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY,
4170 DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM,
4171 D3D_OK,
4172 D3D_OK,
4173 D3D_OK,
4174 FALSE,
4177 NULL,
4178 DDSCAPS_3DDEVICE,
4179 DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM,
4180 D3D_OK,
4181 D3D_OK,
4182 D3D_OK,
4183 FALSE,
4186 NULL,
4188 DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM,
4189 DDERR_INVALIDCAPS,
4190 DDERR_INVALIDCAPS,
4191 DDERR_INVALIDCAPS,
4192 FALSE,
4195 NULL,
4196 DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
4197 DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
4198 D3DERR_SURFACENOTINVIDMEM,
4199 D3D_OK,
4200 D3D_OK,
4201 FALSE,
4204 NULL,
4205 DDSCAPS_SYSTEMMEMORY,
4206 DDSCAPS_SYSTEMMEMORY,
4207 DDERR_INVALIDCAPS,
4208 DDERR_INVALIDCAPS,
4209 DDERR_INVALIDCAPS,
4210 FALSE,
4213 &p8_fmt,
4215 DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM,
4216 DDERR_INVALIDCAPS,
4217 DDERR_INVALIDCAPS,
4218 DDERR_INVALIDCAPS,
4219 FALSE,
4222 &p8_fmt,
4223 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE,
4224 ~0U /* AMD r200 */,
4225 DDERR_NOPALETTEATTACHED,
4226 DDERR_INVALIDCAPS,
4227 DDERR_INVALIDCAPS,
4228 FALSE,
4231 &p8_fmt,
4232 DDSCAPS_OFFSCREENPLAIN,
4233 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM,
4234 DDERR_INVALIDCAPS,
4235 DDERR_INVALIDCAPS,
4236 DDERR_INVALIDCAPS,
4237 FALSE,
4240 &p8_fmt,
4241 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
4242 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
4243 DDERR_NOPALETTEATTACHED,
4244 DDERR_INVALIDCAPS,
4245 DDERR_INVALIDCAPS,
4246 FALSE,
4249 &p8_fmt,
4250 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
4251 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
4252 DDERR_INVALIDCAPS,
4253 DDERR_INVALIDCAPS,
4254 DDERR_INVALIDCAPS,
4255 FALSE,
4258 NULL,
4259 DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_ZBUFFER,
4260 DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_ZBUFFER | DDSCAPS_LOCALVIDMEM,
4261 DDERR_INVALIDCAPS,
4262 DDERR_INVALIDPIXELFORMAT,
4263 DDERR_INVALIDCAPS,
4264 TRUE /* AMD Evergreen */,
4267 NULL,
4268 DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER,
4269 ~0U /* AMD Evergreen */,
4270 DDERR_INVALIDCAPS,
4271 DDERR_INVALIDPIXELFORMAT,
4272 DDERR_INVALIDCAPS,
4273 FALSE,
4276 NULL,
4277 DDSCAPS_ZBUFFER,
4278 ~0U /* AMD Evergreen */,
4279 DDERR_INVALIDCAPS,
4280 DDERR_INVALIDCAPS,
4281 DDERR_INVALIDCAPS,
4282 FALSE,
4285 NULL,
4286 DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER,
4287 DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER,
4288 DDERR_INVALIDCAPS,
4289 DDERR_INVALIDPIXELFORMAT,
4290 DDERR_INVALIDPIXELFORMAT,
4291 TRUE /* Nvidia Kepler */,
4294 NULL,
4295 DDSCAPS_SYSTEMMEMORY | DDSCAPS_ZBUFFER,
4296 DDSCAPS_SYSTEMMEMORY | DDSCAPS_ZBUFFER,
4297 DDERR_INVALIDCAPS,
4298 DDERR_INVALIDCAPS,
4299 DDERR_INVALIDCAPS,
4300 TRUE /* Nvidia Kepler */,
4304 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
4305 0, 0, 640, 480, 0, 0, 0, 0);
4306 ddraw = create_ddraw();
4307 ok(!!ddraw, "Failed to create a ddraw object.\n");
4308 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
4310 skip("Failed to create a 3D device, skipping test.\n");
4311 IDirectDraw2_Release(ddraw);
4312 DestroyWindow(window);
4313 return;
4315 z_depth = get_device_z_depth(device);
4316 ok(!!z_depth, "Failed to get device z depth.\n");
4317 IDirect3DDevice2_Release(device);
4319 if (FAILED(IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d)))
4321 skip("D3D interface is not available, skipping test.\n");
4322 goto done;
4325 memset(palette_entries, 0, sizeof(palette_entries));
4326 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, palette_entries, &palette, NULL);
4327 ok(SUCCEEDED(hr), "Failed to create palette, hr %#x.\n", hr);
4329 for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
4331 IDirectDrawSurface *surface, *rt, *expected_rt, *tmp;
4332 DDSURFACEDESC surface_desc;
4333 IDirect3DDevice2 *device;
4335 memset(&surface_desc, 0, sizeof(surface_desc));
4336 surface_desc.dwSize = sizeof(surface_desc);
4337 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
4338 surface_desc.ddsCaps.dwCaps = test_data[i].caps_in;
4339 if (test_data[i].pf)
4341 surface_desc.dwFlags |= DDSD_PIXELFORMAT;
4342 surface_desc.ddpfPixelFormat = *test_data[i].pf;
4344 if (test_data[i].caps_in & DDSCAPS_ZBUFFER)
4346 surface_desc.dwFlags |= DDSD_ZBUFFERBITDEPTH;
4347 U2(surface_desc).dwZBufferBitDepth = z_depth;
4349 surface_desc.dwWidth = 640;
4350 surface_desc.dwHeight = 480;
4351 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
4352 ok(SUCCEEDED(hr) || broken(test_data[i].create_may_fail),
4353 "Test %u: Failed to create surface with caps %#x, hr %#x.\n",
4354 i, test_data[i].caps_in, hr);
4355 if (FAILED(hr))
4356 continue;
4358 memset(&surface_desc, 0, sizeof(surface_desc));
4359 surface_desc.dwSize = sizeof(surface_desc);
4360 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
4361 ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#x.\n", i, hr);
4362 ok(test_data[i].caps_out == ~0U || surface_desc.ddsCaps.dwCaps == test_data[i].caps_out,
4363 "Test %u: Got unexpected caps %#x, expected %#x.\n",
4364 i, surface_desc.ddsCaps.dwCaps, test_data[i].caps_out);
4366 hr = IDirect3D2_CreateDevice(d3d, &IID_IDirect3DHALDevice, surface, &device);
4367 ok(hr == test_data[i].create_device_hr, "Test %u: Got unexpected hr %#x, expected %#x.\n",
4368 i, hr, test_data[i].create_device_hr);
4369 if (FAILED(hr))
4371 if (hr == DDERR_NOPALETTEATTACHED)
4373 hr = IDirectDrawSurface_SetPalette(surface, palette);
4374 ok(SUCCEEDED(hr), "Test %u: Failed to set palette, hr %#x.\n", i, hr);
4375 hr = IDirect3D2_CreateDevice(d3d, &IID_IDirect3DHALDevice, surface, &device);
4376 if (surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
4377 ok(hr == DDERR_INVALIDPIXELFORMAT, "Test %u: Got unexpected hr %#x.\n", i, hr);
4378 else
4379 ok(hr == D3DERR_SURFACENOTINVIDMEM, "Test %u: Got unexpected hr %#x.\n", i, hr);
4381 IDirectDrawSurface_Release(surface);
4383 memset(&surface_desc, 0, sizeof(surface_desc));
4384 surface_desc.dwSize = sizeof(surface_desc);
4385 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
4386 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
4387 surface_desc.dwWidth = 640;
4388 surface_desc.dwHeight = 480;
4389 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
4390 ok(SUCCEEDED(hr), "Test %u: Failed to create surface, hr %#x.\n", i, hr);
4392 hr = IDirect3D2_CreateDevice(d3d, &IID_IDirect3DHALDevice, surface, &device);
4393 ok(SUCCEEDED(hr), "Test %u: Failed to create device, hr %#x.\n", i, hr);
4396 memset(&surface_desc, 0, sizeof(surface_desc));
4397 surface_desc.dwSize = sizeof(surface_desc);
4398 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
4399 surface_desc.ddsCaps.dwCaps = test_data[i].caps_in;
4400 if (test_data[i].pf)
4402 surface_desc.dwFlags |= DDSD_PIXELFORMAT;
4403 surface_desc.ddpfPixelFormat = *test_data[i].pf;
4405 if (test_data[i].caps_in & DDSCAPS_ZBUFFER)
4407 surface_desc.dwFlags |= DDSD_ZBUFFERBITDEPTH;
4408 U2(surface_desc).dwZBufferBitDepth = z_depth;
4410 surface_desc.dwWidth = 640;
4411 surface_desc.dwHeight = 480;
4412 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &rt, NULL);
4413 ok(SUCCEEDED(hr), "Test %u: Failed to create surface with caps %#x, hr %#x.\n",
4414 i, test_data[i].caps_in, hr);
4416 hr = IDirect3DDevice2_SetRenderTarget(device, rt, 0);
4417 ok(hr == test_data[i].set_rt_hr || broken(hr == test_data[i].alternative_set_rt_hr),
4418 "Test %u: Got unexpected hr %#x, expected %#x.\n",
4419 i, hr, test_data[i].set_rt_hr);
4420 if (SUCCEEDED(hr) || hr == DDERR_INVALIDPIXELFORMAT)
4421 expected_rt = rt;
4422 else
4423 expected_rt = surface;
4425 /* It appears the surface is set as render target in this case, but no
4426 * reference is taken. */
4427 if (hr == DDERR_INVALIDPIXELFORMAT)
4429 refcount = IDirectDrawSurface_AddRef(rt);
4430 ok(refcount == 2, "Test %u: Got unexpected refcount %u.\n", i, refcount);
4433 hr = IDirect3DDevice2_GetRenderTarget(device, &tmp);
4434 ok(SUCCEEDED(hr), "Test %u: Failed to get render target, hr %#x.\n", i, hr);
4435 ok(tmp == expected_rt, "Test %u: Got unexpected rt %p.\n", i, tmp);
4437 IDirectDrawSurface_Release(tmp);
4438 IDirectDrawSurface_Release(rt);
4439 refcount = IDirect3DDevice2_Release(device);
4440 ok(refcount == 0, "Test %u: The device was not properly freed, refcount %u.\n", i, refcount);
4441 refcount = IDirectDrawSurface_Release(surface);
4442 ok(refcount == 0, "Test %u: The surface was not properly freed, refcount %u.\n", i, refcount);
4445 IDirectDrawPalette_Release(palette);
4446 IDirect3D2_Release(d3d);
4448 done:
4449 refcount = IDirectDraw2_Release(ddraw);
4450 ok(refcount == 0, "The ddraw object was not properly freed, refcount %u.\n", refcount);
4451 DestroyWindow(window);
4454 static void test_primary_caps(void)
4456 const DWORD placement = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
4457 IDirectDrawSurface *surface;
4458 DDSURFACEDESC surface_desc;
4459 IDirectDraw2 *ddraw;
4460 unsigned int i;
4461 ULONG refcount;
4462 HWND window;
4463 HRESULT hr;
4465 static const struct
4467 DWORD coop_level;
4468 DWORD caps_in;
4469 DWORD back_buffer_count;
4470 HRESULT hr;
4471 DWORD caps_out;
4473 test_data[] =
4476 DDSCL_NORMAL,
4477 DDSCAPS_PRIMARYSURFACE,
4478 ~0u,
4479 DD_OK,
4480 DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE,
4483 DDSCL_NORMAL,
4484 DDSCAPS_PRIMARYSURFACE | DDSCAPS_TEXTURE,
4485 ~0u,
4486 DDERR_INVALIDCAPS,
4487 ~0u,
4490 DDSCL_NORMAL,
4491 DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER,
4492 ~0u,
4493 DDERR_INVALIDCAPS,
4494 ~0u,
4497 DDSCL_NORMAL,
4498 DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER,
4499 ~0u,
4500 DDERR_INVALIDCAPS,
4501 ~0u,
4504 DDSCL_NORMAL,
4505 DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP,
4506 ~0u,
4507 DDERR_INVALIDCAPS,
4508 ~0u,
4511 DDSCL_NORMAL,
4512 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX,
4513 ~0u,
4514 DDERR_INVALIDCAPS,
4515 ~0u,
4518 DDSCL_NORMAL,
4519 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
4520 ~0u,
4521 DDERR_INVALIDCAPS,
4522 ~0u,
4525 DDSCL_NORMAL,
4526 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
4528 DDERR_INVALIDCAPS,
4529 ~0u,
4532 DDSCL_NORMAL,
4533 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
4535 DDERR_NOEXCLUSIVEMODE,
4536 ~0u,
4539 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
4540 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
4542 DDERR_INVALIDCAPS,
4543 ~0u,
4546 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
4547 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
4549 DD_OK,
4550 DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER | DDSCAPS_FLIP | DDSCAPS_COMPLEX,
4553 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
4554 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER,
4556 DDERR_INVALIDCAPS,
4557 ~0u,
4560 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
4561 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_BACKBUFFER,
4563 DDERR_INVALIDCAPS,
4564 ~0u,
4568 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
4569 0, 0, 640, 480, 0, 0, 0, 0);
4570 ddraw = create_ddraw();
4571 ok(!!ddraw, "Failed to create a ddraw object.\n");
4573 for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
4575 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, test_data[i].coop_level);
4576 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
4578 memset(&surface_desc, 0, sizeof(surface_desc));
4579 surface_desc.dwSize = sizeof(surface_desc);
4580 surface_desc.dwFlags = DDSD_CAPS;
4581 if (test_data[i].back_buffer_count != ~0u)
4582 surface_desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
4583 surface_desc.ddsCaps.dwCaps = test_data[i].caps_in;
4584 surface_desc.dwBackBufferCount = test_data[i].back_buffer_count;
4585 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
4586 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#x, expected %#x.\n", i, hr, test_data[i].hr);
4587 if (FAILED(hr))
4588 continue;
4590 memset(&surface_desc, 0, sizeof(surface_desc));
4591 surface_desc.dwSize = sizeof(surface_desc);
4592 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
4593 ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#x.\n", i, hr);
4594 ok((surface_desc.ddsCaps.dwCaps & ~placement) == test_data[i].caps_out,
4595 "Test %u: Got unexpected caps %#x, expected %#x.\n",
4596 i, surface_desc.ddsCaps.dwCaps, test_data[i].caps_out);
4598 IDirectDrawSurface_Release(surface);
4601 refcount = IDirectDraw2_Release(ddraw);
4602 ok(refcount == 0, "The ddraw object was not properly freed, refcount %u.\n", refcount);
4603 DestroyWindow(window);
4606 static void test_surface_lock(void)
4608 IDirectDraw2 *ddraw;
4609 IDirectDrawSurface *surface;
4610 IDirect3DDevice2 *device;
4611 HRESULT hr;
4612 HWND window;
4613 unsigned int i;
4614 DDSURFACEDESC ddsd;
4615 ULONG refcount;
4616 DWORD z_depth = 0;
4617 static const struct
4619 DWORD caps;
4620 const char *name;
4622 tests[] =
4625 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
4626 "videomemory offscreenplain"
4629 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
4630 "systemmemory offscreenplain"
4633 DDSCAPS_PRIMARYSURFACE,
4634 "primary"
4637 DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY,
4638 "videomemory texture"
4641 DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY,
4642 "systemmemory texture"
4645 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE,
4646 "render target"
4649 DDSCAPS_ZBUFFER,
4650 "Z buffer"
4654 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
4655 0, 0, 640, 480, 0, 0, 0, 0);
4656 ddraw = create_ddraw();
4657 ok(!!ddraw, "Failed to create a ddraw object.\n");
4658 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
4660 skip("Failed to create a 3D device, skipping test.\n");
4661 IDirectDraw2_Release(ddraw);
4662 DestroyWindow(window);
4663 return;
4665 z_depth = get_device_z_depth(device);
4666 ok(!!z_depth, "Failed to get device z depth.\n");
4667 IDirect3DDevice2_Release(device);
4669 for (i = 0; i < sizeof(tests) / sizeof(*tests); i++)
4671 memset(&ddsd, 0, sizeof(ddsd));
4672 ddsd.dwSize = sizeof(ddsd);
4673 ddsd.dwFlags = DDSD_CAPS;
4674 if (!(tests[i].caps & DDSCAPS_PRIMARYSURFACE))
4676 ddsd.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
4677 ddsd.dwWidth = 64;
4678 ddsd.dwHeight = 64;
4680 if (tests[i].caps & DDSCAPS_ZBUFFER)
4682 ddsd.dwFlags |= DDSD_ZBUFFERBITDEPTH;
4683 U2(ddsd).dwZBufferBitDepth = z_depth;
4685 ddsd.ddsCaps.dwCaps = tests[i].caps;
4687 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
4688 ok(SUCCEEDED(hr), "Failed to create surface, type %s, hr %#x.\n", tests[i].name, hr);
4690 memset(&ddsd, 0, sizeof(ddsd));
4691 ddsd.dwSize = sizeof(ddsd);
4692 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_WAIT, NULL);
4693 ok(SUCCEEDED(hr), "Failed to lock surface, type %s, hr %#x.\n", tests[i].name, hr);
4694 if (SUCCEEDED(hr))
4696 hr = IDirectDrawSurface_Unlock(surface, NULL);
4697 ok(SUCCEEDED(hr), "Failed to unlock surface, type %s, hr %#x.\n", tests[i].name, hr);
4700 IDirectDrawSurface_Release(surface);
4703 refcount = IDirectDraw2_Release(ddraw);
4704 ok(refcount == 0, "The ddraw object was not properly freed, refcount %u.\n", refcount);
4705 DestroyWindow(window);
4708 static void test_surface_discard(void)
4710 IDirectDraw2 *ddraw;
4711 IDirect3DDevice2 *device;
4712 HRESULT hr;
4713 HWND window;
4714 DDSURFACEDESC ddsd;
4715 IDirectDrawSurface *surface, *target;
4716 void *addr;
4717 static const struct
4719 DWORD caps;
4720 BOOL discard;
4722 tests[] =
4724 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY, TRUE},
4725 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY, FALSE},
4726 {DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, TRUE},
4727 {DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY, FALSE},
4729 unsigned int i;
4731 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
4732 0, 0, 640, 480, 0, 0, 0, 0);
4733 ddraw = create_ddraw();
4734 ok(!!ddraw, "Failed to create a ddraw object.\n");
4735 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
4737 skip("Failed to create a 3D device, skipping test.\n");
4738 DestroyWindow(window);
4739 IDirectDraw2_Release(ddraw);
4740 return;
4743 hr = IDirect3DDevice2_GetRenderTarget(device, &target);
4744 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
4746 for (i = 0; i < sizeof(tests) / sizeof(*tests); i++)
4748 BOOL discarded;
4750 memset(&ddsd, 0, sizeof(ddsd));
4751 ddsd.dwSize = sizeof(ddsd);
4752 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
4753 ddsd.ddsCaps.dwCaps = tests[i].caps;
4754 ddsd.dwWidth = 64;
4755 ddsd.dwHeight = 64;
4756 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
4757 if (FAILED(hr))
4759 skip("Failed to create surface, skipping.\n");
4760 continue;
4763 memset(&ddsd, 0, sizeof(ddsd));
4764 ddsd.dwSize = sizeof(ddsd);
4765 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_WAIT, NULL);
4766 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
4767 addr = ddsd.lpSurface;
4768 hr = IDirectDrawSurface_Unlock(surface, NULL);
4769 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
4771 memset(&ddsd, 0, sizeof(ddsd));
4772 ddsd.dwSize = sizeof(ddsd);
4773 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_DISCARDCONTENTS | DDLOCK_WAIT, NULL);
4774 ok(SUCCEEDED(hr) , "Failed to lock surface, hr %#x.\n", hr);
4775 discarded = ddsd.lpSurface != addr;
4776 hr = IDirectDrawSurface_Unlock(surface, NULL);
4777 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
4779 hr = IDirectDrawSurface_Blt(target, NULL, surface, NULL, DDBLT_WAIT, NULL);
4780 ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
4782 memset(&ddsd, 0, sizeof(ddsd));
4783 ddsd.dwSize = sizeof(ddsd);
4784 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_DISCARDCONTENTS | DDLOCK_WAIT, NULL);
4785 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
4786 discarded |= ddsd.lpSurface != addr;
4787 hr = IDirectDrawSurface_Unlock(surface, NULL);
4788 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
4790 IDirectDrawSurface_Release(surface);
4792 /* Windows 7 reliably changes the address of surfaces that are discardable (Nvidia Kepler,
4793 * AMD r500, evergreen). Windows XP, at least on AMD r200, never changes the pointer. */
4794 ok(!discarded || tests[i].discard, "Expected surface not to be discarded, case %u\n", i);
4797 IDirectDrawSurface_Release(target);
4798 IDirect3DDevice2_Release(device);
4799 IDirectDraw2_Release(ddraw);
4800 DestroyWindow(window);
4803 static void test_flip(void)
4805 const DWORD placement = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
4806 IDirectDrawSurface *frontbuffer, *backbuffer1, *backbuffer2, *backbuffer3, *surface;
4807 DDSCAPS caps = {DDSCAPS_FLIP};
4808 DDSURFACEDESC surface_desc;
4809 BOOL sysmem_primary;
4810 IDirectDraw2 *ddraw;
4811 DWORD expected_caps;
4812 unsigned int i;
4813 D3DCOLOR color;
4814 ULONG refcount;
4815 HWND window;
4816 DDBLTFX fx;
4817 HRESULT hr;
4819 static const struct
4821 const char *name;
4822 DWORD caps;
4824 test_data[] =
4826 {"PRIMARYSURFACE", DDSCAPS_PRIMARYSURFACE},
4827 {"OFFSCREENPLAIN", DDSCAPS_OFFSCREENPLAIN},
4828 {"TEXTURE", DDSCAPS_TEXTURE},
4831 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
4832 0, 0, 640, 480, 0, 0, 0, 0);
4833 ddraw = create_ddraw();
4834 ok(!!ddraw, "Failed to create a ddraw object.\n");
4836 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4837 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
4839 for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
4841 memset(&surface_desc, 0, sizeof(surface_desc));
4842 surface_desc.dwSize = sizeof(surface_desc);
4843 surface_desc.dwFlags = DDSD_CAPS;
4844 if (!(test_data[i].caps & DDSCAPS_PRIMARYSURFACE))
4845 surface_desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
4846 surface_desc.ddsCaps.dwCaps = DDSCAPS_COMPLEX | DDSCAPS_FLIP | test_data[i].caps;
4847 surface_desc.dwWidth = 512;
4848 surface_desc.dwHeight = 512;
4849 surface_desc.dwBackBufferCount = 3;
4850 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
4851 ok(hr == DDERR_INVALIDCAPS, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4853 surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_FLIP;
4854 surface_desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
4855 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
4856 ok(hr == DDERR_INVALIDCAPS, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4858 surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_COMPLEX;
4859 surface_desc.ddsCaps.dwCaps |= DDSCAPS_FLIP;
4860 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
4861 ok(hr == DDERR_INVALIDCAPS, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4863 surface_desc.ddsCaps.dwCaps |= DDSCAPS_COMPLEX;
4864 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
4865 todo_wine_if(test_data[i].caps & DDSCAPS_TEXTURE)
4866 ok(SUCCEEDED(hr), "%s: Failed to create surface, hr %#x.\n", test_data[i].name, hr);
4867 if (FAILED(hr))
4868 continue;
4870 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
4871 ok(SUCCEEDED(hr), "%s: Failed to set cooperative level, hr %#x.\n", test_data[i].name, hr);
4872 hr = IDirectDrawSurface_IsLost(frontbuffer);
4873 ok(hr == DD_OK, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4874 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
4875 if (test_data[i].caps & DDSCAPS_PRIMARYSURFACE)
4876 ok(hr == DDERR_NOEXCLUSIVEMODE, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4877 else
4878 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#x.\n", test_data[i].name, hr);
4879 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4880 ok(SUCCEEDED(hr), "%s: Failed to set cooperative level, hr %#x.\n", test_data[i].name, hr);
4881 hr = IDirectDrawSurface_IsLost(frontbuffer);
4882 todo_wine ok(hr == DDERR_SURFACELOST, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4883 hr = restore_surfaces(ddraw);
4884 ok(SUCCEEDED(hr), "%s: Failed to restore surfaces, hr %#x.\n", test_data[i].name, hr);
4886 memset(&surface_desc, 0, sizeof(surface_desc));
4887 surface_desc.dwSize = sizeof(surface_desc);
4888 hr = IDirectDrawSurface_GetSurfaceDesc(frontbuffer, &surface_desc);
4889 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#x.\n", test_data[i].name, hr);
4890 expected_caps = DDSCAPS_FRONTBUFFER | DDSCAPS_COMPLEX | DDSCAPS_FLIP | test_data[i].caps;
4891 if (test_data[i].caps & DDSCAPS_PRIMARYSURFACE)
4892 expected_caps |= DDSCAPS_VISIBLE;
4893 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
4894 "%s: Got unexpected caps %#x.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
4895 sysmem_primary = surface_desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY;
4897 hr = IDirectDrawSurface_GetAttachedSurface(frontbuffer, &caps, &backbuffer1);
4898 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#x.\n", test_data[i].name, hr);
4899 memset(&surface_desc, 0, sizeof(surface_desc));
4900 surface_desc.dwSize = sizeof(surface_desc);
4901 hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer1, &surface_desc);
4902 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#x.\n", test_data[i].name, hr);
4903 ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %u.\n",
4904 test_data[i].name, surface_desc.dwBackBufferCount);
4905 expected_caps &= ~(DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER);
4906 expected_caps |= DDSCAPS_BACKBUFFER;
4907 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
4908 "%s: Got unexpected caps %#x.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
4910 hr = IDirectDrawSurface_GetAttachedSurface(backbuffer1, &caps, &backbuffer2);
4911 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#x.\n", test_data[i].name, hr);
4912 memset(&surface_desc, 0, sizeof(surface_desc));
4913 surface_desc.dwSize = sizeof(surface_desc);
4914 hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer2, &surface_desc);
4915 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#x.\n", test_data[i].name, hr);
4916 ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %u.\n",
4917 test_data[i].name, surface_desc.dwBackBufferCount);
4918 expected_caps &= ~DDSCAPS_BACKBUFFER;
4919 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
4920 "%s: Got unexpected caps %#x.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
4922 hr = IDirectDrawSurface_GetAttachedSurface(backbuffer2, &caps, &backbuffer3);
4923 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#x.\n", test_data[i].name, hr);
4924 memset(&surface_desc, 0, sizeof(surface_desc));
4925 surface_desc.dwSize = sizeof(surface_desc);
4926 hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer3, &surface_desc);
4927 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#x.\n", test_data[i].name, hr);
4928 ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %u.\n",
4929 test_data[i].name, surface_desc.dwBackBufferCount);
4930 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
4931 "%s: Got unexpected caps %#x.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
4933 hr = IDirectDrawSurface_GetAttachedSurface(backbuffer3, &caps, &surface);
4934 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#x.\n", test_data[i].name, hr);
4935 ok(surface == frontbuffer, "%s: Got unexpected surface %p, expected %p.\n",
4936 test_data[i].name, surface, frontbuffer);
4937 IDirectDrawSurface_Release(surface);
4939 memset(&surface_desc, 0, sizeof(surface_desc));
4940 surface_desc.dwSize = sizeof(surface_desc);
4941 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
4942 surface_desc.ddsCaps.dwCaps = 0;
4943 surface_desc.dwWidth = 640;
4944 surface_desc.dwHeight = 480;
4945 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
4946 ok(SUCCEEDED(hr), "%s: Failed to create surface, hr %#x.\n", test_data[i].name, hr);
4947 hr = IDirectDrawSurface_Flip(frontbuffer, surface, DDFLIP_WAIT);
4948 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4949 IDirectDrawSurface_Release(surface);
4951 hr = IDirectDrawSurface_Flip(frontbuffer, frontbuffer, DDFLIP_WAIT);
4952 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4953 hr = IDirectDrawSurface_Flip(backbuffer1, NULL, DDFLIP_WAIT);
4954 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4955 hr = IDirectDrawSurface_Flip(backbuffer2, NULL, DDFLIP_WAIT);
4956 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4957 hr = IDirectDrawSurface_Flip(backbuffer3, NULL, DDFLIP_WAIT);
4958 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#x.\n", test_data[i].name, hr);
4960 memset(&fx, 0, sizeof(fx));
4961 fx.dwSize = sizeof(fx);
4962 U5(fx).dwFillColor = 0xffff0000;
4963 hr = IDirectDrawSurface_Blt(backbuffer1, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
4964 ok(SUCCEEDED(hr), "%s: Failed to fill surface, hr %#x.\n", test_data[i].name, hr);
4965 U5(fx).dwFillColor = 0xff00ff00;
4966 hr = IDirectDrawSurface_Blt(backbuffer2, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
4967 ok(SUCCEEDED(hr), "%s: Failed to fill surface, hr %#x.\n", test_data[i].name, hr);
4968 U5(fx).dwFillColor = 0xff0000ff;
4969 hr = IDirectDrawSurface_Blt(backbuffer3, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
4970 ok(SUCCEEDED(hr), "%s: Failed to fill surface, hr %#x.\n", test_data[i].name, hr);
4972 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
4973 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#x.\n", test_data[i].name, hr);
4974 color = get_surface_color(backbuffer1, 320, 240);
4975 /* The testbot seems to just copy the contents of one surface to all the
4976 * others, instead of properly flipping. */
4977 ok(compare_color(color, 0x0000ff00, 1) || broken(sysmem_primary && compare_color(color, 0x000000ff, 1)),
4978 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
4979 color = get_surface_color(backbuffer2, 320, 240);
4980 ok(compare_color(color, 0x000000ff, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
4981 U5(fx).dwFillColor = 0xffff0000;
4982 hr = IDirectDrawSurface_Blt(backbuffer3, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
4983 ok(SUCCEEDED(hr), "%s: Failed to fill surface, hr %#x.\n", test_data[i].name, hr);
4985 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
4986 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#x.\n", test_data[i].name, hr);
4987 color = get_surface_color(backbuffer1, 320, 240);
4988 ok(compare_color(color, 0x000000ff, 1) || broken(sysmem_primary && compare_color(color, 0x00ff0000, 1)),
4989 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
4990 color = get_surface_color(backbuffer2, 320, 240);
4991 ok(compare_color(color, 0x00ff0000, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
4992 U5(fx).dwFillColor = 0xff00ff00;
4993 hr = IDirectDrawSurface_Blt(backbuffer3, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
4994 ok(SUCCEEDED(hr), "%s: Failed to fill surface, hr %#x.\n", test_data[i].name, hr);
4996 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
4997 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#x.\n", test_data[i].name, hr);
4998 color = get_surface_color(backbuffer1, 320, 240);
4999 ok(compare_color(color, 0x00ff0000, 1) || broken(sysmem_primary && compare_color(color, 0x0000ff00, 1)),
5000 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5001 color = get_surface_color(backbuffer2, 320, 240);
5002 ok(compare_color(color, 0x0000ff00, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5003 U5(fx).dwFillColor = 0xff0000ff;
5004 hr = IDirectDrawSurface_Blt(backbuffer3, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
5005 ok(SUCCEEDED(hr), "%s: Failed to fill surface, hr %#x.\n", test_data[i].name, hr);
5007 hr = IDirectDrawSurface_Flip(frontbuffer, backbuffer1, DDFLIP_WAIT);
5008 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#x.\n", test_data[i].name, hr);
5009 color = get_surface_color(backbuffer2, 320, 240);
5010 ok(compare_color(color, 0x0000ff00, 1) || broken(sysmem_primary && compare_color(color, 0x000000ff, 1)),
5011 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5012 color = get_surface_color(backbuffer3, 320, 240);
5013 ok(compare_color(color, 0x000000ff, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5014 U5(fx).dwFillColor = 0xffff0000;
5015 hr = IDirectDrawSurface_Blt(backbuffer1, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
5016 ok(SUCCEEDED(hr), "%s: Failed to fill surface, hr %#x.\n", test_data[i].name, hr);
5018 hr = IDirectDrawSurface_Flip(frontbuffer, backbuffer2, DDFLIP_WAIT);
5019 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#x.\n", test_data[i].name, hr);
5020 color = get_surface_color(backbuffer1, 320, 240);
5021 ok(compare_color(color, 0x00ff0000, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5022 color = get_surface_color(backbuffer3, 320, 240);
5023 ok(compare_color(color, 0x000000ff, 1) || broken(sysmem_primary && compare_color(color, 0x00ff0000, 1)),
5024 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5025 U5(fx).dwFillColor = 0xff00ff00;
5026 hr = IDirectDrawSurface_Blt(backbuffer2, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
5027 ok(SUCCEEDED(hr), "%s: Failed to fill surface, hr %#x.\n", test_data[i].name, hr);
5029 hr = IDirectDrawSurface_Flip(frontbuffer, backbuffer3, DDFLIP_WAIT);
5030 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#x.\n", test_data[i].name, hr);
5031 color = get_surface_color(backbuffer1, 320, 240);
5032 ok(compare_color(color, 0x00ff0000, 1) || broken(sysmem_primary && compare_color(color, 0x0000ff00, 1)),
5033 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5034 color = get_surface_color(backbuffer2, 320, 240);
5035 ok(compare_color(color, 0x0000ff00, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5037 IDirectDrawSurface_Release(backbuffer3);
5038 IDirectDrawSurface_Release(backbuffer2);
5039 IDirectDrawSurface_Release(backbuffer1);
5040 IDirectDrawSurface_Release(frontbuffer);
5043 refcount = IDirectDraw2_Release(ddraw);
5044 ok(refcount == 0, "The ddraw object was not properly freed, refcount %u.\n", refcount);
5045 DestroyWindow(window);
5048 static void reset_ddsd(DDSURFACEDESC *ddsd)
5050 memset(ddsd, 0, sizeof(*ddsd));
5051 ddsd->dwSize = sizeof(*ddsd);
5054 static void test_set_surface_desc(void)
5056 IDirectDraw2 *ddraw;
5057 HWND window;
5058 HRESULT hr;
5059 DDSURFACEDESC ddsd;
5060 IDirectDrawSurface *surface;
5061 IDirectDrawSurface3 *surface3;
5062 BYTE data[16*16*4];
5063 ULONG ref;
5064 unsigned int i;
5065 static const struct
5067 DWORD caps;
5068 BOOL supported;
5069 const char *name;
5071 invalid_caps_tests[] =
5073 {DDSCAPS_VIDEOMEMORY, FALSE, "videomemory plain"},
5074 {DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY, TRUE, "systemmemory texture"},
5075 {DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY, FALSE, "systemmemory primary"},
5078 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
5079 0, 0, 640, 480, 0, 0, 0, 0);
5080 ddraw = create_ddraw();
5081 ok(!!ddraw, "Failed to create a ddraw object.\n");
5082 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
5083 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
5085 reset_ddsd(&ddsd);
5086 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
5087 ddsd.dwWidth = 8;
5088 ddsd.dwHeight = 8;
5089 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
5090 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
5091 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
5092 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
5093 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
5094 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
5095 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
5097 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
5098 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5100 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
5101 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface3 interface, hr %#x.\n", hr);
5102 IDirectDrawSurface_Release(surface);
5104 reset_ddsd(&ddsd);
5105 ddsd.dwFlags = DDSD_LPSURFACE;
5106 ddsd.lpSurface = data;
5107 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5108 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#x.\n", hr);
5110 /* Redundantly setting the same lpSurface is not an error. */
5111 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5112 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#x.\n", hr);
5113 hr = IDirectDrawSurface3_GetSurfaceDesc(surface3, &ddsd);
5114 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
5115 ok(!(ddsd.dwFlags & DDSD_LPSURFACE), "DDSD_LPSURFACE is set.\n");
5116 ok(ddsd.lpSurface == NULL, "lpSurface is %p, expected NULL.\n", ddsd.lpSurface);
5118 hr = IDirectDrawSurface3_Lock(surface3, NULL, &ddsd, 0, NULL);
5119 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
5120 ok(!(ddsd.dwFlags & DDSD_LPSURFACE), "DDSD_LPSURFACE is set.\n");
5121 ok(ddsd.lpSurface == data, "lpSurface is %p, expected %p.\n", data, data);
5122 hr = IDirectDrawSurface3_Unlock(surface3, NULL);
5123 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
5125 reset_ddsd(&ddsd);
5126 ddsd.dwFlags = DDSD_LPSURFACE;
5127 ddsd.lpSurface = data;
5128 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 1);
5129 ok(hr == DDERR_INVALIDPARAMS, "SetSurfaceDesc with flags=1 returned %#x.\n", hr);
5131 ddsd.lpSurface = NULL;
5132 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5133 ok(hr == DDERR_INVALIDPARAMS, "Setting lpSurface=NULL returned %#x.\n", hr);
5135 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, NULL, 0);
5136 ok(hr == DDERR_INVALIDPARAMS, "SetSurfaceDesc with NULL desc returned %#x.\n", hr);
5138 hr = IDirectDrawSurface3_GetSurfaceDesc(surface3, &ddsd);
5139 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
5140 ok(ddsd.ddsCaps.dwCaps == (DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN),
5141 "Got unexpected caps %#x.\n", ddsd.ddsCaps.dwCaps);
5143 /* Setting the caps is an error. This also means the original description cannot be reapplied. */
5144 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5145 ok(hr == DDERR_INVALIDPARAMS, "Setting the original desc returned %#x.\n", hr);
5147 ddsd.dwFlags = DDSD_CAPS;
5148 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5149 ok(hr == DDERR_INVALIDPARAMS, "Setting DDSD_CAPS returned %#x.\n", hr);
5151 /* dwCaps = 0 is allowed, but ignored. */
5152 ddsd.dwFlags = DDSD_CAPS | DDSD_LPSURFACE;
5153 ddsd.lpSurface = data;
5154 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5155 ok(hr == DDERR_INVALIDCAPS, "Setting DDSD_CAPS returned %#x.\n", hr);
5156 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
5157 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5158 ok(hr == DDERR_INVALIDCAPS, "Setting DDSD_CAPS returned %#x.\n", hr);
5159 ddsd.ddsCaps.dwCaps = 0;
5160 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5161 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#x.\n", hr);
5163 hr = IDirectDrawSurface3_GetSurfaceDesc(surface3, &ddsd);
5164 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
5165 ok(ddsd.ddsCaps.dwCaps == (DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN),
5166 "Got unexpected caps %#x.\n", ddsd.ddsCaps.dwCaps);
5168 /* Setting the height is allowed, but it cannot be set to 0, and only if LPSURFACE is set too. */
5169 reset_ddsd(&ddsd);
5170 ddsd.dwFlags = DDSD_HEIGHT;
5171 ddsd.dwHeight = 16;
5172 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5173 ok(hr == DDERR_INVALIDPARAMS, "Setting height without lpSurface returned %#x.\n", hr);
5175 ddsd.lpSurface = data;
5176 ddsd.dwFlags = DDSD_HEIGHT | DDSD_LPSURFACE;
5177 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5178 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#x.\n", hr);
5180 ddsd.dwHeight = 0;
5181 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5182 ok(hr == DDERR_INVALIDPARAMS, "Setting height=0 returned %#x.\n", hr);
5184 reset_ddsd(&ddsd);
5185 hr = IDirectDrawSurface3_GetSurfaceDesc(surface3, &ddsd);
5186 ok(SUCCEEDED(hr), "GetSurfaceDesc failed, hr %#x.\n", hr);
5187 ok(ddsd.dwWidth == 8, "SetSurfaceDesc: Expected width 8, got %u.\n", ddsd.dwWidth);
5188 ok(ddsd.dwHeight == 16, "SetSurfaceDesc: Expected height 16, got %u.\n", ddsd.dwHeight);
5190 /* Pitch and width can be set, but only together, and only with LPSURFACE. They must not be 0. */
5191 reset_ddsd(&ddsd);
5192 ddsd.dwFlags = DDSD_PITCH;
5193 U1(ddsd).lPitch = 8 * 4;
5194 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5195 ok(hr == DDERR_INVALIDPARAMS, "Setting pitch without lpSurface or width returned %#x.\n", hr);
5197 ddsd.dwFlags = DDSD_WIDTH;
5198 ddsd.dwWidth = 16;
5199 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5200 ok(hr == DDERR_INVALIDPARAMS, "Setting width without lpSurface or pitch returned %#x.\n", hr);
5202 ddsd.dwFlags = DDSD_PITCH | DDSD_LPSURFACE;
5203 ddsd.lpSurface = data;
5204 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5205 ok(hr == DDERR_INVALIDPARAMS, "Setting pitch and lpSurface without width returned %#x.\n", hr);
5207 ddsd.dwFlags = DDSD_WIDTH | DDSD_LPSURFACE;
5208 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5209 ok(hr == DDERR_INVALIDPARAMS, "Setting width and lpSurface without pitch returned %#x.\n", hr);
5211 ddsd.dwFlags = DDSD_WIDTH | DDSD_PITCH | DDSD_LPSURFACE;
5212 U1(ddsd).lPitch = 16 * 4;
5213 ddsd.dwWidth = 16;
5214 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5215 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#x.\n", hr);
5217 reset_ddsd(&ddsd);
5218 hr = IDirectDrawSurface3_GetSurfaceDesc(surface3, &ddsd);
5219 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
5220 ok(ddsd.dwWidth == 16, "SetSurfaceDesc: Expected width 8, got %u.\n", ddsd.dwWidth);
5221 ok(ddsd.dwHeight == 16, "SetSurfaceDesc: Expected height 16, got %u.\n", ddsd.dwHeight);
5222 ok(U1(ddsd).lPitch == 16 * 4, "SetSurfaceDesc: Expected pitch 64, got %u.\n", U1(ddsd).lPitch);
5224 /* The pitch must be 32 bit aligned and > 0, but is not verified for sanity otherwise.
5226 * VMware rejects those calls, but all real drivers accept it. Mark the VMware behavior broken. */
5227 ddsd.dwFlags = DDSD_WIDTH | DDSD_PITCH | DDSD_LPSURFACE;
5228 U1(ddsd).lPitch = 4 * 4;
5229 ddsd.lpSurface = data;
5230 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5231 ok(SUCCEEDED(hr) || broken(hr == DDERR_INVALIDPARAMS), "Failed to set surface desc, hr %#x.\n", hr);
5233 U1(ddsd).lPitch = 4;
5234 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5235 ok(SUCCEEDED(hr) || broken(hr == DDERR_INVALIDPARAMS), "Failed to set surface desc, hr %#x.\n", hr);
5237 U1(ddsd).lPitch = 16 * 4 + 1;
5238 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5239 ok(hr == DDERR_INVALIDPARAMS, "Setting misaligned pitch returned %#x.\n", hr);
5241 U1(ddsd).lPitch = 16 * 4 + 3;
5242 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5243 ok(hr == DDERR_INVALIDPARAMS, "Setting misaligned pitch returned %#x.\n", hr);
5245 U1(ddsd).lPitch = -4;
5246 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5247 ok(hr == DDERR_INVALIDPARAMS, "Setting negative pitch returned %#x.\n", hr);
5249 U1(ddsd).lPitch = 16 * 4;
5250 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5251 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#x.\n", hr);
5253 reset_ddsd(&ddsd);
5254 ddsd.dwFlags = DDSD_WIDTH | DDSD_PITCH | DDSD_LPSURFACE;
5255 U1(ddsd).lPitch = 0;
5256 ddsd.dwWidth = 16;
5257 ddsd.lpSurface = data;
5258 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5259 ok(hr == DDERR_INVALIDPARAMS, "Setting zero pitch returned %#x.\n", hr);
5261 ddsd.dwFlags = DDSD_WIDTH | DDSD_PITCH | DDSD_LPSURFACE;
5262 U1(ddsd).lPitch = 16 * 4;
5263 ddsd.dwWidth = 0;
5264 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5265 ok(hr == DDERR_INVALIDPARAMS, "Setting zero width returned %#x.\n", hr);
5267 /* Setting the pixelformat without LPSURFACE is an error, but with LPSURFACE it works. */
5268 ddsd.dwFlags = DDSD_PIXELFORMAT;
5269 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
5270 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
5271 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
5272 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
5273 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
5274 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
5275 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5276 ok(hr == DDERR_INVALIDPARAMS, "Setting the pixel format returned %#x.\n", hr);
5278 ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_LPSURFACE;
5279 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5280 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#x.\n", hr);
5282 /* Can't set color keys. */
5283 reset_ddsd(&ddsd);
5284 ddsd.dwFlags = DDSD_CKSRCBLT;
5285 ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00ff0000;
5286 ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00ff0000;
5287 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5288 ok(hr == DDERR_INVALIDPARAMS, "Setting ddckCKSrcBlt returned %#x.\n", hr);
5290 ddsd.dwFlags = DDSD_CKSRCBLT | DDSD_LPSURFACE;
5291 ddsd.lpSurface = data;
5292 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5293 ok(hr == DDERR_INVALIDPARAMS, "Setting ddckCKSrcBlt returned %#x.\n", hr);
5295 IDirectDrawSurface3_Release(surface3);
5297 /* SetSurfaceDesc needs systemmemory surfaces.
5299 * As a sidenote, fourcc surfaces aren't allowed in sysmem, thus testing DDSD_LINEARSIZE is moot. */
5300 for (i = 0; i < sizeof(invalid_caps_tests) / sizeof(*invalid_caps_tests); i++)
5302 reset_ddsd(&ddsd);
5303 ddsd.dwFlags = DDSD_CAPS;
5304 ddsd.ddsCaps.dwCaps = invalid_caps_tests[i].caps;
5305 if (!(invalid_caps_tests[i].caps & DDSCAPS_PRIMARYSURFACE))
5307 ddsd.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
5308 ddsd.dwWidth = 8;
5309 ddsd.dwHeight = 8;
5310 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
5311 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
5312 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
5313 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
5314 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
5315 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
5318 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
5319 ok(SUCCEEDED(hr) || hr == DDERR_NODIRECTDRAWHW, "Failed to create surface, hr %#x.\n", hr);
5320 if (FAILED(hr))
5322 skip("Cannot create a %s surface, skipping vidmem SetSurfaceDesc test.\n",
5323 invalid_caps_tests[i].name);
5324 goto done;
5326 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
5327 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface3 interface, hr %#x.\n", hr);
5328 IDirectDrawSurface_Release(surface);
5330 reset_ddsd(&ddsd);
5331 ddsd.dwFlags = DDSD_LPSURFACE;
5332 ddsd.lpSurface = data;
5333 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5334 if (invalid_caps_tests[i].supported)
5336 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#x.\n", hr);
5338 else
5340 ok(hr == DDERR_INVALIDSURFACETYPE, "SetSurfaceDesc on a %s surface returned %#x.\n",
5341 invalid_caps_tests[i].name, hr);
5343 /* Check priority of error conditions. */
5344 ddsd.dwFlags = DDSD_WIDTH;
5345 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5346 ok(hr == DDERR_INVALIDSURFACETYPE, "SetSurfaceDesc on a %s surface returned %#x.\n",
5347 invalid_caps_tests[i].name, hr);
5350 IDirectDrawSurface3_Release(surface3);
5353 done:
5354 ref = IDirectDraw2_Release(ddraw);
5355 ok(ref == 0, "Ddraw object not properly released, refcount %u.\n", ref);
5356 DestroyWindow(window);
5359 static void test_user_memory_getdc(void)
5361 IDirectDraw2 *ddraw;
5362 HWND window;
5363 HRESULT hr;
5364 DDSURFACEDESC ddsd;
5365 IDirectDrawSurface *surface;
5366 IDirectDrawSurface3 *surface3;
5367 DWORD data[16][16];
5368 HBITMAP bitmap;
5369 DIBSECTION dib;
5370 ULONG ref;
5371 int size;
5372 HDC dc;
5373 unsigned int x, y;
5375 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
5376 0, 0, 640, 480, 0, 0, 0, 0);
5377 ddraw = create_ddraw();
5378 ok(!!ddraw, "Failed to create a ddraw object.\n");
5380 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
5381 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
5383 reset_ddsd(&ddsd);
5384 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
5385 ddsd.dwWidth = 16;
5386 ddsd.dwHeight = 16;
5387 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
5388 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
5389 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
5390 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
5391 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
5392 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
5393 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
5394 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
5395 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5397 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
5398 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface3 interface, hr %#x.\n", hr);
5399 IDirectDrawSurface_Release(surface);
5401 memset(data, 0xaa, sizeof(data));
5402 reset_ddsd(&ddsd);
5403 ddsd.dwFlags = DDSD_LPSURFACE;
5404 ddsd.lpSurface = data;
5405 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5406 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#x.\n", hr);
5408 hr = IDirectDrawSurface3_GetDC(surface3, &dc);
5409 ok(SUCCEEDED(hr), "Failed to get DC, hr %#x.\n", hr);
5410 bitmap = GetCurrentObject(dc, OBJ_BITMAP);
5411 ok(!!bitmap, "Failed to get bitmap.\n");
5412 size = GetObjectA(bitmap, sizeof(dib), &dib);
5413 ok(size == sizeof(dib), "Got unexpected size %d.\n", size);
5414 ok(dib.dsBm.bmBits == data, "Got unexpected bits %p, expected %p.\n", dib.dsBm.bmBits, data);
5415 BitBlt(dc, 0, 0, 16, 8, NULL, 0, 0, WHITENESS);
5416 BitBlt(dc, 0, 8, 16, 8, NULL, 0, 0, BLACKNESS);
5417 hr = IDirectDrawSurface3_ReleaseDC(surface3, dc);
5418 ok(SUCCEEDED(hr), "Failed to release DC, hr %#x.\n", hr);
5420 ok(data[0][0] == 0xffffffff, "Expected color 0xffffffff, got %#x.\n", data[0][0]);
5421 ok(data[15][15] == 0x00000000, "Expected color 0x00000000, got %#x.\n", data[15][15]);
5423 ddsd.dwFlags = DDSD_LPSURFACE | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH;
5424 ddsd.lpSurface = data;
5425 ddsd.dwWidth = 4;
5426 ddsd.dwHeight = 8;
5427 U1(ddsd).lPitch = sizeof(*data);
5428 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
5429 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#x.\n", hr);
5431 memset(data, 0xaa, sizeof(data));
5432 hr = IDirectDrawSurface3_GetDC(surface3, &dc);
5433 ok(SUCCEEDED(hr), "Failed to get DC, hr %#x.\n", hr);
5434 BitBlt(dc, 0, 0, 4, 8, NULL, 0, 0, BLACKNESS);
5435 BitBlt(dc, 1, 1, 2, 2, NULL, 0, 0, WHITENESS);
5436 hr = IDirectDrawSurface3_ReleaseDC(surface3, dc);
5437 ok(SUCCEEDED(hr), "Failed to release DC, hr %#x.\n", hr);
5439 for (y = 0; y < 4; y++)
5441 for (x = 0; x < 4; x++)
5443 if ((x == 1 || x == 2) && (y == 1 || y == 2))
5444 ok(data[y][x] == 0xffffffff, "Expected color 0xffffffff on position %ux%u, got %#x.\n",
5445 x, y, data[y][x]);
5446 else
5447 ok(data[y][x] == 0x00000000, "Expected color 0xaaaaaaaa on position %ux%u, got %#x.\n",
5448 x, y, data[y][x]);
5451 ok(data[0][5] == 0xaaaaaaaa, "Expected color 0xaaaaaaaa on position 5x0, got %#x.\n",
5452 data[0][5]);
5453 ok(data[7][3] == 0x00000000, "Expected color 0x00000000 on position 3x7, got %#x.\n",
5454 data[7][3]);
5455 ok(data[7][4] == 0xaaaaaaaa, "Expected color 0xaaaaaaaa on position 4x7, got %#x.\n",
5456 data[7][4]);
5457 ok(data[8][0] == 0xaaaaaaaa, "Expected color 0xaaaaaaaa on position 0x8, got %#x.\n",
5458 data[8][0]);
5460 IDirectDrawSurface3_Release(surface3);
5461 ref = IDirectDraw2_Release(ddraw);
5462 ok(ref == 0, "Ddraw object not properly released, refcount %u.\n", ref);
5463 DestroyWindow(window);
5466 static void test_sysmem_overlay(void)
5468 IDirectDraw2 *ddraw;
5469 HWND window;
5470 HRESULT hr;
5471 DDSURFACEDESC ddsd;
5472 IDirectDrawSurface *surface;
5473 ULONG ref;
5475 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
5476 0, 0, 640, 480, 0, 0, 0, 0);
5477 ddraw = create_ddraw();
5478 ok(!!ddraw, "Failed to create a ddraw object.\n");
5480 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
5481 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
5483 reset_ddsd(&ddsd);
5484 ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
5485 ddsd.dwWidth = 16;
5486 ddsd.dwHeight = 16;
5487 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OVERLAY;
5488 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
5489 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
5490 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
5491 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
5492 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
5493 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
5494 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
5495 ok(hr == DDERR_NOOVERLAYHW, "Got unexpected hr %#x.\n", hr);
5497 ref = IDirectDraw2_Release(ddraw);
5498 ok(ref == 0, "Ddraw object not properly released, refcount %u.\n", ref);
5499 DestroyWindow(window);
5502 static void test_primary_palette(void)
5504 DDSCAPS surface_caps = {DDSCAPS_FLIP};
5505 IDirectDrawSurface *primary, *backbuffer;
5506 PALETTEENTRY palette_entries[256];
5507 IDirectDrawPalette *palette, *tmp;
5508 DDSURFACEDESC surface_desc;
5509 IDirectDraw2 *ddraw;
5510 DWORD palette_caps;
5511 ULONG refcount;
5512 HWND window;
5513 HRESULT hr;
5515 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
5516 0, 0, 640, 480, 0, 0, 0, 0);
5517 ddraw = create_ddraw();
5518 ok(!!ddraw, "Failed to create a ddraw object.\n");
5519 if (FAILED(IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 8, 0, 0)))
5521 win_skip("Failed to set 8 bpp display mode, skipping test.\n");
5522 IDirectDraw2_Release(ddraw);
5523 DestroyWindow(window);
5524 return;
5526 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
5527 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
5529 memset(&surface_desc, 0, sizeof(surface_desc));
5530 surface_desc.dwSize = sizeof(surface_desc);
5531 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
5532 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
5533 surface_desc.dwBackBufferCount = 1;
5534 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
5535 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5536 hr = IDirectDrawSurface_GetAttachedSurface(primary, &surface_caps, &backbuffer);
5537 ok(SUCCEEDED(hr), "Failed to get attached surface, hr %#x.\n", hr);
5539 memset(palette_entries, 0, sizeof(palette_entries));
5540 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256, palette_entries, &palette, NULL);
5541 ok(SUCCEEDED(hr), "Failed to create palette, hr %#x.\n", hr);
5542 refcount = get_refcount((IUnknown *)palette);
5543 ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
5545 hr = IDirectDrawPalette_GetCaps(palette, &palette_caps);
5546 ok(SUCCEEDED(hr), "Failed to get palette caps, hr %#x.\n", hr);
5547 ok(palette_caps == (DDPCAPS_8BIT | DDPCAPS_ALLOW256), "Got unexpected palette caps %#x.\n", palette_caps);
5549 hr = IDirectDrawSurface_SetPalette(primary, palette);
5550 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
5552 /* The Windows 8 testbot attaches the palette to the backbuffer as well,
5553 * and is generally somewhat broken with respect to 8 bpp / palette
5554 * handling. */
5555 if (SUCCEEDED(IDirectDrawSurface_GetPalette(backbuffer, &tmp)))
5557 win_skip("Broken palette handling detected, skipping tests.\n");
5558 IDirectDrawPalette_Release(tmp);
5559 IDirectDrawPalette_Release(palette);
5560 /* The Windows 8 testbot keeps extra references to the primary and
5561 * backbuffer while in 8 bpp mode. */
5562 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
5563 ok(SUCCEEDED(hr), "Failed to restore display mode, hr %#x.\n", hr);
5564 goto done;
5567 refcount = get_refcount((IUnknown *)palette);
5568 ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
5570 hr = IDirectDrawPalette_GetCaps(palette, &palette_caps);
5571 ok(SUCCEEDED(hr), "Failed to get palette caps, hr %#x.\n", hr);
5572 ok(palette_caps == (DDPCAPS_8BIT | DDPCAPS_PRIMARYSURFACE | DDPCAPS_ALLOW256),
5573 "Got unexpected palette caps %#x.\n", palette_caps);
5575 hr = IDirectDrawSurface_SetPalette(primary, NULL);
5576 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
5577 refcount = get_refcount((IUnknown *)palette);
5578 ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
5580 hr = IDirectDrawPalette_GetCaps(palette, &palette_caps);
5581 ok(SUCCEEDED(hr), "Failed to get palette caps, hr %#x.\n", hr);
5582 ok(palette_caps == (DDPCAPS_8BIT | DDPCAPS_ALLOW256), "Got unexpected palette caps %#x.\n", palette_caps);
5584 hr = IDirectDrawSurface_SetPalette(primary, palette);
5585 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
5586 refcount = get_refcount((IUnknown *)palette);
5587 ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
5589 hr = IDirectDrawSurface_GetPalette(primary, &tmp);
5590 ok(SUCCEEDED(hr), "Failed to get palette, hr %#x.\n", hr);
5591 ok(tmp == palette, "Got unexpected palette %p, expected %p.\n", tmp, palette);
5592 IDirectDrawPalette_Release(tmp);
5593 hr = IDirectDrawSurface_GetPalette(backbuffer, &tmp);
5594 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#x.\n", hr);
5596 refcount = IDirectDrawPalette_Release(palette);
5597 ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
5598 refcount = IDirectDrawPalette_Release(palette);
5599 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
5601 /* Note that this only seems to work when the palette is attached to the
5602 * primary surface. When attached to a regular surface, attempting to get
5603 * the palette here will cause an access violation. */
5604 hr = IDirectDrawSurface_GetPalette(primary, &tmp);
5605 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#x.\n", hr);
5607 done:
5608 refcount = IDirectDrawSurface_Release(backbuffer);
5609 ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
5610 refcount = IDirectDrawSurface_Release(primary);
5611 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
5612 refcount = IDirectDraw2_Release(ddraw);
5613 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
5614 DestroyWindow(window);
5617 static HRESULT WINAPI surface_counter(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
5619 UINT *surface_count = context;
5621 ++(*surface_count);
5622 IDirectDrawSurface_Release(surface);
5624 return DDENUMRET_OK;
5627 static void test_surface_attachment(void)
5629 IDirectDrawSurface *surface1, *surface2, *surface3, *surface4;
5630 DDSCAPS caps = {DDSCAPS_TEXTURE};
5631 DDSURFACEDESC surface_desc;
5632 IDirectDraw2 *ddraw;
5633 UINT surface_count;
5634 ULONG refcount;
5635 HWND window;
5636 HRESULT hr;
5638 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
5639 0, 0, 640, 480, 0, 0, 0, 0);
5640 ddraw = create_ddraw();
5641 ok(!!ddraw, "Failed to create a ddraw object.\n");
5642 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
5643 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
5645 memset(&surface_desc, 0, sizeof(surface_desc));
5646 surface_desc.dwSize = sizeof(surface_desc);
5647 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
5648 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
5649 U2(surface_desc).dwMipMapCount = 3;
5650 surface_desc.dwWidth = 128;
5651 surface_desc.dwHeight = 128;
5652 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
5653 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5655 hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &surface2);
5656 ok(SUCCEEDED(hr), "Failed to get mip level, hr %#x.\n", hr);
5657 hr = IDirectDrawSurface_GetAttachedSurface(surface2, &caps, &surface3);
5658 ok(SUCCEEDED(hr), "Failed to get mip level, hr %#x.\n", hr);
5659 hr = IDirectDrawSurface_GetAttachedSurface(surface3, &caps, &surface4);
5660 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#x.\n", hr);
5662 surface_count = 0;
5663 IDirectDrawSurface_EnumAttachedSurfaces(surface1, &surface_count, surface_counter);
5664 ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
5665 surface_count = 0;
5666 IDirectDrawSurface_EnumAttachedSurfaces(surface2, &surface_count, surface_counter);
5667 ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
5668 surface_count = 0;
5669 IDirectDrawSurface_EnumAttachedSurfaces(surface3, &surface_count, surface_counter);
5670 ok(!surface_count, "Got unexpected surface_count %u.\n", surface_count);
5672 memset(&surface_desc, 0, sizeof(surface_desc));
5673 surface_desc.dwSize = sizeof(surface_desc);
5674 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5675 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5676 surface_desc.dwWidth = 16;
5677 surface_desc.dwHeight = 16;
5678 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
5679 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5681 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
5682 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5683 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
5684 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5685 hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface4);
5686 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5687 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface3);
5688 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5689 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface4);
5690 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5691 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface2);
5692 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5694 IDirectDrawSurface_Release(surface4);
5696 memset(&surface_desc, 0, sizeof(surface_desc));
5697 surface_desc.dwSize = sizeof(surface_desc);
5698 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5699 surface_desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
5700 surface_desc.dwWidth = 16;
5701 surface_desc.dwHeight = 16;
5702 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
5703 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5705 if (SUCCEEDED(hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4)))
5707 skip("Running on refrast, skipping some tests.\n");
5708 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface4);
5709 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
5711 else
5713 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5714 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
5715 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5716 hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface4);
5717 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5718 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface3);
5719 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5720 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface4);
5721 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5722 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface2);
5723 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5726 IDirectDrawSurface_Release(surface4);
5727 IDirectDrawSurface_Release(surface3);
5728 IDirectDrawSurface_Release(surface2);
5729 IDirectDrawSurface_Release(surface1);
5731 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
5732 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
5734 /* Try a single primary and two offscreen plain surfaces. */
5735 memset(&surface_desc, 0, sizeof(surface_desc));
5736 surface_desc.dwSize = sizeof(surface_desc);
5737 surface_desc.dwFlags = DDSD_CAPS;
5738 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
5739 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
5740 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5742 memset(&surface_desc, 0, sizeof(surface_desc));
5743 surface_desc.dwSize = sizeof(surface_desc);
5744 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5745 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
5746 surface_desc.dwWidth = registry_mode.dmPelsWidth;
5747 surface_desc.dwHeight = registry_mode.dmPelsHeight;
5748 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
5749 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5751 memset(&surface_desc, 0, sizeof(surface_desc));
5752 surface_desc.dwSize = sizeof(surface_desc);
5753 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5754 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
5755 surface_desc.dwWidth = registry_mode.dmPelsWidth;
5756 surface_desc.dwHeight = registry_mode.dmPelsHeight;
5757 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
5758 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5760 /* This one has a different size. */
5761 memset(&surface_desc, 0, sizeof(surface_desc));
5762 surface_desc.dwSize = sizeof(surface_desc);
5763 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5764 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
5765 surface_desc.dwWidth = 128;
5766 surface_desc.dwHeight = 128;
5767 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
5768 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5770 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
5771 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
5772 /* Try the reverse without detaching first. */
5773 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
5774 ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#x.\n", hr);
5775 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
5776 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
5778 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
5779 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
5780 /* Try to detach reversed. */
5781 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
5782 ok(hr == DDERR_CANNOTDETACHSURFACE, "Got unexpected hr %#x.\n", hr);
5783 hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface1);
5784 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
5786 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3);
5787 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
5788 hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface3);
5789 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
5791 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
5792 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5793 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
5794 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
5796 IDirectDrawSurface_Release(surface4);
5797 IDirectDrawSurface_Release(surface3);
5798 IDirectDrawSurface_Release(surface2);
5799 IDirectDrawSurface_Release(surface1);
5801 /* Test DeleteAttachedSurface() and automatic detachment of attached surfaces on release. */
5802 memset(&surface_desc, 0, sizeof(surface_desc));
5803 surface_desc.dwSize = sizeof(surface_desc);
5804 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
5805 surface_desc.dwWidth = 64;
5806 surface_desc.dwHeight = 64;
5807 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
5808 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
5809 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB; /* D3DFMT_R5G6B5 */
5810 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 16;
5811 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xf800;
5812 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x07e0;
5813 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x001f;
5814 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
5815 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5816 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
5817 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5819 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
5820 surface_desc.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
5821 U1(surface_desc.ddpfPixelFormat).dwZBufferBitDepth = 16;
5822 U3(surface_desc.ddpfPixelFormat).dwZBitMask = 0x0000ffff;
5823 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
5824 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
5826 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
5827 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
5828 refcount = get_refcount((IUnknown *)surface2);
5829 ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
5830 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
5831 ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#x.\n", hr);
5833 /* Attaching while already attached to other surface. */
5834 hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface2);
5835 todo_wine ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
5836 hr = IDirectDrawSurface_DeleteAttachedSurface(surface3, 0, surface2);
5837 todo_wine ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
5838 IDirectDrawSurface_Release(surface3);
5840 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
5841 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
5842 refcount = get_refcount((IUnknown *)surface2);
5843 ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
5845 /* Automatic detachment on release. */
5846 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
5847 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
5848 refcount = get_refcount((IUnknown *)surface2);
5849 ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
5850 refcount = IDirectDrawSurface_Release(surface1);
5851 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
5852 refcount = IDirectDrawSurface_Release(surface2);
5853 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
5854 refcount = IDirectDraw2_Release(ddraw);
5855 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
5856 DestroyWindow(window);
5859 static void test_pixel_format(void)
5861 HWND window, window2 = NULL;
5862 HDC hdc, hdc2 = NULL;
5863 HMODULE gl = NULL;
5864 int format, test_format;
5865 PIXELFORMATDESCRIPTOR pfd;
5866 IDirectDraw2 *ddraw = NULL;
5867 IDirectDrawClipper *clipper = NULL;
5868 DDSURFACEDESC ddsd;
5869 IDirectDrawSurface *primary = NULL;
5870 DDBLTFX fx;
5871 HRESULT hr;
5873 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5874 100, 100, 160, 160, NULL, NULL, NULL, NULL);
5875 if (!window)
5877 skip("Failed to create window\n");
5878 return;
5881 window2 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5882 100, 100, 160, 160, NULL, NULL, NULL, NULL);
5884 hdc = GetDC(window);
5885 if (!hdc)
5887 skip("Failed to get DC\n");
5888 goto cleanup;
5891 if (window2)
5892 hdc2 = GetDC(window2);
5894 gl = LoadLibraryA("opengl32.dll");
5895 ok(!!gl, "failed to load opengl32.dll; SetPixelFormat()/GetPixelFormat() may not work right\n");
5897 format = GetPixelFormat(hdc);
5898 ok(format == 0, "new window has pixel format %d\n", format);
5900 ZeroMemory(&pfd, sizeof(pfd));
5901 pfd.nSize = sizeof(pfd);
5902 pfd.nVersion = 1;
5903 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
5904 pfd.iPixelType = PFD_TYPE_RGBA;
5905 pfd.iLayerType = PFD_MAIN_PLANE;
5906 format = ChoosePixelFormat(hdc, &pfd);
5907 if (format <= 0)
5909 skip("no pixel format available\n");
5910 goto cleanup;
5913 if (!SetPixelFormat(hdc, format, &pfd) || GetPixelFormat(hdc) != format)
5915 skip("failed to set pixel format\n");
5916 goto cleanup;
5919 if (!hdc2 || !SetPixelFormat(hdc2, format, &pfd) || GetPixelFormat(hdc2) != format)
5921 skip("failed to set pixel format on second window\n");
5922 if (hdc2)
5924 ReleaseDC(window2, hdc2);
5925 hdc2 = NULL;
5929 ddraw = create_ddraw();
5930 ok(!!ddraw, "Failed to create a ddraw object.\n");
5932 test_format = GetPixelFormat(hdc);
5933 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5935 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
5936 if (FAILED(hr))
5938 skip("Failed to set cooperative level, hr %#x.\n", hr);
5939 goto cleanup;
5942 test_format = GetPixelFormat(hdc);
5943 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5945 if (hdc2)
5947 hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL);
5948 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
5949 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window2);
5950 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
5952 test_format = GetPixelFormat(hdc);
5953 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5955 test_format = GetPixelFormat(hdc2);
5956 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
5959 memset(&ddsd, 0, sizeof(ddsd));
5960 ddsd.dwSize = sizeof(ddsd);
5961 ddsd.dwFlags = DDSD_CAPS;
5962 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
5964 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
5965 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
5967 test_format = GetPixelFormat(hdc);
5968 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5970 if (hdc2)
5972 test_format = GetPixelFormat(hdc2);
5973 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
5976 if (clipper)
5978 hr = IDirectDrawSurface2_SetClipper(primary, clipper);
5979 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#x.\n", hr);
5981 test_format = GetPixelFormat(hdc);
5982 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5984 test_format = GetPixelFormat(hdc2);
5985 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
5988 memset(&fx, 0, sizeof(fx));
5989 fx.dwSize = sizeof(fx);
5990 hr = IDirectDrawSurface2_Blt(primary, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
5991 ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#x.\n", hr);
5993 test_format = GetPixelFormat(hdc);
5994 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5996 if (hdc2)
5998 test_format = GetPixelFormat(hdc2);
5999 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
6002 cleanup:
6003 if (primary) IDirectDrawSurface2_Release(primary);
6004 if (clipper) IDirectDrawClipper_Release(clipper);
6005 if (ddraw) IDirectDraw2_Release(ddraw);
6006 if (gl) FreeLibrary(gl);
6007 if (hdc) ReleaseDC(window, hdc);
6008 if (hdc2) ReleaseDC(window2, hdc2);
6009 if (window) DestroyWindow(window);
6010 if (window2) DestroyWindow(window2);
6013 static void test_create_surface_pitch(void)
6015 IDirectDrawSurface *surface;
6016 DDSURFACEDESC surface_desc;
6017 IDirectDraw2 *ddraw;
6018 unsigned int i;
6019 ULONG refcount;
6020 HWND window;
6021 HRESULT hr;
6022 void *mem;
6024 static const struct
6026 DWORD caps;
6027 DWORD flags_in;
6028 DWORD pitch_in;
6029 HRESULT hr;
6030 DWORD flags_out;
6031 DWORD pitch_out32;
6032 DWORD pitch_out64;
6034 test_data[] =
6036 /* 0 */
6037 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
6038 0, 0, DD_OK,
6039 DDSD_PITCH, 0x100, 0x100},
6040 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
6041 DDSD_PITCH, 0x104, DD_OK,
6042 DDSD_PITCH, 0x100, 0x100},
6043 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
6044 DDSD_PITCH, 0x0f8, DD_OK,
6045 DDSD_PITCH, 0x100, 0x100},
6046 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
6047 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDCAPS,
6048 0, 0, 0 },
6049 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6050 0, 0, DD_OK,
6051 DDSD_PITCH, 0x100, 0x0fc},
6052 /* 5 */
6053 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6054 DDSD_PITCH, 0x104, DD_OK,
6055 DDSD_PITCH, 0x100, 0x0fc},
6056 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6057 DDSD_PITCH, 0x0f8, DD_OK,
6058 DDSD_PITCH, 0x100, 0x0fc},
6059 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6060 DDSD_PITCH | DDSD_LINEARSIZE, 0, DD_OK,
6061 DDSD_PITCH, 0x100, 0x0fc},
6062 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6063 DDSD_LPSURFACE, 0, DDERR_INVALIDPARAMS,
6064 0, 0, 0 },
6065 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6066 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDPARAMS,
6067 0, 0, 0 },
6068 /* 10 */
6069 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN | DDSCAPS_ALLOCONLOAD,
6070 0, 0, DDERR_INVALIDCAPS,
6071 0, 0, 0 },
6072 {DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
6073 0, 0, DD_OK,
6074 DDSD_PITCH, 0x100, 0 },
6075 {DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
6076 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDCAPS,
6077 0, 0, 0 },
6078 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN | DDSCAPS_ALLOCONLOAD,
6079 0, 0, DDERR_INVALIDCAPS,
6080 0, 0, 0 },
6081 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
6082 0, 0, DD_OK,
6083 DDSD_PITCH, 0x100, 0 },
6084 /* 15 */
6085 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
6086 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDPARAMS,
6087 0, 0, 0 },
6089 DWORD flags_mask = DDSD_PITCH | DDSD_LPSURFACE | DDSD_LINEARSIZE;
6091 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
6092 0, 0, 640, 480, 0, 0, 0, 0);
6093 ddraw = create_ddraw();
6094 ok(!!ddraw, "Failed to create a ddraw object.\n");
6095 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
6096 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
6098 mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((63 * 4) + 8) * 63);
6100 for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
6102 memset(&surface_desc, 0, sizeof(surface_desc));
6103 surface_desc.dwSize = sizeof(surface_desc);
6104 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | test_data[i].flags_in;
6105 surface_desc.ddsCaps.dwCaps = test_data[i].caps;
6106 surface_desc.dwWidth = 63;
6107 surface_desc.dwHeight = 63;
6108 U1(surface_desc).lPitch = test_data[i].pitch_in;
6109 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
6110 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
6111 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
6112 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
6113 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
6114 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
6115 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
6116 if (test_data[i].flags_in & DDSD_LPSURFACE)
6118 HRESULT expected_hr = SUCCEEDED(test_data[i].hr) ? DDERR_INVALIDPARAMS : test_data[i].hr;
6119 ok(hr == expected_hr, "Test %u: Got unexpected hr %#x, expected %#x.\n", i, hr, expected_hr);
6120 surface_desc.lpSurface = mem;
6121 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
6123 if ((test_data[i].caps & DDSCAPS_VIDEOMEMORY) && hr == DDERR_NODIRECTDRAWHW)
6124 continue;
6125 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#x, expected %#x.\n", i, hr, test_data[i].hr);
6126 if (FAILED(hr))
6127 continue;
6129 memset(&surface_desc, 0, sizeof(surface_desc));
6130 surface_desc.dwSize = sizeof(surface_desc);
6131 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
6132 ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#x.\n", i, hr);
6133 ok((surface_desc.dwFlags & flags_mask) == test_data[i].flags_out,
6134 "Test %u: Got unexpected flags %#x, expected %#x.\n",
6135 i, surface_desc.dwFlags & flags_mask, test_data[i].flags_out);
6136 /* The pitch for textures seems to be implementation specific. */
6137 if (!(test_data[i].caps & DDSCAPS_TEXTURE))
6139 if (is_ddraw64 && test_data[i].pitch_out32 != test_data[i].pitch_out64)
6140 todo_wine ok(U1(surface_desc).lPitch == test_data[i].pitch_out64,
6141 "Test %u: Got unexpected pitch %u, expected %u.\n",
6142 i, U1(surface_desc).lPitch, test_data[i].pitch_out64);
6143 else
6144 ok(U1(surface_desc).lPitch == test_data[i].pitch_out32,
6145 "Test %u: Got unexpected pitch %u, expected %u.\n",
6146 i, U1(surface_desc).lPitch, test_data[i].pitch_out32);
6148 ok(!surface_desc.lpSurface, "Test %u: Got unexpected lpSurface %p.\n", i, surface_desc.lpSurface);
6150 IDirectDrawSurface_Release(surface);
6153 HeapFree(GetProcessHeap(), 0, mem);
6154 refcount = IDirectDraw2_Release(ddraw);
6155 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
6156 DestroyWindow(window);
6159 static void test_mipmap(void)
6161 IDirectDrawSurface *surface1;
6162 IDirectDrawSurface2 *surface, *surface2;
6163 DDSURFACEDESC surface_desc;
6164 IDirectDraw2 *ddraw;
6165 unsigned int i;
6166 ULONG refcount;
6167 HWND window;
6168 HRESULT hr;
6169 DDSCAPS caps = {DDSCAPS_COMPLEX};
6170 DDCAPS hal_caps;
6172 static const struct
6174 DWORD flags;
6175 DWORD caps;
6176 DWORD width;
6177 DWORD height;
6178 DWORD mipmap_count_in;
6179 HRESULT hr;
6180 DWORD mipmap_count_out;
6182 tests[] =
6184 {DDSD_MIPMAPCOUNT, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 128, 32, 3, DD_OK, 3},
6185 {DDSD_MIPMAPCOUNT, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 128, 32, 0, DDERR_INVALIDPARAMS, 0},
6186 {0, DDSCAPS_TEXTURE | DDSCAPS_MIPMAP, 128, 32, 0, DD_OK, 1},
6187 {0, DDSCAPS_MIPMAP, 128, 32, 0, DDERR_INVALIDCAPS, 0},
6188 {0, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 128, 32, 0, DD_OK, 6},
6189 {0, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 32, 64, 0, DD_OK, 6},
6192 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
6193 0, 0, 640, 480, 0, 0, 0, 0);
6194 ddraw = create_ddraw();
6195 ok(!!ddraw, "Failed to create a ddraw object.\n");
6196 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
6197 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
6199 memset(&hal_caps, 0, sizeof(hal_caps));
6200 hal_caps.dwSize = sizeof(hal_caps);
6201 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, NULL);
6202 ok(SUCCEEDED(hr), "Failed to get caps, hr %#x.\n", hr);
6203 if ((hal_caps.ddsCaps.dwCaps & (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP)) != (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP))
6205 skip("Mipmapped textures not supported, skipping tests.\n");
6206 IDirectDraw2_Release(ddraw);
6207 DestroyWindow(window);
6208 return;
6211 for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
6213 memset(&surface_desc, 0, sizeof(surface_desc));
6214 surface_desc.dwSize = sizeof(surface_desc);
6215 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | tests[i].flags;
6216 surface_desc.ddsCaps.dwCaps = tests[i].caps;
6217 surface_desc.dwWidth = tests[i].width;
6218 surface_desc.dwHeight = tests[i].height;
6219 if (tests[i].flags & DDSD_MIPMAPCOUNT)
6220 U2(surface_desc).dwMipMapCount = tests[i].mipmap_count_in;
6221 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
6222 ok(hr == tests[i].hr, "Test %u: Got unexpected hr %#x.\n", i, hr);
6223 if (FAILED(hr))
6224 continue;
6226 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface);
6227 ok(SUCCEEDED(hr), "Test %u: Failed to get IDirectDrawSurface2 interface, hr %#x.\n", i, hr);
6228 IDirectDrawSurface_Release(surface1);
6230 memset(&surface_desc, 0, sizeof(surface_desc));
6231 surface_desc.dwSize = sizeof(surface_desc);
6232 hr = IDirectDrawSurface2_GetSurfaceDesc(surface, &surface_desc);
6233 ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#x.\n", i, hr);
6234 ok(surface_desc.dwFlags & DDSD_MIPMAPCOUNT,
6235 "Test %u: Got unexpected flags %#x.\n", i, surface_desc.dwFlags);
6236 ok(U2(surface_desc).dwMipMapCount == tests[i].mipmap_count_out,
6237 "Test %u: Got unexpected mipmap count %u.\n", i, U2(surface_desc).dwMipMapCount);
6239 if (U2(surface_desc).dwMipMapCount > 1)
6241 hr = IDirectDrawSurface2_GetAttachedSurface(surface, &caps, &surface2);
6242 ok(SUCCEEDED(hr), "Test %u: Failed to get attached surface, hr %#x.\n", i, hr);
6244 memset(&surface_desc, 0, sizeof(surface_desc));
6245 surface_desc.dwSize = sizeof(surface_desc);
6246 hr = IDirectDrawSurface2_Lock(surface, NULL, &surface_desc, 0, NULL);
6247 ok(SUCCEEDED(hr), "Test %u: Failed to lock surface, hr %#x.\n", i, hr);
6248 memset(&surface_desc, 0, sizeof(surface_desc));
6249 surface_desc.dwSize = sizeof(surface_desc);
6250 hr = IDirectDrawSurface2_Lock(surface2, NULL, &surface_desc, 0, NULL);
6251 ok(SUCCEEDED(hr), "Test %u: Failed to lock surface, hr %#x.\n", i, hr);
6252 IDirectDrawSurface2_Unlock(surface2, NULL);
6253 IDirectDrawSurface2_Unlock(surface, NULL);
6255 IDirectDrawSurface2_Release(surface2);
6258 IDirectDrawSurface2_Release(surface);
6261 refcount = IDirectDraw2_Release(ddraw);
6262 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
6263 DestroyWindow(window);
6266 static void test_palette_complex(void)
6268 IDirectDrawSurface *surface1;
6269 IDirectDrawSurface2 *surface, *mipmap, *tmp;
6270 DDSURFACEDESC surface_desc;
6271 IDirectDraw2 *ddraw;
6272 IDirectDrawPalette *palette, *palette2, *palette_mipmap;
6273 ULONG refcount;
6274 HWND window;
6275 HRESULT hr;
6276 DDSCAPS caps = {DDSCAPS_COMPLEX};
6277 DDCAPS hal_caps;
6278 PALETTEENTRY palette_entries[256];
6279 unsigned int i;
6280 HDC dc;
6281 RGBQUAD rgbquad;
6282 UINT count;
6284 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
6285 0, 0, 640, 480, 0, 0, 0, 0);
6286 ddraw = create_ddraw();
6287 ok(!!ddraw, "Failed to create a ddraw object.\n");
6288 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
6289 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
6291 memset(&hal_caps, 0, sizeof(hal_caps));
6292 hal_caps.dwSize = sizeof(hal_caps);
6293 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, NULL);
6294 ok(SUCCEEDED(hr), "Failed to get caps, hr %#x.\n", hr);
6295 if ((hal_caps.ddsCaps.dwCaps & (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP)) != (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP))
6297 skip("Mipmapped textures not supported, skipping mipmap palette test.\n");
6298 IDirectDraw2_Release(ddraw);
6299 DestroyWindow(window);
6300 return;
6303 memset(&surface_desc, 0, sizeof(surface_desc));
6304 surface_desc.dwSize = sizeof(surface_desc);
6305 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
6306 surface_desc.dwWidth = 128;
6307 surface_desc.dwHeight = 128;
6308 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
6309 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
6310 surface_desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
6311 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 8;
6312 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
6313 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
6314 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface);
6315 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface2 interface, hr %#x.\n", hr);
6316 IDirectDrawSurface_Release(surface1);
6318 memset(palette_entries, 0, sizeof(palette_entries));
6319 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
6320 palette_entries, &palette, NULL);
6321 ok(SUCCEEDED(hr), "Failed to create palette, hr %#x.\n", hr);
6323 memset(palette_entries, 0, sizeof(palette_entries));
6324 palette_entries[1].peRed = 0xff;
6325 palette_entries[1].peGreen = 0x80;
6326 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
6327 palette_entries, &palette_mipmap, NULL);
6328 ok(SUCCEEDED(hr), "Failed to create palette, hr %#x.\n", hr);
6330 palette2 = (void *)0xdeadbeef;
6331 hr = IDirectDrawSurface2_GetPalette(surface, &palette2);
6332 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#x.\n", hr);
6333 ok(!palette2, "Got unexpected palette %p.\n", palette2);
6334 hr = IDirectDrawSurface2_SetPalette(surface, palette);
6335 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
6336 hr = IDirectDrawSurface2_GetPalette(surface, &palette2);
6337 ok(SUCCEEDED(hr), "Failed to get palette, hr %#x.\n", hr);
6338 ok(palette == palette2, "Got unexpected palette %p.\n", palette2);
6339 IDirectDrawPalette_Release(palette2);
6341 mipmap = surface;
6342 IDirectDrawSurface2_AddRef(mipmap);
6343 for (i = 0; i < 7; ++i)
6345 hr = IDirectDrawSurface2_GetAttachedSurface(mipmap, &caps, &tmp);
6346 ok(SUCCEEDED(hr), "Failed to get attached surface, i %u, hr %#x.\n", i, hr);
6347 palette2 = (void *)0xdeadbeef;
6348 hr = IDirectDrawSurface2_GetPalette(tmp, &palette2);
6349 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#x, i %u.\n", hr, i);
6350 ok(!palette2, "Got unexpected palette %p, i %u.\n", palette2, i);
6352 hr = IDirectDrawSurface2_SetPalette(tmp, palette_mipmap);
6353 ok(SUCCEEDED(hr), "Failed to set palette, i %u, hr %#x.\n", i, hr);
6355 hr = IDirectDrawSurface2_GetPalette(tmp, &palette2);
6356 ok(SUCCEEDED(hr), "Failed to get palette, i %u, hr %#x.\n", i, hr);
6357 ok(palette_mipmap == palette2, "Got unexpected palette %p.\n", palette2);
6358 IDirectDrawPalette_Release(palette2);
6360 hr = IDirectDrawSurface2_GetDC(tmp, &dc);
6361 ok(SUCCEEDED(hr), "Failed to get DC, i %u, hr %#x.\n", i, hr);
6362 count = GetDIBColorTable(dc, 1, 1, &rgbquad);
6363 ok(count == 1, "Expected count 1, got %u.\n", count);
6364 ok(rgbquad.rgbRed == 0xff, "Expected rgbRed = 0xff, got %#x.\n", rgbquad.rgbRed);
6365 ok(rgbquad.rgbGreen == 0x80, "Expected rgbGreen = 0x80, got %#x.\n", rgbquad.rgbGreen);
6366 ok(rgbquad.rgbBlue == 0x0, "Expected rgbBlue = 0x0, got %#x.\n", rgbquad.rgbBlue);
6367 hr = IDirectDrawSurface2_ReleaseDC(tmp, dc);
6368 ok(SUCCEEDED(hr), "Failed to release DC, i %u, hr %#x.\n", i, hr);
6370 IDirectDrawSurface2_Release(mipmap);
6371 mipmap = tmp;
6374 hr = IDirectDrawSurface2_GetAttachedSurface(mipmap, &caps, &tmp);
6375 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#x.\n", hr);
6376 IDirectDrawSurface2_Release(mipmap);
6377 refcount = IDirectDrawSurface2_Release(surface);
6378 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
6379 refcount = IDirectDrawPalette_Release(palette_mipmap);
6380 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
6381 refcount = IDirectDrawPalette_Release(palette);
6382 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
6384 refcount = IDirectDraw2_Release(ddraw);
6385 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
6386 DestroyWindow(window);
6389 static BOOL ddraw_is_warp(IDirectDraw2 *ddraw)
6391 IDirectDraw4 *ddraw4;
6392 DDDEVICEIDENTIFIER identifier;
6393 HRESULT hr;
6395 if (!strcmp(winetest_platform, "wine"))
6396 return FALSE;
6398 hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirectDraw4, (void **)&ddraw4);
6399 ok(SUCCEEDED(hr), "Failed to get IDirectDraw4 interface, hr %#x.\n", hr);
6400 hr = IDirectDraw4_GetDeviceIdentifier(ddraw4, &identifier, 0);
6401 ok(SUCCEEDED(hr), "Failed to get device identifier, hr %#x.\n", hr);
6402 IDirectDraw4_Release(ddraw4);
6403 return !!strstr(identifier.szDriver, "warp");
6406 static void test_p8_blit(void)
6408 IDirectDrawSurface *src, *dst, *dst_p8;
6409 DDSURFACEDESC surface_desc;
6410 IDirectDraw2 *ddraw;
6411 IDirectDrawPalette *palette, *palette2;
6412 ULONG refcount;
6413 HWND window;
6414 HRESULT hr;
6415 PALETTEENTRY palette_entries[256];
6416 unsigned int x;
6417 DDBLTFX fx;
6418 BOOL is_warp;
6419 static const BYTE src_data[] = {0x10, 0x1, 0x2, 0x3, 0x4, 0x5, 0xff, 0x80};
6420 static const BYTE src_data2[] = {0x10, 0x5, 0x4, 0x3, 0x2, 0x1, 0xff, 0x80};
6421 static const BYTE expected_p8[] = {0x10, 0x1, 0x4, 0x3, 0x4, 0x5, 0xff, 0x80};
6422 static const D3DCOLOR expected[] =
6424 0x00101010, 0x00010101, 0x00020202, 0x00030303,
6425 0x00040404, 0x00050505, 0x00ffffff, 0x00808080,
6427 D3DCOLOR color;
6429 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
6430 0, 0, 640, 480, 0, 0, 0, 0);
6431 ddraw = create_ddraw();
6432 ok(!!ddraw, "Failed to create a ddraw object.\n");
6433 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
6434 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
6435 is_warp = ddraw_is_warp(ddraw);
6437 memset(palette_entries, 0, sizeof(palette_entries));
6438 palette_entries[1].peGreen = 0xff;
6439 palette_entries[2].peBlue = 0xff;
6440 palette_entries[3].peFlags = 0xff;
6441 palette_entries[4].peRed = 0xff;
6442 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
6443 palette_entries, &palette, NULL);
6444 ok(SUCCEEDED(hr), "Failed to create palette, hr %#x.\n", hr);
6445 palette_entries[1].peBlue = 0xff;
6446 palette_entries[2].peGreen = 0xff;
6447 palette_entries[3].peRed = 0xff;
6448 palette_entries[4].peFlags = 0x0;
6449 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
6450 palette_entries, &palette2, NULL);
6451 ok(SUCCEEDED(hr), "Failed to create palette, hr %#x.\n", hr);
6453 memset(&surface_desc, 0, sizeof(surface_desc));
6454 surface_desc.dwSize = sizeof(surface_desc);
6455 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
6456 surface_desc.dwWidth = 8;
6457 surface_desc.dwHeight = 1;
6458 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
6459 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
6460 surface_desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
6461 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 8;
6462 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &src, NULL);
6463 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
6464 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst_p8, NULL);
6465 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
6466 hr = IDirectDrawSurface_SetPalette(dst_p8, palette2);
6467 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
6469 memset(&surface_desc, 0, sizeof(surface_desc));
6470 surface_desc.dwSize = sizeof(surface_desc);
6471 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
6472 surface_desc.dwWidth = 8;
6473 surface_desc.dwHeight = 1;
6474 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
6475 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
6476 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
6477 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
6478 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
6479 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
6480 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
6481 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
6482 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst, NULL);
6483 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
6485 memset(&surface_desc, 0, sizeof(surface_desc));
6486 surface_desc.dwSize = sizeof(surface_desc);
6487 hr = IDirectDrawSurface_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
6488 ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#x.\n", hr);
6489 memcpy(surface_desc.lpSurface, src_data, sizeof(src_data));
6490 hr = IDirectDrawSurface_Unlock(src, NULL);
6491 ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#x.\n", hr);
6493 hr = IDirectDrawSurface_Lock(dst_p8, NULL, &surface_desc, DDLOCK_WAIT, NULL);
6494 ok(SUCCEEDED(hr), "Failed to lock destination surface, hr %#x.\n", hr);
6495 memcpy(surface_desc.lpSurface, src_data2, sizeof(src_data2));
6496 hr = IDirectDrawSurface_Unlock(dst_p8, NULL);
6497 ok(SUCCEEDED(hr), "Failed to unlock destination surface, hr %#x.\n", hr);
6499 hr = IDirectDrawSurface_SetPalette(src, palette);
6500 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
6501 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_WAIT, NULL);
6502 /* The r500 Windows 7 driver returns E_NOTIMPL. r200 on Windows XP works.
6503 * The Geforce 7 driver on Windows Vista returns E_FAIL. Newer Nvidia GPUs work. */
6504 ok(SUCCEEDED(hr) || broken(hr == E_NOTIMPL) || broken(hr == E_FAIL),
6505 "Failed to blit, hr %#x.\n", hr);
6507 if (SUCCEEDED(hr))
6509 for (x = 0; x < sizeof(expected) / sizeof(*expected); x++)
6511 color = get_surface_color(dst, x, 0);
6512 todo_wine ok(compare_color(color, expected[x], 0),
6513 "Pixel %u: Got color %#x, expected %#x.\n",
6514 x, color, expected[x]);
6518 memset(&fx, 0, sizeof(fx));
6519 fx.dwSize = sizeof(fx);
6520 fx.ddckSrcColorkey.dwColorSpaceHighValue = 0x2;
6521 fx.ddckSrcColorkey.dwColorSpaceLowValue = 0x2;
6522 hr = IDirectDrawSurface7_Blt(dst_p8, NULL, src, NULL, DDBLT_WAIT | DDBLT_KEYSRCOVERRIDE, &fx);
6523 ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
6525 hr = IDirectDrawSurface_Lock(dst_p8, NULL, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
6526 ok(SUCCEEDED(hr), "Failed to lock destination surface, hr %#x.\n", hr);
6527 /* A color keyed P8 blit doesn't do anything on WARP - it just leaves the data in the destination
6528 * surface untouched. P8 blits without color keys work. Error checking (DDBLT_KEYSRC without a key
6529 * for example) also works as expected.
6531 * Using DDBLT_KEYSRC instead of DDBLT_KEYSRCOVERRIDE doesn't change this. Doing this blit with
6532 * the display mode set to P8 doesn't help either. */
6533 ok(!memcmp(surface_desc.lpSurface, expected_p8, sizeof(expected_p8))
6534 || broken(is_warp && !memcmp(surface_desc.lpSurface, src_data2, sizeof(src_data2))),
6535 "Got unexpected P8 color key blit result.\n");
6536 hr = IDirectDrawSurface_Unlock(dst_p8, NULL);
6537 ok(SUCCEEDED(hr), "Failed to unlock destination surface, hr %#x.\n", hr);
6539 IDirectDrawSurface_Release(src);
6540 IDirectDrawSurface_Release(dst);
6541 IDirectDrawSurface_Release(dst_p8);
6542 IDirectDrawPalette_Release(palette);
6543 IDirectDrawPalette_Release(palette2);
6545 refcount = IDirectDraw2_Release(ddraw);
6546 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
6547 DestroyWindow(window);
6550 static void test_material(void)
6552 IDirect3DMaterial2 *background, *material;
6553 D3DMATERIALHANDLE mat_handle, tmp;
6554 IDirect3DViewport2 *viewport;
6555 IDirect3DDevice2 *device;
6556 IDirectDrawSurface *rt;
6557 IDirectDraw2 *ddraw;
6558 D3DCOLOR color;
6559 ULONG refcount;
6560 unsigned int i;
6561 HWND window;
6562 HRESULT hr;
6563 BOOL valid;
6565 static D3DVERTEX quad[] =
6567 {{-1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
6568 {{-1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
6569 {{ 1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
6570 {{ 1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
6572 static const struct
6574 BOOL material;
6575 D3DCOLOR expected_color;
6577 test_data[] =
6579 {TRUE, 0x0000ff00},
6580 {FALSE, 0x00ffffff},
6582 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
6584 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
6585 0, 0, 640, 480, 0, 0, 0, 0);
6586 ddraw = create_ddraw();
6587 ok(!!ddraw, "Failed to create a ddraw object.\n");
6588 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
6590 skip("Failed to create a 3D device, skipping test.\n");
6591 DestroyWindow(window);
6592 return;
6595 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
6596 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
6598 background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
6599 viewport = create_viewport(device, 0, 0, 640, 480);
6600 viewport_set_background(device, viewport, background);
6601 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
6602 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
6604 material = create_emissive_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
6605 hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle);
6606 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
6608 hr = IDirect3DDevice2_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
6609 ok(SUCCEEDED(hr), "Failed to get light state, hr %#x.\n", hr);
6610 ok(!tmp, "Got unexpected material handle %#x.\n", tmp);
6611 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
6612 ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
6613 hr = IDirect3DDevice2_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
6614 ok(SUCCEEDED(hr), "Failed to get light state, hr %#x.\n", hr);
6615 ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
6616 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, 0);
6617 ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
6618 hr = IDirect3DDevice2_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
6619 ok(SUCCEEDED(hr), "Failed to get light state, hr %#x.\n", hr);
6620 ok(!tmp, "Got unexpected material handle %#x.\n", tmp);
6622 for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
6624 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
6625 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
6627 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, test_data[i].material ? mat_handle : 0);
6628 ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
6630 hr = IDirect3DDevice2_BeginScene(device);
6631 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
6632 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_VERTEX, quad, 4, 0);
6633 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
6634 hr = IDirect3DDevice2_EndScene(device);
6635 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
6636 color = get_surface_color(rt, 320, 240);
6637 ok(compare_color(color, test_data[i].expected_color, 1),
6638 "Got unexpected color 0x%08x, test %u.\n", color, i);
6641 destroy_material(material);
6642 material = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
6643 hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle);
6644 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
6646 hr = IDirect3DViewport2_SetBackground(viewport, mat_handle);
6647 ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#x.\n", hr);
6648 hr = IDirect3DViewport2_GetBackground(viewport, &tmp, &valid);
6649 ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
6650 ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
6651 ok(valid, "Got unexpected valid %#x.\n", valid);
6652 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
6653 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
6654 color = get_surface_color(rt, 320, 240);
6655 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
6657 hr = IDirect3DViewport2_SetBackground(viewport, 0);
6658 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
6659 hr = IDirect3DViewport2_GetBackground(viewport, &tmp, &valid);
6660 ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
6661 ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
6662 ok(valid, "Got unexpected valid %#x.\n", valid);
6663 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
6664 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
6665 color = get_surface_color(rt, 320, 240);
6666 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
6668 destroy_viewport(device, viewport);
6669 viewport = create_viewport(device, 0, 0, 640, 480);
6671 hr = IDirect3DViewport2_GetBackground(viewport, &tmp, &valid);
6672 ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
6673 ok(!tmp, "Got unexpected material handle %#x.\n", tmp);
6674 ok(!valid, "Got unexpected valid %#x.\n", valid);
6675 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
6676 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
6677 color = get_surface_color(rt, 320, 240);
6678 ok(compare_color(color, 0x00000000, 1), "Got unexpected color 0x%08x.\n", color);
6680 destroy_viewport(device, viewport);
6681 destroy_material(background);
6682 destroy_material(material);
6683 IDirectDrawSurface_Release(rt);
6684 refcount = IDirect3DDevice2_Release(device);
6685 ok(!refcount, "Device has %u references left.\n", refcount);
6686 refcount = IDirectDraw2_Release(ddraw);
6687 ok(!refcount, "Ddraw object has %u references left.\n", refcount);
6688 DestroyWindow(window);
6691 static void test_lighting(void)
6693 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
6694 static D3DMATRIX mat =
6696 1.0f, 0.0f, 0.0f, 0.0f,
6697 0.0f, 1.0f, 0.0f, 0.0f,
6698 0.0f, 0.0f, 1.0f, 0.0f,
6699 0.0f, 0.0f, 0.0f, 1.0f,
6701 mat_singular =
6703 1.0f, 0.0f, 1.0f, 0.0f,
6704 0.0f, 1.0f, 0.0f, 0.0f,
6705 1.0f, 0.0f, 1.0f, 0.0f,
6706 0.0f, 0.0f, 0.5f, 1.0f,
6708 mat_transf =
6710 0.0f, 0.0f, 1.0f, 0.0f,
6711 0.0f, 1.0f, 0.0f, 0.0f,
6712 -1.0f, 0.0f, 0.0f, 0.0f,
6713 10.f, 10.0f, 10.0f, 1.0f,
6715 mat_nonaffine =
6717 1.0f, 0.0f, 0.0f, 0.0f,
6718 0.0f, 1.0f, 0.0f, 0.0f,
6719 0.0f, 0.0f, 1.0f, -1.0f,
6720 10.f, 10.0f, 10.0f, 0.0f,
6722 static D3DLVERTEX unlitquad[] =
6724 {{-1.0f}, {-1.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
6725 {{-1.0f}, { 0.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
6726 {{ 0.0f}, { 0.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
6727 {{ 0.0f}, {-1.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
6729 litquad[] =
6731 {{-1.0f}, { 0.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
6732 {{-1.0f}, { 1.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
6733 {{ 0.0f}, { 1.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
6734 {{ 0.0f}, { 0.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
6736 static D3DVERTEX unlitnquad[] =
6738 {{0.0f}, {-1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6739 {{0.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6740 {{1.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6741 {{1.0f}, {-1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6743 litnquad[] =
6745 {{0.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6746 {{0.0f}, { 1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6747 {{1.0f}, { 1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6748 {{1.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6750 nquad[] =
6752 {{-1.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6753 {{-1.0f}, { 1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6754 {{ 1.0f}, { 1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6755 {{ 1.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6757 rotatedquad[] =
6759 {{-10.0f}, {-11.0f}, {11.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
6760 {{-10.0f}, { -9.0f}, {11.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
6761 {{-10.0f}, { -9.0f}, { 9.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
6762 {{-10.0f}, {-11.0f}, { 9.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
6764 translatedquad[] =
6766 {{-11.0f}, {-11.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6767 {{-11.0f}, { -9.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6768 {{ -9.0f}, { -9.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6769 {{ -9.0f}, {-11.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6771 static WORD indices[] = {0, 1, 2, 2, 3, 0};
6772 static const struct
6774 D3DMATRIX *world_matrix;
6775 void *quad;
6776 DWORD expected;
6777 const char *message;
6779 tests[] =
6781 {&mat, nquad, 0x000000ff, "Lit quad with light"},
6782 {&mat_singular, nquad, 0x000000b4, "Lit quad with singular world matrix"},
6783 {&mat_transf, rotatedquad, 0x000000ff, "Lit quad with transformation matrix"},
6784 {&mat_nonaffine, translatedquad, 0x000000ff, "Lit quad with non-affine matrix"},
6787 HWND window;
6788 IDirect3D2 *d3d;
6789 IDirect3DDevice2 *device;
6790 IDirectDraw2 *ddraw;
6791 IDirectDrawSurface *rt;
6792 IDirect3DViewport2 *viewport;
6793 IDirect3DMaterial2 *material;
6794 IDirect3DLight *light;
6795 D3DMATERIALHANDLE mat_handle;
6796 D3DLIGHT2 light_desc;
6797 HRESULT hr;
6798 D3DCOLOR color;
6799 ULONG refcount;
6800 unsigned int i;
6802 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
6803 0, 0, 640, 480, 0, 0, 0, 0);
6804 ddraw = create_ddraw();
6805 ok(!!ddraw, "Failed to create a ddraw object.\n");
6806 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
6808 skip("Failed to create a 3D device, skipping test.\n");
6809 DestroyWindow(window);
6810 return;
6813 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
6814 ok(SUCCEEDED(hr), "Failed to get D3D interface, hr %#x.\n", hr);
6816 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
6817 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
6819 viewport = create_viewport(device, 0, 0, 640, 480);
6820 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
6821 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
6823 material = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
6824 viewport_set_background(device, viewport, material);
6826 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
6827 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
6829 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat);
6830 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr);
6831 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat);
6832 ok(SUCCEEDED(hr), "Failed to set view transform, hr %#x.\n", hr);
6833 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat);
6834 ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#x.\n", hr);
6835 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CLIPPING, FALSE);
6836 ok(SUCCEEDED(hr), "Failed to disable clipping, hr %#x.\n", hr);
6837 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, FALSE);
6838 ok(SUCCEEDED(hr), "Failed to disable zbuffer, hr %#x.\n", hr);
6839 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_FOGENABLE, FALSE);
6840 ok(SUCCEEDED(hr), "Failed to disable fog, hr %#x.\n", hr);
6841 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
6842 ok(SUCCEEDED(hr), "Failed to disable culling, hr %#x.\n", hr);
6844 hr = IDirect3DDevice2_BeginScene(device);
6845 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
6847 /* There is no D3DRENDERSTATE_LIGHTING on ddraw < 7. */
6848 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
6849 ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr);
6850 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_LVERTEX, unlitquad,
6851 4, indices, 6, 0);
6852 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
6854 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, TRUE);
6855 ok(SUCCEEDED(hr), "Failed to enable lighting, hr %#x.\n", hr);
6856 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_LVERTEX, litquad,
6857 4, indices, 6, 0);
6858 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
6860 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
6861 ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr);
6862 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX, unlitnquad,
6863 4, indices, 6, 0);
6864 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
6866 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, TRUE);
6867 ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr);
6868 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX, litnquad,
6869 4, indices, 6, 0);
6870 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
6872 hr = IDirect3DDevice2_EndScene(device);
6873 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
6875 color = get_surface_color(rt, 160, 360);
6876 ok(color == 0x00ff0000, "Unlit quad without normals has color 0x%08x.\n", color);
6877 color = get_surface_color(rt, 160, 120);
6878 ok(color == 0x0000ff00, "Lit quad without normals has color 0x%08x.\n", color);
6879 color = get_surface_color(rt, 480, 360);
6880 ok(color == 0x00ffffff, "Unlit quad with normals has color 0x%08x.\n", color);
6881 color = get_surface_color(rt, 480, 120);
6882 ok(color == 0x00ffffff, "Lit quad with normals has color 0x%08x.\n", color);
6884 hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle);
6885 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
6886 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
6887 ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
6889 hr = IDirect3D2_CreateLight(d3d, &light, NULL);
6890 ok(SUCCEEDED(hr), "Failed to create a light object, hr %#x.\n", hr);
6891 memset(&light_desc, 0, sizeof(light_desc));
6892 light_desc.dwSize = sizeof(light_desc);
6893 light_desc.dltType = D3DLIGHT_DIRECTIONAL;
6894 U1(light_desc.dcvColor).r = 0.0f;
6895 U2(light_desc.dcvColor).g = 0.0f;
6896 U3(light_desc.dcvColor).b = 1.0f;
6897 U4(light_desc.dcvColor).a = 1.0f;
6898 U3(light_desc.dvDirection).z = 1.0f;
6899 hr = IDirect3DLight_SetLight(light, (D3DLIGHT *)&light_desc);
6900 ok(SUCCEEDED(hr), "Failed to set light, hr %#x.\n", hr);
6901 hr = IDirect3DViewport2_AddLight(viewport, light);
6902 ok(SUCCEEDED(hr), "Failed to add a light to the viewport, hr %#x.\n", hr);
6904 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
6905 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
6907 hr = IDirect3DDevice2_BeginScene(device);
6908 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
6910 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX, nquad,
6911 4, indices, 6, 0);
6912 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
6914 hr = IDirect3DDevice2_EndScene(device);
6915 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
6917 color = get_surface_color(rt, 320, 240);
6918 ok(color == 0x00000000, "Lit quad with no light has color 0x%08x.\n", color);
6920 light_desc.dwFlags = D3DLIGHT_ACTIVE;
6921 hr = IDirect3DLight_SetLight(light, (D3DLIGHT *)&light_desc);
6922 ok(SUCCEEDED(hr), "Failed to set light, hr %#x.\n", hr);
6924 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i)
6926 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, tests[i].world_matrix);
6927 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr);
6929 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
6930 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
6932 hr = IDirect3DDevice2_BeginScene(device);
6933 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
6935 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX,
6936 tests[i].quad, 4, indices, 6, 0);
6937 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
6939 hr = IDirect3DDevice2_EndScene(device);
6940 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
6942 color = get_surface_color(rt, 320, 240);
6943 ok(color == tests[i].expected, "%s has color 0x%08x.\n", tests[i].message, color);
6946 hr = IDirect3DViewport2_DeleteLight(viewport, light);
6947 ok(SUCCEEDED(hr), "Failed to remove a light from the viewport, hr %#x.\n", hr);
6948 IDirect3DLight_Release(light);
6949 destroy_material(material);
6950 destroy_viewport(device, viewport);
6951 IDirectDrawSurface2_Release(rt);
6952 refcount = IDirect3DDevice2_Release(device);
6953 ok(!refcount, "Device has %u references left.\n", refcount);
6954 IDirect3D2_Release(d3d);
6955 refcount = IDirectDraw2_Release(ddraw);
6956 ok(!refcount, "Ddraw object has %u references left.\n", refcount);
6957 DestroyWindow(window);
6960 static void test_specular_lighting(void)
6962 static const unsigned int vertices_side = 5;
6963 const unsigned int indices_count = (vertices_side - 1) * (vertices_side - 1) * 2 * 3;
6964 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
6965 static D3DMATRIX mat =
6967 1.0f, 0.0f, 0.0f, 0.0f,
6968 0.0f, 1.0f, 0.0f, 0.0f,
6969 0.0f, 0.0f, 1.0f, 0.0f,
6970 0.0f, 0.0f, 0.0f, 1.0f,
6972 static D3DLIGHT2 directional =
6974 sizeof(D3DLIGHT2),
6975 D3DLIGHT_DIRECTIONAL,
6976 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
6977 {{0.0f}, {0.0f}, {0.0f}},
6978 {{0.0f}, {0.0f}, {1.0f}},
6980 point =
6982 sizeof(D3DLIGHT2),
6983 D3DLIGHT_POINT,
6984 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
6985 {{0.0f}, {0.0f}, {0.0f}},
6986 {{0.0f}, {0.0f}, {0.0f}},
6987 100.0f,
6988 0.0f,
6989 0.0f, 0.0f, 1.0f,
6991 spot =
6993 sizeof(D3DLIGHT2),
6994 D3DLIGHT_SPOT,
6995 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
6996 {{0.0f}, {0.0f}, {0.0f}},
6997 {{0.0f}, {0.0f}, {1.0f}},
6998 100.0f,
6999 1.0f,
7000 0.0f, 0.0f, 1.0f,
7001 M_PI / 12.0f, M_PI / 3.0f
7003 parallelpoint =
7005 sizeof(D3DLIGHT2),
7006 D3DLIGHT_PARALLELPOINT,
7007 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
7008 {{0.5f}, {0.0f}, {-1.0f}},
7009 {{0.0f}, {0.0f}, {0.0f}},
7011 static const struct expected_color
7013 unsigned int x, y;
7014 D3DCOLOR color;
7016 expected_directional_local[] =
7018 {160, 120, 0x003c3c3c},
7019 {320, 120, 0x00717171},
7020 {480, 120, 0x003c3c3c},
7021 {160, 240, 0x00717171},
7022 {320, 240, 0x00ffffff},
7023 {480, 240, 0x00717171},
7024 {160, 360, 0x003c3c3c},
7025 {320, 360, 0x00717171},
7026 {480, 360, 0x003c3c3c},
7028 expected_point_local[] =
7030 {160, 120, 0x00000000},
7031 {320, 120, 0x00090909},
7032 {480, 120, 0x00000000},
7033 {160, 240, 0x00090909},
7034 {320, 240, 0x00fafafa},
7035 {480, 240, 0x00090909},
7036 {160, 360, 0x00000000},
7037 {320, 360, 0x00090909},
7038 {480, 360, 0x00000000},
7040 expected_spot_local[] =
7042 {160, 120, 0x00000000},
7043 {320, 120, 0x00020202},
7044 {480, 120, 0x00000000},
7045 {160, 240, 0x00020202},
7046 {320, 240, 0x00fafafa},
7047 {480, 240, 0x00020202},
7048 {160, 360, 0x00000000},
7049 {320, 360, 0x00020202},
7050 {480, 360, 0x00000000},
7052 expected_parallelpoint[] =
7054 {160, 120, 0x00050505},
7055 {320, 120, 0x002c2c2c},
7056 {480, 120, 0x006e6e6e},
7057 {160, 240, 0x00090909},
7058 {320, 240, 0x00717171},
7059 {480, 240, 0x00ffffff},
7060 {160, 360, 0x00050505},
7061 {320, 360, 0x002c2c2c},
7062 {480, 360, 0x006e6e6e},
7064 static const struct
7066 D3DLIGHT2 *light;
7067 const struct expected_color *expected;
7068 unsigned int expected_count;
7070 tests[] =
7072 {&directional, expected_directional_local,
7073 sizeof(expected_directional_local) / sizeof(expected_directional_local[0])},
7074 {&point, expected_point_local,
7075 sizeof(expected_point_local) / sizeof(expected_point_local[0])},
7076 {&spot, expected_spot_local,
7077 sizeof(expected_spot_local) / sizeof(expected_spot_local[0])},
7078 {&parallelpoint, expected_parallelpoint,
7079 sizeof(expected_parallelpoint) / sizeof(expected_parallelpoint[0])},
7081 IDirect3D2 *d3d;
7082 IDirect3DDevice2 *device;
7083 IDirectDraw2 *ddraw;
7084 IDirectDrawSurface *rt;
7085 IDirect3DViewport2 *viewport;
7086 IDirect3DMaterial2 *material, *background_material;
7087 IDirect3DLight *light;
7088 D3DMATERIALHANDLE mat_handle;
7089 D3DCOLOR color;
7090 ULONG refcount;
7091 HWND window;
7092 HRESULT hr;
7093 unsigned int i, j, x, y;
7094 D3DVERTEX *quad;
7095 WORD *indices;
7097 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
7098 0, 0, 640, 480, 0, 0, 0, 0);
7099 ddraw = create_ddraw();
7100 ok(!!ddraw, "Failed to create a ddraw object.\n");
7101 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
7103 skip("Failed to create a 3D device, skipping test.\n");
7104 DestroyWindow(window);
7105 return;
7108 quad = HeapAlloc(GetProcessHeap(), 0, vertices_side * vertices_side * sizeof(*quad));
7109 indices = HeapAlloc(GetProcessHeap(), 0, indices_count * sizeof(*indices));
7110 for (i = 0, y = 0; y < vertices_side; ++y)
7112 for (x = 0; x < vertices_side; ++x)
7114 U1(quad[i]).x = x * 2.0f / (vertices_side - 1) - 1.0f;
7115 U2(quad[i]).y = y * 2.0f / (vertices_side - 1) - 1.0f;
7116 U3(quad[i]).z = 1.0f;
7117 U4(quad[i]).nx = 0.0f;
7118 U5(quad[i]).ny = 0.0f;
7119 U6(quad[i]).nz = -1.0f;
7120 U7(quad[i]).tu = 0.0f;
7121 U8(quad[i++]).tv = 0.0f;
7124 for (i = 0, y = 0; y < (vertices_side - 1); ++y)
7126 for (x = 0; x < (vertices_side - 1); ++x)
7128 indices[i++] = y * vertices_side + x + 1;
7129 indices[i++] = y * vertices_side + x;
7130 indices[i++] = (y + 1) * vertices_side + x;
7131 indices[i++] = y * vertices_side + x + 1;
7132 indices[i++] = (y + 1) * vertices_side + x;
7133 indices[i++] = (y + 1) * vertices_side + x + 1;
7137 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
7138 ok(SUCCEEDED(hr), "Failed to get D3D interface, hr %#x.\n", hr);
7140 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
7141 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
7143 viewport = create_viewport(device, 0, 0, 640, 480);
7144 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
7145 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
7147 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat);
7148 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr);
7149 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat);
7150 ok(SUCCEEDED(hr), "Failed to set view transform, hr %#x.\n", hr);
7151 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat);
7152 ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#x.\n", hr);
7153 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CLIPPING, FALSE);
7154 ok(SUCCEEDED(hr), "Failed to disable clipping, hr %#x.\n", hr);
7155 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, FALSE);
7156 ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#x.\n", hr);
7157 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_FOGENABLE, FALSE);
7158 ok(SUCCEEDED(hr), "Failed to disable fog, hr %#x.\n", hr);
7160 background_material = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
7161 viewport_set_background(device, viewport, background_material);
7163 material = create_specular_material(device, 1.0f, 1.0f, 1.0f, 1.0f, 30.0f);
7164 hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle);
7165 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
7166 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
7167 ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
7169 hr = IDirect3D2_CreateLight(d3d, &light, NULL);
7170 ok(SUCCEEDED(hr), "Failed to create a light object, hr %#x.\n", hr);
7171 hr = IDirect3DViewport2_AddLight(viewport, light);
7172 ok(SUCCEEDED(hr), "Failed to add a light to the viewport, hr %#x.\n", hr);
7174 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SPECULARENABLE, TRUE);
7175 ok(SUCCEEDED(hr), "Failed to enable specular lighting, hr %#x.\n", hr);
7177 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i)
7179 tests[i].light->dwFlags = D3DLIGHT_ACTIVE;
7180 hr = IDirect3DLight_SetLight(light, (D3DLIGHT *)tests[i].light);
7181 ok(SUCCEEDED(hr), "Failed to set light, hr %#x.\n", hr);
7183 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
7184 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
7186 hr = IDirect3DDevice2_BeginScene(device);
7187 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
7189 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX,
7190 quad, vertices_side * vertices_side, indices, indices_count, 0);
7191 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
7193 hr = IDirect3DDevice2_EndScene(device);
7194 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
7196 for (j = 0; j < tests[i].expected_count; ++j)
7198 color = get_surface_color(rt, tests[i].expected[j].x, tests[i].expected[j].y);
7199 ok(compare_color(color, tests[i].expected[j].color, 1),
7200 "Expected color 0x%08x at location (%u, %u), got 0x%08x, case %u.\n",
7201 tests[i].expected[j].color, tests[i].expected[j].x,
7202 tests[i].expected[j].y, color, i);
7206 hr = IDirect3DViewport2_DeleteLight(viewport, light);
7207 ok(SUCCEEDED(hr), "Failed to remove a light from the viewport, hr %#x.\n", hr);
7208 IDirect3DLight_Release(light);
7209 destroy_material(material);
7210 destroy_material(background_material);
7211 destroy_viewport(device, viewport);
7212 IDirectDrawSurface2_Release(rt);
7213 refcount = IDirect3DDevice2_Release(device);
7214 ok(!refcount, "Device has %u references left.\n", refcount);
7215 IDirect3D2_Release(d3d);
7216 refcount = IDirectDraw2_Release(ddraw);
7217 ok(!refcount, "Ddraw object has %u references left.\n", refcount);
7218 DestroyWindow(window);
7219 HeapFree(GetProcessHeap(), 0, indices);
7220 HeapFree(GetProcessHeap(), 0, quad);
7223 static void test_palette_gdi(void)
7225 IDirectDrawSurface *surface, *primary;
7226 DDSURFACEDESC surface_desc;
7227 IDirectDraw2 *ddraw;
7228 IDirectDrawPalette *palette, *palette2;
7229 ULONG refcount;
7230 HWND window;
7231 HRESULT hr;
7232 PALETTEENTRY palette_entries[256];
7233 UINT i;
7234 HDC dc;
7235 DDBLTFX fx;
7236 RECT r;
7237 COLORREF color;
7238 /* On the Windows 8 testbot palette index 0 of the onscreen palette is forced to
7239 * r = 0, g = 0, b = 0. Do not attempt to set it to something else as this is
7240 * not the point of this test. */
7241 static const RGBQUAD expected1[] =
7243 {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x01, 0x00}, {0x00, 0x02, 0x00, 0x00},
7244 {0x03, 0x00, 0x00, 0x00}, {0x15, 0x14, 0x13, 0x00},
7246 static const RGBQUAD expected2[] =
7248 {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x01, 0x00}, {0x00, 0x02, 0x00, 0x00},
7249 {0x03, 0x00, 0x00, 0x00}, {0x25, 0x24, 0x23, 0x00},
7251 static const RGBQUAD expected3[] =
7253 {0x00, 0x00, 0x00, 0x00}, {0x40, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x40, 0x00},
7254 {0x00, 0x40, 0x00, 0x00}, {0x56, 0x34, 0x12, 0x00},
7256 HPALETTE ddraw_palette_handle;
7257 /* Similar to index 0, index 255 is r = 0xff, g = 0xff, b = 0xff on the Win8 VMs. */
7258 RGBQUAD rgbquad[255];
7259 static const RGBQUAD rgb_zero = {0, 0, 0, 0};
7261 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
7262 0, 0, 640, 480, 0, 0, 0, 0);
7263 ddraw = create_ddraw();
7264 ok(!!ddraw, "Failed to create a ddraw object.\n");
7265 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
7266 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
7268 memset(&surface_desc, 0, sizeof(surface_desc));
7269 surface_desc.dwSize = sizeof(surface_desc);
7270 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
7271 surface_desc.dwWidth = 16;
7272 surface_desc.dwHeight = 16;
7273 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
7274 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
7275 surface_desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
7276 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 8;
7277 hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7278 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
7280 /* Avoid colors from the Windows default palette. */
7281 memset(palette_entries, 0, sizeof(palette_entries));
7282 palette_entries[1].peRed = 0x01;
7283 palette_entries[2].peGreen = 0x02;
7284 palette_entries[3].peBlue = 0x03;
7285 palette_entries[4].peRed = 0x13;
7286 palette_entries[4].peGreen = 0x14;
7287 palette_entries[4].peBlue = 0x15;
7288 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
7289 palette_entries, &palette, NULL);
7290 ok(SUCCEEDED(hr), "Failed to create palette, hr %#x.\n", hr);
7292 /* If there is no palette assigned and the display mode is not 8 bpp, some
7293 * drivers refuse to create a DC while others allow it. If a DC is created,
7294 * the DIB color table is uninitialized and contains random colors. No error
7295 * is generated when trying to read pixels and random garbage is returned.
7297 * The most likely explanation is that if the driver creates a DC, it (or
7298 * the higher-level runtime) uses GetSystemPaletteEntries to find the
7299 * palette, but GetSystemPaletteEntries fails when bpp > 8 and the palette
7300 * contains uninitialized garbage. See comments below for the P8 case. */
7302 hr = IDirectDrawSurface_SetPalette(surface, palette);
7303 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
7304 hr = IDirectDrawSurface_GetDC(surface, &dc);
7305 ok(SUCCEEDED(hr), "Failed to get DC, hr %#x.\n", hr);
7306 ddraw_palette_handle = SelectPalette(dc, GetStockObject(DEFAULT_PALETTE), FALSE);
7307 ok(ddraw_palette_handle == GetStockObject(DEFAULT_PALETTE),
7308 "Got unexpected palette %p, expected %p.\n",
7309 ddraw_palette_handle, GetStockObject(DEFAULT_PALETTE));
7311 i = GetDIBColorTable(dc, 0, sizeof(rgbquad) / sizeof(*rgbquad), rgbquad);
7312 ok(i == sizeof(rgbquad) / sizeof(*rgbquad), "Expected count 255, got %u.\n", i);
7313 for (i = 0; i < sizeof(expected1) / sizeof(*expected1); i++)
7315 ok(!memcmp(&rgbquad[i], &expected1[i], sizeof(rgbquad[i])),
7316 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7317 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
7318 expected1[i].rgbRed, expected1[i].rgbGreen, expected1[i].rgbBlue);
7320 for (; i < sizeof(rgbquad) / sizeof(*rgbquad); i++)
7322 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
7323 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
7324 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
7327 /* Update the palette while the DC is in use. This does not modify the DC. */
7328 palette_entries[4].peRed = 0x23;
7329 palette_entries[4].peGreen = 0x24;
7330 palette_entries[4].peBlue = 0x25;
7331 hr = IDirectDrawPalette_SetEntries(palette, 0, 4, 1, &palette_entries[4]);
7332 ok(SUCCEEDED(hr), "Failed to set palette entries, hr %#x.\n", hr);
7334 i = GetDIBColorTable(dc, 4, 1, &rgbquad[4]);
7335 ok(i == 1, "Expected count 1, got %u.\n", i);
7336 ok(!memcmp(&rgbquad[4], &expected1[4], sizeof(rgbquad[4])),
7337 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7338 i, rgbquad[4].rgbRed, rgbquad[4].rgbGreen, rgbquad[4].rgbBlue,
7339 expected1[4].rgbRed, expected1[4].rgbGreen, expected1[4].rgbBlue);
7341 /* Neither does re-setting the palette. */
7342 hr = IDirectDrawSurface_SetPalette(surface, NULL);
7343 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
7344 hr = IDirectDrawSurface_SetPalette(surface, palette);
7345 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
7347 i = GetDIBColorTable(dc, 4, 1, &rgbquad[4]);
7348 ok(i == 1, "Expected count 1, got %u.\n", i);
7349 ok(!memcmp(&rgbquad[4], &expected1[4], sizeof(rgbquad[4])),
7350 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7351 i, rgbquad[4].rgbRed, rgbquad[4].rgbGreen, rgbquad[4].rgbBlue,
7352 expected1[4].rgbRed, expected1[4].rgbGreen, expected1[4].rgbBlue);
7354 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
7355 ok(SUCCEEDED(hr), "Failed to release DC, hr %#x.\n", hr);
7357 /* Refresh the DC. This updates the palette. */
7358 hr = IDirectDrawSurface_GetDC(surface, &dc);
7359 ok(SUCCEEDED(hr), "Failed to get DC, hr %#x.\n", hr);
7360 i = GetDIBColorTable(dc, 0, sizeof(rgbquad) / sizeof(*rgbquad), rgbquad);
7361 ok(i == sizeof(rgbquad) / sizeof(*rgbquad), "Expected count 255, got %u.\n", i);
7362 for (i = 0; i < sizeof(expected2) / sizeof(*expected2); i++)
7364 ok(!memcmp(&rgbquad[i], &expected2[i], sizeof(rgbquad[i])),
7365 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7366 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
7367 expected2[i].rgbRed, expected2[i].rgbGreen, expected2[i].rgbBlue);
7369 for (; i < sizeof(rgbquad) / sizeof(*rgbquad); i++)
7371 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
7372 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
7373 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
7375 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
7376 ok(SUCCEEDED(hr), "Failed to release DC, hr %#x.\n", hr);
7378 refcount = IDirectDrawSurface_Release(surface);
7379 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
7381 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
7382 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
7383 if (FAILED(IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 8, 0, 0)))
7385 win_skip("Failed to set 8 bpp display mode, skipping test.\n");
7386 IDirectDrawPalette_Release(palette);
7387 IDirectDraw2_Release(ddraw);
7388 DestroyWindow(window);
7389 return;
7391 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#x.\n", hr);
7393 memset(&surface_desc, 0, sizeof(surface_desc));
7394 surface_desc.dwSize = sizeof(surface_desc);
7395 surface_desc.dwFlags = DDSD_CAPS;
7396 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
7397 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
7398 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
7400 memset(&fx, 0, sizeof(fx));
7401 fx.dwSize = sizeof(fx);
7402 fx.dwFillColor = 3;
7403 SetRect(&r, 0, 0, 319, 479);
7404 hr = IDirectDrawSurface_Blt(primary, &r, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
7405 ok(SUCCEEDED(hr), "Failed to clear surface, hr %#x.\n", hr);
7406 SetRect(&r, 320, 0, 639, 479);
7407 fx.dwFillColor = 4;
7408 hr = IDirectDrawSurface_Blt(primary, &r, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
7409 ok(SUCCEEDED(hr), "Failed to clear surface, hr %#x.\n", hr);
7411 hr = IDirectDrawSurface_SetPalette(primary, palette);
7412 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
7413 hr = IDirectDrawSurface_GetDC(primary, &dc);
7414 ok(SUCCEEDED(hr), "Failed to get DC, hr %#x.\n", hr);
7416 color = GetPixel(dc, 160, 240);
7417 ok(color == 0x00030000, "Clear index 3: Got unexpected color 0x%08x.\n", color);
7418 color = GetPixel(dc, 480, 240);
7419 ok(color == 0x00252423, "Clear index 4: Got unexpected color 0x%08x.\n", color);
7421 ddraw_palette_handle = SelectPalette(dc, GetStockObject(DEFAULT_PALETTE), FALSE);
7422 /* Windows 2000 on the testbot assigns a different palette to the primary. Refrast? */
7423 ok(ddraw_palette_handle == GetStockObject(DEFAULT_PALETTE) || broken(TRUE),
7424 "Got unexpected palette %p, expected %p.\n",
7425 ddraw_palette_handle, GetStockObject(DEFAULT_PALETTE));
7426 SelectPalette(dc, ddraw_palette_handle, FALSE);
7428 /* The primary uses the system palette. In exclusive mode, the system palette matches
7429 * the ddraw palette attached to the primary, so the result is what you would expect
7430 * from a regular surface. Tests for the interaction between the ddraw palette and
7431 * the system palette are not included pending an application that depends on this.
7432 * The relation between those causes problems on Windows Vista and newer for games
7433 * like Age of Empires or StarCraft. Don't emulate it without a real need. */
7434 i = GetDIBColorTable(dc, 0, sizeof(rgbquad) / sizeof(*rgbquad), rgbquad);
7435 ok(i == sizeof(rgbquad) / sizeof(*rgbquad), "Expected count 255, got %u.\n", i);
7436 for (i = 0; i < sizeof(expected2) / sizeof(*expected2); i++)
7438 ok(!memcmp(&rgbquad[i], &expected2[i], sizeof(rgbquad[i])),
7439 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7440 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
7441 expected2[i].rgbRed, expected2[i].rgbGreen, expected2[i].rgbBlue);
7443 for (; i < sizeof(rgbquad) / sizeof(*rgbquad); i++)
7445 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
7446 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
7447 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
7449 hr = IDirectDrawSurface_ReleaseDC(primary, dc);
7450 ok(SUCCEEDED(hr), "Failed to release DC, hr %#x.\n", hr);
7452 memset(&surface_desc, 0, sizeof(surface_desc));
7453 surface_desc.dwSize = sizeof(surface_desc);
7454 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
7455 surface_desc.dwWidth = 16;
7456 surface_desc.dwHeight = 16;
7457 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
7458 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7459 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
7461 /* Here the offscreen surface appears to use the primary's palette,
7462 * but in all likelihood it is actually the system palette. */
7463 hr = IDirectDrawSurface_GetDC(surface, &dc);
7464 ok(SUCCEEDED(hr), "Failed to get DC, hr %#x.\n", hr);
7465 i = GetDIBColorTable(dc, 0, sizeof(rgbquad) / sizeof(*rgbquad), rgbquad);
7466 ok(i == sizeof(rgbquad) / sizeof(*rgbquad), "Expected count 255, got %u.\n", i);
7467 for (i = 0; i < sizeof(expected2) / sizeof(*expected2); i++)
7469 ok(!memcmp(&rgbquad[i], &expected2[i], sizeof(rgbquad[i])),
7470 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7471 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
7472 expected2[i].rgbRed, expected2[i].rgbGreen, expected2[i].rgbBlue);
7474 for (; i < sizeof(rgbquad) / sizeof(*rgbquad); i++)
7476 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
7477 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
7478 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
7480 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
7481 ok(SUCCEEDED(hr), "Failed to release DC, hr %#x.\n", hr);
7483 /* On real hardware a change to the primary surface's palette applies immediately,
7484 * even on device contexts from offscreen surfaces that do not have their own
7485 * palette. On the testbot VMs this is not the case. Don't test this until we
7486 * know of an application that depends on this. */
7488 memset(palette_entries, 0, sizeof(palette_entries));
7489 palette_entries[1].peBlue = 0x40;
7490 palette_entries[2].peRed = 0x40;
7491 palette_entries[3].peGreen = 0x40;
7492 palette_entries[4].peRed = 0x12;
7493 palette_entries[4].peGreen = 0x34;
7494 palette_entries[4].peBlue = 0x56;
7495 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
7496 palette_entries, &palette2, NULL);
7497 ok(SUCCEEDED(hr), "Failed to create palette, hr %#x.\n", hr);
7498 hr = IDirectDrawSurface_SetPalette(surface, palette2);
7499 ok(SUCCEEDED(hr), "Failed to set palette, hr %#x.\n", hr);
7501 /* A palette assigned to the offscreen surface overrides the primary / system
7502 * palette. */
7503 hr = IDirectDrawSurface_GetDC(surface, &dc);
7504 ok(SUCCEEDED(hr), "Failed to get DC, hr %#x.\n", hr);
7505 i = GetDIBColorTable(dc, 0, sizeof(rgbquad) / sizeof(*rgbquad), rgbquad);
7506 ok(i == sizeof(rgbquad) / sizeof(*rgbquad), "Expected count 255, got %u.\n", i);
7507 for (i = 0; i < sizeof(expected3) / sizeof(*expected3); i++)
7509 ok(!memcmp(&rgbquad[i], &expected3[i], sizeof(rgbquad[i])),
7510 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7511 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
7512 expected3[i].rgbRed, expected3[i].rgbGreen, expected3[i].rgbBlue);
7514 for (; i < sizeof(rgbquad) / sizeof(*rgbquad); i++)
7516 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
7517 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
7518 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
7520 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
7521 ok(SUCCEEDED(hr), "Failed to release DC, hr %#x.\n", hr);
7523 refcount = IDirectDrawSurface_Release(surface);
7524 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
7526 /* The Windows 8 testbot keeps extra references to the primary and
7527 * backbuffer while in 8 bpp mode. */
7528 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
7529 ok(SUCCEEDED(hr), "Failed to restore display mode, hr %#x.\n", hr);
7531 refcount = IDirectDrawSurface_Release(primary);
7532 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
7533 refcount = IDirectDrawPalette_Release(palette2);
7534 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
7535 refcount = IDirectDrawPalette_Release(palette);
7536 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
7537 refcount = IDirectDraw2_Release(ddraw);
7538 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
7539 DestroyWindow(window);
7542 static void test_palette_alpha(void)
7544 IDirectDrawSurface *surface1;
7545 IDirectDrawSurface2 *surface;
7546 DDSURFACEDESC surface_desc;
7547 IDirectDraw2 *ddraw;
7548 IDirectDrawPalette *palette;
7549 ULONG refcount;
7550 HWND window;
7551 HRESULT hr;
7552 PALETTEENTRY palette_entries[256];
7553 unsigned int i;
7554 static const struct
7556 DWORD caps, flags;
7557 BOOL attach_allowed;
7558 const char *name;
7560 test_data[] =
7562 {DDSCAPS_OFFSCREENPLAIN, DDSD_WIDTH | DDSD_HEIGHT, FALSE, "offscreenplain"},
7563 {DDSCAPS_TEXTURE, DDSD_WIDTH | DDSD_HEIGHT, TRUE, "texture"},
7564 {DDSCAPS_PRIMARYSURFACE, 0, FALSE, "primary"}
7567 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
7568 0, 0, 640, 480, 0, 0, 0, 0);
7569 ddraw = create_ddraw();
7570 ok(!!ddraw, "Failed to create a ddraw object.\n");
7571 if (FAILED(IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 8, 0, 0)))
7573 win_skip("Failed to set 8 bpp display mode, skipping test.\n");
7574 IDirectDraw2_Release(ddraw);
7575 DestroyWindow(window);
7576 return;
7578 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
7579 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
7581 memset(palette_entries, 0, sizeof(palette_entries));
7582 palette_entries[1].peFlags = 0x42;
7583 palette_entries[2].peFlags = 0xff;
7584 palette_entries[3].peFlags = 0x80;
7585 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, palette_entries, &palette, NULL);
7586 ok(SUCCEEDED(hr), "Failed to create palette, hr %#x.\n", hr);
7588 memset(palette_entries, 0x66, sizeof(palette_entries));
7589 hr = IDirectDrawPalette_GetEntries(palette, 0, 1, 4, palette_entries);
7590 ok(SUCCEEDED(hr), "Failed to get palette entries, hr %#x.\n", hr);
7591 ok(palette_entries[0].peFlags == 0x42, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
7592 palette_entries[0].peFlags);
7593 ok(palette_entries[1].peFlags == 0xff, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
7594 palette_entries[1].peFlags);
7595 ok(palette_entries[2].peFlags == 0x80, "Got unexpected peFlags 0x%02x, expected 0x80.\n",
7596 palette_entries[2].peFlags);
7597 ok(palette_entries[3].peFlags == 0x00, "Got unexpected peFlags 0x%02x, expected 0x00.\n",
7598 palette_entries[3].peFlags);
7600 IDirectDrawPalette_Release(palette);
7602 memset(palette_entries, 0, sizeof(palette_entries));
7603 palette_entries[1].peFlags = 0x42;
7604 palette_entries[1].peRed = 0xff;
7605 palette_entries[2].peFlags = 0xff;
7606 palette_entries[3].peFlags = 0x80;
7607 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_ALLOW256 | DDPCAPS_8BIT | DDPCAPS_ALPHA,
7608 palette_entries, &palette, NULL);
7609 ok(SUCCEEDED(hr), "Failed to create palette, hr %#x.\n", hr);
7611 memset(palette_entries, 0x66, sizeof(palette_entries));
7612 hr = IDirectDrawPalette_GetEntries(palette, 0, 1, 4, palette_entries);
7613 ok(SUCCEEDED(hr), "Failed to get palette entries, hr %#x.\n", hr);
7614 ok(palette_entries[0].peFlags == 0x42, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
7615 palette_entries[0].peFlags);
7616 ok(palette_entries[1].peFlags == 0xff, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
7617 palette_entries[1].peFlags);
7618 ok(palette_entries[2].peFlags == 0x80, "Got unexpected peFlags 0x%02x, expected 0x80.\n",
7619 palette_entries[2].peFlags);
7620 ok(palette_entries[3].peFlags == 0x00, "Got unexpected peFlags 0x%02x, expected 0x00.\n",
7621 palette_entries[3].peFlags);
7623 for (i = 0; i < sizeof(test_data) / sizeof(*test_data); i++)
7625 memset(&surface_desc, 0, sizeof(surface_desc));
7626 surface_desc.dwSize = sizeof(surface_desc);
7627 surface_desc.dwFlags = DDSD_CAPS | test_data[i].flags;
7628 surface_desc.dwWidth = 128;
7629 surface_desc.dwHeight = 128;
7630 surface_desc.ddsCaps.dwCaps = test_data[i].caps;
7631 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
7632 ok(SUCCEEDED(hr), "Failed to create %s surface, hr %#x.\n", test_data[i].name, hr);
7633 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface);
7634 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface2 interface, hr %#x.\n", hr);
7635 IDirectDrawSurface_Release(surface1);
7637 hr = IDirectDrawSurface2_SetPalette(surface, palette);
7638 if (test_data[i].attach_allowed)
7639 ok(SUCCEEDED(hr), "Failed to attach palette to %s surface, hr %#x.\n", test_data[i].name, hr);
7640 else
7641 ok(hr == DDERR_INVALIDSURFACETYPE, "Got unexpected hr %#x, %s surface.\n", hr, test_data[i].name);
7643 if (SUCCEEDED(hr))
7645 HDC dc;
7646 RGBQUAD rgbquad;
7647 UINT retval;
7649 hr = IDirectDrawSurface2_GetDC(surface, &dc);
7650 ok(SUCCEEDED(hr) || broken(hr == DDERR_CANTCREATEDC) /* Win2k testbot */,
7651 "Failed to get DC, hr %#x, %s surface.\n", hr, test_data[i].name);
7652 if (SUCCEEDED(hr))
7654 retval = GetDIBColorTable(dc, 1, 1, &rgbquad);
7655 ok(retval == 1, "GetDIBColorTable returned unexpected result %u.\n", retval);
7656 ok(rgbquad.rgbRed == 0xff, "Expected rgbRed = 0xff, got %#x, %s surface.\n",
7657 rgbquad.rgbRed, test_data[i].name);
7658 ok(rgbquad.rgbGreen == 0, "Expected rgbGreen = 0, got %#x, %s surface.\n",
7659 rgbquad.rgbGreen, test_data[i].name);
7660 ok(rgbquad.rgbBlue == 0, "Expected rgbBlue = 0, got %#x, %s surface.\n",
7661 rgbquad.rgbBlue, test_data[i].name);
7662 todo_wine ok(rgbquad.rgbReserved == 0, "Expected rgbReserved = 0, got %u, %s surface.\n",
7663 rgbquad.rgbReserved, test_data[i].name);
7664 hr = IDirectDrawSurface2_ReleaseDC(surface, dc);
7665 ok(SUCCEEDED(hr), "Failed to release DC, hr %#x.\n", hr);
7668 IDirectDrawSurface2_Release(surface);
7671 /* Test INVALIDSURFACETYPE vs INVALIDPIXELFORMAT. */
7672 memset(&surface_desc, 0, sizeof(surface_desc));
7673 surface_desc.dwSize = sizeof(surface_desc);
7674 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
7675 surface_desc.dwWidth = 128;
7676 surface_desc.dwHeight = 128;
7677 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
7678 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
7679 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
7680 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
7681 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
7682 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
7683 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
7684 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
7685 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
7686 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface);
7687 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface2 interface, hr %#x.\n", hr);
7688 IDirectDrawSurface_Release(surface1);
7690 hr = IDirectDrawSurface2_SetPalette(surface, palette);
7691 ok(hr == DDERR_INVALIDSURFACETYPE, "Got unexpected hr %#x.\n", hr);
7692 IDirectDrawSurface2_Release(surface);
7694 /* The Windows 8 testbot keeps extra references to the primary
7695 * while in 8 bpp mode. */
7696 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
7697 ok(SUCCEEDED(hr), "Failed to restore display mode, hr %#x.\n", hr);
7699 refcount = IDirectDrawPalette_Release(palette);
7700 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
7701 refcount = IDirectDraw2_Release(ddraw);
7702 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
7703 DestroyWindow(window);
7706 static void test_lost_device(void)
7708 IDirectDrawSurface *surface;
7709 DDSURFACEDESC surface_desc;
7710 HWND window1, window2;
7711 IDirectDraw2 *ddraw;
7712 ULONG refcount;
7713 HRESULT hr;
7714 BOOL ret;
7716 window1 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
7717 0, 0, 640, 480, 0, 0, 0, 0);
7718 window2 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
7719 0, 0, 640, 480, 0, 0, 0, 0);
7720 ddraw = create_ddraw();
7721 ok(!!ddraw, "Failed to create a ddraw object.\n");
7722 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
7723 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
7725 memset(&surface_desc, 0, sizeof(surface_desc));
7726 surface_desc.dwSize = sizeof(surface_desc);
7727 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
7728 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
7729 surface_desc.dwBackBufferCount = 1;
7730 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7731 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
7733 hr = IDirectDrawSurface_IsLost(surface);
7734 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7735 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7736 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7738 ret = SetForegroundWindow(GetDesktopWindow());
7739 ok(ret, "Failed to set foreground window.\n");
7740 hr = IDirectDrawSurface_IsLost(surface);
7741 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
7742 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7743 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
7745 ret = SetForegroundWindow(window1);
7746 ok(ret, "Failed to set foreground window.\n");
7747 hr = IDirectDrawSurface_IsLost(surface);
7748 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
7749 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7750 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
7752 hr = restore_surfaces(ddraw);
7753 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7754 hr = IDirectDrawSurface_IsLost(surface);
7755 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7756 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7757 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7759 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
7760 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7761 hr = IDirectDrawSurface_IsLost(surface);
7762 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
7763 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7764 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
7766 /* Trying to restore the primary will crash, probably because flippable
7767 * surfaces can't exist in DDSCL_NORMAL. */
7768 IDirectDrawSurface_Release(surface);
7769 memset(&surface_desc, 0, sizeof(surface_desc));
7770 surface_desc.dwSize = sizeof(surface_desc);
7771 surface_desc.dwFlags = DDSD_CAPS;
7772 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
7773 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7774 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
7776 hr = IDirectDrawSurface_IsLost(surface);
7777 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7779 ret = SetForegroundWindow(GetDesktopWindow());
7780 ok(ret, "Failed to set foreground window.\n");
7781 hr = IDirectDrawSurface_IsLost(surface);
7782 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7784 ret = SetForegroundWindow(window1);
7785 ok(ret, "Failed to set foreground window.\n");
7786 hr = IDirectDrawSurface_IsLost(surface);
7787 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7789 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
7790 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7791 hr = IDirectDrawSurface_IsLost(surface);
7792 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
7794 hr = restore_surfaces(ddraw);
7795 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7796 hr = IDirectDrawSurface_IsLost(surface);
7797 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7799 IDirectDrawSurface_Release(surface);
7800 memset(&surface_desc, 0, sizeof(surface_desc));
7801 surface_desc.dwSize = sizeof(surface_desc);
7802 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
7803 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
7804 U5(surface_desc).dwBackBufferCount = 1;
7805 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7806 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
7808 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
7809 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7810 hr = IDirectDrawSurface_IsLost(surface);
7811 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7812 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7813 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7815 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL | DDSCL_FULLSCREEN);
7816 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7817 hr = IDirectDrawSurface_IsLost(surface);
7818 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7819 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7820 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#x.\n", hr);
7822 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
7823 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7824 hr = IDirectDrawSurface_IsLost(surface);
7825 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7826 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7827 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#x.\n", hr);
7829 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL);
7830 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7831 hr = IDirectDrawSurface_IsLost(surface);
7832 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7833 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7834 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#x.\n", hr);
7836 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL | DDSCL_FULLSCREEN);
7837 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7838 hr = IDirectDrawSurface_IsLost(surface);
7839 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7840 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7841 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#x.\n", hr);
7843 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window2, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
7844 ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
7845 hr = IDirectDrawSurface_IsLost(surface);
7846 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
7847 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
7848 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
7850 IDirectDrawSurface_Release(surface);
7851 refcount = IDirectDraw2_Release(ddraw);
7852 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
7853 DestroyWindow(window2);
7854 DestroyWindow(window1);
7857 static void test_surface_desc_lock(void)
7859 IDirectDrawSurface *surface;
7860 DDSURFACEDESC surface_desc;
7861 IDirectDraw2 *ddraw;
7862 ULONG refcount;
7863 HWND window;
7864 HRESULT hr;
7866 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
7867 0, 0, 640, 480, 0, 0, 0, 0);
7868 ddraw = create_ddraw();
7869 ok(!!ddraw, "Failed to create a ddraw object.\n");
7870 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
7871 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
7873 memset(&surface_desc, 0, sizeof(surface_desc));
7874 surface_desc.dwSize = sizeof(surface_desc);
7875 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
7876 surface_desc.dwWidth = 16;
7877 surface_desc.dwHeight = 16;
7878 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
7879 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7880 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
7882 memset(&surface_desc, 0xaa, sizeof(surface_desc));
7883 surface_desc.dwSize = sizeof(surface_desc);
7884 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
7885 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
7886 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
7888 memset(&surface_desc, 0xaa, sizeof(surface_desc));
7889 surface_desc.dwSize = sizeof(surface_desc);
7890 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, 0, NULL);
7891 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
7892 ok(surface_desc.lpSurface != NULL, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
7893 memset(&surface_desc, 0xaa, sizeof(surface_desc));
7894 surface_desc.dwSize = sizeof(surface_desc);
7895 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
7896 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
7897 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
7898 hr = IDirectDrawSurface_Unlock(surface, NULL);
7899 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
7901 memset(&surface_desc, 0xaa, sizeof(surface_desc));
7902 surface_desc.dwSize = sizeof(surface_desc);
7903 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
7904 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
7905 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
7907 IDirectDrawSurface_Release(surface);
7908 refcount = IDirectDraw2_Release(ddraw);
7909 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
7910 DestroyWindow(window);
7913 static void test_texturemapblend(void)
7915 HRESULT hr;
7916 DDSURFACEDESC ddsd;
7917 DDBLTFX fx;
7918 static RECT rect = {0, 0, 64, 128};
7919 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
7920 DDCOLORKEY ckey;
7921 IDirectDrawSurface *surface, *rt;
7922 IDirect3DTexture2 *texture;
7923 D3DTEXTUREHANDLE texture_handle;
7924 HWND window;
7925 IDirectDraw2 *ddraw;
7926 IDirect3DDevice2 *device;
7927 IDirect3DMaterial2 *material;
7928 IDirect3DViewport2 *viewport;
7929 ULONG ref;
7930 D3DCOLOR color;
7932 static D3DTLVERTEX test1_quads[] =
7934 {{0.0f}, {0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {0.0f}, {0.0f}},
7935 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {0.0f}, {1.0f}},
7936 {{640.0f}, {0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {1.0f}, {0.0f}},
7937 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {1.0f}, {1.0f}},
7938 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {0.0f}, {0.0f}},
7939 {{0.0f}, {480.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {0.0f}, {1.0f}},
7940 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {1.0f}, {0.0f}},
7941 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {1.0f}, {1.0f}},
7943 test2_quads[] =
7945 {{0.0f}, {0.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {0.0f}, {0.0f}},
7946 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {0.0f}, {1.0f}},
7947 {{640.0f}, {0.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {1.0f}, {0.0f}},
7948 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {1.0f}, {1.0f}},
7949 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {0.0f}, {0.0f}},
7950 {{0.0f}, {480.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {0.0f}, {1.0f}},
7951 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {1.0f}, {0.0f}},
7952 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {1.0f}, {1.0f}},
7955 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
7956 0, 0, 640, 480, 0, 0, 0, 0);
7957 ddraw = create_ddraw();
7958 ok(!!ddraw, "Failed to create a ddraw object.\n");
7959 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
7961 skip("Failed to create a 3D device, skipping test.\n");
7962 DestroyWindow(window);
7963 IDirectDraw2_Release(ddraw);
7964 return;
7967 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
7968 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
7970 material = create_diffuse_material(device, 0.0f, 0.0f, 0.0f, 1.0f);
7971 viewport = create_viewport(device, 0, 0, 640, 480);
7972 viewport_set_background(device, viewport, material);
7973 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
7974 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
7976 /* Test alpha with DDPF_ALPHAPIXELS texture - should be taken from texture alpha channel.
7978 * The vertex alpha is completely ignored in this case, so case 1 and 2 combined are not
7979 * a D3DTOP_MODULATE with texture alpha = 0xff in case 2 (no alpha in texture). */
7980 memset(&ddsd, 0, sizeof(ddsd));
7981 ddsd.dwSize = sizeof(ddsd);
7982 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
7983 ddsd.dwHeight = 128;
7984 ddsd.dwWidth = 128;
7985 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
7986 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
7987 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
7988 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
7989 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
7990 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
7991 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
7992 U5(ddsd.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
7993 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
7994 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
7996 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
7997 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
7998 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
7999 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
8000 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
8001 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8003 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8004 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
8006 memset(&fx, 0, sizeof(fx));
8007 fx.dwSize = sizeof(fx);
8008 U5(fx).dwFillColor = 0xff0000ff;
8009 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8010 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#x.\n", hr);
8011 U5(fx).dwFillColor = 0x800000ff;
8012 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8013 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#x.\n", hr);
8015 /* Note that the ddraw1 version of this test runs tests 1-3 with D3DRENDERSTATE_COLORKEYENABLE
8016 * enabled, whereas this version only runs test 4 with color keying on. Because no color key
8017 * is set on the texture this should not result in different behavior. */
8018 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
8019 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8020 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
8021 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8022 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
8023 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8024 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
8025 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8026 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
8027 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8028 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
8029 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8031 hr = IDirect3DDevice2_BeginScene(device);
8032 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
8033 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[0], 4, 0);
8034 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
8035 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[4], 4, 0);
8036 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
8037 hr = IDirect3DDevice2_EndScene(device);
8038 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
8040 color = get_surface_color(rt, 5, 5);
8041 ok(compare_color(color, 0x00000080, 2), "Got unexpected color 0x%08x.\n", color);
8042 color = get_surface_color(rt, 400, 5);
8043 ok(compare_color(color, 0x000000ff, 2), "Got unexpected color 0x%08x.\n", color);
8044 color = get_surface_color(rt, 5, 245);
8045 ok(compare_color(color, 0x00000080, 2), "Got unexpected color 0x%08x.\n", color);
8046 color = get_surface_color(rt, 400, 245);
8047 ok(compare_color(color, 0x000000ff, 2), "Got unexpected color 0x%08x.\n", color);
8049 IDirect3DTexture2_Release(texture);
8050 ref = IDirectDrawSurface_Release(surface);
8051 ok(ref == 0, "Surface not properly released, refcount %u.\n", ref);
8053 /* Test alpha with texture that has no alpha channel - alpha should be taken from diffuse vertex color. */
8054 memset(&ddsd, 0, sizeof(ddsd));
8055 ddsd.dwSize = sizeof(ddsd);
8056 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
8057 ddsd.dwHeight = 128;
8058 ddsd.dwWidth = 128;
8059 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
8060 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
8061 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
8062 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
8063 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
8064 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
8065 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
8067 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
8068 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
8070 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
8071 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
8072 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
8073 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
8074 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
8075 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8077 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8078 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
8080 U5(fx).dwFillColor = 0xff0000ff;
8081 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8082 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#x.\n", hr);
8083 U5(fx).dwFillColor = 0x800000ff;
8084 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8085 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#x.\n", hr);
8087 hr = IDirect3DDevice2_BeginScene(device);
8088 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
8089 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[0], 4, 0);
8090 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
8091 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[4], 4, 0);
8092 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
8093 hr = IDirect3DDevice2_EndScene(device);
8094 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
8096 color = get_surface_color(rt, 5, 5);
8097 ok(compare_color(color, 0x000000ff, 2), "Got unexpected color 0x%08x.\n", color);
8098 color = get_surface_color(rt, 400, 5);
8099 ok(compare_color(color, 0x000000ff, 2), "Got unexpected color 0x%08x.\n", color);
8100 color = get_surface_color(rt, 5, 245);
8101 ok(compare_color(color, 0x00000080, 2), "Got unexpected color 0x%08x.\n", color);
8102 color = get_surface_color(rt, 400, 245);
8103 ok(compare_color(color, 0x00000080, 2), "Got unexpected color 0x%08x.\n", color);
8105 IDirect3DTexture2_Release(texture);
8106 ref = IDirectDrawSurface_Release(surface);
8107 ok(ref == 0, "Surface not properly released, refcount %u.\n", ref);
8109 /* Test RGB - should multiply color components from diffuse vertex color and texture. */
8110 memset(&ddsd, 0, sizeof(ddsd));
8111 ddsd.dwSize = sizeof(ddsd);
8112 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
8113 ddsd.dwHeight = 128;
8114 ddsd.dwWidth = 128;
8115 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
8116 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
8117 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
8118 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
8119 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
8120 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
8121 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
8122 U5(ddsd.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
8123 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
8124 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
8126 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
8127 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
8128 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
8129 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
8130 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
8131 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8133 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8134 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
8136 U5(fx).dwFillColor = 0x00ffffff;
8137 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8138 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#x.\n", hr);
8139 U5(fx).dwFillColor = 0x00ffff80;
8140 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8141 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#x.\n", hr);
8143 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
8144 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8146 hr = IDirect3DDevice2_BeginScene(device);
8147 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
8148 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test2_quads[0], 4, 0);
8149 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
8150 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test2_quads[4], 4, 0);
8151 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
8152 hr = IDirect3DDevice2_EndScene(device);
8153 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
8155 color = get_surface_color(rt, 5, 5);
8156 ok(compare_color(color, 0x00ff0040, 2), "Got unexpected color 0x%08x.\n", color);
8157 color = get_surface_color(rt, 400, 5);
8158 ok(compare_color(color, 0x00ff0080, 2), "Got unexpected color 0x%08x.\n", color);
8159 color = get_surface_color(rt, 5, 245);
8160 ok(compare_color(color, 0x00800080, 2), "Got unexpected color 0x%08x.\n", color);
8161 color = get_surface_color(rt, 400, 245);
8162 ok(compare_color(color, 0x008000ff, 2), "Got unexpected color 0x%08x.\n", color);
8164 IDirect3DTexture2_Release(texture);
8165 ref = IDirectDrawSurface_Release(surface);
8166 ok(ref == 0, "Surface not properly released, refcount %u.\n", ref);
8168 /* Test alpha again, now with color keyed texture (colorkey emulation in wine can interfere). */
8169 memset(&ddsd, 0, sizeof(ddsd));
8170 ddsd.dwSize = sizeof(ddsd);
8171 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
8172 ddsd.dwHeight = 128;
8173 ddsd.dwWidth = 128;
8174 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
8175 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
8176 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
8177 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 16;
8178 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0xf800;
8179 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x07e0;
8180 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x001f;
8182 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
8183 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
8185 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
8186 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
8187 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
8188 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
8189 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
8190 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8192 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8193 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
8195 U5(fx).dwFillColor = 0xf800;
8196 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8197 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#x.\n", hr);
8198 U5(fx).dwFillColor = 0x001f;
8199 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8200 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#x.\n", hr);
8202 ckey.dwColorSpaceLowValue = 0x001f;
8203 ckey.dwColorSpaceHighValue = 0x001f;
8204 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &ckey);
8205 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
8207 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
8208 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8209 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
8210 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8212 hr = IDirect3DDevice2_BeginScene(device);
8213 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
8214 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[0], 4, 0);
8215 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
8216 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[4], 4, 0);
8217 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
8218 hr = IDirect3DDevice2_EndScene(device);
8219 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
8221 color = get_surface_color(rt, 5, 5);
8222 ok(compare_color(color, 0x00000000, 2), "Got unexpected color 0x%08x.\n", color);
8223 color = get_surface_color(rt, 400, 5);
8224 ok(compare_color(color, 0x00ff0000, 2), "Got unexpected color 0x%08x.\n", color);
8225 color = get_surface_color(rt, 5, 245);
8226 ok(compare_color(color, 0x00000000, 2), "Got unexpected color 0x%08x.\n", color);
8227 color = get_surface_color(rt, 400, 245);
8228 ok(compare_color(color, 0x00800000, 2), "Got unexpected color 0x%08x.\n", color);
8230 IDirect3DTexture2_Release(texture);
8231 ref = IDirectDrawSurface_Release(surface);
8232 ok(ref == 0, "Surface not properly released, refcount %u.\n", ref);
8234 destroy_viewport(device, viewport);
8235 ref = IDirect3DMaterial2_Release(material);
8236 ok(ref == 0, "Material not properly released, refcount %u.\n", ref);
8237 IDirectDrawSurface_Release(rt);
8238 IDirect3DDevice2_Release(device);
8239 ref = IDirectDraw2_Release(ddraw);
8240 ok(ref == 0, "Ddraw object not properly released, refcount %u.\n", ref);
8241 DestroyWindow(window);
8244 static void test_viewport_clear_rect(void)
8246 HRESULT hr;
8247 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
8248 static D3DRECT clear_rect2 = {{90}, {90}, {110}, {110}};
8249 IDirectDrawSurface *rt;
8250 HWND window;
8251 IDirectDraw2 *ddraw;
8252 IDirect3DDevice2 *device;
8253 IDirect3DMaterial2 *red, *green;
8254 IDirect3DViewport2 *viewport, *viewport2;
8255 ULONG ref;
8256 D3DCOLOR color;
8258 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
8259 0, 0, 640, 480, 0, 0, 0, 0);
8260 ddraw = create_ddraw();
8261 ok(!!ddraw, "Failed to create a ddraw object.\n");
8262 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
8264 skip("Failed to create a 3D device, skipping test.\n");
8265 DestroyWindow(window);
8266 IDirectDraw2_Release(ddraw);
8267 return;
8270 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
8271 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
8273 red = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
8274 viewport = create_viewport(device, 0, 0, 640, 480);
8275 viewport_set_background(device, viewport, red);
8276 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8277 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
8279 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 1.0f);
8280 viewport2 = create_viewport(device, 100, 100, 20, 20);
8281 viewport_set_background(device, viewport2, green);
8282 hr = IDirect3DViewport2_Clear(viewport2, 1, &clear_rect2, D3DCLEAR_TARGET);
8283 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
8285 color = get_surface_color(rt, 85, 85); /* Outside both. */
8286 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
8287 color = get_surface_color(rt, 95, 95); /* Outside vp, inside rect. */
8288 /* AMD GPUs ignore the viewport dimensions and only care about the rectangle. */
8289 ok(compare_color(color, 0x00ff0000, 1) || broken(compare_color(color, 0x0000ff00, 1)),
8290 "Got unexpected color 0x%08x.\n", color);
8291 color = get_surface_color(rt, 105, 105); /* Inside both. */
8292 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
8293 color = get_surface_color(rt, 115, 115); /* Inside vp, outside rect. */
8294 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
8295 color = get_surface_color(rt, 125, 125); /* Outside both. */
8296 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
8298 destroy_viewport(device, viewport2);
8299 destroy_material(green);
8300 destroy_viewport(device, viewport);
8301 destroy_material(red);
8302 IDirectDrawSurface_Release(rt);
8303 IDirect3DDevice2_Release(device);
8304 ref = IDirectDraw2_Release(ddraw);
8305 ok(ref == 0, "Ddraw object not properly released, refcount %u.\n", ref);
8306 DestroyWindow(window);
8309 static void test_color_fill(void)
8311 HRESULT hr;
8312 IDirect3DDevice2 *device;
8313 IDirectDraw2 *ddraw;
8314 IDirectDrawSurface *surface, *surface2;
8315 DDSURFACEDESC surface_desc;
8316 ULONG refcount;
8317 HWND window;
8318 unsigned int i;
8319 DDBLTFX fx;
8320 RECT rect = {5, 5, 7, 7};
8321 DWORD *color;
8322 DWORD num_fourcc_codes, *fourcc_codes;
8323 DDCAPS hal_caps;
8324 BOOL support_uyvy = FALSE, support_yuy2 = FALSE;
8325 static const struct
8327 DWORD caps;
8328 HRESULT colorfill_hr, depthfill_hr;
8329 BOOL rop_success;
8330 const char *name;
8331 DWORD result;
8332 BOOL check_result;
8333 DDPIXELFORMAT format;
8335 tests[] =
8338 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
8339 DD_OK, DDERR_INVALIDPARAMS, TRUE, "vidmem offscreenplain RGB", 0xdeadbeef, TRUE,
8341 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
8342 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
8346 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
8347 DD_OK, DDERR_INVALIDPARAMS, TRUE, "sysmem offscreenplain RGB", 0xdeadbeef, TRUE,
8349 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
8350 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
8354 DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY,
8355 DD_OK, DDERR_INVALIDPARAMS, TRUE, "vidmem texture RGB", 0xdeadbeef, TRUE,
8357 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
8358 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
8362 DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY,
8363 DD_OK, DDERR_INVALIDPARAMS, TRUE, "sysmem texture RGB", 0xdeadbeef, TRUE,
8365 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
8366 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
8370 DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY,
8371 DDERR_INVALIDPARAMS, DD_OK, TRUE, "vidmem zbuffer", 0, FALSE,
8372 {0, 0, 0, {0}, {0}, {0}, {0}, {0}}
8375 /* Colorfill on YUV surfaces always returns DD_OK, but the content is
8376 * different afterwards. DX9+ GPUs set one of the two luminance values
8377 * in each block, but AMD and Nvidia GPUs disagree on which luminance
8378 * value they set. r200 (dx8) just sets the entire block to the clear
8379 * value. */
8380 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
8381 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem offscreenplain YUY2", 0, FALSE,
8383 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y', 'U', 'Y', '2'),
8384 {0}, {0}, {0}, {0}, {0}
8388 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
8389 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem offscreenplain UYVY", 0, FALSE,
8391 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('U', 'Y', 'V', 'Y'),
8392 {0}, {0}, {0}, {0}, {0}
8396 DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY,
8397 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem overlay YUY2", 0, FALSE,
8399 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y', 'U', 'Y', '2'),
8400 {0}, {0}, {0}, {0}, {0}
8404 DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY,
8405 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem overlay UYVY", 0, FALSE,
8407 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('U', 'Y', 'V', 'Y'),
8408 {0}, {0}, {0}, {0}, {0}
8412 DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY,
8413 E_NOTIMPL, DDERR_INVALIDPARAMS, FALSE, "vidmem texture DXT1", 0, FALSE,
8415 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'),
8416 {0}, {0}, {0}, {0}, {0}
8420 DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY,
8421 E_NOTIMPL, DDERR_INVALIDPARAMS, FALSE, "sysmem texture DXT1", 0, FALSE,
8423 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'),
8424 {0}, {0}, {0}, {0}, {0}
8428 /* The testbot fills this with 0x00 instead of the blue channel. The sysmem
8429 * surface works, presumably because it is handled by the runtime instead of
8430 * the driver. */
8431 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
8432 DD_OK, DDERR_INVALIDPARAMS, TRUE, "vidmem offscreenplain P8", 0xefefefef, FALSE,
8434 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED8, 0,
8435 {8}, {0}, {0}, {0}, {0}
8439 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
8440 DD_OK, DDERR_INVALIDPARAMS, TRUE, "sysmem offscreenplain P8", 0xefefefef, TRUE,
8442 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED8, 0,
8443 {8}, {0}, {0}, {0}, {0}
8447 static const struct
8449 DWORD rop;
8450 const char *name;
8451 HRESULT hr;
8453 rops[] =
8455 {SRCCOPY, "SRCCOPY", DD_OK},
8456 {SRCPAINT, "SRCPAINT", DDERR_NORASTEROPHW},
8457 {SRCAND, "SRCAND", DDERR_NORASTEROPHW},
8458 {SRCINVERT, "SRCINVERT", DDERR_NORASTEROPHW},
8459 {SRCERASE, "SRCERASE", DDERR_NORASTEROPHW},
8460 {NOTSRCCOPY, "NOTSRCCOPY", DDERR_NORASTEROPHW},
8461 {NOTSRCERASE, "NOTSRCERASE", DDERR_NORASTEROPHW},
8462 {MERGECOPY, "MERGECOPY", DDERR_NORASTEROPHW},
8463 {MERGEPAINT, "MERGEPAINT", DDERR_NORASTEROPHW},
8464 {PATCOPY, "PATCOPY", DDERR_NORASTEROPHW},
8465 {PATPAINT, "PATPAINT", DDERR_NORASTEROPHW},
8466 {PATINVERT, "PATINVERT", DDERR_NORASTEROPHW},
8467 {DSTINVERT, "DSTINVERT", DDERR_NORASTEROPHW},
8468 {BLACKNESS, "BLACKNESS", DD_OK},
8469 {WHITENESS, "WHITENESS", DD_OK},
8470 {0xaa0029, "0xaa0029", DDERR_NORASTEROPHW} /* noop */
8473 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
8474 0, 0, 640, 480, 0, 0, 0, 0);
8475 ddraw = create_ddraw();
8476 ok(!!ddraw, "Failed to create a ddraw object.\n");
8477 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
8479 skip("Failed to create a 3D device, skipping test.\n");
8480 DestroyWindow(window);
8481 IDirectDraw2_Release(ddraw);
8482 return;
8485 hr = IDirectDraw2_GetFourCCCodes(ddraw, &num_fourcc_codes, NULL);
8486 ok(SUCCEEDED(hr), "Failed to get fourcc codes %#x.\n", hr);
8487 fourcc_codes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
8488 num_fourcc_codes * sizeof(*fourcc_codes));
8489 if (!fourcc_codes)
8490 goto done;
8491 hr = IDirectDraw2_GetFourCCCodes(ddraw, &num_fourcc_codes, fourcc_codes);
8492 ok(SUCCEEDED(hr), "Failed to get fourcc codes %#x.\n", hr);
8493 for (i = 0; i < num_fourcc_codes; i++)
8495 if (fourcc_codes[i] == MAKEFOURCC('Y', 'U', 'Y', '2'))
8496 support_yuy2 = TRUE;
8497 else if (fourcc_codes[i] == MAKEFOURCC('U', 'Y', 'V', 'Y'))
8498 support_uyvy = TRUE;
8500 HeapFree(GetProcessHeap(), 0, fourcc_codes);
8502 memset(&hal_caps, 0, sizeof(hal_caps));
8503 hal_caps.dwSize = sizeof(hal_caps);
8504 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, NULL);
8505 ok(SUCCEEDED(hr), "Failed to get caps, hr %#x.\n", hr);
8507 if ((!support_yuy2 && !support_uyvy) || !(hal_caps.dwCaps & DDCAPS_OVERLAY))
8508 skip("Overlays or some YUV formats not supported, skipping YUV colorfill tests.\n");
8510 for (i = 0; i < sizeof(tests) / sizeof(*tests); i++)
8512 /* Some Windows drivers modify dwFillColor when it is used on P8 or FourCC formats. */
8513 memset(&fx, 0, sizeof(fx));
8514 fx.dwSize = sizeof(fx);
8515 U5(fx).dwFillColor = 0xdeadbeef;
8517 memset(&surface_desc, 0, sizeof(surface_desc));
8518 surface_desc.dwSize = sizeof(surface_desc);
8519 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
8520 surface_desc.dwWidth = 64;
8521 surface_desc.dwHeight = 64;
8522 surface_desc.ddpfPixelFormat = tests[i].format;
8523 surface_desc.ddsCaps.dwCaps = tests[i].caps;
8525 if (tests[i].caps & DDSCAPS_TEXTURE)
8527 struct format_support_check check = {&tests[i].format, FALSE};
8528 hr = IDirect3DDevice2_EnumTextureFormats(device, test_unsupported_formats_cb, &check);
8529 ok(SUCCEEDED(hr), "Failed to enumerate texture formats %#x.\n", hr);
8530 if (!check.supported)
8531 continue;
8534 if (tests[i].format.dwFourCC == MAKEFOURCC('Y','U','Y','2') && !support_yuy2)
8535 continue;
8536 if (tests[i].format.dwFourCC == MAKEFOURCC('U','Y','V','Y') && !support_uyvy)
8537 continue;
8538 if (tests[i].caps & DDSCAPS_OVERLAY && !(hal_caps.dwCaps & DDCAPS_OVERLAY))
8539 continue;
8541 if (tests[i].caps & DDSCAPS_ZBUFFER)
8543 surface_desc.dwFlags &= ~DDSD_PIXELFORMAT;
8544 surface_desc.dwFlags |= DDSD_ZBUFFERBITDEPTH;
8545 U2(surface_desc).dwZBufferBitDepth = get_device_z_depth(device);
8548 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
8549 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x, surface %s.\n", hr, tests[i].name);
8551 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8552 todo_wine_if (tests[i].format.dwFourCC)
8553 ok(hr == tests[i].colorfill_hr, "Blt returned %#x, expected %#x, surface %s.\n",
8554 hr, tests[i].colorfill_hr, tests[i].name);
8556 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8557 todo_wine_if (tests[i].format.dwFourCC)
8558 ok(hr == tests[i].colorfill_hr, "Blt returned %#x, expected %#x, surface %s.\n",
8559 hr, tests[i].colorfill_hr, tests[i].name);
8561 if (SUCCEEDED(hr) && tests[i].check_result)
8563 memset(&surface_desc, 0, sizeof(surface_desc));
8564 surface_desc.dwSize = sizeof(surface_desc);
8565 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
8566 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x, surface %s.\n", hr, tests[i].name);
8567 color = surface_desc.lpSurface;
8568 ok(*color == tests[i].result, "Got clear result 0x%08x, expected 0x%08x, surface %s.\n",
8569 *color, tests[i].result, tests[i].name);
8570 hr = IDirectDrawSurface_Unlock(surface, NULL);
8571 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x, surface %s.\n", hr, tests[i].name);
8574 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8575 ok(hr == tests[i].depthfill_hr, "Blt returned %#x, expected %#x, surface %s.\n",
8576 hr, tests[i].depthfill_hr, tests[i].name);
8577 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8578 ok(hr == tests[i].depthfill_hr, "Blt returned %#x, expected %#x, surface %s.\n",
8579 hr, tests[i].depthfill_hr, tests[i].name);
8581 U5(fx).dwFillColor = 0xdeadbeef;
8582 fx.dwROP = BLACKNESS;
8583 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
8584 ok(FAILED(hr) == !tests[i].rop_success, "Blt returned %#x, expected %s, surface %s.\n",
8585 hr, tests[i].rop_success ? "success" : "failure", tests[i].name);
8586 ok(U5(fx).dwFillColor == 0xdeadbeef, "dwFillColor was set to 0x%08x, surface %s\n",
8587 U5(fx).dwFillColor, tests[i].name);
8589 if (SUCCEEDED(hr) && tests[i].check_result)
8591 memset(&surface_desc, 0, sizeof(surface_desc));
8592 surface_desc.dwSize = sizeof(surface_desc);
8593 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
8594 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x, surface %s.\n", hr, tests[i].name);
8595 color = surface_desc.lpSurface;
8596 ok(*color == 0, "Got clear result 0x%08x, expected 0x00000000, surface %s.\n",
8597 *color, tests[i].name);
8598 hr = IDirectDrawSurface_Unlock(surface, NULL);
8599 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x, surface %s.\n", hr, tests[i].name);
8602 fx.dwROP = WHITENESS;
8603 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
8604 ok(FAILED(hr) == !tests[i].rop_success, "Blt returned %#x, expected %s, surface %s.\n",
8605 hr, tests[i].rop_success ? "success" : "failure", tests[i].name);
8606 ok(U5(fx).dwFillColor == 0xdeadbeef, "dwFillColor was set to 0x%08x, surface %s\n",
8607 U5(fx).dwFillColor, tests[i].name);
8609 if (SUCCEEDED(hr) && tests[i].check_result)
8611 memset(&surface_desc, 0, sizeof(surface_desc));
8612 surface_desc.dwSize = sizeof(surface_desc);
8613 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
8614 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x, surface %s.\n", hr, tests[i].name);
8615 color = surface_desc.lpSurface;
8616 /* WHITENESS sets the alpha channel to 0x00. Ignore this for now. */
8617 ok((*color & 0x00ffffff) == 0x00ffffff, "Got clear result 0x%08x, expected 0xffffffff, surface %s.\n",
8618 *color, tests[i].name);
8619 hr = IDirectDrawSurface_Unlock(surface, NULL);
8620 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x, surface %s.\n", hr, tests[i].name);
8623 IDirectDrawSurface_Release(surface);
8626 memset(&fx, 0, sizeof(fx));
8627 fx.dwSize = sizeof(fx);
8628 U5(fx).dwFillColor = 0xdeadbeef;
8629 fx.dwROP = WHITENESS;
8631 memset(&surface_desc, 0, sizeof(surface_desc));
8632 surface_desc.dwSize = sizeof(surface_desc);
8633 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
8634 surface_desc.dwWidth = 64;
8635 surface_desc.dwHeight = 64;
8636 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
8637 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
8638 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
8639 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
8640 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
8641 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
8642 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
8643 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
8644 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
8645 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
8646 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
8648 /* No DDBLTFX. */
8649 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, NULL);
8650 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8651 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_ROP | DDBLT_WAIT, NULL);
8652 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8654 /* Unused source rectangle. */
8655 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8656 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
8657 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
8658 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
8660 /* Unused source surface. */
8661 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8662 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8663 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
8664 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
8665 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8666 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8667 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
8668 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
8670 /* Inverted destination or source rectangle. */
8671 SetRect(&rect, 5, 7, 7, 5);
8672 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8673 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
8674 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8675 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
8676 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8677 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8678 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8679 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8680 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
8681 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
8683 /* Negative rectangle. */
8684 SetRect(&rect, -1, -1, 5, 5);
8685 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8686 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
8687 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8688 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
8689 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8690 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8691 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8692 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8693 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
8694 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
8696 /* Out of bounds rectangle. */
8697 SetRect(&rect, 0, 0, 65, 65);
8698 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8699 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
8700 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
8701 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
8703 /* Combine multiple flags. */
8704 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8705 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
8706 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_ROP | DDBLT_WAIT, &fx);
8707 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8708 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ROP | DDBLT_WAIT, &fx);
8709 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8711 for (i = 0; i < sizeof(rops) / sizeof(*rops); i++)
8713 fx.dwROP = rops[i].rop;
8714 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
8715 ok(hr == rops[i].hr, "Got unexpected hr %#x for rop %s.\n", hr, rops[i].name);
8718 IDirectDrawSurface_Release(surface2);
8719 IDirectDrawSurface_Release(surface);
8721 memset(&surface_desc, 0, sizeof(surface_desc));
8722 surface_desc.dwSize = sizeof(surface_desc);
8723 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_ZBUFFERBITDEPTH;
8724 surface_desc.dwWidth = 64;
8725 surface_desc.dwHeight = 64;
8726 U2(surface_desc).dwZBufferBitDepth = get_device_z_depth(device);
8727 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
8728 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
8729 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
8730 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
8731 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
8733 /* No DDBLTFX. */
8734 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, NULL);
8735 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8737 /* Unused source rectangle. */
8738 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8739 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
8741 /* Unused source surface. */
8742 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8743 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8744 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8745 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8747 /* Inverted destination or source rectangle. */
8748 SetRect(&rect, 5, 7, 7, 5);
8749 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8750 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
8751 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8752 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
8753 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8754 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8755 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8756 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8758 /* Negative rectangle. */
8759 SetRect(&rect, -1, -1, 5, 5);
8760 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8761 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
8762 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8763 ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
8764 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8765 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8766 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8767 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8769 /* Out of bounds rectangle. */
8770 SetRect(&rect, 0, 0, 65, 65);
8771 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8772 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
8774 /* Combine multiple flags. */
8775 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
8776 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
8778 IDirectDrawSurface_Release(surface2);
8779 IDirectDrawSurface_Release(surface);
8781 done:
8782 IDirect3DDevice2_Release(device);
8783 refcount = IDirectDraw2_Release(ddraw);
8784 ok(refcount == 0, "Ddraw object not properly released, refcount %u.\n", refcount);
8785 DestroyWindow(window);
8788 static BOOL ddraw_is_nvidia(IDirectDraw2 *ddraw)
8790 IDirectDraw4 *ddraw4;
8791 DDDEVICEIDENTIFIER identifier;
8792 HRESULT hr;
8794 if (!strcmp(winetest_platform, "wine"))
8795 return FALSE;
8797 hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirectDraw4, (void **)&ddraw4);
8798 ok(SUCCEEDED(hr), "Failed to get IDirectDraw4 interface, hr %#x.\n", hr);
8799 hr = IDirectDraw4_GetDeviceIdentifier(ddraw4, &identifier, 0);
8800 ok(SUCCEEDED(hr), "Failed to get device identifier, hr %#x.\n", hr);
8801 IDirectDraw4_Release(ddraw4);
8802 return identifier.dwVendorId == 0x10de;
8805 static void test_colorkey_precision(void)
8807 static D3DLVERTEX quad[] =
8809 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xff000000}, {0}, {0.0f}, {0.0f}},
8810 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff000000}, {0}, {0.0f}, {1.0f}},
8811 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xff000000}, {0}, {1.0f}, {0.0f}},
8812 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xff000000}, {0}, {1.0f}, {1.0f}},
8814 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
8815 IDirect3DDevice2 *device;
8816 IDirectDraw2 *ddraw;
8817 IDirectDrawSurface *rt;
8818 IDirect3DViewport2 *viewport;
8819 HWND window;
8820 HRESULT hr;
8821 IDirectDrawSurface *src, *dst, *texture;
8822 D3DTEXTUREHANDLE handle;
8823 IDirect3DTexture2 *d3d_texture;
8824 IDirect3DMaterial2 *green;
8825 DDSURFACEDESC surface_desc, lock_desc;
8826 ULONG refcount;
8827 D3DCOLOR color;
8828 unsigned int t, c;
8829 DDCOLORKEY ckey;
8830 DDBLTFX fx;
8831 DWORD data[4] = {0}, color_mask;
8832 BOOL is_nvidia, is_warp;
8833 static const struct
8835 unsigned int max, shift, bpp, clear;
8836 const char *name;
8837 BOOL skip_nv;
8838 DDPIXELFORMAT fmt;
8840 tests[] =
8843 255, 0, 4, 0x00345678, "D3DFMT_X8R8G8B8", FALSE,
8845 sizeof(DDPIXELFORMAT), DDPF_RGB, 0,
8846 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0x00000000}
8851 63, 5, 2, 0x5678, "D3DFMT_R5G6B5, G channel", FALSE,
8853 sizeof(DDPIXELFORMAT), DDPF_RGB, 0,
8854 {16}, {0xf800}, {0x07e0}, {0x001f}, {0x0000}
8859 31, 0, 2, 0x5678, "D3DFMT_R5G6B5, B channel", FALSE,
8861 sizeof(DDPIXELFORMAT), DDPF_RGB, 0,
8862 {16}, {0xf800}, {0x07e0}, {0x001f}, {0x0000}
8867 15, 0, 2, 0x0678, "D3DFMT_A4R4G4B4", TRUE,
8869 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
8870 {16}, {0x0f00}, {0x00f0}, {0x000f}, {0xf000}
8875 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
8876 0, 0, 640, 480, 0, 0, 0, 0);
8877 ddraw = create_ddraw();
8878 ok(!!ddraw, "Failed to create a ddraw object.\n");
8879 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
8881 skip("Failed to create a 3D device, skipping test.\n");
8882 DestroyWindow(window);
8883 IDirectDraw2_Release(ddraw);
8884 return;
8886 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
8887 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
8889 is_nvidia = ddraw_is_nvidia(ddraw);
8890 /* The Windows 8 WARP driver has plenty of false negatives in X8R8G8B8
8891 * (color key doesn't match although the values are equal), and a false
8892 * positive when the color key is 0 and the texture contains the value 1.
8893 * I don't want to mark this broken unconditionally since this would
8894 * essentially disable the test on Windows. Also on random occasions
8895 * 254 == 255 and 255 != 255.*/
8896 is_warp = ddraw_is_warp(ddraw);
8898 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
8899 viewport = create_viewport(device, 0, 0, 640, 480);
8900 viewport_set_background(device, viewport, green);
8901 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
8902 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
8904 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
8905 ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#x.\n", hr);
8906 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
8907 ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
8908 /* There's no way to ignore the texture color in d3d2, so multiply the texture color
8909 * with a black vertex color. */
8910 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA);
8911 ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
8913 memset(&fx, 0, sizeof(fx));
8914 fx.dwSize = sizeof(fx);
8915 memset(&lock_desc, 0, sizeof(lock_desc));
8916 lock_desc.dwSize = sizeof(lock_desc);
8918 for (t = 0; t < sizeof(tests) / sizeof(*tests); ++t)
8920 if (is_nvidia && tests[t].skip_nv)
8922 win_skip("Skipping test %s on Nvidia Windows drivers.\n", tests[t].name);
8923 continue;
8926 memset(&surface_desc, 0, sizeof(surface_desc));
8927 surface_desc.dwSize = sizeof(surface_desc);
8928 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
8929 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
8930 surface_desc.dwWidth = 4;
8931 surface_desc.dwHeight = 1;
8932 surface_desc.ddpfPixelFormat = tests[t].fmt;
8933 /* Windows XP (at least with the r200 driver, other drivers untested) produces
8934 * garbage when doing color keyed texture->texture blits. */
8935 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &src, NULL);
8936 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
8937 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst, NULL);
8938 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
8940 fx.dwFillColor = tests[t].clear;
8941 /* On the w8 testbot (WARP driver) the blit result has different values in the
8942 * X channel. */
8943 color_mask = U2(tests[t].fmt).dwRBitMask
8944 | U3(tests[t].fmt).dwGBitMask
8945 | U4(tests[t].fmt).dwBBitMask;
8947 for (c = 0; c <= tests[t].max; ++c)
8949 /* The idiotic Nvidia Windows driver can't change the color key on a d3d
8950 * texture after it has been set once... */
8951 surface_desc.dwFlags |= DDSD_CKSRCBLT;
8952 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
8953 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = c << tests[t].shift;
8954 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = c << tests[t].shift;
8955 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &texture, NULL);
8956 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
8958 hr = IDirectDrawSurface4_QueryInterface(texture, &IID_IDirect3DTexture2, (void **)&d3d_texture);
8959 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
8960 hr = IDirect3DTexture2_GetHandle(d3d_texture, device, &handle);
8961 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
8962 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, handle);
8963 ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#x.\n", hr);
8964 IDirect3DTexture2_Release(d3d_texture);
8966 hr = IDirectDrawSurface_Blt(dst, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8967 ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
8969 hr = IDirectDrawSurface_Lock(src, NULL, &lock_desc, DDLOCK_WAIT, NULL);
8970 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
8971 switch (tests[t].bpp)
8973 case 4:
8974 ((DWORD *)lock_desc.lpSurface)[0] = (c ? c - 1 : 0) << tests[t].shift;
8975 ((DWORD *)lock_desc.lpSurface)[1] = c << tests[t].shift;
8976 ((DWORD *)lock_desc.lpSurface)[2] = min(c + 1, tests[t].max) << tests[t].shift;
8977 ((DWORD *)lock_desc.lpSurface)[3] = 0xffffffff;
8978 break;
8980 case 2:
8981 ((WORD *)lock_desc.lpSurface)[0] = (c ? c - 1 : 0) << tests[t].shift;
8982 ((WORD *)lock_desc.lpSurface)[1] = c << tests[t].shift;
8983 ((WORD *)lock_desc.lpSurface)[2] = min(c + 1, tests[t].max) << tests[t].shift;
8984 ((WORD *)lock_desc.lpSurface)[3] = 0xffff;
8985 break;
8987 hr = IDirectDrawSurface_Unlock(src, 0);
8988 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
8989 hr = IDirectDrawSurface_Blt(texture, NULL, src, NULL, DDBLT_WAIT, NULL);
8990 ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
8992 ckey.dwColorSpaceLowValue = c << tests[t].shift;
8993 ckey.dwColorSpaceHighValue = c << tests[t].shift;
8994 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
8995 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
8997 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC | DDBLT_WAIT, NULL);
8998 ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
9000 /* Don't make this read only, it somehow breaks the detection of the Nvidia bug below. */
9001 hr = IDirectDrawSurface_Lock(dst, NULL, &lock_desc, DDLOCK_WAIT, NULL);
9002 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
9003 switch (tests[t].bpp)
9005 case 4:
9006 data[0] = ((DWORD *)lock_desc.lpSurface)[0] & color_mask;
9007 data[1] = ((DWORD *)lock_desc.lpSurface)[1] & color_mask;
9008 data[2] = ((DWORD *)lock_desc.lpSurface)[2] & color_mask;
9009 data[3] = ((DWORD *)lock_desc.lpSurface)[3] & color_mask;
9010 break;
9012 case 2:
9013 data[0] = ((WORD *)lock_desc.lpSurface)[0] & color_mask;
9014 data[1] = ((WORD *)lock_desc.lpSurface)[1] & color_mask;
9015 data[2] = ((WORD *)lock_desc.lpSurface)[2] & color_mask;
9016 data[3] = ((WORD *)lock_desc.lpSurface)[3] & color_mask;
9017 break;
9019 hr = IDirectDrawSurface_Unlock(dst, 0);
9020 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
9022 if (!c)
9024 ok(data[0] == tests[t].clear, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
9025 tests[t].clear, data[0], tests[t].name, c);
9027 if (data[3] == tests[t].clear)
9029 /* My Geforce GTX 460 on Windows 7 misbehaves when A4R4G4B4 is blitted with color
9030 * keying: The blit takes ~0.5 seconds, and subsequent color keying draws are broken,
9031 * even when a different surface is used. The blit itself doesn't draw anything,
9032 * so we can detect the bug by looking at the otherwise unused 4th texel. It should
9033 * never be masked out by the key.
9035 * On Windows 10 the problem is worse, Blt just hangs. For this reason the ARGB4444
9036 * test is disabled entirely.
9038 * Also appears to affect the testbot in some way with R5G6B5. Color keying is
9039 * terrible on WARP. */
9040 skip("Nvidia A4R4G4B4 color keying blit bug detected, skipping.\n");
9041 IDirectDrawSurface_Release(texture);
9042 IDirectDrawSurface_Release(src);
9043 IDirectDrawSurface_Release(dst);
9044 goto done;
9047 else
9048 ok(data[0] == (c - 1) << tests[t].shift, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
9049 (c - 1) << tests[t].shift, data[0], tests[t].name, c);
9051 ok(data[1] == tests[t].clear, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
9052 tests[t].clear, data[1], tests[t].name, c);
9054 if (c == tests[t].max)
9055 ok(data[2] == tests[t].clear, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
9056 tests[t].clear, data[2], tests[t].name, c);
9057 else
9058 ok(data[2] == (c + 1) << tests[t].shift, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
9059 (c + 1) << tests[t].shift, data[2], tests[t].name, c);
9061 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
9062 ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr);
9064 hr = IDirect3DDevice2_BeginScene(device);
9065 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
9066 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad, 4, 0);
9067 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
9068 hr = IDirect3DDevice2_EndScene(device);
9069 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
9071 color = get_surface_color(rt, 80, 240);
9072 if (!c)
9073 ok(compare_color(color, 0x0000ff00, 1) || broken(is_warp && compare_color(color, 0x00000000, 1)),
9074 "Got unexpected color 0x%08x, format %s, c=%u.\n",
9075 color, tests[t].name, c);
9076 else
9077 ok(compare_color(color, 0x00000000, 1) || broken(is_warp && compare_color(color, 0x0000ff00, 1)),
9078 "Got unexpected color 0x%08x, format %s, c=%u.\n",
9079 color, tests[t].name, c);
9081 color = get_surface_color(rt, 240, 240);
9082 ok(compare_color(color, 0x0000ff00, 1) || broken(is_warp && compare_color(color, 0x00000000, 1)),
9083 "Got unexpected color 0x%08x, format %s, c=%u.\n",
9084 color, tests[t].name, c);
9086 color = get_surface_color(rt, 400, 240);
9087 if (c == tests[t].max)
9088 ok(compare_color(color, 0x0000ff00, 1) || broken(is_warp && compare_color(color, 0x00000000, 1)),
9089 "Got unexpected color 0x%08x, format %s, c=%u.\n",
9090 color, tests[t].name, c);
9091 else
9092 ok(compare_color(color, 0x00000000, 1) || broken(is_warp && compare_color(color, 0x0000ff00, 1)),
9093 "Got unexpected color 0x%08x, format %s, c=%u.\n",
9094 color, tests[t].name, c);
9096 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
9097 ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#x.\n", hr);
9098 IDirectDrawSurface_Release(texture);
9100 IDirectDrawSurface_Release(src);
9101 IDirectDrawSurface_Release(dst);
9103 done:
9105 destroy_viewport(device, viewport);
9106 destroy_material(green);
9107 IDirectDrawSurface_Release(rt);
9108 IDirect3DDevice2_Release(device);
9109 refcount = IDirectDraw2_Release(ddraw);
9110 ok(refcount == 0, "Ddraw object not properly released, refcount %u.\n", refcount);
9111 DestroyWindow(window);
9114 static void test_range_colorkey(void)
9116 IDirectDraw2 *ddraw;
9117 HWND window;
9118 HRESULT hr;
9119 IDirectDrawSurface *surface;
9120 DDSURFACEDESC surface_desc;
9121 ULONG refcount;
9122 DDCOLORKEY ckey;
9124 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
9125 0, 0, 640, 480, 0, 0, 0, 0);
9126 ddraw = create_ddraw();
9127 ok(!!ddraw, "Failed to create a ddraw object.\n");
9128 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
9129 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
9131 memset(&surface_desc, 0, sizeof(surface_desc));
9132 surface_desc.dwSize = sizeof(surface_desc);
9133 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
9134 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
9135 surface_desc.dwWidth = 1;
9136 surface_desc.dwHeight = 1;
9137 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
9138 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
9139 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
9140 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
9141 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
9142 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0x00000000;
9144 /* Creating a surface with a range color key fails with DDERR_NOCOLORKEY. */
9145 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000000;
9146 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000001;
9147 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9148 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#x.\n", hr);
9150 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000001;
9151 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000000;
9152 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9153 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#x.\n", hr);
9155 /* Same for DDSCAPS_OFFSCREENPLAIN. */
9156 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
9157 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000000;
9158 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000001;
9159 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9160 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#x.\n", hr);
9162 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000001;
9163 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000000;
9164 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9165 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#x.\n", hr);
9167 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000000;
9168 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000000;
9169 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9170 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
9172 /* Setting a range color key without DDCKEY_COLORSPACE collapses the key. */
9173 ckey.dwColorSpaceLowValue = 0x00000000;
9174 ckey.dwColorSpaceHighValue = 0x00000001;
9175 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9176 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
9178 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9179 ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
9180 ok(!ckey.dwColorSpaceLowValue, "Got unexpected value 0x%08x.\n", ckey.dwColorSpaceLowValue);
9181 ok(!ckey.dwColorSpaceHighValue, "Got unexpected value 0x%08x.\n", ckey.dwColorSpaceHighValue);
9183 ckey.dwColorSpaceLowValue = 0x00000001;
9184 ckey.dwColorSpaceHighValue = 0x00000000;
9185 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9186 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
9188 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9189 ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
9190 ok(ckey.dwColorSpaceLowValue == 0x00000001, "Got unexpected value 0x%08x.\n", ckey.dwColorSpaceLowValue);
9191 ok(ckey.dwColorSpaceHighValue == 0x00000001, "Got unexpected value 0x%08x.\n", ckey.dwColorSpaceHighValue);
9193 /* DDCKEY_COLORSPACE is ignored if the key is a single value. */
9194 ckey.dwColorSpaceLowValue = 0x00000000;
9195 ckey.dwColorSpaceHighValue = 0x00000000;
9196 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
9197 ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
9199 /* Using it with a range key results in DDERR_NOCOLORKEYHW. */
9200 ckey.dwColorSpaceLowValue = 0x00000001;
9201 ckey.dwColorSpaceHighValue = 0x00000000;
9202 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
9203 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#x.\n", hr);
9204 ckey.dwColorSpaceLowValue = 0x00000000;
9205 ckey.dwColorSpaceHighValue = 0x00000001;
9206 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
9207 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#x.\n", hr);
9208 /* Range destination keys don't work either. */
9209 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_DESTBLT | DDCKEY_COLORSPACE, &ckey);
9210 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#x.\n", hr);
9212 /* Just to show it's not because of A, R, and G having equal values. */
9213 ckey.dwColorSpaceLowValue = 0x00000000;
9214 ckey.dwColorSpaceHighValue = 0x01010101;
9215 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
9216 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#x.\n", hr);
9218 /* None of these operations modified the key. */
9219 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9220 ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
9221 ok(!ckey.dwColorSpaceLowValue, "Got unexpected value 0x%08x.\n", ckey.dwColorSpaceLowValue);
9222 ok(!ckey.dwColorSpaceHighValue, "Got unexpected value 0x%08x.\n", ckey.dwColorSpaceHighValue);
9224 IDirectDrawSurface_Release(surface),
9225 refcount = IDirectDraw2_Release(ddraw);
9226 ok(!refcount, "Got unexpected refcount %u.\n", refcount);
9227 DestroyWindow(window);
9230 static void test_shademode(void)
9232 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
9233 IDirect3DMaterial2 *background;
9234 IDirect3DViewport2 *viewport;
9235 IDirect3DDevice2 *device;
9236 IDirectDrawSurface *rt;
9237 DWORD color0, color1;
9238 IDirectDraw2 *ddraw;
9239 D3DLVERTEX *quad;
9240 ULONG refcount;
9241 UINT i, count;
9242 HWND window;
9243 HRESULT hr;
9244 static D3DLVERTEX quad_strip[] =
9246 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xffff0000}},
9247 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
9248 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xff0000ff}},
9249 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xffffffff}},
9251 quad_list[] =
9253 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xffff0000}},
9254 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
9255 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xff0000ff}},
9257 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xff0000ff}},
9258 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
9259 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xffffffff}},
9261 static const struct
9263 DWORD primtype;
9264 DWORD shademode;
9265 DWORD color0, color1;
9267 tests[] =
9269 {D3DPT_TRIANGLESTRIP, D3DSHADE_FLAT, 0x00ff0000, 0x0000ff00},
9270 {D3DPT_TRIANGLESTRIP, D3DSHADE_PHONG, 0x000dca28, 0x000d45c7},
9271 {D3DPT_TRIANGLESTRIP, D3DSHADE_GOURAUD, 0x000dca28, 0x000d45c7},
9272 {D3DPT_TRIANGLESTRIP, D3DSHADE_PHONG, 0x000dca28, 0x000d45c7},
9273 {D3DPT_TRIANGLELIST, D3DSHADE_FLAT, 0x00ff0000, 0x000000ff},
9274 {D3DPT_TRIANGLELIST, D3DSHADE_GOURAUD, 0x000dca28, 0x000d45c7},
9277 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
9278 0, 0, 640, 480, 0, 0, 0, 0);
9279 ddraw = create_ddraw();
9280 ok(!!ddraw, "Failed to create a ddraw object.\n");
9281 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
9283 skip("Failed to create a 3D device, skipping test.\n");
9284 IDirectDraw2_Release(ddraw);
9285 DestroyWindow(window);
9286 return;
9289 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
9290 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
9292 background = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
9293 viewport = create_viewport(device, 0, 0, 640, 480);
9294 viewport_set_background(device, viewport, background);
9295 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
9296 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
9298 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_FOGENABLE, FALSE);
9299 ok(SUCCEEDED(hr), "Failed to disable fog, hr %#x.\n", hr);
9301 /* Try it first with a TRIANGLESTRIP. Do it with different geometry because
9302 * the color fixups we have to do for FLAT shading will be dependent on that. */
9304 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i)
9306 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
9307 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
9309 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SHADEMODE, tests[i].shademode);
9310 ok(hr == D3D_OK, "Failed to set shade mode, hr %#x.\n", hr);
9312 hr = IDirect3DDevice2_BeginScene(device);
9313 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
9314 quad = tests[i].primtype == D3DPT_TRIANGLESTRIP ? quad_strip : quad_list;
9315 count = tests[i].primtype == D3DPT_TRIANGLESTRIP ? 4 : 6;
9316 hr = IDirect3DDevice2_DrawPrimitive(device, tests[i].primtype, D3DVT_LVERTEX, quad, count, 0);
9317 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
9318 hr = IDirect3DDevice2_EndScene(device);
9319 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
9321 color0 = get_surface_color(rt, 100, 100); /* Inside first triangle */
9322 color1 = get_surface_color(rt, 500, 350); /* Inside second triangle */
9324 /* For D3DSHADE_FLAT it should take the color of the first vertex of
9325 * each triangle. This requires EXT_provoking_vertex or similar
9326 * functionality being available. */
9327 /* PHONG should be the same as GOURAUD, since no hardware implements
9328 * this. */
9329 ok(compare_color(color0, tests[i].color0, 1), "Test %u shading has color0 %08x, expected %08x.\n",
9330 i, color0, tests[i].color0);
9331 ok(compare_color(color1, tests[i].color1, 1), "Test %u shading has color1 %08x, expected %08x.\n",
9332 i, color1, tests[i].color1);
9335 destroy_viewport(device, viewport);
9336 destroy_material(background);
9337 IDirectDrawSurface_Release(rt);
9338 refcount = IDirect3DDevice2_Release(device);
9339 ok(!refcount, "Device has %u references left.\n", refcount);
9340 IDirectDraw_Release(ddraw);
9341 DestroyWindow(window);
9344 static void test_lockrect_invalid(void)
9346 unsigned int i, r;
9347 IDirectDraw2 *ddraw;
9348 IDirectDrawSurface *surface1;
9349 IDirectDrawSurface2 *surface;
9350 HWND window;
9351 HRESULT hr;
9352 DDSURFACEDESC surface_desc;
9353 DDCAPS hal_caps;
9354 DWORD needed_caps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
9355 static RECT valid[] =
9357 {60, 60, 68, 68},
9358 {60, 60, 60, 68},
9359 {60, 60, 68, 60},
9360 {120, 60, 128, 68},
9361 {60, 120, 68, 128},
9363 static RECT invalid[] =
9365 {68, 60, 60, 68}, /* left > right */
9366 {60, 68, 68, 60}, /* top > bottom */
9367 {-8, 60, 0, 68}, /* left < surface */
9368 {60, -8, 68, 0}, /* top < surface */
9369 {-16, 60, -8, 68}, /* right < surface */
9370 {60, -16, 68, -8}, /* bottom < surface */
9371 {60, 60, 136, 68}, /* right > surface */
9372 {60, 60, 68, 136}, /* bottom > surface */
9373 {136, 60, 144, 68}, /* left > surface */
9374 {60, 136, 68, 144}, /* top > surface */
9376 static const struct
9378 DWORD caps;
9379 const char *name;
9380 HRESULT hr;
9382 resources[] =
9384 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY, "sysmem offscreenplain", DDERR_INVALIDPARAMS},
9385 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY, "vidmem offscreenplain", DDERR_INVALIDPARAMS},
9386 {DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY, "sysmem texture", DDERR_INVALIDPARAMS},
9387 {DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, "vidmem texture", DDERR_INVALIDPARAMS},
9390 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
9391 0, 0, 640, 480, 0, 0, 0, 0);
9392 ddraw = create_ddraw();
9393 ok(!!ddraw, "Failed to create a ddraw object.\n");
9394 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
9395 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
9397 memset(&hal_caps, 0, sizeof(hal_caps));
9398 hal_caps.dwSize = sizeof(hal_caps);
9399 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, NULL);
9400 ok(SUCCEEDED(hr), "Failed to get caps, hr %#x.\n", hr);
9401 if ((hal_caps.ddsCaps.dwCaps & needed_caps) != needed_caps)
9403 skip("Required surface types not supported, skipping test.\n");
9404 goto done;
9407 for (r = 0; r < sizeof(resources) / sizeof(*resources); ++r)
9409 memset(&surface_desc, 0, sizeof(surface_desc));
9410 surface_desc.dwSize = sizeof(surface_desc);
9411 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
9412 surface_desc.ddsCaps.dwCaps = resources[r].caps;
9413 surface_desc.dwWidth = 128;
9414 surface_desc.dwHeight = 128;
9415 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
9416 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
9417 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
9418 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xff0000;
9419 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x00ff00;
9420 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x0000ff;
9422 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
9423 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x, type %s.\n", hr, resources[r].name);
9424 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface);
9425 ok(SUCCEEDED(hr), "Failed to QI IDirectDrawSurface2 interface, hr %#x.\n", hr);
9426 IDirectDrawSurface_Release(surface1);
9428 hr = IDirectDrawSurface2_Lock(surface, NULL, NULL, DDLOCK_WAIT, NULL);
9429 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x, type %s.\n", hr, resources[r].name);
9431 for (i = 0; i < sizeof(valid) / sizeof(*valid); ++i)
9433 RECT *rect = &valid[i];
9435 memset(&surface_desc, 0, sizeof(surface_desc));
9436 surface_desc.dwSize = sizeof(surface_desc);
9438 hr = IDirectDrawSurface2_Lock(surface, rect, &surface_desc, DDLOCK_WAIT, NULL);
9439 ok(SUCCEEDED(hr), "Lock failed (%#x) for rect %s, type %s.\n",
9440 hr, wine_dbgstr_rect(rect), resources[r].name);
9442 hr = IDirectDrawSurface2_Unlock(surface, NULL);
9443 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x, type %s.\n", hr, resources[r].name);
9446 for (i = 0; i < sizeof(invalid) / sizeof(*invalid); ++i)
9448 RECT *rect = &invalid[i];
9450 memset(&surface_desc, 1, sizeof(surface_desc));
9451 surface_desc.dwSize = sizeof(surface_desc);
9453 hr = IDirectDrawSurface2_Lock(surface, rect, &surface_desc, DDLOCK_WAIT, NULL);
9454 ok(hr == resources[r].hr, "Lock returned %#x for rect %s, type %s.\n",
9455 hr, wine_dbgstr_rect(rect), resources[r].name);
9456 if (SUCCEEDED(hr))
9458 hr = IDirectDrawSurface2_Unlock(surface, NULL);
9459 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x, type %s.\n", hr, resources[r].name);
9461 else
9462 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
9465 hr = IDirectDrawSurface2_Lock(surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
9466 ok(SUCCEEDED(hr), "Lock(rect = NULL) failed, hr %#x, type %s.\n",
9467 hr, resources[r].name);
9468 hr = IDirectDrawSurface2_Lock(surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
9469 ok(hr == DDERR_SURFACEBUSY, "Double lock(rect = NULL) returned %#x, type %s.\n",
9470 hr, resources[r].name);
9471 hr = IDirectDrawSurface2_Unlock(surface, NULL);
9472 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x, type %s.\n", hr, resources[r].name);
9474 hr = IDirectDrawSurface2_Lock(surface, &valid[0], &surface_desc, DDLOCK_WAIT, NULL);
9475 ok(SUCCEEDED(hr), "Lock(rect = %s) failed (%#x).\n", wine_dbgstr_rect(&valid[0]), hr);
9476 hr = IDirectDrawSurface2_Lock(surface, &valid[0], &surface_desc, DDLOCK_WAIT, NULL);
9477 ok(hr == DDERR_SURFACEBUSY, "Double lock(rect = %s) failed (%#x).\n",
9478 wine_dbgstr_rect(&valid[0]), hr);
9480 /* Locking a different rectangle returns DD_OK, but it seems to break the surface.
9481 * Afterwards unlocking the surface fails(NULL rectangle or both locked rectangles) */
9483 hr = IDirectDrawSurface2_Unlock(surface, NULL);
9484 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x, type %s.\n", hr, resources[r].name);
9486 IDirectDrawSurface2_Release(surface);
9489 done:
9490 IDirectDraw2_Release(ddraw);
9491 DestroyWindow(window);
9494 static void test_yv12_overlay(void)
9496 IDirectDrawSurface *src_surface, *dst_surface;
9497 RECT rect = {13, 17, 14, 18};
9498 unsigned int offset, y;
9499 unsigned char *base;
9500 IDirectDraw2 *ddraw;
9501 DDSURFACEDESC desc;
9502 HWND window;
9503 HRESULT hr;
9505 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
9506 0, 0, 640, 480, 0, 0, 0, 0);
9507 ddraw = create_ddraw();
9508 ok(!!ddraw, "Failed to create a ddraw object.\n");
9509 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
9510 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
9512 if (!(src_surface = create_overlay(ddraw, 256, 256, MAKEFOURCC('Y','V','1','2'))))
9514 skip("Failed to create a YV12 overlay, skipping test.\n");
9515 goto done;
9518 memset(&desc, 0, sizeof(desc));
9519 desc.dwSize = sizeof(desc);
9520 hr = IDirectDrawSurface_Lock(src_surface, NULL, &desc, DDLOCK_WAIT, NULL);
9521 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
9523 ok(desc.dwFlags == (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH),
9524 "Got unexpected flags %#x.\n", desc.dwFlags);
9525 ok(desc.ddsCaps.dwCaps == (DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_HWCODEC)
9526 || desc.ddsCaps.dwCaps == (DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM),
9527 "Got unexpected caps %#x.\n", desc.ddsCaps.dwCaps);
9528 ok(desc.dwWidth == 256, "Got unexpected width %u.\n", desc.dwWidth);
9529 ok(desc.dwHeight == 256, "Got unexpected height %u.\n", desc.dwHeight);
9530 /* The overlay pitch seems to have 256 byte alignment. */
9531 ok(!(U1(desc).lPitch & 0xff), "Got unexpected pitch %u.\n", U1(desc).lPitch);
9533 /* Fill the surface with some data for the blit test. */
9534 base = desc.lpSurface;
9535 /* Luminance */
9536 for (y = 0; y < desc.dwHeight; ++y)
9538 memset(base + U1(desc).lPitch * y, 0x10, desc.dwWidth);
9540 /* V */
9541 for (; y < desc.dwHeight + desc.dwHeight / 4; ++y)
9543 memset(base + U1(desc).lPitch * y, 0x20, desc.dwWidth);
9545 /* U */
9546 for (; y < desc.dwHeight + desc.dwHeight / 2; ++y)
9548 memset(base + U1(desc).lPitch * y, 0x30, desc.dwWidth);
9551 hr = IDirectDrawSurface_Unlock(src_surface, NULL);
9552 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
9554 /* YV12 uses 2x2 blocks with 6 bytes per block (4*Y, 1*U, 1*V). Unlike
9555 * other block-based formats like DXT the entire Y channel is stored in
9556 * one big chunk of memory, followed by the chroma channels. So partial
9557 * locks do not really make sense. Show that they are allowed nevertheless
9558 * and the offset points into the luminance data. */
9559 hr = IDirectDrawSurface_Lock(src_surface, &rect, &desc, DDLOCK_WAIT, NULL);
9560 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
9561 offset = ((const unsigned char *)desc.lpSurface - base);
9562 ok(offset == rect.top * U1(desc).lPitch + rect.left, "Got unexpected offset %u, expected %u.\n",
9563 offset, rect.top * U1(desc).lPitch + rect.left);
9564 hr = IDirectDrawSurface_Unlock(src_surface, NULL);
9565 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
9567 if (!(dst_surface = create_overlay(ddraw, 256, 256, MAKEFOURCC('Y','V','1','2'))))
9569 /* Windows XP with a Radeon X1600 GPU refuses to create a second
9570 * overlay surface, DDERR_NOOVERLAYHW, making the blit tests moot. */
9571 skip("Failed to create a second YV12 surface, skipping blit test.\n");
9572 IDirectDrawSurface_Release(src_surface);
9573 goto done;
9576 hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, NULL, DDBLT_WAIT, NULL);
9577 /* VMware rejects YV12 blits. This behavior has not been seen on real
9578 * hardware yet, so mark it broken. */
9579 ok(SUCCEEDED(hr) || broken(hr == E_NOTIMPL), "Failed to blit, hr %#x.\n", hr);
9581 if (SUCCEEDED(hr))
9583 memset(&desc, 0, sizeof(desc));
9584 desc.dwSize = sizeof(desc);
9585 hr = IDirectDrawSurface_Lock(dst_surface, NULL, &desc, DDLOCK_WAIT, NULL);
9586 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
9588 base = desc.lpSurface;
9589 ok(base[0] == 0x10, "Got unexpected Y data 0x%02x.\n", base[0]);
9590 base += desc.dwHeight * U1(desc).lPitch;
9591 todo_wine ok(base[0] == 0x20, "Got unexpected V data 0x%02x.\n", base[0]);
9592 base += desc.dwHeight / 4 * U1(desc).lPitch;
9593 todo_wine ok(base[0] == 0x30, "Got unexpected U data 0x%02x.\n", base[0]);
9595 hr = IDirectDrawSurface_Unlock(dst_surface, NULL);
9596 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
9599 IDirectDrawSurface_Release(dst_surface);
9600 IDirectDrawSurface_Release(src_surface);
9601 done:
9602 IDirectDraw2_Release(ddraw);
9603 DestroyWindow(window);
9606 static BOOL dwm_enabled(void)
9608 BOOL ret = FALSE;
9610 if (!strcmp(winetest_platform, "wine"))
9611 return FALSE;
9612 if (!pDwmIsCompositionEnabled)
9613 return FALSE;
9614 if (FAILED(pDwmIsCompositionEnabled(&ret)))
9615 return FALSE;
9616 return ret;
9619 static void test_offscreen_overlay(void)
9621 IDirectDrawSurface *overlay, *offscreen, *primary;
9622 DDSURFACEDESC surface_desc;
9623 IDirectDraw2 *ddraw;
9624 HWND window;
9625 HRESULT hr;
9626 HDC dc;
9628 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
9629 0, 0, 640, 480, 0, 0, 0, 0);
9630 ddraw = create_ddraw();
9631 ok(!!ddraw, "Failed to create a ddraw object.\n");
9632 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
9633 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
9635 if (!(overlay = create_overlay(ddraw, 64, 64, MAKEFOURCC('U','Y','V','Y'))))
9637 skip("Failed to create a UYVY overlay, skipping test.\n");
9638 goto done;
9641 memset(&surface_desc, 0, sizeof(surface_desc));
9642 surface_desc.dwSize = sizeof(surface_desc);
9643 surface_desc.dwFlags = DDSD_CAPS;
9644 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
9645 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
9646 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
9648 /* On Windows 7, and probably Vista, UpdateOverlay() will return
9649 * DDERR_OUTOFCAPS if the dwm is active. Calling GetDC() on the primary
9650 * surface prevents this by disabling the dwm. */
9651 hr = IDirectDrawSurface_GetDC(primary, &dc);
9652 ok(SUCCEEDED(hr), "Failed to get DC, hr %#x.\n", hr);
9653 hr = IDirectDrawSurface_ReleaseDC(primary, dc);
9654 ok(SUCCEEDED(hr), "Failed to release DC, hr %#x.\n", hr);
9656 /* Try to overlay a NULL surface. */
9657 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, NULL, NULL, DDOVER_SHOW, NULL);
9658 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
9659 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, NULL, NULL, DDOVER_HIDE, NULL);
9660 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
9662 /* Try to overlay an offscreen surface. */
9663 memset(&surface_desc, 0, sizeof(surface_desc));
9664 surface_desc.dwSize = sizeof(surface_desc);
9665 surface_desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
9666 surface_desc.dwWidth = 64;
9667 surface_desc.dwHeight = 64;
9668 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
9669 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
9670 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
9671 surface_desc.ddpfPixelFormat.dwFourCC = 0;
9672 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 16;
9673 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xf800;
9674 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x07e0;
9675 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x001f;
9676 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &offscreen, NULL);
9677 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
9679 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, offscreen, NULL, DDOVER_SHOW, NULL);
9680 ok(SUCCEEDED(hr) || broken(hr == DDERR_OUTOFCAPS && dwm_enabled()),
9681 "Failed to update overlay, hr %#x.\n", hr);
9683 /* Try to overlay the primary with a non-overlay surface. */
9684 hr = IDirectDrawSurface_UpdateOverlay(offscreen, NULL, primary, NULL, DDOVER_SHOW, NULL);
9685 ok(hr == DDERR_NOTAOVERLAYSURFACE, "Got unexpected hr %#x.\n", hr);
9686 hr = IDirectDrawSurface_UpdateOverlay(offscreen, NULL, primary, NULL, DDOVER_HIDE, NULL);
9687 ok(hr == DDERR_NOTAOVERLAYSURFACE, "Got unexpected hr %#x.\n", hr);
9689 IDirectDrawSurface_Release(offscreen);
9690 IDirectDrawSurface_Release(primary);
9691 IDirectDrawSurface_Release(overlay);
9692 done:
9693 IDirectDraw2_Release(ddraw);
9694 DestroyWindow(window);
9697 static void test_overlay_rect(void)
9699 IDirectDrawSurface *overlay, *primary = NULL;
9700 DDSURFACEDESC surface_desc;
9701 RECT rect = {0, 0, 64, 64};
9702 IDirectDraw2 *ddraw;
9703 LONG pos_x, pos_y;
9704 HRESULT hr, hr2;
9705 HWND window;
9706 HDC dc;
9708 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
9709 0, 0, 640, 480, 0, 0, 0, 0);
9710 ddraw = create_ddraw();
9711 ok(!!ddraw, "Failed to create a ddraw object.\n");
9712 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
9713 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
9715 if (!(overlay = create_overlay(ddraw, 64, 64, MAKEFOURCC('U','Y','V','Y'))))
9717 skip("Failed to create a UYVY overlay, skipping test.\n");
9718 goto done;
9721 memset(&surface_desc, 0, sizeof(surface_desc));
9722 surface_desc.dwSize = sizeof(surface_desc);
9723 surface_desc.dwFlags = DDSD_CAPS;
9724 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
9725 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
9726 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
9728 /* On Windows 7, and probably Vista, UpdateOverlay() will return
9729 * DDERR_OUTOFCAPS if the dwm is active. Calling GetDC() on the primary
9730 * surface prevents this by disabling the dwm. */
9731 hr = IDirectDrawSurface_GetDC(primary, &dc);
9732 ok(SUCCEEDED(hr), "Failed to get DC, hr %#x.\n", hr);
9733 hr = IDirectDrawSurface_ReleaseDC(primary, dc);
9734 ok(SUCCEEDED(hr), "Failed to release DC, hr %#x.\n", hr);
9736 /* On Windows 8 and newer DWM can't be turned off, making overlays unusable. */
9737 if (dwm_enabled())
9739 win_skip("Cannot disable DWM, skipping overlay test.\n");
9740 goto done;
9743 /* The dx sdk sort of implies that rect must be set when DDOVER_SHOW is
9744 * used. This is not true in Windows Vista and earlier, but changed in
9745 * Windows 7. */
9746 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, &rect, DDOVER_SHOW, NULL);
9747 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#x.\n", hr);
9748 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, NULL, DDOVER_HIDE, NULL);
9749 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#x.\n", hr);
9750 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, NULL, DDOVER_SHOW, NULL);
9751 ok(hr == DD_OK || hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
9753 /* Show that the overlay position is the (top, left) coordinate of the
9754 * destination rectangle. */
9755 OffsetRect(&rect, 32, 16);
9756 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, &rect, DDOVER_SHOW, NULL);
9757 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#x.\n", hr);
9758 pos_x = -1; pos_y = -1;
9759 hr = IDirectDrawSurface_GetOverlayPosition(overlay, &pos_x, &pos_y);
9760 ok(SUCCEEDED(hr), "Failed to get overlay position, hr %#x.\n", hr);
9761 ok(pos_x == rect.left, "Got unexpected pos_x %d, expected %d.\n", pos_x, rect.left);
9762 ok(pos_y == rect.top, "Got unexpected pos_y %d, expected %d.\n", pos_y, rect.top);
9764 /* Passing a NULL dest rect sets the position to 0/0. Visually it can be
9765 * seen that the overlay overlays the whole primary(==screen). */
9766 hr2 = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, NULL, 0, NULL);
9767 ok(hr2 == DD_OK || hr2 == DDERR_INVALIDPARAMS || hr2 == DDERR_OUTOFCAPS, "Got unexpected hr %#x.\n", hr2);
9768 hr = IDirectDrawSurface_GetOverlayPosition(overlay, &pos_x, &pos_y);
9769 ok(SUCCEEDED(hr), "Failed to get overlay position, hr %#x.\n", hr);
9770 if (SUCCEEDED(hr2))
9772 ok(!pos_x, "Got unexpected pos_x %d.\n", pos_x);
9773 ok(!pos_y, "Got unexpected pos_y %d.\n", pos_y);
9775 else
9777 ok(pos_x == 32, "Got unexpected pos_x %d.\n", pos_x);
9778 ok(pos_y == 16, "Got unexpected pos_y %d.\n", pos_y);
9781 /* The position cannot be retrieved when the overlay is not shown. */
9782 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, &rect, DDOVER_HIDE, NULL);
9783 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#x.\n", hr);
9784 pos_x = -1; pos_y = -1;
9785 hr = IDirectDrawSurface_GetOverlayPosition(overlay, &pos_x, &pos_y);
9786 ok(hr == DDERR_OVERLAYNOTVISIBLE, "Got unexpected hr %#x.\n", hr);
9787 ok(!pos_x, "Got unexpected pos_x %d.\n", pos_x);
9788 ok(!pos_y, "Got unexpected pos_y %d.\n", pos_y);
9790 IDirectDrawSurface_Release(overlay);
9791 done:
9792 if (primary)
9793 IDirectDrawSurface_Release(primary);
9794 IDirectDraw2_Release(ddraw);
9795 DestroyWindow(window);
9798 static void test_blt(void)
9800 IDirectDrawSurface *surface, *rt;
9801 DDSURFACEDESC surface_desc;
9802 IDirect3DDevice2 *device;
9803 IDirectDraw2 *ddraw;
9804 unsigned int i;
9805 ULONG refcount;
9806 HWND window;
9807 HRESULT hr;
9809 static struct
9811 RECT src_rect;
9812 RECT dst_rect;
9813 HRESULT hr;
9815 test_data[] =
9817 {{160, 0, 640, 480}, { 0, 0, 480, 480}, DD_OK}, /* Overlapped blit. */
9818 {{160, 480, 640, 0}, { 0, 0, 480, 480}, DDERR_INVALIDRECT}, /* Overlapped blit, flipped source. */
9819 {{640, 0, 160, 480}, { 0, 0, 480, 480}, DDERR_INVALIDRECT}, /* Overlapped blit, mirrored source. */
9820 {{160, 0, 480, 480}, { 0, 0, 480, 480}, DD_OK}, /* Overlapped blit, stretched x. */
9821 {{160, 160, 640, 480}, { 0, 0, 480, 480}, DD_OK}, /* Overlapped blit, stretched y. */
9822 {{ 0, 0, 640, 480}, { 0, 0, 640, 480}, DD_OK}, /* Full surface blit. */
9823 {{ 0, 0, 640, 480}, { 0, 480, 640, 0}, DDERR_INVALIDRECT}, /* Full surface, flipped destination. */
9824 {{ 0, 0, 640, 480}, {640, 0, 0, 480}, DDERR_INVALIDRECT}, /* Full surface, mirrored destination. */
9825 {{ 0, 480, 640, 0}, { 0, 0, 640, 480}, DDERR_INVALIDRECT}, /* Full surface, flipped source. */
9826 {{640, 0, 0, 480}, { 0, 0, 640, 480}, DDERR_INVALIDRECT}, /* Full surface, mirrored source. */
9829 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
9830 0, 0, 640, 480, 0, 0, 0, 0);
9831 ddraw = create_ddraw();
9832 ok(!!ddraw, "Failed to create a ddraw object.\n");
9833 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
9835 skip("Failed to create a 3D device, skipping test.\n");
9836 IDirectDraw2_Release(ddraw);
9837 DestroyWindow(window);
9838 return;
9841 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
9842 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
9844 memset(&surface_desc, 0, sizeof(surface_desc));
9845 surface_desc.dwSize = sizeof(surface_desc);
9846 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
9847 surface_desc.dwWidth = 640;
9848 surface_desc.dwHeight = 480;
9849 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
9850 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9851 ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
9853 hr = IDirectDrawSurface_Blt(surface, NULL, surface, NULL, 0, NULL);
9854 ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
9856 hr = IDirectDrawSurface_Blt(surface, NULL, rt, NULL, 0, NULL);
9857 ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
9859 for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
9861 hr = IDirectDrawSurface_Blt(surface, &test_data[i].dst_rect,
9862 surface, &test_data[i].src_rect, DDBLT_WAIT, NULL);
9863 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#x, expected %#x.\n", i, hr, test_data[i].hr);
9865 hr = IDirectDrawSurface_Blt(surface, &test_data[i].dst_rect,
9866 rt, &test_data[i].src_rect, DDBLT_WAIT, NULL);
9867 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#x, expected %#x.\n", i, hr, test_data[i].hr);
9870 IDirectDrawSurface_Release(surface);
9871 IDirectDrawSurface_Release(rt);
9872 refcount = IDirect3DDevice2_Release(device);
9873 ok(!refcount, "Device has %u references left.\n", refcount);
9874 IDirectDraw2_Release(ddraw);
9875 DestroyWindow(window);
9878 static void test_getdc(void)
9880 IDirectDrawSurface *surface, *surface2, *tmp;
9881 DDSURFACEDESC surface_desc, map_desc;
9882 DDSCAPS caps = {DDSCAPS_COMPLEX};
9883 IDirectDraw2 *ddraw;
9884 unsigned int i;
9885 HWND window;
9886 HDC dc, dc2;
9887 HRESULT hr;
9889 static const struct
9891 const char *name;
9892 DDPIXELFORMAT format;
9893 BOOL getdc_supported;
9894 HRESULT alt_result;
9896 test_data[] =
9898 {"D3DFMT_A8R8G8B8", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {32},
9899 {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}}, TRUE},
9900 {"D3DFMT_X8R8G8B8", {sizeof(test_data->format), DDPF_RGB, 0, {32},
9901 {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0x00000000}}, TRUE},
9902 {"D3DFMT_R5G6B5", {sizeof(test_data->format), DDPF_RGB, 0, {16},
9903 {0x0000f800}, {0x000007e0}, {0x0000001f}, {0x00000000}}, TRUE},
9904 {"D3DFMT_X1R5G5B5", {sizeof(test_data->format), DDPF_RGB, 0, {16},
9905 {0x00007c00}, {0x000003e0}, {0x0000001f}, {0x00000000}}, TRUE},
9906 {"D3DFMT_A1R5G5B5", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {16},
9907 {0x00007c00}, {0x000003e0}, {0x0000001f}, {0x00008000}}, TRUE},
9908 {"D3DFMT_A4R4G4B4", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {16},
9909 {0x00000f00}, {0x000000f0}, {0x0000000f}, {0x0000f000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
9910 {"D3DFMT_X4R4G4B4", {sizeof(test_data->format), DDPF_RGB, 0, {16},
9911 {0x00000f00}, {0x000000f0}, {0x0000000f}, {0x00000000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
9912 {"D3DFMT_A2R10G10B10", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {32},
9913 {0xc0000000}, {0x3ff00000}, {0x000ffc00}, {0x000003ff}}, TRUE},
9914 {"D3DFMT_A8B8G8R8", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {32},
9915 {0x000000ff}, {0x0000ff00}, {0x00ff0000}, {0xff000000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
9916 {"D3DFMT_X8B8G8R8", {sizeof(test_data->format), DDPF_RGB, 0, {32},
9917 {0x000000ff}, {0x0000ff00}, {0x00ff0000}, {0x00000000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
9918 {"D3DFMT_R3G3B2", {sizeof(test_data->format), DDPF_RGB, 0, {8},
9919 {0x000000e0}, {0x0000001c}, {0x00000003}, {0x00000000}}, FALSE},
9920 /* GetDC() on a P8 surface fails unless the display mode is 8 bpp.
9921 * This is not implemented in wine yet, so disable the test for now.
9922 * Succeeding P8 GetDC() calls are tested in the ddraw:visual test.
9923 {"D3DFMT_P8", {sizeof(test_data->format), DDPF_PALETTEINDEXED8 | DDPF_RGB, 0, {8 },
9924 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
9926 {"D3DFMT_L8", {sizeof(test_data->format), DDPF_LUMINANCE, 0, {8},
9927 {0x000000ff}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
9928 {"D3DFMT_A8L8", {sizeof(test_data->format), DDPF_ALPHAPIXELS | DDPF_LUMINANCE, 0, {16},
9929 {0x000000ff}, {0x00000000}, {0x00000000}, {0x0000ff00}}, FALSE},
9930 {"D3DFMT_DXT1", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','1'), {0},
9931 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
9932 {"D3DFMT_DXT2", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','2'), {0},
9933 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
9934 {"D3DFMT_DXT3", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','3'), {0},
9935 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
9936 {"D3DFMT_DXT4", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','4'), {0},
9937 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
9938 {"D3DFMT_DXT5", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','5'), {0},
9939 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
9942 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
9943 0, 0, 640, 480, 0, 0, 0, 0);
9944 ddraw = create_ddraw();
9945 ok(!!ddraw, "Failed to create a ddraw object.\n");
9946 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
9947 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
9949 for (i = 0; i < (sizeof(test_data) / sizeof(*test_data)); ++i)
9951 memset(&surface_desc, 0, sizeof(surface_desc));
9952 surface_desc.dwSize = sizeof(surface_desc);
9953 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
9954 surface_desc.dwWidth = 64;
9955 surface_desc.dwHeight = 64;
9956 U4(surface_desc).ddpfPixelFormat = test_data[i].format;
9957 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
9959 if (FAILED(IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
9961 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
9962 if (FAILED(hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
9964 skip("Failed to create surface for format %s (hr %#x), skipping tests.\n", test_data[i].name, hr);
9965 continue;
9969 dc = (void *)0x1234;
9970 hr = IDirectDrawSurface_GetDC(surface, &dc);
9971 if (test_data[i].getdc_supported)
9972 ok(SUCCEEDED(hr) || (test_data[i].alt_result && hr == test_data[i].alt_result),
9973 "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
9974 else
9975 ok(FAILED(hr), "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
9977 if (SUCCEEDED(hr))
9979 unsigned int width_bytes;
9980 DIBSECTION dib;
9981 HBITMAP bitmap;
9982 DWORD type;
9983 int size;
9985 type = GetObjectType(dc);
9986 ok(type == OBJ_MEMDC, "Got unexpected object type %#x for format %s.\n", type, test_data[i].name);
9987 bitmap = GetCurrentObject(dc, OBJ_BITMAP);
9988 type = GetObjectType(bitmap);
9989 ok(type == OBJ_BITMAP, "Got unexpected object type %#x for format %s.\n", type, test_data[i].name);
9991 size = GetObjectA(bitmap, sizeof(dib), &dib);
9992 ok(size == sizeof(dib), "Got unexpected size %d for format %s.\n", size, test_data[i].name);
9993 ok(!dib.dsBm.bmType, "Got unexpected type %#x for format %s.\n",
9994 dib.dsBm.bmType, test_data[i].name);
9995 ok(dib.dsBm.bmWidth == surface_desc.dwWidth, "Got unexpected width %d for format %s.\n",
9996 dib.dsBm.bmWidth, test_data[i].name);
9997 ok(dib.dsBm.bmHeight == surface_desc.dwHeight, "Got unexpected height %d for format %s.\n",
9998 dib.dsBm.bmHeight, test_data[i].name);
9999 width_bytes = ((dib.dsBm.bmWidth * U1(test_data[i].format).dwRGBBitCount + 31) >> 3) & ~3;
10000 ok(dib.dsBm.bmWidthBytes == width_bytes, "Got unexpected width bytes %d for format %s.\n",
10001 dib.dsBm.bmWidthBytes, test_data[i].name);
10002 ok(dib.dsBm.bmPlanes == 1, "Got unexpected plane count %d for format %s.\n",
10003 dib.dsBm.bmPlanes, test_data[i].name);
10004 ok(dib.dsBm.bmBitsPixel == U1(test_data[i].format).dwRGBBitCount,
10005 "Got unexpected bit count %d for format %s.\n",
10006 dib.dsBm.bmBitsPixel, test_data[i].name);
10007 ok(!!dib.dsBm.bmBits, "Got unexpected bits %p for format %s.\n",
10008 dib.dsBm.bmBits, test_data[i].name);
10010 ok(dib.dsBmih.biSize == sizeof(dib.dsBmih), "Got unexpected size %u for format %s.\n",
10011 dib.dsBmih.biSize, test_data[i].name);
10012 ok(dib.dsBmih.biWidth == surface_desc.dwWidth, "Got unexpected width %d for format %s.\n",
10013 dib.dsBmih.biHeight, test_data[i].name);
10014 ok(dib.dsBmih.biHeight == surface_desc.dwHeight, "Got unexpected height %d for format %s.\n",
10015 dib.dsBmih.biHeight, test_data[i].name);
10016 ok(dib.dsBmih.biPlanes == 1, "Got unexpected plane count %u for format %s.\n",
10017 dib.dsBmih.biPlanes, test_data[i].name);
10018 ok(dib.dsBmih.biBitCount == U1(test_data[i].format).dwRGBBitCount,
10019 "Got unexpected bit count %u for format %s.\n",
10020 dib.dsBmih.biBitCount, test_data[i].name);
10021 ok(dib.dsBmih.biCompression == (U1(test_data[i].format).dwRGBBitCount == 16 ? BI_BITFIELDS : BI_RGB)
10022 || broken(U2(test_data[i].format).dwRGBBitCount == 32 && dib.dsBmih.biCompression == BI_BITFIELDS),
10023 "Got unexpected compression %#x for format %s.\n",
10024 dib.dsBmih.biCompression, test_data[i].name);
10025 ok(!dib.dsBmih.biSizeImage, "Got unexpected image size %u for format %s.\n",
10026 dib.dsBmih.biSizeImage, test_data[i].name);
10027 ok(!dib.dsBmih.biXPelsPerMeter, "Got unexpected horizontal resolution %d for format %s.\n",
10028 dib.dsBmih.biXPelsPerMeter, test_data[i].name);
10029 ok(!dib.dsBmih.biYPelsPerMeter, "Got unexpected vertical resolution %d for format %s.\n",
10030 dib.dsBmih.biYPelsPerMeter, test_data[i].name);
10031 ok(!dib.dsBmih.biClrUsed, "Got unexpected used colour count %u for format %s.\n",
10032 dib.dsBmih.biClrUsed, test_data[i].name);
10033 ok(!dib.dsBmih.biClrImportant, "Got unexpected important colour count %u for format %s.\n",
10034 dib.dsBmih.biClrImportant, test_data[i].name);
10036 if (dib.dsBmih.biCompression == BI_BITFIELDS)
10038 ok((dib.dsBitfields[0] == U2(test_data[i].format).dwRBitMask
10039 && dib.dsBitfields[1] == U3(test_data[i].format).dwGBitMask
10040 && dib.dsBitfields[2] == U4(test_data[i].format).dwBBitMask)
10041 || broken(!dib.dsBitfields[0] && !dib.dsBitfields[1] && !dib.dsBitfields[2]),
10042 "Got unexpected colour masks 0x%08x 0x%08x 0x%08x for format %s.\n",
10043 dib.dsBitfields[0], dib.dsBitfields[1], dib.dsBitfields[2], test_data[i].name);
10045 else
10047 ok(!dib.dsBitfields[0] && !dib.dsBitfields[1] && !dib.dsBitfields[2],
10048 "Got unexpected colour masks 0x%08x 0x%08x 0x%08x for format %s.\n",
10049 dib.dsBitfields[0], dib.dsBitfields[1], dib.dsBitfields[2], test_data[i].name);
10051 ok(!dib.dshSection, "Got unexpected section %p for format %s.\n", dib.dshSection, test_data[i].name);
10052 ok(!dib.dsOffset, "Got unexpected offset %u for format %s.\n", dib.dsOffset, test_data[i].name);
10054 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10055 ok(hr == DD_OK, "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10057 else
10059 ok(!dc, "Got unexpected dc %p for format %s.\n", dc, test_data[i].name);
10062 IDirectDrawSurface_Release(surface);
10064 if (FAILED(hr))
10065 continue;
10067 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
10068 if (FAILED(hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
10070 skip("Failed to create mip-mapped texture for format %s (hr %#x), skipping tests.\n",
10071 test_data[i].name, hr);
10072 continue;
10075 hr = IDirectDrawSurface_GetAttachedSurface(surface, &caps, &tmp);
10076 ok(SUCCEEDED(hr), "Failed to get attached surface for format %s, hr %#x.\n", test_data[i].name, hr);
10077 hr = IDirectDrawSurface_GetAttachedSurface(tmp, &caps, &surface2);
10078 ok(SUCCEEDED(hr), "Failed to get attached surface for format %s, hr %#x.\n", test_data[i].name, hr);
10079 IDirectDrawSurface_Release(tmp);
10081 hr = IDirectDrawSurface_GetDC(surface, &dc);
10082 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10083 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10084 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10085 hr = IDirectDrawSurface_GetDC(surface2, &dc);
10086 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10087 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
10088 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10090 hr = IDirectDrawSurface_GetDC(surface, &dc);
10091 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10092 dc2 = (void *)0x1234;
10093 hr = IDirectDrawSurface_GetDC(surface, &dc2);
10094 ok(hr == DDERR_DCALREADYCREATED, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10095 ok(dc2 == (void *)0x1234, "Got unexpected dc %p for format %s.\n", dc, test_data[i].name);
10096 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10097 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10098 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10099 ok(hr == DDERR_NODC, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10101 map_desc.dwSize = sizeof(map_desc);
10102 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10103 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#x.\n", test_data[i].name, hr);
10104 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10105 ok(hr == DDERR_SURFACEBUSY, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10106 hr = IDirectDrawSurface_Unlock(surface, NULL);
10107 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#x.\n", test_data[i].name, hr);
10108 hr = IDirectDrawSurface_Unlock(surface, NULL);
10109 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10111 hr = IDirectDrawSurface_GetDC(surface, &dc);
10112 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10113 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10114 ok(hr == DDERR_SURFACEBUSY, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10115 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10116 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10118 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10119 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#x.\n", test_data[i].name, hr);
10120 hr = IDirectDrawSurface_GetDC(surface, &dc);
10121 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10122 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10123 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10124 hr = IDirectDrawSurface_Unlock(surface, NULL);
10125 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#x.\n", test_data[i].name, hr);
10127 hr = IDirectDrawSurface_GetDC(surface, &dc);
10128 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10129 hr = IDirectDrawSurface_GetDC(surface2, &dc2);
10130 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10131 hr = IDirectDrawSurface_ReleaseDC(surface2, dc2);
10132 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10133 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10134 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10136 hr = IDirectDrawSurface_GetDC(surface2, &dc);
10137 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10138 hr = IDirectDrawSurface_GetDC(surface, &dc2);
10139 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10140 hr = IDirectDrawSurface_ReleaseDC(surface, dc2);
10141 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10142 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
10143 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10145 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10146 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#x.\n", test_data[i].name, hr);
10147 hr = IDirectDrawSurface_Lock(surface2, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10148 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#x.\n", test_data[i].name, hr);
10149 hr = IDirectDrawSurface_Unlock(surface2, NULL);
10150 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#x.\n", test_data[i].name, hr);
10151 hr = IDirectDrawSurface_Unlock(surface, NULL);
10152 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#x.\n", test_data[i].name, hr);
10154 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10155 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#x.\n", test_data[i].name, hr);
10156 hr = IDirectDrawSurface_GetDC(surface, &dc);
10157 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10158 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10159 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10160 hr = IDirectDrawSurface_Unlock(surface, NULL);
10161 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#x.\n", test_data[i].name, hr);
10163 hr = IDirectDrawSurface_Lock(surface2, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10164 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#x.\n", test_data[i].name, hr);
10165 hr = IDirectDrawSurface_GetDC(surface, &dc);
10166 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10167 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10168 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10169 hr = IDirectDrawSurface_Unlock(surface2, NULL);
10170 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#x.\n", test_data[i].name, hr);
10172 hr = IDirectDrawSurface_GetDC(surface, &dc);
10173 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10174 hr = IDirectDrawSurface_Lock(surface2, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10175 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#x.\n", test_data[i].name, hr);
10176 hr = IDirectDrawSurface_Unlock(surface2, NULL);
10177 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#x.\n", test_data[i].name, hr);
10178 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10179 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10181 hr = IDirectDrawSurface_GetDC(surface2, &dc);
10182 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10183 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10184 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#x.\n", test_data[i].name, hr);
10185 hr = IDirectDrawSurface_Unlock(surface, NULL);
10186 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#x.\n", test_data[i].name, hr);
10187 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
10188 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10190 hr = IDirectDrawSurface_Unlock(surface, NULL);
10191 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10192 hr = IDirectDrawSurface_GetDC(surface2, &dc);
10193 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10194 hr = IDirectDrawSurface_Unlock(surface, NULL);
10195 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10196 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
10197 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10198 hr = IDirectDrawSurface_Unlock(surface, NULL);
10199 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10201 hr = IDirectDrawSurface_Unlock(surface2, NULL);
10202 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10203 hr = IDirectDrawSurface_GetDC(surface, &dc);
10204 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#x.\n", test_data[i].name, hr);
10205 hr = IDirectDrawSurface_Unlock(surface2, NULL);
10206 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10207 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10208 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#x.\n", test_data[i].name, hr);
10209 hr = IDirectDrawSurface_Unlock(surface2, NULL);
10210 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#x for format %s.\n", hr, test_data[i].name);
10212 IDirectDrawSurface_Release(surface2);
10213 IDirectDrawSurface_Release(surface);
10216 IDirectDraw2_Release(ddraw);
10217 DestroyWindow(window);
10220 static void test_draw_primitive(void)
10222 static WORD indices[] = {0, 1, 2, 3};
10223 static D3DVERTEX quad[] =
10225 {{-1.0f}, {-1.0f}, {0.0f}},
10226 {{-1.0f}, { 1.0f}, {0.0f}},
10227 {{ 1.0f}, {-1.0f}, {0.0f}},
10228 {{ 1.0f}, { 1.0f}, {0.0f}},
10230 IDirect3DViewport2 *viewport;
10231 IDirect3DDevice2 *device;
10232 IDirectDraw2 *ddraw;
10233 IDirect3D2 *d3d;
10234 ULONG refcount;
10235 HWND window;
10236 HRESULT hr;
10238 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
10239 0, 0, 640, 480, NULL, NULL, NULL, NULL);
10240 ddraw = create_ddraw();
10241 ok(!!ddraw, "Failed to create a ddraw object.\n");
10242 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
10244 skip("Failed to create a 3D device, skipping test.\n");
10245 IDirectDraw2_Release(ddraw);
10246 DestroyWindow(window);
10247 return;
10250 viewport = create_viewport(device, 0, 0, 640, 480);
10251 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
10252 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
10254 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
10255 ok(SUCCEEDED(hr), "Failed to get D3D interface, hr %#x.\n", hr);
10257 IDirect3D2_Release(d3d);
10259 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, NULL, 0, NULL, 0, 0);
10260 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10261 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, NULL, 0, 0);
10262 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10264 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, NULL, 0, indices, 4, 0);
10265 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10267 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, quad, 4, NULL, 0, 0);
10268 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10269 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, quad, 4, 0);
10270 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10271 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, quad, 4, indices, 4, 0);
10272 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10274 destroy_viewport(device, viewport);
10275 refcount = IDirect3DDevice2_Release(device);
10276 ok(!refcount, "Device has %u references left.\n", refcount);
10277 IDirectDraw2_Release(ddraw);
10278 DestroyWindow(window);
10281 static void test_edge_antialiasing_blending(void)
10283 D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
10284 IDirect3DMaterial2 *green_background;
10285 IDirect3DMaterial2 *red_background;
10286 IDirectDrawSurface *offscreen, *ds;
10287 D3DDEVICEDESC hal_desc, hel_desc;
10288 IDirect3DViewport2 *viewport;
10289 DDSURFACEDESC surface_desc;
10290 IDirect3DDevice2 *device;
10291 IDirectDraw2 *ddraw;
10292 ULONG refcount;
10293 D3DCOLOR color;
10294 HWND window;
10295 HRESULT hr;
10297 static D3DMATRIX mat =
10299 1.0f, 0.0f, 0.0f, 0.0f,
10300 0.0f, 1.0f, 0.0f, 0.0f,
10301 0.0f, 0.0f, 1.0f, 0.0f,
10302 0.0f, 0.0f, 0.0f, 1.0f,
10304 static D3DLVERTEX green_quad[] =
10306 {{-1.0f}, {-1.0f}, {0.1f}, 0, {0x7f00ff00}},
10307 {{-1.0f}, { 1.0f}, {0.1f}, 0, {0x7f00ff00}},
10308 {{ 1.0f}, {-1.0f}, {0.1f}, 0, {0x7f00ff00}},
10309 {{ 1.0f}, { 1.0f}, {0.1f}, 0, {0x7f00ff00}},
10311 static D3DLVERTEX red_quad[] =
10313 {{-1.0f}, {-1.0f}, {0.1f}, 0, {0xccff0000}},
10314 {{-1.0f}, { 1.0f}, {0.1f}, 0, {0xccff0000}},
10315 {{ 1.0f}, {-1.0f}, {0.1f}, 0, {0xccff0000}},
10316 {{ 1.0f}, { 1.0f}, {0.1f}, 0, {0xccff0000}},
10319 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
10320 0, 0, 640, 480, NULL, NULL, NULL, NULL);
10321 ddraw = create_ddraw();
10322 ok(!!ddraw, "Failed to create a ddraw object.\n");
10323 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
10325 skip("Failed to create a 3D device.\n");
10326 DestroyWindow(window);
10327 return;
10330 memset(&hal_desc, 0, sizeof(hal_desc));
10331 hal_desc.dwSize = sizeof(hal_desc);
10332 memset(&hel_desc, 0, sizeof(hel_desc));
10333 hel_desc.dwSize = sizeof(hel_desc);
10334 hr = IDirect3DDevice2_GetCaps(device, &hal_desc, &hel_desc);
10335 ok(SUCCEEDED(hr), "Failed to get device caps, hr %#x.\n", hr);
10336 trace("HAL line edge antialiasing support: %#x.\n",
10337 hal_desc.dpcLineCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES);
10338 trace("HAL triangle edge antialiasing support: %#x.\n",
10339 hal_desc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES);
10340 trace("HEL line edge antialiasing support: %#x.\n",
10341 hel_desc.dpcLineCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES);
10342 trace("HEL triangle edge antialiasing support: %#x.\n",
10343 hel_desc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES);
10345 memset(&surface_desc, 0, sizeof(surface_desc));
10346 surface_desc.dwSize = sizeof(surface_desc);
10347 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
10348 surface_desc.dwWidth = 640;
10349 surface_desc.dwHeight = 480;
10350 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
10351 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
10352 U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
10353 U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount = 32;
10354 U2(U4(surface_desc).ddpfPixelFormat).dwRBitMask = 0x00ff0000;
10355 U3(U4(surface_desc).ddpfPixelFormat).dwGBitMask = 0x0000ff00;
10356 U4(U4(surface_desc).ddpfPixelFormat).dwBBitMask = 0x000000ff;
10357 U5(U4(surface_desc).ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
10358 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &offscreen, NULL);
10359 ok(hr == D3D_OK, "Creating the offscreen render target failed, hr %#x.\n", hr);
10361 ds = get_depth_stencil(device);
10362 hr = IDirectDrawSurface_AddAttachedSurface(offscreen, ds);
10363 todo_wine ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
10364 IDirectDrawSurface_Release(ds);
10366 hr = IDirect3DDevice2_SetRenderTarget(device, offscreen, 0);
10367 ok(SUCCEEDED(hr), "Failed to set render target, hr %#x.\n", hr);
10369 red_background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 0.8f);
10370 green_background = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 0.5f);
10372 viewport = create_viewport(device, 0, 0, 640, 480);
10373 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
10374 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
10376 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat);
10377 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr);
10378 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat);
10379 ok(SUCCEEDED(hr), "Failed to set view transform, hr %#x.\n", hr);
10380 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat);
10381 ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#x.\n", hr);
10382 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CLIPPING, FALSE);
10383 ok(SUCCEEDED(hr), "Failed to disable clipping, hr %#x.\n", hr);
10384 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, FALSE);
10385 ok(SUCCEEDED(hr), "Failed to disable Z test, hr %#x.\n", hr);
10386 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_FOGENABLE, FALSE);
10387 ok(SUCCEEDED(hr), "Failed to disable fog, hr %#x.\n", hr);
10388 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_STENCILENABLE, FALSE);
10389 ok(SUCCEEDED(hr), "Failed to disable stencil test, hr %#x.\n", hr);
10390 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
10391 ok(SUCCEEDED(hr), "Failed to disable culling, hr %#x.\n", hr);
10392 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
10393 ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr);
10395 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
10396 ok(SUCCEEDED(hr), "Failed to enable blending, hr %#x.\n", hr);
10397 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
10398 ok(SUCCEEDED(hr), "Failed to set src blend, hr %#x.\n", hr);
10399 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_DESTALPHA);
10400 ok(SUCCEEDED(hr), "Failed to set dest blend, hr %#x.\n", hr);
10402 viewport_set_background(device, viewport, red_background);
10403 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
10404 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
10405 hr = IDirect3DDevice2_BeginScene(device);
10406 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
10407 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, green_quad, 4, 0);
10408 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10409 hr = IDirect3DDevice2_EndScene(device);
10410 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
10411 color = get_surface_color(offscreen, 320, 240);
10412 ok(compare_color(color, 0x00cc7f00, 1), "Got unexpected color 0x%08x.\n", color);
10414 viewport_set_background(device, viewport, green_background);
10415 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
10416 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
10417 hr = IDirect3DDevice2_BeginScene(device);
10418 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
10419 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, red_quad, 4, 0);
10420 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10421 hr = IDirect3DDevice2_EndScene(device);
10422 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
10423 color = get_surface_color(offscreen, 320, 240);
10424 ok(compare_color(color, 0x00cc7f00, 1), "Got unexpected color 0x%08x.\n", color);
10426 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
10427 ok(SUCCEEDED(hr), "Failed to disable blending, hr %#x.\n", hr);
10429 viewport_set_background(device, viewport, red_background);
10430 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
10431 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
10432 hr = IDirect3DDevice2_BeginScene(device);
10433 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
10434 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, green_quad, 4, 0);
10435 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10436 hr = IDirect3DDevice2_EndScene(device);
10437 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
10438 color = get_surface_color(offscreen, 320, 240);
10439 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
10441 viewport_set_background(device, viewport, green_background);
10442 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
10443 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
10444 hr = IDirect3DDevice2_BeginScene(device);
10445 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
10446 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, red_quad, 4, 0);
10447 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10448 hr = IDirect3DDevice2_EndScene(device);
10449 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
10450 color = get_surface_color(offscreen, 320, 240);
10451 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
10453 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_EDGEANTIALIAS, TRUE);
10454 ok(SUCCEEDED(hr), "Failed to enable edge antialiasing, hr %#x.\n", hr);
10456 viewport_set_background(device, viewport, red_background);
10457 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
10458 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
10459 hr = IDirect3DDevice2_BeginScene(device);
10460 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
10461 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, green_quad, 4, 0);
10462 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10463 hr = IDirect3DDevice2_EndScene(device);
10464 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
10465 color = get_surface_color(offscreen, 320, 240);
10466 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
10468 viewport_set_background(device, viewport, green_background);
10469 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
10470 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
10471 hr = IDirect3DDevice2_BeginScene(device);
10472 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
10473 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, red_quad, 4, 0);
10474 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10475 hr = IDirect3DDevice2_EndScene(device);
10476 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
10477 color = get_surface_color(offscreen, 320, 240);
10478 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
10480 IDirectDrawSurface_Release(offscreen);
10481 destroy_viewport(device, viewport);
10482 destroy_material(red_background);
10483 destroy_material(green_background);
10484 refcount = IDirect3DDevice2_Release(device);
10485 ok(!refcount, "Device has %u references left.\n", refcount);
10486 IDirectDraw2_Release(ddraw);
10487 DestroyWindow(window);
10490 /* TransformVertices always writes 32 bytes regardless of the input / output stride.
10491 * The stride is honored for navigating to the next vertex. 3 floats input position
10492 * are read, and 16 bytes extra vertex data are copied around. */
10493 struct transform_input
10495 float x, y, z, unused1; /* Position data, transformed. */
10496 DWORD v1, v2, v3, v4; /* Extra data, e.g. color and texture coords, copied. */
10497 DWORD unused2;
10500 struct transform_output
10502 float x, y, z, w;
10503 DWORD v1, v2, v3, v4;
10504 DWORD unused3, unused4;
10507 static void test_transform_vertices(void)
10509 IDirect3DDevice2 *device;
10510 IDirectDrawSurface *rt;
10511 IDirectDraw2 *ddraw;
10512 ULONG refcount;
10513 HWND window;
10514 HRESULT hr;
10515 D3DCOLOR color;
10516 IDirect3DViewport2 *viewport;
10517 IDirect3DMaterial2 *background;
10518 static struct transform_input position_tests[] =
10520 { 0.0f, 0.0f, 0.0f, 0.0f, 1, 2, 3, 4, 5},
10521 { 1.0f, 1.0f, 1.0f, 8.0f, 6, 7, 8, 9, 10},
10522 {-1.0f, -1.0f, -1.0f, 4.0f, 11, 12, 13, 14, 15},
10523 { 0.5f, 0.5f, 0.5f, 2.0f, 16, 17, 18, 19, 20},
10524 {-0.5f, -0.5f, -0.5f, 1.0f, ~1U, ~2U, ~3U, ~4U, ~5U},
10525 {-0.5f, -0.5f, 0.0f, 0.0f, ~6U, ~7U, ~8U, ~9U, ~0U},
10527 static struct transform_input cliptest[] =
10529 { 25.59f, 25.59f, 1.0f, 0.0f, 1, 2, 3, 4, 5},
10530 { 25.61f, 25.61f, 1.01f, 0.0f, 1, 2, 3, 4, 5},
10531 {-25.59f, -25.59f, 0.0f, 0.0f, 1, 2, 3, 4, 5},
10532 {-25.61f, -25.61f, -0.01f, 0.0f, 1, 2, 3, 4, 5},
10534 static struct transform_input offscreentest[] =
10536 {128.1f, 0.0f, 0.0f, 0.0f, 1, 2, 3, 4, 5},
10538 struct transform_output out[ARRAY_SIZE(position_tests)];
10539 D3DHVERTEX out_h[ARRAY_SIZE(position_tests)];
10540 D3DTRANSFORMDATA transformdata;
10541 static const D3DVIEWPORT vp_template =
10543 sizeof(vp_template), 0, 0, 256, 256, 5.0f, 5.0f, 256.0f, 256.0f, -25.0f, 60.0f
10545 D3DVIEWPORT vp_data =
10547 sizeof(vp_data), 0, 0, 256, 256, 1.0f, 1.0f, 256.0f, 256.0f, 0.0f, 1.0f
10549 unsigned int i;
10550 DWORD offscreen;
10551 static D3DMATRIX mat_scale =
10553 2.0f, 0.0f, 0.0f, 0.0f,
10554 0.0f, 2.0f, 0.0f, 0.0f,
10555 0.0f, 0.0f, 2.0f, 0.0f,
10556 0.0f, 0.0f, 0.0f, 1.0f,
10558 mat_translate1 =
10560 1.0f, 0.0f, 0.0f, 0.0f,
10561 0.0f, 1.0f, 0.0f, 0.0f,
10562 0.0f, 0.0f, 1.0f, 0.0f,
10563 1.0f, 0.0f, 0.0f, 1.0f,
10565 mat_translate2 =
10567 1.0f, 0.0f, 0.0f, 0.0f,
10568 0.0f, 1.0f, 0.0f, 0.0f,
10569 0.0f, 0.0f, 1.0f, 0.0f,
10570 0.0f, 1.0f, 0.0f, 1.0f,
10572 static D3DLVERTEX quad[] =
10574 {{-0.75f},{-0.5f }, {0.0f}, 0, {0xffff0000}},
10575 {{-0.75f},{ 0.25f}, {0.0f}, 0, {0xffff0000}},
10576 {{ 0.5f}, {-0.5f }, {0.0f}, 0, {0xffff0000}},
10577 {{ 0.5f}, { 0.25f}, {0.0f}, 0, {0xffff0000}},
10579 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
10582 for (i = 0; i < ARRAY_SIZE(out); ++i)
10584 out[i].unused3 = 0xdeadbeef;
10585 out[i].unused4 = 0xcafecafe;
10588 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
10589 0, 0, 640, 480, 0, 0, 0, 0);
10590 ddraw = create_ddraw();
10591 ok(!!ddraw, "Failed to create a ddraw object.\n");
10592 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
10594 skip("Failed to create a 3D device, skipping test.\n");
10595 IDirectDraw2_Release(ddraw);
10596 DestroyWindow(window);
10597 return;
10599 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
10600 ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
10602 viewport = create_viewport(device, 0, 0, 256, 256);
10603 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
10604 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
10606 memset(&transformdata, 0, sizeof(transformdata));
10607 transformdata.dwSize = sizeof(transformdata);
10608 transformdata.lpIn = position_tests;
10609 transformdata.dwInSize = sizeof(position_tests[0]);
10610 transformdata.lpOut = out;
10611 transformdata.dwOutSize = sizeof(out[0]);
10612 transformdata.lpHOut = NULL;
10614 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
10615 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
10616 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10617 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10619 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
10621 static const struct vec4 cmp[] =
10623 {128.0f, 128.0f, 0.0f, 1.0f}, {129.0f, 127.0f, 1.0f, 1.0f}, {127.0f, 129.0f, -1.0f, 1.0f},
10624 {128.5f, 127.5f, 0.5f, 1.0f}, {127.5f, 128.5f, -0.5f, 1.0f}, {127.5f, 128.5f, 0.0f, 1.0f}
10627 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
10628 "Vertex %u differs. Got %f %f %f %f.\n", i,
10629 out[i].x, out[i].y, out[i].z, out[i].w);
10630 ok(out[i].v1 == position_tests[i].v1 && out[i].v2 == position_tests[i].v2
10631 && out[i].v3 == position_tests[i].v3 && out[i].v4 == position_tests[i].v4,
10632 "Vertex %u payload is %u %u %u %u.\n", i, out[i].v1, out[i].v2, out[i].v3, out[i].v4);
10633 ok(out[i].unused3 == 0xdeadbeef && out[i].unused4 == 0xcafecafe,
10634 "Vertex %u unused data is %#x, %#x.\n", i, out[i].unused3, out[i].unused4);
10637 vp_data = vp_template;
10638 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
10639 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
10640 offscreen = 0xdeadbeef;
10641 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
10642 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
10643 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10644 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10646 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
10648 static const struct vec4 cmp[] =
10650 {128.0f, 128.0f, 0.0f, 1.0f}, {133.0f, 123.0f, 1.0f, 1.0f}, {123.0f, 133.0f, -1.0f, 1.0f},
10651 {130.5f, 125.5f, 0.5f, 1.0f}, {125.5f, 130.5f, -0.5f, 1.0f}, {125.5f, 130.5f, 0.0f, 1.0f}
10653 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
10654 "Vertex %u differs. Got %f %f %f %f.\n", i,
10655 out[i].x, out[i].y, out[i].z, out[i].w);
10658 vp_data.dwX = 10;
10659 vp_data.dwY = 20;
10660 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
10661 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
10662 offscreen = 0xdeadbeef;
10663 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
10664 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
10665 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10666 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10667 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
10669 static const struct vec4 cmp[] =
10671 {138.0f, 148.0f, 0.0f, 1.0f}, {143.0f, 143.0f, 1.0f, 1.0f}, {133.0f, 153.0f, -1.0f, 1.0f},
10672 {140.5f, 145.5f, 0.5f, 1.0f}, {135.5f, 150.5f, -0.5f, 1.0f}, {135.5f, 150.5f, 0.0f, 1.0f}
10674 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
10675 "Vertex %u differs. Got %f %f %f %f.\n", i,
10676 out[i].x, out[i].y, out[i].z, out[i].w);
10679 transformdata.lpHOut = out_h;
10680 offscreen = 0xdeadbeef;
10681 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
10682 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10683 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10684 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10685 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
10687 static const D3DHVERTEX cmp_h[] =
10689 {0, { 0.0f}, { 0.0f}, { 0.0f}}, {0, { 1.0f}, { 1.0f}, {1.0f}},
10690 {D3DCLIP_FRONT, {-1.0f}, {-1.0f}, {-1.0f}}, {0, { 0.5f}, { 0.5f}, {0.5f}},
10691 {D3DCLIP_FRONT, {-0.5f}, {-0.5f}, {-0.5f}}, {0, {-0.5f}, {-0.5f}, {0.0f}}
10693 ok(compare_float(U1(cmp_h[i]).hx, U1(out_h[i]).hx, 4096)
10694 && compare_float(U1(cmp_h[i]).hy, U1(out_h[i]).hy, 4096)
10695 && compare_float(U1(cmp_h[i]).hz, U1(out_h[i]).hz, 4096)
10696 && cmp_h[i].dwFlags == out_h[i].dwFlags,
10697 "HVertex %u differs. Got %#x %f %f %f.\n", i,
10698 out_h[i].dwFlags, U1(out_h[i]).hx, U2(out_h[i]).hy, U3(out_h[i]).hz);
10700 /* No scheme has been found behind those return values. It seems to be
10701 * whatever data windows has when throwing the vertex away. Modify the
10702 * input test vertices to test this more. Depending on the input data
10703 * it can happen that the z coord gets written into y, or similar things. */
10704 if (0)
10706 static const struct vec4 cmp[] =
10708 {138.0f, 148.0f, 0.0f, 1.0f}, {143.0f, 143.0f, 1.0f, 1.0f}, { -1.0f, -1.0f, 0.5f, 1.0f},
10709 {140.5f, 145.5f, 0.5f, 1.0f}, { -0.5f, -0.5f, -0.5f, 1.0f}, {135.5f, 150.5f, 0.0f, 1.0f}
10711 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
10712 "Vertex %u differs. Got %f %f %f %f.\n", i,
10713 out[i].x, out[i].y, out[i].z, out[i].w);
10717 transformdata.lpIn = cliptest;
10718 transformdata.dwInSize = sizeof(cliptest[0]);
10719 offscreen = 0xdeadbeef;
10720 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(cliptest),
10721 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10722 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10723 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10724 for (i = 0; i < ARRAY_SIZE(cliptest); ++i)
10726 static const DWORD flags[] =
10729 D3DCLIP_RIGHT | D3DCLIP_BACK | D3DCLIP_TOP,
10731 D3DCLIP_LEFT | D3DCLIP_BOTTOM | D3DCLIP_FRONT,
10733 ok(flags[i] == out_h[i].dwFlags, "Cliptest %u returned %#x.\n", i, out_h[i].dwFlags);
10736 vp_data = vp_template;
10737 vp_data.dwWidth = 10;
10738 vp_data.dwHeight = 480;
10739 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
10740 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
10741 offscreen = 0xdeadbeef;
10742 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(cliptest),
10743 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10744 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10745 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10746 for (i = 0; i < ARRAY_SIZE(cliptest); ++i)
10748 static const DWORD flags[] =
10750 D3DCLIP_RIGHT,
10751 D3DCLIP_RIGHT | D3DCLIP_BACK,
10752 D3DCLIP_LEFT,
10753 D3DCLIP_LEFT | D3DCLIP_FRONT,
10755 ok(flags[i] == out_h[i].dwFlags, "Cliptest %u returned %#x.\n", i, out_h[i].dwFlags);
10758 vp_data = vp_template;
10759 vp_data.dwWidth = 256;
10760 vp_data.dwHeight = 256;
10761 vp_data.dvScaleX = 1;
10762 vp_data.dvScaleY = 1;
10763 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
10764 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
10765 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(cliptest),
10766 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10767 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10768 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10769 for (i = 0; i < ARRAY_SIZE(cliptest); ++i)
10771 static const DWORD flags[] =
10774 D3DCLIP_BACK,
10776 D3DCLIP_FRONT,
10778 ok(flags[i] == out_h[i].dwFlags, "Cliptest %u returned %#x.\n", i, out_h[i].dwFlags);
10781 /* Finally try to figure out how the DWORD dwOffscreen works.
10782 * It is a logical AND of the vertices' dwFlags members. */
10783 vp_data = vp_template;
10784 vp_data.dwWidth = 5;
10785 vp_data.dwHeight = 5;
10786 vp_data.dvScaleX = 10000.0f;
10787 vp_data.dvScaleY = 10000.0f;
10788 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
10789 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
10790 transformdata.lpIn = cliptest;
10791 offscreen = 0xdeadbeef;
10792 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10793 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
10794 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10795 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10797 offscreen = 0xdeadbeef;
10798 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10799 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10800 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10801 ok(offscreen == (D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %x.\n", offscreen);
10802 offscreen = 0xdeadbeef;
10803 hr = IDirect3DViewport2_TransformVertices(viewport, 2,
10804 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10805 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10806 ok(offscreen == (D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %x.\n", offscreen);
10807 hr = IDirect3DViewport2_TransformVertices(viewport, 3,
10808 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10809 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10810 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10812 transformdata.lpIn = cliptest + 1;
10813 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10814 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10815 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10816 ok(offscreen == (D3DCLIP_BACK | D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %x.\n", offscreen);
10818 transformdata.lpIn = cliptest + 2;
10819 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10820 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10821 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10822 ok(offscreen == (D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %x.\n", offscreen);
10823 offscreen = 0xdeadbeef;
10824 hr = IDirect3DViewport2_TransformVertices(viewport, 2,
10825 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10826 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10827 ok(offscreen == (D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %x.\n", offscreen);
10829 transformdata.lpIn = cliptest + 3;
10830 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10831 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10832 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10833 ok(offscreen == (D3DCLIP_FRONT | D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %x.\n", offscreen);
10835 transformdata.lpIn = offscreentest;
10836 transformdata.dwInSize = sizeof(offscreentest[0]);
10837 vp_data = vp_template;
10838 vp_data.dwWidth = 257;
10839 vp_data.dwHeight = 257;
10840 vp_data.dvScaleX = 1.0f;
10841 vp_data.dvScaleY = 1.0f;
10842 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
10843 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
10844 offscreen = 0xdeadbeef;
10845 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10846 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10847 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10848 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10850 vp_data.dwWidth = 256;
10851 vp_data.dwHeight = 256;
10852 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
10853 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
10854 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10855 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10856 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10857 ok(offscreen == D3DCLIP_RIGHT, "Offscreen is %x.\n", offscreen);
10859 /* Test the effect of Matrices.
10861 * Basically the x coodinate ends up as ((x + 1) * 2 + 0) * 5 and
10862 * y as ((y + 0) * 2 + 1) * 5. The 5 comes from dvScaleX/Y, 2 from
10863 * the view matrix and the +1's from the world and projection matrix. */
10864 vp_data.dwX = 0;
10865 vp_data.dwX = 0;
10866 vp_data.dwWidth = 256;
10867 vp_data.dwHeight = 256;
10868 vp_data.dvScaleX = 5.0f;
10869 vp_data.dvScaleY = 5.0f;
10870 vp_data.dvMinZ = 0.0f;
10871 vp_data.dvMaxZ = 1.0f;
10872 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
10873 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
10875 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat_translate1);
10876 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr);
10877 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat_scale);
10878 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr);
10879 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat_translate2);
10880 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr);
10882 transformdata.lpIn = position_tests;
10883 transformdata.dwInSize = sizeof(position_tests[0]);
10884 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
10885 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
10886 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10888 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
10890 static const struct vec4 cmp[] =
10892 {138.0f, 123.0f, 0.0f, 1.0f}, {148.0f, 113.0f, 2.0f, 1.0f}, {128.0f, 133.0f, -2.0f, 1.0f},
10893 {143.0f, 118.0f, 1.0f, 1.0f}, {133.0f, 128.0f, -1.0f, 1.0f}, {133.0f, 128.0f, 0.0f, 1.0f}
10896 todo_wine ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
10897 "Vertex %u differs. Got %f %f %f %f.\n", i,
10898 out[i].x, out[i].y, out[i].z, out[i].w);
10901 /* Invalid flags. */
10902 offscreen = 0xdeadbeef;
10903 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
10904 &transformdata, 0, &offscreen);
10905 ok(hr == DDERR_INVALIDPARAMS, "TransformVertices returned %#x.\n", hr);
10906 ok(offscreen == 0xdeadbeef, "Offscreen is %x.\n", offscreen);
10908 /* NULL transform data. */
10909 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10910 NULL, D3DTRANSFORM_UNCLIPPED, &offscreen);
10911 ok(hr == DDERR_INVALIDPARAMS, "TransformVertices returned %#x.\n", hr);
10912 ok(offscreen == 0xdeadbeef, "Offscreen is %x.\n", offscreen);
10913 hr = IDirect3DViewport2_TransformVertices(viewport, 0,
10914 NULL, D3DTRANSFORM_UNCLIPPED, &offscreen);
10915 ok(hr == DDERR_INVALIDPARAMS, "TransformVertices returned %#x.\n", hr);
10916 ok(offscreen == 0xdeadbeef, "Offscreen is %x.\n", offscreen);
10918 /* NULL transform data and NULL dwOffscreen.
10920 * Valid transform data + NULL dwOffscreen -> crash. */
10921 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10922 NULL, D3DTRANSFORM_UNCLIPPED, NULL);
10923 ok(hr == DDERR_INVALIDPARAMS, "TransformVertices returned %#x.\n", hr);
10925 /* No vertices. */
10926 hr = IDirect3DViewport2_TransformVertices(viewport, 0,
10927 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
10928 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10929 ok(!offscreen, "Offscreen is %x.\n", offscreen);
10930 hr = IDirect3DViewport2_TransformVertices(viewport, 0,
10931 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10932 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10933 ok(offscreen == ~0U, "Offscreen is %x.\n", offscreen);
10935 /* Invalid sizes. */
10936 offscreen = 0xdeadbeef;
10937 transformdata.dwSize = sizeof(transformdata) - 1;
10938 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10939 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
10940 ok(hr == DDERR_INVALIDPARAMS, "TransformVertices returned %#x.\n", hr);
10941 ok(offscreen == 0xdeadbeef, "Offscreen is %x.\n", offscreen);
10942 transformdata.dwSize = sizeof(transformdata) + 1;
10943 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
10944 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
10945 ok(hr == DDERR_INVALIDPARAMS, "TransformVertices returned %#x.\n", hr);
10946 ok(offscreen == 0xdeadbeef, "Offscreen is %x.\n", offscreen);
10948 /* NULL lpIn or lpOut -> crash, except when transforming 0 vertices. */
10949 transformdata.dwSize = sizeof(transformdata);
10950 transformdata.lpIn = NULL;
10951 transformdata.lpOut = NULL;
10952 offscreen = 0xdeadbeef;
10953 hr = IDirect3DViewport2_TransformVertices(viewport, 0,
10954 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
10955 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#x.\n", hr);
10956 ok(offscreen == ~0U, "Offscreen is %x.\n", offscreen);
10958 /* Test how vertices are transformed during draws. */
10959 vp_data.dwX = 20;
10960 vp_data.dwY = 20;
10961 vp_data.dwWidth = 200;
10962 vp_data.dwHeight = 400;
10963 vp_data.dvScaleX = 20.0f;
10964 vp_data.dvScaleY = 50.0f;
10965 vp_data.dvMinZ = 0.0f;
10966 vp_data.dvMaxZ = 1.0f;
10967 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
10968 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr);
10969 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
10970 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
10972 ok(SUCCEEDED(hr), "Failed to clear the render target, hr %#x.\n", hr);
10973 background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 0.0f);
10974 viewport_set_background(device, viewport, background);
10975 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
10976 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
10978 hr = IDirect3DDevice2_BeginScene(device);
10979 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
10980 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad, 4, 0);
10981 ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
10982 hr = IDirect3DDevice2_EndScene(device);
10983 ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
10985 color = get_surface_color(rt, 128, 143);
10986 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
10987 color = get_surface_color(rt, 132, 143);
10988 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
10989 color = get_surface_color(rt, 128, 147);
10990 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
10991 color = get_surface_color(rt, 132, 147);
10992 todo_wine ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
10994 color = get_surface_color(rt, 177, 217);
10995 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
10996 color = get_surface_color(rt, 181, 217);
10997 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
10998 color = get_surface_color(rt, 177, 221);
10999 todo_wine ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
11000 color = get_surface_color(rt, 181, 221);
11001 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
11003 IDirectDrawSurface_Release(rt);
11004 destroy_viewport(device, viewport);
11005 IDirect3DMaterial2_Release(background);
11006 refcount = IDirect3DDevice_Release(device);
11007 ok(!refcount, "Device has %u references left.\n", refcount);
11008 IDirectDraw2_Release(ddraw);
11009 DestroyWindow(window);
11012 START_TEST(ddraw2)
11014 IDirectDraw2 *ddraw;
11015 DEVMODEW current_mode;
11016 HMODULE dwmapi;
11018 if (!(ddraw = create_ddraw()))
11020 skip("Failed to create a ddraw object, skipping tests.\n");
11021 return;
11023 IDirectDraw2_Release(ddraw);
11025 memset(&current_mode, 0, sizeof(current_mode));
11026 current_mode.dmSize = sizeof(current_mode);
11027 ok(EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &current_mode), "Failed to get display mode.\n");
11028 registry_mode.dmSize = sizeof(registry_mode);
11029 ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &registry_mode), "Failed to get display mode.\n");
11030 if (registry_mode.dmPelsWidth != current_mode.dmPelsWidth
11031 || registry_mode.dmPelsHeight != current_mode.dmPelsHeight)
11033 skip("Current mode does not match registry mode, skipping test.\n");
11034 return;
11037 if ((dwmapi = LoadLibraryA("dwmapi.dll")))
11038 pDwmIsCompositionEnabled = (void *)GetProcAddress(dwmapi, "DwmIsCompositionEnabled");
11040 test_coop_level_create_device_window();
11041 test_clipper_blt();
11042 test_coop_level_d3d_state();
11043 test_surface_interface_mismatch();
11044 test_coop_level_threaded();
11045 test_depth_blit();
11046 test_texture_load_ckey();
11047 test_viewport();
11048 test_zenable();
11049 test_ck_rgba();
11050 test_ck_default();
11051 test_ck_complex();
11052 test_surface_qi();
11053 test_device_qi();
11054 test_wndproc();
11055 test_window_style();
11056 test_redundant_mode_set();
11057 test_coop_level_mode_set();
11058 test_coop_level_mode_set_multi();
11059 test_initialize();
11060 test_coop_level_surf_create();
11061 test_coop_level_multi_window();
11062 test_clear_rect_count();
11063 test_coop_level_versions();
11064 test_lighting_interface_versions();
11065 test_coop_level_activateapp();
11066 test_unsupported_formats();
11067 test_rt_caps();
11068 test_primary_caps();
11069 test_surface_lock();
11070 test_surface_discard();
11071 test_flip();
11072 test_set_surface_desc();
11073 test_user_memory_getdc();
11074 test_sysmem_overlay();
11075 test_primary_palette();
11076 test_surface_attachment();
11077 test_pixel_format();
11078 test_create_surface_pitch();
11079 test_mipmap();
11080 test_palette_complex();
11081 test_p8_blit();
11082 test_material();
11083 test_lighting();
11084 test_specular_lighting();
11085 test_palette_gdi();
11086 test_palette_alpha();
11087 test_lost_device();
11088 test_surface_desc_lock();
11089 test_texturemapblend();
11090 test_viewport_clear_rect();
11091 test_color_fill();
11092 test_colorkey_precision();
11093 test_range_colorkey();
11094 test_shademode();
11095 test_lockrect_invalid();
11096 test_yv12_overlay();
11097 test_offscreen_overlay();
11098 test_overlay_rect();
11099 test_blt();
11100 test_getdc();
11101 test_draw_primitive();
11102 test_edge_antialiasing_blending();
11103 test_transform_vertices();