vertexdeclaration.c 36.3 KB
Newer Older
1 2
/*
 * Copyright (C) 2005 Henri Verbeet
3
 * Copyright (C) 2006 Ivan Gyurdiev
4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 21 22 23
 */

#define COBJMACROS
#include <d3d9.h>
#include "wine/test.h"

24 25
static HMODULE d3d9_handle = 0;

26 27 28 29
#define VDECL_CHECK(fcall) \
    if(fcall != S_OK) \
        trace(" Test failed on line #%d\n", __LINE__);

30 31 32
static HWND create_window(void)
{
    WNDCLASS wc = {0};
33
    wc.lpfnWndProc = DefWindowProc;
34 35 36 37 38 39 40
    wc.lpszClassName = "d3d9_test_wc";
    RegisterClass(&wc);

    return CreateWindow("d3d9_test_wc", "d3d9_test",
            0, 0, 0, 0, 0, 0, 0, 0, 0);
}

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
static IDirect3DDevice9 *init_d3d9(void)
{
    IDirect3D9 * (__stdcall * d3d9_create)(UINT SDKVersion) = 0;
    IDirect3D9 *d3d9_ptr = 0;
    IDirect3DDevice9 *device_ptr = 0;
    D3DPRESENT_PARAMETERS present_parameters;
    HRESULT hres;

    d3d9_create = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9");
    ok(d3d9_create != NULL, "Failed to get address of Direct3DCreate9\n");
    if (!d3d9_create) return NULL;
    
    d3d9_ptr = d3d9_create(D3D_SDK_VERSION);
    ok(d3d9_ptr != NULL, "Failed to create IDirect3D9 object\n");
    if (!d3d9_ptr) return NULL;

    ZeroMemory(&present_parameters, sizeof(present_parameters));
    present_parameters.Windowed = TRUE;
59
    present_parameters.hDeviceWindow = create_window();
60 61 62
    present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;

    hres = IDirect3D9_CreateDevice(d3d9_ptr, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device_ptr);
63 64 65

    if(FAILED(hres))
    {
66 67 68 69 70 71
        hres = IDirect3D9_CreateDevice(d3d9_ptr, D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device_ptr);
        if(FAILED(hres))
        {
            trace("could not create device, IDirect3D9_CreateDevice returned %#x\n", hres);
            return NULL;
        }
72
    }
73 74 75 76 77 78 79 80 81 82

    return device_ptr;
}

static int get_refcount(IUnknown *object)
{
    IUnknown_AddRef(object);
    return IUnknown_Release(object);
}

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
static inline void print_elements(
    D3DVERTEXELEMENT9 *elements) {

    D3DVERTEXELEMENT9 last = D3DDECL_END();
    D3DVERTEXELEMENT9 *ptr = elements;
    int count = 0;

    while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9))) {

        trace(
            "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
             count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);

        ptr++;
        count++;
    }
}

