wined3d: Add an alpha blending test.
[wine] / dlls / d3d9 / tests / vertexdeclaration.c
1 /*
2  * Copyright (C) 2005 Henri Verbeet
3  * Copyright (C) 2006 Ivan Gyurdiev
4  *
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.
9  *
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.
14  *
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
18  */
19
20 #define COBJMACROS
21 #include <d3d9.h>
22 #include "wine/test.h"
23
24 static HMODULE d3d9_handle = 0;
25
26 #define VDECL_CHECK(fcall) \
27     if(fcall != S_OK) \
28         trace(" Test failed on line #%d\n", __LINE__);
29
30 static HWND create_window(void)
31 {
32     WNDCLASS wc = {0};
33     wc.lpfnWndProc = &DefWindowProc;
34     wc.lpszClassName = "d3d9_test_wc";
35     RegisterClass(&wc);
36
37     return CreateWindow("d3d9_test_wc", "d3d9_test",
38             0, 0, 0, 0, 0, 0, 0, 0, 0);
39 }
40
41 static IDirect3DDevice9 *init_d3d9(void)
42 {
43     IDirect3D9 * (__stdcall * d3d9_create)(UINT SDKVersion) = 0;
44     IDirect3D9 *d3d9_ptr = 0;
45     IDirect3DDevice9 *device_ptr = 0;
46     D3DPRESENT_PARAMETERS present_parameters;
47     HRESULT hres;
48
49     d3d9_create = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9");
50     ok(d3d9_create != NULL, "Failed to get address of Direct3DCreate9\n");
51     if (!d3d9_create) return NULL;
52     
53     d3d9_ptr = d3d9_create(D3D_SDK_VERSION);
54     ok(d3d9_ptr != NULL, "Failed to create IDirect3D9 object\n");
55     if (!d3d9_ptr) return NULL;
56
57     ZeroMemory(&present_parameters, sizeof(present_parameters));
58     present_parameters.Windowed = TRUE;
59     present_parameters.hDeviceWindow = create_window();
60     present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
61
62     hres = IDirect3D9_CreateDevice(d3d9_ptr, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device_ptr);
63
64     if(FAILED(hres))
65     {
66         trace("could not create device, IDirect3D9_CreateDevice returned %#x\n", hres);
67         return NULL;
68     }
69
70     return device_ptr;
71 }
72
73 static int get_refcount(IUnknown *object)
74 {
75     IUnknown_AddRef(object);
76     return IUnknown_Release(object);
77 }
78
79 static inline void print_elements(
80     D3DVERTEXELEMENT9 *elements) {
81
82     D3DVERTEXELEMENT9 last = D3DDECL_END();
83     D3DVERTEXELEMENT9 *ptr = elements;
84     int count = 0;
85
86     while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9))) {
87
88         trace(
89             "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
90              count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
91
92         ptr++;
93         count++;
94     }
95 }
96
97 static int compare_elements(
98     IDirect3DVertexDeclaration9 *decl,
99     const D3DVERTEXELEMENT9 *expected_elements) {
100
101     HRESULT hr;
102     unsigned int i, size;
103     D3DVERTEXELEMENT9 last = D3DDECL_END();
104     D3DVERTEXELEMENT9 *elements = NULL;
105
106     /* How many elements are there? */
107     hr = IDirect3DVertexDeclaration9_GetDeclaration( decl, NULL, &size );
108     ok(SUCCEEDED(hr), "GetDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
109     if (FAILED(hr)) goto fail;
110
111     /* Allocate buffer */
112     elements = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(D3DVERTEXELEMENT9) * size);
113     ok (elements != NULL, "Out of memory, aborting test\n");
114     if (elements == NULL) goto fail;
115
116     /* Get the elements */
117     hr = IDirect3DVertexDeclaration9_GetDeclaration( decl, elements, &size);
118     ok(SUCCEEDED(hr), "GetDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
119     if (FAILED(hr)) goto fail;
120
121     /* Compare one by one */
122     for (i = 0; i < size; i++) {
123
124         int status;
125
126         int end1 = memcmp(&elements[i], &last, sizeof(D3DVERTEXELEMENT9));
127         int end2 = memcmp(&expected_elements[i], &last, sizeof(D3DVERTEXELEMENT9));
128         status = ((end1 && !end2) || (!end1 && end2));
129         ok (!status, "Mismatch in size, test declaration is %s than expected\n",
130             (end1 && !end2) ? "shorter" : "longer");
131         if (status) { print_elements(elements); goto fail; }
132
133         status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
134         ok (!status, "Mismatch in element %d\n", i);
135         if (status) { print_elements(elements); goto fail; }
136     }
137
138     HeapFree(GetProcessHeap(), 0, elements);
139     return S_OK;
140
141     fail:
142     HeapFree(GetProcessHeap(), 0, elements);
143     return E_FAIL;
144 }
145
146 static IDirect3DVertexDeclaration9 *test_create_vertex_declaration(IDirect3DDevice9 *device_ptr, D3DVERTEXELEMENT9 *vertex_decl)
147 {
148     IDirect3DVertexDeclaration9 *decl_ptr = 0;
149     HRESULT hret = 0;
150
151     hret = IDirect3DDevice9_CreateVertexDeclaration(device_ptr, vertex_decl, &decl_ptr);
152     ok(hret == D3D_OK && decl_ptr != NULL, "CreateVertexDeclaration returned: hret 0x%x, decl_ptr %p. "
153         "Expected hret 0x%x, decl_ptr != %p. Aborting.\n", hret, decl_ptr, D3D_OK, NULL);
154
155     return decl_ptr;
156 }
157
158 static void test_get_set_vertex_declaration(IDirect3DDevice9 *device_ptr, IDirect3DVertexDeclaration9 *decl_ptr)
159 {
160     IDirect3DVertexDeclaration9 *current_decl_ptr = 0;
161     HRESULT hret = 0;
162     int decl_refcount = 0;
163     int i = 0;
164     
165     /* SetVertexDeclaration should not touch the declaration's refcount. */
166     i = get_refcount((IUnknown *)decl_ptr);
167     hret = IDirect3DDevice9_SetVertexDeclaration(device_ptr, decl_ptr);
168     decl_refcount = get_refcount((IUnknown *)decl_ptr);
169     ok(hret == D3D_OK && decl_refcount == i, "SetVertexDeclaration returned: hret 0x%x, refcount %d. "
170         "Expected hret 0x%x, refcount %d.\n", hret, decl_refcount, D3D_OK, i);
171     
172     /* GetVertexDeclaration should increase the declaration's refcount by one. */
173     i = decl_refcount+1;
174     hret = IDirect3DDevice9_GetVertexDeclaration(device_ptr, &current_decl_ptr);
175     decl_refcount = get_refcount((IUnknown *)decl_ptr);
176     ok(hret == D3D_OK && decl_refcount == i && current_decl_ptr == decl_ptr, 
177         "GetVertexDeclaration returned: hret 0x%x, current_decl_ptr %p refcount %d. "
178         "Expected hret 0x%x, current_decl_ptr %p, refcount %d.\n", hret, current_decl_ptr, decl_refcount, D3D_OK, decl_ptr, i);
179 }
180
181 static void test_get_declaration(IDirect3DVertexDeclaration9 *decl_ptr, D3DVERTEXELEMENT9 *vertex_decl, UINT expected_num_elements)
182 {
183     int i;
184     UINT num_elements = 0;
185     D3DVERTEXELEMENT9 *decl = 0;
186     HRESULT hret = 0;
187
188     /* First test only getting the number of elements */
189     num_elements = 0x1337c0de;
190     hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, NULL, &num_elements);
191     ok(hret == D3D_OK && num_elements == expected_num_elements,
192             "GetDeclaration returned: hret 0x%x, num_elements %d. "
193             "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
194
195     num_elements = 0;
196     hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, NULL, &num_elements);
197     ok(hret == D3D_OK && num_elements == expected_num_elements,
198             "GetDeclaration returned: hret 0x%x, num_elements %d. "
199             "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
200
201     /* Also test the returned data */
202     decl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(D3DVERTEXELEMENT9) * expected_num_elements);
203
204     num_elements = 0x1337c0de;
205     hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, decl, &num_elements);
206     ok(hret == D3D_OK && num_elements == expected_num_elements,
207             "GetDeclaration returned: hret 0x%x, num_elements %d. "
208             "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
209     i = memcmp(decl, vertex_decl, sizeof(vertex_decl));
210     ok (!i, "Original and returned vertexdeclarations are not the same\n");
211     ZeroMemory(decl, sizeof(D3DVERTEXELEMENT9) * expected_num_elements);
212
213     num_elements = 0;
214     hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, decl, &num_elements);
215     ok(hret == D3D_OK && num_elements == expected_num_elements,
216             "GetDeclaration returned: hret 0x%x, num_elements %d. "
217             "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
218     i = memcmp(decl, vertex_decl, sizeof(vertex_decl));
219     ok (!i, "Original and returned vertexdeclarations are not the same\n");
220
221     HeapFree(GetProcessHeap(), 0, decl);
222 }
223
224 /* FIXME: also write a test, which shows that attempting to set
225  * an invalid vertex declaration returns E_FAIL */
226
227 static HRESULT test_fvf_to_decl(
228     IDirect3DDevice9* device,
229     IDirect3DVertexDeclaration9* default_decl,
230     DWORD test_fvf,
231     const D3DVERTEXELEMENT9 expected_elements[],
232     char object_should_change) 
233 {
234
235     HRESULT hr;
236     IDirect3DVertexDeclaration9 *result_decl = NULL;
237
238     /* Set a default declaration to make sure it is changed */
239     hr = IDirect3DDevice9_SetVertexDeclaration ( device, default_decl );
240     ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
241     if (FAILED(hr)) goto fail;
242
243     /* Set an FVF */
244     hr = IDirect3DDevice9_SetFVF( device, test_fvf);
245     ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
246     if (FAILED(hr)) goto fail;
247
248     /* Check if the declaration object changed underneath */
249     hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl);
250     ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
251     if (FAILED(hr)) goto fail;
252     if (object_should_change) {
253        ok(result_decl != default_decl, "result declaration matches original\n");
254        if (result_decl == default_decl) goto fail;
255     } else {
256        ok(result_decl == default_decl, "result declaration does not match original\n");
257        if (result_decl != default_decl) goto fail;
258     }
259
260     /* Declaration content/size test */
261     ok(result_decl != NULL, "result declaration was null\n");
262     if (result_decl == NULL) 
263         goto fail;
264     else if (compare_elements(result_decl, expected_elements) != S_OK)
265         goto fail;
266
267     if (result_decl) IUnknown_Release( result_decl );
268     return S_OK;    
269
270     fail:
271     if (result_decl) IUnknown_Release( result_decl );
272     return E_FAIL;
273 }
274
275 static HRESULT test_decl_to_fvf(
276     IDirect3DDevice9* device,
277     DWORD default_fvf,
278     CONST D3DVERTEXELEMENT9 test_decl[],
279     DWORD test_fvf)
280 {
281
282     HRESULT hr;
283     IDirect3DVertexDeclaration9 *vdecl = NULL;
284
285     DWORD result_fvf = 0xdeadbeef;
286
287     /* Set a default FVF of SPECULAR and DIFFUSE to make sure it is changed back to 0 */
288     hr = IDirect3DDevice9_SetFVF( device, default_fvf);
289     ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
290     if (FAILED(hr)) goto fail;
291
292     /* Create a testing declaration */
293     hr = IDirect3DDevice9_CreateVertexDeclaration( device, test_decl, &vdecl );
294     ok(SUCCEEDED(hr), "CreateVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
295     if (FAILED(hr)) goto fail;
296
297     /* Set the declaration */
298     hr = IDirect3DDevice9_SetVertexDeclaration ( device, vdecl );
299     ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
300     if (FAILED(hr)) goto fail;
301
302     /* Check the FVF */
303     hr = IDirect3DDevice9_GetFVF( device, &result_fvf);
304     ok(SUCCEEDED(hr), "GetFVF returned %#x, expected %#x\n", hr, D3D_OK);
305     if (FAILED(hr)) goto fail;
306     todo_wine {
307        ok(test_fvf == result_fvf, "result FVF was: %#x, expected: %#x\n", result_fvf, test_fvf);
308     }
309     if (test_fvf != result_fvf) goto fail;
310
311     IDirect3DDevice9_SetVertexDeclaration ( device, NULL );
312     if (vdecl) IUnknown_Release( vdecl );
313     return S_OK;
314
315     fail:
316     IDirect3DDevice9_SetVertexDeclaration ( device, NULL );
317     if (vdecl) IUnknown_Release( vdecl );
318     return E_FAIL;
319 }
320
321 static void test_fvf_decl_conversion(IDirect3DDevice9 *pDevice)
322 {
323
324     HRESULT hr;
325     unsigned int i;
326
327     IDirect3DVertexDeclaration9* default_decl = NULL;
328     DWORD default_fvf = D3DFVF_SPECULAR | D3DFVF_DIFFUSE;
329     D3DVERTEXELEMENT9 default_elements[] =
330         { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 },
331           { 0, 4, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };
332
333     /* Create a default declaration and FVF that does not match any of the tests */
334     hr = IDirect3DDevice9_CreateVertexDeclaration( pDevice, default_elements, &default_decl );
335     ok(SUCCEEDED(hr), "CreateVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
336     if (FAILED(hr)) goto cleanup;
337
338     /* Test conversions from vertex declaration to an FVF.
339      * For some reason those seem to occur only for POSITION/POSITIONT,
340      * Otherwise the FVF is forced to 0 - maybe this is configuration specific */
341     {
342         CONST D3DVERTEXELEMENT9 test_buffer[] =
343             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() };
344         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, D3DFVF_XYZ));
345     }
346     {
347         CONST D3DVERTEXELEMENT9 test_buffer[] =
348             { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() };
349         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, D3DFVF_XYZRHW));
350     }
351     for (i = 0; i < 4; i++) {
352         CONST D3DVERTEXELEMENT9 test_buffer[] =
353             { { 0, 0, D3DDECLTYPE_FLOAT1+i, 0, D3DDECLUSAGE_BLENDWEIGHT, 0}, D3DDECL_END() };
354         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
355     }
356     {
357         CONST D3DVERTEXELEMENT9 test_buffer[] = 
358             { { 0, 0, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0}, D3DDECL_END() };
359         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
360     }
361     {
362         CONST D3DVERTEXELEMENT9 test_buffer[] =
363             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() };
364         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
365     }
366     {
367         CONST D3DVERTEXELEMENT9 test_buffer[] =
368             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, D3DDECL_END() };
369         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
370     }
371     {
372         CONST D3DVERTEXELEMENT9 test_buffer[] =
373             { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() };
374         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
375     }
376     {
377         CONST D3DVERTEXELEMENT9 test_buffer[] =
378             { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };
379         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
380     }
381
382     /* Make sure textures of different sizes work */
383     {
384         CONST D3DVERTEXELEMENT9 test_buffer[] =
385             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
386         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
387     }
388     {
389         CONST D3DVERTEXELEMENT9 test_buffer[] =
390             { { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
391         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
392     }
393     {
394         CONST D3DVERTEXELEMENT9 test_buffer[] =
395             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
396         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
397     }
398     {
399         CONST D3DVERTEXELEMENT9 test_buffer[] =
400             { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
401         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
402     }
403
404     /* Make sure the TEXCOORD index works correctly - try several textures */
405     {
406         CONST D3DVERTEXELEMENT9 test_buffer[] =
407             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
408               { 0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 },
409               { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2 },
410               { 0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3 }, D3DDECL_END() };
411         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
412     }
413
414     /* No FVF mapping available */
415     {
416         CONST D3DVERTEXELEMENT9 test_buffer[] =
417             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1 }, D3DDECL_END() };
418         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
419     }
420     {
421         CONST D3DVERTEXELEMENT9 test_buffer[] =
422             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1 }, D3DDECL_END() };
423         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
424     }
425
426     /* Try empty declaration */
427     {
428         CONST D3DVERTEXELEMENT9 test_buffer[] = { D3DDECL_END() };
429         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
430     }
431
432     /* Now try a combination test */
433     {
434         CONST D3DVERTEXELEMENT9 test_buffer[] =
435             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITIONT, 0 },
436               { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 },
437               { 0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 },
438               { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 },
439               { 0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
440               { 0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1 }, D3DDECL_END() };
441         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
442     }
443
444     /* Test conversions from FVF to a vertex declaration 
445      * These seem to always occur internally. A new declaration object is created if necessary */
446
447     {
448         CONST D3DVERTEXELEMENT9 test_buffer[] =
449             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() };
450         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZ, test_buffer, 1));
451     }
452     {
453         CONST D3DVERTEXELEMENT9 test_buffer[] =
454           { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() };
455         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZRHW, test_buffer, 1));
456     }
457     {
458         CONST D3DVERTEXELEMENT9 test_buffer[] =
459             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
460               { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
461               { 0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
462         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
463             D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
464     }
465     {
466         CONST D3DVERTEXELEMENT9 test_buffer[] =
467             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
468               { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
469               { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
470         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
471            D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
472     }
473     {
474         CONST D3DVERTEXELEMENT9 test_buffer[] =
475             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
476               { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
477               { 0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
478         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB5, test_buffer, 1));
479     }
480     {
481         CONST D3DVERTEXELEMENT9 test_buffer[] =
482             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
483               { 0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
484         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB1, test_buffer, 1));
485     }
486     {
487         CONST D3DVERTEXELEMENT9 test_buffer[] =
488             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
489               { 0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
490         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
491             D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
492     }
493     {
494         CONST D3DVERTEXELEMENT9 test_buffer[] =
495             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
496               { 0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
497         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
498             D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
499     }
500     {
501          CONST D3DVERTEXELEMENT9 test_buffer[] =
502              { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
503                { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
504          VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB2, test_buffer, 1));
505     }
506     {
507          CONST D3DVERTEXELEMENT9 test_buffer[] =
508              { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
509                { 0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
510                { 0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
511          VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
512              D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
513      }
514      {
515          CONST D3DVERTEXELEMENT9 test_buffer[] =
516              { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
517                { 0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
518                { 0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
519          VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
520              D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
521      }
522      {
523         CONST D3DVERTEXELEMENT9 test_buffer[] =
524             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
525               { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
526         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB3, test_buffer, 1));
527     }
528     {
529         CONST D3DVERTEXELEMENT9 test_buffer[] =
530             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
531               { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
532               { 0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
533         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
534             D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
535     }
536     {
537         CONST D3DVERTEXELEMENT9 test_buffer[] =
538             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
539               { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
540               { 0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
541         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
542             D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
543     }
544     {
545         CONST D3DVERTEXELEMENT9 test_buffer[] =
546             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
547               { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
548         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4, test_buffer, 1));
549     }
550     {
551         CONST D3DVERTEXELEMENT9 test_buffer[] =
552             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
553               { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
554               { 0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
555         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
556             D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
557     }
558     {
559         CONST D3DVERTEXELEMENT9 test_buffer[] =
560             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
561               { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
562               { 0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
563         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
564             D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
565     }
566     {
567         CONST D3DVERTEXELEMENT9 test_buffer[] =
568             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() };
569         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_NORMAL, test_buffer, 1));
570     }
571     {
572         CONST D3DVERTEXELEMENT9 test_buffer[] =
573             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, D3DDECL_END() };
574         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_PSIZE, test_buffer, 1));
575     }
576     {
577         CONST D3DVERTEXELEMENT9 test_buffer[] =
578             { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() };
579         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_DIFFUSE, test_buffer, 1));
580     }
581     {
582         CONST D3DVERTEXELEMENT9 test_buffer[] =
583             { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };
584         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_SPECULAR, test_buffer, 1));
585     }
586
587     /* Make sure textures of different sizes work */
588     {
589         CONST D3DVERTEXELEMENT9 test_buffer[] =
590             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
591         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
592             D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1, test_buffer, 1));
593     }
594     {
595         CONST D3DVERTEXELEMENT9 test_buffer[] =
596             { { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
597         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
598             D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1, test_buffer, 1));
599     }
600     {
601         CONST D3DVERTEXELEMENT9 test_buffer[] =
602             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
603         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
604             D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1, test_buffer, 1));
605     }
606     {
607         CONST D3DVERTEXELEMENT9 test_buffer[] =
608             { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
609         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
610             D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1, test_buffer, 1));
611     }
612
613     /* Make sure the TEXCOORD index works correctly - try several textures */
614     {
615         CONST D3DVERTEXELEMENT9 test_buffer[] =
616             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
617               { 0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 },
618               { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2 },
619               { 0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3 }, D3DDECL_END() };
620         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
621             D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEXCOORDSIZE2(2) |
622             D3DFVF_TEXCOORDSIZE4(3) | D3DFVF_TEX4, test_buffer, 1));
623     }
624
625     /* Now try a combination test  */
626     {
627        CONST D3DVERTEXELEMENT9 test_buffer[] =
628                 { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
629                   { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
630                   { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 },
631                   { 0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 },
632                   { 0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 },
633                   { 0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 }, D3DDECL_END() };
634        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4 | D3DFVF_SPECULAR | D3DFVF_DIFFUSE |
635            D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEX2, test_buffer, 1));
636     }
637
638     /* Setting the FVF to 0 should result in no change to the default decl */
639     VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, 0, default_elements, 0));
640
641     cleanup:
642     IDirect3DDevice9_SetVertexDeclaration ( pDevice, NULL );
643     if ( default_decl ) IUnknown_Release (default_decl);
644 }
645
646 /* Check whether a declaration converted from FVF is shared.
647  * Check whether refcounts behave as expected */
648 static void test_fvf_decl_management(
649     IDirect3DDevice9* device) {
650
651     HRESULT hr;
652     IDirect3DVertexDeclaration9* result_decl1 = NULL;
653     IDirect3DVertexDeclaration9* result_decl2 = NULL;
654     IDirect3DVertexDeclaration9* result_decl3 = NULL;
655     IDirect3DVertexDeclaration9* result_decl4 = NULL;
656     int ref1, ref2, ref3, ref4;
657
658     DWORD test_fvf1 = D3DFVF_XYZRHW;
659     DWORD test_fvf2 = D3DFVF_NORMAL;
660     CONST D3DVERTEXELEMENT9 test_elements1[] =
661         { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() };
662     CONST D3DVERTEXELEMENT9 test_elements2[] =
663         { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() };
664
665     /* Clear down any current vertex declaration */
666     hr = IDirect3DDevice9_SetVertexDeclaration ( device, NULL );
667     ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
668     if (FAILED(hr)) return;
669
670     /* Conversion */
671     hr = IDirect3DDevice9_SetFVF( device, test_fvf1);
672     ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
673     if (FAILED(hr)) return;
674
675     /* Get converted decl (#1) */
676     hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl1);
677     ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
678     if (FAILED(hr)) return;
679
680     /* Get converted decl again (#2) */
681     hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl2);
682     ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
683     if (FAILED(hr)) return;
684
685     /* Conversion */
686     hr = IDirect3DDevice9_SetFVF( device, test_fvf2);
687     ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
688     if (FAILED(hr)) return;
689
690     /* The contents should correspond to the first conversion */
691     VDECL_CHECK(compare_elements(result_decl1, test_elements1));
692
693     /* Get converted decl (#3) */
694     hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl3);
695     ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
696     if (FAILED(hr)) return;
697
698     /* The object should be the same */
699     ok (result_decl1 == result_decl2, "Declaration object changes on the second Get() call\n");
700     ok (result_decl2 != result_decl3, "Declaration object did not change during conversion\n");
701
702     /* The contents should correspond to the second conversion */
703     VDECL_CHECK(compare_elements(result_decl3, test_elements2));
704     /* Re-Check if the first decl was overwritten by the new Get() */
705     VDECL_CHECK(compare_elements(result_decl1, test_elements1));
706
707     hr = IDirect3DDevice9_SetFVF( device, test_fvf1);
708     ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
709     if (FAILED(hr)) return;
710
711     hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl4);
712     ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
713     if (FAILED(hr)) return;
714
715     ok(result_decl4 == result_decl1, "Setting an already used FVF over results in a different vertexdeclaration\n");
716
717     ref1 = get_refcount((IUnknown*) result_decl1);
718     ref2 = get_refcount((IUnknown*) result_decl2);
719     ref3 = get_refcount((IUnknown*) result_decl3);
720     ref4 = get_refcount((IUnknown*) result_decl4);
721     ok (ref1 == 3, "Refcount #1 is %d, expected 3\n", ref1);
722     ok (ref2 == 3, "Refcount #2 is %d, expected 3\n", ref2);
723     ok (ref3 == 1, "Refcount #3 is %d, expected 1\n", ref3);
724     ok (ref4 == 3, "Refcount #4 is %d, expected 3\n", ref4);
725
726     /* Clear down any current vertex declaration */
727     hr = IDirect3DDevice9_SetVertexDeclaration ( device, NULL );
728     ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
729     if (FAILED(hr)) return;
730
731     IDirect3DVertexDeclaration9_Release(result_decl1);
732     IDirect3DVertexDeclaration9_Release(result_decl2);
733     IDirect3DVertexDeclaration9_Release(result_decl3);
734     IDirect3DVertexDeclaration9_Release(result_decl4);
735
736     return;
737 }
738
739 START_TEST(vertexdeclaration)
740 {
741     static D3DVERTEXELEMENT9 simple_decl[] = {
742         { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
743         D3DDECL_END()};
744     UINT simple_decl_num_elements = sizeof(simple_decl) / sizeof(*simple_decl);
745     IDirect3DDevice9 *device_ptr = 0;
746     IDirect3DVertexDeclaration9 *decl_ptr = 0;
747
748     d3d9_handle = LoadLibraryA("d3d9.dll");
749     if (!d3d9_handle)
750     {
751         skip("Could not load d3d9.dll\n");
752         return;
753     }
754
755     device_ptr = init_d3d9();
756     if (!device_ptr)
757     {
758         skip("Failed to initialise d3d9\n");
759         return;
760     }
761
762     decl_ptr = test_create_vertex_declaration(device_ptr, simple_decl);
763     if (!decl_ptr)
764     {
765         skip("Failed to create a vertex declaration\n");
766         return;
767     }
768
769     test_get_set_vertex_declaration(device_ptr, decl_ptr);
770     test_get_declaration(decl_ptr, simple_decl, simple_decl_num_elements);
771     test_fvf_decl_conversion(device_ptr);
772     test_fvf_decl_management(device_ptr);
773 }