ddraw/tests: Do not create a fullscreen test window in test_window_position_cb().
[wine.git] / dlls / ddraw / tests / ddraw1.c
blob3d81c590a3a4d030731de4dbe3eaab236213c317
1 /*
2 * Copyright 2005 Antoine Chavasse (a.chavasse@gmail.com)
3 * Copyright 2008, 2011, 2012-2013 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 #define COBJMACROS
23 #include "wine/test.h"
24 #include "wine/heap.h"
25 #include <limits.h>
26 #include <math.h>
27 #include "ddrawi.h"
28 #include "d3dhal.h"
30 static BOOL is_ddraw64 = sizeof(DWORD) != sizeof(DWORD *);
31 static DEVMODEW registry_mode;
33 static HRESULT (WINAPI *pDwmIsCompositionEnabled)(BOOL *);
35 struct vec2
37 float x, y;
40 struct vec4
42 float x, y, z, w;
45 struct create_window_thread_param
47 HWND window;
48 HANDLE window_created;
49 HANDLE destroy_window;
50 HANDLE thread;
53 static BOOL compare_float(float f, float g, unsigned int ulps)
55 int x = *(int *)&f;
56 int y = *(int *)&g;
58 if (x < 0)
59 x = INT_MIN - x;
60 if (y < 0)
61 y = INT_MIN - y;
63 if (abs(x - y) > ulps)
64 return FALSE;
66 return TRUE;
69 static BOOL compare_vec4(const struct vec4 *vec, float x, float y, float z, float w, unsigned int ulps)
71 return compare_float(vec->x, x, ulps)
72 && compare_float(vec->y, y, ulps)
73 && compare_float(vec->z, z, ulps)
74 && compare_float(vec->w, w, ulps);
77 static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff)
79 unsigned int diff = x > y ? x - y : y - x;
81 return diff <= max_diff;
84 static BOOL compare_color(D3DCOLOR c1, D3DCOLOR c2, BYTE max_diff)
86 return compare_uint(c1 & 0xff, c2 & 0xff, max_diff)
87 && compare_uint((c1 >> 8) & 0xff, (c2 >> 8) & 0xff, max_diff)
88 && compare_uint((c1 >> 16) & 0xff, (c2 >> 16) & 0xff, max_diff)
89 && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff);
92 static void get_virtual_rect(RECT *rect)
94 rect->left = GetSystemMetrics(SM_XVIRTUALSCREEN);
95 rect->top = GetSystemMetrics(SM_YVIRTUALSCREEN);
96 rect->right = rect->left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
97 rect->bottom = rect->top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
100 /* Try to make sure pending X events have been processed before continuing */
101 static void flush_events(void)
103 int diff = 200;
104 DWORD time;
105 MSG msg;
107 time = GetTickCount() + diff;
108 while (diff > 0)
110 if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT)
111 break;
112 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
113 DispatchMessageA(&msg);
114 diff = time - GetTickCount();
118 static BOOL ddraw_get_identifier(IDirectDraw *ddraw, DDDEVICEIDENTIFIER *identifier)
120 IDirectDraw4 *ddraw4;
121 HRESULT hr;
123 hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirectDraw4, (void **)&ddraw4);
124 ok(SUCCEEDED(hr), "Failed to get IDirectDraw4 interface, hr %#lx.\n", hr);
125 hr = IDirectDraw4_GetDeviceIdentifier(ddraw4, identifier, 0);
126 ok(SUCCEEDED(hr), "Failed to get device identifier, hr %#lx.\n", hr);
127 IDirectDraw4_Release(ddraw4);
129 return SUCCEEDED(hr);
132 static BOOL ddraw_is_warp(IDirectDraw *ddraw)
134 DDDEVICEIDENTIFIER identifier;
136 return strcmp(winetest_platform, "wine")
137 && ddraw_get_identifier(ddraw, &identifier)
138 && strstr(identifier.szDriver, "warp");
141 static BOOL ddraw_is_vendor(IDirectDraw *ddraw, DWORD vendor)
143 DDDEVICEIDENTIFIER identifier;
145 return strcmp(winetest_platform, "wine")
146 && ddraw_get_identifier(ddraw, &identifier)
147 && identifier.dwVendorId == vendor;
150 static BOOL ddraw_is_amd(IDirectDraw *ddraw)
152 return ddraw_is_vendor(ddraw, 0x1002);
155 static BOOL ddraw_is_intel(IDirectDraw *ddraw)
157 return ddraw_is_vendor(ddraw, 0x8086);
160 static BOOL ddraw_is_nvidia(IDirectDraw *ddraw)
162 return ddraw_is_vendor(ddraw, 0x10de);
165 static BOOL ddraw_is_vmware(IDirectDraw *ddraw)
167 return ddraw_is_vendor(ddraw, 0x15ad);
170 static BOOL is_software_device_type(const GUID *device_guid)
172 return device_guid != &IID_IDirect3DHALDevice;
175 static IDirectDrawSurface *create_overlay(IDirectDraw *ddraw,
176 unsigned int width, unsigned int height, DWORD format)
178 IDirectDrawSurface *surface;
179 DDSURFACEDESC desc;
181 memset(&desc, 0, sizeof(desc));
182 desc.dwSize = sizeof(desc);
183 desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
184 desc.dwWidth = width;
185 desc.dwHeight = height;
186 desc.ddsCaps.dwCaps = DDSCAPS_OVERLAY;
187 desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
188 desc.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
189 desc.ddpfPixelFormat.dwFourCC = format;
191 if (FAILED(IDirectDraw_CreateSurface(ddraw, &desc, &surface, NULL)))
192 return NULL;
193 return surface;
196 static HWND create_window(void)
198 RECT r = {0, 0, 640, 480};
200 AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE);
202 return CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
203 CW_USEDEFAULT, CW_USEDEFAULT, r.right - r.left, r.bottom - r.top, NULL, NULL, NULL, NULL);
206 static DWORD WINAPI create_window_thread_proc(void *param)
208 struct create_window_thread_param *p = param;
209 DWORD res;
210 BOOL ret;
212 p->window = create_window();
213 ret = SetEvent(p->window_created);
214 ok(ret, "SetEvent failed, last error %lu.\n", GetLastError());
216 for (;;)
218 MSG msg;
220 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
221 DispatchMessageA(&msg);
222 res = WaitForSingleObject(p->destroy_window, 100);
223 if (res == WAIT_OBJECT_0)
224 break;
225 if (res != WAIT_TIMEOUT)
227 ok(0, "Wait failed (%#lx), last error %lu.\n", res, GetLastError());
228 break;
232 DestroyWindow(p->window);
234 return 0;
237 static void create_window_thread(struct create_window_thread_param *p)
239 DWORD res, tid;
241 p->window_created = CreateEventA(NULL, FALSE, FALSE, NULL);
242 ok(!!p->window_created, "CreateEvent failed, last error %lu.\n", GetLastError());
243 p->destroy_window = CreateEventA(NULL, FALSE, FALSE, NULL);
244 ok(!!p->destroy_window, "CreateEvent failed, last error %lu.\n", GetLastError());
245 p->thread = CreateThread(NULL, 0, create_window_thread_proc, p, 0, &tid);
246 ok(!!p->thread, "Failed to create thread, last error %lu.\n", GetLastError());
247 res = WaitForSingleObject(p->window_created, INFINITE);
248 ok(res == WAIT_OBJECT_0, "Wait failed (%#lx), last error %lu.\n", res, GetLastError());
251 static void destroy_window_thread(struct create_window_thread_param *p)
253 SetEvent(p->destroy_window);
254 WaitForSingleObject(p->thread, INFINITE);
255 CloseHandle(p->destroy_window);
256 CloseHandle(p->window_created);
257 CloseHandle(p->thread);
260 static IDirectDrawSurface *get_depth_stencil(IDirect3DDevice *device)
262 IDirectDrawSurface *rt, *ret;
263 DDSCAPS caps = {DDSCAPS_ZBUFFER};
264 HRESULT hr;
266 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
267 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
268 hr = IDirectDrawSurface_GetAttachedSurface(rt, &caps, &ret);
269 ok(SUCCEEDED(hr) || hr == DDERR_NOTFOUND, "Failed to get the z buffer, hr %#lx.\n", hr);
270 IDirectDrawSurface_Release(rt);
271 return ret;
274 /* Free original_modes after finished using it */
275 static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
277 unsigned int number, size = 2, count = 0, index = 0;
278 DISPLAY_DEVICEW display_device;
279 DEVMODEW *modes, *tmp;
281 if (!(modes = heap_alloc(size * sizeof(*modes))))
282 return FALSE;
284 display_device.cb = sizeof(display_device);
285 while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
287 /* Skip software devices */
288 if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
289 continue;
291 if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
292 continue;
294 if (count >= size)
296 size *= 2;
297 if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
299 heap_free(modes);
300 return FALSE;
302 modes = tmp;
305 memset(&modes[count], 0, sizeof(modes[count]));
306 modes[count].dmSize = sizeof(modes[count]);
307 if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
309 heap_free(modes);
310 return FALSE;
313 lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
316 *original_modes = modes;
317 *display_count = count;
318 return TRUE;
321 static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
323 unsigned int index;
324 LONG ret;
326 for (index = 0; index < count; ++index)
328 ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
329 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
330 if (ret != DISP_CHANGE_SUCCESSFUL)
331 return FALSE;
333 ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
334 return ret == DISP_CHANGE_SUCCESSFUL;
337 static HRESULT set_display_mode(IDirectDraw *ddraw, DWORD width, DWORD height)
339 if (SUCCEEDED(IDirectDraw_SetDisplayMode(ddraw, width, height, 32)))
340 return DD_OK;
341 return IDirectDraw_SetDisplayMode(ddraw, width, height, 24);
344 static D3DCOLOR get_surface_color(IDirectDrawSurface *surface, UINT x, UINT y)
346 RECT rect = {x, y, x + 1, y + 1};
347 DDSURFACEDESC surface_desc;
348 D3DCOLOR color;
349 HRESULT hr;
351 memset(&surface_desc, 0, sizeof(surface_desc));
352 surface_desc.dwSize = sizeof(surface_desc);
354 hr = IDirectDrawSurface_Lock(surface, &rect, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
355 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
356 if (FAILED(hr))
357 return 0xdeadbeef;
359 color = *((DWORD *)surface_desc.lpSurface) & 0x00ffffff;
361 hr = IDirectDrawSurface_Unlock(surface, NULL);
362 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
364 return color;
367 static void fill_surface(IDirectDrawSurface *surface, D3DCOLOR color)
369 DDSURFACEDESC surface_desc = {sizeof(surface_desc)};
370 HRESULT hr;
371 unsigned int x, y;
372 DWORD *ptr;
374 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
375 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
377 for (y = 0; y < surface_desc.dwHeight; ++y)
379 ptr = (DWORD *)((BYTE *)surface_desc.lpSurface + y * U1(surface_desc).lPitch);
380 for (x = 0; x < surface_desc.dwWidth; ++x)
382 ptr[x] = color;
386 hr = IDirectDrawSurface_Unlock(surface, NULL);
387 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
390 static void check_rect(IDirectDrawSurface *surface, RECT r)
392 LONG x_coords[2][2] =
394 {r.left - 1, r.left + 1},
395 {r.right + 1, r.right - 1},
397 LONG y_coords[2][2] =
399 {r.top - 1, r.top + 1},
400 {r.bottom + 1, r.bottom - 1}
402 unsigned int i, j, x_side, y_side, color;
403 LONG x, y;
405 for (i = 0; i < 2; ++i)
407 for (j = 0; j < 2; ++j)
409 for (x_side = 0; x_side < 2; ++x_side)
411 for (y_side = 0; y_side < 2; ++y_side)
413 unsigned int expected = (x_side == 1 && y_side == 1) ? 0x00ffffff : 0x00000000;
415 x = x_coords[i][x_side];
416 y = y_coords[j][y_side];
417 if (x < 0 || x >= 640 || y < 0 || y >= 480)
418 continue;
419 color = get_surface_color(surface, x, y);
420 ok(color == expected, "Pixel (%ld, %ld) has color %08x, expected %08x.\n", x, y, color, expected);
427 static void emit_process_vertices(void **ptr, DWORD flags, WORD base_idx, DWORD vertex_count)
429 D3DINSTRUCTION *inst = *ptr;
430 D3DPROCESSVERTICES *pv = (D3DPROCESSVERTICES *)(inst + 1);
432 inst->bOpcode = D3DOP_PROCESSVERTICES;
433 inst->bSize = sizeof(*pv);
434 inst->wCount = 1;
436 pv->dwFlags = flags;
437 pv->wStart = base_idx;
438 pv->wDest = 0;
439 pv->dwCount = vertex_count;
440 pv->dwReserved = 0;
442 *ptr = pv + 1;
445 static void emit_set_ts(void **ptr, D3DTRANSFORMSTATETYPE state, DWORD value)
447 D3DINSTRUCTION *inst = *ptr;
448 D3DSTATE *ts = (D3DSTATE *)(inst + 1);
450 inst->bOpcode = D3DOP_STATETRANSFORM;
451 inst->bSize = sizeof(*ts);
452 inst->wCount = 1;
454 U1(*ts).dtstTransformStateType = state;
455 U2(*ts).dwArg[0] = value;
457 *ptr = ts + 1;
460 static void emit_set_ls(void **ptr, D3DLIGHTSTATETYPE state, DWORD value)
462 D3DINSTRUCTION *inst = *ptr;
463 D3DSTATE *ls = (D3DSTATE *)(inst + 1);
465 inst->bOpcode = D3DOP_STATELIGHT;
466 inst->bSize = sizeof(*ls);
467 inst->wCount = 1;
469 U1(*ls).dlstLightStateType = state;
470 U2(*ls).dwArg[0] = value;
472 *ptr = ls + 1;
475 static void emit_set_rs(void **ptr, D3DRENDERSTATETYPE state, DWORD value)
477 D3DINSTRUCTION *inst = *ptr;
478 D3DSTATE *rs = (D3DSTATE *)(inst + 1);
480 inst->bOpcode = D3DOP_STATERENDER;
481 inst->bSize = sizeof(*rs);
482 inst->wCount = 1;
484 U1(*rs).drstRenderStateType = state;
485 U2(*rs).dwArg[0] = value;
487 *ptr = rs + 1;
490 static void emit_tquad(void **ptr, WORD base_idx)
492 D3DINSTRUCTION *inst = *ptr;
493 D3DTRIANGLE *tri = (D3DTRIANGLE *)(inst + 1);
495 inst->bOpcode = D3DOP_TRIANGLE;
496 inst->bSize = sizeof(*tri);
497 inst->wCount = 2;
499 U1(*tri).v1 = base_idx;
500 U2(*tri).v2 = base_idx + 1;
501 U3(*tri).v3 = base_idx + 2;
502 tri->wFlags = D3DTRIFLAG_START;
503 ++tri;
505 U1(*tri).v1 = base_idx + 2;
506 U2(*tri).v2 = base_idx + 1;
507 U3(*tri).v3 = base_idx + 3;
508 tri->wFlags = D3DTRIFLAG_ODD;
509 ++tri;
511 *ptr = tri;
514 static void emit_tquad_tlist(void **ptr, WORD base_idx)
516 D3DINSTRUCTION *inst = *ptr;
517 D3DTRIANGLE *tri = (D3DTRIANGLE *)(inst + 1);
519 inst->bOpcode = D3DOP_TRIANGLE;
520 inst->bSize = sizeof(*tri);
521 inst->wCount = 2;
523 U1(*tri).v1 = base_idx;
524 U2(*tri).v2 = base_idx + 1;
525 U3(*tri).v3 = base_idx + 2;
526 tri->wFlags = D3DTRIFLAG_START;
527 ++tri;
529 U1(*tri).v1 = base_idx + 2;
530 U2(*tri).v2 = base_idx + 3;
531 U3(*tri).v3 = base_idx;
532 tri->wFlags = D3DTRIFLAG_START;
533 ++tri;
535 *ptr = tri;
538 static void emit_tri_indices(void **ptr, WORD *indices, unsigned int primitive_count)
540 D3DINSTRUCTION *inst = *ptr;
541 D3DTRIANGLE *tri = (D3DTRIANGLE *)(inst + 1);
542 unsigned int i;
544 inst->bOpcode = D3DOP_TRIANGLE;
545 inst->bSize = sizeof(*tri);
546 inst->wCount = primitive_count;
548 for (i = 0; i < primitive_count; ++i)
550 U1(*tri).v1 = indices[i * 3];
551 U2(*tri).v2 = indices[i * 3 + 1];
552 U3(*tri).v3 = indices[i * 3 + 2];
553 tri->wFlags = D3DTRIFLAG_START;
554 ++tri;
556 *ptr = tri;
559 static void emit_texture_load(void **ptr, D3DTEXTUREHANDLE dst_texture,
560 D3DTEXTUREHANDLE src_texture)
562 D3DINSTRUCTION *instruction = *ptr;
563 D3DTEXTURELOAD *texture_load = (D3DTEXTURELOAD *)(instruction + 1);
565 instruction->bOpcode = D3DOP_TEXTURELOAD;
566 instruction->bSize = sizeof(*texture_load);
567 instruction->wCount = 1;
569 texture_load->hDestTexture = dst_texture;
570 texture_load->hSrcTexture = src_texture;
571 ++texture_load;
573 *ptr = texture_load;
576 static void emit_end(void **ptr)
578 D3DINSTRUCTION *inst = *ptr;
580 inst->bOpcode = D3DOP_EXIT;
581 inst->bSize = 0;
582 inst->wCount = 0;
584 *ptr = inst + 1;
587 static void set_execute_data(IDirect3DExecuteBuffer *execute_buffer, UINT vertex_count, UINT offset, UINT len)
589 D3DEXECUTEDATA exec_data;
590 HRESULT hr;
592 memset(&exec_data, 0, sizeof(exec_data));
593 exec_data.dwSize = sizeof(exec_data);
594 exec_data.dwVertexCount = vertex_count;
595 exec_data.dwInstructionOffset = offset;
596 exec_data.dwInstructionLength = len;
597 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
598 ok(SUCCEEDED(hr), "Failed to set execute data, hr %#lx.\n", hr);
601 static DWORD get_device_z_depth(IDirect3DDevice *device)
603 DDSCAPS caps = {DDSCAPS_ZBUFFER};
604 IDirectDrawSurface *ds, *rt;
605 DDSURFACEDESC desc;
606 HRESULT hr;
608 if (FAILED(IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt)))
609 return 0;
611 hr = IDirectDrawSurface_GetAttachedSurface(rt, &caps, &ds);
612 IDirectDrawSurface_Release(rt);
613 if (FAILED(hr))
614 return 0;
616 desc.dwSize = sizeof(desc);
617 hr = IDirectDrawSurface_GetSurfaceDesc(ds, &desc);
618 IDirectDrawSurface_Release(ds);
619 if (FAILED(hr))
620 return 0;
622 return U2(desc).dwZBufferBitDepth;
625 static IDirectDraw *create_ddraw(void)
627 IDirectDraw *ddraw;
629 if (FAILED(DirectDrawCreate(NULL, &ddraw, NULL)))
630 return NULL;
632 return ddraw;
635 static IDirect3DDevice *create_device_ex(IDirectDraw *ddraw, HWND window, DWORD coop_level, const GUID *device_guid)
637 /* Prefer 16 bit depth buffers because Nvidia gives us an unpadded D24 buffer if we ask
638 * for 24 bit and handles such buffers incorrectly in DDBLT_DEPTHFILL. AMD only supports
639 * 16 bit buffers in ddraw1/2. Stencil was added in ddraw4, so we cannot create a D24S8
640 * buffer here. */
641 static const DWORD z_depths[] = {16, 32, 24};
642 IDirectDrawSurface *surface, *ds;
643 IDirect3DDevice *device = NULL;
644 DDSURFACEDESC surface_desc;
645 unsigned int i;
646 HRESULT hr;
648 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, coop_level);
649 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
651 memset(&surface_desc, 0, sizeof(surface_desc));
652 surface_desc.dwSize = sizeof(surface_desc);
653 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
654 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
655 if (is_software_device_type(device_guid))
656 surface_desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
657 surface_desc.dwWidth = 640;
658 surface_desc.dwHeight = 480;
660 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
661 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
663 if (coop_level & DDSCL_NORMAL)
665 IDirectDrawClipper *clipper;
667 hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
668 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
669 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
670 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
671 hr = IDirectDrawSurface_SetClipper(surface, clipper);
672 ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#lx.\n", hr);
673 IDirectDrawClipper_Release(clipper);
676 /* We used to use EnumDevices() for this, but it seems
677 * D3DDEVICEDESC.dwDeviceZBufferBitDepth only has a very casual
678 * relationship with reality. */
679 for (i = 0; i < ARRAY_SIZE(z_depths); ++i)
681 memset(&surface_desc, 0, sizeof(surface_desc));
682 surface_desc.dwSize = sizeof(surface_desc);
683 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
684 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
685 if (is_software_device_type(device_guid))
686 surface_desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
687 U2(surface_desc).dwZBufferBitDepth = z_depths[i];
688 surface_desc.dwWidth = 640;
689 surface_desc.dwHeight = 480;
690 if (FAILED(IDirectDraw_CreateSurface(ddraw, &surface_desc, &ds, NULL)))
691 continue;
693 hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
694 ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#lx.\n", hr);
695 IDirectDrawSurface_Release(ds);
696 if (FAILED(hr))
697 continue;
699 if (SUCCEEDED(IDirectDrawSurface_QueryInterface(surface, device_guid, (void **)&device)))
700 break;
702 IDirectDrawSurface_DeleteAttachedSurface(surface, 0, ds);
705 IDirectDrawSurface_Release(surface);
706 return device;
709 static IDirect3DDevice *create_device(IDirectDraw *ddraw, HWND window, DWORD coop_level)
711 return create_device_ex(ddraw, window, coop_level, &IID_IDirect3DHALDevice);
714 static IDirect3DViewport *create_viewport(IDirect3DDevice *device, UINT x, UINT y, UINT w, UINT h)
716 IDirect3DViewport *viewport;
717 D3DVIEWPORT vp;
718 IDirect3D *d3d;
719 HRESULT hr;
721 hr = IDirect3DDevice_GetDirect3D(device, &d3d);
722 ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#lx.\n", hr);
723 hr = IDirect3D_CreateViewport(d3d, &viewport, NULL);
724 ok(SUCCEEDED(hr), "Failed to create viewport, hr %#lx.\n", hr);
725 hr = IDirect3DDevice_AddViewport(device, viewport);
726 ok(SUCCEEDED(hr), "Failed to add viewport, hr %#lx.\n", hr);
727 memset(&vp, 0, sizeof(vp));
728 vp.dwSize = sizeof(vp);
729 vp.dwX = x;
730 vp.dwY = y;
731 vp.dwWidth = w;
732 vp.dwHeight = h;
733 vp.dvScaleX = (float)w / 2.0f;
734 vp.dvScaleY = (float)h / 2.0f;
735 vp.dvMaxX = 1.0f;
736 vp.dvMaxY = 1.0f;
737 vp.dvMinZ = 0.0f;
738 vp.dvMaxZ = 1.0f;
739 hr = IDirect3DViewport_SetViewport(viewport, &vp);
740 ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#lx.\n", hr);
741 IDirect3D_Release(d3d);
743 return viewport;
746 static void viewport_set_background(IDirect3DDevice *device, IDirect3DViewport *viewport,
747 IDirect3DMaterial *material)
749 D3DMATERIALHANDLE material_handle;
750 HRESULT hr;
752 hr = IDirect3DMaterial2_GetHandle(material, device, &material_handle);
753 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#lx.\n", hr);
754 hr = IDirect3DViewport2_SetBackground(viewport, material_handle);
755 ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#lx.\n", hr);
758 static void destroy_viewport(IDirect3DDevice *device, IDirect3DViewport *viewport)
760 HRESULT hr;
762 hr = IDirect3DDevice_DeleteViewport(device, viewport);
763 ok(SUCCEEDED(hr), "Failed to delete viewport, hr %#lx.\n", hr);
764 IDirect3DViewport_Release(viewport);
767 static IDirect3DMaterial *create_material(IDirect3DDevice *device, D3DMATERIAL *mat)
769 IDirect3DMaterial *material;
770 IDirect3D *d3d;
771 HRESULT hr;
773 hr = IDirect3DDevice_GetDirect3D(device, &d3d);
774 ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#lx.\n", hr);
775 hr = IDirect3D_CreateMaterial(d3d, &material, NULL);
776 ok(SUCCEEDED(hr), "Failed to create material, hr %#lx.\n", hr);
777 hr = IDirect3DMaterial_SetMaterial(material, mat);
778 ok(SUCCEEDED(hr), "Failed to set material data, hr %#lx.\n", hr);
779 IDirect3D_Release(d3d);
781 return material;
784 static IDirect3DMaterial *create_diffuse_material(IDirect3DDevice *device, float r, float g, float b, float a)
786 D3DMATERIAL mat;
788 memset(&mat, 0, sizeof(mat));
789 mat.dwSize = sizeof(mat);
790 U1(U(mat).diffuse).r = r;
791 U2(U(mat).diffuse).g = g;
792 U3(U(mat).diffuse).b = b;
793 U4(U(mat).diffuse).a = a;
795 return create_material(device, &mat);
798 static IDirect3DMaterial *create_diffuse_and_ambient_material(IDirect3DDevice *device,
799 float r, float g, float b, float a)
801 D3DMATERIAL mat;
803 memset(&mat, 0, sizeof(mat));
804 mat.dwSize = sizeof(mat);
805 U1(U(mat).diffuse).r = r;
806 U2(U(mat).diffuse).g = g;
807 U3(U(mat).diffuse).b = b;
808 U4(U(mat).diffuse).a = a;
810 U1(U(mat).ambient).r = r;
811 U2(U(mat).ambient).g = g;
812 U3(U(mat).ambient).b = b;
813 U4(U(mat).ambient).a = a;
815 return create_material(device, &mat);
818 static IDirect3DMaterial *create_emissive_material(IDirect3DDevice *device, float r, float g, float b, float a)
820 D3DMATERIAL mat;
822 memset(&mat, 0, sizeof(mat));
823 mat.dwSize = sizeof(mat);
824 U1(U3(mat).emissive).r = r;
825 U2(U3(mat).emissive).g = g;
826 U3(U3(mat).emissive).b = b;
827 U4(U3(mat).emissive).a = a;
829 return create_material(device, &mat);
832 static IDirect3DMaterial *create_specular_material(IDirect3DDevice *device,
833 float r, float g, float b, float a, float power)
835 D3DMATERIAL mat;
837 memset(&mat, 0, sizeof(mat));
838 mat.dwSize = sizeof(mat);
839 U1(U2(mat).specular).r = r;
840 U2(U2(mat).specular).g = g;
841 U3(U2(mat).specular).b = b;
842 U4(U2(mat).specular).a = a;
843 U4(mat).power = power;
845 return create_material(device, &mat);
848 static void destroy_material(IDirect3DMaterial *material)
850 IDirect3DMaterial_Release(material);
853 struct message
855 UINT message;
856 BOOL check_wparam;
857 WPARAM expect_wparam;
860 static const struct message *expect_messages;
862 static LRESULT CALLBACK test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
864 if (expect_messages && message == expect_messages->message)
866 if (expect_messages->check_wparam)
867 ok (wparam == expect_messages->expect_wparam,
868 "Got unexpected wparam %#Ix for message %#x, expected %#Ix.\n",
869 wparam, message, expect_messages->expect_wparam);
871 ++expect_messages;
874 return DefWindowProcA(hwnd, message, wparam, lparam);
877 /* Set the wndproc back to what ddraw expects it to be, and release the ddraw
878 * interface. This prevents subsequent SetCooperativeLevel() calls on a
879 * different window from failing with DDERR_HWNDALREADYSET. */
880 static void fix_wndproc(HWND window, LONG_PTR proc)
882 IDirectDraw *ddraw;
883 HRESULT hr;
885 if (!(ddraw = create_ddraw()))
886 return;
888 SetWindowLongPtrA(window, GWLP_WNDPROC, proc);
889 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
890 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
891 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
892 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
894 IDirectDraw_Release(ddraw);
897 static HRESULT CALLBACK restore_callback(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
899 HRESULT hr = IDirectDrawSurface_Restore(surface);
900 ok(SUCCEEDED(hr) || hr == DDERR_IMPLICITLYCREATED, "Failed to restore surface, hr %#lx.\n", hr);
901 IDirectDrawSurface_Release(surface);
903 return DDENUMRET_OK;
906 static HRESULT restore_surfaces(IDirectDraw *ddraw)
908 return IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_ALL | DDENUMSURFACES_DOESEXIST,
909 NULL, NULL, restore_callback);
912 static void test_coop_level_create_device_window(void)
914 HWND focus_window, device_window;
915 IDirectDraw *ddraw;
916 HRESULT hr;
918 focus_window = create_window();
919 ddraw = create_ddraw();
920 ok(!!ddraw, "Failed to create a ddraw object.\n");
922 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
923 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
924 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
925 ok(!device_window, "Unexpected device window found.\n");
926 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW);
927 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
928 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
929 ok(!device_window, "Unexpected device window found.\n");
930 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL);
931 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
932 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
933 ok(!device_window, "Unexpected device window found.\n");
934 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL | DDSCL_FULLSCREEN);
935 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
936 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
937 ok(!device_window, "Unexpected device window found.\n");
938 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
939 ok(hr == DDERR_NOFOCUSWINDOW || broken(hr == DDERR_INVALIDPARAMS), "Got unexpected hr %#lx.\n", hr);
940 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
941 ok(!device_window, "Unexpected device window found.\n");
943 /* Windows versions before 98 / NT5 don't support DDSCL_CREATEDEVICEWINDOW. */
944 if (broken(hr == DDERR_INVALIDPARAMS))
946 win_skip("DDSCL_CREATEDEVICEWINDOW not supported, skipping test.\n");
947 IDirectDraw_Release(ddraw);
948 DestroyWindow(focus_window);
949 return;
952 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
953 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
954 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
955 ok(!device_window, "Unexpected device window found.\n");
956 hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
957 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
958 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
959 ok(!device_window, "Unexpected device window found.\n");
961 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
962 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
963 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
964 ok(!device_window, "Unexpected device window found.\n");
965 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_SETFOCUSWINDOW
966 | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
967 ok(hr == DDERR_NOHWND, "Got unexpected hr %#lx.\n", hr);
968 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
969 ok(!!device_window, "Device window not found.\n");
971 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
972 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
973 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
974 ok(!device_window, "Unexpected device window found.\n");
975 hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW
976 | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
977 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
978 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
979 ok(!!device_window, "Device window not found.\n");
981 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
982 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
983 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
984 ok(!device_window, "Unexpected device window found.\n");
985 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
986 ok(hr == DDERR_NOFOCUSWINDOW, "Got unexpected hr %#lx.\n", hr);
987 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
988 ok(!device_window, "Unexpected device window found.\n");
989 hr = IDirectDraw_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW);
990 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
991 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
992 ok(!device_window, "Unexpected device window found.\n");
993 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
994 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
995 device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
996 ok(!!device_window, "Device window not found.\n");
998 IDirectDraw_Release(ddraw);
999 DestroyWindow(focus_window);
1002 static void test_clipper_blt(void)
1004 IDirectDrawSurface *src_surface, *dst_surface;
1005 unsigned int color, i, j, x, y;
1006 RECT client_rect, src_rect;
1007 IDirectDrawClipper *clipper;
1008 DDSURFACEDESC surface_desc;
1009 IDirectDraw *ddraw;
1010 RGNDATA *rgn_data;
1011 ULONG refcount;
1012 HRGN r1, r2;
1013 HWND window;
1014 DDBLTFX fx;
1015 HRESULT hr;
1016 DWORD *ptr;
1017 DWORD ret;
1019 static const DWORD src_data[] =
1021 0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
1022 0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
1023 0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
1025 static const unsigned int expected1[] =
1027 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
1028 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
1029 0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
1030 0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
1032 /* Nvidia on Windows seems to have an off-by-one error
1033 * when processing source rectangles. Our left = 1 and
1034 * right = 5 input reads from x = {1, 2, 3}. x = 4 is
1035 * read as well, but only for the edge pixels on the
1036 * output image. The bug happens on the y axis as well,
1037 * but we only read one row there, and all source rows
1038 * contain the same data. This bug is not dependent on
1039 * the presence of a clipper. */
1040 static const D3DCOLOR expected1_broken[] =
1042 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
1043 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
1044 0x00000000, 0x00000000, 0x00ff0000, 0x00ff0000,
1045 0x00000000, 0x00000000, 0x0000ff00, 0x00ff0000,
1047 static const unsigned int expected2[] =
1049 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
1050 0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
1051 0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
1052 0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
1055 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1056 10, 10, 640, 480, 0, 0, 0, 0);
1057 ShowWindow(window, SW_SHOW);
1058 ddraw = create_ddraw();
1059 ok(!!ddraw, "Failed to create a ddraw object.\n");
1061 ret = GetClientRect(window, &client_rect);
1062 ok(ret, "Failed to get client rect.\n");
1063 ret = MapWindowPoints(window, NULL, (POINT *)&client_rect, 2);
1064 ok(ret, "Failed to map client rect.\n");
1066 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
1067 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
1069 hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
1070 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
1071 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
1072 ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#lx.\n", hr);
1073 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
1074 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
1075 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
1076 ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#lx.\n", hr);
1077 rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
1078 hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret);
1079 ok(SUCCEEDED(hr), "Failed to get clip list, hr %#lx.\n", hr);
1080 ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#lx.\n", rgn_data->rdh.dwSize);
1081 ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#lx.\n", rgn_data->rdh.iType);
1082 ok(rgn_data->rdh.nCount >= 1, "Got unexpected count %lu.\n", rgn_data->rdh.nCount);
1083 ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
1084 "Got unexpected bounding rect %s, expected %s.\n",
1085 wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&client_rect));
1086 HeapFree(GetProcessHeap(), 0, rgn_data);
1088 r1 = CreateRectRgn(0, 0, 320, 240);
1089 ok(!!r1, "Failed to create region.\n");
1090 r2 = CreateRectRgn(320, 240, 640, 480);
1091 ok(!!r2, "Failed to create region.\n");
1092 CombineRgn(r1, r1, r2, RGN_OR);
1093 ret = GetRegionData(r1, 0, NULL);
1094 rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
1095 ret = GetRegionData(r1, ret, rgn_data);
1096 ok(!!ret, "Failed to get region data.\n");
1098 DeleteObject(r2);
1099 DeleteObject(r1);
1101 hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
1102 ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#lx.\n", hr);
1103 hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
1104 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
1105 hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
1106 ok(SUCCEEDED(hr), "Failed to set clip list, hr %#lx.\n", hr);
1108 HeapFree(GetProcessHeap(), 0, rgn_data);
1110 memset(&surface_desc, 0, sizeof(surface_desc));
1111 surface_desc.dwSize = sizeof(surface_desc);
1112 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
1113 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
1114 surface_desc.dwWidth = 640;
1115 surface_desc.dwHeight = 480;
1116 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1117 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
1118 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1119 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1120 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1121 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1123 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
1124 ok(SUCCEEDED(hr), "Failed to create source surface, hr %#lx.\n", hr);
1125 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
1126 ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#lx.\n", hr);
1128 memset(&fx, 0, sizeof(fx));
1129 fx.dwSize = sizeof(fx);
1130 hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1131 ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#lx.\n", hr);
1132 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1133 ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#lx.\n", hr);
1135 hr = IDirectDrawSurface_Lock(src_surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
1136 ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#lx.\n", hr);
1137 ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %lu.\n", U1(surface_desc).lPitch);
1138 ptr = surface_desc.lpSurface;
1139 memcpy(&ptr[ 0], &src_data[ 0], 6 * sizeof(DWORD));
1140 memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
1141 memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
1142 hr = IDirectDrawSurface_Unlock(src_surface, NULL);
1143 ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#lx.\n", hr);
1145 hr = IDirectDrawSurface_SetClipper(dst_surface, clipper);
1146 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
1148 SetRect(&src_rect, 1, 1, 5, 2);
1149 hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
1150 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
1151 for (i = 0; i < 4; ++i)
1153 for (j = 0; j < 4; ++j)
1155 x = 80 * ((2 * j) + 1);
1156 y = 60 * ((2 * i) + 1);
1157 color = get_surface_color(dst_surface, x, y);
1158 ok(compare_color(color, expected1[i * 4 + j], 1)
1159 || broken(compare_color(color, expected1_broken[i * 4 + j], 1)),
1160 "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
1164 U5(fx).dwFillColor = 0xff0000ff;
1165 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1166 ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#lx.\n", hr);
1167 for (i = 0; i < 4; ++i)
1169 for (j = 0; j < 4; ++j)
1171 x = 80 * ((2 * j) + 1);
1172 y = 60 * ((2 * i) + 1);
1173 color = get_surface_color(dst_surface, x, y);
1174 ok(compare_color(color, expected2[i * 4 + j], 1),
1175 "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
1179 hr = IDirectDrawSurface_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
1180 ok(hr == DDERR_BLTFASTCANTCLIP || broken(hr == E_NOTIMPL /* NT4 */), "Got unexpected hr %#lx.\n", hr);
1182 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
1183 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
1184 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
1185 ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#lx.\n", hr);
1186 DestroyWindow(window);
1187 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
1188 ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr);
1189 hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
1190 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
1191 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
1192 ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#lx.\n", hr);
1193 hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
1194 ok(SUCCEEDED(hr), "Failed to set clip list, hr %#lx.\n", hr);
1195 hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
1196 ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#lx.\n", hr);
1197 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1198 ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#lx.\n", hr);
1200 IDirectDrawSurface_Release(dst_surface);
1201 IDirectDrawSurface_Release(src_surface);
1202 refcount = IDirectDrawClipper_Release(clipper);
1203 ok(!refcount, "Clipper has %lu references left.\n", refcount);
1204 IDirectDraw_Release(ddraw);
1207 static void test_coop_level_d3d_state(void)
1209 D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1210 IDirectDrawSurface *rt, *surface;
1211 IDirect3DMaterial *background;
1212 IDirect3DViewport *viewport;
1213 IDirect3DDevice *device;
1214 D3DMATERIAL material;
1215 DDSURFACEDESC lock;
1216 unsigned int color;
1217 IDirectDraw *ddraw;
1218 HWND window;
1219 HRESULT hr;
1221 window = create_window();
1222 ddraw = create_ddraw();
1223 ok(!!ddraw, "Failed to create a ddraw object.\n");
1224 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1226 skip("Failed to create a 3D device, skipping test.\n");
1227 IDirectDraw_Release(ddraw);
1228 DestroyWindow(window);
1229 return;
1232 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1233 viewport = create_viewport(device, 0, 0, 640, 480);
1234 viewport_set_background(device, viewport, background);
1236 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
1237 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1238 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1239 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1240 color = get_surface_color(rt, 320, 240);
1241 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
1243 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1244 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1245 hr = IDirectDrawSurface_IsLost(rt);
1246 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
1248 memset(&lock, 0, sizeof(lock));
1249 lock.dwSize = sizeof(lock);
1250 lock.lpSurface = (void *)0xdeadbeef;
1251 hr = IDirectDrawSurface_Lock(rt, NULL, &lock, DDLOCK_READONLY, NULL);
1252 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
1253 ok(lock.lpSurface == (void *)0xdeadbeef, "Got unexpected lock.lpSurface %p.\n", lock.lpSurface);
1255 hr = restore_surfaces(ddraw);
1256 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1258 hr = IDirectDrawSurface_Lock(rt, NULL, &lock, DDLOCK_READONLY, NULL);
1259 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1260 hr = IDirectDrawSurface2_Unlock(rt, NULL);
1261 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1263 memset(&material, 0, sizeof(material));
1264 material.dwSize = sizeof(material);
1265 U1(U(material).diffuse).r = 0.0f;
1266 U2(U(material).diffuse).g = 1.0f;
1267 U3(U(material).diffuse).b = 0.0f;
1268 U4(U(material).diffuse).a = 1.0f;
1269 hr = IDirect3DMaterial_SetMaterial(background, &material);
1270 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1272 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&surface);
1273 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1274 ok(surface == rt, "Got unexpected surface %p.\n", surface);
1275 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1276 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1277 color = get_surface_color(rt, 320, 240);
1278 ok(compare_color(color, 0x0000ff00, 1) || broken(compare_color(color, 0x00000000, 1)),
1279 "Got unexpected color 0x%08x.\n", color);
1281 destroy_viewport(device, viewport);
1282 destroy_material(background);
1283 IDirectDrawSurface_Release(surface);
1284 IDirectDrawSurface_Release(rt);
1285 IDirect3DDevice_Release(device);
1286 IDirectDraw_Release(ddraw);
1287 DestroyWindow(window);
1290 static void test_surface_interface_mismatch(void)
1292 IDirectDraw *ddraw = NULL;
1293 IDirectDrawSurface *surface = NULL, *ds;
1294 IDirectDrawSurface3 *surface3 = NULL;
1295 IDirect3DDevice *device = NULL;
1296 IDirect3DViewport *viewport = NULL;
1297 IDirect3DMaterial *background = NULL;
1298 DDSURFACEDESC surface_desc;
1299 unsigned int color;
1300 DWORD z_depth = 0;
1301 ULONG refcount;
1302 HRESULT hr;
1303 HWND window;
1304 D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1306 window = create_window();
1307 ddraw = create_ddraw();
1308 ok(!!ddraw, "Failed to create a ddraw object.\n");
1309 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1311 skip("Failed to create a 3D device, skipping test.\n");
1312 IDirectDraw_Release(ddraw);
1313 DestroyWindow(window);
1314 return;
1316 z_depth = get_device_z_depth(device);
1317 ok(!!z_depth, "Failed to get device z depth.\n");
1318 IDirect3DDevice_Release(device);
1319 device = NULL;
1321 memset(&surface_desc, 0, sizeof(surface_desc));
1322 surface_desc.dwSize = sizeof(surface_desc);
1323 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1324 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
1325 surface_desc.dwWidth = 640;
1326 surface_desc.dwHeight = 480;
1328 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1329 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
1331 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
1332 if (FAILED(hr))
1334 skip("Failed to get the IDirectDrawSurface3 interface, skipping test.\n");
1335 goto cleanup;
1338 memset(&surface_desc, 0, sizeof(surface_desc));
1339 surface_desc.dwSize = sizeof(surface_desc);
1340 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
1341 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
1342 U2(surface_desc).dwZBufferBitDepth = z_depth;
1343 surface_desc.dwWidth = 640;
1344 surface_desc.dwHeight = 480;
1345 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &ds, NULL);
1346 ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#lx.\n", hr);
1347 if (FAILED(hr))
1348 goto cleanup;
1350 /* Using a different surface interface version still works */
1351 hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
1352 ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#lx.\n", hr);
1353 refcount = IDirectDrawSurface_Release(ds);
1354 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
1355 if (FAILED(hr))
1356 goto cleanup;
1358 /* Here too */
1359 hr = IDirectDrawSurface3_QueryInterface(surface3, &IID_IDirect3DHALDevice, (void **)&device);
1360 ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
1361 if (FAILED(hr))
1362 goto cleanup;
1364 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1365 viewport = create_viewport(device, 0, 0, 640, 480);
1366 viewport_set_background(device, viewport, background);
1368 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1369 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
1370 color = get_surface_color(surface, 320, 240);
1371 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
1373 cleanup:
1374 if (viewport)
1375 destroy_viewport(device, viewport);
1376 if (background)
1377 destroy_material(background);
1378 if (surface3) IDirectDrawSurface3_Release(surface3);
1379 if (surface) IDirectDrawSurface_Release(surface);
1380 if (device) IDirect3DDevice_Release(device);
1381 if (ddraw) IDirectDraw_Release(ddraw);
1382 DestroyWindow(window);
1385 static void test_coop_level_threaded(void)
1387 struct create_window_thread_param p;
1388 IDirectDraw *ddraw;
1389 HRESULT hr;
1391 ddraw = create_ddraw();
1392 ok(!!ddraw, "Failed to create a ddraw object.\n");
1393 create_window_thread(&p);
1395 hr = IDirectDraw_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1396 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
1398 destroy_window_thread(&p);
1399 IDirectDraw_Release(ddraw);
1402 static BOOL compare_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
1404 return mode1->dmPosition.x == mode2->dmPosition.x
1405 && mode1->dmPosition.y == mode2->dmPosition.y
1406 && mode1->dmPelsWidth == mode2->dmPelsWidth
1407 && mode1->dmPelsHeight == mode2->dmPelsHeight;
1410 static ULONG get_refcount(IUnknown *test_iface)
1412 IUnknown_AddRef(test_iface);
1413 return IUnknown_Release(test_iface);
1416 static void test_viewport_object(void)
1418 IDirect3DViewport *viewport, *another_vp;
1419 IDirectDrawGammaControl *gamma;
1420 IDirect3DViewport2 *viewport2;
1421 IDirect3DViewport3 *viewport3;
1422 IDirect3DDevice *device;
1423 IUnknown *unknown;
1424 IDirectDraw *ddraw;
1425 D3DVIEWPORT2 vp2;
1426 D3DVIEWPORT vp;
1427 IDirect3D *d3d;
1428 HWND window;
1429 HRESULT hr;
1430 ULONG ref;
1431 union
1433 D3DVIEWPORT vp1;
1434 BYTE blob[1024];
1435 } desc;
1437 window = create_window();
1438 ddraw = create_ddraw();
1439 ok(!!ddraw, "Failed to create a ddraw object.\n");
1440 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1442 skip("Failed to create a 3D device, skipping test.\n");
1443 IDirectDraw_Release(ddraw);
1444 DestroyWindow(window);
1445 return;
1448 hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
1449 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1450 ref = get_refcount((IUnknown *) d3d);
1451 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1453 hr = IDirect3D_CreateViewport(d3d, &viewport, NULL);
1454 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1455 ref = get_refcount((IUnknown *)viewport);
1456 ok(ref == 1, "Got unexpected refcount %lu.\n", ref);
1457 ref = get_refcount((IUnknown *)d3d);
1458 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1460 memset(&desc, 0, sizeof(desc));
1461 hr = IDirect3DViewport_GetViewport(viewport, &desc.vp1);
1462 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1463 desc.vp1.dwSize = sizeof(desc.vp1) + 1;
1464 hr = IDirect3DViewport_GetViewport(viewport, &desc.vp1);
1465 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1466 desc.vp1.dwSize = sizeof(desc.vp1) - 1;
1467 hr = IDirect3DViewport_GetViewport(viewport, &desc.vp1);
1468 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1469 desc.vp1.dwSize = sizeof(desc.vp1);
1470 hr = IDirect3DViewport_GetViewport(viewport, &desc.vp1);
1471 ok(hr == D3DERR_VIEWPORTDATANOTSET, "Got unexpected hr %#lx.\n", hr);
1472 ok(desc.vp1.dwSize == sizeof(desc.vp1), "Got unexpected dwSize %lu.\n", desc.vp1.dwSize);
1474 /* E_FAIL return values are returned by Winetestbot Windows NT machines. While not supporting
1475 * newer interfaces is legitimate for old ddraw versions, E_FAIL violates Microsoft's rules
1476 * for QueryInterface, hence the broken() */
1477 gamma = (IDirectDrawGammaControl *)0xdeadbeef;
1478 hr = IDirect3DViewport_QueryInterface(viewport, &IID_IDirectDrawGammaControl, (void **)&gamma);
1479 ok(hr == E_NOINTERFACE || broken(hr == E_FAIL), "Got unexpected hr %#lx.\n", hr);
1480 ok(gamma == NULL, "Interface not set to NULL by failed QI call: %p\n", gamma);
1482 hr = IDirect3DViewport_QueryInterface(viewport, &IID_IDirect3DViewport2, (void **)&viewport2);
1483 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1485 ref = get_refcount((IUnknown *)viewport);
1486 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1487 ref = get_refcount((IUnknown *)viewport2);
1488 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1490 hr = IDirect3DViewport_QueryInterface(viewport, &IID_IDirect3DViewport3, (void **)&viewport3);
1491 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1493 ref = get_refcount((IUnknown *)viewport);
1494 ok(ref == 3, "Got unexpected refcount %lu.\n", ref);
1495 ref = get_refcount((IUnknown *)viewport3);
1496 ok(ref == 3, "Got unexpected refcount %lu.\n", ref);
1497 IDirect3DViewport3_Release(viewport3);
1499 hr = IDirect3DViewport_QueryInterface(viewport, &IID_IUnknown, (void **)&unknown);
1500 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1501 ref = get_refcount((IUnknown *)viewport);
1502 ok(ref == 3, "Got unexpected refcount %lu.\n", ref);
1503 ref = get_refcount(unknown);
1504 ok(ref == 3, "Got unexpected refcount %lu.\n", ref);
1505 IUnknown_Release(unknown);
1507 hr = IDirect3DDevice_DeleteViewport(device, NULL);
1508 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1510 hr = IDirect3D_CreateViewport(d3d, &another_vp, NULL);
1511 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1513 /* AddViewport(NULL): Segfault */
1514 hr = IDirect3DDevice_AddViewport(device, viewport);
1515 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1516 ref = get_refcount((IUnknown *) viewport);
1517 ok(ref == 3, "Got unexpected refcount %lu.\n", ref);
1518 hr = IDirect3DDevice_AddViewport(device, another_vp);
1519 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1520 ref = get_refcount((IUnknown *) another_vp);
1521 ok(ref == 2, "Got unexpected refcount %lu.\n", ref);
1523 memset(&vp, 0, sizeof(vp));
1524 vp.dwX = 0;
1525 vp.dwY = 0;
1526 vp.dwWidth = 640;
1527 vp.dwHeight = 480;
1528 vp.dvMinZ = 0.0f;
1529 vp.dvMaxZ = 1.0f;
1530 vp.dvScaleX = vp.dwWidth / 2.0f;
1531 vp.dvScaleY = vp.dwHeight / 2.0f;
1532 vp.dvMaxX = 1.0f;
1533 vp.dvMaxY = 1.0f;
1534 hr = IDirect3DViewport_SetViewport(viewport, &vp);
1535 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
1537 vp.dwSize = sizeof(vp);
1538 hr = IDirect3DViewport_SetViewport(viewport, &vp);
1539 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1541 vp2.dwSize = sizeof(vp2);
1542 vp2.dwX = 160;
1543 vp2.dwY = 120;
1544 vp2.dwWidth = 640 - vp2.dwX;
1545 vp2.dwHeight = 480 - vp2.dwY;
1546 vp2.dvClipX = 2.0f;
1547 vp2.dvClipY = -1.75f;
1548 vp2.dvClipWidth = 2.5f;
1549 vp2.dvClipHeight = -1.5f;
1550 vp2.dvMinZ = 0.5f;
1551 vp2.dvMaxZ = 2.0f;
1552 hr = IDirect3DViewport2_SetViewport2(viewport2, &vp2);
1553 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1555 memset(&vp, 0xff, sizeof(vp));
1556 vp.dwSize = sizeof(vp);
1557 hr = IDirect3DViewport2_GetViewport(viewport2, &vp);
1558 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1559 ok(vp.dvMaxX == 4.5f && vp.dvMaxY == -1.75f && vp.dvScaleX == 192.0f
1560 && vp.dvScaleY == -240.0f && vp.dvMinZ == 0.0f && vp.dvMaxZ == 1.0f,
1561 "Got unexpected values %g, %g, %g, %g, %g, %g.\n",
1562 vp.dvMaxX, vp.dvMaxY, vp.dvScaleX, vp.dvScaleY, vp.dvMinZ, vp.dvMaxZ);
1564 vp2.dvClipX = -1.5f;
1565 vp2.dvClipY = 1.75f;
1566 vp2.dvClipWidth = -1.5f;
1567 vp2.dvClipHeight = 2.0f;
1568 vp2.dvMinZ = 2.0f;
1569 vp2.dvMaxZ = 0.5f;
1571 hr = IDirect3DViewport2_SetViewport2(viewport2, &vp2);
1572 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1574 memset(&vp, 0xff, sizeof(vp));
1575 vp.dwSize = sizeof(vp);
1576 hr = IDirect3DViewport2_GetViewport(viewport2, &vp);
1577 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1578 ok(vp.dvMaxX == -3.0f && vp.dvMaxY == 1.75f && vp.dvScaleX == -320.0f
1579 && vp.dvScaleY == 180.0f && vp.dvMinZ == 0.0f && vp.dvMaxZ == 1.0f,
1580 "Got unexpected values %g, %g, %g, %g, %g, %g.\n",
1581 vp.dvMaxX, vp.dvMaxY, vp.dvScaleX, vp.dvScaleY, vp.dvMinZ, vp.dvMaxZ);
1583 vp.dwSize = sizeof(vp);
1584 vp.dvMinZ = 0.5f;
1585 vp.dvMaxZ = 2.0f;
1586 hr = IDirect3DViewport2_SetViewport(viewport2, &vp);
1587 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1589 memset(&vp2, 0xff, sizeof(vp2));
1590 vp2.dwSize = sizeof(vp2);
1591 hr = IDirect3DViewport2_GetViewport2(viewport2, &vp2);
1592 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1593 ok(vp2.dvClipX == 0.75f && vp2.dvClipY == 1.0f && vp2.dvClipWidth == -1.5f
1594 && vp2.dvClipHeight == 2.0f && vp2.dvMinZ == 0.0f && vp2.dvMaxZ == 1.0f,
1595 "Got unexpected values %g, %g, %g, %g, %g, %g.\n",
1596 vp2.dvClipX, vp2.dvClipY, vp2.dvClipWidth, vp2.dvClipHeight, vp2.dvMinZ, vp2.dvMaxZ);
1598 vp.dvMaxX = 4.5f;
1599 vp.dvMaxY = -1.75f;
1600 vp.dvScaleX = 192.0f;
1601 vp.dvScaleY = -240.0f;
1602 vp.dvMinZ = 2.0f;
1603 vp.dvMaxZ = 0.5f;
1605 hr = IDirect3DViewport3_SetViewport(viewport3, &vp);
1606 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1608 memset(&vp2, 0xff, sizeof(vp2));
1609 vp2.dwSize = sizeof(vp2);
1610 hr = IDirect3DViewport2_GetViewport2(viewport2, &vp2);
1611 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1612 ok(vp2.dvClipX == -1.25f && vp2.dvClipY == -0.75f && vp2.dvClipWidth == 2.5f
1613 && vp2.dvClipHeight == -1.5f && vp2.dvMinZ == 0.0f && vp2.dvMaxZ == 1.0f,
1614 "Got unexpected values %g, %g, %g, %g, %g, %g.\n",
1615 vp2.dvClipX, vp2.dvClipY, vp2.dvClipWidth, vp2.dvClipHeight, vp2.dvMinZ, vp2.dvMaxZ);
1617 IDirect3DViewport2_Release(viewport2);
1619 hr = IDirect3DDevice_DeleteViewport(device, another_vp);
1620 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1621 ref = get_refcount((IUnknown *) another_vp);
1622 ok(ref == 1, "Got unexpected refcount %lu.\n", ref);
1624 IDirect3DDevice_Release(device);
1625 ref = get_refcount((IUnknown *) viewport);
1626 ok(ref == 1, "Got unexpected refcount %lu.\n", ref);
1628 hr = IDirect3DViewport_SetViewport(viewport, &vp);
1629 ok(hr == D3DERR_VIEWPORTHASNODEVICE, "Got unexpected hr %#lx.\n", hr);
1631 IDirect3DViewport_Release(another_vp);
1632 IDirect3D_Release(d3d);
1633 IDirect3DViewport_Release(viewport);
1634 DestroyWindow(window);
1635 IDirectDraw_Release(ddraw);
1638 static void test_zenable(const GUID *device_guid)
1640 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1641 static D3DTLVERTEX tquad[] =
1643 {{ 0.0f}, {480.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1644 {{ 0.0f}, { 0.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1645 {{640.0f}, {480.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1646 {{640.0f}, { 0.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1648 unsigned int inst_length, color, x, y, i, j;
1649 IDirect3DExecuteBuffer *execute_buffer;
1650 D3DEXECUTEBUFFERDESC exec_desc;
1651 IDirect3DMaterial *background;
1652 IDirect3DViewport *viewport;
1653 IDirect3DDevice *device;
1654 IDirectDrawSurface *rt;
1655 IDirectDraw *ddraw;
1656 HWND window;
1657 HRESULT hr;
1658 void *ptr;
1660 window = create_window();
1661 ddraw = create_ddraw();
1662 ok(!!ddraw, "Failed to create a ddraw object.\n");
1663 if (!(device = create_device_ex(ddraw, window, DDSCL_NORMAL, device_guid)))
1665 skip("Failed to create a 3D device, skipping test.\n");
1666 IDirectDraw_Release(ddraw);
1667 DestroyWindow(window);
1668 return;
1671 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1672 viewport = create_viewport(device, 0, 0, 640, 480);
1673 viewport_set_background(device, viewport, background);
1675 memset(&exec_desc, 0, sizeof(exec_desc));
1676 exec_desc.dwSize = sizeof(exec_desc);
1677 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
1678 exec_desc.dwBufferSize = 1024;
1679 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
1681 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
1682 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
1683 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
1684 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
1685 memcpy(exec_desc.lpData, tquad, sizeof(tquad));
1686 ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad);
1687 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
1688 emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1689 emit_tquad(&ptr, 0);
1690 emit_end(&ptr);
1691 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
1692 inst_length -= sizeof(tquad);
1693 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
1694 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1696 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1697 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1698 hr = IDirect3DDevice_BeginScene(device);
1699 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1700 set_execute_data(execute_buffer, 4, sizeof(tquad), inst_length);
1701 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1702 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1703 hr = IDirect3DDevice_EndScene(device);
1704 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1706 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
1707 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1708 for (i = 0; i < 4; ++i)
1710 for (j = 0; j < 4; ++j)
1712 x = 80 * ((2 * j) + 1);
1713 y = 60 * ((2 * i) + 1);
1714 color = get_surface_color(rt, x, y);
1715 ok(compare_color(color, 0x0000ff00, 1),
1716 "Expected color 0x0000ff00 at %u, %u, got 0x%08x.\n", x, y, color);
1719 IDirectDrawSurface_Release(rt);
1721 destroy_viewport(device, viewport);
1722 IDirect3DExecuteBuffer_Release(execute_buffer);
1723 destroy_material(background);
1724 IDirect3DDevice_Release(device);
1725 IDirectDraw_Release(ddraw);
1726 DestroyWindow(window);
1729 static void test_ck_rgba(const GUID *device_guid)
1731 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1732 static D3DTLVERTEX tquad[] =
1734 {{ 0.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1735 {{ 0.0f}, { 0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1736 {{640.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1737 {{640.0f}, { 0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1738 {{ 0.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1739 {{ 0.0f}, { 0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1740 {{640.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1741 {{640.0f}, { 0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1743 /* Supposedly there was no D3DRENDERSTATE_COLORKEYENABLE in D3D < 5.
1744 * Maybe the WARP driver on Windows 8 ignores setting it via the older
1745 * device interface but it's buggy in that the internal state is not
1746 * initialized, or possibly toggling D3DRENDERSTATE_COLORKEYENABLE /
1747 * D3DRENDERSTATE_ALPHABLENDENABLE has unintended side effects.
1748 * Checking the W8 test results it seems like test 1 fails most of the time
1749 * and test 0 fails very rarely. */
1750 static const struct
1752 D3DCOLOR fill_color;
1753 BOOL color_key;
1754 BOOL blend;
1755 unsigned int result1, result1_r200, result1_warp;
1756 unsigned int result2, result2_r200, result2_warp;
1758 tests[] =
1760 /* r200 on Windows doesn't check the alpha component when applying the color
1761 * key, so the key matches on every texel. */
1762 {0xff00ff00, TRUE, TRUE, 0x00ff0000, 0x00ff0000, 0x0000ff00,
1763 0x000000ff, 0x000000ff, 0x0000ff00},
1764 {0xff00ff00, TRUE, FALSE, 0x00ff0000, 0x00ff0000, 0x0000ff00,
1765 0x000000ff, 0x000000ff, 0x0000ff00},
1766 {0xff00ff00, FALSE, TRUE, 0x0000ff00, 0x0000ff00, 0x0000ff00,
1767 0x0000ff00, 0x0000ff00, 0x0000ff00},
1768 {0xff00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00, 0x0000ff00,
1769 0x0000ff00, 0x0000ff00, 0x0000ff00},
1770 {0x7f00ff00, TRUE, TRUE, 0x00807f00, 0x00ff0000, 0x00807f00,
1771 0x00807f00, 0x000000ff, 0x00807f00},
1772 {0x7f00ff00, TRUE, FALSE, 0x0000ff00, 0x00ff0000, 0x0000ff00,
1773 0x0000ff00, 0x000000ff, 0x0000ff00},
1774 {0x7f00ff00, FALSE, TRUE, 0x00807f00, 0x00807f00, 0x00807f00,
1775 0x00807f00, 0x00807f00, 0x00807f00},
1776 {0x7f00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00, 0x0000ff00,
1777 0x0000ff00, 0x0000ff00, 0x0000ff00},
1780 IDirect3DExecuteBuffer *execute_buffer;
1781 D3DTEXTUREHANDLE texture_handle;
1782 D3DEXECUTEBUFFERDESC exec_desc;
1783 IDirect3DMaterial *background;
1784 IDirectDrawSurface *surface;
1785 IDirect3DViewport *viewport;
1786 DDSURFACEDESC surface_desc;
1787 IDirect3DTexture *texture;
1788 IDirect3DDevice *device;
1789 IDirectDrawSurface *rt;
1790 unsigned int color, i;
1791 IDirectDraw *ddraw;
1792 HWND window;
1793 DDBLTFX fx;
1794 HRESULT hr;
1796 window = create_window();
1797 ddraw = create_ddraw();
1798 ok(!!ddraw, "Failed to create a ddraw object.\n");
1799 if (!(device = create_device_ex(ddraw, window, DDSCL_NORMAL, device_guid)))
1801 skip("Failed to create a 3D device, skipping test.\n");
1802 IDirectDraw_Release(ddraw);
1803 DestroyWindow(window);
1804 return;
1807 background = create_diffuse_material(device, 1.0, 0.0f, 0.0f, 1.0f);
1808 viewport = create_viewport(device, 0, 0, 640, 480);
1809 viewport_set_background(device, viewport, background);
1811 memset(&surface_desc, 0, sizeof(surface_desc));
1812 surface_desc.dwSize = sizeof(surface_desc);
1813 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1814 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1815 if (is_software_device_type(device_guid))
1816 surface_desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
1817 surface_desc.dwWidth = 256;
1818 surface_desc.dwHeight = 256;
1819 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1820 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
1821 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1822 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1823 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1824 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1825 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
1826 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0xff00ff00;
1827 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0xff00ff00;
1828 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1829 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1830 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture, (void **)&texture);
1831 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1832 hr = IDirect3DTexture_GetHandle(texture, device, &texture_handle);
1833 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1834 IDirect3DTexture_Release(texture);
1836 memset(&exec_desc, 0, sizeof(exec_desc));
1837 exec_desc.dwSize = sizeof(exec_desc);
1838 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
1839 exec_desc.dwBufferSize = 1024;
1840 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
1841 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
1842 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1844 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
1845 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1847 for (i = 0; i < ARRAY_SIZE(tests); ++i)
1849 UINT draw1_len, draw2_len;
1850 void *ptr;
1852 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
1853 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1854 memcpy(exec_desc.lpData, tquad, sizeof(tquad));
1855 ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad);
1856 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
1857 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1858 emit_set_rs(&ptr, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
1859 emit_set_rs(&ptr, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
1860 emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, tests[i].color_key);
1862 if (is_software_device_type(device_guid))
1864 /* It looks like D3DRENDERSTATE_COLORKEYENABLE is ignored with software device
1865 * on Windows and the colour key is always enabled if set on surface. */
1866 IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, tests[i].color_key
1867 ? &surface_desc.ddckCKSrcBlt : NULL);
1870 emit_set_rs(&ptr, D3DRENDERSTATE_ALPHABLENDENABLE, tests[i].blend);
1871 emit_tquad(&ptr, 0);
1872 emit_end(&ptr);
1873 draw1_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - sizeof(tquad);
1874 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 4, 4);
1875 emit_tquad(&ptr, 0);
1876 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1877 emit_end(&ptr);
1878 draw2_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw1_len;
1879 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
1880 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1882 memset(&fx, 0, sizeof(fx));
1883 fx.dwSize = sizeof(fx);
1884 U5(fx).dwFillColor = tests[i].fill_color;
1885 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1886 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1888 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
1889 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1890 /* RT clears are broken on Windows for software render target. */
1891 if (is_software_device_type(device_guid))
1892 fill_surface(rt, 0xffff0000);
1894 hr = IDirect3DDevice_BeginScene(device);
1895 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1896 set_execute_data(execute_buffer, 8, sizeof(tquad), draw1_len);
1897 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1898 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1899 hr = IDirect3DDevice_EndScene(device);
1900 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1902 color = get_surface_color(rt, 320, 240);
1903 ok(compare_color(color, tests[i].result1, 2)
1904 || broken(compare_color(color, tests[i].result1_r200, 1))
1905 || broken(compare_color(color, tests[i].result1_warp, 1)),
1906 "Got unexpected color 0x%08x for test %u.\n", color, i);
1908 U5(fx).dwFillColor = 0xff0000ff;
1909 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1910 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
1912 hr = IDirect3DDevice_BeginScene(device);
1913 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1914 set_execute_data(execute_buffer, 8, sizeof(tquad) + draw1_len, draw2_len);
1915 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
1916 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1917 hr = IDirect3DDevice_EndScene(device);
1918 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
1920 /* This tests that fragments that are masked out by the color key are
1921 * discarded, instead of just fully transparent. */
1922 color = get_surface_color(rt, 320, 240);
1923 ok(compare_color(color, tests[i].result2, 2)
1924 || broken(compare_color(color, tests[i].result2_r200, 1))
1925 || broken(compare_color(color, tests[i].result2_warp, 1)),
1926 "Got unexpected color 0x%08x for test %u.\n", color, i);
1929 IDirectDrawSurface_Release(rt);
1930 IDirect3DExecuteBuffer_Release(execute_buffer);
1931 IDirectDrawSurface_Release(surface);
1932 destroy_viewport(device, viewport);
1933 destroy_material(background);
1934 IDirect3DDevice_Release(device);
1935 IDirectDraw_Release(ddraw);
1936 DestroyWindow(window);
1939 static void test_ck_default(void)
1941 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1942 static D3DTLVERTEX tquad[] =
1944 {{ 0.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1945 {{ 0.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1946 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1947 {{640.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1949 IDirect3DExecuteBuffer *execute_buffer;
1950 IDirectDrawSurface *surface, *rt;
1951 D3DTEXTUREHANDLE texture_handle;
1952 D3DEXECUTEBUFFERDESC exec_desc;
1953 IDirect3DMaterial *background;
1954 UINT draw1_offset, draw1_len;
1955 UINT draw2_offset, draw2_len;
1956 UINT draw3_offset, draw3_len;
1957 UINT draw4_offset, draw4_len;
1958 IDirect3DViewport *viewport;
1959 DDSURFACEDESC surface_desc;
1960 IDirect3DTexture *texture;
1961 IDirect3DDevice *device;
1962 unsigned int color;
1963 IDirectDraw *ddraw;
1964 HWND window;
1965 DDBLTFX fx;
1966 HRESULT hr;
1967 void *ptr;
1969 window = create_window();
1970 ddraw = create_ddraw();
1971 ok(!!ddraw, "Failed to create a ddraw object.\n");
1972 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1974 skip("Failed to create a 3D device, skipping test.\n");
1975 IDirectDraw_Release(ddraw);
1976 DestroyWindow(window);
1977 return;
1980 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
1981 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
1983 background = create_diffuse_material(device, 0.0, 1.0f, 0.0f, 1.0f);
1984 viewport = create_viewport(device, 0, 0, 640, 480);
1985 viewport_set_background(device, viewport, background);
1987 memset(&surface_desc, 0, sizeof(surface_desc));
1988 surface_desc.dwSize = sizeof(surface_desc);
1989 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1990 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1991 surface_desc.dwWidth = 256;
1992 surface_desc.dwHeight = 256;
1993 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1994 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
1995 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1996 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1997 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1998 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1999 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x000000ff;
2000 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x000000ff;
2001 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
2002 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
2003 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture, (void **)&texture);
2004 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
2005 hr = IDirect3DTexture_GetHandle(texture, device, &texture_handle);
2006 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
2007 IDirect3DTexture_Release(texture);
2009 memset(&fx, 0, sizeof(fx));
2010 fx.dwSize = sizeof(fx);
2011 U5(fx).dwFillColor = 0x000000ff;
2012 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
2013 ok(SUCCEEDED(hr), "Failed to fill surface, hr %#lx.\n", hr);
2015 memset(&exec_desc, 0, sizeof(exec_desc));
2016 exec_desc.dwSize = sizeof(exec_desc);
2017 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
2018 exec_desc.dwBufferSize = 1024;
2019 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
2020 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
2021 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
2023 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
2024 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
2025 memcpy(exec_desc.lpData, tquad, sizeof(tquad));
2026 ptr = (BYTE *)exec_desc.lpData + sizeof(tquad);
2027 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
2028 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
2029 emit_tquad(&ptr, 0);
2030 emit_end(&ptr);
2031 draw1_offset = sizeof(tquad);
2032 draw1_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw1_offset;
2033 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
2034 emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, FALSE);
2035 emit_tquad(&ptr, 0);
2036 emit_end(&ptr);
2037 draw2_offset = draw1_offset + draw1_len;
2038 draw2_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw2_offset;
2039 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
2040 emit_tquad(&ptr, 0);
2041 emit_end(&ptr);
2042 draw3_offset = draw2_offset + draw2_len;
2043 draw3_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw3_offset;
2044 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
2045 emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
2046 emit_tquad(&ptr, 0);
2047 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, 0);
2048 emit_end(&ptr);
2049 draw4_offset = draw3_offset + draw3_len;
2050 draw4_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw4_offset;
2051 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
2052 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
2054 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
2055 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
2056 hr = IDirect3DDevice_BeginScene(device);
2057 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
2058 set_execute_data(execute_buffer, 4, draw1_offset, draw1_len);
2059 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
2060 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
2061 hr = IDirect3DDevice_EndScene(device);
2062 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
2063 color = get_surface_color(rt, 320, 240);
2064 /* Color keying is supposed to be on by default in ddraw1, but used only if a ckey is set.
2065 * WARP begs to differ. The default of D3DRENDERSTATE_COLORKEYENABLE is random, and it
2066 * doesn't mind the absence of a color key (the latter part affects other tests, not this one). */
2067 ok(compare_color(color, 0x0000ff00, 1) || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x000000ff, 1)),
2068 "Got unexpected color 0x%08x.\n", color);
2070 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
2071 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
2072 hr = IDirect3DDevice_BeginScene(device);
2073 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
2074 set_execute_data(execute_buffer, 4, draw2_offset, draw2_len);
2075 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
2076 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
2077 hr = IDirect3DDevice_EndScene(device);
2078 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
2079 color = get_surface_color(rt, 320, 240);
2080 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
2082 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
2083 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
2084 hr = IDirect3DDevice_BeginScene(device);
2085 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
2086 set_execute_data(execute_buffer, 4, draw3_offset, draw3_len);
2087 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
2088 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
2089 hr = IDirect3DDevice_EndScene(device);
2090 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
2091 color = get_surface_color(rt, 320, 240);
2092 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
2094 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
2095 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
2096 hr = IDirect3DDevice_BeginScene(device);
2097 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
2098 set_execute_data(execute_buffer, 4, draw4_offset, draw4_len);
2099 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
2100 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
2101 hr = IDirect3DDevice_EndScene(device);
2102 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
2103 color = get_surface_color(rt, 320, 240);
2104 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
2106 IDirect3DExecuteBuffer_Release(execute_buffer);
2107 IDirectDrawSurface_Release(surface);
2108 destroy_viewport(device, viewport);
2109 destroy_material(background);
2110 IDirectDrawSurface_Release(rt);
2111 IDirect3DDevice_Release(device);
2112 IDirectDraw_Release(ddraw);
2113 DestroyWindow(window);
2116 static void test_ck_complex(void)
2118 IDirectDrawSurface *surface, *mipmap, *tmp;
2119 DDSCAPS caps = {DDSCAPS_COMPLEX};
2120 DDSURFACEDESC surface_desc;
2121 IDirect3DDevice *device;
2122 DDCOLORKEY color_key;
2123 IDirectDraw *ddraw;
2124 unsigned int i;
2125 ULONG refcount;
2126 HWND window;
2127 HRESULT hr;
2129 window = create_window();
2130 ddraw = create_ddraw();
2131 ok(!!ddraw, "Failed to create a ddraw object.\n");
2132 if (!(device = create_device(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN)))
2134 skip("Failed to create a 3D device, skipping test.\n");
2135 DestroyWindow(window);
2136 IDirectDraw_Release(ddraw);
2137 return;
2139 IDirect3DDevice_Release(device);
2141 memset(&surface_desc, 0, sizeof(surface_desc));
2142 surface_desc.dwSize = sizeof(surface_desc);
2143 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2144 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2145 surface_desc.dwWidth = 128;
2146 surface_desc.dwHeight = 128;
2147 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
2148 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
2150 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2151 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx.\n", hr);
2152 color_key.dwColorSpaceLowValue = 0x0000ff00;
2153 color_key.dwColorSpaceHighValue = 0x0000ff00;
2154 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2155 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
2156 memset(&color_key, 0, sizeof(color_key));
2157 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2158 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
2159 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2160 color_key.dwColorSpaceLowValue);
2161 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2162 color_key.dwColorSpaceHighValue);
2164 mipmap = surface;
2165 IDirectDrawSurface_AddRef(mipmap);
2166 for (i = 0; i < 7; ++i)
2168 hr = IDirectDrawSurface_GetAttachedSurface(mipmap, &caps, &tmp);
2169 ok(SUCCEEDED(hr), "Failed to get attached surface, i %u, hr %#lx.\n", i, hr);
2171 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2172 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx, i %u.\n", hr, i);
2173 color_key.dwColorSpaceLowValue = 0x000000ff;
2174 color_key.dwColorSpaceHighValue = 0x000000ff;
2175 hr = IDirectDrawSurface_SetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2176 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx, i %u.\n", hr, i);
2177 memset(&color_key, 0, sizeof(color_key));
2178 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2179 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx, i %u.\n", hr, i);
2180 ok(color_key.dwColorSpaceLowValue == 0x000000ff, "Got unexpected value 0x%08lx, i %u.\n",
2181 color_key.dwColorSpaceLowValue, i);
2182 ok(color_key.dwColorSpaceHighValue == 0x000000ff, "Got unexpected value 0x%08lx, i %u.\n",
2183 color_key.dwColorSpaceHighValue, i);
2185 IDirectDrawSurface_Release(mipmap);
2186 mipmap = tmp;
2189 memset(&color_key, 0, sizeof(color_key));
2190 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2191 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
2192 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2193 color_key.dwColorSpaceLowValue);
2194 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2195 color_key.dwColorSpaceHighValue);
2197 hr = IDirectDrawSurface_GetAttachedSurface(mipmap, &caps, &tmp);
2198 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
2199 IDirectDrawSurface_Release(mipmap);
2200 refcount = IDirectDrawSurface_Release(surface);
2201 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
2203 memset(&surface_desc, 0, sizeof(surface_desc));
2204 surface_desc.dwSize = sizeof(surface_desc);
2205 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
2206 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
2207 surface_desc.dwBackBufferCount = 1;
2208 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
2209 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
2211 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2212 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx.\n", hr);
2213 color_key.dwColorSpaceLowValue = 0x0000ff00;
2214 color_key.dwColorSpaceHighValue = 0x0000ff00;
2215 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2216 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
2217 memset(&color_key, 0, sizeof(color_key));
2218 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &color_key);
2219 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
2220 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2221 color_key.dwColorSpaceLowValue);
2222 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2223 color_key.dwColorSpaceHighValue);
2225 hr = IDirectDrawSurface_GetAttachedSurface(surface, &caps, &tmp);
2226 ok(SUCCEEDED(hr), "Failed to get attached surface, hr %#lx.\n", hr);
2228 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2229 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx, i %u.\n", hr, i);
2230 color_key.dwColorSpaceLowValue = 0x0000ff00;
2231 color_key.dwColorSpaceHighValue = 0x0000ff00;
2232 hr = IDirectDrawSurface_SetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2233 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
2234 memset(&color_key, 0, sizeof(color_key));
2235 hr = IDirectDrawSurface_GetColorKey(tmp, DDCKEY_SRCBLT, &color_key);
2236 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
2237 ok(color_key.dwColorSpaceLowValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2238 color_key.dwColorSpaceLowValue);
2239 ok(color_key.dwColorSpaceHighValue == 0x0000ff00, "Got unexpected value 0x%08lx.\n",
2240 color_key.dwColorSpaceHighValue);
2242 IDirectDrawSurface_Release(tmp);
2244 refcount = IDirectDrawSurface_Release(surface);
2245 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
2246 refcount = IDirectDraw_Release(ddraw);
2247 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
2248 DestroyWindow(window);
2251 struct qi_test
2253 REFIID iid;
2254 REFIID refcount_iid;
2255 HRESULT hr;
2258 static void test_qi(const char *test_name, IUnknown *base_iface,
2259 REFIID refcount_iid, const struct qi_test *tests, UINT entry_count)
2261 ULONG refcount, expected_refcount;
2262 IUnknown *iface1, *iface2;
2263 HRESULT hr;
2264 UINT i, j;
2266 for (i = 0; i < entry_count; ++i)
2268 hr = IUnknown_QueryInterface(base_iface, tests[i].iid, (void **)&iface1);
2269 ok(hr == tests[i].hr, "Got hr %#lx for test \"%s\" %u.\n", hr, test_name, i);
2270 if (SUCCEEDED(hr))
2272 for (j = 0; j < entry_count; ++j)
2274 hr = IUnknown_QueryInterface(iface1, tests[j].iid, (void **)&iface2);
2275 ok(hr == tests[j].hr, "Got hr %#lx for test \"%s\" %u, %u.\n", hr, test_name, i, j);
2276 if (SUCCEEDED(hr))
2278 expected_refcount = 0;
2279 if (IsEqualGUID(refcount_iid, tests[j].refcount_iid))
2280 ++expected_refcount;
2281 if (IsEqualGUID(tests[i].refcount_iid, tests[j].refcount_iid))
2282 ++expected_refcount;
2283 refcount = IUnknown_Release(iface2);
2284 ok(refcount == expected_refcount, "Got refcount %lu for test \"%s\" %u, %u, expected %lu.\n",
2285 refcount, test_name, i, j, expected_refcount);
2289 expected_refcount = 0;
2290 if (IsEqualGUID(refcount_iid, tests[i].refcount_iid))
2291 ++expected_refcount;
2292 refcount = IUnknown_Release(iface1);
2293 ok(refcount == expected_refcount, "Got refcount %lu for test \"%s\" %u, expected %lu.\n",
2294 refcount, test_name, i, expected_refcount);
2299 static void test_surface_qi(void)
2301 static const struct qi_test tests[] =
2303 {&IID_IDirect3DTexture2, &IID_IDirectDrawSurface, S_OK },
2304 {&IID_IDirect3DTexture, &IID_IDirectDrawSurface, S_OK },
2305 {&IID_IDirectDrawGammaControl, &IID_IDirectDrawGammaControl, S_OK },
2306 {&IID_IDirectDrawColorControl, NULL, E_NOINTERFACE},
2307 {&IID_IDirectDrawSurface7, &IID_IDirectDrawSurface7, S_OK },
2308 {&IID_IDirectDrawSurface4, &IID_IDirectDrawSurface4, S_OK },
2309 {&IID_IDirectDrawSurface3, &IID_IDirectDrawSurface3, S_OK },
2310 {&IID_IDirectDrawSurface2, &IID_IDirectDrawSurface2, S_OK },
2311 {&IID_IDirectDrawSurface, &IID_IDirectDrawSurface, S_OK },
2312 {&IID_IDirect3DDevice7, NULL, E_INVALIDARG },
2313 {&IID_IDirect3DDevice3, NULL, E_INVALIDARG },
2314 {&IID_IDirect3DDevice2, NULL, E_INVALIDARG },
2315 {&IID_IDirect3DDevice, NULL, E_INVALIDARG },
2316 {&IID_IDirect3D7, NULL, E_INVALIDARG },
2317 {&IID_IDirect3D3, NULL, E_INVALIDARG },
2318 {&IID_IDirect3D2, NULL, E_INVALIDARG },
2319 {&IID_IDirect3D, NULL, E_INVALIDARG },
2320 {&IID_IDirectDraw7, NULL, E_INVALIDARG },
2321 {&IID_IDirectDraw4, NULL, E_INVALIDARG },
2322 {&IID_IDirectDraw3, NULL, E_INVALIDARG },
2323 {&IID_IDirectDraw2, NULL, E_INVALIDARG },
2324 {&IID_IDirectDraw, NULL, E_INVALIDARG },
2325 {&IID_IDirect3DLight, NULL, E_INVALIDARG },
2326 {&IID_IDirect3DMaterial, NULL, E_INVALIDARG },
2327 {&IID_IDirect3DMaterial2, NULL, E_INVALIDARG },
2328 {&IID_IDirect3DMaterial3, NULL, E_INVALIDARG },
2329 {&IID_IDirect3DExecuteBuffer, NULL, E_INVALIDARG },
2330 {&IID_IDirect3DViewport, NULL, E_INVALIDARG },
2331 {&IID_IDirect3DViewport2, NULL, E_INVALIDARG },
2332 {&IID_IDirect3DViewport3, NULL, E_INVALIDARG },
2333 {&IID_IDirect3DVertexBuffer, NULL, E_INVALIDARG },
2334 {&IID_IDirect3DVertexBuffer7, NULL, E_INVALIDARG },
2335 {&IID_IDirectDrawPalette, NULL, E_INVALIDARG },
2336 {&IID_IDirectDrawClipper, NULL, E_INVALIDARG },
2337 {&IID_IUnknown, &IID_IDirectDrawSurface, S_OK },
2338 {NULL, NULL, E_INVALIDARG },
2341 IDirectDrawSurface *surface;
2342 DDSURFACEDESC surface_desc;
2343 IDirect3DDevice *device;
2344 IDirectDraw *ddraw;
2345 HWND window;
2346 HRESULT hr;
2348 if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
2350 win_skip("DirectDrawCreateEx not available, skipping test.\n");
2351 return;
2354 window = create_window();
2355 ddraw = create_ddraw();
2356 ok(!!ddraw, "Failed to create a ddraw object.\n");
2357 /* Try to create a D3D device to see if the ddraw implementation supports
2358 * D3D. 64-bit ddraw in particular doesn't seem to support D3D, and
2359 * doesn't support e.g. the IDirect3DTexture interfaces. */
2360 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
2362 skip("Failed to create a 3D device, skipping test.\n");
2363 IDirectDraw_Release(ddraw);
2364 DestroyWindow(window);
2365 return;
2367 IDirect3DDevice_Release(device);
2369 memset(&surface_desc, 0, sizeof(surface_desc));
2370 surface_desc.dwSize = sizeof(surface_desc);
2371 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2372 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
2373 surface_desc.dwWidth = 512;
2374 surface_desc.dwHeight = 512;
2375 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, (IDirectDrawSurface **)0xdeadbeef, NULL);
2376 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2377 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
2378 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
2380 test_qi("surface_qi", (IUnknown *)surface, &IID_IDirectDrawSurface, tests, ARRAY_SIZE(tests));
2382 IDirectDrawSurface_Release(surface);
2383 IDirectDraw_Release(ddraw);
2384 DestroyWindow(window);
2387 static void test_device_qi(void)
2389 static const struct qi_test tests[] =
2391 {&IID_IDirect3DTexture2, &IID_IDirectDrawSurface, S_OK },
2392 {&IID_IDirect3DTexture, &IID_IDirectDrawSurface, S_OK },
2393 {&IID_IDirectDrawGammaControl, &IID_IDirectDrawGammaControl, S_OK },
2394 {&IID_IDirectDrawColorControl, NULL, E_NOINTERFACE},
2395 {&IID_IDirectDrawSurface7, &IID_IDirectDrawSurface7, S_OK },
2396 {&IID_IDirectDrawSurface4, &IID_IDirectDrawSurface4, S_OK },
2397 {&IID_IDirectDrawSurface3, &IID_IDirectDrawSurface3, S_OK },
2398 {&IID_IDirectDrawSurface2, &IID_IDirectDrawSurface2, S_OK },
2399 {&IID_IDirectDrawSurface, &IID_IDirectDrawSurface, S_OK },
2400 {&IID_IDirect3DDevice7, NULL, E_INVALIDARG },
2401 {&IID_IDirect3DDevice3, NULL, E_INVALIDARG },
2402 {&IID_IDirect3DDevice2, NULL, E_INVALIDARG },
2403 {&IID_IDirect3DDevice, NULL, E_INVALIDARG },
2404 {&IID_IDirect3DHALDevice, &IID_IDirectDrawSurface, S_OK },
2405 {&IID_IDirect3D7, NULL, E_INVALIDARG },
2406 {&IID_IDirect3D3, NULL, E_INVALIDARG },
2407 {&IID_IDirect3D2, NULL, E_INVALIDARG },
2408 {&IID_IDirect3D, NULL, E_INVALIDARG },
2409 {&IID_IDirectDraw7, NULL, E_INVALIDARG },
2410 {&IID_IDirectDraw4, NULL, E_INVALIDARG },
2411 {&IID_IDirectDraw3, NULL, E_INVALIDARG },
2412 {&IID_IDirectDraw2, NULL, E_INVALIDARG },
2413 {&IID_IDirectDraw, NULL, E_INVALIDARG },
2414 {&IID_IDirect3DLight, NULL, E_INVALIDARG },
2415 {&IID_IDirect3DMaterial, NULL, E_INVALIDARG },
2416 {&IID_IDirect3DMaterial2, NULL, E_INVALIDARG },
2417 {&IID_IDirect3DMaterial3, NULL, E_INVALIDARG },
2418 {&IID_IDirect3DExecuteBuffer, NULL, E_INVALIDARG },
2419 {&IID_IDirect3DViewport, NULL, E_INVALIDARG },
2420 {&IID_IDirect3DViewport2, NULL, E_INVALIDARG },
2421 {&IID_IDirect3DViewport3, NULL, E_INVALIDARG },
2422 {&IID_IDirect3DVertexBuffer, NULL, E_INVALIDARG },
2423 {&IID_IDirect3DVertexBuffer7, NULL, E_INVALIDARG },
2424 {&IID_IDirectDrawPalette, NULL, E_INVALIDARG },
2425 {&IID_IDirectDrawClipper, NULL, E_INVALIDARG },
2426 {&IID_IUnknown, &IID_IDirectDrawSurface, S_OK },
2430 IDirect3DDevice *device;
2431 IDirectDraw *ddraw;
2432 HWND window;
2434 if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
2436 win_skip("DirectDrawCreateEx not available, skipping test.\n");
2437 return;
2440 window = create_window();
2441 ddraw = create_ddraw();
2442 ok(!!ddraw, "Failed to create a ddraw object.\n");
2443 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
2445 skip("Failed to create a 3D device, skipping test.\n");
2446 IDirectDraw_Release(ddraw);
2447 DestroyWindow(window);
2448 return;
2451 test_qi("device_qi", (IUnknown *)device, &IID_IDirectDrawSurface, tests, ARRAY_SIZE(tests));
2453 IDirect3DDevice_Release(device);
2454 IDirectDraw_Release(ddraw);
2455 DestroyWindow(window);
2458 static void test_wndproc(void)
2460 LONG_PTR proc, ddraw_proc;
2461 IDirectDraw *ddraw;
2462 WNDCLASSA wc = {0};
2463 HWND window;
2464 HRESULT hr;
2465 ULONG ref;
2467 static struct message messages[] =
2469 {WM_WINDOWPOSCHANGING, FALSE, 0},
2470 {WM_MOVE, FALSE, 0},
2471 {WM_SIZE, FALSE, 0},
2472 {WM_WINDOWPOSCHANGING, FALSE, 0},
2473 {WM_ACTIVATE, FALSE, 0},
2474 {WM_SETFOCUS, FALSE, 0},
2475 {0, FALSE, 0},
2478 /* DDSCL_EXCLUSIVE replaces the window's window proc. */
2479 ddraw = create_ddraw();
2480 ok(!!ddraw, "Failed to create a ddraw object.\n");
2482 wc.lpfnWndProc = test_proc;
2483 wc.lpszClassName = "ddraw_test_wndproc_wc";
2484 ok(RegisterClassA(&wc), "Failed to register window class.\n");
2486 window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test",
2487 WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
2489 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2490 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2491 (LONG_PTR)test_proc, proc);
2492 expect_messages = messages;
2493 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2494 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2495 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
2496 expect_messages = NULL;
2497 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2498 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#Ix, got %#Ix.\n",
2499 (LONG_PTR)test_proc, proc);
2500 ref = IDirectDraw_Release(ddraw);
2501 ok(!ref, "Unexpected refcount %lu.\n", ref);
2502 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2503 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2504 (LONG_PTR)test_proc, proc);
2506 /* DDSCL_NORMAL doesn't. */
2507 ddraw = create_ddraw();
2508 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2509 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2510 (LONG_PTR)test_proc, proc);
2511 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
2512 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2513 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2514 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2515 (LONG_PTR)test_proc, proc);
2516 ref = IDirectDraw_Release(ddraw);
2517 ok(!ref, "Unexpected refcount %lu.\n", ref);
2518 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2519 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2520 (LONG_PTR)test_proc, proc);
2522 /* The original window proc is only restored by ddraw if the current
2523 * window proc matches the one ddraw set. This also affects switching
2524 * from DDSCL_NORMAL to DDSCL_EXCLUSIVE. */
2525 ddraw = create_ddraw();
2526 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2527 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2528 (LONG_PTR)test_proc, proc);
2529 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2530 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2531 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2532 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#Ix, got %#Ix.\n",
2533 (LONG_PTR)test_proc, proc);
2534 ddraw_proc = proc;
2535 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2536 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2537 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2538 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2539 (LONG_PTR)test_proc, proc);
2540 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2541 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2542 proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
2543 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#Ix, got %#Ix.\n",
2544 (LONG_PTR)test_proc, proc);
2545 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2546 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2547 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2548 ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#Ix, got %#Ix.\n",
2549 (LONG_PTR)DefWindowProcA, proc);
2550 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2551 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2552 proc = SetWindowLongPtrA(window, GWLP_WNDPROC, ddraw_proc);
2553 ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#Ix, got %#Ix.\n",
2554 (LONG_PTR)DefWindowProcA, proc);
2555 ref = IDirectDraw_Release(ddraw);
2556 ok(!ref, "Unexpected refcount %lu.\n", ref);
2557 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2558 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2559 (LONG_PTR)test_proc, proc);
2561 ddraw = create_ddraw();
2562 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2563 ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#Ix, got %#Ix.\n",
2564 (LONG_PTR)test_proc, proc);
2565 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2566 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2567 proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
2568 ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#Ix, got %#Ix.\n",
2569 (LONG_PTR)test_proc, proc);
2570 ref = IDirectDraw_Release(ddraw);
2571 ok(!ref, "Unexpected refcount %lu.\n", ref);
2572 proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
2573 ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#Ix, got %#Ix.\n",
2574 (LONG_PTR)DefWindowProcA, proc);
2576 fix_wndproc(window, (LONG_PTR)test_proc);
2577 expect_messages = NULL;
2578 DestroyWindow(window);
2579 UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
2582 static void test_window_style(void)
2584 LONG style, exstyle, tmp, expected_style;
2585 RECT fullscreen_rect, r;
2586 HWND window, window2;
2587 IDirectDraw *ddraw;
2588 HRESULT hr;
2589 ULONG ref;
2590 BOOL ret;
2592 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2593 0, 0, 100, 100, 0, 0, 0, 0);
2594 window2 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2595 0, 0, 50, 50, 0, 0, 0, 0);
2596 ddraw = create_ddraw();
2597 ok(!!ddraw, "Failed to create a ddraw object.\n");
2599 style = GetWindowLongA(window, GWL_STYLE);
2600 exstyle = GetWindowLongA(window, GWL_EXSTYLE);
2601 SetRect(&fullscreen_rect, 0, 0, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
2603 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2604 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2606 tmp = GetWindowLongA(window, GWL_STYLE);
2607 todo_wine ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2608 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2609 todo_wine ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2611 GetWindowRect(window, &r);
2612 ok(EqualRect(&r, &fullscreen_rect), "Expected %s, got %s.\n",
2613 wine_dbgstr_rect(&fullscreen_rect), wine_dbgstr_rect(&r));
2614 GetClientRect(window, &r);
2615 todo_wine ok(!EqualRect(&r, &fullscreen_rect), "Client rect and window rect are equal.\n");
2617 ret = SetForegroundWindow(GetDesktopWindow());
2618 ok(ret, "Failed to set foreground window.\n");
2620 tmp = GetWindowLongA(window, GWL_STYLE);
2621 todo_wine ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2622 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2623 todo_wine ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2625 ret = SetForegroundWindow(window);
2626 ok(ret, "Failed to set foreground window.\n");
2627 /* Windows 7 (but not Vista and XP) shows the window when it receives focus. Hide it again,
2628 * the next tests expect this. */
2629 ShowWindow(window, SW_HIDE);
2631 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2632 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2634 tmp = GetWindowLongA(window, GWL_STYLE);
2635 ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2636 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2637 ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2639 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES);
2640 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2642 tmp = GetWindowLongA(window, GWL_STYLE);
2643 todo_wine ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2644 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2645 todo_wine ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2647 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2648 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2650 tmp = GetWindowLongA(window, GWL_STYLE);
2651 expected_style = style | WS_VISIBLE;
2652 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2653 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2654 expected_style = exstyle | WS_EX_TOPMOST;
2655 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2657 ShowWindow(window, SW_HIDE);
2658 tmp = GetWindowLongA(window, GWL_STYLE);
2659 todo_wine ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2660 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2661 expected_style = exstyle | WS_EX_TOPMOST;
2662 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2664 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_NOWINDOWCHANGES);
2665 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2667 tmp = GetWindowLongA(window, GWL_STYLE);
2668 ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2669 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2670 expected_style = exstyle | WS_EX_TOPMOST;
2671 ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2673 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2674 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2676 tmp = GetWindowLongA(window, GWL_STYLE);
2677 ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2678 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2679 expected_style = exstyle | WS_EX_TOPMOST;
2680 ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2682 ret = SetForegroundWindow(window);
2683 ok(ret, "Failed to set foreground window.\n");
2685 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2686 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2688 tmp = GetWindowLongA(window, GWL_STYLE);
2689 expected_style = style | WS_VISIBLE;
2690 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2691 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2692 expected_style = exstyle | WS_EX_TOPMOST;
2693 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2695 ShowWindow(window, SW_HIDE);
2696 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2697 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2699 tmp = GetWindowLongA(window, GWL_STYLE);
2700 ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2701 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2702 ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2704 ShowWindow(window, SW_SHOW);
2705 ret = SetForegroundWindow(GetDesktopWindow());
2706 ok(ret, "Failed to set foreground window.\n");
2707 SetActiveWindow(window);
2708 ok(GetActiveWindow() == window, "Unexpected active window.\n");
2709 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2710 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2712 tmp = GetWindowLongA(window, GWL_STYLE);
2713 expected_style = style | WS_VISIBLE;
2714 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2715 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2716 todo_wine ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2718 GetWindowRect(window, &r);
2719 ok(EqualRect(&r, &fullscreen_rect), "Expected %s, got %s.\n",
2720 wine_dbgstr_rect(&fullscreen_rect), wine_dbgstr_rect(&r));
2722 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2723 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2725 SetWindowPos(window, NULL, 0, 0, 100, 100, SWP_NOZORDER | SWP_NOACTIVATE);
2726 GetWindowRect(window, &r);
2727 ok(!EqualRect(&r, &fullscreen_rect), "Window resize failed? got %s.\n",
2728 wine_dbgstr_rect(&r));
2730 ret = SetForegroundWindow(window2);
2731 ok(ret, "Failed to set foreground window.\n");
2732 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2733 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2735 tmp = GetWindowLongA(window, GWL_STYLE);
2736 expected_style = style | WS_VISIBLE;
2737 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2738 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2739 todo_wine ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2741 GetWindowRect(window, &r);
2742 ok(EqualRect(&r, &fullscreen_rect), "Expected %s, got %s.\n",
2743 wine_dbgstr_rect(&fullscreen_rect), wine_dbgstr_rect(&r));
2745 ret = SetForegroundWindow(window);
2746 ok(ret, "Failed to set foreground window.\n");
2747 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2748 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2750 tmp = GetWindowLongA(window, GWL_STYLE);
2751 expected_style = style | WS_VISIBLE;
2752 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2753 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2754 expected_style = exstyle | WS_EX_TOPMOST;
2755 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2757 ShowWindow(window, SW_HIDE);
2758 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2759 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2761 tmp = GetWindowLongA(window, GWL_STYLE);
2762 ok(tmp == style, "Expected window style %#lx, got %#lx.\n", style, tmp);
2763 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2764 ok(tmp == exstyle, "Expected window extended style %#lx, got %#lx.\n", exstyle, tmp);
2766 ShowWindow(window, SW_SHOW);
2767 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2768 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2770 tmp = GetWindowLongA(window, GWL_STYLE);
2771 expected_style = style | WS_VISIBLE;
2772 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2773 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2774 expected_style = exstyle | WS_EX_TOPMOST;
2775 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2777 ret = SetForegroundWindow(GetDesktopWindow());
2778 ok(ret, "Failed to set foreground window.\n");
2779 tmp = GetWindowLongA(window, GWL_STYLE);
2780 expected_style = style | WS_VISIBLE | WS_MINIMIZE;
2781 todo_wine ok(tmp == expected_style, "Expected window style %#lx, got %#lx.\n", expected_style, tmp);
2782 tmp = GetWindowLongA(window, GWL_EXSTYLE);
2783 expected_style = exstyle | WS_EX_TOPMOST;
2784 todo_wine ok(tmp == expected_style, "Expected window extended style %#lx, got %#lx.\n", expected_style, tmp);
2786 ref = IDirectDraw_Release(ddraw);
2787 ok(!ref, "Unexpected refcount %lu.\n", ref);
2789 DestroyWindow(window2);
2790 DestroyWindow(window);
2793 static void test_redundant_mode_set(void)
2795 DDSURFACEDESC surface_desc = {0};
2796 IDirectDraw *ddraw;
2797 RECT q, r, s;
2798 HWND window;
2799 HRESULT hr;
2800 ULONG ref;
2802 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2803 0, 0, 100, 100, 0, 0, 0, 0);
2804 ddraw = create_ddraw();
2805 ok(!!ddraw, "Failed to create a ddraw object.\n");
2807 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2808 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
2810 surface_desc.dwSize = sizeof(surface_desc);
2811 hr = IDirectDraw_GetDisplayMode(ddraw, &surface_desc);
2812 ok(SUCCEEDED(hr), "GetDisplayMode failed, hr %#lx.\n", hr);
2814 hr = IDirectDraw_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2815 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount);
2816 ok(SUCCEEDED(hr), "SetDisplayMode failed, hr %#lx.\n", hr);
2818 GetWindowRect(window, &q);
2819 r = q;
2820 r.right /= 2;
2821 r.bottom /= 2;
2822 SetWindowPos(window, HWND_TOP, r.left, r.top, r.right, r.bottom, 0);
2823 GetWindowRect(window, &s);
2824 ok(EqualRect(&r, &s), "Expected %s, got %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&s));
2826 hr = IDirectDraw_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2827 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount);
2828 ok(SUCCEEDED(hr), "SetDisplayMode failed, hr %#lx.\n", hr);
2830 GetWindowRect(window, &s);
2831 ok(EqualRect(&r, &s) || broken(EqualRect(&q, &s) /* Windows 10 */),
2832 "Expected %s, got %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&s));
2834 ref = IDirectDraw_Release(ddraw);
2835 ok(!ref, "Unexpected refcount %lu.\n", ref);
2837 DestroyWindow(window);
2840 static SIZE screen_size;
2842 static LRESULT CALLBACK mode_set_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2844 if (message == WM_SIZE)
2846 screen_size.cx = GetSystemMetrics(SM_CXSCREEN);
2847 screen_size.cy = GetSystemMetrics(SM_CYSCREEN);
2850 return test_proc(hwnd, message, wparam, lparam);
2853 struct test_coop_level_mode_set_enum_param
2855 DWORD ddraw_width, ddraw_height, user32_width, user32_height;
2858 static HRESULT CALLBACK test_coop_level_mode_set_enum_cb(DDSURFACEDESC *surface_desc, void *context)
2860 struct test_coop_level_mode_set_enum_param *param = context;
2862 if (U1(surface_desc->ddpfPixelFormat).dwRGBBitCount != registry_mode.dmBitsPerPel)
2863 return DDENUMRET_OK;
2864 if (surface_desc->dwWidth == registry_mode.dmPelsWidth
2865 && surface_desc->dwHeight == registry_mode.dmPelsHeight)
2866 return DDENUMRET_OK;
2868 if (!param->ddraw_width)
2870 param->ddraw_width = surface_desc->dwWidth;
2871 param->ddraw_height = surface_desc->dwHeight;
2872 return DDENUMRET_OK;
2874 if (surface_desc->dwWidth == param->ddraw_width && surface_desc->dwHeight == param->ddraw_height)
2875 return DDENUMRET_OK;
2877 /* The docs say the DDENUMRET_CANCEL below cancels the enumeration, so the check should be
2878 * redundant. However, since Windows 10 this no longer works and the enumeration continues
2879 * until all supported modes are enumerated. Win8 and earlier do cancel.
2881 * Unrelatedly, some testbot machines report high res modes like 1920x1080, but suffer from
2882 * some problems when we actually try to set them (w10pro64 and its localization siblings).
2883 * Try to stay below the registry mode if possible. */
2884 if (!param->user32_width || (surface_desc->dwWidth < registry_mode.dmPelsWidth
2885 && surface_desc->dwHeight < registry_mode.dmPelsHeight))
2887 param->user32_width = surface_desc->dwWidth;
2888 param->user32_height = surface_desc->dwHeight;
2890 return DDENUMRET_CANCEL;
2893 static void test_coop_level_mode_set(void)
2895 DEVMODEW *original_modes = NULL, devmode, devmode2;
2896 unsigned int display_count = 0;
2897 IDirectDrawSurface *primary;
2898 RECT registry_rect, ddraw_rect, user32_rect, r;
2899 IDirectDraw *ddraw;
2900 DDSURFACEDESC ddsd;
2901 WNDCLASSA wc = {0};
2902 HWND window;
2903 HRESULT hr;
2904 ULONG ref;
2905 MSG msg;
2906 struct test_coop_level_mode_set_enum_param param;
2907 BOOL ret;
2908 LONG change_ret;
2910 static const struct message exclusive_messages[] =
2912 {WM_WINDOWPOSCHANGING, FALSE, 0},
2913 {WM_WINDOWPOSCHANGED, FALSE, 0},
2914 {WM_SIZE, FALSE, 0},
2915 {WM_DISPLAYCHANGE, FALSE, 0},
2916 {0, FALSE, 0},
2918 static const struct message exclusive_focus_loss_messages[] =
2920 {WM_ACTIVATE, TRUE, WA_INACTIVE},
2921 {WM_WINDOWPOSCHANGING, FALSE, 0}, /* Window resize due to mode change. */
2922 {WM_WINDOWPOSCHANGED, FALSE, 0},
2923 {WM_SIZE, TRUE, SIZE_RESTORED}, /* Generated by DefWindowProc. */
2924 {WM_DISPLAYCHANGE, FALSE, 0},
2925 {WM_KILLFOCUS, FALSE, 0},
2926 {WM_WINDOWPOSCHANGING, FALSE, 0}, /* Window minimized. */
2927 /* Like d3d8 and d3d9 ddraw seems to use SW_SHOWMINIMIZED instead of
2928 * SW_MINIMIZED, causing a recursive window activation that does not
2929 * produce the same result in Wine yet. Ignore the difference for now.
2930 * {WM_ACTIVATE, TRUE, 0x200000 | WA_ACTIVE}, */
2931 {WM_WINDOWPOSCHANGED, FALSE, 0},
2932 {WM_MOVE, FALSE, 0},
2933 {WM_SIZE, TRUE, SIZE_MINIMIZED},
2934 {WM_ACTIVATEAPP, TRUE, FALSE},
2935 {0, FALSE, 0},
2937 static const struct message exclusive_focus_restore_messages[] =
2939 {WM_WINDOWPOSCHANGING, FALSE, 0}, /* From the ShowWindow(SW_RESTORE). */
2940 {WM_WINDOWPOSCHANGING, FALSE, 0}, /* Generated by ddraw, matches d3d9 behavior. */
2941 {WM_WINDOWPOSCHANGED, FALSE, 0}, /* Matching previous message. */
2942 {WM_SIZE, FALSE, 0}, /* DefWindowProc. */
2943 {WM_DISPLAYCHANGE, FALSE, 0}, /* Ddraw restores mode. */
2944 /* Native redundantly sets the window size here. */
2945 {WM_ACTIVATEAPP, TRUE, TRUE}, /* End of ddraw's hooks. */
2946 {WM_WINDOWPOSCHANGED, FALSE, 0}, /* Matching the one from ShowWindow. */
2947 {WM_MOVE, FALSE, 0}, /* DefWindowProc. */
2948 {WM_SIZE, TRUE, SIZE_RESTORED}, /* DefWindowProc. */
2949 {0, FALSE, 0},
2951 static const struct message sc_restore_messages[] =
2953 {WM_SYSCOMMAND, TRUE, SC_RESTORE},
2954 {WM_WINDOWPOSCHANGING, FALSE, 0},
2955 {WM_WINDOWPOSCHANGED, FALSE, 0},
2956 {WM_SIZE, TRUE, SIZE_RESTORED},
2957 {0, FALSE, 0},
2959 static const struct message sc_minimize_messages[] =
2961 {WM_SYSCOMMAND, TRUE, SC_MINIMIZE},
2962 {WM_WINDOWPOSCHANGING, FALSE, 0},
2963 {WM_WINDOWPOSCHANGED, FALSE, 0},
2964 {WM_SIZE, TRUE, SIZE_MINIMIZED},
2965 {0, FALSE, 0},
2967 static const struct message sc_maximize_messages[] =
2969 {WM_SYSCOMMAND, TRUE, SC_MAXIMIZE},
2970 {WM_WINDOWPOSCHANGING, FALSE, 0},
2971 {WM_WINDOWPOSCHANGED, FALSE, 0},
2972 {WM_SIZE, TRUE, SIZE_MAXIMIZED},
2973 {0, FALSE, 0},
2976 static const struct message normal_messages[] =
2978 {WM_DISPLAYCHANGE, FALSE, 0},
2979 {0, FALSE, 0},
2982 memset(&devmode, 0, sizeof(devmode));
2983 devmode.dmSize = sizeof(devmode);
2984 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
2985 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
2986 ok(compare_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
2987 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
2988 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
2989 ok(compare_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
2991 ret = save_display_modes(&original_modes, &display_count);
2992 ok(ret, "Failed to save original display modes.\n");
2994 ddraw = create_ddraw();
2995 ok(!!ddraw, "Failed to create a ddraw object.\n");
2997 memset(&param, 0, sizeof(param));
2998 hr = IDirectDraw_EnumDisplayModes(ddraw, 0, NULL, &param, test_coop_level_mode_set_enum_cb);
2999 ok(SUCCEEDED(hr), "Failed to enumerate display mode, hr %#lx.\n", hr);
3000 ref = IDirectDraw_Release(ddraw);
3001 ok(!ref, "Unexpected refcount %lu.\n", ref);
3003 if (!param.user32_height)
3005 skip("Fewer than 3 different modes supported, skipping mode restore test.\n");
3006 heap_free(original_modes);
3007 return;
3010 SetRect(&registry_rect, 0, 0, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
3011 SetRect(&ddraw_rect, 0, 0, param.ddraw_width, param.ddraw_height);
3012 SetRect(&user32_rect, 0, 0, param.user32_width, param.user32_height);
3014 memset(&devmode, 0, sizeof(devmode));
3015 devmode.dmSize = sizeof(devmode);
3016 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
3017 devmode.dmPelsWidth = param.user32_width;
3018 devmode.dmPelsHeight = param.user32_height;
3019 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
3020 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3022 ddraw = create_ddraw();
3023 ok(!!ddraw, "Failed to create a ddraw object.\n");
3025 wc.lpfnWndProc = mode_set_proc;
3026 wc.lpszClassName = "ddraw_test_wndproc_wc";
3027 ok(RegisterClassA(&wc), "Failed to register window class.\n");
3029 window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test", WS_OVERLAPPEDWINDOW,
3030 0, 0, 100, 100, 0, 0, 0, 0);
3032 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3033 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3035 GetWindowRect(window, &r);
3036 ok(EqualRect(&r, &user32_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&user32_rect),
3037 wine_dbgstr_rect(&r));
3039 memset(&ddsd, 0, sizeof(ddsd));
3040 ddsd.dwSize = sizeof(ddsd);
3041 ddsd.dwFlags = DDSD_CAPS;
3042 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3044 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
3045 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3046 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3047 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3048 ok(ddsd.dwWidth == param.user32_width, "Expected surface width %lu, got %lu.\n",
3049 param.user32_width, ddsd.dwWidth);
3050 ok(ddsd.dwHeight == param.user32_height, "Expected surface height %lu, got %lu.\n",
3051 param.user32_height, ddsd.dwHeight);
3053 GetWindowRect(window, &r);
3054 ok(EqualRect(&r, &user32_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&user32_rect),
3055 wine_dbgstr_rect(&r));
3057 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3058 expect_messages = exclusive_messages;
3059 screen_size.cx = 0;
3060 screen_size.cy = 0;
3062 hr = IDirectDrawSurface_IsLost(primary);
3063 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3064 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3065 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3066 hr = IDirectDrawSurface_IsLost(primary);
3067 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3069 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3070 expect_messages = NULL;
3071 ok(screen_size.cx == param.ddraw_width && screen_size.cy == param.ddraw_height,
3072 "Expected screen size %lux%lu, got %lux%lu.\n",
3073 param.ddraw_width, param.ddraw_height, screen_size.cx, screen_size.cy);
3075 GetWindowRect(window, &r);
3076 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3077 wine_dbgstr_rect(&r));
3079 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3080 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3081 ok(ddsd.dwWidth == param.user32_width, "Expected surface width %lu, got %lu.\n",
3082 param.user32_width, ddsd.dwWidth);
3083 ok(ddsd.dwHeight == param.user32_height, "Expected surface height %lu, got %lu.\n",
3084 param.user32_height, ddsd.dwHeight);
3085 IDirectDrawSurface_Release(primary);
3087 memset(&ddsd, 0, sizeof(ddsd));
3088 ddsd.dwSize = sizeof(ddsd);
3089 ddsd.dwFlags = DDSD_CAPS;
3090 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3092 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
3093 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3094 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3095 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3096 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3097 param.ddraw_width, ddsd.dwWidth);
3098 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3099 param.ddraw_height, ddsd.dwHeight);
3101 GetWindowRect(window, &r);
3102 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3103 wine_dbgstr_rect(&r));
3105 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3106 expect_messages = exclusive_messages;
3107 screen_size.cx = 0;
3108 screen_size.cy = 0;
3110 hr = IDirectDrawSurface_IsLost(primary);
3111 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3112 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
3113 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3114 hr = IDirectDrawSurface_IsLost(primary);
3115 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3117 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3118 expect_messages = NULL;
3119 ok(screen_size.cx == param.user32_width && screen_size.cy == param.user32_height,
3120 "Expected screen size %lux%lu, got %lux%lu.\n",
3121 param.user32_width, param.user32_height, screen_size.cx, screen_size.cy);
3123 GetWindowRect(window, &r);
3124 ok(EqualRect(&r, &user32_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&user32_rect),
3125 wine_dbgstr_rect(&r));
3127 expect_messages = exclusive_focus_loss_messages;
3128 ret = SetForegroundWindow(GetDesktopWindow());
3129 ok(ret, "Failed to set foreground window.\n");
3130 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3131 memset(&devmode, 0, sizeof(devmode));
3132 devmode.dmSize = sizeof(devmode);
3133 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3134 ok(ret, "Failed to get display mode.\n");
3135 ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
3136 && devmode.dmPelsHeight == registry_mode.dmPelsHeight, "Got unexpected screen size %lux%lu.\n",
3137 devmode.dmPelsWidth, devmode.dmPelsHeight);
3139 expect_messages = exclusive_focus_restore_messages;
3140 ShowWindow(window, SW_RESTORE);
3141 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3143 GetWindowRect(window, &r);
3144 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3145 wine_dbgstr_rect(&r));
3146 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3147 ok(ret, "Failed to get display mode.\n");
3148 ok(devmode.dmPelsWidth == param.ddraw_width
3149 && devmode.dmPelsHeight == param.ddraw_height, "Got unexpected screen size %lux%lu.\n",
3150 devmode.dmPelsWidth, devmode.dmPelsHeight);
3152 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3153 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3154 /* Normally the primary should be restored here. Unfortunately this causes the
3155 * GetSurfaceDesc call after the next display mode change to crash on the Windows 8
3156 * testbot. Another Restore call would presumably avoid the crash, but it also moots
3157 * the point of the GetSurfaceDesc call. */
3159 expect_messages = sc_minimize_messages;
3160 SendMessageA(window, WM_SYSCOMMAND, SC_MINIMIZE, 0);
3161 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3162 expect_messages = NULL;
3164 expect_messages = sc_restore_messages;
3165 SendMessageA(window, WM_SYSCOMMAND, SC_RESTORE, 0);
3166 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3167 expect_messages = NULL;
3169 expect_messages = sc_maximize_messages;
3170 SendMessageA(window, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
3171 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3172 expect_messages = NULL;
3174 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3175 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3177 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3178 expect_messages = exclusive_messages;
3179 screen_size.cx = 0;
3180 screen_size.cy = 0;
3182 hr = IDirectDrawSurface_IsLost(primary);
3183 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3184 hr = IDirectDraw_RestoreDisplayMode(ddraw);
3185 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#lx.\n", hr);
3186 hr = IDirectDrawSurface_IsLost(primary);
3187 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3189 flaky /* win8 */
3190 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3191 expect_messages = NULL;
3192 flaky /* win8 */
3193 ok(screen_size.cx == registry_mode.dmPelsWidth
3194 && screen_size.cy == registry_mode.dmPelsHeight,
3195 "Expected screen size %lux%lu, got %lux%lu.\n",
3196 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight, screen_size.cx, screen_size.cy);
3198 GetWindowRect(window, &r);
3199 flaky /* win8 */
3200 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3201 wine_dbgstr_rect(&r));
3203 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3204 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3205 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3206 param.ddraw_width, ddsd.dwWidth);
3207 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3208 param.ddraw_height, ddsd.dwHeight);
3209 IDirectDrawSurface_Release(primary);
3211 /* For Wine. */
3212 change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
3213 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3215 memset(&ddsd, 0, sizeof(ddsd));
3216 ddsd.dwSize = sizeof(ddsd);
3217 ddsd.dwFlags = DDSD_CAPS;
3218 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3220 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
3221 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3222 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3223 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3224 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3225 registry_mode.dmPelsWidth, ddsd.dwWidth);
3226 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3227 registry_mode.dmPelsHeight, ddsd.dwHeight);
3229 GetWindowRect(window, &r);
3230 flaky /* win8 */
3231 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3232 wine_dbgstr_rect(&r));
3234 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3235 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3237 GetWindowRect(window, &r);
3238 flaky /* win8 */
3239 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3240 wine_dbgstr_rect(&r));
3242 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3243 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3244 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3245 registry_mode.dmPelsWidth, ddsd.dwWidth);
3246 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3247 registry_mode.dmPelsHeight, ddsd.dwHeight);
3248 IDirectDrawSurface_Release(primary);
3250 memset(&ddsd, 0, sizeof(ddsd));
3251 ddsd.dwSize = sizeof(ddsd);
3252 ddsd.dwFlags = DDSD_CAPS;
3253 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3255 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
3256 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3257 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3258 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3259 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3260 registry_mode.dmPelsWidth, ddsd.dwWidth);
3261 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3262 registry_mode.dmPelsHeight, ddsd.dwHeight);
3264 GetWindowRect(window, &r);
3265 flaky /* win8 */
3266 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3267 wine_dbgstr_rect(&r));
3269 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3270 expect_messages = normal_messages;
3271 screen_size.cx = 0;
3272 screen_size.cy = 0;
3274 hr = IDirectDrawSurface_IsLost(primary);
3275 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3276 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
3277 devmode.dmPelsWidth = param.user32_width;
3278 devmode.dmPelsHeight = param.user32_height;
3279 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
3280 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3281 hr = IDirectDrawSurface_IsLost(primary);
3282 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3284 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3285 expect_messages = NULL;
3286 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3288 GetWindowRect(window, &r);
3289 flaky /* win8 */
3290 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3291 wine_dbgstr_rect(&r));
3293 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3294 expect_messages = normal_messages;
3295 screen_size.cx = 0;
3296 screen_size.cy = 0;
3298 hr = IDirectDrawSurface_Restore(primary);
3299 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
3300 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3301 if (hr == DDERR_NOEXCLUSIVEMODE /* NT4 testbot */)
3303 win_skip("Broken SetDisplayMode(), skipping remaining tests.\n");
3304 IDirectDrawSurface_Release(primary);
3305 IDirectDraw_Release(ddraw);
3306 goto done;
3308 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3309 hr = IDirectDrawSurface_Restore(primary);
3310 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
3311 hr = IDirectDrawSurface_IsLost(primary);
3312 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3314 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3315 expect_messages = NULL;
3316 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3318 GetWindowRect(window, &r);
3319 flaky /* win8 */
3320 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3321 wine_dbgstr_rect(&r));
3323 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3324 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3325 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3326 registry_mode.dmPelsWidth, ddsd.dwWidth);
3327 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3328 registry_mode.dmPelsHeight, ddsd.dwHeight);
3329 IDirectDrawSurface_Release(primary);
3331 memset(&ddsd, 0, sizeof(ddsd));
3332 ddsd.dwSize = sizeof(ddsd);
3333 ddsd.dwFlags = DDSD_CAPS;
3334 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3336 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
3337 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3338 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3339 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3340 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3341 param.ddraw_width, ddsd.dwWidth);
3342 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3343 param.ddraw_height, ddsd.dwHeight);
3345 GetWindowRect(window, &r);
3346 flaky /* win8 */
3347 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3348 wine_dbgstr_rect(&r));
3350 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3351 expect_messages = normal_messages;
3352 screen_size.cx = 0;
3353 screen_size.cy = 0;
3355 hr = IDirectDrawSurface_IsLost(primary);
3356 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3357 hr = IDirectDraw_RestoreDisplayMode(ddraw);
3358 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#lx.\n", hr);
3359 hr = IDirectDrawSurface_IsLost(primary);
3360 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3362 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3363 expect_messages = NULL;
3364 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3366 GetWindowRect(window, &r);
3367 flaky /* win8 */
3368 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3369 wine_dbgstr_rect(&r));
3371 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3372 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3373 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3374 param.ddraw_width, ddsd.dwWidth);
3375 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3376 param.ddraw_height, ddsd.dwHeight);
3377 IDirectDrawSurface_Release(primary);
3379 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3380 ok(ret, "Failed to get display mode.\n");
3381 ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
3382 && devmode.dmPelsHeight == registry_mode.dmPelsHeight,
3383 "Expected resolution %lux%lu, got %lux%lu.\n",
3384 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight,
3385 devmode.dmPelsWidth, devmode.dmPelsHeight);
3386 change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
3387 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3389 memset(&ddsd, 0, sizeof(ddsd));
3390 ddsd.dwSize = sizeof(ddsd);
3391 ddsd.dwFlags = DDSD_CAPS;
3392 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3394 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
3395 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3396 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3397 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3398 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3399 registry_mode.dmPelsWidth, ddsd.dwWidth);
3400 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3401 registry_mode.dmPelsHeight, ddsd.dwHeight);
3403 GetWindowRect(window, &r);
3404 flaky /* win8 */
3405 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3406 wine_dbgstr_rect(&r));
3408 /* DDSCL_NORMAL | DDSCL_FULLSCREEN behaves the same as just DDSCL_NORMAL.
3409 * Resizing the window on mode changes is a property of DDSCL_EXCLUSIVE,
3410 * not DDSCL_FULLSCREEN. */
3411 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
3412 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3414 GetWindowRect(window, &r);
3415 flaky /* win8 */
3416 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3417 wine_dbgstr_rect(&r));
3419 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3420 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3421 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3422 registry_mode.dmPelsWidth, ddsd.dwWidth);
3423 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3424 registry_mode.dmPelsHeight, ddsd.dwHeight);
3425 IDirectDrawSurface_Release(primary);
3427 memset(&ddsd, 0, sizeof(ddsd));
3428 ddsd.dwSize = sizeof(ddsd);
3429 ddsd.dwFlags = DDSD_CAPS;
3430 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3432 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
3433 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3434 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3435 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3436 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3437 registry_mode.dmPelsWidth, ddsd.dwWidth);
3438 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3439 registry_mode.dmPelsHeight, ddsd.dwHeight);
3441 GetWindowRect(window, &r);
3442 flaky /* win8 */
3443 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3444 wine_dbgstr_rect(&r));
3446 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3447 expect_messages = normal_messages;
3448 screen_size.cx = 0;
3449 screen_size.cy = 0;
3451 hr = IDirectDrawSurface_IsLost(primary);
3452 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3453 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
3454 devmode.dmPelsWidth = param.user32_width;
3455 devmode.dmPelsHeight = param.user32_height;
3456 change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
3457 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3458 hr = IDirectDrawSurface_IsLost(primary);
3459 todo_wine ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3461 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3462 expect_messages = NULL;
3463 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3465 GetWindowRect(window, &r);
3466 flaky /* win8 */
3467 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3468 wine_dbgstr_rect(&r));
3470 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3471 expect_messages = normal_messages;
3472 screen_size.cx = 0;
3473 screen_size.cy = 0;
3475 hr = IDirectDrawSurface_Restore(primary);
3476 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
3477 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3478 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3479 hr = IDirectDrawSurface_Restore(primary);
3480 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
3481 hr = IDirectDrawSurface_IsLost(primary);
3482 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3484 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3485 expect_messages = NULL;
3486 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3488 GetWindowRect(window, &r);
3489 flaky /* win8 */
3490 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3491 wine_dbgstr_rect(&r));
3493 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3494 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3495 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3496 registry_mode.dmPelsWidth, ddsd.dwWidth);
3497 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3498 registry_mode.dmPelsHeight, ddsd.dwHeight);
3499 IDirectDrawSurface_Release(primary);
3501 memset(&ddsd, 0, sizeof(ddsd));
3502 ddsd.dwSize = sizeof(ddsd);
3503 ddsd.dwFlags = DDSD_CAPS;
3504 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3506 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
3507 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3508 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3509 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3510 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3511 param.ddraw_width, ddsd.dwWidth);
3512 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3513 param.ddraw_height, ddsd.dwHeight);
3515 GetWindowRect(window, &r);
3516 flaky /* win8 */
3517 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3518 wine_dbgstr_rect(&r));
3520 PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
3521 expect_messages = normal_messages;
3522 screen_size.cx = 0;
3523 screen_size.cy = 0;
3525 hr = IDirectDrawSurface_IsLost(primary);
3526 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
3527 hr = IDirectDraw_RestoreDisplayMode(ddraw);
3528 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#lx.\n", hr);
3529 hr = IDirectDrawSurface_IsLost(primary);
3530 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
3532 ok(!expect_messages->message, "Expected message %#x, but didn't receive it.\n", expect_messages->message);
3533 expect_messages = NULL;
3534 ok(!screen_size.cx && !screen_size.cy, "Got unexpected screen size %lux%lu.\n", screen_size.cx, screen_size.cy);
3536 GetWindowRect(window, &r);
3537 flaky /* win8 */
3538 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3539 wine_dbgstr_rect(&r));
3541 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3542 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3543 ok(ddsd.dwWidth == param.ddraw_width, "Expected surface width %lu, got %lu.\n",
3544 param.ddraw_width, ddsd.dwWidth);
3545 ok(ddsd.dwHeight == param.ddraw_height, "Expected surface height %lu, got %lu.\n",
3546 param.ddraw_height, ddsd.dwHeight);
3547 IDirectDrawSurface_Release(primary);
3549 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3550 ok(ret, "Failed to get display mode.\n");
3551 ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
3552 && devmode.dmPelsHeight == registry_mode.dmPelsHeight,
3553 "Expected resolution %lux%lu, got %lux%lu.\n",
3554 registry_mode.dmPelsWidth, registry_mode.dmPelsHeight,
3555 devmode.dmPelsWidth, devmode.dmPelsHeight);
3556 change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
3557 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#lx.\n", change_ret);
3559 memset(&ddsd, 0, sizeof(ddsd));
3560 ddsd.dwSize = sizeof(ddsd);
3561 ddsd.dwFlags = DDSD_CAPS;
3562 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3564 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
3565 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
3566 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
3567 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
3568 ok(ddsd.dwWidth == registry_mode.dmPelsWidth, "Expected surface width %lu, got %lu.\n",
3569 registry_mode.dmPelsWidth, ddsd.dwWidth);
3570 ok(ddsd.dwHeight == registry_mode.dmPelsHeight, "Expected surface height %lu, got %lu.\n",
3571 registry_mode.dmPelsHeight, ddsd.dwHeight);
3572 IDirectDrawSurface_Release(primary);
3574 GetWindowRect(window, &r);
3575 flaky /* win8 */
3576 ok(EqualRect(&r, &registry_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&registry_rect),
3577 wine_dbgstr_rect(&r));
3579 /* Unlike ddraw2-7, changing from EXCLUSIVE to NORMAL does not restore the resolution */
3580 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3581 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3582 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3583 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3585 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3586 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3588 memset(&ddsd, 0, sizeof(ddsd));
3589 ddsd.dwSize = sizeof(ddsd);
3590 ddsd.dwFlags = DDSD_CAPS;
3591 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3593 hr = IDirectDraw_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);
3601 IDirectDrawSurface_Release(primary);
3602 hr = IDirectDraw_RestoreDisplayMode(ddraw);
3603 ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#lx.\n", hr);
3605 ref = IDirectDraw_Release(ddraw);
3606 ok(!ref, "Unexpected refcount %lu.\n", ref);
3608 GetWindowRect(window, &r);
3609 ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
3610 wine_dbgstr_rect(&r));
3612 ret = restore_display_modes(original_modes, display_count);
3613 ok(ret, "Failed to restore display modes.\n");
3615 /* Test that no mode restorations if no mode changes happened */
3616 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
3617 devmode.dmPelsWidth = param.user32_width;
3618 devmode.dmPelsHeight = param.user32_height;
3619 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
3620 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
3622 ddraw = create_ddraw();
3623 ok(!!ddraw, "Failed to create a ddraw object.\n");
3624 ref = IDirectDraw_Release(ddraw);
3625 ok(!ref, "Unexpected refcount %lu.\n", ref);
3627 memset(&devmode2, 0, sizeof(devmode2));
3628 devmode2.dmSize = sizeof(devmode2);
3629 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
3630 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3631 ok(compare_mode_rect(&devmode2, &registry_mode), "Got a different mode.\n");
3632 ret = restore_display_modes(original_modes, display_count);
3633 ok(ret, "Failed to restore display modes.\n");
3635 /* Test that no mode restorations if no mode changes happened with fullscreen ddraw objects */
3636 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
3637 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
3639 ddraw = create_ddraw();
3640 ok(!!ddraw, "Failed to create a ddraw object.\n");
3641 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3642 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
3643 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
3644 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
3645 ref = IDirectDraw_Release(ddraw);
3646 ok(!ref, "Unexpected refcount %lu.\n", ref);
3648 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
3649 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3650 ok(compare_mode_rect(&devmode2, &registry_mode), "Got a different mode.\n");
3651 ret = restore_display_modes(original_modes, display_count);
3652 ok(ret, "Failed to restore display modes.\n");
3654 /* Test that mode restorations use display settings in the registry after ddraw object releases
3655 * if SetDisplayMode() was called */
3656 ddraw = create_ddraw();
3657 ok(!!ddraw, "Failed to create a ddraw object.\n");
3658 hr = set_display_mode(ddraw, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
3659 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
3661 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
3662 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
3664 ref = IDirectDraw_Release(ddraw);
3665 ok(!ref, "Unexpected refcount %lu.\n", ref);
3667 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
3668 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3669 ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
3670 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
3671 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3672 ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
3673 ret = restore_display_modes(original_modes, display_count);
3674 ok(ret, "Failed to restore display modes.\n");
3676 /* Test that mode restorations use display settings in the registry after RestoreDisplayMode() */
3677 ddraw = create_ddraw();
3678 ok(!!ddraw, "Failed to create a ddraw object.\n");
3679 hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
3680 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
3682 change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
3683 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %ld.\n", change_ret);
3685 hr = IDirectDraw_RestoreDisplayMode(ddraw);
3686 ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#lx.\n", hr);
3688 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
3689 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3690 ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
3691 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
3692 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3693 ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
3695 ref = IDirectDraw_Release(ddraw);
3696 ok(!ref, "Unexpected refcount %lu.\n", ref);
3698 done:
3699 expect_messages = NULL;
3700 DestroyWindow(window);
3701 UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
3702 ret = restore_display_modes(original_modes, display_count);
3703 ok(ret, "Failed to restore display modes.\n");
3704 heap_free(original_modes);
3707 static void test_coop_level_mode_set_multi(void)
3709 DEVMODEW old_devmode, devmode, devmode2, devmode3, *original_modes = NULL;
3710 unsigned int mode_idx = 0, display_idx, display_count = 0;
3711 WCHAR second_monitor_name[CCHDEVICENAME];
3712 IDirectDraw *ddraw1, *ddraw2;
3713 LONG change_ret;
3714 UINT w, h;
3715 HWND window;
3716 HRESULT hr;
3717 ULONG ref;
3718 BOOL ret;
3720 memset(&devmode, 0, sizeof(devmode));
3721 devmode.dmSize = sizeof(devmode);
3722 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3723 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3724 ok(compare_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
3725 ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
3726 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3727 ok(compare_mode_rect(&devmode, &registry_mode), "Got a different mode.\n");
3729 ret = save_display_modes(&original_modes, &display_count);
3730 ok(ret, "Failed to save original display modes.\n");
3732 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
3733 0, 0, 100, 100, 0, 0, 0, 0);
3734 ddraw1 = create_ddraw();
3735 ok(!!ddraw1, "Failed to create a ddraw object.\n");
3737 /* With just a single ddraw object, the display mode is restored on
3738 * release. */
3739 hr = set_display_mode(ddraw1, 800, 600);
3740 if (hr == DDERR_NOEXCLUSIVEMODE /* NT4 testbot */)
3742 win_skip("Broken SetDisplayMode(), skipping test.\n");
3743 IDirectDraw_Release(ddraw1);
3744 DestroyWindow(window);
3745 return;
3747 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3748 w = GetSystemMetrics(SM_CXSCREEN);
3749 ok(w == 800, "Got unexpected screen width %u.\n", w);
3750 h = GetSystemMetrics(SM_CYSCREEN);
3751 ok(h == 600, "Got unexpected screen height %u.\n", h);
3753 ref = IDirectDraw_Release(ddraw1);
3754 ok(!ref, "Unexpected refcount %lu.\n", ref);
3755 w = GetSystemMetrics(SM_CXSCREEN);
3756 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3757 h = GetSystemMetrics(SM_CYSCREEN);
3758 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3760 /* When there are multiple ddraw objects, the display mode is restored to
3761 * the initial mode, before the first SetDisplayMode() call. */
3762 ddraw1 = create_ddraw();
3763 hr = set_display_mode(ddraw1, 800, 600);
3764 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3765 w = GetSystemMetrics(SM_CXSCREEN);
3766 ok(w == 800, "Got unexpected screen width %u.\n", w);
3767 h = GetSystemMetrics(SM_CYSCREEN);
3768 ok(h == 600, "Got unexpected screen height %u.\n", h);
3770 ddraw2 = create_ddraw();
3771 hr = set_display_mode(ddraw2, 640, 480);
3772 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3773 w = GetSystemMetrics(SM_CXSCREEN);
3774 ok(w == 640, "Got unexpected screen width %u.\n", w);
3775 h = GetSystemMetrics(SM_CYSCREEN);
3776 ok(h == 480, "Got unexpected screen height %u.\n", h);
3778 ref = IDirectDraw_Release(ddraw2);
3779 ok(!ref, "Unexpected refcount %lu.\n", ref);
3780 w = GetSystemMetrics(SM_CXSCREEN);
3781 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3782 h = GetSystemMetrics(SM_CYSCREEN);
3783 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3785 ref = IDirectDraw_Release(ddraw1);
3786 ok(!ref, "Unexpected refcount %lu.\n", ref);
3787 w = GetSystemMetrics(SM_CXSCREEN);
3788 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3789 h = GetSystemMetrics(SM_CYSCREEN);
3790 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3792 /* Regardless of release ordering. */
3793 ddraw1 = create_ddraw();
3794 hr = set_display_mode(ddraw1, 800, 600);
3795 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3796 w = GetSystemMetrics(SM_CXSCREEN);
3797 ok(w == 800, "Got unexpected screen width %u.\n", w);
3798 h = GetSystemMetrics(SM_CYSCREEN);
3799 ok(h == 600, "Got unexpected screen height %u.\n", h);
3801 ddraw2 = create_ddraw();
3802 hr = set_display_mode(ddraw2, 640, 480);
3803 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3804 w = GetSystemMetrics(SM_CXSCREEN);
3805 ok(w == 640, "Got unexpected screen width %u.\n", w);
3806 h = GetSystemMetrics(SM_CYSCREEN);
3807 ok(h == 480, "Got unexpected screen height %u.\n", h);
3809 ref = IDirectDraw_Release(ddraw1);
3810 ok(!ref, "Unexpected refcount %lu.\n", ref);
3811 w = GetSystemMetrics(SM_CXSCREEN);
3812 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3813 h = GetSystemMetrics(SM_CYSCREEN);
3814 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3816 ref = IDirectDraw_Release(ddraw2);
3817 ok(!ref, "Unexpected refcount %lu.\n", ref);
3818 w = GetSystemMetrics(SM_CXSCREEN);
3819 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3820 h = GetSystemMetrics(SM_CYSCREEN);
3821 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3823 /* But only for ddraw objects that called SetDisplayMode(). */
3824 ddraw1 = create_ddraw();
3825 ddraw2 = create_ddraw();
3826 hr = set_display_mode(ddraw2, 640, 480);
3827 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3828 w = GetSystemMetrics(SM_CXSCREEN);
3829 ok(w == 640, "Got unexpected screen width %u.\n", w);
3830 h = GetSystemMetrics(SM_CYSCREEN);
3831 ok(h == 480, "Got unexpected screen height %u.\n", h);
3833 ref = IDirectDraw_Release(ddraw1);
3834 ok(!ref, "Unexpected refcount %lu.\n", ref);
3835 w = GetSystemMetrics(SM_CXSCREEN);
3836 ok(w == 640, "Got unexpected screen width %u.\n", w);
3837 h = GetSystemMetrics(SM_CYSCREEN);
3838 ok(h == 480, "Got unexpected screen height %u.\n", h);
3840 ref = IDirectDraw_Release(ddraw2);
3841 ok(!ref, "Unexpected refcount %lu.\n", ref);
3842 w = GetSystemMetrics(SM_CXSCREEN);
3843 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3844 h = GetSystemMetrics(SM_CYSCREEN);
3845 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3847 /* If there's a ddraw object that's currently in exclusive mode, it blocks
3848 * restoring the display mode. */
3849 ddraw1 = create_ddraw();
3850 hr = set_display_mode(ddraw1, 800, 600);
3851 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3852 w = GetSystemMetrics(SM_CXSCREEN);
3853 ok(w == 800, "Got unexpected screen width %u.\n", w);
3854 h = GetSystemMetrics(SM_CYSCREEN);
3855 ok(h == 600, "Got unexpected screen height %u.\n", h);
3857 ddraw2 = create_ddraw();
3858 hr = set_display_mode(ddraw2, 640, 480);
3859 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3860 w = GetSystemMetrics(SM_CXSCREEN);
3861 ok(w == 640, "Got unexpected screen width %u.\n", w);
3862 h = GetSystemMetrics(SM_CYSCREEN);
3863 ok(h == 480, "Got unexpected screen height %u.\n", h);
3865 hr = IDirectDraw_SetCooperativeLevel(ddraw2, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3866 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3868 ref = IDirectDraw_Release(ddraw1);
3869 ok(!ref, "Unexpected refcount %lu.\n", ref);
3870 w = GetSystemMetrics(SM_CXSCREEN);
3871 ok(w == 640, "Got unexpected screen width %u.\n", w);
3872 h = GetSystemMetrics(SM_CYSCREEN);
3873 ok(h == 480, "Got unexpected screen height %u.\n", h);
3875 ref = IDirectDraw_Release(ddraw2);
3876 ok(!ref, "Unexpected refcount %lu.\n", ref);
3877 w = GetSystemMetrics(SM_CXSCREEN);
3878 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3879 h = GetSystemMetrics(SM_CYSCREEN);
3880 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3882 /* Exclusive mode blocks mode setting on other ddraw objects in general. */
3883 ddraw1 = create_ddraw();
3884 hr = set_display_mode(ddraw1, 800, 600);
3885 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
3886 w = GetSystemMetrics(SM_CXSCREEN);
3887 ok(w == 800, "Got unexpected screen width %u.\n", w);
3888 h = GetSystemMetrics(SM_CYSCREEN);
3889 ok(h == 600, "Got unexpected screen height %u.\n", h);
3891 hr = IDirectDraw_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3892 ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#lx.\n", hr);
3894 ddraw2 = create_ddraw();
3895 hr = set_display_mode(ddraw2, 640, 480);
3896 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#lx.\n", hr);
3898 ref = IDirectDraw_Release(ddraw1);
3899 ok(!ref, "Unexpected refcount %lu.\n", ref);
3900 w = GetSystemMetrics(SM_CXSCREEN);
3901 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3902 h = GetSystemMetrics(SM_CYSCREEN);
3903 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3905 ref = IDirectDraw_Release(ddraw2);
3906 ok(!ref, "Unexpected refcount %lu.\n", ref);
3907 w = GetSystemMetrics(SM_CXSCREEN);
3908 ok(w == registry_mode.dmPelsWidth, "Got unexpected screen width %u.\n", w);
3909 h = GetSystemMetrics(SM_CYSCREEN);
3910 ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
3912 if (display_count < 2)
3914 skip("Following tests require two monitors.\n");
3915 goto done;
3918 ret = restore_display_modes(original_modes, display_count);
3919 ok(ret, "Failed to restore display modes.\n");
3921 second_monitor_name[0] = '\0';
3922 for (display_idx = 0; display_idx < display_count; ++display_idx)
3924 if (original_modes[display_idx].dmPosition.x || original_modes[display_idx].dmPosition.y)
3926 lstrcpyW(second_monitor_name, original_modes[display_idx].dmDeviceName);
3927 break;
3930 ok(lstrlenW(second_monitor_name), "Got an empty second monitor name.\n");
3931 memset(&old_devmode, 0, sizeof(old_devmode));
3932 old_devmode.dmSize = sizeof(old_devmode);
3933 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
3934 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3936 devmode = old_devmode;
3937 while (EnumDisplaySettingsW(second_monitor_name, mode_idx++, &devmode))
3939 if (devmode.dmPelsWidth != old_devmode.dmPelsWidth
3940 || devmode.dmPelsHeight != old_devmode.dmPelsHeight)
3941 break;
3943 ok(devmode.dmPelsWidth != old_devmode.dmPelsWidth
3944 || devmode.dmPelsHeight != old_devmode.dmPelsHeight,
3945 "Failed to find a different mode for the second monitor.\n");
3947 /* Test that no mode restorations for non-primary monitors if SetDisplayMode() was not called */
3948 ddraw1 = create_ddraw();
3949 ok(!!ddraw1, "Failed to create a ddraw object.\n");
3950 hr = IDirectDraw_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3951 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
3953 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
3954 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
3956 memset(&devmode2, 0, sizeof(devmode2));
3957 devmode2.dmSize = sizeof(devmode2);
3958 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
3959 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3960 if (compare_mode_rect(&devmode2, &old_devmode))
3962 skip("Failed to change display settings of the second monitor.\n");
3963 ref = IDirectDraw_Release(ddraw1);
3964 ok(!ref, "Unexpected refcount %lu.\n", ref);
3965 goto done;
3968 hr = IDirectDraw_SetCooperativeLevel(ddraw1, window, DDSCL_NORMAL);
3969 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
3970 ref = IDirectDraw_Release(ddraw1);
3971 ok(!ref, "Unexpected refcount %lu.\n", ref);
3973 memset(&devmode3, 0, sizeof(devmode3));
3974 devmode3.dmSize = sizeof(devmode3);
3975 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode3);
3976 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3977 ok(compare_mode_rect(&devmode3, &devmode2), "Got a different mode.\n");
3978 ret = restore_display_modes(original_modes, display_count);
3979 ok(ret, "Failed to restore display modes.\n");
3981 /* Test that mode restorations happen for non-primary monitors on ddraw releases if
3982 * SetDisplayMode() was called */
3983 ddraw1 = create_ddraw();
3984 ok(!!ddraw1, "Failed to create a ddraw object.\n");
3985 hr = set_display_mode(ddraw1, 800, 600);
3986 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
3988 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
3989 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
3991 ref = IDirectDraw_Release(ddraw1);
3992 ok(!ref, "Unexpected refcount %lu.\n", ref);
3994 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
3995 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3996 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
3997 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
3998 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
3999 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4000 ret = restore_display_modes(original_modes, display_count);
4001 ok(ret, "Failed to restore display modes.\n");
4003 /* Test that mode restorations happen for non-primary monitors as well */
4004 ddraw1 = create_ddraw();
4005 ok(!!ddraw1, "Failed to create a ddraw object.\n");
4006 hr = set_display_mode(ddraw1, 800, 600);
4007 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4009 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
4010 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
4012 hr = IDirectDraw_RestoreDisplayMode(ddraw1);
4013 ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#lx.\n", hr);
4015 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
4016 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4017 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4018 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
4019 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4020 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4022 ref = IDirectDraw_Release(ddraw1);
4023 ok(!ref, "Unexpected refcount %lu.\n", ref);
4024 ret = restore_display_modes(original_modes, display_count);
4025 ok(ret, "Failed to restore display modes.\n");
4027 /* Test that mode restorations for non-primary monitors use display settings in the registry */
4028 ddraw1 = create_ddraw();
4029 ok(!!ddraw1, "Failed to create a ddraw object.\n");
4030 hr = set_display_mode(ddraw1, 800, 600);
4031 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4033 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
4034 CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
4035 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
4037 ref = IDirectDraw_Release(ddraw1);
4038 ok(!ref, "Unexpected refcount %lu.\n", ref);
4040 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
4041 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4042 ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
4043 "Expected resolution %lux%lu, got %lux%lu.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
4044 devmode2.dmPelsWidth, devmode2.dmPelsHeight);
4045 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
4046 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4047 ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
4048 "Expected resolution %lux%lu, got %lux%lu.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
4049 devmode2.dmPelsWidth, devmode2.dmPelsHeight);
4050 ret = restore_display_modes(original_modes, display_count);
4051 ok(ret, "Failed to restore display modes.\n");
4053 /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
4054 * objects and one of them restores display mode */
4055 ddraw1 = create_ddraw();
4056 ok(!!ddraw1, "Failed to create a ddraw object.\n");
4057 ddraw2 = create_ddraw();
4058 ok(!!ddraw2, "Failed to create a ddraw object.\n");
4059 hr = set_display_mode(ddraw1, 800, 600);
4060 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4061 hr = set_display_mode(ddraw2, 640, 480);
4062 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4064 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
4065 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
4067 hr = IDirectDraw_RestoreDisplayMode(ddraw2);
4068 ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#lx.\n", hr);
4070 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
4071 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4072 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4073 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
4074 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4075 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4077 ref = IDirectDraw_Release(ddraw2);
4078 ok(!ref, "Unexpected refcount %lu.\n", ref);
4079 ref = IDirectDraw_Release(ddraw1);
4080 ok(!ref, "Unexpected refcount %lu.\n", ref);
4081 ret = restore_display_modes(original_modes, display_count);
4082 ok(ret, "Failed to restore display modes.\n");
4084 /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
4085 * objects and one of them got released */
4086 ddraw1 = create_ddraw();
4087 ok(!!ddraw1, "Failed to create a ddraw object.\n");
4088 ddraw2 = create_ddraw();
4089 ok(!!ddraw2, "Failed to create a ddraw object.\n");
4090 hr = set_display_mode(ddraw1, 800, 600);
4091 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4092 hr = set_display_mode(ddraw2, 640, 480);
4093 ok(hr == DD_OK, "Failed to set display mode, hr %#lx.\n", hr);
4095 change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
4096 ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %ld.\n", change_ret);
4098 ref = IDirectDraw_Release(ddraw2);
4099 ok(!ref, "Unexpected refcount %lu.\n", ref);
4101 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
4102 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4103 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4104 ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
4105 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
4106 ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
4108 ref = IDirectDraw_Release(ddraw1);
4109 ok(!ref, "Unexpected refcount %lu.\n", ref);
4111 done:
4112 DestroyWindow(window);
4113 ret = restore_display_modes(original_modes, display_count);
4114 ok(ret, "Failed to restore display modes.\n");
4115 heap_free(original_modes);
4118 static void test_initialize(void)
4120 IDirectDraw *ddraw;
4121 IDirect3D *d3d;
4122 HRESULT hr;
4124 ddraw = create_ddraw();
4125 ok(!!ddraw, "Failed to create a ddraw object.\n");
4127 hr = IDirectDraw_Initialize(ddraw, NULL);
4128 ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#lx.\n", hr);
4129 IDirectDraw_Release(ddraw);
4131 CoInitialize(NULL);
4132 hr = CoCreateInstance(&CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectDraw, (void **)&ddraw);
4133 ok(SUCCEEDED(hr), "Failed to create IDirectDraw instance, hr %#lx.\n", hr);
4134 hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
4135 if (SUCCEEDED(hr))
4137 /* IDirect3D_Initialize() just returns DDERR_ALREADYINITIALIZED. */
4138 hr = IDirect3D_Initialize(d3d, NULL);
4139 ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#lx, expected DDERR_ALREADYINITIALIZED.\n", hr);
4140 IDirect3D_Release(d3d);
4142 else
4143 skip("D3D interface is not available, skipping test.\n");
4144 hr = IDirectDraw_Initialize(ddraw, NULL);
4145 ok(hr == DD_OK, "Initialize returned hr %#lx, expected DD_OK.\n", hr);
4146 hr = IDirectDraw_Initialize(ddraw, NULL);
4147 ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#lx, expected DDERR_ALREADYINITIALIZED.\n", hr);
4148 IDirectDraw_Release(ddraw);
4149 CoUninitialize();
4151 if (0) /* This crashes on the W2KPROSP4 testbot. */
4153 CoInitialize(NULL);
4154 hr = CoCreateInstance(&CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER, &IID_IDirect3D, (void **)&d3d);
4155 ok(hr == E_NOINTERFACE, "CoCreateInstance returned hr %#lx, expected E_NOINTERFACE.\n", hr);
4156 CoUninitialize();
4160 static void test_coop_level_surf_create(void)
4162 IDirectDrawSurface *surface;
4163 IDirectDraw *ddraw;
4164 DDSURFACEDESC ddsd;
4165 HRESULT hr;
4167 ddraw = create_ddraw();
4168 ok(!!ddraw, "Failed to create a ddraw object.\n");
4170 memset(&ddsd, 0, sizeof(ddsd));
4171 ddsd.dwSize = sizeof(ddsd);
4172 ddsd.dwFlags = DDSD_CAPS;
4173 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
4174 surface = (void *)0xdeadbeef;
4175 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
4176 ok(hr == DDERR_NOCOOPERATIVELEVELSET, "Surface creation returned hr %#lx.\n", hr);
4177 ok(surface == (void *)0xdeadbeef, "Got unexpected surface %p.\n", surface);
4179 surface = (void *)0xdeadbeef;
4180 hr = IDirectDraw_CreateSurface(ddraw, NULL, &surface, NULL);
4181 ok(hr == DDERR_NOCOOPERATIVELEVELSET, "Surface creation returned hr %#lx.\n", hr);
4182 ok(surface == (void *)0xdeadbeef, "Got unexpected surface %p.\n", surface);
4184 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4185 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4187 surface = (void *)0xdeadbeef;
4188 hr = IDirectDraw_CreateSurface(ddraw, NULL, &surface, NULL);
4189 ok(hr == DDERR_INVALIDPARAMS, "Unexpected hr %#lx.\n", hr);
4190 ok(surface == (void *)0xdeadbeef, "Got unexpected surface %p.\n", surface);
4192 IDirectDraw_Release(ddraw);
4195 static void test_coop_level_multi_window(void)
4197 HWND window1, window2;
4198 IDirectDraw *ddraw;
4199 HRESULT hr;
4201 window1 = create_window();
4202 window2 = create_window();
4203 ddraw = create_ddraw();
4204 ok(!!ddraw, "Failed to create a ddraw object.\n");
4206 hr = IDirectDraw_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
4207 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4208 hr = IDirectDraw_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL);
4209 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4210 ok(IsWindow(window1), "Window 1 was destroyed.\n");
4211 ok(IsWindow(window2), "Window 2 was destroyed.\n");
4213 IDirectDraw_Release(ddraw);
4214 DestroyWindow(window2);
4215 DestroyWindow(window1);
4218 static void test_clear_rect_count(void)
4220 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
4221 IDirect3DMaterial *white, *red, *green, *blue;
4222 IDirect3DViewport *viewport;
4223 IDirect3DDevice *device;
4224 IDirectDrawSurface *rt;
4225 unsigned int color;
4226 IDirectDraw *ddraw;
4227 HWND window;
4228 HRESULT hr;
4230 window = create_window();
4231 ddraw = create_ddraw();
4232 ok(!!ddraw, "Failed to create a ddraw object.\n");
4233 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
4235 skip("Failed to create a 3D device, skipping test.\n");
4236 IDirectDraw_Release(ddraw);
4237 DestroyWindow(window);
4238 return;
4241 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
4242 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
4244 white = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
4245 red = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
4246 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 1.0f);
4247 blue = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
4248 viewport = create_viewport(device, 0, 0, 640, 480);
4250 viewport_set_background(device, viewport, white);
4251 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
4252 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
4253 viewport_set_background(device, viewport, red);
4254 hr = IDirect3DViewport_Clear(viewport, 0, &clear_rect, D3DCLEAR_TARGET);
4255 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
4256 viewport_set_background(device, viewport, green);
4257 hr = IDirect3DViewport_Clear(viewport, 0, NULL, D3DCLEAR_TARGET);
4258 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
4259 viewport_set_background(device, viewport, blue);
4260 hr = IDirect3DViewport_Clear(viewport, 1, NULL, D3DCLEAR_TARGET);
4261 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
4263 color = get_surface_color(rt, 320, 240);
4264 ok(compare_color(color, 0x00ffffff, 1) || broken(compare_color(color, 0x000000ff, 1)),
4265 "Got unexpected color 0x%08x.\n", color);
4267 IDirectDrawSurface_Release(rt);
4268 destroy_viewport(device, viewport);
4269 destroy_material(white);
4270 destroy_material(red);
4271 destroy_material(green);
4272 destroy_material(blue);
4273 IDirect3DDevice_Release(device);
4274 IDirectDraw_Release(ddraw);
4275 DestroyWindow(window);
4278 static struct
4280 BOOL received;
4281 IDirectDraw *ddraw;
4282 HWND window;
4283 DWORD coop_level;
4284 } activateapp_testdata;
4286 static LRESULT CALLBACK activateapp_test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
4288 if (message == WM_ACTIVATEAPP)
4290 if (activateapp_testdata.ddraw)
4292 HRESULT hr;
4293 activateapp_testdata.received = FALSE;
4294 hr = IDirectDraw_SetCooperativeLevel(activateapp_testdata.ddraw,
4295 activateapp_testdata.window, activateapp_testdata.coop_level);
4296 ok(SUCCEEDED(hr), "Recursive SetCooperativeLevel call failed, hr %#lx.\n", hr);
4297 ok(!activateapp_testdata.received, "Received WM_ACTIVATEAPP during recursive SetCooperativeLevel call.\n");
4299 activateapp_testdata.received = TRUE;
4302 return DefWindowProcA(hwnd, message, wparam, lparam);
4305 static void test_coop_level_activateapp(void)
4307 IDirectDraw *ddraw;
4308 HRESULT hr;
4309 HWND window;
4310 WNDCLASSA wc = {0};
4311 DDSURFACEDESC ddsd;
4312 IDirectDrawSurface *surface;
4314 ddraw = create_ddraw();
4315 ok(!!ddraw, "Failed to create a ddraw object.\n");
4317 wc.lpfnWndProc = activateapp_test_proc;
4318 wc.lpszClassName = "ddraw_test_wndproc_wc";
4319 ok(RegisterClassA(&wc), "Failed to register window class.\n");
4321 window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test",
4322 WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
4324 /* Exclusive with window already active. */
4325 SetForegroundWindow(window);
4326 activateapp_testdata.received = FALSE;
4327 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4328 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4329 ok(!activateapp_testdata.received, "Received WM_ACTIVATEAPP although window was already active.\n");
4330 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4331 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4333 /* Exclusive with window not active. */
4334 SetForegroundWindow(GetDesktopWindow());
4335 activateapp_testdata.received = FALSE;
4336 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4337 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4338 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
4339 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4340 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4342 /* Normal with window not active, then exclusive with the same window. */
4343 SetForegroundWindow(GetDesktopWindow());
4344 activateapp_testdata.received = FALSE;
4345 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
4346 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4347 ok(!activateapp_testdata.received, "Received WM_ACTIVATEAPP when setting DDSCL_NORMAL.\n");
4348 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4349 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4350 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
4351 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4352 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4354 /* Recursive set of DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN. */
4355 SetForegroundWindow(GetDesktopWindow());
4356 activateapp_testdata.received = FALSE;
4357 activateapp_testdata.ddraw = ddraw;
4358 activateapp_testdata.window = window;
4359 activateapp_testdata.coop_level = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
4360 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4361 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4362 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
4363 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4364 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4366 /* The recursive call seems to have some bad effect on native ddraw, despite (apparently)
4367 * succeeding. Another switch to exclusive and back to normal is needed to release the
4368 * window properly. Without doing this, SetCooperativeLevel(EXCLUSIVE) will not send
4369 * WM_ACTIVATEAPP messages. */
4370 activateapp_testdata.ddraw = NULL;
4371 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4372 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4373 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4374 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4376 /* Setting DDSCL_NORMAL with recursive invocation. */
4377 SetForegroundWindow(GetDesktopWindow());
4378 activateapp_testdata.received = FALSE;
4379 activateapp_testdata.ddraw = ddraw;
4380 activateapp_testdata.window = window;
4381 activateapp_testdata.coop_level = DDSCL_NORMAL;
4382 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4383 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4384 ok(activateapp_testdata.received, "Expected WM_ACTIVATEAPP, but did not receive it.\n");
4386 /* DDraw is in exclusive mode now. */
4387 memset(&ddsd, 0, sizeof(ddsd));
4388 ddsd.dwSize = sizeof(ddsd);
4389 ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
4390 ddsd.dwBackBufferCount = 1;
4391 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
4392 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
4393 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
4394 IDirectDrawSurface_Release(surface);
4396 /* Recover again, just to be sure. */
4397 activateapp_testdata.ddraw = NULL;
4398 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
4399 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4400 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
4401 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4403 DestroyWindow(window);
4404 UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
4405 IDirectDraw_Release(ddraw);
4408 struct format_support_check
4410 const DDPIXELFORMAT *format;
4411 BOOL supported;
4414 static HRESULT WINAPI test_unsupported_formats_cb(DDSURFACEDESC *desc, void *ctx)
4416 struct format_support_check *format = ctx;
4418 if (!memcmp(format->format, &desc->ddpfPixelFormat, sizeof(*format->format)))
4420 format->supported = TRUE;
4421 return DDENUMRET_CANCEL;
4424 return DDENUMRET_OK;
4427 static void test_unsupported_formats(void)
4429 HRESULT hr;
4430 BOOL expect_success;
4431 HWND window;
4432 IDirectDraw *ddraw;
4433 IDirect3DDevice *device;
4434 IDirectDrawSurface *surface;
4435 DDSURFACEDESC ddsd;
4436 unsigned int i, j;
4437 DWORD expected_caps;
4438 static const struct
4440 const char *name;
4441 DDPIXELFORMAT fmt;
4443 formats[] =
4446 "D3DFMT_A8R8G8B8",
4448 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
4449 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
4453 "D3DFMT_P8",
4455 sizeof(DDPIXELFORMAT), DDPF_PALETTEINDEXED8 | DDPF_RGB, 0,
4456 {8 }, {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}
4460 static const DWORD caps[] = {0, DDSCAPS_SYSTEMMEMORY, DDSCAPS_VIDEOMEMORY};
4462 window = create_window();
4463 ddraw = create_ddraw();
4464 ok(!!ddraw, "Failed to create a ddraw object.\n");
4465 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
4467 skip("Failed to create a 3D device, skipping test.\n");
4468 IDirectDraw_Release(ddraw);
4469 DestroyWindow(window);
4470 return;
4473 for (i = 0; i < ARRAY_SIZE(formats); i++)
4475 struct format_support_check check = {&formats[i].fmt, FALSE};
4476 hr = IDirect3DDevice_EnumTextureFormats(device, test_unsupported_formats_cb, &check);
4477 ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr);
4479 for (j = 0; j < ARRAY_SIZE(caps); j++)
4481 memset(&ddsd, 0, sizeof(ddsd));
4482 ddsd.dwSize = sizeof(ddsd);
4483 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
4484 ddsd.ddpfPixelFormat = formats[i].fmt;
4485 ddsd.dwWidth = 4;
4486 ddsd.dwHeight = 4;
4487 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | caps[j];
4489 if (caps[j] & DDSCAPS_VIDEOMEMORY && !check.supported)
4490 expect_success = FALSE;
4491 else
4492 expect_success = TRUE;
4494 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
4495 ok(SUCCEEDED(hr) == expect_success,
4496 "Got unexpected hr %#lx for format %s, caps %#lx, expected %s.\n",
4497 hr, formats[i].name, caps[j], expect_success ? "success" : "failure");
4498 if (FAILED(hr))
4499 continue;
4501 memset(&ddsd, 0, sizeof(ddsd));
4502 ddsd.dwSize = sizeof(ddsd);
4503 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &ddsd);
4504 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
4506 if (caps[j] & DDSCAPS_VIDEOMEMORY)
4507 expected_caps = DDSCAPS_VIDEOMEMORY;
4508 else if (caps[j] & DDSCAPS_SYSTEMMEMORY)
4509 expected_caps = DDSCAPS_SYSTEMMEMORY;
4510 else if (check.supported)
4511 expected_caps = DDSCAPS_VIDEOMEMORY;
4512 else
4513 expected_caps = DDSCAPS_SYSTEMMEMORY;
4515 ok(ddsd.ddsCaps.dwCaps & expected_caps,
4516 "Expected caps %#lx, format %s, input caps %#lx.\n",
4517 expected_caps, formats[i].name, caps[j]);
4519 IDirectDrawSurface_Release(surface);
4523 IDirect3DDevice_Release(device);
4524 IDirectDraw_Release(ddraw);
4525 DestroyWindow(window);
4528 static void test_rt_caps(const GUID *device_guid)
4530 PALETTEENTRY palette_entries[256];
4531 IDirectDrawPalette *palette;
4532 IDirect3DDevice *device;
4533 BOOL software_device;
4534 IDirectDraw *ddraw;
4535 DWORD z_depth = 0;
4536 DDCAPS hal_caps;
4537 unsigned int i;
4538 ULONG refcount;
4539 HWND window;
4540 HRESULT hr;
4542 static const DDPIXELFORMAT p8_fmt =
4544 sizeof(DDPIXELFORMAT), DDPF_PALETTEINDEXED8 | DDPF_RGB, 0,
4545 {8}, {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000},
4548 static const struct
4550 const DDPIXELFORMAT *pf;
4551 DWORD caps_in;
4552 HRESULT create_device_hr;
4553 BOOL create_may_fail;
4555 test_data[] =
4558 NULL,
4559 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY,
4560 D3D_OK,
4561 FALSE,
4564 NULL,
4565 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE,
4566 D3D_OK,
4567 FALSE,
4570 NULL,
4571 DDSCAPS_OFFSCREENPLAIN,
4572 DDERR_INVALIDCAPS,
4573 FALSE,
4576 NULL,
4577 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
4578 D3DERR_SURFACENOTINVIDMEM,
4579 FALSE,
4582 NULL,
4583 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
4584 DDERR_INVALIDCAPS,
4585 FALSE,
4588 NULL,
4589 DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY,
4590 D3D_OK,
4591 FALSE,
4594 NULL,
4595 DDSCAPS_3DDEVICE,
4596 D3D_OK,
4597 FALSE,
4600 NULL,
4602 DDERR_INVALIDCAPS,
4603 FALSE,
4606 NULL,
4607 DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
4608 D3DERR_SURFACENOTINVIDMEM,
4609 FALSE,
4612 NULL,
4613 DDSCAPS_SYSTEMMEMORY,
4614 DDERR_INVALIDCAPS,
4615 FALSE,
4618 &p8_fmt,
4620 DDERR_INVALIDCAPS,
4621 FALSE,
4624 &p8_fmt,
4625 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE,
4626 DDERR_NOPALETTEATTACHED,
4627 FALSE,
4630 &p8_fmt,
4631 DDSCAPS_OFFSCREENPLAIN,
4632 DDERR_INVALIDCAPS,
4633 FALSE,
4636 &p8_fmt,
4637 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE,
4638 DDERR_NOPALETTEATTACHED,
4639 FALSE,
4642 &p8_fmt,
4643 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
4644 DDERR_INVALIDCAPS,
4645 FALSE,
4648 NULL,
4649 DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_ZBUFFER,
4650 DDERR_INVALIDCAPS,
4651 TRUE /* AMD Evergreen */,
4654 NULL,
4655 DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER,
4656 DDERR_INVALIDCAPS,
4657 FALSE,
4660 NULL,
4661 DDSCAPS_ZBUFFER,
4662 DDERR_INVALIDCAPS,
4663 FALSE,
4666 NULL,
4667 DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER,
4668 DDERR_INVALIDCAPS,
4669 TRUE /* Nvidia Kepler */,
4672 NULL,
4673 DDSCAPS_SYSTEMMEMORY | DDSCAPS_ZBUFFER,
4674 DDERR_INVALIDCAPS,
4675 TRUE /* Nvidia Kepler */,
4679 software_device = is_software_device_type(device_guid);
4681 window = create_window();
4682 ddraw = create_ddraw();
4683 ok(!!ddraw, "Failed to create a ddraw object.\n");
4684 if (!(device = create_device_ex(ddraw, window, DDSCL_NORMAL, device_guid)))
4686 skip("Failed to create a 3D device, skipping test.\n");
4687 IDirectDraw_Release(ddraw);
4688 DestroyWindow(window);
4689 return;
4691 z_depth = get_device_z_depth(device);
4692 ok(!!z_depth, "Failed to get device z depth.\n");
4693 IDirect3DDevice_Release(device);
4695 memset(palette_entries, 0, sizeof(palette_entries));
4696 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, palette_entries, &palette, NULL);
4697 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
4699 memset(&hal_caps, 0, sizeof(hal_caps));
4700 hal_caps.dwSize = sizeof(hal_caps);
4701 hr = IDirectDraw_GetCaps(ddraw, &hal_caps, NULL);
4702 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
4704 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
4706 DWORD caps_in, expected_caps;
4707 IDirectDrawSurface *surface;
4708 DDSURFACEDESC surface_desc;
4709 IDirect3DDevice *device;
4710 HRESULT expected_hr;
4712 caps_in = test_data[i].caps_in;
4714 memset(&surface_desc, 0, sizeof(surface_desc));
4715 surface_desc.dwSize = sizeof(surface_desc);
4716 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
4717 surface_desc.ddsCaps.dwCaps = caps_in;
4718 if (test_data[i].pf)
4720 surface_desc.dwFlags |= DDSD_PIXELFORMAT;
4721 surface_desc.ddpfPixelFormat = *test_data[i].pf;
4723 if (caps_in & DDSCAPS_ZBUFFER)
4725 surface_desc.dwFlags |= DDSD_ZBUFFERBITDEPTH;
4726 U2(surface_desc).dwZBufferBitDepth = z_depth;
4728 surface_desc.dwWidth = 640;
4729 surface_desc.dwHeight = 480;
4730 if ((caps_in & DDSCAPS_VIDEOMEMORY) && !(hal_caps.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
4731 expected_hr = DDERR_NODIRECTDRAWHW;
4732 else
4733 expected_hr = DD_OK;
4734 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
4735 ok(hr == expected_hr || broken(test_data[i].create_may_fail
4736 || (software_device && test_data[i].pf == &p8_fmt && hr == DDERR_INVALIDPIXELFORMAT)),
4737 "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
4738 if (FAILED(hr))
4739 continue;
4741 memset(&surface_desc, 0, sizeof(surface_desc));
4742 surface_desc.dwSize = sizeof(surface_desc);
4743 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
4744 ok(hr == DD_OK, "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
4746 if ((caps_in & DDSCAPS_SYSTEMMEMORY) || !(hal_caps.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
4747 expected_caps = caps_in | DDSCAPS_SYSTEMMEMORY;
4748 else
4749 expected_caps = caps_in | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
4751 ok(surface_desc.ddsCaps.dwCaps == expected_caps || (test_data[i].pf == &p8_fmt
4752 && surface_desc.ddsCaps.dwCaps == (caps_in | DDSCAPS_SYSTEMMEMORY))
4753 || (software_device && caps_in & DDSCAPS_ZBUFFER
4754 && surface_desc.ddsCaps.dwCaps == (caps_in | DDSCAPS_SYSTEMMEMORY)),
4755 "Got unexpected caps %#lx, expected %#lx, test %u, software_device %u.\n",
4756 surface_desc.ddsCaps.dwCaps, expected_caps, i, software_device);
4758 hr = IDirectDrawSurface_QueryInterface(surface, device_guid, (void **)&device);
4759 ok((!software_device && hr == test_data[i].create_device_hr)
4760 || (software_device && (hr == (test_data[i].create_device_hr == D3DERR_SURFACENOTINVIDMEM
4761 ? DD_OK : test_data[i].create_device_hr))),
4762 "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
4763 if (hr == DDERR_NOPALETTEATTACHED)
4765 hr = IDirectDrawSurface_SetPalette(surface, palette);
4766 ok(hr == DD_OK, "Got unexpected hr %#lx, test %u, software_device %u.\n", hr, i, software_device);
4767 hr = IDirectDrawSurface_QueryInterface(surface, device_guid, (void **)&device);
4768 if (software_device)
4769 todo_wine
4770 ok(hr == DD_OK, "Got unexpected hr %#lx, test %u, software_device %u.\n",
4771 hr, i, software_device);
4772 else if (surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
4773 ok(hr == DDERR_INVALIDPIXELFORMAT, "Got unexpected hr %#lx, test %u, software_device %u.\n",
4774 hr, i, software_device);
4775 else
4776 ok(hr == D3DERR_SURFACENOTINVIDMEM, "Got unexpected hr %#lx, test %u, software_device %u.\n",
4777 hr, i, software_device);
4779 if (SUCCEEDED(hr))
4781 refcount = IDirect3DDevice_Release(device);
4782 ok(refcount == 1, "Test %u: Got unexpected refcount %lu.\n", i, refcount);
4785 refcount = IDirectDrawSurface_Release(surface);
4786 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
4789 IDirectDrawPalette_Release(palette);
4790 refcount = IDirectDraw_Release(ddraw);
4791 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
4792 DestroyWindow(window);
4795 static void test_primary_caps(void)
4797 const DWORD placement = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
4798 IDirectDrawSurface *surface;
4799 DDSURFACEDESC surface_desc;
4800 IDirectDraw *ddraw;
4801 unsigned int i;
4802 ULONG refcount;
4803 HWND window;
4804 HRESULT hr;
4806 static const struct
4808 DWORD coop_level;
4809 DWORD caps_in;
4810 DWORD back_buffer_count;
4811 HRESULT hr;
4812 DWORD caps_out;
4814 test_data[] =
4817 DDSCL_NORMAL,
4818 DDSCAPS_PRIMARYSURFACE,
4819 ~0u,
4820 DD_OK,
4821 DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE,
4824 DDSCL_NORMAL,
4825 DDSCAPS_PRIMARYSURFACE | DDSCAPS_TEXTURE,
4826 ~0u,
4827 DDERR_INVALIDCAPS,
4828 ~0u,
4831 DDSCL_NORMAL,
4832 DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER,
4833 ~0u,
4834 DD_OK,
4835 DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER,
4838 DDSCL_NORMAL,
4839 DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER,
4840 ~0u,
4841 DDERR_INVALIDCAPS,
4842 ~0u,
4845 DDSCL_NORMAL,
4846 DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP,
4847 ~0u,
4848 DDERR_INVALIDCAPS,
4849 ~0u,
4852 DDSCL_NORMAL,
4853 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX,
4854 ~0u,
4855 DDERR_INVALIDCAPS,
4856 ~0u,
4859 DDSCL_NORMAL,
4860 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
4861 ~0u,
4862 DDERR_INVALIDCAPS,
4863 ~0u,
4866 DDSCL_NORMAL,
4867 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
4869 DDERR_INVALIDCAPS,
4870 ~0u,
4873 DDSCL_NORMAL,
4874 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
4876 DDERR_NOEXCLUSIVEMODE,
4877 ~0u,
4880 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
4881 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
4883 DDERR_INVALIDCAPS,
4884 ~0u,
4887 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
4888 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP,
4890 DD_OK,
4891 DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER | DDSCAPS_FLIP | DDSCAPS_COMPLEX,
4894 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
4895 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER,
4897 DDERR_INVALIDCAPS,
4898 ~0u,
4901 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,
4902 DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_BACKBUFFER,
4904 DDERR_INVALIDCAPS,
4905 ~0u,
4909 window = create_window();
4910 ddraw = create_ddraw();
4911 ok(!!ddraw, "Failed to create a ddraw object.\n");
4913 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
4915 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, test_data[i].coop_level);
4916 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
4918 memset(&surface_desc, 0, sizeof(surface_desc));
4919 surface_desc.dwSize = sizeof(surface_desc);
4920 surface_desc.dwFlags = DDSD_CAPS;
4921 if (test_data[i].back_buffer_count != ~0u)
4922 surface_desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
4923 surface_desc.ddsCaps.dwCaps = test_data[i].caps_in;
4924 surface_desc.dwBackBufferCount = test_data[i].back_buffer_count;
4925 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
4926 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#lx, expected %#lx.\n", i, hr, test_data[i].hr);
4927 if (FAILED(hr))
4928 continue;
4930 memset(&surface_desc, 0, sizeof(surface_desc));
4931 surface_desc.dwSize = sizeof(surface_desc);
4932 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
4933 ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#lx.\n", i, hr);
4934 ok((surface_desc.ddsCaps.dwCaps & ~placement) == test_data[i].caps_out,
4935 "Test %u: Got unexpected caps %#lx, expected %#lx.\n",
4936 i, surface_desc.ddsCaps.dwCaps, test_data[i].caps_out);
4938 IDirectDrawSurface_Release(surface);
4941 refcount = IDirectDraw_Release(ddraw);
4942 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
4943 DestroyWindow(window);
4946 static void test_surface_lock(void)
4948 IDirectDraw *ddraw;
4949 IDirectDrawSurface *surface;
4950 IDirect3DDevice *device;
4951 HRESULT hr;
4952 HWND window;
4953 unsigned int i;
4954 DDSURFACEDESC ddsd;
4955 ULONG refcount;
4956 DWORD z_depth = 0;
4957 static const struct
4959 DWORD caps;
4960 const char *name;
4962 tests[] =
4965 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
4966 "videomemory offscreenplain"
4969 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
4970 "systemmemory offscreenplain"
4973 DDSCAPS_PRIMARYSURFACE,
4974 "primary"
4977 DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY,
4978 "videomemory texture"
4981 DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY,
4982 "systemmemory texture"
4985 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE,
4986 "render target"
4989 DDSCAPS_ZBUFFER,
4990 "Z buffer"
4994 window = create_window();
4995 ddraw = create_ddraw();
4996 ok(!!ddraw, "Failed to create a ddraw object.\n");
4997 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
4999 skip("Failed to create a 3D device, skipping test.\n");
5000 IDirectDraw_Release(ddraw);
5001 DestroyWindow(window);
5002 return;
5004 z_depth = get_device_z_depth(device);
5005 ok(!!z_depth, "Failed to get device z depth.\n");
5006 IDirect3DDevice_Release(device);
5008 for (i = 0; i < ARRAY_SIZE(tests); i++)
5010 memset(&ddsd, 0, sizeof(ddsd));
5011 ddsd.dwSize = sizeof(ddsd);
5012 ddsd.dwFlags = DDSD_CAPS;
5013 if (!(tests[i].caps & DDSCAPS_PRIMARYSURFACE))
5015 ddsd.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
5016 ddsd.dwWidth = 64;
5017 ddsd.dwHeight = 64;
5019 if (tests[i].caps & DDSCAPS_ZBUFFER)
5021 ddsd.dwFlags |= DDSD_ZBUFFERBITDEPTH;
5022 U2(ddsd).dwZBufferBitDepth = z_depth;
5024 ddsd.ddsCaps.dwCaps = tests[i].caps;
5026 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
5027 ok(SUCCEEDED(hr), "Failed to create surface, type %s, hr %#lx.\n", tests[i].name, hr);
5029 memset(&ddsd, 0, sizeof(ddsd));
5030 ddsd.dwSize = sizeof(ddsd);
5031 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_WAIT, NULL);
5032 ok(SUCCEEDED(hr), "Failed to lock surface, type %s, hr %#lx.\n", tests[i].name, hr);
5033 if (SUCCEEDED(hr))
5035 hr = IDirectDrawSurface_Unlock(surface, NULL);
5036 ok(SUCCEEDED(hr), "Failed to unlock surface, type %s, hr %#lx.\n", tests[i].name, hr);
5039 memset(&ddsd, 0, sizeof(ddsd));
5040 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_WAIT, NULL);
5041 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx, type %s.\n", hr, tests[i].name);
5043 IDirectDrawSurface_Release(surface);
5046 refcount = IDirectDraw_Release(ddraw);
5047 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
5048 DestroyWindow(window);
5051 static void test_surface_discard(void)
5053 IDirectDraw *ddraw;
5054 IDirect3DDevice *device;
5055 HRESULT hr;
5056 HWND window;
5057 DDSURFACEDESC ddsd;
5058 IDirectDrawSurface *surface, *target;
5059 void *addr;
5060 static const struct
5062 DWORD caps;
5063 BOOL discard;
5065 tests[] =
5067 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY, TRUE},
5068 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY, FALSE},
5069 {DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, TRUE},
5070 {DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY, FALSE},
5072 unsigned int i;
5074 window = create_window();
5076 for (i = 0; i < ARRAY_SIZE(tests); i++)
5078 BOOL discarded;
5080 /* Sigh. Anything other than the first run of the loop randomly fails with
5081 * DDERR_SURFACELOST on my Radeon Pro 560 on Win10 19.09. Most of the time
5082 * the blit fails, but with sleeps added between surface creation and lock
5083 * the lock can fail too. Interestingly ddraw claims the render target has
5084 * been lost, not the test surface.
5086 * Recreating ddraw every iteration seems to fix this. */
5087 ddraw = create_ddraw();
5088 ok(!!ddraw, "Failed to create a ddraw object.\n");
5089 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
5091 skip("Failed to create a 3D device, skipping test.\n");
5092 IDirectDraw_Release(ddraw);
5093 DestroyWindow(window);
5094 return;
5097 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void**)&target);
5098 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
5100 memset(&ddsd, 0, sizeof(ddsd));
5101 ddsd.dwSize = sizeof(ddsd);
5102 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5103 ddsd.ddsCaps.dwCaps = tests[i].caps;
5104 ddsd.dwWidth = 64;
5105 ddsd.dwHeight = 64;
5106 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
5107 if (FAILED(hr))
5109 skip("Failed to create surface, skipping.\n");
5110 continue;
5113 memset(&ddsd, 0, sizeof(ddsd));
5114 ddsd.dwSize = sizeof(ddsd);
5115 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_WAIT, NULL);
5116 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
5117 addr = ddsd.lpSurface;
5118 hr = IDirectDrawSurface_Unlock(surface, NULL);
5119 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
5121 memset(&ddsd, 0, sizeof(ddsd));
5122 ddsd.dwSize = sizeof(ddsd);
5123 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_DISCARDCONTENTS | DDLOCK_WAIT, NULL);
5124 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
5125 discarded = ddsd.lpSurface != addr;
5126 hr = IDirectDrawSurface_Unlock(surface, NULL);
5127 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
5129 hr = IDirectDrawSurface_Blt(target, NULL, surface, NULL, DDBLT_WAIT, NULL);
5130 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
5132 memset(&ddsd, 0, sizeof(ddsd));
5133 ddsd.dwSize = sizeof(ddsd);
5134 hr = IDirectDrawSurface_Lock(surface, NULL, &ddsd, DDLOCK_DISCARDCONTENTS | DDLOCK_WAIT, NULL);
5135 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
5136 discarded |= ddsd.lpSurface != addr;
5137 hr = IDirectDrawSurface_Unlock(surface, NULL);
5138 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
5140 IDirectDrawSurface_Release(surface);
5142 /* Windows 7 reliably changes the address of surfaces that are discardable (Nvidia Kepler,
5143 * AMD r500, evergreen). Windows XP, at least on AMD r200, never changes the pointer. */
5144 ok(!discarded || tests[i].discard, "Expected surface not to be discarded, case %u\n", i);
5146 IDirectDrawSurface_Release(target);
5147 IDirect3DDevice_Release(device);
5148 IDirectDraw_Release(ddraw);
5151 DestroyWindow(window);
5154 static void test_flip(void)
5156 const DWORD placement = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
5157 IDirectDrawSurface *frontbuffer, *backbuffer1, *backbuffer2, *backbuffer3, *surface;
5158 DDSCAPS caps = {DDSCAPS_FLIP};
5159 DDSURFACEDESC surface_desc;
5160 unsigned int color, i;
5161 BOOL sysmem_primary;
5162 IDirectDraw *ddraw;
5163 DWORD expected_caps;
5164 ULONG refcount;
5165 HWND window;
5166 HRESULT hr;
5168 static const struct
5170 const char *name;
5171 DWORD caps;
5173 test_data[] =
5175 {"PRIMARYSURFACE", DDSCAPS_PRIMARYSURFACE},
5176 {"OFFSCREENPLAIN", DDSCAPS_OFFSCREENPLAIN},
5177 {"TEXTURE", DDSCAPS_TEXTURE},
5180 window = create_window();
5181 ddraw = create_ddraw();
5182 ok(!!ddraw, "Failed to create a ddraw object.\n");
5184 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
5185 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
5187 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
5189 /* Creating a flippable texture induces a BSoD on some versions of the
5190 * Intel graphics driver. At least Intel GMA 950 with driver version
5191 * 6.14.10.4926 on Windows XP SP3 is affected. */
5192 if ((test_data[i].caps & DDSCAPS_TEXTURE) && ddraw_is_intel(ddraw))
5194 win_skip("Skipping flippable texture test.\n");
5195 continue;
5198 memset(&surface_desc, 0, sizeof(surface_desc));
5199 surface_desc.dwSize = sizeof(surface_desc);
5200 surface_desc.dwFlags = DDSD_CAPS;
5201 if (!(test_data[i].caps & DDSCAPS_PRIMARYSURFACE))
5202 surface_desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
5203 surface_desc.ddsCaps.dwCaps = DDSCAPS_COMPLEX | DDSCAPS_FLIP | test_data[i].caps;
5204 surface_desc.dwWidth = 512;
5205 surface_desc.dwHeight = 512;
5206 surface_desc.dwBackBufferCount = 3;
5207 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
5208 ok(hr == DDERR_INVALIDCAPS, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5210 surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_FLIP;
5211 surface_desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
5212 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
5213 ok(hr == DDERR_INVALIDCAPS, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5215 surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_COMPLEX;
5216 surface_desc.ddsCaps.dwCaps |= DDSCAPS_FLIP;
5217 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
5218 ok(hr == DDERR_INVALIDCAPS, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5220 surface_desc.ddsCaps.dwCaps |= DDSCAPS_COMPLEX;
5221 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL);
5222 todo_wine_if(test_data[i].caps & DDSCAPS_TEXTURE)
5223 ok(SUCCEEDED(hr), "%s: Failed to create surface, hr %#lx.\n", test_data[i].name, hr);
5224 if (FAILED(hr))
5225 continue;
5227 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
5228 ok(SUCCEEDED(hr), "%s: Failed to set cooperative level, hr %#lx.\n", test_data[i].name, hr);
5229 hr = IDirectDrawSurface_IsLost(frontbuffer);
5230 ok(hr == DD_OK, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5231 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
5232 if (test_data[i].caps & DDSCAPS_PRIMARYSURFACE)
5233 ok(hr == DDERR_NOEXCLUSIVEMODE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5234 else
5235 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5236 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
5237 ok(SUCCEEDED(hr), "%s: Failed to set cooperative level, hr %#lx.\n", test_data[i].name, hr);
5238 hr = IDirectDrawSurface_IsLost(frontbuffer);
5239 todo_wine ok(hr == DDERR_SURFACELOST, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5240 hr = restore_surfaces(ddraw);
5241 ok(SUCCEEDED(hr), "%s: Failed to restore surfaces, hr %#lx.\n", test_data[i].name, hr);
5243 memset(&surface_desc, 0, sizeof(surface_desc));
5244 surface_desc.dwSize = sizeof(surface_desc);
5245 hr = IDirectDrawSurface_GetSurfaceDesc(frontbuffer, &surface_desc);
5246 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr);
5247 expected_caps = DDSCAPS_FRONTBUFFER | DDSCAPS_COMPLEX | DDSCAPS_FLIP | test_data[i].caps;
5248 if (test_data[i].caps & DDSCAPS_PRIMARYSURFACE)
5249 expected_caps |= DDSCAPS_VISIBLE;
5250 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
5251 "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
5252 sysmem_primary = surface_desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY;
5254 hr = IDirectDrawSurface_GetAttachedSurface(frontbuffer, &caps, &backbuffer1);
5255 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr);
5256 memset(&surface_desc, 0, sizeof(surface_desc));
5257 surface_desc.dwSize = sizeof(surface_desc);
5258 hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer1, &surface_desc);
5259 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr);
5260 ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %lu.\n",
5261 test_data[i].name, surface_desc.dwBackBufferCount);
5262 expected_caps &= ~(DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER);
5263 expected_caps |= DDSCAPS_BACKBUFFER;
5264 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
5265 "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
5267 hr = IDirectDrawSurface_GetAttachedSurface(backbuffer1, &caps, &backbuffer2);
5268 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr);
5269 memset(&surface_desc, 0, sizeof(surface_desc));
5270 surface_desc.dwSize = sizeof(surface_desc);
5271 hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer2, &surface_desc);
5272 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr);
5273 ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %lu.\n",
5274 test_data[i].name, surface_desc.dwBackBufferCount);
5275 expected_caps &= ~DDSCAPS_BACKBUFFER;
5276 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
5277 "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
5279 hr = IDirectDrawSurface_GetAttachedSurface(backbuffer2, &caps, &backbuffer3);
5280 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr);
5281 memset(&surface_desc, 0, sizeof(surface_desc));
5282 surface_desc.dwSize = sizeof(surface_desc);
5283 hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer3, &surface_desc);
5284 ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr);
5285 ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %lu.\n",
5286 test_data[i].name, surface_desc.dwBackBufferCount);
5287 ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps,
5288 "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps);
5290 hr = IDirectDrawSurface_GetAttachedSurface(backbuffer3, &caps, &surface);
5291 ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr);
5292 ok(surface == frontbuffer, "%s: Got unexpected surface %p, expected %p.\n",
5293 test_data[i].name, surface, frontbuffer);
5294 IDirectDrawSurface_Release(surface);
5296 memset(&surface_desc, 0, sizeof(surface_desc));
5297 surface_desc.dwSize = sizeof(surface_desc);
5298 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5299 surface_desc.ddsCaps.dwCaps = 0;
5300 surface_desc.dwWidth = 640;
5301 surface_desc.dwHeight = 480;
5302 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
5303 ok(SUCCEEDED(hr), "%s: Failed to create surface, hr %#lx.\n", test_data[i].name, hr);
5304 hr = IDirectDrawSurface_Flip(frontbuffer, surface, DDFLIP_WAIT);
5305 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5306 IDirectDrawSurface_Release(surface);
5308 hr = IDirectDrawSurface_Flip(frontbuffer, frontbuffer, DDFLIP_WAIT);
5309 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5310 hr = IDirectDrawSurface_Flip(backbuffer1, NULL, DDFLIP_WAIT);
5311 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5312 hr = IDirectDrawSurface_Flip(backbuffer2, NULL, DDFLIP_WAIT);
5313 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5314 hr = IDirectDrawSurface_Flip(backbuffer3, NULL, DDFLIP_WAIT);
5315 ok(hr == DDERR_NOTFLIPPABLE, "%s: Got unexpected hr %#lx.\n", test_data[i].name, hr);
5317 /* The Nvidia Geforce 7 driver cannot do a color fill on a texture backbuffer after
5318 * the backbuffer has been locked or GetSurfaceDesc has been called. Do it ourselves
5319 * as a workaround. */
5320 fill_surface(backbuffer1, 0xffff0000);
5321 fill_surface(backbuffer2, 0xff00ff00);
5322 fill_surface(backbuffer3, 0xff0000ff);
5324 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
5325 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5326 color = get_surface_color(backbuffer1, 320, 240);
5327 /* The testbot seems to just copy the contents of one surface to all the
5328 * others, instead of properly flipping. */
5329 ok(compare_color(color, 0x0000ff00, 1) || broken(sysmem_primary && compare_color(color, 0x000000ff, 1)),
5330 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5331 color = get_surface_color(backbuffer2, 320, 240);
5332 ok(compare_color(color, 0x000000ff, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5333 fill_surface(backbuffer3, 0xffff0000);
5335 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
5336 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5337 color = get_surface_color(backbuffer1, 320, 240);
5338 ok(compare_color(color, 0x000000ff, 1) || broken(sysmem_primary && compare_color(color, 0x00ff0000, 1)),
5339 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5340 color = get_surface_color(backbuffer2, 320, 240);
5341 ok(compare_color(color, 0x00ff0000, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5342 fill_surface(backbuffer3, 0xff00ff00);
5344 hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT);
5345 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5346 color = get_surface_color(backbuffer1, 320, 240);
5347 ok(compare_color(color, 0x00ff0000, 1) || broken(sysmem_primary && compare_color(color, 0x0000ff00, 1)),
5348 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5349 color = get_surface_color(backbuffer2, 320, 240);
5350 ok(compare_color(color, 0x0000ff00, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5351 fill_surface(backbuffer3, 0xff0000ff);
5353 hr = IDirectDrawSurface_Flip(frontbuffer, backbuffer1, DDFLIP_WAIT);
5354 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5355 color = get_surface_color(backbuffer2, 320, 240);
5356 ok(compare_color(color, 0x0000ff00, 1) || broken(sysmem_primary && compare_color(color, 0x000000ff, 1)),
5357 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5358 color = get_surface_color(backbuffer3, 320, 240);
5359 ok(compare_color(color, 0x000000ff, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5360 fill_surface(backbuffer1, 0xffff0000);
5362 hr = IDirectDrawSurface_Flip(frontbuffer, backbuffer2, DDFLIP_WAIT);
5363 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5364 color = get_surface_color(backbuffer1, 320, 240);
5365 ok(compare_color(color, 0x00ff0000, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5366 color = get_surface_color(backbuffer3, 320, 240);
5367 ok(compare_color(color, 0x000000ff, 1) || broken(sysmem_primary && compare_color(color, 0x00ff0000, 1)),
5368 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5369 fill_surface(backbuffer2, 0xff00ff00);
5371 hr = IDirectDrawSurface_Flip(frontbuffer, backbuffer3, DDFLIP_WAIT);
5372 ok(SUCCEEDED(hr), "%s: Failed to flip, hr %#lx.\n", test_data[i].name, hr);
5373 color = get_surface_color(backbuffer1, 320, 240);
5374 ok(compare_color(color, 0x00ff0000, 1) || broken(sysmem_primary && compare_color(color, 0x0000ff00, 1)),
5375 "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5376 color = get_surface_color(backbuffer2, 320, 240);
5377 ok(compare_color(color, 0x0000ff00, 1), "%s: Got unexpected color 0x%08x.\n", test_data[i].name, color);
5379 IDirectDrawSurface_Release(backbuffer3);
5380 IDirectDrawSurface_Release(backbuffer2);
5381 IDirectDrawSurface_Release(backbuffer1);
5382 IDirectDrawSurface_Release(frontbuffer);
5385 refcount = IDirectDraw_Release(ddraw);
5386 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
5387 DestroyWindow(window);
5390 static void test_sysmem_overlay(void)
5392 IDirectDraw *ddraw;
5393 HWND window;
5394 HRESULT hr;
5395 DDSURFACEDESC ddsd;
5396 IDirectDrawSurface *surface;
5397 ULONG ref;
5399 window = create_window();
5400 ddraw = create_ddraw();
5401 ok(!!ddraw, "Failed to create a ddraw object.\n");
5403 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
5404 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
5406 memset(&ddsd, 0, sizeof(ddsd));
5407 ddsd.dwSize = sizeof(ddsd);
5408 ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
5409 ddsd.dwWidth = 16;
5410 ddsd.dwHeight = 16;
5411 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OVERLAY;
5412 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
5413 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
5414 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
5415 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
5416 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
5417 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
5418 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
5419 ok(hr == DDERR_NOOVERLAYHW, "Got unexpected hr %#lx.\n", hr);
5421 ref = IDirectDraw_Release(ddraw);
5422 ok(!ref, "Unexpected refcount %lu.\n", ref);
5423 DestroyWindow(window);
5426 static void test_primary_palette(void)
5428 DDSCAPS surface_caps = {DDSCAPS_FLIP};
5429 IDirectDrawSurface *primary, *backbuffer;
5430 PALETTEENTRY palette_entries[256];
5431 IDirectDrawPalette *palette, *tmp;
5432 DDSURFACEDESC surface_desc;
5433 IDirectDraw *ddraw;
5434 DWORD palette_caps;
5435 ULONG refcount;
5436 HWND window;
5437 HRESULT hr;
5439 window = create_window();
5440 ddraw = create_ddraw();
5441 ok(!!ddraw, "Failed to create a ddraw object.\n");
5442 if (FAILED(IDirectDraw_SetDisplayMode(ddraw, 640, 480, 8)))
5444 win_skip("Failed to set 8 bpp display mode, skipping test.\n");
5445 IDirectDraw_Release(ddraw);
5446 DestroyWindow(window);
5447 return;
5449 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
5450 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
5452 memset(&surface_desc, 0, sizeof(surface_desc));
5453 surface_desc.dwSize = sizeof(surface_desc);
5454 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
5455 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
5456 surface_desc.dwBackBufferCount = 1;
5457 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &primary, NULL);
5458 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5459 hr = IDirectDrawSurface_GetAttachedSurface(primary, &surface_caps, &backbuffer);
5460 ok(SUCCEEDED(hr), "Failed to get attached surface, hr %#lx.\n", hr);
5462 memset(palette_entries, 0, sizeof(palette_entries));
5463 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256, palette_entries, &palette, NULL);
5464 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
5465 refcount = get_refcount((IUnknown *)palette);
5466 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
5468 hr = IDirectDrawPalette_GetCaps(palette, &palette_caps);
5469 ok(SUCCEEDED(hr), "Failed to get palette caps, hr %#lx.\n", hr);
5470 ok(palette_caps == (DDPCAPS_8BIT | DDPCAPS_ALLOW256), "Got unexpected palette caps %#lx.\n", palette_caps);
5472 hr = IDirectDrawSurface_SetPalette(primary, palette);
5473 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
5475 /* The Windows 8 testbot attaches the palette to the backbuffer as well,
5476 * and is generally somewhat broken with respect to 8 bpp / palette
5477 * handling. */
5478 if (SUCCEEDED(IDirectDrawSurface_GetPalette(backbuffer, &tmp)))
5480 win_skip("Broken palette handling detected, skipping tests.\n");
5481 IDirectDrawPalette_Release(tmp);
5482 IDirectDrawPalette_Release(palette);
5483 /* The Windows 8 testbot keeps extra references to the primary and
5484 * backbuffer while in 8 bpp mode. */
5485 hr = IDirectDraw_RestoreDisplayMode(ddraw);
5486 ok(SUCCEEDED(hr), "Failed to restore display mode, hr %#lx.\n", hr);
5487 goto done;
5490 refcount = get_refcount((IUnknown *)palette);
5491 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
5493 hr = IDirectDrawPalette_GetCaps(palette, &palette_caps);
5494 ok(SUCCEEDED(hr), "Failed to get palette caps, hr %#lx.\n", hr);
5495 ok(palette_caps == (DDPCAPS_8BIT | DDPCAPS_PRIMARYSURFACE | DDPCAPS_ALLOW256),
5496 "Got unexpected palette caps %#lx.\n", palette_caps);
5498 hr = IDirectDrawSurface_SetPalette(primary, NULL);
5499 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
5500 refcount = get_refcount((IUnknown *)palette);
5501 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
5503 hr = IDirectDrawPalette_GetCaps(palette, &palette_caps);
5504 ok(SUCCEEDED(hr), "Failed to get palette caps, hr %#lx.\n", hr);
5505 ok(palette_caps == (DDPCAPS_8BIT | DDPCAPS_ALLOW256), "Got unexpected palette caps %#lx.\n", palette_caps);
5507 hr = IDirectDrawSurface_SetPalette(primary, palette);
5508 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
5509 refcount = get_refcount((IUnknown *)palette);
5510 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
5512 hr = IDirectDrawSurface_GetPalette(primary, &tmp);
5513 ok(SUCCEEDED(hr), "Failed to get palette, hr %#lx.\n", hr);
5514 ok(tmp == palette, "Got unexpected palette %p, expected %p.\n", tmp, palette);
5515 IDirectDrawPalette_Release(tmp);
5516 hr = IDirectDrawSurface_GetPalette(backbuffer, &tmp);
5517 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#lx.\n", hr);
5519 refcount = IDirectDrawPalette_Release(palette);
5520 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
5521 refcount = IDirectDrawPalette_Release(palette);
5522 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
5524 /* Note that this only seems to work when the palette is attached to the
5525 * primary surface. When attached to a regular surface, attempting to get
5526 * the palette here will cause an access violation. */
5527 hr = IDirectDrawSurface_GetPalette(primary, &tmp);
5528 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#lx.\n", hr);
5530 hr = IDirectDrawSurface_IsLost(primary);
5531 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
5533 memset(&surface_desc, 0, sizeof(surface_desc));
5534 surface_desc.dwSize = sizeof(surface_desc);
5535 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &surface_desc);
5536 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
5537 ok(surface_desc.dwWidth == 640, "Got unexpected surface width %lu.\n", surface_desc.dwWidth);
5538 ok(surface_desc.dwHeight == 480, "Got unexpected surface height %lu.\n", surface_desc.dwHeight);
5539 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == 8, "Got unexpected bit count %lu.\n",
5540 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount);
5542 hr = set_display_mode(ddraw, 640, 480);
5543 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
5545 memset(&surface_desc, 0, sizeof(surface_desc));
5546 surface_desc.dwSize = sizeof(surface_desc);
5547 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &surface_desc);
5548 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
5549 ok(surface_desc.dwWidth == 640, "Got unexpected surface width %lu.\n", surface_desc.dwWidth);
5550 ok(surface_desc.dwHeight == 480, "Got unexpected surface height %lu.\n", surface_desc.dwHeight);
5551 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == 32
5552 || U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == 24,
5553 "Got unexpected bit count %lu.\n", U1(surface_desc.ddpfPixelFormat).dwRGBBitCount);
5555 hr = IDirectDrawSurface_IsLost(primary);
5556 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
5557 hr = IDirectDrawSurface_Restore(primary);
5558 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
5559 hr = IDirectDrawSurface_IsLost(primary);
5560 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
5562 memset(&surface_desc, 0, sizeof(surface_desc));
5563 surface_desc.dwSize = sizeof(surface_desc);
5564 hr = IDirectDrawSurface_GetSurfaceDesc(primary, &surface_desc);
5565 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
5566 ok(surface_desc.dwWidth == 640, "Got unexpected surface width %lu.\n", surface_desc.dwWidth);
5567 ok(surface_desc.dwHeight == 480, "Got unexpected surface height %lu.\n", surface_desc.dwHeight);
5568 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == 32
5569 || U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == 24,
5570 "Got unexpected bit count %lu.\n", U1(surface_desc.ddpfPixelFormat).dwRGBBitCount);
5572 done:
5573 refcount = IDirectDrawSurface_Release(backbuffer);
5574 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
5575 refcount = IDirectDrawSurface_Release(primary);
5576 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
5577 refcount = IDirectDraw_Release(ddraw);
5578 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
5579 DestroyWindow(window);
5582 static HRESULT WINAPI surface_counter(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
5584 UINT *surface_count = context;
5586 ++(*surface_count);
5587 IDirectDrawSurface_Release(surface);
5589 return DDENUMRET_OK;
5592 static void test_surface_attachment(void)
5594 IDirectDrawSurface *surface1, *surface2, *surface3, *surface4;
5595 DDSCAPS caps = {DDSCAPS_TEXTURE};
5596 DDSURFACEDESC surface_desc;
5597 IDirectDraw *ddraw;
5598 UINT surface_count;
5599 ULONG refcount;
5600 HWND window;
5601 HRESULT hr;
5603 window = create_window();
5604 ddraw = create_ddraw();
5605 ok(!!ddraw, "Failed to create a ddraw object.\n");
5606 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
5607 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
5609 memset(&surface_desc, 0, sizeof(surface_desc));
5610 surface_desc.dwSize = sizeof(surface_desc);
5611 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
5612 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
5613 U2(surface_desc).dwMipMapCount = 3;
5614 surface_desc.dwWidth = 128;
5615 surface_desc.dwHeight = 128;
5616 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
5617 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5619 hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &surface2);
5620 ok(SUCCEEDED(hr), "Failed to get mip level, hr %#lx.\n", hr);
5621 hr = IDirectDrawSurface_GetAttachedSurface(surface2, &caps, &surface3);
5622 ok(SUCCEEDED(hr), "Failed to get mip level, hr %#lx.\n", hr);
5623 hr = IDirectDrawSurface_GetAttachedSurface(surface3, &caps, &surface4);
5624 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
5626 surface_count = 0;
5627 IDirectDrawSurface_EnumAttachedSurfaces(surface1, &surface_count, surface_counter);
5628 ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
5629 surface_count = 0;
5630 IDirectDrawSurface_EnumAttachedSurfaces(surface2, &surface_count, surface_counter);
5631 ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
5632 surface_count = 0;
5633 IDirectDrawSurface_EnumAttachedSurfaces(surface3, &surface_count, surface_counter);
5634 ok(!surface_count, "Got unexpected surface_count %u.\n", surface_count);
5636 memset(&surface_desc, 0, sizeof(surface_desc));
5637 surface_desc.dwSize = sizeof(surface_desc);
5638 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5639 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5640 surface_desc.dwWidth = 16;
5641 surface_desc.dwHeight = 16;
5642 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
5643 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5645 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
5646 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5647 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
5648 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5649 hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface4);
5650 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5651 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface3);
5652 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5653 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface4);
5654 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5655 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface2);
5656 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5658 IDirectDrawSurface_Release(surface4);
5660 memset(&surface_desc, 0, sizeof(surface_desc));
5661 surface_desc.dwSize = sizeof(surface_desc);
5662 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5663 surface_desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
5664 surface_desc.dwWidth = 16;
5665 surface_desc.dwHeight = 16;
5666 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
5667 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5669 if (SUCCEEDED(hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4)))
5671 skip("Running on refrast, skipping some tests.\n");
5672 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface4);
5673 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
5675 else
5677 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5678 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
5679 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5680 hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface4);
5681 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5682 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface3);
5683 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5684 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface4);
5685 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5686 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface2);
5687 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5690 IDirectDrawSurface_Release(surface4);
5691 IDirectDrawSurface_Release(surface3);
5692 IDirectDrawSurface_Release(surface2);
5693 IDirectDrawSurface_Release(surface1);
5695 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
5696 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
5698 /* Try a single primary and two offscreen plain surfaces. */
5699 memset(&surface_desc, 0, sizeof(surface_desc));
5700 surface_desc.dwSize = sizeof(surface_desc);
5701 surface_desc.dwFlags = DDSD_CAPS;
5702 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
5703 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
5704 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5706 memset(&surface_desc, 0, sizeof(surface_desc));
5707 surface_desc.dwSize = sizeof(surface_desc);
5708 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5709 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
5710 surface_desc.dwWidth = registry_mode.dmPelsWidth;
5711 surface_desc.dwHeight = registry_mode.dmPelsHeight;
5712 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
5713 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5715 memset(&surface_desc, 0, sizeof(surface_desc));
5716 surface_desc.dwSize = sizeof(surface_desc);
5717 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5718 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
5719 surface_desc.dwWidth = registry_mode.dmPelsWidth;
5720 surface_desc.dwHeight = registry_mode.dmPelsHeight;
5721 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
5722 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5724 /* This one has a different size. */
5725 memset(&surface_desc, 0, sizeof(surface_desc));
5726 surface_desc.dwSize = sizeof(surface_desc);
5727 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5728 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
5729 surface_desc.dwWidth = 128;
5730 surface_desc.dwHeight = 128;
5731 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
5732 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5734 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
5735 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
5736 /* Try the reverse without detaching first. */
5737 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
5738 ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#lx.\n", hr);
5739 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
5740 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
5742 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
5743 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
5744 /* Try to detach reversed. */
5745 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
5746 ok(hr == DDERR_CANNOTDETACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5747 hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface1);
5748 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
5750 hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3);
5751 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
5752 hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface3);
5753 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
5755 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
5756 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5757 hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
5758 ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5760 IDirectDrawSurface_Release(surface4);
5761 IDirectDrawSurface_Release(surface3);
5762 IDirectDrawSurface_Release(surface2);
5763 IDirectDrawSurface_Release(surface1);
5765 /* Test depth surfaces of different sizes. */
5766 memset(&surface_desc, 0, sizeof(surface_desc));
5767 surface_desc.dwSize = sizeof(surface_desc);
5768 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
5769 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
5770 surface_desc.dwWidth = 64;
5771 surface_desc.dwHeight = 64;
5772 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
5773 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
5775 memset(&surface_desc, 0, sizeof(surface_desc));
5776 surface_desc.dwSize = sizeof(surface_desc);
5777 surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
5778 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
5779 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
5780 surface_desc.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
5781 U1(surface_desc.ddpfPixelFormat).dwZBufferBitDepth = 16;
5782 U3(surface_desc.ddpfPixelFormat).dwZBitMask = 0x0000ffff;
5783 surface_desc.dwWidth = 32;
5784 surface_desc.dwHeight = 32;
5785 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
5786 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
5787 surface_desc.dwWidth = 64;
5788 surface_desc.dwHeight = 64;
5789 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
5790 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
5791 surface_desc.dwWidth = 128;
5792 surface_desc.dwHeight = 128;
5793 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
5794 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
5796 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
5797 todo_wine ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5798 if (SUCCEEDED(hr))
5799 IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
5800 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface3);
5801 ok(hr == D3D_OK, "Failed to attach depth buffer, hr %#lx.\n", hr);
5802 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface3);
5803 ok(hr == D3D_OK, "Failed to detach depth buffer, hr %#lx.\n", hr);
5804 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
5805 todo_wine ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr);
5807 IDirectDrawSurface_Release(surface4);
5808 IDirectDrawSurface_Release(surface3);
5809 IDirectDrawSurface_Release(surface2);
5810 IDirectDrawSurface_Release(surface1);
5812 /* Test DeleteAttachedSurface() and automatic detachment of attached surfaces on release. */
5813 memset(&surface_desc, 0, sizeof(surface_desc));
5814 surface_desc.dwSize = sizeof(surface_desc);
5815 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
5816 surface_desc.dwWidth = 64;
5817 surface_desc.dwHeight = 64;
5818 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
5819 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
5820 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB; /* D3DFMT_R5G6B5 */
5821 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 16;
5822 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xf800;
5823 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x07e0;
5824 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x001f;
5825 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
5826 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5827 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
5828 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5830 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
5831 surface_desc.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
5832 U1(surface_desc.ddpfPixelFormat).dwZBufferBitDepth = 16;
5833 U3(surface_desc.ddpfPixelFormat).dwZBitMask = 0x0000ffff;
5834 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
5835 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
5837 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
5838 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
5839 refcount = get_refcount((IUnknown *)surface2);
5840 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
5841 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
5842 ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#lx.\n", hr);
5844 /* Attaching while already attached to other surface. */
5845 hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface2);
5846 todo_wine ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
5847 hr = IDirectDrawSurface_DeleteAttachedSurface(surface3, 0, surface2);
5848 todo_wine ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
5849 IDirectDrawSurface_Release(surface3);
5851 hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
5852 ok(SUCCEEDED(hr), "Failed to detach surface, hr %#lx.\n", hr);
5853 refcount = get_refcount((IUnknown *)surface2);
5854 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
5856 /* Automatic detachment on release. */
5857 hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
5858 ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr);
5859 refcount = get_refcount((IUnknown *)surface2);
5860 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
5861 refcount = IDirectDrawSurface_Release(surface1);
5862 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
5863 refcount = IDirectDrawSurface_Release(surface2);
5864 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
5865 refcount = IDirectDraw_Release(ddraw);
5866 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
5867 DestroyWindow(window);
5870 static void test_pixel_format(void)
5872 HWND window, window2 = NULL;
5873 HDC hdc, hdc2 = NULL;
5874 HMODULE gl = NULL;
5875 int format, test_format;
5876 PIXELFORMATDESCRIPTOR pfd;
5877 IDirectDraw *ddraw = NULL;
5878 IDirectDrawClipper *clipper = NULL;
5879 DDSURFACEDESC ddsd;
5880 IDirectDrawSurface *primary = NULL, *offscreen;
5881 DDBLTFX fx;
5882 HRESULT hr;
5884 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5885 100, 100, 160, 160, NULL, NULL, NULL, NULL);
5886 if (!window)
5888 skip("Failed to create window\n");
5889 return;
5892 window2 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5893 100, 100, 160, 160, NULL, NULL, NULL, NULL);
5895 hdc = GetDC(window);
5896 if (!hdc)
5898 skip("Failed to get DC\n");
5899 goto cleanup;
5902 if (window2)
5903 hdc2 = GetDC(window2);
5905 gl = LoadLibraryA("opengl32.dll");
5906 ok(!!gl, "failed to load opengl32.dll; SetPixelFormat()/GetPixelFormat() may not work right\n");
5908 format = GetPixelFormat(hdc);
5909 ok(format == 0, "new window has pixel format %d\n", format);
5911 ZeroMemory(&pfd, sizeof(pfd));
5912 pfd.nSize = sizeof(pfd);
5913 pfd.nVersion = 1;
5914 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
5915 pfd.iPixelType = PFD_TYPE_RGBA;
5916 pfd.iLayerType = PFD_MAIN_PLANE;
5917 format = ChoosePixelFormat(hdc, &pfd);
5918 if (format <= 0)
5920 skip("no pixel format available\n");
5921 goto cleanup;
5924 if (!SetPixelFormat(hdc, format, &pfd) || GetPixelFormat(hdc) != format)
5926 skip("failed to set pixel format\n");
5927 goto cleanup;
5930 if (!hdc2 || !SetPixelFormat(hdc2, format, &pfd) || GetPixelFormat(hdc2) != format)
5932 skip("failed to set pixel format on second window\n");
5933 if (hdc2)
5935 ReleaseDC(window2, hdc2);
5936 hdc2 = NULL;
5940 ddraw = create_ddraw();
5941 ok(!!ddraw, "Failed to create a ddraw object.\n");
5943 test_format = GetPixelFormat(hdc);
5944 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5946 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
5947 if (FAILED(hr))
5949 skip("Failed to set cooperative level, hr %#lx.\n", hr);
5950 goto cleanup;
5953 test_format = GetPixelFormat(hdc);
5954 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5956 if (hdc2)
5958 hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
5959 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
5960 hr = IDirectDrawClipper_SetHWnd(clipper, 0, window2);
5961 ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#lx.\n", hr);
5963 test_format = GetPixelFormat(hdc);
5964 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5966 test_format = GetPixelFormat(hdc2);
5967 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
5970 memset(&ddsd, 0, sizeof(ddsd));
5971 ddsd.dwSize = sizeof(ddsd);
5972 ddsd.dwFlags = DDSD_CAPS;
5973 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
5975 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &primary, NULL);
5976 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
5978 test_format = GetPixelFormat(hdc);
5979 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5981 if (hdc2)
5983 test_format = GetPixelFormat(hdc2);
5984 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
5987 if (clipper)
5989 hr = IDirectDrawSurface_SetClipper(primary, clipper);
5990 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
5992 test_format = GetPixelFormat(hdc);
5993 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
5995 test_format = GetPixelFormat(hdc2);
5996 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
5999 memset(&ddsd, 0, sizeof(ddsd));
6000 ddsd.dwSize = sizeof(ddsd);
6001 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
6002 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
6003 ddsd.dwWidth = ddsd.dwHeight = 64;
6004 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &offscreen, NULL);
6005 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
6007 memset(&fx, 0, sizeof(fx));
6008 fx.dwSize = sizeof(fx);
6009 hr = IDirectDrawSurface_Blt(offscreen, NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
6010 ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#lx.\n", hr);
6012 test_format = GetPixelFormat(hdc);
6013 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
6015 hr = IDirectDrawSurface_Blt(primary, NULL, offscreen, NULL, DDBLT_WAIT, NULL);
6016 ok(SUCCEEDED(hr), "Failed to blit to primary surface, hr %#lx.\n", hr);
6018 test_format = GetPixelFormat(hdc);
6019 ok(test_format == format, "window has pixel format %d, expected %d\n", test_format, format);
6021 if (hdc2)
6023 test_format = GetPixelFormat(hdc2);
6024 ok(test_format == format, "second window has pixel format %d, expected %d\n", test_format, format);
6027 IDirectDrawSurface_Release(offscreen);
6029 cleanup:
6030 if (primary) IDirectDrawSurface_Release(primary);
6031 if (clipper) IDirectDrawClipper_Release(clipper);
6032 if (ddraw) IDirectDraw_Release(ddraw);
6033 if (gl) FreeLibrary(gl);
6034 if (hdc) ReleaseDC(window, hdc);
6035 if (hdc2) ReleaseDC(window2, hdc2);
6036 DestroyWindow(window);
6037 if (window2) DestroyWindow(window2);
6040 static void test_create_surface_pitch(void)
6042 IDirectDrawSurface *surface, *primary;
6043 DDSURFACEDESC surface_desc;
6044 DDCAPS caps1, caps2;
6045 IDirectDraw *ddraw;
6046 unsigned int i;
6047 ULONG refcount;
6048 HWND window;
6049 HRESULT hr;
6050 void *mem;
6052 static const struct
6054 DWORD caps;
6055 DWORD flags_in;
6056 DWORD pitch_in;
6057 HRESULT hr;
6058 DWORD flags_out;
6059 DWORD pitch_out32;
6060 DWORD pitch_out64;
6062 test_data[] =
6064 /* 0 */
6065 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
6066 0, 0, DD_OK,
6067 DDSD_PITCH, 0x100, 0x100},
6068 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
6069 DDSD_PITCH, 0x104, DD_OK,
6070 DDSD_PITCH, 0x100, 0x100},
6071 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
6072 DDSD_PITCH, 0x0f8, DD_OK,
6073 DDSD_PITCH, 0x100, 0x100},
6074 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN,
6075 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDCAPS,
6076 0, 0, 0 },
6077 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6078 0, 0, DD_OK,
6079 DDSD_PITCH, 0x100, 0x0fc},
6080 /* 5 */
6081 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6082 DDSD_PITCH, 0x104, DD_OK,
6083 DDSD_PITCH, 0x100, 0x0fc},
6084 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6085 DDSD_PITCH, 0x0f8, DD_OK,
6086 DDSD_PITCH, 0x100, 0x0fc},
6087 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6088 DDSD_PITCH | DDSD_LINEARSIZE, 0, DD_OK,
6089 DDSD_PITCH, 0x100, 0x0fc},
6090 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6091 DDSD_LPSURFACE, 0, DDERR_INVALIDPARAMS,
6092 0, 0, 0 },
6093 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN,
6094 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDPARAMS,
6095 0, 0, 0 },
6096 /* 10 */
6097 {DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN | DDSCAPS_ALLOCONLOAD,
6098 0, 0, DDERR_INVALIDCAPS,
6099 0, 0, 0 },
6100 {DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
6101 0, 0, DD_OK,
6102 DDSD_PITCH, 0x100, 0 },
6103 {DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE,
6104 0, 0, DD_OK,
6105 DDSD_PITCH, 0x100, 0 },
6106 {DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
6107 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDCAPS,
6108 0, 0, 0 },
6109 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN | DDSCAPS_ALLOCONLOAD,
6110 0, 0, DDERR_INVALIDCAPS,
6111 0, 0, 0 },
6112 /* 15 */
6113 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
6114 0, 0, DD_OK,
6115 DDSD_PITCH, 0x100, 0 },
6116 {DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD,
6117 DDSD_LPSURFACE | DDSD_PITCH, 0x100, DDERR_INVALIDPARAMS,
6118 0, 0, 0 },
6120 DWORD flags_mask = DDSD_PITCH | DDSD_LPSURFACE | DDSD_LINEARSIZE;
6122 window = create_window();
6123 ddraw = create_ddraw();
6124 ok(!!ddraw, "Failed to create a ddraw object.\n");
6125 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
6126 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
6128 mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((63 * 4) + 8) * 63);
6130 /* We need a primary surface and exclusive mode for video memory accounting to work
6131 * right on Windows. Otherwise it gives us junk data, like creating a video memory
6132 * surface freeing up memory. */
6133 memset(&surface_desc, 0, sizeof(surface_desc));
6134 surface_desc.dwSize = sizeof(surface_desc);
6135 surface_desc.dwFlags = DDSD_CAPS;
6136 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
6137 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &primary, NULL);
6138 ok(SUCCEEDED(hr), "Failed to create a primary surface, hr %#lx.\n", hr);
6140 memset(&caps1, 0, sizeof(caps1));
6141 caps1.dwSize = sizeof(caps1);
6142 hr = IDirectDraw_GetCaps(ddraw, &caps1, NULL);
6143 ok(SUCCEEDED(hr), "Failed to get ddraw caps, hr %#lx.\n", hr);
6145 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
6147 memset(&surface_desc, 0, sizeof(surface_desc));
6148 surface_desc.dwSize = sizeof(surface_desc);
6149 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | test_data[i].flags_in;
6150 surface_desc.ddsCaps.dwCaps = test_data[i].caps;
6151 surface_desc.dwWidth = 63;
6152 surface_desc.dwHeight = 63;
6153 U1(surface_desc).lPitch = test_data[i].pitch_in;
6154 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
6155 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
6156 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
6157 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
6158 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
6159 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
6160 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
6161 if (test_data[i].flags_in & DDSD_LPSURFACE)
6163 HRESULT expected_hr = SUCCEEDED(test_data[i].hr) ? DDERR_INVALIDPARAMS : test_data[i].hr;
6164 ok(hr == expected_hr, "Test %u: Got unexpected hr %#lx, expected %#lx.\n", i, hr, expected_hr);
6165 surface_desc.lpSurface = mem;
6166 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
6168 if ((test_data[i].caps & DDSCAPS_VIDEOMEMORY) && hr == DDERR_NODIRECTDRAWHW)
6169 continue;
6170 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#lx, expected %#lx.\n", i, hr, test_data[i].hr);
6171 if (FAILED(hr))
6172 continue;
6174 memset(&surface_desc, 0, sizeof(surface_desc));
6175 surface_desc.dwSize = sizeof(surface_desc);
6176 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
6177 ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#lx.\n", i, hr);
6178 ok((surface_desc.dwFlags & flags_mask) == test_data[i].flags_out,
6179 "Test %u: Got unexpected flags %#lx, expected %#lx.\n",
6180 i, surface_desc.dwFlags & flags_mask, test_data[i].flags_out);
6181 if (!(test_data[i].caps & DDSCAPS_TEXTURE))
6183 if (is_ddraw64 && test_data[i].pitch_out32 != test_data[i].pitch_out64)
6184 todo_wine ok(U1(surface_desc).lPitch == test_data[i].pitch_out64,
6185 "Test %u: Got unexpected pitch %#lx, expected %#lx.\n",
6186 i, U1(surface_desc).lPitch, test_data[i].pitch_out64);
6187 else
6188 ok(U1(surface_desc).lPitch == test_data[i].pitch_out32,
6189 "Test %u: Got unexpected pitch %#lx, expected %#lx.\n",
6190 i, U1(surface_desc).lPitch, test_data[i].pitch_out32);
6192 ok(!surface_desc.lpSurface, "Test %u: Got unexpected lpSurface %p.\n", i, surface_desc.lpSurface);
6194 memset(&caps2, 0, sizeof(caps2));
6195 caps2.dwSize = sizeof(caps2);
6196 hr = IDirectDraw_GetCaps(ddraw, &caps2, NULL);
6197 ok(SUCCEEDED(hr), "Failed to get ddraw caps, hr %#lx.\n", hr);
6198 if (surface_desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
6200 /* Star Trek Starfleet Academy cares about this bit here: That creating a system memory
6201 * resource does not influence available video memory. */
6202 ok(caps2.dwVidMemFree == caps1.dwVidMemFree, "Free video memory changed from %#lx to %#lx, test %u.\n",
6203 caps1.dwVidMemFree, caps2.dwVidMemFree, i);
6205 else if (surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
6207 /* DDSCAPS_ALLOCONLOAD does not seem to delay video memory allocation, at least not on
6208 * modern Windows.
6210 * The amount of video memory consumed is different from what dwHeight * lPitch would
6211 * suggest, although not by much. */
6212 ok(caps2.dwVidMemFree < caps1.dwVidMemFree,
6213 "Expected free video memory to change, but it did not, test %u.\n", i);
6216 IDirectDrawSurface_Release(surface);
6218 hr = IDirectDraw_GetCaps(ddraw, &caps2, NULL);
6219 ok(SUCCEEDED(hr), "Failed to get ddraw caps, hr %#lx.\n", hr);
6220 ok(caps2.dwVidMemFree == caps1.dwVidMemFree, "Free video memory changed from %#lx to %#lx, test %u.\n",
6221 caps1.dwVidMemFree, caps2.dwVidMemFree, i);
6224 HeapFree(GetProcessHeap(), 0, mem);
6225 refcount = IDirectDraw_Release(ddraw);
6226 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6227 DestroyWindow(window);
6230 static void test_mipmap(void)
6232 IDirectDrawSurface *surface, *surface_base, *surface_mip;
6233 unsigned int i, mipmap_count;
6234 DDSURFACEDESC surface_desc;
6235 IDirectDraw *ddraw;
6236 ULONG refcount;
6237 HWND window;
6238 HRESULT hr;
6239 DDSCAPS caps = {DDSCAPS_COMPLEX};
6240 DDCAPS hal_caps;
6242 static const struct
6244 DWORD flags;
6245 DWORD caps;
6246 DWORD width;
6247 DWORD height;
6248 DWORD mipmap_count_in;
6249 HRESULT hr;
6250 DWORD mipmap_count_out;
6252 tests[] =
6254 {DDSD_MIPMAPCOUNT, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 128, 32, 3, DD_OK, 3},
6255 {DDSD_MIPMAPCOUNT, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 128, 32, 0, DDERR_INVALIDPARAMS, 0},
6256 {0, DDSCAPS_TEXTURE | DDSCAPS_MIPMAP, 128, 32, 0, DD_OK, 1},
6257 {0, DDSCAPS_MIPMAP, 128, 32, 0, DDERR_INVALIDCAPS, 0},
6258 {0, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 128, 32, 0, DD_OK, 6},
6259 {0, DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP, 32, 64, 0, DD_OK, 6},
6262 window = create_window();
6263 ddraw = create_ddraw();
6264 ok(!!ddraw, "Failed to create a ddraw object.\n");
6265 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
6266 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
6268 memset(&hal_caps, 0, sizeof(hal_caps));
6269 hal_caps.dwSize = sizeof(hal_caps);
6270 hr = IDirectDraw_GetCaps(ddraw, &hal_caps, NULL);
6271 ok(SUCCEEDED(hr), "Failed to get caps, hr %#lx.\n", hr);
6272 if ((hal_caps.ddsCaps.dwCaps & (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP)) != (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP))
6274 skip("Mipmapped textures not supported, skipping tests.\n");
6275 IDirectDraw_Release(ddraw);
6276 DestroyWindow(window);
6277 return;
6280 for (i = 0; i < ARRAY_SIZE(tests); ++i)
6282 memset(&surface_desc, 0, sizeof(surface_desc));
6283 surface_desc.dwSize = sizeof(surface_desc);
6284 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | tests[i].flags;
6285 surface_desc.ddsCaps.dwCaps = tests[i].caps;
6286 surface_desc.dwWidth = tests[i].width;
6287 surface_desc.dwHeight = tests[i].height;
6288 if (tests[i].flags & DDSD_MIPMAPCOUNT)
6289 U2(surface_desc).dwMipMapCount = tests[i].mipmap_count_in;
6290 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
6291 ok(hr == tests[i].hr, "Test %u: Got unexpected hr %#lx.\n", i, hr);
6292 if (FAILED(hr))
6293 continue;
6295 memset(&surface_desc, 0, sizeof(surface_desc));
6296 surface_desc.dwSize = sizeof(surface_desc);
6297 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
6298 ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#lx.\n", i, hr);
6299 ok(surface_desc.dwFlags & DDSD_MIPMAPCOUNT,
6300 "Test %u: Got unexpected flags %#lx.\n", i, surface_desc.dwFlags);
6301 ok(U2(surface_desc).dwMipMapCount == tests[i].mipmap_count_out,
6302 "Test %u: Got unexpected mipmap count %lu.\n", i, U2(surface_desc).dwMipMapCount);
6304 surface_base = surface;
6305 IDirectDrawSurface2_AddRef(surface_base);
6306 mipmap_count = U2(surface_desc).dwMipMapCount;
6307 while (mipmap_count > 1)
6309 hr = IDirectDrawSurface_GetAttachedSurface(surface_base, &caps, &surface_mip);
6310 ok(SUCCEEDED(hr), "Test %u, %u: Failed to get attached surface, hr %#lx.\n", i, mipmap_count, hr);
6312 memset(&surface_desc, 0, sizeof(surface_desc));
6313 surface_desc.dwSize = sizeof(surface_desc);
6314 hr = IDirectDrawSurface_GetSurfaceDesc(surface_base, &surface_desc);
6315 ok(SUCCEEDED(hr), "Test %u, %u: Failed to get surface desc, hr %#lx.\n", i, mipmap_count, hr);
6316 ok(surface_desc.dwFlags & DDSD_MIPMAPCOUNT,
6317 "Test %u, %u: Got unexpected flags %#lx.\n", i, mipmap_count, surface_desc.dwFlags);
6318 ok(U2(surface_desc).dwMipMapCount == mipmap_count,
6319 "Test %u, %u: Got unexpected mipmap count %lu.\n",
6320 i, mipmap_count, U2(surface_desc).dwMipMapCount);
6322 memset(&surface_desc, 0, sizeof(surface_desc));
6323 surface_desc.dwSize = sizeof(surface_desc);
6324 hr = IDirectDrawSurface_Lock(surface_base, NULL, &surface_desc, 0, NULL);
6325 ok(SUCCEEDED(hr), "Test %u, %u: Failed to lock surface, hr %#lx.\n", i, mipmap_count, hr);
6326 ok(surface_desc.dwMipMapCount == mipmap_count,
6327 "Test %u, %u: unexpected change of mipmap count %lu.\n",
6328 i, mipmap_count, surface_desc.dwMipMapCount);
6329 memset(&surface_desc, 0, sizeof(surface_desc));
6330 surface_desc.dwSize = sizeof(surface_desc);
6331 hr = IDirectDrawSurface_Lock(surface_mip, NULL, &surface_desc, 0, NULL);
6332 ok(SUCCEEDED(hr), "Test %u, %u: Failed to lock surface, hr %#lx.\n", i, mipmap_count, hr);
6333 ok(surface_desc.dwMipMapCount == mipmap_count - 1,
6334 "Test %u, %u: Got unexpected child mipmap count %lu.\n", i, mipmap_count, surface_desc.dwMipMapCount);
6335 IDirectDrawSurface_Unlock(surface_mip, NULL);
6336 IDirectDrawSurface_Unlock(surface_base, NULL);
6338 IDirectDrawSurface_Release(surface_base);
6339 surface_base = surface_mip;
6340 --mipmap_count;
6342 IDirectDrawSurface_Release(surface_base);
6344 IDirectDrawSurface_Release(surface);
6347 refcount = IDirectDraw_Release(ddraw);
6348 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6349 DestroyWindow(window);
6352 static void test_palette_complex(void)
6354 IDirectDrawSurface *surface, *mipmap, *tmp;
6355 DDSURFACEDESC surface_desc;
6356 IDirectDraw *ddraw;
6357 IDirectDrawPalette *palette, *palette2, *palette_mipmap;
6358 ULONG refcount;
6359 HWND window;
6360 HRESULT hr;
6361 DDSCAPS caps = {DDSCAPS_COMPLEX};
6362 DDCAPS hal_caps;
6363 PALETTEENTRY palette_entries[256];
6364 unsigned int i;
6365 HDC dc;
6366 RGBQUAD rgbquad;
6367 UINT count;
6369 window = create_window();
6370 ddraw = create_ddraw();
6371 ok(!!ddraw, "Failed to create a ddraw object.\n");
6372 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
6373 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
6375 memset(&hal_caps, 0, sizeof(hal_caps));
6376 hal_caps.dwSize = sizeof(hal_caps);
6377 hr = IDirectDraw_GetCaps(ddraw, &hal_caps, NULL);
6378 ok(SUCCEEDED(hr), "Failed to get caps, hr %#lx.\n", hr);
6379 if ((hal_caps.ddsCaps.dwCaps & (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP)) != (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP))
6381 skip("Mipmapped textures not supported, skipping mipmap palette test.\n");
6382 IDirectDraw_Release(ddraw);
6383 DestroyWindow(window);
6384 return;
6387 memset(&surface_desc, 0, sizeof(surface_desc));
6388 surface_desc.dwSize = sizeof(surface_desc);
6389 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
6390 surface_desc.dwWidth = 128;
6391 surface_desc.dwHeight = 128;
6392 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
6393 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
6394 surface_desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
6395 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 8;
6396 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
6397 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6399 memset(palette_entries, 0, sizeof(palette_entries));
6400 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
6401 palette_entries, &palette, NULL);
6402 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
6404 memset(palette_entries, 0, sizeof(palette_entries));
6405 palette_entries[1].peRed = 0xff;
6406 palette_entries[1].peGreen = 0x80;
6407 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
6408 palette_entries, &palette_mipmap, NULL);
6409 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
6411 palette2 = (void *)0xdeadbeef;
6412 hr = IDirectDrawSurface_GetPalette(surface, &palette2);
6413 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#lx.\n", hr);
6414 ok(!palette2, "Got unexpected palette %p.\n", palette2);
6415 hr = IDirectDrawSurface_SetPalette(surface, palette);
6416 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
6417 hr = IDirectDrawSurface_GetPalette(surface, &palette2);
6418 ok(SUCCEEDED(hr), "Failed to get palette, hr %#lx.\n", hr);
6419 ok(palette == palette2, "Got unexpected palette %p.\n", palette2);
6420 IDirectDrawPalette_Release(palette2);
6422 mipmap = surface;
6423 IDirectDrawSurface_AddRef(mipmap);
6424 for (i = 0; i < 7; ++i)
6426 hr = IDirectDrawSurface_GetAttachedSurface(mipmap, &caps, &tmp);
6427 ok(SUCCEEDED(hr), "Failed to get attached surface, i %u, hr %#lx.\n", i, hr);
6428 palette2 = (void *)0xdeadbeef;
6429 hr = IDirectDrawSurface_GetPalette(tmp, &palette2);
6430 ok(hr == DDERR_NOPALETTEATTACHED, "Got unexpected hr %#lx, i %u.\n", hr, i);
6431 ok(!palette2, "Got unexpected palette %p, i %u.\n", palette2, i);
6433 hr = IDirectDrawSurface_SetPalette(tmp, palette_mipmap);
6434 ok(SUCCEEDED(hr), "Failed to set palette, i %u, hr %#lx.\n", i, hr);
6436 hr = IDirectDrawSurface_GetPalette(tmp, &palette2);
6437 ok(SUCCEEDED(hr), "Failed to get palette, i %u, hr %#lx.\n", i, hr);
6438 ok(palette_mipmap == palette2, "Got unexpected palette %p.\n", palette2);
6439 IDirectDrawPalette_Release(palette2);
6441 hr = IDirectDrawSurface_GetDC(tmp, &dc);
6442 ok(SUCCEEDED(hr), "Failed to get DC, i %u, hr %#lx.\n", i, hr);
6443 count = GetDIBColorTable(dc, 1, 1, &rgbquad);
6444 ok(count == 1, "Expected count 1, got %u.\n", count);
6445 ok(rgbquad.rgbRed == 0xff, "Expected rgbRed = 0xff, got %#x.\n", rgbquad.rgbRed);
6446 ok(rgbquad.rgbGreen == 0x80, "Expected rgbGreen = 0x80, got %#x.\n", rgbquad.rgbGreen);
6447 ok(rgbquad.rgbBlue == 0x0, "Expected rgbBlue = 0x0, got %#x.\n", rgbquad.rgbBlue);
6448 hr = IDirectDrawSurface_ReleaseDC(tmp, dc);
6449 ok(SUCCEEDED(hr), "Failed to release DC, i %u, hr %#lx.\n", i, hr);
6451 IDirectDrawSurface_Release(mipmap);
6452 mipmap = tmp;
6455 hr = IDirectDrawSurface_GetAttachedSurface(mipmap, &caps, &tmp);
6456 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
6457 IDirectDrawSurface_Release(mipmap);
6458 refcount = IDirectDrawSurface_Release(surface);
6459 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6460 refcount = IDirectDrawPalette_Release(palette_mipmap);
6461 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6462 refcount = IDirectDrawPalette_Release(palette);
6463 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6465 refcount = IDirectDraw_Release(ddraw);
6466 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6467 DestroyWindow(window);
6470 static void test_p8_blit(void)
6472 IDirectDrawSurface *src, *dst, *dst_p8;
6473 DDSURFACEDESC surface_desc;
6474 unsigned int color, x;
6475 IDirectDraw *ddraw;
6476 IDirectDrawPalette *palette, *palette2;
6477 ULONG refcount;
6478 HWND window;
6479 HRESULT hr;
6480 PALETTEENTRY palette_entries[256];
6481 DDBLTFX fx;
6482 BOOL is_warp;
6483 static const BYTE src_data[] = {0x10, 0x1, 0x2, 0x3, 0x4, 0x5, 0xff, 0x80};
6484 static const BYTE src_data2[] = {0x10, 0x5, 0x4, 0x3, 0x2, 0x1, 0xff, 0x80};
6485 static const BYTE expected_p8[] = {0x10, 0x1, 0x4, 0x3, 0x4, 0x5, 0xff, 0x80};
6486 static const unsigned int expected[] =
6488 0x00101010, 0x00010101, 0x00020202, 0x00030303,
6489 0x00040404, 0x00050505, 0x00ffffff, 0x00808080,
6492 window = create_window();
6493 ddraw = create_ddraw();
6494 ok(!!ddraw, "Failed to create a ddraw object.\n");
6495 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
6496 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
6497 is_warp = ddraw_is_warp(ddraw);
6499 memset(palette_entries, 0, sizeof(palette_entries));
6500 palette_entries[1].peGreen = 0xff;
6501 palette_entries[2].peBlue = 0xff;
6502 palette_entries[3].peFlags = 0xff;
6503 palette_entries[4].peRed = 0xff;
6504 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
6505 palette_entries, &palette, NULL);
6506 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
6507 palette_entries[1].peBlue = 0xff;
6508 palette_entries[2].peGreen = 0xff;
6509 palette_entries[3].peRed = 0xff;
6510 palette_entries[4].peFlags = 0x0;
6511 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
6512 palette_entries, &palette2, NULL);
6513 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
6515 memset(&surface_desc, 0, sizeof(surface_desc));
6516 surface_desc.dwSize = sizeof(surface_desc);
6517 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
6518 surface_desc.dwWidth = 8;
6519 surface_desc.dwHeight = 1;
6520 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
6521 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
6522 surface_desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
6523 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 8;
6524 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src, NULL);
6525 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6526 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst_p8, NULL);
6527 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6528 hr = IDirectDrawSurface_SetPalette(dst_p8, palette2);
6529 ok(SUCCEEDED(hr), "Failed to set palette, 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_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
6534 surface_desc.dwWidth = 8;
6535 surface_desc.dwHeight = 1;
6536 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
6537 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
6538 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
6539 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
6540 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
6541 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
6542 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
6543 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
6544 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst, NULL);
6545 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
6547 memset(&surface_desc, 0, sizeof(surface_desc));
6548 surface_desc.dwSize = sizeof(surface_desc);
6549 hr = IDirectDrawSurface_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
6550 ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#lx.\n", hr);
6551 memcpy(surface_desc.lpSurface, src_data, sizeof(src_data));
6552 hr = IDirectDrawSurface_Unlock(src, NULL);
6553 ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#lx.\n", hr);
6555 hr = IDirectDrawSurface_Lock(dst_p8, NULL, &surface_desc, DDLOCK_WAIT, NULL);
6556 ok(SUCCEEDED(hr), "Failed to lock destination surface, hr %#lx.\n", hr);
6557 memcpy(surface_desc.lpSurface, src_data2, sizeof(src_data2));
6558 hr = IDirectDrawSurface_Unlock(dst_p8, NULL);
6559 ok(SUCCEEDED(hr), "Failed to unlock destination surface, hr %#lx.\n", hr);
6561 fx.dwSize = sizeof(fx);
6562 fx.dwFillColor = 0xdeadbeef;
6563 hr = IDirectDrawSurface_Blt(dst, NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
6564 ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr);
6566 hr = IDirectDrawSurface_SetPalette(src, palette);
6567 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
6568 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_WAIT, NULL);
6569 /* The r500 Windows 7 driver returns E_NOTIMPL. r200 on Windows XP works.
6570 * The Geforce 7 driver on Windows Vista returns E_FAIL. Newer Nvidia GPUs work. */
6571 ok(SUCCEEDED(hr) || broken(hr == E_NOTIMPL) || broken(hr == E_FAIL),
6572 "Failed to blit, hr %#lx.\n", hr);
6574 if (SUCCEEDED(hr))
6576 for (x = 0; x < ARRAY_SIZE(expected); x++)
6578 color = get_surface_color(dst, x, 0);
6579 /* WARP on 1709 and newer write zeroes on non-colorkeyed P8 -> RGB blits. For ckey
6580 * blits see below. */
6581 todo_wine ok(compare_color(color, expected[x], 0)
6582 || broken(is_warp && compare_color(color, 0x00000000, 0)),
6583 "Pixel %u: Got color %#x, expected %#x.\n",
6584 x, color, expected[x]);
6588 fx.ddckSrcColorkey.dwColorSpaceHighValue = 0x2;
6589 fx.ddckSrcColorkey.dwColorSpaceLowValue = 0x2;
6590 hr = IDirectDrawSurface_Blt(dst_p8, NULL, src, NULL, DDBLT_WAIT | DDBLT_KEYSRCOVERRIDE, &fx);
6591 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
6593 hr = IDirectDrawSurface_Lock(dst_p8, NULL, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
6594 ok(SUCCEEDED(hr), "Failed to lock destination surface, hr %#lx.\n", hr);
6595 /* A color keyed P8 blit doesn't do anything on WARP - it just leaves the data in the destination
6596 * surface untouched. Error checking (DDBLT_KEYSRC without a key
6597 * for example) also works as expected.
6599 * Using DDBLT_KEYSRC instead of DDBLT_KEYSRCOVERRIDE doesn't change this. Doing this blit with
6600 * the display mode set to P8 doesn't help either. */
6601 ok(!memcmp(surface_desc.lpSurface, expected_p8, sizeof(expected_p8))
6602 || broken(is_warp && !memcmp(surface_desc.lpSurface, src_data2, sizeof(src_data2))),
6603 "Got unexpected P8 color key blit result.\n");
6604 hr = IDirectDrawSurface_Unlock(dst_p8, NULL);
6605 ok(SUCCEEDED(hr), "Failed to unlock destination surface, hr %#lx.\n", hr);
6607 IDirectDrawSurface_Release(src);
6608 IDirectDrawSurface_Release(dst);
6609 IDirectDrawSurface_Release(dst_p8);
6610 IDirectDrawPalette_Release(palette);
6611 IDirectDrawPalette_Release(palette2);
6613 refcount = IDirectDraw_Release(ddraw);
6614 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
6615 DestroyWindow(window);
6618 static void test_material(void)
6620 IDirect3DMaterial *background, *material;
6621 IDirect3DExecuteBuffer *execute_buffer;
6622 D3DMATERIALHANDLE mat_handle, tmp;
6623 D3DEXECUTEBUFFERDESC exec_desc;
6624 IDirect3DViewport *viewport;
6625 IDirect3DDevice *device;
6626 IDirectDrawSurface *rt;
6627 unsigned int color, i;
6628 IDirectDraw *ddraw;
6629 UINT inst_length;
6630 ULONG refcount;
6631 HWND window;
6632 HRESULT hr;
6633 BOOL valid;
6634 void *ptr;
6636 static D3DVERTEX quad[] =
6638 {{-1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
6639 {{-1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
6640 {{ 1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
6641 {{ 1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
6643 static const struct
6645 BOOL material;
6646 D3DCOLOR expected_color;
6648 test_data[] =
6650 {TRUE, 0x0000ff00},
6651 {FALSE, 0x00ffffff},
6653 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
6655 window = create_window();
6656 ddraw = create_ddraw();
6657 ok(!!ddraw, "Failed to create a ddraw object.\n");
6658 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
6660 skip("Failed to create a 3D device, skipping test.\n");
6661 DestroyWindow(window);
6662 return;
6665 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
6666 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
6668 background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
6669 viewport = create_viewport(device, 0, 0, 640, 480);
6670 viewport_set_background(device, viewport, background);
6672 material = create_emissive_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
6673 hr = IDirect3DMaterial_GetHandle(material, device, &mat_handle);
6674 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#lx.\n", hr);
6676 memset(&exec_desc, 0, sizeof(exec_desc));
6677 exec_desc.dwSize = sizeof(exec_desc);
6678 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
6679 exec_desc.dwBufferSize = 1024;
6680 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
6682 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
6683 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
6685 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
6687 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
6688 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
6690 memcpy(exec_desc.lpData, quad, sizeof(quad));
6691 ptr = ((BYTE *)exec_desc.lpData) + sizeof(quad);
6692 emit_set_ls(&ptr, D3DLIGHTSTATE_MATERIAL, test_data[i].material ? mat_handle : 0);
6693 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORMLIGHT, 0, 4);
6694 emit_tquad(&ptr, 0);
6695 emit_end(&ptr);
6696 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
6697 inst_length -= sizeof(quad);
6699 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
6700 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
6702 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
6703 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
6705 hr = IDirect3DDevice_BeginScene(device);
6706 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
6707 set_execute_data(execute_buffer, 4, sizeof(quad), inst_length);
6708 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
6709 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
6710 hr = IDirect3DDevice_EndScene(device);
6711 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
6712 color = get_surface_color(rt, 320, 240);
6713 if (test_data[i].material)
6714 ok(compare_color(color, test_data[i].expected_color, 1)
6715 /* The Windows 8 testbot appears to return undefined results. */
6716 || broken(TRUE),
6717 "Got unexpected color 0x%08x, test %u.\n", color, i);
6718 else
6719 ok(compare_color(color, test_data[i].expected_color, 1),
6720 "Got unexpected color 0x%08x, test %u.\n", color, i);
6723 destroy_material(material);
6724 material = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
6725 hr = IDirect3DMaterial_GetHandle(material, device, &mat_handle);
6726 ok(SUCCEEDED(hr), "Failed to get material handle, hr %#lx.\n", hr);
6728 hr = IDirect3DViewport_SetBackground(viewport, mat_handle);
6729 ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#lx.\n", hr);
6730 hr = IDirect3DViewport_GetBackground(viewport, &tmp, &valid);
6731 ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#lx.\n", hr);
6732 ok(tmp == mat_handle, "Got unexpected material handle %#lx, expected %#lx.\n", tmp, mat_handle);
6733 ok(valid, "Got unexpected valid %#x.\n", valid);
6734 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
6735 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
6736 color = get_surface_color(rt, 320, 240);
6737 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
6739 hr = IDirect3DViewport_SetBackground(viewport, 0);
6740 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
6741 hr = IDirect3DViewport_GetBackground(viewport, &tmp, &valid);
6742 ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#lx.\n", hr);
6743 ok(tmp == mat_handle, "Got unexpected material handle %#lx, expected %#lx.\n", tmp, mat_handle);
6744 ok(valid, "Got unexpected valid %#x.\n", valid);
6745 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
6746 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
6747 color = get_surface_color(rt, 320, 240);
6748 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
6750 destroy_viewport(device, viewport);
6751 viewport = create_viewport(device, 0, 0, 640, 480);
6753 hr = IDirect3DViewport_GetBackground(viewport, &tmp, &valid);
6754 ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#lx.\n", hr);
6755 ok(!tmp, "Got unexpected material handle %#lx.\n", tmp);
6756 ok(!valid, "Got unexpected valid %#x.\n", valid);
6757 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
6758 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
6759 color = get_surface_color(rt, 320, 240);
6760 ok(compare_color(color, 0x00000000, 1), "Got unexpected color 0x%08x.\n", color);
6762 IDirect3DExecuteBuffer_Release(execute_buffer);
6763 destroy_viewport(device, viewport);
6764 destroy_material(background);
6765 destroy_material(material);
6766 IDirectDrawSurface_Release(rt);
6767 refcount = IDirect3DDevice_Release(device);
6768 ok(!refcount, "Device has %lu references left.\n", refcount);
6769 refcount = IDirectDraw_Release(ddraw);
6770 ok(!refcount, "Ddraw object has %lu references left.\n", refcount);
6771 DestroyWindow(window);
6774 static void test_lighting(void)
6776 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
6777 static D3DMATRIX mat =
6779 1.0f, 0.0f, 0.0f, 0.0f,
6780 0.0f, 1.0f, 0.0f, 0.0f,
6781 0.0f, 0.0f, 1.0f, 0.0f,
6782 0.0f, 0.0f, 0.0f, 1.0f,
6784 mat_singular =
6786 1.0f, 0.0f, 1.0f, 0.0f,
6787 0.0f, 1.0f, 0.0f, 0.0f,
6788 1.0f, 0.0f, 1.0f, 0.0f,
6789 0.0f, 0.0f, 0.5f, 1.0f,
6791 mat_transf =
6793 0.0f, 0.0f, 1.0f, 0.0f,
6794 0.0f, 1.0f, 0.0f, 0.0f,
6795 -1.0f, 0.0f, 0.0f, 0.0f,
6796 10.f, 10.0f, 10.0f, 1.0f,
6798 mat_nonaffine =
6800 1.0f, 0.0f, 0.0f, 0.0f,
6801 0.0f, 1.0f, 0.0f, 0.0f,
6802 0.0f, 0.0f, 1.0f, -1.0f,
6803 10.f, 10.0f, 10.0f, 0.0f,
6805 static D3DLVERTEX unlitquad[] =
6807 {{-1.0f}, {-1.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
6808 {{-1.0f}, { 0.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
6809 {{ 0.0f}, { 0.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
6810 {{ 0.0f}, {-1.0f}, {0.1f}, 0, {0xffff0000}, {0}, {0.0f}, {0.0f}},
6812 litquad[] =
6814 {{-1.0f}, { 0.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
6815 {{-1.0f}, { 1.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
6816 {{ 0.0f}, { 1.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
6817 {{ 0.0f}, { 0.0f}, {0.1f}, 0, {0xff00ff00}, {0}, {0.0f}, {0.0f}},
6819 static D3DVERTEX unlitnquad[] =
6821 {{0.0f}, {-1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6822 {{0.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6823 {{1.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6824 {{1.0f}, {-1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6826 litnquad[] =
6828 {{0.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6829 {{0.0f}, { 1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6830 {{1.0f}, { 1.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6831 {{1.0f}, { 0.0f}, {0.1f}, {1.0f}, {1.0f}, {1.0f}, {0.0f}, {0.0f}},
6833 nquad[] =
6835 {{-1.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6836 {{-1.0f}, { 1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6837 {{ 1.0f}, { 1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6838 {{ 1.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6840 rotatedquad[] =
6842 {{-10.0f}, {-11.0f}, {11.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
6843 {{-10.0f}, { -9.0f}, {11.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
6844 {{-10.0f}, { -9.0f}, { 9.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
6845 {{-10.0f}, {-11.0f}, { 9.0f}, {-1.0f}, {0.0f}, {0.0f}, {0.0f}, {0.0f}},
6847 translatedquad[] =
6849 {{-11.0f}, {-11.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6850 {{-11.0f}, { -9.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6851 {{ -9.0f}, { -9.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6852 {{ -9.0f}, {-11.0f}, {-10.0f}, {0.0f}, {0.0f}, {-1.0f}, {0.0f}, {0.0f}},
6854 static const struct
6856 D3DMATRIX *world_matrix;
6857 void *quad;
6858 DWORD expected;
6859 const char *message;
6861 tests[] =
6863 {&mat, nquad, 0x000060ff, "Lit quad with light"},
6864 {&mat_singular, nquad, 0x00004db4, "Lit quad with singular world matrix"},
6865 {&mat_transf, rotatedquad, 0x000060ff, "Lit quad with transformation matrix"},
6866 {&mat_nonaffine, translatedquad, 0x000060ff, "Lit quad with non-affine matrix"},
6869 D3DMATRIXHANDLE world_handle, view_handle, proj_handle;
6870 IDirect3DViewport *viewport, *viewport2;
6871 IDirect3DExecuteBuffer *execute_buffer;
6872 unsigned int inst_length, color, i;
6873 D3DEXECUTEBUFFERDESC exec_desc;
6874 D3DMATERIALHANDLE mat_handle;
6875 IDirect3DMaterial *material;
6876 IDirect3DDevice *device;
6877 IDirectDrawSurface *rt;
6878 IDirect3DLight *light;
6879 D3DLIGHT light_desc;
6880 IDirectDraw *ddraw;
6881 ULONG refcount;
6882 IDirect3D *d3d;
6883 HWND window;
6884 HRESULT hr;
6885 void *ptr;
6887 window = create_window();
6888 ddraw = create_ddraw();
6889 ok(!!ddraw, "Failed to create a ddraw object.\n");
6890 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
6892 skip("Failed to create a 3D device, skipping test.\n");
6893 IDirectDraw_Release(ddraw);
6894 DestroyWindow(window);
6895 return;
6898 hr = IDirect3DDevice_GetDirect3D(device, &d3d);
6899 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6901 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
6902 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6904 viewport = create_viewport(device, 0, 0, 640, 480);
6905 material = create_diffuse_and_ambient_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
6906 viewport_set_background(device, viewport, material);
6908 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
6909 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6911 hr = IDirect3DDevice_CreateMatrix(device, &world_handle);
6912 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6913 hr = IDirect3DDevice_SetMatrix(device, world_handle, &mat);
6914 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6915 hr = IDirect3DDevice_CreateMatrix(device, &view_handle);
6916 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6917 hr = IDirect3DDevice_SetMatrix(device, view_handle, &mat);
6918 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6919 hr = IDirect3DDevice_CreateMatrix(device, &proj_handle);
6920 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6921 hr = IDirect3DDevice_SetMatrix(device, proj_handle, &mat);
6922 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6924 memset(&exec_desc, 0, sizeof(exec_desc));
6925 exec_desc.dwSize = sizeof(exec_desc);
6926 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
6927 exec_desc.dwBufferSize = 1024;
6928 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
6930 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
6931 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6933 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
6934 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6936 memcpy(exec_desc.lpData, unlitquad, sizeof(unlitquad));
6937 ptr = ((BYTE *)exec_desc.lpData) + sizeof(unlitquad);
6938 emit_set_ts(&ptr, D3DTRANSFORMSTATE_WORLD, world_handle);
6939 emit_set_ts(&ptr, D3DTRANSFORMSTATE_VIEW, view_handle);
6940 emit_set_ts(&ptr, D3DTRANSFORMSTATE_PROJECTION, proj_handle);
6941 emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, FALSE);
6942 emit_set_rs(&ptr, D3DRENDERSTATE_FOGENABLE, FALSE);
6943 emit_set_rs(&ptr, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
6944 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORM, 0, 4);
6945 emit_tquad_tlist(&ptr, 0);
6946 emit_end(&ptr);
6947 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
6948 inst_length -= sizeof(unlitquad);
6950 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
6951 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6953 hr = IDirect3DDevice_BeginScene(device);
6954 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6956 set_execute_data(execute_buffer, 4, sizeof(unlitquad), inst_length);
6957 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
6958 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6960 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
6961 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6963 memcpy(exec_desc.lpData, litquad, sizeof(litquad));
6964 ptr = ((BYTE *)exec_desc.lpData) + sizeof(litquad);
6965 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORM, 0, 4);
6966 emit_tquad_tlist(&ptr, 0);
6967 emit_end(&ptr);
6968 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
6969 inst_length -= sizeof(litquad);
6971 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
6972 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6974 set_execute_data(execute_buffer, 4, sizeof(litquad), inst_length);
6975 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
6976 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6978 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
6979 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6981 memcpy(exec_desc.lpData, unlitnquad, sizeof(unlitnquad));
6982 ptr = ((BYTE *)exec_desc.lpData) + sizeof(unlitnquad);
6983 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORMLIGHT, 0, 4);
6984 emit_tquad_tlist(&ptr, 0);
6985 emit_end(&ptr);
6986 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
6987 inst_length -= sizeof(unlitnquad);
6989 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
6990 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6992 set_execute_data(execute_buffer, 4, sizeof(unlitnquad), inst_length);
6993 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
6994 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6996 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
6997 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
6999 memcpy(exec_desc.lpData, litnquad, sizeof(litnquad));
7000 ptr = ((BYTE *)exec_desc.lpData) + sizeof(litnquad);
7001 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORMLIGHT, 0, 4);
7002 emit_tquad_tlist(&ptr, 0);
7003 emit_end(&ptr);
7004 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
7005 inst_length -= sizeof(litnquad);
7007 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
7008 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7010 set_execute_data(execute_buffer, 4, sizeof(litnquad), inst_length);
7011 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
7012 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7014 hr = IDirect3DDevice_EndScene(device);
7015 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7017 color = get_surface_color(rt, 160, 360);
7018 ok(color == 0x00ff0000, "Unlit quad without normals has color 0x%08x.\n", color);
7019 color = get_surface_color(rt, 160, 120);
7020 ok(color == 0x0000ff00, "Lit quad without normals has color 0x%08x.\n", color);
7021 color = get_surface_color(rt, 480, 360);
7022 ok(color == 0x00ffffff, "Unlit quad with normals has color 0x%08x.\n", color);
7023 color = get_surface_color(rt, 480, 120);
7024 ok(color == 0x00ffffff, "Lit quad with normals has color 0x%08x.\n", color);
7026 hr = IDirect3DMaterial_GetHandle(material, device, &mat_handle);
7027 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7029 hr = IDirect3D_CreateLight(d3d, &light, NULL);
7030 ok(SUCCEEDED(hr), "Failed to create a light object, hr %#lx.\n", hr);
7031 memset(&light_desc, 0, sizeof(light_desc));
7032 light_desc.dwSize = sizeof(light_desc);
7033 light_desc.dltType = D3DLIGHT_DIRECTIONAL;
7034 U1(light_desc.dcvColor).r = 0.0f;
7035 U2(light_desc.dcvColor).g = 0.25f;
7036 U3(light_desc.dcvColor).b = 1.0f;
7037 U4(light_desc.dcvColor).a = 1.0f;
7038 U3(light_desc.dvDirection).z = 1.0f;
7039 hr = IDirect3DLight_SetLight(light, &light_desc);
7040 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7041 hr = IDirect3DViewport_AddLight(viewport, light);
7042 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7043 hr = IDirect3DViewport_AddLight(viewport, light);
7044 ok(hr == D3DERR_LIGHTHASVIEWPORT, "Got unexpected hr %#lx.\n", hr);
7046 viewport2 = create_viewport(device, 0, 0, 640, 480);
7047 hr = IDirect3DViewport_AddLight(viewport2, light);
7048 ok(hr == D3DERR_LIGHTHASVIEWPORT, "Got unexpected hr %#lx.\n", hr);
7049 destroy_viewport(device, viewport2);
7051 hr = IDirect3DViewport_DeleteLight(viewport, light);
7052 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7053 hr = IDirect3DViewport_AddLight(viewport, light);
7054 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7056 for (i = 0; i < ARRAY_SIZE(tests); ++i)
7058 hr = IDirect3DDevice_SetMatrix(device, world_handle, tests[i].world_matrix);
7059 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7061 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
7062 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7064 hr = IDirect3DDevice_BeginScene(device);
7065 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7067 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
7068 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7070 memcpy(exec_desc.lpData, tests[i].quad, sizeof(nquad));
7071 ptr = ((BYTE *)exec_desc.lpData) + sizeof(nquad);
7072 emit_set_ls(&ptr, D3DLIGHTSTATE_MATERIAL, mat_handle);
7073 emit_set_ls(&ptr, D3DLIGHTSTATE_AMBIENT, 0xff002000);
7074 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORMLIGHT, 0, 4);
7075 emit_tquad_tlist(&ptr, 0);
7076 emit_end(&ptr);
7077 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
7078 inst_length -= sizeof(nquad);
7080 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
7081 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7083 set_execute_data(execute_buffer, 4, sizeof(nquad), inst_length);
7084 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
7085 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7087 hr = IDirect3DDevice_EndScene(device);
7088 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7090 color = get_surface_color(rt, 320, 240);
7091 ok(color == tests[i].expected, "%s has color 0x%08x.\n", tests[i].message, color);
7094 IDirect3DExecuteBuffer_Release(execute_buffer);
7095 IDirect3DDevice_DeleteMatrix(device, world_handle);
7096 IDirect3DDevice_DeleteMatrix(device, view_handle);
7097 IDirect3DDevice_DeleteMatrix(device, proj_handle);
7098 hr = IDirect3DViewport_DeleteLight(viewport, light);
7099 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7100 IDirect3DLight_Release(light);
7101 destroy_material(material);
7102 destroy_viewport(device, viewport);
7103 IDirectDrawSurface_Release(rt);
7104 refcount = IDirect3DDevice_Release(device);
7105 ok(!refcount, "Device has %lu references left.\n", refcount);
7106 IDirect3D_Release(d3d);
7107 refcount = IDirectDraw_Release(ddraw);
7108 ok(!refcount, "Ddraw object has %lu references left.\n", refcount);
7109 DestroyWindow(window);
7112 static void test_specular_lighting(void)
7114 static const unsigned int vertices_side = 5;
7115 const unsigned int indices_count = (vertices_side - 1) * (vertices_side - 1) * 2 * 3;
7116 const unsigned int vertex_count = vertices_side * vertices_side;
7117 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
7118 static D3DMATRIX mat =
7120 1.0f, 0.0f, 0.0f, 0.0f,
7121 0.0f, 1.0f, 0.0f, 0.0f,
7122 0.0f, 0.0f, 1.0f, 0.0f,
7123 0.0f, 0.0f, 0.0f, 1.0f,
7125 /* Use of D3DLIGHT2 instead of D3DLIGHT is intentional. Using D3DLIGHT
7126 * without dwFlags looks broken on Windows 7: directional light behaves as
7127 * if _LOCALVIEWER state is off, point and spot lights do not work at all
7128 * and always output zero colours. */
7129 static D3DLIGHT2 directional =
7131 sizeof(D3DLIGHT2),
7132 D3DLIGHT_DIRECTIONAL,
7133 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
7134 {{0.0f}, {0.0f}, {0.0f}},
7135 {{0.0f}, {0.0f}, {1.0f}},
7137 point =
7139 sizeof(D3DLIGHT2),
7140 D3DLIGHT_POINT,
7141 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
7142 {{0.0f}, {0.0f}, {0.0f}},
7143 {{0.0f}, {0.0f}, {0.0f}},
7144 100.0f,
7145 0.0f,
7146 0.0f, 0.0f, 1.0f,
7148 spot =
7150 sizeof(D3DLIGHT2),
7151 D3DLIGHT_SPOT,
7152 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
7153 {{0.0f}, {0.0f}, {0.0f}},
7154 {{0.0f}, {0.0f}, {1.0f}},
7155 100.0f,
7156 1.0f,
7157 0.0f, 0.0f, 1.0f,
7158 M_PI / 12.0f, M_PI / 3.0f
7160 parallelpoint =
7162 sizeof(D3DLIGHT2),
7163 D3DLIGHT_PARALLELPOINT,
7164 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
7165 {{0.5f}, {0.0f}, {-1.0f}},
7166 {{0.0f}, {0.0f}, {0.0f}},
7168 point_side =
7170 sizeof(D3DLIGHT2),
7171 D3DLIGHT_POINT,
7172 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
7173 {{-1.1f}, {0.0f}, {1.1f}},
7174 {{0.0f}, {0.0f}, {0.0f}},
7175 100.0f,
7176 0.0f,
7177 1.0f, 0.0f, 0.0f,
7179 point_far =
7181 sizeof(D3DLIGHT2),
7182 D3DLIGHT_POINT,
7183 {{1.0f}, {1.0f}, {1.0f}, {0.0f}},
7184 {{0.0f}, {0.0f}, {0.1f}},
7185 {{0.0f}, {0.0f}, {0.0f}},
7186 1.0f,
7187 0.0f,
7188 1.0f, 0.0f, 0.0f,
7190 static const struct expected_color
7192 unsigned int x, y, colour;
7194 expected_directional_local[] =
7196 {160, 120, 0x003c3c3c},
7197 {320, 120, 0x00717171},
7198 {480, 120, 0x003c3c3c},
7199 {160, 240, 0x00717171},
7200 {320, 240, 0x00ffffff},
7201 {480, 240, 0x00717171},
7202 {160, 360, 0x003c3c3c},
7203 {320, 360, 0x00717171},
7204 {480, 360, 0x003c3c3c},
7206 expected_point_local[] =
7208 {160, 120, 0x00000000},
7209 {320, 120, 0x00090909},
7210 {480, 120, 0x00000000},
7211 {160, 240, 0x00090909},
7212 {320, 240, 0x00fafafa},
7213 {480, 240, 0x00090909},
7214 {160, 360, 0x00000000},
7215 {320, 360, 0x00090909},
7216 {480, 360, 0x00000000},
7218 expected_spot_local[] =
7220 {160, 120, 0x00000000},
7221 {320, 120, 0x00020202},
7222 {480, 120, 0x00000000},
7223 {160, 240, 0x00020202},
7224 {320, 240, 0x00fafafa},
7225 {480, 240, 0x00020202},
7226 {160, 360, 0x00000000},
7227 {320, 360, 0x00020202},
7228 {480, 360, 0x00000000},
7230 expected_parallelpoint[] =
7232 {160, 120, 0x00050505},
7233 {320, 120, 0x002c2c2c},
7234 {480, 120, 0x006e6e6e},
7235 {160, 240, 0x00090909},
7236 {320, 240, 0x00717171},
7237 {480, 240, 0x00ffffff},
7238 {160, 360, 0x00050505},
7239 {320, 360, 0x002c2c2c},
7240 {480, 360, 0x006e6e6e},
7242 expected_point_far[] =
7244 {160, 120, 0x00000000},
7245 {320, 120, 0x00000000},
7246 {480, 120, 0x00000000},
7247 {160, 240, 0x00000000},
7248 {320, 240, 0x00ffffff},
7249 {480, 240, 0x00000000},
7250 {160, 360, 0x00000000},
7251 {320, 360, 0x00000000},
7252 {480, 360, 0x00000000},
7254 expected_zero[] =
7256 {160, 120, 0x00000000},
7257 {320, 120, 0x00000000},
7258 {480, 120, 0x00000000},
7259 {160, 240, 0x00000000},
7260 {320, 240, 0x00000000},
7261 {480, 240, 0x00000000},
7262 {160, 360, 0x00000000},
7263 {320, 360, 0x00000000},
7264 {480, 360, 0x00000000},
7266 static const struct
7268 D3DLIGHT2 *light;
7269 float specular_power;
7270 const struct expected_color *expected;
7271 unsigned int expected_count;
7273 tests[] =
7275 {&directional, 30.0f, expected_directional_local, ARRAY_SIZE(expected_directional_local)},
7276 {&point, 30.0f, expected_point_local, ARRAY_SIZE(expected_point_local)},
7277 {&spot, 30.0f, expected_spot_local, ARRAY_SIZE(expected_spot_local)},
7278 {&parallelpoint, 30.0f, expected_parallelpoint, ARRAY_SIZE(expected_parallelpoint)},
7279 {&point_side, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
7280 {&point_far, 1.0f, expected_point_far, ARRAY_SIZE(expected_point_far)},
7281 {&directional, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
7282 {&point, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
7283 {&spot, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
7284 {&parallelpoint, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
7285 {&point_far, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)},
7288 D3DMATRIXHANDLE world_handle, view_handle, proj_handle;
7289 IDirect3DMaterial *material, *background_material;
7290 unsigned int inst_length, colour, i, j, x, y;
7291 IDirect3DExecuteBuffer *execute_buffer;
7292 D3DEXECUTEBUFFERDESC exec_desc;
7293 D3DMATERIALHANDLE mat_handle;
7294 IDirect3DViewport *viewport;
7295 IDirect3DDevice *device;
7296 IDirectDrawSurface *rt;
7297 IDirect3DLight *light;
7298 IDirectDraw *ddraw;
7299 D3DVERTEX *quad;
7300 IDirect3D *d3d;
7301 ULONG refcount;
7302 WORD *indices;
7303 BOOL is_warp;
7304 HWND window;
7305 HRESULT hr;
7306 void *ptr;
7308 window = create_window();
7309 ddraw = create_ddraw();
7310 ok(!!ddraw, "Failed to create a ddraw object.\n");
7311 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
7313 skip("Failed to create a 3D device, skipping test.\n");
7314 IDirectDraw_Release(ddraw);
7315 DestroyWindow(window);
7316 return;
7318 is_warp = ddraw_is_warp(ddraw);
7320 quad = heap_alloc(vertex_count * sizeof(*quad));
7321 indices = heap_alloc(indices_count * sizeof(*indices));
7322 for (i = 0, y = 0; y < vertices_side; ++y)
7324 for (x = 0; x < vertices_side; ++x)
7326 U1(quad[i]).x = x * 2.0f / (vertices_side - 1) - 1.0f;
7327 U2(quad[i]).y = y * 2.0f / (vertices_side - 1) - 1.0f;
7328 U3(quad[i]).z = 1.0f;
7329 U4(quad[i]).nx = 0.0f;
7330 U5(quad[i]).ny = 0.0f;
7331 U6(quad[i]).nz = -1.0f;
7332 U7(quad[i]).tu = 0.0f;
7333 U8(quad[i++]).tv = 0.0f;
7336 for (i = 0, y = 0; y < (vertices_side - 1); ++y)
7338 for (x = 0; x < (vertices_side - 1); ++x)
7340 indices[i++] = y * vertices_side + x + 1;
7341 indices[i++] = y * vertices_side + x;
7342 indices[i++] = (y + 1) * vertices_side + x;
7343 indices[i++] = y * vertices_side + x + 1;
7344 indices[i++] = (y + 1) * vertices_side + x;
7345 indices[i++] = (y + 1) * vertices_side + x + 1;
7349 hr = IDirect3DDevice_GetDirect3D(device, &d3d);
7350 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7352 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
7353 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7355 viewport = create_viewport(device, 0, 0, 640, 480);
7356 background_material = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
7357 viewport_set_background(device, viewport, background_material);
7359 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
7360 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7362 hr = IDirect3DDevice_CreateMatrix(device, &world_handle);
7363 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7364 hr = IDirect3DDevice_SetMatrix(device, world_handle, &mat);
7365 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7366 hr = IDirect3DDevice_CreateMatrix(device, &view_handle);
7367 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7368 hr = IDirect3DDevice_SetMatrix(device, view_handle, &mat);
7369 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7370 hr = IDirect3DDevice_CreateMatrix(device, &proj_handle);
7371 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7372 hr = IDirect3DDevice_SetMatrix(device, proj_handle, &mat);
7373 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7376 hr = IDirect3D_CreateLight(d3d, &light, NULL);
7377 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7378 hr = IDirect3DViewport_AddLight(viewport, light);
7379 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7381 memset(&exec_desc, 0, sizeof(exec_desc));
7382 exec_desc.dwSize = sizeof(exec_desc);
7383 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
7384 exec_desc.dwBufferSize = 10240;
7385 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
7387 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
7388 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7390 for (i = 0; i < ARRAY_SIZE(tests); ++i)
7392 tests[i].light->dwFlags = D3DLIGHT_ACTIVE;
7393 material = create_specular_material(device, 1.0f, 1.0f, 1.0f, 1.0f, tests[i].specular_power);
7394 hr = IDirect3DMaterial_GetHandle(material, device, &mat_handle);
7395 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7397 hr = IDirect3DLight_SetLight(light, (D3DLIGHT *)tests[i].light);
7398 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7400 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
7401 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7403 hr = IDirect3DDevice_BeginScene(device);
7404 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7406 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
7407 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7409 memcpy(exec_desc.lpData, quad, sizeof(*quad) * vertex_count);
7410 ptr = ((BYTE *)exec_desc.lpData) + sizeof(*quad) * vertex_count;
7412 emit_set_ls(&ptr, D3DLIGHTSTATE_MATERIAL, mat_handle);
7413 emit_set_ts(&ptr, D3DTRANSFORMSTATE_WORLD, world_handle);
7414 emit_set_ts(&ptr, D3DTRANSFORMSTATE_VIEW, view_handle);
7415 emit_set_ts(&ptr, D3DTRANSFORMSTATE_PROJECTION, proj_handle);
7416 emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, FALSE);
7417 emit_set_rs(&ptr, D3DRENDERSTATE_SPECULARENABLE, TRUE);
7419 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORMLIGHT, 0, vertex_count);
7420 emit_tri_indices(&ptr, indices, indices_count / 3);
7421 emit_end(&ptr);
7422 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
7423 ok(inst_length <= exec_desc.dwBufferSize, "Execute buffer overflow, size %u.\n", inst_length);
7424 inst_length -= sizeof(*quad) * vertex_count;
7426 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
7427 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7429 set_execute_data(execute_buffer, vertex_count, sizeof(*quad) * vertex_count, inst_length);
7430 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
7431 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7433 hr = IDirect3DDevice_EndScene(device);
7434 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7436 for (j = 0; j < tests[i].expected_count; ++j)
7438 colour = get_surface_color(rt, tests[i].expected[j].x, tests[i].expected[j].y);
7439 ok(compare_color(colour, tests[i].expected[j].colour, 1)
7440 || broken(is_warp && compare_color(colour, 0x00ff0000, 1)),
7441 "Expected colour 0x%08x at location (%u, %u), got 0x%08x, case %u.\n",
7442 tests[i].expected[j].colour, tests[i].expected[j].x,
7443 tests[i].expected[j].y, colour, i);
7445 destroy_material(material);
7448 IDirect3DExecuteBuffer_Release(execute_buffer);
7449 IDirect3DDevice_DeleteMatrix(device, world_handle);
7450 IDirect3DDevice_DeleteMatrix(device, view_handle);
7451 IDirect3DDevice_DeleteMatrix(device, proj_handle);
7453 hr = IDirect3DViewport_DeleteLight(viewport, light);
7454 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
7455 IDirect3DLight_Release(light);
7456 destroy_material(background_material);
7457 destroy_viewport(device, viewport);
7458 IDirectDrawSurface_Release(rt);
7459 refcount = IDirect3DDevice_Release(device);
7460 ok(!refcount, "Device has %lu references left.\n", refcount);
7461 IDirect3D_Release(d3d);
7462 refcount = IDirectDraw_Release(ddraw);
7463 ok(!refcount, "Ddraw object has %lu references left.\n", refcount);
7464 DestroyWindow(window);
7465 heap_free(indices);
7466 heap_free(quad);
7469 static void test_palette_gdi(void)
7471 IDirectDrawSurface *surface, *primary;
7472 DDSURFACEDESC surface_desc;
7473 unsigned int color, i;
7474 IDirectDraw *ddraw;
7475 IDirectDrawPalette *palette, *palette2;
7476 ULONG refcount;
7477 HWND window;
7478 HRESULT hr;
7479 PALETTEENTRY palette_entries[256];
7480 HDC dc;
7481 DDBLTFX fx;
7482 RECT r;
7484 /* On the Windows 8 testbot palette index 0 of the onscreen palette is forced to
7485 * r = 0, g = 0, b = 0. Do not attempt to set it to something else as this is
7486 * not the point of this test. */
7487 static const RGBQUAD expected1[] =
7489 {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x01, 0x00}, {0x00, 0x02, 0x00, 0x00},
7490 {0x03, 0x00, 0x00, 0x00}, {0x15, 0x14, 0x13, 0x00},
7492 static const RGBQUAD expected2[] =
7494 {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x01, 0x00}, {0x00, 0x02, 0x00, 0x00},
7495 {0x03, 0x00, 0x00, 0x00}, {0x25, 0x24, 0x23, 0x00},
7497 static const RGBQUAD expected3[] =
7499 {0x00, 0x00, 0x00, 0x00}, {0x40, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x40, 0x00},
7500 {0x00, 0x40, 0x00, 0x00}, {0x56, 0x34, 0x12, 0x00},
7502 HPALETTE ddraw_palette_handle;
7503 /* Similar to index 0, index 255 is r = 0xff, g = 0xff, b = 0xff on the Win8 VMs. */
7504 RGBQUAD rgbquad[255];
7505 static const RGBQUAD rgb_zero = {0, 0, 0, 0};
7507 window = create_window();
7508 ddraw = create_ddraw();
7509 ok(!!ddraw, "Failed to create a ddraw object.\n");
7510 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
7511 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
7513 memset(&surface_desc, 0, sizeof(surface_desc));
7514 surface_desc.dwSize = sizeof(surface_desc);
7515 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
7516 surface_desc.dwWidth = 16;
7517 surface_desc.dwHeight = 16;
7518 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
7519 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
7520 surface_desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
7521 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 8;
7522 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7523 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
7525 /* Avoid colors from the Windows default palette. */
7526 memset(palette_entries, 0, sizeof(palette_entries));
7527 palette_entries[1].peRed = 0x01;
7528 palette_entries[2].peGreen = 0x02;
7529 palette_entries[3].peBlue = 0x03;
7530 palette_entries[4].peRed = 0x13;
7531 palette_entries[4].peGreen = 0x14;
7532 palette_entries[4].peBlue = 0x15;
7533 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
7534 palette_entries, &palette, NULL);
7535 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
7537 /* If there is no palette assigned and the display mode is not 8 bpp, some
7538 * drivers refuse to create a DC while others allow it. If a DC is created,
7539 * the DIB color table is uninitialized and contains random colors. No error
7540 * is generated when trying to read pixels and random garbage is returned.
7542 * The most likely explanation is that if the driver creates a DC, it (or
7543 * the higher-level runtime) uses GetSystemPaletteEntries to find the
7544 * palette, but GetSystemPaletteEntries fails when bpp > 8 and the palette
7545 * contains uninitialized garbage. See comments below for the P8 case. */
7547 hr = IDirectDrawSurface_SetPalette(surface, palette);
7548 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
7549 hr = IDirectDrawSurface_GetDC(surface, &dc);
7550 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
7551 ddraw_palette_handle = SelectPalette(dc, GetStockObject(DEFAULT_PALETTE), FALSE);
7552 ok(ddraw_palette_handle == GetStockObject(DEFAULT_PALETTE),
7553 "Got unexpected palette %p, expected %p.\n",
7554 ddraw_palette_handle, GetStockObject(DEFAULT_PALETTE));
7556 i = GetDIBColorTable(dc, 0, ARRAY_SIZE(rgbquad), rgbquad);
7557 ok(i == ARRAY_SIZE(rgbquad), "Expected count 255, got %u.\n", i);
7558 for (i = 0; i < ARRAY_SIZE(expected1); i++)
7560 ok(!memcmp(&rgbquad[i], &expected1[i], sizeof(rgbquad[i])),
7561 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7562 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
7563 expected1[i].rgbRed, expected1[i].rgbGreen, expected1[i].rgbBlue);
7565 for (; i < ARRAY_SIZE(rgbquad); i++)
7567 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
7568 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
7569 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
7572 /* Update the palette while the DC is in use. This does not modify the DC. */
7573 palette_entries[4].peRed = 0x23;
7574 palette_entries[4].peGreen = 0x24;
7575 palette_entries[4].peBlue = 0x25;
7576 hr = IDirectDrawPalette_SetEntries(palette, 0, 4, 1, &palette_entries[4]);
7577 ok(SUCCEEDED(hr), "Failed to set palette entries, hr %#lx.\n", hr);
7579 i = GetDIBColorTable(dc, 4, 1, &rgbquad[4]);
7580 ok(i == 1, "Expected count 1, got %u.\n", i);
7581 ok(!memcmp(&rgbquad[4], &expected1[4], sizeof(rgbquad[4])),
7582 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7583 i, rgbquad[4].rgbRed, rgbquad[4].rgbGreen, rgbquad[4].rgbBlue,
7584 expected1[4].rgbRed, expected1[4].rgbGreen, expected1[4].rgbBlue);
7586 /* Neither does re-setting the palette. */
7587 hr = IDirectDrawSurface_SetPalette(surface, NULL);
7588 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
7589 hr = IDirectDrawSurface_SetPalette(surface, palette);
7590 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
7592 i = GetDIBColorTable(dc, 4, 1, &rgbquad[4]);
7593 ok(i == 1, "Expected count 1, got %u.\n", i);
7594 ok(!memcmp(&rgbquad[4], &expected1[4], sizeof(rgbquad[4])),
7595 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7596 i, rgbquad[4].rgbRed, rgbquad[4].rgbGreen, rgbquad[4].rgbBlue,
7597 expected1[4].rgbRed, expected1[4].rgbGreen, expected1[4].rgbBlue);
7599 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
7600 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
7602 /* Refresh the DC. This updates the palette. */
7603 hr = IDirectDrawSurface_GetDC(surface, &dc);
7604 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
7605 i = GetDIBColorTable(dc, 0, ARRAY_SIZE(rgbquad), rgbquad);
7606 ok(i == ARRAY_SIZE(rgbquad), "Expected count 255, got %u.\n", i);
7607 for (i = 0; i < ARRAY_SIZE(expected2); i++)
7609 ok(!memcmp(&rgbquad[i], &expected2[i], sizeof(rgbquad[i])),
7610 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7611 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
7612 expected2[i].rgbRed, expected2[i].rgbGreen, expected2[i].rgbBlue);
7614 for (; i < ARRAY_SIZE(rgbquad); i++)
7616 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
7617 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
7618 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
7620 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
7621 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
7623 refcount = IDirectDrawSurface_Release(surface);
7624 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7626 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
7627 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
7628 if (FAILED(IDirectDraw_SetDisplayMode(ddraw, 640, 480, 8)))
7630 win_skip("Failed to set 8 bpp display mode, skipping test.\n");
7631 IDirectDrawPalette_Release(palette);
7632 IDirectDraw_Release(ddraw);
7633 DestroyWindow(window);
7634 return;
7636 ok(SUCCEEDED(hr), "Failed to set display mode, hr %#lx.\n", hr);
7638 memset(&surface_desc, 0, sizeof(surface_desc));
7639 surface_desc.dwSize = sizeof(surface_desc);
7640 surface_desc.dwFlags = DDSD_CAPS;
7641 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
7642 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &primary, NULL);
7643 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
7645 memset(&fx, 0, sizeof(fx));
7646 fx.dwSize = sizeof(fx);
7647 U5(fx).dwFillColor = 3;
7648 SetRect(&r, 0, 0, 319, 479);
7649 hr = IDirectDrawSurface_Blt(primary, &r, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
7650 ok(SUCCEEDED(hr), "Failed to clear surface, hr %#lx.\n", hr);
7651 SetRect(&r, 320, 0, 639, 479);
7652 U5(fx).dwFillColor = 4;
7653 hr = IDirectDrawSurface_Blt(primary, &r, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
7654 ok(SUCCEEDED(hr), "Failed to clear surface, hr %#lx.\n", hr);
7656 hr = IDirectDrawSurface_SetPalette(primary, palette);
7657 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
7658 hr = IDirectDrawSurface_GetDC(primary, &dc);
7659 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
7661 color = GetPixel(dc, 160, 240);
7662 ok(color == 0x00030000, "Clear index 3: Got unexpected color 0x%08x.\n", color);
7663 color = GetPixel(dc, 480, 240);
7664 ok(color == 0x00252423, "Clear index 4: Got unexpected color 0x%08x.\n", color);
7666 ddraw_palette_handle = SelectPalette(dc, GetStockObject(DEFAULT_PALETTE), FALSE);
7667 ok(ddraw_palette_handle == GetStockObject(DEFAULT_PALETTE),
7668 "Got unexpected palette %p, expected %p.\n",
7669 ddraw_palette_handle, GetStockObject(DEFAULT_PALETTE));
7670 SelectPalette(dc, ddraw_palette_handle, FALSE);
7672 /* The primary uses the system palette. In exclusive mode, the system palette matches
7673 * the ddraw palette attached to the primary, so the result is what you would expect
7674 * from a regular surface. Tests for the interaction between the ddraw palette and
7675 * the system palette are not included pending an application that depends on this.
7676 * The relation between those causes problems on Windows Vista and newer for games
7677 * like Age of Empires or StarCraft. Don't emulate it without a real need. */
7678 i = GetDIBColorTable(dc, 0, ARRAY_SIZE(rgbquad), rgbquad);
7679 ok(i == ARRAY_SIZE(rgbquad), "Expected count 255, got %u.\n", i);
7680 for (i = 0; i < ARRAY_SIZE(expected2); i++)
7682 ok(!memcmp(&rgbquad[i], &expected2[i], sizeof(rgbquad[i])),
7683 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7684 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
7685 expected2[i].rgbRed, expected2[i].rgbGreen, expected2[i].rgbBlue);
7687 for (; i < ARRAY_SIZE(rgbquad); i++)
7689 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
7690 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
7691 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
7693 hr = IDirectDrawSurface_ReleaseDC(primary, dc);
7694 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
7696 memset(&surface_desc, 0, sizeof(surface_desc));
7697 surface_desc.dwSize = sizeof(surface_desc);
7698 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
7699 surface_desc.dwWidth = 16;
7700 surface_desc.dwHeight = 16;
7701 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
7702 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7703 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
7705 /* Here the offscreen surface appears to use the primary's palette,
7706 * but in all likelihood it is actually the system palette. */
7707 hr = IDirectDrawSurface_GetDC(surface, &dc);
7708 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
7709 i = GetDIBColorTable(dc, 0, ARRAY_SIZE(rgbquad), rgbquad);
7710 ok(i == ARRAY_SIZE(rgbquad), "Expected count 255, got %u.\n", i);
7711 for (i = 0; i < ARRAY_SIZE(expected2); i++)
7713 ok(!memcmp(&rgbquad[i], &expected2[i], sizeof(rgbquad[i])),
7714 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7715 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
7716 expected2[i].rgbRed, expected2[i].rgbGreen, expected2[i].rgbBlue);
7718 for (; i < ARRAY_SIZE(rgbquad); i++)
7720 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
7721 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
7722 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
7724 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
7725 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
7727 /* On real hardware a change to the primary surface's palette applies immediately,
7728 * even on device contexts from offscreen surfaces that do not have their own
7729 * palette. On the testbot VMs this is not the case. Don't test this until we
7730 * know of an application that depends on this. */
7732 memset(palette_entries, 0, sizeof(palette_entries));
7733 palette_entries[1].peBlue = 0x40;
7734 palette_entries[2].peRed = 0x40;
7735 palette_entries[3].peGreen = 0x40;
7736 palette_entries[4].peRed = 0x12;
7737 palette_entries[4].peGreen = 0x34;
7738 palette_entries[4].peBlue = 0x56;
7739 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
7740 palette_entries, &palette2, NULL);
7741 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
7742 hr = IDirectDrawSurface_SetPalette(surface, palette2);
7743 ok(SUCCEEDED(hr), "Failed to set palette, hr %#lx.\n", hr);
7745 /* A palette assigned to the offscreen surface overrides the primary / system
7746 * palette. */
7747 hr = IDirectDrawSurface_GetDC(surface, &dc);
7748 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
7749 i = GetDIBColorTable(dc, 0, ARRAY_SIZE(rgbquad), rgbquad);
7750 ok(i == ARRAY_SIZE(rgbquad), "Expected count 255, got %u.\n", i);
7751 for (i = 0; i < ARRAY_SIZE(expected3); i++)
7753 ok(!memcmp(&rgbquad[i], &expected3[i], sizeof(rgbquad[i])),
7754 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=%#x g=%#x b=%#x.\n",
7755 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue,
7756 expected3[i].rgbRed, expected3[i].rgbGreen, expected3[i].rgbBlue);
7758 for (; i < ARRAY_SIZE(rgbquad); i++)
7760 ok(!memcmp(&rgbquad[i], &rgb_zero, sizeof(rgbquad[i])),
7761 "Got color table entry %u r=%#x g=%#x b=%#x, expected r=0 g=0 b=0.\n",
7762 i, rgbquad[i].rgbRed, rgbquad[i].rgbGreen, rgbquad[i].rgbBlue);
7764 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
7765 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
7767 refcount = IDirectDrawSurface_Release(surface);
7768 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7770 /* The Windows 8 testbot keeps extra references to the primary and
7771 * backbuffer while in 8 bpp mode. */
7772 hr = IDirectDraw_RestoreDisplayMode(ddraw);
7773 ok(SUCCEEDED(hr), "Failed to restore display mode, hr %#lx.\n", hr);
7775 refcount = IDirectDrawSurface_Release(primary);
7776 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7777 refcount = IDirectDrawPalette_Release(palette2);
7778 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7779 refcount = IDirectDrawPalette_Release(palette);
7780 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7781 refcount = IDirectDraw_Release(ddraw);
7782 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7783 DestroyWindow(window);
7786 static void test_palette_alpha(void)
7788 IDirectDrawSurface *surface;
7789 DDSURFACEDESC surface_desc;
7790 IDirectDraw *ddraw;
7791 IDirectDrawPalette *palette;
7792 ULONG refcount;
7793 HWND window;
7794 HRESULT hr;
7795 PALETTEENTRY palette_entries[256];
7796 unsigned int i;
7797 static const struct
7799 DWORD caps, flags;
7800 BOOL attach_allowed;
7801 const char *name;
7803 test_data[] =
7805 {DDSCAPS_OFFSCREENPLAIN, DDSD_WIDTH | DDSD_HEIGHT, FALSE, "offscreenplain"},
7806 {DDSCAPS_TEXTURE, DDSD_WIDTH | DDSD_HEIGHT, TRUE, "texture"},
7807 {DDSCAPS_PRIMARYSURFACE, 0, FALSE, "primary"}
7810 window = create_window();
7811 ddraw = create_ddraw();
7812 ok(!!ddraw, "Failed to create a ddraw object.\n");
7813 if (FAILED(IDirectDraw_SetDisplayMode(ddraw, 640, 480, 8)))
7815 win_skip("Failed to set 8 bpp display mode, skipping test.\n");
7816 IDirectDraw_Release(ddraw);
7817 DestroyWindow(window);
7818 return;
7820 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
7821 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
7823 memset(palette_entries, 0, sizeof(palette_entries));
7824 palette_entries[1].peFlags = 0x42;
7825 palette_entries[2].peFlags = 0xff;
7826 palette_entries[3].peFlags = 0x80;
7827 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, palette_entries, &palette, NULL);
7828 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
7830 memset(palette_entries, 0x66, sizeof(palette_entries));
7831 hr = IDirectDrawPalette_GetEntries(palette, 0, 1, 4, palette_entries);
7832 ok(SUCCEEDED(hr), "Failed to get palette entries, hr %#lx.\n", hr);
7833 ok(palette_entries[0].peFlags == 0x42, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
7834 palette_entries[0].peFlags);
7835 ok(palette_entries[1].peFlags == 0xff, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
7836 palette_entries[1].peFlags);
7837 ok(palette_entries[2].peFlags == 0x80, "Got unexpected peFlags 0x%02x, expected 0x80.\n",
7838 palette_entries[2].peFlags);
7839 ok(palette_entries[3].peFlags == 0x00, "Got unexpected peFlags 0x%02x, expected 0x00.\n",
7840 palette_entries[3].peFlags);
7842 IDirectDrawPalette_Release(palette);
7844 memset(palette_entries, 0, sizeof(palette_entries));
7845 palette_entries[1].peFlags = 0x42;
7846 palette_entries[1].peRed = 0xff;
7847 palette_entries[2].peFlags = 0xff;
7848 palette_entries[3].peFlags = 0x80;
7849 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_ALLOW256 | DDPCAPS_8BIT | DDPCAPS_ALPHA,
7850 palette_entries, &palette, NULL);
7851 ok(SUCCEEDED(hr), "Failed to create palette, hr %#lx.\n", hr);
7853 memset(palette_entries, 0x66, sizeof(palette_entries));
7854 hr = IDirectDrawPalette_GetEntries(palette, 0, 1, 4, palette_entries);
7855 ok(SUCCEEDED(hr), "Failed to get palette entries, hr %#lx.\n", hr);
7856 ok(palette_entries[0].peFlags == 0x42, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
7857 palette_entries[0].peFlags);
7858 ok(palette_entries[1].peFlags == 0xff, "Got unexpected peFlags 0x%02x, expected 0xff.\n",
7859 palette_entries[1].peFlags);
7860 ok(palette_entries[2].peFlags == 0x80, "Got unexpected peFlags 0x%02x, expected 0x80.\n",
7861 palette_entries[2].peFlags);
7862 ok(palette_entries[3].peFlags == 0x00, "Got unexpected peFlags 0x%02x, expected 0x00.\n",
7863 palette_entries[3].peFlags);
7865 for (i = 0; i < ARRAY_SIZE(test_data); i++)
7867 memset(&surface_desc, 0, sizeof(surface_desc));
7868 surface_desc.dwSize = sizeof(surface_desc);
7869 surface_desc.dwFlags = DDSD_CAPS | test_data[i].flags;
7870 surface_desc.dwWidth = 128;
7871 surface_desc.dwHeight = 128;
7872 surface_desc.ddsCaps.dwCaps = test_data[i].caps;
7873 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7874 ok(SUCCEEDED(hr), "Failed to create %s surface, hr %#lx.\n", test_data[i].name, hr);
7876 hr = IDirectDrawSurface_SetPalette(surface, palette);
7877 if (test_data[i].attach_allowed)
7878 ok(SUCCEEDED(hr), "Failed to attach palette to %s surface, hr %#lx.\n", test_data[i].name, hr);
7879 else
7880 ok(hr == DDERR_INVALIDSURFACETYPE, "Got unexpected hr %#lx, %s surface.\n", hr, test_data[i].name);
7882 if (SUCCEEDED(hr))
7884 HDC dc;
7885 RGBQUAD rgbquad;
7886 UINT retval;
7888 hr = IDirectDrawSurface_GetDC(surface, &dc);
7889 ok(SUCCEEDED(hr) || broken(hr == DDERR_CANTCREATEDC) /* Win2k testbot */,
7890 "Failed to get DC, hr %#lx, %s surface.\n", hr, test_data[i].name);
7891 if (SUCCEEDED(hr))
7893 retval = GetDIBColorTable(dc, 1, 1, &rgbquad);
7894 ok(retval == 1, "GetDIBColorTable returned unexpected result %u.\n", retval);
7895 ok(rgbquad.rgbRed == 0xff, "Expected rgbRed = 0xff, got %#x, %s surface.\n",
7896 rgbquad.rgbRed, test_data[i].name);
7897 ok(rgbquad.rgbGreen == 0, "Expected rgbGreen = 0, got %#x, %s surface.\n",
7898 rgbquad.rgbGreen, test_data[i].name);
7899 ok(rgbquad.rgbBlue == 0, "Expected rgbBlue = 0, got %#x, %s surface.\n",
7900 rgbquad.rgbBlue, test_data[i].name);
7901 ok(rgbquad.rgbReserved == 0, "Expected rgbReserved = 0, got %u, %s surface.\n",
7902 rgbquad.rgbReserved, test_data[i].name);
7903 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
7904 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
7907 IDirectDrawSurface_Release(surface);
7910 /* Test INVALIDSURFACETYPE vs INVALIDPIXELFORMAT. */
7911 memset(&surface_desc, 0, sizeof(surface_desc));
7912 surface_desc.dwSize = sizeof(surface_desc);
7913 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
7914 surface_desc.dwWidth = 128;
7915 surface_desc.dwHeight = 128;
7916 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
7917 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
7918 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
7919 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
7920 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
7921 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
7922 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
7923 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7924 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
7925 hr = IDirectDrawSurface_SetPalette(surface, palette);
7926 ok(hr == DDERR_INVALIDSURFACETYPE, "Got unexpected hr %#lx.\n", hr);
7927 IDirectDrawSurface_Release(surface);
7929 /* The Windows 8 testbot keeps extra references to the primary
7930 * while in 8 bpp mode. */
7931 hr = IDirectDraw_RestoreDisplayMode(ddraw);
7932 ok(SUCCEEDED(hr), "Failed to restore display mode, hr %#lx.\n", hr);
7934 refcount = IDirectDrawPalette_Release(palette);
7935 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7936 refcount = IDirectDraw_Release(ddraw);
7937 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
7938 DestroyWindow(window);
7941 static void test_lost_device(void)
7943 IDirectDrawSurface *surface, *back_buffer, *back_buffer2, *ds;
7944 IDirectDrawSurface *sysmem_surface, *vidmem_surface;
7945 DDSURFACEDESC surface_desc;
7946 HWND window1, window2;
7947 IDirectDraw *ddraw;
7948 ULONG refcount;
7949 DDSCAPS caps;
7950 HRESULT hr;
7951 BOOL ret;
7953 window1 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
7954 0, 0, 640, 480, 0, 0, 0, 0);
7955 window2 = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
7956 0, 0, 640, 480, 0, 0, 0, 0);
7957 ddraw = create_ddraw();
7958 ok(!!ddraw, "Failed to create a ddraw object.\n");
7959 hr = IDirectDraw_SetCooperativeLevel(ddraw, window1, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
7960 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
7962 memset(&surface_desc, 0, sizeof(surface_desc));
7963 surface_desc.dwSize = sizeof(surface_desc);
7964 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
7965 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
7966 surface_desc.dwBackBufferCount = 1;
7967 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
7968 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
7970 memset(&surface_desc, 0, sizeof(surface_desc));
7971 surface_desc.dwSize = sizeof(surface_desc);
7972 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
7973 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
7974 surface_desc.dwWidth = 100;
7975 surface_desc.dwHeight = 100;
7976 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &sysmem_surface, NULL);
7977 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
7979 memset(&surface_desc, 0, sizeof(surface_desc));
7980 surface_desc.dwSize = sizeof(surface_desc);
7981 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
7982 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
7983 surface_desc.dwWidth = 64;
7984 surface_desc.dwHeight = 64;
7985 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
7986 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
7987 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
7988 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
7989 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
7990 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
7991 if (FAILED(IDirectDraw_CreateSurface(ddraw, &surface_desc, &vidmem_surface, NULL)))
7993 skip("Failed to create video memory surface, skipping related tests.\n");
7994 vidmem_surface = NULL;
7997 hr = IDirectDrawSurface_IsLost(surface);
7998 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
7999 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8000 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8001 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8002 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8003 if (vidmem_surface)
8005 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8006 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8009 ret = SetForegroundWindow(GetDesktopWindow());
8010 ok(ret, "Failed to set foreground window.\n");
8011 hr = IDirectDrawSurface_IsLost(surface);
8012 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8013 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8014 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8015 hr = IDirectDrawSurface_Restore(surface);
8016 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
8017 hr = IDirectDrawSurface_IsLost(surface);
8018 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8019 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8020 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8021 hr = IDirectDrawSurface_Restore(sysmem_surface);
8022 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8023 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8024 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8025 if (vidmem_surface)
8027 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8028 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8029 hr = IDirectDrawSurface_Restore(vidmem_surface);
8030 ok(hr == DDERR_WRONGMODE, "Got unexpected hr %#lx.\n", hr);
8031 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8032 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8035 ret = SetForegroundWindow(window1);
8036 ok(ret, "Failed to set foreground window.\n");
8037 hr = IDirectDrawSurface_IsLost(surface);
8038 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8039 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8040 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8041 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8042 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8043 if (vidmem_surface)
8045 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8046 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8049 hr = restore_surfaces(ddraw);
8050 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8051 hr = IDirectDrawSurface_IsLost(surface);
8052 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8053 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8054 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8055 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8056 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8057 if (vidmem_surface)
8059 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8060 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8063 hr = IDirectDraw_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
8064 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8065 hr = IDirectDrawSurface_IsLost(surface);
8066 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8067 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8068 ok(hr == DDERR_NOEXCLUSIVEMODE || broken(ddraw_is_warp(ddraw) && hr == DDERR_SURFACELOST),
8069 "Got unexpected hr %#lx.\n", hr);
8070 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8071 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8072 if (vidmem_surface)
8074 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8075 ok(hr == DD_OK || broken(ddraw_is_warp(ddraw) && hr == DDERR_SURFACELOST), "Got unexpected hr %#lx.\n", hr);
8078 /* Trying to restore the primary will crash, probably because flippable
8079 * surfaces can't exist in DDSCL_NORMAL. */
8080 IDirectDrawSurface_Release(surface);
8081 memset(&surface_desc, 0, sizeof(surface_desc));
8082 surface_desc.dwSize = sizeof(surface_desc);
8083 surface_desc.dwFlags = DDSD_CAPS;
8084 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
8085 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
8086 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8087 hr = restore_surfaces(ddraw);
8088 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8090 hr = IDirectDrawSurface_IsLost(surface);
8091 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8093 ret = SetForegroundWindow(GetDesktopWindow());
8094 ok(ret, "Failed to set foreground window.\n");
8095 hr = IDirectDrawSurface_IsLost(surface);
8096 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8097 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8098 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8099 if (vidmem_surface)
8101 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8102 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8105 ret = SetForegroundWindow(window1);
8106 ok(ret, "Failed to set foreground window.\n");
8107 hr = IDirectDrawSurface_IsLost(surface);
8108 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8109 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8110 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8111 if (vidmem_surface)
8113 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8114 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8117 hr = IDirectDraw_SetCooperativeLevel(ddraw, window1, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
8118 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8119 hr = IDirectDrawSurface_IsLost(surface);
8120 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8121 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8122 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8123 if (vidmem_surface)
8125 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8126 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8129 hr = restore_surfaces(ddraw);
8130 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8131 hr = IDirectDrawSurface_IsLost(surface);
8132 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8133 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8134 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8135 if (vidmem_surface)
8137 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8138 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8141 IDirectDrawSurface_Release(surface);
8142 memset(&surface_desc, 0, sizeof(surface_desc));
8143 surface_desc.dwSize = sizeof(surface_desc);
8144 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
8145 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
8146 surface_desc.dwBackBufferCount = 2;
8147 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
8148 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8150 ds = NULL;
8151 memset(&surface_desc, 0, sizeof(surface_desc));
8152 surface_desc.dwSize = sizeof(surface_desc);
8153 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
8154 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
8156 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
8157 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
8158 U2(surface_desc).dwZBufferBitDepth = 16;
8159 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &ds, NULL);
8160 if (FAILED(hr))
8162 skip("Could not create Z buffer, skipping Z buffer restore test.\n");
8164 else
8166 hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
8167 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8170 hr = IDirectDraw_SetCooperativeLevel(ddraw, window1, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
8171 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8172 hr = IDirectDrawSurface_IsLost(surface);
8173 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8174 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8175 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8176 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8177 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8178 if (vidmem_surface)
8180 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8181 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8184 hr = IDirectDraw_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL | DDSCL_FULLSCREEN);
8185 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8186 hr = IDirectDrawSurface_IsLost(surface);
8187 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8188 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8189 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#lx.\n", hr);
8190 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8191 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8192 if (vidmem_surface)
8194 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8195 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8198 hr = IDirectDraw_SetCooperativeLevel(ddraw, window1, DDSCL_NORMAL);
8199 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8200 hr = IDirectDrawSurface_IsLost(surface);
8201 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8202 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8203 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#lx.\n", hr);
8204 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8205 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8206 if (vidmem_surface)
8208 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8209 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8212 hr = IDirectDraw_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL);
8213 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8214 hr = IDirectDrawSurface_IsLost(surface);
8215 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8216 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8217 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#lx.\n", hr);
8218 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8219 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8220 if (vidmem_surface)
8222 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8223 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8226 hr = IDirectDraw_SetCooperativeLevel(ddraw, window2, DDSCL_NORMAL | DDSCL_FULLSCREEN);
8227 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8228 hr = IDirectDrawSurface_IsLost(surface);
8229 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8230 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8231 ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#lx.\n", hr);
8232 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8233 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8234 if (vidmem_surface)
8236 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8237 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8240 hr = IDirectDraw_SetCooperativeLevel(ddraw, window2, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
8241 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8242 hr = IDirectDrawSurface_IsLost(surface);
8243 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8244 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
8245 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8246 hr = IDirectDrawSurface_IsLost(sysmem_surface);
8247 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8248 if (vidmem_surface)
8250 hr = IDirectDrawSurface_IsLost(vidmem_surface);
8251 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8254 memset(&caps, 0, sizeof(caps));
8255 caps.dwCaps = DDSCAPS_FLIP;
8257 hr = IDirectDrawSurface_GetAttachedSurface(surface, &caps, &back_buffer);
8258 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8259 ok(back_buffer != surface, "Got the same surface.\n");
8260 hr = IDirectDrawSurface_Restore(surface);
8261 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8262 hr = IDirectDrawSurface_GetAttachedSurface(surface, &caps, &back_buffer);
8263 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8264 hr = IDirectDrawSurface_IsLost(back_buffer);
8265 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8266 IDirectDrawSurface_Release(back_buffer);
8268 hr = IDirectDrawSurface_GetAttachedSurface(back_buffer, &caps, &back_buffer2);
8269 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8270 ok(back_buffer2 != back_buffer, "Got the same surface.\n");
8271 ok(back_buffer2 != surface, "Got the same surface.\n");
8272 hr = IDirectDrawSurface_IsLost(back_buffer2);
8273 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8274 IDirectDrawSurface_Release(back_buffer2);
8276 if (ds)
8278 hr = IDirectDrawSurface_IsLost(ds);
8279 ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#lx.\n", hr);
8280 hr = IDirectDrawSurface_Restore(ds);
8281 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8282 hr = IDirectDrawSurface_IsLost(ds);
8283 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
8284 IDirectDrawSurface_Release(ds);
8287 if (vidmem_surface)
8288 IDirectDrawSurface_Release(vidmem_surface);
8289 IDirectDrawSurface_Release(sysmem_surface);
8290 IDirectDrawSurface_Release(surface);
8291 refcount = IDirectDraw_Release(ddraw);
8292 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
8293 DestroyWindow(window2);
8294 DestroyWindow(window1);
8297 static void test_surface_desc_lock(void)
8299 IDirectDrawSurface *surface;
8300 DDSURFACEDESC surface_desc;
8301 IDirectDraw *ddraw;
8302 ULONG refcount;
8303 HWND window;
8304 HRESULT hr;
8306 window = create_window();
8307 ddraw = create_ddraw();
8308 ok(!!ddraw, "Failed to create a ddraw object.\n");
8309 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
8310 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
8312 memset(&surface_desc, 0, sizeof(surface_desc));
8313 surface_desc.dwSize = sizeof(surface_desc);
8314 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
8315 surface_desc.dwWidth = 16;
8316 surface_desc.dwHeight = 16;
8317 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
8318 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
8319 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
8321 memset(&surface_desc, 0xaa, sizeof(surface_desc));
8322 surface_desc.dwSize = sizeof(surface_desc);
8323 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
8324 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
8325 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
8327 memset(&surface_desc, 0xaa, sizeof(surface_desc));
8328 surface_desc.dwSize = sizeof(surface_desc);
8329 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, 0, NULL);
8330 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
8331 ok(surface_desc.lpSurface != NULL, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
8332 memset(&surface_desc, 0xaa, sizeof(surface_desc));
8333 surface_desc.dwSize = sizeof(surface_desc);
8334 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
8335 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
8336 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
8337 hr = IDirectDrawSurface_Unlock(surface, NULL);
8338 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
8340 memset(&surface_desc, 0xaa, sizeof(surface_desc));
8341 surface_desc.dwSize = sizeof(surface_desc);
8342 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
8343 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
8344 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
8346 IDirectDrawSurface_Release(surface);
8347 refcount = IDirectDraw_Release(ddraw);
8348 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
8349 DestroyWindow(window);
8352 static void test_texturemapblend(void)
8354 HRESULT hr;
8355 DDSURFACEDESC ddsd;
8356 D3DEXECUTEBUFFERDESC exec_desc;
8357 DDBLTFX fx;
8358 static RECT rect = {0, 0, 64, 128};
8359 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
8360 DDCOLORKEY ckey;
8361 IDirectDrawSurface *surface, *rt;
8362 unsigned int inst_length, color;
8363 IDirect3DTexture *texture;
8364 D3DTEXTUREHANDLE texture_handle;
8365 HWND window;
8366 IDirectDraw *ddraw;
8367 IDirect3DDevice *device;
8368 IDirect3DMaterial *material;
8369 IDirect3DViewport *viewport;
8370 IDirect3DExecuteBuffer *execute_buffer;
8371 void *ptr;
8372 ULONG ref;
8374 static const D3DTLVERTEX test1_quads[] =
8376 {{0.0f}, {0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {0.0f}, {0.0f}},
8377 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {0.0f}, {1.0f}},
8378 {{640.0f}, {0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {1.0f}, {0.0f}},
8379 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0}, {1.0f}, {1.0f}},
8380 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {0.0f}, {0.0f}},
8381 {{0.0f}, {480.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {0.0f}, {1.0f}},
8382 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {1.0f}, {0.0f}},
8383 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0x80ffffff}, {0}, {1.0f}, {1.0f}},
8385 test2_quads[] =
8387 {{0.0f}, {0.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {0.0f}, {0.0f}},
8388 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {0.0f}, {1.0f}},
8389 {{640.0f}, {0.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {1.0f}, {0.0f}},
8390 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0x00ff0080}, {0}, {1.0f}, {1.0f}},
8391 {{0.0f}, {240.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {0.0f}, {0.0f}},
8392 {{0.0f}, {480.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {0.0f}, {1.0f}},
8393 {{640.0f}, {240.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {1.0f}, {0.0f}},
8394 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0x008000ff}, {0}, {1.0f}, {1.0f}},
8397 window = create_window();
8398 ddraw = create_ddraw();
8399 ok(!!ddraw, "Failed to create a ddraw object.\n");
8400 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
8402 skip("Failed to create a 3D device, skipping test.\n");
8403 DestroyWindow(window);
8404 IDirectDraw_Release(ddraw);
8405 return;
8408 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
8409 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
8411 material = create_diffuse_material(device, 0.0f, 0.0f, 0.0f, 1.0f);
8412 viewport = create_viewport(device, 0, 0, 640, 480);
8413 viewport_set_background(device, viewport, material);
8415 memset(&exec_desc, 0, sizeof(exec_desc));
8416 exec_desc.dwSize = sizeof(exec_desc);
8417 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
8418 exec_desc.dwBufferSize = 1024;
8419 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
8420 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
8421 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
8423 /* Test alpha with DDPF_ALPHAPIXELS texture - should be taken from texture alpha channel.
8425 * The vertex alpha is completely ignored in this case, so case 1 and 2 combined are not
8426 * a D3DTOP_MODULATE with texture alpha = 0xff in case 2 (no alpha in texture). */
8427 memset(&ddsd, 0, sizeof(ddsd));
8428 ddsd.dwSize = sizeof(ddsd);
8429 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
8430 ddsd.dwHeight = 128;
8431 ddsd.dwWidth = 128;
8432 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
8433 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
8434 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
8435 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
8436 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
8437 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
8438 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
8439 U5(ddsd.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
8440 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
8441 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
8443 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture, (void **)&texture);
8444 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
8445 hr = IDirect3DTexture_GetHandle(texture, device, &texture_handle);
8446 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
8448 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8449 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
8451 memset(&fx, 0, sizeof(fx));
8452 fx.dwSize = sizeof(fx);
8453 U5(fx).dwFillColor = 0xff0000ff;
8454 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8455 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
8456 U5(fx).dwFillColor = 0x800000ff;
8457 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8458 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
8460 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
8461 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
8463 memcpy(exec_desc.lpData, test1_quads, sizeof(test1_quads));
8465 ptr = ((BYTE *)exec_desc.lpData) + sizeof(test1_quads);
8466 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 8);
8467 emit_set_rs(&ptr, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
8468 emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
8469 emit_set_rs(&ptr, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
8470 emit_set_rs(&ptr, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
8471 /* The history of D3DRENDERSTATE_ALPHABLENDENABLE is quite a mess. In the
8472 * first D3D release there was a D3DRENDERSTATE_BLENDENABLE (enum value 27).
8473 * D3D5 introduced a new and separate D3DRENDERSTATE_ALPHABLENDENABLE (42)
8474 * together with D3DRENDERSTATE_COLORKEYENABLE (41). The docs aren't all
8475 * that clear but they mention that D3DRENDERSTATE_BLENDENABLE overrides the
8476 * two new states.
8477 * Then D3D6 came and got rid of the new D3DRENDERSTATE_ALPHABLENDENABLE
8478 * state (42), renaming the older D3DRENDERSTATE_BLENDENABLE enum (27)
8479 * as D3DRENDERSTATE_ALPHABLENDENABLE.
8480 * There is a comment in the D3D6 docs which mentions that hardware
8481 * rasterizers always used D3DRENDERSTATE_BLENDENABLE to just toggle alpha
8482 * blending while prior to D3D5 software rasterizers toggled both color
8483 * keying and alpha blending according to it. What I gather is that, from
8484 * D3D6 onwards, D3DRENDERSTATE_ALPHABLENDENABLE always only toggles the
8485 * alpha blending state.
8486 * These tests seem to show that actual, current hardware follows the D3D6
8487 * behavior even when using the original D3D interfaces, for the HAL device
8488 * at least. */
8489 emit_set_rs(&ptr, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
8490 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
8491 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
8493 /* SPECULARENABLE shouldn't matter in this test, but WARP begs to
8494 * differ. In the event that color keying is randomly on (see comments
8495 * in test_ck_default for reference), WARP will randomly discard
8496 * fragments based on something, even though texture and diffuse color
8497 * alpha components are non-zero. Setting SPECULARENABLE to FALSE
8498 * prevents this in some cases - presumably WARP multiplies the
8499 * specular color "alpha" channel into the final result and then
8500 * alpha tests the result. Since the specular property normally does
8501 * not have an alpha component the actual specular color we set in
8502 * the vertex data above does not matter. Setting FOGENABLE = FALSE
8503 * does not help either (specular alpha can contain a per-vertex fog
8504 * factor. Doesn't seem to matter here). */
8505 emit_set_rs(&ptr, D3DRENDERSTATE_SPECULARENABLE, FALSE);
8507 emit_tquad(&ptr, 0);
8508 emit_tquad(&ptr, 4);
8509 emit_end(&ptr);
8511 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
8512 inst_length -= sizeof(test1_quads);
8513 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
8514 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
8515 set_execute_data(execute_buffer, 8, sizeof(test1_quads), inst_length);
8517 hr = IDirect3DDevice_BeginScene(device);
8518 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
8519 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_UNCLIPPED);
8520 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
8521 hr = IDirect3DDevice_EndScene(device);
8522 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
8524 /* The above SPECULARENABLE = FALSE on WARP matters here.*/
8525 color = get_surface_color(rt, 5, 5);
8526 ok(compare_color(color, 0x00000080, 2), "Got unexpected color 0x%08x.\n", color);
8527 color = get_surface_color(rt, 400, 5);
8528 ok(compare_color(color, 0x000000ff, 2), "Got unexpected color 0x%08x.\n", color);
8529 color = get_surface_color(rt, 5, 245);
8530 ok(compare_color(color, 0x00000080, 2), "Got unexpected color 0x%08x.\n", color);
8531 color = get_surface_color(rt, 400, 245);
8532 ok(compare_color(color, 0x000000ff, 2), "Got unexpected color 0x%08x.\n", color);
8534 IDirect3DTexture_Release(texture);
8535 ref = IDirectDrawSurface_Release(surface);
8536 ok(!ref, "Unexpected refcount %lu.\n", ref);
8538 /* Test alpha with texture that has no alpha channel - alpha should be taken from diffuse vertex color. */
8539 memset(&ddsd, 0, sizeof(ddsd));
8540 ddsd.dwSize = sizeof(ddsd);
8541 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
8542 ddsd.dwHeight = 128;
8543 ddsd.dwWidth = 128;
8544 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
8545 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
8546 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
8547 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
8548 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
8549 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
8550 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
8552 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
8553 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
8555 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture, (void **)&texture);
8556 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
8557 hr = IDirect3DTexture_GetHandle(texture, device, &texture_handle);
8558 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
8560 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8561 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
8563 U5(fx).dwFillColor = 0xff0000ff;
8564 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8565 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
8566 U5(fx).dwFillColor = 0x800000ff;
8567 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8568 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
8570 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
8571 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
8573 ptr = ((BYTE *)exec_desc.lpData) + sizeof(test1_quads);
8574 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 8);
8575 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
8577 emit_tquad(&ptr, 0);
8578 emit_tquad(&ptr, 4);
8579 emit_end(&ptr);
8581 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
8582 inst_length -= sizeof(test1_quads);
8583 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
8584 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
8585 set_execute_data(execute_buffer, 8, sizeof(test1_quads), inst_length);
8587 hr = IDirect3DDevice_BeginScene(device);
8588 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
8589 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_UNCLIPPED);
8590 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
8591 hr = IDirect3DDevice_EndScene(device);
8592 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
8594 /* Despite our best efforts at not making color keying randomly triggering, those
8595 * four broken() results occur every now and then on WARP. Presumably the non-
8596 * existent alpha channel sometimes samples 0.0 instead of the expected 1.0. */
8597 color = get_surface_color(rt, 5, 5);
8598 ok(compare_color(color, 0x000000ff, 2)
8599 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x00000000, 2)),
8600 "Got unexpected color 0x%08x.\n", color);
8601 color = get_surface_color(rt, 400, 5);
8602 ok(compare_color(color, 0x000000ff, 2)
8603 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x00000000, 2)),
8604 "Got unexpected color 0x%08x.\n", color);
8605 color = get_surface_color(rt, 5, 245);
8606 ok(compare_color(color, 0x00000080, 2)
8607 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x00000000, 2)),
8608 "Got unexpected color 0x%08x.\n", color);
8609 color = get_surface_color(rt, 400, 245);
8610 ok(compare_color(color, 0x00000080, 2)
8611 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x00000000, 2)),
8612 "Got unexpected color 0x%08x.\n", color);
8614 IDirect3DTexture_Release(texture);
8615 ref = IDirectDrawSurface_Release(surface);
8616 ok(!ref, "Unexpected refcount %lu.\n", ref);
8618 /* Test RGB - should multiply color components from diffuse vertex color and texture. */
8619 memset(&ddsd, 0, sizeof(ddsd));
8620 ddsd.dwSize = sizeof(ddsd);
8621 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
8622 ddsd.dwHeight = 128;
8623 ddsd.dwWidth = 128;
8624 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
8625 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
8626 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
8627 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
8628 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
8629 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
8630 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x000000ff;
8631 U5(ddsd.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
8632 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
8633 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
8635 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture, (void **)&texture);
8636 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
8637 hr = IDirect3DTexture_GetHandle(texture, device, &texture_handle);
8638 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
8640 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8641 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
8643 U5(fx).dwFillColor = 0x00ffffff;
8644 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8645 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
8646 U5(fx).dwFillColor = 0x00ffff80;
8647 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8648 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
8650 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
8651 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
8653 memcpy(exec_desc.lpData, test2_quads, sizeof(test2_quads));
8655 ptr = ((BYTE *)exec_desc.lpData) + sizeof(test2_quads);
8656 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 8);
8657 emit_set_rs(&ptr, D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
8658 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
8660 emit_tquad(&ptr, 0);
8661 emit_tquad(&ptr, 4);
8662 emit_end(&ptr);
8664 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
8665 inst_length -= sizeof(test2_quads);
8666 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
8667 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
8668 set_execute_data(execute_buffer, 8, sizeof(test2_quads), inst_length);
8670 hr = IDirect3DDevice_BeginScene(device);
8671 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
8672 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_UNCLIPPED);
8673 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
8674 hr = IDirect3DDevice_EndScene(device);
8675 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
8677 /* WARP (Win8 testbot) emulates color keying with the alpha channel like Wine does,
8678 * but even applies it when there's no color key assigned. The surface alpha is zero
8679 * here, so nothing gets drawn.
8681 * The ddraw2 version of this test draws these quads with color keying off due to
8682 * different defaults in ddraw1 and ddraw2. */
8683 color = get_surface_color(rt, 5, 5);
8684 ok(compare_color(color, 0x00ff0040, 2) || broken(compare_color(color, 0x00000000, 1)),
8685 "Got unexpected color 0x%08x.\n", color);
8686 color = get_surface_color(rt, 400, 5);
8687 ok(compare_color(color, 0x00ff0080, 2) || broken(compare_color(color, 0x00000000, 1)),
8688 "Got unexpected color 0x%08x.\n", color);
8689 color = get_surface_color(rt, 5, 245);
8690 ok(compare_color(color, 0x00800080, 2) || broken(compare_color(color, 0x00000000, 1)),
8691 "Got unexpected color 0x%08x.\n", color);
8692 color = get_surface_color(rt, 400, 245);
8693 ok(compare_color(color, 0x008000ff, 2) || broken(compare_color(color, 0x00000000, 1)),
8694 "Got unexpected color 0x%08x.\n", color);
8696 IDirect3DTexture_Release(texture);
8697 ref = IDirectDrawSurface_Release(surface);
8698 ok(!ref, "Unexpected refcount %lu.\n", ref);
8700 /* Test alpha again, now with color keyed texture (colorkey emulation in wine can interfere). */
8701 memset(&ddsd, 0, sizeof(ddsd));
8702 ddsd.dwSize = sizeof(ddsd);
8703 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
8704 ddsd.dwHeight = 128;
8705 ddsd.dwWidth = 128;
8706 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
8707 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
8708 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
8709 U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 16;
8710 U2(ddsd.ddpfPixelFormat).dwRBitMask = 0xf800;
8711 U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x07e0;
8712 U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x001f;
8714 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
8715 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
8717 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture, (void **)&texture);
8718 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
8719 hr = IDirect3DTexture_GetHandle(texture, device, &texture_handle);
8720 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
8722 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8723 ok(SUCCEEDED(hr), "Failed to clear render target, hr %#lx.\n", hr);
8725 U5(fx).dwFillColor = 0xf800;
8726 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8727 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
8728 U5(fx).dwFillColor = 0x001f;
8729 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
8730 ok(SUCCEEDED(hr), "Failed to clear texture, hr %#lx.\n", hr);
8732 ckey.dwColorSpaceLowValue = 0x001f;
8733 ckey.dwColorSpaceHighValue = 0x001f;
8734 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &ckey);
8735 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
8737 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
8738 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
8740 memcpy(exec_desc.lpData, test1_quads, sizeof(test1_quads));
8742 ptr = ((BYTE *)exec_desc.lpData) + sizeof(test1_quads);
8743 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 8);
8744 emit_set_rs(&ptr, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
8745 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
8746 /* D3DRENDERSTATE_COLORKEYENABLE is supposed to be on by default on version
8747 * 1 devices, but for some reason it randomly defaults to FALSE on the W8
8748 * testbot. This is either the fault of Windows 8 or the WARP driver.
8749 * Also D3DRENDERSTATE_COLORKEYENABLE was introduced in D3D 5 aka version 2
8750 * devices only, which might imply this doesn't actually do anything on
8751 * WARP. */
8752 emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
8754 emit_tquad(&ptr, 0);
8755 emit_tquad(&ptr, 4);
8756 emit_end(&ptr);
8758 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
8759 inst_length -= sizeof(test1_quads);
8760 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
8761 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
8762 set_execute_data(execute_buffer, 8, sizeof(test1_quads), inst_length);
8764 hr = IDirect3DDevice_BeginScene(device);
8765 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
8766 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_UNCLIPPED);
8767 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
8768 hr = IDirect3DDevice_EndScene(device);
8769 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
8771 /* Allow broken WARP results (colorkey disabled). */
8772 color = get_surface_color(rt, 5, 5);
8773 ok(compare_color(color, 0x00000000, 2) || broken(compare_color(color, 0x000000ff, 2)),
8774 "Got unexpected color 0x%08x.\n", color);
8775 color = get_surface_color(rt, 400, 5);
8776 ok(compare_color(color, 0x00ff0000, 2), "Got unexpected color 0x%08x.\n", color);
8777 color = get_surface_color(rt, 5, 245);
8778 ok(compare_color(color, 0x00000000, 2) || broken(compare_color(color, 0x00000080, 2)),
8779 "Got unexpected color 0x%08x.\n", color);
8780 color = get_surface_color(rt, 400, 245);
8781 ok(compare_color(color, 0x00800000, 2), "Got unexpected color 0x%08x.\n", color);
8783 IDirect3DTexture_Release(texture);
8784 ref = IDirectDrawSurface_Release(surface);
8785 ok(!ref, "Unexpected refcount %lu.\n", ref);
8787 ref = IDirect3DExecuteBuffer_Release(execute_buffer);
8788 ok(ref == 0, "Execute buffer not properly released, refcount %lu.\n", ref);
8789 destroy_viewport(device, viewport);
8790 ref = IDirect3DMaterial_Release(material);
8791 ok(ref == 0, "Material not properly released, refcount %lu.\n", ref);
8792 IDirectDrawSurface_Release(rt);
8793 IDirect3DDevice_Release(device);
8794 ref = IDirectDraw_Release(ddraw);
8795 ok(!ref, "Unexpected refcount %lu.\n", ref);
8796 DestroyWindow(window);
8799 static void test_viewport_clear_rect(void)
8801 HRESULT hr;
8802 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
8803 static D3DRECT clear_rect2 = {{90}, {90}, {110}, {110}};
8804 IDirectDrawSurface *rt;
8805 unsigned int color;
8806 HWND window;
8807 IDirectDraw *ddraw;
8808 IDirect3DDevice *device;
8809 IDirect3DMaterial *red, *green;
8810 IDirect3DViewport *viewport, *viewport2;
8811 ULONG ref;
8813 window = create_window();
8814 ddraw = create_ddraw();
8815 ok(!!ddraw, "Failed to create a ddraw object.\n");
8816 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
8818 skip("Failed to create a 3D device, skipping test.\n");
8819 DestroyWindow(window);
8820 IDirectDraw_Release(ddraw);
8821 return;
8824 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
8825 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
8827 red = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
8828 viewport = create_viewport(device, 0, 0, 640, 480);
8829 viewport_set_background(device, viewport, red);
8830 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
8831 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
8833 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 1.0f);
8834 viewport2 = create_viewport(device, 100, 100, 20, 20);
8835 viewport_set_background(device, viewport2, green);
8836 hr = IDirect3DViewport_Clear(viewport2, 1, &clear_rect2, D3DCLEAR_TARGET);
8837 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
8839 color = get_surface_color(rt, 85, 85); /* Outside both. */
8840 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
8841 color = get_surface_color(rt, 95, 95); /* Outside vp, inside rect. */
8842 /* AMD GPUs ignore the viewport dimensions and only care about the rectangle. */
8843 ok(compare_color(color, 0x00ff0000, 1) || broken(compare_color(color, 0x0000ff00, 1)),
8844 "Got unexpected color 0x%08x.\n", color);
8845 color = get_surface_color(rt, 105, 105); /* Inside both. */
8846 ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
8847 color = get_surface_color(rt, 115, 115); /* Inside vp, outside rect. */
8848 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
8849 color = get_surface_color(rt, 125, 125); /* Outside both. */
8850 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
8852 destroy_viewport(device, viewport2);
8853 destroy_material(green);
8854 destroy_viewport(device, viewport);
8855 destroy_material(red);
8856 IDirectDrawSurface_Release(rt);
8857 IDirect3DDevice_Release(device);
8858 ref = IDirectDraw_Release(ddraw);
8859 ok(!ref, "Unexpected refcount %lu.\n", ref);
8860 DestroyWindow(window);
8863 static void test_color_fill(void)
8865 HRESULT hr;
8866 IDirect3DDevice *device;
8867 IDirectDraw *ddraw;
8868 IDirectDrawSurface *surface, *surface2;
8869 DDSURFACEDESC surface_desc;
8870 unsigned int i, *color;
8871 ULONG refcount;
8872 HWND window;
8873 BOOL is_warp;
8874 DDBLTFX fx;
8875 RECT rect = {5, 5, 7, 7};
8876 DWORD num_fourcc_codes, *fourcc_codes;
8877 DDCAPS hal_caps;
8878 BOOL support_uyvy = FALSE, support_yuy2 = FALSE;
8879 static const struct
8881 DWORD caps;
8882 HRESULT colorfill_hr, depthfill_hr;
8883 BOOL rop_success;
8884 const char *name;
8885 unsigned int result;
8886 BOOL check_result;
8887 DDPIXELFORMAT format;
8889 tests[] =
8892 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
8893 DD_OK, DDERR_INVALIDPARAMS, TRUE, "vidmem offscreenplain RGB", 0xdeadbeef, TRUE,
8895 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
8896 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
8900 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
8901 DD_OK, DDERR_INVALIDPARAMS, TRUE, "sysmem offscreenplain RGB", 0xdeadbeef, TRUE,
8903 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
8904 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
8908 DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY,
8909 DD_OK, DDERR_INVALIDPARAMS, TRUE, "vidmem texture RGB", 0xdeadbeef, TRUE,
8911 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
8912 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
8916 DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY,
8917 DD_OK, DDERR_INVALIDPARAMS, TRUE, "sysmem texture RGB", 0xdeadbeef, TRUE,
8919 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
8920 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
8924 DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY,
8925 DDERR_INVALIDPARAMS, DD_OK, TRUE, "vidmem zbuffer", 0xdeadbeef, TRUE,
8926 {0, 0, 0, {0}, {0}, {0}, {0}, {0}}
8929 /* Colorfill on YUV surfaces always returns DD_OK, but the content is
8930 * different afterwards. DX9+ GPUs set one of the two luminance values
8931 * in each block, but AMD and Nvidia GPUs disagree on which luminance
8932 * value they set. r200 (dx8) just sets the entire block to the clear
8933 * value. */
8934 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
8935 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem offscreenplain YUY2", 0, FALSE,
8937 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y', 'U', 'Y', '2'),
8938 {0}, {0}, {0}, {0}, {0}
8942 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
8943 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem offscreenplain UYVY", 0, FALSE,
8945 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('U', 'Y', 'V', 'Y'),
8946 {0}, {0}, {0}, {0}, {0}
8950 DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY,
8951 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem overlay YUY2", 0, FALSE,
8953 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y', 'U', 'Y', '2'),
8954 {0}, {0}, {0}, {0}, {0}
8958 DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY,
8959 DD_OK, DDERR_INVALIDPARAMS, FALSE, "vidmem overlay UYVY", 0, FALSE,
8961 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('U', 'Y', 'V', 'Y'),
8962 {0}, {0}, {0}, {0}, {0}
8966 DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY,
8967 E_NOTIMPL, DDERR_INVALIDPARAMS, FALSE, "vidmem texture DXT1", 0, FALSE,
8969 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'),
8970 {0}, {0}, {0}, {0}, {0}
8974 DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY,
8975 E_NOTIMPL, DDERR_INVALIDPARAMS, FALSE, "sysmem texture DXT1", 0, FALSE,
8977 sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'),
8978 {0}, {0}, {0}, {0}, {0}
8982 /* The testbot fills this with 0x00 instead of the blue channel. The sysmem
8983 * surface works, presumably because it is handled by the runtime instead of
8984 * the driver. */
8985 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
8986 DD_OK, DDERR_INVALIDPARAMS, TRUE, "vidmem offscreenplain P8", 0xefefefef, FALSE,
8988 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED8, 0,
8989 {8}, {0}, {0}, {0}, {0}
8993 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY,
8994 DD_OK, DDERR_INVALIDPARAMS, TRUE, "sysmem offscreenplain P8", 0xefefefef, TRUE,
8996 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED8, 0,
8997 {8}, {0}, {0}, {0}, {0}
9001 static const struct
9003 DWORD rop;
9004 const char *name;
9005 HRESULT hr;
9007 rops[] =
9009 {SRCCOPY, "SRCCOPY", DD_OK},
9010 {SRCPAINT, "SRCPAINT", DDERR_NORASTEROPHW},
9011 {SRCAND, "SRCAND", DDERR_NORASTEROPHW},
9012 {SRCINVERT, "SRCINVERT", DDERR_NORASTEROPHW},
9013 {SRCERASE, "SRCERASE", DDERR_NORASTEROPHW},
9014 {NOTSRCCOPY, "NOTSRCCOPY", DDERR_NORASTEROPHW},
9015 {NOTSRCERASE, "NOTSRCERASE", DDERR_NORASTEROPHW},
9016 {MERGECOPY, "MERGECOPY", DDERR_NORASTEROPHW},
9017 {MERGEPAINT, "MERGEPAINT", DDERR_NORASTEROPHW},
9018 {PATCOPY, "PATCOPY", DDERR_NORASTEROPHW},
9019 {PATPAINT, "PATPAINT", DDERR_NORASTEROPHW},
9020 {PATINVERT, "PATINVERT", DDERR_NORASTEROPHW},
9021 {DSTINVERT, "DSTINVERT", DDERR_NORASTEROPHW},
9022 {BLACKNESS, "BLACKNESS", DD_OK},
9023 {WHITENESS, "WHITENESS", DD_OK},
9024 {0xaa0029, "0xaa0029", DDERR_NORASTEROPHW} /* noop */
9027 window = create_window();
9028 ddraw = create_ddraw();
9029 ok(!!ddraw, "Failed to create a ddraw object.\n");
9030 is_warp = ddraw_is_warp(ddraw);
9031 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
9033 skip("Failed to create a 3D device, skipping test.\n");
9034 DestroyWindow(window);
9035 IDirectDraw_Release(ddraw);
9036 return;
9039 hr = IDirectDraw_GetFourCCCodes(ddraw, &num_fourcc_codes, NULL);
9040 ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr);
9041 fourcc_codes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
9042 num_fourcc_codes * sizeof(*fourcc_codes));
9043 if (!fourcc_codes)
9044 goto done;
9045 hr = IDirectDraw_GetFourCCCodes(ddraw, &num_fourcc_codes, fourcc_codes);
9046 ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr);
9047 for (i = 0; i < num_fourcc_codes; i++)
9049 if (fourcc_codes[i] == MAKEFOURCC('Y', 'U', 'Y', '2'))
9050 support_yuy2 = TRUE;
9051 else if (fourcc_codes[i] == MAKEFOURCC('U', 'Y', 'V', 'Y'))
9052 support_uyvy = TRUE;
9054 HeapFree(GetProcessHeap(), 0, fourcc_codes);
9056 memset(&hal_caps, 0, sizeof(hal_caps));
9057 hal_caps.dwSize = sizeof(hal_caps);
9058 hr = IDirectDraw_GetCaps(ddraw, &hal_caps, NULL);
9059 ok(SUCCEEDED(hr), "Failed to get caps, hr %#lx.\n", hr);
9061 if ((!support_yuy2 && !support_uyvy) || !(hal_caps.dwCaps & DDCAPS_OVERLAY))
9062 skip("Overlays or some YUV formats not supported, skipping YUV colorfill tests.\n");
9064 for (i = 0; i < ARRAY_SIZE(tests); i++)
9066 DWORD expected_broken = tests[i].result;
9067 unsigned int mask = 0xffffffffu;
9069 /* Some Windows drivers modify dwFillColor when it is used on P8 or FourCC formats. */
9070 memset(&fx, 0, sizeof(fx));
9071 fx.dwSize = sizeof(fx);
9072 U5(fx).dwFillColor = 0xdeadbeef;
9074 memset(&surface_desc, 0, sizeof(surface_desc));
9075 surface_desc.dwSize = sizeof(surface_desc);
9076 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
9077 surface_desc.dwWidth = 64;
9078 surface_desc.dwHeight = 64;
9079 surface_desc.ddpfPixelFormat = tests[i].format;
9080 surface_desc.ddsCaps.dwCaps = tests[i].caps;
9082 if (tests[i].caps & DDSCAPS_TEXTURE)
9084 struct format_support_check check = {&tests[i].format, FALSE};
9085 hr = IDirect3DDevice_EnumTextureFormats(device, test_unsupported_formats_cb, &check);
9086 ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr);
9087 if (!check.supported)
9088 continue;
9091 if (tests[i].format.dwFourCC == MAKEFOURCC('Y','U','Y','2') && !support_yuy2)
9092 continue;
9093 if (tests[i].format.dwFourCC == MAKEFOURCC('U','Y','V','Y') && !support_uyvy)
9094 continue;
9095 if (tests[i].caps & DDSCAPS_OVERLAY && !(hal_caps.dwCaps & DDCAPS_OVERLAY))
9096 continue;
9098 if (tests[i].caps & DDSCAPS_ZBUFFER)
9100 surface_desc.dwFlags &= ~DDSD_PIXELFORMAT;
9101 surface_desc.dwFlags |= DDSD_ZBUFFERBITDEPTH;
9102 U2(surface_desc).dwZBufferBitDepth = get_device_z_depth(device);
9103 mask >>= (32 - U2(surface_desc).dwZBufferBitDepth);
9104 /* Some drivers seem to convert depth values incorrectly or not at
9105 * all. Affects at least AMD PALM, 8.17.10.1247. */
9106 if (tests[i].caps & DDSCAPS_VIDEOMEMORY)
9108 DWORD expected;
9109 float f, g;
9111 expected = tests[i].result & mask;
9112 f = ceilf(logf(expected + 1.0f) / logf(2.0f));
9113 g = (f + 1.0f) / 2.0f;
9114 g -= (int)g;
9115 expected_broken = (expected / exp2f(f) - g) * 256;
9116 expected_broken *= 0x01010101;
9120 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9121 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9123 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9124 todo_wine_if (tests[i].format.dwFourCC)
9125 ok(hr == tests[i].colorfill_hr, "Blt returned %#lx, expected %#lx, surface %s.\n",
9126 hr, tests[i].colorfill_hr, tests[i].name);
9128 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9129 todo_wine_if (tests[i].format.dwFourCC)
9130 ok(hr == tests[i].colorfill_hr, "Blt returned %#lx, expected %#lx, surface %s.\n",
9131 hr, tests[i].colorfill_hr, tests[i].name);
9133 if (SUCCEEDED(hr) && tests[i].check_result)
9135 memset(&surface_desc, 0, sizeof(surface_desc));
9136 surface_desc.dwSize = sizeof(surface_desc);
9137 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
9138 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9139 color = surface_desc.lpSurface;
9140 ok(*color == tests[i].result, "Got clear result 0x%08x, expected 0x%08x, surface %s.\n",
9141 *color, tests[i].result, tests[i].name);
9142 hr = IDirectDrawSurface_Unlock(surface, NULL);
9143 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9146 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9147 ok(hr == tests[i].depthfill_hr, "Blt returned %#lx, expected %#lx, surface %s.\n",
9148 hr, tests[i].depthfill_hr, tests[i].name);
9149 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9150 ok(hr == tests[i].depthfill_hr, "Blt returned %#lx, expected %#lx, surface %s.\n",
9151 hr, tests[i].depthfill_hr, tests[i].name);
9153 if (SUCCEEDED(hr) && tests[i].check_result)
9155 memset(&surface_desc, 0, sizeof(surface_desc));
9156 surface_desc.dwSize = sizeof(surface_desc);
9157 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
9158 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9159 color = surface_desc.lpSurface;
9160 todo_wine_if(tests[i].caps & DDSCAPS_VIDEOMEMORY && U2(surface_desc).dwZBufferBitDepth != 16)
9161 ok((*color & mask) == (tests[i].result & mask) || broken((*color & mask) == (expected_broken & mask))
9162 || broken(is_warp && (*color & mask) == (~0u & mask)) /* Windows 8+ testbot. */,
9163 "Got clear result 0x%08x, expected 0x%08x, surface %s.\n",
9164 *color & mask, tests[i].result & mask, tests[i].name);
9165 hr = IDirectDrawSurface_Unlock(surface, NULL);
9166 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9169 U5(fx).dwFillColor = 0xdeadbeef;
9170 fx.dwROP = BLACKNESS;
9171 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
9172 ok(FAILED(hr) == !tests[i].rop_success, "Blt returned %#lx, expected %s, surface %s.\n",
9173 hr, tests[i].rop_success ? "success" : "failure", tests[i].name);
9174 ok(U5(fx).dwFillColor == 0xdeadbeef, "dwFillColor was set to 0x%08lx, surface %s\n",
9175 U5(fx).dwFillColor, tests[i].name);
9177 if (SUCCEEDED(hr) && tests[i].check_result)
9179 memset(&surface_desc, 0, sizeof(surface_desc));
9180 surface_desc.dwSize = sizeof(surface_desc);
9181 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
9182 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9183 color = surface_desc.lpSurface;
9184 ok(*color == 0, "Got clear result 0x%08x, expected 0x00000000, surface %s.\n",
9185 *color, tests[i].name);
9186 hr = IDirectDrawSurface_Unlock(surface, NULL);
9187 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9190 fx.dwROP = WHITENESS;
9191 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
9192 ok(FAILED(hr) == !tests[i].rop_success, "Blt returned %#lx, expected %s, surface %s.\n",
9193 hr, tests[i].rop_success ? "success" : "failure", tests[i].name);
9194 ok(U5(fx).dwFillColor == 0xdeadbeef, "dwFillColor was set to 0x%08lx, surface %s\n",
9195 U5(fx).dwFillColor, tests[i].name);
9197 if (SUCCEEDED(hr) && tests[i].check_result)
9199 memset(&surface_desc, 0, sizeof(surface_desc));
9200 surface_desc.dwSize = sizeof(surface_desc);
9201 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, 0);
9202 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9203 color = surface_desc.lpSurface;
9204 /* WHITENESS sets the alpha channel to 0x00. Ignore this for now. */
9205 ok((*color & 0x00ffffff) == 0x00ffffff, "Got clear result 0x%08x, expected 0xffffffff, surface %s.\n",
9206 *color, tests[i].name);
9207 hr = IDirectDrawSurface_Unlock(surface, NULL);
9208 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, surface %s.\n", hr, tests[i].name);
9211 IDirectDrawSurface_Release(surface);
9214 memset(&fx, 0, sizeof(fx));
9215 fx.dwSize = sizeof(fx);
9216 U5(fx).dwFillColor = 0xdeadbeef;
9217 fx.dwROP = WHITENESS;
9219 memset(&surface_desc, 0, sizeof(surface_desc));
9220 surface_desc.dwSize = sizeof(surface_desc);
9221 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
9222 surface_desc.dwWidth = 64;
9223 surface_desc.dwHeight = 64;
9224 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
9225 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
9226 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
9227 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
9228 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
9229 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
9230 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
9231 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9232 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9233 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
9234 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9236 /* No DDBLTFX. */
9237 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, NULL);
9238 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9239 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_ROP | DDBLT_WAIT, NULL);
9240 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9242 /* Unused source rectangle. */
9243 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9244 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
9245 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
9246 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
9248 /* Unused source surface. */
9249 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9250 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9251 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
9252 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
9253 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9254 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9255 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
9256 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
9258 /* Inverted destination or source rectangle. */
9259 SetRect(&rect, 5, 7, 7, 5);
9260 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9261 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
9262 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9263 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
9264 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9265 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9266 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9267 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9268 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
9269 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
9271 /* Negative rectangle. */
9272 SetRect(&rect, -1, -1, 5, 5);
9273 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9274 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
9275 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9276 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
9277 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9278 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9279 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, &rect, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9280 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9281 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
9282 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
9284 /* Out of bounds rectangle. */
9285 SetRect(&rect, 0, 0, 65, 65);
9286 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9287 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
9288 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_ROP | DDBLT_WAIT, &fx);
9289 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
9291 /* Combine multiple flags. */
9292 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9293 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
9294 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_ROP | DDBLT_WAIT, &fx);
9295 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9296 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ROP | DDBLT_WAIT, &fx);
9297 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9299 for (i = 0; i < ARRAY_SIZE(rops); i++)
9301 fx.dwROP = rops[i].rop;
9302 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
9303 ok(hr == rops[i].hr, "Got unexpected hr %#lx for rop %s.\n", hr, rops[i].name);
9306 IDirectDrawSurface_Release(surface2);
9307 IDirectDrawSurface_Release(surface);
9309 memset(&surface_desc, 0, sizeof(surface_desc));
9310 surface_desc.dwSize = sizeof(surface_desc);
9311 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_ZBUFFERBITDEPTH;
9312 surface_desc.dwWidth = 64;
9313 surface_desc.dwHeight = 64;
9314 U2(surface_desc).dwZBufferBitDepth = get_device_z_depth(device);
9315 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
9316 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9317 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9318 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
9319 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9321 /* No DDBLTFX. */
9322 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, NULL);
9323 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9325 /* Unused source rectangle. */
9326 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9327 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
9329 /* Unused source surface. */
9330 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9331 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9332 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9333 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9335 /* Inverted destination or source rectangle. */
9336 SetRect(&rect, 5, 7, 7, 5);
9337 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9338 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
9339 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9340 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
9341 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9342 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9343 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9344 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9346 /* Negative rectangle. */
9347 SetRect(&rect, -1, -1, 5, 5);
9348 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9349 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
9350 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9351 ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr);
9352 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9353 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9354 hr = IDirectDrawSurface_Blt(surface, &rect, surface2, &rect, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9355 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9357 /* Out of bounds rectangle. */
9358 SetRect(&rect, 0, 0, 65, 65);
9359 hr = IDirectDrawSurface_Blt(surface, &rect, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9360 ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#lx.\n", hr);
9362 /* Combine multiple flags. */
9363 hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
9364 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
9366 IDirectDrawSurface_Release(surface2);
9367 IDirectDrawSurface_Release(surface);
9369 done:
9370 IDirect3DDevice_Release(device);
9371 refcount = IDirectDraw_Release(ddraw);
9372 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
9373 DestroyWindow(window);
9376 static void test_colorkey_precision(void)
9378 static D3DTLVERTEX quad[] =
9380 {{ 0.0f}, {480.0f}, {0.0f}, {1.0f}, {0x00000000}, {0x00000000}, {0.0f}, {1.0f}},
9381 {{ 0.0f}, { 0.0f}, {0.0f}, {1.0f}, {0x00000000}, {0x00000000}, {0.0f}, {0.0f}},
9382 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0x00000000}, {0x00000000}, {1.0f}, {1.0f}},
9383 {{640.0f}, { 0.0f}, {0.0f}, {1.0f}, {0x00000000}, {0x00000000}, {1.0f}, {0.0f}},
9385 unsigned int inst_length, data[4] = {0}, color_mask, color, t, c;
9386 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
9387 IDirect3DDevice *device;
9388 IDirectDraw *ddraw;
9389 IDirectDrawSurface *rt;
9390 IDirect3DViewport *viewport;
9391 IDirect3DExecuteBuffer *execute_buffer;
9392 D3DEXECUTEBUFFERDESC exec_desc;
9393 void *ptr;
9394 HWND window;
9395 HRESULT hr;
9396 IDirectDrawSurface *src, *dst, *texture;
9397 D3DTEXTUREHANDLE handle;
9398 IDirect3DTexture *d3d_texture;
9399 IDirect3DMaterial *green;
9400 DDSURFACEDESC surface_desc, lock_desc;
9401 ULONG refcount;
9402 DDCOLORKEY ckey;
9403 DDBLTFX fx;
9404 BOOL is_nvidia, is_warp;
9405 static const struct
9407 unsigned int max, shift, bpp, clear;
9408 const char *name;
9409 BOOL skip_nv;
9410 DDPIXELFORMAT fmt;
9412 tests[] =
9415 255, 0, 4, 0x00345678, "D3DFMT_X8R8G8B8", FALSE,
9417 sizeof(DDPIXELFORMAT), DDPF_RGB, 0,
9418 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0x00000000}
9423 63, 5, 2, 0x5678, "D3DFMT_R5G6B5, G channel", FALSE,
9425 sizeof(DDPIXELFORMAT), DDPF_RGB, 0,
9426 {16}, {0xf800}, {0x07e0}, {0x001f}, {0x0000}
9431 31, 0, 2, 0x5678, "D3DFMT_R5G6B5, B channel", FALSE,
9433 sizeof(DDPIXELFORMAT), DDPF_RGB, 0,
9434 {16}, {0xf800}, {0x07e0}, {0x001f}, {0x0000}
9439 15, 0, 2, 0x0678, "D3DFMT_A4R4G4B4", TRUE,
9441 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
9442 {16}, {0x0f00}, {0x00f0}, {0x000f}, {0xf000}
9447 window = create_window();
9448 ddraw = create_ddraw();
9449 ok(!!ddraw, "Failed to create a ddraw object.\n");
9450 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
9452 skip("Failed to create a 3D device, skipping test.\n");
9453 DestroyWindow(window);
9454 IDirectDraw_Release(ddraw);
9455 return;
9457 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
9458 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
9460 is_nvidia = ddraw_is_nvidia(ddraw);
9461 /* The Windows 8 WARP driver has plenty of false negatives in X8R8G8B8
9462 * (color key doesn't match although the values are equal), and a false
9463 * positive when the color key is 0 and the texture contains the value 1.
9464 * I don't want to mark this broken unconditionally since this would
9465 * essentially disable the test on Windows. Also on random occasions
9466 * 254 == 255 and 255 != 255.*/
9467 is_warp = ddraw_is_warp(ddraw);
9469 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
9470 viewport = create_viewport(device, 0, 0, 640, 480);
9471 viewport_set_background(device, viewport, green);
9473 memset(&exec_desc, 0, sizeof(exec_desc));
9474 exec_desc.dwSize = sizeof(exec_desc);
9475 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
9476 exec_desc.dwBufferSize = 1024;
9477 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
9478 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
9479 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
9481 memset(&fx, 0, sizeof(fx));
9482 fx.dwSize = sizeof(fx);
9483 memset(&lock_desc, 0, sizeof(lock_desc));
9484 lock_desc.dwSize = sizeof(lock_desc);
9486 for (t = 0; t < ARRAY_SIZE(tests); ++t)
9488 if (is_nvidia && tests[t].skip_nv)
9490 win_skip("Skipping test %s on Nvidia Windows drivers.\n", tests[t].name);
9491 continue;
9494 memset(&surface_desc, 0, sizeof(surface_desc));
9495 surface_desc.dwSize = sizeof(surface_desc);
9496 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
9497 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
9498 surface_desc.dwWidth = 4;
9499 surface_desc.dwHeight = 1;
9500 surface_desc.ddpfPixelFormat = tests[t].fmt;
9501 /* Windows XP (at least with the r200 driver, other drivers untested) produces
9502 * garbage when doing color keyed texture->texture blits. */
9503 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src, NULL);
9504 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9505 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst, NULL);
9506 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9508 U5(fx).dwFillColor = tests[t].clear;
9509 /* On the w8 testbot (WARP driver) the blit result has different values in the
9510 * X channel. */
9511 color_mask = U2(tests[t].fmt).dwRBitMask
9512 | U3(tests[t].fmt).dwGBitMask
9513 | U4(tests[t].fmt).dwBBitMask;
9515 for (c = 0; c <= tests[t].max; ++c)
9517 /* The idiotic Nvidia Windows driver can't change the color key on a d3d
9518 * texture after it has been set once... */
9519 surface_desc.dwFlags |= DDSD_CKSRCBLT;
9520 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
9521 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = c << tests[t].shift;
9522 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = c << tests[t].shift;
9523 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &texture, NULL);
9524 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9526 hr = IDirectDrawSurface_QueryInterface(texture, &IID_IDirect3DTexture, (void **)&d3d_texture);
9527 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
9528 hr = IDirect3DTexture_GetHandle(d3d_texture, device, &handle);
9529 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
9530 IDirect3DTexture_Release(d3d_texture);
9532 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
9533 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
9535 memcpy(exec_desc.lpData, quad, sizeof(quad));
9537 ptr = ((BYTE *)exec_desc.lpData) + sizeof(quad);
9538 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 8);
9539 emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
9540 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, handle);
9541 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA);
9542 /* D3DRENDERSTATE_COLORKEYENABLE is supposed to be on by default on version
9543 * 1 devices, but for some reason it randomly defaults to FALSE on the W8
9544 * testbot. This is either the fault of Windows 8 or the WARP driver.
9545 * Also D3DRENDERSTATE_COLORKEYENABLE was introduced in D3D 5 aka version 2
9546 * devices only, which might imply this doesn't actually do anything on
9547 * WARP. */
9548 emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
9550 emit_tquad(&ptr, 0);
9551 emit_tquad(&ptr, 4);
9552 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, 0);
9553 emit_end(&ptr);
9555 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
9556 inst_length -= sizeof(quad);
9557 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
9558 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
9559 set_execute_data(execute_buffer, 8, sizeof(quad), inst_length);
9561 hr = IDirectDrawSurface_Blt(dst, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
9562 ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#lx.\n", hr);
9564 hr = IDirectDrawSurface_Lock(src, NULL, &lock_desc, DDLOCK_WAIT, NULL);
9565 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
9566 switch (tests[t].bpp)
9568 case 4:
9569 ((DWORD *)lock_desc.lpSurface)[0] = (c ? c - 1 : 0) << tests[t].shift;
9570 ((DWORD *)lock_desc.lpSurface)[1] = c << tests[t].shift;
9571 ((DWORD *)lock_desc.lpSurface)[2] = min(c + 1, tests[t].max) << tests[t].shift;
9572 ((DWORD *)lock_desc.lpSurface)[3] = 0xffffffff;
9573 break;
9575 case 2:
9576 ((WORD *)lock_desc.lpSurface)[0] = (c ? c - 1 : 0) << tests[t].shift;
9577 ((WORD *)lock_desc.lpSurface)[1] = c << tests[t].shift;
9578 ((WORD *)lock_desc.lpSurface)[2] = min(c + 1, tests[t].max) << tests[t].shift;
9579 ((WORD *)lock_desc.lpSurface)[3] = 0xffff;
9580 break;
9582 hr = IDirectDrawSurface_Unlock(src, 0);
9583 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
9584 hr = IDirectDrawSurface_Blt(texture, NULL, src, NULL, DDBLT_WAIT, NULL);
9585 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
9587 ckey.dwColorSpaceLowValue = c << tests[t].shift;
9588 ckey.dwColorSpaceHighValue = c << tests[t].shift;
9589 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
9590 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
9592 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC | DDBLT_WAIT, NULL);
9593 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
9595 /* Don't make this read only, it somehow breaks the detection of the Nvidia bug below. */
9596 hr = IDirectDrawSurface_Lock(dst, NULL, &lock_desc, DDLOCK_WAIT, NULL);
9597 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
9598 switch (tests[t].bpp)
9600 case 4:
9601 data[0] = ((DWORD *)lock_desc.lpSurface)[0] & color_mask;
9602 data[1] = ((DWORD *)lock_desc.lpSurface)[1] & color_mask;
9603 data[2] = ((DWORD *)lock_desc.lpSurface)[2] & color_mask;
9604 data[3] = ((DWORD *)lock_desc.lpSurface)[3] & color_mask;
9605 break;
9607 case 2:
9608 data[0] = ((WORD *)lock_desc.lpSurface)[0] & color_mask;
9609 data[1] = ((WORD *)lock_desc.lpSurface)[1] & color_mask;
9610 data[2] = ((WORD *)lock_desc.lpSurface)[2] & color_mask;
9611 data[3] = ((WORD *)lock_desc.lpSurface)[3] & color_mask;
9612 break;
9614 hr = IDirectDrawSurface_Unlock(dst, 0);
9615 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
9617 if (!c)
9619 ok(data[0] == tests[t].clear, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
9620 tests[t].clear, data[0], tests[t].name, c);
9622 if (data[3] == tests[t].clear)
9624 /* My Geforce GTX 460 on Windows 7 misbehaves when A4R4G4B4 is blitted with color
9625 * keying: The blit takes ~0.5 seconds, and subsequent color keying draws are broken,
9626 * even when a different surface is used. The blit itself doesn't draw anything,
9627 * so we can detect the bug by looking at the otherwise unused 4th texel. It should
9628 * never be masked out by the key.
9630 * On Windows 10 the problem is worse, Blt just hangs. For this reason the ARGB4444
9631 * test is disabled entirely.
9633 * Also appears to affect the testbot in some way with R5G6B5. Color keying is
9634 * terrible on WARP. */
9635 skip("Nvidia A4R4G4B4 color keying blit bug detected, skipping.\n");
9636 IDirectDrawSurface_Release(texture);
9637 IDirectDrawSurface_Release(src);
9638 IDirectDrawSurface_Release(dst);
9639 goto done;
9642 else
9643 ok(data[0] == (c - 1) << tests[t].shift, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
9644 (c - 1) << tests[t].shift, data[0], tests[t].name, c);
9646 ok(data[1] == tests[t].clear, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
9647 tests[t].clear, data[1], tests[t].name, c);
9649 if (c == tests[t].max)
9650 ok(data[2] == tests[t].clear, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
9651 tests[t].clear, data[2], tests[t].name, c);
9652 else
9653 ok(data[2] == (c + 1) << tests[t].shift, "Expected surface content %#x, got %#x, format %s, c=%u.\n",
9654 (c + 1) << tests[t].shift, data[2], tests[t].name, c);
9656 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
9657 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
9659 hr = IDirect3DDevice_BeginScene(device);
9660 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
9661 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_UNCLIPPED);
9662 ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr);
9663 hr = IDirect3DDevice_EndScene(device);
9664 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
9666 color = get_surface_color(rt, 80, 240);
9667 if (!c)
9668 ok(compare_color(color, 0x0000ff00, 1) || broken(is_warp && compare_color(color, 0x00000000, 1)),
9669 "Got unexpected color 0x%08x, format %s, c=%u.\n",
9670 color, tests[t].name, c);
9671 else
9672 ok(compare_color(color, 0x00000000, 1) || broken(is_warp && compare_color(color, 0x0000ff00, 1)),
9673 "Got unexpected color 0x%08x, format %s, c=%u.\n",
9674 color, tests[t].name, c);
9676 color = get_surface_color(rt, 240, 240);
9677 ok(compare_color(color, 0x0000ff00, 1) || broken(is_warp && compare_color(color, 0x00000000, 1)),
9678 "Got unexpected color 0x%08x, format %s, c=%u.\n",
9679 color, tests[t].name, c);
9681 color = get_surface_color(rt, 400, 240);
9682 if (c == tests[t].max)
9683 ok(compare_color(color, 0x0000ff00, 1) || broken(is_warp && compare_color(color, 0x00000000, 1)),
9684 "Got unexpected color 0x%08x, format %s, c=%u.\n",
9685 color, tests[t].name, c);
9686 else
9687 ok(compare_color(color, 0x00000000, 1) || broken(is_warp && compare_color(color, 0x0000ff00, 1)),
9688 "Got unexpected color 0x%08x, format %s, c=%u.\n",
9689 color, tests[t].name, c);
9691 IDirectDrawSurface_Release(texture);
9693 IDirectDrawSurface_Release(src);
9694 IDirectDrawSurface_Release(dst);
9696 done:
9698 destroy_viewport(device, viewport);
9699 destroy_material(green);
9700 IDirectDrawSurface_Release(rt);
9701 IDirect3DExecuteBuffer_Release(execute_buffer);
9702 IDirect3DDevice_Release(device);
9703 refcount = IDirectDraw_Release(ddraw);
9704 ok(!refcount, "Unexpected refcount %lu.\n", refcount);
9705 DestroyWindow(window);
9708 static void test_range_colorkey(void)
9710 IDirectDraw *ddraw;
9711 HWND window;
9712 HRESULT hr;
9713 IDirectDrawSurface *surface;
9714 DDSURFACEDESC surface_desc;
9715 ULONG refcount;
9716 DDCOLORKEY ckey;
9718 window = create_window();
9719 ddraw = create_ddraw();
9720 ok(!!ddraw, "Failed to create a ddraw object.\n");
9721 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
9722 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
9724 memset(&surface_desc, 0, sizeof(surface_desc));
9725 surface_desc.dwSize = sizeof(surface_desc);
9726 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
9727 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
9728 surface_desc.dwWidth = 1;
9729 surface_desc.dwHeight = 1;
9730 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
9731 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
9732 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
9733 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
9734 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
9735 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0x00000000;
9737 /* Creating a surface with a range color key fails with DDERR_NOCOLORKEY. */
9738 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000000;
9739 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000001;
9740 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9741 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
9743 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000001;
9744 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000000;
9745 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9746 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
9748 /* Same for DDSCAPS_OFFSCREENPLAIN. */
9749 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
9750 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000000;
9751 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000001;
9752 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9753 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
9755 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000001;
9756 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000000;
9757 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9758 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
9760 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00000000;
9761 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00000000;
9762 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
9763 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
9765 /* Setting a range color key without DDCKEY_COLORSPACE collapses the key. */
9766 ckey.dwColorSpaceLowValue = 0x00000000;
9767 ckey.dwColorSpaceHighValue = 0x00000001;
9768 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9769 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
9771 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9772 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
9773 ok(!ckey.dwColorSpaceLowValue, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceLowValue);
9774 ok(!ckey.dwColorSpaceHighValue, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceHighValue);
9776 ckey.dwColorSpaceLowValue = 0x00000001;
9777 ckey.dwColorSpaceHighValue = 0x00000000;
9778 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9779 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
9781 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9782 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
9783 ok(ckey.dwColorSpaceLowValue == 0x00000001, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceLowValue);
9784 ok(ckey.dwColorSpaceHighValue == 0x00000001, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceHighValue);
9786 /* DDCKEY_COLORSPACE is ignored if the key is a single value. */
9787 ckey.dwColorSpaceLowValue = 0x00000000;
9788 ckey.dwColorSpaceHighValue = 0x00000000;
9789 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
9790 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
9792 /* Using it with a range key results in DDERR_NOCOLORKEYHW. */
9793 ckey.dwColorSpaceLowValue = 0x00000001;
9794 ckey.dwColorSpaceHighValue = 0x00000000;
9795 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
9796 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
9797 ckey.dwColorSpaceLowValue = 0x00000000;
9798 ckey.dwColorSpaceHighValue = 0x00000001;
9799 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
9800 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
9801 /* Range destination keys don't work either. */
9802 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_DESTBLT | DDCKEY_COLORSPACE, &ckey);
9803 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
9805 /* Just to show it's not because of A, R, and G having equal values. */
9806 ckey.dwColorSpaceLowValue = 0x00000000;
9807 ckey.dwColorSpaceHighValue = 0x01010101;
9808 hr = IDirectDrawSurface_SetColorKey(surface, DDCKEY_SRCBLT | DDCKEY_COLORSPACE, &ckey);
9809 ok(hr == DDERR_NOCOLORKEYHW, "Got unexpected hr %#lx.\n", hr);
9811 /* None of these operations modified the key. */
9812 hr = IDirectDrawSurface_GetColorKey(surface, DDCKEY_SRCBLT, &ckey);
9813 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
9814 ok(!ckey.dwColorSpaceLowValue, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceLowValue);
9815 ok(!ckey.dwColorSpaceHighValue, "Got unexpected value 0x%08lx.\n", ckey.dwColorSpaceHighValue);
9817 IDirectDrawSurface_Release(surface);
9818 refcount = IDirectDraw_Release(ddraw);
9819 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
9820 DestroyWindow(window);
9823 static void test_shademode(void)
9825 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
9826 unsigned int color0, color1, i, inst_length;
9827 IDirect3DExecuteBuffer *execute_buffer;
9828 D3DEXECUTEBUFFERDESC exec_desc;
9829 IDirect3DMaterial *background;
9830 IDirect3DViewport *viewport;
9831 IDirect3DDevice *device;
9832 IDirectDrawSurface *rt;
9833 const D3DLVERTEX *quad;
9834 IDirectDraw *ddraw;
9835 ULONG refcount;
9836 HWND window;
9837 HRESULT hr;
9838 void *ptr;
9839 static const D3DLVERTEX quad_strip[] =
9841 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xffff0000}},
9842 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
9843 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xff0000ff}},
9844 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xffffffff}},
9846 quad_list[] =
9848 {{ 1.0f}, {-1.0f}, {0.0f}, 0, {0xff0000ff}},
9849 {{-1.0f}, {-1.0f}, {0.0f}, 0, {0xffff0000}},
9850 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
9851 {{ 1.0f}, { 1.0f}, {0.0f}, 0, {0xffffffff}},
9853 static const struct
9855 DWORD primtype;
9856 DWORD shademode;
9857 unsigned int color0, color1;
9859 tests[] =
9861 {D3DPT_TRIANGLESTRIP, D3DSHADE_FLAT, 0x00ff0000, 0x000000ff},
9862 {D3DPT_TRIANGLESTRIP, D3DSHADE_PHONG, 0x000dca28, 0x000d45c7},
9863 {D3DPT_TRIANGLESTRIP, D3DSHADE_GOURAUD, 0x000dca28, 0x000d45c7},
9864 {D3DPT_TRIANGLESTRIP, D3DSHADE_PHONG, 0x000dca28, 0x000d45c7},
9865 {D3DPT_TRIANGLELIST, D3DSHADE_FLAT, 0x000000ff, 0x0000ff00},
9866 {D3DPT_TRIANGLELIST, D3DSHADE_GOURAUD, 0x000dca28, 0x000d45c7},
9869 window = create_window();
9870 ddraw = create_ddraw();
9871 ok(!!ddraw, "Failed to create a ddraw object.\n");
9872 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
9874 skip("Failed to create a 3D device, skipping test.\n");
9875 IDirectDraw_Release(ddraw);
9876 DestroyWindow(window);
9877 return;
9880 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
9881 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
9883 background = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
9884 viewport = create_viewport(device, 0, 0, 640, 480);
9885 viewport_set_background(device, viewport, background);
9887 memset(&exec_desc, 0, sizeof(exec_desc));
9888 exec_desc.dwSize = sizeof(exec_desc);
9889 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
9890 exec_desc.dwBufferSize = 1024;
9891 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
9893 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
9894 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
9896 /* Try it first with a TRIANGLESTRIP. Do it with different geometry because
9897 * the color fixups we have to do for FLAT shading will be dependent on that. */
9899 for (i = 0; i < ARRAY_SIZE(tests); ++i)
9901 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
9902 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
9904 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
9905 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
9907 quad = tests[i].primtype == D3DPT_TRIANGLESTRIP ? quad_strip : quad_list;
9908 memcpy(exec_desc.lpData, quad, sizeof(quad_strip));
9909 ptr = ((BYTE *)exec_desc.lpData) + sizeof(quad_strip);
9910 emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, FALSE);
9911 emit_set_rs(&ptr, D3DRENDERSTATE_FOGENABLE, FALSE);
9912 emit_set_rs(&ptr, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
9913 emit_set_rs(&ptr, D3DRENDERSTATE_SHADEMODE, tests[i].shademode);
9915 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORM, 0, 4);
9916 if (tests[i].primtype == D3DPT_TRIANGLESTRIP)
9917 emit_tquad(&ptr, 0);
9918 else
9919 emit_tquad_tlist(&ptr, 0);
9920 emit_end(&ptr);
9921 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
9922 inst_length -= sizeof(quad_strip);
9924 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
9925 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
9927 hr = IDirect3DDevice_BeginScene(device);
9928 set_execute_data(execute_buffer, 4, sizeof(quad_strip), inst_length);
9929 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
9930 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
9931 hr = IDirect3DDevice_EndScene(device);
9932 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
9934 color0 = get_surface_color(rt, 100, 100); /* Inside first triangle */
9935 color1 = get_surface_color(rt, 500, 350); /* Inside second triangle */
9937 /* For D3DSHADE_FLAT it should take the color of the first vertex of
9938 * each triangle. This requires EXT_provoking_vertex or similar
9939 * functionality being available. */
9940 /* PHONG should be the same as GOURAUD, since no hardware implements
9941 * this. */
9942 ok(compare_color(color0, tests[i].color0, 1), "Test %u shading has color0 %08x, expected %08x.\n",
9943 i, color0, tests[i].color0);
9944 ok(compare_color(color1, tests[i].color1, 1), "Test %u shading has color1 %08x, expected %08x.\n",
9945 i, color1, tests[i].color1);
9948 IDirect3DExecuteBuffer_Release(execute_buffer);
9949 destroy_viewport(device, viewport);
9950 destroy_material(background);
9951 IDirectDrawSurface_Release(rt);
9952 refcount = IDirect3DDevice_Release(device);
9953 ok(!refcount, "Device has %lu references left.\n", refcount);
9954 IDirectDraw_Release(ddraw);
9955 DestroyWindow(window);
9958 static void test_lockrect_invalid(void)
9960 unsigned int i, r;
9961 IDirectDraw *ddraw;
9962 IDirectDrawSurface *surface;
9963 HWND window;
9964 HRESULT hr;
9965 DDSURFACEDESC surface_desc;
9966 DDCAPS hal_caps;
9967 DWORD needed_caps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
9968 static RECT valid[] =
9970 {60, 60, 68, 68},
9971 {60, 60, 60, 68},
9972 {60, 60, 68, 60},
9973 {120, 60, 128, 68},
9974 {60, 120, 68, 128},
9976 static RECT invalid[] =
9978 {68, 60, 60, 68}, /* left > right */
9979 {60, 68, 68, 60}, /* top > bottom */
9980 {-8, 60, 0, 68}, /* left < surface */
9981 {60, -8, 68, 0}, /* top < surface */
9982 {-16, 60, -8, 68}, /* right < surface */
9983 {60, -16, 68, -8}, /* bottom < surface */
9984 {60, 60, 136, 68}, /* right > surface */
9985 {60, 60, 68, 136}, /* bottom > surface */
9986 {136, 60, 144, 68}, /* left > surface */
9987 {60, 136, 68, 144}, /* top > surface */
9989 static const struct
9991 DWORD caps;
9992 const char *name;
9993 HRESULT hr;
9995 resources[] =
9997 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY, "sysmem offscreenplain", DDERR_INVALIDPARAMS},
9998 {DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY, "vidmem offscreenplain", DDERR_INVALIDPARAMS},
9999 {DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY, "sysmem texture", DDERR_INVALIDPARAMS},
10000 {DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, "vidmem texture", DDERR_INVALIDPARAMS},
10003 window = create_window();
10004 ddraw = create_ddraw();
10005 ok(!!ddraw, "Failed to create a ddraw object.\n");
10006 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
10007 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
10009 memset(&hal_caps, 0, sizeof(hal_caps));
10010 hal_caps.dwSize = sizeof(hal_caps);
10011 hr = IDirectDraw_GetCaps(ddraw, &hal_caps, NULL);
10012 ok(SUCCEEDED(hr), "Failed to get caps, hr %#lx.\n", hr);
10013 if ((hal_caps.ddsCaps.dwCaps & needed_caps) != needed_caps)
10015 skip("Required surface types not supported, skipping test.\n");
10016 goto done;
10019 for (r = 0; r < ARRAY_SIZE(resources); ++r)
10021 memset(&surface_desc, 0, sizeof(surface_desc));
10022 surface_desc.dwSize = sizeof(surface_desc);
10023 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
10024 surface_desc.ddsCaps.dwCaps = resources[r].caps;
10025 surface_desc.dwWidth = 128;
10026 surface_desc.dwHeight = 128;
10027 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
10028 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
10029 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
10030 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xff0000;
10031 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x00ff00;
10032 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x0000ff;
10034 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
10035 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx, type %s.\n", hr, resources[r].name);
10037 hr = IDirectDrawSurface_Lock(surface, NULL, NULL, DDLOCK_WAIT, NULL);
10038 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx, type %s.\n", hr, resources[r].name);
10040 for (i = 0; i < ARRAY_SIZE(valid); ++i)
10042 RECT *rect = &valid[i];
10044 memset(&surface_desc, 0, sizeof(surface_desc));
10045 surface_desc.dwSize = sizeof(surface_desc);
10047 hr = IDirectDrawSurface_Lock(surface, rect, &surface_desc, DDLOCK_WAIT, NULL);
10048 ok(SUCCEEDED(hr), "Lock failed (%#lx) for rect %s, type %s.\n",
10049 hr, wine_dbgstr_rect(rect), resources[r].name);
10051 hr = IDirectDrawSurface_Unlock(surface, NULL);
10052 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, type %s.\n", hr, resources[r].name);
10055 for (i = 0; i < ARRAY_SIZE(invalid); ++i)
10057 RECT *rect = &invalid[i];
10059 memset(&surface_desc, 1, sizeof(surface_desc));
10060 surface_desc.dwSize = sizeof(surface_desc);
10062 hr = IDirectDrawSurface_Lock(surface, rect, &surface_desc, DDLOCK_WAIT, NULL);
10063 ok(hr == resources[r].hr, "Lock returned %#lx for rect %s, type %s.\n",
10064 hr, wine_dbgstr_rect(rect), resources[r].name);
10065 if (SUCCEEDED(hr))
10067 hr = IDirectDrawSurface_Unlock(surface, NULL);
10068 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, type %s.\n", hr, resources[r].name);
10070 else
10071 ok(!surface_desc.lpSurface, "Got unexpected lpSurface %p.\n", surface_desc.lpSurface);
10074 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
10075 ok(SUCCEEDED(hr), "Lock(rect = NULL) failed, hr %#lx, type %s.\n",
10076 hr, resources[r].name);
10077 hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
10078 ok(hr == DDERR_SURFACEBUSY, "Double lock(rect = NULL) returned %#lx, type %s.\n",
10079 hr, resources[r].name);
10080 hr = IDirectDrawSurface_Unlock(surface, NULL);
10081 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, type %s.\n", hr, resources[r].name);
10083 hr = IDirectDrawSurface_Lock(surface, &valid[0], &surface_desc, DDLOCK_WAIT, NULL);
10084 ok(SUCCEEDED(hr), "Lock(rect = %s) failed (%#lx).\n", wine_dbgstr_rect(&valid[0]), hr);
10085 hr = IDirectDrawSurface_Lock(surface, &valid[0], &surface_desc, DDLOCK_WAIT, NULL);
10086 ok(hr == DDERR_SURFACEBUSY, "Double lock(rect = %s) failed (%#lx).\n",
10087 wine_dbgstr_rect(&valid[0]), hr);
10089 /* Locking a different rectangle returns DD_OK, but it seems to break the surface.
10090 * Afterwards unlocking the surface fails(NULL rectangle or both locked rectangles) */
10092 hr = IDirectDrawSurface_Unlock(surface, NULL);
10093 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx, type %s.\n", hr, resources[r].name);
10095 IDirectDrawSurface_Release(surface);
10098 done:
10099 IDirectDraw_Release(ddraw);
10100 DestroyWindow(window);
10103 static void test_yv12_overlay(void)
10105 IDirectDrawSurface *src_surface, *dst_surface;
10106 RECT rect = {13, 17, 14, 18};
10107 unsigned int offset, y;
10108 unsigned char *base;
10109 DDSURFACEDESC desc;
10110 IDirectDraw *ddraw;
10111 HWND window;
10112 HRESULT hr;
10114 window = create_window();
10115 ddraw = create_ddraw();
10116 ok(!!ddraw, "Failed to create a ddraw object.\n");
10117 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
10118 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
10120 if (!(src_surface = create_overlay(ddraw, 256, 256, MAKEFOURCC('Y','V','1','2'))))
10122 skip("Failed to create a YV12 overlay, skipping test.\n");
10123 goto done;
10126 memset(&desc, 0, sizeof(desc));
10127 desc.dwSize = sizeof(desc);
10128 hr = IDirectDrawSurface_Lock(src_surface, NULL, &desc, DDLOCK_WAIT, NULL);
10129 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
10131 ok(desc.dwFlags == (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH),
10132 "Got unexpected flags %#lx.\n", desc.dwFlags);
10133 ok(desc.ddsCaps.dwCaps == (DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_HWCODEC)
10134 || desc.ddsCaps.dwCaps == (DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM),
10135 "Got unexpected caps %#lx.\n", desc.ddsCaps.dwCaps);
10136 ok(desc.dwWidth == 256, "Got unexpected width %lu.\n", desc.dwWidth);
10137 ok(desc.dwHeight == 256, "Got unexpected height %lu.\n", desc.dwHeight);
10138 /* The overlay pitch seems to have 256 byte alignment. */
10139 ok(!(U1(desc).lPitch & 0xff), "Got unexpected pitch %lu.\n", U1(desc).lPitch);
10141 /* Fill the surface with some data for the blit test. */
10142 base = desc.lpSurface;
10143 /* Luminance */
10144 for (y = 0; y < desc.dwHeight; ++y)
10146 memset(base + U1(desc).lPitch * y, 0x10, desc.dwWidth);
10148 /* V */
10149 for (; y < desc.dwHeight + desc.dwHeight / 4; ++y)
10151 memset(base + U1(desc).lPitch * y, 0x20, desc.dwWidth);
10153 /* U */
10154 for (; y < desc.dwHeight + desc.dwHeight / 2; ++y)
10156 memset(base + U1(desc).lPitch * y, 0x30, desc.dwWidth);
10159 hr = IDirectDrawSurface_Unlock(src_surface, NULL);
10160 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
10162 /* YV12 uses 2x2 blocks with 6 bytes per block (4*Y, 1*U, 1*V). Unlike
10163 * other block-based formats like DXT the entire Y channel is stored in
10164 * one big chunk of memory, followed by the chroma channels. So partial
10165 * locks do not really make sense. Show that they are allowed nevertheless
10166 * and the offset points into the luminance data. */
10167 hr = IDirectDrawSurface_Lock(src_surface, &rect, &desc, DDLOCK_WAIT, NULL);
10168 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
10169 offset = ((const unsigned char *)desc.lpSurface - base);
10170 ok(offset == rect.top * U1(desc).lPitch + rect.left, "Got unexpected offset %u, expected %lu.\n",
10171 offset, rect.top * U1(desc).lPitch + rect.left);
10172 hr = IDirectDrawSurface_Unlock(src_surface, NULL);
10173 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
10175 if (!(dst_surface = create_overlay(ddraw, 256, 256, MAKEFOURCC('Y','V','1','2'))))
10177 /* Windows XP with a Radeon X1600 GPU refuses to create a second
10178 * overlay surface, DDERR_NOOVERLAYHW, making the blit tests moot. */
10179 skip("Failed to create a second YV12 surface, skipping blit test.\n");
10180 IDirectDrawSurface_Release(src_surface);
10181 goto done;
10184 hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, NULL, DDBLT_WAIT, NULL);
10185 /* VMware rejects YV12 blits. This behavior has not been seen on real
10186 * hardware yet, so mark it broken. */
10187 ok(SUCCEEDED(hr) || broken(hr == E_NOTIMPL), "Failed to blit, hr %#lx.\n", hr);
10189 if (SUCCEEDED(hr))
10191 memset(&desc, 0, sizeof(desc));
10192 desc.dwSize = sizeof(desc);
10193 hr = IDirectDrawSurface_Lock(dst_surface, NULL, &desc, DDLOCK_WAIT, NULL);
10194 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
10196 base = desc.lpSurface;
10197 ok(base[0] == 0x10, "Got unexpected Y data 0x%02x.\n", base[0]);
10198 base += desc.dwHeight * U1(desc).lPitch;
10199 ok(base[0] == 0x20, "Got unexpected V data 0x%02x.\n", base[0]);
10200 base += desc.dwHeight / 4 * U1(desc).lPitch;
10201 ok(base[0] == 0x30, "Got unexpected U data 0x%02x.\n", base[0]);
10203 hr = IDirectDrawSurface_Unlock(dst_surface, NULL);
10204 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
10207 IDirectDrawSurface_Release(dst_surface);
10208 IDirectDrawSurface_Release(src_surface);
10209 done:
10210 IDirectDraw_Release(ddraw);
10211 DestroyWindow(window);
10214 static BOOL dwm_enabled(void)
10216 BOOL ret = FALSE;
10218 if (!strcmp(winetest_platform, "wine"))
10219 return FALSE;
10220 if (!pDwmIsCompositionEnabled)
10221 return FALSE;
10222 if (FAILED(pDwmIsCompositionEnabled(&ret)))
10223 return FALSE;
10224 return ret;
10227 static void test_offscreen_overlay(void)
10229 IDirectDrawSurface *overlay, *offscreen, *primary;
10230 DDSURFACEDESC surface_desc;
10231 IDirectDraw *ddraw;
10232 HWND window;
10233 HRESULT hr;
10234 HDC dc;
10236 window = create_window();
10237 ddraw = create_ddraw();
10238 ok(!!ddraw, "Failed to create a ddraw object.\n");
10239 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
10240 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
10242 if (!(overlay = create_overlay(ddraw, 64, 64, MAKEFOURCC('U','Y','V','Y'))))
10244 skip("Failed to create a UYVY overlay, skipping test.\n");
10245 goto done;
10248 memset(&surface_desc, 0, sizeof(surface_desc));
10249 surface_desc.dwSize = sizeof(surface_desc);
10250 surface_desc.dwFlags = DDSD_CAPS;
10251 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
10252 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &primary, NULL);
10253 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
10255 /* On Windows 7, and probably Vista, UpdateOverlay() will return
10256 * DDERR_OUTOFCAPS if the dwm is active. Calling GetDC() on the primary
10257 * surface prevents this by disabling the dwm. */
10258 hr = IDirectDrawSurface_GetDC(primary, &dc);
10259 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
10260 hr = IDirectDrawSurface_ReleaseDC(primary, dc);
10261 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
10263 /* Try to overlay a NULL surface. */
10264 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, NULL, NULL, DDOVER_SHOW, NULL);
10265 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10266 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, NULL, NULL, DDOVER_HIDE, NULL);
10267 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10269 /* Try to overlay an offscreen surface. */
10270 memset(&surface_desc, 0, sizeof(surface_desc));
10271 surface_desc.dwSize = sizeof(surface_desc);
10272 surface_desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
10273 surface_desc.dwWidth = 64;
10274 surface_desc.dwHeight = 64;
10275 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
10276 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
10277 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
10278 surface_desc.ddpfPixelFormat.dwFourCC = 0;
10279 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 16;
10280 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xf800;
10281 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x07e0;
10282 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x001f;
10283 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &offscreen, NULL);
10284 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
10286 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, offscreen, NULL, DDOVER_SHOW, NULL);
10287 ok(SUCCEEDED(hr) || broken(hr == DDERR_OUTOFCAPS && dwm_enabled())
10288 || broken(hr == E_NOTIMPL && ddraw_is_vmware(ddraw)),
10289 "Failed to update overlay, hr %#lx.\n", hr);
10291 /* Try to overlay the primary with a non-overlay surface. */
10292 hr = IDirectDrawSurface_UpdateOverlay(offscreen, NULL, primary, NULL, DDOVER_SHOW, NULL);
10293 ok(hr == DDERR_NOTAOVERLAYSURFACE, "Got unexpected hr %#lx.\n", hr);
10294 hr = IDirectDrawSurface_UpdateOverlay(offscreen, NULL, primary, NULL, DDOVER_HIDE, NULL);
10295 ok(hr == DDERR_NOTAOVERLAYSURFACE, "Got unexpected hr %#lx.\n", hr);
10297 IDirectDrawSurface_Release(offscreen);
10298 IDirectDrawSurface_Release(primary);
10299 IDirectDrawSurface_Release(overlay);
10300 done:
10301 IDirectDraw_Release(ddraw);
10302 DestroyWindow(window);
10305 static void test_overlay_rect(void)
10307 IDirectDrawSurface *overlay, *primary = NULL;
10308 DDSURFACEDESC surface_desc;
10309 RECT rect = {0, 0, 64, 64};
10310 IDirectDraw *ddraw;
10311 LONG pos_x, pos_y;
10312 HRESULT hr, hr2;
10313 HWND window;
10314 HDC dc;
10316 window = create_window();
10317 ddraw = create_ddraw();
10318 ok(!!ddraw, "Failed to create a ddraw object.\n");
10319 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
10320 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
10322 if (!(overlay = create_overlay(ddraw, 64, 64, MAKEFOURCC('U','Y','V','Y'))))
10324 skip("Failed to create a UYVY overlay, skipping test.\n");
10325 goto done;
10328 memset(&surface_desc, 0, sizeof(surface_desc));
10329 surface_desc.dwSize = sizeof(surface_desc);
10330 surface_desc.dwFlags = DDSD_CAPS;
10331 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
10332 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &primary, NULL);
10333 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n",hr);
10335 /* On Windows 7, and probably Vista, UpdateOverlay() will return
10336 * DDERR_OUTOFCAPS if the dwm is active. Calling GetDC() on the primary
10337 * surface prevents this by disabling the dwm. */
10338 hr = IDirectDrawSurface_GetDC(primary, &dc);
10339 ok(SUCCEEDED(hr), "Failed to get DC, hr %#lx.\n", hr);
10340 hr = IDirectDrawSurface_ReleaseDC(primary, dc);
10341 ok(SUCCEEDED(hr), "Failed to release DC, hr %#lx.\n", hr);
10343 /* On Windows 8 and newer DWM can't be turned off, making overlays unusable. */
10344 if (dwm_enabled())
10346 win_skip("Cannot disable DWM, skipping overlay test.\n");
10347 goto done;
10350 /* The dx sdk sort of implies that rect must be set when DDOVER_SHOW is
10351 * used. This is not true in Windows Vista and earlier, but changed in
10352 * Windows 7. */
10353 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, &rect, DDOVER_SHOW, NULL);
10354 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#lx.\n", hr);
10355 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, NULL, DDOVER_HIDE, NULL);
10356 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#lx.\n", hr);
10357 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, NULL, DDOVER_SHOW, NULL);
10358 ok(hr == DD_OK || hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
10360 /* Show that the overlay position is the (top, left) coordinate of the
10361 * destination rectangle. */
10362 OffsetRect(&rect, 32, 16);
10363 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, &rect, DDOVER_SHOW, NULL);
10364 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#lx.\n", hr);
10365 pos_x = -1; pos_y = -1;
10366 hr = IDirectDrawSurface_GetOverlayPosition(overlay, &pos_x, &pos_y);
10367 ok(SUCCEEDED(hr), "Failed to get overlay position, hr %#lx.\n", hr);
10368 ok(pos_x == rect.left, "Got unexpected pos_x %ld, expected %ld.\n", pos_x, rect.left);
10369 ok(pos_y == rect.top, "Got unexpected pos_y %ld, expected %ld.\n", pos_y, rect.top);
10371 /* Passing a NULL dest rect sets the position to 0/0. Visually it can be
10372 * seen that the overlay overlays the whole primary(==screen). */
10373 hr2 = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, NULL, 0, NULL);
10374 ok(hr2 == DD_OK || hr2 == DDERR_INVALIDPARAMS || hr2 == DDERR_OUTOFCAPS, "Got unexpected hr %#lx.\n", hr2);
10375 hr = IDirectDrawSurface_GetOverlayPosition(overlay, &pos_x, &pos_y);
10376 ok(SUCCEEDED(hr), "Failed to get overlay position, hr %#lx.\n", hr);
10377 if (SUCCEEDED(hr2))
10379 ok(!pos_x, "Got unexpected pos_x %ld.\n", pos_x);
10380 ok(!pos_y, "Got unexpected pos_y %ld.\n", pos_y);
10382 else
10384 ok(pos_x == 32, "Got unexpected pos_x %ld.\n", pos_x);
10385 ok(pos_y == 16, "Got unexpected pos_y %ld.\n", pos_y);
10388 /* The position cannot be retrieved when the overlay is not shown. */
10389 hr = IDirectDrawSurface_UpdateOverlay(overlay, NULL, primary, &rect, DDOVER_HIDE, NULL);
10390 ok(SUCCEEDED(hr), "Failed to update overlay, hr %#lx.\n", hr);
10391 pos_x = -1; pos_y = -1;
10392 hr = IDirectDrawSurface_GetOverlayPosition(overlay, &pos_x, &pos_y);
10393 ok(hr == DDERR_OVERLAYNOTVISIBLE, "Got unexpected hr %#lx.\n", hr);
10394 ok(!pos_x, "Got unexpected pos_x %ld.\n", pos_x);
10395 ok(!pos_y, "Got unexpected pos_y %ld.\n", pos_y);
10397 done:
10398 if (primary)
10399 IDirectDrawSurface_Release(primary);
10400 if (overlay)
10401 IDirectDrawSurface_Release(overlay);
10402 IDirectDraw_Release(ddraw);
10403 DestroyWindow(window);
10406 static void test_blt(void)
10408 IDirectDrawSurface *surface, *rt;
10409 DDSURFACEDESC surface_desc;
10410 IDirect3DDevice *device;
10411 IDirectDraw *ddraw;
10412 unsigned int i;
10413 ULONG refcount;
10414 HWND window;
10415 HRESULT hr;
10417 static struct
10419 RECT src_rect;
10420 RECT dst_rect;
10421 HRESULT hr;
10423 test_data[] =
10425 {{160, 0, 640, 480}, { 0, 0, 480, 480}, DD_OK}, /* Overlapped blit. */
10426 {{160, 480, 640, 0}, { 0, 0, 480, 480}, DDERR_INVALIDRECT}, /* Overlapped blit, flipped source. */
10427 {{640, 0, 160, 480}, { 0, 0, 480, 480}, DDERR_INVALIDRECT}, /* Overlapped blit, mirrored source. */
10428 {{160, 0, 480, 480}, { 0, 0, 480, 480}, DD_OK}, /* Overlapped blit, stretched x. */
10429 {{160, 160, 640, 480}, { 0, 0, 480, 480}, DD_OK}, /* Overlapped blit, stretched y. */
10430 {{ 0, 0, 640, 480}, { 0, 0, 640, 480}, DD_OK}, /* Full surface blit. */
10431 {{ 0, 0, 640, 480}, { 0, 480, 640, 0}, DDERR_INVALIDRECT}, /* Full surface, flipped destination. */
10432 {{ 0, 0, 640, 480}, {640, 0, 0, 480}, DDERR_INVALIDRECT}, /* Full surface, mirrored destination. */
10433 {{ 0, 480, 640, 0}, { 0, 0, 640, 480}, DDERR_INVALIDRECT}, /* Full surface, flipped source. */
10434 {{640, 0, 0, 480}, { 0, 0, 640, 480}, DDERR_INVALIDRECT}, /* Full surface, mirrored source. */
10437 window = create_window();
10438 ddraw = create_ddraw();
10439 ok(!!ddraw, "Failed to create a ddraw object.\n");
10440 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
10442 skip("Failed to create a 3D device, skipping test.\n");
10443 IDirectDraw_Release(ddraw);
10444 DestroyWindow(window);
10445 return;
10448 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
10449 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
10451 memset(&surface_desc, 0, sizeof(surface_desc));
10452 surface_desc.dwSize = sizeof(surface_desc);
10453 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
10454 surface_desc.dwWidth = 640;
10455 surface_desc.dwHeight = 480;
10456 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
10457 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
10458 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10460 hr = IDirectDrawSurface_Blt(surface, NULL, surface, NULL, 0, NULL);
10461 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
10463 hr = IDirectDrawSurface_Blt(surface, NULL, rt, NULL, 0, NULL);
10464 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
10466 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
10468 hr = IDirectDrawSurface_Blt(surface, &test_data[i].dst_rect,
10469 surface, &test_data[i].src_rect, DDBLT_WAIT, NULL);
10470 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#lx, expected %#lx.\n", i, hr, test_data[i].hr);
10472 hr = IDirectDrawSurface_Blt(surface, &test_data[i].dst_rect,
10473 rt, &test_data[i].src_rect, DDBLT_WAIT, NULL);
10474 ok(hr == test_data[i].hr, "Test %u: Got unexpected hr %#lx, expected %#lx.\n", i, hr, test_data[i].hr);
10476 hr = IDirectDrawSurface_Blt(surface, &test_data[i].dst_rect,
10477 NULL, &test_data[i].src_rect, DDBLT_WAIT, NULL);
10478 ok(hr == DDERR_INVALIDPARAMS, "Test %u: Got unexpected hr %#lx.\n", i, hr);
10480 hr = IDirectDrawSurface_Blt(surface, &test_data[i].dst_rect, NULL, NULL, DDBLT_WAIT, NULL);
10481 ok(hr == DDERR_INVALIDPARAMS, "Test %u: Got unexpected hr %#lx.\n", i, hr);
10484 IDirectDrawSurface_Release(surface);
10485 IDirectDrawSurface_Release(rt);
10486 refcount = IDirect3DDevice_Release(device);
10487 ok(!refcount, "Device has %lu references left.\n", refcount);
10488 IDirectDraw_Release(ddraw);
10489 DestroyWindow(window);
10492 static void test_blt_z_alpha(void)
10494 DWORD blt_flags[] =
10496 /* 0 */
10497 DDBLT_ALPHADEST,
10498 DDBLT_ALPHADESTCONSTOVERRIDE,
10499 DDBLT_ALPHADESTNEG,
10500 DDBLT_ALPHADESTSURFACEOVERRIDE,
10501 DDBLT_ALPHAEDGEBLEND,
10502 /* 5 */
10503 DDBLT_ALPHASRC,
10504 DDBLT_ALPHASRCCONSTOVERRIDE,
10505 DDBLT_ALPHASRCNEG,
10506 DDBLT_ALPHASRCSURFACEOVERRIDE,
10507 DDBLT_ZBUFFER,
10508 /* 10 */
10509 DDBLT_ZBUFFERDESTCONSTOVERRIDE,
10510 DDBLT_ZBUFFERDESTOVERRIDE,
10511 DDBLT_ZBUFFERSRCCONSTOVERRIDE,
10512 DDBLT_ZBUFFERSRCOVERRIDE,
10514 IDirectDrawSurface *src_surface, *dst_surface;
10515 DDSURFACEDESC surface_desc;
10516 unsigned int color, i;
10517 IDirectDraw *ddraw;
10518 DDPIXELFORMAT pf;
10519 ULONG refcount;
10520 HWND window;
10521 HRESULT hr;
10522 DDBLTFX fx;
10524 window = create_window();
10525 ddraw = create_ddraw();
10526 ok(!!ddraw, "Failed to create a ddraw object.\n");
10527 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
10528 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
10530 memset(&pf, 0, sizeof(pf));
10531 pf.dwSize = sizeof(pf);
10532 pf.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
10533 U1(pf).dwRGBBitCount = 32;
10534 U2(pf).dwRBitMask = 0x00ff0000;
10535 U3(pf).dwGBitMask = 0x0000ff00;
10536 U4(pf).dwBBitMask = 0x000000ff;
10537 U5(pf).dwRGBAlphaBitMask = 0xff000000;
10539 memset(&surface_desc, 0, sizeof(surface_desc));
10540 surface_desc.dwSize = sizeof(surface_desc);
10541 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
10542 surface_desc.dwWidth = 64;
10543 surface_desc.dwHeight = 64;
10544 surface_desc.ddpfPixelFormat = pf;
10545 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
10547 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
10548 ok(SUCCEEDED(hr), "Failed to create source surface, hr %#lx.\n", hr);
10549 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
10550 ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#lx.\n", hr);
10552 memset(&fx, 0, sizeof(fx));
10553 fx.dwSize = sizeof(fx);
10554 fx.dwZBufferOpCode = D3DCMP_NEVER;
10555 fx.dwZDestConstBitDepth = 32;
10556 U1(fx).dwZDestConst = 0x11111111;
10557 fx.dwZSrcConstBitDepth = 32;
10558 U2(fx).dwZSrcConst = 0xeeeeeeee;
10559 fx.dwAlphaEdgeBlendBitDepth = 8;
10560 fx.dwAlphaEdgeBlend = 0x7f;
10561 fx.dwAlphaDestConstBitDepth = 8;
10562 U3(fx).dwAlphaDestConst = 0xdd;
10563 fx.dwAlphaSrcConstBitDepth = 8;
10564 U4(fx).dwAlphaSrcConst = 0x22;
10566 for (i = 0; i < ARRAY_SIZE(blt_flags); ++i)
10568 U5(fx).dwFillColor = 0x3300ff00;
10569 hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10570 ok(SUCCEEDED(hr), "Test %u: Got unexpected hr %#lx.\n", i, hr);
10572 U5(fx).dwFillColor = 0xccff0000;
10573 hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10574 ok(SUCCEEDED(hr), "Test %u: Got unexpected hr %#lx.\n", i, hr);
10576 hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, NULL, blt_flags[i] | DDBLT_WAIT, &fx);
10577 ok(SUCCEEDED(hr), "Test %u: Got unexpected hr %#lx.\n", i, hr);
10579 color = get_surface_color(dst_surface, 32, 32);
10580 ok(compare_color(color, 0x0000ff00, 0), "Test %u: Got unexpected color 0x%08x.\n", i, color);
10583 IDirectDrawSurface_Release(dst_surface);
10584 IDirectDrawSurface_Release(src_surface);
10585 refcount = IDirectDraw_Release(ddraw);
10586 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
10587 DestroyWindow(window);
10590 static void test_cross_device_blt(void)
10592 IDirectDrawSurface *surface, *surface2, *sysmem_surface;
10593 IDirect3DDevice *device, *device2;
10594 IDirectDraw *ddraw, *ddraw2;
10595 DDSURFACEDESC surface_desc;
10596 HWND window, window2;
10597 unsigned int color;
10598 ULONG refcount;
10599 DDBLTFX fx;
10600 HRESULT hr;
10602 window = create_window();
10603 ddraw = create_ddraw();
10604 if (!(device = create_device(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN)))
10606 skip("Failed to create a 3D device.\n");
10607 IDirectDraw_Release(ddraw);
10608 DestroyWindow(window);
10609 return;
10612 window2 = create_window();
10613 ddraw2 = create_ddraw();
10614 if (!(device2 = create_device(ddraw2, window2, DDSCL_NORMAL)))
10616 skip("Failed to create a 3D device.\n");
10617 IDirectDraw_Release(ddraw2);
10618 IDirect3DDevice_Release(device);
10619 IDirectDraw_Release(ddraw);
10620 DestroyWindow(window);
10621 DestroyWindow(window2);
10622 return;
10625 memset(&surface_desc, 0, sizeof(surface_desc));
10626 surface_desc.dwSize = sizeof(surface_desc);
10627 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
10628 surface_desc.dwWidth = 640;
10629 surface_desc.dwHeight = 480;
10630 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
10631 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &sysmem_surface, NULL);
10632 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10634 memset(&surface_desc, 0, sizeof(surface_desc));
10635 surface_desc.dwSize = sizeof(surface_desc);
10636 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
10637 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_VIDEOMEMORY;
10638 surface_desc.dwBackBufferCount = 2;
10639 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
10640 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10642 memset(&surface_desc, 0, sizeof(surface_desc));
10643 surface_desc.dwSize = sizeof(surface_desc);
10644 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
10645 surface_desc.dwWidth = 640;
10646 surface_desc.dwHeight = 480;
10647 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
10648 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
10649 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
10650 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 16;
10651 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00007c00;
10652 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x000003e0;
10653 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x0000001f;
10654 hr = IDirectDraw_CreateSurface(ddraw2, &surface_desc, &surface2, NULL);
10655 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10657 memset(&fx, 0, sizeof(fx));
10658 fx.dwSize = sizeof(fx);
10659 U5(fx).dwFillColor = 0xff0000ff;
10660 hr = IDirectDrawSurface_Blt(surface2, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10661 ok(SUCCEEDED(hr), "Failed to fill surface, hr %#lx.\n", hr);
10663 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_WAIT, NULL);
10664 ok(hr == E_NOTIMPL, "Got unexpected hr %#lx.\n", hr);
10665 hr = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
10666 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
10667 hr = IDirectDrawSurface_Blt(surface, NULL, surface2, NULL, DDBLT_WAIT, NULL);
10668 ok(hr == E_NOTIMPL, "Got unexpected hr %#lx.\n", hr);
10669 color = get_surface_color(surface, 320, 240);
10670 ok(color == 0x00000000, "Got unexpected color 0x%08x.\n", color);
10672 hr = IDirectDrawSurface_Blt(sysmem_surface, NULL, surface2, NULL, DDBLT_WAIT, NULL);
10673 ok(hr == E_NOTIMPL, "Got unexpected hr %#lx.\n", hr);
10674 color = get_surface_color(sysmem_surface, 320, 240);
10675 ok(color == 0x00000000, "Got unexpected color 0x%08x.\n", color);
10677 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
10678 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
10679 hr = IDirectDrawSurface_IsLost(sysmem_surface);
10680 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
10682 hr = IDirectDrawSurface_Blt(sysmem_surface, NULL, surface2, NULL, DDBLT_WAIT, NULL);
10683 ok(hr == E_NOTIMPL, "Got unexpected hr %#lx.\n", hr);
10684 color = get_surface_color(sysmem_surface, 320, 240);
10685 ok(color == 0x00000000, "Got unexpected color 0x%08x.\n", color);
10687 IDirectDrawSurface_Release(surface2);
10688 memset(&surface_desc, 0, sizeof(surface_desc));
10689 surface_desc.dwSize = sizeof(surface_desc);
10690 surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
10691 surface_desc.dwWidth = 640;
10692 surface_desc.dwHeight = 480;
10693 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
10694 hr = IDirectDraw_CreateSurface(ddraw2, &surface_desc, &surface2, NULL);
10695 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
10696 hr = IDirectDrawSurface_Blt(surface2, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
10697 ok(SUCCEEDED(hr), "Failed to fill surface, hr %#lx.\n", hr);
10699 hr = IDirectDrawSurface_Blt(sysmem_surface, NULL, surface2, NULL, DDBLT_WAIT, NULL);
10700 todo_wine ok(hr == D3D_OK, "Failed to blit, hr %#lx.\n", hr);
10701 color = get_surface_color(sysmem_surface, 320, 240);
10702 todo_wine ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
10704 IDirectDrawSurface_Release(surface);
10705 IDirectDrawSurface_Release(surface2);
10706 IDirectDrawSurface_Release(sysmem_surface);
10707 refcount = IDirect3DDevice_Release(device);
10708 ok(!refcount, "Device has %lu references left.\n", refcount);
10709 refcount = IDirect3DDevice_Release(device2);
10710 ok(!refcount, "Device has %lu references left.\n", refcount);
10711 IDirectDraw_Release(ddraw);
10712 IDirectDraw_Release(ddraw2);
10713 DestroyWindow(window);
10714 DestroyWindow(window2);
10717 static void test_getdc(void)
10719 IDirectDrawSurface *surface, *surface2, *tmp;
10720 DDSURFACEDESC surface_desc, map_desc;
10721 DDSCAPS caps = {DDSCAPS_COMPLEX};
10722 IDirectDraw *ddraw;
10723 unsigned int i, screen_bpp;
10724 HWND window;
10725 HDC dc, dc2;
10726 HRESULT hr;
10728 static const struct
10730 const char *name;
10731 DDPIXELFORMAT format;
10732 BOOL getdc_supported;
10733 HRESULT alt_result;
10735 test_data[] =
10737 {"D3DFMT_A8R8G8B8", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {32},
10738 {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}}, TRUE},
10739 {"D3DFMT_X8R8G8B8", {sizeof(test_data->format), DDPF_RGB, 0, {32},
10740 {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0x00000000}}, TRUE},
10741 {"D3DFMT_R5G6B5", {sizeof(test_data->format), DDPF_RGB, 0, {16},
10742 {0x0000f800}, {0x000007e0}, {0x0000001f}, {0x00000000}}, TRUE},
10743 {"D3DFMT_X1R5G5B5", {sizeof(test_data->format), DDPF_RGB, 0, {16},
10744 {0x00007c00}, {0x000003e0}, {0x0000001f}, {0x00000000}}, TRUE},
10745 {"D3DFMT_A1R5G5B5", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {16},
10746 {0x00007c00}, {0x000003e0}, {0x0000001f}, {0x00008000}}, TRUE},
10747 {"D3DFMT_A4R4G4B4", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {16},
10748 {0x00000f00}, {0x000000f0}, {0x0000000f}, {0x0000f000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
10749 {"D3DFMT_X4R4G4B4", {sizeof(test_data->format), DDPF_RGB, 0, {16},
10750 {0x00000f00}, {0x000000f0}, {0x0000000f}, {0x00000000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
10751 {"D3DFMT_A2R10G10B10", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {32},
10752 {0xc0000000}, {0x3ff00000}, {0x000ffc00}, {0x000003ff}}, TRUE},
10753 {"D3DFMT_A8B8G8R8", {sizeof(test_data->format), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {32},
10754 {0x000000ff}, {0x0000ff00}, {0x00ff0000}, {0xff000000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
10755 {"D3DFMT_X8B8G8R8", {sizeof(test_data->format), DDPF_RGB, 0, {32},
10756 {0x000000ff}, {0x0000ff00}, {0x00ff0000}, {0x00000000}}, TRUE, DDERR_CANTCREATEDC /* Vista+ */},
10757 {"D3DFMT_R3G3B2", {sizeof(test_data->format), DDPF_RGB, 0, {8},
10758 {0x000000e0}, {0x0000001c}, {0x00000003}, {0x00000000}}, FALSE},
10759 /* GetDC() on a P8 surface fails unless the display mode is 8 bpp.
10760 * This is not implemented in wine yet, so disable the test for now.
10761 * Succeeding P8 GetDC() calls are tested in the ddraw:visual test.
10762 {"D3DFMT_P8", {sizeof(test_data->format), DDPF_PALETTEINDEXED8 | DDPF_RGB, 0, {8 },
10763 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
10765 {"D3DFMT_L8", {sizeof(test_data->format), DDPF_LUMINANCE, 0, {8},
10766 {0x000000ff}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
10767 {"D3DFMT_A8L8", {sizeof(test_data->format), DDPF_ALPHAPIXELS | DDPF_LUMINANCE, 0, {16},
10768 {0x000000ff}, {0x00000000}, {0x00000000}, {0x0000ff00}}, FALSE},
10769 {"D3DFMT_DXT1", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','1'), {0},
10770 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
10771 {"D3DFMT_DXT2", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','2'), {0},
10772 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
10773 {"D3DFMT_DXT3", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','3'), {0},
10774 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
10775 {"D3DFMT_DXT4", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','4'), {0},
10776 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
10777 {"D3DFMT_DXT5", {sizeof(test_data->format), DDPF_FOURCC, MAKEFOURCC('D','X','T','5'), {0},
10778 {0x00000000}, {0x00000000}, {0x00000000}, {0x00000000}}, FALSE},
10781 window = create_window();
10782 ddraw = create_ddraw();
10783 ok(!!ddraw, "Failed to create a ddraw object.\n");
10784 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
10785 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
10787 surface_desc.dwSize = sizeof(surface_desc);
10788 hr = IDirectDraw_GetDisplayMode(ddraw, &surface_desc);
10789 ok(SUCCEEDED(hr), "Failed to get display mode, hr %#lx.\n", hr);
10790 screen_bpp = U1(surface_desc.ddpfPixelFormat).dwRGBBitCount;
10792 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
10794 memset(&surface_desc, 0, sizeof(surface_desc));
10795 surface_desc.dwSize = sizeof(surface_desc);
10796 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
10797 surface_desc.dwWidth = 64;
10798 surface_desc.dwHeight = 64;
10799 surface_desc.ddpfPixelFormat = test_data[i].format;
10800 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
10802 if (FAILED(IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
10804 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
10805 if (FAILED(hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
10807 skip("Failed to create surface for format %s (hr %#lx), skipping tests.\n", test_data[i].name, hr);
10808 continue;
10812 dc = (void *)0x1234;
10813 hr = IDirectDrawSurface_GetDC(surface, &dc);
10814 if (test_data[i].getdc_supported)
10815 ok(SUCCEEDED(hr) || broken(hr == test_data[i].alt_result || ddraw_is_vmware(ddraw)),
10816 "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
10817 else
10818 ok(FAILED(hr), "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
10820 if (SUCCEEDED(hr))
10822 unsigned int width_bytes;
10823 DIBSECTION dib;
10824 HBITMAP bitmap;
10825 DWORD type;
10826 int size;
10828 type = GetObjectType(dc);
10829 ok(type == OBJ_MEMDC, "Got unexpected object type %#lx for format %s.\n", type, test_data[i].name);
10830 bitmap = GetCurrentObject(dc, OBJ_BITMAP);
10831 type = GetObjectType(bitmap);
10832 ok(type == OBJ_BITMAP, "Got unexpected object type %#lx for format %s.\n", type, test_data[i].name);
10834 size = GetObjectA(bitmap, sizeof(dib), &dib);
10835 ok(size == sizeof(dib), "Got unexpected size %d for format %s.\n", size, test_data[i].name);
10836 ok(!dib.dsBm.bmType, "Got unexpected type %#x for format %s.\n",
10837 dib.dsBm.bmType, test_data[i].name);
10838 ok(dib.dsBm.bmWidth == surface_desc.dwWidth, "Got unexpected width %d for format %s.\n",
10839 dib.dsBm.bmWidth, test_data[i].name);
10840 ok(dib.dsBm.bmHeight == surface_desc.dwHeight, "Got unexpected height %d for format %s.\n",
10841 dib.dsBm.bmHeight, test_data[i].name);
10842 width_bytes = ((dib.dsBm.bmWidth * U1(test_data[i].format).dwRGBBitCount + 31) >> 3) & ~3;
10843 ok(dib.dsBm.bmWidthBytes == width_bytes, "Got unexpected width bytes %d for format %s.\n",
10844 dib.dsBm.bmWidthBytes, test_data[i].name);
10845 ok(dib.dsBm.bmPlanes == 1, "Got unexpected plane count %d for format %s.\n",
10846 dib.dsBm.bmPlanes, test_data[i].name);
10847 ok(dib.dsBm.bmBitsPixel == U1(test_data[i].format).dwRGBBitCount,
10848 "Got unexpected bit count %d for format %s.\n",
10849 dib.dsBm.bmBitsPixel, test_data[i].name);
10850 /* Windows XP sets bmBits == NULL for formats that match the screen at least on my r200 GPU. I
10851 * suspect this applies to all HW accelerated pre-WDDM drivers because they can handle gdi access
10852 * to ddraw surfaces themselves instead of going through a sysmem DIB section. */
10853 ok(!!dib.dsBm.bmBits || broken(!pDwmIsCompositionEnabled && dib.dsBm.bmBitsPixel == screen_bpp),
10854 "Got unexpected bits %p for format %s.\n", dib.dsBm.bmBits, test_data[i].name);
10856 ok(dib.dsBmih.biSize == sizeof(dib.dsBmih), "Got unexpected size %lu for format %s.\n",
10857 dib.dsBmih.biSize, test_data[i].name);
10858 ok(dib.dsBmih.biWidth == surface_desc.dwWidth, "Got unexpected width %ld for format %s.\n",
10859 dib.dsBmih.biHeight, test_data[i].name);
10860 ok(dib.dsBmih.biHeight == surface_desc.dwHeight, "Got unexpected height %ld for format %s.\n",
10861 dib.dsBmih.biHeight, test_data[i].name);
10862 ok(dib.dsBmih.biPlanes == 1, "Got unexpected plane count %u for format %s.\n",
10863 dib.dsBmih.biPlanes, test_data[i].name);
10864 ok(dib.dsBmih.biBitCount == U1(test_data[i].format).dwRGBBitCount,
10865 "Got unexpected bit count %u for format %s.\n",
10866 dib.dsBmih.biBitCount, test_data[i].name);
10867 ok(dib.dsBmih.biCompression == (U1(test_data[i].format).dwRGBBitCount == 16 ? BI_BITFIELDS : BI_RGB)
10868 || broken(U1(test_data[i].format).dwRGBBitCount == 32 && dib.dsBmih.biCompression == BI_BITFIELDS),
10869 "Got unexpected compression %#lx for format %s.\n",
10870 dib.dsBmih.biCompression, test_data[i].name);
10871 ok(!dib.dsBmih.biSizeImage, "Got unexpected image size %lu for format %s.\n",
10872 dib.dsBmih.biSizeImage, test_data[i].name);
10873 ok(!dib.dsBmih.biXPelsPerMeter, "Got unexpected horizontal resolution %ld for format %s.\n",
10874 dib.dsBmih.biXPelsPerMeter, test_data[i].name);
10875 ok(!dib.dsBmih.biYPelsPerMeter, "Got unexpected vertical resolution %ld for format %s.\n",
10876 dib.dsBmih.biYPelsPerMeter, test_data[i].name);
10877 ok(!dib.dsBmih.biClrUsed, "Got unexpected used colour count %lu for format %s.\n",
10878 dib.dsBmih.biClrUsed, test_data[i].name);
10879 ok(!dib.dsBmih.biClrImportant, "Got unexpected important colour count %lu for format %s.\n",
10880 dib.dsBmih.biClrImportant, test_data[i].name);
10882 if (dib.dsBmih.biCompression == BI_BITFIELDS)
10884 ok((dib.dsBitfields[0] == U2(test_data[i].format).dwRBitMask
10885 && dib.dsBitfields[1] == U3(test_data[i].format).dwGBitMask
10886 && dib.dsBitfields[2] == U4(test_data[i].format).dwBBitMask)
10887 || broken(!dib.dsBitfields[0] && !dib.dsBitfields[1] && !dib.dsBitfields[2]),
10888 "Got unexpected colour masks 0x%08lx 0x%08lx 0x%08lx for format %s.\n",
10889 dib.dsBitfields[0], dib.dsBitfields[1], dib.dsBitfields[2], test_data[i].name);
10891 else
10893 ok(!dib.dsBitfields[0] && !dib.dsBitfields[1] && !dib.dsBitfields[2],
10894 "Got unexpected colour masks 0x%08lx 0x%08lx 0x%08lx for format %s.\n",
10895 dib.dsBitfields[0], dib.dsBitfields[1], dib.dsBitfields[2], test_data[i].name);
10897 ok(!dib.dshSection, "Got unexpected section %p for format %s.\n", dib.dshSection, test_data[i].name);
10898 ok(!dib.dsOffset, "Got unexpected offset %lu for format %s.\n", dib.dsOffset, test_data[i].name);
10900 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10901 ok(hr == DD_OK, "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10903 else
10905 ok(!dc, "Got unexpected dc %p for format %s.\n", dc, test_data[i].name);
10908 IDirectDrawSurface_Release(surface);
10910 if (FAILED(hr))
10911 continue;
10913 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
10914 if (FAILED(hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
10916 skip("Failed to create mip-mapped texture for format %s (hr %#lx), skipping tests.\n",
10917 test_data[i].name, hr);
10918 continue;
10921 hr = IDirectDrawSurface_GetAttachedSurface(surface, &caps, &tmp);
10922 ok(SUCCEEDED(hr), "Failed to get attached surface for format %s, hr %#lx.\n", test_data[i].name, hr);
10923 hr = IDirectDrawSurface_GetAttachedSurface(tmp, &caps, &surface2);
10924 ok(SUCCEEDED(hr), "Failed to get attached surface for format %s, hr %#lx.\n", test_data[i].name, hr);
10925 IDirectDrawSurface_Release(tmp);
10927 hr = IDirectDrawSurface_GetDC(surface, &dc);
10928 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10929 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10930 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10931 hr = IDirectDrawSurface_GetDC(surface2, &dc);
10932 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10933 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
10934 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10936 hr = IDirectDrawSurface_GetDC(surface, &dc);
10937 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10938 dc2 = (void *)0x1234;
10939 hr = IDirectDrawSurface_GetDC(surface, &dc2);
10940 ok(hr == DDERR_DCALREADYCREATED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
10941 ok(dc2 == (void *)0x1234, "Got unexpected dc %p for format %s.\n", dc, test_data[i].name);
10942 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10943 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10944 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10945 ok(hr == DDERR_NODC, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
10947 map_desc.dwSize = sizeof(map_desc);
10948 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10949 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
10950 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10951 ok(hr == DDERR_SURFACEBUSY, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
10952 hr = IDirectDrawSurface_Unlock(surface, NULL);
10953 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
10954 hr = IDirectDrawSurface_Unlock(surface, NULL);
10955 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
10957 hr = IDirectDrawSurface_GetDC(surface, &dc);
10958 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10959 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10960 ok(hr == DDERR_SURFACEBUSY, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
10961 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10962 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10964 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10965 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
10966 hr = IDirectDrawSurface_GetDC(surface, &dc);
10967 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10968 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10969 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10970 /* Geforce 9600, Windows 7 returns E_FAIL. The unlock still seems to work as intended, after-
10971 * wards the surface can be locked again. ReleaseDC() does not unlock the surface, trying to
10972 * Lock it after ReleaseDC returns DDERR_SURFACEBUSY. ddraw4 and 7 are unaffected. */
10973 hr = IDirectDrawSurface_Unlock(surface, NULL);
10974 ok(SUCCEEDED(hr) || broken(ddraw_is_nvidia(ddraw) && hr == E_FAIL),
10975 "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
10977 hr = IDirectDrawSurface_GetDC(surface, &dc);
10978 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10979 hr = IDirectDrawSurface_GetDC(surface2, &dc2);
10980 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10981 hr = IDirectDrawSurface_ReleaseDC(surface2, dc2);
10982 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10983 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
10984 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10986 hr = IDirectDrawSurface_GetDC(surface2, &dc);
10987 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10988 hr = IDirectDrawSurface_GetDC(surface, &dc2);
10989 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10990 hr = IDirectDrawSurface_ReleaseDC(surface, dc2);
10991 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10992 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
10993 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
10995 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10996 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
10997 hr = IDirectDrawSurface_Lock(surface2, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
10998 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
10999 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11000 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11001 hr = IDirectDrawSurface_Unlock(surface, NULL);
11002 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11004 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11005 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11006 hr = IDirectDrawSurface_GetDC(surface, &dc);
11007 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11008 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11009 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11010 hr = IDirectDrawSurface_Unlock(surface, NULL);
11011 ok(SUCCEEDED(hr) || broken(ddraw_is_nvidia(ddraw) && hr == E_FAIL),
11012 "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11014 hr = IDirectDrawSurface_Lock(surface2, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11015 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11016 hr = IDirectDrawSurface_GetDC(surface, &dc);
11017 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11018 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11019 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11020 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11021 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11023 hr = IDirectDrawSurface_GetDC(surface, &dc);
11024 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11025 hr = IDirectDrawSurface_Lock(surface2, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11026 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11027 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11028 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11029 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11030 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11032 hr = IDirectDrawSurface_GetDC(surface2, &dc);
11033 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11034 hr = IDirectDrawSurface_Lock(surface, NULL, &map_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
11035 ok(SUCCEEDED(hr), "Failed to map surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11036 hr = IDirectDrawSurface_Unlock(surface, NULL);
11037 ok(SUCCEEDED(hr), "Failed to unmap surface for format %s, hr %#lx.\n", test_data[i].name, hr);
11038 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
11039 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11041 hr = IDirectDrawSurface_Unlock(surface, NULL);
11042 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11043 hr = IDirectDrawSurface_GetDC(surface2, &dc);
11044 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11045 hr = IDirectDrawSurface_Unlock(surface, NULL);
11046 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11047 hr = IDirectDrawSurface_ReleaseDC(surface2, dc);
11048 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11049 hr = IDirectDrawSurface_Unlock(surface, NULL);
11050 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11052 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11053 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11054 hr = IDirectDrawSurface_GetDC(surface, &dc);
11055 ok(SUCCEEDED(hr), "Failed to get DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11056 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11057 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11058 hr = IDirectDrawSurface_ReleaseDC(surface, dc);
11059 ok(SUCCEEDED(hr), "Failed to release DC for format %s, hr %#lx.\n", test_data[i].name, hr);
11060 hr = IDirectDrawSurface_Unlock(surface2, NULL);
11061 ok(hr == DDERR_NOTLOCKED, "Got unexpected hr %#lx for format %s.\n", hr, test_data[i].name);
11063 IDirectDrawSurface_Release(surface2);
11064 IDirectDrawSurface_Release(surface);
11067 IDirectDraw_Release(ddraw);
11068 DestroyWindow(window);
11071 /* TransformVertices always writes 32 bytes regardless of the input / output stride.
11072 * The stride is honored for navigating to the next vertex. 3 floats input position
11073 * are read, and 16 bytes extra vertex data are copied around. */
11074 struct transform_input
11076 float x, y, z, unused1; /* Position data, transformed. */
11077 DWORD v1, v2, v3, v4; /* Extra data, e.g. color and texture coords, copied. */
11078 DWORD unused2;
11081 struct transform_output
11083 float x, y, z, w;
11084 unsigned int v1, v2, v3, v4;
11085 unsigned int unused3, unused4;
11088 static void test_transform_vertices(void)
11090 unsigned int inst_length, color;
11091 IDirect3DDevice *device;
11092 IDirectDrawSurface *rt;
11093 IDirectDraw *ddraw;
11094 ULONG refcount;
11095 HWND window;
11096 HRESULT hr;
11097 IDirect3DViewport *viewport;
11098 IDirect3DExecuteBuffer *execute_buffer;
11099 IDirect3DMaterial *background;
11100 D3DEXECUTEBUFFERDESC exec_desc;
11101 void *ptr;
11102 D3DMATRIXHANDLE world_handle, view_handle, proj_handle;
11103 static struct transform_input position_tests[] =
11105 { 0.0f, 0.0f, 0.0f, 0.0f, 1, 2, 3, 4, 5},
11106 { 1.0f, 1.0f, 1.0f, 8.0f, 6, 7, 8, 9, 10},
11107 {-1.0f, -1.0f, -1.0f, 4.0f, 11, 12, 13, 14, 15},
11108 { 0.5f, 0.5f, 0.5f, 2.0f, 16, 17, 18, 19, 20},
11109 {-0.5f, -0.5f, -0.5f, 1.0f, ~1U, ~2U, ~3U, ~4U, ~5U},
11110 {-0.5f, -0.5f, 0.0f, 0.0f, ~6U, ~7U, ~8U, ~9U, ~0U},
11112 static struct transform_input cliptest[] =
11114 { 25.59f, 25.59f, 1.0f, 0.0f, 1, 2, 3, 4, 5},
11115 { 25.61f, 25.61f, 1.01f, 0.0f, 1, 2, 3, 4, 5},
11116 {-25.59f, -25.59f, 0.0f, 0.0f, 1, 2, 3, 4, 5},
11117 {-25.61f, -25.61f, -0.01f, 0.0f, 1, 2, 3, 4, 5},
11119 static struct transform_input offscreentest[] =
11121 {128.1f, 0.0f, 0.0f, 0.0f, 1, 2, 3, 4, 5},
11123 struct transform_output out[ARRAY_SIZE(position_tests)];
11124 D3DHVERTEX out_h[ARRAY_SIZE(position_tests)];
11125 D3DTRANSFORMDATA transformdata;
11126 static const D3DVIEWPORT vp_template =
11128 sizeof(vp_template), 0, 0, 256, 256, 5.0f, 5.0f, 256.0f, 256.0f, -25.0f, 60.0f
11130 D3DVIEWPORT vp_data =
11132 sizeof(vp_data), 0, 0, 256, 256, 1.0f, 1.0f, 256.0f, 256.0f, 0.0f, 1.0f
11134 unsigned int i;
11135 DWORD offscreen;
11136 static D3DMATRIX mat_scale =
11138 2.0f, 0.0f, 0.0f, 0.0f,
11139 0.0f, 2.0f, 0.0f, 0.0f,
11140 0.0f, 0.0f, 2.0f, 0.0f,
11141 0.0f, 0.0f, 0.0f, 1.0f,
11143 mat_translate1 =
11145 1.0f, 0.0f, 0.0f, 0.0f,
11146 0.0f, 1.0f, 0.0f, 0.0f,
11147 0.0f, 0.0f, 1.0f, 0.0f,
11148 1.0f, 0.0f, 0.0f, 1.0f,
11150 mat_translate2 =
11152 1.0f, 0.0f, 0.0f, 0.0f,
11153 0.0f, 1.0f, 0.0f, 0.0f,
11154 0.0f, 0.0f, 1.0f, 0.0f,
11155 0.0f, 1.0f, 0.0f, 1.0f,
11157 static const D3DLVERTEX quad[] =
11159 {{-0.75f},{-0.5f }, {0.0f}, 0, {0xffff0000}},
11160 {{-0.75f},{ 0.25f}, {0.0f}, 0, {0xffff0000}},
11161 {{ 0.5f}, {-0.5f }, {0.0f}, 0, {0xffff0000}},
11162 {{ 0.5f}, { 0.25f}, {0.0f}, 0, {0xffff0000}},
11164 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
11167 for (i = 0; i < ARRAY_SIZE(out); ++i)
11169 out[i].unused3 = 0xdeadbeef;
11170 out[i].unused4 = 0xcafecafe;
11173 window = create_window();
11174 ddraw = create_ddraw();
11175 ok(!!ddraw, "Failed to create a ddraw object.\n");
11176 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
11178 skip("Failed to create a 3D device, skipping test.\n");
11179 IDirectDraw_Release(ddraw);
11180 DestroyWindow(window);
11181 return;
11184 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
11185 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
11187 viewport = create_viewport(device, 0, 0, 256, 256);
11188 hr = IDirect3DViewport_SetViewport(viewport, &vp_data);
11189 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
11191 memset(&transformdata, 0, sizeof(transformdata));
11192 transformdata.dwSize = sizeof(transformdata);
11193 transformdata.lpIn = position_tests;
11194 transformdata.dwInSize = sizeof(position_tests[0]);
11195 transformdata.lpOut = out;
11196 transformdata.dwOutSize = sizeof(out[0]);
11197 transformdata.lpHOut = NULL;
11199 hr = IDirect3DViewport_TransformVertices(viewport, ARRAY_SIZE(position_tests),
11200 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
11201 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11202 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11204 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
11206 static const struct vec4 cmp[] =
11208 {128.0f, 128.0f, 0.0f, 1.0f}, {129.0f, 127.0f, 1.0f, 1.0f}, {127.0f, 129.0f, -1.0f, 1.0f},
11209 {128.5f, 127.5f, 0.5f, 1.0f}, {127.5f, 128.5f, -0.5f, 1.0f}, {127.5f, 128.5f, 0.0f, 1.0f}
11212 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
11213 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
11214 out[i].x, out[i].y, out[i].z, out[i].w);
11215 ok(out[i].v1 == position_tests[i].v1 && out[i].v2 == position_tests[i].v2
11216 && out[i].v3 == position_tests[i].v3 && out[i].v4 == position_tests[i].v4,
11217 "Vertex %u payload is %u %u %u %u.\n", i, out[i].v1, out[i].v2, out[i].v3, out[i].v4);
11218 ok(out[i].unused3 == 0xdeadbeef && out[i].unused4 == 0xcafecafe,
11219 "Vertex %u unused data is %#x, %#x.\n", i, out[i].unused3, out[i].unused4);
11222 vp_data = vp_template;
11223 hr = IDirect3DViewport_SetViewport(viewport, &vp_data);
11224 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
11225 offscreen = 0xdeadbeef;
11226 hr = IDirect3DViewport_TransformVertices(viewport, ARRAY_SIZE(position_tests),
11227 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
11228 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11229 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11231 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
11233 static const struct vec4 cmp[] =
11235 {128.0f, 128.0f, 0.0f, 1.0f}, {133.0f, 123.0f, 1.0f, 1.0f}, {123.0f, 133.0f, -1.0f, 1.0f},
11236 {130.5f, 125.5f, 0.5f, 1.0f}, {125.5f, 130.5f, -0.5f, 1.0f}, {125.5f, 130.5f, 0.0f, 1.0f}
11238 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
11239 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
11240 out[i].x, out[i].y, out[i].z, out[i].w);
11243 vp_data.dwX = 10;
11244 vp_data.dwY = 20;
11245 hr = IDirect3DViewport_SetViewport(viewport, &vp_data);
11246 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
11247 offscreen = 0xdeadbeef;
11248 hr = IDirect3DViewport_TransformVertices(viewport, ARRAY_SIZE(position_tests),
11249 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
11250 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11251 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11252 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
11254 static const struct vec4 cmp[] =
11256 {138.0f, 148.0f, 0.0f, 1.0f}, {143.0f, 143.0f, 1.0f, 1.0f}, {133.0f, 153.0f, -1.0f, 1.0f},
11257 {140.5f, 145.5f, 0.5f, 1.0f}, {135.5f, 150.5f, -0.5f, 1.0f}, {135.5f, 150.5f, 0.0f, 1.0f}
11259 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
11260 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
11261 out[i].x, out[i].y, out[i].z, out[i].w);
11264 transformdata.lpHOut = out_h;
11265 offscreen = 0xdeadbeef;
11266 hr = IDirect3DViewport_TransformVertices(viewport, ARRAY_SIZE(position_tests),
11267 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11268 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11269 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11270 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
11272 static const D3DHVERTEX cmp_h[] =
11274 {0, { 0.0f}, { 0.0f}, { 0.0f}}, {0, { 1.0f}, { 1.0f}, {1.0f}},
11275 {D3DCLIP_FRONT, {-1.0f}, {-1.0f}, {-1.0f}}, {0, { 0.5f}, { 0.5f}, {0.5f}},
11276 {D3DCLIP_FRONT, {-0.5f}, {-0.5f}, {-0.5f}}, {0, {-0.5f}, {-0.5f}, {0.0f}}
11278 ok(compare_float(U1(cmp_h[i]).hx, U1(out_h[i]).hx, 4096)
11279 && compare_float(U2(cmp_h[i]).hy, U2(out_h[i]).hy, 4096)
11280 && compare_float(U3(cmp_h[i]).hz, U3(out_h[i]).hz, 4096)
11281 && cmp_h[i].dwFlags == out_h[i].dwFlags,
11282 "HVertex %u differs. Got %#lx %.8e %.8e %.8e.\n", i,
11283 out_h[i].dwFlags, U1(out_h[i]).hx, U2(out_h[i]).hy, U3(out_h[i]).hz);
11285 /* No scheme has been found behind those return values. It seems to be
11286 * whatever data windows has when throwing the vertex away. Modify the
11287 * input test vertices to test this more. Depending on the input data
11288 * it can happen that the z coord gets written into y, or similar things. */
11289 if (0)
11291 static const struct vec4 cmp[] =
11293 {138.0f, 148.0f, 0.0f, 1.0f}, {143.0f, 143.0f, 1.0f, 1.0f}, { -1.0f, -1.0f, 0.5f, 1.0f},
11294 {140.5f, 145.5f, 0.5f, 1.0f}, { -0.5f, -0.5f, -0.5f, 1.0f}, {135.5f, 150.5f, 0.0f, 1.0f}
11296 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
11297 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
11298 out[i].x, out[i].y, out[i].z, out[i].w);
11302 transformdata.lpIn = cliptest;
11303 transformdata.dwInSize = sizeof(cliptest[0]);
11304 offscreen = 0xdeadbeef;
11305 hr = IDirect3DViewport_TransformVertices(viewport, ARRAY_SIZE(cliptest),
11306 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11307 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11308 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11309 for (i = 0; i < ARRAY_SIZE(cliptest); ++i)
11311 static const DWORD flags[] =
11314 D3DCLIP_RIGHT | D3DCLIP_BACK | D3DCLIP_TOP,
11316 D3DCLIP_LEFT | D3DCLIP_BOTTOM | D3DCLIP_FRONT,
11318 ok(flags[i] == out_h[i].dwFlags, "Cliptest %u returned %#lx.\n", i, out_h[i].dwFlags);
11321 vp_data = vp_template;
11322 vp_data.dwWidth = 10;
11323 vp_data.dwHeight = 1000;
11324 hr = IDirect3DViewport_SetViewport(viewport, &vp_data);
11325 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
11326 offscreen = 0xdeadbeef;
11327 hr = IDirect3DViewport_TransformVertices(viewport, ARRAY_SIZE(cliptest),
11328 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11329 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11330 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11331 for (i = 0; i < ARRAY_SIZE(cliptest); ++i)
11333 static const DWORD flags[] =
11335 D3DCLIP_RIGHT,
11336 D3DCLIP_RIGHT | D3DCLIP_BACK,
11337 D3DCLIP_LEFT,
11338 D3DCLIP_LEFT | D3DCLIP_FRONT,
11340 ok(flags[i] == out_h[i].dwFlags, "Cliptest %u returned %#lx.\n", i, out_h[i].dwFlags);
11343 vp_data = vp_template;
11344 vp_data.dwWidth = 256;
11345 vp_data.dwHeight = 256;
11346 vp_data.dvScaleX = 1;
11347 vp_data.dvScaleY = 1;
11348 hr = IDirect3DViewport_SetViewport(viewport, &vp_data);
11349 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
11350 hr = IDirect3DViewport_TransformVertices(viewport, ARRAY_SIZE(cliptest),
11351 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11352 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11353 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11354 for (i = 0; i < ARRAY_SIZE(cliptest); ++i)
11356 static const DWORD flags[] =
11359 D3DCLIP_BACK,
11361 D3DCLIP_FRONT,
11363 ok(flags[i] == out_h[i].dwFlags, "Cliptest %u returned %#lx.\n", i, out_h[i].dwFlags);
11366 /* Finally try to figure out how the DWORD dwOffscreen works.
11367 * It is a logical AND of the vertices' dwFlags members. */
11368 vp_data = vp_template;
11369 vp_data.dwWidth = 5;
11370 vp_data.dwHeight = 5;
11371 vp_data.dvScaleX = 10000.0f;
11372 vp_data.dvScaleY = 10000.0f;
11373 hr = IDirect3DViewport_SetViewport(viewport, &vp_data);
11374 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
11375 transformdata.lpIn = cliptest;
11376 offscreen = 0xdeadbeef;
11377 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11378 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
11379 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11380 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11382 offscreen = 0xdeadbeef;
11383 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11384 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11385 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11386 ok(offscreen == (D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %#lx.\n", offscreen);
11387 offscreen = 0xdeadbeef;
11388 hr = IDirect3DViewport_TransformVertices(viewport, 2,
11389 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11390 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11391 ok(offscreen == (D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %#lx.\n", offscreen);
11392 hr = IDirect3DViewport_TransformVertices(viewport, 3,
11393 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11394 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11395 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11397 transformdata.lpIn = cliptest + 1;
11398 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11399 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11400 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11401 ok(offscreen == (D3DCLIP_BACK | D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %#lx.\n", offscreen);
11403 transformdata.lpIn = cliptest + 2;
11404 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11405 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11406 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11407 ok(offscreen == (D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %#lx.\n", offscreen);
11408 offscreen = 0xdeadbeef;
11409 hr = IDirect3DViewport_TransformVertices(viewport, 2,
11410 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11411 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11412 ok(offscreen == (D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %#lx.\n", offscreen);
11414 transformdata.lpIn = cliptest + 3;
11415 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11416 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11417 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11418 ok(offscreen == (D3DCLIP_FRONT | D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %#lx.\n", offscreen);
11420 transformdata.lpIn = offscreentest;
11421 transformdata.dwInSize = sizeof(offscreentest[0]);
11422 vp_data = vp_template;
11423 vp_data.dwWidth = 257;
11424 vp_data.dwHeight = 257;
11425 vp_data.dvScaleX = 1.0f;
11426 vp_data.dvScaleY = 1.0f;
11427 hr = IDirect3DViewport_SetViewport(viewport, &vp_data);
11428 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
11429 offscreen = 0xdeadbeef;
11430 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11431 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11432 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11433 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11435 vp_data.dwWidth = 256;
11436 vp_data.dwHeight = 256;
11437 hr = IDirect3DViewport_SetViewport(viewport, &vp_data);
11438 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
11439 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11440 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11441 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11442 ok(offscreen == D3DCLIP_RIGHT, "Offscreen is %#lx.\n", offscreen);
11444 /* Test the effect of Matrices.
11446 * Basically the x coordinate ends up as ((x + 1) * 2 + 0) * 5 and
11447 * y as ((y + 0) * 2 + 1) * 5. The 5 comes from dvScaleX/Y, 2 from
11448 * the view matrix and the +1's from the world and projection matrix. */
11449 vp_data.dwX = 0;
11450 vp_data.dwY = 0;
11451 vp_data.dwWidth = 256;
11452 vp_data.dwHeight = 256;
11453 vp_data.dvScaleX = 5.0f;
11454 vp_data.dvScaleY = 5.0f;
11455 vp_data.dvMinZ = 0.0f;
11456 vp_data.dvMaxZ = 1.0f;
11457 hr = IDirect3DViewport_SetViewport(viewport, &vp_data);
11458 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
11460 hr = IDirect3DDevice_CreateMatrix(device, &world_handle);
11461 ok(hr == D3D_OK, "Creating a matrix object failed, hr %#lx.\n", hr);
11462 hr = IDirect3DDevice_SetMatrix(device, world_handle, &mat_translate1);
11463 ok(hr == D3D_OK, "Setting a matrix object failed, hr %#lx.\n", hr);
11465 hr = IDirect3DDevice_CreateMatrix(device, &view_handle);
11466 ok(hr == D3D_OK, "Creating a matrix object failed, hr %#lx.\n", hr);
11467 hr = IDirect3DDevice_SetMatrix(device, view_handle, &mat_scale);
11468 ok(hr == D3D_OK, "Setting a matrix object failed, hr %#lx.\n", hr);
11470 hr = IDirect3DDevice_CreateMatrix(device, &proj_handle);
11471 ok(hr == D3D_OK, "Creating a matrix object failed, hr %#lx.\n", hr);
11472 hr = IDirect3DDevice_SetMatrix(device, proj_handle, &mat_translate2);
11473 ok(hr == D3D_OK, "Setting a matrix object failed, hr %#lx.\n", hr);
11475 memset(&exec_desc, 0, sizeof(exec_desc));
11476 exec_desc.dwSize = sizeof(exec_desc);
11477 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
11478 exec_desc.dwBufferSize = 1024;
11479 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
11480 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
11481 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
11483 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
11484 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
11485 ptr = (BYTE *)exec_desc.lpData;
11486 emit_set_ts(&ptr, D3DTRANSFORMSTATE_WORLD, world_handle);
11487 emit_set_ts(&ptr, D3DTRANSFORMSTATE_VIEW, view_handle);
11488 emit_set_ts(&ptr, D3DTRANSFORMSTATE_PROJECTION, proj_handle);
11489 emit_end(&ptr);
11490 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
11491 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
11492 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
11494 set_execute_data(execute_buffer, 0, 0, inst_length);
11495 hr = IDirect3DDevice_BeginScene(device);
11496 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
11497 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
11498 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
11499 hr = IDirect3DDevice_EndScene(device);
11500 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
11502 transformdata.lpIn = position_tests;
11503 transformdata.dwInSize = sizeof(position_tests[0]);
11504 hr = IDirect3DViewport_TransformVertices(viewport, ARRAY_SIZE(position_tests),
11505 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
11506 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11508 for (i = 0; i < ARRAY_SIZE(position_tests); ++i)
11510 static const struct vec4 cmp[] =
11512 {138.0f, 123.0f, 0.0f, 1.0f}, {148.0f, 113.0f, 2.0f, 1.0f}, {128.0f, 133.0f, -2.0f, 1.0f},
11513 {143.0f, 118.0f, 1.0f, 1.0f}, {133.0f, 128.0f, -1.0f, 1.0f}, {133.0f, 128.0f, 0.0f, 1.0f}
11516 ok(compare_vec4(&cmp[i], out[i].x, out[i].y, out[i].z, out[i].w, 4096),
11517 "Vertex %u differs. Got %.8e %.8e %.8e %.8e.\n", i,
11518 out[i].x, out[i].y, out[i].z, out[i].w);
11521 /* Invalid flags. */
11522 offscreen = 0xdeadbeef;
11523 hr = IDirect3DViewport_TransformVertices(viewport, ARRAY_SIZE(position_tests),
11524 &transformdata, 0, &offscreen);
11525 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
11526 ok(offscreen == 0xdeadbeef, "Offscreen is %#lx.\n", offscreen);
11528 /* NULL transform data. */
11529 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11530 NULL, D3DTRANSFORM_UNCLIPPED, &offscreen);
11531 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
11532 ok(offscreen == 0xdeadbeef, "Offscreen is %#lx.\n", offscreen);
11533 hr = IDirect3DViewport_TransformVertices(viewport, 0,
11534 NULL, D3DTRANSFORM_UNCLIPPED, &offscreen);
11535 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
11536 ok(offscreen == 0xdeadbeef, "Offscreen is %#lx.\n", offscreen);
11538 /* NULL transform data and NULL dwOffscreen.
11540 * Valid transform data + NULL dwOffscreen -> crash. */
11541 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11542 NULL, D3DTRANSFORM_UNCLIPPED, NULL);
11543 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
11545 /* No vertices. */
11546 hr = IDirect3DViewport_TransformVertices(viewport, 0,
11547 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
11548 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11549 ok(!offscreen, "Offscreen is %#lx.\n", offscreen);
11550 hr = IDirect3DViewport_TransformVertices(viewport, 0,
11551 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11552 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11553 ok(offscreen == ~0u, "Offscreen is %#lx.\n", offscreen);
11555 /* Invalid sizes. */
11556 offscreen = 0xdeadbeef;
11557 transformdata.dwSize = sizeof(transformdata) - 1;
11558 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11559 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
11560 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
11561 ok(offscreen == 0xdeadbeef, "Offscreen is %#lx.\n", offscreen);
11562 transformdata.dwSize = sizeof(transformdata) + 1;
11563 hr = IDirect3DViewport_TransformVertices(viewport, 1,
11564 &transformdata, D3DTRANSFORM_UNCLIPPED, &offscreen);
11565 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
11566 ok(offscreen == 0xdeadbeef, "Offscreen is %#lx.\n", offscreen);
11568 /* NULL lpIn or lpOut -> crash, except when transforming 0 vertices. */
11569 transformdata.dwSize = sizeof(transformdata);
11570 transformdata.lpIn = NULL;
11571 transformdata.lpOut = NULL;
11572 offscreen = 0xdeadbeef;
11573 hr = IDirect3DViewport_TransformVertices(viewport, 0,
11574 &transformdata, D3DTRANSFORM_CLIPPED, &offscreen);
11575 ok(SUCCEEDED(hr), "Failed to transform vertices, hr %#lx.\n", hr);
11576 ok(offscreen == ~0u, "Offscreen is %#lx.\n", offscreen);
11578 /* Test how vertices are transformed by execute buffers. */
11579 vp_data.dwX = 20;
11580 vp_data.dwY = 20;
11581 vp_data.dwWidth = 200;
11582 vp_data.dwHeight = 400;
11583 vp_data.dvScaleX = 20.0f;
11584 vp_data.dvScaleY = 50.0f;
11585 vp_data.dvMinZ = 0.0f;
11586 vp_data.dvMaxZ = 1.0f;
11587 hr = IDirect3DViewport_SetViewport(viewport, &vp_data);
11588 ok(SUCCEEDED(hr), "Failed to set viewport, hr %#lx.\n", hr);
11590 background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 0.0f);
11591 viewport_set_background(device, viewport, background);
11592 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
11593 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
11595 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
11596 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
11597 memcpy(exec_desc.lpData, quad, sizeof(quad));
11598 ptr = ((BYTE *)exec_desc.lpData) + sizeof(quad);
11599 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORM, 0, 4);
11600 emit_tquad(&ptr, 0);
11601 emit_end(&ptr);
11602 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
11603 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
11604 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
11606 set_execute_data(execute_buffer, 4, sizeof(quad), inst_length);
11607 hr = IDirect3DDevice_BeginScene(device);
11608 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
11609 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
11610 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
11611 hr = IDirect3DDevice_EndScene(device);
11612 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
11614 color = get_surface_color(rt, 128, 143);
11615 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
11616 color = get_surface_color(rt, 132, 143);
11617 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
11618 color = get_surface_color(rt, 128, 147);
11619 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
11620 color = get_surface_color(rt, 132, 147);
11621 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
11623 color = get_surface_color(rt, 177, 217);
11624 ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
11625 color = get_surface_color(rt, 181, 217);
11626 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
11627 color = get_surface_color(rt, 177, 221);
11628 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
11629 color = get_surface_color(rt, 181, 221);
11630 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
11632 IDirect3DDevice_DeleteMatrix(device, world_handle);
11633 IDirect3DDevice_DeleteMatrix(device, view_handle);
11634 IDirect3DDevice_DeleteMatrix(device, proj_handle);
11635 IDirect3DExecuteBuffer_Release(execute_buffer);
11637 IDirectDrawSurface_Release(rt);
11638 destroy_viewport(device, viewport);
11639 IDirect3DMaterial_Release(background);
11640 refcount = IDirect3DDevice_Release(device);
11641 ok(!refcount, "Device has %lu references left.\n", refcount);
11642 IDirectDraw_Release(ddraw);
11643 DestroyWindow(window);
11646 static void test_display_mode_surface_pixel_format(void)
11648 unsigned int width, height, bpp;
11649 IDirectDrawSurface *surface;
11650 DDSURFACEDESC surface_desc;
11651 IDirectDraw *ddraw;
11652 ULONG refcount;
11653 HWND window;
11654 HRESULT hr;
11656 if (!(ddraw = create_ddraw()))
11658 skip("Failed to create ddraw.\n");
11659 return;
11662 surface_desc.dwSize = sizeof(surface_desc);
11663 hr = IDirectDraw_GetDisplayMode(ddraw, &surface_desc);
11664 ok(SUCCEEDED(hr), "Failed to get display mode, hr %#lx.\n", hr);
11665 width = surface_desc.dwWidth;
11666 height = surface_desc.dwHeight;
11668 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
11669 0, 0, width, height, NULL, NULL, NULL, NULL);
11670 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
11671 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
11673 bpp = 0;
11674 if (SUCCEEDED(IDirectDraw_SetDisplayMode(ddraw, width, height, 16)))
11675 bpp = 16;
11676 if (SUCCEEDED(IDirectDraw_SetDisplayMode(ddraw, width, height, 24)))
11677 bpp = 24;
11678 if (SUCCEEDED(IDirectDraw_SetDisplayMode(ddraw, width, height, 32)))
11679 bpp = 32;
11680 ok(bpp, "Set display mode failed.\n");
11682 surface_desc.dwSize = sizeof(surface_desc);
11683 hr = IDirectDraw_GetDisplayMode(ddraw, &surface_desc);
11684 ok(SUCCEEDED(hr), "Failed to get display mode, hr %#lx.\n", hr);
11685 ok(surface_desc.dwWidth == width, "Got width %lu, expected %u.\n", surface_desc.dwWidth, width);
11686 ok(surface_desc.dwHeight == height, "Got height %lu, expected %u.\n", surface_desc.dwHeight, height);
11687 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == bpp, "Got bpp %lu, expected %u.\n",
11688 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, bpp);
11690 memset(&surface_desc, 0, sizeof(surface_desc));
11691 surface_desc.dwSize = sizeof(surface_desc);
11692 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
11693 surface_desc.dwBackBufferCount = 1;
11694 surface_desc.ddsCaps.dwCaps = DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE;
11695 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
11696 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
11697 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
11698 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
11699 ok(surface_desc.dwWidth == width, "Got width %lu, expected %u.\n", surface_desc.dwWidth, width);
11700 ok(surface_desc.dwHeight == height, "Got height %lu, expected %u.\n", surface_desc.dwHeight, height);
11701 ok(surface_desc.ddpfPixelFormat.dwFlags == DDPF_RGB, "Got unexpected pixel format flags %#lx.\n",
11702 surface_desc.ddpfPixelFormat.dwFlags);
11703 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == bpp, "Got bpp %lu, expected %u.\n",
11704 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, bpp);
11705 IDirectDrawSurface_Release(surface);
11707 memset(&surface_desc, 0, sizeof(surface_desc));
11708 surface_desc.dwSize = sizeof(surface_desc);
11709 surface_desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
11710 surface_desc.dwWidth = width;
11711 surface_desc.dwHeight = height;
11712 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
11713 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
11714 ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
11715 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
11716 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
11717 ok(surface_desc.ddpfPixelFormat.dwFlags == DDPF_RGB, "Got unexpected pixel format flags %#lx.\n",
11718 surface_desc.ddpfPixelFormat.dwFlags);
11719 ok(U1(surface_desc.ddpfPixelFormat).dwRGBBitCount == bpp, "Got bpp %lu, expected %u.\n",
11720 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, bpp);
11721 IDirectDrawSurface_Release(surface);
11723 refcount = IDirectDraw_Release(ddraw);
11724 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
11725 DestroyWindow(window);
11728 static void test_surface_desc_size(void)
11730 union
11732 DWORD dwSize;
11733 DDSURFACEDESC desc1;
11734 DDSURFACEDESC2 desc2;
11735 BYTE blob[1024];
11736 } desc;
11737 IDirectDrawSurface7 *surface7;
11738 IDirectDrawSurface *surface;
11739 DDSURFACEDESC surface_desc;
11740 HRESULT expected_hr, hr;
11741 IDirectDraw *ddraw;
11742 unsigned int i, j;
11743 ULONG refcount;
11745 static const struct
11747 unsigned int caps;
11748 const char *name;
11750 surface_caps[] =
11752 {DDSCAPS_OFFSCREENPLAIN, "offscreenplain"},
11753 {DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY, "systemmemory texture"},
11754 {DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, "videomemory texture"},
11756 static const unsigned int desc_sizes[] =
11758 sizeof(DDSURFACEDESC),
11759 sizeof(DDSURFACEDESC2),
11760 sizeof(DDSURFACEDESC) + 1,
11761 sizeof(DDSURFACEDESC2) + 1,
11762 2 * sizeof(DDSURFACEDESC),
11763 2 * sizeof(DDSURFACEDESC2),
11764 sizeof(DDSURFACEDESC) - 1,
11765 sizeof(DDSURFACEDESC2) - 1,
11766 sizeof(DDSURFACEDESC) / 2,
11767 sizeof(DDSURFACEDESC2) / 2,
11771 sizeof(desc) / 2,
11772 sizeof(desc) - 100,
11775 if (!(ddraw = create_ddraw()))
11777 skip("Failed to create ddraw.\n");
11778 return;
11780 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
11781 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
11783 for (i = 0; i < ARRAY_SIZE(surface_caps); ++i)
11785 memset(&surface_desc, 0, sizeof(surface_desc));
11786 surface_desc.dwSize = sizeof(surface_desc);
11787 surface_desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
11788 surface_desc.ddsCaps.dwCaps = surface_caps[i].caps;
11789 surface_desc.dwHeight = 128;
11790 surface_desc.dwWidth = 128;
11791 if (FAILED(IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL)))
11793 skip("Failed to create surface, type %s.\n", surface_caps[i].name);
11794 continue;
11796 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface7, (void **)&surface7);
11797 ok(hr == DD_OK, "Failed to query IDirectDrawSurface7, hr %#lx, type %s.\n", hr, surface_caps[i].name);
11799 /* GetSurfaceDesc() */
11800 for (j = 0; j < ARRAY_SIZE(desc_sizes); ++j)
11802 memset(&desc, 0, sizeof(desc));
11803 desc.dwSize = desc_sizes[j];
11804 expected_hr = desc.dwSize == sizeof(DDSURFACEDESC) ? DD_OK : DDERR_INVALIDPARAMS;
11805 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &desc.desc1);
11806 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u, type %s.\n",
11807 hr, expected_hr, desc_sizes[j], surface_caps[i].name);
11809 memset(&desc, 0, sizeof(desc));
11810 desc.dwSize = desc_sizes[j];
11811 expected_hr = desc.dwSize == sizeof(DDSURFACEDESC2) ? DD_OK : DDERR_INVALIDPARAMS;
11812 hr = IDirectDrawSurface7_GetSurfaceDesc(surface7, &desc.desc2);
11813 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u, type %s.\n",
11814 hr, expected_hr, desc_sizes[j], surface_caps[i].name);
11817 /* Lock() */
11818 for (j = 0; j < ARRAY_SIZE(desc_sizes); ++j)
11820 const BOOL valid_size = desc_sizes[j] == sizeof(DDSURFACEDESC)
11821 || desc_sizes[j] == sizeof(DDSURFACEDESC2);
11822 DWORD expected_texture_stage;
11824 memset(&desc, 0, sizeof(desc));
11825 desc.dwSize = desc_sizes[j];
11826 desc.desc2.dwTextureStage = 0xdeadbeef;
11827 desc.blob[sizeof(DDSURFACEDESC2)] = 0xef;
11828 hr = IDirectDrawSurface_Lock(surface, NULL, &desc.desc1, 0, 0);
11829 expected_hr = valid_size ? DD_OK : DDERR_INVALIDPARAMS;
11830 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u, type %s.\n",
11831 hr, expected_hr, desc_sizes[j], surface_caps[i].name);
11832 ok(desc.dwSize == desc_sizes[j], "dwSize was changed from %u to %lu, type %s.\n",
11833 desc_sizes[j], desc.dwSize, surface_caps[i].name);
11834 ok(desc.blob[sizeof(DDSURFACEDESC2)] == 0xef, "Got unexpected byte %02x, size %u, type %s.\n",
11835 desc.blob[sizeof(DDSURFACEDESC2)], desc_sizes[j], surface_caps[i].name);
11836 if (SUCCEEDED(hr))
11838 ok(desc.desc1.dwWidth == 128, "Got unexpected width %lu, size %u, type %s.\n",
11839 desc.desc1.dwWidth, desc_sizes[j], surface_caps[i].name);
11840 ok(desc.desc1.dwHeight == 128, "Got unexpected height %lu, size %u, type %s.\n",
11841 desc.desc1.dwHeight, desc_sizes[j], surface_caps[i].name);
11842 expected_texture_stage = desc_sizes[j] >= sizeof(DDSURFACEDESC2) ? 0 : 0xdeadbeef;
11843 todo_wine_if(!expected_texture_stage)
11844 ok(desc.desc2.dwTextureStage == expected_texture_stage,
11845 "Got unexpected texture stage %#lx, size %u, type %s.\n",
11846 desc.desc2.dwTextureStage, desc_sizes[j], surface_caps[i].name);
11847 IDirectDrawSurface_Unlock(surface, NULL);
11850 memset(&desc, 0, sizeof(desc));
11851 desc.dwSize = desc_sizes[j];
11852 desc.desc2.dwTextureStage = 0xdeadbeef;
11853 desc.blob[sizeof(DDSURFACEDESC2)] = 0xef;
11854 hr = IDirectDrawSurface7_Lock(surface7, NULL, &desc.desc2, 0, 0);
11855 expected_hr = valid_size ? DD_OK : DDERR_INVALIDPARAMS;
11856 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u, type %s.\n",
11857 hr, expected_hr, desc_sizes[j], surface_caps[i].name);
11858 ok(desc.dwSize == desc_sizes[j], "dwSize was changed from %u to %lu, type %s.\n",
11859 desc_sizes[j], desc.dwSize, surface_caps[i].name);
11860 ok(desc.blob[sizeof(DDSURFACEDESC2)] == 0xef, "Got unexpected byte %02x, size %u, type %s.\n",
11861 desc.blob[sizeof(DDSURFACEDESC2)], desc_sizes[j], surface_caps[i].name);
11862 if (SUCCEEDED(hr))
11864 ok(desc.desc2.dwWidth == 128, "Got unexpected width %lu, size %u, type %s.\n",
11865 desc.desc2.dwWidth, desc_sizes[j], surface_caps[i].name);
11866 ok(desc.desc2.dwHeight == 128, "Got unexpected height %lu, size %u, type %s.\n",
11867 desc.desc2.dwHeight, desc_sizes[j], surface_caps[i].name);
11868 expected_texture_stage = desc_sizes[j] >= sizeof(DDSURFACEDESC2) ? 0 : 0xdeadbeef;
11869 ok(desc.desc2.dwTextureStage == expected_texture_stage,
11870 "Got unexpected texture stage %#lx, size %u, type %s.\n",
11871 desc.desc2.dwTextureStage, desc_sizes[j], surface_caps[i].name);
11872 IDirectDrawSurface7_Unlock(surface7, NULL);
11876 IDirectDrawSurface7_Release(surface7);
11877 IDirectDrawSurface_Release(surface);
11880 /* GetDisplayMode() */
11881 for (j = 0; j < ARRAY_SIZE(desc_sizes); ++j)
11883 memset(&desc, 0xcc, sizeof(desc));
11884 desc.dwSize = desc_sizes[j];
11885 expected_hr = (desc.dwSize == sizeof(DDSURFACEDESC) || desc.dwSize == sizeof(DDSURFACEDESC2))
11886 ? DD_OK : DDERR_INVALIDPARAMS;
11887 hr = IDirectDraw_GetDisplayMode(ddraw, &desc.desc1);
11888 ok(hr == expected_hr, "Got hr %#lx, expected %#lx, size %u.\n", hr, expected_hr, desc_sizes[j]);
11889 if (SUCCEEDED(hr))
11891 ok(desc.dwSize == sizeof(DDSURFACEDESC), "Wrong size %lu for %u.\n", desc.dwSize, desc_sizes[j]);
11892 ok(desc.blob[desc_sizes[j]] == 0xcc, "Overflow for size %u.\n", desc_sizes[j]);
11893 ok(desc.blob[desc_sizes[j] - 1] != 0xcc, "Struct not cleared for size %u.\n", desc_sizes[j]);
11897 refcount = IDirectDraw_Release(ddraw);
11898 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
11901 static void test_texture_load(void)
11903 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
11904 static D3DTLVERTEX tquad[] =
11906 {{ 0.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
11907 {{ 0.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
11908 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
11909 {{640.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
11911 D3DTEXTUREHANDLE dst_texture_handle, src_texture_handle;
11912 IDirectDrawSurface *dst_surface, *src_surface;
11913 IDirect3DExecuteBuffer *execute_buffer;
11914 unsigned int inst_length, color;
11915 D3DEXECUTEBUFFERDESC exec_desc;
11916 IDirect3DMaterial *background;
11917 IDirect3DViewport *viewport;
11918 DDSURFACEDESC surface_desc;
11919 IDirect3DTexture *texture;
11920 IDirect3DDevice *device;
11921 IDirectDrawSurface *rt;
11922 IDirectDraw *ddraw;
11923 ULONG refcount;
11924 HWND window;
11925 DDBLTFX fx;
11926 HRESULT hr;
11927 void *ptr;
11929 window = create_window();
11930 ddraw = create_ddraw();
11931 ok(!!ddraw, "Failed to create a ddraw object.\n");
11932 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
11934 skip("Failed to create a 3D device, skipping test.\n");
11935 IDirectDraw_Release(ddraw);
11936 DestroyWindow(window);
11937 return;
11940 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
11941 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
11943 background = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
11944 viewport = create_viewport(device, 0, 0, 640, 480);
11945 viewport_set_background(device, viewport, background);
11947 memset(&exec_desc, 0, sizeof(exec_desc));
11948 exec_desc.dwSize = sizeof(exec_desc);
11949 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
11950 exec_desc.dwBufferSize = 1024;
11951 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
11952 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
11953 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
11955 memset(&surface_desc, 0, sizeof(surface_desc));
11956 surface_desc.dwSize = sizeof(surface_desc);
11957 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
11958 surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
11959 surface_desc.dwWidth = 256;
11960 surface_desc.dwHeight = 256;
11961 surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
11962 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
11963 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
11964 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
11965 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
11966 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
11968 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
11969 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
11970 hr = IDirectDrawSurface_QueryInterface(src_surface, &IID_IDirect3DTexture, (void **)&texture);
11971 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
11972 hr = IDirect3DTexture_GetHandle(texture, device, &src_texture_handle);
11973 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
11974 IDirect3DTexture_Release(texture);
11976 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
11977 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
11978 hr = IDirectDrawSurface_QueryInterface(dst_surface, &IID_IDirect3DTexture, (void **)&texture);
11979 ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#lx.\n", hr);
11980 hr = IDirect3DTexture_GetHandle(texture, device, &dst_texture_handle);
11981 ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#lx.\n", hr);
11982 IDirect3DTexture_Release(texture);
11984 memset(&fx, 0, sizeof(fx));
11985 fx.dwSize = sizeof(fx);
11986 U5(fx).dwFillColor = 0x0000ffff;
11987 hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
11988 ok(SUCCEEDED(hr), "Failed to fill surface, hr %#lx.\n", hr);
11990 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
11991 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
11992 memcpy(exec_desc.lpData, tquad, sizeof(tquad));
11993 ptr = (BYTE *)exec_desc.lpData + sizeof(tquad);
11994 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
11995 emit_texture_load(&ptr, dst_texture_handle, src_texture_handle);
11996 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, dst_texture_handle);
11997 /* WARP randomly applies color keying without having a key set. */
11998 emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, FALSE);
11999 emit_tquad(&ptr, 0);
12000 emit_end(&ptr);
12001 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData - sizeof(tquad);
12002 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
12003 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
12005 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
12006 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
12007 color = get_surface_color(rt, 320, 240);
12008 ok(compare_color(color, 0x00ffffff, 1), "Got unexpected color 0x%08x.\n", color);
12009 set_execute_data(execute_buffer, 4, sizeof(tquad), inst_length);
12010 hr = IDirect3DDevice_BeginScene(device);
12011 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12012 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
12013 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
12014 hr = IDirect3DDevice_EndScene(device);
12015 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12016 color = get_surface_color(rt, 320, 240);
12017 ok(compare_color(color, 0x0000ffff, 1), "Got unexpected color 0x%08x.\n", color);
12019 memset(&fx, 0, sizeof(fx));
12020 fx.dwSize = sizeof(fx);
12021 U5(fx).dwFillColor = 0x000000ff;
12022 hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
12023 ok(SUCCEEDED(hr), "Failed to fill surface, hr %#lx.\n", hr);
12025 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
12026 ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#lx.\n", hr);
12027 color = get_surface_color(rt, 320, 240);
12028 ok(compare_color(color, 0x00ffffff, 1), "Got unexpected color 0x%08x.\n", color);
12029 set_execute_data(execute_buffer, 4, sizeof(tquad), inst_length);
12030 hr = IDirect3DDevice_BeginScene(device);
12031 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12032 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
12033 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
12034 hr = IDirect3DDevice_EndScene(device);
12035 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12036 color = get_surface_color(rt, 320, 240);
12037 ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
12039 IDirectDrawSurface_Release(dst_surface);
12040 IDirectDrawSurface_Release(src_surface);
12041 IDirectDrawSurface_Release(rt);
12042 IDirect3DExecuteBuffer_Release(execute_buffer);
12043 IDirect3DMaterial_Release(background);
12044 destroy_viewport(device, viewport);
12045 IDirect3DDevice_Release(device);
12046 refcount = IDirectDraw_Release(ddraw);
12047 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
12048 DestroyWindow(window);
12051 static void test_ck_operation(void)
12053 IDirectDrawSurface *src, *dst;
12054 IDirectDrawSurface7 *src7, *dst7;
12055 DDSURFACEDESC surface_desc;
12056 unsigned int i, *color;
12057 IDirectDraw *ddraw;
12058 ULONG refcount;
12059 HWND window;
12060 HRESULT hr;
12061 DDCOLORKEY ckey;
12062 DDBLTFX fx;
12064 window = create_window();
12065 ddraw = create_ddraw();
12066 ok(!!ddraw, "Failed to create a ddraw object.\n");
12067 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
12068 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
12070 memset(&surface_desc, 0, sizeof(surface_desc));
12071 surface_desc.dwSize = sizeof(surface_desc);
12072 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
12073 surface_desc.dwWidth = 4;
12074 surface_desc.dwHeight = 1;
12075 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
12076 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
12077 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
12078 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
12079 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
12080 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
12081 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst, NULL);
12082 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
12084 surface_desc.dwFlags |= DDSD_CKSRCBLT;
12085 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00ff00ff;
12086 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00ff00ff;
12087 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src, NULL);
12088 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
12090 hr = IDirectDrawSurface_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12091 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12092 ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
12093 color = surface_desc.lpSurface;
12094 color[0] = 0x77010203;
12095 color[1] = 0x00010203;
12096 color[2] = 0x77ff00ff;
12097 color[3] = 0x00ff00ff;
12098 hr = IDirectDrawSurface_Unlock(src, NULL);
12099 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12101 for (i = 0; i < 2; ++i)
12103 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12104 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12105 color = surface_desc.lpSurface;
12106 color[0] = 0xcccccccc;
12107 color[1] = 0xcccccccc;
12108 color[2] = 0xcccccccc;
12109 color[3] = 0xcccccccc;
12110 hr = IDirectDrawSurface_Unlock(dst, NULL);
12111 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12113 if (i)
12115 hr = IDirectDrawSurface_BltFast(dst, 0, 0, src, NULL, DDBLTFAST_SRCCOLORKEY);
12116 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
12118 else
12120 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, NULL);
12121 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
12124 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT | DDLOCK_READONLY, NULL);
12125 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12126 ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
12127 color = surface_desc.lpSurface;
12128 /* Different behavior on some drivers / windows versions. Some versions ignore the X channel when
12129 * color keying, but copy it to the destination surface. Others (sysmem surfaces) apply it for
12130 * color keying, but do not copy it into the destination surface. Nvidia neither uses it for
12131 * color keying nor copies it. */
12132 ok((color[0] == 0x77010203 && color[1] == 0x00010203
12133 && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* AMD, Wine */
12134 || broken(color[0] == 0x00010203 && color[1] == 0x00010203
12135 && color[2] == 0x00ff00ff && color[3] == 0xcccccccc) /* Sysmem surfaces? */
12136 || broken(color[0] == 0x00010203 && color[1] == 0x00010203
12137 && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Nvidia */
12138 || broken(color[0] == 0xff010203 && color[1] == 0xff010203
12139 && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Testbot */,
12140 "Destination data after blitting is %08x %08x %08x %08x, i=%u.\n",
12141 color[0], color[1], color[2], color[3], i);
12142 hr = IDirectDrawSurface_Unlock(dst, NULL);
12143 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12146 hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
12147 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
12148 ok(ckey.dwColorSpaceLowValue == 0x00ff00ff && ckey.dwColorSpaceHighValue == 0x00ff00ff,
12149 "Got unexpected color key low=%08lx high=%08lx.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
12151 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
12152 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
12153 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12155 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
12156 hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
12157 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
12158 ok(ckey.dwColorSpaceLowValue == 0x0000ff00 && ckey.dwColorSpaceHighValue == 0x0000ff00,
12159 "Got unexpected color key low=%08lx high=%08lx.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
12161 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0;
12162 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0;
12163 hr = IDirectDrawSurface_GetSurfaceDesc(src, &surface_desc);
12164 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
12165 ok(surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue == 0x0000ff00
12166 && surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue == 0x0000ff00,
12167 "Got unexpected color key low=%08lx high=%08lx.\n", surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue,
12168 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue);
12170 /* Test SetColorKey with dwColorSpaceHighValue < dwColorSpaceLowValue */
12171 ckey.dwColorSpaceLowValue = 0x000000ff;
12172 ckey.dwColorSpaceHighValue = 0x00000000;
12173 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
12174 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12176 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
12177 hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
12178 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
12179 ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
12180 "Got unexpected color key low=%08lx high=%08lx.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
12182 ckey.dwColorSpaceLowValue = 0x000000ff;
12183 ckey.dwColorSpaceHighValue = 0x00000001;
12184 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
12185 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12187 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
12188 hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
12189 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
12190 ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
12191 "Got unexpected color key low=%08lx high=%08lx.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
12193 ckey.dwColorSpaceLowValue = 0x000000fe;
12194 ckey.dwColorSpaceHighValue = 0x000000fd;
12195 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
12196 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12198 ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
12199 hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
12200 ok(SUCCEEDED(hr), "Failed to get color key, hr %#lx.\n", hr);
12201 ok(ckey.dwColorSpaceLowValue == 0x000000fe && ckey.dwColorSpaceHighValue == 0x000000fe,
12202 "Got unexpected color key low=%08lx high=%08lx.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
12204 IDirectDrawSurface_Release(src);
12205 IDirectDrawSurface_Release(dst);
12207 /* Test source and destination keys and where they are read from. Use a surface with alpha
12208 * to avoid driver-dependent content in the X channel. */
12209 memset(&surface_desc, 0, sizeof(surface_desc));
12210 surface_desc.dwSize = sizeof(surface_desc);
12211 surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
12212 surface_desc.dwWidth = 6;
12213 surface_desc.dwHeight = 1;
12214 surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
12215 surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
12216 U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
12217 U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
12218 U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
12219 U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
12220 U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
12221 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst, NULL);
12222 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
12223 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src, NULL);
12224 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
12226 ckey.dwColorSpaceLowValue = 0x0000ff00;
12227 ckey.dwColorSpaceHighValue = 0x0000ff00;
12228 hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
12229 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12230 ckey.dwColorSpaceLowValue = 0x00ff0000;
12231 ckey.dwColorSpaceHighValue = 0x00ff0000;
12232 hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_DESTBLT, &ckey);
12233 ok(SUCCEEDED(hr) || hr == DDERR_NOCOLORKEYHW, "Failed to set color key, hr %#lx.\n", hr);
12234 if (FAILED(hr))
12236 /* Nvidia reject dest keys, AMD allows them. This applies to vidmem and sysmem surfaces. */
12237 skip("Failed to set destination color key, skipping related tests.\n");
12238 goto done;
12241 ckey.dwColorSpaceLowValue = 0x000000ff;
12242 ckey.dwColorSpaceHighValue = 0x000000ff;
12243 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
12244 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12245 ckey.dwColorSpaceLowValue = 0x000000aa;
12246 ckey.dwColorSpaceHighValue = 0x000000aa;
12247 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_DESTBLT, &ckey);
12248 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12250 memset(&fx, 0, sizeof(fx));
12251 fx.dwSize = sizeof(fx);
12252 fx.ddckSrcColorkey.dwColorSpaceHighValue = 0x00110000;
12253 fx.ddckSrcColorkey.dwColorSpaceLowValue = 0x00110000;
12254 fx.ddckDestColorkey.dwColorSpaceHighValue = 0x00001100;
12255 fx.ddckDestColorkey.dwColorSpaceLowValue = 0x00001100;
12257 hr = IDirectDrawSurface_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12258 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12259 color = surface_desc.lpSurface;
12260 color[0] = 0x000000ff; /* Applies to src blt key in src surface. */
12261 color[1] = 0x000000aa; /* Applies to dst blt key in src surface. */
12262 color[2] = 0x00ff0000; /* Dst color key in dst surface. */
12263 color[3] = 0x0000ff00; /* Src color key in dst surface. */
12264 color[4] = 0x00001100; /* Src color key in ddbltfx. */
12265 color[5] = 0x00110000; /* Dst color key in ddbltfx. */
12266 hr = IDirectDrawSurface_Unlock(src, NULL);
12267 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12269 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12270 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12271 color = surface_desc.lpSurface;
12272 color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
12273 hr = IDirectDrawSurface_Unlock(dst, NULL);
12274 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12276 /* Test a blit without keying. */
12277 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, 0, &fx);
12278 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
12280 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12281 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12282 color = surface_desc.lpSurface;
12283 /* Should have copied src data unmodified to dst. */
12284 ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
12285 color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
12286 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
12287 color[0], color[1], color[2], color[3], color[4], color[5]);
12289 color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
12290 hr = IDirectDrawSurface_Unlock(dst, NULL);
12291 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12293 /* Src key. */
12294 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
12295 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
12297 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12298 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12299 color = surface_desc.lpSurface;
12300 /* Src key applied to color[0]. It is unmodified, the others are copied. */
12301 ok(color[0] == 0x55555555 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
12302 color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
12303 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
12304 color[0], color[1], color[2], color[3], color[4], color[5]);
12306 color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
12307 hr = IDirectDrawSurface_Unlock(dst, NULL);
12308 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12310 /* Src override. */
12311 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, &fx);
12312 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
12314 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12315 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12316 color = surface_desc.lpSurface;
12317 /* Override key applied to color[5]. It is unmodified, the others are copied. */
12318 ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
12319 color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x55555555,
12320 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
12321 color[0], color[1], color[2], color[3], color[4], color[5]);
12323 color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
12324 hr = IDirectDrawSurface_Unlock(dst, NULL);
12325 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12327 /* Src override AND src key. That is not supposed to work. */
12328 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE, &fx);
12329 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
12331 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12332 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12333 color = surface_desc.lpSurface;
12334 /* Ensure the destination was not changed. */
12335 ok(color[0] == 0x55555555 && color[1] == 0x55555555 && color[2] == 0x55555555 &&
12336 color[3] == 0x55555555 && color[4] == 0x55555555 && color[5] == 0x55555555,
12337 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
12338 color[0], color[1], color[2], color[3], color[4], color[5]);
12340 /* Use different dst colors for the dst key test. */
12341 color[0] = 0x00ff0000; /* Dest key in dst surface. */
12342 color[1] = 0x00ff0000; /* Dest key in dst surface. */
12343 color[2] = 0x00001100; /* Dest key in override. */
12344 color[3] = 0x00001100; /* Dest key in override. */
12345 color[4] = 0x000000aa; /* Dest key in src surface. */
12346 color[5] = 0x000000aa; /* Dest key in src surface. */
12347 hr = IDirectDrawSurface_Unlock(dst, NULL);
12348 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12350 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
12351 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
12353 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12354 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12355 color = surface_desc.lpSurface;
12356 /* Dst key applied to color[4,5], they are the only changed pixels. */
12357 ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
12358 color[3] == 0x00001100 && color[4] == 0x00001100 && color[5] == 0x00110000,
12359 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
12360 color[0], color[1], color[2], color[3], color[4], color[5]);
12362 color[0] = 0x00ff0000; /* Dest key in dst surface. */
12363 color[1] = 0x00ff0000; /* Dest key in dst surface. */
12364 color[2] = 0x00001100; /* Dest key in override. */
12365 color[3] = 0x00001100; /* Dest key in override. */
12366 color[4] = 0x000000aa; /* Dest key in src surface. */
12367 color[5] = 0x000000aa; /* Dest key in src surface. */
12368 hr = IDirectDrawSurface_Unlock(dst, NULL);
12369 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12371 /* What happens with a QI'd newer version of the interface? It takes the key
12372 * from the destination surface. */
12373 hr = IDirectDrawSurface_QueryInterface(src, &IID_IDirectDrawSurface7, (void **)&src7);
12374 ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#lx.\n", hr);
12375 hr = IDirectDrawSurface_QueryInterface(dst, &IID_IDirectDrawSurface7, (void **)&dst7);
12376 ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#lx.\n", hr);
12378 hr = IDirectDrawSurface7_Blt(dst7, NULL, src7, NULL, DDBLT_KEYDEST, &fx);
12379 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
12381 IDirectDrawSurface7_Release(dst7);
12382 IDirectDrawSurface7_Release(src7);
12384 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12385 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12386 color = surface_desc.lpSurface;
12387 /* Dst key applied to color[0,1], they are the only changed pixels. */
12388 todo_wine ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00001100 &&
12389 color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
12390 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
12391 color[0], color[1], color[2], color[3], color[4], color[5]);
12393 color[0] = 0x00ff0000; /* Dest key in dst surface. */
12394 color[1] = 0x00ff0000; /* Dest key in dst surface. */
12395 color[2] = 0x00001100; /* Dest key in override. */
12396 color[3] = 0x00001100; /* Dest key in override. */
12397 color[4] = 0x000000aa; /* Dest key in src surface. */
12398 color[5] = 0x000000aa; /* Dest key in src surface. */
12399 hr = IDirectDrawSurface_Unlock(dst, NULL);
12400 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12402 /* Dest override key blit. */
12403 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, &fx);
12404 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
12406 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12407 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12408 color = surface_desc.lpSurface;
12409 /* Dst key applied to color[2,3], they are the only changed pixels. */
12410 ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00ff0000 &&
12411 color[3] == 0x0000ff00 && color[4] == 0x000000aa && color[5] == 0x000000aa,
12412 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
12413 color[0], color[1], color[2], color[3], color[4], color[5]);
12415 color[0] = 0x00ff0000; /* Dest key in dst surface. */
12416 color[1] = 0x00ff0000; /* Dest key in dst surface. */
12417 color[2] = 0x00001100; /* Dest key in override. */
12418 color[3] = 0x00001100; /* Dest key in override. */
12419 color[4] = 0x000000aa; /* Dest key in src surface. */
12420 color[5] = 0x000000aa; /* Dest key in src surface. */
12421 hr = IDirectDrawSurface_Unlock(dst, NULL);
12422 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12424 /* Dest override together with surface key. Supposed to fail. */
12425 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE, &fx);
12426 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
12428 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12429 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12430 color = surface_desc.lpSurface;
12431 /* Destination is unchanged. */
12432 ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
12433 color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
12434 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
12435 color[0], color[1], color[2], color[3], color[4], color[5]);
12436 hr = IDirectDrawSurface_Unlock(dst, NULL);
12437 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12439 /* Source and destination key. This is driver dependent. New HW treats it like
12440 * DDBLT_KEYSRC. Older HW and some software renderers apply both keys. */
12441 if (0)
12443 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYSRC, &fx);
12444 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
12446 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12447 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12448 color = surface_desc.lpSurface;
12449 /* Color[0] is filtered by the src key, 2-5 are filtered by the dst key, if
12450 * the driver applies it. */
12451 ok(color[0] == 0x00ff0000 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
12452 color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
12453 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
12454 color[0], color[1], color[2], color[3], color[4], color[5]);
12456 color[0] = 0x00ff0000; /* Dest key in dst surface. */
12457 color[1] = 0x00ff0000; /* Dest key in dst surface. */
12458 color[2] = 0x00001100; /* Dest key in override. */
12459 color[3] = 0x00001100; /* Dest key in override. */
12460 color[4] = 0x000000aa; /* Dest key in src surface. */
12461 color[5] = 0x000000aa; /* Dest key in src surface. */
12462 hr = IDirectDrawSurface_Unlock(dst, NULL);
12463 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12466 /* Override keys without ddbltfx parameter fail */
12467 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, NULL);
12468 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
12469 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, NULL);
12470 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
12472 /* Try blitting without keys in the source surface. */
12473 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, NULL);
12474 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12475 hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_DESTBLT, NULL);
12476 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12478 /* That fails now. Do not bother to check that the data is unmodified. */
12479 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
12480 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
12482 /* Surprisingly this still works. It uses the old key from the src surface. */
12483 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
12484 ok(SUCCEEDED(hr), "Failed to blit, hr %#lx.\n", hr);
12486 hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
12487 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12488 color = surface_desc.lpSurface;
12489 /* Dst key applied to color[4,5], they are the only changed pixels. */
12490 ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
12491 color[3] == 0x00001100 && color[4] == 0x00001100 && color[5] == 0x00110000,
12492 "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
12493 color[0], color[1], color[2], color[3], color[4], color[5]);
12494 hr = IDirectDrawSurface_Unlock(dst, NULL);
12495 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12497 /* This returns DDERR_NOCOLORKEY as expected. */
12498 hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_DESTBLT, &ckey);
12499 ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#lx.\n", hr);
12501 /* GetSurfaceDesc returns a zeroed key as expected. */
12502 surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x12345678;
12503 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x12345678;
12504 hr = IDirectDrawSurface_GetSurfaceDesc(src, &surface_desc);
12505 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr);
12506 ok(!surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue
12507 && !surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue,
12508 "Got unexpected color key low=%08lx high=%08lx.\n", surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue,
12509 surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue);
12511 /* Try blitting without keys in the destination surface. */
12512 hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_SRCBLT, NULL);
12513 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12514 hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_DESTBLT, NULL);
12515 ok(SUCCEEDED(hr), "Failed to set color key, hr %#lx.\n", hr);
12517 /* This is weird. It makes sense in v4 and v7, but because v1
12518 * uses the key from the src surface it makes no sense here. */
12519 hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
12520 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
12522 done:
12523 IDirectDrawSurface_Release(src);
12524 IDirectDrawSurface_Release(dst);
12525 refcount = IDirectDraw_Release(ddraw);
12526 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
12527 DestroyWindow(window);
12530 static void test_depth_readback(void)
12532 unsigned int depth, expected_depth, inst_length, max_diff, x, y;
12533 IDirect3DExecuteBuffer *execute_buffer;
12534 IDirect3DMaterial *blue_background;
12535 D3DEXECUTEBUFFERDESC exec_desc;
12536 IDirectDrawSurface *rt, *ds;
12537 IDirect3DViewport *viewport;
12538 DDSURFACEDESC surface_desc;
12539 IDirect3DDevice *device;
12540 DWORD z_depth, z_mask;
12541 IDirectDraw *ddraw;
12542 ULONG refcount;
12543 HWND window;
12544 HRESULT hr;
12545 void *ptr;
12547 static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
12548 static D3DLVERTEX quad[] =
12550 {{-1.0f}, {-1.0f}, {0.1f}, 0, {0xff00ff00}},
12551 {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
12552 {{ 1.0f}, {-1.0f}, {1.0f}, 0, {0xff00ff00}},
12553 {{ 1.0f}, { 1.0f}, {0.9f}, 0, {0xff00ff00}},
12556 window = create_window();
12557 ok(!!window, "Failed to create a window.\n");
12558 ddraw = create_ddraw();
12559 ok(!!ddraw, "Failed to create a ddraw object.\n");
12560 if (ddraw_is_nvidia(ddraw))
12562 /* ddraw1 only has access to D16 Z buffers (and D24 ones, which are even more
12563 * broken on Nvidia), so don't even attempt to run this test on Nvidia cards
12564 * because some of them have broken D16 readback. See the ddraw7 version of
12565 * this test for a more detailed comment. */
12566 skip("Some Nvidia GPUs have broken D16 readback, skipping.\n");
12567 IDirectDraw_Release(ddraw);
12568 DestroyWindow(window);
12569 return;
12572 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
12574 skip("Failed to create a D3D device, skipping tests.\n");
12575 IDirectDraw_Release(ddraw);
12576 DestroyWindow(window);
12577 return;
12580 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
12581 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
12582 z_depth = get_device_z_depth(device);
12583 z_mask = 0xffffffff >> (32 - z_depth);
12584 ds = get_depth_stencil(device);
12586 /* Changing depth buffers is hard in d3d1, so we only test with the
12587 * initial depth buffer here. */
12589 blue_background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
12590 viewport = create_viewport(device, 0, 0, 640, 480);
12591 viewport_set_background(device, viewport, blue_background);
12593 memset(&exec_desc, 0, sizeof(exec_desc));
12594 exec_desc.dwSize = sizeof(exec_desc);
12595 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
12596 exec_desc.dwBufferSize = 1024;
12597 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
12598 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
12599 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
12601 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
12602 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
12604 memcpy(exec_desc.lpData, quad, sizeof(quad));
12605 ptr = (BYTE *)exec_desc.lpData + sizeof(quad);
12606 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORM, 0, 4);
12607 emit_tquad(&ptr, 0);
12608 emit_end(&ptr);
12610 inst_length = ((BYTE *)ptr - sizeof(quad)) - (BYTE *)exec_desc.lpData;
12612 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
12613 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
12615 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
12616 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
12617 hr = IDirect3DDevice_BeginScene(device);
12618 ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr);
12619 set_execute_data(execute_buffer, 4, sizeof(quad), inst_length);
12620 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_UNCLIPPED);
12621 ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#lx.\n", hr);
12622 hr = IDirect3DDevice_EndScene(device);
12623 ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr);
12625 memset(&surface_desc, 0, sizeof(surface_desc));
12626 surface_desc.dwSize = sizeof(surface_desc);
12627 hr = IDirectDrawSurface_Lock(ds, NULL, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
12628 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
12630 for (y = 60; y < 480; y += 120)
12632 for (x = 80; x < 640; x += 160)
12634 ptr = (BYTE *)surface_desc.lpSurface
12635 + y * U1(surface_desc).lPitch
12636 + x * (z_depth == 16 ? 2 : 4);
12637 depth = *((DWORD *)ptr) & z_mask;
12638 expected_depth = (x * (0.9 / 640.0) + y * (0.1 / 480.0)) * z_mask;
12639 max_diff = ((0.5f * 0.9f) / 640.0f) * z_mask;
12640 ok(compare_uint(expected_depth, depth, max_diff),
12641 "z_depth %lu: Got depth 0x%08x (diff %d), expected 0x%08x+/-%u, at %u, %u.\n",
12642 z_depth, depth, expected_depth - depth, expected_depth, max_diff, x, y);
12646 hr = IDirectDrawSurface_Unlock(ds, NULL);
12647 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
12649 IDirect3DExecuteBuffer_Release(execute_buffer);
12650 destroy_viewport(device, viewport);
12651 destroy_material(blue_background);
12652 IDirectDrawSurface_Release(ds);
12653 IDirect3DDevice_Release(device);
12654 refcount = IDirectDrawSurface_Release(rt);
12655 ok(!refcount, "Device has %lu references left.\n", refcount);
12656 IDirectDraw_Release(ddraw);
12657 DestroyWindow(window);
12660 static void test_clear(void)
12662 D3DRECT rect_negneg, rect_full = {{0}, {0}, {640}, {480}};
12663 IDirect3DViewport *viewport, *viewport2, *viewport3;
12664 IDirect3DMaterial *white, *red, *green, *blue;
12665 IDirect3DDevice *device;
12666 IDirectDrawSurface *rt;
12667 unsigned int color;
12668 IDirectDraw *ddraw;
12669 D3DRECT rect[2];
12670 ULONG refcount;
12671 HWND window;
12672 HRESULT hr;
12674 window = create_window();
12675 ddraw = create_ddraw();
12676 ok(!!ddraw, "Failed to create a ddraw object.\n");
12677 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
12679 skip("Failed to create a 3D device, skipping test.\n");
12680 IDirectDraw_Release(ddraw);
12681 DestroyWindow(window);
12682 return;
12684 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
12685 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
12687 viewport = create_viewport(device, 0, 0, 640, 480);
12689 white = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f);
12690 red = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
12691 green = create_diffuse_material(device, 0.0f, 1.0f, 0.0f, 1.0f);
12692 blue = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
12694 viewport_set_background(device, viewport, white);
12695 hr = IDirect3DViewport_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
12696 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
12698 /* Positive x, negative y. */
12699 U1(rect[0]).x1 = 0;
12700 U2(rect[0]).y1 = 480;
12701 U3(rect[0]).x2 = 320;
12702 U4(rect[0]).y2 = 240;
12704 /* Positive x, positive y. */
12705 U1(rect[1]).x1 = 0;
12706 U2(rect[1]).y1 = 0;
12707 U3(rect[1]).x2 = 320;
12708 U4(rect[1]).y2 = 240;
12710 /* Clear 2 rectangles with one call. Unlike d3d8/9, the refrast does not
12711 * refuse negative rectangles, but it will not clear them either. */
12712 viewport_set_background(device, viewport, red);
12713 hr = IDirect3DViewport_Clear(viewport, 2, rect, D3DCLEAR_TARGET);
12714 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
12716 color = get_surface_color(rt, 160, 360);
12717 ok(compare_color(color, 0x00ffffff, 0), "Clear rectangle 3 (pos, neg) has color 0x%08x.\n", color);
12718 color = get_surface_color(rt, 160, 120);
12719 ok(compare_color(color, 0x00ff0000, 0), "Clear rectangle 1 (pos, pos) has color 0x%08x.\n", color);
12720 color = get_surface_color(rt, 480, 360);
12721 ok(compare_color(color, 0x00ffffff, 0), "Clear rectangle 4 (NULL) has color 0x%08x.\n", color);
12722 color = get_surface_color(rt, 480, 120);
12723 ok(compare_color(color, 0x00ffffff, 0), "Clear rectangle 4 (neg, neg) has color 0x%08x.\n", color);
12725 viewport_set_background(device, viewport, white);
12726 hr = IDirect3DViewport_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
12727 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
12729 /* negative x, negative y.
12730 * Also ignored, except on WARP, which clears the entire screen. */
12731 U1(rect_negneg).x1 = 640;
12732 U2(rect_negneg).y1 = 240;
12733 U3(rect_negneg).x2 = 320;
12734 U4(rect_negneg).y2 = 0;
12735 viewport_set_background(device, viewport, green);
12736 hr = IDirect3DViewport_Clear(viewport, 1, &rect_negneg, D3DCLEAR_TARGET);
12737 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
12739 color = get_surface_color(rt, 160, 360);
12740 ok(compare_color(color, 0x00ffffff, 0)
12741 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x0000ff00, 0)),
12742 "Got unexpected color 0x%08x.\n", color);
12743 color = get_surface_color(rt, 160, 120);
12744 ok(compare_color(color, 0x00ffffff, 0)
12745 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x0000ff00, 0)),
12746 "Got unexpected color 0x%08x.\n", color);
12747 color = get_surface_color(rt, 480, 360);
12748 ok(compare_color(color, 0x00ffffff, 0)
12749 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x0000ff00, 0)),
12750 "Got unexpected color 0x%08x.\n", color);
12751 color = get_surface_color(rt, 480, 120);
12752 ok(compare_color(color, 0x00ffffff, 0)
12753 || broken(ddraw_is_warp(ddraw) && compare_color(color, 0x0000ff00, 0)),
12754 "Got unexpected color 0x%08x.\n", color);
12756 /* Test how the viewport affects clears. */
12757 viewport_set_background(device, viewport, white);
12758 hr = IDirect3DViewport_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
12759 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
12761 viewport2 = create_viewport(device, 160, 120, 160, 120);
12762 viewport_set_background(device, viewport2, blue);
12763 hr = IDirect3DViewport_Clear(viewport2, 1, &rect_full, D3DCLEAR_TARGET);
12764 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
12766 viewport3 = create_viewport(device, 320, 240, 320, 240);
12767 viewport_set_background(device, viewport3, green);
12769 U1(rect[0]).x1 = 160;
12770 U2(rect[0]).y1 = 120;
12771 U3(rect[0]).x2 = 480;
12772 U4(rect[0]).y2 = 360;
12773 hr = IDirect3DViewport_Clear(viewport3, 1, &rect[0], D3DCLEAR_TARGET);
12774 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
12776 /* AMD drivers do not limit the clear area to the viewport rectangle in
12777 * d3d1. It works as intended on other drivers and on d3d2 and newer on
12778 * AMD cards. */
12779 color = get_surface_color(rt, 158, 118);
12780 ok(compare_color(color, 0x00ffffff, 0)
12781 || broken(ddraw_is_amd(ddraw) && compare_color(color, 0x000000ff, 0)),
12782 "(158, 118) has color 0x%08x.\n", color);
12783 color = get_surface_color(rt, 162, 118);
12784 ok(compare_color(color, 0x00ffffff, 0)
12785 || broken(ddraw_is_amd(ddraw) && compare_color(color, 0x000000ff, 0)),
12786 "(162, 118) has color 0x%08x.\n", color);
12787 color = get_surface_color(rt, 158, 122);
12788 ok(compare_color(color, 0x00ffffff, 0)
12789 || broken(ddraw_is_amd(ddraw) && compare_color(color, 0x000000ff, 0)),
12790 "(158, 122) has color 0x%08x.\n", color);
12791 color = get_surface_color(rt, 162, 122);
12792 ok(compare_color(color, 0x000000ff, 0)
12793 || broken(ddraw_is_amd(ddraw) && compare_color(color, 0x0000ff00, 0)),
12794 "(162, 122) has color 0x%08x.\n", color);
12796 color = get_surface_color(rt, 318, 238);
12797 ok(compare_color(color, 0x000000ff, 0)
12798 || broken(ddraw_is_amd(ddraw) && compare_color(color, 0x0000ff00, 0)),
12799 "(318, 238) has color 0x%08x.\n", color);
12800 color = get_surface_color(rt, 322, 238);
12801 ok(compare_color(color, 0x00ffffff, 0)
12802 || broken(ddraw_is_amd(ddraw) && compare_color(color, 0x0000ff00, 0)),
12803 "(322, 328) has color 0x%08x.\n", color);
12804 color = get_surface_color(rt, 318, 242);
12805 ok(compare_color(color, 0x00ffffff, 0)
12806 || broken(ddraw_is_amd(ddraw) && compare_color(color, 0x0000ff00, 0)),
12807 "(318, 242) has color 0x%08x.\n", color);
12808 color = get_surface_color(rt, 322, 242);
12809 ok(compare_color(color, 0x0000ff00, 0), "(322, 242) has color 0x%08x.\n", color);
12811 color = get_surface_color(rt, 478, 358);
12812 ok(compare_color(color, 0x0000ff00, 0), "(478, 358) has color 0x%08x.\n", color);
12813 color = get_surface_color(rt, 482, 358);
12814 ok(compare_color(color, 0x00ffffff, 0)
12815 || broken(ddraw_is_amd(ddraw) && compare_color(color, 0x000000ff, 0)),
12816 "(482, 358) has color 0x%08x.\n", color);
12817 color = get_surface_color(rt, 478, 362);
12818 ok(compare_color(color, 0x00ffffff, 0)
12819 || broken(ddraw_is_amd(ddraw) && compare_color(color, 0x000000ff, 0)),
12820 "(478, 362) has color 0x%08x.\n", color);
12821 color = get_surface_color(rt, 482, 362);
12822 ok(compare_color(color, 0x00ffffff, 0)
12823 || broken(ddraw_is_amd(ddraw) && compare_color(color, 0x000000ff, 0)),
12824 "(482, 362) has color 0x%08x.\n", color);
12826 /* The clear rectangle is rendertarget absolute, not relative to the
12827 * viewport. */
12828 hr = IDirect3DViewport_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
12829 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
12830 U1(rect[0]).x1 = 330;
12831 U2(rect[0]).y1 = 250;
12832 U3(rect[0]).x2 = 340;
12833 U4(rect[0]).y2 = 260;
12834 hr = IDirect3DViewport_Clear(viewport3, 1, &rect[0], D3DCLEAR_TARGET);
12835 ok(SUCCEEDED(hr), "Failed to clear, hr %#lx.\n", hr);
12837 color = get_surface_color(rt, 328, 248);
12838 ok(compare_color(color, 0x00ffffff, 0), "(328, 248) has color 0x%08x.\n", color);
12839 color = get_surface_color(rt, 332, 248);
12840 ok(compare_color(color, 0x00ffffff, 0), "(332, 248) has color 0x%08x.\n", color);
12841 color = get_surface_color(rt, 328, 252);
12842 ok(compare_color(color, 0x00ffffff, 0), "(328, 252) has color 0x%08x.\n", color);
12843 color = get_surface_color(rt, 332, 252);
12844 ok(compare_color(color, 0x0000ff00, 0), "(332, 252) has color 0x%08x.\n", color);
12846 color = get_surface_color(rt, 338, 248);
12847 ok(compare_color(color, 0x00ffffff, 0), "(338, 248) has color 0x%08x.\n", color);
12848 color = get_surface_color(rt, 342, 248);
12849 ok(compare_color(color, 0x00ffffff, 0), "(342, 248) has color 0x%08x.\n", color);
12850 color = get_surface_color(rt, 338, 252);
12851 ok(compare_color(color, 0x0000ff00, 0), "(338, 252) has color 0x%08x.\n", color);
12852 color = get_surface_color(rt, 342, 252);
12853 ok(compare_color(color, 0x00ffffff, 0), "(342, 252) has color 0x%08x.\n", color);
12855 color = get_surface_color(rt, 328, 258);
12856 ok(compare_color(color, 0x00ffffff, 0), "(328, 258) has color 0x%08x.\n", color);
12857 color = get_surface_color(rt, 332, 258);
12858 ok(compare_color(color, 0x0000ff00, 0), "(332, 258) has color 0x%08x.\n", color);
12859 color = get_surface_color(rt, 328, 262);
12860 ok(compare_color(color, 0x00ffffff, 0), "(328, 262) has color 0x%08x.\n", color);
12861 color = get_surface_color(rt, 332, 262);
12862 ok(compare_color(color, 0x00ffffff, 0), "(332, 262) has color 0x%08x.\n", color);
12864 color = get_surface_color(rt, 338, 258);
12865 ok(compare_color(color, 0x0000ff00, 0), "(338, 258) has color 0x%08x.\n", color);
12866 color = get_surface_color(rt, 342, 258);
12867 ok(compare_color(color, 0x00ffffff, 0), "(342, 258) has color 0x%08x.\n", color);
12868 color = get_surface_color(rt, 338, 262);
12869 ok(compare_color(color, 0x00ffffff, 0), "(338, 262) has color 0x%08x.\n", color);
12870 color = get_surface_color(rt, 342, 262);
12871 ok(compare_color(color, 0x00ffffff, 0), "(342, 262) has color 0x%08x.\n", color);
12873 /* COLORWRITEENABLE, SRGBWRITEENABLE and scissor rectangles do not exist
12874 * in d3d1. */
12876 IDirect3DViewport_Release(viewport3);
12877 IDirect3DViewport_Release(viewport2);
12878 IDirect3DViewport_Release(viewport);
12879 IDirect3DMaterial_Release(white);
12880 IDirect3DMaterial_Release(red);
12881 IDirect3DMaterial_Release(green);
12882 IDirect3DMaterial_Release(blue);
12883 IDirectDrawSurface_Release(rt);
12884 refcount = IDirect3DDevice_Release(device);
12885 ok(!refcount, "Device has %lu references left.\n", refcount);
12886 refcount = IDirectDraw_Release(ddraw);
12887 ok(!refcount, "Ddraw object has %lu references left.\n", refcount);
12888 DestroyWindow(window);
12891 struct enum_surfaces_param
12893 IDirectDraw *ddraw;
12894 DDSURFACEDESC modes[20];
12895 unsigned int mode_count;
12897 IDirectDrawSurface *surfaces[8];
12898 unsigned int count;
12901 static HRESULT CALLBACK build_mode_list_cb(DDSURFACEDESC *desc, void *context)
12903 struct enum_surfaces_param *param = context;
12904 IDirectDrawSurface *surface;
12906 if (SUCCEEDED(IDirectDraw_CreateSurface(param->ddraw, desc, &surface, NULL)))
12908 if (param->mode_count < ARRAY_SIZE(param->modes))
12909 param->modes[param->mode_count] = *desc;
12910 ++param->mode_count;
12911 IDirectDrawSurface_Release(surface);
12914 return DDENUMRET_OK;
12917 static HRESULT WINAPI enum_surfaces_cb(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
12919 struct enum_surfaces_param *param = context;
12920 BOOL found = FALSE;
12921 unsigned int i;
12923 for (i = 0; i < ARRAY_SIZE(param->surfaces); ++i)
12925 if (param->surfaces[i] == surface)
12927 found = TRUE;
12928 break;
12932 ok(found, "Unexpected surface %p enumerated.\n", surface);
12933 IDirectDrawSurface_Release(surface);
12934 ++param->count;
12936 return DDENUMRET_OK;
12939 static HRESULT WINAPI enum_surfaces_create_cb(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
12941 static const DWORD expect_flags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_PIXELFORMAT;
12942 struct enum_surfaces_param *param = context;
12944 ok(!surface, "Unexpected surface %p.\n", surface);
12945 ok((desc->dwFlags & expect_flags) == expect_flags, "Got unexpected flags %#lx.\n", desc->dwFlags);
12946 if (param->count < ARRAY_SIZE(param->modes))
12948 const DDSURFACEDESC *expect = &param->modes[param->count];
12949 ok(desc->dwWidth == expect->dwWidth, "Expected width %lu, got %lu.\n", expect->dwWidth, desc->dwWidth);
12950 ok(desc->dwHeight == expect->dwHeight, "Expected height %lu, got %lu.\n", expect->dwHeight, desc->dwHeight);
12951 ok(!memcmp(&U4(*desc).ddpfPixelFormat, &U4(*expect).ddpfPixelFormat, sizeof(U4(*desc).ddpfPixelFormat)),
12952 "Pixel formats didn't match.\n");
12955 ++param->count;
12957 return DDENUMRET_OK;
12960 static void test_enum_surfaces(void)
12962 struct enum_surfaces_param param = {0};
12963 DDPIXELFORMAT current_format;
12964 IDirectDraw *ddraw;
12965 DDSURFACEDESC desc;
12966 HRESULT hr;
12968 ddraw = create_ddraw();
12969 ok(!!ddraw, "Failed to create a ddraw object.\n");
12970 param.ddraw = ddraw;
12972 memset(&desc, 0, sizeof(desc));
12973 desc.dwSize = sizeof(desc);
12974 hr = IDirectDraw_GetDisplayMode(ddraw, &desc);
12975 ok(hr == DD_OK, "Failed to get display mode, hr %#lx.\n", hr);
12976 current_format = desc.ddpfPixelFormat;
12978 hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
12979 ok(hr == DD_OK, "Failed to set cooperative level, hr %#lx.\n", hr);
12981 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_ALL, NULL, NULL, enum_surfaces_cb);
12982 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
12984 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_ALL,
12985 NULL, NULL, enum_surfaces_cb);
12986 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
12988 memset(&desc, 0, sizeof(desc));
12989 desc.dwSize = sizeof(desc);
12990 desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
12991 desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
12992 U2(desc).dwMipMapCount = 3;
12993 desc.dwWidth = 32;
12994 desc.dwHeight = 32;
12995 hr = IDirectDraw_CreateSurface(ddraw, &desc, &param.surfaces[0], NULL);
12996 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
12998 hr = IDirectDrawSurface_GetAttachedSurface(param.surfaces[0], &desc.ddsCaps, &param.surfaces[1]);
12999 ok(SUCCEEDED(hr), "Failed to get attached surface, hr %#lx.\n", hr);
13000 hr = IDirectDrawSurface_GetAttachedSurface(param.surfaces[1], &desc.ddsCaps, &param.surfaces[2]);
13001 ok(SUCCEEDED(hr), "Failed to get attached surface, hr %#lx.\n", hr);
13002 hr = IDirectDrawSurface_GetAttachedSurface(param.surfaces[2], &desc.ddsCaps, &param.surfaces[3]);
13003 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
13004 ok(!param.surfaces[3], "Got unexpected pointer %p.\n", param.surfaces[3]);
13006 param.count = 0;
13007 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_ALL,
13008 &desc, &param, enum_surfaces_cb);
13009 ok(SUCCEEDED(hr), "Failed to enumerate surfaces, hr %#lx.\n", hr);
13010 ok(param.count == 3, "Got unexpected number of enumerated surfaces %u.\n", param.count);
13012 param.count = 0;
13013 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_ALL,
13014 NULL, &param, enum_surfaces_cb);
13015 ok(SUCCEEDED(hr), "Failed to enumerate surfaces, hr %#lx.\n", hr);
13016 ok(param.count == 3, "Got unexpected number of enumerated surfaces %u.\n", param.count);
13018 desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
13019 param.count = 0;
13020 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_MATCH,
13021 &desc, &param, enum_surfaces_cb);
13022 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13023 ok(param.count == 1, "Got unexpected number of enumerated surfaces %u.\n", param.count);
13025 param.count = 0;
13026 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_NOMATCH,
13027 &desc, &param, enum_surfaces_cb);
13028 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13029 ok(param.count == 2, "Got unexpected number of enumerated surfaces %u.\n", param.count);
13031 desc.dwFlags = 0;
13032 param.count = 0;
13033 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_MATCH,
13034 &desc, &param, enum_surfaces_cb);
13035 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13036 ok(param.count == 3, "Got unexpected number of enumerated surfaces %u.\n", param.count);
13038 desc.dwFlags = 0;
13039 param.count = 0;
13040 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST, &desc, &param, enum_surfaces_cb);
13041 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13042 ok(param.count == 3, "Got unexpected number of enumerated surfaces %u.\n", param.count);
13044 IDirectDrawSurface_Release(param.surfaces[2]);
13045 IDirectDrawSurface_Release(param.surfaces[1]);
13046 IDirectDrawSurface_Release(param.surfaces[0]);
13048 param.count = 0;
13049 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_ALL,
13050 NULL, &param, enum_surfaces_cb);
13051 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13052 ok(!param.count, "Got unexpected number of enumerated surfaces %u.\n", param.count);
13054 memset(&desc, 0, sizeof(desc));
13055 desc.dwSize = sizeof(desc);
13056 desc.dwFlags = DDSD_CAPS;
13057 desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
13059 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_ALL,
13060 &desc, &param, enum_surfaces_create_cb);
13061 ok(hr == DDERR_INVALIDPARAMS, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13063 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_NOMATCH,
13064 &desc, &param, enum_surfaces_create_cb);
13065 ok(hr == DDERR_INVALIDPARAMS, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13067 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED,
13068 &desc, &param, enum_surfaces_create_cb);
13069 ok(hr == DDERR_INVALIDPARAMS, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13071 /* When not passed width and height, the callback is called with every
13072 * available display resolution. */
13074 param.mode_count = 0;
13075 desc.dwFlags |= DDSD_PIXELFORMAT;
13076 U4(desc).ddpfPixelFormat = current_format;
13077 hr = IDirectDraw_EnumDisplayModes(ddraw, 0, &desc, &param, build_mode_list_cb);
13078 ok(hr == DD_OK, "Failed to build mode list, hr %#lx.\n", hr);
13080 param.count = 0;
13081 desc.dwFlags &= ~DDSD_PIXELFORMAT;
13082 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_MATCH,
13083 &desc, &param, enum_surfaces_create_cb);
13084 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13085 ok(param.count == param.mode_count, "Expected %u surfaces, got %u.\n", param.mode_count, param.count);
13087 desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
13088 desc.dwWidth = desc.dwHeight = 32;
13090 param.modes[0].dwWidth = param.modes[0].dwHeight = 32;
13092 param.count = 0;
13093 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_MATCH,
13094 &desc, &param, enum_surfaces_create_cb);
13095 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13096 ok(param.count == 1, "Got unexpected number of enumerated surfaces %u.\n", param.count);
13098 hr = IDirectDraw_CreateSurface(ddraw, &desc, &param.surfaces[0], NULL);
13099 ok(hr == DD_OK, "Failed to create surface, hr %#lx.\n", hr);
13100 param.count = 0;
13101 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_MATCH,
13102 &desc, &param, enum_surfaces_create_cb);
13103 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13104 ok(param.count == 1, "Got unexpected number of enumerated surfaces %u.\n", param.count);
13105 IDirectDrawSurface_Release(param.surfaces[0]);
13107 desc.dwFlags |= DDSD_PIXELFORMAT;
13108 desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
13109 desc.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
13110 desc.ddpfPixelFormat.dwFourCC = 0xdeadbeef;
13112 param.count = 0;
13113 hr = IDirectDraw_EnumSurfaces(ddraw, DDENUMSURFACES_CANBECREATED | DDENUMSURFACES_MATCH,
13114 &desc, &param, enum_surfaces_create_cb);
13115 ok(hr == DD_OK, "Failed to enumerate surfaces, hr %#lx.\n", hr);
13116 ok(!param.count, "Got unexpected number of enumerated surfaces %u.\n", param.count);
13118 IDirectDraw_Release(ddraw);
13121 static void test_execute_data(void)
13123 IDirect3DExecuteBuffer *execute_buffer;
13124 D3DEXECUTEBUFFERDESC exec_desc;
13125 IDirect3DDevice *device;
13126 IDirectDraw *ddraw;
13127 HWND window;
13128 HRESULT hr;
13129 D3DEXECUTEDATA exec_data;
13131 window = create_window();
13132 ddraw = create_ddraw();
13133 ok(!!ddraw, "Failed to create a ddraw object.\n");
13134 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
13136 skip("Failed to create a 3D device, skipping test.\n");
13137 IDirectDraw_Release(ddraw);
13138 DestroyWindow(window);
13139 return;
13142 memset(&exec_desc, 0, sizeof(exec_desc));
13143 exec_desc.dwSize = sizeof(exec_desc);
13144 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
13145 exec_desc.dwBufferSize = 1024;
13146 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
13148 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
13149 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
13151 memset(&exec_data, 0, sizeof(exec_data));
13153 /* Success case. */
13154 exec_data.dwSize = sizeof(exec_data);
13155 exec_data.dwVertexCount = 3;
13156 exec_data.dwInstructionOffset = 3 * sizeof(D3DVERTEX);
13157 exec_data.dwInstructionLength = 10;
13158 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
13159 ok(SUCCEEDED(hr), "Failed to set execute data, hr %#lx.\n", hr);
13161 /* dwSize is checked against the expected struct size. */
13162 exec_data.dwSize = sizeof(exec_data) - 1;
13163 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
13164 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13165 exec_data.dwSize = sizeof(exec_data) + 1;
13166 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
13167 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13169 /* The rest of the data is not checked for plausibility. */
13170 exec_data.dwSize = sizeof(exec_data);
13171 exec_data.dwVertexCount = 0;
13172 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
13173 ok(SUCCEEDED(hr), "Failed to set execute data, hr %#lx.\n", hr);
13174 exec_data.dwVertexCount = exec_desc.dwBufferSize / sizeof(D3DVERTEX) - 1;
13175 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
13176 ok(SUCCEEDED(hr), "Failed to set execute data, hr %#lx.\n", hr);
13177 exec_data.dwVertexCount = exec_desc.dwBufferSize / sizeof(D3DVERTEX);
13178 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
13179 ok(SUCCEEDED(hr), "Failed to set execute data, hr %#lx.\n", hr);
13180 exec_data.dwVertexCount = exec_desc.dwBufferSize / sizeof(D3DVERTEX) + 1;
13181 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
13182 ok(SUCCEEDED(hr), "Failed to set execute data, hr %#lx.\n", hr);
13183 exec_data.dwVertexCount = 999999;
13184 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
13185 ok(SUCCEEDED(hr), "Failed to set execute data, hr %#lx.\n", hr);
13186 exec_data.dwInstructionOffset = 999999 * sizeof(D3DVERTEX);
13187 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
13188 ok(SUCCEEDED(hr), "Failed to set execute data, hr %#lx.\n", hr);
13189 exec_data.dwInstructionLength = 10240;
13190 hr = IDirect3DExecuteBuffer_SetExecuteData(execute_buffer, &exec_data);
13191 ok(SUCCEEDED(hr), "Failed to set execute data, hr %#lx.\n", hr);
13193 /* The input structure is not modified. */
13194 ok(exec_data.dwSize == sizeof(exec_data), "Got unexpected struct size %lu.\n",
13195 exec_data.dwSize);
13196 ok(exec_data.dwVertexCount == 999999, "Got unexpected vertex count %lu.\n",
13197 exec_data.dwVertexCount);
13198 ok(exec_data.dwInstructionOffset == 999999 * sizeof(D3DVERTEX), "Got unexpected instruction offset %lu.\n",
13199 exec_data.dwInstructionOffset);
13200 ok(exec_data.dwInstructionLength == 10240, "Got unexpected instruction length %lu.\n",
13201 exec_data.dwInstructionLength);
13203 /* No validation in GetExecuteData. */
13204 memset(&exec_data, 0, sizeof(exec_data));
13205 exec_desc.dwSize = sizeof(exec_desc);
13206 hr = IDirect3DExecuteBuffer_GetExecuteData(execute_buffer, &exec_data);
13207 ok(SUCCEEDED(hr), "Failed to get execute data, hr %#lx.\n", hr);
13209 ok(exec_data.dwSize == sizeof(exec_data), "Got unexpected struct size %lu.\n",
13210 exec_data.dwSize);
13211 ok(exec_data.dwVertexCount == 999999, "Got unexpected vertex count %lu.\n",
13212 exec_data.dwVertexCount);
13213 ok(exec_data.dwInstructionOffset == 999999 * sizeof(D3DVERTEX), "Got unexpected instruction offset %lu.\n",
13214 exec_data.dwInstructionOffset);
13215 ok(exec_data.dwInstructionLength == 10240, "Got unexpected instruction length %lu.\n",
13216 exec_data.dwInstructionLength);
13218 memset(&exec_data, 0xaa, sizeof(exec_data));
13219 exec_desc.dwSize = sizeof(exec_desc) - 1;
13220 hr = IDirect3DExecuteBuffer_GetExecuteData(execute_buffer, &exec_data);
13221 ok(SUCCEEDED(hr), "Failed to get execute data, hr %#lx.\n", hr);
13222 ok(exec_data.dwSize == sizeof(exec_data), "Got unexpected struct size %lu.\n",
13223 exec_data.dwSize);
13224 ok(exec_data.dwVertexCount == 999999, "Got unexpected vertex count %lu.\n",
13225 exec_data.dwVertexCount);
13226 ok(exec_data.dwInstructionOffset == 999999 * sizeof(D3DVERTEX), "Got unexpected instruction offset %lu.\n",
13227 exec_data.dwInstructionOffset);
13228 ok(exec_data.dwInstructionLength == 10240, "Got unexpected instruction length %lu.\n",
13229 exec_data.dwInstructionLength);
13231 exec_desc.dwSize = 0;
13232 hr = IDirect3DExecuteBuffer_GetExecuteData(execute_buffer, &exec_data);
13233 ok(SUCCEEDED(hr), "Failed to get execute data, hr %#lx.\n", hr);
13234 exec_desc.dwSize = sizeof(exec_desc) + 1;
13235 hr = IDirect3DExecuteBuffer_GetExecuteData(execute_buffer, &exec_data);
13236 ok(SUCCEEDED(hr), "Failed to get execute data, hr %#lx.\n", hr);
13237 exec_desc.dwSize = ~0U;
13238 hr = IDirect3DExecuteBuffer_GetExecuteData(execute_buffer, &exec_data);
13239 ok(SUCCEEDED(hr), "Failed to get execute data, hr %#lx.\n", hr);
13241 IDirect3DExecuteBuffer_Release(execute_buffer);
13242 IDirect3DDevice_Release(device);
13243 IDirectDraw_Release(ddraw);
13244 DestroyWindow(window);
13247 static void test_viewport(void)
13249 static struct
13251 D3DVIEWPORT7 vp;
13252 RECT expected_rect;
13253 const char *message;
13255 tests[] =
13257 {{ 0, 0, 640, 480}, { 0, 120, 479, 359}, "(0, 0) - (640, 480) viewport"},
13258 {{ 0, 0, 320, 240}, { 0, 60, 239, 179}, "(0, 0) - (320, 240) viewport"},
13259 {{ 0, 0, 1280, 960}, {-10, -10, -1, -1}, "(0, 0) - (1280, 960) viewport"},
13260 {{ 0, 0, 2000, 1600}, {-10, -10, -1, -1}, "(0, 0) - (2000, 1600) viewport"},
13261 {{100, 100, 640, 480}, {-10, -10, -1, -1}, "(100, 100) - (640, 480) viewport"},
13262 {{ 0, 0, 8192, 8192}, {-10, -10, -1, -1}, "(0, 0) - (8192, 8192) viewport"},
13264 static D3DMATRIX mat =
13266 1.0f, 0.0f, 0.0f, 0.0f,
13267 0.0f, 1.0f, 0.0f, 0.0f,
13268 0.0f, 0.0f, 1.0f, 0.0f,
13269 0.0f, 0.0f, 0.0f, 1.0f,
13271 static D3DLVERTEX quad[] =
13273 {{-1.5f}, {-0.5f}, {0.1f}, 0, {0xffffffff}},
13274 {{-1.5f}, { 0.5f}, {0.1f}, 0, {0xffffffff}},
13275 {{ 0.5f}, {-0.5f}, {0.1f}, 0, {0xffffffff}},
13276 {{ 0.5f}, { 0.5f}, {0.1f}, 0, {0xffffffff}},
13278 D3DMATRIXHANDLE world_handle, view_handle, proj_handle;
13279 IDirect3DViewport *viewport, *full_viewport;
13280 IDirect3DExecuteBuffer *execute_buffer;
13281 IDirect3DMaterial *black_background;
13282 D3DEXECUTEBUFFERDESC exec_desc;
13283 IDirect3DDevice *device;
13284 IDirectDrawSurface *rt;
13285 IDirectDraw *ddraw;
13286 D3DRECT clear_rect;
13287 UINT inst_length;
13288 unsigned int j;
13289 IDirect3D *d3d;
13290 D3DVIEWPORT vp;
13291 ULONG refcount;
13292 HWND window;
13293 HRESULT hr;
13294 void *ptr;
13296 window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
13297 0, 0, 640, 480, 0, 0, 0, 0);
13298 ddraw = create_ddraw();
13299 ok(!!ddraw, "Failed to create a ddraw object.\n");
13300 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
13302 skip("Failed to create a 3D device, skipping test.\n");
13303 IDirectDraw_Release(ddraw);
13304 DestroyWindow(window);
13305 return;
13308 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
13309 ok(SUCCEEDED(hr), "Failed to get render target, hr %#lx.\n", hr);
13311 hr = IDirect3DDevice_GetDirect3D(device, &d3d);
13312 ok(SUCCEEDED(hr), "Failed to get Direct3D3 interface, hr %#lx.\n", hr);
13314 black_background = create_diffuse_material(device, 0.0f, 0.0f, 0.0f, 0.0f);
13316 hr = IDirect3DDevice_CreateMatrix(device, &world_handle);
13317 ok(SUCCEEDED(hr), "Creating a matrix object failed, hr %#lx.\n", hr);
13318 hr = IDirect3DDevice_SetMatrix(device, world_handle, &mat);
13319 ok(SUCCEEDED(hr), "Setting a matrix object failed, hr %#lx.\n", hr);
13320 hr = IDirect3DDevice_CreateMatrix(device, &view_handle);
13321 ok(SUCCEEDED(hr), "Creating a matrix object failed, hr %#lx.\n", hr);
13322 hr = IDirect3DDevice_SetMatrix(device, view_handle, &mat);
13323 ok(SUCCEEDED(hr), "Setting a matrix object failed, hr %#lx.\n", hr);
13324 hr = IDirect3DDevice_CreateMatrix(device, &proj_handle);
13325 ok(SUCCEEDED(hr), "Creating a matrix object failed, hr %#lx.\n", hr);
13326 hr = IDirect3DDevice_SetMatrix(device, proj_handle, &mat);
13327 ok(SUCCEEDED(hr), "Setting a matrix object failed, hr %#lx.\n", hr);
13329 memset(&exec_desc, 0, sizeof(exec_desc));
13330 exec_desc.dwSize = sizeof(exec_desc);
13331 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
13332 exec_desc.dwBufferSize = 1024;
13333 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
13335 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
13336 ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr);
13338 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
13339 ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr);
13341 memcpy(exec_desc.lpData, quad, sizeof(quad));
13342 ptr = ((BYTE *)exec_desc.lpData) + sizeof(quad);
13343 emit_set_ts(&ptr, D3DTRANSFORMSTATE_WORLD, world_handle);
13344 emit_set_ts(&ptr, D3DTRANSFORMSTATE_VIEW, view_handle);
13345 emit_set_ts(&ptr, D3DTRANSFORMSTATE_PROJECTION, proj_handle);
13346 emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, FALSE);
13347 emit_set_rs(&ptr, D3DRENDERSTATE_FOGENABLE, FALSE);
13348 emit_set_rs(&ptr, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
13349 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORM, 0, 4);
13350 emit_tquad(&ptr, 0);
13351 emit_end(&ptr);
13352 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
13353 inst_length -= sizeof(quad);
13355 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
13356 ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
13358 full_viewport = create_viewport(device, 0, 0, 640, 480);
13359 viewport_set_background(device, full_viewport, black_background);
13361 U1(clear_rect).x1 = U2(clear_rect).y1 = 0;
13362 U3(clear_rect).x2 = 640;
13363 U4(clear_rect).y2 = 480;
13365 for (j = 0; j < ARRAY_SIZE(tests); ++j)
13367 winetest_push_context("%s", tests[j].message);
13369 hr = IDirect3DViewport_Clear(full_viewport, 1, &clear_rect, D3DCLEAR_TARGET);
13370 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13372 hr = IDirect3D_CreateViewport(d3d, &viewport, NULL);
13373 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13374 memset(&vp, 0, sizeof(vp));
13375 vp.dwSize = sizeof(vp);
13376 vp.dwX = tests[j].vp.dwX;
13377 vp.dwY = tests[j].vp.dwY;
13378 vp.dwWidth = tests[j].vp.dwWidth;
13379 vp.dwHeight = tests[j].vp.dwHeight;
13380 vp.dvScaleX = tests[j].vp.dwWidth / 2.0f;
13381 vp.dvScaleY = tests[j].vp.dwHeight / 2.0f;
13382 vp.dvMaxX = 1.0f;
13383 vp.dvMaxY = 1.0f;
13384 vp.dvMinZ = 0.0f;
13385 vp.dvMaxZ = 1.0f;
13386 hr = IDirect3DViewport_SetViewport(viewport, &vp);
13387 ok(hr == D3DERR_VIEWPORTHASNODEVICE, "Got unexpected hr %#lx.\n", hr);
13388 hr = IDirect3DDevice_AddViewport(device, viewport);
13389 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13390 hr = IDirect3DViewport_SetViewport(viewport, &vp);
13391 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13393 hr = IDirect3DDevice_BeginScene(device);
13394 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13396 set_execute_data(execute_buffer, 4, sizeof(quad), inst_length);
13397 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
13398 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13400 hr = IDirect3DDevice_EndScene(device);
13401 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13403 check_rect(rt, tests[j].expected_rect);
13405 destroy_viewport(device, viewport);
13407 winetest_pop_context();
13410 destroy_viewport(device, full_viewport);
13411 IDirectDrawSurface_Release(rt);
13413 IDirect3DExecuteBuffer_Release(execute_buffer);
13414 IDirect3DDevice_DeleteMatrix(device, world_handle);
13415 IDirect3DDevice_DeleteMatrix(device, view_handle);
13416 IDirect3DDevice_DeleteMatrix(device, proj_handle);
13417 destroy_material(black_background);
13418 refcount = IDirect3DDevice_Release(device);
13419 ok(!refcount, "Device has %lu references left.\n", refcount);
13420 IDirect3D2_Release(d3d);
13421 IDirectDraw_Release(ddraw);
13422 DestroyWindow(window);
13425 static void test_find_device(void)
13427 D3DFINDDEVICESEARCH search = {0};
13428 D3DFINDDEVICERESULT result = {0};
13429 IDirect3DDevice *device;
13430 IDirectDraw *ddraw;
13431 IDirect3D *d3d;
13432 unsigned int i;
13433 HWND window;
13434 HRESULT hr;
13436 struct
13438 DWORD size;
13439 GUID guid;
13440 D3DDEVICEDESC_V1 hw_desc;
13441 D3DDEVICEDESC_V1 sw_desc;
13442 } result_v1;
13444 struct
13446 DWORD size;
13447 GUID guid;
13448 D3DDEVICEDESC_V2 hw_desc;
13449 D3DDEVICEDESC_V2 sw_desc;
13450 } result_v2;
13452 static const struct
13454 const GUID *guid;
13455 HRESULT hr;
13457 tests[] =
13459 {&IID_IDirect3D, DDERR_NOTFOUND},
13460 {&IID_IDirect3DRampDevice, D3D_OK},
13461 {&IID_IDirect3DRGBDevice, D3D_OK},
13462 {&IID_IDirect3DMMXDevice, DDERR_NOTFOUND},
13463 {&IID_IDirect3DRefDevice, DDERR_NOTFOUND},
13464 {&IID_IDirect3DTnLHalDevice, DDERR_NOTFOUND},
13465 {&IID_IDirect3DNullDevice, DDERR_NOTFOUND},
13468 ddraw = create_ddraw();
13469 ok(!!ddraw, "Failed to create a ddraw object.\n");
13471 if (FAILED(IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d)))
13473 skip("D3D interface is not available, skipping test.\n");
13474 IDirectDraw_Release(ddraw);
13475 return;
13478 result.dwSize = sizeof(result);
13479 search.dwSize = sizeof(search);
13480 hr = IDirect3D_FindDevice(d3d, NULL, NULL);
13481 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13482 hr = IDirect3D_FindDevice(d3d, NULL, &result);
13483 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13484 hr = IDirect3D_FindDevice(d3d, &search, NULL);
13485 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13486 hr = IDirect3D_FindDevice(d3d, &search, &result);
13487 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13488 ok(result.dwSize == sizeof(result), "Got unexpected result size %lu.\n", result.dwSize);
13489 ok(result.ddHwDesc.dwSize == sizeof(result_v1.hw_desc),
13490 "Got unexpected HW desc size %lu.\n", result.ddHwDesc.dwSize);
13491 ok(result.ddSwDesc.dwSize == sizeof(result_v1.sw_desc),
13492 "Got unexpected SW desc size %lu.\n", result.ddSwDesc.dwSize);
13494 memset(&search, 0, sizeof(search));
13495 memset(&result, 0, sizeof(result));
13496 hr = IDirect3D_FindDevice(d3d, &search, &result);
13497 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13499 search.dwSize = sizeof(search) + 1;
13500 result.dwSize = sizeof(result) + 1;
13501 hr = IDirect3D_FindDevice(d3d, &search, &result);
13502 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
13504 search.dwSize = sizeof(search);
13506 memset(&result_v1, 0, sizeof(result_v1));
13507 result_v1.size = sizeof(result_v1);
13508 hr = IDirect3D_FindDevice(d3d, &search, (D3DFINDDEVICERESULT *)&result_v1);
13509 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13510 ok(result_v1.hw_desc.dwSize == sizeof(result_v1.hw_desc),
13511 "Got unexpected HW desc size %lu.\n", result_v1.hw_desc.dwSize);
13512 ok(result_v1.sw_desc.dwSize == sizeof(result_v1.sw_desc),
13513 "Got unexpected SW desc size %lu.\n", result_v1.sw_desc.dwSize);
13515 memset(&result_v2, 0, sizeof(result_v2));
13516 result_v2.size = sizeof(result_v2);
13517 hr = IDirect3D_FindDevice(d3d, &search, (D3DFINDDEVICERESULT *)&result_v2);
13518 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13519 ok(result_v2.hw_desc.dwSize == sizeof(result_v1.hw_desc),
13520 "Got unexpected HW desc size %lu.\n", result_v2.hw_desc.dwSize);
13521 ok(result_v2.sw_desc.dwSize == sizeof(result_v1.sw_desc),
13522 "Got unexpected SW desc size %lu.\n", result_v2.sw_desc.dwSize);
13524 for (i = 0; i < ARRAY_SIZE(tests); ++i)
13526 memset(&search, 0, sizeof(search));
13527 search.dwSize = sizeof(search);
13528 search.dwFlags = D3DFDS_GUID;
13529 search.guid = *tests[i].guid;
13531 memset(&result, 0, sizeof(result));
13532 result.dwSize = sizeof(result);
13534 hr = IDirect3D_FindDevice(d3d, &search, &result);
13535 ok(hr == tests[i].hr, "Test %u: Got unexpected hr %#lx.\n", i, hr);
13536 ok(result.dwSize == sizeof(result), "Test %u: Got unexpected result size %lu.\n", i, result.dwSize);
13537 if (SUCCEEDED(hr))
13539 ok(result.ddHwDesc.dwSize == sizeof(result_v1.hw_desc),
13540 "Test %u: Got unexpected HW desc size %lu.\n", i, result.ddHwDesc.dwSize);
13541 ok(result.ddSwDesc.dwSize == sizeof(result_v1.sw_desc),
13542 "Test %u: Got unexpected SW desc size %lu.\n", i, result.ddSwDesc.dwSize);
13544 else
13546 ok(!result.ddHwDesc.dwSize,
13547 "Test %u: Got unexpected HW desc size %lu.\n", i, result.ddHwDesc.dwSize);
13548 ok(!result.ddSwDesc.dwSize,
13549 "Test %u: Got unexpected SW desc size %lu.\n", i, result.ddSwDesc.dwSize);
13553 /* The HAL device can only be enumerated if hardware acceleration is present. */
13554 search.dwSize = sizeof(search);
13555 search.dwFlags = D3DFDS_GUID;
13556 search.guid = IID_IDirect3DHALDevice;
13557 result.dwSize = sizeof(result);
13558 hr = IDirect3D_FindDevice(d3d, &search, &result);
13560 window = create_window();
13561 device = create_device(ddraw, window, DDSCL_NORMAL);
13562 if (hr == D3D_OK)
13563 ok(!!device, "Failed to create a 3D device.\n");
13564 else
13565 ok(!device, "Succeeded to create a 3D device.\n");
13566 if (device)
13567 IDirect3DDevice_Release(device);
13568 DestroyWindow(window);
13570 /* Curiously the colour model criteria seem to be ignored. */
13571 search.dwSize = sizeof(search);
13572 search.dwFlags = D3DFDS_COLORMODEL;
13573 search.dcmColorModel = 0xdeadbeef;
13574 result.dwSize = sizeof(result);
13575 hr = IDirect3D_FindDevice(d3d, &search, &result);
13576 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13578 IDirect3D_Release(d3d);
13579 IDirectDraw_Release(ddraw);
13582 static IDirectDraw *killfocus_ddraw;
13583 static IDirectDrawSurface *killfocus_surface;
13585 static LRESULT CALLBACK killfocus_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
13587 ULONG ref;
13589 if (message == WM_KILLFOCUS)
13591 ref = IDirectDrawSurface_Release(killfocus_surface);
13592 ok(!ref, "Unexpected surface refcount %lu.\n", ref);
13593 ref = IDirectDraw_Release(killfocus_ddraw);
13594 ok(!ref, "Unexpected ddraw refcount %lu.\n", ref);
13595 killfocus_ddraw = NULL;
13598 return DefWindowProcA(window, message, wparam, lparam);
13601 static void test_killfocus(void)
13603 DDSURFACEDESC surface_desc;
13604 HRESULT hr;
13605 HWND window;
13606 WNDCLASSA wc = {0};
13608 wc.lpfnWndProc = killfocus_proc;
13609 wc.lpszClassName = "ddraw_killfocus_wndproc_wc";
13610 ok(RegisterClassA(&wc), "Failed to register window class.\n");
13612 window = CreateWindowA("ddraw_killfocus_wndproc_wc", "d3d7_test", WS_OVERLAPPEDWINDOW,
13613 0, 0, 640, 480, 0, 0, 0, 0);
13615 killfocus_ddraw = create_ddraw();
13616 ok(!!killfocus_ddraw, "Failed to create a ddraw object.\n");
13618 hr = IDirectDraw_SetCooperativeLevel(killfocus_ddraw, window, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
13619 ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr);
13621 memset(&surface_desc, 0, sizeof(surface_desc));
13622 surface_desc.dwSize = sizeof(surface_desc);
13623 surface_desc.dwFlags = DDSD_CAPS;
13624 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
13625 hr = IDirectDraw_CreateSurface(killfocus_ddraw, &surface_desc, &killfocus_surface, NULL);
13626 ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
13628 SetForegroundWindow(GetDesktopWindow());
13629 ok(!killfocus_ddraw, "WM_KILLFOCUS was not received.\n");
13631 DestroyWindow(window);
13632 UnregisterClassA("ddraw_killfocus_wndproc_wc", GetModuleHandleA(NULL));
13635 static void test_gdi_surface(void)
13637 IDirectDrawSurface *primary, *backbuffer, *gdi_surface;
13638 DDSCAPS caps = {DDSCAPS_BACKBUFFER};
13639 DDSURFACEDESC surface_desc;
13640 IDirectDraw *ddraw;
13641 ULONG refcount;
13642 HWND window;
13643 HRESULT hr;
13645 window = create_window();
13646 ddraw = create_ddraw();
13647 ok(!!ddraw, "Failed to create a ddraw object.\n");
13648 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
13649 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13651 /* Retrieving the GDI surface requires a primary surface to exist. */
13652 gdi_surface = (void *)0xc0dec0de;
13653 hr = IDirectDraw_GetGDISurface(ddraw, &gdi_surface);
13654 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
13655 ok(!gdi_surface, "Got unexpected surface %p.\n", gdi_surface);
13657 hr = IDirectDraw_FlipToGDISurface(ddraw);
13658 ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#lx.\n", hr);
13660 memset(&surface_desc, 0, sizeof(surface_desc));
13661 surface_desc.dwSize = sizeof(surface_desc);
13662 surface_desc.dwFlags = DDSD_CAPS;
13663 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
13664 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &primary, NULL);
13665 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13667 hr = IDirectDraw_GetGDISurface(ddraw, &gdi_surface);
13668 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13669 ok(gdi_surface == primary, "Got unexpected surface %p, expected %p.\n", gdi_surface, primary);
13670 IDirectDrawSurface_Release(gdi_surface);
13672 /* Flipping to the GDI surface requires the primary surface to be
13673 * flippable. */
13674 hr = IDirectDraw_FlipToGDISurface(ddraw);
13675 ok(hr == DDERR_NOTFLIPPABLE, "Got unexpected hr %#lx.\n", hr);
13677 IDirectDrawSurface_Release(primary);
13679 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
13680 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13682 memset(&surface_desc, 0, sizeof(surface_desc));
13683 surface_desc.dwSize = sizeof(surface_desc);
13684 surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
13685 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
13686 U5(surface_desc).dwBackBufferCount = 1;
13687 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &primary, NULL);
13688 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13689 hr = IDirectDrawSurface_GetAttachedSurface(primary, &caps, &backbuffer);
13690 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13691 ok(backbuffer != primary, "Got unexpected backbuffer %p.\n", backbuffer);
13693 hr = IDirectDraw_GetGDISurface(ddraw, &gdi_surface);
13694 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13695 ok(gdi_surface == primary, "Got unexpected surface %p, expected %p.\n", gdi_surface, primary);
13696 IDirectDrawSurface_Release(gdi_surface);
13698 hr = IDirectDrawSurface_Flip(primary, NULL, DDFLIP_WAIT);
13699 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13700 hr = IDirectDraw_GetGDISurface(ddraw, &gdi_surface);
13701 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13702 ok(gdi_surface == backbuffer || broken(gdi_surface == primary),
13703 "Got unexpected surface %p, expected %p.\n", gdi_surface, backbuffer);
13704 IDirectDrawSurface_Release(gdi_surface);
13706 hr = IDirectDraw_FlipToGDISurface(ddraw);
13707 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13709 hr = IDirectDraw_GetGDISurface(ddraw, &gdi_surface);
13710 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13711 ok(gdi_surface == primary, "Got unexpected surface %p, expected %p.\n", gdi_surface, primary);
13712 IDirectDrawSurface_Release(gdi_surface);
13714 hr = IDirectDraw_FlipToGDISurface(ddraw);
13715 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13717 IDirectDrawSurface_Release(backbuffer);
13718 IDirectDrawSurface_Release(primary);
13720 refcount = IDirectDraw_Release(ddraw);
13721 ok(!refcount, "%lu references left.\n", refcount);
13722 DestroyWindow(window);
13725 static void test_alphatest(void)
13727 #define ALPHATEST_PASSED 0x0000ff00
13728 #define ALPHATEST_FAILED 0x00ff0000
13729 D3DRECT rect_full = {{0}, {0}, {640}, {480}};
13730 IDirect3DExecuteBuffer *execute_buffer;
13731 IDirect3DMaterial *blue, *failed;
13732 D3DEXECUTEBUFFERDESC exec_desc;
13733 IDirect3DViewport *viewport;
13734 IDirect3DDevice *device;
13735 IDirectDrawSurface *rt;
13736 unsigned int color, i;
13737 IDirectDraw *ddraw;
13738 UINT inst_length;
13739 ULONG refcount;
13740 HWND window;
13741 HRESULT hr;
13742 void *ptr;
13744 static const struct
13746 D3DCMPFUNC func;
13747 unsigned int color_less, color_equal, color_greater;
13749 test_data[] =
13751 {D3DCMP_NEVER, ALPHATEST_FAILED, ALPHATEST_FAILED, ALPHATEST_FAILED},
13752 {D3DCMP_LESS, ALPHATEST_PASSED, ALPHATEST_FAILED, ALPHATEST_FAILED},
13753 {D3DCMP_EQUAL, ALPHATEST_FAILED, ALPHATEST_PASSED, ALPHATEST_FAILED},
13754 {D3DCMP_LESSEQUAL, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_FAILED},
13755 {D3DCMP_GREATER, ALPHATEST_FAILED, ALPHATEST_FAILED, ALPHATEST_PASSED},
13756 {D3DCMP_NOTEQUAL, ALPHATEST_PASSED, ALPHATEST_FAILED, ALPHATEST_PASSED},
13757 {D3DCMP_GREATEREQUAL, ALPHATEST_FAILED, ALPHATEST_PASSED, ALPHATEST_PASSED},
13758 {D3DCMP_ALWAYS, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED},
13760 static D3DLVERTEX quad[] =
13762 {{-1.0f}, {-1.0f}, {0.1f}, 0, {ALPHATEST_PASSED | 0x80000000}},
13763 {{-1.0f}, { 1.0f}, {0.1f}, 0, {ALPHATEST_PASSED | 0x80000000}},
13764 {{ 1.0f}, {-1.0f}, {0.1f}, 0, {ALPHATEST_PASSED | 0x80000000}},
13765 {{ 1.0f}, { 1.0f}, {0.1f}, 0, {ALPHATEST_PASSED | 0x80000000}},
13768 window = create_window();
13769 ddraw = create_ddraw();
13770 ok(!!ddraw, "Failed to create a ddraw object.\n");
13771 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
13773 skip("Failed to create a 3D device.\n");
13774 IDirectDraw_Release(ddraw);
13775 DestroyWindow(window);
13776 return;
13778 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
13779 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13781 blue = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
13782 failed = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
13784 viewport = create_viewport(device, 0, 0, 640, 480);
13786 viewport_set_background(device, viewport, blue);
13787 hr = IDirect3DViewport_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
13788 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13790 memset(&exec_desc, 0, sizeof(exec_desc));
13791 exec_desc.dwSize = sizeof(exec_desc);
13792 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
13793 exec_desc.dwBufferSize = 1024;
13794 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
13796 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
13797 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13799 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
13800 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13802 ptr = exec_desc.lpData;
13803 emit_set_rs(&ptr, D3DRENDERSTATE_LIGHTING, FALSE);
13804 emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, FALSE);
13805 emit_set_rs(&ptr, D3DRENDERSTATE_ALPHATESTENABLE, TRUE);
13806 emit_end(&ptr);
13807 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
13809 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
13810 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13812 set_execute_data(execute_buffer, 0, 0, inst_length);
13813 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
13814 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13816 viewport_set_background(device, viewport, failed);
13817 for (i = 0; i < ARRAY_SIZE(test_data); ++i)
13819 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
13820 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13822 memcpy(exec_desc.lpData, quad, sizeof(quad));
13823 ptr = ((BYTE *)exec_desc.lpData) + sizeof(quad);
13824 emit_set_rs(&ptr, D3DRENDERSTATE_ALPHAFUNC, test_data[i].func);
13825 emit_set_rs(&ptr, D3DRENDERSTATE_ALPHAREF, 0x70);
13826 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORM, 0, ARRAY_SIZE(quad));
13827 emit_tquad(&ptr, 0);
13828 emit_end(&ptr);
13829 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
13830 inst_length -= sizeof(quad);
13832 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
13833 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13835 hr = IDirect3DViewport_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
13836 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13837 hr = IDirect3DDevice_BeginScene(device);
13838 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13839 set_execute_data(execute_buffer, ARRAY_SIZE(quad), sizeof(quad), inst_length);
13840 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
13841 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13842 hr = IDirect3DDevice_EndScene(device);
13843 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13844 color = get_surface_color(rt, 320, 240);
13845 ok(compare_color(color, test_data[i].color_greater, 0),
13846 "Alphatest failed, color 0x%08x, expected 0x%08x, alpha > ref, func %u.\n",
13847 color, test_data[i].color_greater, test_data[i].func);
13849 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
13850 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13852 memcpy(exec_desc.lpData, quad, sizeof(quad));
13853 ptr = ((BYTE *)exec_desc.lpData) + sizeof(quad);
13854 emit_set_rs(&ptr, D3DRENDERSTATE_ALPHAREF, 0xff70);
13855 emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORM, 0, ARRAY_SIZE(quad));
13856 emit_tquad(&ptr, 0);
13857 emit_end(&ptr);
13858 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
13859 inst_length -= sizeof(quad);
13861 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
13862 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13864 hr = IDirect3DViewport_Clear(viewport, 1, &rect_full, D3DCLEAR_TARGET);
13865 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13866 hr = IDirect3DDevice_BeginScene(device);
13867 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13868 set_execute_data(execute_buffer, ARRAY_SIZE(quad), sizeof(quad), inst_length);
13869 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
13870 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13871 hr = IDirect3DDevice_EndScene(device);
13872 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
13873 color = get_surface_color(rt, 320, 240);
13874 ok(compare_color(color, test_data[i].color_greater, 0),
13875 "Alphatest failed, color 0x%08x, expected 0x%08x, alpha > ref, func %u.\n",
13876 color, test_data[i].color_greater, test_data[i].func);
13879 IDirect3DExecuteBuffer_Release(execute_buffer);
13880 destroy_viewport(device, viewport);
13881 destroy_material(failed);
13882 destroy_material(blue);
13883 IDirectDrawSurface_Release(rt);
13884 refcount = IDirect3DDevice_Release(device);
13885 ok(!refcount, "Device has %lu references left.\n", refcount);
13886 refcount = IDirectDraw_Release(ddraw);
13887 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
13888 DestroyWindow(window);
13891 static void test_clipper_refcount(void)
13893 IDirectDrawSurface *surface;
13894 IDirectDrawClipper *clipper, *clipper2;
13895 DDSURFACEDESC surface_desc;
13896 IDirectDraw *ddraw;
13897 ULONG refcount;
13898 HWND window;
13899 HRESULT hr;
13900 BOOL changed;
13901 const IDirectDrawClipperVtbl *orig_vtbl;
13903 window = create_window();
13904 ddraw = create_ddraw();
13905 ok(!!ddraw, "Failed to create a ddraw object.\n");
13906 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
13907 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13909 memset(&surface_desc, 0, sizeof(surface_desc));
13910 surface_desc.dwSize = sizeof(surface_desc);
13911 surface_desc.dwFlags = DDSD_CAPS;
13912 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
13913 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
13914 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13916 hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
13917 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
13918 refcount = get_refcount((IUnknown *)clipper);
13919 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
13921 /* Show that clipper validation doesn't somehow happen through per-clipper vtable
13922 * pointers. */
13923 hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper2, NULL);
13924 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
13925 ok(clipper->lpVtbl == clipper2->lpVtbl, "Got different clipper vtables %p and %p.\n",
13926 clipper->lpVtbl, clipper2->lpVtbl);
13927 orig_vtbl = clipper->lpVtbl;
13928 IDirectDrawClipper_Release(clipper2);
13930 /* Surfaces hold a reference to clippers. No surprises there. */
13931 hr = IDirectDrawSurface_SetClipper(surface, clipper);
13932 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
13933 refcount = get_refcount((IUnknown *)clipper);
13934 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
13936 hr = IDirectDrawSurface_GetClipper(surface, &clipper2);
13937 ok(SUCCEEDED(hr), "Failed to get clipper, hr %#lx.\n", hr);
13938 ok(clipper == clipper2, "Got clipper %p, expected %p.\n", clipper2, clipper);
13939 refcount = IDirectDrawClipper_Release(clipper2);
13940 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
13942 hr = IDirectDrawSurface_SetClipper(surface, NULL);
13943 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
13944 refcount = get_refcount((IUnknown *)clipper);
13945 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
13947 hr = IDirectDrawSurface_SetClipper(surface, clipper);
13948 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
13949 refcount = get_refcount((IUnknown *)clipper);
13950 ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
13952 refcount = IDirectDrawSurface_Release(surface);
13953 ok(!refcount, "%lu references left.\n", refcount);
13954 refcount = get_refcount((IUnknown *)clipper);
13955 ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
13957 /* SetClipper with an invalid pointer crashes. */
13959 /* Clipper methods work with a broken vtable, with the exception of Release. */
13960 clipper->lpVtbl = (void *)0xdeadbeef;
13961 refcount = orig_vtbl->AddRef(clipper);
13962 todo_wine ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount);
13963 refcount = orig_vtbl->Release(clipper);
13964 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
13966 clipper->lpVtbl = orig_vtbl;
13967 refcount = orig_vtbl->Release(clipper);
13968 todo_wine ok(refcount == 1, "Got unexpected refcount %lu.\n", refcount);
13970 /* Fix the refcount difference because Wine did not increase the ref in the
13971 * AddRef call above. */
13972 if (refcount)
13974 refcount = IDirectDrawClipper_Release(clipper);
13975 ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
13978 /* Steal the reference and see what happens - releasing the surface works fine.
13979 * The clipper is destroyed and not kept alive by a hidden refcount - trying to
13980 * release it after the GetClipper call is likely to crash, and certain to crash
13981 * if we allocate and zero as much heap memory as we can get. */
13982 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
13983 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
13984 hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL);
13985 ok(SUCCEEDED(hr), "Failed to create clipper, hr %#lx.\n", hr);
13986 hr = IDirectDrawSurface_SetClipper(surface, clipper);
13987 ok(SUCCEEDED(hr), "Failed to set clipper, hr %#lx.\n", hr);
13989 IDirectDrawClipper_Release(clipper);
13990 IDirectDrawClipper_Release(clipper);
13992 if (0)
13994 /* Disabled because it causes heap corruption (HeapValidate fails and random
13995 * hangs in a later HeapFree) on Windows on one of my Machines: MacbookPro 10,1
13996 * running Windows 10 18363.535 and Nvidia driver 425.31. Driver version 441.66
13997 * is affected too. Some testbot machines have crashes directly in GetClipper
13998 * or proceed with a corrupted heap too.
14000 * The same Windows and driver versions run the test without heap corruption on
14001 * a Geforce 1060 GTX card. I have not seen the problem on AMD GPUs either. */
14002 hr = IDirectDrawSurface_GetClipper(surface, &clipper2);
14003 ok(SUCCEEDED(hr), "Failed to get clipper, hr %#lx.\n", hr);
14004 ok(clipper == clipper2, "Got clipper %p, expected %p.\n", clipper2, clipper);
14007 /* Show that invoking the Release method does not crash, but don't get the
14008 * vtable through the clipper pointer because it is no longer pointing to
14009 * valid memory. */
14010 refcount = orig_vtbl->Release(clipper);
14011 ok(!refcount, "%lu references left.\n", refcount);
14013 refcount = IDirectDrawSurface_Release(surface);
14014 ok(!refcount, "%lu references left.\n", refcount);
14016 /* It looks like the protection against invalid thispointers is part of
14017 * the IDirectDrawClipper method implementation, not IDirectDrawSurface. */
14018 clipper = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0x1000);
14019 ok(!!clipper, "failed to allocate memory\n");
14021 /* Assigning the vtable to our fake clipper does NOT make a difference on
14022 * native - there is a different member of the clipper implementation struct
14023 * that is used to determine if a clipper is valid. */
14024 clipper->lpVtbl = orig_vtbl;
14026 refcount = orig_vtbl->AddRef(clipper);
14027 todo_wine ok(!refcount, "Got refcount %lu.\n", refcount);
14028 refcount = orig_vtbl->AddRef((IDirectDrawClipper *)(ULONG_PTR)0xdeadbeef);
14029 ok(!refcount, "Got refcount %lu.\n", refcount);
14031 changed = 0x1234;
14032 hr = orig_vtbl->IsClipListChanged(clipper, &changed);
14033 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14034 todo_wine ok(changed == 0x1234, "'changed' changed: %x.\n", changed);
14036 changed = 0x1234;
14037 hr = orig_vtbl->IsClipListChanged((IDirectDrawClipper *)(ULONG_PTR)0xdeadbeef, &changed);
14038 ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14039 ok(changed == 0x1234, "'changed' changed: %x.\n", changed);
14041 /* Nope, we can't initialize our fake clipper. */
14042 hr = orig_vtbl->Initialize(clipper, ddraw, 0);
14043 todo_wine ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#lx.\n", hr);
14045 HeapFree(GetProcessHeap(), 0, clipper);
14047 refcount = IDirectDraw_Release(ddraw);
14048 ok(!refcount, "%lu references left.\n", refcount);
14049 DestroyWindow(window);
14052 static void test_caps(void)
14054 DWORD caps_never, caps_always, caps_hal;
14055 DDCAPS hal_caps, hel_caps;
14056 IDirectDraw *ddraw;
14057 HRESULT hr;
14058 BOOL no3d;
14060 caps_never = DDSCAPS_RESERVED1
14061 | DDSCAPS_ALPHA
14062 | DDSCAPS_PRIMARYSURFACELEFT
14063 | DDSCAPS_SYSTEMMEMORY
14064 | DDSCAPS_VISIBLE
14065 | DDSCAPS_WRITEONLY
14066 | DDSCAPS_LIVEVIDEO
14067 | DDSCAPS_HWCODEC
14068 | DDSCAPS_MODEX
14069 | DDSCAPS_RESERVED2
14070 | 0x01000000u
14071 | 0x02000000u
14072 | DDSCAPS_ALLOCONLOAD
14073 | DDSCAPS_VIDEOPORT
14074 | DDSCAPS_STANDARDVGAMODE
14075 | DDSCAPS_OPTIMIZED;
14077 caps_always = DDSCAPS_FLIP
14078 | DDSCAPS_OFFSCREENPLAIN
14079 | DDSCAPS_PRIMARYSURFACE
14080 | DDSCAPS_TEXTURE
14081 | DDSCAPS_ZBUFFER
14082 | DDSCAPS_MIPMAP;
14084 caps_hal = DDSCAPS_BACKBUFFER
14085 | DDSCAPS_COMPLEX
14086 | DDSCAPS_FRONTBUFFER
14087 | DDSCAPS_3DDEVICE
14088 | DDSCAPS_VIDEOMEMORY
14089 | DDSCAPS_LOCALVIDMEM
14090 | DDSCAPS_NONLOCALVIDMEM;
14092 ddraw = create_ddraw();
14093 ok(!!ddraw, "Failed to create a ddraw object.\n");
14095 memset(&hal_caps, 0, sizeof(hal_caps));
14096 memset(&hel_caps, 0, sizeof(hel_caps));
14097 hal_caps.dwSize = sizeof(hal_caps);
14098 hel_caps.dwSize = sizeof(hel_caps);
14099 hr = IDirectDraw_GetCaps(ddraw, &hal_caps, &hel_caps);
14100 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14101 ok(hal_caps.ddsOldCaps.dwCaps == hal_caps.ddsCaps.dwCaps,
14102 "Got unexpected caps %#lx, expected %#lx.\n",
14103 hal_caps.ddsOldCaps.dwCaps, hal_caps.ddsCaps.dwCaps);
14104 ok(hel_caps.ddsOldCaps.dwCaps == hel_caps.ddsCaps.dwCaps,
14105 "Got unexpected caps %#lx, expected %#lx.\n",
14106 hel_caps.ddsOldCaps.dwCaps, hel_caps.ddsCaps.dwCaps);
14108 no3d = !(hal_caps.ddsCaps.dwCaps & DDSCAPS_3DDEVICE);
14109 if (hal_caps.ddsCaps.dwCaps)
14111 ok(!(hal_caps.ddsCaps.dwCaps & caps_never), "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
14112 ok(!(~hal_caps.ddsCaps.dwCaps & caps_always), "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
14113 todo_wine_if(no3d) ok(!(~hal_caps.ddsCaps.dwCaps & caps_hal),
14114 "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
14116 ok(!(hel_caps.ddsCaps.dwCaps & caps_never), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
14117 ok(!(~hel_caps.ddsCaps.dwCaps & caps_always), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
14118 todo_wine_if(!no3d) ok(!(hel_caps.ddsCaps.dwCaps & caps_hal),
14119 "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
14121 IDirectDraw_Release(ddraw);
14123 if (hal_caps.ddsCaps.dwCaps)
14125 hr = DirectDrawCreate((GUID *)DDCREATE_HARDWAREONLY, &ddraw, NULL);
14126 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14128 memset(&hal_caps, 0, sizeof(hal_caps));
14129 memset(&hel_caps, 0, sizeof(hel_caps));
14130 hal_caps.dwSize = sizeof(hal_caps);
14131 hel_caps.dwSize = sizeof(hel_caps);
14132 hr = IDirectDraw_GetCaps(ddraw, &hal_caps, &hel_caps);
14133 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14134 ok(hal_caps.ddsOldCaps.dwCaps == hal_caps.ddsCaps.dwCaps,
14135 "Got unexpected caps %#lx, expected %#lx.\n",
14136 hal_caps.ddsOldCaps.dwCaps, hal_caps.ddsCaps.dwCaps);
14137 ok(hel_caps.ddsOldCaps.dwCaps == hel_caps.ddsCaps.dwCaps,
14138 "Got unexpected caps %#lx, expected %#lx.\n",
14139 hel_caps.ddsOldCaps.dwCaps, hel_caps.ddsCaps.dwCaps);
14141 ok(!(hal_caps.ddsCaps.dwCaps & caps_never), "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
14142 ok(!(~hal_caps.ddsCaps.dwCaps & caps_always), "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
14143 todo_wine_if(no3d) ok(!(~hal_caps.ddsCaps.dwCaps & caps_hal),
14144 "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
14145 if (is_ddraw64)
14147 ok(!(hel_caps.ddsCaps.dwCaps & caps_never), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
14148 ok(!(~hel_caps.ddsCaps.dwCaps & caps_always), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
14149 todo_wine_if(!no3d) ok(!(hel_caps.ddsCaps.dwCaps & caps_hal),
14150 "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
14152 else
14154 todo_wine ok(!hel_caps.ddsCaps.dwCaps, "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
14157 IDirectDraw_Release(ddraw);
14160 hr = DirectDrawCreate((GUID *)DDCREATE_EMULATIONONLY, &ddraw, NULL);
14161 ok(hr == DD_OK || (is_ddraw64 && hr == E_FAIL), "Got unexpected hr %#lx.\n", hr);
14162 if (SUCCEEDED(hr))
14164 memset(&hal_caps, 0, sizeof(hal_caps));
14165 memset(&hel_caps, 0, sizeof(hel_caps));
14166 hal_caps.dwSize = sizeof(hal_caps);
14167 hel_caps.dwSize = sizeof(hel_caps);
14168 hr = IDirectDraw_GetCaps(ddraw, &hal_caps, &hel_caps);
14169 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14170 ok(hal_caps.ddsOldCaps.dwCaps == hal_caps.ddsCaps.dwCaps,
14171 "Got unexpected caps %#lx, expected %#lx.\n",
14172 hal_caps.ddsOldCaps.dwCaps, hal_caps.ddsCaps.dwCaps);
14173 ok(hel_caps.ddsOldCaps.dwCaps == hel_caps.ddsCaps.dwCaps,
14174 "Got unexpected caps %#lx, expected %#lx.\n",
14175 hel_caps.ddsOldCaps.dwCaps, hel_caps.ddsCaps.dwCaps);
14177 todo_wine ok(!hal_caps.ddsCaps.dwCaps, "Got unexpected caps %#lx.\n", hal_caps.ddsCaps.dwCaps);
14178 ok(!(hel_caps.ddsCaps.dwCaps & caps_never), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
14179 ok(!(~hel_caps.ddsCaps.dwCaps & caps_always), "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
14180 todo_wine_if(!no3d) ok(!(hel_caps.ddsCaps.dwCaps & caps_hal),
14181 "Got unexpected caps %#lx.\n", hel_caps.ddsCaps.dwCaps);
14183 IDirectDraw_Release(ddraw);
14187 static void test_d32_support(void)
14189 IDirectDrawSurface *surface;
14190 DDSURFACEDESC surface_desc;
14191 IDirectDraw *ddraw;
14192 ULONG refcount;
14193 HWND window;
14194 HRESULT hr;
14196 window = create_window();
14197 ddraw = create_ddraw();
14198 ok(!!ddraw, "Failed to create a ddraw object.\n");
14199 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
14200 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14202 memset(&surface_desc, 0, sizeof(surface_desc));
14203 surface_desc.dwSize = sizeof(surface_desc);
14204 surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
14205 surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
14206 U2(surface_desc).dwZBufferBitDepth = 32;
14207 surface_desc.dwWidth = 64;
14208 surface_desc.dwHeight = 64;
14209 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface, NULL);
14210 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14212 memset(&surface_desc, 0, sizeof(surface_desc));
14213 surface_desc.dwSize = sizeof(surface_desc);
14214 hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc);
14215 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14216 ok((surface_desc.dwFlags & DDSD_ZBUFFERBITDEPTH), "Got unexpected flags %#lx.\n", surface_desc.dwFlags);
14217 ok(U2(surface_desc).dwZBufferBitDepth == 32,
14218 "Got unexpected dwZBufferBitDepth %lu.\n", U2(surface_desc).dwZBufferBitDepth);
14219 ok(!(surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY),
14220 "Got unexpected surface caps %#lx.\n", surface_desc.ddsCaps.dwCaps);
14221 IDirectDrawSurface_Release(surface);
14223 refcount = IDirectDraw_Release(ddraw);
14224 ok(!refcount, "%lu references left.\n", refcount);
14225 DestroyWindow(window);
14228 struct find_different_mode_param
14230 unsigned int old_width;
14231 unsigned int old_height;
14232 unsigned int new_width;
14233 unsigned int new_height;
14236 static HRESULT CALLBACK find_different_mode_callback(DDSURFACEDESC *surface_desc, void *context)
14238 struct find_different_mode_param *param = context;
14240 if (U1(U4(*surface_desc).ddpfPixelFormat).dwRGBBitCount != registry_mode.dmBitsPerPel)
14241 return DDENUMRET_OK;
14243 if (surface_desc->dwWidth != param->old_width && surface_desc->dwHeight != param->old_height)
14245 /* See test_coop_level_mode_set_enum_cb() for why enumeration might accidentally continue. */
14246 if (!param->new_width || (param->new_width < registry_mode.dmPelsWidth
14247 && param->new_height < registry_mode.dmPelsHeight))
14249 param->new_width = surface_desc->dwWidth;
14250 param->new_height = surface_desc->dwHeight;
14252 return DDENUMRET_CANCEL;
14255 return DDENUMRET_OK;
14258 static void test_cursor_clipping(void)
14260 struct find_different_mode_param param;
14261 DDSURFACEDESC surface_desc;
14262 RECT rect, clip_rect;
14263 IDirectDraw *ddraw;
14264 HWND window;
14265 HRESULT hr;
14266 BOOL ret;
14268 window = create_window();
14269 ok(!!window, "Failed to create a window.\n");
14270 ddraw = create_ddraw();
14271 ok(!!ddraw, "Failed to create a ddraw object.\n");
14273 memset(&surface_desc, 0, sizeof(surface_desc));
14274 surface_desc.dwSize = sizeof(surface_desc);
14275 hr = IDirectDraw_GetDisplayMode(ddraw, &surface_desc);
14276 ok(hr == DD_OK, "GetDisplayMode failed, hr %#lx.\n", hr);
14278 memset(&param, 0, sizeof(param));
14279 param.old_width = surface_desc.dwWidth;
14280 param.old_height = surface_desc.dwHeight;
14281 hr = IDirectDraw_EnumDisplayModes(ddraw, 0, NULL, &param, find_different_mode_callback);
14282 ok(hr == DD_OK, "EnumDisplayModes failed, hr %#lx.\n", hr);
14283 if (!(param.new_width && param.new_height))
14285 skip("Failed to find a different mode than %ux%u.\n", param.old_width, param.old_height);
14286 goto done;
14289 ret = ClipCursor(NULL);
14290 ok(ret, "ClipCursor failed, error %lu.\n", GetLastError());
14291 get_virtual_rect(&rect);
14292 ret = GetClipCursor(&clip_rect);
14293 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
14294 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
14295 wine_dbgstr_rect(&clip_rect));
14297 /* Set cooperative level to normal */
14298 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
14299 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
14300 flush_events();
14301 get_virtual_rect(&rect);
14302 ret = GetClipCursor(&clip_rect);
14303 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
14304 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
14305 wine_dbgstr_rect(&clip_rect));
14307 hr = set_display_mode(ddraw, param.new_width, param.new_height);
14308 ok(hr == DD_OK || hr == DDERR_UNSUPPORTED, "SetDisplayMode failed, hr %#lx.\n", hr);
14309 if (FAILED(hr))
14311 win_skip("SetDisplayMode failed, hr %#lx.\n", hr);
14312 goto done;
14314 flush_events();
14315 get_virtual_rect(&rect);
14316 ret = GetClipCursor(&clip_rect);
14317 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
14318 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
14319 wine_dbgstr_rect(&clip_rect));
14321 hr = IDirectDraw_RestoreDisplayMode(ddraw);
14322 ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#lx.\n", hr);
14323 flush_events();
14324 get_virtual_rect(&rect);
14325 ret = GetClipCursor(&clip_rect);
14326 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
14327 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
14328 wine_dbgstr_rect(&clip_rect));
14330 /* Switch to full screen cooperative level */
14331 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
14332 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
14333 flush_events();
14334 SetRect(&rect, 0, 0, param.old_width, param.old_height);
14335 ret = GetClipCursor(&clip_rect);
14336 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
14337 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
14338 wine_dbgstr_rect(&clip_rect));
14340 hr = set_display_mode(ddraw, param.new_width, param.new_height);
14341 ok(hr == DD_OK || hr == DDERR_UNSUPPORTED, "SetDisplayMode failed, hr %#lx.\n", hr);
14342 if (FAILED(hr))
14344 win_skip("SetDisplayMode failed, hr %#lx.\n", hr);
14345 goto done;
14347 flush_events();
14348 SetRect(&rect, 0, 0, param.new_width, param.new_height);
14349 ret = GetClipCursor(&clip_rect);
14350 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
14351 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
14352 wine_dbgstr_rect(&clip_rect));
14354 /* Restore display mode */
14355 hr = IDirectDraw_RestoreDisplayMode(ddraw);
14356 ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#lx.\n", hr);
14357 flush_events();
14358 SetRect(&rect, 0, 0, param.old_width, param.old_height);
14359 ret = GetClipCursor(&clip_rect);
14360 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
14361 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
14362 wine_dbgstr_rect(&clip_rect));
14364 /* Switch to normal cooperative level */
14365 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
14366 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
14367 flush_events();
14368 get_virtual_rect(&rect);
14369 ret = GetClipCursor(&clip_rect);
14370 ok(ret, "GetClipCursor failed, error %lu.\n", GetLastError());
14371 ok(EqualRect(&clip_rect, &rect), "Expect clip rect %s, got %s.\n", wine_dbgstr_rect(&rect),
14372 wine_dbgstr_rect(&clip_rect));
14374 done:
14375 IDirectDraw_Release(ddraw);
14376 DestroyWindow(window);
14379 static void check_vtbl_protection_(int line, const void *vtbl)
14381 MEMORY_BASIC_INFORMATION info;
14382 SIZE_T ret = VirtualQuery(vtbl, &info, sizeof(info));
14383 ok_(__FILE__, line)(ret == sizeof(info), "Failed to query memory.\n");
14384 ok_(__FILE__, line)(info.Protect & (PAGE_READWRITE | PAGE_WRITECOPY), "Got protection %#lx.\n", info.Protect);
14386 #define check_vtbl_protection(a) check_vtbl_protection_(__LINE__, a)
14388 static void test_vtbl_protection(void)
14390 PALETTEENTRY palette_entries[256];
14391 IDirectDrawSurface7 *surface7;
14392 IDirectDrawSurface4 *surface4;
14393 IDirectDrawSurface3 *surface3;
14394 IDirectDrawSurface2 *surface2;
14395 IDirectDrawSurface *surface1;
14396 IDirectDrawPalette *palette;
14397 DDSURFACEDESC surface_desc;
14398 IDirectDraw *ddraw;
14399 ULONG refcount;
14400 HWND window;
14401 HRESULT hr;
14403 window = create_window();
14404 ddraw = create_ddraw();
14405 ok(!!ddraw, "Failed to create a ddraw object.\n");
14406 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
14407 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14409 memset(&surface_desc, 0, sizeof(surface_desc));
14410 surface_desc.dwSize = sizeof(surface_desc);
14411 surface_desc.dwFlags = DDSD_CAPS;
14412 surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
14413 hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
14414 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14415 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface2);
14416 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14417 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface3, (void **)&surface3);
14418 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14419 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface4, (void **)&surface4);
14420 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14421 hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface7, (void **)&surface7);
14422 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14424 memset(palette_entries, 0, sizeof(palette_entries));
14425 hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
14426 palette_entries, &palette, NULL);
14427 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14429 check_vtbl_protection(ddraw->lpVtbl);
14430 check_vtbl_protection(palette->lpVtbl);
14431 check_vtbl_protection(surface1->lpVtbl);
14432 check_vtbl_protection(surface2->lpVtbl);
14433 check_vtbl_protection(surface3->lpVtbl);
14434 check_vtbl_protection(surface4->lpVtbl);
14435 check_vtbl_protection(surface7->lpVtbl);
14437 IDirectDrawPalette_Release(palette);
14438 IDirectDrawSurface_Release(surface1);
14439 IDirectDrawSurface2_Release(surface2);
14440 IDirectDrawSurface3_Release(surface3);
14441 IDirectDrawSurface4_Release(surface4);
14442 IDirectDrawSurface7_Release(surface7);
14443 refcount = IDirectDraw_Release(ddraw);
14444 ok(!refcount, "%lu references left.\n", refcount);
14445 DestroyWindow(window);
14448 static BOOL CALLBACK test_window_position_cb(HMONITOR monitor, HDC hdc, RECT *monitor_rect,
14449 LPARAM lparam)
14451 RECT primary_rect, window_rect, new_rect;
14452 IDirectDraw *ddraw;
14453 HWND window;
14454 HRESULT hr;
14455 BOOL ret;
14457 ddraw = create_ddraw();
14458 ok(!!ddraw, "Failed to create a ddraw object.\n");
14459 window = CreateWindowA("static", "ddraw_test", WS_POPUP | WS_VISIBLE, monitor_rect->left,
14460 monitor_rect->top, 100, 100, NULL, NULL, NULL, NULL);
14461 ok(!!window, "Failed to create a window.\n");
14462 flush_events();
14464 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
14465 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
14466 flush_events();
14467 ret = GetWindowRect(window, &window_rect);
14468 ok(ret, "GetWindowRect failed, error %lu.\n", GetLastError());
14469 SetRect(&primary_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
14470 ok(EqualRect(&window_rect, &primary_rect), "Expect window rect %s, got %s.\n",
14471 wine_dbgstr_rect(&primary_rect), wine_dbgstr_rect(&window_rect));
14473 new_rect = window_rect;
14474 --new_rect.right;
14475 --new_rect.bottom;
14477 ret = MoveWindow(window, new_rect.left, new_rect.top, new_rect.right - new_rect.left,
14478 new_rect.bottom - new_rect.top, TRUE);
14479 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
14480 ret = GetWindowRect(window, &window_rect);
14481 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
14482 ok(EqualRect(&window_rect, &new_rect),
14483 "Expected window rect %s, got %s.\n",
14484 wine_dbgstr_rect(monitor_rect), wine_dbgstr_rect(&window_rect));
14485 /* After processing window events window rectangle gets restored. But only once, the size set
14486 * on the second resize remains. */
14487 flush_events();
14488 ret = GetWindowRect(window, &window_rect);
14489 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
14490 /* Both Windows and Wine change the size of the window. On Windows it is exactly the new size but in Wine
14491 * it may get adjusted depending on window manager. */
14492 ok(window_rect.right != monitor_rect->right && window_rect.bottom != monitor_rect->bottom,
14493 "Expected window rect %s, got %s.\n",
14494 wine_dbgstr_rect(monitor_rect), wine_dbgstr_rect(&window_rect));
14496 ret = MoveWindow(window, new_rect.left, new_rect.top, new_rect.right - new_rect.left,
14497 new_rect.bottom - new_rect.top, TRUE);
14498 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
14499 ret = GetWindowRect(window, &window_rect);
14500 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
14501 ok(EqualRect(&window_rect, &new_rect),
14502 "Expected window rect %s, got %s.\n",
14503 wine_dbgstr_rect(monitor_rect), wine_dbgstr_rect(&window_rect));
14504 flush_events();
14505 ret = GetWindowRect(window, &window_rect);
14506 ok(ret, "Got unexpected ret %#x, error %lu.\n", ret, GetLastError());
14507 ok(window_rect.right != monitor_rect->right && window_rect.bottom != monitor_rect->bottom,
14508 "Expected window rect %s, got %s.\n",
14509 wine_dbgstr_rect(monitor_rect), wine_dbgstr_rect(&window_rect));
14511 /* Window activation should restore the window to fit the whole primary monitor */
14512 ret = SetWindowPos(window, 0, monitor_rect->left, monitor_rect->top, 0, 0,
14513 SWP_NOZORDER | SWP_NOSIZE);
14514 ok(ret, "SetWindowPos failed, error %lu.\n", GetLastError());
14515 ret = SetForegroundWindow(GetDesktopWindow());
14516 ok(ret, "Failed to set foreground window.\n");
14517 flush_events();
14518 ret = ShowWindow(window, SW_RESTORE);
14519 ok(ret, "Failed to restore window, error %lu.\n", GetLastError());
14520 flush_events();
14521 ret = SetForegroundWindow(window);
14522 ok(ret, "SetForegroundWindow failed, error %lu.\n", GetLastError());
14523 flush_events();
14524 ret = GetWindowRect(window, &window_rect);
14525 ok(ret, "GetWindowRect failed, error %lu.\n", GetLastError());
14526 ok(EqualRect(&window_rect, &primary_rect), "Expect window rect %s, got %s.\n",
14527 wine_dbgstr_rect(&primary_rect), wine_dbgstr_rect(&window_rect));
14529 hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
14530 ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#lx.\n", hr);
14531 ret = GetWindowRect(window, &window_rect);
14532 ok(ret, "GetWindowRect failed, error %lu.\n", GetLastError());
14533 ok(EqualRect(&window_rect, &primary_rect), "Expect window rect %s, got %s.\n",
14534 wine_dbgstr_rect(&primary_rect), wine_dbgstr_rect(&window_rect));
14536 DestroyWindow(window);
14537 IDirectDraw_Release(ddraw);
14538 return TRUE;
14541 static void test_window_position(void)
14543 EnumDisplayMonitors(NULL, NULL, test_window_position_cb, 0);
14546 static BOOL CALLBACK test_get_display_mode_cb(HMONITOR monitor, HDC hdc, RECT *monitor_rect,
14547 LPARAM lparam)
14549 DDSURFACEDESC surface_desc;
14550 IDirectDraw *ddraw;
14551 HWND window;
14552 HRESULT hr;
14553 BOOL ret;
14555 ddraw = create_ddraw();
14556 ok(!!ddraw, "Failed to create a ddraw object.\n");
14557 window = create_window();
14558 ok(!!window, "Failed to create a window.\n");
14560 /* Test that DirectDraw doesn't use the device window to determine which monitor to use */
14561 ret = SetWindowPos(window, 0, monitor_rect->left, monitor_rect->top, 0, 0,
14562 SWP_NOZORDER | SWP_NOSIZE);
14563 ok(ret, "SetWindowPos failed, error %lu.\n", GetLastError());
14565 surface_desc.dwSize = sizeof(surface_desc);
14566 hr = IDirectDraw_GetDisplayMode(ddraw, &surface_desc);
14567 ok(hr == DD_OK, "GetDisplayMode failed, hr %#lx.\n", hr);
14568 ok(surface_desc.dwWidth == GetSystemMetrics(SM_CXSCREEN), "Expect width %d, got %lu.\n",
14569 GetSystemMetrics(SM_CXSCREEN), surface_desc.dwWidth);
14570 ok(surface_desc.dwHeight == GetSystemMetrics(SM_CYSCREEN), "Expect height %d, got %lu.\n",
14571 GetSystemMetrics(SM_CYSCREEN), surface_desc.dwHeight);
14573 DestroyWindow(window);
14574 IDirectDraw_Release(ddraw);
14575 return TRUE;
14578 static void test_get_display_mode(void)
14580 static const DWORD flags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_REFRESHRATE | DDSD_PIXELFORMAT | DDSD_PITCH;
14581 DDSURFACEDESC surface_desc;
14582 IDirectDraw *ddraw;
14583 DEVMODEW devmode;
14584 HRESULT hr;
14585 BOOL ret;
14587 EnumDisplayMonitors(NULL, NULL, test_get_display_mode_cb, 0);
14589 ddraw = create_ddraw();
14590 ok(!!ddraw, "Failed to create a ddraw object.\n");
14592 memset(&devmode, 0, sizeof(devmode));
14593 devmode.dmSize = sizeof(devmode);
14594 ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
14595 ok(ret, "EnumDisplaySettingsW failed, error %lu.\n", GetLastError());
14597 surface_desc.dwSize = sizeof(surface_desc);
14598 hr = IDirectDraw_GetDisplayMode(ddraw, &surface_desc);
14599 ok(hr == DD_OK, "GetDisplayMode failed, hr %#lx.\n", hr);
14600 ok(surface_desc.dwSize == sizeof(surface_desc), "Got dwSize %lu.\n", surface_desc.dwSize);
14601 ok(surface_desc.dwFlags == flags, "Expected dwFlags %#lx, got %#lx.\n", flags,
14602 surface_desc.dwFlags);
14603 ok(surface_desc.dwWidth == devmode.dmPelsWidth, "Expected width %lu, got %lu.\n",
14604 devmode.dmPelsWidth, surface_desc.dwWidth);
14605 ok(surface_desc.dwHeight == devmode.dmPelsHeight, "Expected height %lu, got %lu.\n",
14606 devmode.dmPelsHeight, surface_desc.dwHeight);
14607 ok(surface_desc.dwRefreshRate == devmode.dmDisplayFrequency, "Expected frequency %lu, got %lu.\n",
14608 devmode.dmDisplayFrequency, surface_desc.dwRefreshRate);
14609 ok(surface_desc.ddpfPixelFormat.dwSize == sizeof(surface_desc.ddpfPixelFormat),
14610 "Got ddpfPixelFormat.dwSize %lu.\n", surface_desc.ddpfPixelFormat.dwSize);
14611 ok(surface_desc.ddpfPixelFormat.dwRGBBitCount == devmode.dmBitsPerPel,
14612 "Expected ddpfPixelFormat.dwRGBBitCount %lu, got %lu.\n", devmode.dmBitsPerPel,
14613 surface_desc.ddpfPixelFormat.dwRGBBitCount);
14614 ok(surface_desc.lPitch == devmode.dmPelsWidth * devmode.dmBitsPerPel / 8,
14615 "Expected pitch %lu, got %lu.\n", devmode.dmPelsWidth * devmode.dmBitsPerPel / 8,
14616 surface_desc.lPitch);
14618 IDirectDraw_Release(ddraw);
14621 static void run_for_each_device_type(void (*test_func)(const GUID *))
14623 test_func(&IID_IDirect3DHALDevice);
14624 test_func(&IID_IDirect3DRGBDevice);
14627 static void test_texture_wrong_caps(const GUID *device_guid)
14629 static D3DTLVERTEX quad[] =
14631 {{ 0.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
14632 {{ 0.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
14633 {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
14634 {{640.0f}, { 0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
14636 static DDPIXELFORMAT fmt =
14638 sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0,
14639 {32}, {0x00ff0000}, {0x0000ff00}, {0x000000ff}, {0xff000000}
14641 unsigned int inst_length, color, expected_color;
14642 D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
14643 IDirect3DExecuteBuffer *execute_buffer;
14644 IDirectDrawSurface *surface, *rt;
14645 D3DTEXTUREHANDLE texture_handle;
14646 D3DEXECUTEBUFFERDESC exec_desc;
14647 IDirect3DMaterial *background;
14648 IDirect3DViewport *viewport;
14649 IDirect3DTexture *texture;
14650 IDirect3DDevice *device;
14651 IDirectDraw *ddraw;
14652 DDSURFACEDESC ddsd;
14653 ULONG refcount;
14654 HWND window;
14655 HRESULT hr;
14656 void *ptr;
14658 window = create_window();
14659 ddraw = create_ddraw();
14660 ok(!!ddraw, "Failed to create a ddraw object.\n");
14661 if (!(device = create_device_ex(ddraw, window, DDSCL_NORMAL, device_guid)))
14663 skip("Failed to create a 3D device, skipping test.\n");
14664 DestroyWindow(window);
14665 return;
14667 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
14668 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14670 viewport = create_viewport(device, 0, 0, 640, 480);
14672 memset(&ddsd, 0, sizeof(ddsd));
14673 ddsd.dwSize = sizeof(ddsd);
14674 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
14675 ddsd.dwHeight = 16;
14676 ddsd.dwWidth = 16;
14677 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
14678 U4(ddsd).ddpfPixelFormat = fmt;
14679 hr = IDirectDraw_CreateSurface(ddraw, &ddsd, &surface, NULL);
14680 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14681 hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture, (void **)&texture);
14682 ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr);
14683 hr = IDirect3DTexture_GetHandle(texture, device, &texture_handle);
14684 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14686 fill_surface(surface, 0xff00ff00);
14688 background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
14689 viewport_set_background(device, viewport, background);
14691 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
14692 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14693 if (is_software_device_type(device_guid))
14694 fill_surface(rt, 0xffff0000);
14696 memset(&exec_desc, 0, sizeof(exec_desc));
14697 exec_desc.dwSize = sizeof(exec_desc);
14698 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
14699 exec_desc.dwBufferSize = 1024;
14700 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
14701 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
14702 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14704 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
14705 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14706 memcpy(exec_desc.lpData, quad, sizeof(quad));
14707 ptr = (BYTE *)exec_desc.lpData + sizeof(quad);
14708 emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
14709 emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
14710 emit_tquad(&ptr, 0);
14711 emit_end(&ptr);
14712 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData - sizeof(quad);
14713 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
14714 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14716 set_execute_data(execute_buffer, 4, sizeof(quad), inst_length);
14718 hr = IDirect3DDevice_BeginScene(device);
14719 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14720 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
14721 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14722 hr = IDirect3DDevice_EndScene(device);
14723 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
14725 expected_color = is_software_device_type(device_guid) ? 0x0000ff00 : 0x00ffffff;
14726 color = get_surface_color(rt, 320, 240);
14727 ok(compare_color(color, expected_color, 1), "Got color 0x%08x, expected 0x%08x.\n", color, expected_color);
14729 IDirect3DTexture_Release(texture);
14730 IDirectDrawSurface_Release(surface);
14731 IDirectDrawSurface_Release(rt);
14732 IDirect3DExecuteBuffer_Release(execute_buffer);
14733 destroy_material(background);
14734 destroy_viewport(device, viewport);
14736 IDirect3DDevice_Release(device);
14737 refcount = IDirectDraw_Release(ddraw);
14738 ok(!refcount, "DirectDraw has %lu references left.\n", refcount);
14739 DestroyWindow(window);
14742 static void test_filling_convention(void)
14744 unsigned int inst_length, colour, expected, i, x, y;
14745 static const DWORD colour_bottom = 0x00ffff00;
14746 static const DWORD colour_clear = 0x000000ff;
14747 static const DWORD colour_right = 0x00000000;
14748 static const DWORD colour_left = 0x00ff0000;
14749 static const DWORD colour_top = 0x0000ff00;
14750 IDirect3DExecuteBuffer *execute_buffer;
14751 D3DEXECUTEBUFFERDESC exec_desc;
14752 IDirectDrawSurface *backbuffer;
14753 IDirect3DMaterial *background;
14754 IDirect3DViewport *viewport;
14755 IDirect3DDevice *device;
14756 IDirectDraw *ddraw;
14757 ULONG refcount;
14758 HWND window;
14759 HRESULT hr;
14760 BOOL todo;
14761 void *ptr;
14763 static const unsigned int vp_size = 8;
14764 D3DRECT clear_rect = {{0}, {0}, {vp_size}, {vp_size}};
14766 /* This test data follows the examples in MSDN's
14767 * "Rasterization Rules (Direct3D 9)" article.
14769 * See the d3d9 test for a comment about the eps value. */
14770 static const float eps = 1.0f / 64.0f;
14771 D3DLVERTEX center_tris[] =
14773 /* left */
14774 {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_left}},
14775 {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_left}},
14776 {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_left}},
14778 /* top */
14779 {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_top}},
14780 {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
14781 {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
14783 /* right */
14784 {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_right}},
14785 {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_right}},
14786 {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_right}},
14788 /* bottom */
14789 {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14790 {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14791 {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14793 edge_tris[] =
14795 /* left */
14796 {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14797 {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14798 {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14800 /* top */
14801 {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14802 {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14803 {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14805 /* right */
14806 {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14807 {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14808 {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14810 /* bottom */
14811 {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14812 {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14813 {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14815 nudge_right_tris[] =
14817 /* left */
14818 {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14819 {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14820 {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14822 /* top */
14823 {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14824 {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14825 {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14827 /* right */
14828 {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14829 {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14830 {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14832 /* bottom */
14833 {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14834 {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14835 {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14837 nudge_left_tris[] =
14839 {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14840 {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14841 {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14843 /* top */
14844 {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14845 {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14846 {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14848 /* right */
14849 {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14850 {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14851 {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14853 /* bottom */
14854 {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14855 {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14856 {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14858 nudge_top_tris[] =
14860 /* left */
14861 {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14862 {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14863 {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14865 /* top */
14866 {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14867 {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14868 {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14870 /* right */
14871 {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14872 {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14873 {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14875 /* bottom */
14876 {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14877 {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14878 {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14880 nudge_bottom_tris[] =
14882 /* left */
14883 {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14884 {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14885 {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
14887 /* top */
14888 {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14889 {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14890 {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
14892 /* right */
14893 {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14894 {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14895 {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
14897 /* bottom */
14898 {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14899 {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14900 {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
14903 D3DTLVERTEX center_tris_t[] =
14905 /* left */
14906 {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_left}},
14907 {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_left}},
14908 {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_left}},
14910 /* top */
14911 {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
14912 {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
14913 {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_top}},
14915 /* right */
14916 {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_right}},
14917 {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_right}},
14918 {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_right}},
14920 /* bottom */
14921 {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_bottom}},
14922 {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
14923 {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
14925 edge_tris_t[] =
14927 /* left */
14928 {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_left}},
14929 {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_left}},
14930 {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_left}},
14932 /* top */
14933 {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
14934 {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
14935 {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_top}},
14937 /* right */
14938 {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_right}},
14939 {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_right}},
14940 {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_right}},
14942 /* bottom */
14943 {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_bottom}},
14944 {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
14945 {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
14948 const struct
14950 void *geometry;
14951 DWORD op;
14952 const char *expected[8];
14954 tests[] =
14957 center_tris,
14958 D3DPROCESSVERTICES_TRANSFORM,
14960 " ",
14961 " ",
14962 " TT ",
14963 " LR ",
14964 " LR ",
14965 " BB ",
14966 " ",
14971 edge_tris,
14972 D3DPROCESSVERTICES_TRANSFORM,
14974 " ",
14975 " TT ",
14976 " LT ",
14977 " LR ",
14978 " LB ",
14979 " ",
14980 " ",
14985 nudge_right_tris,
14986 D3DPROCESSVERTICES_TRANSFORM,
14988 " ",
14989 " TT ",
14990 " TR ",
14991 " LR ",
14992 " BR ",
14993 " ",
14994 " ",
14999 nudge_left_tris,
15000 D3DPROCESSVERTICES_TRANSFORM,
15002 " ",
15003 " TT ",
15004 " LT ",
15005 " LR ",
15006 " LB ",
15007 " ",
15008 " ",
15013 nudge_top_tris,
15014 D3DPROCESSVERTICES_TRANSFORM,
15016 " ",
15017 " LT ",
15018 " LT ",
15019 " LB ",
15020 " LB ",
15021 " ",
15022 " ",
15027 nudge_bottom_tris,
15028 D3DPROCESSVERTICES_TRANSFORM,
15030 " ",
15031 " ",
15032 " LT ",
15033 " Lt ",
15034 " LB ",
15035 " lB ",
15036 " ",
15041 center_tris_t,
15042 D3DPROCESSVERTICES_COPY,
15044 " ",
15045 " ",
15046 " TT ",
15047 " LR ",
15048 " LR ",
15049 " BB ",
15050 " ",
15055 edge_tris_t,
15056 D3DPROCESSVERTICES_COPY,
15058 " ",
15059 " TT ",
15060 " LT ",
15061 " LR ",
15062 " LB ",
15063 " ",
15064 " ",
15069 static WORD indices[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
15071 window = create_window();
15072 ddraw = create_ddraw();
15073 ok(!!ddraw, "Failed to create a ddraw object.\n");
15074 if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
15076 skip("Failed to create a 3D device.\n");
15077 IDirectDraw_Release(ddraw);
15078 DestroyWindow(window);
15079 return;
15082 hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&backbuffer);
15083 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15085 viewport = create_viewport(device, 0, 0, vp_size, vp_size);
15086 background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
15087 viewport_set_background(device, viewport, background);
15089 memset(&exec_desc, 0, sizeof(exec_desc));
15090 exec_desc.dwSize = sizeof(exec_desc);
15091 exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
15092 exec_desc.dwBufferSize = 1024;
15093 exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
15095 hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
15096 ok(hr == D3D_OK, "Failed to create execute buffer, hr %#lx.\n", hr);
15098 for (i = 0; i < ARRAY_SIZE(tests); ++i)
15100 hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
15101 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15103 hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
15104 ok(hr == D3D_OK, "Failed to lock execute buffer, hr %#lx.\n", hr);
15106 /* All test geometry has the same vertex count and vertex size. */
15107 memcpy(exec_desc.lpData, tests[i].geometry, sizeof(center_tris));
15108 ptr = ((BYTE *)exec_desc.lpData) + sizeof(center_tris);
15109 emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, FALSE);
15110 /* Old WARP versions (w8, early win10) apply color keying without textures. */
15111 emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, FALSE);
15113 emit_process_vertices(&ptr, tests[i].op, 0, 12);
15114 emit_tri_indices(&ptr, indices, 4);
15115 emit_end(&ptr);
15116 inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
15117 inst_length -= sizeof(center_tris);
15119 hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
15120 ok(hr == D3D_OK, "Failed to lock execute buffer, hr %#lx.\n", hr);
15122 set_execute_data(execute_buffer, 12, sizeof(center_tris), inst_length);
15124 hr = IDirect3DDevice_BeginScene(device);
15125 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15126 hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
15127 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15128 hr = IDirect3DDevice_EndScene(device);
15129 ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
15131 for (y = 0; y < 8; y++)
15133 for (x = 0; x < 8; x++)
15135 todo = FALSE;
15136 switch (tests[i].expected[y][x])
15138 case 'l': todo = TRUE;
15139 case 'L':
15140 expected = colour_left;
15141 break;
15142 case 't': todo = TRUE;
15143 case 'T':
15144 expected = colour_top;
15145 break;
15146 case 'r': todo = TRUE;
15147 case 'R':
15148 expected = colour_right;
15149 break;
15150 case 'b': todo = TRUE;
15151 case 'B':
15152 expected = colour_bottom;
15153 break;
15154 case ' ':
15155 expected = colour_clear;
15156 break;
15157 default:
15158 ok(0, "Unexpected entry in expected test char\n");
15159 expected = 0xdeadbeef;
15161 colour = get_surface_color(backbuffer, x, y);
15162 /* The nudge-to-bottom test fails on cards that give us a bottom-left
15163 * filling convention. The cause isn't the bottom part of the filling
15164 * convention, but because wined3d will nudge geometry to the left to
15165 * keep diagonals (the 'R' in test case 'edge_tris') intact. */
15166 todo_wine_if(todo && !compare_color(colour, expected, 1))
15167 ok(compare_color(colour, expected, 1), "Got unexpected colour %08x, %ux%u, case %u.\n",
15168 colour, x, y, i);
15173 destroy_viewport(device, viewport);
15174 IDirectDrawSurface_Release(backbuffer);
15175 IDirect3DDevice_Release(device);
15176 refcount = IDirectDraw_Release(ddraw);
15177 ok(!refcount, "Device has %lu references left.\n", refcount);
15178 DestroyWindow(window);
15181 static HRESULT WINAPI test_enum_devices_caps_callback(GUID *guid, char *device_desc,
15182 char *device_name, D3DDEVICEDESC *hal, D3DDEVICEDESC *hel, void *ctx)
15184 if(IsEqualGUID(&IID_IDirect3DRGBDevice, guid))
15186 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
15187 "RGB Device hal line caps has D3DPTEXTURECAPS_POW2 flag set\n");
15188 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
15189 "RGB Device hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n");
15190 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
15191 "RGB Device hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
15192 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
15193 "RGB Device hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
15195 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
15196 "RGB Device hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
15197 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
15198 "RGB Device hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
15199 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
15200 "RGB Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
15201 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
15202 "RGB Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
15204 ok(hal->dcmColorModel == 0, "RGB Device hal caps has colormodel %lu\n", hal->dcmColorModel);
15205 ok(hel->dcmColorModel == D3DCOLOR_RGB, "RGB Device hel caps has colormodel %lu\n", hel->dcmColorModel);
15207 ok(hal->dwFlags == 0, "RGB Device hal caps has hardware flags %#lx\n", hal->dwFlags);
15208 ok(hel->dwFlags != 0, "RGB Device hel caps has hardware flags %#lx\n", hel->dwFlags);
15210 ok((hal->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
15211 "RGB Device hal device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
15212 ok((hel->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
15213 "RGB Device hel device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
15214 ok((hal->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
15215 "RGB Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
15216 ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
15217 "RGB Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
15219 else if(IsEqualGUID(&IID_IDirect3DHALDevice, guid))
15221 ok(hal->dcmColorModel == D3DCOLOR_RGB, "HAL Device hal caps has colormodel %lu\n", hel->dcmColorModel);
15222 ok(hel->dcmColorModel == 0, "HAL Device hel caps has colormodel %lu\n", hel->dcmColorModel);
15224 ok(hal->dwFlags != 0, "HAL Device hal caps has hardware flags %#lx\n", hal->dwFlags);
15225 ok(hel->dwFlags != 0, "HAL Device hel caps has hardware flags %#lx\n", hel->dwFlags);
15227 ok(hal->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT,
15228 "HAL Device hal device caps does not have D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
15229 ok((hel->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
15230 "RGB Device hel device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
15231 ok(hal->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX,
15232 "HAL Device hal device caps does not have D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
15233 ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
15234 "RGB Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
15236 else if(IsEqualGUID(&IID_IDirect3DRefDevice, guid))
15238 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
15239 "REF Device hal line caps has D3DPTEXTURECAPS_POW2 flag set\n");
15240 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
15241 "REF Device hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n");
15242 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
15243 "REF Device hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
15244 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
15245 "REF Device hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
15247 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
15248 "REF Device hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
15249 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
15250 "REF Device hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
15251 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
15252 "REF Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
15253 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
15254 "REF Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
15256 ok((hal->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
15257 "REF Device hal device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
15258 ok((hel->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
15259 "REF Device hel device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
15260 ok((hal->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
15261 "REF Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
15262 ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
15263 "REF Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
15265 else if(IsEqualGUID(&IID_IDirect3DRampDevice, guid))
15267 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
15268 "Ramp Device hal line caps has D3DPTEXTURECAPS_POW2 flag set\n");
15269 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
15270 "Ramp Device hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n");
15271 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
15272 "Ramp Device hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
15273 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
15274 "Ramp Device hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
15276 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
15277 "Ramp Device hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
15278 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
15279 "Ramp Device hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
15280 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
15281 "Ramp Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
15282 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
15283 "Ramp Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
15285 ok(hal->dcmColorModel == 0, "Ramp Device hal caps has colormodel %lu\n", hal->dcmColorModel);
15286 ok(hel->dcmColorModel == D3DCOLOR_MONO, "Ramp Device hel caps has colormodel %lu\n",
15287 hel->dcmColorModel);
15289 ok(hal->dwFlags == 0, "Ramp Device hal caps has hardware flags %#lx\n", hal->dwFlags);
15290 ok(hel->dwFlags != 0, "Ramp Device hel caps has hardware flags %#lx\n", hel->dwFlags);
15292 ok((hal->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
15293 "Ramp Device hal device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
15294 ok((hel->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
15295 "Ramp Device hel device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
15296 ok((hal->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
15297 "Ramp Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
15298 ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
15299 "Ramp Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
15301 else if(IsEqualGUID(&IID_IDirect3DMMXDevice, guid))
15303 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
15304 "MMX Device hal line caps has D3DPTEXTURECAPS_POW2 flag set\n");
15305 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
15306 "MMX Device hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n");
15307 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
15308 "MMX Device hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
15309 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
15310 "MMX Device hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n");
15312 ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
15313 "MMX Device hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
15314 ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
15315 "MMX Device hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n");
15316 ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
15317 "MMX Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
15318 ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
15319 "MMX Device hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n");
15321 ok(hal->dcmColorModel == 0, "MMX Device hal caps has colormodel %lu\n", hal->dcmColorModel);
15322 ok(hel->dcmColorModel == D3DCOLOR_RGB, "MMX Device hel caps has colormodel %lu\n", hel->dcmColorModel);
15324 ok(hal->dwFlags == 0, "MMX Device hal caps has hardware flags %#lx\n", hal->dwFlags);
15325 ok(hel->dwFlags != 0, "MMX Device hel caps has hardware flags %#lx\n", hel->dwFlags);
15327 ok((hal->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
15328 "MMX Device hal device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
15329 ok((hel->dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0,
15330 "MMX Device hel device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n");
15331 ok((hal->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
15332 "MMX Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
15333 ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0,
15334 "MMX Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n");
15336 else
15338 ok(FALSE, "Unexpected device enumerated: \"%s\" \"%s\"\n", device_desc, device_name);
15339 if (hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2)
15340 trace("hal line has pow2 set\n");
15341 else
15342 trace("hal line does NOT have pow2 set\n");
15343 if (hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2)
15344 trace("hal tri has pow2 set\n");
15345 else
15346 trace("hal tri does NOT have pow2 set\n");
15347 if (hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2)
15348 trace("hel line has pow2 set\n");
15349 else
15350 trace("hel line does NOT have pow2 set\n");
15351 if (hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2)
15352 trace("hel tri has pow2 set\n");
15353 else
15354 trace("hel tri does NOT have pow2 set\n");
15357 return DDENUMRET_OK;
15360 static void test_enum_devices(void)
15362 IDirectDraw *ddraw;
15363 IDirect3D *d3d;
15364 ULONG refcount;
15365 HRESULT hr;
15367 ddraw = create_ddraw();
15368 ok(!!ddraw, "Failed to create a ddraw object.\n");
15370 hr = IDirectDraw_QueryInterface(ddraw, &IID_IDirect3D, (void **)&d3d);
15371 if (FAILED(hr))
15373 skip("D3D interface is not available, skipping test.\n");
15374 IDirectDraw_Release(ddraw);
15375 return;
15378 hr = IDirect3D_EnumDevices(d3d, NULL, NULL);
15379 ok(hr == DDERR_INVALIDPARAMS, "Got hr %#lx.\n", hr);
15381 hr = IDirect3D_EnumDevices(d3d, test_enum_devices_caps_callback, NULL);
15382 ok(hr == D3D_OK, "Got hr %#lx.\n", hr);
15384 IDirect3D_Release(d3d);
15385 refcount = IDirectDraw_Release(ddraw);
15386 ok(!refcount, "Device has %lu references left.\n", refcount);
15389 START_TEST(ddraw1)
15391 DDDEVICEIDENTIFIER identifier;
15392 DEVMODEW current_mode;
15393 IDirectDraw *ddraw;
15394 HMODULE dwmapi;
15396 if (!(ddraw = create_ddraw()))
15398 skip("Failed to create a ddraw object, skipping tests.\n");
15399 return;
15402 if (ddraw_get_identifier(ddraw, &identifier))
15404 trace("Driver string: \"%s\"\n", identifier.szDriver);
15405 trace("Description string: \"%s\"\n", identifier.szDescription);
15406 trace("Driver version %d.%d.%d.%d\n",
15407 HIWORD(U(identifier.liDriverVersion).HighPart), LOWORD(U(identifier.liDriverVersion).HighPart),
15408 HIWORD(U(identifier.liDriverVersion).LowPart), LOWORD(U(identifier.liDriverVersion).LowPart));
15410 IDirectDraw_Release(ddraw);
15412 memset(&current_mode, 0, sizeof(current_mode));
15413 current_mode.dmSize = sizeof(current_mode);
15414 ok(EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &current_mode), "Failed to get display mode.\n");
15415 registry_mode.dmSize = sizeof(registry_mode);
15416 ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &registry_mode), "Failed to get display mode.\n");
15417 if (registry_mode.dmPelsWidth != current_mode.dmPelsWidth
15418 || registry_mode.dmPelsHeight != current_mode.dmPelsHeight)
15420 skip("Current mode does not match registry mode, skipping test.\n");
15421 return;
15424 if ((dwmapi = LoadLibraryA("dwmapi.dll")))
15425 pDwmIsCompositionEnabled = (void *)GetProcAddress(dwmapi, "DwmIsCompositionEnabled");
15427 test_coop_level_create_device_window();
15428 test_clipper_blt();
15429 test_coop_level_d3d_state();
15430 test_surface_interface_mismatch();
15431 test_coop_level_threaded();
15432 test_viewport_object();
15433 run_for_each_device_type(test_zenable);
15434 run_for_each_device_type(test_ck_rgba);
15435 test_ck_default();
15436 test_ck_complex();
15437 test_surface_qi();
15438 test_device_qi();
15439 test_wndproc();
15440 test_window_style();
15441 test_redundant_mode_set();
15442 test_coop_level_mode_set();
15443 test_coop_level_mode_set_multi();
15444 test_initialize();
15445 test_coop_level_surf_create();
15446 test_coop_level_multi_window();
15447 test_clear_rect_count();
15448 test_coop_level_activateapp();
15449 test_unsupported_formats();
15450 run_for_each_device_type(test_rt_caps);
15451 test_primary_caps();
15452 test_surface_lock();
15453 test_surface_discard();
15454 test_flip();
15455 test_sysmem_overlay();
15456 test_primary_palette();
15457 test_surface_attachment();
15458 test_pixel_format();
15459 test_create_surface_pitch();
15460 test_mipmap();
15461 test_palette_complex();
15462 test_p8_blit();
15463 test_material();
15464 test_lighting();
15465 test_specular_lighting();
15466 test_palette_gdi();
15467 test_palette_alpha();
15468 test_lost_device();
15469 test_surface_desc_lock();
15470 test_texturemapblend();
15471 test_viewport_clear_rect();
15472 test_color_fill();
15473 test_colorkey_precision();
15474 test_range_colorkey();
15475 test_shademode();
15476 test_lockrect_invalid();
15477 test_yv12_overlay();
15478 test_offscreen_overlay();
15479 test_overlay_rect();
15480 test_blt();
15481 test_blt_z_alpha();
15482 test_cross_device_blt();
15483 test_getdc();
15484 test_transform_vertices();
15485 test_display_mode_surface_pixel_format();
15486 test_surface_desc_size();
15487 test_texture_load();
15488 test_ck_operation();
15489 test_depth_readback();
15490 test_clear();
15491 test_enum_surfaces();
15492 test_execute_data();
15493 test_viewport();
15494 test_find_device();
15495 test_killfocus();
15496 test_gdi_surface();
15497 test_alphatest();
15498 test_clipper_refcount();
15499 test_caps();
15500 test_d32_support();
15501 test_cursor_clipping();
15502 test_vtbl_protection();
15503 test_window_position();
15504 test_get_display_mode();
15505 run_for_each_device_type(test_texture_wrong_caps);
15506 test_filling_convention();
15507 test_enum_devices();