ddraw/tests: Avoid picking a large mode on Win10 in test_coop_level_mode_set_enum_cb.
[wine.git] / dlls / ddraw / tests / ddraw2.c
blob4c20a774b05a3bec435567320012a5711daca69b
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 "wine/heap.h"
26 #include <limits.h>
27 #include <math.h>
28 #include "ddrawi.h"
29 #include "d3dhal.h"
31 static BOOL is_ddraw64 = sizeof(DWORD) != sizeof(DWORD *);
32 static DEVMODEW registry_mode;
34 static HRESULT (WINAPI *pDwmIsCompositionEnabled)(BOOL *);
36 struct vec2
38 float x, y;
41 struct vec4
43 float x, y, z, w;
46 struct create_window_thread_param
48 HWND window;
49 HANDLE window_created;
50 HANDLE destroy_window;
51 HANDLE thread;
54 static BOOL compare_float(float f, float g, unsigned int ulps)
56 int x = *(int *)&f;
57 int y = *(int *)&g;
59 if (x < 0)
60 x = INT_MIN - x;
61 if (y < 0)
62 y = INT_MIN - y;
64 if (abs(x - y) > ulps)
65 return FALSE;
67 return TRUE;
70 static BOOL compare_vec4(const struct vec4 *vec, float x, float y, float z, float w, unsigned int ulps)
72 return compare_float(vec->x, x, ulps)
73 && compare_float(vec->y, y, ulps)
74 && compare_float(vec->z, z, ulps)
75 && compare_float(vec->w, w, ulps);
78 static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff)
80 unsigned int diff = x > y ? x - y : y - x;
82 return diff <= max_diff;
85 static BOOL compare_color(D3DCOLOR c1, D3DCOLOR c2, BYTE max_diff)
87 return compare_uint(c1 & 0xff, c2 & 0xff, max_diff)
88 && compare_uint((c1 >> 8) & 0xff, (c2 >> 8) & 0xff, max_diff)
89 && compare_uint((c1 >> 16) & 0xff, (c2 >> 16) & 0xff, max_diff)
90 && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff);
93 static void get_virtual_rect(RECT *rect)
95 rect->left = GetSystemMetrics(SM_XVIRTUALSCREEN);
96 rect->top = GetSystemMetrics(SM_YVIRTUALSCREEN);
97 rect->right = rect->left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
98 rect->bottom = rect->top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
101 /* Try to make sure pending X events have been processed before continuing */
102 static void flush_events(void)
104 int diff = 200;
105 DWORD time;
106 MSG msg;
108 time = GetTickCount() + diff;
109 while (diff > 0)
111 if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT)
112 break;
113 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
114 DispatchMessageA(&msg);
115 diff = time - GetTickCount();
119 static BOOL ddraw_get_identifier(IDirectDraw2 *ddraw, DDDEVICEIDENTIFIER *identifier)
121 IDirectDraw4 *ddraw4;
122 HRESULT hr;
124 hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirectDraw4, (void **)&ddraw4);
125 ok(SUCCEEDED(hr), "Failed to get IDirectDraw4 interface, hr %#lx.\n", hr);
126 hr = IDirectDraw4_GetDeviceIdentifier(ddraw4, identifier, 0);
127 ok(SUCCEEDED(hr), "Failed to get device identifier, hr %#lx.\n", hr);
128 IDirectDraw4_Release(ddraw4);
130 return SUCCEEDED(hr);
133 static BOOL ddraw_is_warp(IDirectDraw2 *ddraw)
135 DDDEVICEIDENTIFIER identifier;
137 return strcmp(winetest_platform, "wine")
138 && ddraw_get_identifier(ddraw, &identifier)
139 && strstr(identifier.szDriver, "warp");
142 static BOOL ddraw_is_vendor(IDirectDraw2 *ddraw, DWORD vendor)
144 DDDEVICEIDENTIFIER identifier;
146 return strcmp(winetest_platform, "wine")
147 && ddraw_get_identifier(ddraw, &identifier)
148 && identifier.dwVendorId == vendor;
151 static BOOL ddraw_is_amd(IDirectDraw2 *ddraw)
153 return ddraw_is_vendor(ddraw, 0x1002);
156 static BOOL ddraw_is_intel(IDirectDraw2 *ddraw)
158 return ddraw_is_vendor(ddraw, 0x8086);
161 static BOOL ddraw_is_nvidia(IDirectDraw2 *ddraw)
163 return ddraw_is_vendor(ddraw, 0x10de);
166 static BOOL ddraw_is_vmware(IDirectDraw2 *ddraw)
168 return ddraw_is_vendor(ddraw, 0x15ad);
171 static BOOL is_software_device_type(const GUID *device_guid)
173 return device_guid != &IID_IDirect3DHALDevice;
176 static IDirectDrawSurface *create_overlay(IDirectDraw2 *ddraw,
177 unsigned int width, unsigned int height, DWORD format)
179 IDirectDrawSurface *surface;
180 DDSURFACEDESC desc;
182 memset(&desc, 0, sizeof(desc));
183 desc.dwSize = sizeof(desc);
184 desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
185 desc.dwWidth = width;
186 desc.dwHeight = height;
187 desc.ddsCaps.dwCaps = DDSCAPS_OVERLAY;
188 desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
189 desc.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
190 desc.ddpfPixelFormat.dwFourCC = format;
192 if (FAILED(IDirectDraw2_CreateSurface(ddraw, &desc, &surface, NULL)))
193 return NULL;
194 return surface;
197 static HWND create_window(void)
199 RECT r = {0, 0, 640, 480};
201 AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE);
203 return CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
204 CW_USEDEFAULT, CW_USEDEFAULT, r.right - r.left, r.bottom - r.top, NULL, NULL, NULL, NULL);
207 static DWORD WINAPI create_window_thread_proc(void *param)
209 struct create_window_thread_param *p = param;
210 DWORD res;
211 BOOL ret;
213 p->window = create_window();
214 ret = SetEvent(p->window_created);
215 ok(ret, "SetEvent failed, last error %lu.\n", GetLastError());
217 for (;;)
219 MSG msg;
221 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
222 DispatchMessageA(&msg);
223 res = WaitForSingleObject(p->destroy_window, 100);
224 if (res == WAIT_OBJECT_0)
225 break;
226 if (res != WAIT_TIMEOUT)
228 ok(0, "Wait failed (%#lx), last error %lu.\n", res, GetLastError());
229 break;
233 DestroyWindow(p->window);
235 return 0;
238 static void create_window_thread(struct create_window_thread_param *p)
240 DWORD res, tid;
242 p->window_created = CreateEventA(NULL, FALSE, FALSE, NULL);
243 ok(!!p->window_created, "CreateEvent failed, last error %lu.\n", GetLastError());
244 p->destroy_window = CreateEventA(NULL, FALSE, FALSE, NULL);
245 ok(!!p->destroy_window, "CreateEvent failed, last error %lu.\n", GetLastError());
246 p->thread = CreateThread(NULL, 0, create_window_thread_proc, p, 0, &tid);
247 ok(!!p->thread, "Failed to create thread, last error %lu.\n", GetLastError());
248 res = WaitForSingleObject(p->window_created, INFINITE);
249 ok(res == WAIT_OBJECT_0, "Wait failed (%#lx), last error %lu.\n", res, GetLastError());
252 static void destroy_window_thread(struct create_window_thread_param *p)
254 SetEvent(p->destroy_window);
255 WaitForSingleObject(p->thread, INFINITE);
256 CloseHandle(p->destroy_window);
257 CloseHandle(p->window_created);
258 CloseHandle(p->thread);
261 static IDirectDrawSurface *get_depth_stencil(IDirect3DDevice2 *device)
263 IDirectDrawSurface *rt, *ret;
264 DDSCAPS caps = {DDSCAPS_ZBUFFER};
265 HRESULT hr;
267 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
268 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
269 hr = IDirectDrawSurface_GetAttachedSurface(rt, &caps, &ret);
270 ok(SUCCEEDED(hr) || hr == DDERR_NOTFOUND, "Failed to get the z buffer, hr %#lx.\n", hr);
271 IDirectDrawSurface_Release(rt);
272 return ret;
275 /* Free original_modes after finished using it */
276 static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
278 unsigned int number, size = 2, count = 0, index = 0;
279 DISPLAY_DEVICEW display_device;
280 DEVMODEW *modes, *tmp;
282 if (!(modes = heap_alloc(size * sizeof(*modes))))
283 return FALSE;
285 display_device.cb = sizeof(display_device);
286 while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
288 /* Skip software devices */
289 if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
290 continue;
292 if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
293 continue;
295 if (count >= size)
297 size *= 2;
298 if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
300 heap_free(modes);
301 return FALSE;
303 modes = tmp;
306 memset(&modes[count], 0, sizeof(modes[count]));
307 modes[count].dmSize = sizeof(modes[count]);
308 if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
310 heap_free(modes);
311 return FALSE;
314 lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
317 *original_modes = modes;
318 *display_count = count;
319 return TRUE;
322 static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
324 unsigned int index;
325 LONG ret;
327 for (index = 0; index < count; ++index)
329 ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
330 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
331 if (ret != DISP_CHANGE_SUCCESSFUL)
332 return FALSE;
334 ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
335 return ret == DISP_CHANGE_SUCCESSFUL;
338 static HRESULT set_display_mode(IDirectDraw2 *ddraw, DWORD width, DWORD height)
340 if (SUCCEEDED(IDirectDraw2_SetDisplayMode(ddraw, width, height, 32, 0, 0)))
341 return DD_OK;
342 return IDirectDraw2_SetDisplayMode(ddraw, width, height, 24, 0, 0);
345 static D3DCOLOR get_surface_color(IDirectDrawSurface *surface, UINT x, UINT y)
347 RECT rect = {x, y, x + 1, y + 1};
348 DDSURFACEDESC surface_desc;
349 D3DCOLOR color;
350 HRESULT hr;
352 memset(&surface_desc, 0, sizeof(surface_desc));
353 surface_desc.dwSize = sizeof(surface_desc);
355 hr = IDirectDrawSurface_Lock(surface, &rect, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
356 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
357 if (FAILED(hr))
358 return 0xdeadbeef;
360 color = *((DWORD *)surface_desc.lpSurface) & 0x00ffffff;
362 hr = IDirectDrawSurface_Unlock(surface, NULL);
363 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
365 return color;
368 static void fill_surface(IDirectDrawSurface *surface, D3DCOLOR color)
370 DDSURFACEDESC surface_desc = {sizeof(surface_desc)};
371 HRESULT hr;
372 unsigned int x, y;
373 DWORD *ptr;
375 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
376 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
378 for (y = 0; y < surface_desc.dwHeight; ++y)
380 ptr = (DWORD *)((BYTE *)surface_desc.lpSurface + y * U1(surface_desc).lPitch);
381 for (x = 0; x < surface_desc.dwWidth; ++x)
383 ptr[x] = color;
387 hr = IDirectDrawSurface_Unlock(surface, NULL);
388 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
391 static void check_rect(IDirectDrawSurface *surface, RECT r)
393 LONG x_coords[2][2] =
395 {r.left - 1, r.left + 1},
396 {r.right + 1, r.right - 1},
398 LONG y_coords[2][2] =
400 {r.top - 1, r.top + 1},
401 {r.bottom + 1, r.bottom - 1}
403 unsigned int i, j, x_side, y_side, color;
404 LONG x, y;
406 for (i = 0; i < 2; ++i)
408 for (j = 0; j < 2; ++j)
410 for (x_side = 0; x_side < 2; ++x_side)
412 for (y_side = 0; y_side < 2; ++y_side)
414 unsigned int expected = (x_side == 1 && y_side == 1) ? 0x00ffffff : 0x00000000;
416 x = x_coords[i][x_side];
417 y = y_coords[j][y_side];
418 if (x < 0 || x >= 640 || y < 0 || y >= 480)
419 continue;
420 color = get_surface_color(surface, x, y);
421 ok(color == expected, "Pixel (%ld, %ld) has color %08x, expected %08x.\n", x, y, color, expected);
428 static DWORD get_device_z_depth(IDirect3DDevice2 *device)
430 DDSCAPS caps = {DDSCAPS_ZBUFFER};
431 IDirectDrawSurface *ds, *rt;
432 DDSURFACEDESC desc;
433 HRESULT hr;
435 if (FAILED(IDirect3DDevice2_GetRenderTarget(device, &rt)))
436 return 0;
438 hr = IDirectDrawSurface_GetAttachedSurface(rt, &caps, &ds);
439 IDirectDrawSurface_Release(rt);
440 if (FAILED(hr))
441 return 0;
443 desc.dwSize = sizeof(desc);
444 hr = IDirectDrawSurface_GetSurfaceDesc(ds, &desc);
445 IDirectDrawSurface_Release(ds);
446 if (FAILED(hr))
447 return 0;
449 return U2(desc).dwZBufferBitDepth;
452 static IDirectDraw2 *create_ddraw(void)
454 IDirectDraw2 *ddraw2;
455 IDirectDraw *ddraw1;
456 HRESULT hr;
458 if (FAILED(DirectDrawCreate(NULL, &ddraw1, NULL)))
459 return NULL;
461 hr = IDirectDraw_QueryInterface(ddraw1, &IID_IDirectDraw2, (void **)&ddraw2);
462 IDirectDraw_Release(ddraw1);
463 if (FAILED(hr))
464 return NULL;
466 return ddraw2;
469 static IDirect3DDevice2 *create_device_ex(IDirectDraw2 *ddraw, HWND window, DWORD coop_level, const GUID *device_guid)
471 /* Prefer 16 bit depth buffers because Nvidia gives us an unpadded D24 buffer if we ask
472 * for 24 bit and handles such buffers incorrectly in DDBLT_DEPTHFILL. AMD only supports
473 * 16 bit buffers in ddraw1/2. Stencil was added in ddraw4, so we cannot create a D24S8
474 * buffer here. */
475 static const DWORD z_depths[] = {16, 32, 24};
476 IDirectDrawSurface *surface, *ds;
477 IDirect3DDevice2 *device = NULL;
478 DDSURFACEDESC surface_desc;
479 IDirect3D2 *d3d;
480 unsigned int i;
481 HRESULT hr;
483 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, coop_level);
484 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
486 memset(&surface_desc, 0, sizeof(surface_desc));
487 surface_desc.dwSize = sizeof(surface_desc);
488 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
489 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
490 if (is_software_device_type(device_guid))
491 surface_desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
492 surface_desc.dwWidth = 640;
493 surface_desc.dwHeight = 480;
495 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
496 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
498 if (coop_level & DDSCL_NORMAL)
500 IDirectDrawClipper *clipper;
502 hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL);
503 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
504 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
505 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
506 hr = IDirectDrawSurface_SetClipper(surface, clipper);
507 ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#lx.\n", hr);
508 IDirectDrawClipper_Release(clipper);
511 hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
512 if (FAILED(hr))
514 IDirectDrawSurface_Release(surface);
515 return NULL;
518 /* We used to use EnumDevices() for this, but it seems
519 * D3DDEVICEDESC.dwDeviceZBufferBitDepth only has a very casual
520 * relationship with reality. */
521 for (i = 0; i < ARRAY_SIZE(z_depths); ++i)
523 memset(&surface_desc, 0, sizeof(surface_desc));
524 surface_desc.dwSize = sizeof(surface_desc);
525 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
526 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
527 if (is_software_device_type(device_guid))
528 surface_desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
529 U2(surface_desc).dwZBufferBitDepth = z_depths[i];
530 surface_desc.dwWidth = 640;
531 surface_desc.dwHeight = 480;
532 if (FAILED(IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL)))
533 continue;
535 hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
536 ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#lx.\n", hr);
537 IDirectDrawSurface_Release(ds);
538 if (FAILED(hr))
539 continue;
541 if (SUCCEEDED(IDirect3D2_CreateDevice(d3d, device_guid, surface, &device)))
542 break;
544 IDirectDrawSurface_DeleteAttachedSurface(surface, 0, ds);
547 IDirect3D2_Release(d3d);
548 IDirectDrawSurface_Release(surface);
549 return device;
552 static IDirect3DDevice2 *create_device(IDirectDraw2 *ddraw, HWND window, DWORD coop_level)
554 return create_device_ex(ddraw, window, coop_level, &IID_IDirect3DHALDevice);
557 static IDirect3DViewport2 *create_viewport(IDirect3DDevice2 *device, UINT x, UINT y, UINT w, UINT h)
559 IDirect3DViewport2 *viewport;
560 D3DVIEWPORT2 vp;
561 IDirect3D2 *d3d;
562 HRESULT hr;
564 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
565 ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#lx.\n", hr);
566 hr = IDirect3D2_CreateViewport(d3d, &viewport, NULL);
567 ok(SUCCEEDED(hr), "Failed to create viewport, hr %#lx.\n", hr);
568 hr = IDirect3DDevice2_AddViewport(device, viewport);
569 ok(SUCCEEDED(hr), "Failed to add viewport, hr %#lx.\n", hr);
570 memset(&vp, 0, sizeof(vp));
571 vp.dwSize = sizeof(vp);
572 vp.dwX = x;
573 vp.dwY = y;
574 vp.dwWidth = w;
575 vp.dwHeight = h;
576 vp.dvClipX = -1.0f;
577 vp.dvClipY = 1.0f;
578 vp.dvClipWidth = 2.0f;
579 vp.dvClipHeight = 2.0f;
580 vp.dvMinZ = 0.0f;
581 vp.dvMaxZ = 1.0f;
582 hr = IDirect3DViewport2_SetViewport2(viewport, &vp);
583 ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#lx.\n", hr);
584 IDirect3D2_Release(d3d);
586 return viewport;
589 static void viewport_set_background(IDirect3DDevice2 *device, IDirect3DViewport2 *viewport,
590 IDirect3DMaterial2 *material)
592 D3DMATERIALHANDLE material_handle;
593 HRESULT hr;
595 hr = IDirect3DMaterial2_GetHandle(material, device, &material_handle);
596 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#lx.\n", hr);
597 hr = IDirect3DViewport2_SetBackground(viewport, material_handle);
598 ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#lx.\n", hr);
601 static void destroy_viewport(IDirect3DDevice2 *device, IDirect3DViewport2 *viewport)
603 HRESULT hr;
605 hr = IDirect3DDevice2_DeleteViewport(device, viewport);
606 ok(SUCCEEDED(hr), "Failed to delete viewport, hr %#lx.\n", hr);
607 IDirect3DViewport2_Release(viewport);
610 static IDirect3DMaterial2 *create_material(IDirect3DDevice2 *device, D3DMATERIAL *mat)
612 IDirect3DMaterial2 *material;
613 IDirect3D2 *d3d;
614 HRESULT hr;
616 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
617 ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#lx.\n", hr);
618 hr = IDirect3D2_CreateMaterial(d3d, &material, NULL);
619 ok(SUCCEEDED(hr), "Failed to create material, hr %#lx.\n", hr);
620 hr = IDirect3DMaterial2_SetMaterial(material, mat);
621 ok(SUCCEEDED(hr), "Failed to set material data, hr %#lx.\n", hr);
622 IDirect3D2_Release(d3d);
624 return material;
627 static IDirect3DMaterial2 *create_diffuse_material(IDirect3DDevice2 *device, float r, float g, float b, float a)
629 D3DMATERIAL mat;
631 memset(&mat, 0, sizeof(mat));
632 mat.dwSize = sizeof(mat);
633 U1(U(mat).diffuse).r = r;
634 U2(U(mat).diffuse).g = g;
635 U3(U(mat).diffuse).b = b;
636 U4(U(mat).diffuse).a = a;
638 return create_material(device, &mat);
641 static IDirect3DMaterial2 *create_diffuse_and_ambient_material(IDirect3DDevice2 *device,
642 float r, float g, float b, float a)
644 D3DMATERIAL mat;
646 memset(&mat, 0, sizeof(mat));
647 mat.dwSize = sizeof(mat);
648 U1(U(mat).diffuse).r = r;
649 U2(U(mat).diffuse).g = g;
650 U3(U(mat).diffuse).b = b;
651 U4(U(mat).diffuse).a = a;
653 U1(U(mat).ambient).r = r;
654 U2(U(mat).ambient).g = g;
655 U3(U(mat).ambient).b = b;
656 U4(U(mat).ambient).a = a;
658 return create_material(device, &mat);
661 static IDirect3DMaterial2 *create_specular_material(IDirect3DDevice2 *device,
662 float r, float g, float b, float a, float power)
664 D3DMATERIAL mat;
666 memset(&mat, 0, sizeof(mat));
667 mat.dwSize = sizeof(mat);
668 U1(U2(mat).specular).r = r;
669 U2(U2(mat).specular).g = g;
670 U3(U2(mat).specular).b = b;
671 U4(U2(mat).specular).a = a;
672 U4(mat).power = power;
674 return create_material(device, &mat);
677 static IDirect3DMaterial2 *create_emissive_material(IDirect3DDevice2 *device, float r, float g, float b, float a)
679 D3DMATERIAL mat;
681 memset(&mat, 0, sizeof(mat));
682 mat.dwSize = sizeof(mat);
683 U1(U3(mat).emissive).r = r;
684 U2(U3(mat).emissive).g = g;
685 U3(U3(mat).emissive).b = b;
686 U4(U3(mat).emissive).a = a;
688 return create_material(device, &mat);
691 static void destroy_material(IDirect3DMaterial2 *material)
693 IDirect3DMaterial2_Release(material);
696 struct message
698 UINT message;
699 BOOL check_wparam;
700 WPARAM expect_wparam;
703 static const struct message *expect_messages;
705 static LRESULT CALLBACK test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
707 if (expect_messages && message == expect_messages->message)
709 if (expect_messages->check_wparam)
710 ok (wparam == expect_messages->expect_wparam,
711 "Got unexpected wparam %#Ix for message %#x, expected %#Ix.\n",
712 wparam, message, expect_messages->expect_wparam);
714 ++expect_messages;
717 return DefWindowProcA(hwnd, message, wparam, lparam);
720 /* Set the wndproc back to what ddraw expects it to be, and release the ddraw
721 * interface. This prevents subsequent SetCooperativeLevel() calls on a
722 * different window from failing with DDERR_HWNDALREADYSET. */
723 static void fix_wndproc(HWND window, LONG_PTR proc)
725 IDirectDraw2 *ddraw;
726 HRESULT hr;
728 if (!(ddraw = create_ddraw()))
729 return;
731 SetWindowLongPtrA(window, GWLP_WNDPROC, proc);
732 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
733 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
734 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
735 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
737 IDirectDraw2_Release(ddraw);
740 static HRESULT CALLBACK restore_callback(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
742 HRESULT hr = IDirectDrawSurface_Restore(surface);
743 ok(SUCCEEDED(hr) || hr == DDERR_IMPLICITLYCREATED, "Failed to restore surface, hr %#lx.\n", hr);
744 IDirectDrawSurface_Release(surface);
746 return DDENUMRET_OK;
749 static HRESULT restore_surfaces(IDirectDraw2 *ddraw)
751 return IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_ALL | DDENUMSURFACES_DOESEXIST,
752 NULL, NULL, restore_callback);
755 static void test_coop_level_create_device_window(void)
757 HWND focus_window, device_window;
758 IDirectDraw2 *ddraw;
759 HRESULT hr;
761 focus_window = create_window();
762 ddraw = create_ddraw();
763 ok(!!ddraw, "Failed to create a ddraw object.\n");
765 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
766 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
767 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
768 ok(!device_window, "Unexpected device window found.\n");
769 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW);
770 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
771 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
772 ok(!device_window, "Unexpected device window found.\n");
773 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL);
774 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
775 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
776 ok(!device_window, "Unexpected device window found.\n");
777 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL | DDSCL_FULLSCREEN);
778 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
779 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
780 ok(!device_window, "Unexpected device window found.\n");
781 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
782 ok(hr == DDERR_NOFOCUSWINDOW || broken(hr == DDERR_INVALIDPARAMS), "Got unexpected hr %#lx.\n", hr);
783 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
784 ok(!device_window, "Unexpected device window found.\n");
786 /* Windows versions before 98 / NT5 don't support DDSCL_CREATEDEVICEWINDOW. */
787 if (broken(hr == DDERR_INVALIDPARAMS))
789 win_skip("DDSCL_CREATEDEVICEWINDOW not supported, skipping test.\n");
790 IDirectDraw2_Release(ddraw);
791 DestroyWindow(focus_window);
792 return;
795 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
796 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
797 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
798 ok(!device_window, "Unexpected device window found.\n");
799 hr = IDirectDraw2_SetCooperativeLevel(ddraw, focus_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
800 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
801 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
802 ok(!device_window, "Unexpected device window found.\n");
804 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
805 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
806 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
807 ok(!device_window, "Unexpected device window found.\n");
808 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_SETFOCUSWINDOW
809 | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
810 ok(hr == DDERR_NOHWND, "Got unexpected hr %#lx.\n", hr);
811 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
812 ok(!!device_window, "Device window not found.\n");
814 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
815 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
816 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
817 ok(!device_window, "Unexpected device window found.\n");
818 hr = IDirectDraw2_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW
819 | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
820 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
821 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
822 ok(!!device_window, "Device window not found.\n");
824 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
825 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
826 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
827 ok(!device_window, "Unexpected device window found.\n");
828 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
829 ok(hr == DDERR_NOFOCUSWINDOW, "Got unexpected hr %#lx.\n", hr);
830 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
831 ok(!device_window, "Unexpected device window found.\n");
832 hr = IDirectDraw2_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW);
833 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
834 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
835 ok(!device_window, "Unexpected device window found.\n");
836 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
837 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
838 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
839 ok(!!device_window, "Device window not found.\n");
841 IDirectDraw2_Release(ddraw);
842 DestroyWindow(focus_window);
845 static void test_clipper_blt(void)
847 IDirectDrawSurface *src_surface, *dst_surface;
848 unsigned int color, i, j, x, y;
849 RECT client_rect, src_rect;
850 IDirectDrawClipper *clipper;
851 DDSURFACEDESC surface_desc;
852 IDirectDraw2 *ddraw;
853 RGNDATA *rgn_data;
854 ULONG refcount;
855 HRGN r1, r2;
856 HWND window;
857 DDBLTFX fx;
858 HRESULT hr;
859 DWORD *ptr;
860 DWORD ret;
862 static const DWORD src_data[] =
864 0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
865 0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
866 0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
868 static const unsigned int expected1[] =
870 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
871 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
872 0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
873 0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
875 /* Nvidia on Windows seems to have an off-by-one error
876 * when processing source rectangles. Our left = 1 and
877 * right = 5 input reads from x = {1, 2, 3}. x = 4 is
878 * read as well, but only for the edge pixels on the
879 * output image. The bug happens on the y axis as well,
880 * but we only read one row there, and all source rows
881 * contain the same data. This bug is not dependent on
882 * the presence of a clipper. */
883 static const D3DCOLOR expected1_broken[] =
885 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
886 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
887 0x00000000, 0x00000000, 0x00ff0000, 0x00ff0000,
888 0x00000000, 0x00000000, 0x0000ff00, 0x00ff0000,
890 static const unsigned int expected2[] =
892 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
893 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
894 0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
895 0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
898 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
899 10, 10, 640, 480, 0, 0, 0, 0);
900 ShowWindow(window, SW_SHOW);
901 ddraw = create_ddraw();
902 ok(!!ddraw, "Failed to create a ddraw object.\n");
904 ret = GetClientRect(window, &client_rect);
905 ok(ret, "Failed to get client rect.\n");
906 ret = MapWindowPoints(window, NULL, (POINT *)&client_rect, 2);
907 ok(ret, "Failed to map client rect.\n");
909 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
910 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
912 hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL);
913 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
914 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
915 ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#lx.\n", hr);
916 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
917 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
918 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
919 ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#lx.\n", hr);
920 rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
921 hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret);
922 ok(SUCCEEDED(hr), "Failed to get clip list, hr %#lx.\n", hr);
923 ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#lx.\n", rgn_data->rdh.dwSize);
924 ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#lx.\n", rgn_data->rdh.iType);
925 ok(rgn_data->rdh.nCount >= 1, "Got unexpected count %lu.\n", rgn_data->rdh.nCount);
926 ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
927 "Got unexpected bounding rect %s, expected %s.\n",
928 wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&client_rect));
929 HeapFree(GetProcessHeap(), 0, rgn_data);
931 r1 = CreateRectRgn(0, 0, 320, 240);
932 ok(!!r1, "Failed to create region.\n");
933 r2 = CreateRectRgn(320, 240, 640, 480);
934 ok(!!r2, "Failed to create region.\n");
935 CombineRgn(r1, r1, r2, RGN_OR);
936 ret = GetRegionData(r1, 0, NULL);
937 rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
938 ret = GetRegionData(r1, ret, rgn_data);
939 ok(!!ret, "Failed to get region data.\n");
941 DeleteObject(r2);
942 DeleteObject(r1);
944 hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
945 ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#lx.\n", hr);
946 hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
947 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
948 hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
949 ok(SUCCEEDED(hr), "Failed to set clip list, hr %#lx.\n", hr);
951 HeapFree(GetProcessHeap(), 0, rgn_data);
953 memset(&surface_desc, 0, sizeof(surface_desc));
954 surface_desc.dwSize = sizeof(surface_desc);
955 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
956 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
957 surface_desc.dwWidth = 640;
958 surface_desc.dwHeight = 480;
959 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
960 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
961 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
962 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
963 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
964 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
966 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
967 ok(SUCCEEDED(hr), "Failed to create source surface, hr %#lx.\n", hr);
968 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
969 ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#lx.\n", hr);
971 memset(&fx, 0, sizeof(fx));
972 fx.dwSize = sizeof(fx);
973 hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
974 ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#lx.\n", hr);
975 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
976 ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#lx.\n", hr);
978 hr = IDirectDrawSurface_Lock(src_surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
979 ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#lx.\n", hr);
980 ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %lu.\n", U1(surface_desc).lPitch);
981 ptr = surface_desc.lpSurface;
982 memcpy(&ptr[ 0], &src_data[ 0], 6 * sizeof(DWORD));
983 memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
984 memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
985 hr = IDirectDrawSurface_Unlock(src_surface, NULL);
986 ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#lx.\n", hr);
988 hr = IDirectDrawSurface_SetClipper(dst_surface, clipper);
989 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
991 SetRect(&src_rect, 1, 1, 5, 2);
992 hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
993 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
994 for (i = 0; i < 4; ++i)
996 for (j = 0; j < 4; ++j)
998 x = 80 * ((2 * j) + 1);
999 y = 60 * ((2 * i) + 1);
1000 color = get_surface_color(dst_surface, x, y);
1001 ok(compare_color(color, expected1[i * 4 + j], 1)
1002 || broken(compare_color(color, expected1_broken[i * 4 + j], 1)),
1003 "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
1007 U5(fx).dwFillColor = 0xff0000ff;
1008 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1009 ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#lx.\n", hr);
1010 for (i = 0; i < 4; ++i)
1012 for (j = 0; j < 4; ++j)
1014 x = 80 * ((2 * j) + 1);
1015 y = 60 * ((2 * i) + 1);
1016 color = get_surface_color(dst_surface, x, y);
1017 ok(compare_color(color, expected2[i * 4 + j], 1),
1018 "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
1022 hr = IDirectDrawSurface_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
1023 ok(hr == DDERR_BLTFASTCANTCLIP || broken(hr == E_NOTIMPL /* NT4 */), "Got unexpected hr %#lx.\n", hr);
1025 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
1026 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
1027 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
1028 ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#lx.\n", hr);
1029 DestroyWindow(window);
1030 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
1031 ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr);
1032 hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
1033 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
1034 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
1035 ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#lx.\n", hr);
1036 hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
1037 ok(SUCCEEDED(hr), "Failed to set clip list, hr %#lx.\n", hr);
1038 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
1039 ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#lx.\n", hr);
1040 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1041 ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#lx.\n", hr);
1043 IDirectDrawSurface_Release(dst_surface);
1044 IDirectDrawSurface_Release(src_surface);
1045 refcount = IDirectDrawClipper_Release(clipper);
1046 ok(!refcount, "Clipper has %lu references left.\n", refcount);
1047 IDirectDraw2_Release(ddraw);
1050 static void test_coop_level_d3d_state(void)
1052 D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1053 IDirectDrawSurface *rt, *surface;
1054 IDirect3DMaterial2 *background;
1055 IDirect3DViewport2 *viewport;
1056 IDirect3DDevice2 *device;
1057 D3DMATERIAL material;
1058 IDirectDraw2 *ddraw;
1059 DDSURFACEDESC lock;
1060 unsigned int color;
1061 DWORD value;
1062 HWND window;
1063 HRESULT hr;
1065 static D3DLVERTEX quad[] =
1067 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0x800000ff}},
1068 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0x800000ff}},
1069 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0x800000ff}},
1070 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0x800000ff}},
1073 window = create_window();
1074 ddraw = create_ddraw();
1075 ok(!!ddraw, "Failed to create a ddraw object.\n");
1077 if (ddraw_is_warp(ddraw))
1079 /* ddraw2 crashes in EndScene, and if it doesn't crash it fails with
1080 * DDERR_SURFACELOST on WARP. */
1081 win_skip("Skipping test that crashes WARP occasionally.\n");
1082 IDirectDraw2_Release(ddraw);
1083 DestroyWindow(window);
1084 return;
1087 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1089 skip("Failed to create a 3D device, skipping test.\n");
1090 IDirectDraw2_Release(ddraw);
1091 DestroyWindow(window);
1092 return;
1095 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1096 viewport = create_viewport(device, 0, 0, 640, 480);
1097 viewport_set_background(device, viewport, background);
1099 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
1100 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1101 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_DESTALPHA);
1102 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1104 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1105 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1106 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
1107 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1108 ok(!!value, "Got unexpected z-enable state %#lx.\n", value);
1109 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
1110 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1111 ok(!value, "Got unexpected alpha blend enable state %#lx.\n", value);
1112 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
1113 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1114 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1115 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1116 color = get_surface_color(rt, 320, 240);
1117 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
1119 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1120 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1121 hr = IDirectDrawSurface_IsLost(rt);
1122 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
1124 memset(&lock, 0, sizeof(lock));
1125 lock.dwSize = sizeof(lock);
1126 lock.lpSurface = (void *)0xdeadbeef;
1127 hr = IDirectDrawSurface2_Lock(rt, NULL, &lock, DDLOCK_READONLY, NULL);
1128 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
1129 ok(lock.lpSurface == (void *)0xdeadbeef, "Got unexpected lock.lpSurface %p.\n", lock.lpSurface);
1131 hr = restore_surfaces(ddraw);
1132 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1134 hr = IDirectDrawSurface2_Lock(rt, NULL, &lock, DDLOCK_READONLY, NULL);
1135 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1136 hr = IDirectDrawSurface2_Unlock(rt, NULL);
1137 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1139 memset(&material, 0, sizeof(material));
1140 material.dwSize = sizeof(material);
1141 U1(U(material).diffuse).r = 0.0f;
1142 U2(U(material).diffuse).g = 1.0f;
1143 U3(U(material).diffuse).b = 0.0f;
1144 U4(U(material).diffuse).a = 1.0f;
1145 hr = IDirect3DMaterial2_SetMaterial(background, &material);
1146 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1148 hr = IDirect3DDevice2_GetRenderTarget(device, &surface);
1149 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1150 ok(surface == rt, "Got unexpected surface %p.\n", surface);
1151 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
1152 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1153 ok(!!value, "Got unexpected z-enable state %#lx.\n", value);
1154 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
1155 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1156 ok(!!value, "Got unexpected alpha blend enable state %#lx.\n", value);
1157 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
1158 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1159 color = get_surface_color(rt, 320, 240);
1160 ok(compare_color(color, 0x0000ff00, 1) || broken(compare_color(color, 0x00000000, 1)),
1161 "Got unexpected color 0x%08x.\n", color);
1163 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1164 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1165 hr = IDirect3DDevice2_BeginScene(device);
1166 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1167 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad, ARRAY_SIZE(quad), 0);
1168 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1169 hr = IDirect3DDevice2_EndScene(device);
1170 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1171 color = get_surface_color(rt, 320, 240);
1172 ok(compare_color(color, 0x0000ff80, 1), "Got unexpected color 0x%08x.\n", color);
1174 destroy_viewport(device, viewport);
1175 destroy_material(background);
1176 IDirectDrawSurface_Release(surface);
1177 IDirectDrawSurface_Release(rt);
1178 IDirect3DDevice2_Release(device);
1179 IDirectDraw2_Release(ddraw);
1180 DestroyWindow(window);
1183 static void test_surface_interface_mismatch(void)
1185 IDirectDraw2 *ddraw = NULL;
1186 IDirect3D2 *d3d = NULL;
1187 IDirectDrawSurface *surface = NULL, *ds;
1188 IDirectDrawSurface3 *surface3 = NULL;
1189 IDirect3DDevice2 *device = NULL;
1190 IDirect3DViewport2 *viewport = NULL;
1191 IDirect3DMaterial2 *background = NULL;
1192 DDSURFACEDESC surface_desc;
1193 unsigned int color;
1194 DWORD z_depth = 0;
1195 ULONG refcount;
1196 HRESULT hr;
1197 HWND window;
1198 D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1200 window = create_window();
1201 ddraw = create_ddraw();
1202 ok(!!ddraw, "Failed to create a ddraw object.\n");
1203 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1205 skip("Failed to create a 3D device, skipping test.\n");
1206 IDirectDraw2_Release(ddraw);
1207 DestroyWindow(window);
1208 return;
1210 z_depth = get_device_z_depth(device);
1211 ok(!!z_depth, "Failed to get device z depth.\n");
1212 IDirect3DDevice2_Release(device);
1213 device = NULL;
1215 memset(&surface_desc, 0, sizeof(surface_desc));
1216 surface_desc.dwSize = sizeof(surface_desc);
1217 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1218 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
1219 surface_desc.dwWidth = 640;
1220 surface_desc.dwHeight = 480;
1222 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1223 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
1225 hr = IDirectDrawSurface2_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
1226 if (FAILED(hr))
1228 skip("Failed to get the IDirectDrawSurface3 interface, skipping test.\n");
1229 goto cleanup;
1232 if (FAILED(IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d)))
1234 skip("D3D interface is not available, skipping test.\n");
1235 goto cleanup;
1238 memset(&surface_desc, 0, sizeof(surface_desc));
1239 surface_desc.dwSize = sizeof(surface_desc);
1240 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
1241 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
1242 U2(surface_desc).dwZBufferBitDepth = z_depth;
1243 surface_desc.dwWidth = 640;
1244 surface_desc.dwHeight = 480;
1245 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL);
1246 ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#lx.\n", hr);
1247 if (FAILED(hr))
1248 goto cleanup;
1250 /* Using a different surface interface version still works */
1251 hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
1252 ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#lx.\n", hr);
1253 refcount = IDirectDrawSurface_Release(ds);
1254 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
1255 if (FAILED(hr))
1256 goto cleanup;
1258 /* Here too */
1259 hr = IDirect3D2_CreateDevice(d3d, &IID_IDirect3DHALDevice, (IDirectDrawSurface *)surface3, &device);
1260 ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
1261 if (FAILED(hr))
1262 goto cleanup;
1264 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1265 viewport = create_viewport(device, 0, 0, 640, 480);
1266 viewport_set_background(device, viewport, background);
1268 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1269 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
1270 color = get_surface_color(surface, 320, 240);
1271 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
1273 cleanup:
1274 if (viewport)
1275 destroy_viewport(device, viewport);
1276 if (background)
1277 destroy_material(background);
1278 if (surface3) IDirectDrawSurface3_Release(surface3);
1279 if (surface) IDirectDrawSurface_Release(surface);
1280 if (device) IDirect3DDevice2_Release(device);
1281 if (d3d) IDirect3D2_Release(d3d);
1282 if (ddraw) IDirectDraw2_Release(ddraw);
1283 DestroyWindow(window);
1286 static void test_coop_level_threaded(void)
1288 struct create_window_thread_param p;
1289 IDirectDraw2 *ddraw;
1290 HRESULT hr;
1292 ddraw = create_ddraw();
1293 ok(!!ddraw, "Failed to create a ddraw object.\n");
1294 create_window_thread(&p);
1296 hr = IDirectDraw2_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1297 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
1299 destroy_window_thread(&p);
1300 IDirectDraw2_Release(ddraw);
1303 static void test_depth_blit(const GUID *device_guid)
1305 static D3DLVERTEX quad1[] =
1307 {{-1.0}, { 1.0}, {0.50f}, 0, {0xff00ff00}},
1308 {{ 1.0}, { 1.0}, {0.50f}, 0, {0xff00ff00}},
1309 {{-1.0}, {-1.0}, {0.50f}, 0, {0xff00ff00}},
1310 {{ 1.0}, {-1.0}, {0.50f}, 0, {0xff00ff00}},
1312 static const unsigned int expected_colors[4][4] =
1314 {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
1315 {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
1316 {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1317 {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1319 DDSURFACEDESC ddsd_new, ddsd_existing;
1321 IDirect3DDevice2 *device;
1322 IDirectDrawSurface *ds1, *ds2, *ds3, *rt;
1323 BOOL depth_fill_broken = FALSE;
1324 IDirect3DViewport2 *viewport;
1325 RECT src_rect, dst_rect;
1326 unsigned int color, i, j;
1327 HRESULT hr;
1328 IDirectDraw2 *ddraw;
1329 DDBLTFX fx;
1330 HWND window;
1331 D3DRECT d3drect;
1332 IDirect3DMaterial2 *background;
1334 window = create_window();
1335 ddraw = create_ddraw();
1336 ok(!!ddraw, "Failed to create a ddraw object.\n");
1337 if (!(device = create_device_ex(ddraw, window, DDSCL_NORMAL, device_guid)))
1339 skip("Failed to create a 3D device, skipping test.\n");
1340 IDirectDraw2_Release(ddraw);
1341 DestroyWindow(window);
1342 return;
1345 ds1 = get_depth_stencil(device);
1347 memset(&ddsd_new, 0, sizeof(ddsd_new));
1348 ddsd_new.dwSize = sizeof(ddsd_new);
1349 memset(&ddsd_existing, 0, sizeof(ddsd_existing));
1350 ddsd_existing.dwSize = sizeof(ddsd_existing);
1351 hr = IDirectDrawSurface_GetSurfaceDesc(ds1, &ddsd_existing);
1352 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1353 ddsd_new.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
1354 ddsd_new.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
1355 if (is_software_device_type(device_guid))
1356 ddsd_new.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
1357 ddsd_new.dwWidth = ddsd_existing.dwWidth;
1358 ddsd_new.dwHeight = ddsd_existing.dwHeight;
1359 ddsd_new.ddpfPixelFormat = ddsd_existing.ddpfPixelFormat;
1360 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd_new, &ds2, NULL);
1361 ok(SUCCEEDED(hr), "Failed to create a surface, hr %#lx.\n", hr);
1362 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd_new, &ds3, NULL);
1363 ok(SUCCEEDED(hr), "Failed to create a surface, hr %#lx.\n", hr);
1365 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1366 viewport = create_viewport(device, 0, 0, ddsd_existing.dwWidth, ddsd_existing.dwHeight);
1367 viewport_set_background(device, viewport, background);
1368 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1369 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#lx.\n", hr);
1371 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_TRUE);
1372 ok(SUCCEEDED(hr), "Failed to enable z testing, hr %#lx.\n", hr);
1373 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
1374 ok(SUCCEEDED(hr), "Failed to set the z function, hr %#lx.\n", hr);
1376 U1(d3drect).x1 = U2(d3drect).y1 = 0;
1377 U3(d3drect).x2 = ddsd_existing.dwWidth; U4(d3drect).y2 = ddsd_existing.dwHeight;
1378 hr = IDirect3DViewport2_Clear(viewport, 1, &d3drect, D3DCLEAR_ZBUFFER);
1379 ok(SUCCEEDED(hr), "Failed to clear the z buffer, hr %#lx.\n", hr);
1381 /* Partial blit. */
1382 SetRect(&src_rect, 0, 0, 320, 240);
1383 SetRect(&dst_rect, 0, 0, 320, 240);
1384 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1385 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1386 /* Different locations. */
1387 SetRect(&src_rect, 0, 0, 320, 240);
1388 SetRect(&dst_rect, 320, 240, 640, 480);
1389 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1390 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1391 /* Stretched. */
1392 SetRect(&src_rect, 0, 0, 320, 240);
1393 SetRect(&dst_rect, 0, 0, 640, 480);
1394 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1395 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1396 /* Flipped. */
1397 SetRect(&src_rect, 0, 480, 640, 0);
1398 SetRect(&dst_rect, 0, 0, 640, 480);
1399 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1400 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
1401 SetRect(&src_rect, 0, 0, 640, 480);
1402 SetRect(&dst_rect, 0, 480, 640, 0);
1403 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1404 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
1405 /* Full, explicit. */
1406 SetRect(&src_rect, 0, 0, 640, 480);
1407 SetRect(&dst_rect, 0, 0, 640, 480);
1408 hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1409 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1410 /* Depth -> color blit: Succeeds on Win7 + Radeon HD 5700, fails on WinXP + Radeon X1600 */
1412 /* Depth blit inside a BeginScene / EndScene pair */
1413 hr = IDirect3DDevice2_BeginScene(device);
1414 ok(SUCCEEDED(hr), "Failed to start a scene, hr %#lx.\n", hr);
1415 /* From the current depth stencil */
1416 hr = IDirectDrawSurface_Blt(ds2, NULL, ds1, NULL, DDBLT_WAIT, NULL);
1417 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1418 /* To the current depth stencil */
1419 hr = IDirectDrawSurface_Blt(ds1, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1420 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1421 /* Between unbound surfaces */
1422 hr = IDirectDrawSurface_Blt(ds3, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1423 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1424 hr = IDirect3DDevice2_EndScene(device);
1425 ok(SUCCEEDED(hr), "Failed to end a scene, hr %#lx.\n", hr);
1427 /* Avoid changing the depth stencil, it doesn't work properly on Windows.
1428 * Instead use DDBLT_DEPTHFILL to clear the depth stencil. Unfortunately
1429 * drivers disagree on the meaning of dwFillDepth. Only 0 seems to produce
1430 * a reliable result(z = 0.0) */
1431 memset(&fx, 0, sizeof(fx));
1432 fx.dwSize = sizeof(fx);
1433 U5(fx).dwFillDepth = 0;
1434 hr = IDirectDrawSurface_Blt(ds2, NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
1435 ok(hr == D3D_OK || broken(is_software_device_type(device_guid)
1436 && hr == 0x8876086c /* D3DERR_INVALIDCALL */), "Got unexpected hr %#lx.\n", hr);
1437 if (hr != D3D_OK)
1438 depth_fill_broken = TRUE;
1440 /* This clears the Z buffer with 1.0 */
1441 hr = IDirect3DViewport2_Clear(viewport, 1, &d3drect, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET);
1442 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1444 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1445 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1447 color = get_surface_color(rt, 80, 60);
1448 /* For some reason clears and colour fill blits randomly fail with software render target. */
1449 ok(color == 0x00ff0000 || broken(is_software_device_type(device_guid) && !color),
1450 "Got unexpected colour 0x%08x.\n", color);
1451 if (!color)
1453 fill_surface(rt, 0xffff0000);
1455 color = get_surface_color(rt, 80, 60);
1456 ok(color == 0x00ff0000, "Got unexpected colour 0x%08x.\n", color);
1459 SetRect(&dst_rect, 0, 0, 320, 240);
1460 hr = IDirectDrawSurface_Blt(ds1, &dst_rect, ds2, NULL, DDBLT_WAIT, NULL);
1461 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1462 IDirectDrawSurface_Release(ds3);
1463 IDirectDrawSurface_Release(ds2);
1464 IDirectDrawSurface_Release(ds1);
1466 hr = IDirect3DDevice2_BeginScene(device);
1467 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1468 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad1, 4, 0);
1469 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1470 hr = IDirect3DDevice2_EndScene(device);
1471 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1473 for (i = 0; i < 4; ++i)
1475 for (j = 0; j < 4; ++j)
1477 unsigned int x = 80 * ((2 * j) + 1);
1478 unsigned int y = 60 * ((2 * i) + 1);
1479 color = get_surface_color(rt, x, y);
1480 ok(compare_color(color, expected_colors[i][j], 1) || broken(depth_fill_broken && color == 0x0000ff00),
1481 "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected_colors[i][j], x, y, color);
1484 IDirectDrawSurface_Release(rt);
1486 destroy_viewport(device, viewport);
1487 destroy_material(background);
1488 IDirect3DDevice2_Release(device);
1489 IDirectDraw2_Release(ddraw);
1490 DestroyWindow(window);
1493 static void test_texture_load_ckey(void)
1495 IDirectDraw2 *ddraw = NULL;
1496 IDirectDrawSurface *src = NULL;
1497 IDirectDrawSurface *dst = NULL;
1498 IDirect3DTexture *src_tex = NULL;
1499 IDirect3DTexture *dst_tex = NULL;
1500 DDSURFACEDESC ddsd;
1501 HRESULT hr;
1502 DDCOLORKEY ckey;
1504 ddraw = create_ddraw();
1505 ok(!!ddraw, "Failed to create a ddraw object.\n");
1506 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
1507 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
1509 memset(&ddsd, 0, sizeof(ddsd));
1510 ddsd.dwSize = sizeof(ddsd);
1511 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1512 ddsd.dwHeight = 128;
1513 ddsd.dwWidth = 128;
1514 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
1515 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &src, NULL);
1516 ok(SUCCEEDED(hr), "Failed to create source texture, hr %#lx.\n", hr);
1517 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1518 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &dst, NULL);
1519 ok(SUCCEEDED(hr), "Failed to create destination texture, hr %#lx.\n", hr);
1521 hr = IDirectDrawSurface_QueryInterface(src, &IID_IDirect3DTexture, (void **)&src_tex);
1522 ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to get Direct3DTexture interface, hr %#lx.\n", hr);
1523 if (FAILED(hr))
1525 /* 64 bit ddraw does not support d3d */
1526 skip("Could not get Direct3DTexture interface, skipping texture::Load color keying tests.\n");
1527 goto done;
1529 hr = IDirectDrawSurface_QueryInterface(dst, &IID_IDirect3DTexture, (void **)&dst_tex);
1530 ok(SUCCEEDED(hr), "Failed to get Direct3DTexture interface, hr %#lx.\n", hr);
1532 /* No surface has a color key */
1533 hr = IDirect3DTexture_Load(dst_tex, src_tex);
1534 ok(SUCCEEDED(hr) || broken(hr == DDERR_INVALIDCAPS), "Got unexpected hr %#lx.\n", hr);
1535 if (FAILED(hr))
1537 /* Testbot Windows NT VMs */
1538 skip("IDirect3DTexture::Load does not work, skipping color keying tests.\n");
1539 goto done;
1542 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0xdeadbeef;
1543 hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1544 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx.\n", hr);
1545 ok(ckey.dwColorSpaceLowValue == 0xdeadbeef, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceLowValue);
1546 ok(ckey.dwColorSpaceHighValue == 0xdeadbeef, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceHighValue);
1548 /* Source surface has a color key */
1549 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
1550 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
1551 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
1552 hr = IDirect3DTexture_Load(dst_tex, src_tex);
1553 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1554 hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1555 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1556 ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceLowValue);
1557 ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceHighValue);
1559 /* Both surfaces have a color key: Dest ckey is overwritten */
1560 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x000000ff;
1561 hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1562 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
1563 hr = IDirect3DTexture_Load(dst_tex, src_tex);
1564 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1565 hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1566 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1567 ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceLowValue);
1568 ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceHighValue);
1570 /* Only the destination has a color key: It is not deleted */
1571 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, NULL);
1572 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
1573 hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
1574 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx.\n", hr);
1575 hr = IDirect3DTexture_Load(dst_tex, src_tex);
1576 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1577 hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1578 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
1579 ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceLowValue);
1580 ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceHighValue);
1582 done:
1583 if (dst_tex) IDirect3DTexture_Release(dst_tex);
1584 if (src_tex) IDirect3DTexture_Release(src_tex);
1585 if (dst) IDirectDrawSurface_Release(dst);
1586 if (src) IDirectDrawSurface_Release(src);
1587 if (ddraw) IDirectDraw2_Release(ddraw);
1590 static BOOL compare_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
1592 return mode1->dmPosition.x == mode2->dmPosition.x
1593 && mode1->dmPosition.y == mode2->dmPosition.y
1594 && mode1->dmPelsWidth == mode2->dmPelsWidth
1595 && mode1->dmPelsHeight == mode2->dmPelsHeight;
1598 static ULONG get_refcount(IUnknown *test_iface)
1600 IUnknown_AddRef(test_iface);
1601 return IUnknown_Release(test_iface);
1604 static void test_viewport_object(void)
1606 IDirectDraw2 *ddraw;
1607 IDirect3D2 *d3d;
1608 HRESULT hr;
1609 ULONG ref, old_d3d_ref;
1610 D3DVIEWPORT vp;
1611 D3DVIEWPORT2 vp2;
1612 IDirect3DViewport *viewport;
1613 IDirect3DViewport2 *viewport2, *another_vp, *test_vp;
1614 IDirect3DViewport3 *viewport3;
1615 IDirectDrawGammaControl *gamma;
1616 IUnknown *unknown;
1617 IDirect3DDevice2 *device;
1618 HWND window;
1619 union
1621 D3DVIEWPORT2 vp2;
1622 D3DVIEWPORT vp1;
1623 BYTE blob[1024];
1624 } desc;
1626 window = create_window();
1627 ddraw = create_ddraw();
1628 ok(!!ddraw, "Failed to create a ddraw object.\n");
1629 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1631 skip("Failed to create a 3D device, skipping test.\n");
1632 IDirectDraw2_Release(ddraw);
1633 DestroyWindow(window);
1634 return;
1637 hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
1638 ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to get d3d interface, hr %#lx.\n", hr);
1639 if (FAILED(hr))
1641 skip("D3D interface is not available, skipping test.\n");
1642 IDirectDraw2_Release(ddraw);
1643 return;
1645 old_d3d_ref = get_refcount((IUnknown *)d3d);
1647 hr = IDirect3D2_CreateViewport(d3d, &viewport2, NULL);
1648 ok(SUCCEEDED(hr), "Failed to create viewport, hr %#lx.\n", hr);
1649 ref = get_refcount((IUnknown *)viewport2);
1650 ok(ref == 1, "Got unexpected refcount %lu.\n", ref);
1651 ref = get_refcount((IUnknown *)d3d);
1652 ok(ref == old_d3d_ref, "Got unexpected refcount %lu.\n", ref);
1654 memset(&desc, 0, sizeof(desc));
1655 hr = IDirect3DViewport2_GetViewport(viewport2, &desc.vp1);
1656 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1657 desc.vp1.dwSize = sizeof(desc.vp1) + 1;
1658 hr = IDirect3DViewport2_GetViewport(viewport2, &desc.vp1);
1659 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1660 desc.vp1.dwSize = sizeof(desc.vp1) - 1;
1661 hr = IDirect3DViewport2_GetViewport(viewport2, &desc.vp1);
1662 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1663 desc.vp1.dwSize = sizeof(desc.vp1);
1664 hr = IDirect3DViewport2_GetViewport(viewport2, &desc.vp1);
1665 ok(hr == D3DERR_VIEWPORTDATANOTSET, "Got unexpected hr %#lx.\n", hr);
1666 ok(desc.vp1.dwSize == sizeof(desc.vp1), "Got unexpected dwSize %lu.\n", desc.vp1.dwSize);
1667 hr = IDirect3DViewport2_GetViewport2(viewport2, &desc.vp2);
1668 ok(hr == D3DERR_VIEWPORTDATANOTSET, "Got unexpected hr %#lx.\n", hr);
1669 ok(desc.vp2.dwSize == sizeof(desc.vp2), "Got unexpected dwSize %lu.\n", desc.vp2.dwSize);
1670 desc.vp2.dwSize = sizeof(desc.vp2) + 1;
1671 hr = IDirect3DViewport2_GetViewport2(viewport2, &desc.vp2);
1672 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1674 gamma = (IDirectDrawGammaControl *)0xdeadbeef;
1675 hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirectDrawGammaControl, (void **)&gamma);
1676 ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
1677 ok(!gamma, "Interface not set to NULL by failed QI call: %p\n", gamma);
1678 /* NULL iid: Segfaults */
1680 hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirect3DViewport, (void **)&viewport);
1681 ok(SUCCEEDED(hr), "Failed to QI IDirect3DViewport, hr %#lx.\n", hr);
1682 ref = get_refcount((IUnknown *)viewport);
1683 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1684 ref = get_refcount((IUnknown *)viewport2);
1685 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1686 IDirect3DViewport_Release(viewport);
1687 viewport = NULL;
1689 hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirect3DViewport3, (void **)&viewport3);
1690 ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to QI IDirect3DViewport3, hr %#lx.\n", hr);
1691 if (viewport3)
1693 ref = get_refcount((IUnknown *)viewport2);
1694 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1695 ref = get_refcount((IUnknown *)viewport3);
1696 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1697 IDirect3DViewport3_Release(viewport3);
1700 hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IUnknown, (void **)&unknown);
1701 ok(SUCCEEDED(hr), "Failed to QI IUnknown, hr %#lx.\n", hr);
1702 ref = get_refcount((IUnknown *)viewport2);
1703 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1704 ref = get_refcount(unknown);
1705 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1706 IUnknown_Release(unknown);
1708 hr = IDirect3DDevice2_DeleteViewport(device, NULL);
1709 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1710 hr = IDirect3DDevice2_GetCurrentViewport(device, NULL);
1711 ok(hr == D3DERR_NOCURRENTVIEWPORT, "Got unexpected hr %#lx.\n", hr);
1713 hr = IDirect3D2_CreateViewport(d3d, &another_vp, NULL);
1714 ok(SUCCEEDED(hr), "Failed to create viewport, hr %#lx.\n", hr);
1716 /* Setting a viewport not in the viewport list fails */
1717 hr = IDirect3DDevice2_SetCurrentViewport(device, another_vp);
1718 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1720 /* AddViewport(NULL): Segfault */
1721 hr = IDirect3DDevice2_AddViewport(device, viewport2);
1722 ok(SUCCEEDED(hr), "Failed to add viewport to device, hr %#lx.\n", hr);
1723 ref = get_refcount((IUnknown *) viewport2);
1724 ok(ref == 2, "viewport2 refcount is %lu.\n", ref);
1725 hr = IDirect3DDevice2_AddViewport(device, another_vp);
1726 ok(SUCCEEDED(hr), "Failed to add viewport to device, hr %#lx.\n", hr);
1727 ref = get_refcount((IUnknown *) another_vp);
1728 ok(ref == 2, "another_vp refcount is %lu.\n", ref);
1730 test_vp = (IDirect3DViewport2 *) 0xbaadc0de;
1731 hr = IDirect3DDevice2_GetCurrentViewport(device, &test_vp);
1732 ok(hr == D3DERR_NOCURRENTVIEWPORT, "Got unexpected hr %#lx.\n", hr);
1733 ok(test_vp == (IDirect3DViewport2 *) 0xbaadc0de, "Got unexpected pointer %p\n", test_vp);
1735 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport2);
1736 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
1737 ref = get_refcount((IUnknown *) viewport2);
1738 ok(ref == 3, "Got unexpected refcount %lu.\n", ref);
1739 ref = get_refcount((IUnknown *) device);
1740 ok(ref == 1, "Got unexpected refcount %lu.\n", ref);
1742 test_vp = NULL;
1743 hr = IDirect3DDevice2_GetCurrentViewport(device, &test_vp);
1744 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1745 ok(test_vp == viewport2, "Got unexpected viewport %p\n", test_vp);
1746 ref = get_refcount((IUnknown *) viewport2);
1747 ok(ref == 4, "Got unexpected refcount %lu.\n", ref);
1748 if (test_vp)
1749 IDirect3DViewport2_Release(test_vp);
1751 /* GetCurrentViewport with a viewport set and NULL input param: Segfault */
1753 /* Cannot set the viewport to NULL */
1754 hr = IDirect3DDevice2_SetCurrentViewport(device, NULL);
1755 ok(hr == DDERR_INVALIDPARAMS, "Failed to set viewport to NULL, hr %#lx.\n", hr);
1756 test_vp = NULL;
1757 hr = IDirect3DDevice2_GetCurrentViewport(device, &test_vp);
1758 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1759 ok(test_vp == viewport2, "Got unexpected viewport %p\n", test_vp);
1760 if (test_vp)
1761 IDirect3DViewport2_Release(test_vp);
1763 /* SetCurrentViewport properly releases the old viewport's reference */
1764 hr = IDirect3DDevice2_SetCurrentViewport(device, another_vp);
1765 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
1766 ref = get_refcount((IUnknown *) viewport2);
1767 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1768 ref = get_refcount((IUnknown *) another_vp);
1769 ok(ref == 3, "Got unexpected refcount %lu.\n", ref);
1771 /* Deleting the viewport removes the reference added by AddViewport, but not
1772 * the one added by SetCurrentViewport. */
1773 hr = IDirect3DDevice2_DeleteViewport(device, another_vp);
1774 ok(SUCCEEDED(hr), "Failed to delete viewport from device, hr %#lx.\n", hr);
1775 ref = get_refcount((IUnknown *) another_vp);
1776 todo_wine ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1778 /* GetCurrentViewport fails though */
1779 test_vp = NULL;
1780 hr = IDirect3DDevice2_GetCurrentViewport(device, &test_vp);
1781 ok(hr == D3DERR_NOCURRENTVIEWPORT, "Got unexpected hr %#lx.\n", hr);
1782 ok(!test_vp, "Got unexpected viewport %p\n", test_vp);
1784 /* Setting a different viewport does not free the leaked reference. How
1785 * do I get rid of it? Leak the viewport for now. */
1786 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport2);
1787 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
1788 ref = get_refcount((IUnknown *) viewport2);
1789 ok(ref == 3, "Got unexpected refcount %lu.\n", ref);
1790 ref = get_refcount((IUnknown *) another_vp);
1791 todo_wine ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1793 memset(&vp, 0, sizeof(vp));
1794 memset(&vp, 0, sizeof(vp2));
1795 vp.dwX = vp2.dwX = 0;
1796 vp.dwY = vp2.dwY = 0;
1797 vp.dwWidth = vp2.dwWidth = 640;
1798 vp.dwHeight = vp2.dwHeight = 480;
1799 vp.dvMinZ = vp2.dvMinZ = 0.0f;
1800 vp.dvMaxZ = vp2.dvMaxZ = 1.0f;
1801 vp.dvScaleX = vp.dwWidth / 2.0f;
1802 vp.dvScaleY = vp.dwHeight / 2.0f;
1803 vp.dvMaxX = 1.0f;
1804 vp.dvMaxY = 1.0f;
1805 vp2.dvClipX = -1.0f;
1806 vp2.dvClipY = 1.0f;
1807 vp2.dvClipWidth = 2.0f;
1808 vp2.dvClipHeight = 2.0f;
1809 hr = IDirect3DViewport2_SetViewport(viewport2, &vp);
1810 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1811 hr = IDirect3DViewport2_SetViewport2(viewport2, &vp2);
1812 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1814 vp.dwSize = sizeof(vp);
1815 hr = IDirect3DViewport2_SetViewport(viewport2, &vp);
1816 ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#lx.\n", hr);
1817 vp2.dwSize = sizeof(vp2);
1818 hr = IDirect3DViewport2_SetViewport2(viewport2, &vp2);
1819 ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#lx.\n", hr);
1821 /* Destroying the device removes the viewport, but does not free the reference
1822 * added by SetCurrentViewport. */
1823 IDirect3DDevice2_Release(device);
1824 ref = get_refcount((IUnknown *) viewport2);
1825 todo_wine ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1827 vp.dwSize = sizeof(vp);
1828 hr = IDirect3DViewport2_SetViewport(viewport2, &vp);
1829 ok(hr == D3DERR_VIEWPORTHASNODEVICE, "Got unexpected hr %#lx.\n", hr);
1830 vp2.dwSize = sizeof(vp2);
1831 hr = IDirect3DViewport2_SetViewport2(viewport2, &vp2);
1832 ok(hr == D3DERR_VIEWPORTHASNODEVICE, "Got unexpected hr %#lx.\n", hr);
1834 IDirect3DViewport2_Release(another_vp);
1835 IDirect3DViewport2_Release(viewport2);
1836 IDirect3D2_Release(d3d);
1837 DestroyWindow(window);
1838 IDirectDraw2_Release(ddraw);
1841 static void test_zenable(const GUID *device_guid)
1843 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1844 static D3DTLVERTEX tquad[] =
1846 {{ 0.0f}, {480.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1847 {{ 0.0f}, { 0.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1848 {{640.0f}, {480.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1849 {{640.0f}, { 0.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1851 IDirect3DMaterial2 *background;
1852 unsigned int color, x, y, i, j;
1853 IDirect3DViewport2 *viewport;
1854 IDirect3DDevice2 *device;
1855 IDirectDrawSurface *rt;
1856 IDirectDraw2 *ddraw;
1857 HWND window;
1858 HRESULT hr;
1860 window = create_window();
1861 ddraw = create_ddraw();
1862 ok(!!ddraw, "Failed to create a ddraw object.\n");
1863 if (!(device = create_device_ex(ddraw, window, DDSCL_NORMAL, device_guid)))
1865 skip("Failed to create a 3D device, skipping test.\n");
1866 IDirectDraw2_Release(ddraw);
1867 DestroyWindow(window);
1868 return;
1871 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1872 viewport = create_viewport(device, 0, 0, 640, 480);
1873 viewport_set_background(device, viewport, background);
1874 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1875 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1877 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1878 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1880 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1881 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1883 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1884 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1886 color = get_surface_color(rt, 80, 60);
1887 /* For some reason clears and colour fill blits randomly fail with software render target. */
1888 ok(color == 0x00ff0000 || broken(is_software_device_type(device_guid) && !color),
1889 "Got unexpected colour 0x%08x.\n", color);
1890 if (!color)
1892 fill_surface(rt, 0xffff0000);
1894 color = get_surface_color(rt, 80, 60);
1895 ok(color == 0x00ff0000, "Got unexpected colour 0x%08x.\n", color);
1898 hr = IDirect3DDevice2_BeginScene(device);
1899 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1900 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, tquad, 4, 0);
1901 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1902 hr = IDirect3DDevice2_EndScene(device);
1903 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1905 for (i = 0; i < 4; ++i)
1907 for (j = 0; j < 4; ++j)
1909 x = 80 * ((2 * j) + 1);
1910 y = 60 * ((2 * i) + 1);
1911 color = get_surface_color(rt, x, y);
1912 ok(compare_color(color, 0x0000ff00, 1),
1913 "Expected color 0x0000ff00 at %u, %u, got 0x%08x.\n", x, y, color);
1916 IDirectDrawSurface_Release(rt);
1918 destroy_viewport(device, viewport);
1919 destroy_material(background);
1920 IDirect3DDevice2_Release(device);
1921 IDirectDraw2_Release(ddraw);
1922 DestroyWindow(window);
1925 static void test_ck_rgba(const GUID *device_guid)
1927 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1928 static D3DTLVERTEX tquad[] =
1930 {{ 0.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1931 {{ 0.0f}, { 0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1932 {{640.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1933 {{640.0f}, { 0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1934 {{ 0.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1935 {{ 0.0f}, { 0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1936 {{640.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1937 {{640.0f}, { 0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1939 static const struct
1941 D3DCOLOR fill_color;
1942 BOOL color_key;
1943 BOOL blend;
1944 unsigned int result1, result1_broken;
1945 unsigned int result2, result2_broken;
1947 tests[] =
1949 /* r200 on Windows doesn't check the alpha component when applying the color
1950 * key, so the key matches on every texel. */
1951 {0xff00ff00, TRUE, TRUE, 0x00ff0000, 0x00ff0000, 0x000000ff, 0x000000ff},
1952 {0xff00ff00, TRUE, FALSE, 0x00ff0000, 0x00ff0000, 0x000000ff, 0x000000ff},
1953 {0xff00ff00, FALSE, TRUE, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1954 {0xff00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1955 {0x7f00ff00, TRUE, TRUE, 0x00807f00, 0x00ff0000, 0x00807f00, 0x000000ff},
1956 {0x7f00ff00, TRUE, FALSE, 0x0000ff00, 0x00ff0000, 0x0000ff00, 0x000000ff},
1957 {0x7f00ff00, FALSE, TRUE, 0x00807f00, 0x00807f00, 0x00807f00, 0x00807f00},
1958 {0x7f00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
1961 D3DTEXTUREHANDLE texture_handle;
1962 IDirect3DMaterial2 *background;
1963 IDirectDrawSurface *surface;
1964 IDirect3DViewport2 *viewport;
1965 IDirect3DTexture2 *texture;
1966 DDSURFACEDESC surface_desc;
1967 IDirect3DDevice2 *device;
1968 IDirectDrawSurface *rt;
1969 unsigned int color, i;
1970 IDirectDraw2 *ddraw;
1971 HWND window;
1972 DDBLTFX fx;
1973 HRESULT hr;
1975 window = create_window();
1976 ddraw = create_ddraw();
1977 ok(!!ddraw, "Failed to create a ddraw object.\n");
1978 if (!(device = create_device_ex(ddraw, window, DDSCL_NORMAL, device_guid)))
1980 skip("Failed to create a 3D device, skipping test.\n");
1981 IDirectDraw2_Release(ddraw);
1982 DestroyWindow(window);
1983 return;
1986 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1987 viewport = create_viewport(device, 0, 0, 640, 480);
1988 viewport_set_background(device, viewport, background);
1989 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1990 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1992 memset(&surface_desc, 0, sizeof(surface_desc));
1993 surface_desc.dwSize = sizeof(surface_desc);
1994 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1995 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1996 if (is_software_device_type(device_guid))
1997 surface_desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
1998 surface_desc.dwWidth = 256;
1999 surface_desc.dwHeight = 256;
2000 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
2001 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
2002 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
2003 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
2004 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
2005 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
2006 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
2007 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0xff00ff00;
2008 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0xff00ff00;
2009 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
2010 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
2011 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
2012 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
2013 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
2014 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2015 IDirect3DTexture2_Release(texture);
2017 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
2018 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2019 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
2020 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2021 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
2022 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2024 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
2025 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2027 for (i = 0; i < ARRAY_SIZE(tests); ++i)
2029 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, tests[i].color_key);
2030 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2031 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, tests[i].blend);
2032 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2034 memset(&fx, 0, sizeof(fx));
2035 fx.dwSize = sizeof(fx);
2036 U5(fx).dwFillColor = tests[i].fill_color;
2037 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
2038 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
2040 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
2041 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2042 /* RT clears are broken on Windows for software render target. */
2043 if (is_software_device_type(device_guid))
2044 fill_surface(rt, 0xffff0000);
2046 hr = IDirect3DDevice2_BeginScene(device);
2047 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2048 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
2049 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2050 hr = IDirect3DDevice2_EndScene(device);
2051 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2053 color = get_surface_color(rt, 320, 240);
2054 ok(compare_color(color, tests[i].result1, 2) || compare_color(color, tests[i].result1_broken, 1),
2055 "Expected color 0x%08x for test %u, got 0x%08x.\n",
2056 tests[i].result1, i, color);
2058 U5(fx).dwFillColor = 0xff0000ff;
2059 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
2060 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
2062 hr = IDirect3DDevice2_BeginScene(device);
2063 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2064 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[4], 4, 0);
2065 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2066 hr = IDirect3DDevice2_EndScene(device);
2067 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2069 /* This tests that fragments that are masked out by the color key are
2070 * discarded, instead of just fully transparent. */
2071 color = get_surface_color(rt, 320, 240);
2072 ok(compare_color(color, tests[i].result2, 2) || compare_color(color, tests[i].result2_broken, 1),
2073 "Expected color 0x%08x for test %u, got 0x%08x.\n",
2074 tests[i].result2, i, color);
2077 IDirectDrawSurface_Release(rt);
2078 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
2079 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
2080 IDirectDrawSurface_Release(surface);
2081 destroy_viewport(device, viewport);
2082 destroy_material(background);
2083 IDirect3DDevice2_Release(device);
2084 IDirectDraw2_Release(ddraw);
2085 DestroyWindow(window);
2088 static void test_ck_default(void)
2090 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
2091 static D3DTLVERTEX tquad[] =
2093 {{ 0.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
2094 {{ 0.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
2095 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
2096 {{640.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
2098 IDirectDrawSurface *surface, *rt;
2099 D3DTEXTUREHANDLE texture_handle;
2100 IDirect3DMaterial2 *background;
2101 IDirect3DViewport2 *viewport;
2102 DDSURFACEDESC surface_desc;
2103 IDirect3DTexture2 *texture;
2104 IDirect3DDevice2 *device;
2105 IDirectDraw2 *ddraw;
2106 unsigned int color;
2107 DWORD value;
2108 HWND window;
2109 DDBLTFX fx;
2110 HRESULT hr;
2112 window = create_window();
2113 ddraw = create_ddraw();
2114 ok(!!ddraw, "Failed to create a ddraw object.\n");
2115 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
2117 skip("Failed to create a 3D device, skipping test.\n");
2118 IDirectDraw2_Release(ddraw);
2119 DestroyWindow(window);
2120 return;
2123 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
2124 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
2126 background = create_diffuse_material(device, 0.0, 1.0f, 0.0f, 1.0f);
2127 viewport = create_viewport(device, 0, 0, 640, 480);
2128 viewport_set_background(device, viewport, background);
2129 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
2130 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
2132 memset(&surface_desc, 0, sizeof(surface_desc));
2133 surface_desc.dwSize = sizeof(surface_desc);
2134 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
2135 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
2136 surface_desc.dwWidth = 256;
2137 surface_desc.dwHeight = 256;
2138 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
2139 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
2140 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
2141 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
2142 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
2143 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
2144 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x000000ff;
2145 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x000000ff;
2146 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
2147 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
2148 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
2149 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
2150 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
2151 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
2152 IDirect3DTexture_Release(texture);
2154 memset(&fx, 0, sizeof(fx));
2155 fx.dwSize = sizeof(fx);
2156 U5(fx).dwFillColor = 0x000000ff;
2157 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
2158 ok(SUCCEEDED(hr), "Failed to fill surface, hr %#lx.\n", hr);
2160 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
2161 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
2162 hr = IDirect3DDevice2_BeginScene(device);
2163 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
2164 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
2165 ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#lx.\n", hr);
2166 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
2167 ok(SUCCEEDED(hr), "Failed to get render state, hr %#lx.\n", hr);
2168 ok(!value, "Got unexpected color keying state %#lx.\n", value);
2169 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
2170 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
2171 hr = IDirect3DDevice2_EndScene(device);
2172 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
2173 color = get_surface_color(rt, 320, 240);
2174 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
2176 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
2177 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
2178 hr = IDirect3DDevice2_BeginScene(device);
2179 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
2180 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
2181 ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#lx.\n", hr);
2182 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
2183 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
2184 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
2185 ok(SUCCEEDED(hr), "Failed to get render state, hr %#lx.\n", hr);
2186 ok(!!value, "Got unexpected color keying state %#lx.\n", value);
2187 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
2188 ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#lx.\n", hr);
2189 hr = IDirect3DDevice2_EndScene(device);
2190 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
2191 color = get_surface_color(rt, 320, 240);
2192 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
2194 IDirectDrawSurface_Release(surface);
2195 destroy_viewport(device, viewport);
2196 destroy_material(background);
2197 IDirectDrawSurface_Release(rt);
2198 IDirect3DDevice2_Release(device);
2199 IDirectDraw2_Release(ddraw);
2200 DestroyWindow(window);
2203 static void test_ck_complex(void)
2205 IDirectDrawSurface *surface, *mipmap, *tmp;
2206 DDSCAPS caps = {DDSCAPS_COMPLEX};
2207 DDSURFACEDESC surface_desc;
2208 IDirect3DDevice2 *device;
2209 DDCOLORKEY color_key;
2210 IDirectDraw2 *ddraw;
2211 unsigned int i;
2212 ULONG refcount;
2213 HWND window;
2214 HRESULT hr;
2216 window = create_window();
2217 ddraw = create_ddraw();
2218 ok(!!ddraw, "Failed to create a ddraw object.\n");
2219 if (!(device = create_device(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN)))
2221 skip("Failed to create a 3D device, skipping test.\n");
2222 DestroyWindow(window);
2223 IDirectDraw2_Release(ddraw);
2224 return;
2226 IDirect3DDevice2_Release(device);
2228 memset(&surface_desc, 0, sizeof(surface_desc));
2229 surface_desc.dwSize = sizeof(surface_desc);
2230 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2231 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2232 surface_desc.dwWidth = 128;
2233 surface_desc.dwHeight = 128;
2234 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
2235 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
2237 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2238 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx.\n", hr);
2239 color_key.dwColorSpaceLowValue = 0x0000ff00;
2240 color_key.dwColorSpaceHighValue = 0x0000ff00;
2241 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2242 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
2243 memset(&color_key, 0, sizeof(color_key));
2244 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2245 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
2246 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2247 color_key.dwColorSpaceLowValue);
2248 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2249 color_key.dwColorSpaceHighValue);
2251 mipmap = surface;
2252 IDirectDrawSurface_AddRef(mipmap);
2253 for (i = 0; i < 7; ++i)
2255 hr = IDirectDrawSurface_GetAttachedSurface(mipmap, &caps, &tmp);
2256 ok(SUCCEEDED(hr), "Failed to get attached surface, i %u, hr %#lx.\n", i, hr);
2258 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2259 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx, i %u.\n", hr, i);
2260 color_key.dwColorSpaceLowValue = 0x000000ff;
2261 color_key.dwColorSpaceHighValue = 0x000000ff;
2262 hr = IDirectDrawSurface_SetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2263 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx, i %u.\n", hr, i);
2264 memset(&color_key, 0, sizeof(color_key));
2265 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2266 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx, i %u.\n", hr, i);
2267 ok(color_key.dwColorSpaceLowValue == 0x000000ff, "Got unexpected value 0x%08lx, i %u.\n",
2268 color_key.dwColorSpaceLowValue, i);
2269 ok(color_key.dwColorSpaceHighValue == 0x000000ff, "Got unexpected value 0x%08lx, i %u.\n",
2270 color_key.dwColorSpaceHighValue, i);
2272 IDirectDrawSurface_Release(mipmap);
2273 mipmap = tmp;
2276 memset(&color_key, 0, sizeof(color_key));
2277 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2278 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
2279 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2280 color_key.dwColorSpaceLowValue);
2281 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2282 color_key.dwColorSpaceHighValue);
2284 hr = IDirectDrawSurface_GetAttachedSurface(mipmap, &caps, &tmp);
2285 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
2286 IDirectDrawSurface_Release(mipmap);
2287 refcount = IDirectDrawSurface_Release(surface);
2288 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
2290 memset(&surface_desc, 0, sizeof(surface_desc));
2291 surface_desc.dwSize = sizeof(surface_desc);
2292 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
2293 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
2294 surface_desc.dwBackBufferCount = 1;
2295 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
2296 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
2298 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2299 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx.\n", hr);
2300 color_key.dwColorSpaceLowValue = 0x0000ff00;
2301 color_key.dwColorSpaceHighValue = 0x0000ff00;
2302 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2303 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
2304 memset(&color_key, 0, sizeof(color_key));
2305 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2306 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
2307 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2308 color_key.dwColorSpaceLowValue);
2309 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2310 color_key.dwColorSpaceHighValue);
2312 hr = IDirectDrawSurface_GetAttachedSurface(surface, &caps, &tmp);
2313 ok(SUCCEEDED(hr), "Failed to get attached surface, hr %#lx.\n", hr);
2315 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2316 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx, i %u.\n", hr, i);
2317 color_key.dwColorSpaceLowValue = 0x0000ff00;
2318 color_key.dwColorSpaceHighValue = 0x0000ff00;
2319 hr = IDirectDrawSurface_SetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2320 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
2321 memset(&color_key, 0, sizeof(color_key));
2322 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2323 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
2324 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2325 color_key.dwColorSpaceLowValue);
2326 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2327 color_key.dwColorSpaceHighValue);
2329 IDirectDrawSurface_Release(tmp);
2331 refcount = IDirectDrawSurface_Release(surface);
2332 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
2333 refcount = IDirectDraw2_Release(ddraw);
2334 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
2335 DestroyWindow(window);
2338 struct qi_test
2340 REFIID iid;
2341 REFIID refcount_iid;
2342 HRESULT hr;
2345 static void test_qi(const char *test_name, IUnknown *base_iface,
2346 REFIID refcount_iid, const struct qi_test *tests, UINT entry_count)
2348 ULONG refcount, expected_refcount;
2349 IUnknown *iface1, *iface2;
2350 HRESULT hr;
2351 UINT i, j;
2353 for (i = 0; i < entry_count; ++i)
2355 hr = IUnknown_QueryInterface(base_iface, tests[i].iid, (void **)&iface1);
2356 ok(hr == tests[i].hr, "Got hr %#lx for test \"%s\" %u.\n", hr, test_name, i);
2357 if (SUCCEEDED(hr))
2359 for (j = 0; j < entry_count; ++j)
2361 hr = IUnknown_QueryInterface(iface1, tests[j].iid, (void **)&iface2);
2362 ok(hr == tests[j].hr, "Got hr %#lx for test \"%s\" %u, %u.\n", hr, test_name, i, j);
2363 if (SUCCEEDED(hr))
2365 expected_refcount = 0;
2366 if (IsEqualGUID(refcount_iid, tests[j].refcount_iid))
2367 ++expected_refcount;
2368 if (IsEqualGUID(tests[i].refcount_iid, tests[j].refcount_iid))
2369 ++expected_refcount;
2370 refcount = IUnknown_Release(iface2);
2371 ok(refcount == expected_refcount, "Got refcount %lu for test \"%s\" %u, %u, expected %lu.\n",
2372 refcount, test_name, i, j, expected_refcount);
2376 expected_refcount = 0;
2377 if (IsEqualGUID(refcount_iid, tests[i].refcount_iid))
2378 ++expected_refcount;
2379 refcount = IUnknown_Release(iface1);
2380 ok(refcount == expected_refcount, "Got refcount %lu for test \"%s\" %u, expected %lu.\n",
2381 refcount, test_name, i, expected_refcount);
2386 static void test_surface_qi(void)
2388 static const struct qi_test tests[] =
2390 {&IID_IDirect3DTexture2, &IID_IDirectDrawSurface, S_OK },
2391 {&IID_IDirect3DTexture, &IID_IDirectDrawSurface, S_OK },
2392 {&IID_IDirectDrawGammaControl, &IID_IDirectDrawGammaControl, S_OK },
2393 {&IID_IDirectDrawColorControl, NULL, E_NOINTERFACE},
2394 {&IID_IDirectDrawSurface7, &IID_IDirectDrawSurface7, S_OK },
2395 {&IID_IDirectDrawSurface4, &IID_IDirectDrawSurface4, S_OK },
2396 {&IID_IDirectDrawSurface3, &IID_IDirectDrawSurface3, S_OK },
2397 {&IID_IDirectDrawSurface2, &IID_IDirectDrawSurface2, S_OK },
2398 {&IID_IDirectDrawSurface, &IID_IDirectDrawSurface, S_OK },
2399 {&IID_IDirect3DDevice7, NULL, E_INVALIDARG },
2400 {&IID_IDirect3DDevice3, NULL, E_INVALIDARG },
2401 {&IID_IDirect3DDevice2, NULL, E_INVALIDARG },
2402 {&IID_IDirect3DDevice, NULL, E_INVALIDARG },
2403 {&IID_IDirect3D7, NULL, E_INVALIDARG },
2404 {&IID_IDirect3D3, NULL, E_INVALIDARG },
2405 {&IID_IDirect3D2, NULL, E_INVALIDARG },
2406 {&IID_IDirect3D, NULL, E_INVALIDARG },
2407 {&IID_IDirectDraw7, NULL, E_INVALIDARG },
2408 {&IID_IDirectDraw4, NULL, E_INVALIDARG },
2409 {&IID_IDirectDraw3, NULL, E_INVALIDARG },
2410 {&IID_IDirectDraw2, NULL, E_INVALIDARG },
2411 {&IID_IDirectDraw, NULL, E_INVALIDARG },
2412 {&IID_IDirect3DLight, NULL, E_INVALIDARG },
2413 {&IID_IDirect3DMaterial, NULL, E_INVALIDARG },
2414 {&IID_IDirect3DMaterial2, NULL, E_INVALIDARG },
2415 {&IID_IDirect3DMaterial3, NULL, E_INVALIDARG },
2416 {&IID_IDirect3DExecuteBuffer, NULL, E_INVALIDARG },
2417 {&IID_IDirect3DViewport, NULL, E_INVALIDARG },
2418 {&IID_IDirect3DViewport2, NULL, E_INVALIDARG },
2419 {&IID_IDirect3DViewport3, NULL, E_INVALIDARG },
2420 {&IID_IDirect3DVertexBuffer, NULL, E_INVALIDARG },
2421 {&IID_IDirect3DVertexBuffer7, NULL, E_INVALIDARG },
2422 {&IID_IDirectDrawPalette, NULL, E_INVALIDARG },
2423 {&IID_IDirectDrawClipper, NULL, E_INVALIDARG },
2424 {&IID_IUnknown, &IID_IDirectDrawSurface, S_OK },
2425 {NULL, NULL, E_INVALIDARG },
2428 IDirectDrawSurface *surface;
2429 DDSURFACEDESC surface_desc;
2430 IDirect3DDevice2 *device;
2431 IDirectDraw2 *ddraw;
2432 HWND window;
2433 HRESULT hr;
2435 if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
2437 win_skip("DirectDrawCreateEx not available, skipping test.\n");
2438 return;
2441 window = create_window();
2442 ddraw = create_ddraw();
2443 ok(!!ddraw, "Failed to create a ddraw object.\n");
2444 /* Try to create a D3D device to see if the ddraw implementation supports
2445 * D3D. 64-bit ddraw in particular doesn't seem to support D3D, and
2446 * doesn't support e.g. the IDirect3DTexture interfaces. */
2447 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
2449 skip("Failed to create a 3D device, skipping test.\n");
2450 IDirectDraw2_Release(ddraw);
2451 DestroyWindow(window);
2452 return;
2454 IDirect3DDevice_Release(device);
2456 memset(&surface_desc, 0, sizeof(surface_desc));
2457 surface_desc.dwSize = sizeof(surface_desc);
2458 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2459 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
2460 surface_desc.dwWidth = 512;
2461 surface_desc.dwHeight = 512;
2462 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, (IDirectDrawSurface **)0xdeadbeef, NULL);
2463 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2464 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
2465 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
2467 test_qi("surface_qi", (IUnknown *)surface, &IID_IDirectDrawSurface, tests, ARRAY_SIZE(tests));
2469 IDirectDrawSurface_Release(surface);
2470 IDirectDraw2_Release(ddraw);
2471 DestroyWindow(window);
2474 static void test_device_qi(void)
2476 static const struct qi_test tests[] =
2478 {&IID_IDirect3DTexture2, NULL, E_NOINTERFACE},
2479 {&IID_IDirect3DTexture, NULL, E_NOINTERFACE},
2480 {&IID_IDirectDrawGammaControl, NULL, E_NOINTERFACE},
2481 {&IID_IDirectDrawColorControl, NULL, E_NOINTERFACE},
2482 {&IID_IDirectDrawSurface7, NULL, E_NOINTERFACE},
2483 {&IID_IDirectDrawSurface4, NULL, E_NOINTERFACE},
2484 {&IID_IDirectDrawSurface3, NULL, E_NOINTERFACE},
2485 {&IID_IDirectDrawSurface2, NULL, E_NOINTERFACE},
2486 {&IID_IDirectDrawSurface, NULL, E_NOINTERFACE},
2487 {&IID_IDirect3DDevice7, NULL, E_NOINTERFACE},
2488 {&IID_IDirect3DDevice3, NULL, E_NOINTERFACE},
2489 {&IID_IDirect3DDevice2, &IID_IDirect3DDevice2, S_OK },
2490 {&IID_IDirect3DDevice, &IID_IDirect3DDevice2, S_OK },
2491 {&IID_IDirect3DRampDevice, NULL, E_NOINTERFACE},
2492 {&IID_IDirect3DRGBDevice, NULL, E_NOINTERFACE},
2493 {&IID_IDirect3DHALDevice, NULL, E_NOINTERFACE},
2494 {&IID_IDirect3DMMXDevice, NULL, E_NOINTERFACE},
2495 {&IID_IDirect3DRefDevice, NULL, E_NOINTERFACE},
2496 {&IID_IDirect3DTnLHalDevice, NULL, E_NOINTERFACE},
2497 {&IID_IDirect3DNullDevice, NULL, E_NOINTERFACE},
2498 {&IID_IDirect3D7, NULL, E_NOINTERFACE},
2499 {&IID_IDirect3D3, NULL, E_NOINTERFACE},
2500 {&IID_IDirect3D2, NULL, E_NOINTERFACE},
2501 {&IID_IDirect3D, NULL, E_NOINTERFACE},
2502 {&IID_IDirectDraw7, NULL, E_NOINTERFACE},
2503 {&IID_IDirectDraw4, NULL, E_NOINTERFACE},
2504 {&IID_IDirectDraw3, NULL, E_NOINTERFACE},
2505 {&IID_IDirectDraw2, NULL, E_NOINTERFACE},
2506 {&IID_IDirectDraw, NULL, E_NOINTERFACE},
2507 {&IID_IDirect3DLight, NULL, E_NOINTERFACE},
2508 {&IID_IDirect3DMaterial, NULL, E_NOINTERFACE},
2509 {&IID_IDirect3DMaterial2, NULL, E_NOINTERFACE},
2510 {&IID_IDirect3DMaterial3, NULL, E_NOINTERFACE},
2511 {&IID_IDirect3DExecuteBuffer, NULL, E_NOINTERFACE},
2512 {&IID_IDirect3DViewport, NULL, E_NOINTERFACE},
2513 {&IID_IDirect3DViewport2, NULL, E_NOINTERFACE},
2514 {&IID_IDirect3DViewport3, NULL, E_NOINTERFACE},
2515 {&IID_IDirect3DVertexBuffer, NULL, E_NOINTERFACE},
2516 {&IID_IDirect3DVertexBuffer7, NULL, E_NOINTERFACE},
2517 {&IID_IDirectDrawPalette, NULL, E_NOINTERFACE},
2518 {&IID_IDirectDrawClipper, NULL, E_NOINTERFACE},
2519 {&IID_IUnknown, &IID_IDirect3DDevice2, S_OK },
2522 IDirect3DDevice2 *device;
2523 IDirectDraw2 *ddraw;
2524 HWND window;
2526 window = create_window();
2527 ddraw = create_ddraw();
2528 ok(!!ddraw, "Failed to create a ddraw object.\n");
2529 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
2531 skip("Failed to create a 3D device, skipping test.\n");
2532 IDirectDraw2_Release(ddraw);
2533 DestroyWindow(window);
2534 return;
2537 test_qi("device_qi", (IUnknown *)device, &IID_IDirect3DDevice2, tests, ARRAY_SIZE(tests));
2539 IDirect3DDevice2_Release(device);
2540 IDirectDraw2_Release(ddraw);
2541 DestroyWindow(window);
2544 static void test_wndproc(void)
2546 LONG_PTR proc, ddraw_proc;
2547 IDirectDraw2 *ddraw;
2548 WNDCLASSA wc = {0};
2549 HWND window;
2550 HRESULT hr;
2551 ULONG ref;
2553 static struct message messages[] =
2555 {WM_WINDOWPOSCHANGING, FALSE, 0},
2556 {WM_MOVE, FALSE, 0},
2557 {WM_SIZE, FALSE, 0},
2558 {WM_WINDOWPOSCHANGING, FALSE, 0},
2559 {WM_ACTIVATE, FALSE, 0},
2560 {WM_SETFOCUS, FALSE, 0},
2561 {0, FALSE, 0},
2564 /* DDSCL_EXCLUSIVE replaces the window's window proc. */
2565 ddraw = create_ddraw();
2566 ok(!!ddraw, "Failed to create a ddraw object.\n");
2568 wc.lpfnWndProc = test_proc;
2569 wc.lpszClassName = "ddraw_test_wndproc_wc";
2570 ok(RegisterClassA(&wc), "Failed to register window class.\n");
2572 window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test",
2573 WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
2575 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2576 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2577 (LONG_PTR)test_proc, proc);
2578 expect_messages = messages;
2579 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2580 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2581 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2582 expect_messages = NULL;
2583 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2584 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#Ix, got %#Ix.\n",
2585 (LONG_PTR)test_proc, proc);
2586 ref = IDirectDraw2_Release(ddraw);
2587 ok(!ref, "Unexpected refcount %lu.\n", ref);
2588 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2589 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2590 (LONG_PTR)test_proc, proc);
2592 /* DDSCL_NORMAL doesn't. */
2593 ddraw = create_ddraw();
2594 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2595 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2596 (LONG_PTR)test_proc, proc);
2597 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
2598 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2599 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2600 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2601 (LONG_PTR)test_proc, proc);
2602 ref = IDirectDraw2_Release(ddraw);
2603 ok(!ref, "Unexpected refcount %lu.\n", ref);
2604 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2605 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2606 (LONG_PTR)test_proc, proc);
2608 /* The original window proc is only restored by ddraw if the current
2609 * window proc matches the one ddraw set. This also affects switching
2610 * from DDSCL_NORMAL to DDSCL_EXCLUSIVE. */
2611 ddraw = create_ddraw();
2612 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2613 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2614 (LONG_PTR)test_proc, proc);
2615 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2616 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2617 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2618 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#Ix, got %#Ix.\n",
2619 (LONG_PTR)test_proc, proc);
2620 ddraw_proc = proc;
2621 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2622 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2623 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2624 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2625 (LONG_PTR)test_proc, proc);
2626 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2627 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2628 proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
2629 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#Ix, got %#Ix.\n",
2630 (LONG_PTR)test_proc, proc);
2631 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2632 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2633 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2634 ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#Ix, got %#Ix.\n",
2635 (LONG_PTR)DefWindowProcA, proc);
2636 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2637 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2638 proc = SetWindowLongPtrA(window, GWLP_WNDPROC, ddraw_proc);
2639 ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#Ix, got %#Ix.\n",
2640 (LONG_PTR)DefWindowProcA, proc);
2641 ref = IDirectDraw2_Release(ddraw);
2642 ok(!ref, "Unexpected refcount %lu.\n", ref);
2643 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2644 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2645 (LONG_PTR)test_proc, proc);
2647 ddraw = create_ddraw();
2648 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2649 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2650 (LONG_PTR)test_proc, proc);
2651 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2652 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2653 proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
2654 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#Ix, got %#Ix.\n",
2655 (LONG_PTR)test_proc, proc);
2656 ref = IDirectDraw2_Release(ddraw);
2657 ok(!ref, "Unexpected refcount %lu.\n", ref);
2658 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2659 ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#Ix, got %#Ix.\n",
2660 (LONG_PTR)DefWindowProcA, proc);
2662 fix_wndproc(window, (LONG_PTR)test_proc);
2663 expect_messages = NULL;
2664 DestroyWindow(window);
2665 UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
2668 static void test_window_style(void)
2670 LONG style, exstyle, tmp, expected_style;
2671 RECT fullscreen_rect, r;
2672 HWND window, window2;
2673 IDirectDraw2 *ddraw;
2674 HRESULT hr;
2675 ULONG ref;
2676 BOOL ret;
2678 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2679 0, 0, 100, 100, 0, 0, 0, 0);
2680 window2 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2681 0, 0, 50, 50, 0, 0, 0, 0);
2682 ddraw = create_ddraw();
2683 ok(!!ddraw, "Failed to create a ddraw object.\n");
2685 style = GetWindowLongA(window, GWL_STYLE);
2686 exstyle = GetWindowLongA(window, GWL_EXSTYLE);
2687 SetRect(&fullscreen_rect, 0, 0, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
2689 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2690 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2692 tmp = GetWindowLongA(window, GWL_STYLE);
2693 todo_wine ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2694 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2695 todo_wine ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2697 GetWindowRect(window, &r);
2698 ok(EqualRect(&r, &fullscreen_rect), "Expected %s, got %s.\n",
2699 wine_dbgstr_rect(&fullscreen_rect), wine_dbgstr_rect(&r));
2700 GetClientRect(window, &r);
2701 todo_wine ok(!EqualRect(&r, &fullscreen_rect), "Client rect and window rect are equal.\n");
2703 ret = SetForegroundWindow(GetDesktopWindow());
2704 ok(ret, "Failed to set foreground window.\n");
2706 tmp = GetWindowLongA(window, GWL_STYLE);
2707 todo_wine ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2708 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2709 todo_wine ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2711 ret = SetForegroundWindow(window);
2712 ok(ret, "Failed to set foreground window.\n");
2713 /* Windows 7 (but not Vista and XP) shows the window when it receives focus. Hide it again,
2714 * the next tests expect this. */
2715 ShowWindow(window, SW_HIDE);
2717 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2718 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2720 tmp = GetWindowLongA(window, GWL_STYLE);
2721 ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2722 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2723 ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2725 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES);
2726 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2728 tmp = GetWindowLongA(window, GWL_STYLE);
2729 todo_wine ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2730 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2731 todo_wine ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2733 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2734 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2736 tmp = GetWindowLongA(window, GWL_STYLE);
2737 expected_style = style | WS_VISIBLE;
2738 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2739 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2740 expected_style = exstyle | WS_EX_TOPMOST;
2741 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2743 ShowWindow(window, SW_HIDE);
2744 tmp = GetWindowLongA(window, GWL_STYLE);
2745 todo_wine ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2746 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2747 expected_style = exstyle | WS_EX_TOPMOST;
2748 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2750 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_NOWINDOWCHANGES);
2751 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2753 tmp = GetWindowLongA(window, GWL_STYLE);
2754 ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2755 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2756 expected_style = exstyle | WS_EX_TOPMOST;
2757 ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2759 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2760 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2762 tmp = GetWindowLongA(window, GWL_STYLE);
2763 ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2764 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2765 expected_style = exstyle | WS_EX_TOPMOST;
2766 ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2768 ret = SetForegroundWindow(window);
2769 ok(ret, "Failed to set foreground window.\n");
2771 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2772 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2774 tmp = GetWindowLongA(window, GWL_STYLE);
2775 expected_style = style | WS_VISIBLE;
2776 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2777 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2778 expected_style = exstyle | WS_EX_TOPMOST;
2779 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2781 ShowWindow(window, SW_HIDE);
2782 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2783 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2785 tmp = GetWindowLongA(window, GWL_STYLE);
2786 ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2787 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2788 ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2790 ShowWindow(window, SW_SHOW);
2791 ret = SetForegroundWindow(GetDesktopWindow());
2792 ok(ret, "Failed to set foreground window.\n");
2793 SetActiveWindow(window);
2794 ok(GetActiveWindow() == window, "Unexpected active window.\n");
2795 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2796 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2798 tmp = GetWindowLongA(window, GWL_STYLE);
2799 expected_style = style | WS_VISIBLE;
2800 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2801 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2802 todo_wine ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2804 GetWindowRect(window, &r);
2805 ok(EqualRect(&r, &fullscreen_rect), "Expected %s, got %s.\n",
2806 wine_dbgstr_rect(&fullscreen_rect), wine_dbgstr_rect(&r));
2808 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2809 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2811 SetWindowPos(window, NULL, 0, 0, 100, 100, SWP_NOZORDER | SWP_NOACTIVATE);
2812 GetWindowRect(window, &r);
2813 ok(!EqualRect(&r, &fullscreen_rect), "Window resize failed? got %s.\n",
2814 wine_dbgstr_rect(&r));
2816 ret = SetForegroundWindow(window2);
2817 ok(ret, "Failed to set foreground window.\n");
2818 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2819 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2821 tmp = GetWindowLongA(window, GWL_STYLE);
2822 expected_style = style | WS_VISIBLE;
2823 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2824 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2825 todo_wine ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2827 GetWindowRect(window, &r);
2828 ok(EqualRect(&r, &fullscreen_rect), "Expected %s, got %s.\n",
2829 wine_dbgstr_rect(&fullscreen_rect), wine_dbgstr_rect(&r));
2831 ret = SetForegroundWindow(window);
2832 ok(ret, "Failed to set foreground window.\n");
2833 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2834 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2836 tmp = GetWindowLongA(window, GWL_STYLE);
2837 expected_style = style | WS_VISIBLE;
2838 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2839 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2840 expected_style = exstyle | WS_EX_TOPMOST;
2841 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2843 ShowWindow(window, SW_HIDE);
2844 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2845 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2847 tmp = GetWindowLongA(window, GWL_STYLE);
2848 ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2849 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2850 ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2852 ShowWindow(window, SW_SHOW);
2853 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2854 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2856 tmp = GetWindowLongA(window, GWL_STYLE);
2857 expected_style = style | WS_VISIBLE;
2858 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2859 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2860 expected_style = exstyle | WS_EX_TOPMOST;
2861 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2863 ret = SetForegroundWindow(GetDesktopWindow());
2864 ok(ret, "Failed to set foreground window.\n");
2865 tmp = GetWindowLongA(window, GWL_STYLE);
2866 expected_style = style | WS_VISIBLE | WS_MINIMIZE;
2867 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2868 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2869 expected_style = exstyle | WS_EX_TOPMOST;
2870 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2872 ref = IDirectDraw2_Release(ddraw);
2873 ok(!ref, "Unexpected refcount %lu.\n", ref);
2875 DestroyWindow(window2);
2876 DestroyWindow(window);
2879 static void test_redundant_mode_set(void)
2881 DDSURFACEDESC surface_desc = {0};
2882 IDirectDraw2 *ddraw;
2883 RECT q, r, s;
2884 HWND window;
2885 HRESULT hr;
2886 ULONG ref;
2888 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2889 0, 0, 100, 100, 0, 0, 0, 0);
2890 ddraw = create_ddraw();
2891 ok(!!ddraw, "Failed to create a ddraw object.\n");
2893 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2894 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2896 surface_desc.dwSize = sizeof(surface_desc);
2897 hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
2898 ok(SUCCEEDED(hr), "GetDisplayMode failed, hr %#lx.\n", hr);
2900 hr = IDirectDraw2_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2901 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, 0, 0);
2902 ok(SUCCEEDED(hr), "SetDisplayMode failed, hr %#lx.\n", hr);
2904 GetWindowRect(window, &q);
2905 r = q;
2906 r.right /= 2;
2907 r.bottom /= 2;
2908 SetWindowPos(window, HWND_TOP, r.left, r.top, r.right, r.bottom, 0);
2909 GetWindowRect(window, &s);
2910 ok(EqualRect(&r, &s), "Expected %s, got %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&s));
2912 hr = IDirectDraw2_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2913 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, 0, 0);
2914 ok(SUCCEEDED(hr), "SetDisplayMode failed, hr %#lx.\n", hr);
2916 GetWindowRect(window, &s);
2917 ok(EqualRect(&r, &s) || broken(EqualRect(&q, &s) /* Windows 10 */),
2918 "Expected %s, got %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&s));
2920 ref = IDirectDraw2_Release(ddraw);
2921 ok(!ref, "Unexpected refcount %lu.\n", ref);
2923 DestroyWindow(window);
2926 static SIZE screen_size, screen_size2;
2928 static LRESULT CALLBACK mode_set_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2930 if (message == WM_SIZE)
2932 screen_size.cx = GetSystemMetrics(SM_CXSCREEN);
2933 screen_size.cy = GetSystemMetrics(SM_CYSCREEN);
2936 return test_proc(hwnd, message, wparam, lparam);
2939 static LRESULT CALLBACK mode_set_proc2(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2941 if (message == WM_SIZE)
2943 screen_size2.cx = GetSystemMetrics(SM_CXSCREEN);
2944 screen_size2.cy = GetSystemMetrics(SM_CYSCREEN);
2947 return test_proc(hwnd, message, wparam, lparam);
2950 struct test_coop_level_mode_set_enum_param
2952 DWORD ddraw_width, ddraw_height, user32_width, user32_height;
2955 static HRESULT CALLBACK test_coop_level_mode_set_enum_cb(DDSURFACEDESC *surface_desc, void *context)
2957 struct test_coop_level_mode_set_enum_param *param = context;
2959 if (U1(surface_desc->ddpfPixelFormat).dwRGBBitCount != registry_mode.dmBitsPerPel)
2960 return DDENUMRET_OK;
2961 if (surface_desc->dwWidth == registry_mode.dmPelsWidth
2962 && surface_desc->dwHeight == registry_mode.dmPelsHeight)
2963 return DDENUMRET_OK;
2965 if (!param->ddraw_width)
2967 param->ddraw_width = surface_desc->dwWidth;
2968 param->ddraw_height = surface_desc->dwHeight;
2969 return DDENUMRET_OK;
2971 if (surface_desc->dwWidth == param->ddraw_width && surface_desc->dwHeight == param->ddraw_height)
2972 return DDENUMRET_OK;
2974 /* The docs say the DDENUMRET_CANCEL below cancels the enumeration, so the check should be
2975 * redundant. However, since Windows 10 this no longer works and the enumeration continues
2976 * until all supported modes are enumerated. Win8 and earlier do cancel.
2978 * Unrelatedly, some testbot machines report high res modes like 1920x1080, but suffer from
2979 * some problems when we actually try to set them (w10pro64 and its localization siblings).
2980 * Try to stay below the registry mode if possible. */
2981 if (!param->user32_width || (surface_desc->dwWidth < registry_mode.dmPelsWidth
2982 && surface_desc->dwHeight < registry_mode.dmPelsHeight))
2984 param->user32_width = surface_desc->dwWidth;
2985 param->user32_height = surface_desc->dwHeight;
2987 return DDENUMRET_CANCEL;
2990 static void test_coop_level_mode_set(void)
2992 DEVMODEW *original_modes = NULL, devmode, devmode2;
2993 unsigned int display_count = 0;
2994 IDirectDrawSurface *primary;
2995 RECT registry_rect, ddraw_rect, user32_rect, r;
2996 IDirectDraw2 *ddraw;
2997 DDSURFACEDESC ddsd;
2998 WNDCLASSA wc = {0};
2999 HWND window, window2;
3000 HRESULT hr;
3001 ULONG ref;
3002 MSG msg;
3003 struct test_coop_level_mode_set_enum_param param;
3004 BOOL ret;
3005 LONG change_ret;
3007 static const struct message exclusive_messages[] =
3009 {WM_WINDOWPOSCHANGING, FALSE, 0},
3010 {WM_WINDOWPOSCHANGED, FALSE, 0},
3011 {WM_SIZE, FALSE, 0},
3012 {WM_DISPLAYCHANGE, FALSE, 0},
3013 {0, FALSE, 0},
3015 static const struct message exclusive_focus_loss_messages[] =
3017 {WM_ACTIVATE, TRUE, WA_INACTIVE},
3018 {WM_WINDOWPOSCHANGING, FALSE, 0}, /* Window resize due to mode change. */
3019 {WM_WINDOWPOSCHANGED, FALSE, 0},
3020 {WM_SIZE, TRUE, SIZE_RESTORED}, /* Generated by DefWindowProc. */
3021 {WM_DISPLAYCHANGE, FALSE, 0},
3022 {WM_KILLFOCUS, FALSE, 0},
3023 {WM_WINDOWPOSCHANGING, FALSE, 0}, /* Window minimized. */
3024 /* Like d3d8 and d3d9 ddraw seems to use SW_SHOWMINIMIZED instead of
3025 * SW_MINIMIZED, causing a recursive window activation that does not
3026 * produce the same result in Wine yet. Ignore the difference for now.
3027 * {WM_ACTIVATE, TRUE, 0x200000 | WA_ACTIVE}, */
3028 {WM_WINDOWPOSCHANGED, FALSE, 0},
3029 {WM_MOVE, FALSE, 0},
3030 {WM_SIZE, TRUE, SIZE_MINIMIZED},
3031 {WM_ACTIVATEAPP, TRUE, FALSE},
3032 {0, FALSE, 0},
3034 static const struct message exclusive_focus_restore_messages[] =
3036 {WM_WINDOWPOSCHANGING, FALSE, 0}, /* From the ShowWindow(SW_RESTORE). */
3037 {WM_WINDOWPOSCHANGING, FALSE, 0}, /* Generated by ddraw, matches d3d9 behavior. */
3038 {WM_WINDOWPOSCHANGED, FALSE, 0}, /* Matching previous message. */
3039 {WM_SIZE, FALSE, 0}, /* DefWindowProc. */
3040 {WM_DISPLAYCHANGE, FALSE, 0}, /* Ddraw restores mode. */
3041 /* Native redundantly sets the window size here. */
3042 {WM_ACTIVATEAPP, TRUE, TRUE}, /* End of ddraw's hooks. */
3043 {WM_WINDOWPOSCHANGED, FALSE, 0}, /* Matching the one from ShowWindow. */
3044 {WM_MOVE, FALSE, 0}, /* DefWindowProc. */
3045 {WM_SIZE, TRUE, SIZE_RESTORED}, /* DefWindowProc. */
3046 {0, FALSE, 0},
3048 static const struct message sc_restore_messages[] =
3050 {WM_SYSCOMMAND, TRUE, SC_RESTORE},
3051 {WM_WINDOWPOSCHANGING, FALSE, 0},
3052 {WM_WINDOWPOSCHANGED, FALSE, 0},
3053 {WM_SIZE, TRUE, SIZE_RESTORED},
3054 {0, FALSE, 0},
3056 static const struct message sc_minimize_messages[] =
3058 {WM_SYSCOMMAND, TRUE, SC_MINIMIZE},
3059 {WM_WINDOWPOSCHANGING, FALSE, 0},
3060 {WM_WINDOWPOSCHANGED, FALSE, 0},
3061 {WM_SIZE, TRUE, SIZE_MINIMIZED},
3062 {0, FALSE, 0},
3064 static const struct message sc_maximize_messages[] =
3066 {WM_SYSCOMMAND, TRUE, SC_MAXIMIZE},
3067 {WM_WINDOWPOSCHANGING, FALSE, 0},
3068 {WM_WINDOWPOSCHANGED, FALSE, 0},
3069 {WM_SIZE, TRUE, SIZE_MAXIMIZED},
3070 {0, FALSE, 0},
3073 static const struct message normal_messages[] =
3075 {WM_DISPLAYCHANGE, FALSE, 0},
3076 {0, FALSE, 0},
3079 memset(&devmode, 0, sizeof(devmode));
3080 devmode.dmSize = sizeof(devmode);
3081 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3082 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3083 ok(compare_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
3084 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
3085 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3086 ok(compare_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
3088 ret = save_display_modes(&original_modes, &display_count);
3089 ok(ret, "Failed to save original display modes.\n");
3091 ddraw = create_ddraw();
3092 ok(!!ddraw, "Failed to create a ddraw object.\n");
3094 memset(&param, 0, sizeof(param));
3095 hr = IDirectDraw2_EnumDisplayModes(ddraw, 0, NULL, &param, test_coop_level_mode_set_enum_cb);
3096 ok(SUCCEEDED(hr), "Failed to enumerate display mode, hr %#lx.\n", hr);
3097 ref = IDirectDraw2_Release(ddraw);
3098 ok(!ref, "Unexpected refcount %lu.\n", ref);
3100 if (!param.user32_height)
3102 skip("Fewer than 3 different modes supported, skipping mode restore test.\n");
3103 heap_free(original_modes);
3104 return;
3107 SetRect(&registry_rect, 0, 0, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
3108 SetRect(&ddraw_rect, 0, 0, param.ddraw_width, param.ddraw_height);
3109 SetRect(&user32_rect, 0, 0, param.user32_width, param.user32_height);
3111 memset(&devmode, 0, sizeof(devmode));
3112 devmode.dmSize = sizeof(devmode);
3113 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
3114 devmode.dmPelsWidth = param.user32_width;
3115 devmode.dmPelsHeight = param.user32_height;
3116 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
3117 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3119 ddraw = create_ddraw();
3120 ok(!!ddraw, "Failed to create a ddraw object.\n");
3122 wc.lpfnWndProc = mode_set_proc;
3123 wc.lpszClassName = "ddraw_test_wndproc_wc";
3124 ok(RegisterClassA(&wc), "Failed to register window class.\n");
3125 wc.lpfnWndProc = mode_set_proc2;
3126 wc.lpszClassName = "ddraw_test_wndproc_wc2";
3127 ok(RegisterClassA(&wc), "Failed to register window class.\n");
3129 window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test", WS_OVERLAPPEDWINDOW,
3130 0, 0, 100, 100, 0, 0, 0, 0);
3131 window2 = CreateWindowA("ddraw_test_wndproc_wc2", "ddraw_test", WS_OVERLAPPEDWINDOW,
3132 0, 0, 100, 100, 0, 0, 0, 0);
3134 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3135 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3137 GetWindowRect(window, &r);
3138 ok(EqualRect(&r, &user32_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&user32_rect),
3139 wine_dbgstr_rect(&r));
3141 memset(&ddsd, 0, sizeof(ddsd));
3142 ddsd.dwSize = sizeof(ddsd);
3143 ddsd.dwFlags = DDSD_CAPS;
3144 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3146 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3147 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3148 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3149 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3150 ok(ddsd.dwWidth == param.user32_width, "Expected surface width %lu, got %lu.\n",
3151 param.user32_width, ddsd.dwWidth);
3152 ok(ddsd.dwHeight == param.user32_height, "Expected surface height %lu, got %lu.\n",
3153 param.user32_height, ddsd.dwHeight);
3155 GetWindowRect(window, &r);
3156 ok(EqualRect(&r, &user32_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&user32_rect),
3157 wine_dbgstr_rect(&r));
3159 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3160 expect_messages = exclusive_messages;
3161 screen_size.cx = 0;
3162 screen_size.cy = 0;
3164 hr = IDirectDrawSurface_IsLost(primary);
3165 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3166 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3167 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3168 hr = IDirectDrawSurface_IsLost(primary);
3169 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3171 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3172 expect_messages = NULL;
3173 ok(screen_size.cx == param.ddraw_width && screen_size.cy == param.ddraw_height,
3174 "Expected screen size %lux%lu, got %lux%lu.\n",
3175 param.ddraw_width, param.ddraw_height, screen_size.cx, screen_size.cy);
3177 GetWindowRect(window, &r);
3178 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3179 wine_dbgstr_rect(&r));
3181 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3182 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3183 ok(ddsd.dwWidth == param.user32_width, "Expected surface width %lu, got %lu.\n",
3184 param.user32_width, ddsd.dwWidth);
3185 ok(ddsd.dwHeight == param.user32_height, "Expected surface height %lu, got %lu.\n",
3186 param.user32_height, ddsd.dwHeight);
3187 IDirectDrawSurface_Release(primary);
3189 memset(&ddsd, 0, sizeof(ddsd));
3190 ddsd.dwSize = sizeof(ddsd);
3191 ddsd.dwFlags = DDSD_CAPS;
3192 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3194 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3195 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3196 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3197 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3198 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3199 param.ddraw_width, ddsd.dwWidth);
3200 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3201 param.ddraw_height, ddsd.dwHeight);
3203 GetWindowRect(window, &r);
3204 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3205 wine_dbgstr_rect(&r));
3207 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3208 expect_messages = exclusive_messages;
3209 screen_size.cx = 0;
3210 screen_size.cy = 0;
3212 hr = IDirectDrawSurface_IsLost(primary);
3213 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3214 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
3215 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3216 hr = IDirectDrawSurface_IsLost(primary);
3217 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3219 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3220 expect_messages = NULL;
3221 ok(screen_size.cx == param.user32_width && screen_size.cy == param.user32_height,
3222 "Expected screen size %lux%lu, got %lux%lu.\n",
3223 param.user32_width, param.user32_height, screen_size.cx, screen_size.cy);
3225 GetWindowRect(window, &r);
3226 ok(EqualRect(&r, &user32_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&user32_rect),
3227 wine_dbgstr_rect(&r));
3229 expect_messages = exclusive_focus_loss_messages;
3230 ret = SetForegroundWindow(GetDesktopWindow());
3231 ok(ret, "Failed to set foreground window.\n");
3232 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3233 memset(&devmode, 0, sizeof(devmode));
3234 devmode.dmSize = sizeof(devmode);
3235 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3236 ok(ret, "Failed to get display mode.\n");
3237 ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
3238 && devmode.dmPelsHeight == registry_mode.dmPelsHeight, "Got unexpected screen size %lux%lu.\n",
3239 devmode.dmPelsWidth, devmode.dmPelsHeight);
3241 expect_messages = exclusive_focus_restore_messages;
3242 ShowWindow(window, SW_RESTORE);
3243 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3245 GetWindowRect(window, &r);
3246 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3247 wine_dbgstr_rect(&r));
3248 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3249 ok(ret, "Failed to get display mode.\n");
3250 ok(devmode.dmPelsWidth == param.ddraw_width
3251 && devmode.dmPelsHeight == param.ddraw_height, "Got unexpected screen size %lux%lu.\n",
3252 devmode.dmPelsWidth, devmode.dmPelsHeight);
3254 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3255 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3256 /* Normally the primary should be restored here. Unfortunately this causes the
3257 * GetSurfaceDesc call after the next display mode change to crash on the Windows 8
3258 * testbot. Another Restore call would presumably avoid the crash, but it also moots
3259 * the point of the GetSurfaceDesc call. */
3261 expect_messages = sc_minimize_messages;
3262 SendMessageA(window, WM_SYSCOMMAND, SC_MINIMIZE, 0);
3263 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3264 expect_messages = NULL;
3266 expect_messages = sc_restore_messages;
3267 SendMessageA(window, WM_SYSCOMMAND, SC_RESTORE, 0);
3268 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3269 expect_messages = NULL;
3271 expect_messages = sc_maximize_messages;
3272 SendMessageA(window, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
3273 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3274 expect_messages = NULL;
3276 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3277 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3279 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3280 expect_messages = exclusive_messages;
3281 screen_size.cx = 0;
3282 screen_size.cy = 0;
3284 hr = IDirectDrawSurface_IsLost(primary);
3285 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3286 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
3287 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#lx.\n", hr);
3288 hr = IDirectDrawSurface_IsLost(primary);
3289 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3291 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3292 expect_messages = NULL;
3293 ok(screen_size.cx == registry_mode.dmPelsWidth
3294 && screen_size.cy == registry_mode.dmPelsHeight,
3295 "Expected screen size %lux%lu, got %lux%lu.\n",
3296 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight, screen_size.cx, screen_size.cy);
3298 GetWindowRect(window, &r);
3299 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3300 wine_dbgstr_rect(&r));
3302 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3303 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3304 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3305 param.ddraw_width, ddsd.dwWidth);
3306 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3307 param.ddraw_height, ddsd.dwHeight);
3308 IDirectDrawSurface_Release(primary);
3310 /* For Wine. */
3311 change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
3312 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3314 memset(&ddsd, 0, sizeof(ddsd));
3315 ddsd.dwSize = sizeof(ddsd);
3316 ddsd.dwFlags = DDSD_CAPS;
3317 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3319 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3320 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3321 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3322 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3323 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3324 registry_mode.dmPelsWidth, ddsd.dwWidth);
3325 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3326 registry_mode.dmPelsHeight, ddsd.dwHeight);
3328 GetWindowRect(window, &r);
3329 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3330 wine_dbgstr_rect(&r));
3332 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3333 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3335 GetWindowRect(window, &r);
3336 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3337 wine_dbgstr_rect(&r));
3339 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3340 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3341 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3342 registry_mode.dmPelsWidth, ddsd.dwWidth);
3343 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3344 registry_mode.dmPelsHeight, ddsd.dwHeight);
3345 IDirectDrawSurface_Release(primary);
3347 memset(&ddsd, 0, sizeof(ddsd));
3348 ddsd.dwSize = sizeof(ddsd);
3349 ddsd.dwFlags = DDSD_CAPS;
3350 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3352 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3353 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3354 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3355 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3356 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3357 registry_mode.dmPelsWidth, ddsd.dwWidth);
3358 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3359 registry_mode.dmPelsHeight, ddsd.dwHeight);
3361 GetWindowRect(window, &r);
3362 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3363 wine_dbgstr_rect(&r));
3365 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3366 expect_messages = normal_messages;
3367 screen_size.cx = 0;
3368 screen_size.cy = 0;
3370 hr = IDirectDrawSurface_IsLost(primary);
3371 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3372 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
3373 devmode.dmPelsWidth = param.user32_width;
3374 devmode.dmPelsHeight = param.user32_height;
3375 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
3376 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3377 hr = IDirectDrawSurface_IsLost(primary);
3378 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3380 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3381 expect_messages = NULL;
3382 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3384 GetWindowRect(window, &r);
3385 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3386 wine_dbgstr_rect(&r));
3388 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3389 expect_messages = normal_messages;
3390 screen_size.cx = 0;
3391 screen_size.cy = 0;
3393 hr = IDirectDrawSurface_Restore(primary);
3394 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
3395 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3396 if (hr == DDERR_NOEXCLUSIVEMODE /* NT4 testbot */)
3398 win_skip("Broken SetDisplayMode(), skipping remaining tests.\n");
3399 IDirectDrawSurface_Release(primary);
3400 IDirectDraw2_Release(ddraw);
3401 goto done;
3403 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3404 hr = IDirectDrawSurface_Restore(primary);
3405 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
3406 hr = IDirectDrawSurface_IsLost(primary);
3407 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3409 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3410 expect_messages = NULL;
3411 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3413 GetWindowRect(window, &r);
3414 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3415 wine_dbgstr_rect(&r));
3417 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3418 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3419 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3420 registry_mode.dmPelsWidth, ddsd.dwWidth);
3421 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3422 registry_mode.dmPelsHeight, ddsd.dwHeight);
3423 IDirectDrawSurface_Release(primary);
3425 memset(&ddsd, 0, sizeof(ddsd));
3426 ddsd.dwSize = sizeof(ddsd);
3427 ddsd.dwFlags = DDSD_CAPS;
3428 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3430 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3431 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3432 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3433 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3434 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3435 param.ddraw_width, ddsd.dwWidth);
3436 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3437 param.ddraw_height, ddsd.dwHeight);
3439 GetWindowRect(window, &r);
3440 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3441 wine_dbgstr_rect(&r));
3443 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3444 expect_messages = normal_messages;
3445 screen_size.cx = 0;
3446 screen_size.cy = 0;
3448 hr = IDirectDrawSurface_IsLost(primary);
3449 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3450 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
3451 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#lx.\n", hr);
3452 hr = IDirectDrawSurface_IsLost(primary);
3453 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3455 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3456 expect_messages = NULL;
3457 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3459 GetWindowRect(window, &r);
3460 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3461 wine_dbgstr_rect(&r));
3463 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3464 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3465 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3466 param.ddraw_width, ddsd.dwWidth);
3467 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3468 param.ddraw_height, ddsd.dwHeight);
3469 IDirectDrawSurface_Release(primary);
3471 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3472 ok(ret, "Failed to get display mode.\n");
3473 ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
3474 && devmode.dmPelsHeight == registry_mode.dmPelsHeight,
3475 "Expected resolution %lux%lu, got %lux%lu.\n",
3476 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight,
3477 devmode.dmPelsWidth, devmode.dmPelsHeight);
3478 change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
3479 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3481 memset(&ddsd, 0, sizeof(ddsd));
3482 ddsd.dwSize = sizeof(ddsd);
3483 ddsd.dwFlags = DDSD_CAPS;
3484 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3486 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3487 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3488 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3489 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3490 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3491 registry_mode.dmPelsWidth, ddsd.dwWidth);
3492 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3493 registry_mode.dmPelsHeight, ddsd.dwHeight);
3495 GetWindowRect(window, &r);
3496 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3497 wine_dbgstr_rect(&r));
3499 /* DDSCL_NORMAL | DDSCL_FULLSCREEN behaves the same as just DDSCL_NORMAL.
3500 * Resizing the window on mode changes is a property of DDSCL_EXCLUSIVE,
3501 * not DDSCL_FULLSCREEN. */
3502 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
3503 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3505 GetWindowRect(window, &r);
3506 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3507 wine_dbgstr_rect(&r));
3509 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3510 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3511 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3512 registry_mode.dmPelsWidth, ddsd.dwWidth);
3513 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3514 registry_mode.dmPelsHeight, ddsd.dwHeight);
3515 IDirectDrawSurface_Release(primary);
3517 memset(&ddsd, 0, sizeof(ddsd));
3518 ddsd.dwSize = sizeof(ddsd);
3519 ddsd.dwFlags = DDSD_CAPS;
3520 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3522 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3523 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3524 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3525 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3526 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3527 registry_mode.dmPelsWidth, ddsd.dwWidth);
3528 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3529 registry_mode.dmPelsHeight, ddsd.dwHeight);
3531 GetWindowRect(window, &r);
3532 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3533 wine_dbgstr_rect(&r));
3535 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3536 expect_messages = normal_messages;
3537 screen_size.cx = 0;
3538 screen_size.cy = 0;
3540 hr = IDirectDrawSurface_IsLost(primary);
3541 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3542 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
3543 devmode.dmPelsWidth = param.user32_width;
3544 devmode.dmPelsHeight = param.user32_height;
3545 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
3546 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3547 hr = IDirectDrawSurface_IsLost(primary);
3548 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3550 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3551 expect_messages = NULL;
3552 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3554 GetWindowRect(window, &r);
3555 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3556 wine_dbgstr_rect(&r));
3558 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3559 expect_messages = normal_messages;
3560 screen_size.cx = 0;
3561 screen_size.cy = 0;
3563 hr = IDirectDrawSurface_Restore(primary);
3564 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
3565 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3566 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3567 hr = IDirectDrawSurface_Restore(primary);
3568 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
3569 hr = IDirectDrawSurface_IsLost(primary);
3570 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3572 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3573 expect_messages = NULL;
3574 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3576 GetWindowRect(window, &r);
3577 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3578 wine_dbgstr_rect(&r));
3580 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3581 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3582 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3583 registry_mode.dmPelsWidth, ddsd.dwWidth);
3584 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3585 registry_mode.dmPelsHeight, ddsd.dwHeight);
3586 IDirectDrawSurface_Release(primary);
3588 memset(&ddsd, 0, sizeof(ddsd));
3589 ddsd.dwSize = sizeof(ddsd);
3590 ddsd.dwFlags = DDSD_CAPS;
3591 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3593 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3594 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3595 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3596 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3597 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3598 param.ddraw_width, ddsd.dwWidth);
3599 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3600 param.ddraw_height, ddsd.dwHeight);
3602 GetWindowRect(window, &r);
3603 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3604 wine_dbgstr_rect(&r));
3606 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3607 expect_messages = normal_messages;
3608 screen_size.cx = 0;
3609 screen_size.cy = 0;
3611 hr = IDirectDrawSurface_IsLost(primary);
3612 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3613 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
3614 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#lx.\n", hr);
3615 hr = IDirectDrawSurface_IsLost(primary);
3616 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3618 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3619 expect_messages = NULL;
3620 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3622 GetWindowRect(window, &r);
3623 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3624 wine_dbgstr_rect(&r));
3626 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3627 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3628 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3629 param.ddraw_width, ddsd.dwWidth);
3630 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3631 param.ddraw_height, ddsd.dwHeight);
3632 IDirectDrawSurface_Release(primary);
3634 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3635 ok(ret, "Failed to get display mode.\n");
3636 ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
3637 && devmode.dmPelsHeight == registry_mode.dmPelsHeight,
3638 "Expected resolution %lux%lu, got %lux%lu.\n",
3639 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight,
3640 devmode.dmPelsWidth, devmode.dmPelsHeight);
3641 change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
3642 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3644 memset(&ddsd, 0, sizeof(ddsd));
3645 ddsd.dwSize = sizeof(ddsd);
3646 ddsd.dwFlags = DDSD_CAPS;
3647 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3649 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3650 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3651 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3652 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3653 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3654 registry_mode.dmPelsWidth, ddsd.dwWidth);
3655 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3656 registry_mode.dmPelsHeight, ddsd.dwHeight);
3657 IDirectDrawSurface_Release(primary);
3659 GetWindowRect(window, &r);
3660 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3661 wine_dbgstr_rect(&r));
3663 /* Changing the coop level from EXCLUSIVE to NORMAL restores the screen resolution */
3664 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3665 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3666 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3667 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3669 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3670 expect_messages = exclusive_messages;
3671 screen_size.cx = 0;
3672 screen_size.cy = 0;
3674 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3675 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3677 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3678 expect_messages = NULL;
3679 ok(screen_size.cx == registry_mode.dmPelsWidth
3680 && screen_size.cy == registry_mode.dmPelsHeight,
3681 "Expected screen size %lux%lu, got %lux%lu.\n",
3682 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight,
3683 screen_size.cx, screen_size.cy);
3685 GetWindowRect(window, &r);
3686 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3687 wine_dbgstr_rect(&r));
3689 memset(&ddsd, 0, sizeof(ddsd));
3690 ddsd.dwSize = sizeof(ddsd);
3691 ddsd.dwFlags = DDSD_CAPS;
3692 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3694 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3695 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3696 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3697 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3698 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3699 registry_mode.dmPelsWidth, ddsd.dwWidth);
3700 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3701 registry_mode.dmPelsHeight, ddsd.dwHeight);
3702 IDirectDrawSurface_Release(primary);
3704 /* The screen restore is a property of DDSCL_EXCLUSIVE */
3705 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
3706 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3707 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3708 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3710 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3711 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3713 memset(&ddsd, 0, sizeof(ddsd));
3714 ddsd.dwSize = sizeof(ddsd);
3715 ddsd.dwFlags = DDSD_CAPS;
3716 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3718 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3719 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3720 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3721 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3722 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3723 param.ddraw_width, ddsd.dwWidth);
3724 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3725 param.ddraw_height, ddsd.dwHeight);
3726 IDirectDrawSurface_Release(primary);
3728 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
3729 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#lx.\n", hr);
3731 /* If the window is changed at the same time, messages are sent to the new window. */
3732 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3733 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3734 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3735 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3737 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3738 expect_messages = exclusive_messages;
3739 screen_size.cx = 0;
3740 screen_size.cy = 0;
3741 screen_size2.cx = 0;
3742 screen_size2.cy = 0;
3744 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL);
3745 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3747 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3748 expect_messages = NULL;
3749 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n",
3750 screen_size.cx, screen_size.cy);
3751 ok(screen_size2.cx == registry_mode.dmPelsWidth && screen_size2.cy == registry_mode.dmPelsHeight,
3752 "Expected screen size 2 %lux%lu, got %lux%lu.\n",
3753 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight, screen_size2.cx, screen_size2.cy);
3755 GetWindowRect(window, &r);
3756 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3757 wine_dbgstr_rect(&r));
3758 GetWindowRect(window2, &r);
3759 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3760 wine_dbgstr_rect(&r));
3762 memset(&ddsd, 0, sizeof(ddsd));
3763 ddsd.dwSize = sizeof(ddsd);
3764 ddsd.dwFlags = DDSD_CAPS;
3765 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3767 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
3768 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3769 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3770 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3771 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3772 registry_mode.dmPelsWidth, ddsd.dwWidth);
3773 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3774 registry_mode.dmPelsHeight, ddsd.dwHeight);
3775 IDirectDrawSurface_Release(primary);
3777 ref = IDirectDraw2_Release(ddraw);
3778 ok(!ref, "Unexpected refcount %lu.\n", ref);
3780 GetWindowRect(window, &r);
3781 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3782 wine_dbgstr_rect(&r));
3784 ret = restore_display_modes(original_modes, display_count);
3785 ok(ret, "Failed to restore display modes.\n");
3787 /* Test that no mode restorations if no mode changes happened */
3788 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
3789 devmode.dmPelsWidth = param.user32_width;
3790 devmode.dmPelsHeight = param.user32_height;
3791 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
3792 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
3794 ddraw = create_ddraw();
3795 ok(!!ddraw, "Failed to create a ddraw object.\n");
3796 ref = IDirectDraw2_Release(ddraw);
3797 ok(!ref, "Unexpected refcount %lu.\n", ref);
3799 memset(&devmode2, 0, sizeof(devmode2));
3800 devmode2.dmSize = sizeof(devmode2);
3801 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
3802 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3803 ok(compare_mode_rect(&devmode2, &registry_mode), "Got a different mode.\n");
3804 ret = restore_display_modes(original_modes, display_count);
3805 ok(ret, "Failed to restore display modes.\n");
3807 /* Test that no mode restorations if no mode changes happened with fullscreen ddraw objects */
3808 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
3809 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
3811 ddraw = create_ddraw();
3812 ok(!!ddraw, "Failed to create a ddraw object.\n");
3813 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3814 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
3815 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3816 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
3817 ref = IDirectDraw2_Release(ddraw);
3818 ok(!ref, "Unexpected refcount %lu.\n", ref);
3820 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
3821 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3822 ok(compare_mode_rect(&devmode2, &registry_mode), "Got a different mode.\n");
3823 ret = restore_display_modes(original_modes, display_count);
3824 ok(ret, "Failed to restore display modes.\n");
3826 /* Test that mode restorations use display settings in the registry after ddraw object releases
3827 * if SetDisplayMode() was called */
3828 ddraw = create_ddraw();
3829 ok(!!ddraw, "Failed to create a ddraw object.\n");
3830 hr = set_display_mode(ddraw, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
3831 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
3833 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
3834 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
3836 ref = IDirectDraw2_Release(ddraw);
3837 ok(!ref, "Unexpected refcount %lu.\n", ref);
3839 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
3840 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3841 ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
3842 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
3843 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3844 ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
3845 ret = restore_display_modes(original_modes, display_count);
3846 ok(ret, "Failed to restore display modes.\n");
3848 /* Test that mode restorations use display settings in the registry after RestoreDisplayMode() */
3849 ddraw = create_ddraw();
3850 ok(!!ddraw, "Failed to create a ddraw object.\n");
3851 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3852 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
3854 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
3855 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
3857 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
3858 ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#lx.\n", hr);
3860 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
3861 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3862 ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
3863 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
3864 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3865 ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
3867 ref = IDirectDraw2_Release(ddraw);
3868 ok(!ref, "Unexpected refcount %lu.\n", ref);
3870 done:
3871 expect_messages = NULL;
3872 DestroyWindow(window);
3873 DestroyWindow(window2);
3874 UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
3875 UnregisterClassA("ddraw_test_wndproc_wc2", GetModuleHandleA(NULL));
3876 ret = restore_display_modes(original_modes, display_count);
3877 ok(ret, "Failed to restore display modes.\n");
3878 heap_free(original_modes);
3881 static void test_coop_level_mode_set_multi(void)
3883 DEVMODEW old_devmode, devmode, devmode2, devmode3, *original_modes = NULL;
3884 unsigned int mode_idx = 0, display_idx, display_count = 0;
3885 WCHAR second_monitor_name[CCHDEVICENAME];
3886 IDirectDraw2 *ddraw1, *ddraw2;
3887 LONG change_ret;
3888 UINT w, h;
3889 HWND window;
3890 HRESULT hr;
3891 ULONG ref;
3892 BOOL ret;
3894 memset(&devmode, 0, sizeof(devmode));
3895 devmode.dmSize = sizeof(devmode);
3896 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3897 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3898 ok(compare_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
3899 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
3900 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3901 ok(compare_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
3903 ret = save_display_modes(&original_modes, &display_count);
3904 ok(ret, "Failed to save original display modes.\n");
3906 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
3907 0, 0, 100, 100, 0, 0, 0, 0);
3908 ddraw1 = create_ddraw();
3909 ok(!!ddraw1, "Failed to create a ddraw object.\n");
3911 /* With just a single ddraw object, the display mode is restored on
3912 * release. */
3913 hr = set_display_mode(ddraw1, 800, 600);
3914 if (hr == DDERR_NOEXCLUSIVEMODE /* NT4 testbot */)
3916 win_skip("Broken SetDisplayMode(), skipping test.\n");
3917 IDirectDraw2_Release(ddraw1);
3918 DestroyWindow(window);
3919 return;
3921 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3922 w = GetSystemMetrics(SM_CXSCREEN);
3923 ok(w == 800, "Got unexpected screen width %u.\n", w);
3924 h = GetSystemMetrics(SM_CYSCREEN);
3925 ok(h == 600, "Got unexpected screen height %u.\n", h);
3927 ref = IDirectDraw2_Release(ddraw1);
3928 ok(!ref, "Unexpected refcount %lu.\n", ref);
3929 w = GetSystemMetrics(SM_CXSCREEN);
3930 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3931 h = GetSystemMetrics(SM_CYSCREEN);
3932 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3934 /* When there are multiple ddraw objects, the display mode is restored to
3935 * the initial mode, before the first SetDisplayMode() call. */
3936 ddraw1 = create_ddraw();
3937 hr = set_display_mode(ddraw1, 800, 600);
3938 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3939 w = GetSystemMetrics(SM_CXSCREEN);
3940 ok(w == 800, "Got unexpected screen width %u.\n", w);
3941 h = GetSystemMetrics(SM_CYSCREEN);
3942 ok(h == 600, "Got unexpected screen height %u.\n", h);
3944 ddraw2 = create_ddraw();
3945 hr = set_display_mode(ddraw2, 640, 480);
3946 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3947 w = GetSystemMetrics(SM_CXSCREEN);
3948 ok(w == 640, "Got unexpected screen width %u.\n", w);
3949 h = GetSystemMetrics(SM_CYSCREEN);
3950 ok(h == 480, "Got unexpected screen height %u.\n", h);
3952 ref = IDirectDraw2_Release(ddraw2);
3953 ok(!ref, "Unexpected refcount %lu.\n", ref);
3954 w = GetSystemMetrics(SM_CXSCREEN);
3955 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3956 h = GetSystemMetrics(SM_CYSCREEN);
3957 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3959 ref = IDirectDraw2_Release(ddraw1);
3960 ok(!ref, "Unexpected refcount %lu.\n", ref);
3961 w = GetSystemMetrics(SM_CXSCREEN);
3962 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3963 h = GetSystemMetrics(SM_CYSCREEN);
3964 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3966 /* Regardless of release ordering. */
3967 ddraw1 = create_ddraw();
3968 hr = set_display_mode(ddraw1, 800, 600);
3969 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3970 w = GetSystemMetrics(SM_CXSCREEN);
3971 ok(w == 800, "Got unexpected screen width %u.\n", w);
3972 h = GetSystemMetrics(SM_CYSCREEN);
3973 ok(h == 600, "Got unexpected screen height %u.\n", h);
3975 ddraw2 = create_ddraw();
3976 hr = set_display_mode(ddraw2, 640, 480);
3977 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3978 w = GetSystemMetrics(SM_CXSCREEN);
3979 ok(w == 640, "Got unexpected screen width %u.\n", w);
3980 h = GetSystemMetrics(SM_CYSCREEN);
3981 ok(h == 480, "Got unexpected screen height %u.\n", h);
3983 ref = IDirectDraw2_Release(ddraw1);
3984 ok(!ref, "Unexpected refcount %lu.\n", ref);
3985 w = GetSystemMetrics(SM_CXSCREEN);
3986 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3987 h = GetSystemMetrics(SM_CYSCREEN);
3988 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3990 ref = IDirectDraw2_Release(ddraw2);
3991 ok(!ref, "Unexpected refcount %lu.\n", ref);
3992 w = GetSystemMetrics(SM_CXSCREEN);
3993 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3994 h = GetSystemMetrics(SM_CYSCREEN);
3995 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3997 /* But only for ddraw objects that called SetDisplayMode(). */
3998 ddraw1 = create_ddraw();
3999 ddraw2 = create_ddraw();
4000 hr = set_display_mode(ddraw2, 640, 480);
4001 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
4002 w = GetSystemMetrics(SM_CXSCREEN);
4003 ok(w == 640, "Got unexpected screen width %u.\n", w);
4004 h = GetSystemMetrics(SM_CYSCREEN);
4005 ok(h == 480, "Got unexpected screen height %u.\n", h);
4007 ref = IDirectDraw2_Release(ddraw1);
4008 ok(!ref, "Unexpected refcount %lu.\n", ref);
4009 w = GetSystemMetrics(SM_CXSCREEN);
4010 ok(w == 640, "Got unexpected screen width %u.\n", w);
4011 h = GetSystemMetrics(SM_CYSCREEN);
4012 ok(h == 480, "Got unexpected screen height %u.\n", h);
4014 ref = IDirectDraw2_Release(ddraw2);
4015 ok(!ref, "Unexpected refcount %lu.\n", ref);
4016 w = GetSystemMetrics(SM_CXSCREEN);
4017 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
4018 h = GetSystemMetrics(SM_CYSCREEN);
4019 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
4021 /* If there's a ddraw object that's currently in exclusive mode, it blocks
4022 * restoring the display mode. */
4023 ddraw1 = create_ddraw();
4024 hr = set_display_mode(ddraw1, 800, 600);
4025 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
4026 w = GetSystemMetrics(SM_CXSCREEN);
4027 ok(w == 800, "Got unexpected screen width %u.\n", w);
4028 h = GetSystemMetrics(SM_CYSCREEN);
4029 ok(h == 600, "Got unexpected screen height %u.\n", h);
4031 ddraw2 = create_ddraw();
4032 hr = set_display_mode(ddraw2, 640, 480);
4033 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
4034 w = GetSystemMetrics(SM_CXSCREEN);
4035 ok(w == 640, "Got unexpected screen width %u.\n", w);
4036 h = GetSystemMetrics(SM_CYSCREEN);
4037 ok(h == 480, "Got unexpected screen height %u.\n", h);
4039 hr = IDirectDraw2_SetCooperativeLevel(ddraw2, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4040 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4042 ref = IDirectDraw2_Release(ddraw1);
4043 ok(!ref, "Unexpected refcount %lu.\n", ref);
4044 w = GetSystemMetrics(SM_CXSCREEN);
4045 ok(w == 640, "Got unexpected screen width %u.\n", w);
4046 h = GetSystemMetrics(SM_CYSCREEN);
4047 ok(h == 480, "Got unexpected screen height %u.\n", h);
4049 ref = IDirectDraw2_Release(ddraw2);
4050 ok(!ref, "Unexpected refcount %lu.\n", ref);
4051 w = GetSystemMetrics(SM_CXSCREEN);
4052 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
4053 h = GetSystemMetrics(SM_CYSCREEN);
4054 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
4056 /* Exclusive mode blocks mode setting on other ddraw objects in general. */
4057 ddraw1 = create_ddraw();
4058 hr = set_display_mode(ddraw1, 800, 600);
4059 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
4060 w = GetSystemMetrics(SM_CXSCREEN);
4061 ok(w == 800, "Got unexpected screen width %u.\n", w);
4062 h = GetSystemMetrics(SM_CYSCREEN);
4063 ok(h == 600, "Got unexpected screen height %u.\n", h);
4065 hr = IDirectDraw2_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4066 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4068 ddraw2 = create_ddraw();
4069 hr = set_display_mode(ddraw2, 640, 480);
4070 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#lx.\n", hr);
4072 ref = IDirectDraw2_Release(ddraw1);
4073 ok(!ref, "Unexpected refcount %lu.\n", ref);
4074 w = GetSystemMetrics(SM_CXSCREEN);
4075 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
4076 h = GetSystemMetrics(SM_CYSCREEN);
4077 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
4079 ref = IDirectDraw2_Release(ddraw2);
4080 ok(!ref, "Unexpected refcount %lu.\n", ref);
4081 w = GetSystemMetrics(SM_CXSCREEN);
4082 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
4083 h = GetSystemMetrics(SM_CYSCREEN);
4084 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
4086 if (display_count < 2)
4088 skip("Following tests require two monitors.\n");
4089 goto done;
4092 ret = restore_display_modes(original_modes, display_count);
4093 ok(ret, "Failed to restore display modes.\n");
4095 second_monitor_name[0] = '\0';
4096 for (display_idx = 0; display_idx < display_count; ++display_idx)
4098 if (original_modes[display_idx].dmPosition.x || original_modes[display_idx].dmPosition.y)
4100 lstrcpyW(second_monitor_name, original_modes[display_idx].dmDeviceName);
4101 break;
4104 ok(lstrlenW(second_monitor_name), "Got an empty second monitor name.\n");
4105 memset(&old_devmode, 0, sizeof(old_devmode));
4106 old_devmode.dmSize = sizeof(old_devmode);
4107 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
4108 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4110 devmode = old_devmode;
4111 while (EnumDisplaySettingsW(second_monitor_name, mode_idx++, &devmode))
4113 if (devmode.dmPelsWidth != old_devmode.dmPelsWidth
4114 || devmode.dmPelsHeight != old_devmode.dmPelsHeight)
4115 break;
4117 ok(devmode.dmPelsWidth != old_devmode.dmPelsWidth
4118 || devmode.dmPelsHeight != old_devmode.dmPelsHeight,
4119 "Failed to find a different mode for the second monitor.\n");
4121 /* Test that no mode restorations for non-primary monitors if SetDisplayMode() was not called */
4122 ddraw1 = create_ddraw();
4123 ok(!!ddraw1, "Failed to create a ddraw object.\n");
4124 hr = IDirectDraw2_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4125 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
4127 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
4128 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
4130 memset(&devmode2, 0, sizeof(devmode2));
4131 devmode2.dmSize = sizeof(devmode2);
4132 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
4133 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4134 if (compare_mode_rect(&devmode2, &old_devmode))
4136 skip("Failed to change display settings of the second monitor.\n");
4137 ref = IDirectDraw2_Release(ddraw1);
4138 ok(!ref, "Unexpected refcount %lu.\n", ref);
4139 goto done;
4142 hr = IDirectDraw2_SetCooperativeLevel(ddraw1, window, DDSCL_NORMAL);
4143 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
4144 ref = IDirectDraw2_Release(ddraw1);
4145 ok(!ref, "Unexpected refcount %lu.\n", ref);
4147 memset(&devmode3, 0, sizeof(devmode3));
4148 devmode3.dmSize = sizeof(devmode3);
4149 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode3);
4150 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4151 ok(compare_mode_rect(&devmode3, &devmode2), "Got a different mode.\n");
4152 ret = restore_display_modes(original_modes, display_count);
4153 ok(ret, "Failed to restore display modes.\n");
4155 /* Test that mode restorations happen for non-primary monitors on ddraw releases if
4156 * SetDisplayMode() was called */
4157 ddraw1 = create_ddraw();
4158 ok(!!ddraw1, "Failed to create a ddraw object.\n");
4159 hr = set_display_mode(ddraw1, 800, 600);
4160 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4162 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
4163 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
4165 ref = IDirectDraw2_Release(ddraw1);
4166 ok(!ref, "Unexpected refcount %lu.\n", ref);
4168 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
4169 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4170 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4171 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
4172 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4173 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4174 ret = restore_display_modes(original_modes, display_count);
4175 ok(ret, "Failed to restore display modes.\n");
4177 /* Test that mode restorations happen for non-primary monitors as well */
4178 ddraw1 = create_ddraw();
4179 ok(!!ddraw1, "Failed to create a ddraw object.\n");
4180 hr = set_display_mode(ddraw1, 800, 600);
4181 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4183 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
4184 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
4186 hr = IDirectDraw2_RestoreDisplayMode(ddraw1);
4187 ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#lx.\n", hr);
4189 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
4190 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4191 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4192 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
4193 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4194 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4196 ref = IDirectDraw2_Release(ddraw1);
4197 ok(!ref, "Unexpected refcount %lu.\n", ref);
4198 ret = restore_display_modes(original_modes, display_count);
4199 ok(ret, "Failed to restore display modes.\n");
4201 /* Test that mode restorations for non-primary monitors use display settings in the registry */
4202 ddraw1 = create_ddraw();
4203 ok(!!ddraw1, "Failed to create a ddraw object.\n");
4204 hr = set_display_mode(ddraw1, 800, 600);
4205 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4207 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
4208 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
4209 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
4211 ref = IDirectDraw2_Release(ddraw1);
4212 ok(!ref, "Unexpected refcount %lu.\n", ref);
4214 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
4215 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4216 ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
4217 "Expected resolution %lux%lu, got %lux%lu.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
4218 devmode2.dmPelsWidth, devmode2.dmPelsHeight);
4219 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
4220 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4221 ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
4222 "Expected resolution %lux%lu, got %lux%lu.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
4223 devmode2.dmPelsWidth, devmode2.dmPelsHeight);
4224 ret = restore_display_modes(original_modes, display_count);
4225 ok(ret, "Failed to restore display modes.\n");
4227 /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
4228 * objects and one of them restores display mode */
4229 ddraw1 = create_ddraw();
4230 ok(!!ddraw1, "Failed to create a ddraw object.\n");
4231 ddraw2 = create_ddraw();
4232 ok(!!ddraw2, "Failed to create a ddraw object.\n");
4233 hr = set_display_mode(ddraw1, 800, 600);
4234 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4235 hr = set_display_mode(ddraw2, 640, 480);
4236 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4238 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
4239 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
4241 hr = IDirectDraw2_RestoreDisplayMode(ddraw2);
4242 ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#lx.\n", hr);
4244 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
4245 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4246 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4247 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
4248 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4249 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4251 ref = IDirectDraw2_Release(ddraw2);
4252 ok(!ref, "Unexpected refcount %lu.\n", ref);
4253 ref = IDirectDraw2_Release(ddraw1);
4254 ok(!ref, "Unexpected refcount %lu.\n", ref);
4255 ret = restore_display_modes(original_modes, display_count);
4256 ok(ret, "Failed to restore display modes.\n");
4258 /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
4259 * objects and one of them got released */
4260 ddraw1 = create_ddraw();
4261 ok(!!ddraw1, "Failed to create a ddraw object.\n");
4262 ddraw2 = create_ddraw();
4263 ok(!!ddraw2, "Failed to create a ddraw object.\n");
4264 hr = set_display_mode(ddraw1, 800, 600);
4265 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4266 hr = set_display_mode(ddraw2, 640, 480);
4267 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4269 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
4270 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
4272 ref = IDirectDraw2_Release(ddraw2);
4273 ok(!ref, "Unexpected refcount %lu.\n", ref);
4275 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
4276 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4277 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4278 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
4279 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4280 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4282 ref = IDirectDraw2_Release(ddraw1);
4283 ok(!ref, "Unexpected refcount %lu.\n", ref);
4285 done:
4286 DestroyWindow(window);
4287 ret = restore_display_modes(original_modes, display_count);
4288 ok(ret, "Failed to restore display modes.\n");
4289 heap_free(original_modes);
4292 static void test_initialize(void)
4294 IDirectDraw2 *ddraw;
4295 HRESULT hr;
4297 ddraw = create_ddraw();
4298 ok(!!ddraw, "Failed to create a ddraw object.\n");
4300 hr = IDirectDraw2_Initialize(ddraw, NULL);
4301 ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#lx.\n", hr);
4302 IDirectDraw2_Release(ddraw);
4304 CoInitialize(NULL);
4305 hr = CoCreateInstance(&CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectDraw2, (void **)&ddraw);
4306 ok(SUCCEEDED(hr), "Failed to create IDirectDraw2 instance, hr %#lx.\n", hr);
4307 hr = IDirectDraw2_Initialize(ddraw, NULL);
4308 ok(hr == DD_OK, "Initialize returned hr %#lx, expected DD_OK.\n", hr);
4309 hr = IDirectDraw2_Initialize(ddraw, NULL);
4310 ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#lx, expected DDERR_ALREADYINITIALIZED.\n", hr);
4311 IDirectDraw2_Release(ddraw);
4312 CoUninitialize();
4315 static void test_coop_level_surf_create(void)
4317 IDirectDrawSurface *surface;
4318 IDirectDraw2 *ddraw;
4319 DDSURFACEDESC ddsd;
4320 HRESULT hr;
4322 ddraw = create_ddraw();
4323 ok(!!ddraw, "Failed to create a ddraw object.\n");
4325 memset(&ddsd, 0, sizeof(ddsd));
4326 ddsd.dwSize = sizeof(ddsd);
4327 ddsd.dwFlags = DDSD_CAPS;
4328 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
4329 surface = (void *)0xdeadbeef;
4330 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
4331 ok(hr == DDERR_NOCOOPERATIVELEVELSET, "Surface creation returned hr %#lx.\n", hr);
4332 ok(surface == (void *)0xdeadbeef, "Got unexpected surface %p.\n", surface);
4334 surface = (void *)0xdeadbeef;
4335 hr = IDirectDraw2_CreateSurface(ddraw, NULL, &surface, NULL);
4336 ok(hr == DDERR_NOCOOPERATIVELEVELSET, "Surface creation returned hr %#lx.\n", hr);
4337 ok(surface == (void *)0xdeadbeef, "Got unexpected surface %p.\n", surface);
4339 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4340 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4342 surface = (void *)0xdeadbeef;
4343 hr = IDirectDraw2_CreateSurface(ddraw, NULL, &surface, NULL);
4344 ok(hr == DDERR_INVALIDPARAMS, "Unexpected hr %#lx.\n", hr);
4345 ok(surface == (void *)0xdeadbeef, "Got unexpected surface %p.\n", surface);
4347 IDirectDraw2_Release(ddraw);
4350 static void test_coop_level_multi_window(void)
4352 HWND window1, window2;
4353 IDirectDraw2 *ddraw;
4354 HRESULT hr;
4356 window1 = create_window();
4357 window2 = create_window();
4358 ddraw = create_ddraw();
4359 ok(!!ddraw, "Failed to create a ddraw object.\n");
4361 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
4362 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4363 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL);
4364 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4365 ok(IsWindow(window1), "Window 1 was destroyed.\n");
4366 ok(IsWindow(window2), "Window 2 was destroyed.\n");
4368 IDirectDraw2_Release(ddraw);
4369 DestroyWindow(window2);
4370 DestroyWindow(window1);
4373 static void test_clear_rect_count(void)
4375 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
4376 IDirect3DMaterial2 *white, *red, *green, *blue;
4377 IDirect3DViewport2 *viewport;
4378 IDirect3DDevice2 *device;
4379 IDirectDrawSurface *rt;
4380 IDirectDraw2 *ddraw;
4381 unsigned int color;
4382 HWND window;
4383 HRESULT hr;
4385 window = create_window();
4386 ddraw = create_ddraw();
4387 ok(!!ddraw, "Failed to create a ddraw object.\n");
4388 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
4390 skip("Failed to create a 3D device, skipping test.\n");
4391 IDirectDraw2_Release(ddraw);
4392 DestroyWindow(window);
4393 return;
4396 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
4397 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
4399 white = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
4400 red = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
4401 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 1.0f);
4402 blue = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
4404 viewport = create_viewport(device, 0, 0, 640, 480);
4405 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
4406 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
4408 viewport_set_background(device, viewport, white);
4409 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
4410 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
4411 viewport_set_background(device, viewport, red);
4412 hr = IDirect3DViewport2_Clear(viewport, 0, &clear_rect, D3DCLEAR_TARGET);
4413 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
4414 viewport_set_background(device, viewport, green);
4415 hr = IDirect3DViewport2_Clear(viewport, 0, NULL, D3DCLEAR_TARGET);
4416 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
4417 viewport_set_background(device, viewport, blue);
4418 hr = IDirect3DViewport2_Clear(viewport, 0, &clear_rect, D3DCLEAR_TARGET);
4419 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
4421 color = get_surface_color(rt, 320, 240);
4422 ok(compare_color(color, 0x00ffffff, 1) || broken(compare_color(color, 0x000000ff, 1)),
4423 "Got unexpected color 0x%08x.\n", color);
4425 IDirectDrawSurface_Release(rt);
4426 destroy_viewport(device, viewport);
4427 destroy_material(white);
4428 destroy_material(red);
4429 destroy_material(green);
4430 destroy_material(blue);
4431 IDirect3DDevice2_Release(device);
4432 IDirectDraw2_Release(ddraw);
4433 DestroyWindow(window);
4436 static BOOL test_mode_restored(IDirectDraw2 *ddraw, HWND window)
4438 DDSURFACEDESC ddsd1, ddsd2;
4439 HRESULT hr;
4441 memset(&ddsd1, 0, sizeof(ddsd1));
4442 ddsd1.dwSize = sizeof(ddsd1);
4443 hr = IDirectDraw2_GetDisplayMode(ddraw, &ddsd1);
4444 ok(SUCCEEDED(hr), "GetDisplayMode failed, hr %#lx.\n", hr);
4446 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4447 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4448 hr = set_display_mode(ddraw, 640, 480);
4449 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
4450 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
4451 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4453 memset(&ddsd2, 0, sizeof(ddsd2));
4454 ddsd2.dwSize = sizeof(ddsd2);
4455 hr = IDirectDraw2_GetDisplayMode(ddraw, &ddsd2);
4456 ok(SUCCEEDED(hr), "GetDisplayMode failed, hr %#lx.\n", hr);
4457 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
4458 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#lx.\n", hr);
4460 return ddsd1.dwWidth == ddsd2.dwWidth && ddsd1.dwHeight == ddsd2.dwHeight;
4463 static void test_coop_level_versions(void)
4465 HWND window;
4466 IDirectDraw *ddraw;
4467 HRESULT hr;
4468 BOOL restored;
4469 IDirectDrawSurface *surface;
4470 IDirectDraw2 *ddraw2;
4471 DDSURFACEDESC ddsd;
4473 window = create_window();
4474 ddraw2 = create_ddraw();
4475 ok(!!ddraw2, "Failed to create a ddraw object.\n");
4476 /* Newly created ddraw objects restore the mode on ddraw2+::SetCooperativeLevel(NORMAL) */
4477 restored = test_mode_restored(ddraw2, window);
4478 ok(restored, "Display mode not restored in new ddraw object\n");
4480 /* A failing ddraw1::SetCooperativeLevel call does not have an effect */
4481 hr = IDirectDraw2_QueryInterface(ddraw2, &IID_IDirectDraw, (void **)&ddraw);
4482 ok(SUCCEEDED(hr), "QueryInterface failed, hr %#lx.\n", hr);
4484 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
4485 ok(FAILED(hr), "SetCooperativeLevel returned %#lx, expected failure.\n", hr);
4486 restored = test_mode_restored(ddraw2, window);
4487 ok(restored, "Display mode not restored after bad ddraw1::SetCooperativeLevel call\n");
4489 /* A successful one does */
4490 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4491 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4492 restored = test_mode_restored(ddraw2, window);
4493 ok(!restored, "Display mode restored after good ddraw1::SetCooperativeLevel call\n");
4495 IDirectDraw_Release(ddraw);
4496 IDirectDraw2_Release(ddraw2);
4498 ddraw2 = create_ddraw();
4499 ok(!!ddraw2, "Failed to create a ddraw object.\n");
4500 hr = IDirectDraw2_QueryInterface(ddraw2, &IID_IDirectDraw, (void **)&ddraw);
4501 ok(SUCCEEDED(hr), "QueryInterface failed, hr %#lx.\n", hr);
4503 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_SETFOCUSWINDOW);
4504 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4505 restored = test_mode_restored(ddraw2, window);
4506 ok(!restored, "Display mode restored after ddraw1::SetCooperativeLevel(SETFOCUSWINDOW) call\n");
4508 IDirectDraw_Release(ddraw);
4509 IDirectDraw2_Release(ddraw2);
4511 /* A failing call does not restore the ddraw2+ behavior */
4512 ddraw2 = create_ddraw();
4513 ok(!!ddraw2, "Failed to create a ddraw object.\n");
4514 hr = IDirectDraw2_QueryInterface(ddraw2, &IID_IDirectDraw, (void **)&ddraw);
4515 ok(SUCCEEDED(hr), "QueryInterface failed, hr %#lx.\n", hr);
4517 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4518 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4519 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
4520 ok(FAILED(hr), "SetCooperativeLevel returned %#lx, expected failure.\n", hr);
4521 restored = test_mode_restored(ddraw2, window);
4522 ok(!restored, "Display mode restored after good-bad ddraw1::SetCooperativeLevel() call sequence\n");
4524 IDirectDraw_Release(ddraw);
4525 IDirectDraw2_Release(ddraw2);
4527 /* Neither does a sequence of successful calls with the new interface */
4528 ddraw2 = create_ddraw();
4529 ok(!!ddraw2, "Failed to create a ddraw object.\n");
4530 hr = IDirectDraw2_QueryInterface(ddraw2, &IID_IDirectDraw, (void **)&ddraw);
4531 ok(SUCCEEDED(hr), "QueryInterface failed, hr %#lx.\n", hr);
4533 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4534 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4535 hr = IDirectDraw2_SetCooperativeLevel(ddraw2, window, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
4536 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4537 hr = IDirectDraw2_SetCooperativeLevel(ddraw2, window, DDSCL_NORMAL);
4538 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4540 restored = test_mode_restored(ddraw2, window);
4541 ok(!restored, "Display mode restored after ddraw1-ddraw2 SetCooperativeLevel() call sequence\n");
4542 IDirectDraw_Release(ddraw);
4543 IDirectDraw2_Release(ddraw2);
4545 /* ddraw1::CreateSurface does not triger the ddraw1 behavior */
4546 ddraw2 = create_ddraw();
4547 ok(!!ddraw2, "Failed to create a ddraw object.\n");
4548 hr = IDirectDraw2_QueryInterface(ddraw2, &IID_IDirectDraw, (void **)&ddraw);
4549 ok(SUCCEEDED(hr), "QueryInterface failed, hr %#lx.\n", hr);
4551 hr = IDirectDraw2_SetCooperativeLevel(ddraw2, window, DDSCL_NORMAL);
4552 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
4554 memset(&ddsd, 0, sizeof(ddsd));
4555 ddsd.dwSize = sizeof(ddsd);
4556 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
4557 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
4558 ddsd.dwWidth = ddsd.dwHeight = 8;
4559 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
4560 ok(SUCCEEDED(hr), "CreateSurface failed, hr %#lx.\n", hr);
4561 IDirectDrawSurface_Release(surface);
4562 restored = test_mode_restored(ddraw2, window);
4563 ok(restored, "Display mode not restored after ddraw1::CreateSurface() call\n");
4565 IDirectDraw_Release(ddraw);
4566 IDirectDraw2_Release(ddraw2);
4567 DestroyWindow(window);
4570 static void test_lighting_interface_versions(void)
4572 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
4573 IDirect3DMaterial2 *emissive, *background;
4574 IDirect3DViewport2 *viewport;
4575 IDirect3DDevice2 *device;
4576 IDirectDrawSurface *rt;
4577 unsigned int color, i;
4578 IDirectDraw2 *ddraw;
4579 HWND window;
4580 HRESULT hr;
4581 D3DMATERIALHANDLE mat_handle;
4582 DWORD rs;
4583 ULONG ref;
4584 static D3DVERTEX quad[] =
4586 {{-1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
4587 {{ 1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
4588 {{-1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
4589 {{ 1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
4591 static D3DLVERTEX lquad[] =
4593 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xffff0000}, {0xff808080}},
4594 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xffff0000}, {0xff808080}},
4595 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xffff0000}, {0xff808080}},
4596 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xffff0000}, {0xff808080}},
4598 static D3DTLVERTEX tlquad[] =
4600 {{ 0.0f}, { 480.0f}, {0.0f}, {1.0f}, {0xff0000ff}, {0xff808080}},
4601 {{ 0.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xff0000ff}, {0xff808080}},
4602 {{ 640.0f}, { 480.0f}, {0.0f}, {1.0f}, {0xff0000ff}, {0xff808080}},
4603 {{ 640.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xff0000ff}, {0xff808080}},
4605 static const struct
4607 D3DVERTEXTYPE vertextype;
4608 void *data;
4609 DWORD d3drs_lighting, d3drs_specular;
4610 DWORD draw_flags;
4611 unsigned int color;
4613 tests[] =
4615 /* Lighting is enabled when D3DVT_VERTEX is used and D3DDP_DONOTLIGHT is not
4616 * set. D3DVT_VERTEX has diffuse = 0xffffffff and specular = 0x00000000, as
4617 * in later d3d versions */
4618 { D3DVT_VERTEX, quad, FALSE, FALSE, 0, 0x0000ff00},
4619 { D3DVT_VERTEX, quad, TRUE, FALSE, 0, 0x0000ff00},
4620 { D3DVT_VERTEX, quad, FALSE, FALSE, D3DDP_DONOTLIGHT, 0x00ffffff},
4621 { D3DVT_VERTEX, quad, TRUE, FALSE, D3DDP_DONOTLIGHT, 0x00ffffff},
4622 { D3DVT_VERTEX, quad, FALSE, TRUE, 0, 0x0000ff00},
4623 { D3DVT_VERTEX, quad, TRUE, TRUE, 0, 0x0000ff00},
4624 { D3DVT_VERTEX, quad, FALSE, TRUE, D3DDP_DONOTLIGHT, 0x00ffffff},
4625 { D3DVT_VERTEX, quad, TRUE, TRUE, D3DDP_DONOTLIGHT, 0x00ffffff},
4627 { D3DVT_LVERTEX, lquad, FALSE, FALSE, 0, 0x00ff0000},
4628 { D3DVT_LVERTEX, lquad, TRUE, FALSE, 0, 0x00ff0000},
4629 { D3DVT_LVERTEX, lquad, FALSE, FALSE, D3DDP_DONOTLIGHT, 0x00ff0000},
4630 { D3DVT_LVERTEX, lquad, TRUE, FALSE, D3DDP_DONOTLIGHT, 0x00ff0000},
4631 { D3DVT_LVERTEX, lquad, FALSE, TRUE, 0, 0x00ff8080},
4632 { D3DVT_LVERTEX, lquad, TRUE, TRUE, 0, 0x00ff8080},
4633 { D3DVT_LVERTEX, lquad, FALSE, TRUE, D3DDP_DONOTLIGHT, 0x00ff8080},
4634 { D3DVT_LVERTEX, lquad, TRUE, TRUE, D3DDP_DONOTLIGHT, 0x00ff8080},
4636 { D3DVT_TLVERTEX, tlquad, FALSE, FALSE, 0, 0x000000ff},
4637 { D3DVT_TLVERTEX, tlquad, TRUE, FALSE, 0, 0x000000ff},
4638 { D3DVT_TLVERTEX, tlquad, FALSE, FALSE, D3DDP_DONOTLIGHT, 0x000000ff},
4639 { D3DVT_TLVERTEX, tlquad, TRUE, FALSE, D3DDP_DONOTLIGHT, 0x000000ff},
4640 { D3DVT_TLVERTEX, tlquad, FALSE, TRUE, 0, 0x008080ff},
4641 { D3DVT_TLVERTEX, tlquad, TRUE, TRUE, 0, 0x008080ff},
4642 { D3DVT_TLVERTEX, tlquad, FALSE, TRUE, D3DDP_DONOTLIGHT, 0x008080ff},
4643 { D3DVT_TLVERTEX, tlquad, TRUE, TRUE, D3DDP_DONOTLIGHT, 0x008080ff},
4646 window = create_window();
4647 ddraw = create_ddraw();
4648 ok(!!ddraw, "Failed to create a ddraw object.\n");
4649 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
4651 skip("Failed to create a 3D device, skipping test.\n");
4652 IDirectDraw2_Release(ddraw);
4653 DestroyWindow(window);
4654 return;
4657 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
4658 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
4660 viewport = create_viewport(device, 0, 0, 640, 480);
4661 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
4662 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
4664 emissive = create_emissive_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
4665 hr = IDirect3DMaterial2_GetHandle(emissive, device, &mat_handle);
4666 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#lx.\n", hr);
4667 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
4668 ok(SUCCEEDED(hr), "Failed to set material state, hr %#lx.\n", hr);
4669 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
4670 ok(SUCCEEDED(hr), "Failed to disable z test, hr %#lx.\n", hr);
4672 background = create_diffuse_material(device, 0.1f, 0.1f, 0.1f, 0.1f);
4673 viewport_set_background(device, viewport, background);
4675 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_SPECULARENABLE, &rs);
4676 ok(SUCCEEDED(hr), "Failed to get specularenable render state, hr %#lx.\n", hr);
4677 ok(rs == TRUE, "Initial D3DRENDERSTATE_SPECULARENABLE is %#lx, expected TRUE.\n", rs);
4679 for (i = 0; i < ARRAY_SIZE(tests); i++)
4681 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
4682 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
4684 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, tests[i].d3drs_lighting);
4685 ok(SUCCEEDED(hr), "Failed to set lighting render state, hr %#lx.\n", hr);
4686 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SPECULARENABLE,
4687 tests[i].d3drs_specular);
4688 ok(SUCCEEDED(hr), "Failed to set specularenable render state, hr %#lx.\n", hr);
4690 hr = IDirect3DDevice2_BeginScene(device);
4691 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
4692 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP,
4693 tests[i].vertextype, tests[i].data, 4, tests[i].draw_flags | D3DDP_WAIT);
4694 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
4695 hr = IDirect3DDevice2_EndScene(device);
4696 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
4698 color = get_surface_color(rt, 320, 240);
4699 ok(compare_color(color, tests[i].color, 1),
4700 "Got unexpected color 0x%08x, expected 0x%08x, test %u.\n",
4701 color, tests[i].color, i);
4704 destroy_material(background);
4705 destroy_material(emissive);
4706 destroy_viewport(device, viewport);
4707 IDirectDrawSurface_Release(rt);
4708 IDirect3DDevice2_Release(device);
4709 ref = IDirectDraw2_Release(ddraw);
4710 ok(!ref, "Unexpected refcount %lu.\n", ref);
4711 DestroyWindow(window);
4714 static struct
4716 BOOL received;
4717 IDirectDraw2 *ddraw;
4718 HWND window;
4719 DWORD coop_level;
4720 } activateapp_testdata;
4722 static LRESULT CALLBACK activateapp_test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
4724 if (message == WM_ACTIVATEAPP)
4726 if (activateapp_testdata.ddraw)
4728 HRESULT hr;
4729 activateapp_testdata.received = FALSE;
4730 hr = IDirectDraw2_SetCooperativeLevel(activateapp_testdata.ddraw,
4731 activateapp_testdata.window, activateapp_testdata.coop_level);
4732 ok(SUCCEEDED(hr), "Recursive SetCooperativeLevel call failed, hr %#lx.\n", hr);
4733 ok(!activateapp_testdata.received, "Received WM_ACTIVATEAPP during recursive SetCooperativeLevel call.\n");
4735 activateapp_testdata.received = TRUE;
4738 return DefWindowProcA(hwnd, message, wparam, lparam);
4741 static void test_coop_level_activateapp(void)
4743 IDirectDraw2 *ddraw;
4744 HRESULT hr;
4745 HWND window;
4746 WNDCLASSA wc = {0};
4747 DDSURFACEDESC ddsd;
4748 IDirectDrawSurface *surface;
4750 ddraw = create_ddraw();
4751 ok(!!ddraw, "Failed to create a ddraw object.\n");
4753 wc.lpfnWndProc = activateapp_test_proc;
4754 wc.lpszClassName = "ddraw_test_wndproc_wc";
4755 ok(RegisterClassA(&wc), "Failed to register window class.\n");
4757 window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test",
4758 WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
4760 /* Exclusive with window already active. */
4761 SetForegroundWindow(window);
4762 activateapp_testdata.received = FALSE;
4763 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4764 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4765 ok(!activateapp_testdata.received, "Received WM_ACTIVATEAPP although window was already active.\n");
4766 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4767 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4769 /* Exclusive with window not active. */
4770 SetForegroundWindow(GetDesktopWindow());
4771 activateapp_testdata.received = FALSE;
4772 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4773 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4774 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
4775 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4776 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4778 /* Normal with window not active, then exclusive with the same window. */
4779 SetForegroundWindow(GetDesktopWindow());
4780 activateapp_testdata.received = FALSE;
4781 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
4782 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4783 ok(!activateapp_testdata.received, "Received WM_ACTIVATEAPP when setting DDSCL_NORMAL.\n");
4784 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4785 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4786 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
4787 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4788 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4790 /* Recursive set of DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN. */
4791 SetForegroundWindow(GetDesktopWindow());
4792 activateapp_testdata.received = FALSE;
4793 activateapp_testdata.ddraw = ddraw;
4794 activateapp_testdata.window = window;
4795 activateapp_testdata.coop_level = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
4796 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4797 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4798 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
4799 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4800 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4802 /* The recursive call seems to have some bad effect on native ddraw, despite (apparently)
4803 * succeeding. Another switch to exclusive and back to normal is needed to release the
4804 * window properly. Without doing this, SetCooperativeLevel(EXCLUSIVE) will not send
4805 * WM_ACTIVATEAPP messages. */
4806 activateapp_testdata.ddraw = NULL;
4807 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4808 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4809 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4810 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4812 /* Setting DDSCL_NORMAL with recursive invocation. */
4813 SetForegroundWindow(GetDesktopWindow());
4814 activateapp_testdata.received = FALSE;
4815 activateapp_testdata.ddraw = ddraw;
4816 activateapp_testdata.window = window;
4817 activateapp_testdata.coop_level = DDSCL_NORMAL;
4818 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4819 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4820 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
4822 /* DDraw is in exclusive mode now. */
4823 memset(&ddsd, 0, sizeof(ddsd));
4824 ddsd.dwSize = sizeof(ddsd);
4825 ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
4826 ddsd.dwBackBufferCount = 1;
4827 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
4828 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
4829 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
4830 IDirectDrawSurface_Release(surface);
4832 /* Recover again, just to be sure. */
4833 activateapp_testdata.ddraw = NULL;
4834 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4835 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4836 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4837 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4839 DestroyWindow(window);
4840 UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
4841 IDirectDraw2_Release(ddraw);
4844 struct format_support_check
4846 const DDPIXELFORMAT *format;
4847 BOOL supported;
4850 static HRESULT WINAPI test_unsupported_formats_cb(DDSURFACEDESC *desc, void *ctx)
4852 struct format_support_check *format = ctx;
4854 if (!memcmp(format->format, &desc->ddpfPixelFormat, sizeof(*format->format)))
4856 format->supported = TRUE;
4857 return DDENUMRET_CANCEL;
4860 return DDENUMRET_OK;
4863 static void test_unsupported_formats(void)
4865 HRESULT hr;
4866 BOOL expect_success;
4867 HWND window;
4868 IDirectDraw2 *ddraw;
4869 IDirect3DDevice2 *device;
4870 IDirectDrawSurface *surface;
4871 DDSURFACEDESC ddsd;
4872 unsigned int i, j;
4873 DWORD expected_caps;
4874 static const struct
4876 const char *name;
4877 DDPIXELFORMAT fmt;
4879 formats[] =
4882 "D3DFMT_A8R8G8B8",
4884 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
4885 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
4889 "D3DFMT_P8",
4891 sizeof(DDPIXELFORMAT), DDPF_PALETTEINDEXED8 | DDPF_RGB, 0,
4892 {8 }, {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}
4896 static const DWORD caps[] = {0, DDSCAPS_SYSTEMMEMORY, DDSCAPS_VIDEOMEMORY};
4898 window = create_window();
4899 ddraw = create_ddraw();
4900 ok(!!ddraw, "Failed to create a ddraw object.\n");
4901 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
4903 skip("Failed to create a 3D device, skipping test.\n");
4904 IDirectDraw2_Release(ddraw);
4905 DestroyWindow(window);
4906 return;
4909 for (i = 0; i < ARRAY_SIZE(formats); i++)
4911 struct format_support_check check = {&formats[i].fmt, FALSE};
4912 hr = IDirect3DDevice2_EnumTextureFormats(device, test_unsupported_formats_cb, &check);
4913 ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr);
4915 for (j = 0; j < ARRAY_SIZE(caps); j++)
4917 memset(&ddsd, 0, sizeof(ddsd));
4918 ddsd.dwSize = sizeof(ddsd);
4919 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
4920 ddsd.ddpfPixelFormat = formats[i].fmt;
4921 ddsd.dwWidth = 4;
4922 ddsd.dwHeight = 4;
4923 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | caps[j];
4925 if (caps[j] & DDSCAPS_VIDEOMEMORY && !check.supported)
4926 expect_success = FALSE;
4927 else
4928 expect_success = TRUE;
4930 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
4931 ok(SUCCEEDED(hr) == expect_success,
4932 "Got unexpected hr %#lx for format %s, caps %#lx, expected %s.\n",
4933 hr, formats[i].name, caps[j], expect_success ? "success" : "failure");
4934 if (FAILED(hr))
4935 continue;
4937 memset(&ddsd, 0, sizeof(ddsd));
4938 ddsd.dwSize = sizeof(ddsd);
4939 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &ddsd);
4940 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
4942 if (caps[j] & DDSCAPS_VIDEOMEMORY)
4943 expected_caps = DDSCAPS_VIDEOMEMORY;
4944 else if (caps[j] & DDSCAPS_SYSTEMMEMORY)
4945 expected_caps = DDSCAPS_SYSTEMMEMORY;
4946 else if (check.supported)
4947 expected_caps = DDSCAPS_VIDEOMEMORY;
4948 else
4949 expected_caps = DDSCAPS_SYSTEMMEMORY;
4951 ok(ddsd.ddsCaps.dwCaps & expected_caps,
4952 "Expected caps %#lx, format %s, input caps %#lx.\n",
4953 expected_caps, formats[i].name, caps[j]);
4955 IDirectDrawSurface_Release(surface);
4959 IDirect3DDevice2_Release(device);
4960 IDirectDraw2_Release(ddraw);
4961 DestroyWindow(window);
4964 static void test_rt_caps(const GUID *device_guid)
4966 PALETTEENTRY palette_entries[256];
4967 IDirectDrawPalette *palette;
4968 IDirect3DDevice2 *device;
4969 BOOL software_device;
4970 IDirectDraw2 *ddraw;
4971 DWORD z_depth = 0;
4972 IDirect3D2 *d3d;
4973 DDCAPS hal_caps;
4974 unsigned int i;
4975 ULONG refcount;
4976 HWND window;
4977 HRESULT hr;
4979 static const DDPIXELFORMAT p8_fmt =
4981 sizeof(DDPIXELFORMAT), DDPF_PALETTEINDEXED8 | DDPF_RGB, 0,
4982 {8}, {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000},
4985 static const struct
4987 const DDPIXELFORMAT *pf;
4988 DWORD caps_in;
4989 HRESULT create_device_hr;
4990 HRESULT set_rt_hr;
4991 HRESULT alternative_set_rt_hr;
4992 BOOL create_may_fail;
4994 test_data[] =
4997 NULL,
4998 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY,
4999 D3D_OK,
5000 D3D_OK,
5001 D3D_OK,
5002 FALSE,
5005 NULL,
5006 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE,
5007 D3D_OK,
5008 D3D_OK,
5009 D3D_OK,
5010 FALSE,
5013 NULL,
5014 DDSCAPS_OFFSCREENPLAIN,
5015 DDERR_INVALIDCAPS,
5016 DDERR_INVALIDCAPS,
5017 DDERR_INVALIDCAPS,
5018 FALSE,
5021 NULL,
5022 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
5023 D3DERR_SURFACENOTINVIDMEM,
5024 D3D_OK,
5025 D3D_OK,
5026 FALSE,
5029 NULL,
5030 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
5031 DDERR_INVALIDCAPS,
5032 DDERR_INVALIDCAPS,
5033 DDERR_INVALIDCAPS,
5034 FALSE,
5037 NULL,
5038 DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY,
5039 D3D_OK,
5040 D3D_OK,
5041 D3D_OK,
5042 FALSE,
5045 NULL,
5046 DDSCAPS_3DDEVICE,
5047 D3D_OK,
5048 D3D_OK,
5049 D3D_OK,
5050 FALSE,
5053 NULL,
5055 DDERR_INVALIDCAPS,
5056 DDERR_INVALIDCAPS,
5057 DDERR_INVALIDCAPS,
5058 FALSE,
5061 NULL,
5062 DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
5063 D3DERR_SURFACENOTINVIDMEM,
5064 D3D_OK,
5065 D3D_OK,
5066 FALSE,
5069 NULL,
5070 DDSCAPS_SYSTEMMEMORY,
5071 DDERR_INVALIDCAPS,
5072 DDERR_INVALIDCAPS,
5073 DDERR_INVALIDCAPS,
5074 FALSE,
5077 &p8_fmt,
5079 DDERR_INVALIDCAPS,
5080 DDERR_INVALIDCAPS,
5081 DDERR_INVALIDCAPS,
5082 FALSE,
5085 &p8_fmt,
5086 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE,
5087 DDERR_NOPALETTEATTACHED,
5088 DDERR_INVALIDCAPS,
5089 DDERR_INVALIDCAPS,
5090 FALSE,
5093 &p8_fmt,
5094 DDSCAPS_OFFSCREENPLAIN,
5095 DDERR_INVALIDCAPS,
5096 DDERR_INVALIDCAPS,
5097 DDERR_INVALIDCAPS,
5098 FALSE,
5101 &p8_fmt,
5102 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
5103 DDERR_NOPALETTEATTACHED,
5104 DDERR_INVALIDCAPS,
5105 DDERR_INVALIDCAPS,
5106 FALSE,
5109 &p8_fmt,
5110 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
5111 DDERR_INVALIDCAPS,
5112 DDERR_INVALIDCAPS,
5113 DDERR_INVALIDCAPS,
5114 FALSE,
5117 NULL,
5118 DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_ZBUFFER,
5119 DDERR_INVALIDCAPS,
5120 DDERR_INVALIDPIXELFORMAT,
5121 DDERR_INVALIDCAPS,
5122 TRUE /* AMD Evergreen */,
5125 NULL,
5126 DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER,
5127 DDERR_INVALIDCAPS,
5128 DDERR_INVALIDPIXELFORMAT,
5129 DDERR_INVALIDCAPS,
5130 FALSE,
5133 NULL,
5134 DDSCAPS_ZBUFFER,
5135 DDERR_INVALIDCAPS,
5136 DDERR_INVALIDCAPS,
5137 DDERR_INVALIDCAPS,
5138 FALSE,
5141 NULL,
5142 DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER,
5143 DDERR_INVALIDCAPS,
5144 DDERR_INVALIDPIXELFORMAT,
5145 DDERR_INVALIDPIXELFORMAT,
5146 TRUE /* Nvidia Kepler */,
5149 NULL,
5150 DDSCAPS_SYSTEMMEMORY | DDSCAPS_ZBUFFER,
5151 DDERR_INVALIDCAPS,
5152 DDERR_INVALIDCAPS,
5153 DDERR_INVALIDCAPS,
5154 TRUE /* Nvidia Kepler */,
5158 software_device = is_software_device_type(device_guid);
5160 window = create_window();
5161 ddraw = create_ddraw();
5162 ok(!!ddraw, "Failed to create a ddraw object.\n");
5163 if (!(device = create_device_ex(ddraw, window, DDSCL_NORMAL, device_guid)))
5165 skip("Failed to create a 3D device, skipping test.\n");
5166 IDirectDraw2_Release(ddraw);
5167 DestroyWindow(window);
5168 return;
5170 z_depth = get_device_z_depth(device);
5171 ok(!!z_depth, "Failed to get device z depth.\n");
5172 IDirect3DDevice2_Release(device);
5174 if (FAILED(IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d)))
5176 skip("D3D interface is not available, skipping test.\n");
5177 goto done;
5180 memset(palette_entries, 0, sizeof(palette_entries));
5181 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, palette_entries, &palette, NULL);
5182 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
5184 memset(&hal_caps, 0, sizeof(hal_caps));
5185 hal_caps.dwSize = sizeof(hal_caps);
5186 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, NULL);
5187 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
5189 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
5191 IDirectDrawSurface *surface, *rt, *expected_rt, *tmp;
5192 DWORD caps_in, expected_caps;
5193 DDSURFACEDESC surface_desc;
5194 IDirect3DDevice2 *device;
5195 HRESULT expected_hr;
5197 caps_in = test_data[i].caps_in;
5199 memset(&surface_desc, 0, sizeof(surface_desc));
5200 surface_desc.dwSize = sizeof(surface_desc);
5201 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5202 surface_desc.ddsCaps.dwCaps = caps_in;
5203 if (test_data[i].pf)
5205 surface_desc.dwFlags |= DDSD_PIXELFORMAT;
5206 surface_desc.ddpfPixelFormat = *test_data[i].pf;
5208 if (caps_in & DDSCAPS_ZBUFFER)
5210 surface_desc.dwFlags |= DDSD_ZBUFFERBITDEPTH;
5211 U2(surface_desc).dwZBufferBitDepth = z_depth;
5213 surface_desc.dwWidth = 640;
5214 surface_desc.dwHeight = 480;
5215 if ((caps_in & DDSCAPS_VIDEOMEMORY) && !(hal_caps.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
5216 expected_hr = DDERR_NODIRECTDRAWHW;
5217 else
5218 expected_hr = DD_OK;
5219 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
5220 ok(hr == expected_hr || broken(test_data[i].create_may_fail
5221 || (software_device && test_data[i].pf == &p8_fmt && hr == DDERR_INVALIDPIXELFORMAT)),
5222 "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
5223 if (FAILED(hr))
5224 continue;
5226 memset(&surface_desc, 0, sizeof(surface_desc));
5227 surface_desc.dwSize = sizeof(surface_desc);
5228 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
5230 if ((caps_in & DDSCAPS_SYSTEMMEMORY) || !(hal_caps.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
5231 expected_caps = caps_in | DDSCAPS_SYSTEMMEMORY;
5232 else
5233 expected_caps = caps_in | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
5235 ok(surface_desc.ddsCaps.dwCaps == expected_caps || (test_data[i].pf == &p8_fmt
5236 && surface_desc.ddsCaps.dwCaps == (caps_in | DDSCAPS_SYSTEMMEMORY))
5237 || (software_device && caps_in & DDSCAPS_ZBUFFER
5238 && surface_desc.ddsCaps.dwCaps == (caps_in | DDSCAPS_SYSTEMMEMORY)),
5239 "Got unexpected caps %#lx, expected %#lx, test %u, software_device %u.\n",
5240 surface_desc.ddsCaps.dwCaps, expected_caps, i, software_device);
5242 hr = IDirect3D2_CreateDevice(d3d, device_guid, surface, &device);
5244 ok((!software_device && hr == test_data[i].create_device_hr)
5245 || (software_device && (hr == (test_data[i].create_device_hr == D3DERR_SURFACENOTINVIDMEM
5246 ? DD_OK : test_data[i].create_device_hr))),
5247 "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
5249 if (FAILED(hr))
5251 if (hr == DDERR_NOPALETTEATTACHED)
5253 hr = IDirectDrawSurface_SetPalette(surface, palette);
5254 ok(hr == DD_OK, "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
5255 hr = IDirect3D2_CreateDevice(d3d, device_guid, surface, &device);
5256 if (software_device)
5257 todo_wine
5258 ok(hr == DD_OK, "Got unexpected hr %#lx, test %u, software_device %u.\n",
5259 hr, i, software_device);
5260 else if (surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
5261 ok(hr == DDERR_INVALIDPIXELFORMAT, "Got unexpected hr %#lx, test %u, software_device %u.\n",
5262 hr, i, software_device);
5263 else
5264 ok(hr == D3DERR_SURFACENOTINVIDMEM, "Got unexpected hr %#lx, test %u, software_device %u.\n",
5265 hr, i, software_device);
5267 if (hr == DD_OK)
5269 refcount = IDirect3DDevice2_Release(device);
5270 ok(!refcount, "Test %u: The device was not properly freed, refcount %lu.\n", i, refcount);
5273 IDirectDrawSurface_Release(surface);
5275 memset(&surface_desc, 0, sizeof(surface_desc));
5276 surface_desc.dwSize = sizeof(surface_desc);
5277 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5278 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
5279 surface_desc.dwWidth = 640;
5280 surface_desc.dwHeight = 480;
5281 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
5282 ok(hr == DD_OK, "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
5284 hr = IDirect3D2_CreateDevice(d3d, device_guid, surface, &device);
5285 ok(hr == DD_OK, "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
5288 memset(&surface_desc, 0, sizeof(surface_desc));
5289 surface_desc.dwSize = sizeof(surface_desc);
5290 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5291 surface_desc.ddsCaps.dwCaps = test_data[i].caps_in;
5292 if (test_data[i].pf)
5294 surface_desc.dwFlags |= DDSD_PIXELFORMAT;
5295 surface_desc.ddpfPixelFormat = *test_data[i].pf;
5297 if (test_data[i].caps_in & DDSCAPS_ZBUFFER)
5299 surface_desc.dwFlags |= DDSD_ZBUFFERBITDEPTH;
5300 U2(surface_desc).dwZBufferBitDepth = z_depth;
5302 surface_desc.dwWidth = 640;
5303 surface_desc.dwHeight = 480;
5304 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &rt, NULL);
5305 ok(hr == DD_OK, "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
5307 hr = IDirect3DDevice2_SetRenderTarget(device, rt, 0);
5308 ok(hr == test_data[i].set_rt_hr || (software_device && hr == DDERR_NOPALETTEATTACHED)
5309 || broken(hr == test_data[i].alternative_set_rt_hr),
5310 "Got unexpected hr %#lx, test %u, software_device %u.\n",
5311 hr, i, software_device);
5313 if (SUCCEEDED(hr) || hr == DDERR_INVALIDPIXELFORMAT)
5314 expected_rt = rt;
5315 else
5316 expected_rt = surface;
5318 /* It appears the surface is set as render target in this case, but no
5319 * reference is taken. */
5320 if (hr == DDERR_INVALIDPIXELFORMAT)
5322 refcount = IDirectDrawSurface_AddRef(rt);
5323 ok(refcount == 2, "Test %u: Got unexpected refcount %lu.\n", i, refcount);
5326 hr = IDirect3DDevice2_GetRenderTarget(device, &tmp);
5327 ok(hr == DD_OK, "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
5328 ok(tmp == expected_rt, "Got unexpected rt %p, test %u, software_device %u.\n", tmp, i, software_device);
5330 IDirectDrawSurface_Release(tmp);
5331 IDirectDrawSurface_Release(rt);
5332 refcount = IDirect3DDevice2_Release(device);
5333 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
5334 refcount = IDirectDrawSurface_Release(surface);
5335 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
5338 IDirectDrawPalette_Release(palette);
5339 IDirect3D2_Release(d3d);
5341 done:
5342 refcount = IDirectDraw2_Release(ddraw);
5343 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
5344 DestroyWindow(window);
5347 static void test_primary_caps(void)
5349 const DWORD placement = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
5350 IDirectDrawSurface *surface;
5351 DDSURFACEDESC surface_desc;
5352 IDirectDraw2 *ddraw;
5353 unsigned int i;
5354 ULONG refcount;
5355 HWND window;
5356 HRESULT hr;
5358 static const struct
5360 DWORD coop_level;
5361 DWORD caps_in;
5362 DWORD back_buffer_count;
5363 HRESULT hr;
5364 DWORD caps_out;
5366 test_data[] =
5369 DDSCL_NORMAL,
5370 DDSCAPS_PRIMARYSURFACE,
5371 ~0u,
5372 DD_OK,
5373 DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE,
5376 DDSCL_NORMAL,
5377 DDSCAPS_PRIMARYSURFACE | DDSCAPS_TEXTURE,
5378 ~0u,
5379 DDERR_INVALIDCAPS,
5380 ~0u,
5383 DDSCL_NORMAL,
5384 DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER,
5385 ~0u,
5386 DDERR_INVALIDCAPS,
5387 ~0u,
5390 DDSCL_NORMAL,
5391 DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER,
5392 ~0u,
5393 DDERR_INVALIDCAPS,
5394 ~0u,
5397 DDSCL_NORMAL,
5398 DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP,
5399 ~0u,
5400 DDERR_INVALIDCAPS,
5401 ~0u,
5404 DDSCL_NORMAL,
5405 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX,
5406 ~0u,
5407 DDERR_INVALIDCAPS,
5408 ~0u,
5411 DDSCL_NORMAL,
5412 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
5413 ~0u,
5414 DDERR_INVALIDCAPS,
5415 ~0u,
5418 DDSCL_NORMAL,
5419 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
5421 DDERR_INVALIDCAPS,
5422 ~0u,
5425 DDSCL_NORMAL,
5426 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
5428 DDERR_NOEXCLUSIVEMODE,
5429 ~0u,
5432 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
5433 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
5435 DDERR_INVALIDCAPS,
5436 ~0u,
5439 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
5440 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
5442 DD_OK,
5443 DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER | DDSCAPS_FLIP | DDSCAPS_COMPLEX,
5446 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
5447 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER,
5449 DDERR_INVALIDCAPS,
5450 ~0u,
5453 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
5454 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_BACKBUFFER,
5456 DDERR_INVALIDCAPS,
5457 ~0u,
5461 window = create_window();
5462 ddraw = create_ddraw();
5463 ok(!!ddraw, "Failed to create a ddraw object.\n");
5465 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
5467 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, test_data[i].coop_level);
5468 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
5470 memset(&surface_desc, 0, sizeof(surface_desc));
5471 surface_desc.dwSize = sizeof(surface_desc);
5472 surface_desc.dwFlags = DDSD_CAPS;
5473 if (test_data[i].back_buffer_count != ~0u)
5474 surface_desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
5475 surface_desc.ddsCaps.dwCaps = test_data[i].caps_in;
5476 surface_desc.dwBackBufferCount = test_data[i].back_buffer_count;
5477 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
5478 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#lx, expected %#lx.\n", i, hr, test_data[i].hr);
5479 if (FAILED(hr))
5480 continue;
5482 memset(&surface_desc, 0, sizeof(surface_desc));
5483 surface_desc.dwSize = sizeof(surface_desc);
5484 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
5485 ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#lx.\n", i, hr);
5486 ok((surface_desc.ddsCaps.dwCaps & ~placement) == test_data[i].caps_out,
5487 "Test %u: Got unexpected caps %#lx, expected %#lx.\n",
5488 i, surface_desc.ddsCaps.dwCaps, test_data[i].caps_out);
5490 IDirectDrawSurface_Release(surface);
5493 refcount = IDirectDraw2_Release(ddraw);
5494 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
5495 DestroyWindow(window);
5498 static void test_surface_lock(void)
5500 IDirectDraw2 *ddraw;
5501 IDirectDrawSurface *surface;
5502 IDirect3DDevice2 *device;
5503 HRESULT hr;
5504 HWND window;
5505 unsigned int i;
5506 DDSURFACEDESC ddsd;
5507 ULONG refcount;
5508 DWORD z_depth = 0;
5509 static const struct
5511 DWORD caps;
5512 const char *name;
5514 tests[] =
5517 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
5518 "videomemory offscreenplain"
5521 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
5522 "systemmemory offscreenplain"
5525 DDSCAPS_PRIMARYSURFACE,
5526 "primary"
5529 DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY,
5530 "videomemory texture"
5533 DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY,
5534 "systemmemory texture"
5537 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE,
5538 "render target"
5541 DDSCAPS_ZBUFFER,
5542 "Z buffer"
5546 window = create_window();
5547 ddraw = create_ddraw();
5548 ok(!!ddraw, "Failed to create a ddraw object.\n");
5549 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
5551 skip("Failed to create a 3D device, skipping test.\n");
5552 IDirectDraw2_Release(ddraw);
5553 DestroyWindow(window);
5554 return;
5556 z_depth = get_device_z_depth(device);
5557 ok(!!z_depth, "Failed to get device z depth.\n");
5558 IDirect3DDevice2_Release(device);
5560 for (i = 0; i < ARRAY_SIZE(tests); i++)
5562 memset(&ddsd, 0, sizeof(ddsd));
5563 ddsd.dwSize = sizeof(ddsd);
5564 ddsd.dwFlags = DDSD_CAPS;
5565 if (!(tests[i].caps & DDSCAPS_PRIMARYSURFACE))
5567 ddsd.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
5568 ddsd.dwWidth = 64;
5569 ddsd.dwHeight = 64;
5571 if (tests[i].caps & DDSCAPS_ZBUFFER)
5573 ddsd.dwFlags |= DDSD_ZBUFFERBITDEPTH;
5574 U2(ddsd).dwZBufferBitDepth = z_depth;
5576 ddsd.ddsCaps.dwCaps = tests[i].caps;
5578 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
5579 ok(SUCCEEDED(hr), "Failed to create surface, type %s, hr %#lx.\n", tests[i].name, hr);
5581 memset(&ddsd, 0, sizeof(ddsd));
5582 ddsd.dwSize = sizeof(ddsd);
5583 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_WAIT, NULL);
5584 ok(SUCCEEDED(hr), "Failed to lock surface, type %s, hr %#lx.\n", tests[i].name, hr);
5585 if (SUCCEEDED(hr))
5587 hr = IDirectDrawSurface_Unlock(surface, NULL);
5588 ok(SUCCEEDED(hr), "Failed to unlock surface, type %s, hr %#lx.\n", tests[i].name, hr);
5591 memset(&ddsd, 0, sizeof(ddsd));
5592 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_WAIT, NULL);
5593 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx, type %s.\n", hr, tests[i].name);
5595 IDirectDrawSurface_Release(surface);
5598 refcount = IDirectDraw2_Release(ddraw);
5599 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
5600 DestroyWindow(window);
5603 static void test_surface_discard(void)
5605 IDirectDraw2 *ddraw;
5606 IDirect3DDevice2 *device;
5607 HRESULT hr;
5608 HWND window;
5609 DDSURFACEDESC ddsd;
5610 IDirectDrawSurface *surface, *target;
5611 void *addr;
5612 static const struct
5614 DWORD caps;
5615 BOOL discard;
5617 tests[] =
5619 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY, TRUE},
5620 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY, FALSE},
5621 {DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, TRUE},
5622 {DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY, FALSE},
5624 unsigned int i;
5626 window = create_window();
5628 for (i = 0; i < ARRAY_SIZE(tests); i++)
5630 BOOL discarded;
5632 /* Sigh. Anything other than the first run of the loop randomly fails with
5633 * DDERR_SURFACELOST on my Radeon Pro 560 on Win10 19.09. Most of the time
5634 * the blit fails, but with sleeps added between surface creation and lock
5635 * the lock can fail too. Interestingly ddraw claims the render target has
5636 * been lost, not the test surface.
5638 * Recreating ddraw every iteration seems to fix this. */
5639 ddraw = create_ddraw();
5640 ok(!!ddraw, "Failed to create a ddraw object.\n");
5641 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
5643 skip("Failed to create a 3D device, skipping test.\n");
5644 DestroyWindow(window);
5645 IDirectDraw2_Release(ddraw);
5646 return;
5649 hr = IDirect3DDevice2_GetRenderTarget(device, &target);
5650 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
5652 memset(&ddsd, 0, sizeof(ddsd));
5653 ddsd.dwSize = sizeof(ddsd);
5654 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5655 ddsd.ddsCaps.dwCaps = tests[i].caps;
5656 ddsd.dwWidth = 64;
5657 ddsd.dwHeight = 64;
5658 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
5659 if (FAILED(hr))
5661 skip("Failed to create surface, skipping.\n");
5662 continue;
5665 memset(&ddsd, 0, sizeof(ddsd));
5666 ddsd.dwSize = sizeof(ddsd);
5667 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_WAIT, NULL);
5668 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
5669 addr = ddsd.lpSurface;
5670 hr = IDirectDrawSurface_Unlock(surface, NULL);
5671 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
5673 memset(&ddsd, 0, sizeof(ddsd));
5674 ddsd.dwSize = sizeof(ddsd);
5675 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_DISCARDCONTENTS | DDLOCK_WAIT, NULL);
5676 ok(SUCCEEDED(hr) , "Failed to lock surface, hr %#lx.\n", hr);
5677 discarded = ddsd.lpSurface != addr;
5678 hr = IDirectDrawSurface_Unlock(surface, NULL);
5679 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
5681 hr = IDirectDrawSurface_Blt(target, NULL, surface, NULL, DDBLT_WAIT, NULL);
5682 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
5684 memset(&ddsd, 0, sizeof(ddsd));
5685 ddsd.dwSize = sizeof(ddsd);
5686 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_DISCARDCONTENTS | DDLOCK_WAIT, NULL);
5687 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
5688 discarded |= ddsd.lpSurface != addr;
5689 hr = IDirectDrawSurface_Unlock(surface, NULL);
5690 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
5692 IDirectDrawSurface_Release(surface);
5694 /* Windows 7 reliably changes the address of surfaces that are discardable (Nvidia Kepler,
5695 * AMD r500, evergreen). Windows XP, at least on AMD r200, never changes the pointer. */
5696 ok(!discarded || tests[i].discard, "Expected surface not to be discarded, case %u\n", i);
5698 IDirectDrawSurface_Release(target);
5699 IDirect3DDevice2_Release(device);
5700 IDirectDraw2_Release(ddraw);
5703 DestroyWindow(window);
5706 static void test_flip(void)
5708 const DWORD placement = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
5709 IDirectDrawSurface *frontbuffer, *backbuffer1, *backbuffer2, *backbuffer3, *surface;
5710 DDSCAPS caps = {DDSCAPS_FLIP};
5711 DDSURFACEDESC surface_desc;
5712 unsigned int color, i;
5713 BOOL sysmem_primary;
5714 IDirectDraw2 *ddraw;
5715 DWORD expected_caps;
5716 ULONG refcount;
5717 HWND window;
5718 HRESULT hr;
5720 static const struct
5722 const char *name;
5723 DWORD caps;
5725 test_data[] =
5727 {"PRIMARYSURFACE", DDSCAPS_PRIMARYSURFACE},
5728 {"OFFSCREENPLAIN", DDSCAPS_OFFSCREENPLAIN},
5729 {"TEXTURE", DDSCAPS_TEXTURE},
5732 window = create_window();
5733 ddraw = create_ddraw();
5734 ok(!!ddraw, "Failed to create a ddraw object.\n");
5736 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
5737 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
5739 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
5741 /* Creating a flippable texture induces a BSoD on some versions of the
5742 * Intel graphics driver. At least Intel GMA 950 with driver version
5743 * 6.14.10.4926 on Windows XP SP3 is affected. */
5744 if ((test_data[i].caps & DDSCAPS_TEXTURE) && ddraw_is_intel(ddraw))
5746 win_skip("Skipping flippable texture test.\n");
5747 continue;
5750 memset(&surface_desc, 0, sizeof(surface_desc));
5751 surface_desc.dwSize = sizeof(surface_desc);
5752 surface_desc.dwFlags = DDSD_CAPS;
5753 if (!(test_data[i].caps & DDSCAPS_PRIMARYSURFACE))
5754 surface_desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
5755 surface_desc.ddsCaps.dwCaps = DDSCAPS_COMPLEX | DDSCAPS_FLIP | test_data[i].caps;
5756 surface_desc.dwWidth = 512;
5757 surface_desc.dwHeight = 512;
5758 surface_desc.dwBackBufferCount = 3;
5759 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
5760 ok(hr == DDERR_INVALIDCAPS, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5762 surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_FLIP;
5763 surface_desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
5764 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
5765 ok(hr == DDERR_INVALIDCAPS, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5767 surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_COMPLEX;
5768 surface_desc.ddsCaps.dwCaps |= DDSCAPS_FLIP;
5769 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
5770 ok(hr == DDERR_INVALIDCAPS, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5772 surface_desc.ddsCaps.dwCaps |= DDSCAPS_COMPLEX;
5773 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
5774 todo_wine_if(test_data[i].caps & DDSCAPS_TEXTURE)
5775 ok(SUCCEEDED(hr), "%s: Failed to create surface, hr %#lx.\n", test_data[i].name, hr);
5776 if (FAILED(hr))
5777 continue;
5779 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
5780 ok(SUCCEEDED(hr), "%s: Failed to set cooperative level, hr %#lx.\n", test_data[i].name, hr);
5781 hr = IDirectDrawSurface_IsLost(frontbuffer);
5782 ok(hr == DD_OK, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5783 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
5784 if (test_data[i].caps & DDSCAPS_PRIMARYSURFACE)
5785 ok(hr == DDERR_NOEXCLUSIVEMODE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5786 else
5787 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5788 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
5789 ok(SUCCEEDED(hr), "%s: Failed to set cooperative level, hr %#lx.\n", test_data[i].name, hr);
5790 hr = IDirectDrawSurface_IsLost(frontbuffer);
5791 todo_wine ok(hr == DDERR_SURFACELOST, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5792 hr = restore_surfaces(ddraw);
5793 ok(SUCCEEDED(hr), "%s: Failed to restore surfaces, hr %#lx.\n", test_data[i].name, hr);
5795 memset(&surface_desc, 0, sizeof(surface_desc));
5796 surface_desc.dwSize = sizeof(surface_desc);
5797 hr = IDirectDrawSurface_GetSurfaceDesc(frontbuffer, &surface_desc);
5798 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr);
5799 expected_caps = DDSCAPS_FRONTBUFFER | DDSCAPS_COMPLEX | DDSCAPS_FLIP | test_data[i].caps;
5800 if (test_data[i].caps & DDSCAPS_PRIMARYSURFACE)
5801 expected_caps |= DDSCAPS_VISIBLE;
5802 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
5803 "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
5804 sysmem_primary = surface_desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY;
5806 hr = IDirectDrawSurface_GetAttachedSurface(frontbuffer, &caps, &backbuffer1);
5807 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr);
5808 memset(&surface_desc, 0, sizeof(surface_desc));
5809 surface_desc.dwSize = sizeof(surface_desc);
5810 hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer1, &surface_desc);
5811 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr);
5812 ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %lu.\n",
5813 test_data[i].name, surface_desc.dwBackBufferCount);
5814 expected_caps &= ~(DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER);
5815 expected_caps |= DDSCAPS_BACKBUFFER;
5816 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
5817 "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
5819 hr = IDirectDrawSurface_GetAttachedSurface(backbuffer1, &caps, &backbuffer2);
5820 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr);
5821 memset(&surface_desc, 0, sizeof(surface_desc));
5822 surface_desc.dwSize = sizeof(surface_desc);
5823 hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer2, &surface_desc);
5824 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr);
5825 ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %lu.\n",
5826 test_data[i].name, surface_desc.dwBackBufferCount);
5827 expected_caps &= ~DDSCAPS_BACKBUFFER;
5828 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
5829 "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
5831 hr = IDirectDrawSurface_GetAttachedSurface(backbuffer2, &caps, &backbuffer3);
5832 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr);
5833 memset(&surface_desc, 0, sizeof(surface_desc));
5834 surface_desc.dwSize = sizeof(surface_desc);
5835 hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer3, &surface_desc);
5836 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr);
5837 ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %lu.\n",
5838 test_data[i].name, surface_desc.dwBackBufferCount);
5839 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
5840 "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
5842 hr = IDirectDrawSurface_GetAttachedSurface(backbuffer3, &caps, &surface);
5843 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr);
5844 ok(surface == frontbuffer, "%s: Got unexpected surface %p, expected %p.\n",
5845 test_data[i].name, surface, frontbuffer);
5846 IDirectDrawSurface_Release(surface);
5848 memset(&surface_desc, 0, sizeof(surface_desc));
5849 surface_desc.dwSize = sizeof(surface_desc);
5850 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5851 surface_desc.ddsCaps.dwCaps = 0;
5852 surface_desc.dwWidth = 640;
5853 surface_desc.dwHeight = 480;
5854 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
5855 ok(SUCCEEDED(hr), "%s: Failed to create surface, hr %#lx.\n", test_data[i].name, hr);
5856 hr = IDirectDrawSurface_Flip(frontbuffer, surface, DDFLIP_WAIT);
5857 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5858 IDirectDrawSurface_Release(surface);
5860 hr = IDirectDrawSurface_Flip(frontbuffer, frontbuffer, DDFLIP_WAIT);
5861 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5862 hr = IDirectDrawSurface_Flip(backbuffer1, NULL, DDFLIP_WAIT);
5863 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5864 hr = IDirectDrawSurface_Flip(backbuffer2, NULL, DDFLIP_WAIT);
5865 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5866 hr = IDirectDrawSurface_Flip(backbuffer3, NULL, DDFLIP_WAIT);
5867 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5869 /* The Nvidia Geforce 7 driver cannot do a color fill on a texture backbuffer after
5870 * the backbuffer has been locked or GetSurfaceDesc has been called. Do it ourselves
5871 * as a workaround. */
5872 fill_surface(backbuffer1, 0xffff0000);
5873 fill_surface(backbuffer2, 0xff00ff00);
5874 fill_surface(backbuffer3, 0xff0000ff);
5876 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
5877 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5878 color = get_surface_color(backbuffer1, 320, 240);
5879 /* The testbot seems to just copy the contents of one surface to all the
5880 * others, instead of properly flipping. */
5881 ok(compare_color(color, 0x0000ff00, 1) || broken(sysmem_primary && compare_color(color, 0x000000ff, 1)),
5882 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5883 color = get_surface_color(backbuffer2, 320, 240);
5884 ok(compare_color(color, 0x000000ff, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5885 fill_surface(backbuffer3, 0xffff0000);
5887 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
5888 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5889 color = get_surface_color(backbuffer1, 320, 240);
5890 ok(compare_color(color, 0x000000ff, 1) || broken(sysmem_primary && compare_color(color, 0x00ff0000, 1)),
5891 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5892 color = get_surface_color(backbuffer2, 320, 240);
5893 ok(compare_color(color, 0x00ff0000, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5894 fill_surface(backbuffer3, 0xff00ff00);
5896 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
5897 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5898 color = get_surface_color(backbuffer1, 320, 240);
5899 ok(compare_color(color, 0x00ff0000, 1) || broken(sysmem_primary && compare_color(color, 0x0000ff00, 1)),
5900 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5901 color = get_surface_color(backbuffer2, 320, 240);
5902 ok(compare_color(color, 0x0000ff00, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5903 fill_surface(backbuffer3, 0xff0000ff);
5905 hr = IDirectDrawSurface_Flip(frontbuffer, backbuffer1, DDFLIP_WAIT);
5906 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5907 color = get_surface_color(backbuffer2, 320, 240);
5908 ok(compare_color(color, 0x0000ff00, 1) || broken(sysmem_primary && compare_color(color, 0x000000ff, 1)),
5909 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5910 color = get_surface_color(backbuffer3, 320, 240);
5911 ok(compare_color(color, 0x000000ff, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5912 fill_surface(backbuffer1, 0xffff0000);
5914 hr = IDirectDrawSurface_Flip(frontbuffer, backbuffer2, DDFLIP_WAIT);
5915 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5916 color = get_surface_color(backbuffer1, 320, 240);
5917 ok(compare_color(color, 0x00ff0000, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5918 color = get_surface_color(backbuffer3, 320, 240);
5919 ok(compare_color(color, 0x000000ff, 1) || broken(sysmem_primary && compare_color(color, 0x00ff0000, 1)),
5920 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5921 fill_surface(backbuffer2, 0xff00ff00);
5923 hr = IDirectDrawSurface_Flip(frontbuffer, backbuffer3, DDFLIP_WAIT);
5924 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5925 color = get_surface_color(backbuffer1, 320, 240);
5926 ok(compare_color(color, 0x00ff0000, 1) || broken(sysmem_primary && compare_color(color, 0x0000ff00, 1)),
5927 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5928 color = get_surface_color(backbuffer2, 320, 240);
5929 ok(compare_color(color, 0x0000ff00, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5931 IDirectDrawSurface_Release(backbuffer3);
5932 IDirectDrawSurface_Release(backbuffer2);
5933 IDirectDrawSurface_Release(backbuffer1);
5934 IDirectDrawSurface_Release(frontbuffer);
5937 refcount = IDirectDraw2_Release(ddraw);
5938 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
5939 DestroyWindow(window);
5942 static void reset_ddsd(DDSURFACEDESC *ddsd)
5944 memset(ddsd, 0, sizeof(*ddsd));
5945 ddsd->dwSize = sizeof(*ddsd);
5948 static void test_set_surface_desc(void)
5950 IDirectDraw2 *ddraw;
5951 HWND window;
5952 HRESULT hr;
5953 DDSURFACEDESC ddsd;
5954 IDirectDrawSurface *surface;
5955 IDirectDrawSurface3 *surface3;
5956 BYTE data[16*16*4];
5957 ULONG ref;
5958 unsigned int i;
5959 static const struct
5961 DWORD caps;
5962 BOOL supported;
5963 const char *name;
5965 invalid_caps_tests[] =
5967 {DDSCAPS_VIDEOMEMORY, FALSE, "videomemory plain"},
5968 {DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY, TRUE, "systemmemory texture"},
5969 {DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY, FALSE, "systemmemory primary"},
5972 window = create_window();
5973 ddraw = create_ddraw();
5974 ok(!!ddraw, "Failed to create a ddraw object.\n");
5975 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
5976 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
5978 reset_ddsd(&ddsd);
5979 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
5980 ddsd.dwWidth = 8;
5981 ddsd.dwHeight = 8;
5982 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
5983 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
5984 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
5985 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
5986 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
5987 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
5988 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
5990 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
5991 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5993 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
5994 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface3 interface, hr %#lx.\n", hr);
5995 IDirectDrawSurface_Release(surface);
5997 reset_ddsd(&ddsd);
5998 ddsd.dwFlags = DDSD_LPSURFACE;
5999 ddsd.lpSurface = data;
6000 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6001 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#lx.\n", hr);
6003 /* Redundantly setting the same lpSurface is not an error. */
6004 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6005 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#lx.\n", hr);
6006 hr = IDirectDrawSurface3_GetSurfaceDesc(surface3, &ddsd);
6007 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
6008 ok(!(ddsd.dwFlags & DDSD_LPSURFACE), "DDSD_LPSURFACE is set.\n");
6009 ok(ddsd.lpSurface == NULL, "lpSurface is %p, expected NULL.\n", ddsd.lpSurface);
6011 hr = IDirectDrawSurface3_Lock(surface3, NULL, &ddsd, 0, NULL);
6012 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
6013 ok(!(ddsd.dwFlags & DDSD_LPSURFACE), "DDSD_LPSURFACE is set.\n");
6014 ok(ddsd.lpSurface == data, "lpSurface is %p, expected %p.\n", data, data);
6015 hr = IDirectDrawSurface3_Unlock(surface3, NULL);
6016 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
6018 reset_ddsd(&ddsd);
6019 ddsd.dwFlags = DDSD_LPSURFACE;
6020 ddsd.lpSurface = data;
6021 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 1);
6022 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6024 ddsd.lpSurface = NULL;
6025 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6026 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6028 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, NULL, 0);
6029 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6031 hr = IDirectDrawSurface3_GetSurfaceDesc(surface3, &ddsd);
6032 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
6033 ok(ddsd.ddsCaps.dwCaps == (DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN),
6034 "Got unexpected caps %#lx.\n", ddsd.ddsCaps.dwCaps);
6036 /* Setting the caps is an error. This also means the original description cannot be reapplied. */
6037 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6038 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6040 ddsd.dwFlags = DDSD_CAPS;
6041 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6042 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6044 /* dwCaps = 0 is allowed, but ignored. */
6045 ddsd.dwFlags = DDSD_CAPS | DDSD_LPSURFACE;
6046 ddsd.lpSurface = data;
6047 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6048 ok(hr == DDERR_INVALIDCAPS, "Got hr %#lx.\n", hr);
6049 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
6050 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6051 ok(hr == DDERR_INVALIDCAPS, "Got hr %#lx.\n", hr);
6052 ddsd.ddsCaps.dwCaps = 0;
6053 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6054 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#lx.\n", hr);
6056 hr = IDirectDrawSurface3_GetSurfaceDesc(surface3, &ddsd);
6057 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
6058 ok(ddsd.ddsCaps.dwCaps == (DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN),
6059 "Got unexpected caps %#lx.\n", ddsd.ddsCaps.dwCaps);
6061 /* Setting the height is allowed, but it cannot be set to 0, and only if LPSURFACE is set too. */
6062 reset_ddsd(&ddsd);
6063 ddsd.dwFlags = DDSD_HEIGHT;
6064 ddsd.dwHeight = 16;
6065 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6066 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6068 ddsd.lpSurface = data;
6069 ddsd.dwFlags = DDSD_HEIGHT | DDSD_LPSURFACE;
6070 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6071 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#lx.\n", hr);
6073 ddsd.dwHeight = 0;
6074 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6075 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6077 reset_ddsd(&ddsd);
6078 hr = IDirectDrawSurface3_GetSurfaceDesc(surface3, &ddsd);
6079 ok(SUCCEEDED(hr), "GetSurfaceDesc failed, hr %#lx.\n", hr);
6080 ok(ddsd.dwWidth == 8, "SetSurfaceDesc: Expected width 8, got %lu.\n", ddsd.dwWidth);
6081 ok(ddsd.dwHeight == 16, "SetSurfaceDesc: Expected height 16, got %lu.\n", ddsd.dwHeight);
6083 /* Pitch and width can be set, but only together, and only with LPSURFACE. They must not be 0. */
6084 reset_ddsd(&ddsd);
6085 ddsd.dwFlags = DDSD_PITCH;
6086 U1(ddsd).lPitch = 8 * 4;
6087 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6088 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6090 ddsd.dwFlags = DDSD_WIDTH;
6091 ddsd.dwWidth = 16;
6092 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6093 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6095 ddsd.dwFlags = DDSD_PITCH | DDSD_LPSURFACE;
6096 ddsd.lpSurface = data;
6097 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6098 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6100 ddsd.dwFlags = DDSD_WIDTH | DDSD_LPSURFACE;
6101 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6102 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6104 ddsd.dwFlags = DDSD_WIDTH | DDSD_PITCH | DDSD_LPSURFACE;
6105 U1(ddsd).lPitch = 16 * 4;
6106 ddsd.dwWidth = 16;
6107 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6108 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#lx.\n", hr);
6110 reset_ddsd(&ddsd);
6111 hr = IDirectDrawSurface3_GetSurfaceDesc(surface3, &ddsd);
6112 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
6113 ok(ddsd.dwWidth == 16, "SetSurfaceDesc: Expected width 8, got %lu.\n", ddsd.dwWidth);
6114 ok(ddsd.dwHeight == 16, "SetSurfaceDesc: Expected height 16, got %lu.\n", ddsd.dwHeight);
6115 ok(U1(ddsd).lPitch == 16 * 4, "SetSurfaceDesc: Expected pitch 64, got %lu.\n", U1(ddsd).lPitch);
6117 /* The pitch must be 32 bit aligned and > 0, but is not verified for sanity otherwise.
6119 * VMware rejects those calls, but all real drivers accept it. Mark the VMware behavior broken. */
6120 ddsd.dwFlags = DDSD_WIDTH | DDSD_PITCH | DDSD_LPSURFACE;
6121 U1(ddsd).lPitch = 4 * 4;
6122 ddsd.lpSurface = data;
6123 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6124 ok(SUCCEEDED(hr) || broken(hr == DDERR_INVALIDPARAMS), "Failed to set surface desc, hr %#lx.\n", hr);
6126 U1(ddsd).lPitch = 4;
6127 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6128 ok(SUCCEEDED(hr) || broken(hr == DDERR_INVALIDPARAMS), "Failed to set surface desc, hr %#lx.\n", hr);
6130 U1(ddsd).lPitch = 16 * 4 + 1;
6131 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6132 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6134 U1(ddsd).lPitch = 16 * 4 + 3;
6135 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6136 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6138 U1(ddsd).lPitch = -4;
6139 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6140 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6142 U1(ddsd).lPitch = 16 * 4;
6143 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6144 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#lx.\n", hr);
6146 reset_ddsd(&ddsd);
6147 ddsd.dwFlags = DDSD_WIDTH | DDSD_PITCH | DDSD_LPSURFACE;
6148 U1(ddsd).lPitch = 0;
6149 ddsd.dwWidth = 16;
6150 ddsd.lpSurface = data;
6151 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6152 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6154 ddsd.dwFlags = DDSD_WIDTH | DDSD_PITCH | DDSD_LPSURFACE;
6155 U1(ddsd).lPitch = 16 * 4;
6156 ddsd.dwWidth = 0;
6157 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6158 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6160 /* Setting the pixelformat without LPSURFACE is an error, but with LPSURFACE it works. */
6161 ddsd.dwFlags = DDSD_PIXELFORMAT;
6162 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
6163 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
6164 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
6165 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
6166 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
6167 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
6168 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6169 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6171 ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_LPSURFACE;
6172 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6173 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#lx.\n", hr);
6175 /* Can't set color keys. */
6176 reset_ddsd(&ddsd);
6177 ddsd.dwFlags = DDSD_CKSRCBLT;
6178 ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00ff0000;
6179 ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00ff0000;
6180 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6181 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6183 ddsd.dwFlags = DDSD_CKSRCBLT | DDSD_LPSURFACE;
6184 ddsd.lpSurface = data;
6185 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6186 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
6188 IDirectDrawSurface3_Release(surface3);
6190 /* Test mipmap texture. */
6191 reset_ddsd(&ddsd);
6192 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_MIPMAPCOUNT;
6193 ddsd.dwWidth = 8;
6194 ddsd.dwHeight = 8;
6195 U2(ddsd).dwMipMapCount = 3;
6196 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
6197 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
6198 ok(hr == DD_OK || hr == DDERR_NODIRECTDRAWHW || hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
6200 if (FAILED(hr))
6202 skip("Mipmaps are not supported.\n");
6204 else
6206 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
6207 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6208 IDirectDrawSurface_Release(surface);
6210 /* Changing surface desc for mipmap fails even without changing any
6211 * parameters. */
6212 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6213 ok(hr == DDERR_INVALIDSURFACETYPE, "Got unexpected hr %#lx.\n", hr);
6215 reset_ddsd(&ddsd);
6216 ddsd.dwFlags = DDSD_LPSURFACE;
6217 ddsd.lpSurface = data;
6218 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6219 ok(hr == DDERR_INVALIDSURFACETYPE, "Got unexpected hr %#lx.\n", hr);
6220 IDirectDrawSurface3_Release(surface3);
6223 reset_ddsd(&ddsd);
6224 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_MIPMAPCOUNT;
6225 ddsd.dwWidth = 8;
6226 ddsd.dwHeight = 8;
6227 U2(ddsd).dwMipMapCount = 3;
6228 ddsd.lpSurface = data;
6229 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
6231 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
6232 ok(hr == DD_OK || hr == DDERR_NODIRECTDRAWHW || hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
6234 if (hr == DD_OK)
6236 static DDSCAPS caps = {DDSCAPS_TEXTURE};
6237 IDirectDrawSurface3 *surface2;
6239 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
6240 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6241 IDirectDrawSurface_Release(surface);
6243 hr = IDirectDrawSurface3_GetAttachedSurface(surface3, &caps, &surface2);
6244 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6245 reset_ddsd(&ddsd);
6246 hr = IDirectDrawSurface3_GetSurfaceDesc(surface2, &ddsd);
6247 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6248 ok(ddsd.dwWidth == 4, "Got unexpected dwWidth %lu.\n", ddsd.dwWidth);
6250 reset_ddsd(&ddsd);
6251 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE;
6252 ddsd.dwWidth = 16;
6253 ddsd.dwHeight = 16;
6254 U1(ddsd).lPitch = 16 * 4;
6255 ddsd.lpSurface = data;
6256 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6257 todo_wine ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6259 reset_ddsd(&ddsd);
6260 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE;
6261 ddsd.dwWidth = 8;
6262 ddsd.dwHeight = 8;
6263 U1(ddsd).lPitch = 8 * 4;
6264 ddsd.lpSurface = data;
6265 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6266 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6267 if (0)
6269 /* _Lock causes access violation on Windows. */
6270 reset_ddsd(&ddsd);
6271 hr = IDirectDrawSurface3_Lock(surface2, NULL, &ddsd, DDLOCK_WAIT, NULL);
6272 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6273 IDirectDrawSurface3_Unlock(surface2, NULL);
6276 if (0)
6278 /* Causes access violation on Windows. */
6279 reset_ddsd(&ddsd);
6280 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE;
6281 ddsd.dwWidth = 4;
6282 ddsd.dwHeight = 4;
6283 U1(ddsd).lPitch = 4 * 4;
6284 ddsd.lpSurface = data;
6285 hr = IDirectDrawSurface3_SetSurfaceDesc(surface2, &ddsd, 0);
6286 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6288 IDirectDrawSurface3_Release(surface2);
6289 IDirectDrawSurface3_Release(surface3);
6292 /* Test surface created with DDSD_LPSURFACE. */
6293 reset_ddsd(&ddsd);
6294 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_LPSURFACE | DDSD_PITCH;
6295 ddsd.dwWidth = 8;
6296 ddsd.dwHeight = 8;
6297 ddsd.lpSurface = data;
6298 U1(ddsd).lPitch = 8 * 4;
6299 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
6300 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
6301 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
6303 /* SetSurfaceDesc needs systemmemory surfaces.
6305 * As a sidenote, fourcc surfaces aren't allowed in sysmem, thus testing DDSD_LINEARSIZE is moot. */
6306 for (i = 0; i < ARRAY_SIZE(invalid_caps_tests); i++)
6308 reset_ddsd(&ddsd);
6309 ddsd.dwFlags = DDSD_CAPS;
6310 ddsd.ddsCaps.dwCaps = invalid_caps_tests[i].caps;
6311 if (!(invalid_caps_tests[i].caps & DDSCAPS_PRIMARYSURFACE))
6313 ddsd.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
6314 ddsd.dwWidth = 8;
6315 ddsd.dwHeight = 8;
6316 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
6317 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
6318 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
6319 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
6320 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
6321 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
6324 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
6325 ok(hr == DD_OK || hr == DDERR_NODIRECTDRAWHW, "Got unexpected hr %#lx.\n", hr);
6326 if (FAILED(hr))
6328 skip("Cannot create a %s surface, skipping vidmem SetSurfaceDesc test.\n",
6329 invalid_caps_tests[i].name);
6330 goto done;
6332 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
6333 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6334 IDirectDrawSurface_Release(surface);
6336 reset_ddsd(&ddsd);
6337 ddsd.dwFlags = DDSD_LPSURFACE;
6338 ddsd.lpSurface = data;
6339 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6340 if (invalid_caps_tests[i].supported)
6342 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6344 else
6346 ok(hr == DDERR_INVALIDSURFACETYPE, "SetSurfaceDesc on a %s surface returned %#lx.\n",
6347 invalid_caps_tests[i].name, hr);
6349 /* Check priority of error conditions. */
6350 ddsd.dwFlags = DDSD_WIDTH;
6351 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6352 ok(hr == DDERR_INVALIDSURFACETYPE, "SetSurfaceDesc on a %s surface returned %#lx.\n",
6353 invalid_caps_tests[i].name, hr);
6356 IDirectDrawSurface3_Release(surface3);
6359 done:
6360 ref = IDirectDraw2_Release(ddraw);
6361 ok(!ref, "Unexpected refcount %lu.\n", ref);
6362 DestroyWindow(window);
6365 static void test_user_memory_getdc(void)
6367 unsigned int data[16][16], x, y;
6368 IDirectDraw2 *ddraw;
6369 HWND window;
6370 HRESULT hr;
6371 DDSURFACEDESC ddsd;
6372 IDirectDrawSurface *surface;
6373 IDirectDrawSurface3 *surface3;
6374 HBITMAP bitmap;
6375 DIBSECTION dib;
6376 ULONG ref;
6377 int size;
6378 HDC dc;
6380 window = create_window();
6381 ddraw = create_ddraw();
6382 ok(!!ddraw, "Failed to create a ddraw object.\n");
6384 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
6385 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
6387 reset_ddsd(&ddsd);
6388 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
6389 ddsd.dwWidth = 16;
6390 ddsd.dwHeight = 16;
6391 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
6392 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
6393 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
6394 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
6395 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
6396 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
6397 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
6398 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
6399 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6401 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
6402 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface3 interface, hr %#lx.\n", hr);
6403 IDirectDrawSurface_Release(surface);
6405 memset(data, 0xaa, sizeof(data));
6406 reset_ddsd(&ddsd);
6407 ddsd.dwFlags = DDSD_LPSURFACE;
6408 ddsd.lpSurface = data;
6409 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6410 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#lx.\n", hr);
6412 hr = IDirectDrawSurface3_GetDC(surface3, &dc);
6413 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
6414 bitmap = GetCurrentObject(dc, OBJ_BITMAP);
6415 ok(!!bitmap, "Failed to get bitmap.\n");
6416 size = GetObjectA(bitmap, sizeof(dib), &dib);
6417 ok(size == sizeof(dib), "Got unexpected size %d.\n", size);
6418 ok(dib.dsBm.bmBits == data, "Got unexpected bits %p, expected %p.\n", dib.dsBm.bmBits, data);
6419 BitBlt(dc, 0, 0, 16, 8, NULL, 0, 0, WHITENESS);
6420 BitBlt(dc, 0, 8, 16, 8, NULL, 0, 0, BLACKNESS);
6421 hr = IDirectDrawSurface3_ReleaseDC(surface3, dc);
6422 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
6424 ok(data[0][0] == 0xffffffff, "Expected color 0xffffffff, got %#x.\n", data[0][0]);
6425 ok(data[15][15] == 0x00000000, "Expected color 0x00000000, got %#x.\n", data[15][15]);
6427 ddsd.dwFlags = DDSD_LPSURFACE | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH;
6428 ddsd.lpSurface = data;
6429 ddsd.dwWidth = 4;
6430 ddsd.dwHeight = 8;
6431 U1(ddsd).lPitch = sizeof(*data);
6432 hr = IDirectDrawSurface3_SetSurfaceDesc(surface3, &ddsd, 0);
6433 ok(SUCCEEDED(hr), "Failed to set surface desc, hr %#lx.\n", hr);
6435 memset(data, 0xaa, sizeof(data));
6436 hr = IDirectDrawSurface3_GetDC(surface3, &dc);
6437 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
6438 BitBlt(dc, 0, 0, 4, 8, NULL, 0, 0, BLACKNESS);
6439 BitBlt(dc, 1, 1, 2, 2, NULL, 0, 0, WHITENESS);
6440 hr = IDirectDrawSurface3_ReleaseDC(surface3, dc);
6441 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
6443 for (y = 0; y < 4; y++)
6445 for (x = 0; x < 4; x++)
6447 if ((x == 1 || x == 2) && (y == 1 || y == 2))
6448 ok(data[y][x] == 0xffffffff, "Expected color 0xffffffff on position %ux%u, got %#x.\n",
6449 x, y, data[y][x]);
6450 else
6451 ok(data[y][x] == 0x00000000, "Expected color 0xaaaaaaaa on position %ux%u, got %#x.\n",
6452 x, y, data[y][x]);
6455 ok(data[0][5] == 0xaaaaaaaa, "Expected color 0xaaaaaaaa on position 5x0, got %#x.\n",
6456 data[0][5]);
6457 ok(data[7][3] == 0x00000000, "Expected color 0x00000000 on position 3x7, got %#x.\n",
6458 data[7][3]);
6459 ok(data[7][4] == 0xaaaaaaaa, "Expected color 0xaaaaaaaa on position 4x7, got %#x.\n",
6460 data[7][4]);
6461 ok(data[8][0] == 0xaaaaaaaa, "Expected color 0xaaaaaaaa on position 0x8, got %#x.\n",
6462 data[8][0]);
6464 IDirectDrawSurface3_Release(surface3);
6465 ref = IDirectDraw2_Release(ddraw);
6466 ok(!ref, "Unexpected refcount %lu.\n", ref);
6467 DestroyWindow(window);
6470 static void test_sysmem_overlay(void)
6472 IDirectDraw2 *ddraw;
6473 HWND window;
6474 HRESULT hr;
6475 DDSURFACEDESC ddsd;
6476 IDirectDrawSurface *surface;
6477 ULONG ref;
6479 window = create_window();
6480 ddraw = create_ddraw();
6481 ok(!!ddraw, "Failed to create a ddraw object.\n");
6483 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
6484 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
6486 reset_ddsd(&ddsd);
6487 ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
6488 ddsd.dwWidth = 16;
6489 ddsd.dwHeight = 16;
6490 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OVERLAY;
6491 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
6492 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
6493 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
6494 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
6495 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
6496 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
6497 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
6498 ok(hr == DDERR_NOOVERLAYHW, "Got unexpected hr %#lx.\n", hr);
6500 ref = IDirectDraw2_Release(ddraw);
6501 ok(!ref, "Unexpected refcount %lu.\n", ref);
6502 DestroyWindow(window);
6505 static void test_primary_palette(void)
6507 DDSCAPS surface_caps = {DDSCAPS_FLIP};
6508 IDirectDrawSurface *primary, *backbuffer;
6509 PALETTEENTRY palette_entries[256];
6510 IDirectDrawPalette *palette, *tmp;
6511 DDSURFACEDESC surface_desc;
6512 IDirectDraw2 *ddraw;
6513 DWORD palette_caps;
6514 ULONG refcount;
6515 HWND window;
6516 HRESULT hr;
6518 window = create_window();
6519 ddraw = create_ddraw();
6520 ok(!!ddraw, "Failed to create a ddraw object.\n");
6521 if (FAILED(IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 8, 0, 0)))
6523 win_skip("Failed to set 8 bpp display mode, skipping test.\n");
6524 IDirectDraw2_Release(ddraw);
6525 DestroyWindow(window);
6526 return;
6528 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
6529 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
6531 memset(&surface_desc, 0, sizeof(surface_desc));
6532 surface_desc.dwSize = sizeof(surface_desc);
6533 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
6534 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
6535 surface_desc.dwBackBufferCount = 1;
6536 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
6537 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6538 hr = IDirectDrawSurface_GetAttachedSurface(primary, &surface_caps, &backbuffer);
6539 ok(SUCCEEDED(hr), "Failed to get attached surface, hr %#lx.\n", hr);
6541 memset(palette_entries, 0, sizeof(palette_entries));
6542 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256, palette_entries, &palette, NULL);
6543 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
6544 refcount = get_refcount((IUnknown *)palette);
6545 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
6547 hr = IDirectDrawPalette_GetCaps(palette, &palette_caps);
6548 ok(SUCCEEDED(hr), "Failed to get palette caps, hr %#lx.\n", hr);
6549 ok(palette_caps == (DDPCAPS_8BIT | DDPCAPS_ALLOW256), "Got unexpected palette caps %#lx.\n", palette_caps);
6551 hr = IDirectDrawSurface_SetPalette(primary, palette);
6552 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
6554 /* The Windows 8 testbot attaches the palette to the backbuffer as well,
6555 * and is generally somewhat broken with respect to 8 bpp / palette
6556 * handling. */
6557 if (SUCCEEDED(IDirectDrawSurface_GetPalette(backbuffer, &tmp)))
6559 win_skip("Broken palette handling detected, skipping tests.\n");
6560 IDirectDrawPalette_Release(tmp);
6561 IDirectDrawPalette_Release(palette);
6562 /* The Windows 8 testbot keeps extra references to the primary and
6563 * backbuffer while in 8 bpp mode. */
6564 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
6565 ok(SUCCEEDED(hr), "Failed to restore display mode, hr %#lx.\n", hr);
6566 goto done;
6569 refcount = get_refcount((IUnknown *)palette);
6570 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
6572 hr = IDirectDrawPalette_GetCaps(palette, &palette_caps);
6573 ok(SUCCEEDED(hr), "Failed to get palette caps, hr %#lx.\n", hr);
6574 ok(palette_caps == (DDPCAPS_8BIT | DDPCAPS_PRIMARYSURFACE | DDPCAPS_ALLOW256),
6575 "Got unexpected palette caps %#lx.\n", palette_caps);
6577 hr = IDirectDrawSurface_SetPalette(primary, NULL);
6578 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
6579 refcount = get_refcount((IUnknown *)palette);
6580 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
6582 hr = IDirectDrawPalette_GetCaps(palette, &palette_caps);
6583 ok(SUCCEEDED(hr), "Failed to get palette caps, hr %#lx.\n", hr);
6584 ok(palette_caps == (DDPCAPS_8BIT | DDPCAPS_ALLOW256), "Got unexpected palette caps %#lx.\n", palette_caps);
6586 hr = IDirectDrawSurface_SetPalette(primary, palette);
6587 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
6588 refcount = get_refcount((IUnknown *)palette);
6589 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
6591 hr = IDirectDrawSurface_GetPalette(primary, &tmp);
6592 ok(SUCCEEDED(hr), "Failed to get palette, hr %#lx.\n", hr);
6593 ok(tmp == palette, "Got unexpected palette %p, expected %p.\n", tmp, palette);
6594 IDirectDrawPalette_Release(tmp);
6595 hr = IDirectDrawSurface_GetPalette(backbuffer, &tmp);
6596 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#lx.\n", hr);
6598 refcount = IDirectDrawPalette_Release(palette);
6599 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
6600 refcount = IDirectDrawPalette_Release(palette);
6601 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6603 /* Note that this only seems to work when the palette is attached to the
6604 * primary surface. When attached to a regular surface, attempting to get
6605 * the palette here will cause an access violation. */
6606 hr = IDirectDrawSurface_GetPalette(primary, &tmp);
6607 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#lx.\n", hr);
6609 hr = IDirectDrawSurface_IsLost(primary);
6610 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
6612 memset(&surface_desc, 0, sizeof(surface_desc));
6613 surface_desc.dwSize = sizeof(surface_desc);
6614 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &surface_desc);
6615 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
6616 ok(surface_desc.dwWidth == 640, "Got unexpected surface width %lu.\n", surface_desc.dwWidth);
6617 ok(surface_desc.dwHeight == 480, "Got unexpected surface height %lu.\n", surface_desc.dwHeight);
6618 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == 8, "Got unexpected bit count %lu.\n",
6619 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount);
6621 hr = set_display_mode(ddraw, 640, 480);
6622 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
6624 memset(&surface_desc, 0, sizeof(surface_desc));
6625 surface_desc.dwSize = sizeof(surface_desc);
6626 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &surface_desc);
6627 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
6628 ok(surface_desc.dwWidth == 640, "Got unexpected surface width %lu.\n", surface_desc.dwWidth);
6629 ok(surface_desc.dwHeight == 480, "Got unexpected surface height %lu.\n", surface_desc.dwHeight);
6630 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == 32
6631 || U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == 24,
6632 "Got unexpected bit count %lu.\n", U1(surface_desc.ddpfPixelFormat).dwRGBBitCount);
6634 hr = IDirectDrawSurface_IsLost(primary);
6635 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
6636 hr = IDirectDrawSurface_Restore(primary);
6637 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
6638 hr = IDirectDrawSurface_IsLost(primary);
6639 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
6641 memset(&surface_desc, 0, sizeof(surface_desc));
6642 surface_desc.dwSize = sizeof(surface_desc);
6643 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &surface_desc);
6644 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
6645 ok(surface_desc.dwWidth == 640, "Got unexpected surface width %lu.\n", surface_desc.dwWidth);
6646 ok(surface_desc.dwHeight == 480, "Got unexpected surface height %lu.\n", surface_desc.dwHeight);
6647 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == 32
6648 || U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == 24,
6649 "Got unexpected bit count %lu.\n", U1(surface_desc.ddpfPixelFormat).dwRGBBitCount);
6651 done:
6652 refcount = IDirectDrawSurface_Release(backbuffer);
6653 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
6654 refcount = IDirectDrawSurface_Release(primary);
6655 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6656 refcount = IDirectDraw2_Release(ddraw);
6657 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6658 DestroyWindow(window);
6661 static HRESULT WINAPI surface_counter(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
6663 UINT *surface_count = context;
6665 ++(*surface_count);
6666 IDirectDrawSurface_Release(surface);
6668 return DDENUMRET_OK;
6671 static void test_surface_attachment(void)
6673 IDirectDrawSurface *surface1, *surface2, *surface3, *surface4;
6674 DDSCAPS caps = {DDSCAPS_TEXTURE};
6675 DDSURFACEDESC surface_desc;
6676 IDirectDraw2 *ddraw;
6677 UINT surface_count;
6678 ULONG refcount;
6679 HWND window;
6680 HRESULT hr;
6682 window = create_window();
6683 ddraw = create_ddraw();
6684 ok(!!ddraw, "Failed to create a ddraw object.\n");
6685 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
6686 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
6688 memset(&surface_desc, 0, sizeof(surface_desc));
6689 surface_desc.dwSize = sizeof(surface_desc);
6690 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
6691 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
6692 U2(surface_desc).dwMipMapCount = 3;
6693 surface_desc.dwWidth = 128;
6694 surface_desc.dwHeight = 128;
6695 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
6696 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6698 hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &surface2);
6699 ok(SUCCEEDED(hr), "Failed to get mip level, hr %#lx.\n", hr);
6700 hr = IDirectDrawSurface_GetAttachedSurface(surface2, &caps, &surface3);
6701 ok(SUCCEEDED(hr), "Failed to get mip level, hr %#lx.\n", hr);
6702 hr = IDirectDrawSurface_GetAttachedSurface(surface3, &caps, &surface4);
6703 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
6705 surface_count = 0;
6706 IDirectDrawSurface_EnumAttachedSurfaces(surface1, &surface_count, surface_counter);
6707 ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
6708 surface_count = 0;
6709 IDirectDrawSurface_EnumAttachedSurfaces(surface2, &surface_count, surface_counter);
6710 ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
6711 surface_count = 0;
6712 IDirectDrawSurface_EnumAttachedSurfaces(surface3, &surface_count, surface_counter);
6713 ok(!surface_count, "Got unexpected surface_count %u.\n", surface_count);
6715 memset(&surface_desc, 0, sizeof(surface_desc));
6716 surface_desc.dwSize = sizeof(surface_desc);
6717 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
6718 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6719 surface_desc.dwWidth = 16;
6720 surface_desc.dwHeight = 16;
6721 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
6722 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6724 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
6725 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6726 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
6727 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6728 hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface4);
6729 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6730 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface3);
6731 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6732 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface4);
6733 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6734 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface2);
6735 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6737 IDirectDrawSurface_Release(surface4);
6739 memset(&surface_desc, 0, sizeof(surface_desc));
6740 surface_desc.dwSize = sizeof(surface_desc);
6741 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
6742 surface_desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
6743 surface_desc.dwWidth = 16;
6744 surface_desc.dwHeight = 16;
6745 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
6746 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6748 if (SUCCEEDED(hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4)))
6750 skip("Running on refrast, skipping some tests.\n");
6751 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface4);
6752 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
6754 else
6756 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6757 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
6758 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6759 hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface4);
6760 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6761 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface3);
6762 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6763 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface4);
6764 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6765 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface2);
6766 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6769 IDirectDrawSurface_Release(surface4);
6770 IDirectDrawSurface_Release(surface3);
6771 IDirectDrawSurface_Release(surface2);
6772 IDirectDrawSurface_Release(surface1);
6774 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
6775 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
6777 /* Try a single primary and two offscreen plain surfaces. */
6778 memset(&surface_desc, 0, sizeof(surface_desc));
6779 surface_desc.dwSize = sizeof(surface_desc);
6780 surface_desc.dwFlags = DDSD_CAPS;
6781 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
6782 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
6783 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6785 memset(&surface_desc, 0, sizeof(surface_desc));
6786 surface_desc.dwSize = sizeof(surface_desc);
6787 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
6788 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
6789 surface_desc.dwWidth = registry_mode.dmPelsWidth;
6790 surface_desc.dwHeight = registry_mode.dmPelsHeight;
6791 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
6792 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6794 memset(&surface_desc, 0, sizeof(surface_desc));
6795 surface_desc.dwSize = sizeof(surface_desc);
6796 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
6797 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
6798 surface_desc.dwWidth = registry_mode.dmPelsWidth;
6799 surface_desc.dwHeight = registry_mode.dmPelsHeight;
6800 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
6801 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6803 /* This one has a different size. */
6804 memset(&surface_desc, 0, sizeof(surface_desc));
6805 surface_desc.dwSize = sizeof(surface_desc);
6806 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
6807 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
6808 surface_desc.dwWidth = 128;
6809 surface_desc.dwHeight = 128;
6810 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
6811 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6813 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
6814 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
6815 /* Try the reverse without detaching first. */
6816 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
6817 ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#lx.\n", hr);
6818 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
6819 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
6821 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
6822 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
6823 /* Try to detach reversed. */
6824 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
6825 ok(hr == DDERR_CANNOTDETACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6826 hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface1);
6827 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
6829 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3);
6830 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
6831 hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface3);
6832 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
6834 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
6835 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6836 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
6837 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6839 IDirectDrawSurface_Release(surface4);
6840 IDirectDrawSurface_Release(surface3);
6841 IDirectDrawSurface_Release(surface2);
6842 IDirectDrawSurface_Release(surface1);
6844 /* Test depth surfaces of different sizes. */
6845 memset(&surface_desc, 0, sizeof(surface_desc));
6846 surface_desc.dwSize = sizeof(surface_desc);
6847 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
6848 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
6849 surface_desc.dwWidth = 64;
6850 surface_desc.dwHeight = 64;
6851 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
6852 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
6854 memset(&surface_desc, 0, sizeof(surface_desc));
6855 surface_desc.dwSize = sizeof(surface_desc);
6856 surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
6857 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
6858 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
6859 surface_desc.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
6860 U1(surface_desc.ddpfPixelFormat).dwZBufferBitDepth = 16;
6861 U3(surface_desc.ddpfPixelFormat).dwZBitMask = 0x0000ffff;
6862 surface_desc.dwWidth = 32;
6863 surface_desc.dwHeight = 32;
6864 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
6865 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
6866 surface_desc.dwWidth = 64;
6867 surface_desc.dwHeight = 64;
6868 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
6869 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
6870 surface_desc.dwWidth = 128;
6871 surface_desc.dwHeight = 128;
6872 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
6873 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
6875 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
6876 todo_wine ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6877 if (SUCCEEDED(hr))
6878 IDirectDrawSurface2_DeleteAttachedSurface(surface1, 0, surface2);
6879 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface3);
6880 ok(hr == D3D_OK, "Failed to attach depth buffer, hr %#lx.\n", hr);
6881 hr = IDirectDrawSurface2_DeleteAttachedSurface(surface1, 0, surface3);
6882 ok(hr == D3D_OK, "Failed to detach depth buffer, hr %#lx.\n", hr);
6883 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
6884 todo_wine ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
6886 IDirectDrawSurface2_Release(surface4);
6887 IDirectDrawSurface2_Release(surface3);
6888 IDirectDrawSurface2_Release(surface2);
6889 IDirectDrawSurface2_Release(surface1);
6891 /* Test DeleteAttachedSurface() and automatic detachment of attached surfaces on release. */
6892 memset(&surface_desc, 0, sizeof(surface_desc));
6893 surface_desc.dwSize = sizeof(surface_desc);
6894 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
6895 surface_desc.dwWidth = 64;
6896 surface_desc.dwHeight = 64;
6897 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
6898 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
6899 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB; /* D3DFMT_R5G6B5 */
6900 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 16;
6901 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xf800;
6902 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x07e0;
6903 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x001f;
6904 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
6905 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6906 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
6907 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6909 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
6910 surface_desc.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
6911 U1(surface_desc.ddpfPixelFormat).dwZBufferBitDepth = 16;
6912 U3(surface_desc.ddpfPixelFormat).dwZBitMask = 0x0000ffff;
6913 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
6914 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6916 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
6917 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
6918 refcount = get_refcount((IUnknown *)surface2);
6919 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
6920 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
6921 ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#lx.\n", hr);
6923 /* Attaching while already attached to other surface. */
6924 hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface2);
6925 todo_wine ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
6926 hr = IDirectDrawSurface_DeleteAttachedSurface(surface3, 0, surface2);
6927 todo_wine ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
6928 IDirectDrawSurface_Release(surface3);
6930 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
6931 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
6932 refcount = get_refcount((IUnknown *)surface2);
6933 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
6935 /* Automatic detachment on release. */
6936 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
6937 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
6938 refcount = get_refcount((IUnknown *)surface2);
6939 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
6940 refcount = IDirectDrawSurface_Release(surface1);
6941 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6942 refcount = IDirectDrawSurface_Release(surface2);
6943 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6944 refcount = IDirectDraw2_Release(ddraw);
6945 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6946 DestroyWindow(window);
6949 static void test_pixel_format(void)
6951 HWND window, window2 = NULL;
6952 HDC hdc, hdc2 = NULL;
6953 HMODULE gl = NULL;
6954 int format, test_format;
6955 PIXELFORMATDESCRIPTOR pfd;
6956 IDirectDraw2 *ddraw = NULL;
6957 IDirectDrawClipper *clipper = NULL;
6958 DDSURFACEDESC ddsd;
6959 IDirectDrawSurface *primary = NULL, *offscreen;
6960 DDBLTFX fx;
6961 HRESULT hr;
6963 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6964 100, 100, 160, 160, NULL, NULL, NULL, NULL);
6965 if (!window)
6967 skip("Failed to create window\n");
6968 return;
6971 window2 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6972 100, 100, 160, 160, NULL, NULL, NULL, NULL);
6974 hdc = GetDC(window);
6975 if (!hdc)
6977 skip("Failed to get DC\n");
6978 goto cleanup;
6981 if (window2)
6982 hdc2 = GetDC(window2);
6984 gl = LoadLibraryA("opengl32.dll");
6985 ok(!!gl, "failed to load opengl32.dll; SetPixelFormat()/GetPixelFormat() may not work right\n");
6987 format = GetPixelFormat(hdc);
6988 ok(format == 0, "new window has pixel format %d\n", format);
6990 ZeroMemory(&pfd, sizeof(pfd));
6991 pfd.nSize = sizeof(pfd);
6992 pfd.nVersion = 1;
6993 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
6994 pfd.iPixelType = PFD_TYPE_RGBA;
6995 pfd.iLayerType = PFD_MAIN_PLANE;
6996 format = ChoosePixelFormat(hdc, &pfd);
6997 if (format <= 0)
6999 skip("no pixel format available\n");
7000 goto cleanup;
7003 if (!SetPixelFormat(hdc, format, &pfd) || GetPixelFormat(hdc) != format)
7005 skip("failed to set pixel format\n");
7006 goto cleanup;
7009 if (!hdc2 || !SetPixelFormat(hdc2, format, &pfd) || GetPixelFormat(hdc2) != format)
7011 skip("failed to set pixel format on second window\n");
7012 if (hdc2)
7014 ReleaseDC(window2, hdc2);
7015 hdc2 = NULL;
7019 ddraw = create_ddraw();
7020 ok(!!ddraw, "Failed to create a ddraw object.\n");
7022 test_format = GetPixelFormat(hdc);
7023 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
7025 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
7026 if (FAILED(hr))
7028 skip("Failed to set cooperative level, hr %#lx.\n", hr);
7029 goto cleanup;
7032 test_format = GetPixelFormat(hdc);
7033 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
7035 if (hdc2)
7037 hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL);
7038 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
7039 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window2);
7040 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
7042 test_format = GetPixelFormat(hdc);
7043 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
7045 test_format = GetPixelFormat(hdc2);
7046 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
7049 memset(&ddsd, 0, sizeof(ddsd));
7050 ddsd.dwSize = sizeof(ddsd);
7051 ddsd.dwFlags = DDSD_CAPS;
7052 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
7054 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
7055 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
7057 test_format = GetPixelFormat(hdc);
7058 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
7060 if (hdc2)
7062 test_format = GetPixelFormat(hdc2);
7063 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
7066 if (clipper)
7068 hr = IDirectDrawSurface_SetClipper(primary, clipper);
7069 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
7071 test_format = GetPixelFormat(hdc);
7072 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
7074 test_format = GetPixelFormat(hdc2);
7075 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
7078 memset(&ddsd, 0, sizeof(ddsd));
7079 ddsd.dwSize = sizeof(ddsd);
7080 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
7081 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
7082 ddsd.dwWidth = ddsd.dwHeight = 64;
7083 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &offscreen, NULL);
7084 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
7086 memset(&fx, 0, sizeof(fx));
7087 fx.dwSize = sizeof(fx);
7088 hr = IDirectDrawSurface_Blt(offscreen, NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
7089 ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#lx.\n", hr);
7091 test_format = GetPixelFormat(hdc);
7092 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
7094 hr = IDirectDrawSurface_Blt(primary, NULL, offscreen, NULL, DDBLT_WAIT, NULL);
7095 ok(SUCCEEDED(hr), "Failed to blit to primary surface, hr %#lx.\n", hr);
7097 test_format = GetPixelFormat(hdc);
7098 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
7100 if (hdc2)
7102 test_format = GetPixelFormat(hdc2);
7103 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
7106 IDirectDrawSurface_Release(offscreen);
7108 cleanup:
7109 if (primary) IDirectDrawSurface_Release(primary);
7110 if (clipper) IDirectDrawClipper_Release(clipper);
7111 if (ddraw) IDirectDraw2_Release(ddraw);
7112 if (gl) FreeLibrary(gl);
7113 if (hdc) ReleaseDC(window, hdc);
7114 if (hdc2) ReleaseDC(window2, hdc2);
7115 DestroyWindow(window);
7116 if (window2) DestroyWindow(window2);
7119 static void test_create_surface_pitch(void)
7121 DWORD vidmem_total = 0, vidmem_free = 0, vidmem_free2 = 0;
7122 DDSCAPS vidmem_caps = {DDSCAPS_TEXTURE};
7123 IDirectDrawSurface * surface, *primary;
7124 DDSURFACEDESC surface_desc;
7125 IDirectDraw2 *ddraw;
7126 unsigned int i;
7127 ULONG refcount;
7128 HWND window;
7129 HRESULT hr;
7130 void *mem;
7132 static const struct
7134 DWORD caps;
7135 DWORD flags_in;
7136 DWORD pitch_in;
7137 HRESULT hr;
7138 DWORD flags_out;
7139 DWORD pitch_out32;
7140 DWORD pitch_out64;
7142 test_data[] =
7144 /* 0 */
7145 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
7146 0, 0, DD_OK,
7147 DDSD_PITCH, 0x100, 0x100},
7148 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
7149 DDSD_PITCH, 0x104, DD_OK,
7150 DDSD_PITCH, 0x100, 0x100},
7151 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
7152 DDSD_PITCH, 0x0f8, DD_OK,
7153 DDSD_PITCH, 0x100, 0x100},
7154 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
7155 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDCAPS,
7156 0, 0, 0 },
7157 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
7158 0, 0, DD_OK,
7159 DDSD_PITCH, 0x100, 0x0fc},
7160 /* 5 */
7161 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
7162 DDSD_PITCH, 0x104, DD_OK,
7163 DDSD_PITCH, 0x100, 0x0fc},
7164 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
7165 DDSD_PITCH, 0x0f8, DD_OK,
7166 DDSD_PITCH, 0x100, 0x0fc},
7167 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
7168 DDSD_PITCH | DDSD_LINEARSIZE, 0, DD_OK,
7169 DDSD_PITCH, 0x100, 0x0fc},
7170 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
7171 DDSD_LPSURFACE, 0, DDERR_INVALIDPARAMS,
7172 0, 0, 0 },
7173 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
7174 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDPARAMS,
7175 0, 0, 0 },
7176 /* 10 */
7177 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN | DDSCAPS_ALLOCONLOAD,
7178 0, 0, DDERR_INVALIDCAPS,
7179 0, 0, 0 },
7180 {DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
7181 0, 0, DD_OK,
7182 DDSD_PITCH, 0x100, 0 },
7183 {DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE,
7184 0, 0, DD_OK,
7185 DDSD_PITCH, 0x100, 0 },
7186 {DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
7187 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDCAPS,
7188 0, 0, 0 },
7189 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN | DDSCAPS_ALLOCONLOAD,
7190 0, 0, DDERR_INVALIDCAPS,
7191 0, 0, 0 },
7192 /* 15 */
7193 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
7194 0, 0, DD_OK,
7195 DDSD_PITCH, 0x100, 0 },
7196 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
7197 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDPARAMS,
7198 0, 0, 0 },
7200 DWORD flags_mask = DDSD_PITCH | DDSD_LPSURFACE | DDSD_LINEARSIZE;
7202 window = create_window();
7203 ddraw = create_ddraw();
7204 ok(!!ddraw, "Failed to create a ddraw object.\n");
7205 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
7206 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
7208 mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((63 * 4) + 8) * 63);
7210 /* We need a primary surface and exclusive mode for video memory accounting to work
7211 * right on Windows. Otherwise it gives us junk data, like creating a video memory
7212 * surface freeing up memory. */
7213 memset(&surface_desc, 0, sizeof(surface_desc));
7214 surface_desc.dwSize = sizeof(surface_desc);
7215 surface_desc.dwFlags = DDSD_CAPS;
7216 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
7217 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
7218 ok(SUCCEEDED(hr), "Failed to create a primary surface, hr %#lx.\n", hr);
7220 hr = IDirectDraw2_GetAvailableVidMem(ddraw, &vidmem_caps, &vidmem_total, &vidmem_free);
7221 ok(SUCCEEDED(hr) || hr == DDERR_NODIRECTDRAWHW,
7222 "Failed to get available video memory, hr %#lx.\n", hr);
7224 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
7226 memset(&surface_desc, 0, sizeof(surface_desc));
7227 surface_desc.dwSize = sizeof(surface_desc);
7228 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | test_data[i].flags_in;
7229 surface_desc.ddsCaps.dwCaps = test_data[i].caps;
7230 surface_desc.dwWidth = 63;
7231 surface_desc.dwHeight = 63;
7232 U1(surface_desc).lPitch = test_data[i].pitch_in;
7233 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
7234 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
7235 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
7236 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
7237 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
7238 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
7239 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7240 if (test_data[i].flags_in & DDSD_LPSURFACE)
7242 HRESULT expected_hr = SUCCEEDED(test_data[i].hr) ? DDERR_INVALIDPARAMS : test_data[i].hr;
7243 ok(hr == expected_hr, "Test %u: Got unexpected hr %#lx, expected %#lx.\n", i, hr, expected_hr);
7244 surface_desc.lpSurface = mem;
7245 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7247 if ((test_data[i].caps & DDSCAPS_VIDEOMEMORY) && hr == DDERR_NODIRECTDRAWHW)
7248 continue;
7249 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#lx, expected %#lx.\n", i, hr, test_data[i].hr);
7250 if (FAILED(hr))
7251 continue;
7253 memset(&surface_desc, 0, sizeof(surface_desc));
7254 surface_desc.dwSize = sizeof(surface_desc);
7255 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
7256 ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#lx.\n", i, hr);
7257 ok((surface_desc.dwFlags & flags_mask) == test_data[i].flags_out,
7258 "Test %u: Got unexpected flags %#lx, expected %#lx.\n",
7259 i, surface_desc.dwFlags & flags_mask, test_data[i].flags_out);
7260 /* The pitch for textures seems to be implementation specific. */
7261 if (!(test_data[i].caps & DDSCAPS_TEXTURE))
7263 if (is_ddraw64 && test_data[i].pitch_out32 != test_data[i].pitch_out64)
7264 todo_wine ok(U1(surface_desc).lPitch == test_data[i].pitch_out64,
7265 "Test %u: Got unexpected pitch %#lx, expected %#lx.\n",
7266 i, U1(surface_desc).lPitch, test_data[i].pitch_out64);
7267 else
7268 ok(U1(surface_desc).lPitch == test_data[i].pitch_out32,
7269 "Test %u: Got unexpected pitch %#lx, expected %#lx.\n",
7270 i, U1(surface_desc).lPitch, test_data[i].pitch_out32);
7272 ok(!surface_desc.lpSurface, "Test %u: Got unexpected lpSurface %p.\n", i, surface_desc.lpSurface);
7274 hr = IDirectDraw2_GetAvailableVidMem(ddraw, &vidmem_caps, &vidmem_total, &vidmem_free2);
7275 ok(SUCCEEDED(hr) || hr == DDERR_NODIRECTDRAWHW,
7276 "Failed to get available video memory, hr %#lx.\n", hr);
7277 if (SUCCEEDED(hr) && surface_desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
7279 /* Star Trek Starfleet Academy cares about this bit here: That creating a system memory
7280 * resource does not influence available video memory. */
7281 ok(vidmem_free2 == vidmem_free, "Free video memory changed from %#lx to %#lx, test %u.\n",
7282 vidmem_free, vidmem_free2, i);
7284 else if (SUCCEEDED(hr) && surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
7286 /* DDSCAPS_ALLOCONLOAD does not seem to delay video memory allocation, at least not on
7287 * modern Windows.
7289 * The amount of video memory consumed is different from what dwHeight * lPitch would
7290 * suggest, although not by much. */
7291 ok(vidmem_free2 < vidmem_free,
7292 "Expected free video memory to change, but it did not, test %u.\n", i);
7295 IDirectDrawSurface_Release(surface);
7297 hr = IDirectDraw2_GetAvailableVidMem(ddraw, &vidmem_caps, &vidmem_total, &vidmem_free2);
7298 ok(SUCCEEDED(hr) || hr == DDERR_NODIRECTDRAWHW,
7299 "Failed to get available video memory, hr %#lx.\n", hr);
7300 ok(hr == DDERR_NODIRECTDRAWHW || vidmem_free2 == vidmem_free,
7301 "Free video memory changed from %#lx to %#lx, test %u.\n",
7302 vidmem_free, vidmem_free2, i);
7305 IDirectDrawSurface_Release(primary);
7306 HeapFree(GetProcessHeap(), 0, mem);
7307 refcount = IDirectDraw2_Release(ddraw);
7308 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7309 DestroyWindow(window);
7312 static void test_mipmap(void)
7314 IDirectDrawSurface *surface1;
7315 IDirectDrawSurface2 *surface, *surface_base, *surface_mip;
7316 unsigned int i, mipmap_count;
7317 DDSURFACEDESC surface_desc;
7318 IDirectDraw2 *ddraw;
7319 ULONG refcount;
7320 HWND window;
7321 HRESULT hr;
7322 DDSCAPS caps = {DDSCAPS_COMPLEX};
7323 DDCAPS hal_caps;
7325 static const struct
7327 DWORD flags;
7328 DWORD caps;
7329 DWORD width;
7330 DWORD height;
7331 DWORD mipmap_count_in;
7332 HRESULT hr;
7333 DWORD mipmap_count_out;
7335 tests[] =
7337 {DDSD_MIPMAPCOUNT, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 128, 32, 3, DD_OK, 3},
7338 {DDSD_MIPMAPCOUNT, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 128, 32, 0, DDERR_INVALIDPARAMS, 0},
7339 {0, DDSCAPS_TEXTURE | DDSCAPS_MIPMAP, 128, 32, 0, DD_OK, 1},
7340 {0, DDSCAPS_MIPMAP, 128, 32, 0, DDERR_INVALIDCAPS, 0},
7341 {0, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 128, 32, 0, DD_OK, 6},
7342 {0, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 32, 64, 0, DD_OK, 6},
7345 window = create_window();
7346 ddraw = create_ddraw();
7347 ok(!!ddraw, "Failed to create a ddraw object.\n");
7348 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
7349 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
7351 memset(&hal_caps, 0, sizeof(hal_caps));
7352 hal_caps.dwSize = sizeof(hal_caps);
7353 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, NULL);
7354 ok(SUCCEEDED(hr), "Failed to get caps, hr %#lx.\n", hr);
7355 if ((hal_caps.ddsCaps.dwCaps & (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP)) != (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP))
7357 skip("Mipmapped textures not supported, skipping tests.\n");
7358 IDirectDraw2_Release(ddraw);
7359 DestroyWindow(window);
7360 return;
7363 for (i = 0; i < ARRAY_SIZE(tests); ++i)
7365 memset(&surface_desc, 0, sizeof(surface_desc));
7366 surface_desc.dwSize = sizeof(surface_desc);
7367 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | tests[i].flags;
7368 surface_desc.ddsCaps.dwCaps = tests[i].caps;
7369 surface_desc.dwWidth = tests[i].width;
7370 surface_desc.dwHeight = tests[i].height;
7371 if (tests[i].flags & DDSD_MIPMAPCOUNT)
7372 U2(surface_desc).dwMipMapCount = tests[i].mipmap_count_in;
7373 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
7374 ok(hr == tests[i].hr, "Test %u: Got unexpected hr %#lx.\n", i, hr);
7375 if (FAILED(hr))
7376 continue;
7378 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface);
7379 ok(SUCCEEDED(hr), "Test %u: Failed to get IDirectDrawSurface2 interface, hr %#lx.\n", i, hr);
7380 IDirectDrawSurface_Release(surface1);
7382 memset(&surface_desc, 0, sizeof(surface_desc));
7383 surface_desc.dwSize = sizeof(surface_desc);
7384 hr = IDirectDrawSurface2_GetSurfaceDesc(surface, &surface_desc);
7385 ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#lx.\n", i, hr);
7386 ok(surface_desc.dwFlags & DDSD_MIPMAPCOUNT,
7387 "Test %u: Got unexpected flags %#lx.\n", i, surface_desc.dwFlags);
7388 ok(U2(surface_desc).dwMipMapCount == tests[i].mipmap_count_out,
7389 "Test %u: Got unexpected mipmap count %lu.\n", i, U2(surface_desc).dwMipMapCount);
7391 surface_base = surface;
7392 IDirectDrawSurface2_AddRef(surface_base);
7393 mipmap_count = U2(surface_desc).dwMipMapCount;
7394 while (mipmap_count > 1)
7396 hr = IDirectDrawSurface2_GetAttachedSurface(surface_base, &caps, &surface_mip);
7397 ok(SUCCEEDED(hr), "Test %u, %u: Failed to get attached surface, hr %#lx.\n", i, mipmap_count, hr);
7399 memset(&surface_desc, 0, sizeof(surface_desc));
7400 surface_desc.dwSize = sizeof(surface_desc);
7401 hr = IDirectDrawSurface2_GetSurfaceDesc(surface_base, &surface_desc);
7402 ok(SUCCEEDED(hr), "Test %u, %u: Failed to get surface desc, hr %#lx.\n", i, mipmap_count, hr);
7403 ok(surface_desc.dwFlags & DDSD_MIPMAPCOUNT,
7404 "Test %u, %u: Got unexpected flags %#lx.\n", i, mipmap_count, surface_desc.dwFlags);
7405 ok(U2(surface_desc).dwMipMapCount == mipmap_count,
7406 "Test %u, %u: Got unexpected mipmap count %lu.\n",
7407 i, mipmap_count, U2(surface_desc).dwMipMapCount);
7409 memset(&surface_desc, 0, sizeof(surface_desc));
7410 surface_desc.dwSize = sizeof(surface_desc);
7411 hr = IDirectDrawSurface2_Lock(surface_base, NULL, &surface_desc, 0, NULL);
7412 ok(SUCCEEDED(hr), "Test %u, %u: Failed to lock surface, hr %#lx.\n", i, mipmap_count, hr);
7413 ok(surface_desc.dwMipMapCount == mipmap_count,
7414 "Test %u, %u: unexpected change of mipmap count %lu.\n",
7415 i, mipmap_count, surface_desc.dwMipMapCount);
7416 memset(&surface_desc, 0, sizeof(surface_desc));
7417 surface_desc.dwSize = sizeof(surface_desc);
7418 hr = IDirectDrawSurface2_Lock(surface_mip, NULL, &surface_desc, 0, NULL);
7419 ok(SUCCEEDED(hr), "Test %u, %u: Failed to lock surface, hr %#lx.\n", i, mipmap_count, hr);
7420 ok(surface_desc.dwMipMapCount == mipmap_count - 1,
7421 "Test %u, %u: Got unexpected child mipmap count %lu.\n", i, mipmap_count, surface_desc.dwMipMapCount);
7422 IDirectDrawSurface2_Unlock(surface_mip, NULL);
7423 IDirectDrawSurface2_Unlock(surface_base, NULL);
7425 IDirectDrawSurface2_Release(surface_base);
7426 surface_base = surface_mip;
7427 --mipmap_count;
7429 IDirectDrawSurface2_Release(surface_base);
7431 IDirectDrawSurface2_Release(surface);
7434 refcount = IDirectDraw2_Release(ddraw);
7435 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7436 DestroyWindow(window);
7439 static void test_palette_complex(void)
7441 IDirectDrawSurface *surface1;
7442 IDirectDrawSurface2 *surface, *mipmap, *tmp;
7443 DDSURFACEDESC surface_desc;
7444 IDirectDraw2 *ddraw;
7445 IDirectDrawPalette *palette, *palette2, *palette_mipmap;
7446 ULONG refcount;
7447 HWND window;
7448 HRESULT hr;
7449 DDSCAPS caps = {DDSCAPS_COMPLEX};
7450 DDCAPS hal_caps;
7451 PALETTEENTRY palette_entries[256];
7452 unsigned int i;
7453 HDC dc;
7454 RGBQUAD rgbquad;
7455 UINT count;
7457 window = create_window();
7458 ddraw = create_ddraw();
7459 ok(!!ddraw, "Failed to create a ddraw object.\n");
7460 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
7461 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
7463 memset(&hal_caps, 0, sizeof(hal_caps));
7464 hal_caps.dwSize = sizeof(hal_caps);
7465 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, NULL);
7466 ok(SUCCEEDED(hr), "Failed to get caps, hr %#lx.\n", hr);
7467 if ((hal_caps.ddsCaps.dwCaps & (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP)) != (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP))
7469 skip("Mipmapped textures not supported, skipping mipmap palette test.\n");
7470 IDirectDraw2_Release(ddraw);
7471 DestroyWindow(window);
7472 return;
7475 memset(&surface_desc, 0, sizeof(surface_desc));
7476 surface_desc.dwSize = sizeof(surface_desc);
7477 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
7478 surface_desc.dwWidth = 128;
7479 surface_desc.dwHeight = 128;
7480 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
7481 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
7482 surface_desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
7483 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 8;
7484 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
7485 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
7486 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface);
7487 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface2 interface, hr %#lx.\n", hr);
7488 IDirectDrawSurface_Release(surface1);
7490 memset(palette_entries, 0, sizeof(palette_entries));
7491 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
7492 palette_entries, &palette, NULL);
7493 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
7495 memset(palette_entries, 0, sizeof(palette_entries));
7496 palette_entries[1].peRed = 0xff;
7497 palette_entries[1].peGreen = 0x80;
7498 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
7499 palette_entries, &palette_mipmap, NULL);
7500 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
7502 palette2 = (void *)0xdeadbeef;
7503 hr = IDirectDrawSurface2_GetPalette(surface, &palette2);
7504 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#lx.\n", hr);
7505 ok(!palette2, "Got unexpected palette %p.\n", palette2);
7506 hr = IDirectDrawSurface2_SetPalette(surface, palette);
7507 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
7508 hr = IDirectDrawSurface2_GetPalette(surface, &palette2);
7509 ok(SUCCEEDED(hr), "Failed to get palette, hr %#lx.\n", hr);
7510 ok(palette == palette2, "Got unexpected palette %p.\n", palette2);
7511 IDirectDrawPalette_Release(palette2);
7513 mipmap = surface;
7514 IDirectDrawSurface2_AddRef(mipmap);
7515 for (i = 0; i < 7; ++i)
7517 hr = IDirectDrawSurface2_GetAttachedSurface(mipmap, &caps, &tmp);
7518 ok(SUCCEEDED(hr), "Failed to get attached surface, i %u, hr %#lx.\n", i, hr);
7519 palette2 = (void *)0xdeadbeef;
7520 hr = IDirectDrawSurface2_GetPalette(tmp, &palette2);
7521 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#lx, i %u.\n", hr, i);
7522 ok(!palette2, "Got unexpected palette %p, i %u.\n", palette2, i);
7524 hr = IDirectDrawSurface2_SetPalette(tmp, palette_mipmap);
7525 ok(SUCCEEDED(hr), "Failed to set palette, i %u, hr %#lx.\n", i, hr);
7527 hr = IDirectDrawSurface2_GetPalette(tmp, &palette2);
7528 ok(SUCCEEDED(hr), "Failed to get palette, i %u, hr %#lx.\n", i, hr);
7529 ok(palette_mipmap == palette2, "Got unexpected palette %p.\n", palette2);
7530 IDirectDrawPalette_Release(palette2);
7532 hr = IDirectDrawSurface2_GetDC(tmp, &dc);
7533 ok(SUCCEEDED(hr), "Failed to get DC, i %u, hr %#lx.\n", i, hr);
7534 count = GetDIBColorTable(dc, 1, 1, &rgbquad);
7535 ok(count == 1, "Expected count 1, got %u.\n", count);
7536 ok(rgbquad.rgbRed == 0xff, "Expected rgbRed = 0xff, got %#x.\n", rgbquad.rgbRed);
7537 ok(rgbquad.rgbGreen == 0x80, "Expected rgbGreen = 0x80, got %#x.\n", rgbquad.rgbGreen);
7538 ok(rgbquad.rgbBlue == 0x0, "Expected rgbBlue = 0x0, got %#x.\n", rgbquad.rgbBlue);
7539 hr = IDirectDrawSurface2_ReleaseDC(tmp, dc);
7540 ok(SUCCEEDED(hr), "Failed to release DC, i %u, hr %#lx.\n", i, hr);
7542 IDirectDrawSurface2_Release(mipmap);
7543 mipmap = tmp;
7546 hr = IDirectDrawSurface2_GetAttachedSurface(mipmap, &caps, &tmp);
7547 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
7548 IDirectDrawSurface2_Release(mipmap);
7549 refcount = IDirectDrawSurface2_Release(surface);
7550 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7551 refcount = IDirectDrawPalette_Release(palette_mipmap);
7552 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7553 refcount = IDirectDrawPalette_Release(palette);
7554 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7556 refcount = IDirectDraw2_Release(ddraw);
7557 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7558 DestroyWindow(window);
7561 static void test_p8_blit(void)
7563 IDirectDrawSurface *src, *dst, *dst_p8;
7564 DDSURFACEDESC surface_desc;
7565 unsigned int color, x;
7566 IDirectDraw2 *ddraw;
7567 IDirectDrawPalette *palette, *palette2;
7568 ULONG refcount;
7569 HWND window;
7570 HRESULT hr;
7571 PALETTEENTRY palette_entries[256];
7572 DDBLTFX fx;
7573 BOOL is_warp;
7574 static const BYTE src_data[] = {0x10, 0x1, 0x2, 0x3, 0x4, 0x5, 0xff, 0x80};
7575 static const BYTE src_data2[] = {0x10, 0x5, 0x4, 0x3, 0x2, 0x1, 0xff, 0x80};
7576 static const BYTE expected_p8[] = {0x10, 0x1, 0x4, 0x3, 0x4, 0x5, 0xff, 0x80};
7577 static const unsigned int expected[] =
7579 0x00101010, 0x00010101, 0x00020202, 0x00030303,
7580 0x00040404, 0x00050505, 0x00ffffff, 0x00808080,
7583 window = create_window();
7584 ddraw = create_ddraw();
7585 ok(!!ddraw, "Failed to create a ddraw object.\n");
7586 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
7587 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
7588 is_warp = ddraw_is_warp(ddraw);
7590 memset(palette_entries, 0, sizeof(palette_entries));
7591 palette_entries[1].peGreen = 0xff;
7592 palette_entries[2].peBlue = 0xff;
7593 palette_entries[3].peFlags = 0xff;
7594 palette_entries[4].peRed = 0xff;
7595 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
7596 palette_entries, &palette, NULL);
7597 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
7598 palette_entries[1].peBlue = 0xff;
7599 palette_entries[2].peGreen = 0xff;
7600 palette_entries[3].peRed = 0xff;
7601 palette_entries[4].peFlags = 0x0;
7602 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
7603 palette_entries, &palette2, NULL);
7604 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
7606 memset(&surface_desc, 0, sizeof(surface_desc));
7607 surface_desc.dwSize = sizeof(surface_desc);
7608 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
7609 surface_desc.dwWidth = 8;
7610 surface_desc.dwHeight = 1;
7611 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
7612 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
7613 surface_desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
7614 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 8;
7615 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &src, NULL);
7616 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
7617 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst_p8, NULL);
7618 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
7619 hr = IDirectDrawSurface_SetPalette(dst_p8, palette2);
7620 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
7622 memset(&surface_desc, 0, sizeof(surface_desc));
7623 surface_desc.dwSize = sizeof(surface_desc);
7624 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
7625 surface_desc.dwWidth = 8;
7626 surface_desc.dwHeight = 1;
7627 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
7628 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
7629 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
7630 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
7631 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
7632 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
7633 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
7634 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
7635 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst, NULL);
7636 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
7638 memset(&surface_desc, 0, sizeof(surface_desc));
7639 surface_desc.dwSize = sizeof(surface_desc);
7640 hr = IDirectDrawSurface_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
7641 ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#lx.\n", hr);
7642 memcpy(surface_desc.lpSurface, src_data, sizeof(src_data));
7643 hr = IDirectDrawSurface_Unlock(src, NULL);
7644 ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#lx.\n", hr);
7646 hr = IDirectDrawSurface_Lock(dst_p8, NULL, &surface_desc, DDLOCK_WAIT, NULL);
7647 ok(SUCCEEDED(hr), "Failed to lock destination surface, hr %#lx.\n", hr);
7648 memcpy(surface_desc.lpSurface, src_data2, sizeof(src_data2));
7649 hr = IDirectDrawSurface_Unlock(dst_p8, NULL);
7650 ok(SUCCEEDED(hr), "Failed to unlock destination surface, hr %#lx.\n", hr);
7652 fx.dwSize = sizeof(fx);
7653 fx.dwFillColor = 0xdeadbeef;
7654 hr = IDirectDrawSurface_Blt(dst, NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
7655 ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr);
7657 hr = IDirectDrawSurface_SetPalette(src, palette);
7658 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
7659 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_WAIT, NULL);
7660 /* The r500 Windows 7 driver returns E_NOTIMPL. r200 on Windows XP works.
7661 * The Geforce 7 driver on Windows Vista returns E_FAIL. Newer Nvidia GPUs work. */
7662 ok(SUCCEEDED(hr) || broken(hr == E_NOTIMPL) || broken(hr == E_FAIL),
7663 "Failed to blit, hr %#lx.\n", hr);
7665 if (SUCCEEDED(hr))
7667 for (x = 0; x < ARRAY_SIZE(expected); x++)
7669 color = get_surface_color(dst, x, 0);
7670 /* WARP on 1709 and newer write zeroes on non-colorkeyed P8 -> RGB blits. For ckey
7671 * blits see below. */
7672 todo_wine ok(compare_color(color, expected[x], 0)
7673 || broken(is_warp && compare_color(color, 0x00000000, 0)),
7674 "Pixel %u: Got color %#x, expected %#x.\n",
7675 x, color, expected[x]);
7679 fx.ddckSrcColorkey.dwColorSpaceHighValue = 0x2;
7680 fx.ddckSrcColorkey.dwColorSpaceLowValue = 0x2;
7681 hr = IDirectDrawSurface7_Blt(dst_p8, NULL, src, NULL, DDBLT_WAIT | DDBLT_KEYSRCOVERRIDE, &fx);
7682 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
7684 hr = IDirectDrawSurface_Lock(dst_p8, NULL, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
7685 ok(SUCCEEDED(hr), "Failed to lock destination surface, hr %#lx.\n", hr);
7686 /* A color keyed P8 blit doesn't do anything on WARP - it just leaves the data in the destination
7687 * surface untouched. Error checking (DDBLT_KEYSRC without a key
7688 * for example) also works as expected.
7690 * Using DDBLT_KEYSRC instead of DDBLT_KEYSRCOVERRIDE doesn't change this. Doing this blit with
7691 * the display mode set to P8 doesn't help either. */
7692 ok(!memcmp(surface_desc.lpSurface, expected_p8, sizeof(expected_p8))
7693 || broken(is_warp && !memcmp(surface_desc.lpSurface, src_data2, sizeof(src_data2))),
7694 "Got unexpected P8 color key blit result.\n");
7695 hr = IDirectDrawSurface_Unlock(dst_p8, NULL);
7696 ok(SUCCEEDED(hr), "Failed to unlock destination surface, hr %#lx.\n", hr);
7698 IDirectDrawSurface_Release(src);
7699 IDirectDrawSurface_Release(dst);
7700 IDirectDrawSurface_Release(dst_p8);
7701 IDirectDrawPalette_Release(palette);
7702 IDirectDrawPalette_Release(palette2);
7704 refcount = IDirectDraw2_Release(ddraw);
7705 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7706 DestroyWindow(window);
7709 static void test_material(void)
7711 IDirect3DMaterial2 *background, *material;
7712 D3DMATERIALHANDLE mat_handle, tmp;
7713 IDirect3DViewport2 *viewport;
7714 IDirect3DDevice2 *device;
7715 IDirectDrawSurface *rt;
7716 unsigned int color, i;
7717 IDirectDraw2 *ddraw;
7718 ULONG refcount;
7719 HWND window;
7720 HRESULT hr;
7721 BOOL valid;
7723 static D3DVERTEX quad[] =
7725 {{-1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
7726 {{-1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
7727 {{ 1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
7728 {{ 1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
7730 static const struct
7732 BOOL material;
7733 D3DCOLOR expected_color;
7735 test_data[] =
7737 {TRUE, 0x0000ff00},
7738 {FALSE, 0x00ffffff},
7740 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
7742 window = create_window();
7743 ddraw = create_ddraw();
7744 ok(!!ddraw, "Failed to create a ddraw object.\n");
7745 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
7747 skip("Failed to create a 3D device, skipping test.\n");
7748 DestroyWindow(window);
7749 return;
7752 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
7753 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
7755 background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
7756 viewport = create_viewport(device, 0, 0, 640, 480);
7757 viewport_set_background(device, viewport, background);
7758 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
7759 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
7761 material = create_emissive_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
7762 hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle);
7763 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#lx.\n", hr);
7765 hr = IDirect3DDevice2_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
7766 ok(SUCCEEDED(hr), "Failed to get light state, hr %#lx.\n", hr);
7767 ok(!tmp, "Got unexpected material handle %#lx.\n", tmp);
7768 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
7769 ok(SUCCEEDED(hr), "Failed to set material state, hr %#lx.\n", hr);
7770 hr = IDirect3DDevice2_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
7771 ok(SUCCEEDED(hr), "Failed to get light state, hr %#lx.\n", hr);
7772 ok(tmp == mat_handle, "Got unexpected material handle %#lx, expected %#lx.\n", tmp, mat_handle);
7773 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, 0);
7774 ok(SUCCEEDED(hr), "Failed to set material state, hr %#lx.\n", hr);
7775 hr = IDirect3DDevice2_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
7776 ok(SUCCEEDED(hr), "Failed to get light state, hr %#lx.\n", hr);
7777 ok(!tmp, "Got unexpected material handle %#lx.\n", tmp);
7779 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
7781 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
7782 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
7784 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, test_data[i].material ? mat_handle : 0);
7785 ok(SUCCEEDED(hr), "Failed to set material state, hr %#lx.\n", hr);
7787 hr = IDirect3DDevice2_BeginScene(device);
7788 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
7789 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_VERTEX, quad, 4, 0);
7790 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
7791 hr = IDirect3DDevice2_EndScene(device);
7792 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
7793 color = get_surface_color(rt, 320, 240);
7794 ok(compare_color(color, test_data[i].expected_color, 1),
7795 "Got unexpected color 0x%08x, test %u.\n", color, i);
7798 destroy_material(material);
7799 material = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
7800 hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle);
7801 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#lx.\n", hr);
7803 hr = IDirect3DViewport2_SetBackground(viewport, mat_handle);
7804 ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#lx.\n", hr);
7805 hr = IDirect3DViewport2_GetBackground(viewport, &tmp, &valid);
7806 ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#lx.\n", hr);
7807 ok(tmp == mat_handle, "Got unexpected material handle %#lx, expected %#lx.\n", tmp, mat_handle);
7808 ok(valid, "Got unexpected valid %#x.\n", valid);
7809 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
7810 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
7811 color = get_surface_color(rt, 320, 240);
7812 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
7814 hr = IDirect3DViewport2_SetBackground(viewport, 0);
7815 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
7816 hr = IDirect3DViewport2_GetBackground(viewport, &tmp, &valid);
7817 ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#lx.\n", hr);
7818 ok(tmp == mat_handle, "Got unexpected material handle %#lx, expected %#lx.\n", tmp, mat_handle);
7819 ok(valid, "Got unexpected valid %#x.\n", valid);
7820 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
7821 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
7822 color = get_surface_color(rt, 320, 240);
7823 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
7825 destroy_viewport(device, viewport);
7826 viewport = create_viewport(device, 0, 0, 640, 480);
7828 hr = IDirect3DViewport2_GetBackground(viewport, &tmp, &valid);
7829 ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#lx.\n", hr);
7830 ok(!tmp, "Got unexpected material handle %#lx.\n", tmp);
7831 ok(!valid, "Got unexpected valid %#x.\n", valid);
7832 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
7833 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
7834 color = get_surface_color(rt, 320, 240);
7835 ok(compare_color(color, 0x00000000, 1), "Got unexpected color 0x%08x.\n", color);
7837 destroy_viewport(device, viewport);
7838 destroy_material(background);
7839 destroy_material(material);
7840 IDirectDrawSurface_Release(rt);
7841 refcount = IDirect3DDevice2_Release(device);
7842 ok(!refcount, "Device has %lu references left.\n", refcount);
7843 refcount = IDirectDraw2_Release(ddraw);
7844 ok(!refcount, "Ddraw object has %lu references left.\n", refcount);
7845 DestroyWindow(window);
7848 static void test_lighting(void)
7850 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
7851 static D3DMATRIX mat =
7853 1.0f, 0.0f, 0.0f, 0.0f,
7854 0.0f, 1.0f, 0.0f, 0.0f,
7855 0.0f, 0.0f, 1.0f, 0.0f,
7856 0.0f, 0.0f, 0.0f, 1.0f,
7858 mat_singular =
7860 1.0f, 0.0f, 1.0f, 0.0f,
7861 0.0f, 1.0f, 0.0f, 0.0f,
7862 1.0f, 0.0f, 1.0f, 0.0f,
7863 0.0f, 0.0f, 0.5f, 1.0f,
7865 mat_transf =
7867 0.0f, 0.0f, 1.0f, 0.0f,
7868 0.0f, 1.0f, 0.0f, 0.0f,
7869 -1.0f, 0.0f, 0.0f, 0.0f,
7870 10.f, 10.0f, 10.0f, 1.0f,
7872 mat_nonaffine =
7874 1.0f, 0.0f, 0.0f, 0.0f,
7875 0.0f, 1.0f, 0.0f, 0.0f,
7876 0.0f, 0.0f, 1.0f, -1.0f,
7877 10.f, 10.0f, 10.0f, 0.0f,
7879 static D3DLVERTEX unlitquad[] =
7881 {{-1.0f}, {-1.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
7882 {{-1.0f}, { 0.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
7883 {{ 0.0f}, { 0.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
7884 {{ 0.0f}, {-1.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
7886 litquad[] =
7888 {{-1.0f}, { 0.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
7889 {{-1.0f}, { 1.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
7890 {{ 0.0f}, { 1.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
7891 {{ 0.0f}, { 0.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
7893 static D3DVERTEX unlitnquad[] =
7895 {{0.0f}, {-1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
7896 {{0.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
7897 {{1.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
7898 {{1.0f}, {-1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
7900 litnquad[] =
7902 {{0.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
7903 {{0.0f}, { 1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
7904 {{1.0f}, { 1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
7905 {{1.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
7907 nquad[] =
7909 {{-1.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
7910 {{-1.0f}, { 1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
7911 {{ 1.0f}, { 1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
7912 {{ 1.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
7914 rotatedquad[] =
7916 {{-10.0f}, {-11.0f}, {11.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
7917 {{-10.0f}, { -9.0f}, {11.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
7918 {{-10.0f}, { -9.0f}, { 9.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
7919 {{-10.0f}, {-11.0f}, { 9.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
7921 translatedquad[] =
7923 {{-11.0f}, {-11.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
7924 {{-11.0f}, { -9.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
7925 {{ -9.0f}, { -9.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
7926 {{ -9.0f}, {-11.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
7928 static WORD indices[] = {0, 1, 2, 2, 3, 0};
7929 static const struct
7931 D3DMATRIX *world_matrix;
7932 void *quad;
7933 DWORD expected;
7934 const char *message;
7936 tests[] =
7938 {&mat, nquad, 0x000060ff, "Lit quad with light"},
7939 {&mat_singular, nquad, 0x00004db4, "Lit quad with singular world matrix"},
7940 {&mat_transf, rotatedquad, 0x000060ff, "Lit quad with transformation matrix"},
7941 {&mat_nonaffine, translatedquad, 0x000060ff, "Lit quad with non-affine matrix"},
7944 IDirect3DViewport2 *viewport, *viewport2;
7945 D3DMATERIALHANDLE mat_handle;
7946 IDirect3DMaterial2 *material;
7947 IDirect3DDevice2 *device;
7948 IDirectDrawSurface *rt;
7949 IDirect3DLight *light;
7950 unsigned int color, i;
7951 D3DLIGHT2 light_desc;
7952 IDirectDraw2 *ddraw;
7953 IDirect3D2 *d3d;
7954 ULONG refcount;
7955 HWND window;
7956 HRESULT hr;
7958 window = create_window();
7959 ddraw = create_ddraw();
7960 ok(!!ddraw, "Failed to create a ddraw object.\n");
7961 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
7963 skip("Failed to create a 3D device, skipping test.\n");
7964 DestroyWindow(window);
7965 return;
7968 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
7969 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7971 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
7972 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7974 viewport = create_viewport(device, 0, 0, 640, 480);
7975 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
7976 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7978 material = create_diffuse_and_ambient_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
7979 viewport_set_background(device, viewport, material);
7981 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
7982 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
7984 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat);
7985 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
7986 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat);
7987 ok(SUCCEEDED(hr), "Failed to set view transform, hr %#lx.\n", hr);
7988 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat);
7989 ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#lx.\n", hr);
7990 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, FALSE);
7991 ok(SUCCEEDED(hr), "Failed to disable zbuffer, hr %#lx.\n", hr);
7992 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_FOGENABLE, FALSE);
7993 ok(SUCCEEDED(hr), "Failed to disable fog, hr %#lx.\n", hr);
7994 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
7995 ok(SUCCEEDED(hr), "Failed to disable culling, hr %#lx.\n", hr);
7997 hr = IDirect3DDevice2_BeginScene(device);
7998 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
8000 /* There is no D3DRENDERSTATE_LIGHTING on ddraw < 7. */
8001 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
8002 ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#lx.\n", hr);
8003 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_LVERTEX, unlitquad,
8004 4, indices, 6, 0);
8005 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
8007 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, TRUE);
8008 ok(SUCCEEDED(hr), "Failed to enable lighting, hr %#lx.\n", hr);
8009 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_LVERTEX, litquad,
8010 4, indices, 6, 0);
8011 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
8013 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
8014 ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#lx.\n", hr);
8015 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX, unlitnquad,
8016 4, indices, 6, 0);
8017 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
8019 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, TRUE);
8020 ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#lx.\n", hr);
8021 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX, litnquad,
8022 4, indices, 6, 0);
8023 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
8025 hr = IDirect3DDevice2_EndScene(device);
8026 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
8028 color = get_surface_color(rt, 160, 360);
8029 ok(color == 0x00ff0000, "Unlit quad without normals has color 0x%08x.\n", color);
8030 color = get_surface_color(rt, 160, 120);
8031 ok(color == 0x0000ff00, "Lit quad without normals has color 0x%08x.\n", color);
8032 color = get_surface_color(rt, 480, 360);
8033 ok(color == 0x00ffffff, "Unlit quad with normals has color 0x%08x.\n", color);
8034 color = get_surface_color(rt, 480, 120);
8035 ok(color == 0x00ffffff, "Lit quad with normals has color 0x%08x.\n", color);
8037 hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle);
8038 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8039 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
8040 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8041 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_AMBIENT, 0xff002000);
8042 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8044 hr = IDirect3D2_CreateLight(d3d, &light, NULL);
8045 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8046 memset(&light_desc, 0, sizeof(light_desc));
8047 light_desc.dwSize = sizeof(light_desc);
8048 light_desc.dltType = D3DLIGHT_DIRECTIONAL;
8049 U1(light_desc.dcvColor).r = 0.0f;
8050 U2(light_desc.dcvColor).g = 0.25f;
8051 U3(light_desc.dcvColor).b = 1.0f;
8052 U4(light_desc.dcvColor).a = 1.0f;
8053 U3(light_desc.dvDirection).z = 1.0f;
8054 hr = IDirect3DLight_SetLight(light, (D3DLIGHT *)&light_desc);
8055 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8056 hr = IDirect3DViewport2_AddLight(viewport, light);
8057 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8058 hr = IDirect3DViewport2_AddLight(viewport, light);
8059 ok(hr == D3DERR_LIGHTHASVIEWPORT, "Got unexpected hr %#lx.\n", hr);
8061 viewport2 = create_viewport(device, 0, 0, 640, 480);
8062 hr = IDirect3DViewport2_AddLight(viewport2, light);
8063 ok(hr == D3DERR_LIGHTHASVIEWPORT, "Got unexpected hr %#lx.\n", hr);
8064 destroy_viewport(device, viewport2);
8066 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8067 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8069 hr = IDirect3DDevice2_BeginScene(device);
8070 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8072 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX, nquad,
8073 4, indices, 6, 0);
8074 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8076 hr = IDirect3DDevice2_EndScene(device);
8077 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8079 color = get_surface_color(rt, 320, 240);
8080 ok(color == 0x00002000, "Lit quad with no light has color 0x%08x.\n", color);
8082 light_desc.dwFlags = D3DLIGHT_ACTIVE;
8083 hr = IDirect3DLight_SetLight(light, (D3DLIGHT *)&light_desc);
8084 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8085 hr = IDirect3DViewport2_DeleteLight(viewport, light);
8086 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8087 light_desc.dwFlags = 0;
8088 hr = IDirect3DLight_GetLight(light, (D3DLIGHT *)&light_desc);
8089 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8090 ok(light_desc.dwFlags == D3DLIGHT_ACTIVE, "Got unexpected flags %#lx.\n", light_desc.dwFlags);
8092 hr = IDirect3DViewport2_AddLight(viewport, light);
8093 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8094 for (i = 0; i < ARRAY_SIZE(tests); ++i)
8096 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, tests[i].world_matrix);
8097 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
8099 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8100 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
8102 hr = IDirect3DDevice2_BeginScene(device);
8103 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
8105 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX,
8106 tests[i].quad, 4, indices, 6, 0);
8107 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
8109 hr = IDirect3DDevice2_EndScene(device);
8110 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
8112 color = get_surface_color(rt, 320, 240);
8113 ok(color == tests[i].expected, "%s has color 0x%08x.\n", tests[i].message, color);
8116 hr = IDirect3DViewport2_DeleteLight(viewport, light);
8117 ok(SUCCEEDED(hr), "Failed to remove a light from the viewport, hr %#lx.\n", hr);
8118 IDirect3DLight_Release(light);
8119 destroy_material(material);
8120 destroy_viewport(device, viewport);
8121 IDirectDrawSurface2_Release(rt);
8122 refcount = IDirect3DDevice2_Release(device);
8123 ok(!refcount, "Device has %lu references left.\n", refcount);
8124 IDirect3D2_Release(d3d);
8125 refcount = IDirectDraw2_Release(ddraw);
8126 ok(!refcount, "Ddraw object has %lu references left.\n", refcount);
8127 DestroyWindow(window);
8130 static void test_specular_lighting(void)
8132 static const unsigned int vertices_side = 5;
8133 const unsigned int indices_count = (vertices_side - 1) * (vertices_side - 1) * 2 * 3;
8134 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
8135 static D3DMATRIX mat =
8137 1.0f, 0.0f, 0.0f, 0.0f,
8138 0.0f, 1.0f, 0.0f, 0.0f,
8139 0.0f, 0.0f, 1.0f, 0.0f,
8140 0.0f, 0.0f, 0.0f, 1.0f,
8142 static D3DLIGHT2 directional =
8144 sizeof(D3DLIGHT2),
8145 D3DLIGHT_DIRECTIONAL,
8146 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
8147 {{0.0f}, {0.0f}, {0.0f}},
8148 {{0.0f}, {0.0f}, {1.0f}},
8150 point =
8152 sizeof(D3DLIGHT2),
8153 D3DLIGHT_POINT,
8154 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
8155 {{0.0f}, {0.0f}, {0.0f}},
8156 {{0.0f}, {0.0f}, {0.0f}},
8157 100.0f,
8158 0.0f,
8159 0.0f, 0.0f, 1.0f,
8161 spot =
8163 sizeof(D3DLIGHT2),
8164 D3DLIGHT_SPOT,
8165 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
8166 {{0.0f}, {0.0f}, {0.0f}},
8167 {{0.0f}, {0.0f}, {1.0f}},
8168 100.0f,
8169 1.0f,
8170 0.0f, 0.0f, 1.0f,
8171 M_PI / 12.0f, M_PI / 3.0f
8173 parallelpoint =
8175 sizeof(D3DLIGHT2),
8176 D3DLIGHT_PARALLELPOINT,
8177 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
8178 {{0.5f}, {0.0f}, {-1.0f}},
8179 {{0.0f}, {0.0f}, {0.0f}},
8181 point_side =
8183 sizeof(D3DLIGHT2),
8184 D3DLIGHT_POINT,
8185 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
8186 {{-1.1f}, {0.0f}, {1.1f}},
8187 {{0.0f}, {0.0f}, {0.0f}},
8188 100.0f,
8189 0.0f,
8190 1.0f, 0.0f, 0.0f,
8192 point_far =
8194 sizeof(D3DLIGHT2),
8195 D3DLIGHT_POINT,
8196 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
8197 {{0.0f}, {0.0f}, {0.1f}},
8198 {{0.0f}, {0.0f}, {0.0f}},
8199 1.0f,
8200 0.0f,
8201 1.0f, 0.0f, 0.0f,
8203 static const struct expected_color
8205 unsigned int x, y, color;
8207 expected_directional_local[] =
8209 {160, 120, 0x003c3c3c},
8210 {320, 120, 0x00717171},
8211 {480, 120, 0x003c3c3c},
8212 {160, 240, 0x00717171},
8213 {320, 240, 0x00ffffff},
8214 {480, 240, 0x00717171},
8215 {160, 360, 0x003c3c3c},
8216 {320, 360, 0x00717171},
8217 {480, 360, 0x003c3c3c},
8219 expected_point_local[] =
8221 {160, 120, 0x00000000},
8222 {320, 120, 0x00090909},
8223 {480, 120, 0x00000000},
8224 {160, 240, 0x00090909},
8225 {320, 240, 0x00fafafa},
8226 {480, 240, 0x00090909},
8227 {160, 360, 0x00000000},
8228 {320, 360, 0x00090909},
8229 {480, 360, 0x00000000},
8231 expected_spot_local[] =
8233 {160, 120, 0x00000000},
8234 {320, 120, 0x00020202},
8235 {480, 120, 0x00000000},
8236 {160, 240, 0x00020202},
8237 {320, 240, 0x00fafafa},
8238 {480, 240, 0x00020202},
8239 {160, 360, 0x00000000},
8240 {320, 360, 0x00020202},
8241 {480, 360, 0x00000000},
8243 expected_parallelpoint[] =
8245 {160, 120, 0x00050505},
8246 {320, 120, 0x002c2c2c},
8247 {480, 120, 0x006e6e6e},
8248 {160, 240, 0x00090909},
8249 {320, 240, 0x00717171},
8250 {480, 240, 0x00ffffff},
8251 {160, 360, 0x00050505},
8252 {320, 360, 0x002c2c2c},
8253 {480, 360, 0x006e6e6e},
8255 expected_point_far[] =
8257 {160, 120, 0x00000000},
8258 {320, 120, 0x00000000},
8259 {480, 120, 0x00000000},
8260 {160, 240, 0x00000000},
8261 {320, 240, 0x00ffffff},
8262 {480, 240, 0x00000000},
8263 {160, 360, 0x00000000},
8264 {320, 360, 0x00000000},
8265 {480, 360, 0x00000000},
8267 expected_zero[] =
8269 {160, 120, 0x00000000},
8270 {320, 120, 0x00000000},
8271 {480, 120, 0x00000000},
8272 {160, 240, 0x00000000},
8273 {320, 240, 0x00000000},
8274 {480, 240, 0x00000000},
8275 {160, 360, 0x00000000},
8276 {320, 360, 0x00000000},
8277 {480, 360, 0x00000000},
8279 static const struct
8281 D3DLIGHT2 *light;
8282 float specular_power;
8283 const struct expected_color *expected;
8284 unsigned int expected_count;
8286 tests[] =
8288 {&directional, 30.0f, expected_directional_local, ARRAY_SIZE(expected_directional_local)},
8289 {&point, 30.0f, expected_point_local, ARRAY_SIZE(expected_point_local)},
8290 {&spot, 30.0f, expected_spot_local, ARRAY_SIZE(expected_spot_local)},
8291 {&parallelpoint, 30.0f, expected_parallelpoint, ARRAY_SIZE(expected_parallelpoint)},
8292 {&point_side, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
8293 {&point_far, 1.0f, expected_point_far, ARRAY_SIZE(expected_point_far)},
8294 {&directional, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
8295 {&point, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
8296 {&spot, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
8297 {&parallelpoint, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
8298 {&point_far, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
8300 IDirect3D2 *d3d;
8301 IDirect3DDevice2 *device;
8302 IDirectDraw2 *ddraw;
8303 IDirectDrawSurface *rt;
8304 IDirect3DViewport2 *viewport;
8305 IDirect3DMaterial2 *material, *background_material;
8306 unsigned int color, i, j, x, y;
8307 IDirect3DLight *light;
8308 D3DMATERIALHANDLE mat_handle;
8309 ULONG refcount;
8310 HWND window;
8311 HRESULT hr;
8312 D3DVERTEX *quad;
8313 WORD *indices;
8315 window = create_window();
8316 ddraw = create_ddraw();
8317 ok(!!ddraw, "Failed to create a ddraw object.\n");
8318 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
8320 skip("Failed to create a 3D device, skipping test.\n");
8321 DestroyWindow(window);
8322 return;
8325 quad = HeapAlloc(GetProcessHeap(), 0, vertices_side * vertices_side * sizeof(*quad));
8326 indices = HeapAlloc(GetProcessHeap(), 0, indices_count * sizeof(*indices));
8327 for (i = 0, y = 0; y < vertices_side; ++y)
8329 for (x = 0; x < vertices_side; ++x)
8331 U1(quad[i]).x = x * 2.0f / (vertices_side - 1) - 1.0f;
8332 U2(quad[i]).y = y * 2.0f / (vertices_side - 1) - 1.0f;
8333 U3(quad[i]).z = 1.0f;
8334 U4(quad[i]).nx = 0.0f;
8335 U5(quad[i]).ny = 0.0f;
8336 U6(quad[i]).nz = -1.0f;
8337 U7(quad[i]).tu = 0.0f;
8338 U8(quad[i++]).tv = 0.0f;
8341 for (i = 0, y = 0; y < (vertices_side - 1); ++y)
8343 for (x = 0; x < (vertices_side - 1); ++x)
8345 indices[i++] = y * vertices_side + x + 1;
8346 indices[i++] = y * vertices_side + x;
8347 indices[i++] = (y + 1) * vertices_side + x;
8348 indices[i++] = y * vertices_side + x + 1;
8349 indices[i++] = (y + 1) * vertices_side + x;
8350 indices[i++] = (y + 1) * vertices_side + x + 1;
8354 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
8355 ok(SUCCEEDED(hr), "Failed to get D3D interface, hr %#lx.\n", hr);
8357 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
8358 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
8360 viewport = create_viewport(device, 0, 0, 640, 480);
8361 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
8362 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
8364 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat);
8365 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
8366 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat);
8367 ok(SUCCEEDED(hr), "Failed to set view transform, hr %#lx.\n", hr);
8368 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat);
8369 ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#lx.\n", hr);
8370 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, FALSE);
8371 ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#lx.\n", hr);
8372 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_FOGENABLE, FALSE);
8373 ok(SUCCEEDED(hr), "Failed to disable fog, hr %#lx.\n", hr);
8375 background_material = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
8376 viewport_set_background(device, viewport, background_material);
8378 hr = IDirect3D2_CreateLight(d3d, &light, NULL);
8379 ok(SUCCEEDED(hr), "Failed to create a light object, hr %#lx.\n", hr);
8380 hr = IDirect3DViewport2_AddLight(viewport, light);
8381 ok(SUCCEEDED(hr), "Failed to add a light to the viewport, hr %#lx.\n", hr);
8383 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SPECULARENABLE, TRUE);
8384 ok(SUCCEEDED(hr), "Failed to enable specular lighting, hr %#lx.\n", hr);
8386 for (i = 0; i < ARRAY_SIZE(tests); ++i)
8388 tests[i].light->dwFlags = D3DLIGHT_ACTIVE;
8389 hr = IDirect3DLight_SetLight(light, (D3DLIGHT *)tests[i].light);
8390 ok(SUCCEEDED(hr), "Failed to set light, hr %#lx.\n", hr);
8392 material = create_specular_material(device, 1.0f, 1.0f, 1.0f, 1.0f, tests[i].specular_power);
8393 hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle);
8394 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#lx.\n", hr);
8395 hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
8396 ok(SUCCEEDED(hr), "Failed to set material state, hr %#lx.\n", hr);
8398 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8399 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
8401 hr = IDirect3DDevice2_BeginScene(device);
8402 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
8404 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX,
8405 quad, vertices_side * vertices_side, indices, indices_count, 0);
8406 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
8408 hr = IDirect3DDevice2_EndScene(device);
8409 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
8411 for (j = 0; j < tests[i].expected_count; ++j)
8413 color = get_surface_color(rt, tests[i].expected[j].x, tests[i].expected[j].y);
8414 ok(compare_color(color, tests[i].expected[j].color, 1),
8415 "Expected color 0x%08x at location (%u, %u), got 0x%08x, case %u.\n",
8416 tests[i].expected[j].color, tests[i].expected[j].x,
8417 tests[i].expected[j].y, color, i);
8420 destroy_material(material);
8423 hr = IDirect3DViewport2_DeleteLight(viewport, light);
8424 ok(SUCCEEDED(hr), "Failed to remove a light from the viewport, hr %#lx.\n", hr);
8425 IDirect3DLight_Release(light);
8426 destroy_material(background_material);
8427 destroy_viewport(device, viewport);
8428 IDirectDrawSurface2_Release(rt);
8429 refcount = IDirect3DDevice2_Release(device);
8430 ok(!refcount, "Device has %lu references left.\n", refcount);
8431 IDirect3D2_Release(d3d);
8432 refcount = IDirectDraw2_Release(ddraw);
8433 ok(!refcount, "Ddraw object has %lu references left.\n", refcount);
8434 DestroyWindow(window);
8435 HeapFree(GetProcessHeap(), 0, indices);
8436 HeapFree(GetProcessHeap(), 0, quad);
8439 static void test_palette_gdi(void)
8441 IDirectDrawSurface *surface, *primary;
8442 DDSURFACEDESC surface_desc;
8443 unsigned int color, i;
8444 IDirectDraw2 *ddraw;
8445 IDirectDrawPalette *palette, *palette2;
8446 ULONG refcount;
8447 HWND window;
8448 HRESULT hr;
8449 PALETTEENTRY palette_entries[256];
8450 HDC dc;
8451 DDBLTFX fx;
8452 RECT r;
8454 /* On the Windows 8 testbot palette index 0 of the onscreen palette is forced to
8455 * r = 0, g = 0, b = 0. Do not attempt to set it to something else as this is
8456 * not the point of this test. */
8457 static const RGBQUAD expected1[] =
8459 {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x01, 0x00}, {0x00, 0x02, 0x00, 0x00},
8460 {0x03, 0x00, 0x00, 0x00}, {0x15, 0x14, 0x13, 0x00},
8462 static const RGBQUAD expected2[] =
8464 {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x01, 0x00}, {0x00, 0x02, 0x00, 0x00},
8465 {0x03, 0x00, 0x00, 0x00}, {0x25, 0x24, 0x23, 0x00},
8467 static const RGBQUAD expected3[] =
8469 {0x00, 0x00, 0x00, 0x00}, {0x40, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x40, 0x00},
8470 {0x00, 0x40, 0x00, 0x00}, {0x56, 0x34, 0x12, 0x00},
8472 HPALETTE ddraw_palette_handle;
8473 /* Similar to index 0, index 255 is r = 0xff, g = 0xff, b = 0xff on the Win8 VMs. */
8474 RGBQUAD rgbquad[255];
8475 static const RGBQUAD rgb_zero = {0, 0, 0, 0};
8477 window = create_window();
8478 ddraw = create_ddraw();
8479 ok(!!ddraw, "Failed to create a ddraw object.\n");
8480 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
8481 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
8483 memset(&surface_desc, 0, sizeof(surface_desc));
8484 surface_desc.dwSize = sizeof(surface_desc);
8485 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
8486 surface_desc.dwWidth = 16;
8487 surface_desc.dwHeight = 16;
8488 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
8489 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
8490 surface_desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
8491 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 8;
8492 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
8493 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
8495 /* Avoid colors from the Windows default palette. */
8496 memset(palette_entries, 0, sizeof(palette_entries));
8497 palette_entries[1].peRed = 0x01;
8498 palette_entries[2].peGreen = 0x02;
8499 palette_entries[3].peBlue = 0x03;
8500 palette_entries[4].peRed = 0x13;
8501 palette_entries[4].peGreen = 0x14;
8502 palette_entries[4].peBlue = 0x15;
8503 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
8504 palette_entries, &palette, NULL);
8505 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
8507 /* If there is no palette assigned and the display mode is not 8 bpp, some
8508 * drivers refuse to create a DC while others allow it. If a DC is created,
8509 * the DIB color table is uninitialized and contains random colors. No error
8510 * is generated when trying to read pixels and random garbage is returned.
8512 * The most likely explanation is that if the driver creates a DC, it (or
8513 * the higher-level runtime) uses GetSystemPaletteEntries to find the
8514 * palette, but GetSystemPaletteEntries fails when bpp > 8 and the palette
8515 * contains uninitialized garbage. See comments below for the P8 case. */
8517 hr = IDirectDrawSurface_SetPalette(surface, palette);
8518 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
8519 hr = IDirectDrawSurface_GetDC(surface, &dc);
8520 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
8521 ddraw_palette_handle = SelectPalette(dc, GetStockObject(DEFAULT_PALETTE), FALSE);
8522 ok(ddraw_palette_handle == GetStockObject(DEFAULT_PALETTE),
8523 "Got unexpected palette %p, expected %p.\n",
8524 ddraw_palette_handle, GetStockObject(DEFAULT_PALETTE));
8526 i = GetDIBColorTable(dc, 0, ARRAY_SIZE(rgbquad), rgbquad);
8527 ok(i == ARRAY_SIZE(rgbquad), "Expected count 255, got %u.\n", i);
8528 for (i = 0; i < ARRAY_SIZE(expected1); i++)
8530 ok(!memcmp(&rgbquad[i], &expected1[i], sizeof(rgbquad[i])),
8531 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
8532 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
8533 expected1[i].rgbRed, expected1[i].rgbGreen, expected1[i].rgbBlue);
8535 for (; i < ARRAY_SIZE(rgbquad); i++)
8537 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
8538 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
8539 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
8542 /* Update the palette while the DC is in use. This does not modify the DC. */
8543 palette_entries[4].peRed = 0x23;
8544 palette_entries[4].peGreen = 0x24;
8545 palette_entries[4].peBlue = 0x25;
8546 hr = IDirectDrawPalette_SetEntries(palette, 0, 4, 1, &palette_entries[4]);
8547 ok(SUCCEEDED(hr), "Failed to set palette entries, hr %#lx.\n", hr);
8549 i = GetDIBColorTable(dc, 4, 1, &rgbquad[4]);
8550 ok(i == 1, "Expected count 1, got %u.\n", i);
8551 ok(!memcmp(&rgbquad[4], &expected1[4], sizeof(rgbquad[4])),
8552 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
8553 i, rgbquad[4].rgbRed, rgbquad[4].rgbGreen, rgbquad[4].rgbBlue,
8554 expected1[4].rgbRed, expected1[4].rgbGreen, expected1[4].rgbBlue);
8556 /* Neither does re-setting the palette. */
8557 hr = IDirectDrawSurface_SetPalette(surface, NULL);
8558 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
8559 hr = IDirectDrawSurface_SetPalette(surface, palette);
8560 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
8562 i = GetDIBColorTable(dc, 4, 1, &rgbquad[4]);
8563 ok(i == 1, "Expected count 1, got %u.\n", i);
8564 ok(!memcmp(&rgbquad[4], &expected1[4], sizeof(rgbquad[4])),
8565 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
8566 i, rgbquad[4].rgbRed, rgbquad[4].rgbGreen, rgbquad[4].rgbBlue,
8567 expected1[4].rgbRed, expected1[4].rgbGreen, expected1[4].rgbBlue);
8569 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
8570 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
8572 /* Refresh the DC. This updates the palette. */
8573 hr = IDirectDrawSurface_GetDC(surface, &dc);
8574 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
8575 i = GetDIBColorTable(dc, 0, ARRAY_SIZE(rgbquad), rgbquad);
8576 ok(i == ARRAY_SIZE(rgbquad), "Expected count 255, got %u.\n", i);
8577 for (i = 0; i < ARRAY_SIZE(expected2); i++)
8579 ok(!memcmp(&rgbquad[i], &expected2[i], sizeof(rgbquad[i])),
8580 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
8581 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
8582 expected2[i].rgbRed, expected2[i].rgbGreen, expected2[i].rgbBlue);
8584 for (; i < ARRAY_SIZE(rgbquad); i++)
8586 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
8587 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
8588 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
8590 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
8591 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
8593 refcount = IDirectDrawSurface_Release(surface);
8594 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
8596 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
8597 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
8598 if (FAILED(IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 8, 0, 0)))
8600 win_skip("Failed to set 8 bpp display mode, skipping test.\n");
8601 IDirectDrawPalette_Release(palette);
8602 IDirectDraw2_Release(ddraw);
8603 DestroyWindow(window);
8604 return;
8606 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
8608 memset(&surface_desc, 0, sizeof(surface_desc));
8609 surface_desc.dwSize = sizeof(surface_desc);
8610 surface_desc.dwFlags = DDSD_CAPS;
8611 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
8612 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
8613 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
8615 memset(&fx, 0, sizeof(fx));
8616 fx.dwSize = sizeof(fx);
8617 U5(fx).dwFillColor = 3;
8618 SetRect(&r, 0, 0, 319, 479);
8619 hr = IDirectDrawSurface_Blt(primary, &r, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8620 ok(SUCCEEDED(hr), "Failed to clear surface, hr %#lx.\n", hr);
8621 SetRect(&r, 320, 0, 639, 479);
8622 U5(fx).dwFillColor = 4;
8623 hr = IDirectDrawSurface_Blt(primary, &r, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8624 ok(SUCCEEDED(hr), "Failed to clear surface, hr %#lx.\n", hr);
8626 hr = IDirectDrawSurface_SetPalette(primary, palette);
8627 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
8628 hr = IDirectDrawSurface_GetDC(primary, &dc);
8629 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
8631 color = GetPixel(dc, 160, 240);
8632 ok(color == 0x00030000, "Clear index 3: Got unexpected color 0x%08x.\n", color);
8633 color = GetPixel(dc, 480, 240);
8634 ok(color == 0x00252423, "Clear index 4: Got unexpected color 0x%08x.\n", color);
8636 ddraw_palette_handle = SelectPalette(dc, GetStockObject(DEFAULT_PALETTE), FALSE);
8637 ok(ddraw_palette_handle == GetStockObject(DEFAULT_PALETTE),
8638 "Got unexpected palette %p, expected %p.\n",
8639 ddraw_palette_handle, GetStockObject(DEFAULT_PALETTE));
8640 SelectPalette(dc, ddraw_palette_handle, FALSE);
8642 /* The primary uses the system palette. In exclusive mode, the system palette matches
8643 * the ddraw palette attached to the primary, so the result is what you would expect
8644 * from a regular surface. Tests for the interaction between the ddraw palette and
8645 * the system palette are not included pending an application that depends on this.
8646 * The relation between those causes problems on Windows Vista and newer for games
8647 * like Age of Empires or StarCraft. Don't emulate it without a real need. */
8648 i = GetDIBColorTable(dc, 0, ARRAY_SIZE(rgbquad), rgbquad);
8649 ok(i == ARRAY_SIZE(rgbquad), "Expected count 255, got %u.\n", i);
8650 for (i = 0; i < ARRAY_SIZE(expected2); i++)
8652 ok(!memcmp(&rgbquad[i], &expected2[i], sizeof(rgbquad[i])),
8653 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
8654 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
8655 expected2[i].rgbRed, expected2[i].rgbGreen, expected2[i].rgbBlue);
8657 for (; i < ARRAY_SIZE(rgbquad); i++)
8659 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
8660 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
8661 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
8663 hr = IDirectDrawSurface_ReleaseDC(primary, dc);
8664 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
8666 memset(&surface_desc, 0, sizeof(surface_desc));
8667 surface_desc.dwSize = sizeof(surface_desc);
8668 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
8669 surface_desc.dwWidth = 16;
8670 surface_desc.dwHeight = 16;
8671 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
8672 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
8673 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
8675 /* Here the offscreen surface appears to use the primary's palette,
8676 * but in all likelihood it is actually the system palette. */
8677 hr = IDirectDrawSurface_GetDC(surface, &dc);
8678 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
8679 i = GetDIBColorTable(dc, 0, ARRAY_SIZE(rgbquad), rgbquad);
8680 ok(i == ARRAY_SIZE(rgbquad), "Expected count 255, got %u.\n", i);
8681 for (i = 0; i < ARRAY_SIZE(expected2); i++)
8683 ok(!memcmp(&rgbquad[i], &expected2[i], sizeof(rgbquad[i])),
8684 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
8685 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
8686 expected2[i].rgbRed, expected2[i].rgbGreen, expected2[i].rgbBlue);
8688 for (; i < ARRAY_SIZE(rgbquad); i++)
8690 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
8691 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
8692 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
8694 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
8695 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
8697 /* On real hardware a change to the primary surface's palette applies immediately,
8698 * even on device contexts from offscreen surfaces that do not have their own
8699 * palette. On the testbot VMs this is not the case. Don't test this until we
8700 * know of an application that depends on this. */
8702 memset(palette_entries, 0, sizeof(palette_entries));
8703 palette_entries[1].peBlue = 0x40;
8704 palette_entries[2].peRed = 0x40;
8705 palette_entries[3].peGreen = 0x40;
8706 palette_entries[4].peRed = 0x12;
8707 palette_entries[4].peGreen = 0x34;
8708 palette_entries[4].peBlue = 0x56;
8709 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
8710 palette_entries, &palette2, NULL);
8711 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
8712 hr = IDirectDrawSurface_SetPalette(surface, palette2);
8713 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
8715 /* A palette assigned to the offscreen surface overrides the primary / system
8716 * palette. */
8717 hr = IDirectDrawSurface_GetDC(surface, &dc);
8718 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
8719 i = GetDIBColorTable(dc, 0, ARRAY_SIZE(rgbquad), rgbquad);
8720 ok(i == ARRAY_SIZE(rgbquad), "Expected count 255, got %u.\n", i);
8721 for (i = 0; i < ARRAY_SIZE(expected3); i++)
8723 ok(!memcmp(&rgbquad[i], &expected3[i], sizeof(rgbquad[i])),
8724 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
8725 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
8726 expected3[i].rgbRed, expected3[i].rgbGreen, expected3[i].rgbBlue);
8728 for (; i < ARRAY_SIZE(rgbquad); i++)
8730 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
8731 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
8732 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
8734 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
8735 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
8737 refcount = IDirectDrawSurface_Release(surface);
8738 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
8740 /* The Windows 8 testbot keeps extra references to the primary and
8741 * backbuffer while in 8 bpp mode. */
8742 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
8743 ok(SUCCEEDED(hr), "Failed to restore display mode, hr %#lx.\n", hr);
8745 refcount = IDirectDrawSurface_Release(primary);
8746 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
8747 refcount = IDirectDrawPalette_Release(palette2);
8748 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
8749 refcount = IDirectDrawPalette_Release(palette);
8750 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
8751 refcount = IDirectDraw2_Release(ddraw);
8752 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
8753 DestroyWindow(window);
8756 static void test_palette_alpha(void)
8758 IDirectDrawSurface *surface1;
8759 IDirectDrawSurface2 *surface;
8760 DDSURFACEDESC surface_desc;
8761 IDirectDraw2 *ddraw;
8762 IDirectDrawPalette *palette;
8763 ULONG refcount;
8764 HWND window;
8765 HRESULT hr;
8766 PALETTEENTRY palette_entries[256];
8767 unsigned int i;
8768 static const struct
8770 DWORD caps, flags;
8771 BOOL attach_allowed;
8772 const char *name;
8774 test_data[] =
8776 {DDSCAPS_OFFSCREENPLAIN, DDSD_WIDTH | DDSD_HEIGHT, FALSE, "offscreenplain"},
8777 {DDSCAPS_TEXTURE, DDSD_WIDTH | DDSD_HEIGHT, TRUE, "texture"},
8778 {DDSCAPS_PRIMARYSURFACE, 0, FALSE, "primary"}
8781 window = create_window();
8782 ddraw = create_ddraw();
8783 ok(!!ddraw, "Failed to create a ddraw object.\n");
8784 if (FAILED(IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 8, 0, 0)))
8786 win_skip("Failed to set 8 bpp display mode, skipping test.\n");
8787 IDirectDraw2_Release(ddraw);
8788 DestroyWindow(window);
8789 return;
8791 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
8792 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
8794 memset(palette_entries, 0, sizeof(palette_entries));
8795 palette_entries[1].peFlags = 0x42;
8796 palette_entries[2].peFlags = 0xff;
8797 palette_entries[3].peFlags = 0x80;
8798 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, palette_entries, &palette, NULL);
8799 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
8801 memset(palette_entries, 0x66, sizeof(palette_entries));
8802 hr = IDirectDrawPalette_GetEntries(palette, 0, 1, 4, palette_entries);
8803 ok(SUCCEEDED(hr), "Failed to get palette entries, hr %#lx.\n", hr);
8804 ok(palette_entries[0].peFlags == 0x42, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
8805 palette_entries[0].peFlags);
8806 ok(palette_entries[1].peFlags == 0xff, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
8807 palette_entries[1].peFlags);
8808 ok(palette_entries[2].peFlags == 0x80, "Got unexpected peFlags 0x%02x, expected 0x80.\n",
8809 palette_entries[2].peFlags);
8810 ok(palette_entries[3].peFlags == 0x00, "Got unexpected peFlags 0x%02x, expected 0x00.\n",
8811 palette_entries[3].peFlags);
8813 IDirectDrawPalette_Release(palette);
8815 memset(palette_entries, 0, sizeof(palette_entries));
8816 palette_entries[1].peFlags = 0x42;
8817 palette_entries[1].peRed = 0xff;
8818 palette_entries[2].peFlags = 0xff;
8819 palette_entries[3].peFlags = 0x80;
8820 hr = IDirectDraw2_CreatePalette(ddraw, DDPCAPS_ALLOW256 | DDPCAPS_8BIT | DDPCAPS_ALPHA,
8821 palette_entries, &palette, NULL);
8822 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
8824 memset(palette_entries, 0x66, sizeof(palette_entries));
8825 hr = IDirectDrawPalette_GetEntries(palette, 0, 1, 4, palette_entries);
8826 ok(SUCCEEDED(hr), "Failed to get palette entries, hr %#lx.\n", hr);
8827 ok(palette_entries[0].peFlags == 0x42, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
8828 palette_entries[0].peFlags);
8829 ok(palette_entries[1].peFlags == 0xff, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
8830 palette_entries[1].peFlags);
8831 ok(palette_entries[2].peFlags == 0x80, "Got unexpected peFlags 0x%02x, expected 0x80.\n",
8832 palette_entries[2].peFlags);
8833 ok(palette_entries[3].peFlags == 0x00, "Got unexpected peFlags 0x%02x, expected 0x00.\n",
8834 palette_entries[3].peFlags);
8836 for (i = 0; i < ARRAY_SIZE(test_data); i++)
8838 memset(&surface_desc, 0, sizeof(surface_desc));
8839 surface_desc.dwSize = sizeof(surface_desc);
8840 surface_desc.dwFlags = DDSD_CAPS | test_data[i].flags;
8841 surface_desc.dwWidth = 128;
8842 surface_desc.dwHeight = 128;
8843 surface_desc.ddsCaps.dwCaps = test_data[i].caps;
8844 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
8845 ok(SUCCEEDED(hr), "Failed to create %s surface, hr %#lx.\n", test_data[i].name, hr);
8846 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface);
8847 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface2 interface, hr %#lx.\n", hr);
8848 IDirectDrawSurface_Release(surface1);
8850 hr = IDirectDrawSurface2_SetPalette(surface, palette);
8851 if (test_data[i].attach_allowed)
8852 ok(SUCCEEDED(hr), "Failed to attach palette to %s surface, hr %#lx.\n", test_data[i].name, hr);
8853 else
8854 ok(hr == DDERR_INVALIDSURFACETYPE, "Got unexpected hr %#lx, %s surface.\n", hr, test_data[i].name);
8856 if (SUCCEEDED(hr))
8858 HDC dc;
8859 RGBQUAD rgbquad;
8860 UINT retval;
8862 hr = IDirectDrawSurface2_GetDC(surface, &dc);
8863 ok(SUCCEEDED(hr) || broken(hr == DDERR_CANTCREATEDC) /* Win2k testbot */,
8864 "Failed to get DC, hr %#lx, %s surface.\n", hr, test_data[i].name);
8865 if (SUCCEEDED(hr))
8867 retval = GetDIBColorTable(dc, 1, 1, &rgbquad);
8868 ok(retval == 1, "GetDIBColorTable returned unexpected result %u.\n", retval);
8869 ok(rgbquad.rgbRed == 0xff, "Expected rgbRed = 0xff, got %#x, %s surface.\n",
8870 rgbquad.rgbRed, test_data[i].name);
8871 ok(rgbquad.rgbGreen == 0, "Expected rgbGreen = 0, got %#x, %s surface.\n",
8872 rgbquad.rgbGreen, test_data[i].name);
8873 ok(rgbquad.rgbBlue == 0, "Expected rgbBlue = 0, got %#x, %s surface.\n",
8874 rgbquad.rgbBlue, test_data[i].name);
8875 ok(rgbquad.rgbReserved == 0, "Expected rgbReserved = 0, got %u, %s surface.\n",
8876 rgbquad.rgbReserved, test_data[i].name);
8877 hr = IDirectDrawSurface2_ReleaseDC(surface, dc);
8878 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
8881 IDirectDrawSurface2_Release(surface);
8884 /* Test INVALIDSURFACETYPE vs INVALIDPIXELFORMAT. */
8885 memset(&surface_desc, 0, sizeof(surface_desc));
8886 surface_desc.dwSize = sizeof(surface_desc);
8887 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
8888 surface_desc.dwWidth = 128;
8889 surface_desc.dwHeight = 128;
8890 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
8891 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
8892 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
8893 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
8894 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
8895 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
8896 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
8897 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
8898 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
8899 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface);
8900 ok(SUCCEEDED(hr), "Failed to get IDirectDrawSurface2 interface, hr %#lx.\n", hr);
8901 IDirectDrawSurface_Release(surface1);
8903 hr = IDirectDrawSurface2_SetPalette(surface, palette);
8904 ok(hr == DDERR_INVALIDSURFACETYPE, "Got unexpected hr %#lx.\n", hr);
8905 IDirectDrawSurface2_Release(surface);
8907 /* The Windows 8 testbot keeps extra references to the primary
8908 * while in 8 bpp mode. */
8909 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
8910 ok(SUCCEEDED(hr), "Failed to restore display mode, hr %#lx.\n", hr);
8912 refcount = IDirectDrawPalette_Release(palette);
8913 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
8914 refcount = IDirectDraw2_Release(ddraw);
8915 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
8916 DestroyWindow(window);
8919 static void test_lost_device(void)
8921 IDirectDrawSurface *surface, *back_buffer, *back_buffer2, *ds;
8922 IDirectDrawSurface *sysmem_surface, *vidmem_surface;
8923 DDSURFACEDESC surface_desc;
8924 HWND window1, window2;
8925 IDirectDraw2 *ddraw;
8926 ULONG refcount;
8927 DDSCAPS caps;
8928 HRESULT hr;
8929 BOOL ret;
8931 window1 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
8932 0, 0, 640, 480, 0, 0, 0, 0);
8933 window2 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
8934 0, 0, 640, 480, 0, 0, 0, 0);
8935 ddraw = create_ddraw();
8936 ok(!!ddraw, "Failed to create a ddraw object.\n");
8937 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
8938 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8940 memset(&surface_desc, 0, sizeof(surface_desc));
8941 surface_desc.dwSize = sizeof(surface_desc);
8942 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
8943 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
8944 surface_desc.dwBackBufferCount = 1;
8945 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
8946 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8948 memset(&surface_desc, 0, sizeof(surface_desc));
8949 surface_desc.dwSize = sizeof(surface_desc);
8950 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
8951 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
8952 surface_desc.dwWidth = 100;
8953 surface_desc.dwHeight = 100;
8954 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &sysmem_surface, NULL);
8955 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8957 memset(&surface_desc, 0, sizeof(surface_desc));
8958 surface_desc.dwSize = sizeof(surface_desc);
8959 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
8960 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
8961 surface_desc.dwWidth = 64;
8962 surface_desc.dwHeight = 64;
8963 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
8964 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
8965 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
8966 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
8967 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
8968 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
8969 if (FAILED(IDirectDraw2_CreateSurface(ddraw, &surface_desc, &vidmem_surface, NULL)))
8971 skip("Failed to create video memory surface, skipping related tests.\n");
8972 vidmem_surface = NULL;
8975 hr = IDirectDrawSurface_IsLost(surface);
8976 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8977 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8978 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8979 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8980 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8981 if (vidmem_surface)
8983 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8984 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8987 ret = SetForegroundWindow(GetDesktopWindow());
8988 ok(ret, "Failed to set foreground window.\n");
8989 hr = IDirectDrawSurface_IsLost(surface);
8990 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8991 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8992 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8993 hr = IDirectDrawSurface_Restore(surface);
8994 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
8995 hr = IDirectDrawSurface_IsLost(surface);
8996 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8997 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8998 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8999 hr = IDirectDrawSurface_Restore(sysmem_surface);
9000 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9001 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9002 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9003 if (vidmem_surface)
9005 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9006 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9007 hr = IDirectDrawSurface_Restore(vidmem_surface);
9008 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
9009 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9010 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9013 ret = SetForegroundWindow(window1);
9014 ok(ret, "Failed to set foreground window.\n");
9015 hr = IDirectDrawSurface_IsLost(surface);
9016 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9017 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
9018 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9019 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9020 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9021 if (vidmem_surface)
9023 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9024 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9027 hr = restore_surfaces(ddraw);
9028 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9029 hr = IDirectDrawSurface_IsLost(surface);
9030 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9031 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
9032 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9033 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9034 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9035 if (vidmem_surface)
9037 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9038 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9041 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
9042 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9043 hr = IDirectDrawSurface_IsLost(surface);
9044 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9045 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
9046 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9047 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9048 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9049 if (vidmem_surface)
9051 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9052 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9055 /* Trying to restore the primary will crash, probably because flippable
9056 * surfaces can't exist in DDSCL_NORMAL. */
9057 IDirectDrawSurface_Release(surface);
9058 memset(&surface_desc, 0, sizeof(surface_desc));
9059 surface_desc.dwSize = sizeof(surface_desc);
9060 surface_desc.dwFlags = DDSD_CAPS;
9061 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
9062 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9063 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9064 hr = restore_surfaces(ddraw);
9065 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9067 hr = IDirectDrawSurface_IsLost(surface);
9068 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9070 ret = SetForegroundWindow(GetDesktopWindow());
9071 ok(ret, "Failed to set foreground window.\n");
9072 hr = IDirectDrawSurface_IsLost(surface);
9073 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9074 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9075 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9076 if (vidmem_surface)
9078 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9079 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9082 ret = SetForegroundWindow(window1);
9083 ok(ret, "Failed to set foreground window.\n");
9084 hr = IDirectDrawSurface_IsLost(surface);
9085 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9086 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9087 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9088 if (vidmem_surface)
9090 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9091 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9094 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
9095 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9096 hr = IDirectDrawSurface_IsLost(surface);
9097 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9098 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9099 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9100 if (vidmem_surface)
9102 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9103 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9106 hr = restore_surfaces(ddraw);
9107 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9108 hr = IDirectDrawSurface_IsLost(surface);
9109 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9110 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9111 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9112 if (vidmem_surface)
9114 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9115 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9118 IDirectDrawSurface_Release(surface);
9119 memset(&surface_desc, 0, sizeof(surface_desc));
9120 surface_desc.dwSize = sizeof(surface_desc);
9121 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
9122 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
9123 surface_desc.dwBackBufferCount = 2;
9124 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9125 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9127 ds = NULL;
9128 memset(&surface_desc, 0, sizeof(surface_desc));
9129 surface_desc.dwSize = sizeof(surface_desc);
9130 hr = IDirectDrawSurface2_GetSurfaceDesc(surface, &surface_desc);
9131 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
9133 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
9134 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
9135 U2(surface_desc).dwZBufferBitDepth = 16;
9136 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL);
9137 if (FAILED(hr))
9139 skip("Could not create Z buffer, skipping Z buffer restore test.\n");
9141 else
9143 hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
9144 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9147 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
9148 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9149 hr = IDirectDrawSurface_IsLost(surface);
9150 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9151 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
9152 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9153 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9154 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9155 if (vidmem_surface)
9157 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9158 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9161 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL | DDSCL_FULLSCREEN);
9162 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9163 hr = IDirectDrawSurface_IsLost(surface);
9164 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9165 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
9166 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#lx.\n", hr);
9167 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9168 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9169 if (vidmem_surface)
9171 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9172 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9175 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
9176 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9177 hr = IDirectDrawSurface_IsLost(surface);
9178 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9179 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
9180 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#lx.\n", hr);
9181 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9182 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9183 if (vidmem_surface)
9185 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9186 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9189 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL);
9190 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9191 hr = IDirectDrawSurface_IsLost(surface);
9192 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9193 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
9194 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#lx.\n", hr);
9195 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9196 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9197 if (vidmem_surface)
9199 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9200 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9203 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL | DDSCL_FULLSCREEN);
9204 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9205 hr = IDirectDrawSurface_IsLost(surface);
9206 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9207 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
9208 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#lx.\n", hr);
9209 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9210 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9211 if (vidmem_surface)
9213 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9214 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9217 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window2, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
9218 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9219 hr = IDirectDrawSurface_IsLost(surface);
9220 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9221 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
9222 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9223 hr = IDirectDrawSurface_IsLost(sysmem_surface);
9224 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9225 if (vidmem_surface)
9227 hr = IDirectDrawSurface_IsLost(vidmem_surface);
9228 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9231 memset(&caps, 0, sizeof(caps));
9232 caps.dwCaps = DDSCAPS_FLIP;
9234 hr = IDirectDrawSurface_GetAttachedSurface(surface, &caps, &back_buffer);
9235 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9236 ok(back_buffer != surface, "Got the same surface.\n");
9237 hr = IDirectDrawSurface_Restore(surface);
9238 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9239 hr = IDirectDrawSurface_GetAttachedSurface(surface, &caps, &back_buffer);
9240 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9241 hr = IDirectDrawSurface_IsLost(back_buffer);
9242 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9243 IDirectDrawSurface_Release(back_buffer);
9245 hr = IDirectDrawSurface_GetAttachedSurface(back_buffer, &caps, &back_buffer2);
9246 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9247 ok(back_buffer2 != back_buffer, "Got the same surface.\n");
9248 ok(back_buffer2 != surface, "Got the same surface.\n");
9249 hr = IDirectDrawSurface_IsLost(back_buffer2);
9250 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9251 IDirectDrawSurface_Release(back_buffer2);
9253 if (ds)
9255 hr = IDirectDrawSurface_IsLost(ds);
9256 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
9257 hr = IDirectDrawSurface_Restore(ds);
9258 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9259 hr = IDirectDrawSurface_IsLost(ds);
9260 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
9261 IDirectDrawSurface_Release(ds);
9264 if (vidmem_surface)
9265 IDirectDrawSurface_Release(vidmem_surface);
9266 IDirectDrawSurface_Release(sysmem_surface);
9267 IDirectDrawSurface_Release(surface);
9268 refcount = IDirectDraw2_Release(ddraw);
9269 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
9270 DestroyWindow(window2);
9271 DestroyWindow(window1);
9274 static void test_surface_desc_lock(void)
9276 IDirectDrawSurface *surface;
9277 DDSURFACEDESC surface_desc;
9278 IDirectDraw2 *ddraw;
9279 ULONG refcount;
9280 HWND window;
9281 HRESULT hr;
9283 window = create_window();
9284 ddraw = create_ddraw();
9285 ok(!!ddraw, "Failed to create a ddraw object.\n");
9286 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
9287 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
9289 memset(&surface_desc, 0, sizeof(surface_desc));
9290 surface_desc.dwSize = sizeof(surface_desc);
9291 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
9292 surface_desc.dwWidth = 16;
9293 surface_desc.dwHeight = 16;
9294 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
9295 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9296 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9298 memset(&surface_desc, 0xaa, sizeof(surface_desc));
9299 surface_desc.dwSize = sizeof(surface_desc);
9300 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
9301 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
9302 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
9304 memset(&surface_desc, 0xaa, sizeof(surface_desc));
9305 surface_desc.dwSize = sizeof(surface_desc);
9306 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, 0, NULL);
9307 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
9308 ok(surface_desc.lpSurface != NULL, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
9309 memset(&surface_desc, 0xaa, sizeof(surface_desc));
9310 surface_desc.dwSize = sizeof(surface_desc);
9311 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
9312 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
9313 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
9314 hr = IDirectDrawSurface_Unlock(surface, NULL);
9315 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
9317 memset(&surface_desc, 0xaa, sizeof(surface_desc));
9318 surface_desc.dwSize = sizeof(surface_desc);
9319 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
9320 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
9321 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
9323 IDirectDrawSurface_Release(surface);
9324 refcount = IDirectDraw2_Release(ddraw);
9325 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
9326 DestroyWindow(window);
9329 static void test_texturemapblend(void)
9331 HRESULT hr;
9332 DDSURFACEDESC ddsd;
9333 DDBLTFX fx;
9334 static RECT rect = {0, 0, 64, 128};
9335 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
9336 DDCOLORKEY ckey;
9337 IDirectDrawSurface *surface, *rt;
9338 IDirect3DTexture2 *texture;
9339 D3DTEXTUREHANDLE texture_handle;
9340 unsigned int color;
9341 HWND window;
9342 IDirectDraw2 *ddraw;
9343 IDirect3DDevice2 *device;
9344 IDirect3DMaterial2 *material;
9345 IDirect3DViewport2 *viewport;
9346 ULONG ref;
9348 static D3DTLVERTEX test1_quads[] =
9350 {{0.0f}, {0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {0.0f}, {0.0f}},
9351 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {0.0f}, {1.0f}},
9352 {{640.0f}, {0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {1.0f}, {0.0f}},
9353 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {1.0f}, {1.0f}},
9354 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {0.0f}, {0.0f}},
9355 {{0.0f}, {480.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {0.0f}, {1.0f}},
9356 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {1.0f}, {0.0f}},
9357 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {1.0f}, {1.0f}},
9359 test2_quads[] =
9361 {{0.0f}, {0.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {0.0f}, {0.0f}},
9362 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {0.0f}, {1.0f}},
9363 {{640.0f}, {0.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {1.0f}, {0.0f}},
9364 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {1.0f}, {1.0f}},
9365 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {0.0f}, {0.0f}},
9366 {{0.0f}, {480.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {0.0f}, {1.0f}},
9367 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {1.0f}, {0.0f}},
9368 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {1.0f}, {1.0f}},
9371 window = create_window();
9372 ddraw = create_ddraw();
9373 ok(!!ddraw, "Failed to create a ddraw object.\n");
9374 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
9376 skip("Failed to create a 3D device, skipping test.\n");
9377 DestroyWindow(window);
9378 IDirectDraw2_Release(ddraw);
9379 return;
9382 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
9383 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
9385 material = create_diffuse_material(device, 0.0f, 0.0f, 0.0f, 1.0f);
9386 viewport = create_viewport(device, 0, 0, 640, 480);
9387 viewport_set_background(device, viewport, material);
9388 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
9389 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
9391 /* Test alpha with DDPF_ALPHAPIXELS texture - should be taken from texture alpha channel.
9393 * The vertex alpha is completely ignored in this case, so case 1 and 2 combined are not
9394 * a D3DTOP_MODULATE with texture alpha = 0xff in case 2 (no alpha in texture). */
9395 memset(&ddsd, 0, sizeof(ddsd));
9396 ddsd.dwSize = sizeof(ddsd);
9397 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
9398 ddsd.dwHeight = 128;
9399 ddsd.dwWidth = 128;
9400 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
9401 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
9402 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
9403 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
9404 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
9405 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
9406 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
9407 U5(ddsd.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
9408 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
9409 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9411 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
9412 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
9413 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
9414 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
9415 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
9416 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9418 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
9419 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
9421 memset(&fx, 0, sizeof(fx));
9422 fx.dwSize = sizeof(fx);
9423 U5(fx).dwFillColor = 0xff0000ff;
9424 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9425 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
9426 U5(fx).dwFillColor = 0x800000ff;
9427 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9428 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
9430 /* Note that the ddraw1 version of this test runs tests 1-3 with D3DRENDERSTATE_COLORKEYENABLE
9431 * enabled, whereas this version only runs test 4 with color keying on. Because no color key
9432 * is set on the texture this should not result in different behavior. */
9433 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
9434 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9435 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
9436 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9437 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
9438 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9439 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
9440 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9441 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
9442 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9443 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
9444 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9446 hr = IDirect3DDevice2_BeginScene(device);
9447 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
9448 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[0], 4, 0);
9449 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
9450 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[4], 4, 0);
9451 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
9452 hr = IDirect3DDevice2_EndScene(device);
9453 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
9455 color = get_surface_color(rt, 5, 5);
9456 ok(compare_color(color, 0x00000080, 2), "Got unexpected color 0x%08x.\n", color);
9457 color = get_surface_color(rt, 400, 5);
9458 ok(compare_color(color, 0x000000ff, 2), "Got unexpected color 0x%08x.\n", color);
9459 color = get_surface_color(rt, 5, 245);
9460 ok(compare_color(color, 0x00000080, 2), "Got unexpected color 0x%08x.\n", color);
9461 color = get_surface_color(rt, 400, 245);
9462 ok(compare_color(color, 0x000000ff, 2), "Got unexpected color 0x%08x.\n", color);
9464 IDirect3DTexture2_Release(texture);
9465 ref = IDirectDrawSurface_Release(surface);
9466 ok(!ref, "Unexpected refcount %lu.\n", ref);
9468 /* Test alpha with texture that has no alpha channel - alpha should be taken from diffuse vertex color. */
9469 memset(&ddsd, 0, sizeof(ddsd));
9470 ddsd.dwSize = sizeof(ddsd);
9471 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
9472 ddsd.dwHeight = 128;
9473 ddsd.dwWidth = 128;
9474 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
9475 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
9476 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
9477 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
9478 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
9479 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
9480 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
9482 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
9483 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9485 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
9486 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
9487 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
9488 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
9489 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
9490 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9492 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
9493 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
9495 U5(fx).dwFillColor = 0xff0000ff;
9496 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9497 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
9498 U5(fx).dwFillColor = 0x800000ff;
9499 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9500 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
9502 hr = IDirect3DDevice2_BeginScene(device);
9503 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
9504 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[0], 4, 0);
9505 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
9506 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[4], 4, 0);
9507 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
9508 hr = IDirect3DDevice2_EndScene(device);
9509 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
9511 color = get_surface_color(rt, 5, 5);
9512 ok(compare_color(color, 0x000000ff, 2), "Got unexpected color 0x%08x.\n", color);
9513 color = get_surface_color(rt, 400, 5);
9514 ok(compare_color(color, 0x000000ff, 2), "Got unexpected color 0x%08x.\n", color);
9515 color = get_surface_color(rt, 5, 245);
9516 ok(compare_color(color, 0x00000080, 2), "Got unexpected color 0x%08x.\n", color);
9517 color = get_surface_color(rt, 400, 245);
9518 ok(compare_color(color, 0x00000080, 2), "Got unexpected color 0x%08x.\n", color);
9520 IDirect3DTexture2_Release(texture);
9521 ref = IDirectDrawSurface_Release(surface);
9522 ok(!ref, "Unexpected refcount %lu.\n", ref);
9524 /* Test RGB - should multiply color components from diffuse vertex color and texture. */
9525 memset(&ddsd, 0, sizeof(ddsd));
9526 ddsd.dwSize = sizeof(ddsd);
9527 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
9528 ddsd.dwHeight = 128;
9529 ddsd.dwWidth = 128;
9530 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
9531 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
9532 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
9533 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
9534 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
9535 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
9536 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
9537 U5(ddsd.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
9538 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
9539 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9541 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
9542 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
9543 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
9544 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
9545 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
9546 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9548 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
9549 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
9551 U5(fx).dwFillColor = 0x00ffffff;
9552 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9553 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
9554 U5(fx).dwFillColor = 0x00ffff80;
9555 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9556 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
9558 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
9559 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9561 hr = IDirect3DDevice2_BeginScene(device);
9562 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
9563 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test2_quads[0], 4, 0);
9564 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
9565 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test2_quads[4], 4, 0);
9566 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
9567 hr = IDirect3DDevice2_EndScene(device);
9568 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
9570 color = get_surface_color(rt, 5, 5);
9571 ok(compare_color(color, 0x00ff0040, 2), "Got unexpected color 0x%08x.\n", color);
9572 color = get_surface_color(rt, 400, 5);
9573 ok(compare_color(color, 0x00ff0080, 2), "Got unexpected color 0x%08x.\n", color);
9574 color = get_surface_color(rt, 5, 245);
9575 ok(compare_color(color, 0x00800080, 2), "Got unexpected color 0x%08x.\n", color);
9576 color = get_surface_color(rt, 400, 245);
9577 ok(compare_color(color, 0x008000ff, 2), "Got unexpected color 0x%08x.\n", color);
9579 IDirect3DTexture2_Release(texture);
9580 ref = IDirectDrawSurface_Release(surface);
9581 ok(!ref, "Unexpected refcount %lu.\n", ref);
9583 /* Test alpha again, now with color keyed texture (colorkey emulation in wine can interfere). */
9584 memset(&ddsd, 0, sizeof(ddsd));
9585 ddsd.dwSize = sizeof(ddsd);
9586 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
9587 ddsd.dwHeight = 128;
9588 ddsd.dwWidth = 128;
9589 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
9590 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
9591 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
9592 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 16;
9593 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0xf800;
9594 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x07e0;
9595 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x001f;
9597 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
9598 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9600 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
9601 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
9602 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
9603 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
9604 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
9605 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9607 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
9608 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
9610 U5(fx).dwFillColor = 0xf800;
9611 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9612 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
9613 U5(fx).dwFillColor = 0x001f;
9614 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9615 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
9617 ckey.dwColorSpaceLowValue = 0x001f;
9618 ckey.dwColorSpaceHighValue = 0x001f;
9619 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9620 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
9622 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
9623 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9624 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
9625 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
9627 hr = IDirect3DDevice2_BeginScene(device);
9628 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
9629 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[0], 4, 0);
9630 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
9631 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &test1_quads[4], 4, 0);
9632 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
9633 hr = IDirect3DDevice2_EndScene(device);
9634 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
9636 color = get_surface_color(rt, 5, 5);
9637 ok(compare_color(color, 0x00000000, 2), "Got unexpected color 0x%08x.\n", color);
9638 color = get_surface_color(rt, 400, 5);
9639 ok(compare_color(color, 0x00ff0000, 2), "Got unexpected color 0x%08x.\n", color);
9640 color = get_surface_color(rt, 5, 245);
9641 ok(compare_color(color, 0x00000000, 2), "Got unexpected color 0x%08x.\n", color);
9642 color = get_surface_color(rt, 400, 245);
9643 ok(compare_color(color, 0x00800000, 2), "Got unexpected color 0x%08x.\n", color);
9645 IDirect3DTexture2_Release(texture);
9646 ref = IDirectDrawSurface_Release(surface);
9647 ok(!ref, "Unexpected refcount %lu.\n", ref);
9649 destroy_viewport(device, viewport);
9650 ref = IDirect3DMaterial2_Release(material);
9651 ok(!ref, "Unexpected refcount %lu.\n", ref);
9652 IDirectDrawSurface_Release(rt);
9653 IDirect3DDevice2_Release(device);
9654 ref = IDirectDraw2_Release(ddraw);
9655 ok(!ref, "Unexpected refcount %lu.\n", ref);
9656 DestroyWindow(window);
9659 static void test_viewport_clear_rect(void)
9661 HRESULT hr;
9662 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
9663 static D3DRECT clear_rect2 = {{90}, {90}, {110}, {110}};
9664 IDirectDrawSurface *rt;
9665 unsigned int color;
9666 HWND window;
9667 IDirectDraw2 *ddraw;
9668 IDirect3DDevice2 *device;
9669 IDirect3DMaterial2 *red, *green;
9670 IDirect3DViewport2 *viewport, *viewport2;
9671 ULONG ref;
9673 window = create_window();
9674 ddraw = create_ddraw();
9675 ok(!!ddraw, "Failed to create a ddraw object.\n");
9676 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
9678 skip("Failed to create a 3D device, skipping test.\n");
9679 DestroyWindow(window);
9680 IDirectDraw2_Release(ddraw);
9681 return;
9684 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
9685 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
9687 red = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
9688 viewport = create_viewport(device, 0, 0, 640, 480);
9689 viewport_set_background(device, viewport, red);
9690 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
9691 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
9693 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 1.0f);
9694 viewport2 = create_viewport(device, 100, 100, 20, 20);
9695 viewport_set_background(device, viewport2, green);
9696 hr = IDirect3DViewport2_Clear(viewport2, 1, &clear_rect2, D3DCLEAR_TARGET);
9697 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
9699 color = get_surface_color(rt, 85, 85); /* Outside both. */
9700 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
9701 color = get_surface_color(rt, 95, 95); /* Outside vp, inside rect. */
9702 /* AMD GPUs ignore the viewport dimensions and only care about the rectangle. */
9703 ok(compare_color(color, 0x00ff0000, 1) || broken(compare_color(color, 0x0000ff00, 1)),
9704 "Got unexpected color 0x%08x.\n", color);
9705 color = get_surface_color(rt, 105, 105); /* Inside both. */
9706 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
9707 color = get_surface_color(rt, 115, 115); /* Inside vp, outside rect. */
9708 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
9709 color = get_surface_color(rt, 125, 125); /* Outside both. */
9710 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
9712 destroy_viewport(device, viewport2);
9713 destroy_material(green);
9714 destroy_viewport(device, viewport);
9715 destroy_material(red);
9716 IDirectDrawSurface_Release(rt);
9717 IDirect3DDevice2_Release(device);
9718 ref = IDirectDraw2_Release(ddraw);
9719 ok(!ref, "Unexpected refcount %lu.\n", ref);
9720 DestroyWindow(window);
9723 static void test_color_fill(void)
9725 HRESULT hr;
9726 IDirect3DDevice2 *device;
9727 IDirectDraw2 *ddraw;
9728 IDirectDrawSurface *surface, *surface2;
9729 DDSURFACEDESC surface_desc;
9730 unsigned int i, *color;
9731 ULONG refcount;
9732 BOOL is_warp;
9733 HWND window;
9734 DDBLTFX fx;
9735 RECT rect = {5, 5, 7, 7};
9736 DWORD num_fourcc_codes, *fourcc_codes;
9737 DDCAPS hal_caps;
9738 BOOL support_uyvy = FALSE, support_yuy2 = FALSE;
9739 static const struct
9741 DWORD caps;
9742 HRESULT colorfill_hr, depthfill_hr;
9743 BOOL rop_success;
9744 const char *name;
9745 unsigned int result;
9746 BOOL check_result;
9747 DDPIXELFORMAT format;
9749 tests[] =
9752 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
9753 DD_OK, DDERR_INVALIDPARAMS, TRUE, "vidmem offscreenplain RGB", 0xdeadbeef, TRUE,
9755 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
9756 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
9760 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
9761 DD_OK, DDERR_INVALIDPARAMS, TRUE, "sysmem offscreenplain RGB", 0xdeadbeef, TRUE,
9763 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
9764 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
9768 DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY,
9769 DD_OK, DDERR_INVALIDPARAMS, TRUE, "vidmem texture RGB", 0xdeadbeef, TRUE,
9771 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
9772 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
9776 DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY,
9777 DD_OK, DDERR_INVALIDPARAMS, TRUE, "sysmem texture RGB", 0xdeadbeef, TRUE,
9779 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
9780 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
9784 DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY,
9785 DDERR_INVALIDPARAMS, DD_OK, TRUE, "vidmem zbuffer", 0xdeadbeef, TRUE,
9786 {0, 0, 0, {0}, {0}, {0}, {0}, {0}}
9789 /* Colorfill on YUV surfaces always returns DD_OK, but the content is
9790 * different afterwards. DX9+ GPUs set one of the two luminance values
9791 * in each block, but AMD and Nvidia GPUs disagree on which luminance
9792 * value they set. r200 (dx8) just sets the entire block to the clear
9793 * value. */
9794 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
9795 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem offscreenplain YUY2", 0, FALSE,
9797 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y', 'U', 'Y', '2'),
9798 {0}, {0}, {0}, {0}, {0}
9802 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
9803 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem offscreenplain UYVY", 0, FALSE,
9805 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('U', 'Y', 'V', 'Y'),
9806 {0}, {0}, {0}, {0}, {0}
9810 DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY,
9811 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem overlay YUY2", 0, FALSE,
9813 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y', 'U', 'Y', '2'),
9814 {0}, {0}, {0}, {0}, {0}
9818 DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY,
9819 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem overlay UYVY", 0, FALSE,
9821 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('U', 'Y', 'V', 'Y'),
9822 {0}, {0}, {0}, {0}, {0}
9826 DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY,
9827 E_NOTIMPL, DDERR_INVALIDPARAMS, FALSE, "vidmem texture DXT1", 0, FALSE,
9829 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'),
9830 {0}, {0}, {0}, {0}, {0}
9834 DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY,
9835 E_NOTIMPL, DDERR_INVALIDPARAMS, FALSE, "sysmem texture DXT1", 0, FALSE,
9837 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'),
9838 {0}, {0}, {0}, {0}, {0}
9842 /* The testbot fills this with 0x00 instead of the blue channel. The sysmem
9843 * surface works, presumably because it is handled by the runtime instead of
9844 * the driver. */
9845 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
9846 DD_OK, DDERR_INVALIDPARAMS, TRUE, "vidmem offscreenplain P8", 0xefefefef, FALSE,
9848 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED8, 0,
9849 {8}, {0}, {0}, {0}, {0}
9853 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
9854 DD_OK, DDERR_INVALIDPARAMS, TRUE, "sysmem offscreenplain P8", 0xefefefef, TRUE,
9856 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED8, 0,
9857 {8}, {0}, {0}, {0}, {0}
9861 static const struct
9863 DWORD rop;
9864 const char *name;
9865 HRESULT hr;
9867 rops[] =
9869 {SRCCOPY, "SRCCOPY", DD_OK},
9870 {SRCPAINT, "SRCPAINT", DDERR_NORASTEROPHW},
9871 {SRCAND, "SRCAND", DDERR_NORASTEROPHW},
9872 {SRCINVERT, "SRCINVERT", DDERR_NORASTEROPHW},
9873 {SRCERASE, "SRCERASE", DDERR_NORASTEROPHW},
9874 {NOTSRCCOPY, "NOTSRCCOPY", DDERR_NORASTEROPHW},
9875 {NOTSRCERASE, "NOTSRCERASE", DDERR_NORASTEROPHW},
9876 {MERGECOPY, "MERGECOPY", DDERR_NORASTEROPHW},
9877 {MERGEPAINT, "MERGEPAINT", DDERR_NORASTEROPHW},
9878 {PATCOPY, "PATCOPY", DDERR_NORASTEROPHW},
9879 {PATPAINT, "PATPAINT", DDERR_NORASTEROPHW},
9880 {PATINVERT, "PATINVERT", DDERR_NORASTEROPHW},
9881 {DSTINVERT, "DSTINVERT", DDERR_NORASTEROPHW},
9882 {BLACKNESS, "BLACKNESS", DD_OK},
9883 {WHITENESS, "WHITENESS", DD_OK},
9884 {0xaa0029, "0xaa0029", DDERR_NORASTEROPHW} /* noop */
9887 window = create_window();
9888 ddraw = create_ddraw();
9889 ok(!!ddraw, "Failed to create a ddraw object.\n");
9890 is_warp = ddraw_is_warp(ddraw);
9891 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
9893 skip("Failed to create a 3D device, skipping test.\n");
9894 DestroyWindow(window);
9895 IDirectDraw2_Release(ddraw);
9896 return;
9899 hr = IDirectDraw2_GetFourCCCodes(ddraw, &num_fourcc_codes, NULL);
9900 ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr);
9901 fourcc_codes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
9902 num_fourcc_codes * sizeof(*fourcc_codes));
9903 if (!fourcc_codes)
9904 goto done;
9905 hr = IDirectDraw2_GetFourCCCodes(ddraw, &num_fourcc_codes, fourcc_codes);
9906 ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr);
9907 for (i = 0; i < num_fourcc_codes; i++)
9909 if (fourcc_codes[i] == MAKEFOURCC('Y', 'U', 'Y', '2'))
9910 support_yuy2 = TRUE;
9911 else if (fourcc_codes[i] == MAKEFOURCC('U', 'Y', 'V', 'Y'))
9912 support_uyvy = TRUE;
9914 HeapFree(GetProcessHeap(), 0, fourcc_codes);
9916 memset(&hal_caps, 0, sizeof(hal_caps));
9917 hal_caps.dwSize = sizeof(hal_caps);
9918 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, NULL);
9919 ok(SUCCEEDED(hr), "Failed to get caps, hr %#lx.\n", hr);
9921 if ((!support_yuy2 && !support_uyvy) || !(hal_caps.dwCaps & DDCAPS_OVERLAY))
9922 skip("Overlays or some YUV formats not supported, skipping YUV colorfill tests.\n");
9924 for (i = 0; i < ARRAY_SIZE(tests); i++)
9926 DWORD expected_broken = tests[i].result;
9927 unsigned int mask = 0xffffffffu;
9929 /* Some Windows drivers modify dwFillColor when it is used on P8 or FourCC formats. */
9930 memset(&fx, 0, sizeof(fx));
9931 fx.dwSize = sizeof(fx);
9932 U5(fx).dwFillColor = 0xdeadbeef;
9934 memset(&surface_desc, 0, sizeof(surface_desc));
9935 surface_desc.dwSize = sizeof(surface_desc);
9936 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
9937 surface_desc.dwWidth = 64;
9938 surface_desc.dwHeight = 64;
9939 surface_desc.ddpfPixelFormat = tests[i].format;
9940 surface_desc.ddsCaps.dwCaps = tests[i].caps;
9942 if (tests[i].caps & DDSCAPS_TEXTURE)
9944 struct format_support_check check = {&tests[i].format, FALSE};
9945 hr = IDirect3DDevice2_EnumTextureFormats(device, test_unsupported_formats_cb, &check);
9946 ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr);
9947 if (!check.supported)
9948 continue;
9951 if (tests[i].format.dwFourCC == MAKEFOURCC('Y','U','Y','2') && !support_yuy2)
9952 continue;
9953 if (tests[i].format.dwFourCC == MAKEFOURCC('U','Y','V','Y') && !support_uyvy)
9954 continue;
9955 if (tests[i].caps & DDSCAPS_OVERLAY && !(hal_caps.dwCaps & DDCAPS_OVERLAY))
9956 continue;
9958 if (tests[i].caps & DDSCAPS_ZBUFFER)
9960 surface_desc.dwFlags &= ~DDSD_PIXELFORMAT;
9961 surface_desc.dwFlags |= DDSD_ZBUFFERBITDEPTH;
9962 U2(surface_desc).dwZBufferBitDepth = get_device_z_depth(device);
9963 mask >>= (32 - U2(surface_desc).dwZBufferBitDepth);
9964 /* Some drivers seem to convert depth values incorrectly or not at
9965 * all. Affects at least AMD PALM, 8.17.10.1247. */
9966 if (tests[i].caps & DDSCAPS_VIDEOMEMORY)
9968 DWORD expected;
9969 float f, g;
9971 expected = tests[i].result & mask;
9972 f = ceilf(logf(expected + 1.0f) / logf(2.0f));
9973 g = (f + 1.0f) / 2.0f;
9974 g -= (int)g;
9975 expected_broken = (expected / exp2f(f) - g) * 256;
9976 expected_broken *= 0x01010101;
9980 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9981 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9983 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9984 todo_wine_if (tests[i].format.dwFourCC)
9985 ok(hr == tests[i].colorfill_hr, "Blt returned %#lx, expected %#lx, surface %s.\n",
9986 hr, tests[i].colorfill_hr, tests[i].name);
9988 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9989 todo_wine_if (tests[i].format.dwFourCC)
9990 ok(hr == tests[i].colorfill_hr, "Blt returned %#lx, expected %#lx, surface %s.\n",
9991 hr, tests[i].colorfill_hr, tests[i].name);
9993 if (SUCCEEDED(hr) && tests[i].check_result)
9995 memset(&surface_desc, 0, sizeof(surface_desc));
9996 surface_desc.dwSize = sizeof(surface_desc);
9997 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
9998 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9999 color = surface_desc.lpSurface;
10000 ok(*color == tests[i].result, "Got clear result 0x%08x, expected 0x%08x, surface %s.\n",
10001 *color, tests[i].result, tests[i].name);
10002 hr = IDirectDrawSurface_Unlock(surface, NULL);
10003 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
10006 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10007 ok(hr == tests[i].depthfill_hr, "Blt returned %#lx, expected %#lx, surface %s.\n",
10008 hr, tests[i].depthfill_hr, tests[i].name);
10009 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10010 ok(hr == tests[i].depthfill_hr, "Blt returned %#lx, expected %#lx, surface %s.\n",
10011 hr, tests[i].depthfill_hr, tests[i].name);
10013 if (SUCCEEDED(hr) && tests[i].check_result)
10015 memset(&surface_desc, 0, sizeof(surface_desc));
10016 surface_desc.dwSize = sizeof(surface_desc);
10017 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
10018 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
10019 color = surface_desc.lpSurface;
10020 todo_wine_if(tests[i].caps & DDSCAPS_VIDEOMEMORY && U2(surface_desc).dwZBufferBitDepth != 16)
10021 ok((*color & mask) == (tests[i].result & mask) || broken((*color & mask) == (expected_broken & mask))
10022 || broken(is_warp && (*color & mask) == (~0u & mask)) /* Windows 8+ testbot. */,
10023 "Got clear result 0x%08x, expected 0x%08x, surface %s.\n",
10024 *color & mask, tests[i].result & mask, tests[i].name);
10025 hr = IDirectDrawSurface_Unlock(surface, NULL);
10026 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
10029 U5(fx).dwFillColor = 0xdeadbeef;
10030 fx.dwROP = BLACKNESS;
10031 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
10032 ok(FAILED(hr) == !tests[i].rop_success, "Blt returned %#lx, expected %s, surface %s.\n",
10033 hr, tests[i].rop_success ? "success" : "failure", tests[i].name);
10034 ok(U5(fx).dwFillColor == 0xdeadbeef, "dwFillColor was set to 0x%08lx, surface %s\n",
10035 U5(fx).dwFillColor, tests[i].name);
10037 if (SUCCEEDED(hr) && tests[i].check_result)
10039 memset(&surface_desc, 0, sizeof(surface_desc));
10040 surface_desc.dwSize = sizeof(surface_desc);
10041 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
10042 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
10043 color = surface_desc.lpSurface;
10044 ok(*color == 0, "Got clear result 0x%08x, expected 0x00000000, surface %s.\n",
10045 *color, tests[i].name);
10046 hr = IDirectDrawSurface_Unlock(surface, NULL);
10047 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
10050 fx.dwROP = WHITENESS;
10051 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
10052 ok(FAILED(hr) == !tests[i].rop_success, "Blt returned %#lx, expected %s, surface %s.\n",
10053 hr, tests[i].rop_success ? "success" : "failure", tests[i].name);
10054 ok(U5(fx).dwFillColor == 0xdeadbeef, "dwFillColor was set to 0x%08lx, surface %s\n",
10055 U5(fx).dwFillColor, tests[i].name);
10057 if (SUCCEEDED(hr) && tests[i].check_result)
10059 memset(&surface_desc, 0, sizeof(surface_desc));
10060 surface_desc.dwSize = sizeof(surface_desc);
10061 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
10062 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
10063 color = surface_desc.lpSurface;
10064 /* WHITENESS sets the alpha channel to 0x00. Ignore this for now. */
10065 ok((*color & 0x00ffffff) == 0x00ffffff, "Got clear result 0x%08x, expected 0xffffffff, surface %s.\n",
10066 *color, tests[i].name);
10067 hr = IDirectDrawSurface_Unlock(surface, NULL);
10068 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
10071 IDirectDrawSurface_Release(surface);
10074 memset(&fx, 0, sizeof(fx));
10075 fx.dwSize = sizeof(fx);
10076 U5(fx).dwFillColor = 0xdeadbeef;
10077 fx.dwROP = WHITENESS;
10079 memset(&surface_desc, 0, sizeof(surface_desc));
10080 surface_desc.dwSize = sizeof(surface_desc);
10081 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
10082 surface_desc.dwWidth = 64;
10083 surface_desc.dwHeight = 64;
10084 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
10085 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
10086 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
10087 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
10088 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
10089 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
10090 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
10091 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
10092 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10093 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
10094 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10096 /* No DDBLTFX. */
10097 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, NULL);
10098 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10099 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_ROP | DDBLT_WAIT, NULL);
10100 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10102 /* Unused source rectangle. */
10103 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10104 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
10105 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
10106 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
10108 /* Unused source surface. */
10109 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10110 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10111 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
10112 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
10113 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10114 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10115 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
10116 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
10118 /* Inverted destination or source rectangle. */
10119 SetRect(&rect, 5, 7, 7, 5);
10120 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10121 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
10122 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10123 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
10124 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10125 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10126 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10127 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10128 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
10129 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
10131 /* Negative rectangle. */
10132 SetRect(&rect, -1, -1, 5, 5);
10133 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10134 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
10135 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10136 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
10137 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10138 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10139 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10140 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10141 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
10142 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
10144 /* Out of bounds rectangle. */
10145 SetRect(&rect, 0, 0, 65, 65);
10146 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10147 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
10148 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
10149 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
10151 /* Combine multiple flags. */
10152 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10153 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
10154 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_ROP | DDBLT_WAIT, &fx);
10155 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10156 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ROP | DDBLT_WAIT, &fx);
10157 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10159 for (i = 0; i < ARRAY_SIZE(rops); i++)
10161 fx.dwROP = rops[i].rop;
10162 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
10163 ok(hr == rops[i].hr, "Got unexpected hr %#lx for rop %s.\n", hr, rops[i].name);
10166 IDirectDrawSurface_Release(surface2);
10167 IDirectDrawSurface_Release(surface);
10169 memset(&surface_desc, 0, sizeof(surface_desc));
10170 surface_desc.dwSize = sizeof(surface_desc);
10171 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_ZBUFFERBITDEPTH;
10172 surface_desc.dwWidth = 64;
10173 surface_desc.dwHeight = 64;
10174 U2(surface_desc).dwZBufferBitDepth = get_device_z_depth(device);
10175 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
10176 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
10177 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10178 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
10179 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10181 /* No DDBLTFX. */
10182 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, NULL);
10183 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10185 /* Unused source rectangle. */
10186 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10187 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
10189 /* Unused source surface. */
10190 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10191 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10192 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10193 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10195 /* Inverted destination or source rectangle. */
10196 SetRect(&rect, 5, 7, 7, 5);
10197 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10198 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
10199 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10200 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
10201 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10202 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10203 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10204 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10206 /* Negative rectangle. */
10207 SetRect(&rect, -1, -1, 5, 5);
10208 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10209 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
10210 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10211 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
10212 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10213 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10214 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10215 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10217 /* Out of bounds rectangle. */
10218 SetRect(&rect, 0, 0, 65, 65);
10219 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10220 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
10222 /* Combine multiple flags. */
10223 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
10224 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10226 IDirectDrawSurface_Release(surface2);
10227 IDirectDrawSurface_Release(surface);
10229 done:
10230 IDirect3DDevice2_Release(device);
10231 refcount = IDirectDraw2_Release(ddraw);
10232 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
10233 DestroyWindow(window);
10236 static void test_colorkey_precision(void)
10238 static D3DLVERTEX quad[] =
10240 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xff000000}, {0}, {0.0f}, {0.0f}},
10241 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff000000}, {0}, {0.0f}, {1.0f}},
10242 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xff000000}, {0}, {1.0f}, {0.0f}},
10243 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xff000000}, {0}, {1.0f}, {1.0f}},
10245 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
10246 unsigned int data[4] = {0}, color_mask, color, t, c;
10247 IDirect3DDevice2 *device;
10248 IDirectDraw2 *ddraw;
10249 IDirectDrawSurface *rt;
10250 IDirect3DViewport2 *viewport;
10251 HWND window;
10252 HRESULT hr;
10253 IDirectDrawSurface *src, *dst, *texture;
10254 D3DTEXTUREHANDLE handle;
10255 IDirect3DTexture2 *d3d_texture;
10256 IDirect3DMaterial2 *green;
10257 DDSURFACEDESC surface_desc, lock_desc;
10258 ULONG refcount;
10259 DDCOLORKEY ckey;
10260 DDBLTFX fx;
10261 BOOL is_nvidia, is_warp;
10262 static const struct
10264 unsigned int max, shift, bpp, clear;
10265 const char *name;
10266 BOOL skip_nv;
10267 DDPIXELFORMAT fmt;
10269 tests[] =
10272 255, 0, 4, 0x00345678, "D3DFMT_X8R8G8B8", FALSE,
10274 sizeof(DDPIXELFORMAT), DDPF_RGB, 0,
10275 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0x00000000}
10280 63, 5, 2, 0x5678, "D3DFMT_R5G6B5, G channel", FALSE,
10282 sizeof(DDPIXELFORMAT), DDPF_RGB, 0,
10283 {16}, {0xf800}, {0x07e0}, {0x001f}, {0x0000}
10288 31, 0, 2, 0x5678, "D3DFMT_R5G6B5, B channel", FALSE,
10290 sizeof(DDPIXELFORMAT), DDPF_RGB, 0,
10291 {16}, {0xf800}, {0x07e0}, {0x001f}, {0x0000}
10296 15, 0, 2, 0x0678, "D3DFMT_A4R4G4B4", TRUE,
10298 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
10299 {16}, {0x0f00}, {0x00f0}, {0x000f}, {0xf000}
10304 window = create_window();
10305 ddraw = create_ddraw();
10306 ok(!!ddraw, "Failed to create a ddraw object.\n");
10307 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
10309 skip("Failed to create a 3D device, skipping test.\n");
10310 DestroyWindow(window);
10311 IDirectDraw2_Release(ddraw);
10312 return;
10314 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
10315 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
10317 is_nvidia = ddraw_is_nvidia(ddraw);
10318 /* The Windows 8 WARP driver has plenty of false negatives in X8R8G8B8
10319 * (color key doesn't match although the values are equal), and a false
10320 * positive when the color key is 0 and the texture contains the value 1.
10321 * I don't want to mark this broken unconditionally since this would
10322 * essentially disable the test on Windows. Also on random occasions
10323 * 254 == 255 and 255 != 255.*/
10324 is_warp = ddraw_is_warp(ddraw);
10326 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
10327 viewport = create_viewport(device, 0, 0, 640, 480);
10328 viewport_set_background(device, viewport, green);
10329 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
10330 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#lx.\n", hr);
10332 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
10333 ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#lx.\n", hr);
10334 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
10335 ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#lx.\n", hr);
10336 /* There's no way to ignore the texture color in d3d2, so multiply the texture color
10337 * with a black vertex color. */
10338 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA);
10339 ok(SUCCEEDED(hr), "Failed to set render state, hr %#lx.\n", hr);
10341 memset(&fx, 0, sizeof(fx));
10342 fx.dwSize = sizeof(fx);
10343 memset(&lock_desc, 0, sizeof(lock_desc));
10344 lock_desc.dwSize = sizeof(lock_desc);
10346 for (t = 0; t < ARRAY_SIZE(tests); ++t)
10348 if (is_nvidia && tests[t].skip_nv)
10350 win_skip("Skipping test %s on Nvidia Windows drivers.\n", tests[t].name);
10351 continue;
10354 memset(&surface_desc, 0, sizeof(surface_desc));
10355 surface_desc.dwSize = sizeof(surface_desc);
10356 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
10357 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
10358 surface_desc.dwWidth = 4;
10359 surface_desc.dwHeight = 1;
10360 surface_desc.ddpfPixelFormat = tests[t].fmt;
10361 /* Windows XP (at least with the r200 driver, other drivers untested) produces
10362 * garbage when doing color keyed texture->texture blits. */
10363 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &src, NULL);
10364 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10365 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst, NULL);
10366 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10368 U5(fx).dwFillColor = tests[t].clear;
10369 /* On the w8 testbot (WARP driver) the blit result has different values in the
10370 * X channel. */
10371 color_mask = U2(tests[t].fmt).dwRBitMask
10372 | U3(tests[t].fmt).dwGBitMask
10373 | U4(tests[t].fmt).dwBBitMask;
10375 for (c = 0; c <= tests[t].max; ++c)
10377 /* The idiotic Nvidia Windows driver can't change the color key on a d3d
10378 * texture after it has been set once... */
10379 surface_desc.dwFlags |= DDSD_CKSRCBLT;
10380 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
10381 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = c << tests[t].shift;
10382 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = c << tests[t].shift;
10383 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &texture, NULL);
10384 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10386 hr = IDirectDrawSurface4_QueryInterface(texture, &IID_IDirect3DTexture2, (void **)&d3d_texture);
10387 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
10388 hr = IDirect3DTexture2_GetHandle(d3d_texture, device, &handle);
10389 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
10390 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, handle);
10391 ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#lx.\n", hr);
10392 IDirect3DTexture2_Release(d3d_texture);
10394 hr = IDirectDrawSurface_Blt(dst, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10395 ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#lx.\n", hr);
10397 hr = IDirectDrawSurface_Lock(src, NULL, &lock_desc, DDLOCK_WAIT, NULL);
10398 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
10399 switch (tests[t].bpp)
10401 case 4:
10402 ((DWORD *)lock_desc.lpSurface)[0] = (c ? c - 1 : 0) << tests[t].shift;
10403 ((DWORD *)lock_desc.lpSurface)[1] = c << tests[t].shift;
10404 ((DWORD *)lock_desc.lpSurface)[2] = min(c + 1, tests[t].max) << tests[t].shift;
10405 ((DWORD *)lock_desc.lpSurface)[3] = 0xffffffff;
10406 break;
10408 case 2:
10409 ((WORD *)lock_desc.lpSurface)[0] = (c ? c - 1 : 0) << tests[t].shift;
10410 ((WORD *)lock_desc.lpSurface)[1] = c << tests[t].shift;
10411 ((WORD *)lock_desc.lpSurface)[2] = min(c + 1, tests[t].max) << tests[t].shift;
10412 ((WORD *)lock_desc.lpSurface)[3] = 0xffff;
10413 break;
10415 hr = IDirectDrawSurface_Unlock(src, 0);
10416 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
10417 hr = IDirectDrawSurface_Blt(texture, NULL, src, NULL, DDBLT_WAIT, NULL);
10418 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
10420 ckey.dwColorSpaceLowValue = c << tests[t].shift;
10421 ckey.dwColorSpaceHighValue = c << tests[t].shift;
10422 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
10423 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
10425 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC | DDBLT_WAIT, NULL);
10426 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
10428 /* Don't make this read only, it somehow breaks the detection of the Nvidia bug below. */
10429 hr = IDirectDrawSurface_Lock(dst, NULL, &lock_desc, DDLOCK_WAIT, NULL);
10430 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
10431 switch (tests[t].bpp)
10433 case 4:
10434 data[0] = ((DWORD *)lock_desc.lpSurface)[0] & color_mask;
10435 data[1] = ((DWORD *)lock_desc.lpSurface)[1] & color_mask;
10436 data[2] = ((DWORD *)lock_desc.lpSurface)[2] & color_mask;
10437 data[3] = ((DWORD *)lock_desc.lpSurface)[3] & color_mask;
10438 break;
10440 case 2:
10441 data[0] = ((WORD *)lock_desc.lpSurface)[0] & color_mask;
10442 data[1] = ((WORD *)lock_desc.lpSurface)[1] & color_mask;
10443 data[2] = ((WORD *)lock_desc.lpSurface)[2] & color_mask;
10444 data[3] = ((WORD *)lock_desc.lpSurface)[3] & color_mask;
10445 break;
10447 hr = IDirectDrawSurface_Unlock(dst, 0);
10448 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
10450 if (!c)
10452 ok(data[0] == tests[t].clear, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
10453 tests[t].clear, data[0], tests[t].name, c);
10455 if (data[3] == tests[t].clear)
10457 /* My Geforce GTX 460 on Windows 7 misbehaves when A4R4G4B4 is blitted with color
10458 * keying: The blit takes ~0.5 seconds, and subsequent color keying draws are broken,
10459 * even when a different surface is used. The blit itself doesn't draw anything,
10460 * so we can detect the bug by looking at the otherwise unused 4th texel. It should
10461 * never be masked out by the key.
10463 * On Windows 10 the problem is worse, Blt just hangs. For this reason the ARGB4444
10464 * test is disabled entirely.
10466 * Also appears to affect the testbot in some way with R5G6B5. Color keying is
10467 * terrible on WARP. */
10468 skip("Nvidia A4R4G4B4 color keying blit bug detected, skipping.\n");
10469 IDirectDrawSurface_Release(texture);
10470 IDirectDrawSurface_Release(src);
10471 IDirectDrawSurface_Release(dst);
10472 goto done;
10475 else
10476 ok(data[0] == (c - 1) << tests[t].shift, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
10477 (c - 1) << tests[t].shift, data[0], tests[t].name, c);
10479 ok(data[1] == tests[t].clear, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
10480 tests[t].clear, data[1], tests[t].name, c);
10482 if (c == tests[t].max)
10483 ok(data[2] == tests[t].clear, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
10484 tests[t].clear, data[2], tests[t].name, c);
10485 else
10486 ok(data[2] == (c + 1) << tests[t].shift, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
10487 (c + 1) << tests[t].shift, data[2], tests[t].name, c);
10489 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
10490 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
10492 hr = IDirect3DDevice2_BeginScene(device);
10493 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
10494 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad, 4, 0);
10495 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
10496 hr = IDirect3DDevice2_EndScene(device);
10497 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
10499 color = get_surface_color(rt, 80, 240);
10500 if (!c)
10501 ok(compare_color(color, 0x0000ff00, 1) || broken(is_warp && compare_color(color, 0x00000000, 1)),
10502 "Got unexpected color 0x%08x, format %s, c=%u.\n",
10503 color, tests[t].name, c);
10504 else
10505 ok(compare_color(color, 0x00000000, 1) || broken(is_warp && compare_color(color, 0x0000ff00, 1)),
10506 "Got unexpected color 0x%08x, format %s, c=%u.\n",
10507 color, tests[t].name, c);
10509 color = get_surface_color(rt, 240, 240);
10510 ok(compare_color(color, 0x0000ff00, 1) || broken(is_warp && compare_color(color, 0x00000000, 1)),
10511 "Got unexpected color 0x%08x, format %s, c=%u.\n",
10512 color, tests[t].name, c);
10514 color = get_surface_color(rt, 400, 240);
10515 if (c == tests[t].max)
10516 ok(compare_color(color, 0x0000ff00, 1) || broken(is_warp && compare_color(color, 0x00000000, 1)),
10517 "Got unexpected color 0x%08x, format %s, c=%u.\n",
10518 color, tests[t].name, c);
10519 else
10520 ok(compare_color(color, 0x00000000, 1) || broken(is_warp && compare_color(color, 0x0000ff00, 1)),
10521 "Got unexpected color 0x%08x, format %s, c=%u.\n",
10522 color, tests[t].name, c);
10524 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
10525 ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#lx.\n", hr);
10526 IDirectDrawSurface_Release(texture);
10528 IDirectDrawSurface_Release(src);
10529 IDirectDrawSurface_Release(dst);
10531 done:
10533 destroy_viewport(device, viewport);
10534 destroy_material(green);
10535 IDirectDrawSurface_Release(rt);
10536 IDirect3DDevice2_Release(device);
10537 refcount = IDirectDraw2_Release(ddraw);
10538 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
10539 DestroyWindow(window);
10542 static void test_range_colorkey(void)
10544 IDirectDraw2 *ddraw;
10545 HWND window;
10546 HRESULT hr;
10547 IDirectDrawSurface *surface;
10548 DDSURFACEDESC surface_desc;
10549 ULONG refcount;
10550 DDCOLORKEY ckey;
10552 window = create_window();
10553 ddraw = create_ddraw();
10554 ok(!!ddraw, "Failed to create a ddraw object.\n");
10555 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
10556 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
10558 memset(&surface_desc, 0, sizeof(surface_desc));
10559 surface_desc.dwSize = sizeof(surface_desc);
10560 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
10561 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
10562 surface_desc.dwWidth = 1;
10563 surface_desc.dwHeight = 1;
10564 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
10565 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
10566 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
10567 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
10568 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
10569 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0x00000000;
10571 /* Creating a surface with a range color key fails with DDERR_NOCOLORKEY. */
10572 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000000;
10573 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000001;
10574 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
10575 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
10577 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000001;
10578 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000000;
10579 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
10580 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
10582 /* Same for DDSCAPS_OFFSCREENPLAIN. */
10583 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
10584 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000000;
10585 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000001;
10586 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
10587 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
10589 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000001;
10590 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000000;
10591 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
10592 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
10594 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000000;
10595 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000000;
10596 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
10597 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10599 /* Setting a range color key without DDCKEY_COLORSPACE collapses the key. */
10600 ckey.dwColorSpaceLowValue = 0x00000000;
10601 ckey.dwColorSpaceHighValue = 0x00000001;
10602 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &ckey);
10603 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
10605 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &ckey);
10606 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
10607 ok(!ckey.dwColorSpaceLowValue, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceLowValue);
10608 ok(!ckey.dwColorSpaceHighValue, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceHighValue);
10610 ckey.dwColorSpaceLowValue = 0x00000001;
10611 ckey.dwColorSpaceHighValue = 0x00000000;
10612 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &ckey);
10613 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
10615 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &ckey);
10616 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
10617 ok(ckey.dwColorSpaceLowValue == 0x00000001, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceLowValue);
10618 ok(ckey.dwColorSpaceHighValue == 0x00000001, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceHighValue);
10620 /* DDCKEY_COLORSPACE is ignored if the key is a single value. */
10621 ckey.dwColorSpaceLowValue = 0x00000000;
10622 ckey.dwColorSpaceHighValue = 0x00000000;
10623 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
10624 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
10626 /* Using it with a range key results in DDERR_NOCOLORKEYHW. */
10627 ckey.dwColorSpaceLowValue = 0x00000001;
10628 ckey.dwColorSpaceHighValue = 0x00000000;
10629 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
10630 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
10631 ckey.dwColorSpaceLowValue = 0x00000000;
10632 ckey.dwColorSpaceHighValue = 0x00000001;
10633 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
10634 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
10635 /* Range destination keys don't work either. */
10636 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_DESTBLT | DDCKEY_COLORSPACE, &ckey);
10637 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
10639 /* Just to show it's not because of A, R, and G having equal values. */
10640 ckey.dwColorSpaceLowValue = 0x00000000;
10641 ckey.dwColorSpaceHighValue = 0x01010101;
10642 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
10643 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
10645 /* None of these operations modified the key. */
10646 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &ckey);
10647 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
10648 ok(!ckey.dwColorSpaceLowValue, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceLowValue);
10649 ok(!ckey.dwColorSpaceHighValue, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceHighValue);
10651 IDirectDrawSurface_Release(surface);
10652 refcount = IDirectDraw2_Release(ddraw);
10653 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
10654 DestroyWindow(window);
10657 static void test_shademode(void)
10659 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
10660 unsigned int color0, color1, i, count;
10661 IDirect3DMaterial2 *background;
10662 IDirect3DViewport2 *viewport;
10663 IDirect3DDevice2 *device;
10664 IDirectDrawSurface *rt;
10665 IDirectDraw2 *ddraw;
10666 D3DLVERTEX *quad;
10667 ULONG refcount;
10668 HWND window;
10669 HRESULT hr;
10670 static D3DLVERTEX quad_strip[] =
10672 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xffff0000}},
10673 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
10674 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xff0000ff}},
10675 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xffffffff}},
10677 quad_list[] =
10679 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xffff0000}},
10680 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
10681 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xff0000ff}},
10683 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xff0000ff}},
10684 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
10685 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xffffffff}},
10687 static const struct
10689 DWORD primtype;
10690 DWORD shademode;
10691 unsigned int color0, color1;
10693 tests[] =
10695 {D3DPT_TRIANGLESTRIP, D3DSHADE_FLAT, 0x00ff0000, 0x0000ff00},
10696 {D3DPT_TRIANGLESTRIP, D3DSHADE_PHONG, 0x000dca28, 0x000d45c7},
10697 {D3DPT_TRIANGLESTRIP, D3DSHADE_GOURAUD, 0x000dca28, 0x000d45c7},
10698 {D3DPT_TRIANGLESTRIP, D3DSHADE_PHONG, 0x000dca28, 0x000d45c7},
10699 {D3DPT_TRIANGLELIST, D3DSHADE_FLAT, 0x00ff0000, 0x000000ff},
10700 {D3DPT_TRIANGLELIST, D3DSHADE_GOURAUD, 0x000dca28, 0x000d45c7},
10703 window = create_window();
10704 ddraw = create_ddraw();
10705 ok(!!ddraw, "Failed to create a ddraw object.\n");
10706 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
10708 skip("Failed to create a 3D device, skipping test.\n");
10709 IDirectDraw2_Release(ddraw);
10710 DestroyWindow(window);
10711 return;
10714 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
10715 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
10717 background = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
10718 viewport = create_viewport(device, 0, 0, 640, 480);
10719 viewport_set_background(device, viewport, background);
10720 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
10721 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#lx.\n", hr);
10723 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_FOGENABLE, FALSE);
10724 ok(SUCCEEDED(hr), "Failed to disable fog, hr %#lx.\n", hr);
10726 /* Try it first with a TRIANGLESTRIP. Do it with different geometry because
10727 * the color fixups we have to do for FLAT shading will be dependent on that. */
10729 for (i = 0; i < ARRAY_SIZE(tests); ++i)
10731 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
10732 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
10734 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SHADEMODE, tests[i].shademode);
10735 ok(hr == D3D_OK, "Failed to set shade mode, hr %#lx.\n", hr);
10737 hr = IDirect3DDevice2_BeginScene(device);
10738 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
10739 quad = tests[i].primtype == D3DPT_TRIANGLESTRIP ? quad_strip : quad_list;
10740 count = tests[i].primtype == D3DPT_TRIANGLESTRIP ? 4 : 6;
10741 hr = IDirect3DDevice2_DrawPrimitive(device, tests[i].primtype, D3DVT_LVERTEX, quad, count, 0);
10742 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
10743 hr = IDirect3DDevice2_EndScene(device);
10744 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
10746 color0 = get_surface_color(rt, 100, 100); /* Inside first triangle */
10747 color1 = get_surface_color(rt, 500, 350); /* Inside second triangle */
10749 /* For D3DSHADE_FLAT it should take the color of the first vertex of
10750 * each triangle. This requires EXT_provoking_vertex or similar
10751 * functionality being available. */
10752 /* PHONG should be the same as GOURAUD, since no hardware implements
10753 * this. */
10754 ok(compare_color(color0, tests[i].color0, 1), "Test %u shading has color0 %08x, expected %08x.\n",
10755 i, color0, tests[i].color0);
10756 ok(compare_color(color1, tests[i].color1, 1), "Test %u shading has color1 %08x, expected %08x.\n",
10757 i, color1, tests[i].color1);
10760 destroy_viewport(device, viewport);
10761 destroy_material(background);
10762 IDirectDrawSurface_Release(rt);
10763 refcount = IDirect3DDevice2_Release(device);
10764 ok(!refcount, "Device has %lu references left.\n", refcount);
10765 IDirectDraw2_Release(ddraw);
10766 DestroyWindow(window);
10769 static void test_lockrect_invalid(void)
10771 unsigned int i, r;
10772 IDirectDraw2 *ddraw;
10773 IDirectDrawSurface *surface1;
10774 IDirectDrawSurface2 *surface;
10775 HWND window;
10776 HRESULT hr;
10777 DDSURFACEDESC surface_desc;
10778 DDCAPS hal_caps;
10779 DWORD needed_caps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
10780 static RECT valid[] =
10782 {60, 60, 68, 68},
10783 {60, 60, 60, 68},
10784 {60, 60, 68, 60},
10785 {120, 60, 128, 68},
10786 {60, 120, 68, 128},
10788 static RECT invalid[] =
10790 {68, 60, 60, 68}, /* left > right */
10791 {60, 68, 68, 60}, /* top > bottom */
10792 {-8, 60, 0, 68}, /* left < surface */
10793 {60, -8, 68, 0}, /* top < surface */
10794 {-16, 60, -8, 68}, /* right < surface */
10795 {60, -16, 68, -8}, /* bottom < surface */
10796 {60, 60, 136, 68}, /* right > surface */
10797 {60, 60, 68, 136}, /* bottom > surface */
10798 {136, 60, 144, 68}, /* left > surface */
10799 {60, 136, 68, 144}, /* top > surface */
10801 static const struct
10803 DWORD caps;
10804 const char *name;
10805 HRESULT hr;
10807 resources[] =
10809 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY, "sysmem offscreenplain", DDERR_INVALIDPARAMS},
10810 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY, "vidmem offscreenplain", DDERR_INVALIDPARAMS},
10811 {DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY, "sysmem texture", DDERR_INVALIDPARAMS},
10812 {DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, "vidmem texture", DDERR_INVALIDPARAMS},
10815 window = create_window();
10816 ddraw = create_ddraw();
10817 ok(!!ddraw, "Failed to create a ddraw object.\n");
10818 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
10819 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
10821 memset(&hal_caps, 0, sizeof(hal_caps));
10822 hal_caps.dwSize = sizeof(hal_caps);
10823 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, NULL);
10824 ok(SUCCEEDED(hr), "Failed to get caps, hr %#lx.\n", hr);
10825 if ((hal_caps.ddsCaps.dwCaps & needed_caps) != needed_caps)
10827 skip("Required surface types not supported, skipping test.\n");
10828 goto done;
10831 for (r = 0; r < ARRAY_SIZE(resources); ++r)
10833 memset(&surface_desc, 0, sizeof(surface_desc));
10834 surface_desc.dwSize = sizeof(surface_desc);
10835 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
10836 surface_desc.ddsCaps.dwCaps = resources[r].caps;
10837 surface_desc.dwWidth = 128;
10838 surface_desc.dwHeight = 128;
10839 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
10840 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
10841 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
10842 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xff0000;
10843 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x00ff00;
10844 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x0000ff;
10846 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
10847 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx, type %s.\n", hr, resources[r].name);
10848 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface);
10849 ok(SUCCEEDED(hr), "Failed to QI IDirectDrawSurface2 interface, hr %#lx.\n", hr);
10850 IDirectDrawSurface_Release(surface1);
10852 hr = IDirectDrawSurface2_Lock(surface, NULL, NULL, DDLOCK_WAIT, NULL);
10853 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx, type %s.\n", hr, resources[r].name);
10855 for (i = 0; i < ARRAY_SIZE(valid); ++i)
10857 RECT *rect = &valid[i];
10859 memset(&surface_desc, 0, sizeof(surface_desc));
10860 surface_desc.dwSize = sizeof(surface_desc);
10862 hr = IDirectDrawSurface2_Lock(surface, rect, &surface_desc, DDLOCK_WAIT, NULL);
10863 ok(SUCCEEDED(hr), "Lock failed (%#lx) for rect %s, type %s.\n",
10864 hr, wine_dbgstr_rect(rect), resources[r].name);
10866 hr = IDirectDrawSurface2_Unlock(surface, NULL);
10867 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, type %s.\n", hr, resources[r].name);
10870 for (i = 0; i < ARRAY_SIZE(invalid); ++i)
10872 RECT *rect = &invalid[i];
10874 memset(&surface_desc, 1, sizeof(surface_desc));
10875 surface_desc.dwSize = sizeof(surface_desc);
10877 hr = IDirectDrawSurface2_Lock(surface, rect, &surface_desc, DDLOCK_WAIT, NULL);
10878 ok(hr == resources[r].hr, "Lock returned %#lx for rect %s, type %s.\n",
10879 hr, wine_dbgstr_rect(rect), resources[r].name);
10880 if (SUCCEEDED(hr))
10882 hr = IDirectDrawSurface2_Unlock(surface, NULL);
10883 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, type %s.\n", hr, resources[r].name);
10885 else
10886 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
10889 hr = IDirectDrawSurface2_Lock(surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
10890 ok(SUCCEEDED(hr), "Lock(rect = NULL) failed, hr %#lx, type %s.\n",
10891 hr, resources[r].name);
10892 hr = IDirectDrawSurface2_Lock(surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
10893 ok(hr == DDERR_SURFACEBUSY, "Double lock(rect = NULL) returned %#lx, type %s.\n",
10894 hr, resources[r].name);
10895 hr = IDirectDrawSurface2_Unlock(surface, NULL);
10896 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, type %s.\n", hr, resources[r].name);
10898 hr = IDirectDrawSurface2_Lock(surface, &valid[0], &surface_desc, DDLOCK_WAIT, NULL);
10899 ok(SUCCEEDED(hr), "Lock(rect = %s) failed (%#lx).\n", wine_dbgstr_rect(&valid[0]), hr);
10900 hr = IDirectDrawSurface2_Lock(surface, &valid[0], &surface_desc, DDLOCK_WAIT, NULL);
10901 ok(hr == DDERR_SURFACEBUSY, "Double lock(rect = %s) failed (%#lx).\n",
10902 wine_dbgstr_rect(&valid[0]), hr);
10904 /* Locking a different rectangle returns DD_OK, but it seems to break the surface.
10905 * Afterwards unlocking the surface fails(NULL rectangle or both locked rectangles) */
10907 hr = IDirectDrawSurface2_Unlock(surface, NULL);
10908 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, type %s.\n", hr, resources[r].name);
10910 IDirectDrawSurface2_Release(surface);
10913 done:
10914 IDirectDraw2_Release(ddraw);
10915 DestroyWindow(window);
10918 static void test_yv12_overlay(void)
10920 IDirectDrawSurface *src_surface, *dst_surface;
10921 RECT rect = {13, 17, 14, 18};
10922 unsigned int offset, y;
10923 unsigned char *base;
10924 IDirectDraw2 *ddraw;
10925 DDSURFACEDESC desc;
10926 HWND window;
10927 HRESULT hr;
10929 window = create_window();
10930 ddraw = create_ddraw();
10931 ok(!!ddraw, "Failed to create a ddraw object.\n");
10932 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
10933 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
10935 if (!(src_surface = create_overlay(ddraw, 256, 256, MAKEFOURCC('Y','V','1','2'))))
10937 skip("Failed to create a YV12 overlay, skipping test.\n");
10938 goto done;
10941 memset(&desc, 0, sizeof(desc));
10942 desc.dwSize = sizeof(desc);
10943 hr = IDirectDrawSurface_Lock(src_surface, NULL, &desc, DDLOCK_WAIT, NULL);
10944 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
10946 ok(desc.dwFlags == (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH),
10947 "Got unexpected flags %#lx.\n", desc.dwFlags);
10948 ok(desc.ddsCaps.dwCaps == (DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_HWCODEC)
10949 || desc.ddsCaps.dwCaps == (DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM),
10950 "Got unexpected caps %#lx.\n", desc.ddsCaps.dwCaps);
10951 ok(desc.dwWidth == 256, "Got unexpected width %lu.\n", desc.dwWidth);
10952 ok(desc.dwHeight == 256, "Got unexpected height %lu.\n", desc.dwHeight);
10953 /* The overlay pitch seems to have 256 byte alignment. */
10954 ok(!(U1(desc).lPitch & 0xff), "Got unexpected pitch %lu.\n", U1(desc).lPitch);
10956 /* Fill the surface with some data for the blit test. */
10957 base = desc.lpSurface;
10958 /* Luminance */
10959 for (y = 0; y < desc.dwHeight; ++y)
10961 memset(base + U1(desc).lPitch * y, 0x10, desc.dwWidth);
10963 /* V */
10964 for (; y < desc.dwHeight + desc.dwHeight / 4; ++y)
10966 memset(base + U1(desc).lPitch * y, 0x20, desc.dwWidth);
10968 /* U */
10969 for (; y < desc.dwHeight + desc.dwHeight / 2; ++y)
10971 memset(base + U1(desc).lPitch * y, 0x30, desc.dwWidth);
10974 hr = IDirectDrawSurface_Unlock(src_surface, NULL);
10975 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
10977 /* YV12 uses 2x2 blocks with 6 bytes per block (4*Y, 1*U, 1*V). Unlike
10978 * other block-based formats like DXT the entire Y channel is stored in
10979 * one big chunk of memory, followed by the chroma channels. So partial
10980 * locks do not really make sense. Show that they are allowed nevertheless
10981 * and the offset points into the luminance data. */
10982 hr = IDirectDrawSurface_Lock(src_surface, &rect, &desc, DDLOCK_WAIT, NULL);
10983 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
10984 offset = ((const unsigned char *)desc.lpSurface - base);
10985 ok(offset == rect.top * U1(desc).lPitch + rect.left, "Got unexpected offset %u, expected %lu.\n",
10986 offset, rect.top * U1(desc).lPitch + rect.left);
10987 hr = IDirectDrawSurface_Unlock(src_surface, NULL);
10988 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
10990 if (!(dst_surface = create_overlay(ddraw, 256, 256, MAKEFOURCC('Y','V','1','2'))))
10992 /* Windows XP with a Radeon X1600 GPU refuses to create a second
10993 * overlay surface, DDERR_NOOVERLAYHW, making the blit tests moot. */
10994 skip("Failed to create a second YV12 surface, skipping blit test.\n");
10995 IDirectDrawSurface_Release(src_surface);
10996 goto done;
10999 hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, NULL, DDBLT_WAIT, NULL);
11000 /* VMware rejects YV12 blits. This behavior has not been seen on real
11001 * hardware yet, so mark it broken. */
11002 ok(SUCCEEDED(hr) || broken(hr == E_NOTIMPL), "Failed to blit, hr %#lx.\n", hr);
11004 if (SUCCEEDED(hr))
11006 memset(&desc, 0, sizeof(desc));
11007 desc.dwSize = sizeof(desc);
11008 hr = IDirectDrawSurface_Lock(dst_surface, NULL, &desc, DDLOCK_WAIT, NULL);
11009 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
11011 base = desc.lpSurface;
11012 ok(base[0] == 0x10, "Got unexpected Y data 0x%02x.\n", base[0]);
11013 base += desc.dwHeight * U1(desc).lPitch;
11014 ok(base[0] == 0x20, "Got unexpected V data 0x%02x.\n", base[0]);
11015 base += desc.dwHeight / 4 * U1(desc).lPitch;
11016 ok(base[0] == 0x30, "Got unexpected U data 0x%02x.\n", base[0]);
11018 hr = IDirectDrawSurface_Unlock(dst_surface, NULL);
11019 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
11022 IDirectDrawSurface_Release(dst_surface);
11023 IDirectDrawSurface_Release(src_surface);
11024 done:
11025 IDirectDraw2_Release(ddraw);
11026 DestroyWindow(window);
11029 static BOOL dwm_enabled(void)
11031 BOOL ret = FALSE;
11033 if (!strcmp(winetest_platform, "wine"))
11034 return FALSE;
11035 if (!pDwmIsCompositionEnabled)
11036 return FALSE;
11037 if (FAILED(pDwmIsCompositionEnabled(&ret)))
11038 return FALSE;
11039 return ret;
11042 static void test_offscreen_overlay(void)
11044 IDirectDrawSurface *overlay, *offscreen, *primary;
11045 DDSURFACEDESC surface_desc;
11046 IDirectDraw2 *ddraw;
11047 HWND window;
11048 HRESULT hr;
11049 HDC dc;
11051 window = create_window();
11052 ddraw = create_ddraw();
11053 ok(!!ddraw, "Failed to create a ddraw object.\n");
11054 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
11055 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
11057 if (!(overlay = create_overlay(ddraw, 64, 64, MAKEFOURCC('U','Y','V','Y'))))
11059 skip("Failed to create a UYVY overlay, skipping test.\n");
11060 goto done;
11063 memset(&surface_desc, 0, sizeof(surface_desc));
11064 surface_desc.dwSize = sizeof(surface_desc);
11065 surface_desc.dwFlags = DDSD_CAPS;
11066 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
11067 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
11068 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
11070 /* On Windows 7, and probably Vista, UpdateOverlay() will return
11071 * DDERR_OUTOFCAPS if the dwm is active. Calling GetDC() on the primary
11072 * surface prevents this by disabling the dwm. */
11073 hr = IDirectDrawSurface_GetDC(primary, &dc);
11074 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
11075 hr = IDirectDrawSurface_ReleaseDC(primary, dc);
11076 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
11078 /* Try to overlay a NULL surface. */
11079 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, NULL, NULL, DDOVER_SHOW, NULL);
11080 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
11081 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, NULL, NULL, DDOVER_HIDE, NULL);
11082 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
11084 /* Try to overlay an offscreen surface. */
11085 memset(&surface_desc, 0, sizeof(surface_desc));
11086 surface_desc.dwSize = sizeof(surface_desc);
11087 surface_desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
11088 surface_desc.dwWidth = 64;
11089 surface_desc.dwHeight = 64;
11090 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
11091 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
11092 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
11093 surface_desc.ddpfPixelFormat.dwFourCC = 0;
11094 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 16;
11095 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xf800;
11096 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x07e0;
11097 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x001f;
11098 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &offscreen, NULL);
11099 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
11101 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, offscreen, NULL, DDOVER_SHOW, NULL);
11102 ok(SUCCEEDED(hr) || broken(hr == DDERR_OUTOFCAPS && dwm_enabled())
11103 || broken(hr == E_NOTIMPL && ddraw_is_vmware(ddraw)),
11104 "Failed to update overlay, hr %#lx.\n", hr);
11106 /* Try to overlay the primary with a non-overlay surface. */
11107 hr = IDirectDrawSurface_UpdateOverlay(offscreen, NULL, primary, NULL, DDOVER_SHOW, NULL);
11108 ok(hr == DDERR_NOTAOVERLAYSURFACE, "Got unexpected hr %#lx.\n", hr);
11109 hr = IDirectDrawSurface_UpdateOverlay(offscreen, NULL, primary, NULL, DDOVER_HIDE, NULL);
11110 ok(hr == DDERR_NOTAOVERLAYSURFACE, "Got unexpected hr %#lx.\n", hr);
11112 IDirectDrawSurface_Release(offscreen);
11113 IDirectDrawSurface_Release(primary);
11114 IDirectDrawSurface_Release(overlay);
11115 done:
11116 IDirectDraw2_Release(ddraw);
11117 DestroyWindow(window);
11120 static void test_overlay_rect(void)
11122 IDirectDrawSurface *overlay, *primary = NULL;
11123 DDSURFACEDESC surface_desc;
11124 RECT rect = {0, 0, 64, 64};
11125 IDirectDraw2 *ddraw;
11126 LONG pos_x, pos_y;
11127 HRESULT hr, hr2;
11128 HWND window;
11129 HDC dc;
11131 window = create_window();
11132 ddraw = create_ddraw();
11133 ok(!!ddraw, "Failed to create a ddraw object.\n");
11134 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
11135 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
11137 if (!(overlay = create_overlay(ddraw, 64, 64, MAKEFOURCC('U','Y','V','Y'))))
11139 skip("Failed to create a UYVY overlay, skipping test.\n");
11140 goto done;
11143 memset(&surface_desc, 0, sizeof(surface_desc));
11144 surface_desc.dwSize = sizeof(surface_desc);
11145 surface_desc.dwFlags = DDSD_CAPS;
11146 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
11147 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
11148 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
11150 /* On Windows 7, and probably Vista, UpdateOverlay() will return
11151 * DDERR_OUTOFCAPS if the dwm is active. Calling GetDC() on the primary
11152 * surface prevents this by disabling the dwm. */
11153 hr = IDirectDrawSurface_GetDC(primary, &dc);
11154 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
11155 hr = IDirectDrawSurface_ReleaseDC(primary, dc);
11156 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
11158 /* On Windows 8 and newer DWM can't be turned off, making overlays unusable. */
11159 if (dwm_enabled())
11161 win_skip("Cannot disable DWM, skipping overlay test.\n");
11162 goto done;
11165 /* The dx sdk sort of implies that rect must be set when DDOVER_SHOW is
11166 * used. This is not true in Windows Vista and earlier, but changed in
11167 * Windows 7. */
11168 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, &rect, DDOVER_SHOW, NULL);
11169 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#lx.\n", hr);
11170 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, NULL, DDOVER_HIDE, NULL);
11171 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#lx.\n", hr);
11172 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, NULL, DDOVER_SHOW, NULL);
11173 ok(hr == DD_OK || hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
11175 /* Show that the overlay position is the (top, left) coordinate of the
11176 * destination rectangle. */
11177 OffsetRect(&rect, 32, 16);
11178 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, &rect, DDOVER_SHOW, NULL);
11179 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#lx.\n", hr);
11180 pos_x = -1; pos_y = -1;
11181 hr = IDirectDrawSurface_GetOverlayPosition(overlay, &pos_x, &pos_y);
11182 ok(SUCCEEDED(hr), "Failed to get overlay position, hr %#lx.\n", hr);
11183 ok(pos_x == rect.left, "Got unexpected pos_x %ld, expected %ld.\n", pos_x, rect.left);
11184 ok(pos_y == rect.top, "Got unexpected pos_y %ld, expected %ld.\n", pos_y, rect.top);
11186 /* Passing a NULL dest rect sets the position to 0/0. Visually it can be
11187 * seen that the overlay overlays the whole primary(==screen). */
11188 hr2 = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, NULL, 0, NULL);
11189 ok(hr2 == DD_OK || hr2 == DDERR_INVALIDPARAMS || hr2 == DDERR_OUTOFCAPS, "Got unexpected hr %#lx.\n", hr2);
11190 hr = IDirectDrawSurface_GetOverlayPosition(overlay, &pos_x, &pos_y);
11191 ok(SUCCEEDED(hr), "Failed to get overlay position, hr %#lx.\n", hr);
11192 if (SUCCEEDED(hr2))
11194 ok(!pos_x, "Got unexpected pos_x %ld.\n", pos_x);
11195 ok(!pos_y, "Got unexpected pos_y %ld.\n", pos_y);
11197 else
11199 ok(pos_x == 32, "Got unexpected pos_x %ld.\n", pos_x);
11200 ok(pos_y == 16, "Got unexpected pos_y %ld.\n", pos_y);
11203 /* The position cannot be retrieved when the overlay is not shown. */
11204 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, &rect, DDOVER_HIDE, NULL);
11205 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#lx.\n", hr);
11206 pos_x = -1; pos_y = -1;
11207 hr = IDirectDrawSurface_GetOverlayPosition(overlay, &pos_x, &pos_y);
11208 ok(hr == DDERR_OVERLAYNOTVISIBLE, "Got unexpected hr %#lx.\n", hr);
11209 ok(!pos_x, "Got unexpected pos_x %ld.\n", pos_x);
11210 ok(!pos_y, "Got unexpected pos_y %ld.\n", pos_y);
11212 done:
11213 if (primary)
11214 IDirectDrawSurface_Release(primary);
11215 if (overlay)
11216 IDirectDrawSurface_Release(overlay);
11217 IDirectDraw2_Release(ddraw);
11218 DestroyWindow(window);
11221 static void test_blt(void)
11223 IDirectDrawSurface *surface, *rt;
11224 DDSURFACEDESC surface_desc;
11225 IDirect3DDevice2 *device;
11226 IDirectDraw2 *ddraw;
11227 unsigned int i;
11228 ULONG refcount;
11229 HWND window;
11230 HRESULT hr;
11232 static struct
11234 RECT src_rect;
11235 RECT dst_rect;
11236 HRESULT hr;
11238 test_data[] =
11240 {{160, 0, 640, 480}, { 0, 0, 480, 480}, DD_OK}, /* Overlapped blit. */
11241 {{160, 480, 640, 0}, { 0, 0, 480, 480}, DDERR_INVALIDRECT}, /* Overlapped blit, flipped source. */
11242 {{640, 0, 160, 480}, { 0, 0, 480, 480}, DDERR_INVALIDRECT}, /* Overlapped blit, mirrored source. */
11243 {{160, 0, 480, 480}, { 0, 0, 480, 480}, DD_OK}, /* Overlapped blit, stretched x. */
11244 {{160, 160, 640, 480}, { 0, 0, 480, 480}, DD_OK}, /* Overlapped blit, stretched y. */
11245 {{ 0, 0, 640, 480}, { 0, 0, 640, 480}, DD_OK}, /* Full surface blit. */
11246 {{ 0, 0, 640, 480}, { 0, 480, 640, 0}, DDERR_INVALIDRECT}, /* Full surface, flipped destination. */
11247 {{ 0, 0, 640, 480}, {640, 0, 0, 480}, DDERR_INVALIDRECT}, /* Full surface, mirrored destination. */
11248 {{ 0, 480, 640, 0}, { 0, 0, 640, 480}, DDERR_INVALIDRECT}, /* Full surface, flipped source. */
11249 {{640, 0, 0, 480}, { 0, 0, 640, 480}, DDERR_INVALIDRECT}, /* Full surface, mirrored source. */
11252 window = create_window();
11253 ddraw = create_ddraw();
11254 ok(!!ddraw, "Failed to create a ddraw object.\n");
11255 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
11257 skip("Failed to create a 3D device, skipping test.\n");
11258 IDirectDraw2_Release(ddraw);
11259 DestroyWindow(window);
11260 return;
11263 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
11264 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
11266 memset(&surface_desc, 0, sizeof(surface_desc));
11267 surface_desc.dwSize = sizeof(surface_desc);
11268 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
11269 surface_desc.dwWidth = 640;
11270 surface_desc.dwHeight = 480;
11271 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
11272 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
11273 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
11275 hr = IDirectDrawSurface_Blt(surface, NULL, surface, NULL, 0, NULL);
11276 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
11278 hr = IDirectDrawSurface_Blt(surface, NULL, rt, NULL, 0, NULL);
11279 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
11281 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
11283 hr = IDirectDrawSurface_Blt(surface, &test_data[i].dst_rect,
11284 surface, &test_data[i].src_rect, DDBLT_WAIT, NULL);
11285 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#lx, expected %#lx.\n", i, hr, test_data[i].hr);
11287 hr = IDirectDrawSurface_Blt(surface, &test_data[i].dst_rect,
11288 rt, &test_data[i].src_rect, DDBLT_WAIT, NULL);
11289 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#lx, expected %#lx.\n", i, hr, test_data[i].hr);
11291 hr = IDirectDrawSurface_Blt(surface, &test_data[i].dst_rect,
11292 NULL, &test_data[i].src_rect, DDBLT_WAIT, NULL);
11293 ok(hr == DDERR_INVALIDPARAMS, "Test %u: Got unexpected hr %#lx.\n", i, hr);
11295 hr = IDirectDrawSurface_Blt(surface, &test_data[i].dst_rect, NULL, NULL, DDBLT_WAIT, NULL);
11296 ok(hr == DDERR_INVALIDPARAMS, "Test %u: Got unexpected hr %#lx.\n", i, hr);
11299 IDirectDrawSurface_Release(surface);
11300 IDirectDrawSurface_Release(rt);
11301 refcount = IDirect3DDevice2_Release(device);
11302 ok(!refcount, "Device has %lu references left.\n", refcount);
11303 IDirectDraw2_Release(ddraw);
11304 DestroyWindow(window);
11307 static void test_blt_z_alpha(void)
11309 DWORD blt_flags[] =
11311 /* 0 */
11312 DDBLT_ALPHADEST,
11313 DDBLT_ALPHADESTCONSTOVERRIDE,
11314 DDBLT_ALPHADESTNEG,
11315 DDBLT_ALPHADESTSURFACEOVERRIDE,
11316 DDBLT_ALPHAEDGEBLEND,
11317 /* 5 */
11318 DDBLT_ALPHASRC,
11319 DDBLT_ALPHASRCCONSTOVERRIDE,
11320 DDBLT_ALPHASRCNEG,
11321 DDBLT_ALPHASRCSURFACEOVERRIDE,
11322 DDBLT_ZBUFFER,
11323 /* 10 */
11324 DDBLT_ZBUFFERDESTCONSTOVERRIDE,
11325 DDBLT_ZBUFFERDESTOVERRIDE,
11326 DDBLT_ZBUFFERSRCCONSTOVERRIDE,
11327 DDBLT_ZBUFFERSRCOVERRIDE,
11329 IDirectDrawSurface *src_surface, *dst_surface;
11330 DDSURFACEDESC surface_desc;
11331 unsigned int color, i;
11332 IDirectDraw2 *ddraw;
11333 DDPIXELFORMAT pf;
11334 ULONG refcount;
11335 HWND window;
11336 HRESULT hr;
11337 DDBLTFX fx;
11339 window = create_window();
11340 ddraw = create_ddraw();
11341 ok(!!ddraw, "Failed to create a ddraw object.\n");
11342 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
11343 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
11345 memset(&pf, 0, sizeof(pf));
11346 pf.dwSize = sizeof(pf);
11347 pf.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
11348 U1(pf).dwRGBBitCount = 32;
11349 U2(pf).dwRBitMask = 0x00ff0000;
11350 U3(pf).dwGBitMask = 0x0000ff00;
11351 U4(pf).dwBBitMask = 0x000000ff;
11352 U5(pf).dwRGBAlphaBitMask = 0xff000000;
11354 memset(&surface_desc, 0, sizeof(surface_desc));
11355 surface_desc.dwSize = sizeof(surface_desc);
11356 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
11357 surface_desc.dwWidth = 64;
11358 surface_desc.dwHeight = 64;
11359 surface_desc.ddpfPixelFormat = pf;
11360 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
11362 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
11363 ok(SUCCEEDED(hr), "Failed to create source surface, hr %#lx.\n", hr);
11364 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
11365 ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#lx.\n", hr);
11367 memset(&fx, 0, sizeof(fx));
11368 fx.dwSize = sizeof(fx);
11369 fx.dwZBufferOpCode = D3DCMP_NEVER;
11370 fx.dwZDestConstBitDepth = 32;
11371 U1(fx).dwZDestConst = 0x11111111;
11372 fx.dwZSrcConstBitDepth = 32;
11373 U2(fx).dwZSrcConst = 0xeeeeeeee;
11374 fx.dwAlphaEdgeBlendBitDepth = 8;
11375 fx.dwAlphaEdgeBlend = 0x7f;
11376 fx.dwAlphaDestConstBitDepth = 8;
11377 U3(fx).dwAlphaDestConst = 0xdd;
11378 fx.dwAlphaSrcConstBitDepth = 8;
11379 U4(fx).dwAlphaSrcConst = 0x22;
11381 for (i = 0; i < ARRAY_SIZE(blt_flags); ++i)
11383 U5(fx).dwFillColor = 0x3300ff00;
11384 hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
11385 ok(SUCCEEDED(hr), "Test %u: Got unexpected hr %#lx.\n", i, hr);
11387 U5(fx).dwFillColor = 0xccff0000;
11388 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
11389 ok(SUCCEEDED(hr), "Test %u: Got unexpected hr %#lx.\n", i, hr);
11391 hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, NULL, blt_flags[i] | DDBLT_WAIT, &fx);
11392 ok(SUCCEEDED(hr), "Test %u: Got unexpected hr %#lx.\n", i, hr);
11394 color = get_surface_color(dst_surface, 32, 32);
11395 ok(compare_color(color, 0x0000ff00, 0), "Test %u: Got unexpected color 0x%08x.\n", i, color);
11398 IDirectDrawSurface_Release(dst_surface);
11399 IDirectDrawSurface_Release(src_surface);
11400 refcount = IDirectDraw2_Release(ddraw);
11401 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
11402 DestroyWindow(window);
11405 static void test_cross_device_blt(void)
11407 IDirectDrawSurface *surface, *surface2, *sysmem_surface;
11408 IDirect3DDevice2 *device, *device2;
11409 IDirectDraw2 *ddraw, *ddraw2;
11410 DDSURFACEDESC surface_desc;
11411 HWND window, window2;
11412 unsigned int color;
11413 ULONG refcount;
11414 DDBLTFX fx;
11415 HRESULT hr;
11417 window = create_window();
11418 ddraw = create_ddraw();
11419 if (!(device = create_device(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN)))
11421 skip("Failed to create a 3D device.\n");
11422 IDirectDraw2_Release(ddraw);
11423 DestroyWindow(window);
11424 return;
11427 window2 = create_window();
11428 ddraw2 = create_ddraw();
11429 if (!(device2 = create_device(ddraw2, window2, DDSCL_NORMAL)))
11431 skip("Failed to create a 3D device.\n");
11432 IDirectDraw2_Release(ddraw2);
11433 IDirect3DDevice2_Release(device);
11434 IDirectDraw2_Release(ddraw);
11435 DestroyWindow(window);
11436 DestroyWindow(window2);
11437 return;
11440 memset(&surface_desc, 0, sizeof(surface_desc));
11441 surface_desc.dwSize = sizeof(surface_desc);
11442 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
11443 surface_desc.dwWidth = 640;
11444 surface_desc.dwHeight = 480;
11445 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
11446 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &sysmem_surface, NULL);
11447 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
11449 memset(&surface_desc, 0, sizeof(surface_desc));
11450 surface_desc.dwSize = sizeof(surface_desc);
11451 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
11452 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_VIDEOMEMORY;
11453 surface_desc.dwBackBufferCount = 2;
11454 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
11455 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
11457 memset(&surface_desc, 0, sizeof(surface_desc));
11458 surface_desc.dwSize = sizeof(surface_desc);
11459 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
11460 surface_desc.dwWidth = 640;
11461 surface_desc.dwHeight = 480;
11462 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
11463 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
11464 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
11465 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 16;
11466 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00007c00;
11467 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x000003e0;
11468 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x0000001f;
11469 hr = IDirectDraw2_CreateSurface(ddraw2, &surface_desc, &surface2, NULL);
11470 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
11472 memset(&fx, 0, sizeof(fx));
11473 fx.dwSize = sizeof(fx);
11474 U5(fx).dwFillColor = 0xff0000ff;
11475 hr = IDirectDrawSurface_Blt(surface2, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
11476 ok(SUCCEEDED(hr), "Failed to fill surface, hr %#lx.\n", hr);
11478 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_WAIT, NULL);
11479 ok(hr == E_NOTIMPL, "Got unexpected hr %#lx.\n", hr);
11480 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
11481 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
11482 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_WAIT, NULL);
11483 ok(hr == E_NOTIMPL, "Got unexpected hr %#lx.\n", hr);
11484 color = get_surface_color(surface, 320, 240);
11485 ok(color == 0x00000000, "Got unexpected color 0x%08x.\n", color);
11487 hr = IDirectDrawSurface_Blt(sysmem_surface, NULL, surface2, NULL, DDBLT_WAIT, NULL);
11488 ok(hr == E_NOTIMPL, "Got unexpected hr %#lx.\n", hr);
11489 color = get_surface_color(sysmem_surface, 320, 240);
11490 ok(color == 0x00000000, "Got unexpected color 0x%08x.\n", color);
11492 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
11493 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
11494 hr = IDirectDrawSurface_IsLost(sysmem_surface);
11495 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
11497 hr = IDirectDrawSurface_Blt(sysmem_surface, NULL, surface2, NULL, DDBLT_WAIT, NULL);
11498 ok(hr == E_NOTIMPL, "Got unexpected hr %#lx.\n", hr);
11499 color = get_surface_color(sysmem_surface, 320, 240);
11500 ok(color == 0x00000000, "Got unexpected color 0x%08x.\n", color);
11502 IDirectDrawSurface_Release(surface2);
11503 memset(&surface_desc, 0, sizeof(surface_desc));
11504 surface_desc.dwSize = sizeof(surface_desc);
11505 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
11506 surface_desc.dwWidth = 640;
11507 surface_desc.dwHeight = 480;
11508 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
11509 hr = IDirectDraw2_CreateSurface(ddraw2, &surface_desc, &surface2, NULL);
11510 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
11511 hr = IDirectDrawSurface_Blt(surface2, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
11512 ok(SUCCEEDED(hr), "Failed to fill surface, hr %#lx.\n", hr);
11514 hr = IDirectDrawSurface_Blt(sysmem_surface, NULL, surface2, NULL, DDBLT_WAIT, NULL);
11515 todo_wine ok(hr == D3D_OK, "Failed to blit, hr %#lx.\n", hr);
11516 color = get_surface_color(sysmem_surface, 320, 240);
11517 todo_wine ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
11519 IDirectDrawSurface_Release(surface);
11520 IDirectDrawSurface_Release(surface2);
11521 IDirectDrawSurface_Release(sysmem_surface);
11522 refcount = IDirect3DDevice2_Release(device);
11523 ok(!refcount, "Device has %lu references left.\n", refcount);
11524 refcount = IDirect3DDevice2_Release(device2);
11525 ok(!refcount, "Device has %lu references left.\n", refcount);
11526 IDirectDraw2_Release(ddraw);
11527 IDirectDraw2_Release(ddraw2);
11528 DestroyWindow(window);
11529 DestroyWindow(window2);
11532 static void test_getdc(void)
11534 IDirectDrawSurface *surface, *surface2, *tmp;
11535 DDSURFACEDESC surface_desc, map_desc;
11536 DDSCAPS caps = {DDSCAPS_COMPLEX};
11537 IDirectDraw2 *ddraw;
11538 unsigned int i, screen_bpp;
11539 HWND window;
11540 HDC dc, dc2;
11541 HRESULT hr;
11543 static const struct
11545 const char *name;
11546 DDPIXELFORMAT format;
11547 BOOL getdc_supported;
11548 HRESULT alt_result;
11550 test_data[] =
11552 {"D3DFMT_A8R8G8B8", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {32},
11553 {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}}, TRUE},
11554 {"D3DFMT_X8R8G8B8", {sizeof(test_data->format), DDPF_RGB, 0, {32},
11555 {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0x00000000}}, TRUE},
11556 {"D3DFMT_R5G6B5", {sizeof(test_data->format), DDPF_RGB, 0, {16},
11557 {0x0000f800}, {0x000007e0}, {0x0000001f}, {0x00000000}}, TRUE},
11558 {"D3DFMT_X1R5G5B5", {sizeof(test_data->format), DDPF_RGB, 0, {16},
11559 {0x00007c00}, {0x000003e0}, {0x0000001f}, {0x00000000}}, TRUE},
11560 {"D3DFMT_A1R5G5B5", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {16},
11561 {0x00007c00}, {0x000003e0}, {0x0000001f}, {0x00008000}}, TRUE},
11562 {"D3DFMT_A4R4G4B4", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {16},
11563 {0x00000f00}, {0x000000f0}, {0x0000000f}, {0x0000f000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
11564 {"D3DFMT_X4R4G4B4", {sizeof(test_data->format), DDPF_RGB, 0, {16},
11565 {0x00000f00}, {0x000000f0}, {0x0000000f}, {0x00000000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
11566 {"D3DFMT_A2R10G10B10", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {32},
11567 {0xc0000000}, {0x3ff00000}, {0x000ffc00}, {0x000003ff}}, TRUE},
11568 {"D3DFMT_A8B8G8R8", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {32},
11569 {0x000000ff}, {0x0000ff00}, {0x00ff0000}, {0xff000000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
11570 {"D3DFMT_X8B8G8R8", {sizeof(test_data->format), DDPF_RGB, 0, {32},
11571 {0x000000ff}, {0x0000ff00}, {0x00ff0000}, {0x00000000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
11572 {"D3DFMT_R3G3B2", {sizeof(test_data->format), DDPF_RGB, 0, {8},
11573 {0x000000e0}, {0x0000001c}, {0x00000003}, {0x00000000}}, FALSE},
11574 /* GetDC() on a P8 surface fails unless the display mode is 8 bpp.
11575 * This is not implemented in wine yet, so disable the test for now.
11576 * Succeeding P8 GetDC() calls are tested in the ddraw:visual test.
11577 {"D3DFMT_P8", {sizeof(test_data->format), DDPF_PALETTEINDEXED8 | DDPF_RGB, 0, {8 },
11578 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
11580 {"D3DFMT_L8", {sizeof(test_data->format), DDPF_LUMINANCE, 0, {8},
11581 {0x000000ff}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
11582 {"D3DFMT_A8L8", {sizeof(test_data->format), DDPF_ALPHAPIXELS | DDPF_LUMINANCE, 0, {16},
11583 {0x000000ff}, {0x00000000}, {0x00000000}, {0x0000ff00}}, FALSE},
11584 {"D3DFMT_DXT1", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','1'), {0},
11585 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
11586 {"D3DFMT_DXT2", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','2'), {0},
11587 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
11588 {"D3DFMT_DXT3", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','3'), {0},
11589 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
11590 {"D3DFMT_DXT4", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','4'), {0},
11591 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
11592 {"D3DFMT_DXT5", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','5'), {0},
11593 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
11596 window = create_window();
11597 ddraw = create_ddraw();
11598 ok(!!ddraw, "Failed to create a ddraw object.\n");
11599 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
11600 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
11602 surface_desc.dwSize = sizeof(surface_desc);
11603 hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
11604 ok(SUCCEEDED(hr), "Failed to get display mode, hr %#lx.\n", hr);
11605 screen_bpp = U1(surface_desc.ddpfPixelFormat).dwRGBBitCount;
11607 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
11609 memset(&surface_desc, 0, sizeof(surface_desc));
11610 surface_desc.dwSize = sizeof(surface_desc);
11611 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
11612 surface_desc.dwWidth = 64;
11613 surface_desc.dwHeight = 64;
11614 surface_desc.ddpfPixelFormat = test_data[i].format;
11615 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
11617 if (FAILED(IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
11619 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
11620 if (FAILED(hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
11622 skip("Failed to create surface for format %s (hr %#lx), skipping tests.\n", test_data[i].name, hr);
11623 continue;
11627 dc = (void *)0x1234;
11628 hr = IDirectDrawSurface_GetDC(surface, &dc);
11629 if (test_data[i].getdc_supported)
11630 ok(SUCCEEDED(hr) || broken(hr == test_data[i].alt_result || ddraw_is_vmware(ddraw)),
11631 "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11632 else
11633 ok(FAILED(hr), "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11635 if (SUCCEEDED(hr))
11637 unsigned int width_bytes;
11638 DIBSECTION dib;
11639 HBITMAP bitmap;
11640 DWORD type;
11641 int size;
11643 type = GetObjectType(dc);
11644 ok(type == OBJ_MEMDC, "Got unexpected object type %#lx for format %s.\n", type, test_data[i].name);
11645 bitmap = GetCurrentObject(dc, OBJ_BITMAP);
11646 type = GetObjectType(bitmap);
11647 ok(type == OBJ_BITMAP, "Got unexpected object type %#lx for format %s.\n", type, test_data[i].name);
11649 size = GetObjectA(bitmap, sizeof(dib), &dib);
11650 ok(size == sizeof(dib), "Got unexpected size %d for format %s.\n", size, test_data[i].name);
11651 ok(!dib.dsBm.bmType, "Got unexpected type %#x for format %s.\n",
11652 dib.dsBm.bmType, test_data[i].name);
11653 ok(dib.dsBm.bmWidth == surface_desc.dwWidth, "Got unexpected width %d for format %s.\n",
11654 dib.dsBm.bmWidth, test_data[i].name);
11655 ok(dib.dsBm.bmHeight == surface_desc.dwHeight, "Got unexpected height %d for format %s.\n",
11656 dib.dsBm.bmHeight, test_data[i].name);
11657 width_bytes = ((dib.dsBm.bmWidth * U1(test_data[i].format).dwRGBBitCount + 31) >> 3) & ~3;
11658 ok(dib.dsBm.bmWidthBytes == width_bytes, "Got unexpected width bytes %d for format %s.\n",
11659 dib.dsBm.bmWidthBytes, test_data[i].name);
11660 ok(dib.dsBm.bmPlanes == 1, "Got unexpected plane count %d for format %s.\n",
11661 dib.dsBm.bmPlanes, test_data[i].name);
11662 ok(dib.dsBm.bmBitsPixel == U1(test_data[i].format).dwRGBBitCount,
11663 "Got unexpected bit count %d for format %s.\n",
11664 dib.dsBm.bmBitsPixel, test_data[i].name);
11665 /* Windows XP sets bmBits == NULL for formats that match the screen at least on my r200 GPU. I
11666 * suspect this applies to all HW accelerated pre-WDDM drivers because they can handle gdi access
11667 * to ddraw surfaces themselves instead of going through a sysmem DIB section. */
11668 ok(!!dib.dsBm.bmBits || broken(!pDwmIsCompositionEnabled && dib.dsBm.bmBitsPixel == screen_bpp),
11669 "Got unexpected bits %p for format %s.\n", dib.dsBm.bmBits, test_data[i].name);
11671 ok(dib.dsBmih.biSize == sizeof(dib.dsBmih), "Got unexpected size %lu for format %s.\n",
11672 dib.dsBmih.biSize, test_data[i].name);
11673 ok(dib.dsBmih.biWidth == surface_desc.dwWidth, "Got unexpected width %ld for format %s.\n",
11674 dib.dsBmih.biHeight, test_data[i].name);
11675 ok(dib.dsBmih.biHeight == surface_desc.dwHeight, "Got unexpected height %ld for format %s.\n",
11676 dib.dsBmih.biHeight, test_data[i].name);
11677 ok(dib.dsBmih.biPlanes == 1, "Got unexpected plane count %u for format %s.\n",
11678 dib.dsBmih.biPlanes, test_data[i].name);
11679 ok(dib.dsBmih.biBitCount == U1(test_data[i].format).dwRGBBitCount,
11680 "Got unexpected bit count %u for format %s.\n",
11681 dib.dsBmih.biBitCount, test_data[i].name);
11682 ok(dib.dsBmih.biCompression == (U1(test_data[i].format).dwRGBBitCount == 16 ? BI_BITFIELDS : BI_RGB)
11683 || broken(U1(test_data[i].format).dwRGBBitCount == 32 && dib.dsBmih.biCompression == BI_BITFIELDS),
11684 "Got unexpected compression %#lx for format %s.\n",
11685 dib.dsBmih.biCompression, test_data[i].name);
11686 ok(!dib.dsBmih.biSizeImage, "Got unexpected image size %lu for format %s.\n",
11687 dib.dsBmih.biSizeImage, test_data[i].name);
11688 ok(!dib.dsBmih.biXPelsPerMeter, "Got unexpected horizontal resolution %ld for format %s.\n",
11689 dib.dsBmih.biXPelsPerMeter, test_data[i].name);
11690 ok(!dib.dsBmih.biYPelsPerMeter, "Got unexpected vertical resolution %ld for format %s.\n",
11691 dib.dsBmih.biYPelsPerMeter, test_data[i].name);
11692 ok(!dib.dsBmih.biClrUsed, "Got unexpected used colour count %lu for format %s.\n",
11693 dib.dsBmih.biClrUsed, test_data[i].name);
11694 ok(!dib.dsBmih.biClrImportant, "Got unexpected important colour count %lu for format %s.\n",
11695 dib.dsBmih.biClrImportant, test_data[i].name);
11697 if (dib.dsBmih.biCompression == BI_BITFIELDS)
11699 ok((dib.dsBitfields[0] == U2(test_data[i].format).dwRBitMask
11700 && dib.dsBitfields[1] == U3(test_data[i].format).dwGBitMask
11701 && dib.dsBitfields[2] == U4(test_data[i].format).dwBBitMask)
11702 || broken(!dib.dsBitfields[0] && !dib.dsBitfields[1] && !dib.dsBitfields[2]),
11703 "Got unexpected colour masks 0x%08lx 0x%08lx 0x%08lx for format %s.\n",
11704 dib.dsBitfields[0], dib.dsBitfields[1], dib.dsBitfields[2], test_data[i].name);
11706 else
11708 ok(!dib.dsBitfields[0] && !dib.dsBitfields[1] && !dib.dsBitfields[2],
11709 "Got unexpected colour masks 0x%08lx 0x%08lx 0x%08lx for format %s.\n",
11710 dib.dsBitfields[0], dib.dsBitfields[1], dib.dsBitfields[2], test_data[i].name);
11712 ok(!dib.dshSection, "Got unexpected section %p for format %s.\n", dib.dshSection, test_data[i].name);
11713 ok(!dib.dsOffset, "Got unexpected offset %lu for format %s.\n", dib.dsOffset, test_data[i].name);
11715 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11716 ok(hr == DD_OK, "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11718 else
11720 ok(!dc, "Got unexpected dc %p for format %s.\n", dc, test_data[i].name);
11723 IDirectDrawSurface_Release(surface);
11725 if (FAILED(hr))
11726 continue;
11728 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
11729 if (FAILED(hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
11731 skip("Failed to create mip-mapped texture for format %s (hr %#lx), skipping tests.\n",
11732 test_data[i].name, hr);
11733 continue;
11736 hr = IDirectDrawSurface_GetAttachedSurface(surface, &caps, &tmp);
11737 ok(SUCCEEDED(hr), "Failed to get attached surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11738 hr = IDirectDrawSurface_GetAttachedSurface(tmp, &caps, &surface2);
11739 ok(SUCCEEDED(hr), "Failed to get attached surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11740 IDirectDrawSurface_Release(tmp);
11742 hr = IDirectDrawSurface_GetDC(surface, &dc);
11743 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11744 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11745 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11746 hr = IDirectDrawSurface_GetDC(surface2, &dc);
11747 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11748 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
11749 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11751 hr = IDirectDrawSurface_GetDC(surface, &dc);
11752 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11753 dc2 = (void *)0x1234;
11754 hr = IDirectDrawSurface_GetDC(surface, &dc2);
11755 ok(hr == DDERR_DCALREADYCREATED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11756 ok(dc2 == (void *)0x1234, "Got unexpected dc %p for format %s.\n", dc, test_data[i].name);
11757 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11758 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11759 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11760 ok(hr == DDERR_NODC, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11762 map_desc.dwSize = sizeof(map_desc);
11763 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11764 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11765 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11766 ok(hr == DDERR_SURFACEBUSY, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11767 hr = IDirectDrawSurface_Unlock(surface, NULL);
11768 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11769 hr = IDirectDrawSurface_Unlock(surface, NULL);
11770 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11772 hr = IDirectDrawSurface_GetDC(surface, &dc);
11773 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11774 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11775 ok(hr == DDERR_SURFACEBUSY, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11776 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11777 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11779 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11780 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11781 hr = IDirectDrawSurface_GetDC(surface, &dc);
11782 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11783 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11784 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11785 /* Geforce 9600, Windows 7 returns E_FAIL. The unlock still seems to work as intended, after-
11786 * wards the surface can be locked again. ReleaseDC() does not unlock the surface, trying to
11787 * Lock it after ReleaseDC returns DDERR_SURFACEBUSY. ddraw4 and 7 are unaffected. */
11788 hr = IDirectDrawSurface_Unlock(surface, NULL);
11789 ok(SUCCEEDED(hr) || broken(ddraw_is_nvidia(ddraw) && hr == E_FAIL),
11790 "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11792 hr = IDirectDrawSurface_GetDC(surface, &dc);
11793 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11794 hr = IDirectDrawSurface_GetDC(surface2, &dc2);
11795 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11796 hr = IDirectDrawSurface_ReleaseDC(surface2, dc2);
11797 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11798 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11799 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11801 hr = IDirectDrawSurface_GetDC(surface2, &dc);
11802 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11803 hr = IDirectDrawSurface_GetDC(surface, &dc2);
11804 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11805 hr = IDirectDrawSurface_ReleaseDC(surface, dc2);
11806 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11807 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
11808 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11810 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11811 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11812 hr = IDirectDrawSurface_Lock(surface2, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11813 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11814 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11815 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11816 hr = IDirectDrawSurface_Unlock(surface, NULL);
11817 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11819 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11820 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11821 hr = IDirectDrawSurface_GetDC(surface, &dc);
11822 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11823 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11824 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11825 hr = IDirectDrawSurface_Unlock(surface, NULL);
11826 ok(SUCCEEDED(hr) || broken(ddraw_is_nvidia(ddraw) && hr == E_FAIL),
11827 "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11829 hr = IDirectDrawSurface_Lock(surface2, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11830 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11831 hr = IDirectDrawSurface_GetDC(surface, &dc);
11832 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11833 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11834 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11835 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11836 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11838 hr = IDirectDrawSurface_GetDC(surface, &dc);
11839 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11840 hr = IDirectDrawSurface_Lock(surface2, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11841 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11842 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11843 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11844 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11845 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11847 hr = IDirectDrawSurface_GetDC(surface2, &dc);
11848 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11849 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11850 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11851 hr = IDirectDrawSurface_Unlock(surface, NULL);
11852 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11853 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
11854 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11856 hr = IDirectDrawSurface_Unlock(surface, NULL);
11857 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11858 hr = IDirectDrawSurface_GetDC(surface2, &dc);
11859 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11860 hr = IDirectDrawSurface_Unlock(surface, NULL);
11861 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11862 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
11863 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11864 hr = IDirectDrawSurface_Unlock(surface, NULL);
11865 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11867 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11868 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11869 hr = IDirectDrawSurface_GetDC(surface, &dc);
11870 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11871 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11872 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11873 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11874 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11875 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11876 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11878 IDirectDrawSurface_Release(surface2);
11879 IDirectDrawSurface_Release(surface);
11882 IDirectDraw2_Release(ddraw);
11883 DestroyWindow(window);
11886 static void test_draw_primitive(void)
11888 static WORD indices[] = {0, 1, 2, 3};
11889 static D3DVERTEX quad[] =
11891 {{-1.0f}, {-1.0f}, {0.0f}},
11892 {{-1.0f}, { 1.0f}, {0.0f}},
11893 {{ 1.0f}, {-1.0f}, {0.0f}},
11894 {{ 1.0f}, { 1.0f}, {0.0f}},
11896 IDirect3DViewport2 *viewport;
11897 IDirect3DDevice2 *device;
11898 IDirectDraw2 *ddraw;
11899 IDirect3D2 *d3d;
11900 ULONG refcount;
11901 HWND window;
11902 HRESULT hr;
11904 window = create_window();
11905 ddraw = create_ddraw();
11906 ok(!!ddraw, "Failed to create a ddraw object.\n");
11907 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
11909 skip("Failed to create a 3D device, skipping test.\n");
11910 IDirectDraw2_Release(ddraw);
11911 DestroyWindow(window);
11912 return;
11915 viewport = create_viewport(device, 0, 0, 640, 480);
11916 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
11917 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#lx.\n", hr);
11919 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
11920 ok(SUCCEEDED(hr), "Failed to get D3D interface, hr %#lx.\n", hr);
11922 IDirect3D2_Release(d3d);
11924 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, NULL, 0, NULL, 0, 0);
11925 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
11926 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, NULL, 0, 0);
11927 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
11929 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, NULL, 0, indices, 4, 0);
11930 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
11932 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, quad, 4, NULL, 0, 0);
11933 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
11934 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, quad, 4, 0);
11935 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
11936 hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, quad, 4, indices, 4, 0);
11937 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
11939 destroy_viewport(device, viewport);
11940 refcount = IDirect3DDevice2_Release(device);
11941 ok(!refcount, "Device has %lu references left.\n", refcount);
11942 IDirectDraw2_Release(ddraw);
11943 DestroyWindow(window);
11946 static void test_edge_antialiasing_blending(void)
11948 D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
11949 IDirect3DMaterial2 *green_background;
11950 IDirect3DMaterial2 *red_background;
11951 IDirectDrawSurface *offscreen, *ds;
11952 D3DDEVICEDESC hal_desc, hel_desc;
11953 IDirect3DViewport2 *viewport;
11954 DDSURFACEDESC surface_desc;
11955 IDirect3DDevice2 *device;
11956 IDirectDraw2 *ddraw;
11957 unsigned int color;
11958 ULONG refcount;
11959 HWND window;
11960 HRESULT hr;
11962 static D3DMATRIX mat =
11964 1.0f, 0.0f, 0.0f, 0.0f,
11965 0.0f, 1.0f, 0.0f, 0.0f,
11966 0.0f, 0.0f, 1.0f, 0.0f,
11967 0.0f, 0.0f, 0.0f, 1.0f,
11969 static D3DLVERTEX green_quad[] =
11971 {{-1.0f}, {-1.0f}, {0.1f}, 0, {0x7f00ff00}},
11972 {{-1.0f}, { 1.0f}, {0.1f}, 0, {0x7f00ff00}},
11973 {{ 1.0f}, {-1.0f}, {0.1f}, 0, {0x7f00ff00}},
11974 {{ 1.0f}, { 1.0f}, {0.1f}, 0, {0x7f00ff00}},
11976 static D3DLVERTEX red_quad[] =
11978 {{-1.0f}, {-1.0f}, {0.1f}, 0, {0xccff0000}},
11979 {{-1.0f}, { 1.0f}, {0.1f}, 0, {0xccff0000}},
11980 {{ 1.0f}, {-1.0f}, {0.1f}, 0, {0xccff0000}},
11981 {{ 1.0f}, { 1.0f}, {0.1f}, 0, {0xccff0000}},
11984 window = create_window();
11985 ddraw = create_ddraw();
11986 ok(!!ddraw, "Failed to create a ddraw object.\n");
11987 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
11989 skip("Failed to create a 3D device.\n");
11990 DestroyWindow(window);
11991 return;
11994 memset(&hal_desc, 0, sizeof(hal_desc));
11995 hal_desc.dwSize = sizeof(hal_desc);
11996 memset(&hel_desc, 0, sizeof(hel_desc));
11997 hel_desc.dwSize = sizeof(hel_desc);
11998 hr = IDirect3DDevice2_GetCaps(device, &hal_desc, &hel_desc);
11999 ok(SUCCEEDED(hr), "Failed to get device caps, hr %#lx.\n", hr);
12000 trace("HAL line edge antialiasing support: %#lx.\n",
12001 hal_desc.dpcLineCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES);
12002 trace("HAL triangle edge antialiasing support: %#lx.\n",
12003 hal_desc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES);
12004 trace("HEL line edge antialiasing support: %#lx.\n",
12005 hel_desc.dpcLineCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES);
12006 trace("HEL triangle edge antialiasing support: %#lx.\n",
12007 hel_desc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES);
12009 memset(&surface_desc, 0, sizeof(surface_desc));
12010 surface_desc.dwSize = sizeof(surface_desc);
12011 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
12012 surface_desc.dwWidth = 640;
12013 surface_desc.dwHeight = 480;
12014 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
12015 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
12016 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
12017 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
12018 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
12019 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
12020 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
12021 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
12022 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &offscreen, NULL);
12023 ok(hr == D3D_OK, "Creating the offscreen render target failed, hr %#lx.\n", hr);
12025 ds = get_depth_stencil(device);
12026 hr = IDirectDrawSurface_AddAttachedSurface(offscreen, ds);
12027 todo_wine ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#lx.\n", hr);
12028 IDirectDrawSurface_Release(ds);
12030 hr = IDirect3DDevice2_SetRenderTarget(device, offscreen, 0);
12031 ok(SUCCEEDED(hr), "Failed to set render target, hr %#lx.\n", hr);
12033 red_background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 0.8f);
12034 green_background = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 0.5f);
12036 viewport = create_viewport(device, 0, 0, 640, 480);
12037 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
12038 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#lx.\n", hr);
12040 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat);
12041 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
12042 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat);
12043 ok(SUCCEEDED(hr), "Failed to set view transform, hr %#lx.\n", hr);
12044 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat);
12045 ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#lx.\n", hr);
12046 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, FALSE);
12047 ok(SUCCEEDED(hr), "Failed to disable Z test, hr %#lx.\n", hr);
12048 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_FOGENABLE, FALSE);
12049 ok(SUCCEEDED(hr), "Failed to disable fog, hr %#lx.\n", hr);
12050 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
12051 ok(SUCCEEDED(hr), "Failed to disable culling, hr %#lx.\n", hr);
12053 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
12054 ok(SUCCEEDED(hr), "Failed to enable blending, hr %#lx.\n", hr);
12055 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
12056 ok(SUCCEEDED(hr), "Failed to set src blend, hr %#lx.\n", hr);
12057 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_DESTALPHA);
12058 ok(SUCCEEDED(hr), "Failed to set dest blend, hr %#lx.\n", hr);
12060 viewport_set_background(device, viewport, red_background);
12061 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
12062 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
12063 hr = IDirect3DDevice2_BeginScene(device);
12064 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12065 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, green_quad, 4, 0);
12066 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
12067 hr = IDirect3DDevice2_EndScene(device);
12068 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12069 color = get_surface_color(offscreen, 320, 240);
12070 ok(compare_color(color, 0x00cc7f00, 1), "Got unexpected color 0x%08x.\n", color);
12072 viewport_set_background(device, viewport, green_background);
12073 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
12074 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
12075 hr = IDirect3DDevice2_BeginScene(device);
12076 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12077 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, red_quad, 4, 0);
12078 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
12079 hr = IDirect3DDevice2_EndScene(device);
12080 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12081 color = get_surface_color(offscreen, 320, 240);
12082 ok(compare_color(color, 0x00cc7f00, 1), "Got unexpected color 0x%08x.\n", color);
12084 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
12085 ok(SUCCEEDED(hr), "Failed to disable blending, hr %#lx.\n", hr);
12087 viewport_set_background(device, viewport, red_background);
12088 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
12089 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
12090 hr = IDirect3DDevice2_BeginScene(device);
12091 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12092 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, green_quad, 4, 0);
12093 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
12094 hr = IDirect3DDevice2_EndScene(device);
12095 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12096 color = get_surface_color(offscreen, 320, 240);
12097 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
12099 viewport_set_background(device, viewport, green_background);
12100 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
12101 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
12102 hr = IDirect3DDevice2_BeginScene(device);
12103 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12104 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, red_quad, 4, 0);
12105 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
12106 hr = IDirect3DDevice2_EndScene(device);
12107 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12108 color = get_surface_color(offscreen, 320, 240);
12109 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
12111 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_EDGEANTIALIAS, TRUE);
12112 ok(SUCCEEDED(hr), "Failed to enable edge antialiasing, hr %#lx.\n", hr);
12114 viewport_set_background(device, viewport, red_background);
12115 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
12116 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
12117 hr = IDirect3DDevice2_BeginScene(device);
12118 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12119 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, green_quad, 4, 0);
12120 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
12121 hr = IDirect3DDevice2_EndScene(device);
12122 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12123 color = get_surface_color(offscreen, 320, 240);
12124 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
12126 viewport_set_background(device, viewport, green_background);
12127 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
12128 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
12129 hr = IDirect3DDevice2_BeginScene(device);
12130 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12131 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, red_quad, 4, 0);
12132 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
12133 hr = IDirect3DDevice2_EndScene(device);
12134 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12135 color = get_surface_color(offscreen, 320, 240);
12136 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
12138 IDirectDrawSurface_Release(offscreen);
12139 destroy_viewport(device, viewport);
12140 destroy_material(red_background);
12141 destroy_material(green_background);
12142 refcount = IDirect3DDevice2_Release(device);
12143 ok(!refcount, "Device has %lu references left.\n", refcount);
12144 IDirectDraw2_Release(ddraw);
12145 DestroyWindow(window);
12148 /* TransformVertices always writes 32 bytes regardless of the input / output stride.
12149 * The stride is honored for navigating to the next vertex. 3 floats input position
12150 * are read, and 16 bytes extra vertex data are copied around. */
12151 struct transform_input
12153 float x, y, z, unused1; /* Position data, transformed. */
12154 DWORD v1, v2, v3, v4; /* Extra data, e.g. color and texture coords, copied. */
12155 DWORD unused2;
12158 struct transform_output
12160 float x, y, z, w;
12161 unsigned int v1, v2, v3, v4;
12162 unsigned int unused3, unused4;
12165 static void test_transform_vertices(void)
12167 IDirect3DDevice2 *device;
12168 IDirectDrawSurface *rt;
12169 unsigned int color, i;
12170 IDirectDraw2 *ddraw;
12171 ULONG refcount;
12172 HWND window;
12173 HRESULT hr;
12174 IDirect3DViewport2 *viewport;
12175 IDirect3DMaterial2 *background;
12176 D3DMATERIAL mat;
12177 static struct transform_input position_tests[] =
12179 { 0.0f, 0.0f, 0.0f, 0.0f, 1, 2, 3, 4, 5},
12180 { 1.0f, 1.0f, 1.0f, 8.0f, 6, 7, 8, 9, 10},
12181 {-1.0f, -1.0f, -1.0f, 4.0f, 11, 12, 13, 14, 15},
12182 { 0.5f, 0.5f, 0.5f, 2.0f, 16, 17, 18, 19, 20},
12183 {-0.5f, -0.5f, -0.5f, 1.0f, ~1U, ~2U, ~3U, ~4U, ~5U},
12184 {-0.5f, -0.5f, 0.0f, 0.0f, ~6U, ~7U, ~8U, ~9U, ~0U},
12186 static struct transform_input cliptest[] =
12188 { 25.59f, 25.59f, 1.0f, 0.0f, 1, 2, 3, 4, 5},
12189 { 25.61f, 25.61f, 1.01f, 0.0f, 1, 2, 3, 4, 5},
12190 {-25.59f, -25.59f, 0.0f, 0.0f, 1, 2, 3, 4, 5},
12191 {-25.61f, -25.61f, -0.01f, 0.0f, 1, 2, 3, 4, 5},
12193 static struct transform_input offscreentest[] =
12195 {128.1f, 0.0f, 0.0f, 0.0f, 1, 2, 3, 4, 5},
12197 struct transform_output out[ARRAY_SIZE(position_tests)];
12198 D3DHVERTEX out_h[ARRAY_SIZE(position_tests)];
12199 D3DTRANSFORMDATA transformdata;
12200 static const D3DVIEWPORT vp_template =
12202 sizeof(vp_template), 0, 0, 256, 256, 5.0f, 5.0f, 256.0f, 256.0f, -25.0f, 60.0f
12204 D3DVIEWPORT vp_data =
12206 sizeof(vp_data), 0, 0, 256, 256, 1.0f, 1.0f, 256.0f, 256.0f, 0.0f, 1.0f
12208 D3DVIEWPORT2 vp2_data;
12209 DWORD offscreen;
12210 static D3DMATRIX mat_scale =
12212 2.0f, 0.0f, 0.0f, 0.0f,
12213 0.0f, 2.0f, 0.0f, 0.0f,
12214 0.0f, 0.0f, 2.0f, 0.0f,
12215 0.0f, 0.0f, 0.0f, 1.0f,
12217 mat_translate1 =
12219 1.0f, 0.0f, 0.0f, 0.0f,
12220 0.0f, 1.0f, 0.0f, 0.0f,
12221 0.0f, 0.0f, 1.0f, 0.0f,
12222 1.0f, 0.0f, 0.0f, 1.0f,
12224 mat_translate2 =
12226 1.0f, 0.0f, 0.0f, 0.0f,
12227 0.0f, 1.0f, 0.0f, 0.0f,
12228 0.0f, 0.0f, 1.0f, 0.0f,
12229 0.0f, 1.0f, 0.0f, 1.0f,
12231 mat_transform3 =
12233 1.0f, 0.0f, 0.0f, 0.0f,
12234 0.0f, 1.0f, 0.0f, 0.0f,
12235 0.0f, 0.0f, 1.0f, 0.0f,
12236 0.0f, 19.2f, 0.0f, 2.0f,
12238 mat_identity =
12240 1.0f, 0.0f, 0.0f, 0.0f,
12241 0.0f, 1.0f, 0.0f, 0.0f,
12242 0.0f, 0.0f, 1.0f, 0.0f,
12243 0.0f, 0.0f, 0.0f, 1.0f,
12245 static D3DLVERTEX quad[] =
12247 {{-0.75f},{-0.5f }, {0.0f}, 0, {0xffff0000}},
12248 {{-0.75f},{ 0.25f}, {0.0f}, 0, {0xffff0000}},
12249 {{ 0.5f}, {-0.5f }, {0.0f}, 0, {0xffff0000}},
12250 {{ 0.5f}, { 0.25f}, {0.0f}, 0, {0xffff0000}},
12252 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
12255 for (i = 0; i < ARRAY_SIZE(out); ++i)
12257 out[i].unused3 = 0xdeadbeef;
12258 out[i].unused4 = 0xcafecafe;
12261 window = create_window();
12262 ddraw = create_ddraw();
12263 ok(!!ddraw, "Failed to create a ddraw object.\n");
12264 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
12266 skip("Failed to create a 3D device, skipping test.\n");
12267 IDirectDraw2_Release(ddraw);
12268 DestroyWindow(window);
12269 return;
12271 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
12272 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
12274 viewport = create_viewport(device, 0, 0, 256, 256);
12275 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
12276 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
12278 memset(&transformdata, 0, sizeof(transformdata));
12279 transformdata.dwSize = sizeof(transformdata);
12280 transformdata.lpIn = position_tests;
12281 transformdata.dwInSize = sizeof(position_tests[0]);
12282 transformdata.lpOut = out;
12283 transformdata.dwOutSize = sizeof(out[0]);
12284 transformdata.lpHOut = NULL;
12286 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
12287 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
12288 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12289 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12291 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
12293 static const struct vec4 cmp[] =
12295 {128.0f, 128.0f, 0.0f, 1.0f}, {129.0f, 127.0f, 1.0f, 1.0f}, {127.0f, 129.0f, -1.0f, 1.0f},
12296 {128.5f, 127.5f, 0.5f, 1.0f}, {127.5f, 128.5f, -0.5f, 1.0f}, {127.5f, 128.5f, 0.0f, 1.0f}
12299 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
12300 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
12301 out[i].x, out[i].y, out[i].z, out[i].w);
12302 ok(out[i].v1 == position_tests[i].v1 && out[i].v2 == position_tests[i].v2
12303 && out[i].v3 == position_tests[i].v3 && out[i].v4 == position_tests[i].v4,
12304 "Vertex %u payload is %u %u %u %u.\n", i, out[i].v1, out[i].v2, out[i].v3, out[i].v4);
12305 ok(out[i].unused3 == 0xdeadbeef && out[i].unused4 == 0xcafecafe,
12306 "Vertex %u unused data is %#x, %#x.\n", i, out[i].unused3, out[i].unused4);
12309 vp_data = vp_template;
12310 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
12311 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
12312 offscreen = 0xdeadbeef;
12313 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
12314 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
12315 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12316 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12318 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
12320 static const struct vec4 cmp[] =
12322 {128.0f, 128.0f, 0.0f, 1.0f}, {133.0f, 123.0f, 1.0f, 1.0f}, {123.0f, 133.0f, -1.0f, 1.0f},
12323 {130.5f, 125.5f, 0.5f, 1.0f}, {125.5f, 130.5f, -0.5f, 1.0f}, {125.5f, 130.5f, 0.0f, 1.0f}
12325 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
12326 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
12327 out[i].x, out[i].y, out[i].z, out[i].w);
12330 vp_data.dwX = 10;
12331 vp_data.dwY = 20;
12332 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
12333 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
12334 offscreen = 0xdeadbeef;
12335 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
12336 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
12337 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12338 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12339 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
12341 static const struct vec4 cmp[] =
12343 {138.0f, 148.0f, 0.0f, 1.0f}, {143.0f, 143.0f, 1.0f, 1.0f}, {133.0f, 153.0f, -1.0f, 1.0f},
12344 {140.5f, 145.5f, 0.5f, 1.0f}, {135.5f, 150.5f, -0.5f, 1.0f}, {135.5f, 150.5f, 0.0f, 1.0f}
12346 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
12347 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
12348 out[i].x, out[i].y, out[i].z, out[i].w);
12351 transformdata.lpHOut = out_h;
12352 offscreen = 0xdeadbeef;
12353 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
12354 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12355 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12356 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12357 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
12359 static const D3DHVERTEX cmp_h[] =
12361 {0, { 0.0f}, { 0.0f}, { 0.0f}}, {0, { 1.0f}, { 1.0f}, {1.0f}},
12362 {D3DCLIP_FRONT, {-1.0f}, {-1.0f}, {-1.0f}}, {0, { 0.5f}, { 0.5f}, {0.5f}},
12363 {D3DCLIP_FRONT, {-0.5f}, {-0.5f}, {-0.5f}}, {0, {-0.5f}, {-0.5f}, {0.0f}}
12365 ok(compare_float(U1(cmp_h[i]).hx, U1(out_h[i]).hx, 4096)
12366 && compare_float(U2(cmp_h[i]).hy, U2(out_h[i]).hy, 4096)
12367 && compare_float(U3(cmp_h[i]).hz, U3(out_h[i]).hz, 4096)
12368 && cmp_h[i].dwFlags == out_h[i].dwFlags,
12369 "HVertex %u differs. Got %#lx %.8e %.8e %.8e.\n", i,
12370 out_h[i].dwFlags, U1(out_h[i]).hx, U2(out_h[i]).hy, U3(out_h[i]).hz);
12372 /* No scheme has been found behind those return values. It seems to be
12373 * whatever data windows has when throwing the vertex away. Modify the
12374 * input test vertices to test this more. Depending on the input data
12375 * it can happen that the z coord gets written into y, or similar things. */
12376 if (0)
12378 static const struct vec4 cmp[] =
12380 {138.0f, 148.0f, 0.0f, 1.0f}, {143.0f, 143.0f, 1.0f, 1.0f}, { -1.0f, -1.0f, 0.5f, 1.0f},
12381 {140.5f, 145.5f, 0.5f, 1.0f}, { -0.5f, -0.5f, -0.5f, 1.0f}, {135.5f, 150.5f, 0.0f, 1.0f}
12383 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
12384 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
12385 out[i].x, out[i].y, out[i].z, out[i].w);
12389 transformdata.lpIn = cliptest;
12390 transformdata.dwInSize = sizeof(cliptest[0]);
12391 offscreen = 0xdeadbeef;
12392 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(cliptest),
12393 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12394 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12395 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12396 for (i = 0; i < ARRAY_SIZE(cliptest); ++i)
12398 static const DWORD flags[] =
12401 D3DCLIP_RIGHT | D3DCLIP_BACK | D3DCLIP_TOP,
12403 D3DCLIP_LEFT | D3DCLIP_BOTTOM | D3DCLIP_FRONT,
12405 ok(flags[i] == out_h[i].dwFlags, "Cliptest %u returned %#lx.\n", i, out_h[i].dwFlags);
12408 vp_data = vp_template;
12409 vp_data.dwWidth = 10;
12410 vp_data.dwHeight = 480;
12411 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
12412 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
12413 offscreen = 0xdeadbeef;
12414 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(cliptest),
12415 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12416 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12417 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12418 for (i = 0; i < ARRAY_SIZE(cliptest); ++i)
12420 static const DWORD flags[] =
12422 D3DCLIP_RIGHT,
12423 D3DCLIP_RIGHT | D3DCLIP_BACK,
12424 D3DCLIP_LEFT,
12425 D3DCLIP_LEFT | D3DCLIP_FRONT,
12427 ok(flags[i] == out_h[i].dwFlags, "Cliptest %u returned %#lx.\n", i, out_h[i].dwFlags);
12430 vp_data = vp_template;
12431 vp_data.dwWidth = 256;
12432 vp_data.dwHeight = 256;
12433 vp_data.dvScaleX = 1;
12434 vp_data.dvScaleY = 1;
12435 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
12436 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
12437 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(cliptest),
12438 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12439 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12440 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12441 for (i = 0; i < ARRAY_SIZE(cliptest); ++i)
12443 static const DWORD flags[] =
12446 D3DCLIP_BACK,
12448 D3DCLIP_FRONT,
12450 ok(flags[i] == out_h[i].dwFlags, "Cliptest %u returned %#lx.\n", i, out_h[i].dwFlags);
12453 /* Finally try to figure out how the DWORD dwOffscreen works.
12454 * It is a logical AND of the vertices' dwFlags members. */
12455 vp_data = vp_template;
12456 vp_data.dwWidth = 5;
12457 vp_data.dwHeight = 5;
12458 vp_data.dvScaleX = 10000.0f;
12459 vp_data.dvScaleY = 10000.0f;
12460 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
12461 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
12462 transformdata.lpIn = cliptest;
12463 offscreen = 0xdeadbeef;
12464 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12465 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
12466 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12467 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12469 offscreen = 0xdeadbeef;
12470 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12471 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12472 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12473 ok(offscreen == (D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %#lx.\n", offscreen);
12474 offscreen = 0xdeadbeef;
12475 hr = IDirect3DViewport2_TransformVertices(viewport, 2,
12476 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12477 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12478 ok(offscreen == (D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %#lx.\n", offscreen);
12479 hr = IDirect3DViewport2_TransformVertices(viewport, 3,
12480 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12481 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12482 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12484 transformdata.lpIn = cliptest + 1;
12485 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12486 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12487 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12488 ok(offscreen == (D3DCLIP_BACK | D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %#lx.\n", offscreen);
12490 transformdata.lpIn = cliptest + 2;
12491 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12492 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12493 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12494 ok(offscreen == (D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %#lx.\n", offscreen);
12495 offscreen = 0xdeadbeef;
12496 hr = IDirect3DViewport2_TransformVertices(viewport, 2,
12497 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12498 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12499 ok(offscreen == (D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %#lx.\n", offscreen);
12501 transformdata.lpIn = cliptest + 3;
12502 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12503 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12504 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12505 ok(offscreen == (D3DCLIP_FRONT | D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %#lx.\n", offscreen);
12507 transformdata.lpIn = offscreentest;
12508 transformdata.dwInSize = sizeof(offscreentest[0]);
12509 vp_data = vp_template;
12510 vp_data.dwWidth = 257;
12511 vp_data.dwHeight = 257;
12512 vp_data.dvScaleX = 1.0f;
12513 vp_data.dvScaleY = 1.0f;
12514 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
12515 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
12516 offscreen = 0xdeadbeef;
12517 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12518 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12519 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12520 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12522 vp_data.dwWidth = 256;
12523 vp_data.dwHeight = 256;
12524 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
12525 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
12526 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12527 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12528 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12529 ok(offscreen == D3DCLIP_RIGHT, "Offscreen is %#lx.\n", offscreen);
12531 /* Test the effect of Matrices.
12533 * Basically the x coordinate ends up as ((x + 1) * 2 + 0) * 5 and
12534 * y as ((y + 0) * 2 + 1) * 5. The 5 comes from dvScaleX/Y, 2 from
12535 * the view matrix and the +1's from the world and projection matrix. */
12536 vp_data.dwX = 0;
12537 vp_data.dwY = 0;
12538 vp_data.dwWidth = 256;
12539 vp_data.dwHeight = 256;
12540 vp_data.dvScaleX = 5.0f;
12541 vp_data.dvScaleY = 5.0f;
12542 vp_data.dvMinZ = 0.0f;
12543 vp_data.dvMaxZ = 1.0f;
12544 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
12545 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
12547 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat_translate1);
12548 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
12549 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat_scale);
12550 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
12551 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat_translate2);
12552 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
12554 transformdata.lpIn = position_tests;
12555 transformdata.dwInSize = sizeof(position_tests[0]);
12556 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
12557 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
12558 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12560 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
12562 static const struct vec4 cmp[] =
12564 {138.0f, 123.0f, 0.0f, 1.0f}, {148.0f, 113.0f, 2.0f, 1.0f}, {128.0f, 133.0f, -2.0f, 1.0f},
12565 {143.0f, 118.0f, 1.0f, 1.0f}, {133.0f, 128.0f, -1.0f, 1.0f}, {133.0f, 128.0f, 0.0f, 1.0f}
12568 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
12569 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
12570 out[i].x, out[i].y, out[i].z, out[i].w);
12573 /* Invalid flags. */
12574 offscreen = 0xdeadbeef;
12575 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
12576 &transformdata, 0, &offscreen);
12577 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
12578 ok(offscreen == 0xdeadbeef, "Offscreen is %#lx.\n", offscreen);
12580 /* NULL transform data. */
12581 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12582 NULL, D3DTRANSFORM_UNCLIPPED, &offscreen);
12583 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
12584 ok(offscreen == 0xdeadbeef, "Offscreen is %#lx.\n", offscreen);
12585 hr = IDirect3DViewport2_TransformVertices(viewport, 0,
12586 NULL, D3DTRANSFORM_UNCLIPPED, &offscreen);
12587 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
12588 ok(offscreen == 0xdeadbeef, "Offscreen is %#lx.\n", offscreen);
12590 /* NULL transform data and NULL dwOffscreen.
12592 * Valid transform data + NULL dwOffscreen -> crash. */
12593 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12594 NULL, D3DTRANSFORM_UNCLIPPED, NULL);
12595 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
12597 /* No vertices. */
12598 hr = IDirect3DViewport2_TransformVertices(viewport, 0,
12599 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
12600 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12601 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12602 hr = IDirect3DViewport2_TransformVertices(viewport, 0,
12603 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12604 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12605 ok(offscreen == ~0u, "Offscreen is %#lx.\n", offscreen);
12607 /* Invalid sizes. */
12608 offscreen = 0xdeadbeef;
12609 transformdata.dwSize = sizeof(transformdata) - 1;
12610 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12611 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
12612 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
12613 ok(offscreen == 0xdeadbeef, "Offscreen is %#lx.\n", offscreen);
12614 transformdata.dwSize = sizeof(transformdata) + 1;
12615 hr = IDirect3DViewport2_TransformVertices(viewport, 1,
12616 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
12617 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
12618 ok(offscreen == 0xdeadbeef, "Offscreen is %#lx.\n", offscreen);
12620 /* NULL lpIn or lpOut -> crash, except when transforming 0 vertices. */
12621 transformdata.dwSize = sizeof(transformdata);
12622 transformdata.lpIn = NULL;
12623 transformdata.lpOut = NULL;
12624 offscreen = 0xdeadbeef;
12625 hr = IDirect3DViewport2_TransformVertices(viewport, 0,
12626 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12627 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12628 ok(offscreen == ~0u, "Offscreen is %#lx.\n", offscreen);
12630 /* Test how vertices are transformed during draws. */
12631 vp_data.dwX = 20;
12632 vp_data.dwY = 20;
12633 vp_data.dwWidth = 200;
12634 vp_data.dwHeight = 400;
12635 vp_data.dvScaleX = 20.0f;
12636 vp_data.dvScaleY = 50.0f;
12637 vp_data.dvMinZ = 0.0f;
12638 vp_data.dvMaxZ = 1.0f;
12639 hr = IDirect3DViewport2_SetViewport(viewport, &vp_data);
12640 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
12641 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
12642 ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#lx.\n", hr);
12644 ok(SUCCEEDED(hr), "Failed to clear the render target, hr %#lx.\n", hr);
12645 background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 0.0f);
12646 viewport_set_background(device, viewport, background);
12647 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
12648 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
12650 hr = IDirect3DDevice2_BeginScene(device);
12651 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12652 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad, 4, 0);
12653 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
12654 hr = IDirect3DDevice2_EndScene(device);
12655 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12657 color = get_surface_color(rt, 128, 143);
12658 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
12659 color = get_surface_color(rt, 132, 143);
12660 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
12661 color = get_surface_color(rt, 128, 147);
12662 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
12663 color = get_surface_color(rt, 132, 147);
12664 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
12666 color = get_surface_color(rt, 177, 217);
12667 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
12668 color = get_surface_color(rt, 181, 217);
12669 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
12670 color = get_surface_color(rt, 177, 221);
12671 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
12672 color = get_surface_color(rt, 181, 221);
12673 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
12675 /* Test D3DVIEWPORT2 behavior. */
12676 vp2_data.dwSize = sizeof(vp2_data);
12677 vp2_data.dwX = 20;
12678 vp2_data.dwY = 20;
12679 vp2_data.dwWidth = 200;
12680 vp2_data.dwHeight = 400;
12681 vp2_data.dvClipX = -0.5f;
12682 vp2_data.dvClipY = 4.0f;
12683 vp2_data.dvClipWidth = 5.0f;
12684 vp2_data.dvClipHeight = 10.0f;
12685 vp2_data.dvMinZ = 0.0f;
12686 vp2_data.dvMaxZ = 2.0f;
12687 hr = IDirect3DViewport2_SetViewport2(viewport, &vp2_data);
12688 ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#lx.\n", hr);
12689 transformdata.lpIn = position_tests;
12690 transformdata.lpOut = out;
12691 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(position_tests),
12692 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
12693 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12694 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
12696 static const struct vec4 cmp[] =
12698 {120.0f, 140.0f, 0.0f, 1.0f}, {200.0f, 60.0f, 1.0f, 1.0f}, {40.0f, 220.0f, -1.0f, 1.0f},
12699 {160.0f, 100.0f, 0.5f, 1.0f}, { 80.0f, 180.0f, -0.5f, 1.0f}, {80.0f, 180.0f, 0.0f, 1.0f}
12702 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
12703 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
12704 out[i].x, out[i].y, out[i].z, out[i].w);
12707 memset(&mat, 0, sizeof(mat));
12708 mat.dwSize = sizeof(mat);
12709 U1(U(mat).diffuse).r = 0.0f;
12710 U2(U(mat).diffuse).g = 1.0f;
12711 U3(U(mat).diffuse).b = 0.0f;
12712 U4(U(mat).diffuse).a = 0.0f;
12713 hr = IDirect3DMaterial2_SetMaterial(background, &mat);
12714 ok(SUCCEEDED(hr), "Failed to set material data, hr %#lx.\n", hr);
12715 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
12716 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
12718 hr = IDirect3DDevice2_BeginScene(device);
12719 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12720 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad, 4, 0);
12721 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
12722 hr = IDirect3DDevice2_EndScene(device);
12723 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12725 color = get_surface_color(rt, 58, 118);
12726 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
12727 color = get_surface_color(rt, 62, 118);
12728 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
12729 color = get_surface_color(rt, 58, 122);
12730 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
12731 color = get_surface_color(rt, 62, 122);
12732 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
12734 color = get_surface_color(rt, 157, 177);
12735 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
12736 color = get_surface_color(rt, 161, 177);
12737 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
12738 color = get_surface_color(rt, 157, 181);
12739 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
12740 color = get_surface_color(rt, 161, 181);
12741 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
12743 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat_identity);
12744 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
12745 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat_identity);
12746 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
12747 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat_transform3);
12748 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
12750 vp2_data.dwX = 0.0;
12751 vp2_data.dwY = 0.0;
12752 vp2_data.dwWidth = 1;
12753 vp2_data.dwHeight = 1;
12754 vp2_data.dvClipX = -12.8f;
12755 vp2_data.dvClipY = 12.8f + mat_transform3._42 / mat_transform3._44;
12756 vp2_data.dvClipWidth = 25.6f;
12757 vp2_data.dvClipHeight = 25.6f;
12758 vp2_data.dvMinZ = 0.0f;
12759 vp2_data.dvMaxZ = 0.5f;
12760 hr = IDirect3DViewport2_SetViewport2(viewport, &vp2_data);
12761 ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#lx.\n", hr);
12762 transformdata.lpIn = cliptest;
12763 transformdata.dwInSize = sizeof(cliptest[0]);
12764 offscreen = 0xdeadbeef;
12765 hr = IDirect3DViewport2_TransformVertices(viewport, ARRAY_SIZE(cliptest),
12766 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
12767 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
12768 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
12769 for (i = 0; i < ARRAY_SIZE(cliptest); ++i)
12771 static const D3DHVERTEX cmp_h[] =
12773 {0, { 25.59f}, { 44.79f}, { 1.0f }},
12774 {D3DCLIP_RIGHT | D3DCLIP_TOP | D3DCLIP_BACK, { 25.61f}, { 44.81f}, { 1.01f}},
12775 {0, {-25.59f}, {-6.39f }, { 0.0f }},
12776 {D3DCLIP_LEFT | D3DCLIP_BOTTOM | D3DCLIP_FRONT,{-25.61f}, {-6.41f }, {-0.01f}},
12778 ok(compare_float(U1(cmp_h[i]).hx, U1(out_h[i]).hx, 4096)
12779 && compare_float(U2(cmp_h[i]).hy, U2(out_h[i]).hy, 4096)
12780 && compare_float(U3(cmp_h[i]).hz, U3(out_h[i]).hz, 4096)
12781 && cmp_h[i].dwFlags == out_h[i].dwFlags,
12782 "HVertex %u differs. Got %#lx %.8e %.8e %.8e.\n", i,
12783 out_h[i].dwFlags, U1(out_h[i]).hx, U2(out_h[i]).hy, U3(out_h[i]).hz);
12786 IDirectDrawSurface_Release(rt);
12787 destroy_viewport(device, viewport);
12788 IDirect3DMaterial2_Release(background);
12789 refcount = IDirect3DDevice_Release(device);
12790 ok(!refcount, "Device has %lu references left.\n", refcount);
12791 IDirectDraw2_Release(ddraw);
12792 DestroyWindow(window);
12795 static void test_display_mode_surface_pixel_format(void)
12797 unsigned int width, height, bpp;
12798 IDirectDrawSurface *surface;
12799 DDSURFACEDESC surface_desc;
12800 IDirectDraw2 *ddraw;
12801 ULONG refcount;
12802 HWND window;
12803 HRESULT hr;
12805 if (!(ddraw = create_ddraw()))
12807 skip("Failed to create ddraw.\n");
12808 return;
12811 surface_desc.dwSize = sizeof(surface_desc);
12812 hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
12813 ok(SUCCEEDED(hr), "Failed to get display mode, hr %#lx.\n", hr);
12814 width = surface_desc.dwWidth;
12815 height = surface_desc.dwHeight;
12817 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
12818 0, 0, width, height, NULL, NULL, NULL, NULL);
12819 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
12820 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
12822 bpp = 0;
12823 if (SUCCEEDED(IDirectDraw2_SetDisplayMode(ddraw, width, height, 16, 0, 0)))
12824 bpp = 16;
12825 if (SUCCEEDED(IDirectDraw2_SetDisplayMode(ddraw, width, height, 24, 0, 0)))
12826 bpp = 24;
12827 if (SUCCEEDED(IDirectDraw2_SetDisplayMode(ddraw, width, height, 32, 0, 0)))
12828 bpp = 32;
12829 ok(bpp, "Set display mode failed.\n");
12831 surface_desc.dwSize = sizeof(surface_desc);
12832 hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
12833 ok(SUCCEEDED(hr), "Failed to get display mode, hr %#lx.\n", hr);
12834 ok(surface_desc.dwWidth == width, "Got width %lu, expected %u.\n", surface_desc.dwWidth, width);
12835 ok(surface_desc.dwHeight == height, "Got height %lu, expected %u.\n", surface_desc.dwHeight, height);
12836 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == bpp, "Got bpp %lu, expected %u.\n",
12837 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, bpp);
12839 memset(&surface_desc, 0, sizeof(surface_desc));
12840 surface_desc.dwSize = sizeof(surface_desc);
12841 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
12842 surface_desc.dwBackBufferCount = 1;
12843 surface_desc.ddsCaps.dwCaps = DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE;
12844 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
12845 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
12846 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
12847 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
12848 ok(surface_desc.dwWidth == width, "Got width %lu, expected %u.\n", surface_desc.dwWidth, width);
12849 ok(surface_desc.dwHeight == height, "Got height %lu, expected %u.\n", surface_desc.dwHeight, height);
12850 ok(surface_desc.ddpfPixelFormat.dwFlags == DDPF_RGB, "Got unexpected pixel format flags %#lx.\n",
12851 surface_desc.ddpfPixelFormat.dwFlags);
12852 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == bpp, "Got bpp %lu, expected %u.\n",
12853 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, bpp);
12854 IDirectDrawSurface_Release(surface);
12856 memset(&surface_desc, 0, sizeof(surface_desc));
12857 surface_desc.dwSize = sizeof(surface_desc);
12858 surface_desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
12859 surface_desc.dwWidth = width;
12860 surface_desc.dwHeight = height;
12861 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
12862 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
12863 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
12864 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
12865 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
12866 ok(surface_desc.ddpfPixelFormat.dwFlags == DDPF_RGB, "Got unexpected pixel format flags %#lx.\n",
12867 surface_desc.ddpfPixelFormat.dwFlags);
12868 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == bpp, "Got bpp %lu, expected %u.\n",
12869 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, bpp);
12870 IDirectDrawSurface_Release(surface);
12872 refcount = IDirectDraw2_Release(ddraw);
12873 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
12874 DestroyWindow(window);
12877 static void test_surface_desc_size(void)
12879 union
12881 DWORD dwSize;
12882 DDSURFACEDESC desc1;
12883 DDSURFACEDESC2 desc2;
12884 BYTE blob[1024];
12885 } desc;
12886 IDirectDrawSurface7 *surface7;
12887 IDirectDrawSurface2 *surface2;
12888 IDirectDrawSurface *surface;
12889 DDSURFACEDESC surface_desc;
12890 HRESULT expected_hr, hr;
12891 IDirectDraw2 *ddraw;
12892 unsigned int i, j;
12893 ULONG refcount;
12895 static const struct
12897 unsigned int caps;
12898 const char *name;
12900 surface_caps[] =
12902 {DDSCAPS_OFFSCREENPLAIN, "offscreenplain"},
12903 {DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY, "systemmemory texture"},
12904 {DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, "videomemory texture"},
12906 static const unsigned int desc_sizes[] =
12908 sizeof(DDSURFACEDESC),
12909 sizeof(DDSURFACEDESC2),
12910 sizeof(DDSURFACEDESC) + 1,
12911 sizeof(DDSURFACEDESC2) + 1,
12912 2 * sizeof(DDSURFACEDESC),
12913 2 * sizeof(DDSURFACEDESC2),
12914 sizeof(DDSURFACEDESC) - 1,
12915 sizeof(DDSURFACEDESC2) - 1,
12916 sizeof(DDSURFACEDESC) / 2,
12917 sizeof(DDSURFACEDESC2) / 2,
12921 sizeof(desc) / 2,
12922 sizeof(desc) - 100,
12925 if (!(ddraw = create_ddraw()))
12927 skip("Failed to create ddraw.\n");
12928 return;
12930 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
12931 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
12933 for (i = 0; i < ARRAY_SIZE(surface_caps); ++i)
12935 memset(&surface_desc, 0, sizeof(surface_desc));
12936 surface_desc.dwSize = sizeof(surface_desc);
12937 surface_desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
12938 surface_desc.ddsCaps.dwCaps = surface_caps[i].caps;
12939 surface_desc.dwHeight = 128;
12940 surface_desc.dwWidth = 128;
12941 if (FAILED(IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
12943 skip("Failed to create surface, type %s.\n", surface_caps[i].name);
12944 continue;
12946 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface2, (void **)&surface2);
12947 ok(hr == DD_OK, "Failed to query IDirectDrawSurface2, hr %#lx, type %s.\n", hr, surface_caps[i].name);
12948 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface7, (void **)&surface7);
12949 ok(hr == DD_OK, "Failed to query IDirectDrawSurface7, hr %#lx, type %s.\n", hr, surface_caps[i].name);
12951 /* GetSurfaceDesc() */
12952 for (j = 0; j < ARRAY_SIZE(desc_sizes); ++j)
12954 memset(&desc, 0, sizeof(desc));
12955 desc.dwSize = desc_sizes[j];
12956 expected_hr = desc.dwSize == sizeof(DDSURFACEDESC) ? DD_OK : DDERR_INVALIDPARAMS;
12957 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &desc.desc1);
12958 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u, type %s.\n",
12959 hr, expected_hr, desc_sizes[j], surface_caps[i].name);
12961 memset(&desc, 0, sizeof(desc));
12962 desc.dwSize = desc_sizes[j];
12963 expected_hr = desc.dwSize == sizeof(DDSURFACEDESC) ? DD_OK : DDERR_INVALIDPARAMS;
12964 hr = IDirectDrawSurface2_GetSurfaceDesc(surface2, &desc.desc1);
12965 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u, type %s.\n",
12966 hr, expected_hr, desc_sizes[j], surface_caps[i].name);
12968 memset(&desc, 0, sizeof(desc));
12969 desc.dwSize = desc_sizes[j];
12970 expected_hr = desc.dwSize == sizeof(DDSURFACEDESC2) ? DD_OK : DDERR_INVALIDPARAMS;
12971 hr = IDirectDrawSurface7_GetSurfaceDesc(surface7, &desc.desc2);
12972 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u, type %s.\n",
12973 hr, expected_hr, desc_sizes[j], surface_caps[i].name);
12976 /* Lock() */
12977 for (j = 0; j < ARRAY_SIZE(desc_sizes); ++j)
12979 const BOOL valid_size = desc_sizes[j] == sizeof(DDSURFACEDESC)
12980 || desc_sizes[j] == sizeof(DDSURFACEDESC2);
12981 DWORD expected_texture_stage;
12983 memset(&desc, 0, sizeof(desc));
12984 desc.dwSize = desc_sizes[j];
12985 desc.desc2.dwTextureStage = 0xdeadbeef;
12986 desc.blob[sizeof(DDSURFACEDESC2)] = 0xef;
12987 hr = IDirectDrawSurface_Lock(surface, NULL, &desc.desc1, 0, 0);
12988 expected_hr = valid_size ? DD_OK : DDERR_INVALIDPARAMS;
12989 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u, type %s.\n",
12990 hr, expected_hr, desc_sizes[j], surface_caps[i].name);
12991 ok(desc.dwSize == desc_sizes[j], "dwSize was changed from %u to %lu, type %s.\n",
12992 desc_sizes[j], desc.dwSize, surface_caps[i].name);
12993 ok(desc.blob[sizeof(DDSURFACEDESC2)] == 0xef, "Got unexpected byte %02x, size %u, type %s.\n",
12994 desc.blob[sizeof(DDSURFACEDESC2)], desc_sizes[j], surface_caps[i].name);
12995 if (SUCCEEDED(hr))
12997 ok(desc.desc1.dwWidth == 128, "Got unexpected width %lu, size %u, type %s.\n",
12998 desc.desc1.dwWidth, desc_sizes[j], surface_caps[i].name);
12999 ok(desc.desc1.dwHeight == 128, "Got unexpected height %lu, size %u, type %s.\n",
13000 desc.desc1.dwHeight, desc_sizes[j], surface_caps[i].name);
13001 expected_texture_stage = desc_sizes[j] >= sizeof(DDSURFACEDESC2) ? 0 : 0xdeadbeef;
13002 todo_wine_if(!expected_texture_stage)
13003 ok(desc.desc2.dwTextureStage == expected_texture_stage,
13004 "Got unexpected texture stage %#lx, size %u, type %s.\n",
13005 desc.desc2.dwTextureStage, desc_sizes[j], surface_caps[i].name);
13006 IDirectDrawSurface_Unlock(surface, NULL);
13009 memset(&desc, 0, sizeof(desc));
13010 desc.dwSize = desc_sizes[j];
13011 desc.desc2.dwTextureStage = 0xdeadbeef;
13012 desc.blob[sizeof(DDSURFACEDESC2)] = 0xef;
13013 hr = IDirectDrawSurface2_Lock(surface2, NULL, &desc.desc1, 0, 0);
13014 expected_hr = valid_size ? DD_OK : DDERR_INVALIDPARAMS;
13015 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u, type %s.\n",
13016 hr, expected_hr, desc_sizes[j], surface_caps[i].name);
13017 ok(desc.dwSize == desc_sizes[j], "dwSize was changed from %u to %lu, type %s.\n",
13018 desc_sizes[j], desc.dwSize, surface_caps[i].name);
13019 ok(desc.blob[sizeof(DDSURFACEDESC2)] == 0xef, "Got unexpected byte %02x, size %u, type %s.\n",
13020 desc.blob[sizeof(DDSURFACEDESC2)], desc_sizes[j], surface_caps[i].name);
13021 if (SUCCEEDED(hr))
13023 ok(desc.desc2.dwWidth == 128, "Got unexpected width %lu, size %u, type %s.\n",
13024 desc.desc2.dwWidth, desc_sizes[j], surface_caps[i].name);
13025 ok(desc.desc2.dwHeight == 128, "Got unexpected height %lu, size %u, type %s.\n",
13026 desc.desc2.dwHeight, desc_sizes[j], surface_caps[i].name);
13027 expected_texture_stage = desc_sizes[j] >= sizeof(DDSURFACEDESC2) ? 0 : 0xdeadbeef;
13028 todo_wine_if(!expected_texture_stage)
13029 ok(desc.desc2.dwTextureStage == expected_texture_stage,
13030 "Got unexpected texture stage %#lx, size %u, type %s.\n",
13031 desc.desc2.dwTextureStage, desc_sizes[j], surface_caps[i].name);
13032 IDirectDrawSurface2_Unlock(surface2, NULL);
13035 memset(&desc, 0, sizeof(desc));
13036 desc.dwSize = desc_sizes[j];
13037 desc.desc2.dwTextureStage = 0xdeadbeef;
13038 desc.blob[sizeof(DDSURFACEDESC2)] = 0xef;
13039 hr = IDirectDrawSurface7_Lock(surface7, NULL, &desc.desc2, 0, 0);
13040 expected_hr = valid_size ? DD_OK : DDERR_INVALIDPARAMS;
13041 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u, type %s.\n",
13042 hr, expected_hr, desc_sizes[j], surface_caps[i].name);
13043 ok(desc.dwSize == desc_sizes[j], "dwSize was changed from %u to %lu, type %s.\n",
13044 desc_sizes[j], desc.dwSize, surface_caps[i].name);
13045 ok(desc.blob[sizeof(DDSURFACEDESC2)] == 0xef, "Got unexpected byte %02x, size %u, type %s.\n",
13046 desc.blob[sizeof(DDSURFACEDESC2)], desc_sizes[j], surface_caps[i].name);
13047 if (SUCCEEDED(hr))
13049 ok(desc.desc2.dwWidth == 128, "Got unexpected width %lu, size %u, type %s.\n",
13050 desc.desc2.dwWidth, desc_sizes[j], surface_caps[i].name);
13051 ok(desc.desc2.dwHeight == 128, "Got unexpected height %lu, size %u, type %s.\n",
13052 desc.desc2.dwHeight, desc_sizes[j], surface_caps[i].name);
13053 expected_texture_stage = desc_sizes[j] >= sizeof(DDSURFACEDESC2) ? 0 : 0xdeadbeef;
13054 ok(desc.desc2.dwTextureStage == expected_texture_stage,
13055 "Got unexpected texture stage %#lx, size %u, type %s.\n",
13056 desc.desc2.dwTextureStage, desc_sizes[j], surface_caps[i].name);
13057 IDirectDrawSurface7_Unlock(surface7, NULL);
13061 IDirectDrawSurface7_Release(surface7);
13062 IDirectDrawSurface2_Release(surface2);
13063 IDirectDrawSurface_Release(surface);
13066 /* GetDisplayMode() */
13067 for (j = 0; j < ARRAY_SIZE(desc_sizes); ++j)
13069 memset(&desc, 0xcc, sizeof(desc));
13070 desc.dwSize = desc_sizes[j];
13071 expected_hr = (desc.dwSize == sizeof(DDSURFACEDESC) || desc.dwSize == sizeof(DDSURFACEDESC2))
13072 ? DD_OK : DDERR_INVALIDPARAMS;
13073 hr = IDirectDraw2_GetDisplayMode(ddraw, &desc.desc1);
13074 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u.\n", hr, expected_hr, desc_sizes[j]);
13075 if (SUCCEEDED(hr))
13077 ok(desc.dwSize == sizeof(DDSURFACEDESC), "Wrong size %lu for %u.\n", desc.dwSize, desc_sizes[j]);
13078 ok(desc.blob[desc_sizes[j]] == 0xcc, "Overflow for size %u.\n", desc_sizes[j]);
13079 ok(desc.blob[desc_sizes[j] - 1] != 0xcc, "Struct not cleared for size %u.\n", desc_sizes[j]);
13083 refcount = IDirectDraw2_Release(ddraw);
13084 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
13087 static void test_ck_operation(void)
13089 IDirectDrawSurface2 *src, *dst;
13090 IDirectDrawSurface7 *src7, *dst7;
13091 IDirectDrawSurface *surface1;
13092 DDSURFACEDESC surface_desc;
13093 unsigned int i, *color;
13094 IDirectDraw2 *ddraw;
13095 ULONG refcount;
13096 HWND window;
13097 HRESULT hr;
13098 DDCOLORKEY ckey;
13099 DDBLTFX fx;
13101 window = create_window();
13102 ddraw = create_ddraw();
13103 ok(!!ddraw, "Failed to create a ddraw object.\n");
13104 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
13105 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
13107 memset(&surface_desc, 0, sizeof(surface_desc));
13108 surface_desc.dwSize = sizeof(surface_desc);
13109 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
13110 surface_desc.dwWidth = 4;
13111 surface_desc.dwHeight = 1;
13112 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
13113 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
13114 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
13115 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
13116 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
13117 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
13118 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
13119 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
13120 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&dst);
13121 ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface2, hr %#lx.\n", hr);
13122 IDirectDrawSurface_Release(surface1);
13124 surface_desc.dwFlags |= DDSD_CKSRCBLT;
13125 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00ff00ff;
13126 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00ff00ff;
13127 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
13128 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
13129 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&src);
13130 ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface2, hr %#lx.\n", hr);
13131 IDirectDrawSurface_Release(surface1);
13133 hr = IDirectDrawSurface2_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13134 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13135 ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
13136 color = surface_desc.lpSurface;
13137 color[0] = 0x77010203;
13138 color[1] = 0x00010203;
13139 color[2] = 0x77ff00ff;
13140 color[3] = 0x00ff00ff;
13141 hr = IDirectDrawSurface2_Unlock(src, NULL);
13142 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13144 for (i = 0; i < 2; ++i)
13146 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13147 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13148 color = surface_desc.lpSurface;
13149 color[0] = 0xcccccccc;
13150 color[1] = 0xcccccccc;
13151 color[2] = 0xcccccccc;
13152 color[3] = 0xcccccccc;
13153 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13154 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13156 if (i)
13158 hr = IDirectDrawSurface2_BltFast(dst, 0, 0, src, NULL, DDBLTFAST_SRCCOLORKEY);
13159 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
13161 else
13163 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, NULL);
13164 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
13167 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT | DDLOCK_READONLY, NULL);
13168 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13169 ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
13170 color = surface_desc.lpSurface;
13171 /* Different behavior on some drivers / windows versions. Some versions ignore the X channel when
13172 * color keying, but copy it to the destination surface. Others (sysmem surfaces) apply it for
13173 * color keying, but do not copy it into the destination surface. Nvidia neither uses it for
13174 * color keying nor copies it. */
13175 ok((color[0] == 0x77010203 && color[1] == 0x00010203
13176 && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* AMD, Wine */
13177 || broken(color[0] == 0x00010203 && color[1] == 0x00010203
13178 && color[2] == 0x00ff00ff && color[3] == 0xcccccccc) /* Sysmem surfaces? */
13179 || broken(color[0] == 0x00010203 && color[1] == 0x00010203
13180 && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Nvidia */
13181 || broken(color[0] == 0xff010203 && color[1] == 0xff010203
13182 && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Testbot */,
13183 "Destination data after blitting is %08x %08x %08x %08x, i=%u.\n",
13184 color[0], color[1], color[2], color[3], i);
13185 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13186 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13189 hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
13190 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
13191 ok(ckey.dwColorSpaceLowValue == 0x00ff00ff && ckey.dwColorSpaceHighValue == 0x00ff00ff,
13192 "Got unexpected color key low=%08lx high=%08lx.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
13194 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
13195 hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
13196 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13198 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
13199 hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
13200 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
13201 ok(ckey.dwColorSpaceLowValue == 0x0000ff00 && ckey.dwColorSpaceHighValue == 0x0000ff00,
13202 "Got unexpected color key low=%08lx high=%08lx.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
13204 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0;
13205 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0;
13206 hr = IDirectDrawSurface2_GetSurfaceDesc(src, &surface_desc);
13207 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
13208 ok(surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue == 0x0000ff00
13209 && surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue == 0x0000ff00,
13210 "Got unexpected color key low=%08lx high=%08lx.\n", surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue,
13211 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue);
13213 /* Test SetColorKey with dwColorSpaceHighValue < dwColorSpaceLowValue */
13214 ckey.dwColorSpaceLowValue = 0x000000ff;
13215 ckey.dwColorSpaceHighValue = 0x00000000;
13216 hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
13217 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13219 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
13220 hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
13221 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
13222 ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
13223 "Got unexpected color key low=%08lx high=%08lx.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
13225 ckey.dwColorSpaceLowValue = 0x000000ff;
13226 ckey.dwColorSpaceHighValue = 0x00000001;
13227 hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
13228 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13230 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
13231 hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
13232 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
13233 ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
13234 "Got unexpected color key low=%08lx high=%08lx.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
13236 ckey.dwColorSpaceLowValue = 0x000000fe;
13237 ckey.dwColorSpaceHighValue = 0x000000fd;
13238 hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
13239 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13241 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
13242 hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
13243 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
13244 ok(ckey.dwColorSpaceLowValue == 0x000000fe && ckey.dwColorSpaceHighValue == 0x000000fe,
13245 "Got unexpected color key low=%08lx high=%08lx.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
13247 IDirectDrawSurface2_Release(src);
13248 IDirectDrawSurface2_Release(dst);
13250 /* Test source and destination keys and where they are read from. Use a surface with alpha
13251 * to avoid driver-dependent content in the X channel. */
13252 memset(&surface_desc, 0, sizeof(surface_desc));
13253 surface_desc.dwSize = sizeof(surface_desc);
13254 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
13255 surface_desc.dwWidth = 6;
13256 surface_desc.dwHeight = 1;
13257 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
13258 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
13259 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
13260 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
13261 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
13262 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
13263 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
13264 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
13265 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
13266 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&dst);
13267 ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface2, hr %#lx.\n", hr);
13268 IDirectDrawSurface_Release(surface1);
13270 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
13271 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
13272 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&src);
13273 ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface2, hr %#lx.\n", hr);
13274 IDirectDrawSurface_Release(surface1);
13276 ckey.dwColorSpaceLowValue = 0x0000ff00;
13277 ckey.dwColorSpaceHighValue = 0x0000ff00;
13278 hr = IDirectDrawSurface2_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
13279 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13280 ckey.dwColorSpaceLowValue = 0x00ff0000;
13281 ckey.dwColorSpaceHighValue = 0x00ff0000;
13282 hr = IDirectDrawSurface2_SetColorKey(dst, DDCKEY_DESTBLT, &ckey);
13283 ok(SUCCEEDED(hr) || hr == DDERR_NOCOLORKEYHW, "Failed to set color key, hr %#lx.\n", hr);
13284 if (FAILED(hr))
13286 /* Nvidia reject dest keys, AMD allows them. This applies to vidmem and sysmem surfaces. */
13287 skip("Failed to set destination color key, skipping related tests.\n");
13288 goto done;
13291 ckey.dwColorSpaceLowValue = 0x000000ff;
13292 ckey.dwColorSpaceHighValue = 0x000000ff;
13293 hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
13294 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13295 ckey.dwColorSpaceLowValue = 0x000000aa;
13296 ckey.dwColorSpaceHighValue = 0x000000aa;
13297 hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_DESTBLT, &ckey);
13298 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13300 memset(&fx, 0, sizeof(fx));
13301 fx.dwSize = sizeof(fx);
13302 fx.ddckSrcColorkey.dwColorSpaceHighValue = 0x00110000;
13303 fx.ddckSrcColorkey.dwColorSpaceLowValue = 0x00110000;
13304 fx.ddckDestColorkey.dwColorSpaceHighValue = 0x00001100;
13305 fx.ddckDestColorkey.dwColorSpaceLowValue = 0x00001100;
13307 hr = IDirectDrawSurface2_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13308 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13309 color = surface_desc.lpSurface;
13310 color[0] = 0x000000ff; /* Applies to src blt key in src surface. */
13311 color[1] = 0x000000aa; /* Applies to dst blt key in src surface. */
13312 color[2] = 0x00ff0000; /* Dst color key in dst surface. */
13313 color[3] = 0x0000ff00; /* Src color key in dst surface. */
13314 color[4] = 0x00001100; /* Src color key in ddbltfx. */
13315 color[5] = 0x00110000; /* Dst color key in ddbltfx. */
13316 hr = IDirectDrawSurface2_Unlock(src, NULL);
13317 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13319 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13320 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13321 color = surface_desc.lpSurface;
13322 color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
13323 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13324 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13326 /* Test a blit without keying. */
13327 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, 0, &fx);
13328 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
13330 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13331 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13332 color = surface_desc.lpSurface;
13333 /* Should have copied src data unmodified to dst. */
13334 ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
13335 color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
13336 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
13337 color[0], color[1], color[2], color[3], color[4], color[5]);
13339 color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
13340 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13341 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13343 /* Src key. */
13344 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
13345 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
13347 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13348 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13349 color = surface_desc.lpSurface;
13350 /* Src key applied to color[0]. It is unmodified, the others are copied. */
13351 ok(color[0] == 0x55555555 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
13352 color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
13353 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
13354 color[0], color[1], color[2], color[3], color[4], color[5]);
13356 color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
13357 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13358 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13360 /* Src override. */
13361 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, &fx);
13362 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
13364 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13365 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13366 color = surface_desc.lpSurface;
13367 /* Override key applied to color[5]. It is unmodified, the others are copied. */
13368 ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
13369 color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x55555555,
13370 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
13371 color[0], color[1], color[2], color[3], color[4], color[5]);
13373 color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
13374 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13375 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13377 /* Src override AND src key. That is not supposed to work. */
13378 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE, &fx);
13379 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13381 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13382 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13383 color = surface_desc.lpSurface;
13384 /* Ensure the destination was not changed. */
13385 ok(color[0] == 0x55555555 && color[1] == 0x55555555 && color[2] == 0x55555555 &&
13386 color[3] == 0x55555555 && color[4] == 0x55555555 && color[5] == 0x55555555,
13387 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
13388 color[0], color[1], color[2], color[3], color[4], color[5]);
13390 /* Use different dst colors for the dst key test. */
13391 color[0] = 0x00ff0000; /* Dest key in dst surface. */
13392 color[1] = 0x00ff0000; /* Dest key in dst surface. */
13393 color[2] = 0x00001100; /* Dest key in override. */
13394 color[3] = 0x00001100; /* Dest key in override. */
13395 color[4] = 0x000000aa; /* Dest key in src surface. */
13396 color[5] = 0x000000aa; /* Dest key in src surface. */
13397 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13398 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13400 /* Dest key blit. The key is taken from the SOURCE surface in v2! */
13401 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
13402 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
13404 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13405 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13406 color = surface_desc.lpSurface;
13407 /* Dst key applied to color[4,5], they are the only changed pixels. */
13408 ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
13409 color[3] == 0x00001100 && color[4] == 0x00001100 && color[5] == 0x00110000,
13410 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
13411 color[0], color[1], color[2], color[3], color[4], color[5]);
13413 color[0] = 0x00ff0000; /* Dest key in dst surface. */
13414 color[1] = 0x00ff0000; /* Dest key in dst surface. */
13415 color[2] = 0x00001100; /* Dest key in override. */
13416 color[3] = 0x00001100; /* Dest key in override. */
13417 color[4] = 0x000000aa; /* Dest key in src surface. */
13418 color[5] = 0x000000aa; /* Dest key in src surface. */
13419 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13420 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13422 /* What happens with a QI'd newer version of the interface? It takes the key
13423 * from the destination surface. */
13424 hr = IDirectDrawSurface2_QueryInterface(src, &IID_IDirectDrawSurface7, (void **)&src7);
13425 ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#lx.\n", hr);
13426 hr = IDirectDrawSurface2_QueryInterface(dst, &IID_IDirectDrawSurface7, (void **)&dst7);
13427 ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#lx.\n", hr);
13429 hr = IDirectDrawSurface7_Blt(dst7, NULL, src7, NULL, DDBLT_KEYDEST, &fx);
13430 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
13432 IDirectDrawSurface7_Release(dst7);
13433 IDirectDrawSurface7_Release(src7);
13435 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13436 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13437 color = surface_desc.lpSurface;
13438 /* Dst key applied to color[0,1], they are the only changed pixels. */
13439 todo_wine ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00001100 &&
13440 color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
13441 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
13442 color[0], color[1], color[2], color[3], color[4], color[5]);
13444 color[0] = 0x00ff0000; /* Dest key in dst surface. */
13445 color[1] = 0x00ff0000; /* Dest key in dst surface. */
13446 color[2] = 0x00001100; /* Dest key in override. */
13447 color[3] = 0x00001100; /* Dest key in override. */
13448 color[4] = 0x000000aa; /* Dest key in src surface. */
13449 color[5] = 0x000000aa; /* Dest key in src surface. */
13450 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13451 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13453 /* Dest override key blit. */
13454 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, &fx);
13455 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
13457 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13458 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13459 color = surface_desc.lpSurface;
13460 /* Dst key applied to color[2,3], they are the only changed pixels. */
13461 ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00ff0000 &&
13462 color[3] == 0x0000ff00 && color[4] == 0x000000aa && color[5] == 0x000000aa,
13463 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
13464 color[0], color[1], color[2], color[3], color[4], color[5]);
13466 color[0] = 0x00ff0000; /* Dest key in dst surface. */
13467 color[1] = 0x00ff0000; /* Dest key in dst surface. */
13468 color[2] = 0x00001100; /* Dest key in override. */
13469 color[3] = 0x00001100; /* Dest key in override. */
13470 color[4] = 0x000000aa; /* Dest key in src surface. */
13471 color[5] = 0x000000aa; /* Dest key in src surface. */
13472 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13473 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13475 /* Dest override together with surface key. Supposed to fail. */
13476 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE, &fx);
13477 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13479 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13480 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13481 color = surface_desc.lpSurface;
13482 /* Destination is unchanged. */
13483 ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
13484 color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
13485 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
13486 color[0], color[1], color[2], color[3], color[4], color[5]);
13487 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13488 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13490 /* Source and destination key. This is driver dependent. New HW treats it like
13491 * DDBLT_KEYSRC. Older HW and some software renderers apply both keys. */
13492 if (0)
13494 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYSRC, &fx);
13495 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
13497 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13498 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13499 color = surface_desc.lpSurface;
13500 /* Color[0] is filtered by the src key, 2-5 are filtered by the dst key, if
13501 * the driver applies it. */
13502 ok(color[0] == 0x00ff0000 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
13503 color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
13504 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
13505 color[0], color[1], color[2], color[3], color[4], color[5]);
13507 color[0] = 0x00ff0000; /* Dest key in dst surface. */
13508 color[1] = 0x00ff0000; /* Dest key in dst surface. */
13509 color[2] = 0x00001100; /* Dest key in override. */
13510 color[3] = 0x00001100; /* Dest key in override. */
13511 color[4] = 0x000000aa; /* Dest key in src surface. */
13512 color[5] = 0x000000aa; /* Dest key in src surface. */
13513 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13514 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13517 /* Override keys without ddbltfx parameter fail */
13518 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, NULL);
13519 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13520 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, NULL);
13521 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13523 /* Try blitting without keys in the source surface. */
13524 hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, NULL);
13525 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13526 hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_DESTBLT, NULL);
13527 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13529 /* That fails now. Do not bother to check that the data is unmodified. */
13530 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
13531 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13533 /* Surprisingly this still works. It uses the old key from the src surface. */
13534 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
13535 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
13537 hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
13538 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13539 color = surface_desc.lpSurface;
13540 /* Dst key applied to color[4,5], they are the only changed pixels. */
13541 ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
13542 color[3] == 0x00001100 && color[4] == 0x00001100 && color[5] == 0x00110000,
13543 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
13544 color[0], color[1], color[2], color[3], color[4], color[5]);
13545 hr = IDirectDrawSurface2_Unlock(dst, NULL);
13546 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13548 /* This returns DDERR_NOCOLORKEY as expected. */
13549 hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_DESTBLT, &ckey);
13550 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx.\n", hr);
13552 /* GetSurfaceDesc returns a zeroed key as expected. */
13553 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x12345678;
13554 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x12345678;
13555 hr = IDirectDrawSurface2_GetSurfaceDesc(src, &surface_desc);
13556 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
13557 ok(!surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue
13558 && !surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue,
13559 "Got unexpected color key low=%08lx high=%08lx.\n", surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue,
13560 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue);
13562 /* Try blitting without keys in the destination surface. */
13563 hr = IDirectDrawSurface2_SetColorKey(dst, DDCKEY_SRCBLT, NULL);
13564 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13565 hr = IDirectDrawSurface2_SetColorKey(dst, DDCKEY_DESTBLT, NULL);
13566 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
13568 /* This fails, as sanity would dictate. */
13569 hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
13570 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13572 done:
13573 IDirectDrawSurface2_Release(src);
13574 IDirectDrawSurface2_Release(dst);
13575 refcount = IDirectDraw2_Release(ddraw);
13576 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
13577 DestroyWindow(window);
13580 static void test_set_render_state(void)
13582 IDirect3DDevice2 *device;
13583 IDirectDraw2 *ddraw;
13584 ULONG refcount;
13585 HWND window;
13586 DWORD state;
13587 HRESULT hr;
13589 window = create_window();
13590 ddraw = create_ddraw();
13591 ok(!!ddraw, "Failed to create a ddraw object.\n");
13592 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
13594 skip("Failed to create 3D device.\n");
13595 DestroyWindow(window);
13596 return;
13599 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZVISIBLE, TRUE);
13600 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13601 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZVISIBLE, FALSE);
13602 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13604 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
13605 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13606 state = 0xdeadbeef;
13607 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, &state);
13608 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13609 ok(!state, "Got unexpected render state %#lx.\n", state);
13610 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
13611 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13612 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_TEXTUREMAPBLEND, &state);
13613 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13614 ok(state == D3DTBLEND_MODULATE, "Got unexpected render state %#lx.\n", state);
13616 refcount = IDirect3DDevice2_Release(device);
13617 ok(!refcount, "Device has %lu references left.\n", refcount);
13618 refcount = IDirectDraw2_Release(ddraw);
13619 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
13620 DestroyWindow(window);
13623 static void test_depth_readback(void)
13625 unsigned int depth, expected_depth, i, x, y, max_diff, passed_fmts = 0;
13626 IDirect3DMaterial2 *blue_background;
13627 IDirectDrawSurface *rt, *ds;
13628 IDirect3DViewport2 *viewport;
13629 DDSURFACEDESC surface_desc;
13630 IDirect3DDevice2 *device;
13631 IDirectDraw2 *ddraw;
13632 ULONG refcount;
13633 HWND window;
13634 HRESULT hr;
13635 void *ptr;
13636 BOOL all_pass;
13638 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
13639 static D3DLVERTEX quad[] =
13641 {{-1.0f}, {-1.0f}, {0.1f}, 0, {0xff00ff00}},
13642 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
13643 {{ 1.0f}, {-1.0f}, {1.0f}, 0, {0xff00ff00}},
13644 {{ 1.0f}, { 1.0f}, {0.9f}, 0, {0xff00ff00}},
13647 static const struct
13649 unsigned int z_depth, z_mask;
13651 tests[] =
13653 {16, 0x0000ffff},
13654 {24, 0x00ffffff},
13655 {32, 0xffffffff},
13658 window = create_window();
13659 ok(!!window, "Failed to create a window.\n");
13660 ddraw = create_ddraw();
13661 ok(!!ddraw, "Failed to create a ddraw object.\n");
13662 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
13664 skip("Failed to create a D3D device, skipping tests.\n");
13665 IDirectDraw2_Release(ddraw);
13666 DestroyWindow(window);
13667 return;
13670 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
13671 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
13672 blue_background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
13673 viewport = create_viewport(device, 0, 0, 640, 480);
13674 viewport_set_background(device, viewport, blue_background);
13675 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
13676 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
13678 ds = get_depth_stencil(device);
13679 hr = IDirectDrawSurface_DeleteAttachedSurface(rt, 0, ds);
13680 ok(SUCCEEDED(hr), "Failed to detach depth buffer, hr %#lx.\n", hr);
13681 IDirectDrawSurface_Release(ds);
13683 for (i = 0; i < ARRAY_SIZE(tests); ++i)
13685 memset(&surface_desc, 0, sizeof(surface_desc));
13686 surface_desc.dwSize = sizeof(surface_desc);
13687 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
13688 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY;
13689 U2(surface_desc).dwZBufferBitDepth = tests[i].z_depth;
13690 surface_desc.dwWidth = 640;
13691 surface_desc.dwHeight = 480;
13692 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL);
13693 if (FAILED(hr))
13695 skip("Format %u not supported, skipping test.\n", i);
13696 continue;
13699 hr = IDirectDrawSurface_AddAttachedSurface(rt, ds);
13700 ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#lx.\n", hr);
13701 hr = IDirect3DDevice2_SetRenderTarget(device, rt, 0);
13702 ok(SUCCEEDED(hr), "Failed to set render target, hr %#lx.\n", hr);
13704 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
13705 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
13706 hr = IDirect3DDevice2_BeginScene(device);
13707 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
13708 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad, 4, 0);
13709 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
13710 hr = IDirect3DDevice2_EndScene(device);
13711 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
13713 memset(&surface_desc, 0, sizeof(surface_desc));
13714 surface_desc.dwSize = sizeof(surface_desc);
13715 hr = IDirectDrawSurface_Lock(ds, NULL, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
13716 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
13718 all_pass = TRUE;
13719 for (y = 60; y < 480; y += 120)
13721 for (x = 80; x < 640; x += 160)
13723 ptr = (BYTE *)surface_desc.lpSurface
13724 + y * U1(surface_desc).lPitch
13725 + x * (tests[i].z_depth == 16 ? 2 : 4);
13726 depth = *((DWORD *)ptr) & tests[i].z_mask;
13727 expected_depth = (x * (0.9 / 640.0) + y * (0.1 / 480.0)) * tests[i].z_mask;
13728 max_diff = ((0.5f * 0.9f) / 640.0f) * tests[i].z_mask;
13729 /* The ddraw2 version of this test behaves similarly to the ddraw7 version on Nvidia GPUs,
13730 * except that we only have D16 (broken on geforce 9) and D24X8 (broken on geforce 7) available.
13731 * Accept all nvidia GPUs as broken here, but still expect one of the formats to pass. */
13732 ok(compare_uint(expected_depth, depth, max_diff) || ddraw_is_nvidia(ddraw)
13733 || (ddraw_is_amd(ddraw) && tests[i].z_depth == 24),
13734 "Test %u: Got depth 0x%08x (diff %d), expected 0x%08x+/-%u, at %u, %u.\n",
13735 i, depth, expected_depth - depth, expected_depth, max_diff, x, y);
13736 if (!compare_uint(expected_depth, depth, max_diff))
13737 all_pass = FALSE;
13741 hr = IDirectDrawSurface_Unlock(ds, NULL);
13742 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
13744 if (all_pass)
13745 passed_fmts++;
13747 hr = IDirectDrawSurface_DeleteAttachedSurface(rt, 0, ds);
13748 ok(SUCCEEDED(hr), "Failed to detach depth buffer, hr %#lx.\n", hr);
13749 IDirectDrawSurface_Release(ds);
13752 ok(passed_fmts, "Not a single format passed the tests, this is bad even by Nvidia's standards.\n");
13754 destroy_viewport(device, viewport);
13755 destroy_material(blue_background);
13756 IDirectDrawSurface_Release(rt);
13757 refcount = IDirect3DDevice2_Release(device);
13758 ok(!refcount, "Device has %lu references left.\n", refcount);
13759 IDirectDraw2_Release(ddraw);
13760 DestroyWindow(window);
13763 static void test_clear(void)
13765 D3DRECT rect_negneg, rect_full = {{0}, {0}, {640}, {480}};
13766 IDirect3DViewport2 *viewport, *viewport2, *viewport3;
13767 IDirect3DMaterial2 *white, *red, *green, *blue;
13768 IDirect3DDevice2 *device;
13769 IDirectDrawSurface *rt;
13770 IDirectDraw2 *ddraw;
13771 unsigned int color;
13772 D3DRECT rect[2];
13773 ULONG refcount;
13774 HWND window;
13775 HRESULT hr;
13777 window = create_window();
13778 ddraw = create_ddraw();
13779 ok(!!ddraw, "Failed to create a ddraw object.\n");
13780 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
13782 skip("Failed to create a 3D device, skipping test.\n");
13783 IDirectDraw2_Release(ddraw);
13784 DestroyWindow(window);
13785 return;
13787 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
13788 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
13790 viewport = create_viewport(device, 0, 0, 640, 480);
13791 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
13792 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
13794 white = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
13795 red = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
13796 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 1.0f);
13797 blue = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
13799 viewport_set_background(device, viewport, white);
13800 hr = IDirect3DViewport2_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
13801 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
13803 /* Positive x, negative y. */
13804 U1(rect[0]).x1 = 0;
13805 U2(rect[0]).y1 = 480;
13806 U3(rect[0]).x2 = 320;
13807 U4(rect[0]).y2 = 240;
13809 /* Positive x, positive y. */
13810 U1(rect[1]).x1 = 0;
13811 U2(rect[1]).y1 = 0;
13812 U3(rect[1]).x2 = 320;
13813 U4(rect[1]).y2 = 240;
13815 /* Clear 2 rectangles with one call. Unlike d3d8/9, the refrast does not
13816 * refuse negative rectangles, but it will not clear them either. */
13817 viewport_set_background(device, viewport, red);
13818 hr = IDirect3DViewport2_Clear(viewport, 2, rect, D3DCLEAR_TARGET);
13819 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
13821 color = get_surface_color(rt, 160, 360);
13822 ok(compare_color(color, 0x00ffffff, 0), "Clear rectangle 3 (pos, neg) has color 0x%08x.\n", color);
13823 color = get_surface_color(rt, 160, 120);
13824 ok(compare_color(color, 0x00ff0000, 0), "Clear rectangle 1 (pos, pos) has color 0x%08x.\n", color);
13825 color = get_surface_color(rt, 480, 360);
13826 ok(compare_color(color, 0x00ffffff, 0), "Clear rectangle 4 (NULL) has color 0x%08x.\n", color);
13827 color = get_surface_color(rt, 480, 120);
13828 ok(compare_color(color, 0x00ffffff, 0), "Clear rectangle 4 (neg, neg) has color 0x%08x.\n", color);
13830 viewport_set_background(device, viewport, white);
13831 hr = IDirect3DViewport2_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
13832 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
13834 /* negative x, negative y.
13835 * Also ignored, except on WARP, which clears the entire screen. */
13836 U1(rect_negneg).x1 = 640;
13837 U2(rect_negneg).y1 = 240;
13838 U3(rect_negneg).x2 = 320;
13839 U4(rect_negneg).y2 = 0;
13840 viewport_set_background(device, viewport, green);
13841 hr = IDirect3DViewport2_Clear(viewport, 1, &rect_negneg, D3DCLEAR_TARGET);
13842 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
13844 color = get_surface_color(rt, 160, 360);
13845 ok(compare_color(color, 0x00ffffff, 0)
13846 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x0000ff00, 0)),
13847 "Got unexpected color 0x%08x.\n", color);
13848 color = get_surface_color(rt, 160, 120);
13849 ok(compare_color(color, 0x00ffffff, 0)
13850 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x0000ff00, 0)),
13851 "Got unexpected color 0x%08x.\n", color);
13852 color = get_surface_color(rt, 480, 360);
13853 ok(compare_color(color, 0x00ffffff, 0)
13854 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x0000ff00, 0)),
13855 "Got unexpected color 0x%08x.\n", color);
13856 color = get_surface_color(rt, 480, 120);
13857 ok(compare_color(color, 0x00ffffff, 0)
13858 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x0000ff00, 0)),
13859 "Got unexpected color 0x%08x.\n", color);
13861 /* Test how the viewport affects clears. */
13862 viewport_set_background(device, viewport, white);
13863 hr = IDirect3DViewport2_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
13864 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
13866 viewport2 = create_viewport(device, 160, 120, 160, 120);
13867 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport2);
13868 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
13870 viewport_set_background(device, viewport2, blue);
13871 hr = IDirect3DViewport2_Clear(viewport2, 1, &rect_full, D3DCLEAR_TARGET);
13872 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
13874 viewport3 = create_viewport(device, 320, 240, 320, 240);
13875 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport3);
13876 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
13878 U1(rect[0]).x1 = 160;
13879 U2(rect[0]).y1 = 120;
13880 U3(rect[0]).x2 = 480;
13881 U4(rect[0]).y2 = 360;
13882 viewport_set_background(device, viewport3, green);
13883 hr = IDirect3DViewport2_Clear(viewport3, 1, &rect[0], D3DCLEAR_TARGET);
13884 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
13886 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
13887 ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#lx.\n", hr);
13889 color = get_surface_color(rt, 158, 118);
13890 ok(compare_color(color, 0x00ffffff, 0), "(158, 118) has color 0x%08x.\n", color);
13891 color = get_surface_color(rt, 162, 118);
13892 ok(compare_color(color, 0x00ffffff, 0), "(162, 118) has color 0x%08x.\n", color);
13893 color = get_surface_color(rt, 158, 122);
13894 ok(compare_color(color, 0x00ffffff, 0), "(158, 122) has color 0x%08x.\n", color);
13895 color = get_surface_color(rt, 162, 122);
13896 ok(compare_color(color, 0x000000ff, 0), "(162, 122) has color 0x%08x.\n", color);
13898 color = get_surface_color(rt, 318, 238);
13899 ok(compare_color(color, 0x000000ff, 0), "(318, 238) has color 0x%08x.\n", color);
13900 color = get_surface_color(rt, 322, 238);
13901 ok(compare_color(color, 0x00ffffff, 0), "(322, 238) has color 0x%08x.\n", color);
13902 color = get_surface_color(rt, 318, 242);
13903 ok(compare_color(color, 0x00ffffff, 0), "(318, 242) has color 0x%08x.\n", color);
13904 color = get_surface_color(rt, 322, 242);
13905 ok(compare_color(color, 0x0000ff00, 0), "(322, 242) has color 0x%08x.\n", color);
13907 color = get_surface_color(rt, 478, 358);
13908 ok(compare_color(color, 0x0000ff00, 0), "(478, 358) has color 0x%08x.\n", color);
13909 color = get_surface_color(rt, 482, 358);
13910 ok(compare_color(color, 0x00ffffff, 0), "(482, 358) has color 0x%08x.\n", color);
13911 color = get_surface_color(rt, 478, 362);
13912 ok(compare_color(color, 0x00ffffff, 0), "(478, 362) has color 0x%08x.\n", color);
13913 color = get_surface_color(rt, 482, 362);
13914 ok(compare_color(color, 0x00ffffff, 0), "(482, 362) has color 0x%08x.\n", color);
13916 /* The clear rectangle is rendertarget absolute, not relative to the
13917 * viewport. */
13918 hr = IDirect3DViewport2_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
13919 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
13920 U1(rect[0]).x1 = 330;
13921 U2(rect[0]).y1 = 250;
13922 U3(rect[0]).x2 = 340;
13923 U4(rect[0]).y2 = 260;
13924 hr = IDirect3DViewport2_Clear(viewport3, 1, &rect[0], D3DCLEAR_TARGET);
13925 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
13927 color = get_surface_color(rt, 328, 248);
13928 ok(compare_color(color, 0x00ffffff, 0), "(328, 248) has color 0x%08x.\n", color);
13929 color = get_surface_color(rt, 332, 248);
13930 ok(compare_color(color, 0x00ffffff, 0), "(332, 248) has color 0x%08x.\n", color);
13931 color = get_surface_color(rt, 328, 252);
13932 ok(compare_color(color, 0x00ffffff, 0), "(328, 252) has color 0x%08x.\n", color);
13933 color = get_surface_color(rt, 332, 252);
13934 ok(compare_color(color, 0x0000ff00, 0), "(332, 252) has color 0x%08x.\n", color);
13936 color = get_surface_color(rt, 338, 248);
13937 ok(compare_color(color, 0x00ffffff, 0), "(338, 248) has color 0x%08x.\n", color);
13938 color = get_surface_color(rt, 342, 248);
13939 ok(compare_color(color, 0x00ffffff, 0), "(342, 248) has color 0x%08x.\n", color);
13940 color = get_surface_color(rt, 338, 252);
13941 ok(compare_color(color, 0x0000ff00, 0), "(338, 252) has color 0x%08x.\n", color);
13942 color = get_surface_color(rt, 342, 252);
13943 ok(compare_color(color, 0x00ffffff, 0), "(342, 252) has color 0x%08x.\n", color);
13945 color = get_surface_color(rt, 328, 258);
13946 ok(compare_color(color, 0x00ffffff, 0), "(328, 258) has color 0x%08x.\n", color);
13947 color = get_surface_color(rt, 332, 258);
13948 ok(compare_color(color, 0x0000ff00, 0), "(332, 258) has color 0x%08x.\n", color);
13949 color = get_surface_color(rt, 328, 262);
13950 ok(compare_color(color, 0x00ffffff, 0), "(328, 262) has color 0x%08x.\n", color);
13951 color = get_surface_color(rt, 332, 262);
13952 ok(compare_color(color, 0x00ffffff, 0), "(332, 262) has color 0x%08x.\n", color);
13954 color = get_surface_color(rt, 338, 258);
13955 ok(compare_color(color, 0x0000ff00, 0), "(338, 258) has color 0x%08x.\n", color);
13956 color = get_surface_color(rt, 342, 258);
13957 ok(compare_color(color, 0x00ffffff, 0), "(342, 258) has color 0x%08x.\n", color);
13958 color = get_surface_color(rt, 338, 262);
13959 ok(compare_color(color, 0x00ffffff, 0), "(338, 262) has color 0x%08x.\n", color);
13960 color = get_surface_color(rt, 342, 262);
13961 ok(compare_color(color, 0x00ffffff, 0), "(342, 262) has color 0x%08x.\n", color);
13963 /* COLORWRITEENABLE, SRGBWRITEENABLE and scissor rectangles do not exist
13964 * in d3d2. */
13966 IDirect3DViewport2_Release(viewport3);
13967 IDirect3DViewport2_Release(viewport2);
13968 IDirect3DViewport2_Release(viewport);
13969 IDirect3DMaterial2_Release(white);
13970 IDirect3DMaterial2_Release(red);
13971 IDirect3DMaterial2_Release(green);
13972 IDirect3DMaterial2_Release(blue);
13973 IDirectDrawSurface_Release(rt);
13974 refcount = IDirect3DDevice2_Release(device);
13975 ok(!refcount, "Device has %lu references left.\n", refcount);
13976 refcount = IDirectDraw2_Release(ddraw);
13977 ok(!refcount, "Ddraw object has %lu references left.\n", refcount);
13978 DestroyWindow(window);
13981 struct enum_surfaces_param
13983 IDirectDraw2 *ddraw;
13984 DDSURFACEDESC modes[20];
13985 unsigned int mode_count;
13987 IDirectDrawSurface *surfaces[8];
13988 unsigned int count;
13991 static HRESULT CALLBACK build_mode_list_cb(DDSURFACEDESC *desc, void *context)
13993 struct enum_surfaces_param *param = context;
13994 IDirectDrawSurface *surface;
13996 if (SUCCEEDED(IDirectDraw2_CreateSurface(param->ddraw, desc, &surface, NULL)))
13998 if (param->mode_count < ARRAY_SIZE(param->modes))
13999 param->modes[param->mode_count] = *desc;
14000 ++param->mode_count;
14001 IDirectDrawSurface_Release(surface);
14004 return DDENUMRET_OK;
14007 static HRESULT WINAPI enum_surfaces_cb(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
14009 struct enum_surfaces_param *param = context;
14010 BOOL found = FALSE;
14011 unsigned int i;
14013 for (i = 0; i < ARRAY_SIZE(param->surfaces); ++i)
14015 if (param->surfaces[i] == surface)
14017 found = TRUE;
14018 break;
14022 ok(found, "Unexpected surface %p enumerated.\n", surface);
14023 IDirectDrawSurface_Release(surface);
14024 ++param->count;
14026 return DDENUMRET_OK;
14029 static HRESULT WINAPI enum_surfaces_create_cb(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
14031 static const DWORD expect_flags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_PIXELFORMAT;
14032 struct enum_surfaces_param *param = context;
14034 ok(!surface, "Unexpected surface %p.\n", surface);
14035 ok((desc->dwFlags & expect_flags) == expect_flags, "Got unexpected flags %#lx.\n", desc->dwFlags);
14036 if (param->count < ARRAY_SIZE(param->modes))
14038 const DDSURFACEDESC *expect = &param->modes[param->count];
14039 ok(desc->dwWidth == expect->dwWidth, "Expected width %lu, got %lu.\n", expect->dwWidth, desc->dwWidth);
14040 ok(desc->dwHeight == expect->dwHeight, "Expected height %lu, got %lu.\n", expect->dwHeight, desc->dwHeight);
14041 ok(!memcmp(&U4(*desc).ddpfPixelFormat, &U4(*expect).ddpfPixelFormat, sizeof(U4(*desc).ddpfPixelFormat)),
14042 "Pixel formats didn't match.\n");
14045 ++param->count;
14047 return DDENUMRET_OK;
14050 static void test_enum_surfaces(void)
14052 struct enum_surfaces_param param = {0};
14053 DDPIXELFORMAT current_format;
14054 IDirectDraw2 *ddraw;
14055 DDSURFACEDESC desc;
14056 HRESULT hr;
14058 ddraw = create_ddraw();
14059 ok(!!ddraw, "Failed to create a ddraw object.\n");
14060 param.ddraw = ddraw;
14062 memset(&desc, 0, sizeof(desc));
14063 desc.dwSize = sizeof(desc);
14064 hr = IDirectDraw2_GetDisplayMode(ddraw, &desc);
14065 ok(hr == DD_OK, "Failed to get display mode, hr %#lx.\n", hr);
14066 current_format = desc.ddpfPixelFormat;
14068 hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
14069 ok(hr == DD_OK, "Failed to set cooperative level, hr %#lx.\n", hr);
14071 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_ALL, NULL, NULL, enum_surfaces_cb);
14072 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14074 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_ALL,
14075 NULL, NULL, enum_surfaces_cb);
14076 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14078 memset(&desc, 0, sizeof(desc));
14079 desc.dwSize = sizeof(desc);
14080 desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
14081 desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
14082 U2(desc).dwMipMapCount = 3;
14083 desc.dwWidth = 32;
14084 desc.dwHeight = 32;
14085 hr = IDirectDraw2_CreateSurface(ddraw, &desc, &param.surfaces[0], NULL);
14086 ok(SUCCEEDED(hr), "Failed to create a surface, hr %#lx.\n", hr);
14088 hr = IDirectDrawSurface_GetAttachedSurface(param.surfaces[0], &desc.ddsCaps, &param.surfaces[1]);
14089 ok(SUCCEEDED(hr), "Failed to get attached surface, hr %#lx.\n", hr);
14090 hr = IDirectDrawSurface_GetAttachedSurface(param.surfaces[1], &desc.ddsCaps, &param.surfaces[2]);
14091 ok(SUCCEEDED(hr), "Failed to get attached surface, hr %#lx.\n", hr);
14092 hr = IDirectDrawSurface_GetAttachedSurface(param.surfaces[2], &desc.ddsCaps, &param.surfaces[3]);
14093 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
14094 ok(!param.surfaces[3], "Got unexpected pointer %p.\n", param.surfaces[3]);
14096 param.count = 0;
14097 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_ALL,
14098 &desc, &param, enum_surfaces_cb);
14099 ok(SUCCEEDED(hr), "Failed to enumerate surfaces, hr %#lx.\n", hr);
14100 ok(param.count == 3, "Got unexpected number of enumerated surfaces %u.\n", param.count);
14102 param.count = 0;
14103 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_ALL,
14104 NULL, &param, enum_surfaces_cb);
14105 ok(SUCCEEDED(hr), "Failed to enumerate surfaces, hr %#lx.\n", hr);
14106 ok(param.count == 3, "Got unexpected number of enumerated surfaces %u.\n", param.count);
14108 desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
14109 param.count = 0;
14110 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_MATCH,
14111 &desc, &param, enum_surfaces_cb);
14112 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14113 ok(param.count == 1, "Got unexpected number of enumerated surfaces %u.\n", param.count);
14115 param.count = 0;
14116 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_NOMATCH,
14117 &desc, &param, enum_surfaces_cb);
14118 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14119 ok(param.count == 2, "Got unexpected number of enumerated surfaces %u.\n", param.count);
14121 desc.dwFlags = 0;
14122 param.count = 0;
14123 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_MATCH,
14124 &desc, &param, enum_surfaces_cb);
14125 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14126 ok(param.count == 3, "Got unexpected number of enumerated surfaces %u.\n", param.count);
14128 desc.dwFlags = 0;
14129 param.count = 0;
14130 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST, &desc, &param, enum_surfaces_cb);
14131 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14132 ok(param.count == 3, "Got unexpected number of enumerated surfaces %u.\n", param.count);
14134 IDirectDrawSurface_Release(param.surfaces[2]);
14135 IDirectDrawSurface_Release(param.surfaces[1]);
14136 IDirectDrawSurface_Release(param.surfaces[0]);
14138 param.count = 0;
14139 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_ALL,
14140 NULL, &param, enum_surfaces_cb);
14141 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14142 ok(!param.count, "Got unexpected number of enumerated surfaces %u.\n", param.count);
14144 memset(&desc, 0, sizeof(desc));
14145 desc.dwSize = sizeof(desc);
14146 desc.dwFlags = DDSD_CAPS;
14147 desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
14149 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_ALL,
14150 &desc, &param, enum_surfaces_create_cb);
14151 ok(hr == DDERR_INVALIDPARAMS, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14153 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_NOMATCH,
14154 &desc, &param, enum_surfaces_create_cb);
14155 ok(hr == DDERR_INVALIDPARAMS, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14157 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED,
14158 &desc, &param, enum_surfaces_create_cb);
14159 ok(hr == DDERR_INVALIDPARAMS, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14161 /* When not passed width and height, the callback is called with every
14162 * available display resolution. */
14164 param.mode_count = 0;
14165 desc.dwFlags |= DDSD_PIXELFORMAT;
14166 U4(desc).ddpfPixelFormat = current_format;
14167 hr = IDirectDraw2_EnumDisplayModes(ddraw, 0, &desc, &param, build_mode_list_cb);
14168 ok(hr == DD_OK, "Failed to build mode list, hr %#lx.\n", hr);
14170 param.count = 0;
14171 desc.dwFlags &= ~DDSD_PIXELFORMAT;
14172 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_MATCH,
14173 &desc, &param, enum_surfaces_create_cb);
14174 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14175 ok(param.count == param.mode_count, "Expected %u surfaces, got %u.\n", param.mode_count, param.count);
14177 desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
14178 desc.dwWidth = desc.dwHeight = 32;
14180 param.modes[0].dwWidth = param.modes[0].dwHeight = 32;
14182 param.count = 0;
14183 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_MATCH,
14184 &desc, &param, enum_surfaces_create_cb);
14185 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14186 ok(param.count == 1, "Got unexpected number of enumerated surfaces %u.\n", param.count);
14188 hr = IDirectDraw2_CreateSurface(ddraw, &desc, &param.surfaces[0], NULL);
14189 ok(hr == DD_OK, "Failed to create surface, hr %#lx.\n", hr);
14190 param.count = 0;
14191 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_MATCH,
14192 &desc, &param, enum_surfaces_create_cb);
14193 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14194 ok(param.count == 1, "Got unexpected number of enumerated surfaces %u.\n", param.count);
14195 IDirectDrawSurface2_Release(param.surfaces[0]);
14197 desc.dwFlags |= DDSD_PIXELFORMAT;
14198 desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
14199 desc.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
14200 desc.ddpfPixelFormat.dwFourCC = 0xdeadbeef;
14202 param.count = 0;
14203 hr = IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_MATCH,
14204 &desc, &param, enum_surfaces_create_cb);
14205 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
14206 ok(!param.count, "Got unexpected number of enumerated surfaces %u.\n", param.count);
14208 IDirectDraw2_Release(ddraw);
14211 static void test_viewport(void)
14213 static struct
14215 D3DVIEWPORT7 vp;
14216 RECT expected_rect;
14217 const char *message;
14219 tests[] =
14221 {{ 0, 0, 640, 480}, { 0, 120, 479, 359}, "Viewport (0, 0) - (640, 480)"},
14222 {{ 0, 0, 320, 240}, { 0, 60, 239, 179}, "Viewport (0, 0) - (320, 240)"},
14223 {{ 0, 0, 1280, 960}, { 0, 240, 639, 479}, "Viewport (0, 0) - (1280, 960)"},
14224 {{ 0, 0, 2000, 1600}, { 0, 400, 639, 479}, "Viewport (0, 0) - (2000, 1600)"},
14225 {{100, 100, 640, 480}, {100, 220, 579, 459}, "Viewport (100, 100) - (640, 480)"},
14226 {{ 0, 0, 8192, 8192}, {-10, -10, -10, -10}, "Viewport (0, 0) - (8192, 8192)"},
14228 static const struct
14230 unsigned int x, y;
14232 rt_sizes[] =
14234 {640, 480}, {1280, 960}, {320, 240}, {800, 600},
14236 static D3DMATRIX mat =
14238 1.0f, 0.0f, 0.0f, 0.0f,
14239 0.0f, 1.0f, 0.0f, 0.0f,
14240 0.0f, 0.0f, 1.0f, 0.0f,
14241 0.0f, 0.0f, 0.0f, 1.0f,
14243 static D3DLVERTEX quad[] =
14245 {{-1.5f}, {-0.5f}, {0.1f}, 0, {0xffffffff}},
14246 {{-1.5f}, { 0.5f}, {0.1f}, 0, {0xffffffff}},
14247 {{ 0.5f}, {-0.5f}, {0.1f}, 0, {0xffffffff}},
14248 {{ 0.5f}, { 0.5f}, {0.1f}, 0, {0xffffffff}},
14250 IDirect3DViewport2 *viewport, *full_viewport;
14251 IDirect3DMaterial2 *black_background;
14252 IDirectDrawSurface *rt, *ds;
14253 DDSURFACEDESC surface_desc;
14254 IDirect3DDevice2 *device;
14255 BOOL expected_failure;
14256 IDirectDraw2 *ddraw;
14257 DDPIXELFORMAT z_fmt;
14258 D3DRECT clear_rect;
14259 unsigned int i, j;
14260 IDirect3D2 *d3d;
14261 D3DVIEWPORT vp;
14262 ULONG refcount;
14263 HWND window;
14264 HRESULT hr;
14266 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
14267 0, 0, 640, 480, NULL, NULL, NULL, NULL);
14268 ddraw = create_ddraw();
14269 ok(!!ddraw, "Failed to create a ddraw object.\n");
14270 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
14272 skip("Failed to create a 3D device, skipping test.\n");
14273 IDirectDraw2_Release(ddraw);
14274 DestroyWindow(window);
14275 return;
14278 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
14279 ok(SUCCEEDED(hr), "Failed to get Direct3D2 interface, hr %#lx.\n", hr);
14281 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
14282 ok(SUCCEEDED(hr), "Failed to disable depth test, hr %#lx.\n", hr);
14283 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
14284 ok(SUCCEEDED(hr), "Failed to disable culling, hr %#lx.\n", hr);
14286 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat);
14287 ok(SUCCEEDED(hr), "Failed to set world transform, hr %#lx.\n", hr);
14288 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat);
14289 ok(SUCCEEDED(hr), "Failed to set view transform, hr %#lx.\n", hr);
14290 hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat);
14291 ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#lx.\n", hr);
14293 black_background = create_diffuse_material(device, 0.0f, 0.0f, 0.0f, 0.0f);
14295 ds = get_depth_stencil(device);
14296 memset(&surface_desc, 0, sizeof(surface_desc));
14297 surface_desc.dwSize = sizeof(surface_desc);
14298 hr = IDirectDrawSurface_GetSurfaceDesc(ds, &surface_desc);
14299 z_fmt = surface_desc.ddpfPixelFormat;
14301 for (i = 0; i < ARRAY_SIZE(rt_sizes); ++i)
14303 winetest_push_context("Size %ux%u", rt_sizes[i].x, rt_sizes[i].y);
14305 if (i)
14307 memset(&surface_desc, 0, sizeof(surface_desc));
14308 surface_desc.dwSize = sizeof(surface_desc);
14309 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
14310 surface_desc.dwWidth = rt_sizes[i].x;
14311 surface_desc.dwHeight = rt_sizes[i].y;
14312 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
14313 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &rt, NULL);
14314 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14316 surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
14317 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
14318 surface_desc.ddpfPixelFormat = z_fmt;
14319 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL);
14320 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14321 hr = IDirectDrawSurface_AddAttachedSurface(rt, ds);
14322 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14324 hr = IDirect3DDevice2_SetRenderTarget(device, rt, 0);
14325 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14327 else
14329 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
14330 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14333 full_viewport = create_viewport(device, 0, 0, rt_sizes[i].x, rt_sizes[i].y);
14334 viewport_set_background(device, full_viewport, black_background);
14336 U1(clear_rect).x1 = U2(clear_rect).y1 = 0;
14337 U3(clear_rect).x2 = rt_sizes[i].x;
14338 U4(clear_rect).y2 = rt_sizes[i].y;
14340 for (j = 0; j < ARRAY_SIZE(tests); ++j)
14342 winetest_push_context("%s", tests[j].message);
14344 expected_failure = tests[j].vp.dwX + tests[j].vp.dwWidth > rt_sizes[i].x
14345 || tests[j].vp.dwY + tests[j].vp.dwHeight > rt_sizes[i].y;
14347 hr = IDirect3DViewport2_Clear(full_viewport, 1, &clear_rect, D3DCLEAR_TARGET);
14348 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14350 hr = IDirect3D2_CreateViewport(d3d, &viewport, NULL);
14351 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14352 hr = IDirect3DViewport2_SetViewport2(viewport, NULL);
14353 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
14354 memset(&vp, 0, sizeof(vp));
14355 vp.dwSize = sizeof(vp);
14356 vp.dwX = tests[j].vp.dwX;
14357 vp.dwY = tests[j].vp.dwY;
14358 vp.dwWidth = tests[j].vp.dwWidth;
14359 vp.dwHeight = tests[j].vp.dwHeight;
14360 vp.dvScaleX = tests[j].vp.dwWidth / 2.0f;
14361 vp.dvScaleY = tests[j].vp.dwHeight / 2.0f;
14362 vp.dvMinZ = 0.0f;
14363 vp.dvMaxZ = 1.0f;
14364 hr = IDirect3DViewport2_SetViewport(viewport, &vp);
14365 ok(hr == D3DERR_VIEWPORTHASNODEVICE, "Got unexpected hr %#lx.\n", hr);
14366 hr = IDirect3DDevice2_AddViewport(device, viewport);
14367 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14368 hr = IDirect3DViewport2_SetViewport(viewport, &vp);
14369 ok(hr == (expected_failure ? E_INVALIDARG : DD_OK), "Got unexpected hr %#lx.\n", hr);
14371 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
14372 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14373 if (expected_failure)
14375 destroy_viewport(device, viewport);
14376 winetest_pop_context();
14377 continue;
14380 hr = IDirect3DDevice2_BeginScene(device);
14381 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14382 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad, 4, 0);
14383 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14384 hr = IDirect3DDevice2_EndScene(device);
14385 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14387 check_rect(rt, tests[j].expected_rect);
14389 destroy_viewport(device, viewport);
14390 winetest_pop_context();
14393 destroy_viewport(device, full_viewport);
14395 hr = IDirectDrawSurface_DeleteAttachedSurface(rt, 0, ds);
14396 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx (i %u).\n", hr, i);
14397 IDirectDrawSurface_Release(ds);
14399 IDirectDrawSurface_Release(rt);
14401 winetest_pop_context();
14404 destroy_material(black_background);
14405 refcount = IDirect3DDevice2_Release(device);
14406 ok(!refcount, "Device has %lu references left.\n", refcount);
14407 IDirect3D2_Release(d3d);
14408 IDirectDraw2_Release(ddraw);
14409 DestroyWindow(window);
14412 static void test_find_device(void)
14414 D3DFINDDEVICESEARCH search = {0};
14415 D3DFINDDEVICERESULT result = {0};
14416 IDirect3DDevice2 *device;
14417 IDirectDraw2 *ddraw;
14418 IDirect3D2 *d3d;
14419 unsigned int i;
14420 HWND window;
14421 HRESULT hr;
14423 struct
14425 DWORD size;
14426 GUID guid;
14427 D3DDEVICEDESC_V1 hw_desc;
14428 D3DDEVICEDESC_V1 sw_desc;
14429 } result_v1;
14431 struct
14433 DWORD size;
14434 GUID guid;
14435 D3DDEVICEDESC_V2 hw_desc;
14436 D3DDEVICEDESC_V2 sw_desc;
14437 } result_v2;
14439 static const struct
14441 const GUID *guid;
14442 HRESULT hr;
14444 tests[] =
14446 {&IID_IDirect3D, DDERR_NOTFOUND},
14447 {&IID_IDirect3DRampDevice, D3D_OK},
14448 {&IID_IDirect3DRGBDevice, D3D_OK},
14449 {&IID_IDirect3DMMXDevice, D3D_OK},
14450 {&IID_IDirect3DRefDevice, DDERR_NOTFOUND},
14451 {&IID_IDirect3DTnLHalDevice, DDERR_NOTFOUND},
14452 {&IID_IDirect3DNullDevice, DDERR_NOTFOUND},
14455 ddraw = create_ddraw();
14456 ok(!!ddraw, "Failed to create a ddraw object.\n");
14458 if (FAILED(IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d)))
14460 skip("D3D interface is not available, skipping test.\n");
14461 IDirectDraw2_Release(ddraw);
14462 return;
14465 result.dwSize = sizeof(result);
14466 search.dwSize = sizeof(search);
14467 hr = IDirect3D2_FindDevice(d3d, NULL, NULL);
14468 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14469 hr = IDirect3D2_FindDevice(d3d, NULL, &result);
14470 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14471 hr = IDirect3D2_FindDevice(d3d, &search, NULL);
14472 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14473 hr = IDirect3D2_FindDevice(d3d, &search, &result);
14474 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14475 ok(result.dwSize == sizeof(result), "Got unexpected result size %lu.\n", result.dwSize);
14476 ok(result.ddHwDesc.dwSize == sizeof(result_v2.hw_desc),
14477 "Got unexpected HW desc size %lu.\n", result.ddHwDesc.dwSize);
14478 ok(result.ddSwDesc.dwSize == sizeof(result_v2.sw_desc),
14479 "Got unexpected SW desc size %lu.\n", result.ddSwDesc.dwSize);
14481 memset(&search, 0, sizeof(search));
14482 memset(&result, 0, sizeof(result));
14483 hr = IDirect3D2_FindDevice(d3d, &search, &result);
14484 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14486 search.dwSize = sizeof(search) + 1;
14487 result.dwSize = sizeof(result) + 1;
14488 hr = IDirect3D2_FindDevice(d3d, &search, &result);
14489 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14491 search.dwSize = sizeof(search);
14493 memset(&result_v1, 0, sizeof(result_v1));
14494 result_v1.size = sizeof(result_v1);
14495 hr = IDirect3D2_FindDevice(d3d, &search, (D3DFINDDEVICERESULT *)&result_v1);
14496 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14497 ok(result_v1.hw_desc.dwSize == sizeof(result_v2.hw_desc),
14498 "Got unexpected HW desc size %lu.\n", result_v1.hw_desc.dwSize);
14499 ok(result_v1.sw_desc.dwSize == sizeof(result_v2.sw_desc),
14500 "Got unexpected SW desc size %lu.\n", result_v1.sw_desc.dwSize);
14502 memset(&result_v2, 0, sizeof(result_v2));
14503 result_v2.size = sizeof(result_v2);
14504 hr = IDirect3D2_FindDevice(d3d, &search, (D3DFINDDEVICERESULT *)&result_v2);
14505 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14506 ok(result_v2.hw_desc.dwSize == sizeof(result_v2.hw_desc),
14507 "Got unexpected HW desc size %lu.\n", result_v2.hw_desc.dwSize);
14508 ok(result_v2.sw_desc.dwSize == sizeof(result_v2.sw_desc),
14509 "Got unexpected SW desc size %lu.\n", result_v2.sw_desc.dwSize);
14511 for (i = 0; i < ARRAY_SIZE(tests); ++i)
14513 memset(&search, 0, sizeof(search));
14514 search.dwSize = sizeof(search);
14515 search.dwFlags = D3DFDS_GUID;
14516 search.guid = *tests[i].guid;
14518 memset(&result, 0, sizeof(result));
14519 result.dwSize = sizeof(result);
14521 hr = IDirect3D2_FindDevice(d3d, &search, &result);
14522 ok(hr == tests[i].hr, "Test %u: Got unexpected hr %#lx.\n", i, hr);
14523 ok(result.dwSize == sizeof(result), "Test %u: Got unexpected result size %lu.\n", i, result.dwSize);
14524 if (SUCCEEDED(hr))
14526 ok(result.ddHwDesc.dwSize == sizeof(result_v2.hw_desc),
14527 "Test %u: Got unexpected HW desc size %lu.\n", i, result.ddHwDesc.dwSize);
14528 ok(result.ddSwDesc.dwSize == sizeof(result_v2.sw_desc),
14529 "Test %u: Got unexpected SW desc size %lu.\n", i, result.ddSwDesc.dwSize);
14531 else
14533 ok(!result.ddHwDesc.dwSize,
14534 "Test %u: Got unexpected HW desc size %lu.\n", i, result.ddHwDesc.dwSize);
14535 ok(!result.ddSwDesc.dwSize,
14536 "Test %u: Got unexpected SW desc size %lu.\n", i, result.ddSwDesc.dwSize);
14540 /* The HAL device can only be enumerated if hardware acceleration is present. */
14541 search.dwSize = sizeof(search);
14542 search.dwFlags = D3DFDS_GUID;
14543 search.guid = IID_IDirect3DHALDevice;
14544 result.dwSize = sizeof(result);
14545 hr = IDirect3D2_FindDevice(d3d, &search, &result);
14547 window = create_window();
14548 device = create_device(ddraw, window, DDSCL_NORMAL);
14549 if (hr == D3D_OK)
14550 ok(!!device, "Failed to create a 3D device.\n");
14551 else
14552 ok(!device, "Succeeded to create a 3D device.\n");
14553 if (device)
14554 IDirect3DDevice2_Release(device);
14555 DestroyWindow(window);
14557 /* Curiously the colour model criteria seem to be ignored. */
14558 search.dwSize = sizeof(search);
14559 search.dwFlags = D3DFDS_COLORMODEL;
14560 search.dcmColorModel = 0xdeadbeef;
14561 result.dwSize = sizeof(result);
14562 hr = IDirect3D2_FindDevice(d3d, &search, &result);
14563 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14565 IDirect3D2_Release(d3d);
14566 IDirectDraw2_Release(ddraw);
14569 static IDirectDraw2 *killfocus_ddraw;
14570 static IDirectDrawSurface *killfocus_surface;
14572 static LRESULT CALLBACK killfocus_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
14574 ULONG ref;
14576 if (message == WM_KILLFOCUS)
14578 ref = IDirectDrawSurface_Release(killfocus_surface);
14579 ok(!ref, "Unexpected surface refcount %lu.\n", ref);
14580 ref = IDirectDraw2_Release(killfocus_ddraw);
14581 ok(!ref, "Unexpected ddraw refcount %lu.\n", ref);
14582 killfocus_ddraw = NULL;
14585 return DefWindowProcA(window, message, wparam, lparam);
14588 static void test_killfocus(void)
14590 DDSURFACEDESC surface_desc;
14591 HRESULT hr;
14592 HWND window;
14593 WNDCLASSA wc = {0};
14595 wc.lpfnWndProc = killfocus_proc;
14596 wc.lpszClassName = "ddraw_killfocus_wndproc_wc";
14597 ok(RegisterClassA(&wc), "Failed to register window class.\n");
14599 window = CreateWindowA("ddraw_killfocus_wndproc_wc", "d3d7_test", WS_OVERLAPPEDWINDOW,
14600 0, 0, 640, 480, 0, 0, 0, 0);
14602 killfocus_ddraw = create_ddraw();
14603 ok(!!killfocus_ddraw, "Failed to create a ddraw object.\n");
14605 hr = IDirectDraw2_SetCooperativeLevel(killfocus_ddraw, window, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
14606 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
14608 memset(&surface_desc, 0, sizeof(surface_desc));
14609 surface_desc.dwSize = sizeof(surface_desc);
14610 surface_desc.dwFlags = DDSD_CAPS;
14611 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
14612 hr = IDirectDraw2_CreateSurface(killfocus_ddraw, &surface_desc, &killfocus_surface, NULL);
14613 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
14615 SetForegroundWindow(GetDesktopWindow());
14616 ok(!killfocus_ddraw, "WM_KILLFOCUS was not received.\n");
14618 DestroyWindow(window);
14619 UnregisterClassA("ddraw_killfocus_wndproc_wc", GetModuleHandleA(NULL));
14622 static void test_gdi_surface(void)
14624 IDirectDrawSurface *primary, *backbuffer, *gdi_surface;
14625 DDSCAPS caps = {DDSCAPS_BACKBUFFER};
14626 DDSURFACEDESC surface_desc;
14627 IDirectDraw2 *ddraw;
14628 ULONG refcount;
14629 HWND window;
14630 HRESULT hr;
14632 window = create_window();
14633 ddraw = create_ddraw();
14634 ok(!!ddraw, "Failed to create a ddraw object.\n");
14635 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
14636 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14638 /* Retrieving the GDI surface requires a primary surface to exist. */
14639 gdi_surface = (void *)0xc0dec0de;
14640 hr = IDirectDraw2_GetGDISurface(ddraw, &gdi_surface);
14641 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
14642 ok(!gdi_surface, "Got unexpected surface %p.\n", gdi_surface);
14644 hr = IDirectDraw2_FlipToGDISurface(ddraw);
14645 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
14647 memset(&surface_desc, 0, sizeof(surface_desc));
14648 surface_desc.dwSize = sizeof(surface_desc);
14649 surface_desc.dwFlags = DDSD_CAPS;
14650 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
14651 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
14652 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14654 hr = IDirectDraw2_GetGDISurface(ddraw, &gdi_surface);
14655 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14656 ok(gdi_surface == primary, "Got unexpected surface %p, expected %p.\n", gdi_surface, primary);
14657 IDirectDrawSurface_Release(gdi_surface);
14659 /* Flipping to the GDI surface requires the primary surface to be
14660 * flippable. */
14661 hr = IDirectDraw2_FlipToGDISurface(ddraw);
14662 ok(hr == DDERR_NOTFLIPPABLE, "Got unexpected hr %#lx.\n", hr);
14664 IDirectDrawSurface_Release(primary);
14666 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
14667 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14669 memset(&surface_desc, 0, sizeof(surface_desc));
14670 surface_desc.dwSize = sizeof(surface_desc);
14671 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
14672 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
14673 U5(surface_desc).dwBackBufferCount = 1;
14674 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL);
14675 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14676 hr = IDirectDrawSurface_GetAttachedSurface(primary, &caps, &backbuffer);
14677 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14678 ok(backbuffer != primary, "Got unexpected backbuffer %p.\n", backbuffer);
14680 hr = IDirectDraw2_GetGDISurface(ddraw, &gdi_surface);
14681 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14682 ok(gdi_surface == primary, "Got unexpected surface %p, expected %p.\n", gdi_surface, primary);
14683 IDirectDrawSurface_Release(gdi_surface);
14685 hr = IDirectDrawSurface_Flip(primary, NULL, DDFLIP_WAIT);
14686 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14687 hr = IDirectDraw2_GetGDISurface(ddraw, &gdi_surface);
14688 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14689 ok(gdi_surface == backbuffer || broken(gdi_surface == primary),
14690 "Got unexpected surface %p, expected %p.\n", gdi_surface, backbuffer);
14691 IDirectDrawSurface_Release(gdi_surface);
14693 hr = IDirectDraw2_FlipToGDISurface(ddraw);
14694 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14696 hr = IDirectDraw2_GetGDISurface(ddraw, &gdi_surface);
14697 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14698 ok(gdi_surface == primary, "Got unexpected surface %p, expected %p.\n", gdi_surface, primary);
14699 IDirectDrawSurface_Release(gdi_surface);
14701 hr = IDirectDraw2_FlipToGDISurface(ddraw);
14702 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14704 IDirectDrawSurface_Release(backbuffer);
14705 IDirectDrawSurface_Release(primary);
14707 refcount = IDirectDraw2_Release(ddraw);
14708 ok(!refcount, "%lu references left.\n", refcount);
14709 DestroyWindow(window);
14712 static void test_alphatest(void)
14714 #define ALPHATEST_PASSED 0x0000ff00
14715 #define ALPHATEST_FAILED 0x00ff0000
14716 D3DRECT rect_full = {{0}, {0}, {640}, {480}};
14717 IDirect3DMaterial2 *blue, *failed;
14718 IDirect3DViewport2 *viewport;
14719 IDirect3DDevice2 *device;
14720 IDirectDrawSurface *rt;
14721 unsigned int color, i;
14722 IDirectDraw2 *ddraw;
14723 ULONG refcount;
14724 HWND window;
14725 DWORD value;
14726 HRESULT hr;
14728 static const struct
14730 D3DCMPFUNC func;
14731 unsigned int color_less, color_equal, color_greater;
14733 test_data[] =
14735 {D3DCMP_NEVER, ALPHATEST_FAILED, ALPHATEST_FAILED, ALPHATEST_FAILED},
14736 {D3DCMP_LESS, ALPHATEST_PASSED, ALPHATEST_FAILED, ALPHATEST_FAILED},
14737 {D3DCMP_EQUAL, ALPHATEST_FAILED, ALPHATEST_PASSED, ALPHATEST_FAILED},
14738 {D3DCMP_LESSEQUAL, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_FAILED},
14739 {D3DCMP_GREATER, ALPHATEST_FAILED, ALPHATEST_FAILED, ALPHATEST_PASSED},
14740 {D3DCMP_NOTEQUAL, ALPHATEST_PASSED, ALPHATEST_FAILED, ALPHATEST_PASSED},
14741 {D3DCMP_GREATEREQUAL, ALPHATEST_FAILED, ALPHATEST_PASSED, ALPHATEST_PASSED},
14742 {D3DCMP_ALWAYS, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED},
14744 static D3DLVERTEX quad[] =
14746 {{-1.0f}, {-1.0f}, {0.1f}, 0, {ALPHATEST_PASSED | 0x80000000}},
14747 {{-1.0f}, { 1.0f}, {0.1f}, 0, {ALPHATEST_PASSED | 0x80000000}},
14748 {{ 1.0f}, {-1.0f}, {0.1f}, 0, {ALPHATEST_PASSED | 0x80000000}},
14749 {{ 1.0f}, { 1.0f}, {0.1f}, 0, {ALPHATEST_PASSED | 0x80000000}},
14752 window = create_window();
14753 ddraw = create_ddraw();
14754 ok(!!ddraw, "Failed to create a ddraw object.\n");
14755 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
14757 skip("Failed to create a 3D device.\n");
14758 IDirectDraw2_Release(ddraw);
14759 DestroyWindow(window);
14760 return;
14762 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
14763 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14765 blue = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
14766 failed = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
14768 viewport = create_viewport(device, 0, 0, 640, 480);
14769 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
14770 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14772 viewport_set_background(device, viewport, blue);
14773 hr = IDirect3DViewport2_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
14774 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14775 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
14776 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14777 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, FALSE);
14778 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14779 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHATESTENABLE, TRUE);
14780 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14782 viewport_set_background(device, viewport, failed);
14783 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
14785 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHAFUNC, test_data[i].func);
14786 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14788 hr = IDirect3DViewport2_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
14789 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14790 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHAREF, 0x70);
14791 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14792 hr = IDirect3DDevice2_BeginScene(device);
14793 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14794 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP,
14795 D3DVT_LVERTEX, quad, ARRAY_SIZE(quad), 0);
14796 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14797 hr = IDirect3DDevice2_EndScene(device);
14798 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14799 color = get_surface_color(rt, 320, 240);
14800 ok(compare_color(color, test_data[i].color_greater, 0),
14801 "Alphatest failed, color 0x%08x, expected 0x%08x, alpha > ref, func %u.\n",
14802 color, test_data[i].color_greater, test_data[i].func);
14804 hr = IDirect3DViewport2_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
14805 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14806 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHAREF, 0xff70);
14807 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14808 hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ALPHAREF, &value);
14809 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14810 ok(value == 0xff70, "Got unexpected value %#lx.\n", value);
14811 hr = IDirect3DDevice2_BeginScene(device);
14812 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14813 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP,
14814 D3DVT_LVERTEX, quad, ARRAY_SIZE(quad), 0);
14815 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14816 hr = IDirect3DDevice2_EndScene(device);
14817 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14818 color = get_surface_color(rt, 320, 240);
14819 ok(compare_color(color, test_data[i].color_greater, 0),
14820 "Alphatest failed, color 0x%08x, expected 0x%08x, alpha > ref, func %u.\n",
14821 color, test_data[i].color_greater, test_data[i].func);
14824 destroy_viewport(device, viewport);
14825 destroy_material(failed);
14826 destroy_material(blue);
14827 IDirectDrawSurface_Release(rt);
14828 refcount = IDirect3DDevice2_Release(device);
14829 ok(!refcount, "Device has %lu references left.\n", refcount);
14830 refcount = IDirectDraw2_Release(ddraw);
14831 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
14832 DestroyWindow(window);
14835 static void test_clipper_refcount(void)
14837 IDirectDrawSurface *surface;
14838 IDirectDrawClipper *clipper, *clipper2;
14839 DDSURFACEDESC surface_desc;
14840 IDirectDraw2 *ddraw;
14841 IDirectDraw *ddraw1;
14842 ULONG refcount;
14843 HWND window;
14844 HRESULT hr;
14845 BOOL changed;
14846 const IDirectDrawClipperVtbl *orig_vtbl;
14848 window = create_window();
14849 ddraw = create_ddraw();
14850 ok(!!ddraw, "Failed to create a ddraw object.\n");
14851 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
14852 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14854 memset(&surface_desc, 0, sizeof(surface_desc));
14855 surface_desc.dwSize = sizeof(surface_desc);
14856 surface_desc.dwFlags = DDSD_CAPS;
14857 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
14858 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
14859 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14861 hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL);
14862 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
14863 refcount = get_refcount((IUnknown *)clipper);
14864 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
14866 /* Show that clipper validation doesn't somehow happen through per-clipper vtable
14867 * pointers. */
14868 hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper2, NULL);
14869 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
14870 ok(clipper->lpVtbl == clipper2->lpVtbl, "Got different clipper vtables %p and %p.\n",
14871 clipper->lpVtbl, clipper2->lpVtbl);
14872 orig_vtbl = clipper->lpVtbl;
14873 IDirectDrawClipper_Release(clipper2);
14875 /* Surfaces hold a reference to clippers. No surprises there. */
14876 hr = IDirectDrawSurface_SetClipper(surface, clipper);
14877 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
14878 refcount = get_refcount((IUnknown *)clipper);
14879 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
14881 hr = IDirectDrawSurface_GetClipper(surface, &clipper2);
14882 ok(SUCCEEDED(hr), "Failed to get clipper, hr %#lx.\n", hr);
14883 ok(clipper == clipper2, "Got clipper %p, expected %p.\n", clipper2, clipper);
14884 refcount = IDirectDrawClipper_Release(clipper2);
14885 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
14887 hr = IDirectDrawSurface_SetClipper(surface, NULL);
14888 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
14889 refcount = get_refcount((IUnknown *)clipper);
14890 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
14892 hr = IDirectDrawSurface_SetClipper(surface, clipper);
14893 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
14894 refcount = get_refcount((IUnknown *)clipper);
14895 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
14897 refcount = IDirectDrawSurface_Release(surface);
14898 ok(!refcount, "%lu references left.\n", refcount);
14899 refcount = get_refcount((IUnknown *)clipper);
14900 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
14902 /* SetClipper with an invalid pointer crashes. */
14904 /* Clipper methods work with a broken vtable, with the exception of Release. */
14905 clipper->lpVtbl = (void *)0xdeadbeef;
14906 refcount = orig_vtbl->AddRef(clipper);
14907 todo_wine ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
14908 refcount = orig_vtbl->Release(clipper);
14909 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
14911 clipper->lpVtbl = orig_vtbl;
14912 refcount = orig_vtbl->Release(clipper);
14913 todo_wine ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
14915 /* Fix the refcount difference because Wine did not increase the ref in the
14916 * AddRef call above. */
14917 if (refcount)
14919 refcount = IDirectDrawClipper_Release(clipper);
14920 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
14923 /* Steal the reference and see what happens - releasing the surface works fine.
14924 * The clipper is destroyed and not kept alive by a hidden refcount - trying to
14925 * release it after the GetClipper call is likely to crash, and certain to crash
14926 * if we allocate and zero as much heap memory as we can get. */
14927 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
14928 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14929 hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL);
14930 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
14931 hr = IDirectDrawSurface_SetClipper(surface, clipper);
14932 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
14934 IDirectDrawClipper_Release(clipper);
14935 IDirectDrawClipper_Release(clipper);
14937 if (0)
14939 /* Disabled because it causes heap corruption (HeapValidate fails and random
14940 * hangs in a later HeapFree) on Windows on one of my Machines: MacbookPro 10,1
14941 * running Windows 10 18363.535 and Nvidia driver 425.31. Driver version 441.66
14942 * is affected too. Some testbot machines have crashes directly in GetClipper
14943 * or proceed with a corrupted heap too.
14945 * The same Windows and driver versions run the test without heap corruption on
14946 * a Geforce 1060 GTX card. I have not seen the problem on AMD GPUs either. */
14947 hr = IDirectDrawSurface_GetClipper(surface, &clipper2);
14948 ok(SUCCEEDED(hr), "Failed to get clipper, hr %#lx.\n", hr);
14949 ok(clipper == clipper2, "Got clipper %p, expected %p.\n", clipper2, clipper);
14952 /* Show that invoking the Release method does not crash, but don't get the
14953 * vtable through the clipper pointer because it is no longer pointing to
14954 * valid memory. */
14955 refcount = orig_vtbl->Release(clipper);
14956 ok(!refcount, "%lu references left.\n", refcount);
14958 refcount = IDirectDrawSurface_Release(surface);
14959 ok(!refcount, "%lu references left.\n", refcount);
14961 /* It looks like the protection against invalid thispointers is part of
14962 * the IDirectDrawClipper method implementation, not IDirectDrawSurface. */
14963 clipper = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0x1000);
14964 ok(!!clipper, "failed to allocate memory\n");
14966 /* Assigning the vtable to our fake clipper does NOT make a difference on
14967 * native - there is a different member of the clipper implementation struct
14968 * that is used to determine if a clipper is valid. */
14969 clipper->lpVtbl = orig_vtbl;
14971 refcount = orig_vtbl->AddRef(clipper);
14972 todo_wine ok(!refcount, "Got refcount %lu.\n", refcount);
14973 refcount = orig_vtbl->AddRef((IDirectDrawClipper *)(ULONG_PTR)0xdeadbeef);
14974 ok(!refcount, "Got refcount %lu.\n", refcount);
14976 changed = 0x1234;
14977 hr = orig_vtbl->IsClipListChanged(clipper, &changed);
14978 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14979 todo_wine ok(changed == 0x1234, "'changed' changed: %x.\n", changed);
14981 changed = 0x1234;
14982 hr = orig_vtbl->IsClipListChanged((IDirectDrawClipper *)(ULONG_PTR)0xdeadbeef, &changed);
14983 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14984 ok(changed == 0x1234, "'changed' changed: %x.\n", changed);
14986 /* Nope, we can't initialize our fake clipper. */
14987 hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirectDraw, (void **)&ddraw1);
14988 ok(SUCCEEDED(hr), "Failed to get ddraw1 interface, hr %#lx.\n", hr);
14990 hr = orig_vtbl->Initialize(clipper, ddraw1, 0);
14991 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14993 IDirectDraw_Release(ddraw1);
14995 HeapFree(GetProcessHeap(), 0, clipper);
14997 refcount = IDirectDraw2_Release(ddraw);
14998 ok(!refcount, "%lu references left.\n", refcount);
14999 DestroyWindow(window);
15002 static void test_caps(void)
15004 DWORD caps_never, caps_always, caps_hal;
15005 DDCAPS hal_caps, hel_caps;
15006 IDirectDraw2 *ddraw;
15007 IDirectDraw *ddraw1;
15008 HRESULT hr;
15009 BOOL no3d;
15011 caps_never = DDSCAPS_RESERVED1
15012 | DDSCAPS_ALPHA
15013 | DDSCAPS_PRIMARYSURFACELEFT
15014 | DDSCAPS_SYSTEMMEMORY
15015 | DDSCAPS_VISIBLE
15016 | DDSCAPS_WRITEONLY
15017 | DDSCAPS_LIVEVIDEO
15018 | DDSCAPS_HWCODEC
15019 | DDSCAPS_MODEX
15020 | DDSCAPS_RESERVED2
15021 | 0x01000000u
15022 | 0x02000000u
15023 | DDSCAPS_ALLOCONLOAD
15024 | DDSCAPS_VIDEOPORT
15025 | DDSCAPS_STANDARDVGAMODE
15026 | DDSCAPS_OPTIMIZED;
15028 caps_always = DDSCAPS_FLIP
15029 | DDSCAPS_OFFSCREENPLAIN
15030 | DDSCAPS_PRIMARYSURFACE
15031 | DDSCAPS_TEXTURE
15032 | DDSCAPS_ZBUFFER
15033 | DDSCAPS_MIPMAP;
15035 caps_hal = DDSCAPS_BACKBUFFER
15036 | DDSCAPS_COMPLEX
15037 | DDSCAPS_FRONTBUFFER
15038 | DDSCAPS_3DDEVICE
15039 | DDSCAPS_VIDEOMEMORY
15040 | DDSCAPS_LOCALVIDMEM
15041 | DDSCAPS_NONLOCALVIDMEM;
15043 ddraw = create_ddraw();
15044 ok(!!ddraw, "Failed to create a ddraw object.\n");
15046 memset(&hal_caps, 0, sizeof(hal_caps));
15047 memset(&hel_caps, 0, sizeof(hel_caps));
15048 hal_caps.dwSize = sizeof(hal_caps);
15049 hel_caps.dwSize = sizeof(hel_caps);
15050 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, &hel_caps);
15051 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15052 ok(hal_caps.ddsOldCaps.dwCaps == hal_caps.ddsCaps.dwCaps,
15053 "Got unexpected caps %#lx, expected %#lx.\n",
15054 hal_caps.ddsOldCaps.dwCaps, hal_caps.ddsCaps.dwCaps);
15055 ok(hel_caps.ddsOldCaps.dwCaps == hel_caps.ddsCaps.dwCaps,
15056 "Got unexpected caps %#lx, expected %#lx.\n",
15057 hel_caps.ddsOldCaps.dwCaps, hel_caps.ddsCaps.dwCaps);
15059 no3d = !(hal_caps.ddsCaps.dwCaps & DDSCAPS_3DDEVICE);
15060 if (hal_caps.ddsCaps.dwCaps)
15062 ok(!(hal_caps.ddsCaps.dwCaps & caps_never), "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
15063 ok(!(~hal_caps.ddsCaps.dwCaps & caps_always), "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
15064 todo_wine_if(no3d) ok(!(~hal_caps.ddsCaps.dwCaps & caps_hal),
15065 "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
15067 ok(!(hel_caps.ddsCaps.dwCaps & caps_never), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
15068 ok(!(~hel_caps.ddsCaps.dwCaps & caps_always), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
15069 todo_wine_if(!no3d) ok(!(hel_caps.ddsCaps.dwCaps & caps_hal),
15070 "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
15072 IDirectDraw2_Release(ddraw);
15074 if (hal_caps.ddsCaps.dwCaps)
15076 hr = DirectDrawCreate((GUID *)DDCREATE_HARDWAREONLY, &ddraw1, NULL);
15077 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15078 hr = IDirectDraw_QueryInterface(ddraw1, &IID_IDirectDraw2, (void **)&ddraw);
15079 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15080 IDirectDraw_Release(ddraw1);
15082 memset(&hal_caps, 0, sizeof(hal_caps));
15083 memset(&hel_caps, 0, sizeof(hel_caps));
15084 hal_caps.dwSize = sizeof(hal_caps);
15085 hel_caps.dwSize = sizeof(hel_caps);
15086 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, &hel_caps);
15087 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15088 ok(hal_caps.ddsOldCaps.dwCaps == hal_caps.ddsCaps.dwCaps,
15089 "Got unexpected caps %#lx, expected %#lx.\n",
15090 hal_caps.ddsOldCaps.dwCaps, hal_caps.ddsCaps.dwCaps);
15091 ok(hel_caps.ddsOldCaps.dwCaps == hel_caps.ddsCaps.dwCaps,
15092 "Got unexpected caps %#lx, expected %#lx.\n",
15093 hel_caps.ddsOldCaps.dwCaps, hel_caps.ddsCaps.dwCaps);
15095 ok(!(hal_caps.ddsCaps.dwCaps & caps_never), "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
15096 ok(!(~hal_caps.ddsCaps.dwCaps & caps_always), "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
15097 todo_wine_if(no3d) ok(!(~hal_caps.ddsCaps.dwCaps & caps_hal),
15098 "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
15099 if (is_ddraw64)
15101 ok(!(hel_caps.ddsCaps.dwCaps & caps_never), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
15102 ok(!(~hel_caps.ddsCaps.dwCaps & caps_always), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
15103 todo_wine_if(!no3d) ok(!(hel_caps.ddsCaps.dwCaps & caps_hal),
15104 "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
15106 else
15108 todo_wine ok(!hel_caps.ddsCaps.dwCaps, "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
15111 IDirectDraw2_Release(ddraw);
15114 hr = DirectDrawCreate((GUID *)DDCREATE_EMULATIONONLY, &ddraw1, NULL);
15115 ok(hr == DD_OK || (is_ddraw64 && hr == E_FAIL), "Got unexpected hr %#lx.\n", hr);
15116 if (SUCCEEDED(hr))
15118 hr = IDirectDraw_QueryInterface(ddraw1, &IID_IDirectDraw2, (void **)&ddraw);
15119 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15120 IDirectDraw_Release(ddraw1);
15122 memset(&hal_caps, 0, sizeof(hal_caps));
15123 memset(&hel_caps, 0, sizeof(hel_caps));
15124 hal_caps.dwSize = sizeof(hal_caps);
15125 hel_caps.dwSize = sizeof(hel_caps);
15126 hr = IDirectDraw2_GetCaps(ddraw, &hal_caps, &hel_caps);
15127 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15128 ok(hal_caps.ddsOldCaps.dwCaps == hal_caps.ddsCaps.dwCaps,
15129 "Got unexpected caps %#lx, expected %#lx.\n",
15130 hal_caps.ddsOldCaps.dwCaps, hal_caps.ddsCaps.dwCaps);
15131 ok(hel_caps.ddsOldCaps.dwCaps == hel_caps.ddsCaps.dwCaps,
15132 "Got unexpected caps %#lx, expected %#lx.\n",
15133 hel_caps.ddsOldCaps.dwCaps, hel_caps.ddsCaps.dwCaps);
15135 todo_wine ok(!hal_caps.ddsCaps.dwCaps, "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
15136 ok(!(hel_caps.ddsCaps.dwCaps & caps_never), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
15137 ok(!(~hel_caps.ddsCaps.dwCaps & caps_always), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
15138 todo_wine_if(!no3d) ok(!(hel_caps.ddsCaps.dwCaps & caps_hal),
15139 "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
15141 IDirectDraw2_Release(ddraw);
15145 static void test_d32_support(void)
15147 IDirectDrawSurface *surface;
15148 DDSURFACEDESC surface_desc;
15149 IDirectDraw2 *ddraw;
15150 ULONG refcount;
15151 HWND window;
15152 HRESULT hr;
15154 window = create_window();
15155 ddraw = create_ddraw();
15156 ok(!!ddraw, "Failed to create a ddraw object.\n");
15157 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
15158 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15160 memset(&surface_desc, 0, sizeof(surface_desc));
15161 surface_desc.dwSize = sizeof(surface_desc);
15162 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
15163 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
15164 U2(surface_desc).dwZBufferBitDepth = 32;
15165 surface_desc.dwWidth = 64;
15166 surface_desc.dwHeight = 64;
15167 hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
15168 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15170 memset(&surface_desc, 0, sizeof(surface_desc));
15171 surface_desc.dwSize = sizeof(surface_desc);
15172 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
15173 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15174 ok((surface_desc.dwFlags & DDSD_ZBUFFERBITDEPTH), "Got unexpected flags %#lx.\n", surface_desc.dwFlags);
15175 ok(U2(surface_desc).dwZBufferBitDepth == 32,
15176 "Got unexpected dwZBufferBitDepth %lu.\n", U2(surface_desc).dwZBufferBitDepth);
15177 ok(!(surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY),
15178 "Got unexpected surface caps %#lx.\n", surface_desc.ddsCaps.dwCaps);
15179 IDirectDrawSurface_Release(surface);
15181 refcount = IDirectDraw2_Release(ddraw);
15182 ok(!refcount, "%lu references left.\n", refcount);
15183 DestroyWindow(window);
15186 struct find_different_mode_param
15188 unsigned int old_width;
15189 unsigned int old_height;
15190 unsigned int old_frequency;
15191 unsigned int new_width;
15192 unsigned int new_height;
15193 unsigned int new_frequency;
15194 unsigned int new_bpp;
15197 static HRESULT CALLBACK find_different_mode_callback(DDSURFACEDESC *surface_desc, void *context)
15199 struct find_different_mode_param *param = context;
15201 if (U1(U4(*surface_desc).ddpfPixelFormat).dwRGBBitCount != registry_mode.dmBitsPerPel)
15202 return DDENUMRET_OK;
15204 /* See comment in ddraw7 about the frequency. */
15205 if (surface_desc->dwWidth != param->old_width && surface_desc->dwHeight != param->old_height &&
15206 (!compare_uint(surface_desc->dwRefreshRate, param->old_frequency, 1) || !param->old_frequency))
15208 param->new_width = surface_desc->dwWidth;
15209 param->new_height = surface_desc->dwHeight;
15210 param->new_frequency = surface_desc->dwRefreshRate;
15211 param->new_bpp = surface_desc->ddpfPixelFormat.dwRGBBitCount;
15212 return DDENUMRET_CANCEL;
15215 return DDENUMRET_OK;
15218 static void test_cursor_clipping(void)
15220 struct find_different_mode_param param;
15221 DDSURFACEDESC surface_desc;
15222 RECT rect, clip_rect;
15223 IDirectDraw2 *ddraw;
15224 HWND window;
15225 HRESULT hr;
15226 BOOL ret;
15228 window = create_window();
15229 ok(!!window, "Failed to create a window.\n");
15230 ddraw = create_ddraw();
15231 ok(!!ddraw, "Failed to create a ddraw object.\n");
15233 memset(&surface_desc, 0, sizeof(surface_desc));
15234 surface_desc.dwSize = sizeof(surface_desc);
15235 hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
15236 ok(hr == DD_OK, "GetDisplayMode failed, hr %#lx.\n", hr);
15238 memset(&param, 0, sizeof(param));
15239 param.old_width = surface_desc.dwWidth;
15240 param.old_height = surface_desc.dwHeight;
15241 hr = IDirectDraw2_EnumDisplayModes(ddraw, 0, NULL, &param, find_different_mode_callback);
15242 ok(hr == DD_OK, "EnumDisplayModes failed, hr %#lx.\n", hr);
15243 if (!(param.new_width && param.new_height))
15245 skip("Failed to find a different mode than %ux%u.\n", param.old_width, param.old_height);
15246 goto done;
15249 ret = ClipCursor(NULL);
15250 ok(ret, "ClipCursor failed, error %lu.\n", GetLastError());
15251 get_virtual_rect(&rect);
15252 ret = GetClipCursor(&clip_rect);
15253 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
15254 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
15255 wine_dbgstr_rect(&clip_rect));
15257 /* Set cooperative level to normal */
15258 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
15259 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
15260 flush_events();
15261 get_virtual_rect(&rect);
15262 ret = GetClipCursor(&clip_rect);
15263 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
15264 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
15265 wine_dbgstr_rect(&clip_rect));
15267 hr = set_display_mode(ddraw, param.new_width, param.new_height);
15268 ok(hr == DD_OK || hr == DDERR_UNSUPPORTED, "SetDisplayMode failed, hr %#lx.\n", hr);
15269 if (FAILED(hr))
15271 win_skip("SetDisplayMode failed, hr %#lx.\n", hr);
15272 goto done;
15274 flush_events();
15275 get_virtual_rect(&rect);
15276 ret = GetClipCursor(&clip_rect);
15277 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
15278 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
15279 wine_dbgstr_rect(&clip_rect));
15281 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
15282 ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#lx.\n", hr);
15283 flush_events();
15284 get_virtual_rect(&rect);
15285 ret = GetClipCursor(&clip_rect);
15286 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
15287 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
15288 wine_dbgstr_rect(&clip_rect));
15290 /* Switch to full screen cooperative level */
15291 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
15292 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
15293 flush_events();
15294 SetRect(&rect, 0, 0, param.old_width, param.old_height);
15295 ret = GetClipCursor(&clip_rect);
15296 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
15297 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
15298 wine_dbgstr_rect(&clip_rect));
15300 hr = set_display_mode(ddraw, param.new_width, param.new_height);
15301 ok(hr == DD_OK || hr == DDERR_UNSUPPORTED, "SetDisplayMode failed, hr %#lx.\n", hr);
15302 if (FAILED(hr))
15304 win_skip("SetDisplayMode failed, hr %#lx.\n", hr);
15305 goto done;
15307 flush_events();
15308 SetRect(&rect, 0, 0, param.new_width, param.new_height);
15309 ret = GetClipCursor(&clip_rect);
15310 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
15311 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
15312 wine_dbgstr_rect(&clip_rect));
15314 /* Restore display mode */
15315 hr = IDirectDraw2_RestoreDisplayMode(ddraw);
15316 ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#lx.\n", hr);
15317 flush_events();
15318 SetRect(&rect, 0, 0, param.old_width, param.old_height);
15319 ret = GetClipCursor(&clip_rect);
15320 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
15321 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
15322 wine_dbgstr_rect(&clip_rect));
15324 /* Switch to normal cooperative level */
15325 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
15326 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
15327 flush_events();
15328 get_virtual_rect(&rect);
15329 ret = GetClipCursor(&clip_rect);
15330 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
15331 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
15332 wine_dbgstr_rect(&clip_rect));
15334 done:
15335 IDirectDraw2_Release(ddraw);
15336 DestroyWindow(window);
15339 static BOOL CALLBACK test_window_position_cb(HMONITOR monitor, HDC hdc, RECT *monitor_rect,
15340 LPARAM lparam)
15342 RECT primary_rect, window_rect, new_rect;
15343 IDirectDraw2 *ddraw;
15344 HWND window;
15345 HRESULT hr;
15346 BOOL ret;
15348 ddraw = create_ddraw();
15349 ok(!!ddraw, "Failed to create a ddraw object.\n");
15350 window = CreateWindowA("static", "ddraw_test", WS_POPUP | WS_VISIBLE, monitor_rect->left,
15351 monitor_rect->top, monitor_rect->right - monitor_rect->left,
15352 monitor_rect->bottom - monitor_rect->top, NULL, NULL, NULL, NULL);
15353 ok(!!window, "Failed to create a window.\n");
15354 flush_events();
15356 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
15357 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
15358 flush_events();
15359 ret = GetWindowRect(window, &window_rect);
15360 ok(ret, "GetWindowRect failed, error %lu.\n", GetLastError());
15361 SetRect(&primary_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
15362 ok(EqualRect(&window_rect, &primary_rect), "Expect window rect %s, got %s.\n",
15363 wine_dbgstr_rect(&primary_rect), wine_dbgstr_rect(&window_rect));
15365 new_rect = window_rect;
15366 --new_rect.right;
15367 --new_rect.bottom;
15369 ret = MoveWindow(window, new_rect.left, new_rect.top, new_rect.right - new_rect.left,
15370 new_rect.bottom - new_rect.top, TRUE);
15371 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
15372 ret = GetWindowRect(window, &window_rect);
15373 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
15374 ok(EqualRect(&window_rect, &new_rect),
15375 "Expected window rect %s, got %s.\n",
15376 wine_dbgstr_rect(monitor_rect), wine_dbgstr_rect(&window_rect));
15377 /* After processing window events window rectangle gets restored. But only once, the size set
15378 * on the second resize remains. */
15379 flush_events();
15380 ret = GetWindowRect(window, &window_rect);
15381 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
15382 /* Both Windows and Wine change the size of the window. On Windows it is exactly the new size but in Wine
15383 * it may get adjusted depending on window manager. */
15384 ok(window_rect.right != monitor_rect->right && window_rect.bottom != monitor_rect->bottom,
15385 "Expected window rect %s, got %s.\n",
15386 wine_dbgstr_rect(monitor_rect), wine_dbgstr_rect(&window_rect));
15388 ret = MoveWindow(window, new_rect.left, new_rect.top, new_rect.right - new_rect.left,
15389 new_rect.bottom - new_rect.top, TRUE);
15390 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
15391 ret = GetWindowRect(window, &window_rect);
15392 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
15393 ok(EqualRect(&window_rect, &new_rect),
15394 "Expected window rect %s, got %s.\n",
15395 wine_dbgstr_rect(monitor_rect), wine_dbgstr_rect(&window_rect));
15396 flush_events();
15397 ret = GetWindowRect(window, &window_rect);
15398 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
15399 ok(window_rect.right != monitor_rect->right && window_rect.bottom != monitor_rect->bottom,
15400 "Expected window rect %s, got %s.\n",
15401 wine_dbgstr_rect(monitor_rect), wine_dbgstr_rect(&window_rect));
15403 /* Window activation should restore the window to fit the whole primary monitor */
15404 ret = SetWindowPos(window, 0, monitor_rect->left, monitor_rect->top, 0, 0,
15405 SWP_NOZORDER | SWP_NOSIZE);
15406 ok(ret, "SetWindowPos failed, error %lu.\n", GetLastError());
15407 ret = SetForegroundWindow(GetDesktopWindow());
15408 ok(ret, "Failed to set foreground window.\n");
15409 flush_events();
15410 ret = ShowWindow(window, SW_RESTORE);
15411 ok(ret, "Failed to restore window, error %lu.\n", GetLastError());
15412 flush_events();
15413 ret = SetForegroundWindow(window);
15414 ok(ret, "SetForegroundWindow failed, error %lu.\n", GetLastError());
15415 flush_events();
15416 ret = GetWindowRect(window, &window_rect);
15417 ok(ret, "GetWindowRect failed, error %lu.\n", GetLastError());
15418 ok(EqualRect(&window_rect, &primary_rect), "Expect window rect %s, got %s.\n",
15419 wine_dbgstr_rect(&primary_rect), wine_dbgstr_rect(&window_rect));
15421 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
15422 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
15423 ret = GetWindowRect(window, &window_rect);
15424 ok(ret, "GetWindowRect failed, error %lu.\n", GetLastError());
15425 ok(EqualRect(&window_rect, &primary_rect), "Expect window rect %s, got %s.\n",
15426 wine_dbgstr_rect(&primary_rect), wine_dbgstr_rect(&window_rect));
15428 DestroyWindow(window);
15429 IDirectDraw2_Release(ddraw);
15430 return TRUE;
15433 static void test_window_position(void)
15435 EnumDisplayMonitors(NULL, NULL, test_window_position_cb, 0);
15438 static BOOL CALLBACK test_get_display_mode_cb(HMONITOR monitor, HDC hdc, RECT *monitor_rect,
15439 LPARAM lparam)
15441 DDSURFACEDESC surface_desc;
15442 IDirectDraw2 *ddraw;
15443 HWND window;
15444 HRESULT hr;
15445 BOOL ret;
15447 ddraw = create_ddraw();
15448 ok(!!ddraw, "Failed to create a ddraw object.\n");
15449 window = create_window();
15450 ok(!!window, "Failed to create a window.\n");
15452 /* Test that DirectDraw doesn't use the device window to determine which monitor to use */
15453 ret = SetWindowPos(window, 0, monitor_rect->left, monitor_rect->top, 0, 0,
15454 SWP_NOZORDER | SWP_NOSIZE);
15455 ok(ret, "SetWindowPos failed, error %lu.\n", GetLastError());
15457 surface_desc.dwSize = sizeof(surface_desc);
15458 hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
15459 ok(hr == DD_OK, "GetDisplayMode failed, hr %#lx.\n", hr);
15460 ok(surface_desc.dwWidth == GetSystemMetrics(SM_CXSCREEN), "Expect width %d, got %lu.\n",
15461 GetSystemMetrics(SM_CXSCREEN), surface_desc.dwWidth);
15462 ok(surface_desc.dwHeight == GetSystemMetrics(SM_CYSCREEN), "Expect height %d, got %lu.\n",
15463 GetSystemMetrics(SM_CYSCREEN), surface_desc.dwHeight);
15465 DestroyWindow(window);
15466 IDirectDraw2_Release(ddraw);
15467 return TRUE;
15470 static void test_get_display_mode(void)
15472 static const DWORD flags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_REFRESHRATE | DDSD_PIXELFORMAT | DDSD_PITCH;
15473 struct find_different_mode_param param;
15474 DDSURFACEDESC surface_desc;
15475 IDirectDraw2 *ddraw;
15476 DEVMODEW devmode;
15477 HWND window;
15478 HRESULT hr;
15479 BOOL ret;
15481 EnumDisplayMonitors(NULL, NULL, test_get_display_mode_cb, 0);
15483 ddraw = create_ddraw();
15484 ok(!!ddraw, "Failed to create a ddraw object.\n");
15485 window = create_window();
15486 ok(!!window, "Failed to create a window.\n");
15488 hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
15489 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
15491 memset(&devmode, 0, sizeof(devmode));
15492 devmode.dmSize = sizeof(devmode);
15493 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
15494 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
15496 surface_desc.dwSize = sizeof(surface_desc);
15497 hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
15498 ok(hr == DD_OK, "GetDisplayMode failed, hr %#lx.\n", hr);
15499 ok(surface_desc.dwSize == sizeof(surface_desc), "Got dwSize %lu.\n", surface_desc.dwSize);
15500 ok(surface_desc.dwFlags == flags, "Expected dwFlags %#lx, got %#lx.\n", flags,
15501 surface_desc.dwFlags);
15502 ok(surface_desc.dwWidth == devmode.dmPelsWidth, "Expected width %lu, got %lu.\n",
15503 devmode.dmPelsWidth, surface_desc.dwWidth);
15504 ok(surface_desc.dwHeight == devmode.dmPelsHeight, "Expected height %lu, got %lu.\n",
15505 devmode.dmPelsHeight, surface_desc.dwHeight);
15506 ok(surface_desc.dwRefreshRate == devmode.dmDisplayFrequency, "Expected frequency %lu, got %lu.\n",
15507 devmode.dmDisplayFrequency, surface_desc.dwRefreshRate);
15508 ok(surface_desc.ddpfPixelFormat.dwSize == sizeof(surface_desc.ddpfPixelFormat),
15509 "Got ddpfPixelFormat.dwSize %lu.\n", surface_desc.ddpfPixelFormat.dwSize);
15510 ok(surface_desc.ddpfPixelFormat.dwRGBBitCount == devmode.dmBitsPerPel,
15511 "Expected ddpfPixelFormat.dwRGBBitCount %lu, got %lu.\n", devmode.dmBitsPerPel,
15512 surface_desc.ddpfPixelFormat.dwRGBBitCount);
15513 ok(surface_desc.lPitch == devmode.dmPelsWidth * devmode.dmBitsPerPel / 8,
15514 "Expected pitch %lu, got %lu.\n", devmode.dmPelsWidth * devmode.dmBitsPerPel / 8,
15515 surface_desc.lPitch);
15517 memset(&param, 0, sizeof(param));
15518 param.old_frequency = surface_desc.dwRefreshRate;
15519 hr = IDirectDraw2_EnumDisplayModes(ddraw, DDEDM_REFRESHRATES, NULL, &param,
15520 find_different_mode_callback);
15521 ok(hr == DD_OK, "EnumDisplayModes failed, hr %#lx.\n", hr);
15522 if (!param.new_frequency)
15524 skip("Failed to find a display mode with a different frequency.\n");
15525 goto done;
15528 hr = IDirectDraw2_SetDisplayMode(ddraw, param.new_width, param.new_height, param.new_bpp,
15529 param.new_frequency, 0);
15530 ok(hr == DD_OK, "SetDisplayMode failed, hr %#lx.\n", hr);
15531 hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
15532 ok(hr == DD_OK, "GetDisplayMode failed, hr %#lx.\n", hr);
15533 ok(surface_desc.dwWidth == param.new_width, "Expected width %u, got %lu.\n", param.new_width,
15534 surface_desc.dwWidth);
15535 ok(surface_desc.dwHeight == param.new_height, "Expected height %u, got %lu.\n", param.new_height,
15536 surface_desc.dwHeight);
15537 ok(surface_desc.dwRefreshRate == param.new_frequency, "Expected frequency %u, got %lu.\n",
15538 param.new_frequency, surface_desc.dwRefreshRate);
15539 ok(surface_desc.ddpfPixelFormat.dwRGBBitCount == param.new_bpp,
15540 "Expected ddpfPixelFormat.dwRGBBitCount %lu, got %lu.\n", devmode.dmBitsPerPel,
15541 surface_desc.ddpfPixelFormat.dwRGBBitCount);
15543 done:
15544 DestroyWindow(window);
15545 IDirectDraw2_Release(ddraw);
15548 static void test_texture_wrong_caps(const GUID *device_guid)
15550 static D3DLVERTEX quad[] =
15552 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xffffffff}, {0}, {0.0f}, {1.0f}},
15553 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xffffffff}, {0}, {0.0f}, {0.0f}},
15554 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xffffffff}, {0}, {1.0f}, {1.0f}},
15555 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xffffffff}, {0}, {1.0f}, {0.0f}},
15557 static DDPIXELFORMAT fmt =
15559 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
15560 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
15562 D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
15563 unsigned int color, expected_color;
15564 IDirectDrawSurface *surface, *rt;
15565 D3DTEXTUREHANDLE texture_handle;
15566 IDirect3DMaterial2 *background;
15567 IDirect3DViewport2 *viewport;
15568 IDirect3DTexture2 *texture;
15569 IDirect3DDevice2 *device;
15570 IDirectDraw2 *ddraw;
15571 DDSURFACEDESC ddsd;
15572 ULONG refcount;
15573 HWND window;
15574 HRESULT hr;
15576 window = create_window();
15577 ddraw = create_ddraw();
15578 ok(!!ddraw, "Failed to create a ddraw object.\n");
15579 if (!(device = create_device_ex(ddraw, window, DDSCL_NORMAL, device_guid)))
15581 skip("Failed to create a 3D device, skipping test.\n");
15582 DestroyWindow(window);
15583 return;
15585 hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
15586 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15588 viewport = create_viewport(device, 0, 0, 640, 480);
15589 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
15590 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15592 memset(&ddsd, 0, sizeof(ddsd));
15593 ddsd.dwSize = sizeof(ddsd);
15594 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
15595 ddsd.dwHeight = 16;
15596 ddsd.dwWidth = 16;
15597 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
15598 U4(ddsd).ddpfPixelFormat = fmt;
15599 hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
15600 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15601 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
15602 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15603 hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
15604 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15606 fill_surface(surface, 0xff00ff00);
15608 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
15609 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15610 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
15611 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15613 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
15614 viewport_set_background(device, viewport, background);
15616 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
15617 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15618 if (is_software_device_type(device_guid))
15619 fill_surface(rt, 0xffff0000);
15621 hr = IDirect3DDevice2_BeginScene(device);
15622 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15623 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad, ARRAY_SIZE(quad), 0);
15624 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15625 hr = IDirect3DDevice2_EndScene(device);
15626 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15628 expected_color = is_software_device_type(device_guid) ? 0x0000ff00 : 0x00ffffff;
15629 color = get_surface_color(rt, 320, 240);
15630 ok(compare_color(color, expected_color, 1), "Got color 0x%08x, expected 0x%08x.\n", color, expected_color);
15632 IDirect3DTexture2_Release(texture);
15633 IDirectDrawSurface_Release(surface);
15634 IDirectDrawSurface_Release(rt);
15635 destroy_viewport(device, viewport);
15636 destroy_material(background);
15637 IDirectDraw2_Release(ddraw);
15638 refcount = IDirect3DDevice2_Release(device);
15639 ok(!refcount, "Device has %lu references left.\n", refcount);
15640 DestroyWindow(window);
15643 static void test_filling_convention(void)
15645 IDirectDrawSurface *rt, *backbuffer, *cur, *ds;
15646 static const DWORD colour_bottom = 0x00ffff00;
15647 static const DWORD colour_clear = 0x000000ff;
15648 static const DWORD colour_right = 0x00000000;
15649 static const DWORD colour_left = 0x00ff0000;
15650 static const DWORD colour_top = 0x0000ff00;
15651 unsigned int colour, expected, i, j, x, y;
15652 IDirect3DMaterial2 *background;
15653 IDirect3DViewport2 *viewport;
15654 IDirect3DDevice2 *device;
15655 IDirectDraw2 *ddraw;
15656 DDSURFACEDESC desc;
15657 IDirect3D2 *d3d;
15658 ULONG refcount;
15659 HWND window;
15660 HRESULT hr;
15661 BOOL todo;
15663 static const unsigned int vp_size = 8;
15664 D3DRECT clear_rect = {{0}, {0}, {vp_size}, {vp_size}};
15666 /* This test data follows the examples in MSDN's
15667 * "Rasterization Rules (Direct3D 9)" article.
15669 * See the d3d9 test for a comment about the eps value. */
15670 static const float eps = 1.0f / 64.0f;
15671 D3DLVERTEX center_tris[] =
15673 /* left */
15674 {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_left}},
15675 {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_left}},
15676 {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_left}},
15678 /* top */
15679 {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_top}},
15680 {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
15681 {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
15683 /* right */
15684 {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_right}},
15685 {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_right}},
15686 {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_right}},
15688 /* bottom */
15689 {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15690 {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15691 {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15693 edge_tris[] =
15695 /* left */
15696 {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15697 {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15698 {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15700 /* top */
15701 {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15702 {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15703 {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15705 /* right */
15706 {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15707 {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15708 {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15710 /* bottom */
15711 {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15712 {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15713 {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15715 nudge_right_tris[] =
15717 /* left */
15718 {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15719 {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15720 {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15722 /* top */
15723 {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15724 {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15725 {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15727 /* right */
15728 {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15729 {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15730 {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15732 /* bottom */
15733 {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15734 {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15735 {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15737 nudge_left_tris[] =
15739 {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15740 {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15741 {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15743 /* top */
15744 {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15745 {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15746 {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15748 /* right */
15749 {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15750 {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15751 {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15753 /* bottom */
15754 {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15755 {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15756 {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15758 nudge_top_tris[] =
15760 /* left */
15761 {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15762 {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15763 {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15765 /* top */
15766 {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15767 {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15768 {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15770 /* right */
15771 {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15772 {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15773 {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15775 /* bottom */
15776 {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15777 {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15778 {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15780 nudge_bottom_tris[] =
15782 /* left */
15783 {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15784 {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15785 {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
15787 /* top */
15788 {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15789 {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15790 {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
15792 /* right */
15793 {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15794 {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15795 {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
15797 /* bottom */
15798 {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15799 {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15800 {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
15803 D3DTLVERTEX center_tris_t[] =
15805 /* left */
15806 {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_left}},
15807 {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_left}},
15808 {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_left}},
15810 /* top */
15811 {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
15812 {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
15813 {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_top}},
15815 /* right */
15816 {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_right}},
15817 {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_right}},
15818 {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_right}},
15820 /* bottom */
15821 {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_bottom}},
15822 {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
15823 {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
15825 edge_tris_t[] =
15827 /* left */
15828 {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_left}},
15829 {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_left}},
15830 {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_left}},
15832 /* top */
15833 {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
15834 {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
15835 {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_top}},
15837 /* right */
15838 {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_right}},
15839 {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_right}},
15840 {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_right}},
15842 /* bottom */
15843 {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_bottom}},
15844 {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
15845 {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
15848 const struct
15850 void *geometry;
15851 DWORD fvf;
15852 const char *expected[8];
15854 tests[] =
15857 center_tris,
15858 D3DVT_LVERTEX,
15860 " ",
15861 " ",
15862 " TT ",
15863 " LR ",
15864 " LR ",
15865 " BB ",
15866 " ",
15871 edge_tris,
15872 D3DVT_LVERTEX,
15874 " ",
15875 " TT ",
15876 " LT ",
15877 " LR ",
15878 " LB ",
15879 " ",
15880 " ",
15885 nudge_right_tris,
15886 D3DVT_LVERTEX,
15888 " ",
15889 " TT ",
15890 " TR ",
15891 " LR ",
15892 " BR ",
15893 " ",
15894 " ",
15899 nudge_left_tris,
15900 D3DVT_LVERTEX,
15902 " ",
15903 " TT ",
15904 " LT ",
15905 " LR ",
15906 " LB ",
15907 " ",
15908 " ",
15913 nudge_top_tris,
15914 D3DVT_LVERTEX,
15916 " ",
15917 " LT ",
15918 " LT ",
15919 " LB ",
15920 " LB ",
15921 " ",
15922 " ",
15927 nudge_bottom_tris,
15928 D3DVT_LVERTEX,
15930 " ",
15931 " ",
15932 " LT ",
15933 " Lt ",
15934 " LB ",
15935 " lB ",
15936 " ",
15941 center_tris_t,
15942 D3DVT_TLVERTEX,
15944 " ",
15945 " ",
15946 " TT ",
15947 " LR ",
15948 " LR ",
15949 " BB ",
15950 " ",
15955 edge_tris_t,
15956 D3DVT_TLVERTEX,
15958 " ",
15959 " TT ",
15960 " LT ",
15961 " LR ",
15962 " LB ",
15963 " ",
15964 " ",
15970 window = create_window();
15971 ddraw = create_ddraw();
15972 ok(!!ddraw, "Failed to create a ddraw object.\n");
15973 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
15975 skip("Failed to create a 3D device.\n");
15976 IDirectDraw2_Release(ddraw);
15977 DestroyWindow(window);
15978 return;
15981 hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
15982 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15983 hr = IDirect3DDevice2_GetRenderTarget(device, &backbuffer);
15984 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
15986 viewport = create_viewport(device, 0, 0, vp_size, vp_size);
15987 background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
15988 viewport_set_background(device, viewport, background);
15989 hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
15990 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15992 memset(&desc, 0, sizeof(desc));
15993 desc.dwSize = sizeof(desc);
15994 desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
15995 desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
15996 desc.dwWidth = vp_size;
15997 desc.dwHeight = vp_size;
15998 desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
15999 desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
16000 desc.ddpfPixelFormat.dwRGBBitCount = 32;
16001 desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
16002 desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
16003 desc.ddpfPixelFormat.dwBBitMask = 0x000000ff;
16004 hr = IDirectDraw2_CreateSurface(ddraw, &desc, &rt, NULL);
16005 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
16007 /* Nvidia on Windows 10 refuses to set the offscreen RT
16008 * if it does not have an attached depth stencil. */
16009 ds = get_depth_stencil(device);
16010 memset(&desc, 0, sizeof(desc));
16011 desc.dwSize = sizeof(desc);
16012 desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
16013 hr = IDirectDrawSurface_GetPixelFormat(ds, &desc.ddpfPixelFormat);
16014 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
16015 IDirectDrawSurface4_Release(ds);
16017 desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
16018 desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
16019 desc.dwWidth = vp_size;
16020 desc.dwHeight = vp_size;
16021 hr = IDirectDraw2_CreateSurface(ddraw, &desc, &ds, NULL);
16022 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
16023 hr = IDirectDrawSurface_AddAttachedSurface(rt, ds);
16024 ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#lx.\n", hr);
16026 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
16027 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
16028 hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
16029 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
16031 for (i = 0; i < ARRAY_SIZE(tests); ++i)
16033 for (j = 0; j < 2; ++j)
16035 cur = j ? rt : backbuffer;
16037 hr = IDirect3DDevice2_SetRenderTarget(device, cur, 0);
16038 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
16039 hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
16040 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
16042 hr = IDirect3DDevice2_BeginScene(device);
16043 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
16044 hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLELIST,
16045 tests[i].fvf, tests[i].geometry, 12, 0);
16046 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
16047 hr = IDirect3DDevice2_EndScene(device);
16048 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
16050 for (y = 0; y < 8; y++)
16052 for (x = 0; x < 8; x++)
16054 todo = FALSE;
16055 switch (tests[i].expected[y][x])
16057 case 'l': todo = TRUE;
16058 case 'L':
16059 expected = colour_left;
16060 break;
16061 case 't': todo = TRUE;
16062 case 'T':
16063 expected = colour_top;
16064 break;
16065 case 'r': todo = TRUE;
16066 case 'R':
16067 expected = colour_right;
16068 break;
16069 case 'b': todo = TRUE;
16070 case 'B':
16071 expected = colour_bottom;
16072 break;
16073 case ' ':
16074 expected = colour_clear;
16075 break;
16076 default:
16077 ok(0, "Unexpected entry in expected test char\n");
16078 expected = 0xdeadbeef;
16080 colour = get_surface_color(cur, x, y);
16081 /* The nudge-to-bottom test fails on cards that give us a bottom-left
16082 * filling convention. The cause isn't the bottom part of the filling
16083 * convention, but because wined3d will nudge geometry to the left to
16084 * keep diagonals (the 'R' in test case 'edge_tris') intact. */
16085 todo_wine_if(todo && !compare_color(colour, expected, 1))
16086 ok(compare_color(colour, expected, 1), "Got unexpected colour %08x, %ux%u, case %u, j %u.\n",
16087 colour, x, y, i, j);
16093 destroy_viewport(device, viewport);
16094 IDirectDrawSurface_Release(backbuffer);
16095 IDirectDrawSurface_Release(rt);
16096 IDirectDrawSurface_Release(ds);
16097 IDirect3D2_Release(d3d);
16098 refcount = IDirect3DDevice2_Release(device);
16099 ok(!refcount, "Device has %lu references left.\n", refcount);
16100 refcount = IDirectDraw2_Release(ddraw);
16101 ok(!refcount, "Device has %lu references left.\n", refcount);
16102 DestroyWindow(window);
16105 static HRESULT WINAPI test_enum_devices_caps_callback(GUID *guid, char *device_desc,
16106 char *device_name, D3DDEVICEDESC *hal, D3DDEVICEDESC *hel, void *ctx)
16108 if(IsEqualGUID(&IID_IDirect3DRGBDevice, guid))
16110 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
16111 "RGB Device hal line caps has D3DPTEXTURECAPS_POW2 flag set\n");
16112 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
16113 "RGB Device hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n");
16114 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
16115 "RGB Device hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
16116 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
16117 "RGB Device hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
16119 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
16120 "RGB Device hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
16121 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
16122 "RGB Device hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
16123 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
16124 "RGB Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
16125 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
16126 "RGB Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
16128 ok(hal->dcmColorModel == 0, "RGB Device hal caps has colormodel %lu\n", hal->dcmColorModel);
16129 ok(hel->dcmColorModel == D3DCOLOR_RGB, "RGB Device hel caps has colormodel %lu\n", hel->dcmColorModel);
16131 ok(hal->dwFlags == 0, "RGB Device hal caps has hardware flags %#lx\n", hal->dwFlags);
16132 ok(hel->dwFlags != 0, "RGB Device hel caps has hardware flags %#lx\n", hel->dwFlags);
16134 ok((hal->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
16135 "RGB Device hal device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
16136 ok((hel->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
16137 "RGB Device hel device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
16138 ok((hal->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
16139 "RGB Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
16140 ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
16141 "RGB Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
16143 else if(IsEqualGUID(&IID_IDirect3DHALDevice, guid))
16145 ok(hal->dcmColorModel == D3DCOLOR_RGB, "HAL Device hal caps has colormodel %lu\n", hel->dcmColorModel);
16146 ok(hel->dcmColorModel == 0, "HAL Device hel caps has colormodel %lu\n", hel->dcmColorModel);
16148 ok(hal->dwFlags != 0, "HAL Device hal caps has hardware flags %#lx\n", hal->dwFlags);
16149 ok(hel->dwFlags != 0, "HAL Device hel caps has hardware flags %#lx\n", hel->dwFlags);
16151 ok(hal->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT,
16152 "HAL Device hal device caps does not have D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
16153 ok((hel->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
16154 "RGB Device hel device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
16155 ok(hal->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX,
16156 "HAL Device hal device caps does not have D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
16157 ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
16158 "RGB Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
16160 else if(IsEqualGUID(&IID_IDirect3DRefDevice, guid))
16162 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
16163 "REF Device hal line caps has D3DPTEXTURECAPS_POW2 flag set\n");
16164 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
16165 "REF Device hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n");
16166 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
16167 "REF Device hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
16168 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
16169 "REF Device hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
16171 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
16172 "REF Device hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
16173 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
16174 "REF Device hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
16175 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
16176 "REF Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
16177 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
16178 "REF Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
16180 ok((hal->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
16181 "REF Device hal device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
16182 ok((hel->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
16183 "REF Device hel device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
16184 ok((hal->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
16185 "REF Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
16186 ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
16187 "REF Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
16189 else if(IsEqualGUID(&IID_IDirect3DRampDevice, guid))
16191 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
16192 "Ramp Device hal line caps has D3DPTEXTURECAPS_POW2 flag set\n");
16193 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
16194 "Ramp Device hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n");
16195 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
16196 "Ramp Device hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
16197 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
16198 "Ramp Device hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
16200 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
16201 "Ramp Device hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
16202 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
16203 "Ramp Device hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
16204 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
16205 "Ramp Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
16206 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
16207 "Ramp Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
16209 ok(hal->dcmColorModel == 0, "Ramp Device hal caps has colormodel %lu\n", hal->dcmColorModel);
16210 ok(hel->dcmColorModel == D3DCOLOR_MONO, "Ramp Device hel caps has colormodel %lu\n",
16211 hel->dcmColorModel);
16213 ok(hal->dwFlags == 0, "Ramp Device hal caps has hardware flags %#lx\n", hal->dwFlags);
16214 ok(hel->dwFlags != 0, "Ramp Device hel caps has hardware flags %#lx\n", hel->dwFlags);
16216 ok((hal->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
16217 "Ramp Device hal device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
16218 ok((hel->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
16219 "Ramp Device hel device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
16220 ok((hal->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
16221 "Ramp Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
16222 ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
16223 "Ramp Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
16225 else if(IsEqualGUID(&IID_IDirect3DMMXDevice, guid))
16227 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
16228 "MMX Device hal line caps has D3DPTEXTURECAPS_POW2 flag set\n");
16229 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
16230 "MMX Device hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n");
16231 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
16232 "MMX Device hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
16233 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
16234 "MMX Device hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
16236 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
16237 "MMX Device hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
16238 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
16239 "MMX Device hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
16240 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
16241 "MMX Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
16242 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
16243 "MMX Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
16245 ok(hal->dcmColorModel == 0, "MMX Device hal caps has colormodel %lu\n", hal->dcmColorModel);
16246 ok(hel->dcmColorModel == D3DCOLOR_RGB, "MMX Device hel caps has colormodel %lu\n", hel->dcmColorModel);
16248 ok(hal->dwFlags == 0, "MMX Device hal caps has hardware flags %#lx\n", hal->dwFlags);
16249 ok(hel->dwFlags != 0, "MMX Device hel caps has hardware flags %#lx\n", hel->dwFlags);
16251 ok((hal->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
16252 "MMX Device hal device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
16253 ok((hel->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
16254 "MMX Device hel device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
16255 ok((hal->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
16256 "MMX Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
16257 ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
16258 "MMX Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
16260 else
16262 ok(FALSE, "Unexpected device enumerated: \"%s\" \"%s\"\n", device_desc, device_name);
16263 if (hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2)
16264 trace("hal line has pow2 set\n");
16265 else
16266 trace("hal line does NOT have pow2 set\n");
16267 if (hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2)
16268 trace("hal tri has pow2 set\n");
16269 else
16270 trace("hal tri does NOT have pow2 set\n");
16271 if (hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2)
16272 trace("hel line has pow2 set\n");
16273 else
16274 trace("hel line does NOT have pow2 set\n");
16275 if (hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2)
16276 trace("hel tri has pow2 set\n");
16277 else
16278 trace("hel tri does NOT have pow2 set\n");
16281 return DDENUMRET_OK;
16284 static void test_enum_devices(void)
16286 IDirectDraw2 *ddraw;
16287 IDirect3D2 *d3d;
16288 ULONG refcount;
16289 HRESULT hr;
16291 ddraw = create_ddraw();
16292 ok(!!ddraw, "Failed to create a ddraw object.\n");
16294 hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
16295 if (FAILED(hr))
16297 skip("D3D interface is not available, skipping test.\n");
16298 IDirectDraw2_Release(ddraw);
16299 return;
16302 hr = IDirect3D2_EnumDevices(d3d, NULL, NULL);
16303 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
16305 hr = IDirect3D2_EnumDevices(d3d, test_enum_devices_caps_callback, NULL);
16306 ok(hr == D3D_OK, "Got hr %#lx.\n", hr);
16308 IDirect3D2_Release(d3d);
16309 refcount = IDirectDraw2_Release(ddraw);
16310 ok(!refcount, "Device has %lu references left.\n", refcount);
16313 static void run_for_each_device_type(void (*test_func)(const GUID *))
16315 test_func(&IID_IDirect3DHALDevice);
16316 test_func(&IID_IDirect3DRGBDevice);
16319 START_TEST(ddraw2)
16321 DDDEVICEIDENTIFIER identifier;
16322 DEVMODEW current_mode;
16323 IDirectDraw2 *ddraw;
16324 HMODULE dwmapi;
16326 if (!(ddraw = create_ddraw()))
16328 skip("Failed to create a ddraw object, skipping tests.\n");
16329 return;
16332 if (ddraw_get_identifier(ddraw, &identifier))
16334 trace("Driver string: \"%s\"\n", identifier.szDriver);
16335 trace("Description string: \"%s\"\n", identifier.szDescription);
16336 trace("Driver version %d.%d.%d.%d\n",
16337 HIWORD(U(identifier.liDriverVersion).HighPart), LOWORD(U(identifier.liDriverVersion).HighPart),
16338 HIWORD(U(identifier.liDriverVersion).LowPart), LOWORD(U(identifier.liDriverVersion).LowPart));
16340 IDirectDraw2_Release(ddraw);
16342 memset(&current_mode, 0, sizeof(current_mode));
16343 current_mode.dmSize = sizeof(current_mode);
16344 ok(EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &current_mode), "Failed to get display mode.\n");
16345 registry_mode.dmSize = sizeof(registry_mode);
16346 ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &registry_mode), "Failed to get display mode.\n");
16347 if (registry_mode.dmPelsWidth != current_mode.dmPelsWidth
16348 || registry_mode.dmPelsHeight != current_mode.dmPelsHeight)
16350 skip("Current mode does not match registry mode, skipping test.\n");
16351 return;
16354 if ((dwmapi = LoadLibraryA("dwmapi.dll")))
16355 pDwmIsCompositionEnabled = (void *)GetProcAddress(dwmapi, "DwmIsCompositionEnabled");
16357 test_coop_level_create_device_window();
16358 test_clipper_blt();
16359 test_coop_level_d3d_state();
16360 test_surface_interface_mismatch();
16361 test_coop_level_threaded();
16362 run_for_each_device_type(test_depth_blit);
16363 test_texture_load_ckey();
16364 test_viewport_object();
16365 run_for_each_device_type(test_zenable);
16366 run_for_each_device_type(test_ck_rgba);
16367 test_ck_default();
16368 test_ck_complex();
16369 test_surface_qi();
16370 test_device_qi();
16371 test_wndproc();
16372 test_window_style();
16373 test_redundant_mode_set();
16374 test_coop_level_mode_set();
16375 test_coop_level_mode_set_multi();
16376 test_initialize();
16377 test_coop_level_surf_create();
16378 test_coop_level_multi_window();
16379 test_clear_rect_count();
16380 test_coop_level_versions();
16381 test_lighting_interface_versions();
16382 test_coop_level_activateapp();
16383 test_unsupported_formats();
16384 run_for_each_device_type(test_rt_caps);
16385 test_primary_caps();
16386 test_surface_lock();
16387 test_surface_discard();
16388 test_flip();
16389 test_set_surface_desc();
16390 test_user_memory_getdc();
16391 test_sysmem_overlay();
16392 test_primary_palette();
16393 test_surface_attachment();
16394 test_pixel_format();
16395 test_create_surface_pitch();
16396 test_mipmap();
16397 test_palette_complex();
16398 test_p8_blit();
16399 test_material();
16400 test_lighting();
16401 test_specular_lighting();
16402 test_palette_gdi();
16403 test_palette_alpha();
16404 test_lost_device();
16405 test_surface_desc_lock();
16406 test_texturemapblend();
16407 test_viewport_clear_rect();
16408 test_color_fill();
16409 test_colorkey_precision();
16410 test_range_colorkey();
16411 test_shademode();
16412 test_lockrect_invalid();
16413 test_yv12_overlay();
16414 test_offscreen_overlay();
16415 test_overlay_rect();
16416 test_blt();
16417 test_blt_z_alpha();
16418 test_cross_device_blt();
16419 test_getdc();
16420 test_draw_primitive();
16421 test_edge_antialiasing_blending();
16422 test_transform_vertices();
16423 test_display_mode_surface_pixel_format();
16424 test_surface_desc_size();
16425 test_ck_operation();
16426 test_set_render_state();
16427 test_depth_readback();
16428 test_clear();
16429 test_enum_surfaces();
16430 test_viewport();
16431 test_find_device();
16432 test_killfocus();
16433 test_gdi_surface();
16434 test_alphatest();
16435 test_clipper_refcount();
16436 test_caps();
16437 test_d32_support();
16438 test_cursor_clipping();
16439 test_window_position();
16440 test_get_display_mode();
16441 run_for_each_device_type(test_texture_wrong_caps);
16442 test_filling_convention();
16443 test_enum_devices();