d3d8: Add refcount tests for implicit surfaces.
[wine] / dlls / d3d8 / tests / device.c
1 /*
2  * Copyright (C) 2006 Vitaliy Margolen
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #define COBJMACROS
20 #include <d3d8.h>
21 #include <dxerr8.h>
22 #include "wine/test.h"
23
24 static IDirect3D8 *(WINAPI *pDirect3DCreate8)(UINT);
25
26 static int get_refcount(IUnknown *object)
27 {
28     IUnknown_AddRef( object );
29     return IUnknown_Release( object );
30 }
31
32 #define CHECK_CALL(r,c,d,rc) \
33     if (SUCCEEDED(r)) {\
34         int tmp1 = get_refcount( (IUnknown *)d ); \
35         int rc_new = rc; \
36         ok(tmp1 == rc_new, "Invalid refcount. Expected %d got %d\n", rc_new, tmp1); \
37     } else {\
38         trace("%s failed: %s\n", c, DXGetErrorString8(r)); \
39     }
40 #define CHECK_RELEASE(obj,d,rc) \
41     if (obj) { \
42         int tmp1, rc_new = rc; \
43         IUnknown_Release( obj ); \
44         tmp1 = get_refcount( (IUnknown *)d ); \
45         ok(tmp1 == rc_new, "Invalid refcount. Expected %d got %d\n", rc_new, tmp1); \
46     }
47 #define CHECK_REFCOUNT(obj,rc) \
48     { \
49         int rc_new = rc; \
50         int count = get_refcount( (IUnknown *)obj ); \
51         ok(count == rc_new, "Invalid refcount. Expected %d got %d\n", rc_new, count); \
52     }
53
54 #define CHECK_RELEASE_REFCOUNT(obj,rc) \
55     { \
56         int rc_new = rc; \
57         int count = IUnknown_Release( (IUnknown *)obj ); \
58         ok(count == rc_new, "Invalid refcount. Expected %d got %d\n", rc_new, count); \
59     }
60
61 static void check_mipmap_levels(
62     IDirect3DDevice8* device, 
63     int width, int height, int count) 
64 {
65
66     IDirect3DBaseTexture8* texture = NULL;
67     HRESULT hr = IDirect3DDevice8_CreateTexture( device, width, height, 0, 0, 
68         D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, (IDirect3DTexture8**) &texture );
69        
70     if (SUCCEEDED(hr)) {
71         DWORD levels = IDirect3DBaseTexture8_GetLevelCount(texture);
72         ok(levels == count, "Invalid level count. Expected %d got %u\n", count, levels);
73     } else 
74         trace("CreateTexture failed: %s\n", DXGetErrorString8(hr));
75
76     if (texture) IUnknown_Release( texture );
77 }
78
79 static void test_mipmap_levels(void)
80 {
81
82     HRESULT               hr;
83     HWND                  hwnd = NULL;
84
85     IDirect3D8            *pD3d = NULL;
86     IDirect3DDevice8      *pDevice = NULL;
87     D3DPRESENT_PARAMETERS d3dpp;
88     D3DDISPLAYMODE        d3ddm;
89  
90     pD3d = pDirect3DCreate8( D3D_SDK_VERSION );
91     ok(pD3d != NULL, "Failed to create IDirect3D8 object\n");
92     hwnd = CreateWindow( "static", "d3d8_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
93     ok(hwnd != NULL, "Failed to create window\n");
94     if (!pD3d || !hwnd) goto cleanup;
95
96     IDirect3D8_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
97     ZeroMemory( &d3dpp, sizeof(d3dpp) );
98     d3dpp.Windowed         = TRUE;
99     d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
100     d3dpp.BackBufferFormat = d3ddm.Format;
101
102     hr = IDirect3D8_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
103                                   D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
104     ok(SUCCEEDED(hr), "Failed to create IDirect3D8Device (%s)\n", DXGetErrorString8(hr));
105     if (FAILED(hr)) goto cleanup;
106
107     check_mipmap_levels(pDevice, 32, 32, 6);
108     check_mipmap_levels(pDevice, 256, 1, 9);
109     check_mipmap_levels(pDevice, 1, 256, 9);
110     check_mipmap_levels(pDevice, 1, 1, 1);
111
112     cleanup:
113     if (pD3d)     IUnknown_Release( pD3d );
114     if (pDevice)  IUnknown_Release( pDevice );
115     DestroyWindow( hwnd );
116 }
117
118 static void test_swapchain(void)
119 {
120     HRESULT                      hr;
121     HWND                         hwnd               = NULL;
122     IDirect3D8                  *pD3d               = NULL;
123     IDirect3DDevice8            *pDevice            = NULL;
124     IDirect3DSwapChain8         *swapchain1         = NULL;
125     IDirect3DSwapChain8         *swapchain2         = NULL;
126     IDirect3DSwapChain8         *swapchain3         = NULL;
127     IDirect3DSurface8           *backbuffer         = NULL;
128     D3DPRESENT_PARAMETERS        d3dpp;
129     D3DDISPLAYMODE               d3ddm;
130
131     pD3d = pDirect3DCreate8( D3D_SDK_VERSION );
132     ok(pD3d != NULL, "Failed to create IDirect3D8 object\n");
133     hwnd = CreateWindow( "static", "d3d8_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
134     ok(hwnd != NULL, "Failed to create window\n");
135     if (!pD3d || !hwnd) goto cleanup;
136
137     IDirect3D8_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
138     ZeroMemory( &d3dpp, sizeof(d3dpp) );
139     d3dpp.Windowed         = TRUE;
140     d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
141     d3dpp.BackBufferFormat = d3ddm.Format;
142     d3dpp.BackBufferCount  = 0;
143
144     hr = IDirect3D8_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
145                                   D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
146     ok(SUCCEEDED(hr), "Failed to create IDirect3D8Device (%s)\n", DXGetErrorString8(hr));
147     if (FAILED(hr)) goto cleanup;
148
149     /* Check if the back buffer count was modified */
150     ok(d3dpp.BackBufferCount == 1, "The back buffer count in the presentparams struct is %d\n", d3dpp.BackBufferCount);
151
152     /* Create a bunch of swapchains */
153     d3dpp.BackBufferCount = 0;
154     hr = IDirect3DDevice8_CreateAdditionalSwapChain(pDevice, &d3dpp, &swapchain1);
155     ok(SUCCEEDED(hr), "Failed to create a swapchain (%s)\n", DXGetErrorString8(hr));
156     ok(d3dpp.BackBufferCount == 1, "The back buffer count in the presentparams struct is %d\n", d3dpp.BackBufferCount);
157
158     d3dpp.BackBufferCount  = 1;
159     hr = IDirect3DDevice8_CreateAdditionalSwapChain(pDevice, &d3dpp, &swapchain2);
160     ok(SUCCEEDED(hr), "Failed to create a swapchain (%s)\n", DXGetErrorString8(hr));
161
162     d3dpp.BackBufferCount  = 2;
163     hr = IDirect3DDevice8_CreateAdditionalSwapChain(pDevice, &d3dpp, &swapchain3);
164     ok(SUCCEEDED(hr), "Failed to create a swapchain (%s)\n", DXGetErrorString8(hr));
165     if(SUCCEEDED(hr)) {
166         /* Swapchain 3, created with backbuffercount 2 */
167         backbuffer = (void *) 0xdeadbeef;
168         hr = IDirect3DSwapChain8_GetBackBuffer(swapchain3, 0, 0, &backbuffer);
169         ok(SUCCEEDED(hr), "Failed to get the 1st back buffer (%s)\n", DXGetErrorString8(hr));
170         ok(backbuffer != NULL && backbuffer != (void *) 0xdeadbeef, "The back buffer is %p\n", backbuffer);
171         if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface8_Release(backbuffer);
172
173         backbuffer = (void *) 0xdeadbeef;
174         hr = IDirect3DSwapChain8_GetBackBuffer(swapchain3, 1, 0, &backbuffer);
175         ok(SUCCEEDED(hr), "Failed to get the 2nd back buffer (%s)\n", DXGetErrorString8(hr));
176         ok(backbuffer != NULL && backbuffer != (void *) 0xdeadbeef, "The back buffer is %p\n", backbuffer);
177         if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface8_Release(backbuffer);
178
179         backbuffer = (void *) 0xdeadbeef;
180         hr = IDirect3DSwapChain8_GetBackBuffer(swapchain3, 2, 0, &backbuffer);
181         ok(hr == D3DERR_INVALIDCALL, "GetBackBuffer returned %s\n", DXGetErrorString8(hr));
182         ok(backbuffer == (void *) 0xdeadbeef, "The back buffer pointer was modified (%p)\n", backbuffer);
183         if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface8_Release(backbuffer);
184
185         backbuffer = (void *) 0xdeadbeef;
186         hr = IDirect3DSwapChain8_GetBackBuffer(swapchain3, 3, 0, &backbuffer);
187         ok(FAILED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString8(hr));
188         ok(backbuffer == (void *) 0xdeadbeef, "The back buffer pointer was modified (%p)\n", backbuffer);
189         if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface8_Release(backbuffer);
190     }
191
192     /* Check the back buffers of the swapchains */
193     /* Swapchain 1, created with backbuffercount 0 */
194     hr = IDirect3DSwapChain8_GetBackBuffer(swapchain1, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
195     ok(SUCCEEDED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString8(hr));
196     ok(backbuffer != NULL, "The back buffer is NULL (%s)\n", DXGetErrorString8(hr));
197     if(backbuffer) IDirect3DSurface8_Release(backbuffer);
198
199     backbuffer = (void *) 0xdeadbeef;
200     hr = IDirect3DSwapChain8_GetBackBuffer(swapchain1, 1, 0, &backbuffer);
201     ok(FAILED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString8(hr));
202     ok(backbuffer == (void *) 0xdeadbeef, "The back buffer pointer was modified (%p)\n", backbuffer);
203     if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface8_Release(backbuffer);
204
205     /* Swapchain 2 - created with backbuffercount 1 */
206     backbuffer = (void *) 0xdeadbeef;
207     hr = IDirect3DSwapChain8_GetBackBuffer(swapchain2, 0, 0, &backbuffer);
208     ok(SUCCEEDED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString8(hr));
209     ok(backbuffer != NULL && backbuffer != (void *) 0xdeadbeef, "The back buffer is %p\n", backbuffer);
210     if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface8_Release(backbuffer);
211
212     backbuffer = (void *) 0xdeadbeef;
213     hr = IDirect3DSwapChain8_GetBackBuffer(swapchain2, 1, 0, &backbuffer);
214     ok(hr == D3DERR_INVALIDCALL, "GetBackBuffer returned %s\n", DXGetErrorString8(hr));
215     ok(backbuffer == (void *) 0xdeadbeef, "The back buffer pointer was modified (%p)\n", backbuffer);
216     if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface8_Release(backbuffer);
217
218     backbuffer = (void *) 0xdeadbeef;
219     hr = IDirect3DSwapChain8_GetBackBuffer(swapchain2, 2, 0, &backbuffer);
220     ok(FAILED(hr), "Failed to get the back buffer (%s)\n", DXGetErrorString8(hr));
221     ok(backbuffer == (void *) 0xdeadbeef, "The back buffer pointer was modified (%p)\n", backbuffer);
222     if(backbuffer && backbuffer != (void *) 0xdeadbeef) IDirect3DSurface8_Release(backbuffer);
223
224     cleanup:
225     if(swapchain1) IDirect3DSwapChain8_Release(swapchain1);
226     if(swapchain2) IDirect3DSwapChain8_Release(swapchain2);
227     if(swapchain3) IDirect3DSwapChain8_Release(swapchain3);
228     if(pDevice) IDirect3DDevice8_Release(pDevice);
229     if(pD3d) IDirect3DDevice8_Release(pD3d);
230     DestroyWindow( hwnd );
231 }
232
233 static void test_refcount(void)
234 {
235     HRESULT                      hr;
236     HWND                         hwnd               = NULL;
237     IDirect3D8                  *pD3d               = NULL;
238     IDirect3DDevice8            *pDevice            = NULL;
239     IDirect3DVertexBuffer8      *pVertexBuffer      = NULL;
240     IDirect3DIndexBuffer8       *pIndexBuffer       = NULL;
241     DWORD                       dVertexShader       = -1;
242     DWORD                       dPixelShader        = -1;
243     IDirect3DCubeTexture8       *pCubeTexture       = NULL;
244     IDirect3DTexture8           *pTexture           = NULL;
245     IDirect3DVolumeTexture8     *pVolumeTexture     = NULL;
246     IDirect3DSurface8           *pStencilSurface    = NULL;
247     IDirect3DSurface8           *pImageSurface      = NULL;
248     IDirect3DSurface8           *pRenderTarget      = NULL;
249     IDirect3DSurface8           *pTextureLevel      = NULL;
250     IDirect3DSurface8           *pBackBuffer        = NULL;
251     DWORD                       dStateBlock         = -1;
252     IDirect3DSwapChain8         *pSwapChain         = NULL;
253
254     D3DPRESENT_PARAMETERS        d3dpp;
255     D3DDISPLAYMODE               d3ddm;
256     int                          refcount = 0, tmp;
257
258     DWORD decl[] =
259     {
260         D3DVSD_STREAM(0),
261         D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),  /* D3DVSDE_POSITION, Register v0 */
262         D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR), /* D3DVSDE_DIFFUSE, Register v5 */
263         D3DVSD_END()
264     };
265     static DWORD simple_vs[] = {0xFFFE0101,             /* vs_1_1               */
266         0x00000009, 0xC0010000, 0x90E40000, 0xA0E40000, /* dp4 oPos.x, v0, c0   */
267         0x00000009, 0xC0020000, 0x90E40000, 0xA0E40001, /* dp4 oPos.y, v0, c1   */
268         0x00000009, 0xC0040000, 0x90E40000, 0xA0E40002, /* dp4 oPos.z, v0, c2   */
269         0x00000009, 0xC0080000, 0x90E40000, 0xA0E40003, /* dp4 oPos.w, v0, c3   */
270         0x0000FFFF};                                    /* END                  */
271     static DWORD simple_ps[] = {0xFFFF0101,                                     /* ps_1_1                       */
272         0x00000051, 0xA00F0001, 0x3F800000, 0x00000000, 0x00000000, 0x00000000, /* def c1 = 1.0, 0.0, 0.0, 0.0  */
273         0x00000042, 0xB00F0000,                                                 /* tex t0                       */
274         0x00000008, 0x800F0000, 0xA0E40001, 0xA0E40000,                         /* dp3 r0, c1, c0               */
275         0x00000005, 0x800F0000, 0x90E40000, 0x80E40000,                         /* mul r0, v0, r0               */
276         0x00000005, 0x800F0000, 0xB0E40000, 0x80E40000,                         /* mul r0, t0, r0               */
277         0x0000FFFF};                                                            /* END                          */
278
279
280     pD3d = pDirect3DCreate8( D3D_SDK_VERSION );
281     ok(pD3d != NULL, "Failed to create IDirect3D8 object\n");
282     hwnd = CreateWindow( "static", "d3d8_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
283     ok(hwnd != NULL, "Failed to create window\n");
284     if (!pD3d || !hwnd) goto cleanup;
285
286     IDirect3D8_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
287     ZeroMemory( &d3dpp, sizeof(d3dpp) );
288     d3dpp.Windowed         = TRUE;
289     d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
290     d3dpp.BackBufferFormat = d3ddm.Format;
291     d3dpp.EnableAutoDepthStencil = TRUE;
292     d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
293
294     hr = IDirect3D8_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
295                                   D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
296     ok(SUCCEEDED(hr), "Failed to create IDirect3D8Device (%s)\n", DXGetErrorString8(hr));
297     if (FAILED(hr)) goto cleanup;
298
299     refcount = get_refcount( (IUnknown *)pDevice );
300     ok(refcount == 1, "Invalid device RefCount %d\n", refcount);
301
302     /**
303      * Check refcount of implicit surfaces. Findings:
304      *   - they hold a refernce to the device
305      *   - they are created with a refcount of 0 (Get/Release returns orignial refcount)
306      */
307     hr = IDirect3DDevice8_GetRenderTarget(pDevice, &pRenderTarget);
308     todo_wine CHECK_CALL( hr, "GetRenderTarget", pDevice, ++refcount);
309     if(pRenderTarget)
310     {
311         todo_wine CHECK_REFCOUNT( pRenderTarget, 1);
312         hr = IDirect3DDevice8_GetRenderTarget(pDevice, &pRenderTarget);
313         todo_wine CHECK_CALL( hr, "GetRenderTarget", pDevice, refcount);
314         todo_wine CHECK_REFCOUNT( pRenderTarget, 2);
315         todo_wine CHECK_RELEASE_REFCOUNT( pRenderTarget, 1);
316         todo_wine CHECK_RELEASE_REFCOUNT( pRenderTarget, 0);
317         pRenderTarget = NULL;
318     }
319     CHECK_REFCOUNT( pDevice, --refcount);
320
321     hr = IDirect3DDevice8_GetDepthStencilSurface(pDevice, &pStencilSurface);
322     todo_wine CHECK_CALL( hr, "GetDepthStencilSurface", pDevice, ++refcount);
323     if(pStencilSurface)
324     {
325         todo_wine CHECK_REFCOUNT( pStencilSurface, 1);
326         todo_wine CHECK_RELEASE_REFCOUNT( pStencilSurface, 0);
327         pStencilSurface = NULL;
328     }
329     CHECK_REFCOUNT( pDevice, --refcount);
330
331     hr = IDirect3DDevice8_GetBackBuffer(pDevice, 0, 0, &pBackBuffer);
332     todo_wine CHECK_CALL( hr, "GetBackBuffer", pDevice, ++refcount);
333     if(pBackBuffer)
334     {
335         todo_wine CHECK_REFCOUNT( pBackBuffer, 1);
336         todo_wine CHECK_RELEASE_REFCOUNT( pBackBuffer, 0);
337         pBackBuffer = NULL;
338     }
339     CHECK_REFCOUNT( pDevice, --refcount);
340
341     /* Buffers */
342     hr = IDirect3DDevice8_CreateIndexBuffer( pDevice, 16, 0, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &pIndexBuffer );
343     CHECK_CALL( hr, "CreateIndexBuffer", pDevice, ++refcount );
344     if(pIndexBuffer)
345     {
346         tmp = get_refcount( (IUnknown *)pIndexBuffer );
347
348         hr = IDirect3DDevice8_SetIndices(pDevice, pIndexBuffer, 0);
349         CHECK_CALL( hr, "SetIndices", pIndexBuffer, tmp);
350         hr = IDirect3DDevice8_SetIndices(pDevice, NULL, 0);
351         CHECK_CALL( hr, "SetIndices", pIndexBuffer, tmp);
352     }
353
354     hr = IDirect3DDevice8_CreateVertexBuffer( pDevice, 16, 0, D3DFVF_XYZ, D3DPOOL_DEFAULT, &pVertexBuffer );
355     CHECK_CALL( hr, "CreateVertexBuffer", pDevice, ++refcount );
356     if(pVertexBuffer)
357     {
358         tmp = get_refcount( (IUnknown *)pVertexBuffer );
359
360         hr = IDirect3DDevice8_SetStreamSource(pDevice, 0, pVertexBuffer, 3 * sizeof(float));
361         CHECK_CALL( hr, "SetStreamSource", pVertexBuffer, tmp);
362         hr = IDirect3DDevice8_SetStreamSource(pDevice, 0, NULL, 0);
363         CHECK_CALL( hr, "SetStreamSource", pVertexBuffer, tmp);
364     }
365     /* Shaders */
366     hr = IDirect3DDevice8_CreateVertexShader( pDevice, decl, simple_vs, &dVertexShader, 0 );
367     CHECK_CALL( hr, "CreateVertexShader", pDevice, refcount );
368     hr = IDirect3DDevice8_CreatePixelShader( pDevice, simple_ps, &dPixelShader );
369     CHECK_CALL( hr, "CreatePixelShader", pDevice, refcount );
370     /* Textures */
371     hr = IDirect3DDevice8_CreateTexture( pDevice, 32, 32, 3, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pTexture );
372     CHECK_CALL( hr, "CreateTexture", pDevice, ++refcount );
373     if (pTexture)
374     {
375         tmp = get_refcount( (IUnknown *)pTexture );
376
377         /* SetTexture should not increase refcounts */
378         hr = IDirect3DDevice8_SetTexture(pDevice, 0, (IDirect3DBaseTexture8 *) pTexture);
379         CHECK_CALL( hr, "SetTexture", pTexture, tmp);
380         hr = IDirect3DDevice8_SetTexture(pDevice, 0, NULL);
381         CHECK_CALL( hr, "SetTexture", pTexture, tmp);
382
383         /* This should not increment device refcount */
384         hr = IDirect3DTexture8_GetSurfaceLevel( pTexture, 1, &pTextureLevel );
385         CHECK_CALL( hr, "GetSurfaceLevel", pDevice, refcount );
386         /* But should increment texture's refcount */
387         CHECK_CALL( hr, "GetSurfaceLevel", pTexture, tmp+1 );
388     }
389     hr = IDirect3DDevice8_CreateCubeTexture( pDevice, 32, 0, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pCubeTexture );
390     CHECK_CALL( hr, "CreateCubeTexture", pDevice, ++refcount );
391     hr = IDirect3DDevice8_CreateVolumeTexture( pDevice, 32, 32, 2, 0, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pVolumeTexture );
392     CHECK_CALL( hr, "CreateVolumeTexture", pDevice, ++refcount );
393     /* Surfaces */
394     hr = IDirect3DDevice8_CreateDepthStencilSurface( pDevice, 32, 32, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, &pStencilSurface );
395     CHECK_CALL( hr, "CreateDepthStencilSurface", pDevice, ++refcount );
396     hr = IDirect3DDevice8_CreateImageSurface( pDevice, 32, 32, D3DFMT_X8R8G8B8, &pImageSurface );
397     CHECK_CALL( hr, "CreateImageSurface", pDevice, ++refcount );
398     hr = IDirect3DDevice8_CreateRenderTarget( pDevice, 32, 32, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, TRUE, &pRenderTarget );
399     CHECK_CALL( hr, "CreateRenderTarget", pDevice, ++refcount );
400     /* Misc */
401     hr = IDirect3DDevice8_CreateStateBlock( pDevice, D3DSBT_ALL, &dStateBlock );
402     CHECK_CALL( hr, "CreateStateBlock", pDevice, refcount );
403     hr = IDirect3DDevice8_CreateAdditionalSwapChain( pDevice, &d3dpp, &pSwapChain );
404     CHECK_CALL( hr, "CreateAdditionalSwapChain", pDevice, ++refcount );
405     if(pSwapChain)
406     {
407         /* check implicit back buffer */
408         hr = IDirect3DSwapChain8_GetBackBuffer(pSwapChain, 0, 0, &pBackBuffer);
409         todo_wine CHECK_CALL( hr, "GetBackBuffer", pDevice, ++refcount);
410         todo_wine CHECK_REFCOUNT( pSwapChain, 1);
411         if(pBackBuffer)
412         {
413             todo_wine CHECK_REFCOUNT( pBackBuffer, 1);
414             todo_wine CHECK_RELEASE_REFCOUNT( pBackBuffer, 0);
415             pBackBuffer = NULL;
416         }
417         CHECK_REFCOUNT( pSwapChain, 1);
418         CHECK_REFCOUNT( pDevice, --refcount);
419     }
420
421     if(pVertexBuffer)
422     {
423         BYTE *data;
424         /* Vertex buffers can be locked multiple times */
425         hr = IDirect3DVertexBuffer8_Lock(pVertexBuffer, 0, 0, &data, 0);
426         ok(hr == D3D_OK, "IDirect3DVertexBuffer8::Lock failed with %08x\n", hr);
427         hr = IDirect3DVertexBuffer8_Lock(pVertexBuffer, 0, 0, &data, 0);
428         ok(hr == D3D_OK, "IDirect3DVertexBuffer8::Lock failed with %08x\n", hr);
429         hr = IDirect3DVertexBuffer8_Unlock(pVertexBuffer);
430         ok(hr == D3D_OK, "IDirect3DVertexBuffer8::Unlock failed with %08x\n", hr);
431         hr = IDirect3DVertexBuffer8_Unlock(pVertexBuffer);
432         ok(hr == D3D_OK, "IDirect3DVertexBuffer8::Unlock failed with %08x\n", hr);
433     }
434
435 cleanup:
436     CHECK_RELEASE(pDevice,              pDevice, --refcount);
437
438     /* Buffers */
439     CHECK_RELEASE(pVertexBuffer,        pDevice, --refcount);
440     CHECK_RELEASE(pIndexBuffer,         pDevice, --refcount);
441     /* Shaders */
442     if (dVertexShader != -1)  IDirect3DDevice8_DeleteVertexShader( pDevice, dVertexShader );
443     if (dPixelShader != -1)   IDirect3DDevice8_DeletePixelShader( pDevice, dPixelShader );
444     /* Textures */
445     /* pTextureLevel is holding a reference to the pTexture */
446     CHECK_RELEASE(pTexture,             pDevice,   refcount);
447     CHECK_RELEASE(pTextureLevel,        pDevice, --refcount);
448     CHECK_RELEASE(pCubeTexture,         pDevice, --refcount);
449     CHECK_RELEASE(pVolumeTexture,       pDevice, --refcount);
450     /* Surfaces */
451     CHECK_RELEASE(pStencilSurface,      pDevice, --refcount);
452     CHECK_RELEASE(pImageSurface,        pDevice, --refcount);
453     CHECK_RELEASE(pRenderTarget,        pDevice, --refcount);
454     /* Misc */
455     if (dStateBlock != -1)    IDirect3DDevice8_DeleteStateBlock( pDevice, dStateBlock );
456     /* This will destroy device - cannot check the refcount here */
457     if (pSwapChain)           CHECK_RELEASE_REFCOUNT( pSwapChain, 0);
458
459     if (pD3d)                 CHECK_RELEASE_REFCOUNT( pD3d, 0);
460
461     DestroyWindow( hwnd );
462 }
463
464 static void test_cursor(void)
465 {
466     HRESULT                      hr;
467     HWND                         hwnd               = NULL;
468     IDirect3D8                  *pD3d               = NULL;
469     IDirect3DDevice8            *pDevice            = NULL;
470     D3DPRESENT_PARAMETERS        d3dpp;
471     D3DDISPLAYMODE               d3ddm;
472     CURSORINFO                   info;
473     IDirect3DSurface8 *cursor = NULL;
474     HCURSOR cur;
475
476     memset(&info, 0, sizeof(info));
477     info.cbSize = sizeof(info);
478     hr = GetCursorInfo(&info);
479     cur = info.hCursor;
480
481     pD3d = pDirect3DCreate8( D3D_SDK_VERSION );
482     ok(pD3d != NULL, "Failed to create IDirect3D8 object\n");
483     hwnd = CreateWindow( "static", "d3d8_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
484     ok(hwnd != NULL, "Failed to create window\n");
485     if (!pD3d || !hwnd) goto cleanup;
486
487     IDirect3D8_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
488     ZeroMemory( &d3dpp, sizeof(d3dpp) );
489     d3dpp.Windowed         = TRUE;
490     d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
491     d3dpp.BackBufferFormat = d3ddm.Format;
492
493     hr = IDirect3D8_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
494                                   D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
495     ok(SUCCEEDED(hr), "Failed to create IDirect3D8Device (%s)\n", DXGetErrorString8(hr));
496     if (FAILED(hr)) goto cleanup;
497
498     IDirect3DDevice8_CreateImageSurface(pDevice, 32, 32, D3DFMT_A8R8G8B8, &cursor);
499     ok(cursor != NULL, "IDirect3DDevice8_CreateOffscreenPlainSurface failed with %08x\n", hr);
500
501     /* Initially hidden */
502     hr = IDirect3DDevice8_ShowCursor(pDevice, TRUE);
503     ok(hr == FALSE, "IDirect3DDevice8_ShowCursor returned %08x\n", hr);
504
505     /* Not enabled without a surface*/
506     hr = IDirect3DDevice8_ShowCursor(pDevice, TRUE);
507     ok(hr == FALSE, "IDirect3DDevice8_ShowCursor returned %08x\n", hr);
508
509     /* Fails */
510     hr = IDirect3DDevice8_SetCursorProperties(pDevice, 0, 0, NULL);
511     ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice8_SetCursorProperties returned %08x\n", hr);
512
513     hr = IDirect3DDevice8_SetCursorProperties(pDevice, 0, 0, cursor);
514     ok(hr == D3D_OK, "IDirect3DDevice8_SetCursorProperties returned %08x\n", hr);
515
516     IDirect3DSurface8_Release(cursor);
517
518     memset(&info, 0, sizeof(info));
519     info.cbSize = sizeof(info);
520     hr = GetCursorInfo(&info);
521     ok(hr != 0, "GetCursorInfo returned %08x\n", hr);
522     ok(info.flags & CURSOR_SHOWING, "The gdi cursor is hidden (%08x)\n", info.flags);
523     ok(info.hCursor == cur, "The cursor handle is %p\n", info.hCursor); /* unchanged */
524
525     /* Still hidden */
526     hr = IDirect3DDevice8_ShowCursor(pDevice, TRUE);
527     ok(hr == FALSE, "IDirect3DDevice8_ShowCursor returned %08x\n", hr);
528
529     /* Enabled now*/
530     hr = IDirect3DDevice8_ShowCursor(pDevice, TRUE);
531     ok(hr == TRUE, "IDirect3DDevice8_ShowCursor returned %08x\n", hr);
532
533     /* GDI cursor unchanged */
534     memset(&info, 0, sizeof(info));
535     info.cbSize = sizeof(info);
536     hr = GetCursorInfo(&info);
537     ok(hr != 0, "GetCursorInfo returned %08x\n", hr);
538     ok(info.flags & CURSOR_SHOWING, "The gdi cursor is hidden (%08x)\n", info.flags);
539     ok(info.hCursor == cur, "The cursor handle is %p\n", info.hCursor); /* unchanged */
540
541 cleanup:
542     if(pD3d) IDirect3D8_Release(pD3d);
543     if(pDevice) IDirect3D8_Release(pDevice);
544 }
545
546 START_TEST(device)
547 {
548     HMODULE d3d8_handle = LoadLibraryA( "d3d8.dll" );
549
550     pDirect3DCreate8 = (void *)GetProcAddress( d3d8_handle, "Direct3DCreate8" );
551     if (pDirect3DCreate8)
552     {
553         test_swapchain();
554         test_refcount();
555         test_mipmap_levels();
556         test_cursor();
557     }
558 }