push 5b1efc32b5a8acb1d5b5e60584746392dd0c436e
[wine/hacks.git] / dlls / d3d8 / tests / surface.c
blob4980a412abdf4f61326809bc80df20d72c23d03f
1 /*
2 * Copyright 2006-2007 Henri Verbeet
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 #define COBJMACROS
19 #include <d3d8.h>
20 #include "wine/test.h"
22 static HWND create_window(void)
24 WNDCLASS wc = {0};
25 wc.lpfnWndProc = DefWindowProc;
26 wc.lpszClassName = "d3d8_test_wc";
27 RegisterClass(&wc);
29 return CreateWindow("d3d8_test_wc", "d3d8_test",
30 0, 0, 0, 0, 0, 0, 0, 0, 0);
33 static IDirect3DDevice8 *init_d3d8(HMODULE d3d8_handle)
35 IDirect3D8 * (__stdcall * d3d8_create)(UINT SDKVersion) = 0;
36 IDirect3D8 *d3d8_ptr = 0;
37 IDirect3DDevice8 *device_ptr = 0;
38 D3DPRESENT_PARAMETERS present_parameters;
39 D3DDISPLAYMODE d3ddm;
40 HRESULT hr;
42 d3d8_create = (void *)GetProcAddress(d3d8_handle, "Direct3DCreate8");
43 ok(d3d8_create != NULL, "Failed to get address of Direct3DCreate8\n");
44 if (!d3d8_create) return NULL;
46 d3d8_ptr = d3d8_create(D3D_SDK_VERSION);
47 if (!d3d8_ptr)
49 skip("could not create D3D8\n");
50 return NULL;
53 IDirect3D8_GetAdapterDisplayMode(d3d8_ptr, D3DADAPTER_DEFAULT, &d3ddm );
54 ZeroMemory(&present_parameters, sizeof(present_parameters));
55 present_parameters.Windowed = TRUE;
56 present_parameters.hDeviceWindow = create_window();
57 present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
58 present_parameters.BackBufferFormat = d3ddm.Format;
60 hr = IDirect3D8_CreateDevice(d3d8_ptr, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
61 NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device_ptr);
63 if(FAILED(hr))
65 skip("could not create device, IDirect3D8_CreateDevice returned %#x\n", hr);
66 return NULL;
69 return device_ptr;
72 /* Test the behaviour of the IDirect3DDevice8::CreateImageSurface method.
74 Expected behaviour (and also documented in the original DX8 docs) is that the
75 call returns a surface with the SYSTEMMEM pool type. Games like Max Payne 1
76 and 2 which use Direct3D8 calls depend on this behaviour.
78 A short remark in the DX9 docs however states that the pool of the
79 returned surface object is of type SCRATCH. This is misinformation and results
80 in screenshots not appearing in the savegame loading menu of both games
81 mentioned above (engine tries to display a texture from the scratch pool).
83 This test verifies that the behaviour described in the original D3D8 docs is
84 the correct one. For more information about this issue, see the MSDN:
86 D3D9 docs: "Converting to Direct3D 9"
87 D3D9 reference: "IDirect3DDevice9::CreateOffscreenPlainSurface"
88 D3D8 reference: "IDirect3DDevice8::CreateImageSurface"
91 static void test_image_surface_pool(IDirect3DDevice8 *device) {
92 IDirect3DSurface8 *surface = 0;
93 D3DSURFACE_DESC surf_desc;
94 HRESULT hr;
96 hr = IDirect3DDevice8_CreateImageSurface(device, 128, 128, D3DFMT_A8R8G8B8, &surface);
97 ok(SUCCEEDED(hr), "CreateImageSurface failed (0x%08x)\n", hr);
99 hr = IDirect3DSurface8_GetDesc(surface, &surf_desc);
100 ok(SUCCEEDED(hr), "GetDesc failed (0x%08x)\n", hr);
102 ok((surf_desc.Pool == D3DPOOL_SYSTEMMEM),
103 "CreateImageSurface returns surface with unexpected pool type %u (should be SYSTEMMEM = 2)\n", surf_desc.Pool);
105 IDirect3DSurface8_Release(surface);
108 static void test_surface_get_container(IDirect3DDevice8 *device_ptr)
110 IDirect3DTexture8 *texture_ptr = 0;
111 IDirect3DSurface8 *surface_ptr = 0;
112 void *container_ptr;
113 HRESULT hr;
115 hr = IDirect3DDevice8_CreateTexture(device_ptr, 128, 128, 1, 0,
116 D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture_ptr);
117 ok(SUCCEEDED(hr) && texture_ptr != NULL, "CreateTexture returned: hr %#x, texture_ptr %p. "
118 "Expected hr %#x, texture_ptr != %p\n", hr, texture_ptr, D3D_OK, NULL);
119 if (!texture_ptr || FAILED(hr)) goto cleanup;
121 hr = IDirect3DTexture8_GetSurfaceLevel(texture_ptr, 0, &surface_ptr);
122 ok(SUCCEEDED(hr) && surface_ptr != NULL, "GetSurfaceLevel returned: hr %#x, surface_ptr %p. "
123 "Expected hr %#x, surface_ptr != %p\n", hr, surface_ptr, D3D_OK, NULL);
124 if (!surface_ptr || FAILED(hr)) goto cleanup;
126 /* These should work... */
127 container_ptr = (void *)0x1337c0d3;
128 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IUnknown, &container_ptr);
129 ok(SUCCEEDED(hr) && container_ptr == texture_ptr, "GetContainer returned: hr %#x, container_ptr %p. "
130 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, S_OK, texture_ptr);
131 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
133 container_ptr = (void *)0x1337c0d3;
134 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IDirect3DResource8, &container_ptr);
135 ok(SUCCEEDED(hr) && container_ptr == texture_ptr, "GetContainer returned: hr %#x, container_ptr %p. "
136 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, S_OK, texture_ptr);
137 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
139 container_ptr = (void *)0x1337c0d3;
140 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IDirect3DBaseTexture8, &container_ptr);
141 ok(SUCCEEDED(hr) && container_ptr == texture_ptr, "GetContainer returned: hr %#x, container_ptr %p. "
142 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, S_OK, texture_ptr);
143 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
145 container_ptr = (void *)0x1337c0d3;
146 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IDirect3DTexture8, &container_ptr);
147 ok(SUCCEEDED(hr) && container_ptr == texture_ptr, "GetContainer returned: hr %#x, container_ptr %p. "
148 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, S_OK, texture_ptr);
149 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
151 /* ...and this one shouldn't. This should return E_NOINTERFACE and set container_ptr to NULL */
152 container_ptr = (void *)0x1337c0d3;
153 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IDirect3DSurface8, &container_ptr);
154 ok(hr == E_NOINTERFACE && container_ptr == NULL, "GetContainer returned: hr %#x, container_ptr %p. "
155 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, E_NOINTERFACE, NULL);
156 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
158 cleanup:
159 if (texture_ptr) IDirect3DTexture8_Release(texture_ptr);
160 if (surface_ptr) IDirect3DSurface8_Release(surface_ptr);
163 static void test_lockrect_invalid(IDirect3DDevice8 *device)
165 IDirect3DSurface8 *surface = 0;
166 D3DLOCKED_RECT locked_rect;
167 unsigned int i;
168 BYTE *base;
169 HRESULT hr;
171 const RECT valid[] = {
172 {60, 60, 68, 68},
173 {120, 60, 128, 68},
174 {60, 120, 68, 128},
177 const RECT invalid[] = {
178 {60, 60, 60, 68}, /* 0 height */
179 {60, 60, 68, 60}, /* 0 width */
180 {68, 60, 60, 68}, /* left > right */
181 {60, 68, 68, 60}, /* top > bottom */
182 {-8, 60, 0, 68}, /* left < surface */
183 {60, -8, 68, 0}, /* top < surface */
184 {-16, 60, -8, 68}, /* right < surface */
185 {60, -16, 68, -8}, /* bottom < surface */
186 {60, 60, 136, 68}, /* right > surface */
187 {60, 60, 68, 136}, /* bottom > surface */
188 {136, 60, 144, 68}, /* left > surface */
189 {60, 136, 68, 144}, /* top > surface */
192 hr = IDirect3DDevice8_CreateImageSurface(device, 128, 128, D3DFMT_A8R8G8B8, &surface);
193 ok(SUCCEEDED(hr), "CreateImageSurface failed (0x%08x)\n", hr);
195 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, NULL, 0);
196 ok(SUCCEEDED(hr), "LockRect failed (0x%08x)\n", hr);
198 base = locked_rect.pBits;
200 hr = IDirect3DSurface8_UnlockRect(surface);
201 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
203 for (i = 0; i < (sizeof(valid) / sizeof(*valid)); ++i)
205 unsigned int offset, expected_offset;
206 const RECT *rect = &valid[i];
208 locked_rect.pBits = (BYTE *)0xdeadbeef;
209 locked_rect.Pitch = 0xdeadbeef;
211 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, rect, 0);
212 ok(SUCCEEDED(hr), "LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]\n",
213 hr, rect->left, rect->top, rect->right, rect->bottom);
215 offset = (BYTE *)locked_rect.pBits - base;
216 expected_offset = rect->top * locked_rect.Pitch + rect->left * 4;
217 ok(offset == expected_offset, "Got offset %u, expected offset %u for rect [%d, %d]->[%d, %d]\n",
218 offset, expected_offset, rect->left, rect->top, rect->right, rect->bottom);
220 hr = IDirect3DSurface8_UnlockRect(surface);
221 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
224 for (i = 0; i < (sizeof(invalid) / sizeof(*invalid)); ++i)
226 const RECT *rect = &invalid[i];
228 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, rect, 0);
229 ok(hr == D3DERR_INVALIDCALL, "LockRect returned 0x%08x for rect [%d, %d]->[%d, %d]"
230 ", expected D3DERR_INVALIDCALL (0x%08x)\n", hr, rect->left, rect->top,
231 rect->right, rect->bottom, D3DERR_INVALIDCALL);
234 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, NULL, 0);
235 ok(SUCCEEDED(hr), "LockRect failed (0x%08x) for rect NULL\n", hr);
236 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, NULL, 0);
237 ok(hr == D3DERR_INVALIDCALL, "Double LockRect returned 0x%08x for rect NULL\n", hr);
238 hr = IDirect3DSurface8_UnlockRect(surface);
239 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
241 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &valid[0], 0);
242 ok(hr == D3D_OK, "LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]"
243 ", expected D3D_OK (0x%08x)\n", hr, valid[0].left, valid[0].top,
244 valid[0].right, valid[0].bottom, D3D_OK);
245 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &valid[0], 0);
246 ok(hr == D3DERR_INVALIDCALL, "Double LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]"
247 ", expected D3DERR_INVALIDCALL (0x%08x)\n", hr, valid[0].left, valid[0].top,
248 valid[0].right, valid[0].bottom,D3DERR_INVALIDCALL);
249 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &valid[1], 0);
250 ok(hr == D3DERR_INVALIDCALL, "Double LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]"
251 ", expected D3DERR_INVALIDCALL (0x%08x)\n", hr, valid[1].left, valid[1].top,
252 valid[1].right, valid[1].bottom, D3DERR_INVALIDCALL);
253 hr = IDirect3DSurface8_UnlockRect(surface);
254 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
256 IDirect3DSurface8_Release(surface);
259 static ULONG getref(IUnknown *iface)
261 IUnknown_AddRef(iface);
262 return IUnknown_Release(iface);
265 static void test_private_data(IDirect3DDevice8 *device)
267 HRESULT hr;
268 IDirect3DSurface8 *surface;
269 ULONG ref, ref2;
270 IUnknown *ptr;
271 DWORD size = sizeof(IUnknown *);
273 hr = IDirect3DDevice8_CreateImageSurface(device, 4, 4, D3DFMT_A8R8G8B8, &surface);
274 ok(SUCCEEDED(hr), "CreateImageSurface failed (0x%08x)\n", hr);
275 if(!surface)
277 return;
280 /* This fails */
281 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, 0, D3DSPD_IUNKNOWN);
282 ok(hr == D3DERR_INVALIDCALL, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
283 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, 5, D3DSPD_IUNKNOWN);
284 ok(hr == D3DERR_INVALIDCALL, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
285 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, sizeof(IUnknown *) * 2, D3DSPD_IUNKNOWN);
286 ok(hr == D3DERR_INVALIDCALL, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
288 ref = getref((IUnknown *) device);
289 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
290 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
291 ref2 = getref((IUnknown *) device);
292 ok(ref2 == ref + 1, "Object reference is %d, expected %d\n", ref2, ref + 1);
293 hr = IDirect3DSurface8_FreePrivateData(surface, &IID_IDirect3DSurface8);
294 ok(hr == D3D_OK, "IDirect3DSurface8_FreePrivateData returned %08x\n", hr);
295 ref2 = getref((IUnknown *) device);
296 ok(ref2 == ref, "Object reference is %d, expected %d\n", ref2, ref);
298 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8, device, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
299 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
300 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8, surface, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
301 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
302 ref2 = getref((IUnknown *) device);
303 ok(ref2 == ref, "Object reference is %d, expected %d\n", ref2, ref);
305 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8, device, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
306 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
307 hr = IDirect3DSurface8_GetPrivateData(surface, &IID_IDirect3DSurface8, &ptr, &size);
308 ok(hr == D3D_OK, "IDirect3DSurface8_GetPrivateData failed with %08x\n", hr);
309 ref2 = getref((IUnknown *) device);
310 /* Object is NOT being addrefed */
311 ok(ptr == (IUnknown *) device, "Returned interface pointer is %p, expected %p\n", ptr, device);
312 ok(ref2 == ref + 2, "Object reference is %d, expected %d. ptr at %p, orig at %p\n", ref2, ref + 2, ptr, device);
313 IUnknown_Release(ptr);
315 IDirect3DSurface8_Release(surface);
317 /* Destroying the surface frees the held reference */
318 ref2 = getref((IUnknown *) device);
319 /* -1 because the surface was released and held a reference before */
320 ok(ref2 == (ref - 1), "Object reference is %d, expected %d\n", ref2, ref - 1);
323 START_TEST(surface)
325 HMODULE d3d8_handle;
326 IDirect3DDevice8 *device_ptr;
327 ULONG refcount;
329 d3d8_handle = LoadLibraryA("d3d8.dll");
330 if (!d3d8_handle)
332 skip("Could not load d3d8.dll\n");
333 return;
336 device_ptr = init_d3d8(d3d8_handle);
337 if (!device_ptr) return;
339 test_image_surface_pool(device_ptr);
340 test_surface_get_container(device_ptr);
341 test_lockrect_invalid(device_ptr);
342 test_private_data(device_ptr);
344 refcount = IDirect3DDevice8_Release(device_ptr);
345 ok(!refcount, "Device has %u references left\n", refcount);