mapistub: Forward MAPISendMailW.
[wine/multimedia.git] / dlls / d3d8 / tests / surface.c
blob106297245e3a8ba37d006a12e9fe43def42d9b9c
1 /*
2 * Copyright 2006-2007 Henri Verbeet
3 * Copyright 2011 Stefan Dösinger for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
20 #include <d3d8.h>
21 #include "wine/test.h"
23 static HWND create_window(void)
25 WNDCLASS wc = {0};
26 wc.lpfnWndProc = DefWindowProc;
27 wc.lpszClassName = "d3d8_test_wc";
28 RegisterClass(&wc);
30 return CreateWindow("d3d8_test_wc", "d3d8_test",
31 0, 0, 0, 0, 0, 0, 0, 0, 0);
34 static IDirect3DDevice8 *init_d3d8(HMODULE d3d8_handle)
36 IDirect3D8 * (__stdcall * d3d8_create)(UINT SDKVersion) = 0;
37 IDirect3D8 *d3d8_ptr = 0;
38 IDirect3DDevice8 *device_ptr = 0;
39 D3DPRESENT_PARAMETERS present_parameters;
40 D3DDISPLAYMODE d3ddm;
41 HRESULT hr;
43 d3d8_create = (void *)GetProcAddress(d3d8_handle, "Direct3DCreate8");
44 ok(d3d8_create != NULL, "Failed to get address of Direct3DCreate8\n");
45 if (!d3d8_create) return NULL;
47 d3d8_ptr = d3d8_create(D3D_SDK_VERSION);
48 if (!d3d8_ptr)
50 skip("could not create D3D8\n");
51 return NULL;
54 IDirect3D8_GetAdapterDisplayMode(d3d8_ptr, D3DADAPTER_DEFAULT, &d3ddm );
55 ZeroMemory(&present_parameters, sizeof(present_parameters));
56 present_parameters.Windowed = TRUE;
57 present_parameters.hDeviceWindow = create_window();
58 present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
59 present_parameters.BackBufferFormat = d3ddm.Format;
60 present_parameters.EnableAutoDepthStencil = TRUE;
61 present_parameters.AutoDepthStencilFormat = D3DFMT_D24S8;
63 hr = IDirect3D8_CreateDevice(d3d8_ptr, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
64 NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device_ptr);
66 if(FAILED(hr))
68 skip("could not create device, IDirect3D8_CreateDevice returned %#x\n", hr);
69 return NULL;
72 return device_ptr;
75 /* Test the behaviour of the IDirect3DDevice8::CreateImageSurface method.
77 Expected behaviour (and also documented in the original DX8 docs) is that the
78 call returns a surface with the SYSTEMMEM pool type. Games like Max Payne 1
79 and 2 which use Direct3D8 calls depend on this behaviour.
81 A short remark in the DX9 docs however states that the pool of the
82 returned surface object is of type SCRATCH. This is misinformation and results
83 in screenshots not appearing in the savegame loading menu of both games
84 mentioned above (engine tries to display a texture from the scratch pool).
86 This test verifies that the behaviour described in the original D3D8 docs is
87 the correct one. For more information about this issue, see the MSDN:
89 D3D9 docs: "Converting to Direct3D 9"
90 D3D9 reference: "IDirect3DDevice9::CreateOffscreenPlainSurface"
91 D3D8 reference: "IDirect3DDevice8::CreateImageSurface"
94 static void test_image_surface_pool(IDirect3DDevice8 *device) {
95 IDirect3DSurface8 *surface = 0;
96 D3DSURFACE_DESC surf_desc;
97 HRESULT hr;
99 hr = IDirect3DDevice8_CreateImageSurface(device, 128, 128, D3DFMT_A8R8G8B8, &surface);
100 ok(SUCCEEDED(hr), "CreateImageSurface failed (0x%08x)\n", hr);
102 hr = IDirect3DSurface8_GetDesc(surface, &surf_desc);
103 ok(SUCCEEDED(hr), "GetDesc failed (0x%08x)\n", hr);
105 ok((surf_desc.Pool == D3DPOOL_SYSTEMMEM),
106 "CreateImageSurface returns surface with unexpected pool type %u (should be SYSTEMMEM = 2)\n", surf_desc.Pool);
108 IDirect3DSurface8_Release(surface);
111 static void test_surface_get_container(IDirect3DDevice8 *device_ptr)
113 IDirect3DTexture8 *texture_ptr = 0;
114 IDirect3DSurface8 *surface_ptr = 0;
115 void *container_ptr;
116 HRESULT hr;
118 hr = IDirect3DDevice8_CreateTexture(device_ptr, 128, 128, 1, 0,
119 D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture_ptr);
120 ok(SUCCEEDED(hr) && texture_ptr != NULL, "CreateTexture returned: hr %#x, texture_ptr %p. "
121 "Expected hr %#x, texture_ptr != %p\n", hr, texture_ptr, D3D_OK, NULL);
122 if (!texture_ptr || FAILED(hr)) goto cleanup;
124 hr = IDirect3DTexture8_GetSurfaceLevel(texture_ptr, 0, &surface_ptr);
125 ok(SUCCEEDED(hr) && surface_ptr != NULL, "GetSurfaceLevel returned: hr %#x, surface_ptr %p. "
126 "Expected hr %#x, surface_ptr != %p\n", hr, surface_ptr, D3D_OK, NULL);
127 if (!surface_ptr || FAILED(hr)) goto cleanup;
129 /* These should work... */
130 container_ptr = (void *)0x1337c0d3;
131 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IUnknown, &container_ptr);
132 ok(SUCCEEDED(hr) && container_ptr == texture_ptr, "GetContainer returned: hr %#x, container_ptr %p. "
133 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, S_OK, texture_ptr);
134 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
136 container_ptr = (void *)0x1337c0d3;
137 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IDirect3DResource8, &container_ptr);
138 ok(SUCCEEDED(hr) && container_ptr == texture_ptr, "GetContainer returned: hr %#x, container_ptr %p. "
139 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, S_OK, texture_ptr);
140 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
142 container_ptr = (void *)0x1337c0d3;
143 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IDirect3DBaseTexture8, &container_ptr);
144 ok(SUCCEEDED(hr) && container_ptr == texture_ptr, "GetContainer returned: hr %#x, container_ptr %p. "
145 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, S_OK, texture_ptr);
146 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
148 container_ptr = (void *)0x1337c0d3;
149 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IDirect3DTexture8, &container_ptr);
150 ok(SUCCEEDED(hr) && container_ptr == texture_ptr, "GetContainer returned: hr %#x, container_ptr %p. "
151 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, S_OK, texture_ptr);
152 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
154 /* ...and this one shouldn't. This should return E_NOINTERFACE and set container_ptr to NULL */
155 container_ptr = (void *)0x1337c0d3;
156 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IDirect3DSurface8, &container_ptr);
157 ok(hr == E_NOINTERFACE && container_ptr == NULL, "GetContainer returned: hr %#x, container_ptr %p. "
158 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, E_NOINTERFACE, NULL);
159 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
161 cleanup:
162 if (texture_ptr) IDirect3DTexture8_Release(texture_ptr);
163 if (surface_ptr) IDirect3DSurface8_Release(surface_ptr);
166 static void test_lockrect_invalid(IDirect3DDevice8 *device)
168 IDirect3DSurface8 *surface = 0;
169 D3DLOCKED_RECT locked_rect;
170 unsigned int i;
171 BYTE *base;
172 HRESULT hr;
174 const RECT valid[] = {
175 {60, 60, 68, 68},
176 {120, 60, 128, 68},
177 {60, 120, 68, 128},
180 const RECT invalid[] = {
181 {60, 60, 60, 68}, /* 0 height */
182 {60, 60, 68, 60}, /* 0 width */
183 {68, 60, 60, 68}, /* left > right */
184 {60, 68, 68, 60}, /* top > bottom */
185 {-8, 60, 0, 68}, /* left < surface */
186 {60, -8, 68, 0}, /* top < surface */
187 {-16, 60, -8, 68}, /* right < surface */
188 {60, -16, 68, -8}, /* bottom < surface */
189 {60, 60, 136, 68}, /* right > surface */
190 {60, 60, 68, 136}, /* bottom > surface */
191 {136, 60, 144, 68}, /* left > surface */
192 {60, 136, 68, 144}, /* top > surface */
195 hr = IDirect3DDevice8_CreateImageSurface(device, 128, 128, D3DFMT_A8R8G8B8, &surface);
196 ok(SUCCEEDED(hr), "CreateImageSurface failed (0x%08x)\n", hr);
198 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, NULL, 0);
199 ok(SUCCEEDED(hr), "LockRect failed (0x%08x)\n", hr);
201 base = locked_rect.pBits;
203 hr = IDirect3DSurface8_UnlockRect(surface);
204 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
206 for (i = 0; i < (sizeof(valid) / sizeof(*valid)); ++i)
208 unsigned int offset, expected_offset;
209 const RECT *rect = &valid[i];
211 locked_rect.pBits = (BYTE *)0xdeadbeef;
212 locked_rect.Pitch = 0xdeadbeef;
214 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, rect, 0);
215 ok(SUCCEEDED(hr), "LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]\n",
216 hr, rect->left, rect->top, rect->right, rect->bottom);
218 offset = (BYTE *)locked_rect.pBits - base;
219 expected_offset = rect->top * locked_rect.Pitch + rect->left * 4;
220 ok(offset == expected_offset, "Got offset %u, expected offset %u for rect [%d, %d]->[%d, %d]\n",
221 offset, expected_offset, rect->left, rect->top, rect->right, rect->bottom);
223 hr = IDirect3DSurface8_UnlockRect(surface);
224 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
227 for (i = 0; i < (sizeof(invalid) / sizeof(*invalid)); ++i)
229 const RECT *rect = &invalid[i];
231 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, rect, 0);
232 ok(hr == D3DERR_INVALIDCALL, "LockRect returned 0x%08x for rect [%d, %d]->[%d, %d]"
233 ", expected D3DERR_INVALIDCALL (0x%08x)\n", hr, rect->left, rect->top,
234 rect->right, rect->bottom, D3DERR_INVALIDCALL);
237 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, NULL, 0);
238 ok(SUCCEEDED(hr), "LockRect failed (0x%08x) for rect NULL\n", hr);
239 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, NULL, 0);
240 ok(hr == D3DERR_INVALIDCALL, "Double LockRect returned 0x%08x for rect NULL\n", hr);
241 hr = IDirect3DSurface8_UnlockRect(surface);
242 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
244 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &valid[0], 0);
245 ok(hr == D3D_OK, "LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]"
246 ", expected D3D_OK (0x%08x)\n", hr, valid[0].left, valid[0].top,
247 valid[0].right, valid[0].bottom, D3D_OK);
248 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &valid[0], 0);
249 ok(hr == D3DERR_INVALIDCALL, "Double LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]"
250 ", expected D3DERR_INVALIDCALL (0x%08x)\n", hr, valid[0].left, valid[0].top,
251 valid[0].right, valid[0].bottom,D3DERR_INVALIDCALL);
252 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &valid[1], 0);
253 ok(hr == D3DERR_INVALIDCALL, "Double LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]"
254 ", expected D3DERR_INVALIDCALL (0x%08x)\n", hr, valid[1].left, valid[1].top,
255 valid[1].right, valid[1].bottom, D3DERR_INVALIDCALL);
256 hr = IDirect3DSurface8_UnlockRect(surface);
257 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
259 IDirect3DSurface8_Release(surface);
262 static ULONG getref(IUnknown *iface)
264 IUnknown_AddRef(iface);
265 return IUnknown_Release(iface);
268 static void test_private_data(IDirect3DDevice8 *device)
270 HRESULT hr;
271 IDirect3DSurface8 *surface;
272 ULONG ref, ref2;
273 IUnknown *ptr;
274 DWORD size = sizeof(IUnknown *);
276 hr = IDirect3DDevice8_CreateImageSurface(device, 4, 4, D3DFMT_A8R8G8B8, &surface);
277 ok(SUCCEEDED(hr), "CreateImageSurface failed (0x%08x)\n", hr);
278 if(!surface)
280 return;
283 /* This fails */
284 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, 0, D3DSPD_IUNKNOWN);
285 ok(hr == D3DERR_INVALIDCALL, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
286 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, 5, D3DSPD_IUNKNOWN);
287 ok(hr == D3DERR_INVALIDCALL, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
288 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, sizeof(IUnknown *) * 2, D3DSPD_IUNKNOWN);
289 ok(hr == D3DERR_INVALIDCALL, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
291 ref = getref((IUnknown *) device);
292 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
293 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
294 ref2 = getref((IUnknown *) device);
295 ok(ref2 == ref + 1, "Object reference is %d, expected %d\n", ref2, ref + 1);
296 hr = IDirect3DSurface8_FreePrivateData(surface, &IID_IDirect3DSurface8);
297 ok(hr == D3D_OK, "IDirect3DSurface8_FreePrivateData returned %08x\n", hr);
298 ref2 = getref((IUnknown *) device);
299 ok(ref2 == ref, "Object reference is %d, expected %d\n", ref2, ref);
301 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8, device, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
302 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
303 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8, surface, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
304 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
305 ref2 = getref((IUnknown *) device);
306 ok(ref2 == ref, "Object reference is %d, expected %d\n", ref2, ref);
308 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8, device, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
309 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
310 hr = IDirect3DSurface8_GetPrivateData(surface, &IID_IDirect3DSurface8, &ptr, &size);
311 ok(hr == D3D_OK, "IDirect3DSurface8_GetPrivateData failed with %08x\n", hr);
312 ref2 = getref((IUnknown *) device);
313 /* Object is NOT being addrefed */
314 ok(ptr == (IUnknown *) device, "Returned interface pointer is %p, expected %p\n", ptr, device);
315 ok(ref2 == ref + 2, "Object reference is %d, expected %d. ptr at %p, orig at %p\n", ref2, ref + 2, ptr, device);
316 IUnknown_Release(ptr);
318 IDirect3DSurface8_Release(surface);
320 /* Destroying the surface frees the held reference */
321 ref2 = getref((IUnknown *) device);
322 /* -1 because the surface was released and held a reference before */
323 ok(ref2 == (ref - 1), "Object reference is %d, expected %d\n", ref2, ref - 1);
326 static void test_surface_dimensions(IDirect3DDevice8 *device)
328 IDirect3DSurface8 *surface;
329 HRESULT hr;
331 hr = IDirect3DDevice8_CreateImageSurface(device, 0, 1, D3DFMT_A8R8G8B8, &surface);
332 ok(hr == D3DERR_INVALIDCALL, "CreateOffscreenPlainSurface returned %#x, expected D3DERR_INVALIDCALL.\n", hr);
333 if (SUCCEEDED(hr)) IDirect3DSurface8_Release(surface);
335 hr = IDirect3DDevice8_CreateImageSurface(device, 1, 0, D3DFMT_A8R8G8B8, &surface);
336 ok(hr == D3DERR_INVALIDCALL, "CreateOffscreenPlainSurface returned %#x, expected D3DERR_INVALIDCALL.\n", hr);
337 if (SUCCEEDED(hr)) IDirect3DSurface8_Release(surface);
340 static void test_surface_format_null(IDirect3DDevice8 *device)
342 static const D3DFORMAT D3DFMT_NULL = MAKEFOURCC('N','U','L','L');
343 IDirect3DTexture8 *texture;
344 IDirect3DSurface8 *surface;
345 IDirect3DSurface8 *rt, *ds;
346 D3DLOCKED_RECT locked_rect;
347 D3DSURFACE_DESC desc;
348 IDirect3D8 *d3d;
349 HRESULT hr;
351 IDirect3DDevice8_GetDirect3D(device, &d3d);
353 hr = IDirect3D8_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
354 D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL);
355 if (hr != D3D_OK)
357 skip("No D3DFMT_NULL support, skipping test.\n");
358 IDirect3D8_Release(d3d);
359 return;
362 hr = IDirect3D8_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
363 D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, D3DFMT_NULL);
364 ok(hr == D3D_OK, "D3DFMT_NULL should be supported for render target textures, hr %#x.\n", hr);
366 hr = IDirect3D8_CheckDepthStencilMatch(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
367 D3DFMT_NULL, D3DFMT_D24S8);
368 ok(SUCCEEDED(hr), "Depth stencil match failed for D3DFMT_NULL, hr %#x.\n", hr);
370 IDirect3D8_Release(d3d);
372 hr = IDirect3DDevice8_CreateRenderTarget(device, 128, 128, D3DFMT_NULL,
373 D3DMULTISAMPLE_NONE, TRUE, &surface);
374 ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr);
376 hr = IDirect3DDevice8_GetRenderTarget(device, &rt);
377 ok(SUCCEEDED(hr), "Failed to get original render target, hr %#x.\n", hr);
379 hr = IDirect3DDevice8_GetDepthStencilSurface(device, &ds);
380 ok(SUCCEEDED(hr), "Failed to get original depth/stencil, hr %#x.\n", hr);
382 hr = IDirect3DDevice8_SetRenderTarget(device, surface, NULL);
383 ok(SUCCEEDED(hr), "Failed to set render target, hr %#x.\n", hr);
385 hr = IDirect3DDevice8_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0x00000000, 0.0f, 0);
386 ok(SUCCEEDED(hr), "Clear failed, hr %#x.\n", hr);
388 hr = IDirect3DDevice8_SetRenderTarget(device, rt, ds);
389 ok(SUCCEEDED(hr), "Failed to set render target, hr %#x.\n", hr);
391 IDirect3DSurface8_Release(rt);
392 IDirect3DSurface8_Release(ds);
394 hr = IDirect3DSurface8_GetDesc(surface, &desc);
395 ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
396 ok(desc.Width == 128, "Expected width 128, got %u.\n", desc.Width);
397 ok(desc.Height == 128, "Expected height 128, got %u.\n", desc.Height);
399 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, NULL, 0);
400 ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
401 ok(locked_rect.Pitch, "Expected non-zero pitch, got %u.\n", locked_rect.Pitch);
402 ok(!!locked_rect.pBits, "Expected non-NULL pBits, got %p.\n", locked_rect.pBits);
404 hr = IDirect3DSurface8_UnlockRect(surface);
405 ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
407 IDirect3DSurface8_Release(surface);
409 hr = IDirect3DDevice8_CreateTexture(device, 128, 128, 0, D3DUSAGE_RENDERTARGET,
410 D3DFMT_NULL, D3DPOOL_DEFAULT, &texture);
411 ok(SUCCEEDED(hr), "Failed to create texture, hr %#x.\n", hr);
412 IDirect3DTexture8_Release(texture);
415 static void test_surface_double_unlock(IDirect3DDevice8 *device)
417 static struct
419 D3DPOOL pool;
420 const char *name;
422 pools[] =
424 { D3DPOOL_DEFAULT, "D3DPOOL_DEFAULT" },
425 { D3DPOOL_SYSTEMMEM, "D3DPOOL_SYSTEMMEM" },
427 IDirect3DSurface8 *surface;
428 unsigned int i;
429 HRESULT hr;
430 D3DLOCKED_RECT lr;
431 IDirect3D8 *d3d;
433 hr = IDirect3DDevice8_GetDirect3D(device, &d3d);
434 ok(SUCCEEDED(hr), "IDirect3DDevice8_GetDirect3D failed, hr = 0x%08x\n", hr);
436 for (i = 0; i < (sizeof(pools) / sizeof(*pools)); i++)
438 switch (pools[i].pool)
440 case D3DPOOL_DEFAULT:
441 hr = IDirect3D8_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET,
442 D3DRTYPE_SURFACE, D3DFMT_X8R8G8B8);
443 if (FAILED(hr))
445 skip("D3DFMT_X8R8G8B8 render targets not supported, skipping double unlock DEFAULT pool test\n");
446 continue;
449 hr = IDirect3DDevice8_CreateRenderTarget(device, 64, 64, D3DFMT_X8R8G8B8,
450 D3DMULTISAMPLE_NONE, TRUE, &surface);
451 ok(SUCCEEDED(hr), "IDirect3DDevice8_CreateRenderTarget failed, hr = 0x%08x, pool %s\n",
452 hr, pools[i].name);
453 break;
455 case D3DPOOL_SYSTEMMEM:
456 hr = IDirect3DDevice8_CreateImageSurface(device, 64, 64, D3DFMT_X8R8G8B8, &surface);
457 ok(SUCCEEDED(hr), "IDirect3DDevice8_CreateImageSurface failed, hr = 0x%08x, pool %s\n",
458 hr, pools[i].name);
459 break;
461 default:
462 break;
465 hr = IDirect3DSurface8_UnlockRect(surface);
466 ok(hr == D3DERR_INVALIDCALL, "Unlock without lock returned 0x%08x, expected 0x%08x, pool %s\n",
467 hr, D3DERR_INVALIDCALL, pools[i].name);
469 hr = IDirect3DSurface8_LockRect(surface, &lr, NULL, 0);
470 ok(SUCCEEDED(hr), "IDirect3DSurface8_LockRect failed, hr = 0x%08x, pool %s\n",
471 hr, pools[i].name);
472 hr = IDirect3DSurface8_UnlockRect(surface);
473 ok(SUCCEEDED(hr), "IDirect3DSurface8_UnlockRect failed, hr = 0x%08x, pool %s\n",
474 hr, pools[i].name);
476 hr = IDirect3DSurface8_UnlockRect(surface);
477 ok(hr == D3DERR_INVALIDCALL, "Double unlock returned 0x%08x, expected 0x%08x, pool %s\n",
478 hr, D3DERR_INVALIDCALL, pools[i].name);
480 IDirect3DSurface8_Release(surface);
483 IDirect3D8_Release(d3d);
486 static void test_surface_lockrect_blocks(IDirect3DDevice8 *device)
488 IDirect3DTexture8 *texture;
489 IDirect3DSurface8 *surface;
490 IDirect3D8 *d3d;
491 D3DLOCKED_RECT locked_rect;
492 unsigned int i, j;
493 HRESULT hr;
494 RECT rect;
496 const struct
498 D3DFORMAT fmt;
499 const char *name;
500 unsigned int block_width;
501 unsigned int block_height;
502 BOOL broken;
504 formats[] =
506 {D3DFMT_DXT1, "D3DFMT_DXT1", 4, 4, FALSE},
507 {D3DFMT_DXT2, "D3DFMT_DXT2", 4, 4, FALSE},
508 {D3DFMT_DXT3, "D3DFMT_DXT3", 4, 4, FALSE},
509 {D3DFMT_DXT4, "D3DFMT_DXT4", 4, 4, FALSE},
510 {D3DFMT_DXT5, "D3DFMT_DXT5", 4, 4, FALSE},
511 /* ATI2N has 2x2 blocks on all AMD cards and Geforce 7 cards,
512 * which doesn't match the format spec. On newer Nvidia cards
513 * it has the correct 4x4 block size */
514 {MAKEFOURCC('A','T','I','2'), "ATI2N", 4, 4, TRUE},
515 /* YUY2 and UYVY are not supported in d3d8, there is no way
516 * to use them with this API considering their restrictions */
518 const struct
520 D3DPOOL pool;
521 const char *name;
522 /* Don't check the return value, Nvidia returns D3DERR_INVALIDCALL for some formats
523 * and E_INVALIDARG/DDERR_INVALIDPARAMS for others. */
524 BOOL success;
526 pools[] =
528 {D3DPOOL_DEFAULT, "D3DPOOL_DEFAULT", FALSE},
529 {D3DPOOL_SCRATCH, "D3DPOOL_SCRATCH", TRUE},
530 {D3DPOOL_SYSTEMMEM, "D3DPOOL_SYSTEMMEM",TRUE},
531 {D3DPOOL_MANAGED, "D3DPOOL_MANAGED", TRUE},
534 hr = IDirect3DDevice8_GetDirect3D(device, &d3d);
535 ok(SUCCEEDED(hr), "IDirect3DDevice8_GetDirect3D failed (%08x)\n", hr);
537 for (i = 0; i < (sizeof(formats) / sizeof(*formats)); ++i) {
538 hr = IDirect3D8_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC,
539 D3DRTYPE_TEXTURE, formats[i].fmt);
540 if (FAILED(hr))
542 skip("Format %s not supported, skipping lockrect offset test\n", formats[i].name);
543 continue;
546 for (j = 0; j < (sizeof(pools) / sizeof(*pools)); j++)
548 hr = IDirect3DDevice8_CreateTexture(device, 128, 128, 1,
549 pools[j].pool == D3DPOOL_DEFAULT ? D3DUSAGE_DYNAMIC : 0,
550 formats[i].fmt, pools[j].pool, &texture);
551 ok(SUCCEEDED(hr), "IDirect3DDevice8_CreateTexture failed (%08x)\n", hr);
552 hr = IDirect3DTexture8_GetSurfaceLevel(texture, 0, &surface);
553 ok(SUCCEEDED(hr), "IDirect3DTexture8_GetSurfaceLevel failed (%08x)\n", hr);
554 IDirect3DTexture8_Release(texture);
556 if (formats[i].block_width > 1)
558 SetRect(&rect, formats[i].block_width >> 1, 0, formats[i].block_width, formats[i].block_height);
559 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &rect, 0);
560 ok(!SUCCEEDED(hr) == !pools[j].success || broken(formats[i].broken),
561 "Partial block lock %s, expected %s, format %s, pool %s.\n",
562 SUCCEEDED(hr) ? "succeeded" : "failed",
563 pools[j].success ? "success" : "failure", formats[i].name, pools[j].name);
564 if (SUCCEEDED(hr))
566 hr = IDirect3DSurface8_UnlockRect(surface);
567 ok(SUCCEEDED(hr), "IDirect3DSurface8_UnlockRect failed (%08x)\n", hr);
570 SetRect(&rect, 0, 0, formats[i].block_width >> 1, formats[i].block_height);
571 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &rect, 0);
572 ok(!SUCCEEDED(hr) == !pools[j].success || broken(formats[i].broken),
573 "Partial block lock %s, expected %s, format %s, pool %s.\n",
574 SUCCEEDED(hr) ? "succeeded" : "failed",
575 pools[j].success ? "success" : "failure", formats[i].name, pools[j].name);
576 if (SUCCEEDED(hr))
578 hr = IDirect3DSurface8_UnlockRect(surface);
579 ok(SUCCEEDED(hr), "IDirect3DSurface8_UnlockRect failed (%08x)\n", hr);
583 if (formats[i].block_height > 1)
585 SetRect(&rect, 0, formats[i].block_height >> 1, formats[i].block_width, formats[i].block_height);
586 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &rect, 0);
587 ok(!SUCCEEDED(hr) == !pools[j].success || broken(formats[i].broken),
588 "Partial block lock %s, expected %s, format %s, pool %s.\n",
589 SUCCEEDED(hr) ? "succeeded" : "failed",
590 pools[j].success ? "success" : "failure", formats[i].name, pools[j].name);
591 if (SUCCEEDED(hr))
593 hr = IDirect3DSurface8_UnlockRect(surface);
594 ok(SUCCEEDED(hr), "IDirect3DSurface8_UnlockRect failed (%08x)\n", hr);
597 SetRect(&rect, 0, 0, formats[i].block_width, formats[i].block_height >> 1);
598 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &rect, 0);
599 ok(!SUCCEEDED(hr) == !pools[j].success || broken(formats[i].broken),
600 "Partial block lock %s, expected %s, format %s, pool %s.\n",
601 SUCCEEDED(hr) ? "succeeded" : "failed",
602 pools[j].success ? "success" : "failure", formats[i].name, pools[j].name);
603 if (SUCCEEDED(hr))
605 hr = IDirect3DSurface8_UnlockRect(surface);
606 ok(SUCCEEDED(hr), "IDirect3DSurface8_UnlockRect failed (%08x)\n", hr);
610 SetRect(&rect, 0, 0, formats[i].block_width, formats[i].block_height);
611 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &rect, 0);
612 ok(hr == D3D_OK, "Full block lock returned %08x, expected %08x, format %s, pool %s\n",
613 hr, D3D_OK, formats[i].name, pools[j].name);
614 if (SUCCEEDED(hr))
616 hr = IDirect3DSurface8_UnlockRect(surface);
617 ok(SUCCEEDED(hr), "IDirect3DSurface8_UnlockRect failed (%08x)\n", hr);
620 IDirect3DSurface8_Release(surface);
623 IDirect3D8_Release(d3d);
626 START_TEST(surface)
628 HMODULE d3d8_handle;
629 IDirect3DDevice8 *device_ptr;
630 ULONG refcount;
632 d3d8_handle = LoadLibraryA("d3d8.dll");
633 if (!d3d8_handle)
635 skip("Could not load d3d8.dll\n");
636 return;
639 device_ptr = init_d3d8(d3d8_handle);
640 if (!device_ptr) return;
642 test_image_surface_pool(device_ptr);
643 test_surface_get_container(device_ptr);
644 test_lockrect_invalid(device_ptr);
645 test_private_data(device_ptr);
646 test_surface_dimensions(device_ptr);
647 test_surface_format_null(device_ptr);
648 test_surface_double_unlock(device_ptr);
649 test_surface_lockrect_blocks(device_ptr);
651 refcount = IDirect3DDevice8_Release(device_ptr);
652 ok(!refcount, "Device has %u references left\n", refcount);