static int compare_elements(
    IDirect3DVertexDeclaration9 *decl,
    const D3DVERTEXELEMENT9 *expected_elements) {

    HRESULT hr;
    unsigned int i, size;
    D3DVERTEXELEMENT9 last = D3DDECL_END();
    D3DVERTEXELEMENT9 *elements = NULL;

    /* How many elements are there? */
    hr = IDirect3DVertexDeclaration9_GetDeclaration( decl, NULL, &size );
    ok(SUCCEEDED(hr), "GetDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) goto fail;

    /* Allocate buffer */
    elements = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(D3DVERTEXELEMENT9) * size);
    ok (elements != NULL, "Out of memory, aborting test\n");
    if (elements == NULL) goto fail;

    /* Get the elements */
    hr = IDirect3DVertexDeclaration9_GetDeclaration( decl, elements, &size);
    ok(SUCCEEDED(hr), "GetDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) goto fail;

    /* Compare one by one */
    for (i = 0; i < size; i++) {

        int status;

        int end1 = memcmp(&elements[i], &last, sizeof(D3DVERTEXELEMENT9));
        int end2 = memcmp(&expected_elements[i], &last, sizeof(D3DVERTEXELEMENT9));
        status = ((end1 && !end2) || (!end1 && end2));
        ok (!status, "Mismatch in size, test declaration is %s than expected\n",
            (end1 && !end2) ? "shorter" : "longer");
        if (status) { print_elements(elements); goto fail; }

        status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
        ok (!status, "Mismatch in element %d\n", i);
        if (status) { print_elements(elements); goto fail; }
    }

    HeapFree(GetProcessHeap(), 0, elements);
    return S_OK;

    fail:
    HeapFree(GetProcessHeap(), 0, elements);
    return E_FAIL;
}

150
static IDirect3DVertexDeclaration9 *test_create_vertex_declaration(IDirect3DDevice9 *device_ptr, D3DVERTEXELEMENT9 *vertex_decl)
151 152
{
    IDirect3DVertexDeclaration9 *decl_ptr = 0;
153 154 155
    HRESULT hret = 0;

    hret = IDirect3DDevice9_CreateVertexDeclaration(device_ptr, vertex_decl, &decl_ptr);
156 157
    ok(hret == D3D_OK && decl_ptr != NULL, "CreateVertexDeclaration returned: hret 0x%x, decl_ptr %p. "
        "Expected hret 0x%x, decl_ptr != %p. Aborting.\n", hret, decl_ptr, D3D_OK, NULL);
158 159 160 161 162 163

    return decl_ptr;
}

static void test_get_set_vertex_declaration(IDirect3DDevice9 *device_ptr, IDirect3DVertexDeclaration9 *decl_ptr)
{
164 165 166 167 168 169 170 171 172
    IDirect3DVertexDeclaration9 *current_decl_ptr = 0;
    HRESULT hret = 0;
    int decl_refcount = 0;
    int i = 0;
    
    /* SetVertexDeclaration should not touch the declaration's refcount. */
    i = get_refcount((IUnknown *)decl_ptr);
    hret = IDirect3DDevice9_SetVertexDeclaration(device_ptr, decl_ptr);
    decl_refcount = get_refcount((IUnknown *)decl_ptr);
173 174
    ok(hret == D3D_OK && decl_refcount == i, "SetVertexDeclaration returned: hret 0x%x, refcount %d. "
        "Expected hret 0x%x, refcount %d.\n", hret, decl_refcount, D3D_OK, i);
175 176 177 178 179 180
    
    /* GetVertexDeclaration should increase the declaration's refcount by one. */
    i = decl_refcount+1;
    hret = IDirect3DDevice9_GetVertexDeclaration(device_ptr, &current_decl_ptr);
    decl_refcount = get_refcount((IUnknown *)decl_ptr);
    ok(hret == D3D_OK && decl_refcount == i && current_decl_ptr == decl_ptr, 
181 182
        "GetVertexDeclaration returned: hret 0x%x, current_decl_ptr %p refcount %d. "
        "Expected hret 0x%x, current_decl_ptr %p, refcount %d.\n", hret, current_decl_ptr, decl_refcount, D3D_OK, decl_ptr, i);
183 184
}

185 186 187 188 189 190 191 192 193 194 195
static void test_get_declaration(IDirect3DVertexDeclaration9 *decl_ptr, D3DVERTEXELEMENT9 *vertex_decl, UINT expected_num_elements)
{
    int i;
    UINT num_elements = 0;
    D3DVERTEXELEMENT9 *decl = 0;
    HRESULT hret = 0;

    /* First test only getting the number of elements */
    num_elements = 0x1337c0de;
    hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, NULL, &num_elements);
    ok(hret == D3D_OK && num_elements == expected_num_elements,
196 197
            "GetDeclaration returned: hret 0x%x, num_elements %d. "
            "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
198 199 200 201

    num_elements = 0;
    hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, NULL, &num_elements);
    ok(hret == D3D_OK && num_elements == expected_num_elements,
202 203
            "GetDeclaration returned: hret 0x%x, num_elements %d. "
            "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
204 205 206 207 208 209 210

    /* Also test the returned data */
    decl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(D3DVERTEXELEMENT9) * expected_num_elements);

    num_elements = 0x1337c0de;
    hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, decl, &num_elements);
    ok(hret == D3D_OK && num_elements == expected_num_elements,
211 212
            "GetDeclaration returned: hret 0x%x, num_elements %d. "
            "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
213 214 215 216 217 218 219
    i = memcmp(decl, vertex_decl, sizeof(vertex_decl));
    ok (!i, "Original and returned vertexdeclarations are not the same\n");
    ZeroMemory(decl, sizeof(D3DVERTEXELEMENT9) * expected_num_elements);

    num_elements = 0;
    hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, decl, &num_elements);
    ok(hret == D3D_OK && num_elements == expected_num_elements,
220 221
            "GetDeclaration returned: hret 0x%x, num_elements %d. "
            "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
222 223 224 225 226 227
    i = memcmp(decl, vertex_decl, sizeof(vertex_decl));
    ok (!i, "Original and returned vertexdeclarations are not the same\n");

    HeapFree(GetProcessHeap(), 0, decl);
}

