2 * Copyright (C) 2006 Vitaliy Margolen
3 * Copyright (C) 2006 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
23 #include "wine/test.h"
25 static IDirect3D9 *(WINAPI *pDirect3DCreate9)(UINT);
27 static int get_refcount(IUnknown *object)
29 IUnknown_AddRef( object );
30 return IUnknown_Release( object );
33 #define CHECK_CALL(r,c,d,rc) \
35 int tmp1 = get_refcount( (IUnknown *)d ); \
37 ok(tmp1 == rc_new, "Invalid refcount. Expected %d got %d\n", rc_new, tmp1); \
39 trace("%s failed: %s\n", c, DXGetErrorString9(r)); \
42 #define CHECK_RELEASE(obj,d,rc) \
44 int tmp1, rc_new = rc; \
45 IUnknown_Release( obj ); \
46 tmp1 = get_refcount( (IUnknown *)d ); \
47 ok(tmp1 == rc_new, "Invalid refcount. Expected %d got %d\n", rc_new, tmp1); \
50 #define CHECK_REFCOUNT(obj,rc) \
53 int count = get_refcount( (IUnknown *)obj ); \
54 ok(count == rc_new, "Invalid refcount. Expected %d got %d\n", rc_new, count); \
57 #define CHECK_RELEASE_REFCOUNT(obj,rc) \
60 int count = IUnknown_Release( (IUnknown *)obj ); \
61 ok(count == rc_new, "Invalid refcount. Expected %d got %d\n", rc_new, count); \
64 #define CHECK_ADDREF_REFCOUNT(obj,rc) \
67 int count = IUnknown_AddRef( (IUnknown *)obj ); \
68 ok(count == rc_new, "Invalid refcount. Expected %d got %d\n", rc_new, count); \
71 #define CHECK_SURFACE_CONTAINER(obj,iid,expected) \
73 void *container_ptr = (void *)0x1337c0d3; \
74 hr = IDirect3DSurface9_GetContainer(obj, &iid, &container_ptr); \
75 ok(SUCCEEDED(hr) && container_ptr == expected, "GetContainer returned: hr %#x, container_ptr %p. " \
76 "Expected hr %#x, container_ptr %p\n", hr, container_ptr, S_OK, expected); \
77 if (container_ptr && container_ptr != (void *)0x1337c0d3) IUnknown_Release((IUnknown *)container_ptr); \
80 static void check_mipmap_levels(
81 IDirect3DDevice9* device,
82 int width, int height, int count)
85 IDirect3DBaseTexture9* texture = NULL;
86 HRESULT hr = IDirect3DDevice9_CreateTexture( device, width, height, 0, 0,
87 D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, (IDirect3DTexture9**) &texture, NULL );
90 DWORD levels = IDirect3DBaseTexture9_GetLevelCount(texture);
91 ok(levels == count, "Invalid level count. Expected %d got %u\n", count, levels);
93 trace("CreateTexture failed: %s\n", DXGetErrorString9(hr));
95 if (texture) IUnknown_Release( texture );
98 static void test_mipmap_levels(void)
104 IDirect3D9 *pD3d = NULL;
105 IDirect3DDevice9 *pDevice = NULL;
106 D3DPRESENT_PARAMETERS d3dpp;
107 D3DDISPLAYMODE d3ddm;
109 pD3d = pDirect3DCreate9( D3D_SDK_VERSION );
110 ok(pD3d != NULL, "Failed to create IDirect3D9 object\n");
111 hwnd = CreateWindow( "static", "d3d9_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
112 ok(hwnd != NULL, "Failed to create window\n");
113 if (!pD3d || !hwnd) goto cleanup;
115 IDirect3D9_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
116 ZeroMemory( &d3dpp, sizeof(d3dpp) );
117 d3dpp.Windowed = TRUE;
118 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
119 d3dpp.BackBufferFormat = d3ddm.Format;
121 hr = IDirect3D9_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_NULLREF, hwnd,
122 D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
123 ok(SUCCEEDED(hr), "Failed to create IDirect3D9Device (%s)\n", DXGetErrorString9(hr));
124 if (FAILED(hr)) goto cleanup;
126 check_mipmap_levels(pDevice, 32, 32, 6);
127 check_mipmap_levels(pDevice, 256, 1, 9);
128 check_mipmap_levels(pDevice, 1, 256, 9);
129 check_mipmap_levels(pDevice, 1, 1, 1);
132 if (pD3d) IUnknown_Release( pD3d );
133 if (pDevice) IUnknown_Release( pDevice );
134 DestroyWindow( hwnd );
137 static void test_swapchain(void)
141 IDirect3D9 *pD3d = NULL;
142 IDirect3DDevice9 *pDevice = NULL;
143 IDirect3DSwapChain9 *swapchain0 = NULL;
144 IDirect3DSwapChain9 *swapchain1 = NULL;
145 IDirect3DSwapChain9 *swapchain2 = NULL;
146 IDirect3DSwapChain9 *swapchain3 = NULL;
147 IDirect3DSwapChain9 *swapchainX = NULL;
148 IDirect3DSurface9 *backbuffer = NULL;
149 D3DPRESENT_PARAMETERS d3dpp;
150 D3DDISPLAYMODE d3ddm;
152 pD3d = pDirect3DCreate9( D3D_SDK_VERSION );
153 ok(pD3d != NULL, "Failed to create IDirect3D9 object\n");
154 hwnd = CreateWindow( "static", "d3d9_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
155 ok(hwnd != NULL, "Failed to create window\n");
156 if (!pD3d || !hwnd) goto cleanup;
158 IDirect3D9_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
159 ZeroMemory( &d3dpp, sizeof(d3dpp) );
160 d3dpp.Windowed = TRUE;
161 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
162 d3dpp.BackBufferFormat = d3ddm.Format;
163 d3dpp.BackBufferCount = 0;
165 hr = IDirect3D9_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_NULLREF, hwnd,
166 D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
167 ok(SUCCEEDED(hr), "Failed to create IDirect3D9Device (%s)\n", DXGetErrorString9(hr));
168 if (FAILED(hr)) goto cleanup;
170 /* Check if the back buffer count was modified */
171 ok(d3dpp.BackBufferCount == 1, "The back buffer count in the presentparams struct is %d\n", d3dpp.BackBufferCount);
173 /* Get the implicit swapchain */
174 hr = IDirect3DDevice9_GetSwapChain(pDevice, 0, &swapchain0);
175 ok(SUCCEEDED(hr), "Failed to get the impicit swapchain (%s)\n", DXGetErrorString9(hr));
176 if(swapchain0) IDirect3DSwapChain9_Release(swapchain0);
178 /* Check if there is a back buffer */
179 hr = IDirect3DSwapChain9_GetBackBuffer(swapchain0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
180 ok(SUCCEEDED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString9(hr));
181 ok(backbuffer != NULL, "The back buffer is NULL\n");
182 if(backbuffer) IDirect3DSurface9_Release(backbuffer);
184 /* Try to get a nonexistant swapchain */
185 hr = IDirect3DDevice9_GetSwapChain(pDevice, 1, &swapchainX);
186 ok(hr == D3DERR_INVALIDCALL, "GetSwapChain on an nonexistent swapchain returned (%s)\n", DXGetErrorString9(hr));
187 ok(swapchainX == NULL, "Swapchain 1 is %p\n", swapchainX);
188 if(swapchainX) IDirect3DSwapChain9_Release(swapchainX);
190 /* Create a bunch of swapchains */
191 d3dpp.BackBufferCount = 0;
192 hr = IDirect3DDevice9_CreateAdditionalSwapChain(pDevice, &d3dpp, &swapchain1);
193 ok(SUCCEEDED(hr), "Failed to create a swapchain (%s)\n", DXGetErrorString9(hr));
194 ok(d3dpp.BackBufferCount == 1, "The back buffer count in the presentparams struct is %d\n", d3dpp.BackBufferCount);
196 d3dpp.BackBufferCount = 1;
197 hr = IDirect3DDevice9_CreateAdditionalSwapChain(pDevice, &d3dpp, &swapchain2);
198 ok(SUCCEEDED(hr), "Failed to create a swapchain (%s)\n", DXGetErrorString9(hr));
200 d3dpp.BackBufferCount = 2;
201 hr = IDirect3DDevice9_CreateAdditionalSwapChain(pDevice, &d3dpp, &swapchain3);
202 ok(SUCCEEDED(hr), "Failed to create a swapchain (%s)\n", DXGetErrorString9(hr));
204 /* Swapchain 3, created with backbuffercount 2 */
205 backbuffer = (void *) 0xdeadbeef;
206 hr = IDirect3DSwapChain9_GetBackBuffer(swapchain3, 0, 0, &backbuffer);
207 ok(SUCCEEDED(hr), "Failed to get the 1st back buffer (%s)\n", DXGetErrorString9(hr));
208 ok(backbuffer != NULL && backbuffer != (void *) 0xdeadbeef, "The back buffer is %p\n", backbuffer);
209 if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface9_Release(backbuffer);
211 backbuffer = (void *) 0xdeadbeef;
212 hr = IDirect3DSwapChain9_GetBackBuffer(swapchain3, 1, 0, &backbuffer);
213 ok(SUCCEEDED(hr), "Failed to get the 2nd back buffer (%s)\n", DXGetErrorString9(hr));
214 ok(backbuffer != NULL && backbuffer != (void *) 0xdeadbeef, "The back buffer is %p\n", backbuffer);
215 if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface9_Release(backbuffer);
217 backbuffer = (void *) 0xdeadbeef;
218 hr = IDirect3DSwapChain9_GetBackBuffer(swapchain3, 2, 0, &backbuffer);
219 ok(hr == D3DERR_INVALIDCALL, "GetBackBuffer returned %s\n", DXGetErrorString9(hr));
220 ok(backbuffer == (void *) 0xdeadbeef, "The back buffer pointer was modified (%p)\n", backbuffer);
221 if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface9_Release(backbuffer);
223 backbuffer = (void *) 0xdeadbeef;
224 hr = IDirect3DSwapChain9_GetBackBuffer(swapchain3, 3, 0, &backbuffer);
225 ok(FAILED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString9(hr));
226 ok(backbuffer == (void *) 0xdeadbeef, "The back buffer pointer was modified (%p)\n", backbuffer);
227 if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface9_Release(backbuffer);
230 /* Check the back buffers of the swapchains */
231 /* Swapchain 1, created with backbuffercount 0 */
232 hr = IDirect3DSwapChain9_GetBackBuffer(swapchain1, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
233 ok(SUCCEEDED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString9(hr));
234 ok(backbuffer != NULL, "The back buffer is NULL (%s)\n", DXGetErrorString9(hr));
235 if(backbuffer) IDirect3DSurface9_Release(backbuffer);
237 backbuffer = (void *) 0xdeadbeef;
238 hr = IDirect3DSwapChain9_GetBackBuffer(swapchain1, 1, 0, &backbuffer);
239 ok(FAILED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString9(hr));
240 ok(backbuffer == (void *) 0xdeadbeef, "The back buffer pointer was modified (%p)\n", backbuffer);
241 if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface9_Release(backbuffer);
243 /* Swapchain 2 - created with backbuffercount 1 */
244 backbuffer = (void *) 0xdeadbeef;
245 hr = IDirect3DSwapChain9_GetBackBuffer(swapchain2, 0, 0, &backbuffer);
246 ok(SUCCEEDED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString9(hr));
247 ok(backbuffer != NULL && backbuffer != (void *) 0xdeadbeef, "The back buffer is %p\n", backbuffer);
248 if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface9_Release(backbuffer);
250 backbuffer = (void *) 0xdeadbeef;
251 hr = IDirect3DSwapChain9_GetBackBuffer(swapchain2, 1, 0, &backbuffer);
252 ok(hr == D3DERR_INVALIDCALL, "GetBackBuffer returned %s\n", DXGetErrorString9(hr));
253 ok(backbuffer == (void *) 0xdeadbeef, "The back buffer pointer was modified (%p)\n", backbuffer);
254 if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface9_Release(backbuffer);
256 backbuffer = (void *) 0xdeadbeef;
257 hr = IDirect3DSwapChain9_GetBackBuffer(swapchain2, 2, 0, &backbuffer);
258 ok(FAILED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString9(hr));
259 ok(backbuffer == (void *) 0xdeadbeef, "The back buffer pointer was modified (%p)\n", backbuffer);
260 if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface9_Release(backbuffer);
262 /* Try getSwapChain on a manually created swapchain
263 * it should fail, apparently GetSwapChain only returns implicit swapchains
265 swapchainX = (void *) 0xdeadbeef;
266 hr = IDirect3DDevice9_GetSwapChain(pDevice, 1, &swapchainX);
267 ok(hr == D3DERR_INVALIDCALL, "Failed to get the second swapchain (%s)\n", DXGetErrorString9(hr));
268 ok(swapchainX == NULL, "The swapchain pointer is %p\n", swapchainX);
269 if(swapchainX && swapchainX != (void *) 0xdeadbeef ) IDirect3DSwapChain9_Release(swapchainX);
272 if(swapchain1) IDirect3DSwapChain9_Release(swapchain1);
273 if(swapchain2) IDirect3DSwapChain9_Release(swapchain2);
274 if(swapchain3) IDirect3DSwapChain9_Release(swapchain3);
275 if(pDevice) IDirect3DDevice9_Release(pDevice);
276 if(pD3d) IDirect3DDevice9_Release(pD3d);
277 DestroyWindow( hwnd );
280 static void test_refcount(void)
284 IDirect3D9 *pD3d = NULL;
285 IDirect3DDevice9 *pDevice = NULL;
286 IDirect3DVertexBuffer9 *pVertexBuffer = NULL;
287 IDirect3DIndexBuffer9 *pIndexBuffer = NULL;
288 IDirect3DVertexDeclaration9 *pVertexDeclaration = NULL;
289 IDirect3DVertexShader9 *pVertexShader = NULL;
290 IDirect3DPixelShader9 *pPixelShader = NULL;
291 IDirect3DCubeTexture9 *pCubeTexture = NULL;
292 IDirect3DTexture9 *pTexture = NULL;
293 IDirect3DVolumeTexture9 *pVolumeTexture = NULL;
294 IDirect3DVolume9 *pVolumeLevel = NULL;
295 IDirect3DSurface9 *pStencilSurface = NULL;
296 IDirect3DSurface9 *pOffscreenSurface = NULL;
297 IDirect3DSurface9 *pRenderTarget = NULL;
298 IDirect3DSurface9 *pRenderTarget2 = NULL;
299 IDirect3DSurface9 *pRenderTarget3 = NULL;
300 IDirect3DSurface9 *pTextureLevel = NULL;
301 IDirect3DSurface9 *pBackBuffer = NULL;
302 IDirect3DStateBlock9 *pStateBlock = NULL;
303 IDirect3DStateBlock9 *pStateBlock1 = NULL;
304 IDirect3DSwapChain9 *pSwapChain = NULL;
305 IDirect3DQuery9 *pQuery = NULL;
306 D3DPRESENT_PARAMETERS d3dpp;
307 D3DDISPLAYMODE d3ddm;
308 int refcount = 0, tmp;
310 D3DVERTEXELEMENT9 decl[] =
314 static DWORD simple_vs[] = {0xFFFE0101, /* vs_1_1 */
315 0x0000001F, 0x80000000, 0x900F0000, /* dcl_position0 v0 */
316 0x00000009, 0xC0010000, 0x90E40000, 0xA0E40000, /* dp4 oPos.x, v0, c0 */
317 0x00000009, 0xC0020000, 0x90E40000, 0xA0E40001, /* dp4 oPos.y, v0, c1 */
318 0x00000009, 0xC0040000, 0x90E40000, 0xA0E40002, /* dp4 oPos.z, v0, c2 */
319 0x00000009, 0xC0080000, 0x90E40000, 0xA0E40003, /* dp4 oPos.w, v0, c3 */
320 0x0000FFFF}; /* END */
321 static DWORD simple_ps[] = {0xFFFF0101, /* ps_1_1 */
322 0x00000051, 0xA00F0001, 0x3F800000, 0x00000000, 0x00000000, 0x00000000, /* def c1 = 1.0, 0.0, 0.0, 0.0 */
323 0x00000042, 0xB00F0000, /* tex t0 */
324 0x00000008, 0x800F0000, 0xA0E40001, 0xA0E40000, /* dp3 r0, c1, c0 */
325 0x00000005, 0x800F0000, 0x90E40000, 0x80E40000, /* mul r0, v0, r0 */
326 0x00000005, 0x800F0000, 0xB0E40000, 0x80E40000, /* mul r0, t0, r0 */
327 0x0000FFFF}; /* END */
330 pD3d = pDirect3DCreate9( D3D_SDK_VERSION );
331 ok(pD3d != NULL, "Failed to create IDirect3D9 object\n");
332 hwnd = CreateWindow( "static", "d3d9_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
333 ok(hwnd != NULL, "Failed to create window\n");
334 if (!pD3d || !hwnd) goto cleanup;
336 IDirect3D9_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
337 ZeroMemory( &d3dpp, sizeof(d3dpp) );
338 d3dpp.Windowed = TRUE;
339 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
340 d3dpp.BackBufferFormat = d3ddm.Format;
341 d3dpp.EnableAutoDepthStencil = TRUE;
342 d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
344 hr = IDirect3D9_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_NULLREF, hwnd,
345 D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
346 ok(SUCCEEDED(hr), "Failed to create IDirect3D9Device (%s)\n", DXGetErrorString9(hr));
347 if (FAILED(hr)) goto cleanup;
349 refcount = get_refcount( (IUnknown *)pDevice );
350 ok(refcount == 1, "Invalid device RefCount %d\n", refcount);
353 * Check refcount of implicit surfaces and implicit swapchain. Findings:
354 * - the container is the device OR swapchain
355 * - they hold a refernce to the device
356 * - they are created with a refcount of 0 (Get/Release returns orignial refcount)
357 * - they are not freed if refcount reaches 0.
358 * - the refcount is not forwarded to the container.
360 hr = IDirect3DDevice9_GetSwapChain(pDevice, 0, &pSwapChain);
361 todo_wine CHECK_CALL( hr, "GetSwapChain", pDevice, ++refcount);
364 todo_wine CHECK_REFCOUNT( pSwapChain, 1);
366 hr = IDirect3DDevice9_GetRenderTarget(pDevice, 0, &pRenderTarget);
367 todo_wine CHECK_CALL( hr, "GetRenderTarget", pDevice, ++refcount);
368 todo_wine CHECK_REFCOUNT( pSwapChain, 1);
371 CHECK_SURFACE_CONTAINER( pRenderTarget, IID_IDirect3DSwapChain9, pSwapChain);
372 todo_wine CHECK_REFCOUNT( pRenderTarget, 1);
374 todo_wine CHECK_ADDREF_REFCOUNT(pRenderTarget, 2);
375 todo_wine CHECK_REFCOUNT(pDevice, refcount);
376 todo_wine CHECK_RELEASE_REFCOUNT(pRenderTarget, 1);
377 todo_wine CHECK_REFCOUNT(pDevice, refcount);
379 hr = IDirect3DDevice9_GetRenderTarget(pDevice, 0, &pRenderTarget);
380 todo_wine CHECK_CALL( hr, "GetRenderTarget", pDevice, refcount);
381 todo_wine CHECK_REFCOUNT( pRenderTarget, 2);
382 todo_wine CHECK_RELEASE_REFCOUNT( pRenderTarget, 1);
383 todo_wine CHECK_RELEASE_REFCOUNT( pRenderTarget, 0);
384 todo_wine CHECK_REFCOUNT( pDevice, --refcount);
386 /* The render target is released with the device, so AddRef with refcount=0 is fine here. */
387 todo_wine CHECK_ADDREF_REFCOUNT(pRenderTarget, 1);
388 todo_wine CHECK_REFCOUNT(pDevice, ++refcount);
389 todo_wine CHECK_RELEASE_REFCOUNT(pRenderTarget, 0);
390 todo_wine CHECK_REFCOUNT(pDevice, --refcount);
393 /* Render target and back buffer are identical. */
394 hr = IDirect3DDevice9_GetBackBuffer(pDevice, 0, 0, 0, &pBackBuffer);
395 todo_wine CHECK_CALL( hr, "GetBackBuffer", pDevice, ++refcount);
398 todo_wine CHECK_RELEASE_REFCOUNT(pBackBuffer, 0);
399 ok(pRenderTarget == pBackBuffer, "RenderTarget=%p and BackBuffer=%p should be the same.\n",
400 pRenderTarget, pBackBuffer);
403 todo_wine CHECK_REFCOUNT( pDevice, --refcount);
405 hr = IDirect3DDevice9_GetDepthStencilSurface(pDevice, &pStencilSurface);
406 todo_wine CHECK_CALL( hr, "GetDepthStencilSurface", pDevice, ++refcount);
407 todo_wine CHECK_REFCOUNT( pSwapChain, 1);
410 CHECK_SURFACE_CONTAINER( pStencilSurface, IID_IDirect3DDevice9, pDevice);
411 todo_wine CHECK_REFCOUNT( pStencilSurface, 1);
413 todo_wine CHECK_ADDREF_REFCOUNT(pStencilSurface, 2);
414 todo_wine CHECK_REFCOUNT(pDevice, refcount);
415 todo_wine CHECK_RELEASE_REFCOUNT(pStencilSurface, 1);
416 todo_wine CHECK_REFCOUNT(pDevice, refcount);
418 todo_wine CHECK_RELEASE_REFCOUNT( pStencilSurface, 0);
419 todo_wine CHECK_REFCOUNT( pDevice, --refcount);
421 /* The stencil surface is released with the device, so AddRef with refcount=0 is fine here. */
422 todo_wine CHECK_ADDREF_REFCOUNT(pStencilSurface, 1);
423 todo_wine CHECK_REFCOUNT(pDevice, ++refcount);
424 todo_wine CHECK_RELEASE_REFCOUNT(pStencilSurface, 0);
425 todo_wine CHECK_REFCOUNT(pDevice, --refcount);
426 pStencilSurface = NULL;
429 todo_wine CHECK_RELEASE_REFCOUNT( pSwapChain, 0);
430 CHECK_REFCOUNT( pDevice, --refcount);
432 /* The implicit swapchwin is released with the device, so AddRef with refcount=0 is fine here. */
433 todo_wine CHECK_ADDREF_REFCOUNT(pSwapChain, 1);
434 todo_wine CHECK_REFCOUNT(pDevice, ++refcount);
435 todo_wine CHECK_RELEASE_REFCOUNT(pSwapChain, 0);
436 CHECK_REFCOUNT(pDevice, --refcount);
441 hr = IDirect3DDevice9_CreateIndexBuffer( pDevice, 16, 0, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &pIndexBuffer, NULL );
442 CHECK_CALL( hr, "CreateIndexBuffer", pDevice, ++refcount );
445 tmp = get_refcount( (IUnknown *)pIndexBuffer );
447 hr = IDirect3DDevice9_SetIndices(pDevice, pIndexBuffer);
448 CHECK_CALL( hr, "SetIndices", pIndexBuffer, tmp);
449 hr = IDirect3DDevice9_SetIndices(pDevice, NULL);
450 CHECK_CALL( hr, "SetIndices", pIndexBuffer, tmp);
453 hr = IDirect3DDevice9_CreateVertexBuffer( pDevice, 16, 0, D3DFVF_XYZ, D3DPOOL_DEFAULT, &pVertexBuffer, NULL );
454 CHECK_CALL( hr, "CreateVertexBuffer", pDevice, ++refcount );
457 tmp = get_refcount( (IUnknown *)pVertexBuffer );
459 hr = IDirect3DDevice9_SetStreamSource(pDevice, 0, pVertexBuffer, 0, 3 * sizeof(float));
460 CHECK_CALL( hr, "SetStreamSource", pVertexBuffer, tmp);
461 hr = IDirect3DDevice9_SetStreamSource(pDevice, 0, NULL, 0, 0);
462 CHECK_CALL( hr, "SetStreamSource", pVertexBuffer, tmp);
465 hr = IDirect3DDevice9_CreateVertexDeclaration( pDevice, decl, &pVertexDeclaration );
466 CHECK_CALL( hr, "CreateVertexDeclaration", pDevice, ++refcount );
467 hr = IDirect3DDevice9_CreateVertexShader( pDevice, simple_vs, &pVertexShader );
468 CHECK_CALL( hr, "CreateVertexShader", pDevice, ++refcount );
469 hr = IDirect3DDevice9_CreatePixelShader( pDevice, simple_ps, &pPixelShader );
470 CHECK_CALL( hr, "CreatePixelShader", pDevice, ++refcount );
472 hr = IDirect3DDevice9_CreateTexture( pDevice, 32, 32, 3, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pTexture, NULL );
473 CHECK_CALL( hr, "CreateTexture", pDevice, ++refcount );
476 tmp = get_refcount( (IUnknown *)pTexture );
478 /* SetTexture should not increase refcounts */
479 hr = IDirect3DDevice9_SetTexture(pDevice, 0, (IDirect3DBaseTexture9 *) pTexture);
480 CHECK_CALL( hr, "SetTexture", pTexture, tmp);
481 hr = IDirect3DDevice9_SetTexture(pDevice, 0, NULL);
482 CHECK_CALL( hr, "SetTexture", pTexture, tmp);
484 /* This should not increment device refcount */
485 hr = IDirect3DTexture9_GetSurfaceLevel( pTexture, 1, &pTextureLevel );
486 CHECK_CALL( hr, "GetSurfaceLevel", pDevice, refcount );
487 /* But should increment texture's refcount */
488 CHECK_REFCOUNT( pTexture, tmp+1 );
489 /* Because the texture and surface refcount are identical */
492 CHECK_REFCOUNT ( pTextureLevel, tmp+1 );
493 CHECK_ADDREF_REFCOUNT ( pTextureLevel, tmp+2 );
494 CHECK_REFCOUNT ( pTexture , tmp+2 );
495 CHECK_RELEASE_REFCOUNT( pTextureLevel, tmp+1 );
496 CHECK_REFCOUNT ( pTexture , tmp+1 );
497 CHECK_RELEASE_REFCOUNT( pTexture , tmp );
498 CHECK_REFCOUNT ( pTextureLevel, tmp );
501 hr = IDirect3DDevice9_CreateCubeTexture( pDevice, 32, 0, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pCubeTexture, NULL );
502 CHECK_CALL( hr, "CreateCubeTexture", pDevice, ++refcount );
503 hr = IDirect3DDevice9_CreateVolumeTexture( pDevice, 32, 32, 2, 0, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pVolumeTexture, NULL );
504 CHECK_CALL( hr, "CreateVolumeTexture", pDevice, ++refcount );
507 tmp = get_refcount( (IUnknown *)pVolumeTexture );
509 /* This should not increment device refcount */
510 hr = IDirect3DVolumeTexture9_GetVolumeLevel(pVolumeTexture, 0, &pVolumeLevel);
511 CHECK_CALL( hr, "GetVolumeLevel", pDevice, refcount );
512 /* But should increment volume texture's refcount */
513 CHECK_REFCOUNT( pVolumeTexture, tmp+1 );
514 /* Because the volume texture and volume refcount are identical */
517 CHECK_REFCOUNT ( pVolumeLevel , tmp+1 );
518 CHECK_ADDREF_REFCOUNT ( pVolumeLevel , tmp+2 );
519 CHECK_REFCOUNT ( pVolumeTexture, tmp+2 );
520 CHECK_RELEASE_REFCOUNT( pVolumeLevel , tmp+1 );
521 CHECK_REFCOUNT ( pVolumeTexture, tmp+1 );
522 CHECK_RELEASE_REFCOUNT( pVolumeTexture, tmp );
523 CHECK_REFCOUNT ( pVolumeLevel , tmp );
527 hr = IDirect3DDevice9_CreateDepthStencilSurface( pDevice, 32, 32, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &pStencilSurface, NULL );
528 CHECK_CALL( hr, "CreateDepthStencilSurface", pDevice, ++refcount );
529 hr = IDirect3DDevice9_CreateOffscreenPlainSurface( pDevice, 32, 32, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pOffscreenSurface, NULL );
530 CHECK_CALL( hr, "CreateOffscreenPlainSurface", pDevice, ++refcount );
531 hr = IDirect3DDevice9_CreateRenderTarget( pDevice, 32, 32, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pRenderTarget3, NULL );
532 CHECK_CALL( hr, "CreateRenderTarget", pDevice, ++refcount );
534 hr = IDirect3DDevice9_CreateStateBlock( pDevice, D3DSBT_ALL, &pStateBlock );
535 CHECK_CALL( hr, "CreateStateBlock", pDevice, ++refcount );
536 hr = IDirect3DDevice9_CreateAdditionalSwapChain( pDevice, &d3dpp, &pSwapChain );
537 CHECK_CALL( hr, "CreateAdditionalSwapChain", pDevice, ++refcount );
540 /* check implicit back buffer */
541 hr = IDirect3DSwapChain9_GetBackBuffer(pSwapChain, 0, 0, &pBackBuffer);
542 todo_wine CHECK_CALL( hr, "GetBackBuffer", pDevice, ++refcount);
543 todo_wine CHECK_REFCOUNT( pSwapChain, 1);
546 CHECK_SURFACE_CONTAINER( pBackBuffer, IID_IDirect3DSwapChain9, pSwapChain);
547 todo_wine CHECK_REFCOUNT( pBackBuffer, 1);
548 todo_wine CHECK_RELEASE_REFCOUNT( pBackBuffer, 0);
549 CHECK_REFCOUNT( pDevice, --refcount);
551 /* The back buffer is released with the swapchain, so AddRef with refcount=0 is fine here. */
552 todo_wine CHECK_ADDREF_REFCOUNT(pBackBuffer, 1);
553 todo_wine CHECK_REFCOUNT(pDevice, ++refcount);
554 todo_wine CHECK_RELEASE_REFCOUNT(pBackBuffer, 0);
555 CHECK_REFCOUNT(pDevice, --refcount);
558 CHECK_REFCOUNT( pSwapChain, 1);
560 hr = IDirect3DDevice9_CreateQuery( pDevice, D3DQUERYTYPE_EVENT, &pQuery );
561 CHECK_CALL( hr, "CreateQuery", pDevice, ++refcount );
563 hr = IDirect3DDevice9_BeginStateBlock( pDevice );
564 CHECK_CALL( hr, "BeginStateBlock", pDevice, refcount );
565 hr = IDirect3DDevice9_EndStateBlock( pDevice, &pStateBlock1 );
566 CHECK_CALL( hr, "EndStateBlock", pDevice, ++refcount );
568 /* The implicit render target is not freed if refcount reaches 0.
569 * Otherwise GetRenderTarget would re-allocate it and the pointer would change.*/
570 hr = IDirect3DDevice9_GetRenderTarget(pDevice, 0, &pRenderTarget2);
571 todo_wine CHECK_CALL( hr, "GetRenderTarget", pDevice, ++refcount);
574 todo_wine CHECK_RELEASE_REFCOUNT(pRenderTarget2, 0);
575 ok(pRenderTarget == pRenderTarget2, "RenderTarget=%p and RenderTarget2=%p should be the same.\n",
576 pRenderTarget, pRenderTarget2);
577 CHECK_REFCOUNT( pDevice, --refcount);
578 pRenderTarget2 = NULL;
580 pRenderTarget = NULL;
583 CHECK_RELEASE(pDevice, pDevice, --refcount);
586 CHECK_RELEASE(pVertexBuffer, pDevice, --refcount);
587 CHECK_RELEASE(pIndexBuffer, pDevice, --refcount);
589 CHECK_RELEASE(pVertexDeclaration, pDevice, --refcount);
590 CHECK_RELEASE(pVertexShader, pDevice, --refcount);
591 CHECK_RELEASE(pPixelShader, pDevice, --refcount);
593 CHECK_RELEASE(pTextureLevel, pDevice, --refcount);
594 CHECK_RELEASE(pCubeTexture, pDevice, --refcount);
595 CHECK_RELEASE(pVolumeTexture, pDevice, --refcount);
597 CHECK_RELEASE(pStencilSurface, pDevice, --refcount);
598 CHECK_RELEASE(pOffscreenSurface, pDevice, --refcount);
599 CHECK_RELEASE(pRenderTarget3, pDevice, --refcount);
601 CHECK_RELEASE(pStateBlock, pDevice, --refcount);
602 CHECK_RELEASE(pSwapChain, pDevice, --refcount);
603 CHECK_RELEASE(pQuery, pDevice, --refcount);
604 /* This will destroy device - cannot check the refcount here */
605 if (pStateBlock1) CHECK_RELEASE_REFCOUNT( pStateBlock1, 0);
607 if (pD3d) CHECK_RELEASE_REFCOUNT( pD3d, 0);
609 DestroyWindow( hwnd );
612 static void test_cursor(void)
616 IDirect3D9 *pD3d = NULL;
617 IDirect3DDevice9 *pDevice = NULL;
618 D3DPRESENT_PARAMETERS d3dpp;
619 D3DDISPLAYMODE d3ddm;
621 IDirect3DSurface9 *cursor = NULL;
624 memset(&info, 0, sizeof(info));
625 info.cbSize = sizeof(info);
626 hr = GetCursorInfo(&info);
629 pD3d = pDirect3DCreate9( D3D_SDK_VERSION );
630 ok(pD3d != NULL, "Failed to create IDirect3D9 object\n");
631 hwnd = CreateWindow( "static", "d3d9_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
632 ok(hwnd != NULL, "Failed to create window\n");
633 if (!pD3d || !hwnd) goto cleanup;
635 IDirect3D9_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
636 ZeroMemory( &d3dpp, sizeof(d3dpp) );
637 d3dpp.Windowed = TRUE;
638 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
639 d3dpp.BackBufferFormat = d3ddm.Format;
641 hr = IDirect3D9_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_NULLREF, hwnd,
642 D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
643 ok(SUCCEEDED(hr), "Failed to create IDirect3D9Device (%s)\n", DXGetErrorString9(hr));
644 if (FAILED(hr)) goto cleanup;
646 IDirect3DDevice9_CreateOffscreenPlainSurface(pDevice, 32, 32, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &cursor, 0);
647 ok(cursor != NULL, "IDirect3DDevice9_CreateOffscreenPlainSurface failed with %08x\n", hr);
649 /* Initially hidden */
650 hr = IDirect3DDevice9_ShowCursor(pDevice, TRUE);
651 ok(hr == FALSE, "IDirect3DDevice9_ShowCursor returned %08x\n", hr);
653 /* Not enabled without a surface*/
654 hr = IDirect3DDevice9_ShowCursor(pDevice, TRUE);
655 ok(hr == FALSE, "IDirect3DDevice9_ShowCursor returned %08x\n", hr);
658 hr = IDirect3DDevice9_SetCursorProperties(pDevice, 0, 0, NULL);
659 ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_SetCursorProperties returned %08x\n", hr);
661 hr = IDirect3DDevice9_SetCursorProperties(pDevice, 0, 0, cursor);
662 ok(hr == D3D_OK, "IDirect3DDevice9_SetCursorProperties returned %08x\n", hr);
664 IDirect3DSurface9_Release(cursor);
666 memset(&info, 0, sizeof(info));
667 info.cbSize = sizeof(info);
668 hr = GetCursorInfo(&info);
669 ok(hr != 0, "GetCursorInfo returned %08x\n", hr);
670 ok(info.flags & CURSOR_SHOWING, "The gdi cursor is hidden (%08x)\n", info.flags);
671 ok(info.hCursor == cur, "The cursor handle is %p\n", info.hCursor); /* unchanged */
674 hr = IDirect3DDevice9_ShowCursor(pDevice, TRUE);
675 ok(hr == FALSE, "IDirect3DDevice9_ShowCursor returned %08x\n", hr);
678 hr = IDirect3DDevice9_ShowCursor(pDevice, TRUE);
679 ok(hr == TRUE, "IDirect3DDevice9_ShowCursor returned %08x\n", hr);
681 /* GDI cursor unchanged */
682 memset(&info, 0, sizeof(info));
683 info.cbSize = sizeof(info);
684 hr = GetCursorInfo(&info);
685 ok(hr != 0, "GetCursorInfo returned %08x\n", hr);
686 ok(info.flags & CURSOR_SHOWING, "The gdi cursor is hidden (%08x)\n", info.flags);
687 ok(info.hCursor == cur, "The cursor handle is %p\n", info.hCursor); /* unchanged */
690 if(pDevice) IDirect3D9_Release(pDevice);
691 if(pD3d) IDirect3D9_Release(pD3d);
692 DestroyWindow( hwnd );
695 static void test_reset(void)
699 IDirect3D9 *pD3d = NULL;
700 IDirect3DDevice9 *pDevice = NULL;
701 D3DPRESENT_PARAMETERS d3dpp;
702 D3DDISPLAYMODE d3ddm;
704 DWORD width, orig_width = GetSystemMetrics(SM_CXSCREEN);
705 DWORD height, orig_height = GetSystemMetrics(SM_CYSCREEN);
706 IDirect3DSwapChain9 *pSwapchain;
708 pD3d = pDirect3DCreate9( D3D_SDK_VERSION );
709 ok(pD3d != NULL, "Failed to create IDirect3D9 object\n");
710 hwnd = CreateWindow( "static", "d3d9_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
711 ok(hwnd != NULL, "Failed to create window\n");
712 if (!pD3d || !hwnd) goto cleanup;
714 IDirect3D9_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
715 ZeroMemory( &d3dpp, sizeof(d3dpp) );
716 d3dpp.Windowed = FALSE;
717 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
718 d3dpp.BackBufferWidth = 800;
719 d3dpp.BackBufferHeight = 600;
720 d3dpp.BackBufferFormat = d3ddm.Format;
722 hr = IDirect3D9_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL /* no NULLREF here */, hwnd,
723 D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
724 ok(SUCCEEDED(hr), "Failed to create IDirect3D9Device (%s)\n", DXGetErrorString9(hr));
725 if (FAILED(hr)) goto cleanup;
727 width = GetSystemMetrics(SM_CXSCREEN);
728 height = GetSystemMetrics(SM_CYSCREEN);
729 ok(width == 800, "Screen width is %d\n", width);
730 ok(height == 600, "Screen height is %d\n", height);
732 hr = IDirect3DDevice9_GetViewport(pDevice, &vp);
733 ok(hr == D3D_OK, "IDirect3DDevice9_GetViewport failed with %s\n", DXGetErrorString9(hr));
736 ok(vp.X == 0, "D3DVIEWPORT->X = %d\n", vp.X);
737 ok(vp.Y == 0, "D3DVIEWPORT->X = %d\n", vp.Y);
738 ok(vp.Width == 800, "D3DVIEWPORT->X = %d\n", vp.Width);
739 ok(vp.Height == 600, "D3DVIEWPORT->X = %d\n", vp.Height);
740 ok(vp.MinZ == 0, "D3DVIEWPORT->X = %d\n", vp.Height);
741 ok(vp.MaxZ == 1, "D3DVIEWPORT->X = %d\n", vp.Height);
747 hr = IDirect3DDevice9_SetViewport(pDevice, &vp);
748 ok(hr == D3D_OK, "IDirect3DDevice9_SetViewport failed with %s\n", DXGetErrorString9(hr));
750 ZeroMemory( &d3dpp, sizeof(d3dpp) );
751 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
752 d3dpp.Windowed = FALSE;
753 d3dpp.BackBufferWidth = 640;
754 d3dpp.BackBufferHeight = 480;
755 d3dpp.BackBufferFormat = d3ddm.Format;
756 hr = IDirect3DDevice9_Reset(pDevice, &d3dpp);
757 ok(hr == D3D_OK, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr));
759 ZeroMemory(&vp, sizeof(vp));
760 hr = IDirect3DDevice9_GetViewport(pDevice, &vp);
761 ok(hr == D3D_OK, "IDirect3DDevice9_GetViewport failed with %s\n", DXGetErrorString9(hr));
764 ok(vp.X == 0, "D3DVIEWPORT->X = %d\n", vp.X);
765 ok(vp.Y == 0, "D3DVIEWPORT->X = %d\n", vp.Y);
766 ok(vp.Width == 640, "D3DVIEWPORT->X = %d\n", vp.Width);
767 ok(vp.Height == 480, "D3DVIEWPORT->X = %d\n", vp.Height);
768 ok(vp.MinZ == 0, "D3DVIEWPORT->X = %d\n", vp.Height);
769 ok(vp.MaxZ == 1, "D3DVIEWPORT->X = %d\n", vp.Height);
772 width = GetSystemMetrics(SM_CXSCREEN);
773 height = GetSystemMetrics(SM_CYSCREEN);
774 ok(width == 640, "Screen width is %d\n", width);
775 ok(height == 480, "Screen height is %d\n", height);
777 hr = IDirect3DDevice9_GetSwapChain(pDevice, 0, &pSwapchain);
778 ok(hr == D3D_OK, "IDirect3DDevice9_GetSwapChain returned %s\n", DXGetErrorString9(hr));
781 ZeroMemory(&d3dpp, sizeof(d3dpp));
782 hr = IDirect3DSwapChain9_GetPresentParameters(pSwapchain, &d3dpp);
783 ok(hr == D3D_OK, "IDirect3DSwapChain9_GetPresentParameters returned %s\n", DXGetErrorString9(hr));
786 ok(d3dpp.BackBufferWidth == 640, "Back buffer width is %d\n", d3dpp.BackBufferWidth);
787 ok(d3dpp.BackBufferHeight == 480, "Back buffer height is %d\n", d3dpp.BackBufferHeight);
789 IDirect3DSwapChain9_Release(pSwapchain);
792 ZeroMemory( &d3dpp, sizeof(d3dpp) );
793 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
794 d3dpp.Windowed = TRUE;
795 d3dpp.BackBufferWidth = 400;
796 d3dpp.BackBufferHeight = 300;
797 hr = IDirect3DDevice9_Reset(pDevice, &d3dpp);
798 ok(hr == D3D_OK, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr));
800 width = GetSystemMetrics(SM_CXSCREEN);
801 height = GetSystemMetrics(SM_CYSCREEN);
802 ok(width == orig_width, "Screen width is %d\n", width);
803 ok(height == orig_height, "Screen height is %d\n", height);
805 ZeroMemory(&vp, sizeof(vp));
806 hr = IDirect3DDevice9_GetViewport(pDevice, &vp);
807 ok(hr == D3D_OK, "IDirect3DDevice9_GetViewport failed with %s\n", DXGetErrorString9(hr));
810 ok(vp.X == 0, "D3DVIEWPORT->X = %d\n", vp.X);
811 ok(vp.Y == 0, "D3DVIEWPORT->X = %d\n", vp.Y);
812 ok(vp.Width == 400, "D3DVIEWPORT->X = %d\n", vp.Width);
813 ok(vp.Height == 300, "D3DVIEWPORT->X = %d\n", vp.Height);
814 ok(vp.MinZ == 0, "D3DVIEWPORT->X = %d\n", vp.Height);
815 ok(vp.MaxZ == 1, "D3DVIEWPORT->X = %d\n", vp.Height);
818 hr = IDirect3DDevice9_GetSwapChain(pDevice, 0, &pSwapchain);
819 ok(hr == D3D_OK, "IDirect3DDevice9_GetSwapChain returned %s\n", DXGetErrorString9(hr));
822 ZeroMemory(&d3dpp, sizeof(d3dpp));
823 hr = IDirect3DSwapChain9_GetPresentParameters(pSwapchain, &d3dpp);
824 ok(hr == D3D_OK, "IDirect3DSwapChain9_GetPresentParameters returned %s\n", DXGetErrorString9(hr));
827 ok(d3dpp.BackBufferWidth == 400, "Back buffer width is %d\n", d3dpp.BackBufferWidth);
828 ok(d3dpp.BackBufferHeight == 300, "Back buffer height is %d\n", d3dpp.BackBufferHeight);
830 IDirect3DSwapChain9_Release(pSwapchain);
834 if(pD3d) IDirect3D9_Release(pD3d);
835 if(pDevice) IDirect3D9_Release(pDevice);
840 HMODULE d3d9_handle = LoadLibraryA( "d3d9.dll" );
842 pDirect3DCreate9 = (void *)GetProcAddress( d3d9_handle, "Direct3DCreate9" );
843 if (pDirect3DCreate9)
847 test_mipmap_levels();