user32: Add a bunch of tests for GetQueueStatus and GetMessage combinations.
[wine/multimedia.git] / dlls / d3d8 / tests / surface.c
blob86fb884305096bcac9e0437c6b3c4494aefd730f
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 ok(d3d8_ptr != NULL, "Failed to create IDirect3D8 object\n");
48 if (!d3d8_ptr) return NULL;
50 IDirect3D8_GetAdapterDisplayMode(d3d8_ptr, D3DADAPTER_DEFAULT, &d3ddm );
51 ZeroMemory(&present_parameters, sizeof(present_parameters));
52 present_parameters.Windowed = TRUE;
53 present_parameters.hDeviceWindow = create_window();
54 present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
55 present_parameters.BackBufferFormat = d3ddm.Format;
57 hr = IDirect3D8_CreateDevice(d3d8_ptr, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
58 NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device_ptr);
60 if(FAILED(hr))
62 skip("could not create device, IDirect3D8_CreateDevice returned %#x\n", hr);
63 return NULL;
66 return device_ptr;
69 /* Test the behaviour of the IDirect3DDevice8::CreateImageSurface method.
71 Expected behaviour (and also documented in the original DX8 docs) is that the
72 call returns a surface with the SYSTEMMEM pool type. Games like Max Payne 1
73 and 2 which use Direct3D8 calls depend on this behaviour.
75 A short remark in the DX9 docs however states that the pool of the
76 returned surface object is of type SCRATCH. This is misinformation and results
77 in screenshots not appearing in the savegame loading menu of both games
78 mentioned above (engine tries to display a texture from the scratch pool).
80 This test verifies that the behaviour described in the original D3D8 docs is
81 the correct one. For more information about this issue, see the MSDN:
83 D3D9 docs: "Converting to Direct3D 9"
84 D3D9 reference: "IDirect3DDevice9::CreateOffscreenPlainSurface"
85 D3D8 reference: "IDirect3DDevice8::CreateImageSurface"
88 static void test_image_surface_pool(IDirect3DDevice8 *device) {
89 IDirect3DSurface8 *surface = 0;
90 D3DSURFACE_DESC surf_desc;
91 HRESULT hr;
93 hr = IDirect3DDevice8_CreateImageSurface(device, 128, 128, D3DFMT_A8R8G8B8, &surface);
94 ok(SUCCEEDED(hr), "CreateImageSurface failed (0x%08x)\n", hr);
96 hr = IDirect3DSurface8_GetDesc(surface, &surf_desc);
97 ok(SUCCEEDED(hr), "GetDesc failed (0x%08x)\n", hr);
99 ok((surf_desc.Pool == D3DPOOL_SYSTEMMEM),
100 "CreateImageSurface returns surface with unexpected pool type %u (should be SYSTEMMEM = 2)\n", surf_desc.Pool);
102 IDirect3DSurface8_Release(surface);
105 static void test_surface_get_container(IDirect3DDevice8 *device_ptr)
107 IDirect3DTexture8 *texture_ptr = 0;
108 IDirect3DSurface8 *surface_ptr = 0;
109 void *container_ptr;
110 HRESULT hr;
112 hr = IDirect3DDevice8_CreateTexture(device_ptr, 128, 128, 1, 0,
113 D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture_ptr);
114 ok(SUCCEEDED(hr) && texture_ptr != NULL, "CreateTexture returned: hr %#x, texture_ptr %p. "
115 "Expected hr %#x, texture_ptr != %p\n", hr, texture_ptr, D3D_OK, NULL);
116 if (!texture_ptr || FAILED(hr)) goto cleanup;
118 hr = IDirect3DTexture8_GetSurfaceLevel(texture_ptr, 0, &surface_ptr);
119 ok(SUCCEEDED(hr) && surface_ptr != NULL, "GetSurfaceLevel returned: hr %#x, surface_ptr %p. "
120 "Expected hr %#x, surface_ptr != %p\n", hr, surface_ptr, D3D_OK, NULL);
121 if (!surface_ptr || FAILED(hr)) goto cleanup;
123 /* These should work... */
124 container_ptr = (void *)0x1337c0d3;
125 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IUnknown, &container_ptr);
126 ok(SUCCEEDED(hr) && container_ptr == texture_ptr, "GetContainer returned: hr %#x, container_ptr %p. "
127 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, S_OK, texture_ptr);
128 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
130 container_ptr = (void *)0x1337c0d3;
131 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IDirect3DResource8, &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_IDirect3DBaseTexture8, &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_IDirect3DTexture8, &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 /* ...and this one shouldn't. This should return E_NOINTERFACE and set container_ptr to NULL */
149 container_ptr = (void *)0x1337c0d3;
150 hr = IDirect3DSurface8_GetContainer(surface_ptr, &IID_IDirect3DSurface8, &container_ptr);
151 ok(hr == E_NOINTERFACE && container_ptr == NULL, "GetContainer returned: hr %#x, container_ptr %p. "
152 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, E_NOINTERFACE, NULL);
153 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr);
155 cleanup:
156 if (texture_ptr) IDirect3DTexture8_Release(texture_ptr);
157 if (surface_ptr) IDirect3DSurface8_Release(surface_ptr);
160 static void test_lockrect_invalid(IDirect3DDevice8 *device)
162 IDirect3DSurface8 *surface = 0;
163 D3DLOCKED_RECT locked_rect;
164 unsigned int i;
165 BYTE *base;
166 HRESULT hr;
168 const RECT valid[] = {
169 {60, 60, 68, 68},
170 {120, 60, 128, 68},
171 {60, 120, 68, 128},
174 const RECT invalid[] = {
175 {60, 60, 60, 68}, /* 0 height */
176 {60, 60, 68, 60}, /* 0 width */
177 {68, 60, 60, 68}, /* left > right */
178 {60, 68, 68, 60}, /* top > bottom */
179 {-8, 60, 0, 68}, /* left < surface */
180 {60, -8, 68, 0}, /* top < surface */
181 {-16, 60, -8, 68}, /* right < surface */
182 {60, -16, 68, -8}, /* bottom < surface */
183 {60, 60, 136, 68}, /* right > surface */
184 {60, 60, 68, 136}, /* bottom > surface */
185 {136, 60, 144, 68}, /* left > surface */
186 {60, 136, 68, 144}, /* top > surface */
189 hr = IDirect3DDevice8_CreateImageSurface(device, 128, 128, D3DFMT_A8R8G8B8, &surface);
190 ok(SUCCEEDED(hr), "CreateImageSurface failed (0x%08x)\n", hr);
192 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, NULL, 0);
193 ok(SUCCEEDED(hr), "LockRect failed (0x%08x)\n", hr);
195 base = locked_rect.pBits;
197 hr = IDirect3DSurface8_UnlockRect(surface);
198 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
200 for (i = 0; i < (sizeof(valid) / sizeof(*valid)); ++i)
202 unsigned int offset, expected_offset;
203 const RECT *rect = &valid[i];
205 locked_rect.pBits = (BYTE *)0xdeadbeef;
206 locked_rect.Pitch = 0xdeadbeef;
208 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, rect, 0);
209 ok(SUCCEEDED(hr), "LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]\n",
210 hr, rect->left, rect->top, rect->right, rect->bottom);
212 offset = (BYTE *)locked_rect.pBits - base;
213 expected_offset = rect->top * locked_rect.Pitch + rect->left * 4;
214 ok(offset == expected_offset, "Got offset %u, expected offset %u for rect [%d, %d]->[%d, %d]\n",
215 offset, expected_offset, rect->left, rect->top, rect->right, rect->bottom);
217 hr = IDirect3DSurface8_UnlockRect(surface);
218 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
221 for (i = 0; i < (sizeof(invalid) / sizeof(*invalid)); ++i)
223 const RECT *rect = &invalid[i];
225 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, rect, 0);
226 ok(hr == D3DERR_INVALIDCALL, "LockRect returned 0x%08x for rect [%d, %d]->[%d, %d]"
227 ", expected D3DERR_INVALIDCALL (0x%08x)\n", hr, rect->left, rect->top,
228 rect->right, rect->bottom, D3DERR_INVALIDCALL);
231 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, NULL, 0);
232 ok(SUCCEEDED(hr), "LockRect failed (0x%08x) for rect NULL\n", hr);
233 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, NULL, 0);
234 ok(hr == D3DERR_INVALIDCALL, "Double LockRect returned 0x%08x for rect NULL\n", hr);
235 hr = IDirect3DSurface8_UnlockRect(surface);
236 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
238 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &valid[0], 0);
239 ok(hr == D3D_OK, "LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]"
240 ", expected D3D_OK (0x%08x)\n", hr, valid[0].left, valid[0].top,
241 valid[0].right, valid[0].bottom, D3D_OK);
242 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &valid[0], 0);
243 ok(hr == D3DERR_INVALIDCALL, "Double LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]"
244 ", expected D3DERR_INVALIDCALL (0x%08x)\n", hr, valid[0].left, valid[0].top,
245 valid[0].right, valid[0].bottom,D3DERR_INVALIDCALL);
246 hr = IDirect3DSurface8_LockRect(surface, &locked_rect, &valid[1], 0);
247 ok(hr == D3DERR_INVALIDCALL, "Double LockRect failed (0x%08x) for rect [%d, %d]->[%d, %d]"
248 ", expected D3DERR_INVALIDCALL (0x%08x)\n", hr, valid[1].left, valid[1].top,
249 valid[1].right, valid[1].bottom, D3DERR_INVALIDCALL);
250 hr = IDirect3DSurface8_UnlockRect(surface);
251 ok(SUCCEEDED(hr), "UnlockRect failed (0x%08x)\n", hr);
253 IDirect3DSurface8_Release(surface);
256 static unsigned long getref(IUnknown *iface)
258 IUnknown_AddRef(iface);
259 return IUnknown_Release(iface);
262 static void test_private_data(IDirect3DDevice8 *device)
264 HRESULT hr;
265 IDirect3DSurface8 *surface;
266 ULONG ref, ref2;
267 IUnknown *ptr;
268 DWORD size = sizeof(IUnknown *);
270 hr = IDirect3DDevice8_CreateImageSurface(device, 4, 4, D3DFMT_A8R8G8B8, &surface);
271 ok(SUCCEEDED(hr), "CreateImageSurface failed (0x%08x)\n", hr);
272 if(!surface)
274 return;
277 /* This fails */
278 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, 0, D3DSPD_IUNKNOWN);
279 ok(hr == D3DERR_INVALIDCALL, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
280 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, 5, D3DSPD_IUNKNOWN);
281 ok(hr == D3DERR_INVALIDCALL, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
282 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, sizeof(IUnknown *) * 2, D3DSPD_IUNKNOWN);
283 ok(hr == D3DERR_INVALIDCALL, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
285 ref = getref((IUnknown *) device);
286 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8 /* Abuse this tag */, device, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
287 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
288 ref2 = getref((IUnknown *) device);
289 ok(ref2 == ref + 1, "Object reference is %d, expected %d\n", ref2, ref + 1);
290 hr = IDirect3DSurface8_FreePrivateData(surface, &IID_IDirect3DSurface8);
291 ok(hr == D3D_OK, "IDirect3DSurface8_FreePrivateData returned %08x\n", hr);
292 ref2 = getref((IUnknown *) device);
293 ok(ref2 == ref, "Object reference is %d, expected %d\n", ref2, ref);
295 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8, device, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
296 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
297 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8, surface, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
298 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
299 ref2 = getref((IUnknown *) device);
300 ok(ref2 == ref, "Object reference is %d, expected %d\n", ref2, ref);
302 hr = IDirect3DSurface8_SetPrivateData(surface, &IID_IDirect3DSurface8, device, sizeof(IUnknown *), D3DSPD_IUNKNOWN);
303 ok(hr == D3D_OK, "IDirect3DSurface8_SetPrivateData failed with %08x\n", hr);
304 hr = IDirect3DSurface8_GetPrivateData(surface, &IID_IDirect3DSurface8, &ptr, &size);
305 ok(hr == D3D_OK, "IDirect3DSurface8_GetPrivateData failed with %08x\n", hr);
306 ref2 = getref((IUnknown *) device);
307 /* Object is NOT being addrefed */
308 ok(ptr == (IUnknown *) device, "Returned interface pointer is %p, expected %p\n", ptr, device);
309 ok(ref2 == ref + 2, "Object reference is %d, expected %d. ptr at %p, orig at %p\n", ref2, ref + 2, ptr, device);
310 IUnknown_Release(ptr);
312 IDirect3DSurface8_Release(surface);
314 /* Destroying the surface frees the held reference */
315 ref2 = getref((IUnknown *) device);
316 /* -1 because the surface was released and held a reference before */
317 ok(ref2 == (ref - 1), "Object reference is %d, expected %d\n", ref2, ref - 1);
320 START_TEST(surface)
322 HMODULE d3d8_handle;
323 IDirect3DDevice8 *device_ptr;
325 d3d8_handle = LoadLibraryA("d3d8.dll");
326 if (!d3d8_handle)
328 skip("Could not load d3d8.dll\n");
329 return;
332 device_ptr = init_d3d8(d3d8_handle);
333 if (!device_ptr) return;
335 test_image_surface_pool(device_ptr);
336 test_surface_get_container(device_ptr);
337 test_lockrect_invalid(device_ptr);
338 test_private_data(device_ptr);