228 229 230 231 232 233 234
/* FIXME: also write a test, which shows that attempting to set
 * an invalid vertex declaration returns E_FAIL */

static HRESULT test_fvf_to_decl(
    IDirect3DDevice9* device,
    IDirect3DVertexDeclaration9* default_decl,
    DWORD test_fvf,
235
    const D3DVERTEXELEMENT9 expected_elements[],
236 237 238 239 240 241 242 243
    char object_should_change) 
{

    HRESULT hr;
    IDirect3DVertexDeclaration9 *result_decl = NULL;

    /* Set a default declaration to make sure it is changed */
    hr = IDirect3DDevice9_SetVertexDeclaration ( device, default_decl );
244
    ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
245 246 247 248
    if (FAILED(hr)) goto fail;

    /* Set an FVF */
    hr = IDirect3DDevice9_SetFVF( device, test_fvf);
249
    ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
250 251 252 253
    if (FAILED(hr)) goto fail;

    /* Check if the declaration object changed underneath */
    hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl);
254
    ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
255 256 257 258 259 260 261 262 263 264 265 266 267
    if (FAILED(hr)) goto fail;
    if (object_should_change) {
       ok(result_decl != default_decl, "result declaration matches original\n");
       if (result_decl == default_decl) goto fail;
    } else {
       ok(result_decl == default_decl, "result declaration does not match original\n");
       if (result_decl != default_decl) goto fail;
    }

    /* Declaration content/size test */
    ok(result_decl != NULL, "result declaration was null\n");
    if (result_decl == NULL) 
        goto fail;
268 269
    else if (compare_elements(result_decl, expected_elements) != S_OK)
        goto fail;
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292

    if (result_decl) IUnknown_Release( result_decl );
    return S_OK;    

    fail:
    if (result_decl) IUnknown_Release( result_decl );
    return E_FAIL;
}

static HRESULT test_decl_to_fvf(
    IDirect3DDevice9* device,
    DWORD default_fvf,
    CONST D3DVERTEXELEMENT9 test_decl[],
    DWORD test_fvf)
{

    HRESULT hr;
    IDirect3DVertexDeclaration9 *vdecl = NULL;

    DWORD result_fvf = 0xdeadbeef;

    /* Set a default FVF of SPECULAR and DIFFUSE to make sure it is changed back to 0 */
    hr = IDirect3DDevice9_SetFVF( device, default_fvf);
293
    ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
294 295 296 297
    if (FAILED(hr)) goto fail;

    /* Create a testing declaration */
    hr = IDirect3DDevice9_CreateVertexDeclaration( device, test_decl, &vdecl );
298
    ok(SUCCEEDED(hr), "CreateVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
299 300 301 302
    if (FAILED(hr)) goto fail;

    /* Set the declaration */
    hr = IDirect3DDevice9_SetVertexDeclaration ( device, vdecl );
303
    ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
304 305 306 307
    if (FAILED(hr)) goto fail;

    /* Check the FVF */
    hr = IDirect3DDevice9_GetFVF( device, &result_fvf);
308
    ok(SUCCEEDED(hr), "GetFVF returned %#x, expected %#x\n", hr, D3D_OK);
309 310
    if (FAILED(hr)) goto fail;
    todo_wine {
311
       ok(test_fvf == result_fvf, "result FVF was: %#x, expected: %#x\n", result_fvf, test_fvf);
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
    }
    if (test_fvf != result_fvf) goto fail;

    IDirect3DDevice9_SetVertexDeclaration ( device, NULL );
    if (vdecl) IUnknown_Release( vdecl );
    return S_OK;

    fail:
    IDirect3DDevice9_SetVertexDeclaration ( device, NULL );
    if (vdecl) IUnknown_Release( vdecl );
    return E_FAIL;
}

static void test_fvf_decl_conversion(IDirect3DDevice9 *pDevice)
{

    HRESULT hr;
    unsigned int i;

    IDirect3DVertexDeclaration9* default_decl = NULL;
    DWORD default_fvf = D3DFVF_SPECULAR | D3DFVF_DIFFUSE;
    D3DVERTEXELEMENT9 default_elements[] =
        { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 },
          { 0, 4, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };

    /* Create a default declaration and FVF that does not match any of the tests */
    hr = IDirect3DDevice9_CreateVertexDeclaration( pDevice, default_elements, &default_decl );
339
    ok(SUCCEEDED(hr), "CreateVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
    if (FAILED(hr)) goto cleanup;

    /* Test conversions from vertex declaration to an FVF.
     * For some reason those seem to occur only for POSITION/POSITIONT,
     * Otherwise the FVF is forced to 0 - maybe this is configuration specific */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, D3DFVF_XYZ));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, D3DFVF_XYZRHW));
    }
    for (i = 0; i < 4; i++) {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1+i, 0, D3DDECLUSAGE_BLENDWEIGHT, 0}, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] = 
            { { 0, 0, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0}, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }

    /* Make sure textures of different sizes work */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }

    /* Make sure the TEXCOORD index works correctly - try several textures */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
              { 0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 },
              { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2 },
              { 0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }

    /* No FVF mapping available */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }

    /* Try empty declaration */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] = { D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }

    /* Now try a combination test */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITIONT, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 },
              { 0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 },
              { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 },
              { 0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
              { 0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
    }

    /* Test conversions from FVF to a vertex declaration 
     * These seem to always occur internally. A new declaration object is created if necessary */

    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() };
454
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZ, test_buffer, 1));
455 456 457 458
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
          { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() };
459
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZRHW, test_buffer, 1));
460 461 462 463 464 465
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
466 467
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
468 469 470 471 472 473
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
474 475
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
           D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
476 477 478 479 480 481
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
482
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB5, test_buffer, 1));
483 484 485 486 487
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
488
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB1, test_buffer, 1));
489 490 491 492 493
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
494 495
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
496 497 498 499 500
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
501 502
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
503 504 505 506 507
    }
    {
         CONST D3DVERTEXELEMENT9 test_buffer[] =
             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
               { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
508
         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB2, test_buffer, 1));
509 510 511 512 513 514
    }
    {
         CONST D3DVERTEXELEMENT9 test_buffer[] =
             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
               { 0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
               { 0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
515 516
         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
             D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
517 518 519 520 521 522
     }
     {
         CONST D3DVERTEXELEMENT9 test_buffer[] =
             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
               { 0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
               { 0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
523 524
         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
             D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
525 526 527 528 529
     }
     {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
530
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB3, test_buffer, 1));
531 532 533 534 535 536
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
537 538
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
539 540 541 542 543 544
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
545 546
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
547 548 549 550 551
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
552
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4, test_buffer, 1));
553 554 555 556 557 558
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
559 560
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
561 562 563 564 565 566
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
567 568
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
569 570 571 572
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() };
573
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_NORMAL, test_buffer, 1));
574 575 576 577
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, D3DDECL_END() };
578
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_PSIZE, test_buffer, 1));
579 580 581 582
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() };
583
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_DIFFUSE, test_buffer, 1));
584 585 586 587
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };
588
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_SPECULAR, test_buffer, 1));
589 590 591 592 593 594
    }

    /* Make sure textures of different sizes work */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
595 596
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1, test_buffer, 1));
597 598 599 600
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
601 602
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1, test_buffer, 1));
603 604 605 606
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
607 608
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1, test_buffer, 1));
609 610 611 612
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
613 614
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1, test_buffer, 1));
615 616 617 618 619 620 621 622 623 624 625
    }

    /* Make sure the TEXCOORD index works correctly - try several textures */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
              { 0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 },
              { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2 },
              { 0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEXCOORDSIZE2(2) |
626
            D3DFVF_TEXCOORDSIZE4(3) | D3DFVF_TEX4, test_buffer, 1));
627 628 629 630 631 632 633 634 635 636 637 638
    }

    /* Now try a combination test  */
    {
       CONST D3DVERTEXELEMENT9 test_buffer[] =
                { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
                  { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
                  { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 },
                  { 0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 },
                  { 0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 },
                  { 0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 }, D3DDECL_END() };
       VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4 | D3DFVF_SPECULAR | D3DFVF_DIFFUSE |
639
           D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEX2, test_buffer, 1));
640 641 642
    }

    /* Setting the FVF to 0 should result in no change to the default decl */
643
    VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, 0, default_elements, 0));
644 645 646 647 648 649

    cleanup:
    IDirect3DDevice9_SetVertexDeclaration ( pDevice, NULL );
    if ( default_decl ) IUnknown_Release (default_decl);
}

650 651 652 653 654 655 656 657 658
/* Check whether a declaration converted from FVF is shared.
 * Check whether refcounts behave as expected */
static void test_fvf_decl_management(
    IDirect3DDevice9* device) {

    HRESULT hr;
    IDirect3DVertexDeclaration9* result_decl1 = NULL;
    IDirect3DVertexDeclaration9* result_decl2 = NULL;
    IDirect3DVertexDeclaration9* result_decl3 = NULL;
659 660
    IDirect3DVertexDeclaration9* result_decl4 = NULL;
    int ref1, ref2, ref3, ref4;
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693

    DWORD test_fvf1 = D3DFVF_XYZRHW;
    DWORD test_fvf2 = D3DFVF_NORMAL;
    CONST D3DVERTEXELEMENT9 test_elements1[] =
        { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() };
    CONST D3DVERTEXELEMENT9 test_elements2[] =
        { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() };

    /* Clear down any current vertex declaration */
    hr = IDirect3DDevice9_SetVertexDeclaration ( device, NULL );
    ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) return;

    /* Conversion */
    hr = IDirect3DDevice9_SetFVF( device, test_fvf1);
    ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) return;

    /* Get converted decl (#1) */
    hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl1);
    ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) return;

    /* Get converted decl again (#2) */
    hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl2);
    ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) return;

    /* Conversion */
    hr = IDirect3DDevice9_SetFVF( device, test_fvf2);
    ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) return;

694
    /* The contents should correspond to the first conversion */
695 696 697 698 699 700 701 702 703 704 705 706 707
    VDECL_CHECK(compare_elements(result_decl1, test_elements1));

    /* Get converted decl (#3) */
    hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl3);
    ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) return;

    /* The object should be the same */
    ok (result_decl1 == result_decl2, "Declaration object changes on the second Get() call\n");
    ok (result_decl2 != result_decl3, "Declaration object did not change during conversion\n");

    /* The contents should correspond to the second conversion */
    VDECL_CHECK(compare_elements(result_decl3, test_elements2));
708 709
    /* Re-Check if the first decl was overwritten by the new Get() */
    VDECL_CHECK(compare_elements(result_decl1, test_elements1));
710

711 712 713 714 715 716 717 718 719 720
    hr = IDirect3DDevice9_SetFVF( device, test_fvf1);
    ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) return;

    hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl4);
    ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) return;

    ok(result_decl4 == result_decl1, "Setting an already used FVF over results in a different vertexdeclaration\n");

721 722 723
    ref1 = get_refcount((IUnknown*) result_decl1);
    ref2 = get_refcount((IUnknown*) result_decl2);
    ref3 = get_refcount((IUnknown*) result_decl3);
724 725 726
    ref4 = get_refcount((IUnknown*) result_decl4);
    ok (ref1 == 3, "Refcount #1 is %d, expected 3\n", ref1);
    ok (ref2 == 3, "Refcount #2 is %d, expected 3\n", ref2);
727
    ok (ref3 == 1, "Refcount #3 is %d, expected 1\n", ref3);
728
    ok (ref4 == 3, "Refcount #4 is %d, expected 3\n", ref4);
729 730 731 732 733 734

    /* Clear down any current vertex declaration */
    hr = IDirect3DDevice9_SetVertexDeclaration ( device, NULL );
    ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) return;

735 736 737 738 739
    IDirect3DVertexDeclaration9_Release(result_decl1);
    IDirect3DVertexDeclaration9_Release(result_decl2);
    IDirect3DVertexDeclaration9_Release(result_decl3);
    IDirect3DVertexDeclaration9_Release(result_decl4);

740 741 742
    return;
}

743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
static void test_vertex_declaration_alignment(
    IDirect3DDevice9* device) {

    HRESULT hr;
    IDirect3DVertexDeclaration9* result_decl = NULL;
    int i;

    CONST D3DVERTEXELEMENT9 test_elements[5][3] =
    {
        {
            { 0, 0, D3DDECLTYPE_FLOAT3,   0, D3DDECLUSAGE_POSITION, 0 },
            { 0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR  , 0 },
            D3DDECL_END()
        },
        {
            { 0, 0, D3DDECLTYPE_FLOAT3,   0, D3DDECLUSAGE_POSITION, 0 },
            { 0, 17, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR  , 0 },
            D3DDECL_END()
        },
        {
            { 0, 0, D3DDECLTYPE_FLOAT3,   0, D3DDECLUSAGE_POSITION, 0 },
            { 0, 18, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR  , 0 },
            D3DDECL_END()
        },
        {
            { 0, 0, D3DDECLTYPE_FLOAT3,   0, D3DDECLUSAGE_POSITION, 0 },
            { 0, 19, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR  , 0 },
            D3DDECL_END()
        },
        {
            { 0, 0, D3DDECLTYPE_FLOAT3,   0, D3DDECLUSAGE_POSITION, 0 },
            { 0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR  , 0 },
            D3DDECL_END()
        }
    };
    HRESULT results[5] = {D3D_OK, E_FAIL, E_FAIL, E_FAIL, D3D_OK};

    for(i = 0; i < sizeof(test_elements) / sizeof(test_elements[0]); i++) {
        result_decl = NULL;
        hr = IDirect3DDevice9_CreateVertexDeclaration(device, test_elements[i], &result_decl);
        ok(hr == results[i], "CreateVertexDeclaration for declaration %d returned %#x, expected %#x\n",
                              i, hr, results[i]);
        if(result_decl) IDirect3DVertexDeclaration9_Release(result_decl);
    }
}

789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
static void test_unused_type(
    IDirect3DDevice9* device) {

    HRESULT hr;
    IDirect3DVertexDeclaration9* result_decl = NULL;
    int i;

    static const D3DVERTEXELEMENT9 test_elements[][3] =
    {
        {
            { 0, 0,  D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
            { 0, 16, D3DDECLTYPE_UNUSED, 0, D3DDECLUSAGE_COLOR   , 0 },
            D3DDECL_END()
        },
        {
            { 0, 0,  D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
            { 0, 16, D3DDECLTYPE_UNUSED, 0, D3DDECLUSAGE_TEXCOORD, 0 },
            D3DDECL_END()
        },
        {
            { 0, 0,  D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
            { 0, 16, D3DDECLTYPE_UNUSED, 0, D3DDECLUSAGE_TEXCOORD, 1 },
            D3DDECL_END()
        },
        {
            { 0, 0,  D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
            { 0, 16, D3DDECLTYPE_UNUSED, 0, D3DDECLUSAGE_TEXCOORD, 12},
            D3DDECL_END()
        },
        {
            { 0, 0,  D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
            { 1, 16, D3DDECLTYPE_UNUSED, 0, D3DDECLUSAGE_TEXCOORD, 12},
            D3DDECL_END()
        },
        {
            { 0, 0,  D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
            { 0, 16, D3DDECLTYPE_UNUSED, 0, D3DDECLUSAGE_NORMAL,   0 },
            D3DDECL_END()
        },
        {
            { 0, 0,  D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
            { 1, 16, D3DDECLTYPE_UNUSED, 0, D3DDECLUSAGE_NORMAL,   0 },
            D3DDECL_END()
        },
    };

    for(i = 0; i < sizeof(test_elements) / sizeof(test_elements[0]); i++) {
        result_decl = NULL;
        hr = IDirect3DDevice9_CreateVertexDeclaration(device, test_elements[i], &result_decl);
        ok(hr == E_FAIL, "CreateVertexDeclaration for declaration %d returned %#x, expected E_FAIL(%#x)\n",
                              i, hr, E_FAIL);
        if(result_decl) IDirect3DVertexDeclaration9_Release(result_decl);
    }
}
843 844
START_TEST(vertexdeclaration)
{
845 846 847
    static D3DVERTEXELEMENT9 simple_decl[] = {
        { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
        D3DDECL_END()};
848
    UINT simple_decl_num_elements = sizeof(simple_decl) / sizeof(*simple_decl);
849 850
    IDirect3DDevice9 *device_ptr = 0;
    IDirect3DVertexDeclaration9 *decl_ptr = 0;
851 852 853 854

    d3d9_handle = LoadLibraryA("d3d9.dll");
    if (!d3d9_handle)
    {
855
        skip("Could not load d3d9.dll\n");
856 857 858 859
        return;
    }

    device_ptr = init_d3d9();
860 861
    if (!device_ptr)
    {
862
        skip("Failed to initialise d3d9\n");
863 864 865 866 867 868
        return;
    }

    decl_ptr = test_create_vertex_declaration(device_ptr, simple_decl);
    if (!decl_ptr)
    {
869
        skip("Failed to create a vertex declaration\n");
870 871 872 873
        return;
    }

    test_get_set_vertex_declaration(device_ptr, decl_ptr);
874
    test_get_declaration(decl_ptr, simple_decl, simple_decl_num_elements);
875
    test_fvf_decl_conversion(device_ptr);
876
    test_fvf_decl_management(device_ptr);
877
    test_vertex_declaration_alignment(device_ptr);
878
    test_unused_type(device_ptr);
879
}