[D3DX9_36_WINETEST] Import from wine 4.0
authorJérôme Gardou <jerome.gardou@reactos.org>
Tue, 24 Dec 2019 08:31:48 +0000 (09:31 +0100)
committerJérôme Gardou <zefklop@users.noreply.github.com>
Wed, 26 Feb 2020 17:19:18 +0000 (18:19 +0100)
18 files changed:
modules/rostests/winetests/CMakeLists.txt
modules/rostests/winetests/d3dx9_36/CMakeLists.txt [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/asm.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/bmp1x1.bmp [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/core.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/effect.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/line.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/math.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/mesh.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/res.vsh [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/resources.h [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/rsrc.rc [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/shader.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/surface.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/testlist.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/texture.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/volume.c [new file with mode: 0644]
modules/rostests/winetests/d3dx9_36/xfile.c [new file with mode: 0644]

index 8bb0f90..c4553c5 100644 (file)
@@ -35,6 +35,7 @@ add_subdirectory(cryptnet)
 add_subdirectory(cryptui)
 add_subdirectory(d3dcompiler_43)
 add_subdirectory(d3drm)
+add_subdirectory(d3dx9_36)
 add_subdirectory(devenum)
 add_subdirectory(dinput)
 add_subdirectory(dinput8)
diff --git a/modules/rostests/winetests/d3dx9_36/CMakeLists.txt b/modules/rostests/winetests/d3dx9_36/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2a1dab1
--- /dev/null
@@ -0,0 +1,25 @@
+
+add_executable(d3dx9_36_winetest
+    asm.c
+    core.c 
+    effect.c 
+    line.c
+    math.c
+    mesh.c
+    shader.c
+    surface.c
+    texture.c
+    volume.c
+    xfile.c
+    testlist.c
+    rsrc.rc)
+target_compile_definitions(d3dx9_36_winetest PRIVATE -DUSE_WINE_TODOS -D__WINESRC__ -Disnan=_isnan)
+if(MSVC)
+    # Disable warning C4477 (printf format warnings)
+    target_compile_options(d3dx9_36_winetest PRIVATE "/wd4477")
+endif()
+
+target_link_libraries(d3dx9_36_winetest uuid dxguid)
+set_module_type(d3dx9_36_winetest win32cui)
+add_importlibs(d3dx9_36_winetest d3dx9_36 d3d9 user32 gdi32 msvcrt kernel32)
+add_rostests_file(TARGET d3dx9_36_winetest)
diff --git a/modules/rostests/winetests/d3dx9_36/asm.c b/modules/rostests/winetests/d3dx9_36/asm.c
new file mode 100644 (file)
index 0000000..4087bd8
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 2008 Stefan Dösinger
+ * Copyright (C) 2009 Matteo Bruni
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#define COBJMACROS
+#define CONST_VTABLE
+#include "wine/test.h"
+
+#include <d3dx9.h>
+
+#include "resources.h"
+
+static char temp_path[MAX_PATH];
+
+static BOOL create_file(const char *filename, const char *data, const unsigned int size, char *out_path)
+{
+    DWORD written;
+    HANDLE hfile;
+    char path[MAX_PATH];
+
+    if (!*temp_path)
+        GetTempPathA(sizeof(temp_path), temp_path);
+
+    strcpy(path, temp_path);
+    strcat(path, filename);
+    hfile = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+    if (hfile == INVALID_HANDLE_VALUE)
+        return FALSE;
+
+    if (WriteFile(hfile, data, size, &written, NULL))
+    {
+        CloseHandle(hfile);
+
+        if (out_path)
+            strcpy(out_path, path);
+        return TRUE;
+    }
+
+    CloseHandle(hfile);
+    return FALSE;
+}
+
+static void delete_file(const char *filename)
+{
+    char path[MAX_PATH];
+
+    strcpy(path, temp_path);
+    strcat(path, filename);
+    DeleteFileA(path);
+}
+
+static BOOL create_directory(const char *name)
+{
+    char path[MAX_PATH];
+
+    strcpy(path, temp_path);
+    strcat(path, name);
+    return CreateDirectoryA(path, NULL);
+}
+
+static void delete_directory(const char *name)
+{
+    char path[MAX_PATH];
+
+    strcpy(path, temp_path);
+    strcat(path, name);
+    RemoveDirectoryA(path);
+}
+
+static HRESULT WINAPI testD3DXInclude_open(ID3DXInclude *iface, D3DXINCLUDE_TYPE include_type,
+        const char *filename, const void *parent_data, const void **data, UINT *bytes)
+{
+    char *buffer;
+    static const char shader[] =
+            "#include \"incl.vsh\"\n"
+            "mov REGISTER, v0\n";
+    static const char include[] = "#define REGISTER r0\nvs.1.1\n";
+    static const char include2[] = "#include \"incl3.vsh\"\n";
+    static const char include3[] = "vs.1.1\n";
+
+    trace("filename %s.\n", filename);
+    trace("parent_data %p: %s.\n", parent_data, parent_data ? (char *)parent_data : "(null)");
+
+    if (!strcmp(filename, "shader.vsh"))
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(shader));
+        memcpy(buffer, shader, sizeof(shader));
+        *bytes = sizeof(shader);
+    }
+    else if (!strcmp(filename, "incl.vsh"))
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(include));
+        memcpy(buffer, include, sizeof(include));
+        *bytes = sizeof(include);
+        /* This is included from the first D3DXAssembleShader with non-null ID3DXInclude test
+         * (parent_data == NULL) and from shader.vsh / shader[] (with matching parent_data).
+         * Allow both cases. */
+        ok(parent_data == NULL || !strncmp(shader, parent_data, strlen(shader)), "wrong parent_data value\n");
+    }
+    else if (!strcmp(filename, "incl2.vsh"))
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(include2));
+        memcpy(buffer, include2, sizeof(include2));
+        *bytes = sizeof(include2);
+    }
+    else if (!strcmp(filename, "incl3.vsh"))
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(include3));
+        memcpy(buffer, include3, sizeof(include3));
+        *bytes = sizeof(include3);
+        /* Also check for the correct parent_data content */
+        ok(parent_data != NULL && !strncmp(include2, parent_data, strlen(include2)), "wrong parent_data value\n");
+    }
+    else if (!strcmp(filename, "include/incl3.vsh"))
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(include));
+        memcpy(buffer, include, sizeof(include));
+        *bytes = sizeof(include);
+        ok(!parent_data, "wrong parent_data value\n");
+    }
+    else
+    {
+        ok(0, "Unexpected #include for file %s.\n", filename);
+        return D3DERR_INVALIDCALL;
+    }
+    *data = buffer;
+    return S_OK;
+}
+
+static HRESULT WINAPI testD3DXInclude_close(ID3DXInclude *iface, const void *data)
+{
+    HeapFree(GetProcessHeap(), 0, (void *)data);
+    return S_OK;
+}
+
+static const struct ID3DXIncludeVtbl D3DXInclude_Vtbl = {
+    testD3DXInclude_open,
+    testD3DXInclude_close
+};
+
+struct D3DXIncludeImpl {
+    ID3DXInclude ID3DXInclude_iface;
+};
+
+static void assembleshader_test(void)
+{
+    static const char test1[] =
+        "vs.1.1\n"
+        "mov DEF2, v0\n";
+    static const char testincl[] =
+        "#define REGISTER r0\n"
+        "vs.1.1\n";
+    static const char testshader[] =
+        "#include \"incl.vsh\"\n"
+        "mov REGISTER, v0\n";
+    static const char testshader2[] =
+        "#include \"incl2.vsh\"\n"
+        "mov REGISTER, v0\n";
+    static const char testshader3[] =
+        "#include \"include/incl3.vsh\"\n"
+        "mov REGISTER, v0\n";
+    static const char testincl3[] =
+        "#include \"incl4.vsh\"\n";
+    static const char testincl4_ok[] =
+        "#define REGISTER r0\n"
+        "vs.1.1\n";
+    static const char testincl4_wrong[] =
+        "#error \"wrong include\"\n";
+    HRESULT hr;
+    ID3DXBuffer *shader, *messages;
+    static const D3DXMACRO defines[] = {
+        {
+            "DEF1", "10 + 15"
+        },
+        {
+            "DEF2", "r0"
+        },
+        {
+            NULL, NULL
+        }
+    };
+    struct D3DXIncludeImpl include;
+    char shader_vsh_path[MAX_PATH], shader3_vsh_path[MAX_PATH];
+    static const WCHAR shader_filename_w[] = {'s','h','a','d','e','r','.','v','s','h',0};
+
+    /* pDefines test */
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXAssembleShader(test1, strlen(test1),
+                            defines, NULL, D3DXSHADER_SKIPVALIDATION,
+                            &shader, &messages);
+    ok(hr == D3D_OK, "pDefines test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+
+    /* NULL messages test */
+    shader = NULL;
+    hr = D3DXAssembleShader(test1, strlen(test1),
+                            defines, NULL, D3DXSHADER_SKIPVALIDATION,
+                            &shader, NULL);
+    ok(hr == D3D_OK, "NULL messages test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(shader) ID3DXBuffer_Release(shader);
+
+    /* NULL shader test */
+    messages = NULL;
+    hr = D3DXAssembleShader(test1, strlen(test1),
+                            defines, NULL, D3DXSHADER_SKIPVALIDATION,
+                            NULL, &messages);
+    ok(hr == D3D_OK, "NULL shader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+
+    /* pInclude test */
+    shader = NULL;
+    messages = NULL;
+    include.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
+    hr = D3DXAssembleShader(testshader, strlen(testshader), NULL, &include.ID3DXInclude_iface,
+                            D3DXSHADER_SKIPVALIDATION, &shader, &messages);
+    ok(hr == D3D_OK, "pInclude test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+
+    /* "unexpected #include file from memory" test */
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXAssembleShader(testshader, strlen(testshader),
+                            NULL, NULL, D3DXSHADER_SKIPVALIDATION,
+                            &shader, &messages);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXAssembleShader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+
+    /* recursive #include test */
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXAssembleShader(testshader2, strlen(testshader2), NULL, &include.ID3DXInclude_iface,
+                            D3DXSHADER_SKIPVALIDATION, &shader, &messages);
+    ok(hr == D3D_OK, "D3DXAssembleShader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("recursive D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+
+    /* #include with a path. */
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXAssembleShader(testshader3, strlen(testshader3), NULL, &include.ID3DXInclude_iface,
+            D3DXSHADER_SKIPVALIDATION, &shader, &messages);
+    ok(hr == D3D_OK, "D3DXAssembleShader test failed with error 0x%x - %d\n", hr, hr & 0x0000ffff);
+    if (messages)
+    {
+        trace("Path search D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if (shader)
+        ID3DXBuffer_Release(shader);
+
+    if (create_file("shader.vsh", testshader, sizeof(testshader) - 1, shader_vsh_path))
+    {
+        create_file("incl.vsh", testincl, sizeof(testincl) - 1, NULL);
+
+        /* D3DXAssembleShaderFromFile + #include test */
+        shader = NULL;
+        messages = NULL;
+        hr = D3DXAssembleShaderFromFileA(shader_vsh_path,
+                                         NULL, NULL, D3DXSHADER_SKIPVALIDATION,
+                                         &shader, &messages);
+        ok(hr == D3D_OK, "D3DXAssembleShaderFromFile test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+        if(messages) {
+            trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+            ID3DXBuffer_Release(messages);
+        }
+        if(shader) ID3DXBuffer_Release(shader);
+
+        /* D3DXAssembleShaderFromFile + pInclude test */
+        shader = NULL;
+        messages = NULL;
+        hr = D3DXAssembleShaderFromFileA("shader.vsh", NULL, &include.ID3DXInclude_iface,
+                                         D3DXSHADER_SKIPVALIDATION, &shader, &messages);
+        ok(hr == D3D_OK, "D3DXAssembleShaderFromFile + pInclude test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+        if(messages) {
+            trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+            ID3DXBuffer_Release(messages);
+        }
+        if(shader) ID3DXBuffer_Release(shader);
+
+        create_file("shader3.vsh", testshader3, sizeof(testshader3) - 1, shader3_vsh_path);
+        create_file("incl4.vsh", testincl4_wrong, sizeof(testincl4_wrong) - 1, NULL);
+        if (create_directory("include"))
+        {
+            create_file("include\\incl3.vsh", testincl3, sizeof(testincl3) - 1, NULL);
+            create_file("include\\incl4.vsh", testincl4_ok, sizeof(testincl4_ok) - 1, NULL);
+
+            /* path search #include test */
+            shader = NULL;
+            messages = NULL;
+            hr = D3DXAssembleShaderFromFileA(shader3_vsh_path, NULL, NULL,
+                                             D3DXSHADER_SKIPVALIDATION,
+                                             &shader, &messages);
+            ok(hr == D3D_OK, "D3DXAssembleShaderFromFile path search test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+            if(messages) {
+                trace("D3DXAssembleShaderFromFile path search messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+                ID3DXBuffer_Release(messages);
+            }
+            if(shader) ID3DXBuffer_Release(shader);
+        } else skip("Couldn't create \"include\" directory\n");
+
+        delete_file("shader.vsh");
+        delete_file("incl.vsh");
+        delete_file("shader3.vsh");
+        delete_file("incl4.vsh");
+        delete_file("include\\incl3.vsh");
+        delete_file("include\\incl4.vsh");
+        delete_directory("include");
+
+        /* The main shader is also to be loaded through the ID3DXInclude object. */
+        shader = NULL;
+        messages = NULL;
+        hr = D3DXAssembleShaderFromFileA("shader.vsh", NULL, &include.ID3DXInclude_iface,
+                D3DXSHADER_SKIPVALIDATION, &shader, &messages);
+        ok(hr == D3D_OK, "D3DXAssembleShaderFromFile + pInclude main shader test failed with error 0x%x - %d\n",
+                hr, hr & 0x0000ffff);
+        if (messages)
+        {
+            trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+            ID3DXBuffer_Release(messages);
+        }
+        if (shader)
+            ID3DXBuffer_Release(shader);
+
+        shader = NULL;
+        messages = NULL;
+        hr = D3DXAssembleShaderFromFileW(shader_filename_w, NULL, &include.ID3DXInclude_iface,
+                D3DXSHADER_SKIPVALIDATION, &shader, &messages);
+        ok(hr == D3D_OK, "D3DXAssembleShaderFromFile + pInclude main shader test failed with error 0x%x - %d\n",
+                hr, hr & 0x0000ffff);
+        if (messages)
+        {
+            trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+            ID3DXBuffer_Release(messages);
+        }
+        if (shader)
+            ID3DXBuffer_Release(shader);
+    } else skip("Couldn't create \"shader.vsh\"\n");
+
+    /* NULL shader tests */
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXAssembleShader(NULL, 0,
+                            NULL, NULL, D3DXSHADER_SKIPVALIDATION,
+                            &shader, &messages);
+    ok(hr == D3DXERR_INVALIDDATA, "NULL shader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXAssembleShaderFromFileA("nonexistent.vsh",
+                                     NULL, NULL, D3DXSHADER_SKIPVALIDATION,
+                                     &shader, &messages);
+    ok(hr == D3DXERR_INVALIDDATA || hr == E_FAIL, /* I get this on WinXP */
+        "D3DXAssembleShaderFromFile nonexistent file test failed with error 0x%x - %d\n",
+        hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXAssembleShaderFromFile messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+
+    /* D3DXAssembleShaderFromResource test */
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXAssembleShaderFromResourceA(NULL, MAKEINTRESOURCEA(IDB_ASMSHADER),
+                                         NULL, NULL, D3DXSHADER_SKIPVALIDATION,
+                                         &shader, &messages);
+    ok(hr == D3D_OK, "D3DXAssembleShaderFromResource test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXAssembleShaderFromResource messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+
+    /* D3DXAssembleShaderFromResource with missing shader resource test */
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXAssembleShaderFromResourceA(NULL, "notexisting",
+                                         NULL, NULL, D3DXSHADER_SKIPVALIDATION,
+                                         &shader, &messages);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXAssembleShaderFromResource NULL shader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXAssembleShaderFromResource messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+}
+
+static void d3dxpreprocess_test(void)
+{
+    static const char testincl[] =
+            "#define REGISTER r0\n"
+            "vs.1.1\n";
+    static const char testshader[] =
+            "#include \"incl.vsh\"\n"
+            "mov REGISTER, v0\n";
+    static const char testshader3[] =
+            "#include \"include/incl3.vsh\"\n"
+            "mov REGISTER, v0\n";
+    static const char testincl3[] =
+            "#include \"incl4.vsh\"\n";
+    static const char testincl4_ok[] =
+            "#define REGISTER r0\n"
+            "vs.1.1\n";
+    static const char testincl4_wrong[] =
+            "#error \"wrong include\"\n";
+    HRESULT hr;
+    ID3DXBuffer *shader, *messages;
+    char shader_vsh_path[MAX_PATH], shader3_vsh_path[MAX_PATH];
+    static struct D3DXIncludeImpl include = {{&D3DXInclude_Vtbl}};
+    static const WCHAR shader_filename_w[] = {'s','h','a','d','e','r','.','v','s','h',0};
+
+    if (create_file("shader.vsh", testshader, sizeof(testshader) - 1, shader_vsh_path))
+    {
+        create_file("incl.vsh", testincl, sizeof(testincl) - 1, NULL);
+        create_file("shader3.vsh", testshader3, sizeof(testshader3) - 1, shader3_vsh_path);
+        create_file("incl4.vsh", testincl4_wrong, sizeof(testincl4_wrong) - 1, NULL);
+        if (create_directory("include"))
+        {
+            create_file("include\\incl3.vsh", testincl3, sizeof(testincl3) - 1, NULL);
+            create_file("include\\incl4.vsh", testincl4_ok, sizeof(testincl4_ok) - 1, NULL);
+
+            /* path search #include test */
+            shader = NULL;
+            messages = NULL;
+            hr = D3DXPreprocessShaderFromFileA(shader3_vsh_path, NULL, NULL,
+                                               &shader, &messages);
+            ok(hr == D3D_OK, "D3DXPreprocessShaderFromFile path search test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+            if(messages) {
+                trace("D3DXPreprocessShaderFromFile path search messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+                ID3DXBuffer_Release(messages);
+            }
+            if(shader) ID3DXBuffer_Release(shader);
+        } else skip("Couldn't create \"include\" directory\n");
+
+        /* D3DXPreprocessShaderFromFile + #include test */
+        shader = NULL;
+        messages = NULL;
+        hr = D3DXPreprocessShaderFromFileA(shader_vsh_path,
+                                           NULL, NULL,
+                                           &shader, &messages);
+        ok(hr == D3D_OK, "D3DXPreprocessShaderFromFile test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+        if(messages) {
+            trace("D3DXPreprocessShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+            ID3DXBuffer_Release(messages);
+        }
+        if(shader) ID3DXBuffer_Release(shader);
+
+        /* D3DXPreprocessShaderFromFile + pInclude test */
+        shader = NULL;
+        messages = NULL;
+        hr = D3DXPreprocessShaderFromFileA("shader.vsh", NULL, &include.ID3DXInclude_iface,
+                                           &shader, &messages);
+        ok(hr == D3D_OK, "D3DXPreprocessShaderFromFile + pInclude test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+        if(messages) {
+            trace("D3DXPreprocessShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+            ID3DXBuffer_Release(messages);
+        }
+        if(shader) ID3DXBuffer_Release(shader);
+
+        delete_file("shader.vsh");
+        delete_file("incl.vsh");
+        delete_file("shader3.vsh");
+        delete_file("incl4.vsh");
+        delete_file("include\\incl3.vsh");
+        delete_file("include\\incl4.vsh");
+        delete_directory("include");
+
+        /* The main shader is also to be loaded through the ID3DXInclude object. */
+        shader = NULL;
+        messages = NULL;
+        hr = D3DXPreprocessShaderFromFileA("shader.vsh", NULL, &include.ID3DXInclude_iface,
+                &shader, &messages);
+        ok(hr == D3D_OK, "D3DXPreprocessShaderFromFile + pInclude main shader test failed with error 0x%x - %d\n",
+                hr, hr & 0x0000ffff);
+        if (messages)
+        {
+            trace("D3DXPreprocessShaderFromFile messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+            ID3DXBuffer_Release(messages);
+        }
+        if (shader)
+            ID3DXBuffer_Release(shader);
+
+        shader = NULL;
+        messages = NULL;
+        hr = D3DXPreprocessShaderFromFileW(shader_filename_w, NULL, &include.ID3DXInclude_iface,
+                &shader, &messages);
+        ok(hr == D3D_OK, "D3DXPreprocessShaderFromFile + pInclude main shader test failed with error 0x%x - %d\n",
+                hr, hr & 0x0000ffff);
+        if (messages)
+        {
+            trace("D3DXPreprocessShaderFromFile messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+            ID3DXBuffer_Release(messages);
+        }
+        if (shader)
+            ID3DXBuffer_Release(shader);
+    } else skip("Couldn't create \"shader.vsh\"\n");
+
+    /* NULL shader tests */
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXPreprocessShaderFromFileA("nonexistent.vsh",
+                                       NULL, NULL,
+                                       &shader, &messages);
+    ok(hr == D3DXERR_INVALIDDATA || hr == E_FAIL, /* I get this on WinXP */
+        "D3DXPreprocessShaderFromFile nonexistent file test failed with error 0x%x - %d\n",
+        hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXPreprocessShaderFromFile messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+
+    /* D3DXPreprocessShaderFromResource test */
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXPreprocessShaderFromResourceA(NULL, MAKEINTRESOURCEA(IDB_ASMSHADER),
+                                           NULL, NULL,
+                                           &shader, &messages);
+    ok(hr == D3D_OK, "D3DXPreprocessShaderFromResource test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXPreprocessShaderFromResource messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+
+    /* D3DXPreprocessShaderFromResource with missing shader resource test */
+    shader = NULL;
+    messages = NULL;
+    hr = D3DXPreprocessShaderFromResourceA(NULL, "notexisting",
+                                           NULL, NULL,
+                                           &shader, &messages);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXPreprocessShaderFromResource NULL shader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
+    if(messages) {
+        trace("D3DXPreprocessShaderFromResource messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if(shader) ID3DXBuffer_Release(shader);
+}
+
+START_TEST(asm)
+{
+    assembleshader_test();
+
+    d3dxpreprocess_test();
+}
diff --git a/modules/rostests/winetests/d3dx9_36/bmp1x1.bmp b/modules/rostests/winetests/d3dx9_36/bmp1x1.bmp
new file mode 100644 (file)
index 0000000..7f87ecf
Binary files /dev/null and b/modules/rostests/winetests/d3dx9_36/bmp1x1.bmp differ
diff --git a/modules/rostests/winetests/d3dx9_36/core.c b/modules/rostests/winetests/d3dx9_36/core.c
new file mode 100644 (file)
index 0000000..fa874a5
--- /dev/null
@@ -0,0 +1,1310 @@
+/*
+ * Tests for the D3DX9 core interfaces
+ *
+ * Copyright 2009 Tony Wasserka
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include "wine/test.h"
+#include <dxerr9.h>
+#include "d3dx9core.h"
+
+static inline int get_ref(IUnknown *obj)
+{
+    IUnknown_AddRef(obj);
+    return IUnknown_Release(obj);
+}
+
+#define check_ref(obj, exp) _check_ref(__LINE__, obj, exp)
+static inline void _check_ref(unsigned int line, IUnknown *obj, int exp)
+{
+    int ref = get_ref(obj);
+    ok_(__FILE__, line)(exp == ref, "Invalid refcount. Expected %d, got %d\n", exp, ref);
+}
+
+#define check_release(obj, exp) _check_release(__LINE__, obj, exp)
+static inline void _check_release(unsigned int line, IUnknown *obj, int exp)
+{
+    int ref = IUnknown_Release(obj);
+    ok_(__FILE__, line)(ref == exp, "Invalid refcount. Expected %d, got %d\n", exp, ref);
+}
+
+#define admitted_error 0.0001f
+static inline void check_mat(D3DXMATRIX got, D3DXMATRIX exp)
+{
+    int i, j, equal=1;
+    for (i=0; i<4; i++)
+        for (j=0; j<4; j++)
+            if (fabs(U(exp).m[i][j]-U(got).m[i][j]) > admitted_error)
+                equal=0;
+
+    ok(equal, "Got matrix\n\t(%f,%f,%f,%f\n\t %f,%f,%f,%f\n\t %f,%f,%f,%f\n\t %f,%f,%f,%f)\n"
+       "Expected matrix=\n\t(%f,%f,%f,%f\n\t %f,%f,%f,%f\n\t %f,%f,%f,%f\n\t %f,%f,%f,%f)\n",
+       U(got).m[0][0],U(got).m[0][1],U(got).m[0][2],U(got).m[0][3],
+       U(got).m[1][0],U(got).m[1][1],U(got).m[1][2],U(got).m[1][3],
+       U(got).m[2][0],U(got).m[2][1],U(got).m[2][2],U(got).m[2][3],
+       U(got).m[3][0],U(got).m[3][1],U(got).m[3][2],U(got).m[3][3],
+       U(exp).m[0][0],U(exp).m[0][1],U(exp).m[0][2],U(exp).m[0][3],
+       U(exp).m[1][0],U(exp).m[1][1],U(exp).m[1][2],U(exp).m[1][3],
+       U(exp).m[2][0],U(exp).m[2][1],U(exp).m[2][2],U(exp).m[2][3],
+       U(exp).m[3][0],U(exp).m[3][1],U(exp).m[3][2],U(exp).m[3][3]);
+}
+
+static void test_ID3DXBuffer(void)
+{
+    ID3DXBuffer *buffer;
+    HRESULT hr;
+    ULONG count;
+    DWORD size;
+
+    hr = D3DXCreateBuffer(10, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateBuffer failed, got %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateBuffer(0, &buffer);
+    ok(hr == D3D_OK, "D3DXCreateBuffer failed, got %#x, expected %#x\n", hr, D3D_OK);
+
+    size = ID3DXBuffer_GetBufferSize(buffer);
+    ok(!size, "GetBufferSize failed, got %u, expected %u\n", size, 0);
+
+    count = ID3DXBuffer_Release(buffer);
+    ok(!count, "ID3DXBuffer has %u references left\n", count);
+
+    hr = D3DXCreateBuffer(3, &buffer);
+    ok(hr == D3D_OK, "D3DXCreateBuffer failed, got %#x, expected %#x\n", hr, D3D_OK);
+
+    size = ID3DXBuffer_GetBufferSize(buffer);
+    ok(size == 3, "GetBufferSize failed, got %u, expected %u\n", size, 3);
+
+    count = ID3DXBuffer_Release(buffer);
+    ok(!count, "ID3DXBuffer has %u references left\n", count);
+}
+
+static void test_ID3DXSprite(IDirect3DDevice9 *device)
+{
+    ID3DXSprite *sprite;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *cmpdev;
+    IDirect3DTexture9 *tex1, *tex2;
+    D3DXMATRIX mat, cmpmat;
+    D3DVIEWPORT9 vp;
+    RECT rect;
+    D3DXVECTOR3 pos, center;
+    HRESULT hr;
+
+    IDirect3DDevice9_GetDirect3D(device, &d3d);
+    hr = IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8);
+    IDirect3D9_Release(d3d);
+    ok (hr == D3D_OK, "D3DFMT_A8R8G8B8 not supported\n");
+    if (FAILED(hr)) return;
+
+    hr = IDirect3DDevice9_CreateTexture(device, 64, 64, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tex1, NULL);
+    ok (hr == D3D_OK, "Failed to create first texture (error code: %#x)\n", hr);
+    if (FAILED(hr)) return;
+
+    hr = IDirect3DDevice9_CreateTexture(device, 32, 32, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tex2, NULL);
+    ok (hr == D3D_OK, "Failed to create second texture (error code: %#x)\n", hr);
+    if (FAILED(hr)) {
+        IDirect3DTexture9_Release(tex1);
+        return;
+    }
+
+    /* Test D3DXCreateSprite */
+    hr = D3DXCreateSprite(device, NULL);
+    ok (hr == D3DERR_INVALIDCALL, "D3DXCreateSprite returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateSprite(NULL, &sprite);
+    ok (hr == D3DERR_INVALIDCALL, "D3DXCreateSprite returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateSprite(device, &sprite);
+    ok (hr == D3D_OK, "D3DXCreateSprite returned %#x, expected %#x\n", hr, D3D_OK);
+
+
+    /* Test ID3DXSprite_GetDevice */
+    hr = ID3DXSprite_GetDevice(sprite, NULL);
+    ok (hr == D3DERR_INVALIDCALL, "GetDevice returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = ID3DXSprite_GetDevice(sprite, &cmpdev);  /* cmpdev == NULL */
+    ok (hr == D3D_OK, "GetDevice returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = ID3DXSprite_GetDevice(sprite, &cmpdev);  /* cmpdev != NULL */
+    ok (hr == D3D_OK, "GetDevice returned %#x, expected %#x\n", hr, D3D_OK);
+
+    IDirect3DDevice9_Release(device);
+    IDirect3DDevice9_Release(device);
+
+
+    /* Test ID3DXSprite_GetTransform */
+    hr = ID3DXSprite_GetTransform(sprite, NULL);
+    ok (hr == D3DERR_INVALIDCALL, "GetTransform returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    hr = ID3DXSprite_GetTransform(sprite, &mat);
+    ok (hr == D3D_OK, "GetTransform returned %#x, expected %#x\n", hr, D3D_OK);
+    if(SUCCEEDED(hr)) {
+        D3DXMATRIX identity;
+        D3DXMatrixIdentity(&identity);
+        check_mat(mat, identity);
+    }
+
+    /* Test ID3DXSprite_SetTransform */
+    /* Set a transform and test if it gets returned correctly */
+    U(mat).m[0][0]=2.1f;  U(mat).m[0][1]=6.5f;  U(mat).m[0][2]=-9.6f; U(mat).m[0][3]=1.7f;
+    U(mat).m[1][0]=4.2f;  U(mat).m[1][1]=-2.5f; U(mat).m[1][2]=2.1f;  U(mat).m[1][3]=5.5f;
+    U(mat).m[2][0]=-2.6f; U(mat).m[2][1]=0.3f;  U(mat).m[2][2]=8.6f;  U(mat).m[2][3]=8.4f;
+    U(mat).m[3][0]=6.7f;  U(mat).m[3][1]=-5.1f; U(mat).m[3][2]=6.1f;  U(mat).m[3][3]=2.2f;
+
+    hr = ID3DXSprite_SetTransform(sprite, NULL);
+    ok (hr == D3DERR_INVALIDCALL, "SetTransform returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = ID3DXSprite_SetTransform(sprite, &mat);
+    ok (hr == D3D_OK, "SetTransform returned %#x, expected %#x\n", hr, D3D_OK);
+    if(SUCCEEDED(hr)) {
+        hr=ID3DXSprite_GetTransform(sprite, &cmpmat);
+        if(SUCCEEDED(hr)) check_mat(cmpmat, mat);
+        else skip("GetTransform returned %#x\n", hr);
+    }
+
+    /* Test ID3DXSprite_SetWorldViewLH/RH */
+    todo_wine {
+        hr = ID3DXSprite_SetWorldViewLH(sprite, &mat, &mat);
+        ok (hr == D3D_OK, "SetWorldViewLH returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_SetWorldViewLH(sprite, NULL, &mat);
+        ok (hr == D3D_OK, "SetWorldViewLH returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_SetWorldViewLH(sprite, &mat, NULL);
+        ok (hr == D3D_OK, "SetWorldViewLH returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_SetWorldViewLH(sprite, NULL, NULL);
+        ok (hr == D3D_OK, "SetWorldViewLH returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = ID3DXSprite_SetWorldViewRH(sprite, &mat, &mat);
+        ok (hr == D3D_OK, "SetWorldViewRH returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_SetWorldViewRH(sprite, NULL, &mat);
+        ok (hr == D3D_OK, "SetWorldViewRH returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_SetWorldViewRH(sprite, &mat, NULL);
+        ok (hr == D3D_OK, "SetWorldViewRH returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_SetWorldViewRH(sprite, NULL, NULL);
+        ok (hr == D3D_OK, "SetWorldViewRH returned %#x, expected %#x\n", hr, D3D_OK);
+    }
+    IDirect3DDevice9_BeginScene(device);
+
+    /* Test ID3DXSprite_Begin*/
+    hr = ID3DXSprite_Begin(sprite, 0);
+    ok (hr == D3D_OK, "Begin returned %#x, expected %#x\n", hr, D3D_OK);
+
+    IDirect3DDevice9_GetTransform(device, D3DTS_WORLD, &mat);
+    D3DXMatrixIdentity(&cmpmat);
+    check_mat(mat, cmpmat);
+
+    IDirect3DDevice9_GetTransform(device, D3DTS_VIEW, &mat);
+    check_mat(mat, cmpmat);
+
+    IDirect3DDevice9_GetTransform(device, D3DTS_PROJECTION, &mat);
+    IDirect3DDevice9_GetViewport(device, &vp);
+    D3DXMatrixOrthoOffCenterLH(&cmpmat, vp.X+0.5f, (float)vp.Width+vp.X+0.5f, (float)vp.Height+vp.Y+0.5f, vp.Y+0.5f, vp.MinZ, vp.MaxZ);
+    check_mat(mat, cmpmat);
+
+    /* Test ID3DXSprite_Flush and ID3DXSprite_End */
+    hr = ID3DXSprite_Flush(sprite);
+    ok (hr == D3D_OK, "Flush returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = ID3DXSprite_End(sprite);
+    ok (hr == D3D_OK, "End returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = ID3DXSprite_Flush(sprite); /* May not be called before next Begin */
+    ok (hr == D3DERR_INVALIDCALL, "Flush returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    hr = ID3DXSprite_End(sprite);
+    ok (hr == D3DERR_INVALIDCALL, "End returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    /* Test ID3DXSprite_Draw */
+    hr = ID3DXSprite_Begin(sprite, 0);
+    ok (hr == D3D_OK, "Begin returned %#x, expected %#x\n", hr, D3D_OK);
+
+    if(FAILED(hr)) skip("Couldn't ID3DXSprite_Begin, can't test ID3DXSprite_Draw\n");
+    else { /* Feed the sprite batch */
+        int texref1, texref2;
+
+        SetRect(&rect, 53, 12, 142, 165);
+        pos.x    =  2.2f; pos.y    = 4.5f; pos.z    = 5.1f;
+        center.x = 11.3f; center.y = 3.4f; center.z = 1.2f;
+
+        texref1 = get_ref((IUnknown*)tex1);
+        texref2 = get_ref((IUnknown*)tex2);
+
+        hr = ID3DXSprite_Draw(sprite, NULL, &rect, &center, &pos, D3DCOLOR_XRGB(255, 255, 255));
+        ok (hr == D3DERR_INVALIDCALL, "Draw returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = ID3DXSprite_Draw(sprite, tex1, &rect, &center, &pos, D3DCOLOR_XRGB(255, 255, 255));
+        ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_Draw(sprite, tex2, &rect, &center, &pos, D3DCOLOR_XRGB(  3,  45,  66));
+        ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_Draw(sprite, tex1,  NULL, &center, &pos, D3DCOLOR_XRGB(255, 255, 255));
+        ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_Draw(sprite, tex1, &rect,    NULL, &pos, D3DCOLOR_XRGB(255, 255, 255));
+        ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_Draw(sprite, tex1, &rect, &center, NULL, D3DCOLOR_XRGB(255, 255, 255));
+        ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_Draw(sprite, tex1,  NULL,    NULL, NULL,                            0);
+        ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
+
+        check_ref((IUnknown*)tex1, texref1+5); check_ref((IUnknown*)tex2, texref2+1);
+        hr = ID3DXSprite_Flush(sprite);
+        ok (hr == D3D_OK, "Flush returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXSprite_Flush(sprite);   /* Flushing twice should work */
+        ok (hr == D3D_OK, "Flush returned %#x, expected %#x\n", hr, D3D_OK);
+        check_ref((IUnknown*)tex1, texref1);   check_ref((IUnknown*)tex2, texref2);
+
+        hr = ID3DXSprite_End(sprite);
+        ok (hr == D3D_OK, "End returned %#x, expected %#x\n", hr, D3D_OK);
+    }
+
+    /* Test ID3DXSprite_OnLostDevice and ID3DXSprite_OnResetDevice */
+    /* Both can be called twice */
+    hr = ID3DXSprite_OnLostDevice(sprite);
+    ok (hr == D3D_OK, "OnLostDevice returned %#x, expected %#x\n", hr, D3D_OK);
+    hr = ID3DXSprite_OnLostDevice(sprite);
+    ok (hr == D3D_OK, "OnLostDevice returned %#x, expected %#x\n", hr, D3D_OK);
+    hr = ID3DXSprite_OnResetDevice(sprite);
+    ok (hr == D3D_OK, "OnResetDevice returned %#x, expected %#x\n", hr, D3D_OK);
+    hr = ID3DXSprite_OnResetDevice(sprite);
+    ok (hr == D3D_OK, "OnResetDevice returned %#x, expected %#x\n", hr, D3D_OK);
+
+    /* Make sure everything works like before */
+    hr = ID3DXSprite_Begin(sprite, 0);
+    ok (hr == D3D_OK, "Begin returned %#x, expected %#x\n", hr, D3D_OK);
+    hr = ID3DXSprite_Draw(sprite, tex2, &rect, &center, &pos, D3DCOLOR_XRGB(255, 255, 255));
+    ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
+    hr = ID3DXSprite_Flush(sprite);
+    ok (hr == D3D_OK, "Flush returned %#x, expected %#x\n", hr, D3D_OK);
+    hr = ID3DXSprite_End(sprite);
+    ok (hr == D3D_OK, "End returned %#x, expected %#x\n", hr, D3D_OK);
+
+    /* OnResetDevice makes the interface "forget" the Begin call */
+    hr = ID3DXSprite_Begin(sprite, 0);
+    ok (hr == D3D_OK, "Begin returned %#x, expected %#x\n", hr, D3D_OK);
+    hr = ID3DXSprite_OnResetDevice(sprite);
+    ok (hr == D3D_OK, "OnResetDevice returned %#x, expected %#x\n", hr, D3D_OK);
+    hr = ID3DXSprite_End(sprite);
+    ok (hr == D3DERR_INVALIDCALL, "End returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    IDirect3DDevice9_EndScene(device);
+    check_release((IUnknown*)sprite, 0);
+    check_release((IUnknown*)tex2, 0);
+    check_release((IUnknown*)tex1, 0);
+}
+
+static void test_ID3DXFont(IDirect3DDevice9 *device)
+{
+    static const WCHAR testW[] = {'t','e','s','t',0};
+    static const struct
+    {
+        int font_height;
+        unsigned int expected_size;
+        unsigned int expected_levels;
+    }
+    tests[] =
+    {
+        {  6, 128, 4 },
+        {  8, 128, 4 },
+        { 10, 256, 5 },
+        { 12, 256, 5 },
+        { 72, 256, 8 },
+    };
+    const unsigned int size = ARRAY_SIZE(testW);
+    D3DXFONT_DESCA desc;
+    ID3DXSprite *sprite;
+    int ref, i, height;
+    ID3DXFont *font;
+    HRESULT hr;
+    RECT rect;
+
+    /* D3DXCreateFont */
+    ref = get_ref((IUnknown*)device);
+    hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
+    ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK);
+    check_ref((IUnknown*)device, ref + 1);
+    check_release((IUnknown*)font, 0);
+    check_ref((IUnknown*)device, ref);
+
+    hr = D3DXCreateFontA(device, 0, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
+    ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK);
+    ID3DXFont_Release(font);
+
+    hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, NULL, &font);
+    ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK);
+    ID3DXFont_Release(font);
+
+    hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "", &font);
+    ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK);
+    ID3DXFont_Release(font);
+
+    hr = D3DXCreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+
+    /* D3DXCreateFontIndirect */
+    desc.Height = 12;
+    desc.Width = 0;
+    desc.Weight = FW_DONTCARE;
+    desc.MipLevels = 0;
+    desc.Italic = FALSE;
+    desc.CharSet = DEFAULT_CHARSET;
+    desc.OutputPrecision = OUT_DEFAULT_PRECIS;
+    desc.Quality = DEFAULT_QUALITY;
+    desc.PitchAndFamily = DEFAULT_PITCH;
+    strcpy(desc.FaceName, "Arial");
+    hr = D3DXCreateFontIndirectA(device, &desc, &font);
+    ok(hr == D3D_OK, "D3DXCreateFontIndirect returned %#x, expected %#x\n", hr, D3D_OK);
+    ID3DXFont_Release(font);
+
+    hr = D3DXCreateFontIndirectA(NULL, &desc, &font);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFontIndirect returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateFontIndirectA(device, NULL, &font);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFontIndirect returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateFontIndirectA(device, &desc, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFontIndirect returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+
+    /* ID3DXFont_GetDevice */
+    hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
+    if(SUCCEEDED(hr)) {
+        IDirect3DDevice9 *bufdev;
+
+        hr = ID3DXFont_GetDevice(font, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_GetDevice returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        ref = get_ref((IUnknown*)device);
+        hr = ID3DXFont_GetDevice(font, &bufdev);
+        ok(hr == D3D_OK, "ID3DXFont_GetDevice returned %#x, expected %#x\n", hr, D3D_OK);
+        check_release((IUnknown*)bufdev, ref);
+
+        ID3DXFont_Release(font);
+    } else skip("Failed to create a ID3DXFont object\n");
+
+
+    /* ID3DXFont_GetDesc */
+    hr = D3DXCreateFontA(device, 12, 8, FW_BOLD, 2, TRUE, ANSI_CHARSET, OUT_RASTER_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, "Arial", &font);
+    if(SUCCEEDED(hr)) {
+        hr = ID3DXFont_GetDescA(font, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_GetDevice returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = ID3DXFont_GetDescA(font, &desc);
+        ok(hr == D3D_OK, "ID3DXFont_GetDevice returned %#x, expected %#x\n", hr, D3D_OK);
+
+        ok(desc.Height == 12, "ID3DXFont_GetDesc returned font height %d, expected %d\n", desc.Height, 12);
+        ok(desc.Width == 8, "ID3DXFont_GetDesc returned font width %d, expected %d\n", desc.Width, 8);
+        ok(desc.Weight == FW_BOLD, "ID3DXFont_GetDesc returned font weight %d, expected %d\n", desc.Weight, FW_BOLD);
+        ok(desc.MipLevels == 2, "ID3DXFont_GetDesc returned font miplevels %d, expected %d\n", desc.MipLevels, 2);
+        ok(desc.Italic == TRUE, "ID3DXFont_GetDesc says Italic was %d, but Italic should be %d\n", desc.Italic, TRUE);
+        ok(desc.CharSet == ANSI_CHARSET, "ID3DXFont_GetDesc returned font charset %d, expected %d\n", desc.CharSet, ANSI_CHARSET);
+        ok(desc.OutputPrecision == OUT_RASTER_PRECIS, "ID3DXFont_GetDesc returned an output precision of %d, expected %d\n", desc.OutputPrecision, OUT_RASTER_PRECIS);
+        ok(desc.Quality == ANTIALIASED_QUALITY, "ID3DXFont_GetDesc returned font quality %d, expected %d\n", desc.Quality, ANTIALIASED_QUALITY);
+        ok(desc.PitchAndFamily == VARIABLE_PITCH, "ID3DXFont_GetDesc returned pitch and family %d, expected %d\n", desc.PitchAndFamily, VARIABLE_PITCH);
+        ok(strcmp(desc.FaceName, "Arial") == 0, "ID3DXFont_GetDesc returned facename \"%s\", expected \"%s\"\n", desc.FaceName, "Arial");
+
+        ID3DXFont_Release(font);
+    } else skip("Failed to create a ID3DXFont object\n");
+
+
+    /* ID3DXFont_GetDC + ID3DXFont_GetTextMetrics */
+    hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
+    if(SUCCEEDED(hr)) {
+        HDC hdc;
+
+        hdc = ID3DXFont_GetDC(font);
+        ok(hdc != NULL, "ID3DXFont_GetDC returned an invalid handle\n");
+        if(hdc) {
+            TEXTMETRICA metrics, expmetrics;
+            BOOL ret;
+
+            ret = ID3DXFont_GetTextMetricsA(font, &metrics);
+            ok(ret, "ID3DXFont_GetTextMetricsA failed\n");
+            ret = GetTextMetricsA(hdc, &expmetrics);
+            ok(ret, "GetTextMetricsA failed\n");
+
+            ok(metrics.tmHeight == expmetrics.tmHeight, "Returned height %d, expected %d\n", metrics.tmHeight, expmetrics.tmHeight);
+            ok(metrics.tmAscent == expmetrics.tmAscent, "Returned ascent %d, expected %d\n", metrics.tmAscent, expmetrics.tmAscent);
+            ok(metrics.tmDescent == expmetrics.tmDescent, "Returned descent %d, expected %d\n", metrics.tmDescent, expmetrics.tmDescent);
+            ok(metrics.tmInternalLeading == expmetrics.tmInternalLeading, "Returned internal leading %d, expected %d\n", metrics.tmInternalLeading, expmetrics.tmInternalLeading);
+            ok(metrics.tmExternalLeading == expmetrics.tmExternalLeading, "Returned external leading %d, expected %d\n", metrics.tmExternalLeading, expmetrics.tmExternalLeading);
+            ok(metrics.tmAveCharWidth == expmetrics.tmAveCharWidth, "Returned average char width %d, expected %d\n", metrics.tmAveCharWidth, expmetrics.tmAveCharWidth);
+            ok(metrics.tmMaxCharWidth == expmetrics.tmMaxCharWidth, "Returned maximum char width %d, expected %d\n", metrics.tmMaxCharWidth, expmetrics.tmMaxCharWidth);
+            ok(metrics.tmWeight == expmetrics.tmWeight, "Returned weight %d, expected %d\n", metrics.tmWeight, expmetrics.tmWeight);
+            ok(metrics.tmOverhang == expmetrics.tmOverhang, "Returned overhang %d, expected %d\n", metrics.tmOverhang, expmetrics.tmOverhang);
+            ok(metrics.tmDigitizedAspectX == expmetrics.tmDigitizedAspectX, "Returned digitized x aspect %d, expected %d\n", metrics.tmDigitizedAspectX, expmetrics.tmDigitizedAspectX);
+            ok(metrics.tmDigitizedAspectY == expmetrics.tmDigitizedAspectY, "Returned digitized y aspect %d, expected %d\n", metrics.tmDigitizedAspectY, expmetrics.tmDigitizedAspectY);
+            ok(metrics.tmFirstChar == expmetrics.tmFirstChar, "Returned first char %d, expected %d\n", metrics.tmFirstChar, expmetrics.tmFirstChar);
+            ok(metrics.tmLastChar == expmetrics.tmLastChar, "Returned last char %d, expected %d\n", metrics.tmLastChar, expmetrics.tmLastChar);
+            ok(metrics.tmDefaultChar == expmetrics.tmDefaultChar, "Returned default char %d, expected %d\n", metrics.tmDefaultChar, expmetrics.tmDefaultChar);
+            ok(metrics.tmBreakChar == expmetrics.tmBreakChar, "Returned break char %d, expected %d\n", metrics.tmBreakChar, expmetrics.tmBreakChar);
+            ok(metrics.tmItalic == expmetrics.tmItalic, "Returned italic %d, expected %d\n", metrics.tmItalic, expmetrics.tmItalic);
+            ok(metrics.tmUnderlined == expmetrics.tmUnderlined, "Returned underlined %d, expected %d\n", metrics.tmUnderlined, expmetrics.tmUnderlined);
+            ok(metrics.tmStruckOut == expmetrics.tmStruckOut, "Returned struck out %d, expected %d\n", metrics.tmStruckOut, expmetrics.tmStruckOut);
+            ok(metrics.tmPitchAndFamily == expmetrics.tmPitchAndFamily, "Returned pitch and family %d, expected %d\n", metrics.tmPitchAndFamily, expmetrics.tmPitchAndFamily);
+            ok(metrics.tmCharSet == expmetrics.tmCharSet, "Returned charset %d, expected %d\n", metrics.tmCharSet, expmetrics.tmCharSet);
+        }
+        ID3DXFont_Release(font);
+    } else skip("Failed to create a ID3DXFont object\n");
+
+
+    /* ID3DXFont_PreloadText */
+    hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
+    if(SUCCEEDED(hr)) {
+        todo_wine {
+        hr = ID3DXFont_PreloadTextA(font, NULL, -1);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+        hr = ID3DXFont_PreloadTextA(font, NULL, 0);
+        ok(hr == D3D_OK, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXFont_PreloadTextA(font, NULL, 1);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+        hr = ID3DXFont_PreloadTextA(font, "test", -1);
+        ok(hr == D3D_OK, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = ID3DXFont_PreloadTextW(font, NULL, -1);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+        hr = ID3DXFont_PreloadTextW(font, NULL, 0);
+        ok(hr == D3D_OK, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXFont_PreloadTextW(font, NULL, 1);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+        hr = ID3DXFont_PreloadTextW(font, testW, -1);
+        ok(hr == D3D_OK, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3D_OK);
+        }
+
+        check_release((IUnknown*)font, 0);
+    } else skip("Failed to create a ID3DXFont object\n");
+
+
+    /* ID3DXFont_GetGlyphData, ID3DXFont_PreloadGlyphs, ID3DXFont_PreloadCharacters */
+    hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
+    if(SUCCEEDED(hr)) {
+        char c;
+        HDC hdc;
+        DWORD ret;
+        HRESULT hr;
+        RECT blackbox;
+        POINT cellinc;
+        IDirect3DTexture9 *texture;
+
+        hdc = ID3DXFont_GetDC(font);
+
+        todo_wine {
+        hr = ID3DXFont_GetGlyphData(font, 0, NULL, &blackbox, &cellinc);
+        ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXFont_GetGlyphData(font, 0, &texture, NULL, &cellinc);
+        if(SUCCEEDED(hr)) check_release((IUnknown*)texture, 1);
+        ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXFont_GetGlyphData(font, 0, &texture, &blackbox, NULL);
+        if(SUCCEEDED(hr)) check_release((IUnknown*)texture, 1);
+        ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK);
+        }
+        hr = ID3DXFont_PreloadCharacters(font, 'b', 'a');
+        ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXFont_PreloadGlyphs(font, 1, 0);
+        todo_wine ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = ID3DXFont_PreloadCharacters(font, 'a', 'a');
+        ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK);
+
+        for(c = 'b'; c <= 'z'; c++) {
+            WORD glyph;
+
+            ret = GetGlyphIndicesA(hdc, &c, 1, &glyph, 0);
+            ok(ret != GDI_ERROR, "GetGlyphIndicesA failed\n");
+
+            hr = ID3DXFont_GetGlyphData(font, glyph, &texture, &blackbox, &cellinc);
+            todo_wine ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK);
+            if(SUCCEEDED(hr)) {
+                DWORD levels;
+                D3DSURFACE_DESC desc;
+
+                levels = IDirect3DTexture9_GetLevelCount(texture);
+                ok(levels == 5, "Got levels %u, expected %u\n", levels, 5);
+                hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
+                ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc failed\n");
+                ok(desc.Format == D3DFMT_A8R8G8B8, "Got format %#x, expected %#x\n", desc.Format, D3DFMT_A8R8G8B8);
+                ok(desc.Usage == 0, "Got usage %#x, expected %#x\n", desc.Usage, 0);
+                ok(desc.Width == 256, "Got width %u, expected %u\n", desc.Width, 256);
+                ok(desc.Height == 256, "Got height %u, expected %u\n", desc.Height, 256);
+                ok(desc.Pool == D3DPOOL_MANAGED, "Got pool %u, expected %u\n", desc.Pool, D3DPOOL_MANAGED);
+
+                check_release((IUnknown*)texture, 1);
+            }
+        }
+
+        hr = ID3DXFont_PreloadCharacters(font, 'a', 'z');
+        ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK);
+
+        check_release((IUnknown*)font, 0);
+    } else skip("Failed to create a ID3DXFont object\n");
+
+    for (i = 0; i < ARRAY_SIZE(tests); ++i)
+    {
+        HDC hdc;
+        DWORD ret;
+        HRESULT hr;
+        WORD glyph;
+        char c = 'a';
+        IDirect3DTexture9 *texture;
+
+        hr = D3DXCreateFontA(device, tests[i].font_height, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET,
+                OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
+        if(FAILED(hr)) {
+            skip("Failed to create a ID3DXFont object\n");
+            continue;
+        }
+
+        hdc = ID3DXFont_GetDC(font);
+
+        ret = GetGlyphIndicesA(hdc, &c, 1, &glyph, 0);
+        ok(ret != GDI_ERROR, "GetGlyphIndicesA failed\n");
+
+        hr = ID3DXFont_GetGlyphData(font, glyph, &texture, NULL, NULL);
+        todo_wine ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK);
+        if(SUCCEEDED(hr)) {
+            DWORD levels;
+            D3DSURFACE_DESC desc;
+
+            levels = IDirect3DTexture9_GetLevelCount(texture);
+            ok(levels == tests[i].expected_levels, "Got levels %u, expected %u\n",
+                    levels, tests[i].expected_levels);
+            hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
+            ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc failed\n");
+            ok(desc.Format == D3DFMT_A8R8G8B8, "Got format %#x, expected %#x\n", desc.Format, D3DFMT_A8R8G8B8);
+            ok(desc.Usage == 0, "Got usage %#x, expected %#x\n", desc.Usage, 0);
+            ok(desc.Width == tests[i].expected_size, "Got width %u, expected %u\n",
+                    desc.Width, tests[i].expected_size);
+            ok(desc.Height == tests[i].expected_size, "Got height %u, expected %u\n",
+                    desc.Height, tests[i].expected_size);
+            ok(desc.Pool == D3DPOOL_MANAGED, "Got pool %u, expected %u\n", desc.Pool, D3DPOOL_MANAGED);
+
+            IDirect3DTexture9_Release(texture);
+        }
+
+        /* ID3DXFontImpl_DrawText */
+        D3DXCreateSprite(device, &sprite);
+        SetRect(&rect, 0, 0, 640, 480);
+
+        IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff000000, 1.0f, 0);
+
+        IDirect3DDevice9_BeginScene(device);
+        hr = ID3DXSprite_Begin(sprite, D3DXSPRITE_ALPHABLEND);
+        ok (hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+        todo_wine
+        {
+        height = ID3DXFont_DrawTextW(font, sprite, testW, -1, &rect, DT_TOP, 0xffffffff);
+        ok(height == tests[i].font_height, "Got unexpected height %u.\n", height);
+        height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_TOP, 0xffffffff);
+        ok(height == tests[i].font_height, "Got unexpected height %u.\n", height);
+        height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_RIGHT, 0xffffffff);
+        ok(height == tests[i].font_height, "Got unexpected height %u.\n", height);
+        height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_LEFT | DT_NOCLIP,
+                0xffffffff);
+        ok(height == tests[i].font_height, "Got unexpected height %u.\n", height);
+        }
+
+        SetRectEmpty(&rect);
+        height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect,
+                DT_LEFT | DT_CALCRECT, 0xffffffff);
+        todo_wine ok(height == tests[i].font_height, "Got unexpected height %u.\n", height);
+        ok(!rect.left, "Got unexpected rect left %d.\n", rect.left);
+        ok(!rect.top, "Got unexpected rect top %d.\n", rect.top);
+        todo_wine ok(rect.right, "Got unexpected rect right %d.\n", rect.right);
+        todo_wine ok(rect.bottom == tests[i].font_height, "Got unexpected rect bottom %d.\n", rect.bottom);
+
+        hr = ID3DXSprite_End(sprite);
+        ok (hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+        IDirect3DDevice9_EndScene(device);
+        ID3DXSprite_Release(sprite);
+
+        ID3DXFont_Release(font);
+    }
+}
+
+static void test_D3DXCreateRenderToSurface(IDirect3DDevice9 *device)
+{
+    int i;
+    HRESULT hr;
+    ULONG ref_count;
+    D3DXRTS_DESC desc;
+    ID3DXRenderToSurface *render = (void *)0xdeadbeef;
+    static const D3DXRTS_DESC tests[] =
+    {
+        { 0, 256, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN },
+        { 256, 0, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN },
+        { 256, 0, D3DFMT_A8R8G8B8, FALSE, D3DFMT_D24S8 },
+        { 256, 256, D3DFMT_UNKNOWN, FALSE, D3DFMT_R8G8B8 },
+        { 0, 0, D3DFMT_UNKNOWN, FALSE, D3DFMT_UNKNOWN },
+        { -1, -1, MAKEFOURCC('B','A','D','F'), TRUE, MAKEFOURCC('B','A','D','F') }
+    };
+
+    hr = D3DXCreateRenderToSurface(NULL /* device */, 256, 256, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN, &render);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateRenderToSurface returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    ok(render == (void *)0xdeadbeef, "Got %p, expected %p\n", render, (void *)0xdeadbeef);
+
+    hr = D3DXCreateRenderToSurface(device, 256, 256, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN, NULL /* out */);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateRenderToSurface returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    for (i = 0; i < ARRAY_SIZE(tests); i++)
+    {
+        hr = D3DXCreateRenderToSurface(device, tests[i].Width, tests[i].Height, tests[i].Format, tests[i].DepthStencil,
+                tests[i].DepthStencilFormat, &render);
+        ok(hr == D3D_OK, "%d: D3DXCreateRenderToSurface returned %#x, expected %#x\n", i, hr, D3D_OK);
+        if (SUCCEEDED(hr))
+        {
+            hr = ID3DXRenderToSurface_GetDesc(render, &desc);
+            ok(hr == D3D_OK, "%d: GetDesc failed %#x\n", i, hr);
+            if (SUCCEEDED(hr))
+            {
+                ok(desc.Width == tests[i].Width, "%d: Got width %u, expected %u\n", i, desc.Width, tests[i].Width);
+                ok(desc.Height == tests[i].Height, "%d: Got height %u, expected %u\n", i, desc.Height, tests[i].Height);
+                ok(desc.Format == tests[i].Format, "%d: Got format %#x, expected %#x\n", i, desc.Format, tests[i].Format);
+                ok(desc.DepthStencil == tests[i].DepthStencil, "%d: Got depth stencil %d, expected %d\n",
+                        i, desc.DepthStencil, tests[i].DepthStencil);
+                ok(desc.DepthStencilFormat == tests[i].DepthStencilFormat, "%d: Got depth stencil format %#x, expected %#x\n",
+                        i, desc.DepthStencilFormat, tests[i].DepthStencilFormat);
+            }
+            ID3DXRenderToSurface_Release(render);
+        }
+    }
+
+    /* check device ref count */
+    ref_count = get_ref((IUnknown *)device);
+    hr = D3DXCreateRenderToSurface(device, 0, 0, D3DFMT_UNKNOWN, FALSE, D3DFMT_UNKNOWN, &render);
+    check_ref((IUnknown *)device, ref_count + 1);
+    if (SUCCEEDED(hr)) ID3DXRenderToSurface_Release(render);
+}
+
+/* runs a set of tests for the ID3DXRenderToSurface interface created with given parameters */
+static void check_ID3DXRenderToSurface(IDirect3DDevice9 *device, UINT width, UINT height, D3DFORMAT format,
+        BOOL depth_stencil, D3DFORMAT depth_stencil_format, BOOL render_target)
+{
+    HRESULT hr;
+    D3DFORMAT fmt;
+    HRESULT expected_value;
+    IDirect3DSurface9 *surface;
+    ID3DXRenderToSurface *render;
+    D3DVIEWPORT9 viewport = { 0, 0, width, height, 0.0, 1.0 };
+
+    hr = D3DXCreateRenderToSurface(device, width, height, format, depth_stencil, depth_stencil_format, &render);
+    if (FAILED(hr))
+    {
+        skip("Failed to create ID3DXRenderToSurface\n");
+        return;
+    }
+
+    if (render_target)
+        hr = IDirect3DDevice9_CreateRenderTarget(device, width, height, format, D3DMULTISAMPLE_NONE, 0, FALSE, &surface, NULL);
+    else
+        hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, width, height, format, D3DPOOL_DEFAULT, &surface, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create surface\n");
+        ID3DXRenderToSurface_Release(render);
+        return;
+    }
+
+    /* viewport */
+    hr = ID3DXRenderToSurface_BeginScene(render, surface, &viewport);
+    ok(hr == D3D_OK, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3D_OK);
+    check_ref((IUnknown *)surface, 2);
+    if (SUCCEEDED(hr)) ID3DXRenderToSurface_EndScene(render, D3DX_FILTER_NONE);
+
+    /* invalid viewport */
+    viewport.Width = 2 * width;
+    hr = ID3DXRenderToSurface_BeginScene(render, surface, &viewport);
+    ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    viewport.X = width / 2;
+    viewport.Width = width;
+    hr = ID3DXRenderToSurface_BeginScene(render, surface, &viewport);
+    ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    viewport.X = width;
+    viewport.Width = width;
+    hr = ID3DXRenderToSurface_BeginScene(render, surface, &viewport);
+    ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    /* rendering to a part of a surface is only allowed for render target surfaces */
+    expected_value = render_target ? D3D_OK : D3DERR_INVALIDCALL;
+
+    viewport.X = 0;
+    viewport.Width = width / 2;
+    hr = ID3DXRenderToSurface_BeginScene(render, surface, &viewport);
+    ok(hr == expected_value, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, expected_value);
+    if (SUCCEEDED(hr)) ID3DXRenderToSurface_EndScene(render, D3DX_FILTER_NONE);
+
+    viewport.X = width / 2;
+    viewport.Width = width - width / 2;
+    hr = ID3DXRenderToSurface_BeginScene(render, surface, &viewport);
+    ok(hr == expected_value, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, expected_value);
+    if (SUCCEEDED(hr)) ID3DXRenderToSurface_EndScene(render, D3DX_FILTER_NONE);
+
+    check_release((IUnknown *)surface, 0);
+
+    /* surfaces with different sizes */
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, width / 2, width / 2, format, D3DPOOL_DEFAULT, &surface, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create surface\n");
+        ID3DXRenderToSurface_Release(render);
+        return;
+    }
+    hr = ID3DXRenderToSurface_BeginScene(render, surface, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    check_release((IUnknown *)surface, 0);
+
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 2 * width, 2 * height, format, D3DPOOL_DEFAULT, &surface, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create surface\n");
+        ID3DXRenderToSurface_Release(render);
+        return;
+    }
+    hr = ID3DXRenderToSurface_BeginScene(render, surface, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    viewport.X = 0;
+    viewport.Y = 0;
+    viewport.Width = width;
+    viewport.Height = height;
+    hr = ID3DXRenderToSurface_BeginScene(render, surface, &viewport);
+    ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    check_release((IUnknown *)surface, 0);
+
+    /* surfaces with different formats */
+    for (fmt = D3DFMT_A8R8G8B8; fmt <= D3DFMT_X8R8G8B8; fmt++)
+    {
+        HRESULT expected_result = (fmt != format) ? D3DERR_INVALIDCALL : D3D_OK;
+
+        hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, width, height, fmt, D3DPOOL_DEFAULT, &surface, NULL);
+        if (FAILED(hr))
+        {
+            skip("Failed to create surface\n");
+            continue;
+        }
+
+        hr = ID3DXRenderToSurface_BeginScene(render, surface, NULL);
+        ok(hr == expected_result, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, expected_result);
+
+        if (SUCCEEDED(hr)) ID3DXRenderToSurface_EndScene(render, D3DX_FILTER_NONE);
+        check_release((IUnknown *)surface, 0);
+    }
+
+    check_release((IUnknown *)render, 0);
+}
+
+struct device_state
+{
+    IDirect3DSurface9 *render_target;
+    IDirect3DSurface9 *depth_stencil;
+    D3DVIEWPORT9 viewport;
+};
+
+static void release_device_state(struct device_state *state)
+{
+    if (state->render_target) IDirect3DSurface9_Release(state->render_target);
+    if (state->depth_stencil) IDirect3DSurface9_Release(state->depth_stencil);
+    memset(state, 0, sizeof(*state));
+}
+
+static HRESULT retrieve_device_state(IDirect3DDevice9 *device, struct device_state *state)
+{
+    HRESULT hr;
+
+    memset(state, 0, sizeof(*state));
+
+    hr = IDirect3DDevice9_GetRenderTarget(device, 0, &state->render_target);
+    if (FAILED(hr)) goto cleanup;
+
+    hr = IDirect3DDevice9_GetDepthStencilSurface(device, &state->depth_stencil);
+    if (hr == D3DERR_NOTFOUND)
+        state->depth_stencil = NULL;
+    else if (FAILED(hr))
+        goto cleanup;
+
+    hr = IDirect3DDevice9_GetViewport(device, &state->viewport);
+    if (SUCCEEDED(hr)) return hr;
+
+cleanup:
+    release_device_state(state);
+    return hr;
+}
+
+static HRESULT apply_device_state(IDirect3DDevice9 *device, struct device_state *state)
+{
+    HRESULT hr;
+    HRESULT status = D3D_OK;
+
+    hr = IDirect3DDevice9_SetRenderTarget(device, 0, state->render_target);
+    if (FAILED(hr)) status = hr;
+
+    hr = IDirect3DDevice9_SetDepthStencilSurface(device, state->depth_stencil);
+    if (FAILED(hr)) status = hr;
+
+    hr = IDirect3DDevice9_SetViewport(device, &state->viewport);
+    if (FAILED(hr)) status = hr;
+
+    return status;
+}
+
+static void compare_device_state(struct device_state *state1, struct device_state *state2, BOOL equal)
+{
+    BOOL cmp;
+    const char *message = equal ? "differs" : "is the same";
+
+    cmp = state1->render_target == state2->render_target;
+    ok(equal ? cmp : !cmp, "Render target %s %p, %p\n", message, state1->render_target, state2->render_target);
+
+    cmp = state1->depth_stencil == state2->depth_stencil;
+    ok(equal ? cmp : !cmp, "Depth stencil surface %s %p, %p\n", message, state1->depth_stencil, state2->depth_stencil);
+
+    cmp = state1->viewport.X == state2->viewport.X && state1->viewport.Y == state2->viewport.Y
+            && state1->viewport.Width == state2->viewport.Width && state1->viewport.Height == state2->viewport.Height;
+    ok(equal ? cmp : !cmp, "Viewport %s (%u, %u, %u, %u), (%u, %u, %u, %u)\n", message,
+            state1->viewport.X, state1->viewport.Y, state1->viewport.Width, state1->viewport.Height,
+            state2->viewport.X, state2->viewport.Y, state2->viewport.Width, state2->viewport.Height);
+}
+
+static void test_ID3DXRenderToSurface_device_state(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    IDirect3DSurface9 *surface = NULL;
+    ID3DXRenderToSurface *render = NULL;
+    struct device_state pre_state;
+    struct device_state current_state;
+    IDirect3DSurface9 *depth_stencil_surface;
+
+    /* make sure there is a depth stencil surface present */
+    hr = IDirect3DDevice9_GetDepthStencilSurface(device, &depth_stencil_surface);
+    if (SUCCEEDED(hr))
+    {
+        IDirect3DSurface9_Release(depth_stencil_surface);
+        depth_stencil_surface = NULL;
+    }
+    else if (hr == D3DERR_NOTFOUND)
+    {
+        hr = IDirect3DDevice9_CreateDepthStencilSurface(device, 256, 256, D3DFMT_D24X8,
+                D3DMULTISAMPLE_NONE, 0, TRUE, &depth_stencil_surface, NULL);
+        if (SUCCEEDED(hr)) IDirect3DDevice9_SetDepthStencilSurface(device, depth_stencil_surface);
+    }
+
+    if (FAILED(hr))
+    {
+        skip("Failed to create depth stencil surface\n");
+        return;
+    }
+
+    hr = IDirect3DDevice9_CreateRenderTarget(device, 256, 256, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0,
+        FALSE, &surface, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create render target\n");
+        goto cleanup;
+    }
+
+    hr = retrieve_device_state(device, &pre_state);
+    ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+
+    hr = D3DXCreateRenderToSurface(device, 256, 256, D3DFMT_A8R8G8B8, TRUE, D3DFMT_D24X8, &render);
+    ok(hr == D3D_OK, "D3DXCreateRenderToSurface returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        hr = ID3DXRenderToSurface_BeginScene(render, surface, NULL);
+        ok(hr == D3D_OK, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = retrieve_device_state(device, &current_state);
+        ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+        compare_device_state(&current_state, &pre_state, FALSE);
+        release_device_state(&current_state);
+
+        hr = ID3DXRenderToSurface_EndScene(render, D3DX_FILTER_NONE);
+        ok(hr == D3D_OK, "ID3DXRenderToSurface::EndScene returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = retrieve_device_state(device, &current_state);
+        ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+        compare_device_state(&current_state, &pre_state, TRUE);
+        release_device_state(&current_state);
+
+        check_release((IUnknown *)render, 0);
+    }
+
+    hr = D3DXCreateRenderToSurface(device, 256, 256, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN, &render);
+    if (SUCCEEDED(hr))
+    {
+        hr = ID3DXRenderToSurface_BeginScene(render, surface, NULL);
+        ok(hr == D3D_OK, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = retrieve_device_state(device, &current_state);
+        ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+        compare_device_state(&current_state, &pre_state, FALSE);
+        release_device_state(&current_state);
+
+        hr = ID3DXRenderToSurface_EndScene(render, D3DX_FILTER_NONE);
+        ok(hr == D3D_OK, "ID3DXRenderToSurface::EndScene returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = retrieve_device_state(device, &current_state);
+        ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+        compare_device_state(&current_state, &pre_state, TRUE);
+        release_device_state(&current_state);
+
+        hr = ID3DXRenderToSurface_BeginScene(render, surface, NULL);
+        ok(hr == D3D_OK, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = retrieve_device_state(device, &current_state);
+        ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+        compare_device_state(&current_state, &pre_state, FALSE);
+        release_device_state(&current_state);
+
+        check_release((IUnknown *)render, 0);
+
+        /* if EndScene isn't called, the device state isn't restored */
+        hr = retrieve_device_state(device, &current_state);
+        ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+        compare_device_state(&current_state, &pre_state, FALSE);
+        release_device_state(&current_state);
+
+        hr = apply_device_state(device, &pre_state);
+        ok(SUCCEEDED(hr), "Failed to restore previous device state\n");
+
+        IDirect3DDevice9_EndScene(device);
+    }
+
+    release_device_state(&pre_state);
+
+cleanup:
+    if (depth_stencil_surface)
+    {
+        IDirect3DDevice9_SetDepthStencilSurface(device, NULL);
+        IDirect3DSurface9_Release(depth_stencil_surface);
+    }
+
+    if (surface) check_release((IUnknown *)surface, 0);
+}
+
+static void test_ID3DXRenderToSurface(IDirect3DDevice9 *device)
+{
+    int i;
+    HRESULT hr;
+    ULONG ref_count;
+    IDirect3DDevice9 *out_device;
+    ID3DXRenderToSurface *render;
+    IDirect3DSurface9 *surface;
+    D3DVIEWPORT9 viewport = { 0, 0, 256, 256, 0.0, 1.0 };
+    D3DXRTS_DESC tests[] = {
+        { 256, 256, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN },
+        { 256, 256, D3DFMT_A8R8G8B8, TRUE, D3DFMT_D24S8 },
+        { 256, 256, D3DFMT_A8R8G8B8, TRUE, D3DFMT_D24X8 },
+        { 512, 512, D3DFMT_X8R8G8B8, FALSE, D3DFMT_X8R8G8B8 },
+        { 1024, 1024, D3DFMT_X8R8G8B8, TRUE, D3DFMT_D24S8 }
+    };
+
+    hr = D3DXCreateRenderToSurface(device, 256, 256, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN, &render);
+    ok(hr == D3D_OK, "D3DXCreateRenderToSurface returned %#x, expected %#x\n", hr, D3D_OK);
+    if (FAILED(hr)) return;
+
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 256, 256, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &surface, NULL);
+    if (SUCCEEDED(hr))
+    {
+        ID3DXRenderToSurface *render_surface;
+
+        /* GetDevice */
+        hr = ID3DXRenderToSurface_GetDevice(render, NULL /* device */);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::GetDevice returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        ref_count = get_ref((IUnknown *)device);
+        hr = ID3DXRenderToSurface_GetDevice(render, &out_device);
+        ok(hr == D3D_OK, "ID3DXRenderToSurface::GetDevice returned %#x, expected %#x\n", hr, D3D_OK);
+        check_release((IUnknown *)out_device, ref_count);
+
+        /* BeginScene and EndScene */
+        hr = ID3DXRenderToSurface_EndScene(render, D3DX_FILTER_NONE);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::EndScene returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = ID3DXRenderToSurface_BeginScene(render, NULL /* surface */, &viewport);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        ref_count = get_ref((IUnknown *)surface);
+        hr = ID3DXRenderToSurface_BeginScene(render, surface, NULL);
+        ok(hr == D3D_OK, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3D_OK);
+        if (SUCCEEDED(hr))
+        {
+            check_ref((IUnknown *)surface, ref_count + 1);
+
+            hr = ID3DXRenderToSurface_BeginScene(render, surface, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+            hr = ID3DXRenderToSurface_EndScene(render, D3DX_FILTER_NONE);
+            ok(hr == D3D_OK, "ID3DXRenderToSurface::EndScene returned %#x, expected %#x\n", hr, D3D_OK);
+
+            check_ref((IUnknown *)surface, ref_count);
+        }
+
+        /* error handling is deferred to BeginScene */
+        hr = D3DXCreateRenderToSurface(device, 256, 256, D3DFMT_A8R8G8B8, TRUE, D3DFMT_UNKNOWN, &render_surface);
+        ok(hr == D3D_OK, "D3DXCreateRenderToSurface returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = ID3DXRenderToSurface_BeginScene(render_surface, surface, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToSurface::BeginScene returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+        check_release((IUnknown *)render_surface, 0);
+
+        check_release((IUnknown *)surface, 0);
+    }
+    else skip("Failed to create surface\n");
+
+    check_release((IUnknown *)render, 0);
+
+    for (i = 0; i < ARRAY_SIZE(tests); i++)
+    {
+        check_ID3DXRenderToSurface(device, tests[i].Width, tests[i].Height, tests[i].Format, tests[i].DepthStencil, tests[i].DepthStencilFormat, TRUE);
+        check_ID3DXRenderToSurface(device, tests[i].Width, tests[i].Height, tests[i].Format, tests[i].DepthStencil, tests[i].DepthStencilFormat, FALSE);
+    }
+
+    test_ID3DXRenderToSurface_device_state(device);
+}
+
+static void test_D3DXCreateRenderToEnvMap(IDirect3DDevice9 *device)
+{
+    int i;
+    HRESULT hr;
+    ULONG ref_count;
+    D3DXRTE_DESC desc;
+    ID3DXRenderToEnvMap *render;
+    static const struct {
+        D3DXRTE_DESC parameters;
+        D3DXRTE_DESC expected_values;
+    } tests[] = {
+        { {   0,   0, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN }, {   1, 1, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN } },
+        { { 256,   0, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN }, { 256, 9, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN } },
+        { { 256,   4, D3DFMT_A8R8G8B8, FALSE, D3DFMT_D24S8   }, { 256, 4, D3DFMT_A8R8G8B8, FALSE, D3DFMT_D24S8   } },
+        { { 256, 256, D3DFMT_UNKNOWN,  FALSE, D3DFMT_R8G8B8  }, { 256, 9, D3DFMT_A8R8G8B8, FALSE, D3DFMT_R8G8B8  } },
+        { {  -1,  -1, D3DFMT_A8R8G8B8, TRUE,  D3DFMT_DXT1    }, { 256, 9, D3DFMT_A8R8G8B8, TRUE,  D3DFMT_DXT1    } },
+        { { 256,   1, D3DFMT_X8R8G8B8, TRUE,  D3DFMT_UNKNOWN }, { 256, 1, D3DFMT_X8R8G8B8, TRUE,  D3DFMT_UNKNOWN } }
+    };
+
+    for (i = 0; i < ARRAY_SIZE(tests); i++)
+    {
+        const D3DXRTE_DESC *parameters = &tests[i].parameters;
+        const D3DXRTE_DESC *expected  = &tests[i].expected_values;
+        hr = D3DXCreateRenderToEnvMap(device, parameters->Size, parameters->MipLevels, parameters->Format,
+                parameters->DepthStencil, parameters->DepthStencilFormat, &render);
+        ok(hr == D3D_OK, "%d: D3DXCreateRenderToEnvMap returned %#x, expected %#x\n", i, hr, D3D_OK);
+        if (SUCCEEDED(hr))
+        {
+            hr = ID3DXRenderToEnvMap_GetDesc(render, &desc);
+            ok(hr == D3D_OK, "%d: GetDesc failed %#x\n", i, hr);
+            if (SUCCEEDED(hr))
+            {
+                ok(desc.Size == expected->Size, "%d: Got size %u, expected %u\n", i, desc.Size, expected->Size);
+                ok(desc.MipLevels == expected->MipLevels, "%d: Got miplevels %u, expected %u\n", i, desc.MipLevels, expected->MipLevels);
+                ok(desc.Format == expected->Format, "%d: Got format %#x, expected %#x\n", i, desc.Format, expected->Format);
+                ok(desc.DepthStencil == expected->DepthStencil, "%d: Got depth stencil %d, expected %d\n",
+                        i, expected->DepthStencil, expected->DepthStencil);
+                ok(desc.DepthStencilFormat == expected->DepthStencilFormat, "%d: Got depth stencil format %#x, expected %#x\n",
+                        i, expected->DepthStencilFormat, expected->DepthStencilFormat);
+            }
+            check_release((IUnknown *)render, 0);
+        }
+    }
+
+    /* check device ref count */
+    ref_count = get_ref((IUnknown *)device);
+    hr = D3DXCreateRenderToEnvMap(device, 0, 0, D3DFMT_UNKNOWN, FALSE, D3DFMT_UNKNOWN, &render);
+    check_ref((IUnknown *)device, ref_count + 1);
+    if (SUCCEEDED(hr)) ID3DXRenderToEnvMap_Release(render);
+}
+
+static void test_ID3DXRenderToEnvMap_cube_map(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    IDirect3DCubeTexture9 *cube_texture = NULL;
+    ID3DXRenderToEnvMap *render = NULL;
+    struct device_state pre_state;
+    struct device_state current_state;
+
+    hr = IDirect3DDevice9_CreateCubeTexture(device, 256, 0, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
+        &cube_texture, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create cube texture\n");
+        return;
+    }
+
+    hr = retrieve_device_state(device, &pre_state);
+    ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+
+    hr = D3DXCreateRenderToEnvMap(device, 256, 0, D3DFMT_A8R8G8B8, TRUE, D3DFMT_D24X8, &render);
+    ok(hr == D3D_OK, "D3DCreateRenderToEnvMap returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        DWORD face;
+
+        hr = ID3DXRenderToEnvMap_End(render, D3DX_FILTER_NONE);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToEnvMap::End returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = ID3DXRenderToEnvMap_BeginCube(render, cube_texture);
+        ok(hr == D3D_OK, "ID3DXRenderToEnvMap::BeginCube returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = retrieve_device_state(device, &current_state);
+        ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+        compare_device_state(&current_state, &pre_state, TRUE);
+        release_device_state(&current_state);
+
+        for (face = D3DCUBEMAP_FACE_POSITIVE_X; face <= D3DCUBEMAP_FACE_NEGATIVE_Z; face++)
+        {
+            hr = ID3DXRenderToEnvMap_Face(render, face, D3DX_FILTER_POINT);
+            ok(hr == D3D_OK, "ID3DXRenderToEnvMap::Face returned %#x, expected %#x\n", hr, D3D_OK);
+
+            hr = retrieve_device_state(device, &current_state);
+            ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+            compare_device_state(&current_state, &pre_state, FALSE);
+            release_device_state(&current_state);
+        }
+
+        hr = ID3DXRenderToEnvMap_End(render, D3DX_FILTER_POINT);
+        ok(hr == D3D_OK, "ID3DXRenderToEnvMap::End returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = retrieve_device_state(device, &current_state);
+        ok(SUCCEEDED(hr), "Failed to retrieve device state\n");
+        compare_device_state(&current_state, &pre_state, TRUE);
+        release_device_state(&current_state);
+
+        check_release((IUnknown *)render, 0);
+    }
+
+    release_device_state(&pre_state);
+
+    check_release((IUnknown *)cube_texture, 0);
+}
+
+static void test_ID3DXRenderToEnvMap(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    ID3DXRenderToEnvMap *render;
+    IDirect3DSurface9 *depth_stencil_surface;
+
+    hr = D3DXCreateRenderToEnvMap(device, 256, 0, D3DFMT_A8R8G8B8, FALSE, D3DFMT_UNKNOWN, &render);
+    if (SUCCEEDED(hr))
+    {
+        ULONG ref_count;
+        IDirect3DDevice9 *out_device;
+
+        hr = ID3DXRenderToEnvMap_GetDesc(render, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToEnvMap::GetDesc returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = ID3DXRenderToEnvMap_GetDevice(render, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToEnvMap::GetDevice returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        ref_count = get_ref((IUnknown *)device);
+        hr = ID3DXRenderToEnvMap_GetDevice(render, &out_device);
+        ok(hr == D3D_OK, "ID3DXRenderToEnvMap::GetDevice returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(out_device == device, "ID3DXRenderToEnvMap::GetDevice returned different device\n");
+        check_release((IUnknown *)device, ref_count);
+
+        hr = ID3DXRenderToEnvMap_End(render, D3DX_FILTER_NONE);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToEnvMap::End returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = ID3DXRenderToEnvMap_BeginCube(render, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToEnvMap::BeginCube returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = ID3DXRenderToEnvMap_BeginHemisphere(render, NULL, NULL);
+        todo_wine ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToEnvMap::BeginHemisphere returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = ID3DXRenderToEnvMap_BeginParabolic(render, NULL, NULL);
+        todo_wine ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToEnvMap::BeginParabolic returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = ID3DXRenderToEnvMap_BeginSphere(render, NULL);
+        todo_wine ok(hr == D3DERR_INVALIDCALL, "ID3DXRenderToEnvMap::BeginSphere returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        check_release((IUnknown *)render, 0);
+    } else skip("Failed to create ID3DXRenderToEnvMap\n");
+
+    /* make sure there is a depth stencil surface present */
+    hr = IDirect3DDevice9_GetDepthStencilSurface(device, &depth_stencil_surface);
+    if (SUCCEEDED(hr))
+    {
+        IDirect3DSurface9_Release(depth_stencil_surface);
+        depth_stencil_surface = NULL;
+    }
+    else if (hr == D3DERR_NOTFOUND)
+    {
+        hr = IDirect3DDevice9_CreateDepthStencilSurface(device, 256, 256, D3DFMT_D24X8,
+                D3DMULTISAMPLE_NONE, 0, TRUE, &depth_stencil_surface, NULL);
+        if (SUCCEEDED(hr)) IDirect3DDevice9_SetDepthStencilSurface(device, depth_stencil_surface);
+    }
+
+    if (FAILED(hr))
+    {
+        skip("Failed to create depth stencil surface\n");
+        return;
+    }
+
+    test_ID3DXRenderToEnvMap_cube_map(device);
+
+    if (depth_stencil_surface)
+    {
+        IDirect3DDevice9_SetDepthStencilSurface(device, NULL);
+        IDirect3DSurface9_Release(depth_stencil_surface);
+    }
+}
+
+START_TEST(core)
+{
+    HWND wnd;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *device;
+    D3DPRESENT_PARAMETERS d3dpp;
+    HRESULT hr;
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window\n");
+        return;
+    }
+    if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION)))
+    {
+        skip("Couldn't create IDirect3D9 object\n");
+        DestroyWindow(wnd);
+        return;
+    }
+
+    ZeroMemory(&d3dpp, sizeof(d3dpp));
+    d3dpp.Windowed   = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
+    if(FAILED(hr)) {
+        skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    test_ID3DXBuffer();
+    test_ID3DXSprite(device);
+    test_ID3DXFont(device);
+    test_D3DXCreateRenderToSurface(device);
+    test_ID3DXRenderToSurface(device);
+    test_D3DXCreateRenderToEnvMap(device);
+    test_ID3DXRenderToEnvMap(device);
+
+    check_release((IUnknown*)device, 0);
+    check_release((IUnknown*)d3d, 0);
+    if (wnd) DestroyWindow(wnd);
+}
diff --git a/modules/rostests/winetests/d3dx9_36/effect.c b/modules/rostests/winetests/d3dx9_36/effect.c
new file mode 100644 (file)
index 0000000..423d3b8
--- /dev/null
@@ -0,0 +1,8030 @@
+/*
+ * Copyright 2010 Christian Costa
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include "initguid.h"
+#include <limits.h>
+#include "wine/test.h"
+#include "d3dx9.h"
+
+#ifndef INFINITY
+static inline float __port_infinity(void)
+{
+    static const unsigned __inf_bytes = 0x7f800000;
+    return *(const float *)&__inf_bytes;
+}
+#define INFINITY __port_infinity()
+#endif /* INFINITY */
+
+#ifndef NAN
+static float get_nan(void)
+{
+    DWORD nan = 0x7fc00000;
+
+    return *(float *)&nan;
+}
+#define NAN get_nan()
+#endif
+
+/* helper functions */
+static BOOL compare_float(FLOAT f, FLOAT g, UINT ulps)
+{
+    INT x = *(INT *)&f;
+    INT y = *(INT *)&g;
+
+    if (x < 0)
+        x = INT_MIN - x;
+    if (y < 0)
+        y = INT_MIN - y;
+
+    if (abs(x - y) > ulps)
+        return FALSE;
+
+    return TRUE;
+}
+
+static inline INT get_int(D3DXPARAMETER_TYPE type, const void *data)
+{
+    INT i;
+
+    switch (type)
+    {
+        case D3DXPT_FLOAT:
+            i = *(FLOAT *)data;
+            break;
+
+        case D3DXPT_INT:
+            i = *(INT *)data;
+            break;
+
+        case D3DXPT_BOOL:
+            i = *(BOOL *)data;
+            break;
+
+        default:
+            i = 0;
+            ok(0, "Unhandled type %x.\n", type);
+            break;
+    }
+
+    return i;
+}
+
+static inline float get_float(D3DXPARAMETER_TYPE type, const void *data)
+{
+    float f;
+
+    switch (type)
+    {
+        case D3DXPT_FLOAT:
+            f = *(FLOAT *)data;
+            break;
+
+        case D3DXPT_INT:
+            f = *(INT *)data;
+            break;
+
+        case D3DXPT_BOOL:
+            f = *(BOOL *)data;
+            break;
+
+        default:
+            f = 0.0f;
+            ok(0, "Unhandled type %x.\n", type);
+            break;
+    }
+
+    return f;
+}
+
+static inline BOOL get_bool(const void *data)
+{
+    return !!*(BOOL *)data;
+}
+
+static void set_number(void *outdata, D3DXPARAMETER_TYPE outtype, const void *indata, D3DXPARAMETER_TYPE intype)
+{
+    switch (outtype)
+    {
+        case D3DXPT_FLOAT:
+            *(FLOAT *)outdata = get_float(intype, indata);
+            break;
+
+        case D3DXPT_BOOL:
+            *(BOOL *)outdata = get_bool(indata);
+            break;
+
+        case D3DXPT_INT:
+            *(INT *)outdata = get_int(intype, indata);
+            break;
+
+        case D3DXPT_PIXELSHADER:
+        case D3DXPT_VERTEXSHADER:
+        case D3DXPT_TEXTURE2D:
+        case D3DXPT_STRING:
+            *(INT *)outdata = 0x12345678;
+            break;
+
+        default:
+            ok(0, "Unhandled type %x.\n", outtype);
+            *(INT *)outdata = 0;
+            break;
+    }
+}
+
+static IDirect3DDevice9 *create_device(HWND *window)
+{
+    D3DPRESENT_PARAMETERS present_parameters = { 0 };
+    IDirect3DDevice9 *device;
+    IDirect3D9 *d3d;
+    HRESULT hr;
+    HWND wnd;
+
+    *window = NULL;
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window.\n");
+        return NULL;
+    }
+
+    if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION)))
+    {
+        skip("Couldn't create IDirect3D9 object.\n");
+        DestroyWindow(wnd);
+        return NULL;
+    }
+
+    present_parameters.Windowed = TRUE;
+    present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_HARDWARE_VERTEXPROCESSING,
+            &present_parameters, &device);
+    IDirect3D9_Release(d3d);
+    if (FAILED(hr))
+    {
+        skip("Failed to create IDirect3DDevice9 object %#x.\n", hr);
+        DestroyWindow(wnd);
+        return NULL;
+    }
+
+    *window = wnd;
+    return device;
+}
+
+static char temp_path[MAX_PATH];
+
+static BOOL create_file(const char *filename, const char *data, const unsigned int size, char *out_path)
+{
+    DWORD written;
+    HANDLE hfile;
+    char path[MAX_PATH];
+
+    if (!*temp_path)
+        GetTempPathA(sizeof(temp_path), temp_path);
+
+    strcpy(path, temp_path);
+    strcat(path, filename);
+    hfile = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+    if (hfile == INVALID_HANDLE_VALUE)
+        return FALSE;
+
+    if (WriteFile(hfile, data, size, &written, NULL))
+    {
+        CloseHandle(hfile);
+
+        if (out_path)
+            strcpy(out_path, path);
+        return TRUE;
+    }
+
+    CloseHandle(hfile);
+    return FALSE;
+}
+
+static void delete_file(const char *filename)
+{
+    char path[MAX_PATH];
+
+    strcpy(path, temp_path);
+    strcat(path, filename);
+    DeleteFileA(path);
+}
+
+static BOOL create_directory(const char *name)
+{
+    char path[MAX_PATH];
+
+    strcpy(path, temp_path);
+    strcat(path, name);
+    return CreateDirectoryA(path, NULL);
+}
+
+static void delete_directory(const char *name)
+{
+    char path[MAX_PATH];
+
+    strcpy(path, temp_path);
+    strcat(path, name);
+    RemoveDirectoryA(path);
+}
+
+static const char effect_desc[] =
+"Technique\n"
+"{\n"
+"}\n";
+
+static void test_create_effect_and_pool(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    ID3DXEffect *effect;
+    ID3DXBaseEffect *base;
+    ULONG count;
+    IDirect3DDevice9 *device2;
+    ID3DXEffectStateManager *manager = (ID3DXEffectStateManager *)0xdeadbeef;
+    ID3DXEffectPool *pool = (ID3DXEffectPool *)0xdeadbeef, *pool2;
+
+    hr = D3DXCreateEffect(NULL, effect_desc, sizeof(effect_desc), NULL, NULL, 0, NULL, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3D_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateEffect(device, NULL, 0, NULL, NULL, 0, NULL, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateEffect(device, effect_desc, 0, NULL, NULL, 0, NULL, NULL, NULL);
+    ok(hr == E_FAIL, "Got result %x, expected %x (D3DXERR_INVALIDDATA)\n", hr, E_FAIL);
+
+    hr = D3DXCreateEffect(device, effect_desc, sizeof(effect_desc), NULL, NULL, 0, NULL, NULL, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+    hr = D3DXCreateEffect(device, effect_desc, sizeof(effect_desc), NULL, NULL, 0, NULL, &effect, NULL);
+    todo_wine ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    if (FAILED(hr))
+    {
+        skip("Failed to compile effect, skipping test.\n");
+        return;
+    }
+
+    hr = effect->lpVtbl->QueryInterface(effect, &IID_ID3DXBaseEffect, (void **)&base);
+    ok(hr == E_NOINTERFACE, "QueryInterface failed, got %x, expected %x (E_NOINTERFACE)\n", hr, E_NOINTERFACE);
+
+    hr = effect->lpVtbl->GetStateManager(effect, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "GetStateManager failed, got %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = effect->lpVtbl->GetStateManager(effect, &manager);
+    ok(hr == D3D_OK, "GetStateManager failed, got %x, expected 0 (D3D_OK)\n", hr);
+    ok(!manager, "GetStateManager failed, got %p\n", manager);
+
+    /* this works, but it is not recommended! */
+    hr = effect->lpVtbl->SetStateManager(effect, (ID3DXEffectStateManager *)device);
+    ok(hr == D3D_OK, "SetStateManager failed, got %x, expected 0 (D3D_OK)\n", hr);
+
+    hr = effect->lpVtbl->GetStateManager(effect, &manager);
+    ok(hr == D3D_OK, "GetStateManager failed, got %x, expected 0 (D3D_OK)\n", hr);
+    ok(manager != NULL, "GetStateManager failed\n");
+
+    IDirect3DDevice9_AddRef(device);
+    count = IDirect3DDevice9_Release(device);
+    ok(count == 4, "Release failed, got %u, expected 4\n", count);
+
+    count = IUnknown_Release(manager);
+    ok(count == 3, "Release failed, got %u, expected 3\n", count);
+
+    hr = effect->lpVtbl->SetStateManager(effect, NULL);
+    ok(hr == D3D_OK, "SetStateManager failed, got %x, expected 0 (D3D_OK)\n", hr);
+
+    hr = effect->lpVtbl->GetPool(effect, &pool);
+    ok(hr == D3D_OK, "GetPool failed, got %x, expected 0 (D3D_OK)\n", hr);
+    ok(!pool, "GetPool failed, got %p\n", pool);
+
+    hr = effect->lpVtbl->GetPool(effect, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "GetPool failed, got %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = effect->lpVtbl->GetDevice(effect, &device2);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+    hr = effect->lpVtbl->GetDevice(effect, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "GetDevice failed, got %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    count = IDirect3DDevice9_Release(device2);
+    ok(count == 2, "Release failed, got %u, expected 2\n", count);
+
+    count = effect->lpVtbl->Release(effect);
+    ok(count == 0, "Release failed %u\n", count);
+
+    hr = D3DXCreateEffectPool(NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3D_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateEffectPool(&pool);
+    ok(hr == S_OK, "Got result %x, expected 0 (S_OK)\n", hr);
+
+    count = pool->lpVtbl->Release(pool);
+    ok(count == 0, "Release failed %u\n", count);
+
+    hr = D3DXCreateEffectPool(&pool);
+    ok(hr == S_OK, "Got result %x, expected 0 (S_OK)\n", hr);
+
+    hr = D3DXCreateEffect(device, effect_desc, sizeof(effect_desc), NULL, NULL, 0, pool, NULL, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+    hr = pool->lpVtbl->QueryInterface(pool, &IID_ID3DXEffectPool, (void **)&pool2);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    ok(pool == pool2, "Release failed, got %p, expected %p\n", pool2, pool);
+
+    count = pool2->lpVtbl->Release(pool2);
+    ok(count == 1, "Release failed, got %u, expected 1\n", count);
+
+    hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9, (void **)&device2);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+    count = IDirect3DDevice9_Release(device2);
+    ok(count == 1, "Release failed, got %u, expected 1\n", count);
+
+    hr = D3DXCreateEffect(device, effect_desc, sizeof(effect_desc), NULL, NULL, 0, pool, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+    hr = effect->lpVtbl->GetPool(effect, &pool);
+    ok(hr == D3D_OK, "GetPool failed, got %x, expected 0 (D3D_OK)\n", hr);
+    ok(pool == pool2, "GetPool failed, got %p, expected %p\n", pool2, pool);
+
+    count = pool2->lpVtbl->Release(pool2);
+    ok(count == 2, "Release failed, got %u, expected 2\n", count);
+
+    count = effect->lpVtbl->Release(effect);
+    ok(count == 0, "Release failed %u\n", count);
+
+    count = pool->lpVtbl->Release(pool);
+    ok(count == 0, "Release failed %u\n", count);
+}
+
+static void test_create_effect_compiler(void)
+{
+    HRESULT hr;
+    ID3DXEffectCompiler *compiler, *compiler2;
+    ID3DXBaseEffect *base;
+    IUnknown *unknown;
+    ULONG count;
+
+    hr = D3DXCreateEffectCompiler(NULL, 0, NULL, NULL, 0, &compiler, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3D_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateEffectCompiler(NULL, 0, NULL, NULL, 0, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3D_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateEffectCompiler(effect_desc, 0, NULL, NULL, 0, &compiler, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    if (FAILED(hr))
+    {
+        skip("D3DXCreateEffectCompiler failed, skipping test.\n");
+        return;
+    }
+
+    count = compiler->lpVtbl->Release(compiler);
+    ok(count == 0, "Release failed %u\n", count);
+
+    hr = D3DXCreateEffectCompiler(effect_desc, 0, NULL, NULL, 0, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3D_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateEffectCompiler(NULL, sizeof(effect_desc), NULL, NULL, 0, &compiler, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3D_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateEffectCompiler(NULL, sizeof(effect_desc), NULL, NULL, 0, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3D_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateEffectCompiler(effect_desc, sizeof(effect_desc), NULL, NULL, 0, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateEffectCompiler(effect_desc, sizeof(effect_desc), NULL, NULL, 0, &compiler, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+
+    hr = compiler->lpVtbl->QueryInterface(compiler, &IID_ID3DXBaseEffect, (void **)&base);
+    ok(hr == E_NOINTERFACE, "QueryInterface failed, got %x, expected %x (E_NOINTERFACE)\n", hr, E_NOINTERFACE);
+
+    hr = compiler->lpVtbl->QueryInterface(compiler, &IID_ID3DXEffectCompiler, (void **)&compiler2);
+    ok(hr == D3D_OK, "QueryInterface failed, got %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+
+    hr = compiler->lpVtbl->QueryInterface(compiler, &IID_IUnknown, (void **)&unknown);
+    ok(hr == D3D_OK, "QueryInterface failed, got %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+
+    count = unknown->lpVtbl->Release(unknown);
+    ok(count == 2, "Release failed, got %u, expected %u\n", count, 2);
+
+    count = compiler2->lpVtbl->Release(compiler2);
+    ok(count == 1, "Release failed, got %u, expected %u\n", count, 1);
+
+    count = compiler->lpVtbl->Release(compiler);
+    ok(count == 0, "Release failed %u\n", count);
+}
+
+/*
+ * Parameter value test
+ */
+struct test_effect_parameter_value_result
+{
+    const char *full_name;
+    D3DXPARAMETER_DESC desc;
+    UINT value_offset; /* start position for the value in the blob */
+};
+
+/*
+ * fxc.exe /Tfx_2_0
+ */
+#if 0
+float f = 0.1;
+float1 f1 = {1.1};
+float2 f2 = {2.1, 2.2};
+float3 f3 = {3.1, 3.2, 3.3};
+float4 f4 = {4.1, 4.2, 4.3, 4.4};
+float1x1 f11 = {11.1};
+float1x2 f12 = {12.1, 12.2};
+float1x3 f13 = {13.1, 13.2, 13.3};
+float1x4 f14 = {14.1, 14.2, 14.3, 14.4};
+float2x1 f21 = {{21.11, 21.21}};
+float2x2 f22 = {{22.11, 22.21}, {22.12, 22.22}};
+float2x3 f23 = {{23.11, 23.21}, {23.12, 23.22}, {23.13, 23.23}};
+float2x4 f24 = {{24.11, 24.21}, {24.12, 24.22}, {24.13, 24.23}, {24.14, 24.24}};
+float3x1 f31 = {{31.11, 31.21, 31.31}};
+float3x2 f32 = {{32.11, 32.21, 32.31}, {32.12, 32.22, 32.32}};
+float3x3 f33 = {{33.11, 33.21, 33.31}, {33.12, 33.22, 33.32},
+        {33.13, 33.23, 33.33}};
+float3x4 f34 = {{34.11, 34.21, 34.31}, {34.12, 34.22, 34.32},
+        {34.13, 34.23, 34.33}, {34.14, 34.24, 34.34}};
+float4x1 f41 = {{41.11, 41.21, 41.31, 41.41}};
+float4x2 f42 = {{42.11, 42.21, 42.31, 42.41}, {42.12, 42.22, 42.32, 42.42}};
+float4x3 f43 = {{43.11, 43.21, 43.31, 43.41}, {43.12, 43.22, 43.32, 43.42},
+        {43.13, 43.23, 43.33, 43.43}};
+float4x4 f44 = {{44.11, 44.21, 44.31, 44.41}, {44.12, 44.22, 44.32, 44.42},
+        {44.13, 44.23, 44.33, 44.43}, {44.14, 44.24, 44.34, 44.44}};
+float f_2[2] = {0.101, 0.102};
+float1 f1_2[2] = {{1.101}, {1.102}};
+float2 f2_2[2] = {{2.101, 2.201}, {2.102, 2.202}};
+float3 f3_2[2] = {{3.101, 3.201, 3.301}, {3.102, 3.202, 3.302}};
+float4 f4_2[2] = {{4.101, 4.201, 4.301, 4.401}, {4.102, 4.202, 4.302, 4.402}};
+float1x1 f11_2[2] = {{11.101}, {11.102}};
+float1x2 f12_2[2] = {{12.101, 12.201}, {12.102, 12.202}};
+float1x3 f13_2[2] = {{13.101, 13.201, 13.301}, {13.102, 13.202, 13.302}};
+float1x4 f14_2[2] = {{14.101, 14.201, 14.301, 14.401}, {14.102, 14.202, 14.302, 14.402}};
+float2x1 f21_2[2] = {{{21.1101, 21.2101}}, {{21.1102, 21.2102}}};
+float2x2 f22_2[2] = {{{22.1101, 22.2101}, {22.1201, 22.2201}}, {{22.1102, 22.2102}, {22.1202, 22.2202}}};
+float2x3 f23_2[2] = {{{23.1101, 23.2101}, {23.1201, 23.2201}, {23.1301, 23.2301}}, {{23.1102, 23.2102},
+        {23.1202, 23.2202}, {23.1302, 23.2302}}};
+float2x4 f24_2[2] = {{{24.1101, 24.2101}, {24.1201, 24.2201}, {24.1301, 24.2301}, {24.1401, 24.2401}},
+        {{24.1102, 24.2102}, {24.1202, 24.2202}, {24.1302, 24.2302}, {24.1402, 24.2402}}};
+float3x1 f31_2[2] = {{{31.1101, 31.2101, 31.3101}}, {{31.1102, 31.2102, 31.3102}}};
+float3x2 f32_2[2] = {{{32.1101, 32.2101, 32.3101}, {32.1201, 32.2201, 32.3201}},
+        {{32.1102, 32.2102, 32.3102}, {32.1202, 32.2202, 32.3202}}};
+float3x3 f33_2[2] = {{{33.1101, 33.2101, 33.3101}, {33.1201, 33.2201, 33.3201},
+        {33.1301, 33.2301, 33.3301}}, {{33.1102, 33.2102, 33.3102}, {33.1202, 33.2202, 33.3202},
+        {33.1302, 33.2302, 33.3302}}};
+float3x4 f34_2[2] = {{{34.1101, 34.2101, 34.3101}, {34.1201, 34.2201, 34.3201},
+        {34.1301, 34.2301, 34.3301}, {34.1401, 34.2401, 34.3401}}, {{34.1102, 34.2102, 34.3102},
+        {34.1202, 34.2202, 34.3202}, {34.1302, 34.2302, 34.3302}, {34.1402, 34.2402, 34.3402}}};
+float4x1 f41_2[2] = {{{41.1101, 41.2101, 41.3101, 41.4101}}, {{41.1102, 41.2102, 41.3102, 41.4102}}};
+float4x2 f42_2[2] = {{{42.1101, 42.2101, 42.3101, 42.4101}, {42.1201, 42.2201, 42.3201, 42.4201}},
+        {{42.1102, 42.2102, 42.3102, 42.4102}, {42.1202, 42.2202, 42.3202, 42.4202}}};
+float4x3 f43_2[2] = {{{43.1101, 43.2101, 43.3101, 43.4101}, {43.1201, 43.2201, 43.3201, 43.4201},
+        {43.1301, 43.2301, 43.3301, 43.4301}}, {{43.1102, 43.2102, 43.3102, 43.4102},
+        {43.1202, 43.2202, 43.3202, 43.4202}, {43.1302, 43.2302, 43.3302, 43.4302}}};
+float4x4 f44_2[2] = {{{44.1101, 44.2101, 44.3101, 44.4101}, {44.1201, 44.2201, 44.3201, 44.4201},
+        {44.1301, 44.2301, 44.3301, 44.4301}, {44.1401, 44.2401, 44.3401, 44.4401}},
+        {{44.1102, 44.2102, 44.3102, 44.4102}, {44.1202, 44.2202, 44.3202, 44.4202},
+        {44.1302, 44.2302, 44.3302, 44.4302}, {44.1402, 44.2402, 44.3402, 44.4402}}};
+technique t { pass p { } }
+#endif
+static const DWORD test_effect_parameter_value_blob_float[] =
+{
+0xfeff0901, 0x00000b80, 0x00000000, 0x00000003, 0x00000000, 0x00000024, 0x00000000, 0x00000000,
+0x00000001, 0x00000001, 0x3dcccccd, 0x00000002, 0x00000066, 0x00000003, 0x00000001, 0x0000004c,
+0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x3f8ccccd, 0x00000003, 0x00003166, 0x00000003,
+0x00000001, 0x00000078, 0x00000000, 0x00000000, 0x00000002, 0x00000001, 0x40066666, 0x400ccccd,
+0x00000003, 0x00003266, 0x00000003, 0x00000001, 0x000000a8, 0x00000000, 0x00000000, 0x00000003,
+0x00000001, 0x40466666, 0x404ccccd, 0x40533333, 0x00000003, 0x00003366, 0x00000003, 0x00000001,
+0x000000dc, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x40833333, 0x40866666, 0x4089999a,
+0x408ccccd, 0x00000003, 0x00003466, 0x00000003, 0x00000002, 0x00000104, 0x00000000, 0x00000000,
+0x00000001, 0x00000001, 0x4131999a, 0x00000004, 0x00313166, 0x00000003, 0x00000002, 0x00000130,
+0x00000000, 0x00000000, 0x00000001, 0x00000002, 0x4141999a, 0x41433333, 0x00000004, 0x00323166,
+0x00000003, 0x00000002, 0x00000160, 0x00000000, 0x00000000, 0x00000001, 0x00000003, 0x4151999a,
+0x41533333, 0x4154cccd, 0x00000004, 0x00333166, 0x00000003, 0x00000002, 0x00000194, 0x00000000,
+0x00000000, 0x00000001, 0x00000004, 0x4161999a, 0x41633333, 0x4164cccd, 0x41666666, 0x00000004,
+0x00343166, 0x00000003, 0x00000002, 0x000001c0, 0x00000000, 0x00000000, 0x00000002, 0x00000001,
+0x41a8e148, 0x41a9ae14, 0x00000004, 0x00313266, 0x00000003, 0x00000002, 0x000001f4, 0x00000000,
+0x00000000, 0x00000002, 0x00000002, 0x41b0e148, 0x41b1ae14, 0x41b0f5c3, 0x41b1c28f, 0x00000004,
+0x00323266, 0x00000003, 0x00000002, 0x00000230, 0x00000000, 0x00000000, 0x00000002, 0x00000003,
+0x41b8e148, 0x41b9ae14, 0x41b8f5c3, 0x41b9c28f, 0x41b90a3d, 0x41b9d70a, 0x00000004, 0x00333266,
+0x00000003, 0x00000002, 0x00000274, 0x00000000, 0x00000000, 0x00000002, 0x00000004, 0x41c0e148,
+0x41c1ae14, 0x41c0f5c3, 0x41c1c28f, 0x41c10a3d, 0x41c1d70a, 0x41c11eb8, 0x41c1eb85, 0x00000004,
+0x00343266, 0x00000003, 0x00000002, 0x000002a4, 0x00000000, 0x00000000, 0x00000003, 0x00000001,
+0x41f8e148, 0x41f9ae14, 0x41fa7ae1, 0x00000004, 0x00313366, 0x00000003, 0x00000002, 0x000002e0,
+0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x420070a4, 0x4200d70a, 0x42013d71, 0x42007ae1,
+0x4200e148, 0x420147ae, 0x00000004, 0x00323366, 0x00000003, 0x00000002, 0x00000328, 0x00000000,
+0x00000000, 0x00000003, 0x00000003, 0x420470a4, 0x4204d70a, 0x42053d71, 0x42047ae1, 0x4204e148,
+0x420547ae, 0x4204851f, 0x4204eb85, 0x420551ec, 0x00000004, 0x00333366, 0x00000003, 0x00000002,
+0x0000037c, 0x00000000, 0x00000000, 0x00000003, 0x00000004, 0x420870a4, 0x4208d70a, 0x42093d71,
+0x42087ae1, 0x4208e148, 0x420947ae, 0x4208851f, 0x4208eb85, 0x420951ec, 0x42088f5c, 0x4208f5c3,
+0x42095c29, 0x00000004, 0x00343366, 0x00000003, 0x00000002, 0x000003b0, 0x00000000, 0x00000000,
+0x00000004, 0x00000001, 0x422470a4, 0x4224d70a, 0x42253d71, 0x4225a3d7, 0x00000004, 0x00313466,
+0x00000003, 0x00000002, 0x000003f4, 0x00000000, 0x00000000, 0x00000004, 0x00000002, 0x422870a4,
+0x4228d70a, 0x42293d71, 0x4229a3d7, 0x42287ae1, 0x4228e148, 0x422947ae, 0x4229ae14, 0x00000004,
+0x00323466, 0x00000003, 0x00000002, 0x00000448, 0x00000000, 0x00000000, 0x00000004, 0x00000003,
+0x422c70a4, 0x422cd70a, 0x422d3d71, 0x422da3d7, 0x422c7ae1, 0x422ce148, 0x422d47ae, 0x422dae14,
+0x422c851f, 0x422ceb85, 0x422d51ec, 0x422db852, 0x00000004, 0x00333466, 0x00000003, 0x00000002,
+0x000004ac, 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x423070a4, 0x4230d70a, 0x42313d71,
+0x4231a3d7, 0x42307ae1, 0x4230e148, 0x423147ae, 0x4231ae14, 0x4230851f, 0x4230eb85, 0x423151ec,
+0x4231b852, 0x42308f5c, 0x4230f5c3, 0x42315c29, 0x4231c28f, 0x00000004, 0x00343466, 0x00000003,
+0x00000000, 0x000004d8, 0x00000000, 0x00000002, 0x00000001, 0x00000001, 0x3dced917, 0x3dd0e560,
+0x00000004, 0x00325f66, 0x00000003, 0x00000001, 0x00000504, 0x00000000, 0x00000002, 0x00000001,
+0x00000001, 0x3f8ced91, 0x3f8d0e56, 0x00000005, 0x325f3166, 0x00000000, 0x00000003, 0x00000001,
+0x0000053c, 0x00000000, 0x00000002, 0x00000002, 0x00000001, 0x400676c9, 0x400cdd2f, 0x4006872b,
+0x400ced91, 0x00000005, 0x325f3266, 0x00000000, 0x00000003, 0x00000001, 0x0000057c, 0x00000000,
+0x00000002, 0x00000003, 0x00000001, 0x404676c9, 0x404cdd2f, 0x40534396, 0x4046872b, 0x404ced91,
+0x405353f8, 0x00000005, 0x325f3366, 0x00000000, 0x00000003, 0x00000001, 0x000005c4, 0x00000000,
+0x00000002, 0x00000004, 0x00000001, 0x40833b64, 0x40866e98, 0x4089a1cb, 0x408cd4fe, 0x40834396,
+0x408676c9, 0x4089a9fc, 0x408cdd2f, 0x00000005, 0x325f3466, 0x00000000, 0x00000003, 0x00000002,
+0x000005f4, 0x00000000, 0x00000002, 0x00000001, 0x00000001, 0x41319db2, 0x4131a1cb, 0x00000006,
+0x5f313166, 0x00000032, 0x00000003, 0x00000002, 0x0000062c, 0x00000000, 0x00000002, 0x00000001,
+0x00000002, 0x41419db2, 0x4143374c, 0x4141a1cb, 0x41433b64, 0x00000006, 0x5f323166, 0x00000032,
+0x00000003, 0x00000002, 0x0000066c, 0x00000000, 0x00000002, 0x00000001, 0x00000003, 0x41519db2,
+0x4153374c, 0x4154d0e5, 0x4151a1cb, 0x41533b64, 0x4154d4fe, 0x00000006, 0x5f333166, 0x00000032,
+0x00000003, 0x00000002, 0x000006b4, 0x00000000, 0x00000002, 0x00000001, 0x00000004, 0x41619db2,
+0x4163374c, 0x4164d0e5, 0x41666a7f, 0x4161a1cb, 0x41633b64, 0x4164d4fe, 0x41666e98, 0x00000006,
+0x5f343166, 0x00000032, 0x00000003, 0x00000002, 0x000006ec, 0x00000000, 0x00000002, 0x00000002,
+0x00000001, 0x41a8e17c, 0x41a9ae49, 0x41a8e1b1, 0x41a9ae7d, 0x00000006, 0x5f313266, 0x00000032,
+0x00000003, 0x00000002, 0x00000734, 0x00000000, 0x00000002, 0x00000002, 0x00000002, 0x41b0e17c,
+0x41b1ae49, 0x41b0f5f7, 0x41b1c2c4, 0x41b0e1b1, 0x41b1ae7d, 0x41b0f62b, 0x41b1c2f8, 0x00000006,
+0x5f323266, 0x00000032, 0x00000003, 0x00000002, 0x0000078c, 0x00000000, 0x00000002, 0x00000002,
+0x00000003, 0x41b8e17c, 0x41b9ae49, 0x41b8f5f7, 0x41b9c2c4, 0x41b90a72, 0x41b9d73f, 0x41b8e1b1,
+0x41b9ae7d, 0x41b8f62b, 0x41b9c2f8, 0x41b90aa6, 0x41b9d773, 0x00000006, 0x5f333266, 0x00000032,
+0x00000003, 0x00000002, 0x000007f4, 0x00000000, 0x00000002, 0x00000002, 0x00000004, 0x41c0e17c,
+0x41c1ae49, 0x41c0f5f7, 0x41c1c2c4, 0x41c10a72, 0x41c1d73f, 0x41c11eed, 0x41c1ebba, 0x41c0e1b1,
+0x41c1ae7d, 0x41c0f62b, 0x41c1c2f8, 0x41c10aa6, 0x41c1d773, 0x41c11f21, 0x41c1ebee, 0x00000006,
+0x5f343266, 0x00000032, 0x00000003, 0x00000002, 0x00000834, 0x00000000, 0x00000002, 0x00000003,
+0x00000001, 0x41f8e17c, 0x41f9ae49, 0x41fa7b16, 0x41f8e1b1, 0x41f9ae7d, 0x41fa7b4a, 0x00000006,
+0x5f313366, 0x00000032, 0x00000003, 0x00000002, 0x0000088c, 0x00000000, 0x00000002, 0x00000003,
+0x00000002, 0x420070be, 0x4200d724, 0x42013d8b, 0x42007afb, 0x4200e162, 0x420147c8, 0x420070d8,
+0x4200d73f, 0x42013da5, 0x42007b16, 0x4200e17c, 0x420147e3, 0x00000006, 0x5f323366, 0x00000032,
+0x00000003, 0x00000002, 0x000008fc, 0x00000000, 0x00000002, 0x00000003, 0x00000003, 0x420470be,
+0x4204d724, 0x42053d8b, 0x42047afb, 0x4204e162, 0x420547c8, 0x42048539, 0x4204eb9f, 0x42055206,
+0x420470d8, 0x4204d73f, 0x42053da5, 0x42047b16, 0x4204e17c, 0x420547e3, 0x42048553, 0x4204ebba,
+0x42055220, 0x00000006, 0x5f333366, 0x00000032, 0x00000003, 0x00000002, 0x00000984, 0x00000000,
+0x00000002, 0x00000003, 0x00000004, 0x420870be, 0x4208d724, 0x42093d8b, 0x42087afb, 0x4208e162,
+0x420947c8, 0x42088539, 0x4208eb9f, 0x42095206, 0x42088f76, 0x4208f5dd, 0x42095c43, 0x420870d8,
+0x4208d73f, 0x42093da5, 0x42087b16, 0x4208e17c, 0x420947e3, 0x42088553, 0x4208ebba, 0x42095220,
+0x42088f91, 0x4208f5f7, 0x42095c5d, 0x00000006, 0x5f343366, 0x00000032, 0x00000003, 0x00000002,
+0x000009cc, 0x00000000, 0x00000002, 0x00000004, 0x00000001, 0x422470be, 0x4224d724, 0x42253d8b,
+0x4225a3f1, 0x422470d8, 0x4224d73f, 0x42253da5, 0x4225a40b, 0x00000006, 0x5f313466, 0x00000032,
+0x00000003, 0x00000002, 0x00000a34, 0x00000000, 0x00000002, 0x00000004, 0x00000002, 0x422870be,
+0x4228d724, 0x42293d8b, 0x4229a3f1, 0x42287afb, 0x4228e162, 0x422947c8, 0x4229ae2f, 0x422870d8,
+0x4228d73f, 0x42293da5, 0x4229a40b, 0x42287b16, 0x4228e17c, 0x422947e3, 0x4229ae49, 0x00000006,
+0x5f323466, 0x00000032, 0x00000003, 0x00000002, 0x00000abc, 0x00000000, 0x00000002, 0x00000004,
+0x00000003, 0x422c70be, 0x422cd724, 0x422d3d8b, 0x422da3f1, 0x422c7afb, 0x422ce162, 0x422d47c8,
+0x422dae2f, 0x422c8539, 0x422ceb9f, 0x422d5206, 0x422db86c, 0x422c70d8, 0x422cd73f, 0x422d3da5,
+0x422da40b, 0x422c7b16, 0x422ce17c, 0x422d47e3, 0x422dae49, 0x422c8553, 0x422cebba, 0x422d5220,
+0x422db886, 0x00000006, 0x5f333466, 0x00000032, 0x00000003, 0x00000002, 0x00000b64, 0x00000000,
+0x00000002, 0x00000004, 0x00000004, 0x423070be, 0x4230d724, 0x42313d8b, 0x4231a3f1, 0x42307afb,
+0x4230e162, 0x423147c8, 0x4231ae2f, 0x42308539, 0x4230eb9f, 0x42315206, 0x4231b86c, 0x42308f76,
+0x4230f5dd, 0x42315c43, 0x4231c2aa, 0x423070d8, 0x4230d73f, 0x42313da5, 0x4231a40b, 0x42307b16,
+0x4230e17c, 0x423147e3, 0x4231ae49, 0x42308553, 0x4230ebba, 0x42315220, 0x4231b886, 0x42308f91,
+0x4230f5f7, 0x42315c5d, 0x4231c2c4, 0x00000006, 0x5f343466, 0x00000032, 0x00000002, 0x00000070,
+0x00000002, 0x00000074, 0x0000002a, 0x00000001, 0x00000001, 0x00000001, 0x00000004, 0x00000020,
+0x00000000, 0x00000000, 0x0000002c, 0x00000048, 0x00000000, 0x00000000, 0x00000054, 0x00000070,
+0x00000000, 0x00000000, 0x00000080, 0x0000009c, 0x00000000, 0x00000000, 0x000000b0, 0x000000cc,
+0x00000000, 0x00000000, 0x000000e4, 0x00000100, 0x00000000, 0x00000000, 0x0000010c, 0x00000128,
+0x00000000, 0x00000000, 0x00000138, 0x00000154, 0x00000000, 0x00000000, 0x00000168, 0x00000184,
+0x00000000, 0x00000000, 0x0000019c, 0x000001b8, 0x00000000, 0x00000000, 0x000001c8, 0x000001e4,
+0x00000000, 0x00000000, 0x000001fc, 0x00000218, 0x00000000, 0x00000000, 0x00000238, 0x00000254,
+0x00000000, 0x00000000, 0x0000027c, 0x00000298, 0x00000000, 0x00000000, 0x000002ac, 0x000002c8,
+0x00000000, 0x00000000, 0x000002e8, 0x00000304, 0x00000000, 0x00000000, 0x00000330, 0x0000034c,
+0x00000000, 0x00000000, 0x00000384, 0x000003a0, 0x00000000, 0x00000000, 0x000003b8, 0x000003d4,
+0x00000000, 0x00000000, 0x000003fc, 0x00000418, 0x00000000, 0x00000000, 0x00000450, 0x0000046c,
+0x00000000, 0x00000000, 0x000004b4, 0x000004d0, 0x00000000, 0x00000000, 0x000004e0, 0x000004fc,
+0x00000000, 0x00000000, 0x00000510, 0x0000052c, 0x00000000, 0x00000000, 0x00000548, 0x00000564,
+0x00000000, 0x00000000, 0x00000588, 0x000005a4, 0x00000000, 0x00000000, 0x000005d0, 0x000005ec,
+0x00000000, 0x00000000, 0x00000600, 0x0000061c, 0x00000000, 0x00000000, 0x00000638, 0x00000654,
+0x00000000, 0x00000000, 0x00000678, 0x00000694, 0x00000000, 0x00000000, 0x000006c0, 0x000006dc,
+0x00000000, 0x00000000, 0x000006f8, 0x00000714, 0x00000000, 0x00000000, 0x00000740, 0x0000075c,
+0x00000000, 0x00000000, 0x00000798, 0x000007b4, 0x00000000, 0x00000000, 0x00000800, 0x0000081c,
+0x00000000, 0x00000000, 0x00000840, 0x0000085c, 0x00000000, 0x00000000, 0x00000898, 0x000008b4,
+0x00000000, 0x00000000, 0x00000908, 0x00000924, 0x00000000, 0x00000000, 0x00000990, 0x000009ac,
+0x00000000, 0x00000000, 0x000009d8, 0x000009f4, 0x00000000, 0x00000000, 0x00000a40, 0x00000a5c,
+0x00000000, 0x00000000, 0x00000ac8, 0x00000ae4, 0x00000000, 0x00000000, 0x00000b78, 0x00000000,
+0x00000001, 0x00000b70, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+struct test_effect_parameter_value_result test_effect_parameter_value_result_float[] =
+{
+    {"f",     {"f",     NULL, D3DXPC_SCALAR,      D3DXPT_FLOAT, 1, 1, 0, 0, 0, 0,   4},  10},
+    {"f1",    {"f1",    NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 1, 0, 0, 0, 0,   4},  20},
+    {"f2",    {"f2",    NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 2, 0, 0, 0, 0,   8},  30},
+    {"f3",    {"f3",    NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 3, 0, 0, 0, 0,  12},  41},
+    {"f4",    {"f4",    NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 4, 0, 0, 0, 0,  16},  53},
+    {"f11",   {"f11",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 1, 1, 0, 0, 0, 0,   4},  66},
+    {"f12",   {"f12",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 1, 2, 0, 0, 0, 0,   8},  76},
+    {"f13",   {"f13",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 1, 3, 0, 0, 0, 0,  12},  87},
+    {"f14",   {"f14",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 1, 4, 0, 0, 0, 0,  16},  99},
+    {"f21",   {"f21",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 2, 1, 0, 0, 0, 0,   8}, 112},
+    {"f22",   {"f22",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 2, 2, 0, 0, 0, 0,  16}, 123},
+    {"f23",   {"f23",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 2, 3, 0, 0, 0, 0,  24}, 136},
+    {"f24",   {"f24",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 2, 4, 0, 0, 0, 0,  32}, 151},
+    {"f31",   {"f31",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 1, 0, 0, 0, 0,  12}, 168},
+    {"f32",   {"f32",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 2, 0, 0, 0, 0,  24}, 180},
+    {"f33",   {"f33",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 3, 0, 0, 0, 0,  36}, 195},
+    {"f34",   {"f34",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 4, 0, 0, 0, 0,  48}, 213},
+    {"f41",   {"f41",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 1, 0, 0, 0, 0,  16}, 234},
+    {"f42",   {"f42",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 2, 0, 0, 0, 0,  32}, 247},
+    {"f43",   {"f43",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 3, 0, 0, 0, 0,  48}, 264},
+    {"f44",   {"f44",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 4, 0, 0, 0, 0,  64}, 285},
+    {"f_2",   {"f_2",   NULL, D3DXPC_SCALAR,      D3DXPT_FLOAT, 1, 1, 2, 0, 0, 0,   8}, 310},
+    {"f1_2",  {"f1_2",  NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 1, 2, 0, 0, 0,   8}, 321},
+    {"f2_2",  {"f2_2",  NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 2, 2, 0, 0, 0,  16}, 333},
+    {"f3_2",  {"f3_2",  NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 3, 2, 0, 0, 0,  24}, 347},
+    {"f4_2",  {"f4_2",  NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 4, 2, 0, 0, 0,  32}, 363},
+    {"f11_2", {"f11_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 1, 1, 2, 0, 0, 0,   8}, 381},
+    {"f12_2", {"f12_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 1, 2, 2, 0, 0, 0,  16}, 393},
+    {"f13_2", {"f13_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 1, 3, 2, 0, 0, 0,  24}, 407},
+    {"f14_2", {"f14_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 1, 4, 2, 0, 0, 0,  32}, 423},
+    {"f21_2", {"f21_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 2, 1, 2, 0, 0, 0,  16}, 441},
+    {"f22_2", {"f22_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 2, 2, 2, 0, 0, 0,  32}, 455},
+    {"f23_2", {"f23_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 2, 3, 2, 0, 0, 0,  48}, 473},
+    {"f24_2", {"f24_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 2, 4, 2, 0, 0, 0,  64}, 495},
+    {"f31_2", {"f31_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 1, 2, 0, 0, 0,  24}, 521},
+    {"f32_2", {"f32_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 2, 2, 0, 0, 0,  48}, 537},
+    {"f33_2", {"f33_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 3, 2, 0, 0, 0,  72}, 559},
+    {"f34_2", {"f34_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 4, 2, 0, 0, 0,  96}, 587},
+    {"f41_2", {"f41_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 1, 2, 0, 0, 0,  32}, 621},
+    {"f42_2", {"f42_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 2, 2, 0, 0, 0,  64}, 639},
+    {"f43_2", {"f43_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 3, 2, 0, 0, 0,  96}, 665},
+    {"f44_2", {"f44_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 4, 2, 0, 0, 0, 128}, 699},
+};
+
+/*
+ * fxc.exe /Tfx_2_0
+ */
+#if 0
+int i = 1;
+int1 i1 = {11};
+int2 i2 = {21, 22};
+int3 i3 = {31, 32, 33};
+int4 i4 = {41, 42, 43, 44};
+int1x1 i11 = {111};
+int1x2 i12 = {121, 122};
+int1x3 i13 = {131, 132, 133};
+int1x4 i14 = {141, 142, 143, 144};
+int2x1 i21 = {{2111, 2121}};
+int2x2 i22 = {{2211, 2221}, {2212, 2222}};
+int2x3 i23 = {{2311, 2321}, {2312, 2322}, {2313, 2323}};
+int2x4 i24 = {{2411, 2421}, {2412, 2422}, {2413, 2423}, {2414, 2424}};
+int3x1 i31 = {{3111, 3121, 3131}};
+int3x2 i32 = {{3211, 3221, 3231}, {3212, 3222, 3232}};
+int3x3 i33 = {{3311, 3321, 3331}, {3312, 3322, 3332},
+        {3313, 3323, 3333}};
+int3x4 i34 = {{3411, 3421, 3431}, {3412, 3422, 3432},
+        {3413, 3423, 3433}, {3414, 3424, 3434}};
+int4x1 i41 = {{4111, 4121, 4131, 4141}};
+int4x2 i42 = {{4211, 4221, 4231, 4241}, {4212, 4222, 4232, 4242}};
+int4x3 i43 = {{4311, 4321, 4331, 4341}, {4312, 4322, 4332, 4342},
+        {4313, 4323, 4333, 4343}};
+int4x4 i44 = {{4411, 4421, 4431, 4441}, {4412, 4422, 4432, 4442},
+        {4413, 4423, 4433, 4443}, {4414, 4424, 4434, 4444}};
+int i_2[2] = {0101, 0102};
+int1 i1_2[2] = {{1101}, {1102}};
+int2 i2_2[2] = {{2101, 2201}, {2102, 2202}};
+int3 i3_2[2] = {{3101, 3201, 3301}, {3102, 3202, 3302}};
+int4 i4_2[2] = {{4101, 4201, 4301, 4401}, {4102, 4202, 4302, 4402}};
+int1x1 i11_2[2] = {{11101}, {11102}};
+int1x2 i12_2[2] = {{12101, 12201}, {12102, 12202}};
+int1x3 i13_2[2] = {{13101, 13201, 13301}, {13102, 13202, 13302}};
+int1x4 i14_2[2] = {{14101, 14201, 14301, 14401}, {14102, 14202, 14302, 14402}};
+int2x1 i21_2[2] = {{{211101, 212101}}, {{211102, 212102}}};
+int2x2 i22_2[2] = {{{221101, 222101}, {221201, 222201}}, {{221102, 222102}, {221202, 222202}}};
+int2x3 i23_2[2] = {{{231101, 232101}, {231201, 232201}, {231301, 232301}}, {{231102, 232102},
+        {231202, 232202}, {231302, 232302}}};
+int2x4 i24_2[2] = {{{241101, 242101}, {241201, 242201}, {241301, 242301}, {241401, 242401}},
+        {{241102, 242102}, {241202, 242202}, {241302, 242302}, {241402, 242402}}};
+int3x1 i31_2[2] = {{{311101, 312101, 313101}}, {{311102, 312102, 313102}}};
+int3x2 i32_2[2] = {{{321101, 322101, 323101}, {321201, 322201, 323201}},
+        {{321102, 322102, 323102}, {321202, 322202, 323202}}};
+int3x3 i33_2[2] = {{{331101, 332101, 333101}, {331201, 332201, 333201},
+        {331301, 332301, 333301}}, {{331102, 332102, 333102}, {331202, 332202, 333202},
+        {331302, 332302, 333302}}};
+int3x4 i34_2[2] = {{{341101, 342101, 343101}, {341201, 342201, 343201},
+        {341301, 342301, 343301}, {341401, 342401, 343401}}, {{341102, 342102, 343102},
+        {341202, 342202, 343202}, {341302, 342302, 343302}, {341402, 342402, 343402}}};
+int4x1 i41_2[2] = {{{411101, 412101, 413101, 414101}}, {{411102, 412102, 413102, 414102}}};
+int4x2 i42_2[2] = {{{421101, 422101, 423101, 424101}, {421201, 422201, 423201, 424201}},
+        {{421102, 422102, 423102, 424102}, {421202, 422202, 423202, 424202}}};
+int4x3 i43_2[2] = {{{431101, 432101, 433101, 434101}, {431201, 432201, 433201, 434201},
+        {431301, 432301, 433301, 434301}}, {{431102, 432102, 433102, 434102},
+        {431202, 432202, 433202, 434202}, {431302, 432302, 433302, 434302}}};
+int4x4 i44_2[2] = {{{441101, 442101, 443101, 444101}, {441201, 442201, 443201, 444201},
+        {441301, 442301, 443301, 444301}, {441401, 442401, 443401, 444401}},
+        {{441102, 442102, 443102, 444102}, {441202, 442202, 443202, 444202},
+        {441302, 442302, 443302, 444302}, {441402, 442402, 443402, 444402}}};
+technique t { pass p { } }
+#endif
+static const DWORD test_effect_parameter_value_blob_int[] =
+{
+0xfeff0901, 0x00000b80, 0x00000000, 0x00000002, 0x00000000, 0x00000024, 0x00000000, 0x00000000,
+0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000069, 0x00000002, 0x00000001, 0x0000004c,
+0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x0000000b, 0x00000003, 0x00003169, 0x00000002,
+0x00000001, 0x00000078, 0x00000000, 0x00000000, 0x00000002, 0x00000001, 0x00000015, 0x00000016,
+0x00000003, 0x00003269, 0x00000002, 0x00000001, 0x000000a8, 0x00000000, 0x00000000, 0x00000003,
+0x00000001, 0x0000001f, 0x00000020, 0x00000021, 0x00000003, 0x00003369, 0x00000002, 0x00000001,
+0x000000dc, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000029, 0x0000002a, 0x0000002b,
+0x0000002c, 0x00000003, 0x00003469, 0x00000002, 0x00000002, 0x00000104, 0x00000000, 0x00000000,
+0x00000001, 0x00000001, 0x0000006f, 0x00000004, 0x00313169, 0x00000002, 0x00000002, 0x00000130,
+0x00000000, 0x00000000, 0x00000001, 0x00000002, 0x00000079, 0x0000007a, 0x00000004, 0x00323169,
+0x00000002, 0x00000002, 0x00000160, 0x00000000, 0x00000000, 0x00000001, 0x00000003, 0x00000083,
+0x00000084, 0x00000085, 0x00000004, 0x00333169, 0x00000002, 0x00000002, 0x00000194, 0x00000000,
+0x00000000, 0x00000001, 0x00000004, 0x0000008d, 0x0000008e, 0x0000008f, 0x00000090, 0x00000004,
+0x00343169, 0x00000002, 0x00000002, 0x000001c0, 0x00000000, 0x00000000, 0x00000002, 0x00000001,
+0x0000083f, 0x00000849, 0x00000004, 0x00313269, 0x00000002, 0x00000002, 0x000001f4, 0x00000000,
+0x00000000, 0x00000002, 0x00000002, 0x000008a3, 0x000008ad, 0x000008a4, 0x000008ae, 0x00000004,
+0x00323269, 0x00000002, 0x00000002, 0x00000230, 0x00000000, 0x00000000, 0x00000002, 0x00000003,
+0x00000907, 0x00000911, 0x00000908, 0x00000912, 0x00000909, 0x00000913, 0x00000004, 0x00333269,
+0x00000002, 0x00000002, 0x00000274, 0x00000000, 0x00000000, 0x00000002, 0x00000004, 0x0000096b,
+0x00000975, 0x0000096c, 0x00000976, 0x0000096d, 0x00000977, 0x0000096e, 0x00000978, 0x00000004,
+0x00343269, 0x00000002, 0x00000002, 0x000002a4, 0x00000000, 0x00000000, 0x00000003, 0x00000001,
+0x00000c27, 0x00000c31, 0x00000c3b, 0x00000004, 0x00313369, 0x00000002, 0x00000002, 0x000002e0,
+0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000c8b, 0x00000c95, 0x00000c9f, 0x00000c8c,
+0x00000c96, 0x00000ca0, 0x00000004, 0x00323369, 0x00000002, 0x00000002, 0x00000328, 0x00000000,
+0x00000000, 0x00000003, 0x00000003, 0x00000cef, 0x00000cf9, 0x00000d03, 0x00000cf0, 0x00000cfa,
+0x00000d04, 0x00000cf1, 0x00000cfb, 0x00000d05, 0x00000004, 0x00333369, 0x00000002, 0x00000002,
+0x0000037c, 0x00000000, 0x00000000, 0x00000003, 0x00000004, 0x00000d53, 0x00000d5d, 0x00000d67,
+0x00000d54, 0x00000d5e, 0x00000d68, 0x00000d55, 0x00000d5f, 0x00000d69, 0x00000d56, 0x00000d60,
+0x00000d6a, 0x00000004, 0x00343369, 0x00000002, 0x00000002, 0x000003b0, 0x00000000, 0x00000000,
+0x00000004, 0x00000001, 0x0000100f, 0x00001019, 0x00001023, 0x0000102d, 0x00000004, 0x00313469,
+0x00000002, 0x00000002, 0x000003f4, 0x00000000, 0x00000000, 0x00000004, 0x00000002, 0x00001073,
+0x0000107d, 0x00001087, 0x00001091, 0x00001074, 0x0000107e, 0x00001088, 0x00001092, 0x00000004,
+0x00323469, 0x00000002, 0x00000002, 0x00000448, 0x00000000, 0x00000000, 0x00000004, 0x00000003,
+0x000010d7, 0x000010e1, 0x000010eb, 0x000010f5, 0x000010d8, 0x000010e2, 0x000010ec, 0x000010f6,
+0x000010d9, 0x000010e3, 0x000010ed, 0x000010f7, 0x00000004, 0x00333469, 0x00000002, 0x00000002,
+0x000004ac, 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x0000113b, 0x00001145, 0x0000114f,
+0x00001159, 0x0000113c, 0x00001146, 0x00001150, 0x0000115a, 0x0000113d, 0x00001147, 0x00001151,
+0x0000115b, 0x0000113e, 0x00001148, 0x00001152, 0x0000115c, 0x00000004, 0x00343469, 0x00000002,
+0x00000000, 0x000004d8, 0x00000000, 0x00000002, 0x00000001, 0x00000001, 0x00000041, 0x00000042,
+0x00000004, 0x00325f69, 0x00000002, 0x00000001, 0x00000504, 0x00000000, 0x00000002, 0x00000001,
+0x00000001, 0x0000044d, 0x0000044e, 0x00000005, 0x325f3169, 0x00000000, 0x00000002, 0x00000001,
+0x0000053c, 0x00000000, 0x00000002, 0x00000002, 0x00000001, 0x00000835, 0x00000899, 0x00000836,
+0x0000089a, 0x00000005, 0x325f3269, 0x00000000, 0x00000002, 0x00000001, 0x0000057c, 0x00000000,
+0x00000002, 0x00000003, 0x00000001, 0x00000c1d, 0x00000c81, 0x00000ce5, 0x00000c1e, 0x00000c82,
+0x00000ce6, 0x00000005, 0x325f3369, 0x00000000, 0x00000002, 0x00000001, 0x000005c4, 0x00000000,
+0x00000002, 0x00000004, 0x00000001, 0x00001005, 0x00001069, 0x000010cd, 0x00001131, 0x00001006,
+0x0000106a, 0x000010ce, 0x00001132, 0x00000005, 0x325f3469, 0x00000000, 0x00000002, 0x00000002,
+0x000005f4, 0x00000000, 0x00000002, 0x00000001, 0x00000001, 0x00002b5d, 0x00002b5e, 0x00000006,
+0x5f313169, 0x00000032, 0x00000002, 0x00000002, 0x0000062c, 0x00000000, 0x00000002, 0x00000001,
+0x00000002, 0x00002f45, 0x00002fa9, 0x00002f46, 0x00002faa, 0x00000006, 0x5f323169, 0x00000032,
+0x00000002, 0x00000002, 0x0000066c, 0x00000000, 0x00000002, 0x00000001, 0x00000003, 0x0000332d,
+0x00003391, 0x000033f5, 0x0000332e, 0x00003392, 0x000033f6, 0x00000006, 0x5f333169, 0x00000032,
+0x00000002, 0x00000002, 0x000006b4, 0x00000000, 0x00000002, 0x00000001, 0x00000004, 0x00003715,
+0x00003779, 0x000037dd, 0x00003841, 0x00003716, 0x0000377a, 0x000037de, 0x00003842, 0x00000006,
+0x5f343169, 0x00000032, 0x00000002, 0x00000002, 0x000006ec, 0x00000000, 0x00000002, 0x00000002,
+0x00000001, 0x0003389d, 0x00033c85, 0x0003389e, 0x00033c86, 0x00000006, 0x5f313269, 0x00000032,
+0x00000002, 0x00000002, 0x00000734, 0x00000000, 0x00000002, 0x00000002, 0x00000002, 0x00035fad,
+0x00036395, 0x00036011, 0x000363f9, 0x00035fae, 0x00036396, 0x00036012, 0x000363fa, 0x00000006,
+0x5f323269, 0x00000032, 0x00000002, 0x00000002, 0x0000078c, 0x00000000, 0x00000002, 0x00000002,
+0x00000003, 0x000386bd, 0x00038aa5, 0x00038721, 0x00038b09, 0x00038785, 0x00038b6d, 0x000386be,
+0x00038aa6, 0x00038722, 0x00038b0a, 0x00038786, 0x00038b6e, 0x00000006, 0x5f333269, 0x00000032,
+0x00000002, 0x00000002, 0x000007f4, 0x00000000, 0x00000002, 0x00000002, 0x00000004, 0x0003adcd,
+0x0003b1b5, 0x0003ae31, 0x0003b219, 0x0003ae95, 0x0003b27d, 0x0003aef9, 0x0003b2e1, 0x0003adce,
+0x0003b1b6, 0x0003ae32, 0x0003b21a, 0x0003ae96, 0x0003b27e, 0x0003aefa, 0x0003b2e2, 0x00000006,
+0x5f343269, 0x00000032, 0x00000002, 0x00000002, 0x00000834, 0x00000000, 0x00000002, 0x00000003,
+0x00000001, 0x0004bf3d, 0x0004c325, 0x0004c70d, 0x0004bf3e, 0x0004c326, 0x0004c70e, 0x00000006,
+0x5f313369, 0x00000032, 0x00000002, 0x00000002, 0x0000088c, 0x00000000, 0x00000002, 0x00000003,
+0x00000002, 0x0004e64d, 0x0004ea35, 0x0004ee1d, 0x0004e6b1, 0x0004ea99, 0x0004ee81, 0x0004e64e,
+0x0004ea36, 0x0004ee1e, 0x0004e6b2, 0x0004ea9a, 0x0004ee82, 0x00000006, 0x5f323369, 0x00000032,
+0x00000002, 0x00000002, 0x000008fc, 0x00000000, 0x00000002, 0x00000003, 0x00000003, 0x00050d5d,
+0x00051145, 0x0005152d, 0x00050dc1, 0x000511a9, 0x00051591, 0x00050e25, 0x0005120d, 0x000515f5,
+0x00050d5e, 0x00051146, 0x0005152e, 0x00050dc2, 0x000511aa, 0x00051592, 0x00050e26, 0x0005120e,
+0x000515f6, 0x00000006, 0x5f333369, 0x00000032, 0x00000002, 0x00000002, 0x00000984, 0x00000000,
+0x00000002, 0x00000003, 0x00000004, 0x0005346d, 0x00053855, 0x00053c3d, 0x000534d1, 0x000538b9,
+0x00053ca1, 0x00053535, 0x0005391d, 0x00053d05, 0x00053599, 0x00053981, 0x00053d69, 0x0005346e,
+0x00053856, 0x00053c3e, 0x000534d2, 0x000538ba, 0x00053ca2, 0x00053536, 0x0005391e, 0x00053d06,
+0x0005359a, 0x00053982, 0x00053d6a, 0x00000006, 0x5f343369, 0x00000032, 0x00000002, 0x00000002,
+0x000009cc, 0x00000000, 0x00000002, 0x00000004, 0x00000001, 0x000645dd, 0x000649c5, 0x00064dad,
+0x00065195, 0x000645de, 0x000649c6, 0x00064dae, 0x00065196, 0x00000006, 0x5f313469, 0x00000032,
+0x00000002, 0x00000002, 0x00000a34, 0x00000000, 0x00000002, 0x00000004, 0x00000002, 0x00066ced,
+0x000670d5, 0x000674bd, 0x000678a5, 0x00066d51, 0x00067139, 0x00067521, 0x00067909, 0x00066cee,
+0x000670d6, 0x000674be, 0x000678a6, 0x00066d52, 0x0006713a, 0x00067522, 0x0006790a, 0x00000006,
+0x5f323469, 0x00000032, 0x00000002, 0x00000002, 0x00000abc, 0x00000000, 0x00000002, 0x00000004,
+0x00000003, 0x000693fd, 0x000697e5, 0x00069bcd, 0x00069fb5, 0x00069461, 0x00069849, 0x00069c31,
+0x0006a019, 0x000694c5, 0x000698ad, 0x00069c95, 0x0006a07d, 0x000693fe, 0x000697e6, 0x00069bce,
+0x00069fb6, 0x00069462, 0x0006984a, 0x00069c32, 0x0006a01a, 0x000694c6, 0x000698ae, 0x00069c96,
+0x0006a07e, 0x00000006, 0x5f333469, 0x00000032, 0x00000002, 0x00000002, 0x00000b64, 0x00000000,
+0x00000002, 0x00000004, 0x00000004, 0x0006bb0d, 0x0006bef5, 0x0006c2dd, 0x0006c6c5, 0x0006bb71,
+0x0006bf59, 0x0006c341, 0x0006c729, 0x0006bbd5, 0x0006bfbd, 0x0006c3a5, 0x0006c78d, 0x0006bc39,
+0x0006c021, 0x0006c409, 0x0006c7f1, 0x0006bb0e, 0x0006bef6, 0x0006c2de, 0x0006c6c6, 0x0006bb72,
+0x0006bf5a, 0x0006c342, 0x0006c72a, 0x0006bbd6, 0x0006bfbe, 0x0006c3a6, 0x0006c78e, 0x0006bc3a,
+0x0006c022, 0x0006c40a, 0x0006c7f2, 0x00000006, 0x5f343469, 0x00000032, 0x00000002, 0x00000070,
+0x00000002, 0x00000074, 0x0000002a, 0x00000001, 0x00000001, 0x00000001, 0x00000004, 0x00000020,
+0x00000000, 0x00000000, 0x0000002c, 0x00000048, 0x00000000, 0x00000000, 0x00000054, 0x00000070,
+0x00000000, 0x00000000, 0x00000080, 0x0000009c, 0x00000000, 0x00000000, 0x000000b0, 0x000000cc,
+0x00000000, 0x00000000, 0x000000e4, 0x00000100, 0x00000000, 0x00000000, 0x0000010c, 0x00000128,
+0x00000000, 0x00000000, 0x00000138, 0x00000154, 0x00000000, 0x00000000, 0x00000168, 0x00000184,
+0x00000000, 0x00000000, 0x0000019c, 0x000001b8, 0x00000000, 0x00000000, 0x000001c8, 0x000001e4,
+0x00000000, 0x00000000, 0x000001fc, 0x00000218, 0x00000000, 0x00000000, 0x00000238, 0x00000254,
+0x00000000, 0x00000000, 0x0000027c, 0x00000298, 0x00000000, 0x00000000, 0x000002ac, 0x000002c8,
+0x00000000, 0x00000000, 0x000002e8, 0x00000304, 0x00000000, 0x00000000, 0x00000330, 0x0000034c,
+0x00000000, 0x00000000, 0x00000384, 0x000003a0, 0x00000000, 0x00000000, 0x000003b8, 0x000003d4,
+0x00000000, 0x00000000, 0x000003fc, 0x00000418, 0x00000000, 0x00000000, 0x00000450, 0x0000046c,
+0x00000000, 0x00000000, 0x000004b4, 0x000004d0, 0x00000000, 0x00000000, 0x000004e0, 0x000004fc,
+0x00000000, 0x00000000, 0x00000510, 0x0000052c, 0x00000000, 0x00000000, 0x00000548, 0x00000564,
+0x00000000, 0x00000000, 0x00000588, 0x000005a4, 0x00000000, 0x00000000, 0x000005d0, 0x000005ec,
+0x00000000, 0x00000000, 0x00000600, 0x0000061c, 0x00000000, 0x00000000, 0x00000638, 0x00000654,
+0x00000000, 0x00000000, 0x00000678, 0x00000694, 0x00000000, 0x00000000, 0x000006c0, 0x000006dc,
+0x00000000, 0x00000000, 0x000006f8, 0x00000714, 0x00000000, 0x00000000, 0x00000740, 0x0000075c,
+0x00000000, 0x00000000, 0x00000798, 0x000007b4, 0x00000000, 0x00000000, 0x00000800, 0x0000081c,
+0x00000000, 0x00000000, 0x00000840, 0x0000085c, 0x00000000, 0x00000000, 0x00000898, 0x000008b4,
+0x00000000, 0x00000000, 0x00000908, 0x00000924, 0x00000000, 0x00000000, 0x00000990, 0x000009ac,
+0x00000000, 0x00000000, 0x000009d8, 0x000009f4, 0x00000000, 0x00000000, 0x00000a40, 0x00000a5c,
+0x00000000, 0x00000000, 0x00000ac8, 0x00000ae4, 0x00000000, 0x00000000, 0x00000b78, 0x00000000,
+0x00000001, 0x00000b70, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+struct test_effect_parameter_value_result test_effect_parameter_value_result_int[] =
+{
+    {"i",     {"i",     NULL, D3DXPC_SCALAR,      D3DXPT_INT, 1, 1, 0, 0, 0, 0,   4},  10},
+    {"i1",    {"i1",    NULL, D3DXPC_VECTOR,      D3DXPT_INT, 1, 1, 0, 0, 0, 0,   4},  20},
+    {"i2",    {"i2",    NULL, D3DXPC_VECTOR,      D3DXPT_INT, 1, 2, 0, 0, 0, 0,   8},  30},
+    {"i3",    {"i3",    NULL, D3DXPC_VECTOR,      D3DXPT_INT, 1, 3, 0, 0, 0, 0,  12},  41},
+    {"i4",    {"i4",    NULL, D3DXPC_VECTOR,      D3DXPT_INT, 1, 4, 0, 0, 0, 0,  16},  53},
+    {"i11",   {"i11",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 1, 1, 0, 0, 0, 0,   4},  66},
+    {"i12",   {"i12",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 1, 2, 0, 0, 0, 0,   8},  76},
+    {"i13",   {"i13",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 1, 3, 0, 0, 0, 0,  12},  87},
+    {"i14",   {"i14",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 1, 4, 0, 0, 0, 0,  16},  99},
+    {"i21",   {"i21",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 2, 1, 0, 0, 0, 0,   8}, 112},
+    {"i22",   {"i22",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 2, 2, 0, 0, 0, 0,  16}, 123},
+    {"i23",   {"i23",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 2, 3, 0, 0, 0, 0,  24}, 136},
+    {"i24",   {"i24",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 2, 4, 0, 0, 0, 0,  32}, 151},
+    {"i31",   {"i31",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 1, 0, 0, 0, 0,  12}, 168},
+    {"i32",   {"i32",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 2, 0, 0, 0, 0,  24}, 180},
+    {"i33",   {"i33",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 3, 0, 0, 0, 0,  36}, 195},
+    {"i34",   {"i34",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 4, 0, 0, 0, 0,  48}, 213},
+    {"i41",   {"i41",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 4, 1, 0, 0, 0, 0,  16}, 234},
+    {"i42",   {"i42",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 4, 2, 0, 0, 0, 0,  32}, 247},
+    {"i43",   {"i43",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 4, 3, 0, 0, 0, 0,  48}, 264},
+    {"i44",   {"i44",   NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 4, 4, 0, 0, 0, 0,  64}, 285},
+    {"i_2",   {"i_2",   NULL, D3DXPC_SCALAR,      D3DXPT_INT, 1, 1, 2, 0, 0, 0,   8}, 310},
+    {"i1_2",  {"i1_2",  NULL, D3DXPC_VECTOR,      D3DXPT_INT, 1, 1, 2, 0, 0, 0,   8}, 321},
+    {"i2_2",  {"i2_2",  NULL, D3DXPC_VECTOR,      D3DXPT_INT, 1, 2, 2, 0, 0, 0,  16}, 333},
+    {"i3_2",  {"i3_2",  NULL, D3DXPC_VECTOR,      D3DXPT_INT, 1, 3, 2, 0, 0, 0,  24}, 347},
+    {"i4_2",  {"i4_2",  NULL, D3DXPC_VECTOR,      D3DXPT_INT, 1, 4, 2, 0, 0, 0,  32}, 363},
+    {"i11_2", {"i11_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 1, 1, 2, 0, 0, 0,   8}, 381},
+    {"i12_2", {"i12_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 1, 2, 2, 0, 0, 0,  16}, 393},
+    {"i13_2", {"i13_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 1, 3, 2, 0, 0, 0,  24}, 407},
+    {"i14_2", {"i14_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 1, 4, 2, 0, 0, 0,  32}, 423},
+    {"i21_2", {"i21_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 2, 1, 2, 0, 0, 0,  16}, 441},
+    {"i22_2", {"i22_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 2, 2, 2, 0, 0, 0,  32}, 455},
+    {"i23_2", {"i23_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 2, 3, 2, 0, 0, 0,  48}, 473},
+    {"i24_2", {"i24_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 2, 4, 2, 0, 0, 0,  64}, 495},
+    {"i31_2", {"i31_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 1, 2, 0, 0, 0,  24}, 521},
+    {"i32_2", {"i32_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 2, 2, 0, 0, 0,  48}, 537},
+    {"i33_2", {"i33_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 3, 2, 0, 0, 0,  72}, 559},
+    {"i34_2", {"i34_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 4, 2, 0, 0, 0,  96}, 587},
+    {"i41_2", {"i41_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 4, 1, 2, 0, 0, 0,  32}, 621},
+    {"i42_2", {"i42_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 4, 2, 2, 0, 0, 0,  64}, 639},
+    {"i43_2", {"i43_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 4, 3, 2, 0, 0, 0,  96}, 665},
+    {"i44_2", {"i44_2", NULL, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 4, 4, 2, 0, 0, 0, 128}, 699},
+};
+
+/*
+ * fxc.exe /Tfx_2_0
+ */
+#if 0
+string s = "test";
+string s_2[2] = {"test1", "test2"};
+texture2D tex;
+Vertexshader v;
+Vertexshader v_2[2];
+Pixelshader p;
+Pixelshader p_2[2];
+technique t { pass p { } }
+#endif
+static const DWORD test_effect_parameter_value_blob_object[] =
+{
+0xfeff0901, 0x00000100, 0x00000000, 0x00000004, 0x00000004, 0x0000001c, 0x00000000, 0x00000000,
+0x00000001, 0x00000002, 0x00000073, 0x00000004, 0x00000004, 0x00000040, 0x00000000, 0x00000002,
+0x00000002, 0x00000003, 0x00000004, 0x00325f73, 0x00000007, 0x00000004, 0x00000060, 0x00000000,
+0x00000000, 0x00000004, 0x00000004, 0x00786574, 0x00000010, 0x00000004, 0x00000080, 0x00000000,
+0x00000000, 0x00000005, 0x00000002, 0x00000076, 0x00000010, 0x00000004, 0x000000a4, 0x00000000,
+0x00000002, 0x00000006, 0x00000007, 0x00000004, 0x00325f76, 0x0000000f, 0x00000004, 0x000000c4,
+0x00000000, 0x00000000, 0x00000008, 0x00000002, 0x00000070, 0x0000000f, 0x00000004, 0x000000e8,
+0x00000000, 0x00000002, 0x00000009, 0x0000000a, 0x00000004, 0x00325f70, 0x00000002, 0x00000070,
+0x00000002, 0x00000074, 0x00000007, 0x00000001, 0x00000007, 0x0000000b, 0x00000004, 0x00000018,
+0x00000000, 0x00000000, 0x00000024, 0x00000038, 0x00000000, 0x00000000, 0x00000048, 0x0000005c,
+0x00000000, 0x00000000, 0x00000068, 0x0000007c, 0x00000000, 0x00000000, 0x00000088, 0x0000009c,
+0x00000000, 0x00000000, 0x000000ac, 0x000000c0, 0x00000000, 0x00000000, 0x000000cc, 0x000000e0,
+0x00000000, 0x00000000, 0x000000f8, 0x00000000, 0x00000001, 0x000000f0, 0x00000000, 0x00000000,
+0x0000000a, 0x00000000, 0x00000009, 0x00000000, 0x0000000a, 0x00000000, 0x00000008, 0x00000000,
+0x00000006, 0x00000000, 0x00000007, 0x00000000, 0x00000005, 0x00000000, 0x00000004, 0x00000000,
+0x00000002, 0x00000006, 0x74736574, 0x00000031, 0x00000003, 0x00000006, 0x74736574, 0x00000032,
+0x00000001, 0x00000005, 0x74736574, 0x00000000,
+};
+
+struct test_effect_parameter_value_result test_effect_parameter_value_result_object[] =
+{
+    {"s",   {"s",   NULL, D3DXPC_OBJECT, D3DXPT_STRING,       0, 0, 0, 0, 0, 0, sizeof(void *)},     0},
+    {"s_2", {"s_2", NULL, D3DXPC_OBJECT, D3DXPT_STRING,       0, 0, 2, 0, 0, 0, 2 * sizeof(void *)}, 0},
+    {"tex", {"tex", NULL, D3DXPC_OBJECT, D3DXPT_TEXTURE2D,    0, 0, 0, 0, 0, 0, sizeof(void *)},     0},
+    {"v",   {"v",   NULL, D3DXPC_OBJECT, D3DXPT_VERTEXSHADER, 0, 0, 0, 0, 0, 0, sizeof(void *)},     0},
+    {"v_2", {"v_2", NULL, D3DXPC_OBJECT, D3DXPT_VERTEXSHADER, 0, 0, 2, 0, 0, 0, 2 * sizeof(void *)}, 0},
+    {"p",   {"p",   NULL, D3DXPC_OBJECT, D3DXPT_PIXELSHADER,  0, 0, 0, 0, 0, 0, sizeof(void *)},     0},
+    {"p_2", {"p_2", NULL, D3DXPC_OBJECT, D3DXPT_PIXELSHADER,  0, 0, 2, 0, 0, 0, 2 * sizeof(void *)}, 0},
+};
+
+/*
+ * fxc.exe /Tfx_2_0
+ */
+#if 0
+float3 f3 = {-3.1, 153.2, 283.3};
+float3 f3min = {-31.1, -31.2, -31.3};
+float3 f3max = {320.1, 320.2, 320.3};
+float4 f4 = {-4.1, 154.2, 284.3, 34.4};
+float4 f4min = {-41.1, -41.2, -41.3, -41.4};
+float4 f4max = {420.1, 42.20, 420.3, 420.4};
+technique t { pass p { } }
+#endif
+static const DWORD test_effect_parameter_value_blob_special[] =
+{
+0xfeff0901, 0x00000150, 0x00000000, 0x00000003, 0x00000001, 0x0000002c, 0x00000000, 0x00000000,
+0x00000003, 0x00000001, 0xc0466666, 0x43193333, 0x438da666, 0x00000003, 0x00003366, 0x00000003,
+0x00000001, 0x0000005c, 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0xc1f8cccd, 0xc1f9999a,
+0xc1fa6666, 0x00000006, 0x696d3366, 0x0000006e, 0x00000003, 0x00000001, 0x00000090, 0x00000000,
+0x00000000, 0x00000003, 0x00000001, 0x43a00ccd, 0x43a0199a, 0x43a02666, 0x00000006, 0x616d3366,
+0x00000078, 0x00000003, 0x00000001, 0x000000c8, 0x00000000, 0x00000000, 0x00000004, 0x00000001,
+0xc0833333, 0x431a3333, 0x438e2666, 0x4209999a, 0x00000003, 0x00003466, 0x00000003, 0x00000001,
+0x000000fc, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0xc2246666, 0xc224cccd, 0xc2253333,
+0xc225999a, 0x00000006, 0x696d3466, 0x0000006e, 0x00000003, 0x00000001, 0x00000134, 0x00000000,
+0x00000000, 0x00000004, 0x00000001, 0x43d20ccd, 0x4228cccd, 0x43d22666, 0x43d23333, 0x00000006,
+0x616d3466, 0x00000078, 0x00000002, 0x00000070, 0x00000002, 0x00000074, 0x00000006, 0x00000001,
+0x00000001, 0x00000001, 0x00000004, 0x00000020, 0x00000000, 0x00000000, 0x00000034, 0x00000050,
+0x00000000, 0x00000000, 0x00000068, 0x00000084, 0x00000000, 0x00000000, 0x0000009c, 0x000000b8,
+0x00000000, 0x00000000, 0x000000d0, 0x000000ec, 0x00000000, 0x00000000, 0x00000108, 0x00000124,
+0x00000000, 0x00000000, 0x00000148, 0x00000000, 0x00000001, 0x00000140, 0x00000000, 0x00000000,
+0x00000000, 0x00000000,
+};
+
+struct test_effect_parameter_value_result test_effect_parameter_value_result_special[] =
+{
+    {"f3",    {"f3",    NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 3, 0, 0, 0, 0,  12},  10},
+    {"f3min", {"f3min", NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 3, 0, 0, 0, 0,  12},  22},
+    {"f3max", {"f3max", NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 3, 0, 0, 0, 0,  12},  35},
+    {"f4",    {"f4",    NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 4, 0, 0, 0, 0,  16},  48},
+    {"f4min", {"f4min", NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 4, 0, 0, 0, 0,  16},  61},
+    {"f4max", {"f4max", NULL, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 4, 0, 0, 0, 0,  16},  75},
+};
+
+#define ADD_PARAMETER_VALUE(x) {\
+    test_effect_parameter_value_blob_ ## x,\
+    sizeof(test_effect_parameter_value_blob_ ## x),\
+    test_effect_parameter_value_result_ ## x,\
+    ARRAY_SIZE(test_effect_parameter_value_result_ ## x),\
+}
+
+static const struct
+{
+    const DWORD *blob;
+    UINT blob_size;
+    const struct test_effect_parameter_value_result *res;
+    UINT res_count;
+}
+test_effect_parameter_value_data[] =
+{
+    ADD_PARAMETER_VALUE(float),
+    ADD_PARAMETER_VALUE(int),
+    ADD_PARAMETER_VALUE(object),
+    ADD_PARAMETER_VALUE(special),
+};
+
+#undef ADD_PARAMETER_VALUE
+
+/* Multiple of 16 to cover complete matrices */
+#define EFFECT_PARAMETER_VALUE_ARRAY_SIZE 48
+/* Constants for special INT/FLOAT conversation */
+#define INT_FLOAT_MULTI 255.0f
+#define INT_FLOAT_MULTI_INVERSE (1/INT_FLOAT_MULTI)
+
+static void test_effect_parameter_value_GetValue(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    DWORD value[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+    HRESULT hr;
+    UINT l;
+
+    memset(value, 0xab, sizeof(value));
+    hr = effect->lpVtbl->GetValue(effect, parameter, value, res_desc->Bytes);
+    if (res_desc->Class == D3DXPC_SCALAR
+            || res_desc->Class == D3DXPC_VECTOR
+            || res_desc->Class == D3DXPC_MATRIX_ROWS)
+    {
+        ok(hr == D3D_OK, "%u - %s: GetValue failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+
+        for (l = 0; l < res_desc->Bytes / sizeof(*value); ++l)
+        {
+            ok(value[l] == res_value[l], "%u - %s: GetValue value[%u] failed, got %#x, expected %#x\n",
+                    i, res_full_name, l, value[l], res_value[l]);
+        }
+
+        for (l = res_desc->Bytes / sizeof(*value); l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l)
+        {
+            ok(value[l] == 0xabababab, "%u - %s: GetValue value[%u] failed, got %#x, expected %#x\n",
+                    i, res_full_name, l, value[l], 0xabababab);
+        }
+    }
+    else if (res_desc->Class == D3DXPC_OBJECT)
+    {
+        switch (res_desc->Type)
+        {
+            case D3DXPT_PIXELSHADER:
+            case D3DXPT_VERTEXSHADER:
+            case D3DXPT_TEXTURE2D:
+                ok(hr == D3D_OK, "%u - %s: GetValue failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+
+                for (l = 0; l < (res_desc->Elements ? res_desc->Elements : 1); ++l)
+                {
+                    IUnknown *unk = *((IUnknown **)value + l);
+                    if (unk) IUnknown_Release(unk);
+                }
+                break;
+
+            case D3DXPT_STRING:
+                ok(hr == D3D_OK, "%u - %s: GetValue failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+                break;
+
+            default:
+                ok(0, "Type is %u, this should not happen!\n", res_desc->Type);
+                break;
+        }
+    }
+    else
+    {
+        ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetValue failed, got %#x, expected %#x\n",
+                i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+        for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l)
+        {
+            ok(value[l] == 0xabababab, "%u - %s: GetValue value[%u] failed, got %#x, expected %#x\n",
+                    i, res_full_name, l, value[l], 0xabababab);
+        }
+    }
+}
+
+static void test_effect_parameter_value_GetBool(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    BOOL bvalue = 0xabababab;
+    HRESULT hr;
+
+    hr = effect->lpVtbl->GetBool(effect, parameter, &bvalue);
+    if (!res_desc->Elements && res_desc->Rows == 1 && res_desc->Columns == 1)
+    {
+        ok(hr == D3D_OK, "%u - %s: GetBool failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+        ok(bvalue == get_bool(res_value), "%u - %s: GetBool bvalue failed, got %#x, expected %#x\n",
+                i, res_full_name, bvalue, get_bool(res_value));
+    }
+    else
+    {
+        ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetBool failed, got %#x, expected %#x\n",
+                i, res_full_name, hr, D3DERR_INVALIDCALL);
+        ok(bvalue == 0xabababab, "%u - %s: GetBool bvalue failed, got %#x, expected %#x\n",
+                i, res_full_name, bvalue, 0xabababab);
+    }
+}
+
+static void test_effect_parameter_value_GetBoolArray(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    BOOL bavalue[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+    HRESULT hr;
+    UINT l, err = 0;
+
+    memset(bavalue, 0xab, sizeof(bavalue));
+    hr = effect->lpVtbl->GetBoolArray(effect, parameter, bavalue, res_desc->Bytes / sizeof(*bavalue));
+    if (res_desc->Class == D3DXPC_SCALAR
+            || res_desc->Class == D3DXPC_VECTOR
+            || res_desc->Class == D3DXPC_MATRIX_ROWS)
+    {
+        ok(hr == D3D_OK, "%u - %s: GetBoolArray failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+
+        for (l = 0; l < res_desc->Bytes / sizeof(*bavalue); ++l)
+        {
+            if (bavalue[l] != get_bool(&res_value[l])) ++err;
+        }
+
+        for (l = res_desc->Bytes / sizeof(*bavalue); l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l)
+        {
+            if (bavalue[l] != 0xabababab) ++err;
+        }
+    }
+    else
+    {
+        ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetBoolArray failed, got %#x, expected %#x\n",
+                i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+        for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (bavalue[l] != 0xabababab) ++err;
+    }
+    ok(!err, "%u - %s: GetBoolArray failed with %u errors\n", i, res_full_name, err);
+}
+
+static void test_effect_parameter_value_GetInt(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    INT ivalue = 0xabababab;
+    HRESULT hr;
+
+    hr = effect->lpVtbl->GetInt(effect, parameter, &ivalue);
+    if (!res_desc->Elements && res_desc->Columns == 1 && res_desc->Rows == 1)
+    {
+        ok(hr == D3D_OK, "%u - %s: GetInt failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+        ok(ivalue == get_int(res_desc->Type, res_value), "%u - %s: GetInt ivalue failed, got %i, expected %i\n",
+                i, res_full_name, ivalue, get_int(res_desc->Type, res_value));
+    }
+    else if(!res_desc->Elements && res_desc->Type == D3DXPT_FLOAT &&
+            ((res_desc->Class == D3DXPC_VECTOR && res_desc->Columns != 2) ||
+            (res_desc->Class == D3DXPC_MATRIX_ROWS && res_desc->Rows != 2 && res_desc->Columns == 1)))
+    {
+        INT tmp;
+
+        ok(hr == D3D_OK, "%u - %s: GetInt failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+
+        tmp = (INT)(min(max(0.0f, *((FLOAT *)res_value + 2)), 1.0f) * INT_FLOAT_MULTI);
+        tmp += ((INT)(min(max(0.0f, *((FLOAT *)res_value + 1)), 1.0f) * INT_FLOAT_MULTI)) << 8;
+        tmp += ((INT)(min(max(0.0f, *((FLOAT *)res_value + 0)), 1.0f) * INT_FLOAT_MULTI)) << 16;
+        if (res_desc->Columns * res_desc->Rows > 3)
+        {
+            tmp += ((INT)(min(max(0.0f, *((FLOAT *)res_value + 3)), 1.0f) * INT_FLOAT_MULTI)) << 24;
+        }
+
+        ok(ivalue == tmp, "%u - %s: GetInt ivalue failed, got %x, expected %x\n",
+                i, res_full_name, ivalue, tmp);
+    }
+    else
+    {
+        ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetInt failed, got %#x, expected %#x\n",
+                i, res_full_name, hr, D3DERR_INVALIDCALL);
+        ok(ivalue == 0xabababab, "%u - %s: GetInt ivalue failed, got %i, expected %i\n",
+                i, res_full_name, ivalue, 0xabababab);
+    }
+}
+
+static void test_effect_parameter_value_GetIntArray(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    INT iavalue[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+    HRESULT hr;
+    UINT l, err = 0;
+
+    memset(iavalue, 0xab, sizeof(iavalue));
+    hr = effect->lpVtbl->GetIntArray(effect, parameter, iavalue, res_desc->Bytes / sizeof(*iavalue));
+    if (res_desc->Class == D3DXPC_SCALAR
+            || res_desc->Class == D3DXPC_VECTOR
+            || res_desc->Class == D3DXPC_MATRIX_ROWS)
+    {
+        ok(hr == D3D_OK, "%u - %s: GetIntArray failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+
+        for (l = 0; l < res_desc->Bytes / sizeof(*iavalue); ++l)
+        {
+            if (iavalue[l] != get_int(res_desc->Type, &res_value[l])) ++err;
+        }
+
+        for (l = res_desc->Bytes / sizeof(*iavalue); l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l)
+        {
+            if (iavalue[l] != 0xabababab) ++err;
+        }
+    }
+    else
+    {
+        ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetIntArray failed, got %#x, expected %#x\n",
+                i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+        for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (iavalue[l] != 0xabababab) ++err;
+    }
+    ok(!err, "%u - %s: GetIntArray failed with %u errors\n", i, res_full_name, err);
+}
+
+static void test_effect_parameter_value_GetFloat(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    HRESULT hr;
+    DWORD cmp = 0xabababab;
+    FLOAT fvalue = *(FLOAT *)&cmp;
+
+    hr = effect->lpVtbl->GetFloat(effect, parameter, &fvalue);
+    if (!res_desc->Elements && res_desc->Columns == 1 && res_desc->Rows == 1)
+    {
+        ok(hr == D3D_OK, "%u - %s: GetFloat failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+        ok(compare_float(fvalue, get_float(res_desc->Type, res_value), 512), "%u - %s: GetFloat fvalue failed, got %f, expected %f\n",
+                i, res_full_name, fvalue, get_float(res_desc->Type, res_value));
+    }
+    else
+    {
+        ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetFloat failed, got %#x, expected %#x\n",
+                i, res_full_name, hr, D3DERR_INVALIDCALL);
+        ok(fvalue == *(FLOAT *)&cmp, "%u - %s: GetFloat fvalue failed, got %f, expected %f\n",
+                i, res_full_name, fvalue, *(FLOAT *)&cmp);
+    }
+}
+
+static void test_effect_parameter_value_GetFloatArray(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    FLOAT favalue[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+    HRESULT hr;
+    UINT l, err = 0;
+    DWORD cmp = 0xabababab;
+
+    memset(favalue, 0xab, sizeof(favalue));
+    hr = effect->lpVtbl->GetFloatArray(effect, parameter, favalue, res_desc->Bytes / sizeof(*favalue));
+    if (res_desc->Class == D3DXPC_SCALAR
+            || res_desc->Class == D3DXPC_VECTOR
+            || res_desc->Class == D3DXPC_MATRIX_ROWS)
+    {
+        ok(hr == D3D_OK, "%u - %s: GetFloatArray failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+
+        for (l = 0; l < res_desc->Bytes / sizeof(*favalue); ++l)
+        {
+            if (!compare_float(favalue[l], get_float(res_desc->Type, &res_value[l]), 512)) ++err;
+        }
+
+        for (l = res_desc->Bytes / sizeof(*favalue); l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l)
+        {
+            if (favalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+    }
+    else
+    {
+        ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetFloatArray failed, got %#x, expected %#x\n",
+                i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+        for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (favalue[l] != *(FLOAT *)&cmp) ++err;
+    }
+    ok(!err, "%u - %s: GetFloatArray failed with %u errors\n", i, res_full_name, err);
+}
+
+static void test_effect_parameter_value_GetVector(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    HRESULT hr;
+    DWORD cmp = 0xabababab;
+    FLOAT fvalue[4];
+    UINT l, err = 0;
+
+    memset(fvalue, 0xab, sizeof(fvalue));
+    hr = effect->lpVtbl->GetVector(effect, parameter, (D3DXVECTOR4 *)&fvalue);
+    if (!res_desc->Elements &&
+            (res_desc->Class == D3DXPC_SCALAR || res_desc->Class == D3DXPC_VECTOR) &&
+            res_desc->Type == D3DXPT_INT && res_desc->Bytes == 4)
+    {
+        DWORD tmp;
+
+        ok(hr == D3D_OK, "%u - %s: GetVector failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+
+        tmp = (DWORD)(*(fvalue + 2) * INT_FLOAT_MULTI);
+        tmp += ((DWORD)(*(fvalue + 1) * INT_FLOAT_MULTI)) << 8;
+        tmp += ((DWORD)(*fvalue * INT_FLOAT_MULTI)) << 16;
+        tmp += ((DWORD)(*(fvalue + 3) * INT_FLOAT_MULTI)) << 24;
+
+        if (*res_value != tmp) ++err;
+    }
+    else if (!res_desc->Elements && (res_desc->Class == D3DXPC_SCALAR || res_desc->Class == D3DXPC_VECTOR))
+    {
+        ok(hr == D3D_OK, "%u - %s: GetVector failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+
+        for (l = 0; l < res_desc->Columns; ++l)
+        {
+            if (!compare_float(fvalue[l], get_float(res_desc->Type, &res_value[l]), 512)) ++err;
+        }
+
+        for (l = res_desc->Columns; l < 4; ++l) if (fvalue[l] != 0.0f) ++err;
+    }
+    else
+    {
+        ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetVector failed, got %#x, expected %#x\n",
+                i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+        for (l = 0; l < 4; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+    }
+    ok(!err, "%u - %s: GetVector failed with %u errors\n", i, res_full_name, err);
+}
+
+static void test_effect_parameter_value_GetVectorArray(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    HRESULT hr;
+    DWORD cmp = 0xabababab;
+    FLOAT fvalue[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+    UINT l, k, element, err = 0;
+
+    for (element = 0; element <= res_desc->Elements + 1; ++element)
+    {
+        memset(fvalue, 0xab, sizeof(fvalue));
+        hr = effect->lpVtbl->GetVectorArray(effect, parameter, (D3DXVECTOR4 *)&fvalue, element);
+        if (!element)
+        {
+            ok(hr == D3D_OK, "%u - %s[%u]: GetVectorArray failed, got %#x, expected %#x\n", i, res_full_name, element, hr, D3D_OK);
+
+            for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        else if (element <= res_desc->Elements && res_desc->Class == D3DXPC_VECTOR)
+        {
+            ok(hr == D3D_OK, "%u - %s[%u]: GetVectorArray failed, got %#x, expected %#x\n", i, res_full_name, element, hr, D3D_OK);
+
+            for (k = 0; k < element; ++k)
+            {
+                for (l = 0; l < res_desc->Columns; ++l)
+                {
+                    if (!compare_float(fvalue[l + k * 4], get_float(res_desc->Type,
+                            &res_value[l + k * res_desc->Columns]), 512))
+                        ++err;
+                }
+
+                for (l = res_desc->Columns; l < 4; ++l) if (fvalue[l + k * 4] != 0.0f) ++err;
+            }
+
+            for (l = element * 4; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        else
+        {
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s[%u]: GetVectorArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3DERR_INVALIDCALL);
+
+            for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        ok(!err, "%u - %s[%u]: GetVectorArray failed with %u errors\n", i, res_full_name, element, err);
+    }
+}
+
+static void test_effect_parameter_value_GetMatrix(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    HRESULT hr;
+    union
+    {
+        DWORD d;
+        float f;
+    } cmp;
+    float fvalue[16];
+    UINT l, k, err = 0;
+
+    cmp.d = 0xabababab;
+    memset(fvalue, 0xab, sizeof(fvalue));
+    hr = effect->lpVtbl->GetMatrix(effect, parameter, (D3DXMATRIX *)&fvalue);
+    if (!res_desc->Elements && res_desc->Class == D3DXPC_MATRIX_ROWS)
+    {
+        ok(hr == D3D_OK, "%u - %s: GetMatrix failed, got %#x, expected %#x.\n", i, res_full_name, hr, D3D_OK);
+
+        for (k = 0; k < 4; ++k)
+        {
+            for (l = 0; l < 4; ++l)
+            {
+                if (k < res_desc->Columns && l < res_desc->Rows)
+                {
+                    if (!compare_float(fvalue[l * 4 + k], get_float(res_desc->Type,
+                            &res_value[l * res_desc->Columns + k]), 512))
+                        ++err;
+                }
+                else if (fvalue[l * 4 + k] != 0.0f) ++err;
+            }
+        }
+    }
+    else
+    {
+        ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrix failed, got %#x, expected %#x.\n",
+                i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+        for (l = 0; l < ARRAY_SIZE(fvalue); ++l)
+            if (fvalue[l] != cmp.f)
+                ++err;
+    }
+    ok(!err, "%u - %s: GetMatrix failed with %u errors.\n", i, res_full_name, err);
+}
+
+static void test_effect_parameter_value_GetMatrixArray(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    HRESULT hr;
+    DWORD cmp = 0xabababab;
+    FLOAT fvalue[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+    UINT l, k, m, element, err = 0;
+
+    for (element = 0; element <= res_desc->Elements + 1; ++element)
+    {
+        memset(fvalue, 0xab, sizeof(fvalue));
+        hr = effect->lpVtbl->GetMatrixArray(effect, parameter, (D3DXMATRIX *)&fvalue, element);
+        if (!element)
+        {
+            ok(hr == D3D_OK, "%u - %s[%u]: GetMatrixArray failed, got %#x, expected %#x\n", i, res_full_name, element, hr, D3D_OK);
+
+            for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        else if (element <= res_desc->Elements && res_desc->Class == D3DXPC_MATRIX_ROWS)
+        {
+            ok(hr == D3D_OK, "%u - %s[%u]: GetMatrixArray failed, got %#x, expected %#x\n", i, res_full_name, element, hr, D3D_OK);
+
+            for (m = 0; m < element; ++m)
+            {
+                for (k = 0; k < 4; ++k)
+                {
+                    for (l = 0; l < 4; ++l)
+                    {
+                        if (k < res_desc->Columns && l < res_desc->Rows)
+                        {
+                            if (!compare_float(fvalue[m * 16 + l * 4 + k], get_float(res_desc->Type,
+                                    &res_value[m * res_desc->Columns * res_desc->Rows + l * res_desc->Columns + k]), 512))
+                                ++err;
+                        }
+                        else if (fvalue[m * 16 + l * 4 + k] != 0.0f) ++err;
+                    }
+                }
+            }
+
+            for (l = element * 16; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        else
+        {
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s[%u]: GetMatrixArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3DERR_INVALIDCALL);
+
+            for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        ok(!err, "%u - %s[%u]: GetMatrixArray failed with %u errors\n", i, res_full_name, element, err);
+    }
+}
+
+static void test_effect_parameter_value_GetMatrixPointerArray(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    HRESULT hr;
+    DWORD cmp = 0xabababab;
+    FLOAT fvalue[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+    D3DXMATRIX *matrix_pointer_array[sizeof(fvalue)/sizeof(D3DXMATRIX)];
+    UINT l, k, m, element, err = 0;
+
+    for (element = 0; element <= res_desc->Elements + 1; ++element)
+    {
+        memset(fvalue, 0xab, sizeof(fvalue));
+        for (l = 0; l < element; ++l)
+        {
+            matrix_pointer_array[l] = (D3DXMATRIX *)&fvalue[l * sizeof(**matrix_pointer_array) / sizeof(FLOAT)];
+        }
+        hr = effect->lpVtbl->GetMatrixPointerArray(effect, parameter, matrix_pointer_array, element);
+        if (!element)
+        {
+            ok(hr == D3D_OK, "%u - %s[%u]: GetMatrixPointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3D_OK);
+
+            for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        else if (element <= res_desc->Elements && res_desc->Class == D3DXPC_MATRIX_ROWS)
+        {
+            ok(hr == D3D_OK, "%u - %s[%u]: GetMatrixPointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3D_OK);
+
+            for (m = 0; m < element; ++m)
+            {
+                for (k = 0; k < 4; ++k)
+                {
+                    for (l = 0; l < 4; ++l)
+                    {
+                        if (k < res_desc->Columns && l < res_desc->Rows)
+                        {
+                            if (!compare_float(fvalue[m * 16 + l * 4 + k], get_float(res_desc->Type,
+                                    &res_value[m * res_desc->Columns * res_desc->Rows + l * res_desc->Columns + k]), 512))
+                                ++err;
+                        }
+                        else if (fvalue[m * 16 + l * 4 + k] != 0.0f) ++err;
+                    }
+                }
+            }
+
+            for (l = element * 16; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        else
+        {
+            for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s[%u]: GetMatrixPointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3DERR_INVALIDCALL);
+        }
+        ok(!err, "%u - %s[%u]: GetMatrixPointerArray failed with %u errors\n", i, res_full_name, element, err);
+    }
+}
+
+static void test_effect_parameter_value_GetMatrixTranspose(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    HRESULT hr;
+    union
+    {
+        DWORD d;
+        float f;
+    } cmp;
+    float fvalue[16];
+    UINT l, k, err = 0;
+
+    cmp.d = 0xabababab;
+    memset(fvalue, 0xab, sizeof(fvalue));
+    hr = effect->lpVtbl->GetMatrixTranspose(effect, parameter, (D3DXMATRIX *)&fvalue);
+    if (!res_desc->Elements && res_desc->Class == D3DXPC_MATRIX_ROWS)
+    {
+        ok(hr == D3D_OK, "%u - %s: GetMatrixTranspose failed, got %#x, expected %#x.\n", i, res_full_name, hr, D3D_OK);
+
+        for (k = 0; k < 4; ++k)
+        {
+            for (l = 0; l < 4; ++l)
+            {
+                if (k < res_desc->Columns && l < res_desc->Rows)
+                {
+                    if (!compare_float(fvalue[l + k * 4], get_float(res_desc->Type,
+                            &res_value[l * res_desc->Columns + k]), 512))
+                        ++err;
+                }
+                else if (fvalue[l + k * 4] != 0.0f) ++err;
+            }
+        }
+    }
+    else if (!res_desc->Elements && (res_desc->Class == D3DXPC_VECTOR || res_desc->Class == D3DXPC_SCALAR))
+    {
+        ok(hr == D3D_OK, "%u - %s: GetMatrixTranspose failed, got %#x, expected %#x.\n", i, res_full_name, hr, D3D_OK);
+
+        for (k = 0; k < 4; ++k)
+        {
+            for (l = 0; l < 4; ++l)
+            {
+                if (k < res_desc->Columns && l < res_desc->Rows)
+                {
+                    if (!compare_float(fvalue[l * 4 + k], get_float(res_desc->Type,
+                            &res_value[l * res_desc->Columns + k]), 512))
+                        ++err;
+                }
+                else if (fvalue[l * 4 + k] != 0.0f) ++err;
+            }
+        }
+    }
+    else
+    {
+        ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixTranspose failed, got %#x, expected %#x.\n",
+                i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+        for (l = 0; l < ARRAY_SIZE(fvalue); ++l)
+            if (fvalue[l] != cmp.f)
+                ++err;
+    }
+    ok(!err, "%u - %s: GetMatrixTranspose failed with %u errors.\n", i, res_full_name, err);
+}
+
+static void test_effect_parameter_value_GetMatrixTransposeArray(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    HRESULT hr;
+    DWORD cmp = 0xabababab;
+    FLOAT fvalue[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+    UINT l, k, m, element, err = 0;
+
+    for (element = 0; element <= res_desc->Elements + 1; ++element)
+    {
+        memset(fvalue, 0xab, sizeof(fvalue));
+        hr = effect->lpVtbl->GetMatrixTransposeArray(effect, parameter, (D3DXMATRIX *)&fvalue, element);
+        if (!element)
+        {
+            ok(hr == D3D_OK, "%u - %s[%u]: GetMatrixTransposeArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3D_OK);
+
+            for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        else if (element <= res_desc->Elements && res_desc->Class == D3DXPC_MATRIX_ROWS)
+        {
+            ok(hr == D3D_OK, "%u - %s[%u]: GetMatrixTransposeArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3D_OK);
+
+            for (m = 0; m < element; ++m)
+            {
+                for (k = 0; k < 4; ++k)
+                {
+                    for (l = 0; l < 4; ++l)
+                    {
+                        if (k < res_desc->Columns && l < res_desc->Rows)
+                        {
+                            if (!compare_float(fvalue[m * 16 + l + k * 4], get_float(res_desc->Type,
+                                    &res_value[m * res_desc->Columns * res_desc->Rows + l * res_desc->Columns + k]), 512))
+                                ++err;
+                        }
+                        else if (fvalue[m * 16 + l + k * 4] != 0.0f) ++err;
+                    }
+                }
+            }
+
+            for (l = element * 16; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        else
+        {
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s[%u]: GetMatrixTransposeArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3DERR_INVALIDCALL);
+
+            for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        ok(!err, "%u - %s[%u]: GetMatrixTransposeArray failed with %u errors\n", i, res_full_name, element, err);
+    }
+}
+
+static void test_effect_parameter_value_GetMatrixTransposePointerArray(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    HRESULT hr;
+    DWORD cmp = 0xabababab;
+    FLOAT fvalue[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+    D3DXMATRIX *matrix_pointer_array[sizeof(fvalue)/sizeof(D3DXMATRIX)];
+    UINT l, k, m, element, err = 0;
+
+    for (element = 0; element <= res_desc->Elements + 1; ++element)
+    {
+        memset(fvalue, 0xab, sizeof(fvalue));
+        for (l = 0; l < element; ++l)
+        {
+            matrix_pointer_array[l] = (D3DXMATRIX *)&fvalue[l * sizeof(**matrix_pointer_array) / sizeof(FLOAT)];
+        }
+        hr = effect->lpVtbl->GetMatrixTransposePointerArray(effect, parameter, matrix_pointer_array, element);
+        if (!element)
+        {
+            ok(hr == D3D_OK, "%u - %s[%u]: GetMatrixTransposePointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3D_OK);
+
+            for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        else if (element <= res_desc->Elements && res_desc->Class == D3DXPC_MATRIX_ROWS)
+        {
+            ok(hr == D3D_OK, "%u - %s[%u]: GetMatrixTransposePointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3D_OK);
+
+            for (m = 0; m < element; ++m)
+            {
+                for (k = 0; k < 4; ++k)
+                {
+                    for (l = 0; l < 4; ++l)
+                    {
+                        if (k < res_desc->Columns && l < res_desc->Rows)
+                        {
+                            if (!compare_float(fvalue[m * 16 + l + k * 4], get_float(res_desc->Type,
+                                    &res_value[m * res_desc->Columns * res_desc->Rows + l * res_desc->Columns + k]), 512))
+                                ++err;
+                        }
+                        else if (fvalue[m * 16 + l + k * 4] != 0.0f) ++err;
+                    }
+                }
+            }
+
+            for (l = element * 16; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        else
+        {
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s[%u]: GetMatrixTransposePointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, element, hr, D3DERR_INVALIDCALL);
+
+            for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l) if (fvalue[l] != *(FLOAT *)&cmp) ++err;
+        }
+        ok(!err, "%u - %s[%u]: GetMatrixTransposePointerArray failed with %u errors\n", i, res_full_name, element, err);
+    }
+}
+
+static void test_effect_parameter_value_GetTestGroup(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    test_effect_parameter_value_GetValue(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetBool(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetBoolArray(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetInt(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetIntArray(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetFloat(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetFloatArray(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetVector(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetVectorArray(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetMatrix(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetMatrixArray(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetMatrixPointerArray(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetMatrixTranspose(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetMatrixTransposeArray(res, effect, res_value, parameter, i);
+    test_effect_parameter_value_GetMatrixTransposePointerArray(res, effect, res_value, parameter, i);
+}
+
+static void test_effect_parameter_value_ResetValue(const struct test_effect_parameter_value_result *res,
+        ID3DXEffect *effect, const DWORD *res_value, D3DXHANDLE parameter, UINT i)
+{
+    const D3DXPARAMETER_DESC *res_desc = &res->desc;
+    const char *res_full_name = res->full_name;
+    HRESULT hr;
+
+    if (res_desc->Class == D3DXPC_SCALAR
+            || res_desc->Class == D3DXPC_VECTOR
+            || res_desc->Class == D3DXPC_MATRIX_ROWS)
+    {
+        hr = effect->lpVtbl->SetValue(effect, parameter, res_value, res_desc->Bytes);
+        ok(hr == D3D_OK, "%u - %s: SetValue failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+    }
+    else
+    {
+        /* nothing to do */
+        switch (res_desc->Type)
+        {
+            case D3DXPT_PIXELSHADER:
+            case D3DXPT_VERTEXSHADER:
+            case D3DXPT_TEXTURE2D:
+            case D3DXPT_STRING:
+                break;
+
+            default:
+                ok(0, "Type is %u, this should not happen!\n", res_desc->Type);
+                break;
+        }
+    }
+}
+
+static void test_effect_parameter_value(IDirect3DDevice9 *device)
+{
+    unsigned int effect_count = ARRAY_SIZE(test_effect_parameter_value_data), i;
+
+    for (i = 0; i < effect_count; ++i)
+    {
+        const struct test_effect_parameter_value_result *res = test_effect_parameter_value_data[i].res;
+        UINT res_count = test_effect_parameter_value_data[i].res_count;
+        const DWORD *blob = test_effect_parameter_value_data[i].blob;
+        UINT blob_size = test_effect_parameter_value_data[i].blob_size;
+        HRESULT hr;
+        ID3DXEffect *effect;
+        D3DXEFFECT_DESC edesc;
+        ULONG count;
+        UINT k;
+
+        hr = D3DXCreateEffect(device, blob, blob_size, NULL, NULL, 0, NULL, &effect, NULL);
+        ok(hr == D3D_OK, "%u: D3DXCreateEffect failed, got %#x, expected %#x\n", i, hr, D3D_OK);
+
+        hr = effect->lpVtbl->GetDesc(effect, &edesc);
+        ok(hr == D3D_OK, "%u: GetDesc failed, got %#x, expected %#x\n", i, hr, D3D_OK);
+        ok(edesc.Parameters == res_count, "%u: Parameters failed, got %u, expected %u\n",
+                i, edesc.Parameters, res_count);
+
+        for (k = 0; k < res_count; ++k)
+        {
+            const D3DXPARAMETER_DESC *res_desc = &res[k].desc;
+            const char *res_full_name = res[k].full_name;
+            UINT res_value_offset = res[k].value_offset;
+            D3DXHANDLE parameter;
+            D3DXPARAMETER_DESC pdesc;
+            BOOL bvalue = TRUE;
+            INT ivalue = 42;
+            FLOAT fvalue = 2.71828f;
+            DWORD input_value[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+            DWORD expected_value[EFFECT_PARAMETER_VALUE_ARRAY_SIZE];
+            UINT l, n, m, element;
+            const D3DXMATRIX *matrix_pointer_array[sizeof(input_value)/sizeof(D3DXMATRIX)];
+
+            parameter = effect->lpVtbl->GetParameterByName(effect, NULL, res_full_name);
+            ok(parameter != NULL, "%u - %s: GetParameterByName failed\n", i, res_full_name);
+
+            hr = effect->lpVtbl->GetParameterDesc(effect, parameter, &pdesc);
+            ok(hr == D3D_OK, "%u - %s: GetParameterDesc failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+
+            ok(res_desc->Name ? !strcmp(pdesc.Name, res_desc->Name) : !pdesc.Name,
+                    "%u - %s: GetParameterDesc Name failed, got \"%s\", expected \"%s\"\n",
+                    i, res_full_name, pdesc.Name, res_desc->Name);
+            ok(res_desc->Semantic ? !strcmp(pdesc.Semantic, res_desc->Semantic) : !pdesc.Semantic,
+                    "%u - %s: GetParameterDesc Semantic failed, got \"%s\", expected \"%s\"\n",
+                    i, res_full_name, pdesc.Semantic, res_desc->Semantic);
+            ok(res_desc->Class == pdesc.Class, "%u - %s: GetParameterDesc Class failed, got %#x, expected %#x\n",
+                    i, res_full_name, pdesc.Class, res_desc->Class);
+            ok(res_desc->Type == pdesc.Type, "%u - %s: GetParameterDesc Type failed, got %#x, expected %#x\n",
+                    i, res_full_name, pdesc.Type, res_desc->Type);
+            ok(res_desc->Rows == pdesc.Rows, "%u - %s: GetParameterDesc Rows failed, got %u, expected %u\n",
+                    i, res_full_name, pdesc.Rows, res_desc->Rows);
+            ok(res_desc->Columns == pdesc.Columns, "%u - %s: GetParameterDesc Columns failed, got %u, expected %u\n",
+                    i, res_full_name, pdesc.Columns, res_desc->Columns);
+            ok(res_desc->Elements == pdesc.Elements, "%u - %s: GetParameterDesc Elements failed, got %u, expected %u\n",
+                    i, res_full_name, pdesc.Elements, res_desc->Elements);
+            ok(res_desc->Annotations == pdesc.Annotations, "%u - %s: GetParameterDesc Annotations failed, got %u, expected %u\n",
+                    i, res_full_name, pdesc.Annotations, res_desc->Annotations);
+            ok(res_desc->StructMembers == pdesc.StructMembers, "%u - %s: GetParameterDesc StructMembers failed, got %u, expected %u\n",
+                    i, res_full_name, pdesc.StructMembers, res_desc->StructMembers);
+            ok(res_desc->Flags == pdesc.Flags, "%u - %s: GetParameterDesc Flags failed, got %u, expected %u\n",
+                    i, res_full_name, pdesc.Flags, res_desc->Flags);
+            ok(res_desc->Bytes == pdesc.Bytes, "%u - %s: GetParameterDesc Bytes, got %u, expected %u\n",
+                    i, res_full_name, pdesc.Bytes, res_desc->Bytes);
+
+            /* check size */
+            ok(EFFECT_PARAMETER_VALUE_ARRAY_SIZE >= res_desc->Bytes / 4 +
+                    (res_desc->Elements ? res_desc->Bytes / 4 / res_desc->Elements : 0),
+                    "%u - %s: Warning: Array size too small\n", i, res_full_name);
+
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, &blob[res_value_offset], parameter, i);
+            test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /*
+             * check invalid calls
+             * These will crash:
+             * effect->lpVtbl->SetBoolArray(effect, parameter, NULL, res_desc->Bytes / sizeof(BOOL));
+             * effect->lpVtbl->SetIntArray(effect, parameter, NULL, res_desc->Bytes / sizeof(INT));
+             * effect->lpVtbl->SetFloatArray(effect, parameter, NULL, res_desc->Bytes / sizeof(FLOAT));
+             * effect->lpVtbl->SetVector(effect, parameter, NULL);
+             * effect->lpVtbl->SetVectorArray(effect, parameter, NULL, res_desc->Elements ? res_desc->Elements : 1);
+             * effect->lpVtbl->SetMatrix(effect, parameter, NULL);
+             * effect->lpVtbl->GetMatrix(effect, parameter, NULL);
+             * effect->lpVtbl->SetMatrixArray(effect, parameter, NULL, res_desc->Elements ? res_desc->Elements : 1);
+             * effect->lpVtbl->SetMatrixPointerArray(effect, parameter, NULL, res_desc->Elements ? res_desc->Elements : 1);
+             * effect->lpVtbl->SetMatrixTranspose(effect, parameter, NULL);
+             * effect->lpVtbl->SetMatrixTransposeArray(effect, parameter, NULL, res_desc->Elements ? res_desc->Elements : 1);
+             * effect->lpVtbl->SetMatrixTransposePointerArray(effect, parameter, NULL, res_desc->Elements ? res_desc->Elements : 1);
+             * effect->lpVtbl->GetValue(effect, parameter, NULL, res_desc->Bytes);
+             * effect->lpVtbl->SetValue(effect, parameter, NULL, res_desc->Bytes);
+             */
+            hr = effect->lpVtbl->SetBool(effect, NULL, bvalue);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetBool failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetBool(effect, NULL, &bvalue);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetBool failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetBool(effect, parameter, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetBool failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetBoolArray(effect, NULL, (BOOL *)input_value, res_desc->Bytes / sizeof(BOOL));
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetBoolArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetBoolArray(effect, NULL, (BOOL *)input_value, res_desc->Bytes / sizeof(BOOL));
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetBoolArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetBoolArray(effect, parameter, NULL, res_desc->Bytes / sizeof(BOOL));
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetBoolArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetInt(effect, NULL, ivalue);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetInt failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetInt(effect, NULL, &ivalue);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetInt failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetInt(effect, parameter, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetInt failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetIntArray(effect, NULL, (INT *)input_value, res_desc->Bytes / sizeof(INT));
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetIntArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetIntArray(effect, NULL, (INT *)input_value, res_desc->Bytes / sizeof(INT));
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetIntArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetIntArray(effect, parameter, NULL, res_desc->Bytes / sizeof(INT));
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetIntArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetFloat(effect, NULL, fvalue);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetFloat failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetFloat(effect, NULL, &fvalue);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetFloat failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetFloat(effect, parameter, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetFloat failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetFloatArray(effect, NULL, (FLOAT *)input_value, res_desc->Bytes / sizeof(FLOAT));
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetFloatArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetFloatArray(effect, NULL, (FLOAT *)input_value, res_desc->Bytes / sizeof(FLOAT));
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetFloatArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetFloatArray(effect, parameter, NULL, res_desc->Bytes / sizeof(FLOAT));
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetFloatArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetVector(effect, NULL, (D3DXVECTOR4 *)input_value);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetVector failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetVector(effect, NULL, (D3DXVECTOR4 *)input_value);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetVector failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetVector(effect, parameter, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetVector failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetVectorArray(effect, NULL, (D3DXVECTOR4 *)input_value, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetVectorArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetVectorArray(effect, NULL, (D3DXVECTOR4 *)input_value, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetVectorArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetVectorArray(effect, parameter, NULL, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetVectorArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetMatrix(effect, NULL, (D3DXMATRIX *)input_value);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrix failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrix(effect, NULL, (D3DXMATRIX *)input_value);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrix failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetMatrixArray(effect, NULL, (D3DXMATRIX *)input_value, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrixArray(effect, NULL, (D3DXMATRIX *)input_value, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrixArray(effect, parameter, NULL, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetMatrixPointerArray(effect, NULL, matrix_pointer_array, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixPointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetMatrixPointerArray(effect, NULL, matrix_pointer_array, 0);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixPointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrixPointerArray(effect, NULL, NULL, 0);
+            ok(hr == D3D_OK, "%u - %s: GetMatrixPointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3D_OK);
+
+            hr = effect->lpVtbl->GetMatrixPointerArray(effect, NULL, NULL, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixPointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrixPointerArray(effect, parameter, NULL, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixPointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetMatrixTranspose(effect, NULL, (D3DXMATRIX *)input_value);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixTranspose failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrixTranspose(effect, NULL, (D3DXMATRIX *)input_value);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixTranspose failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrixTranspose(effect, parameter, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixTranspose failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetMatrixTransposeArray(effect, NULL, (D3DXMATRIX *)input_value, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixTransposeArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrixTransposeArray(effect, NULL, (D3DXMATRIX *)input_value, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixTransposeArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrixTransposeArray(effect, parameter, NULL, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixTransposeArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetMatrixTransposePointerArray(effect, NULL, matrix_pointer_array, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixTransposePointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetMatrixTransposePointerArray(effect, NULL, matrix_pointer_array, 0);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixTransposePointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrixTransposePointerArray(effect, NULL, NULL, 0);
+            ok(hr == D3D_OK, "%u - %s: GetMatrixTransposePointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3D_OK);
+
+            hr = effect->lpVtbl->GetMatrixTransposePointerArray(effect, NULL, NULL, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixTransposePointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetMatrixTransposePointerArray(effect, parameter, NULL, res_desc->Elements ? res_desc->Elements : 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetMatrixTransposePointerArray failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetValue(effect, NULL, input_value, res_desc->Bytes);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetValue failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->SetValue(effect, parameter, input_value, res_desc->Bytes - 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetValue failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetValue(effect, NULL, input_value, res_desc->Bytes);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetValue failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            hr = effect->lpVtbl->GetValue(effect, parameter, input_value, res_desc->Bytes - 1);
+            ok(hr == D3DERR_INVALIDCALL, "%u - %s: GetValue failed, got %#x, expected %#x\n",
+                    i, res_full_name, hr, D3DERR_INVALIDCALL);
+
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /* SetBool */
+            bvalue = 5;
+            memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+            hr = effect->lpVtbl->SetBool(effect, parameter, bvalue);
+            if (!res_desc->Elements && res_desc->Rows == 1 && res_desc->Columns == 1)
+            {
+                bvalue = TRUE;
+                set_number(expected_value, res_desc->Type, &bvalue, D3DXPT_BOOL);
+                ok(hr == D3D_OK, "%u - %s: SetBool failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+            }
+            else
+            {
+                ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetBool failed, got %#x, expected %#x\n",
+                        i, res_full_name, hr, D3DERR_INVALIDCALL);
+            }
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+            test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /* SetBoolArray */
+            *input_value = 1;
+            for (l = 1; l < res_desc->Bytes / sizeof(*input_value); ++l)
+            {
+                *(input_value + l) = *(input_value + l - 1) + 1;
+            }
+            memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+            hr = effect->lpVtbl->SetBoolArray(effect, parameter, (BOOL *)input_value, res_desc->Bytes / sizeof(*input_value));
+            if (res_desc->Class == D3DXPC_SCALAR
+                    || res_desc->Class == D3DXPC_VECTOR
+                    || res_desc->Class == D3DXPC_MATRIX_ROWS)
+            {
+                for (l = 0; l < res_desc->Bytes / sizeof(*input_value); ++l)
+                {
+                    set_number(expected_value + l, res_desc->Type, input_value + l, D3DXPT_BOOL);
+                }
+                ok(hr == D3D_OK, "%u - %s: SetBoolArray failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+            }
+            else
+            {
+                ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetBoolArray failed, got %#x, expected %#x\n",
+                        i, res_full_name, hr, D3DERR_INVALIDCALL);
+            }
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+            test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /* SetInt */
+            ivalue = 0x1fbf02ff;
+            memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+            hr = effect->lpVtbl->SetInt(effect, parameter, ivalue);
+            if (!res_desc->Elements && res_desc->Rows == 1 && res_desc->Columns == 1)
+            {
+                set_number(expected_value, res_desc->Type, &ivalue, D3DXPT_INT);
+                ok(hr == D3D_OK, "%u - %s: SetInt failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+            }
+            else if(!res_desc->Elements && res_desc->Type == D3DXPT_FLOAT &&
+                    ((res_desc->Class == D3DXPC_VECTOR && res_desc->Columns != 2) ||
+                    (res_desc->Class == D3DXPC_MATRIX_ROWS && res_desc->Rows != 2 && res_desc->Columns == 1)))
+            {
+                FLOAT tmp = ((ivalue & 0xff0000) >> 16) * INT_FLOAT_MULTI_INVERSE;
+                set_number(expected_value, res_desc->Type, &tmp, D3DXPT_FLOAT);
+                tmp = ((ivalue & 0xff00) >> 8) * INT_FLOAT_MULTI_INVERSE;
+                set_number(expected_value + 1, res_desc->Type, &tmp, D3DXPT_FLOAT);
+                tmp = (ivalue & 0xff) * INT_FLOAT_MULTI_INVERSE;
+                set_number(expected_value + 2, res_desc->Type, &tmp, D3DXPT_FLOAT);
+                tmp = ((ivalue & 0xff000000) >> 24) * INT_FLOAT_MULTI_INVERSE;
+                set_number(expected_value + 3, res_desc->Type, &tmp, D3DXPT_FLOAT);
+
+                ok(hr == D3D_OK, "%u - %s: SetInt failed, got %#x, expected %#x\n",
+                        i, res_full_name, hr, D3D_OK);
+            }
+            else
+            {
+                ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetInt failed, got %#x, expected %#x\n",
+                        i, res_full_name, hr, D3DERR_INVALIDCALL);
+            }
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+            test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /* SetIntArray */
+            *input_value = 123456;
+            for (l = 0; l < res_desc->Bytes / sizeof(*input_value); ++l)
+            {
+                *(input_value + l) = *(input_value + l - 1) + 23;
+            }
+            memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+            hr = effect->lpVtbl->SetIntArray(effect, parameter, (INT *)input_value, res_desc->Bytes / sizeof(*input_value));
+            if (res_desc->Class == D3DXPC_SCALAR
+                    || res_desc->Class == D3DXPC_VECTOR
+                    || res_desc->Class == D3DXPC_MATRIX_ROWS)
+            {
+                for (l = 0; l < res_desc->Bytes / sizeof(*input_value); ++l)
+                {
+                    set_number(expected_value + l, res_desc->Type, input_value + l, D3DXPT_INT);
+                }
+                ok(hr == D3D_OK, "%u - %s: SetIntArray failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+            }
+            else
+            {
+                ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetIntArray failed, got %#x, expected %#x\n",
+                        i, res_full_name, hr, D3DERR_INVALIDCALL);
+            }
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+            test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /* SetFloat */
+            fvalue = 1.33;
+            memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+            hr = effect->lpVtbl->SetFloat(effect, parameter, fvalue);
+            if (!res_desc->Elements && res_desc->Rows == 1 && res_desc->Columns == 1)
+            {
+                set_number(expected_value, res_desc->Type, &fvalue, D3DXPT_FLOAT);
+                ok(hr == D3D_OK, "%u - %s: SetFloat failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+            }
+            else
+            {
+                ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetFloat failed, got %#x, expected %#x\n",
+                        i, res_full_name, hr, D3DERR_INVALIDCALL);
+            }
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+            test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /* SetFloatArray */
+            fvalue = 1.33;
+            for (l = 0; l < res_desc->Bytes / sizeof(fvalue); ++l)
+            {
+                *(input_value + l) = *(DWORD *)&fvalue;
+                fvalue += 1.12;
+            }
+            memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+            hr = effect->lpVtbl->SetFloatArray(effect, parameter, (FLOAT *)input_value, res_desc->Bytes / sizeof(*input_value));
+            if (res_desc->Class == D3DXPC_SCALAR
+                    || res_desc->Class == D3DXPC_VECTOR
+                    || res_desc->Class == D3DXPC_MATRIX_ROWS)
+            {
+                for (l = 0; l < res_desc->Bytes / sizeof(*input_value); ++l)
+                {
+                    set_number(expected_value + l, res_desc->Type, input_value + l, D3DXPT_FLOAT);
+                }
+                ok(hr == D3D_OK, "%u - %s: SetFloatArray failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+            }
+            else
+            {
+                ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetFloatArray failed, got %#x, expected %#x\n",
+                        i, res_full_name, hr, D3DERR_INVALIDCALL);
+            }
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+            test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /* SetVector */
+            fvalue = -1.33;
+            for (l = 0; l < 4; ++l)
+            {
+                *(input_value + l) = *(DWORD *)&fvalue;
+                fvalue += 1.12;
+            }
+            memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+            hr = effect->lpVtbl->SetVector(effect, parameter, (D3DXVECTOR4 *)input_value);
+            if (!res_desc->Elements &&
+                    (res_desc->Class == D3DXPC_SCALAR
+                    || res_desc->Class == D3DXPC_VECTOR))
+            {
+                /* only values between 0 and INT_FLOAT_MULTI are valid */
+                if (res_desc->Type == D3DXPT_INT && res_desc->Bytes == 4)
+                {
+                    *expected_value = (DWORD)(max(min(*(FLOAT *)(input_value + 2), 1.0f), 0.0f) * INT_FLOAT_MULTI);
+                    *expected_value += ((DWORD)(max(min(*(FLOAT *)(input_value + 1), 1.0f), 0.0f) * INT_FLOAT_MULTI)) << 8;
+                    *expected_value += ((DWORD)(max(min(*(FLOAT *)input_value, 1.0f), 0.0f) * INT_FLOAT_MULTI)) << 16;
+                    *expected_value += ((DWORD)(max(min(*(FLOAT *)(input_value + 3), 1.0f), 0.0f) * INT_FLOAT_MULTI)) << 24;
+                }
+                else
+                {
+                    for (l = 0; l < 4; ++l)
+                    {
+                        set_number(expected_value + l, res_desc->Type, input_value + l, D3DXPT_FLOAT);
+                    }
+                }
+                ok(hr == D3D_OK, "%u - %s: SetVector failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+            }
+            else
+            {
+                ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetVector failed, got %#x, expected %#x\n",
+                        i, res_full_name, hr, D3DERR_INVALIDCALL);
+            }
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+            test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /* SetVectorArray */
+            for (element = 0; element < res_desc->Elements + 1; ++element)
+            {
+                fvalue = 1.33;
+                for (l = 0; l < element * 4; ++l)
+                {
+                    *(input_value + l) = *(DWORD *)&fvalue;
+                    fvalue += 1.12;
+                }
+                memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+                hr = effect->lpVtbl->SetVectorArray(effect, parameter, (D3DXVECTOR4 *)input_value, element);
+                if (res_desc->Elements && res_desc->Class == D3DXPC_VECTOR && element <= res_desc->Elements)
+                {
+                    for (m = 0; m < element; ++m)
+                    {
+                        for (l = 0; l < res_desc->Columns; ++l)
+                        {
+                            set_number(expected_value + m * res_desc->Columns + l, res_desc->Type, input_value + m * 4 + l, D3DXPT_FLOAT);
+                        }
+                    }
+                    ok(hr == D3D_OK, "%u - %s: SetVectorArray failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+                }
+                else
+                {
+                    ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetVectorArray failed, got %#x, expected %#x\n",
+                            i, res_full_name, hr, D3DERR_INVALIDCALL);
+                }
+                test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+                test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+            }
+
+            /* SetMatrix */
+            fvalue = 1.33;
+            for (l = 0; l < 16; ++l)
+            {
+                *(input_value + l) = *(DWORD *)&fvalue;
+                fvalue += 1.12;
+            }
+            memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+            hr = effect->lpVtbl->SetMatrix(effect, parameter, (D3DXMATRIX *)input_value);
+            if (!res_desc->Elements && res_desc->Class == D3DXPC_MATRIX_ROWS)
+            {
+                for (l = 0; l < 4; ++l)
+                {
+                    for (m = 0; m < 4; ++m)
+                    {
+                        if (m < res_desc->Rows && l < res_desc->Columns)
+                            set_number(expected_value + l + m * res_desc->Columns, res_desc->Type,
+                                    input_value + l + m * 4, D3DXPT_FLOAT);
+                    }
+
+                }
+                ok(hr == D3D_OK, "%u - %s: SetMatrix failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+            }
+            else
+            {
+                ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrix failed, got %#x, expected %#x\n",
+                        i, res_full_name, hr, D3DERR_INVALIDCALL);
+            }
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+            test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /* SetMatrixArray */
+            for (element = 0; element < res_desc->Elements + 1; ++element)
+            {
+                fvalue = 1.33;
+                for (l = 0; l < element * 16; ++l)
+                {
+                    *(input_value + l) = *(DWORD *)&fvalue;
+                    fvalue += 1.12;
+                }
+                memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+                hr = effect->lpVtbl->SetMatrixArray(effect, parameter, (D3DXMATRIX *)input_value, element);
+                if (res_desc->Class == D3DXPC_MATRIX_ROWS && element <= res_desc->Elements)
+                {
+                    for (n = 0; n < element; ++n)
+                    {
+                        for (l = 0; l < 4; ++l)
+                        {
+                            for (m = 0; m < 4; ++m)
+                            {
+                                if (m < res_desc->Rows && l < res_desc->Columns)
+                                    set_number(expected_value + l + m * res_desc->Columns + n * res_desc->Columns * res_desc->Rows,
+                                            res_desc->Type, input_value + l + m * 4 + n * 16, D3DXPT_FLOAT);
+                            }
+
+                        }
+                    }
+                    ok(hr == D3D_OK, "%u - %s: SetMatrixArray failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+                }
+                else
+                {
+                    ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixArray failed, got %#x, expected %#x\n",
+                            i, res_full_name, hr, D3DERR_INVALIDCALL);
+                }
+                test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+                test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+            }
+
+            /* SetMatrixPointerArray */
+            for (element = 0; element < res_desc->Elements + 1; ++element)
+            {
+                fvalue = 1.33;
+                for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l)
+                {
+                    *(input_value + l) = *(DWORD *)&fvalue;
+                    fvalue += 1.12;
+                }
+                memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+                for (l = 0; l < element; ++l)
+                {
+                    matrix_pointer_array[l] = (D3DXMATRIX *)&input_value[l * sizeof(**matrix_pointer_array) / sizeof(FLOAT)];
+                }
+                hr = effect->lpVtbl->SetMatrixPointerArray(effect, parameter, matrix_pointer_array, element);
+                if (res_desc->Class == D3DXPC_MATRIX_ROWS && res_desc->Elements >= element)
+                {
+                    for (n = 0; n < element; ++n)
+                    {
+                        for (l = 0; l < 4; ++l)
+                        {
+                            for (m = 0; m < 4; ++m)
+                            {
+                                if (m < res_desc->Rows && l < res_desc->Columns)
+                                    set_number(expected_value + l + m * res_desc->Columns + n * res_desc->Columns * res_desc->Rows,
+                                            res_desc->Type, input_value + l + m * 4 + n * 16, D3DXPT_FLOAT);
+                            }
+
+                        }
+                    }
+                    ok(hr == D3D_OK, "%u - %s: SetMatrixPointerArray failed, got %#x, expected %#x\n",
+                            i, res_full_name, hr, D3D_OK);
+                }
+                else
+                {
+                    ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixPointerArray failed, got %#x, expected %#x\n",
+                            i, res_full_name, hr, D3DERR_INVALIDCALL);
+                }
+                test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+                test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+            }
+
+            /* SetMatrixTranspose */
+            fvalue = 1.33;
+            for (l = 0; l < 16; ++l)
+            {
+                *(input_value + l) = *(DWORD *)&fvalue;
+                fvalue += 1.12;
+            }
+            memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+            hr = effect->lpVtbl->SetMatrixTranspose(effect, parameter, (D3DXMATRIX *)input_value);
+            if (!res_desc->Elements && res_desc->Class == D3DXPC_MATRIX_ROWS)
+            {
+                for (l = 0; l < 4; ++l)
+                {
+                    for (m = 0; m < 4; ++m)
+                    {
+                        if (m < res_desc->Rows && l < res_desc->Columns)
+                            set_number(expected_value + l + m * res_desc->Columns, res_desc->Type,
+                                    input_value + l * 4 + m, D3DXPT_FLOAT);
+                    }
+
+                }
+                ok(hr == D3D_OK, "%u - %s: SetMatrixTranspose failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+            }
+            else
+            {
+                ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixTranspose failed, got %#x, expected %#x\n",
+                        i, res_full_name, hr, D3DERR_INVALIDCALL);
+            }
+            test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+            test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+
+            /* SetMatrixTransposeArray */
+            for (element = 0; element < res_desc->Elements + 1; ++element)
+            {
+                fvalue = 1.33;
+                for (l = 0; l < element * 16; ++l)
+                {
+                    *(input_value + l) = *(DWORD *)&fvalue;
+                    fvalue += 1.12;
+                }
+                memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+                hr = effect->lpVtbl->SetMatrixTransposeArray(effect, parameter, (D3DXMATRIX *)input_value, element);
+                if (res_desc->Class == D3DXPC_MATRIX_ROWS && element <= res_desc->Elements)
+                {
+                    for (n = 0; n < element; ++n)
+                    {
+                        for (l = 0; l < 4; ++l)
+                        {
+                            for (m = 0; m < 4; ++m)
+                            {
+                                if (m < res_desc->Rows && l < res_desc->Columns)
+                                    set_number(expected_value + l + m * res_desc->Columns + n * res_desc->Columns * res_desc->Rows,
+                                            res_desc->Type, input_value + l * 4 + m + n * 16, D3DXPT_FLOAT);
+                            }
+
+                        }
+                    }
+                    ok(hr == D3D_OK, "%u - %s: SetMatrixTransposeArray failed, got %#x, expected %#x\n", i, res_full_name, hr, D3D_OK);
+                }
+                else
+                {
+                    ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixTransposeArray failed, got %#x, expected %#x\n",
+                            i, res_full_name, hr, D3DERR_INVALIDCALL);
+                }
+                test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+                test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+            }
+
+            /* SetMatrixTransposePointerArray */
+            for (element = 0; element < res_desc->Elements + 1; ++element)
+            {
+                fvalue = 1.33;
+                for (l = 0; l < EFFECT_PARAMETER_VALUE_ARRAY_SIZE; ++l)
+                {
+                    *(input_value + l) = *(DWORD *)&fvalue;
+                    fvalue += 1.12;
+                }
+                memcpy(expected_value, &blob[res_value_offset], res_desc->Bytes);
+                for (l = 0; l < element; ++l)
+                {
+                    matrix_pointer_array[l] = (D3DXMATRIX *)&input_value[l * sizeof(**matrix_pointer_array) / sizeof(FLOAT)];
+                }
+                hr = effect->lpVtbl->SetMatrixTransposePointerArray(effect, parameter, matrix_pointer_array, element);
+                if (res_desc->Class == D3DXPC_MATRIX_ROWS && res_desc->Elements >= element)
+                {
+                    for (n = 0; n < element; ++n)
+                    {
+                        for (l = 0; l < 4; ++l)
+                        {
+                            for (m = 0; m < 4; ++m)
+                            {
+                                if (m < res_desc->Rows && l < res_desc->Columns)
+                                    set_number(expected_value + l + m * res_desc->Columns + n * res_desc->Columns * res_desc->Rows,
+                                            res_desc->Type, input_value + l * 4 + m + n * 16, D3DXPT_FLOAT);
+                            }
+
+                        }
+                    }
+                    ok(hr == D3D_OK, "%u - %s: SetMatrixTransposePointerArray failed, got %#x, expected %#x\n",
+                            i, res_full_name, hr, D3D_OK);
+                }
+                else
+                {
+                    ok(hr == D3DERR_INVALIDCALL, "%u - %s: SetMatrixTransposePointerArray failed, got %#x, expected %#x\n",
+                            i, res_full_name, hr, D3DERR_INVALIDCALL);
+                }
+                test_effect_parameter_value_GetTestGroup(&res[k], effect, expected_value, parameter, i);
+                test_effect_parameter_value_ResetValue(&res[k], effect, &blob[res_value_offset], parameter, i);
+            }
+        }
+
+        count = effect->lpVtbl->Release(effect);
+        ok(!count, "Release failed %u\n", count);
+    }
+}
+
+static void test_effect_setvalue_object(IDirect3DDevice9 *device)
+{
+    static const char expected_string[] = "test_string_1";
+    static const char expected_string2[] = "test_longer_string_2";
+    static const char *expected_string_array[] = {expected_string, expected_string2};
+    const char *string_array[ARRAY_SIZE(expected_string_array)];
+    const char *string, *string2;
+    IDirect3DTexture9 *texture_set;
+    IDirect3DTexture9 *texture;
+    D3DXHANDLE parameter;
+    ID3DXEffect *effect;
+    unsigned int i;
+    ULONG count;
+    HRESULT hr;
+
+    hr = D3DXCreateEffect(device, test_effect_parameter_value_blob_object,
+            sizeof(test_effect_parameter_value_blob_object), NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK).\n", hr);
+
+    parameter = effect->lpVtbl->GetParameterByName(effect, NULL, "tex");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    texture = NULL;
+    hr = D3DXCreateTexture(device, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK).\n", hr);
+    hr = effect->lpVtbl->SetValue(effect, parameter, &texture, sizeof(texture));
+    ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK).\n", hr);
+    texture_set = NULL;
+    hr = effect->lpVtbl->GetValue(effect, parameter, &texture_set, sizeof(texture_set));
+    ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK).\n", hr);
+    ok(texture == texture_set, "Texture does not match.\n");
+
+    count = IDirect3DTexture9_Release(texture_set);
+    ok(count == 2, "Got reference count %u, expected 2.\n", count);
+    texture_set = NULL;
+    hr = effect->lpVtbl->SetValue(effect, parameter, &texture_set, sizeof(texture_set));
+    ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK).\n", hr);
+    count = IDirect3DTexture9_Release(texture);
+    ok(!count, "Got reference count %u, expected 0.\n", count);
+
+    hr = effect->lpVtbl->SetString(effect, "s", expected_string);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    string = NULL;
+    hr = effect->lpVtbl->GetString(effect, "s", &string);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->GetString(effect, "s", &string2);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ok(string != expected_string, "String pointers are the same.\n");
+    ok(string == string2, "String pointers differ.\n");
+    ok(!strcmp(string, expected_string), "Unexpected string '%s'.\n", string);
+
+    string = expected_string2;
+    hr = effect->lpVtbl->SetValue(effect, "s", &string, sizeof(string) - 1);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->SetValue(effect, "s", &string, sizeof(string));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->SetValue(effect, "s", &string, sizeof(string) * 2);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    string = NULL;
+    hr = effect->lpVtbl->GetValue(effect, "s", &string, sizeof(string));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ok(string != expected_string2, "String pointers are the same.\n");
+    ok(!strcmp(string, expected_string2), "Unexpected string '%s'.\n", string);
+
+    hr = effect->lpVtbl->SetValue(effect, "s_2", expected_string_array,
+            sizeof(expected_string_array));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->GetValue(effect, "s_2", string_array,
+            sizeof(string_array));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    for (i = 0; i < ARRAY_SIZE(expected_string_array); ++i)
+    {
+        ok(!strcmp(string_array[i], expected_string_array[i]), "Unexpected string '%s', i %u.\n",
+                string_array[i], i);
+    }
+    effect->lpVtbl->Release(effect);
+}
+
+/*
+ * fxc.exe /Tfx_2_0
+ */
+#if 0
+float a = 2.1;
+float b[1];
+float c <float d = 3;>;
+struct {float e;} f;
+float g <float h[1] = {3};>;
+struct s {float j;};
+float i <s k[1] = {4};>;
+technique t <s l[1] = {5};> { pass p <s m[1] = {6};> { } }
+#endif
+static const DWORD test_effect_variable_names_blob[] =
+{
+0xfeff0901, 0x0000024c, 0x00000000, 0x00000003, 0x00000000, 0x00000024, 0x00000000, 0x00000000,
+0x00000001, 0x00000001, 0x40066666, 0x00000002, 0x00000061, 0x00000003, 0x00000000, 0x0000004c,
+0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000002, 0x00000062, 0x00000003,
+0x00000000, 0x0000009c, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x40400000,
+0x00000003, 0x00000000, 0x00000094, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000002,
+0x00000064, 0x00000002, 0x00000063, 0x00000000, 0x00000005, 0x000000dc, 0x00000000, 0x00000000,
+0x00000001, 0x00000003, 0x00000000, 0x000000e4, 0x00000000, 0x00000000, 0x00000001, 0x00000001,
+0x00000000, 0x00000002, 0x00000066, 0x00000002, 0x00000065, 0x00000003, 0x00000000, 0x00000134,
+0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x40400000, 0x00000003, 0x00000000,
+0x0000012c, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000068, 0x00000002,
+0x00000067, 0x00000003, 0x00000000, 0x000001a4, 0x00000000, 0x00000000, 0x00000001, 0x00000001,
+0x00000000, 0x40800000, 0x00000000, 0x00000005, 0x00000194, 0x00000000, 0x00000001, 0x00000001,
+0x00000003, 0x00000000, 0x0000019c, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000002,
+0x0000006b, 0x00000002, 0x0000006a, 0x00000002, 0x00000069, 0x40a00000, 0x00000000, 0x00000005,
+0x000001e4, 0x00000000, 0x00000001, 0x00000001, 0x00000003, 0x00000000, 0x000001ec, 0x00000000,
+0x00000000, 0x00000001, 0x00000001, 0x00000002, 0x0000006c, 0x00000002, 0x0000006a, 0x40c00000,
+0x00000000, 0x00000005, 0x0000022c, 0x00000000, 0x00000001, 0x00000001, 0x00000003, 0x00000000,
+0x00000234, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000002, 0x0000006d, 0x00000002,
+0x0000006a, 0x00000002, 0x00000070, 0x00000002, 0x00000074, 0x00000006, 0x00000001, 0x00000001,
+0x00000001, 0x00000004, 0x00000020, 0x00000000, 0x00000000, 0x0000002c, 0x00000048, 0x00000000,
+0x00000000, 0x00000054, 0x00000070, 0x00000000, 0x00000001, 0x00000078, 0x00000074, 0x000000a4,
+0x000000d8, 0x00000000, 0x00000000, 0x000000ec, 0x00000108, 0x00000000, 0x00000001, 0x00000110,
+0x0000010c, 0x0000013c, 0x00000158, 0x00000000, 0x00000001, 0x00000160, 0x0000015c, 0x00000244,
+0x00000001, 0x00000001, 0x000001b0, 0x000001ac, 0x0000023c, 0x00000001, 0x00000000, 0x000001f8,
+0x000001f4, 0x00000000, 0x00000000,
+};
+
+static void test_effect_variable_names(IDirect3DDevice9 *device)
+{
+    ID3DXEffect *effect;
+    ULONG count;
+    HRESULT hr;
+    D3DXHANDLE parameter, p;
+
+    hr = D3DXCreateEffect(device, test_effect_variable_names_blob,
+            sizeof(test_effect_variable_names_blob), NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "D3DXCreateEffect failed, got %#x, expected %#x\n", hr, D3D_OK);
+
+    /*
+     * check invalid calls
+     * This will crash:
+     * effect->lpVtbl->GetAnnotationByName(effect, "invalid1", "invalid2");
+     */
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, NULL);
+    ok(p == NULL, "GetParameterByName failed, got %p, expected %p\n", p, NULL);
+
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "invalid1");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "invalid1", NULL);
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "invalid1", "invalid2");
+    ok(p == NULL, "GetParameterByName failed, got %p, expected %p\n", p, NULL);
+
+    /* float a; */
+    parameter = effect->lpVtbl->GetParameterByName(effect, NULL, "a");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a", NULL);
+    ok(parameter == p, "GetParameterByName failed, got %p, expected %p\n", p, parameter);
+
+    /* members */
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "a.");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a.", NULL);
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a", ".");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "a.invalid");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a.invalid", NULL);
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a", ".invalid");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a.", "invalid");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a", "invalid");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    /* elements */
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "a[]");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a[]", NULL);
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "a[0]");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a[0]", NULL);
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a", "[0]");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterElement(effect, "a", 0);
+    ok(p == NULL, "GetParameterElement failed, got %p\n", p);
+
+    /* annotations */
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "a@");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a@", NULL);
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a", "@invalid");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a@", "invalid");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "a@invalid");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "a@invalid", NULL);
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetAnnotationByName(effect, "a", NULL);
+    ok(p == NULL, "GetAnnotationByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetAnnotationByName(effect, "a", "invalid");
+    ok(p == NULL, "GetAnnotationByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetAnnotation(effect, "a", 0);
+    ok(p == NULL, "GetAnnotation failed, got %p\n", p);
+
+    /* float b[1]; */
+    parameter = effect->lpVtbl->GetParameterByName(effect, NULL, "b");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "b", NULL);
+    ok(parameter == p, "GetParameterByName failed, got %p, expected %p\n", p, parameter);
+
+    /* elements */
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "b[]");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    parameter = effect->lpVtbl->GetParameterByName(effect, NULL, "b[0]");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "b[0]", NULL);
+    ok(parameter == p, "GetParameterByName failed, got %p, expected %p\n", p, parameter);
+
+    p = effect->lpVtbl->GetParameterElement(effect, "b", 0);
+    ok(parameter == p, "GetParameterElement failed, got %p, expected %p\n", p, parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "b", "[0]");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "b[1]");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterElement(effect, "b", 1);
+    ok(p == NULL, "GetParameterElement failed, got %p\n", p);
+
+    /* float c <float d = 3;>; */
+    parameter = effect->lpVtbl->GetParameterByName(effect, NULL, "c");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "c", NULL);
+    ok(parameter == p, "GetParameterByName failed, got %p, expected %p\n", p, parameter);
+
+    /* annotations */
+    p = effect->lpVtbl->GetParameterByName(effect, "c", "@d");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "c@", "d");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "c@invalid");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "c@invalid", NULL);
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetAnnotationByName(effect, "c", NULL);
+    ok(p == NULL, "GetAnnotationByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetAnnotationByName(effect, "c", "invalid");
+    ok(p == NULL, "GetAnnotationByName failed, got %p\n", p);
+
+    parameter = effect->lpVtbl->GetParameterByName(effect, NULL, "c@d");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "c@d", NULL);
+    ok(parameter == p, "GetParameterByName failed, got %p, expected %p\n", p, parameter);
+
+    p = effect->lpVtbl->GetAnnotationByName(effect, "c", "d");
+    ok(parameter == p, "GetAnnotationByName failed, got %p, expected %p\n", p, parameter);
+
+    p = effect->lpVtbl->GetAnnotation(effect, "c", 0);
+    ok(parameter == p, "GetAnnotation failed, got %p, expected %p\n", p, parameter);
+
+    p = effect->lpVtbl->GetAnnotation(effect, "c", 1);
+    ok(p == NULL, "GetAnnotation failed, got %p\n", p);
+
+    /* struct {float e;} f; */
+    parameter = effect->lpVtbl->GetParameterByName(effect, NULL, "f");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "f", NULL);
+    ok(parameter == p, "GetParameterByName failed, got %p, expected %p\n", p, parameter);
+
+    /* members */
+    parameter = effect->lpVtbl->GetParameterByName(effect, NULL, "f.e");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "f.e", NULL);
+    ok(parameter == p, "GetParameterByName failed, got %p, expected %p\n", p, parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "f", "e");
+    ok(parameter == p, "GetParameterByName failed, got %p, expected %p\n", p, parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "f", ".e");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "f.", "e");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, "f.invalid", NULL);
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    p = effect->lpVtbl->GetParameterByName(effect, NULL, "f.invalid");
+    ok(p == NULL, "GetParameterByName failed, got %p\n", p);
+
+    /* float g <float h[1] = {3};>; */
+    parameter = effect->lpVtbl->GetParameterByName(effect, NULL, "g@h[0]");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    p = effect->lpVtbl->GetAnnotationByName(effect, "g", "h[0]");
+    ok(parameter == p, "GetAnnotationByName failed, got %p, expected %p\n", p, parameter);
+
+    p = effect->lpVtbl->GetParameterElement(effect, "g@h", 0);
+    ok(parameter == p, "GetParameterElement failed, got %p, expected %p\n", p, parameter);
+
+    p = effect->lpVtbl->GetParameterElement(effect, effect->lpVtbl->GetAnnotation(effect, "g", 0), 0);
+    ok(parameter == p, "GetParameterElement failed, got %p, expected %p\n", p, parameter);
+
+    /* struct s {float j;}; float i <s k[1] = {4};>; */
+    parameter = effect->lpVtbl->GetParameterByName(effect, NULL, "i@k[0].j");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    p = effect->lpVtbl->GetAnnotationByName(effect, "i", "k[0].j");
+    ok(parameter == p, "GetAnnotationByName failed, got %p, expected %p\n", p, parameter);
+
+    p = effect->lpVtbl->GetParameterByName(effect, effect->lpVtbl->GetParameterElement(effect, "i@k", 0), "j");
+    ok(parameter == p, "GetParameterElement failed, got %p, expected %p\n", p, parameter);
+
+    /* technique t <s l[1] = {5};> */
+    parameter = effect->lpVtbl->GetAnnotationByName(effect, "t", "l[0].j");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    /* pass p <s m[1] = {6};> */
+    parameter = effect->lpVtbl->GetAnnotationByName(effect, effect->lpVtbl->GetPassByName(effect, "t", "p"), "m[0].j");
+    ok(parameter != NULL, "GetParameterByName failed, got %p\n", parameter);
+
+    count = effect->lpVtbl->Release(effect);
+    ok(!count, "Release failed %u\n", count);
+}
+
+static void test_effect_compilation_errors(IDirect3DDevice9 *device)
+{
+    ID3DXEffect *effect;
+    ID3DXBuffer *compilation_errors;
+    HRESULT hr;
+
+    /* Test binary effect */
+    compilation_errors = (ID3DXBuffer*)0xdeadbeef;
+    hr = D3DXCreateEffect(NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, &compilation_errors);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateEffect failed, got %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    ok(!compilation_errors, "Returned %p\n", compilation_errors);
+
+    compilation_errors = (ID3DXBuffer*)0xdeadbeef;
+    hr = D3DXCreateEffect(device, test_effect_variable_names_blob,
+            sizeof(test_effect_variable_names_blob), NULL, NULL, 0, NULL, &effect, &compilation_errors);
+    ok(hr == D3D_OK, "D3DXCreateEffect failed, got %#x, expected %#x\n", hr, D3D_OK);
+    ok(!compilation_errors, "Returned %p\n", compilation_errors);
+    effect->lpVtbl->Release(effect);
+}
+
+/*
+ * fxc.exe /Tfx_2_0
+ */
+#if 0
+vertexshader vs_arr1[2] =
+{
+    asm
+    {
+        vs_1_1
+        def c0, 1, 1, 1, 1
+        mov oPos, c0
+    },
+    asm
+    {
+        vs_2_0
+        def c0, 2, 2, 2, 2
+        mov oPos, c0
+    }
+};
+
+sampler sampler1 =
+    sampler_state
+    {
+        MipFilter = LINEAR;
+    };
+
+float4x4 camera : VIEW = {4.0,0.0,0.0,0.0, 0.0,0.0,0.0,0.0, 0.0,0.0,0.0,0.0, 0.0,0.0,0.0,6.0};
+technique tech0
+{
+   pass p0
+   {
+       vertexshader = vs_arr1[1];
+       VertexShaderConstant1[3] = {2,2,2,2};
+       BlendOp = 2;
+       AlphaOp[3] = 4;
+       ZEnable = true;
+       WorldTransform[1]={2.0,0.0,0.0,0.0, 0.0,0.0,0.0,0.0, 0.0,0.0,0.0,0.0, 0.0,0.0,0.0,4.0};
+       ViewTransform=(camera);
+       LightEnable[2] = TRUE;
+       LightType[2] = POINT;
+       LightPosition[2] = {4.0f, 5.0f, 6.0f};
+       Sampler[1] = sampler1;
+   }
+}
+#endif
+static const DWORD test_effect_states_effect_blob[] =
+{
+    0xfeff0901, 0x000002e8, 0x00000000, 0x00000010, 0x00000004, 0x00000020, 0x00000000, 0x00000002,
+    0x00000001, 0x00000002, 0x00000008, 0x615f7376, 0x00317272, 0x0000000a, 0x00000004, 0x00000074,
+    0x00000000, 0x00000000, 0x00000002, 0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000,
+    0x00000001, 0x00000001, 0x00000001, 0x000000ab, 0x00000100, 0x00000044, 0x00000040, 0x00000009,
+    0x706d6173, 0x3172656c, 0x00000000, 0x00000003, 0x00000002, 0x000000e0, 0x000000ec, 0x00000000,
+    0x00000004, 0x00000004, 0x40800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x40c00000, 0x00000007, 0x656d6163, 0x00006172, 0x00000005, 0x57454956, 0x00000000,
+    0x00000003, 0x00000010, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x40000000, 0x40000000,
+    0x40000000, 0x40000000, 0x00000003, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000004,
+    0x00000001, 0x00000002, 0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
+    0x00000001, 0x00000004, 0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
+    0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
+    0x00000001, 0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x40800000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0x00000001,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000001,
+    0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001,
+    0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x40800000,
+    0x40a00000, 0x40c00000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
+    0x00000001, 0x00000000, 0x0000000a, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
+    0x00003070, 0x00000006, 0x68636574, 0x00000030, 0x00000003, 0x00000001, 0x00000005, 0x00000004,
+    0x00000004, 0x00000018, 0x00000000, 0x00000000, 0x0000002c, 0x00000060, 0x00000000, 0x00000000,
+    0x00000084, 0x000000a0, 0x00000000, 0x00000000, 0x000002dc, 0x00000000, 0x00000001, 0x000002d4,
+    0x00000000, 0x0000000b, 0x00000092, 0x00000000, 0x000000fc, 0x000000f8, 0x00000098, 0x00000003,
+    0x00000120, 0x00000110, 0x0000004b, 0x00000000, 0x00000140, 0x0000013c, 0x0000006b, 0x00000003,
+    0x00000160, 0x0000015c, 0x00000000, 0x00000000, 0x00000180, 0x0000017c, 0x0000007d, 0x00000001,
+    0x000001dc, 0x0000019c, 0x0000007c, 0x00000000, 0x00000238, 0x000001f8, 0x00000091, 0x00000002,
+    0x00000258, 0x00000254, 0x00000084, 0x00000002, 0x00000278, 0x00000274, 0x00000088, 0x00000002,
+    0x000002a0, 0x00000294, 0x000000b2, 0x00000001, 0x000002c0, 0x000002bc, 0x00000002, 0x00000003,
+    0x00000001, 0x0000002c, 0xfffe0101, 0x00000051, 0xa00f0000, 0x3f800000, 0x3f800000, 0x3f800000,
+    0x3f800000, 0x00000001, 0xc00f0000, 0xa0e40000, 0x0000ffff, 0x00000002, 0x0000002c, 0xfffe0200,
+    0x05000051, 0xa00f0000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x02000001, 0xc00f0000,
+    0xa0e40000, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x0000000a, 0x00000001, 0x00000009,
+    0x706d6173, 0x3172656c, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000006, 0x00000000,
+    0x0000016c, 0x46580200, 0x0030fffe, 0x42415443, 0x0000001c, 0x0000008b, 0x46580200, 0x00000001,
+    0x0000001c, 0x20000100, 0x00000088, 0x00000030, 0x00000002, 0x00000004, 0x00000038, 0x00000048,
+    0x656d6163, 0xab006172, 0x00030003, 0x00040004, 0x00000001, 0x00000000, 0x40800000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x0024fffe, 0x434c5846,
+    0x00000004, 0x10000004, 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000004,
+    0x00000000, 0x10000004, 0x00000001, 0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000004,
+    0x00000004, 0x10000004, 0x00000001, 0x00000000, 0x00000002, 0x00000008, 0x00000000, 0x00000004,
+    0x00000008, 0x10000004, 0x00000001, 0x00000000, 0x00000002, 0x0000000c, 0x00000000, 0x00000004,
+    0x0000000c, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000000,
+    0x00000001, 0x0000000b, 0x615f7376, 0x5b317272, 0x00005d31,
+};
+#define TEST_EFFECT_STATES_VSHADER_POS 271
+
+static void test_effect_states(IDirect3DDevice9 *device)
+{
+    D3DMATRIX test_mat =
+    {{{
+        -1.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f
+    }}};
+    D3DMATRIX test_mat_camera =
+    {{{
+        4.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 6.0f
+    }}};
+    D3DMATRIX test_mat_world1 =
+    {{{
+        2.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 4.0f
+    }}};
+    D3DMATRIX mat;
+    HRESULT hr;
+    ID3DXEffect *effect;
+    UINT npasses;
+    DWORD value;
+    IDirect3DVertexShader9 *vshader;
+    void *byte_code;
+    UINT byte_code_size;
+    BOOL bval;
+    D3DLIGHT9 light;
+    float float_data[4];
+
+    hr = D3DXCreateEffect(device, test_effect_states_effect_blob, sizeof(test_effect_states_effect_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    /* State affected in passes saved/restored even if no pass
+       was performed. States not present in passes are not saved &
+       restored */
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_BLENDOP, 1);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHAFUNC, 1);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    hr = effect->lpVtbl->Begin(effect, &npasses, 0);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(npasses == 1, "Expected 1 pass, got %u\n", npasses);
+
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_BLENDOP, 3);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHAFUNC, 2);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_BLENDOP, &value);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(value == 1, "Got result %u, expected %u.\n", value, 1);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_ALPHAFUNC, &value);
+    ok(value == 2, "Got result %u, expected %u.\n", value, 2);
+
+    /* Test states application in BeginPass. No states are restored
+       on EndPass. */
+    hr = IDirect3DDevice9_SetSamplerState(device, 1, D3DSAMP_MIPFILTER, 0);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, 0);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    hr = IDirect3DDevice9_GetLightEnable(device, 2, &bval);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    if (hr == D3D_OK)
+        ok(!bval, "Got result %u, expected 0.\n", bval);
+
+    hr = IDirect3DDevice9_SetTransform(device, D3DTS_WORLDMATRIX(1), &test_mat);
+    hr = effect->lpVtbl->Begin(effect, NULL, 0);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    hr = IDirect3DDevice9_GetTransform(device, D3DTS_WORLDMATRIX(1), &mat);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(!memcmp(mat.m, test_mat.m, sizeof(mat)), "World matrix does not match.\n");
+
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    hr = IDirect3DDevice9_GetTransform(device, D3DTS_WORLDMATRIX(1), &mat);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(!memcmp(mat.m, test_mat_world1.m, sizeof(mat)), "World matrix does not match.\n");
+
+    hr = IDirect3DDevice9_GetTransform(device, D3DTS_VIEW, &mat);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(!memcmp(mat.m, test_mat_camera.m, sizeof(mat)), "View matrix does not match.\n");
+
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_BLENDOP, &value);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(value == 2, "Got result %u, expected %u\n", value, 2);
+
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(vshader != NULL, "Got NULL vshader.\n");
+    if (vshader)
+    {
+        hr = IDirect3DVertexShader9_GetFunction(vshader, NULL, &byte_code_size);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+        byte_code = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, byte_code_size);
+        hr = IDirect3DVertexShader9_GetFunction(vshader, byte_code, &byte_code_size);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+        ok(byte_code_size > 1, "Got unexpected byte code size %u.\n", byte_code_size);
+        ok(!memcmp(byte_code, &test_effect_states_effect_blob[TEST_EFFECT_STATES_VSHADER_POS], byte_code_size),
+            "Incorrect shader selected.\n");
+        HeapFree(GetProcessHeap(), 0, byte_code);
+        IDirect3DVertexShader9_Release(vshader);
+    }
+
+    hr = IDirect3DDevice9_GetLightEnable(device, 2, &bval);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    if (hr == D3D_OK)
+        ok(bval, "Got result %u, expected TRUE.\n", bval);
+    hr = IDirect3DDevice9_GetLight(device, 2, &light);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    if (hr == D3D_OK)
+        ok(light.Position.x == 4.0f && light.Position.y == 5.0f && light.Position.z == 6.0f,
+                "Got unexpected light position (%f, %f, %f).\n", light.Position.x, light.Position.y, light.Position.z);
+    hr = IDirect3DDevice9_GetVertexShaderConstantF(device, 3, float_data, 1);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(float_data[0] == 2.0f && float_data[1] == 2.0f && float_data[2] == 2.0f && float_data[3] == 2.0f,
+            "Got unexpected vertex shader floats: (%f %f %f %f).\n",
+            float_data[0], float_data[1], float_data[2], float_data[3]);
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_BLENDOP, &value);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(value == 2, "Got result %u, expected %u\n", value, 2);
+
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_ZENABLE, &value);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(value, "Got result %u, expected TRUE.\n", value);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, 1, D3DSAMP_MIPFILTER, &value);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(value == D3DTEXF_LINEAR, "Unexpected sampler 1 mipfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetTextureStageState(device, 3, D3DTSS_ALPHAOP, &value);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(value == 4, "Unexpected texture stage 3 AlphaOp %u.\n", value);
+
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    hr = IDirect3DDevice9_GetTransform(device, D3DTS_WORLDMATRIX(1), &mat);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(!memcmp(mat.m, test_mat.m, sizeof(mat)), "World matrix not restored.\n");
+
+    hr = IDirect3DDevice9_GetLightEnable(device, 2, &bval);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    if (hr == D3D_OK)
+        ok(!bval, "Got result %u, expected 0.\n", bval);
+
+    /* State is not restored if effect is released without End call */
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_BLENDOP, 1);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    hr = effect->lpVtbl->Begin(effect, &npasses, 0);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_BLENDOP, 3);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+
+    effect->lpVtbl->Release(effect);
+
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_BLENDOP, &value);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(value == 3, "Got result %u, expected %u.\n", value, 1);
+}
+
+/*
+ * fxc.exe /Tfx_2_0
+ */
+#if 0
+float4 g_Pos1;
+float4 g_Pos2;
+float4 g_Selector[3] = {{0, 0, 0, 0}, {10, 10, 10, 10}, {5001, 5002, 5003, 5004}};
+
+float4 opvect1 = {0.0, -0.0, -2.2, 3.402823466e+38F};
+float4 opvect2 = {1.0, 2.0, -3.0, 4.0};
+float4 opvect3 = {0.0, -0.0, -2.2, 3.402823466e+38F};
+
+float4 vect_sampler = {1, 2, 3, 4};
+
+float3 vec3 = {1001, 1002, 1003};
+
+int4 g_iVect = {4, 3, 2, 1};
+
+vertexshader vs_arr[3] =
+{
+    asm
+    {
+        vs_1_0
+        def c0, 1, 1, 1, 1
+        mov oPos, c0
+    },
+    asm
+    {
+        vs_1_1
+        def c0, 2, 2, 2, 2
+        mov oPos, c0
+    },
+    asm
+    {
+        vs_2_0
+        def c0, 3, 3, 3, 3
+        mov oPos, c0
+    }
+};
+
+float4x4 m4x4 = {{11, 12, 13, 14}, {21, 22, 23, 24}, {31, 32, 33, 34}, {41, 42, 43, 44}};
+
+row_major float4x3 m4x3row = {{11, 12, 13}, {21, 22, 23}, {31, 32, 33}, {41, 42, 43}};
+row_major float3x4 m3x4row = {{11, 12, 13, 14}, {21, 22, 23, 24}, {31, 32, 33, 34}};
+column_major float4x3 m4x3column = {{11, 12, 13},{21, 22, 23},{31, 32, 33},{41, 42, 43}};
+column_major float3x4 m3x4column = {{11, 12, 13, 14}, {21, 22, 23, 24}, {31, 32, 33, 34}};
+row_major float2x2 m2x2row = {{11, 12}, {21, 22}};
+column_major float2x2 m2x2column = {{11, 12}, {21, 22}};
+row_major float2x3 m2x3row = {{11, 12, 13}, {21, 22, 23}};
+column_major float2x3 m2x3column = {{11, 12, 13}, {21, 22, 23}};
+row_major float3x2 m3x2row = {{11, 12}, {21, 22}, {31, 32}};
+column_major float3x2 m3x2column = {{11, 12}, {21, 22}, {31, 32}};
+
+row_major bool2x3 mb2x3row = {{true, false, true}, {false, true, true}};
+column_major bool2x3 mb2x3column = {{true, false, true}, {false, true, true}};
+
+struct test_struct
+{
+    float3 v1;
+    float fv;
+    float4 v2;
+};
+
+struct struct_array
+{
+    test_struct ts[2];
+};
+
+test_struct ts1[1] = {{{9, 10, 11}, 12, {13, 14, 15, 16}}};
+shared test_struct ts2[2] = {{{0, 0, 0}, 0, {0, 0, 0, 0}}, {{1, 2, 3}, 4, {5, 6, 7, 8}}};
+struct_array ts3 = {{{1, 2, 3}, 4, {5, 6, 7, 8}}, {{9, 10, 11}, 12, {13, 14, 15, 16}}};
+
+float arr1[1] = {91};
+shared float arr2[2] = {92, 93};
+
+Texture2D tex1;
+Texture2D tex2;
+sampler sampler1 =
+sampler_state
+{
+    Texture = tex1;
+    MinFilter = g_iVect.y;
+    MagFilter = vect_sampler.x + vect_sampler.y;
+};
+
+sampler samplers_array[2] =
+{
+    sampler_state
+    {
+        MinFilter = 1;
+        MagFilter = vect_sampler.x;
+    },
+    sampler_state
+    {
+        MinFilter = 2;
+        MagFilter = vect_sampler.y;
+    }
+};
+
+struct VS_OUTPUT
+{
+    float4 Position   : POSITION;
+    float2 TextureUV  : TEXCOORD0;
+    float4 Diffuse    : COLOR0;
+};
+VS_OUTPUT RenderSceneVS(float4 vPos : POSITION,
+                        float3 vNormal : NORMAL,
+                        float2 vTexCoord0 : TEXCOORD0,
+                        uniform int nNumLights,
+                        uniform bool bTexture)
+{
+    VS_OUTPUT Output;
+
+    if (g_Selector[1].y > float4(0.5, 0.5, 0.5, 0.5).y)
+        Output.Position = -g_Pos1 * 2 - float4(-4, -5, -6, -7);
+    else
+        Output.Position = -g_Pos2 * 3 - float4(-4, -5, -6, -7);
+    Output.TextureUV = float2(0, 0);
+    Output.Diffuse = 0;
+    Output.Diffuse.xyz = mul(vPos, m4x3column);
+    Output.Diffuse += mul(vPos, m3x4column);
+    Output.Diffuse += mul(vPos, m3x4row);
+    Output.Diffuse.xyz += mul(vPos, m4x3row);
+    Output.Diffuse += mul(vPos, ts1[0].fv);
+    Output.Diffuse += mul(vPos, ts1[0].v2);
+    Output.Diffuse += mul(vPos, ts2[1].fv);
+    Output.Diffuse += mul(vPos, ts2[1].v2);
+    Output.Diffuse += mul(vPos, arr1[0]);
+    Output.Diffuse += mul(vPos, arr2[1]);
+    Output.Diffuse += mul(vPos, ts3.ts[1].fv);
+    Output.Diffuse += mul(vPos, ts3.ts[1].v2);
+    Output.Diffuse += tex2Dlod(sampler1, g_Pos1);
+    Output.Diffuse += tex2Dlod(samplers_array[1], g_Pos1);
+    return Output;
+}
+
+VS_OUTPUT RenderSceneVS2(float4 vPos : POSITION)
+{
+    VS_OUTPUT Output;
+
+    Output.Position = g_Pos1;
+    Output.TextureUV = float2(0, 0);
+    Output.Diffuse = 0;
+    return Output;
+}
+
+struct PS_OUTPUT
+{
+    float4 RGBColor : COLOR0;  /* Pixel color */
+};
+PS_OUTPUT RenderScenePS( VS_OUTPUT In, uniform bool2x3 mb)
+{
+    PS_OUTPUT Output;
+    int i;
+
+    Output.RGBColor = In.Diffuse;
+    Output.RGBColor.xy += mul(In.Diffuse, m2x2row);
+    Output.RGBColor.xy += mul(In.Diffuse, m2x2column);
+    Output.RGBColor.xy += mul(In.Diffuse, m3x2row);
+    Output.RGBColor.xy += mul(In.Diffuse, m3x2column);
+    Output.RGBColor.xyz += mul(In.Diffuse, m2x3row);
+    Output.RGBColor.xyz += mul(In.Diffuse, m2x3column);
+    for (i = 0; i < g_iVect.x; ++i)
+        Output.RGBColor.xyz += mul(In.Diffuse, m2x3column);
+    if (mb[1][1])
+    {
+        Output.RGBColor += sin(Output.RGBColor);
+        Output.RGBColor += cos(Output.RGBColor);
+        Output.RGBColor.xyz += mul(Output.RGBColor, m2x3column);
+        Output.RGBColor.xyz += mul(Output.RGBColor, m2x3row);
+        Output.RGBColor.xy += mul(Output.RGBColor, m3x2column);
+        Output.RGBColor.xy += mul(Output.RGBColor, m3x2row);
+    }
+    if (mb2x3column[0][0])
+    {
+        Output.RGBColor += sin(Output.RGBColor);
+        Output.RGBColor += cos(Output.RGBColor);
+        Output.RGBColor.xyz += mul(Output.RGBColor, m2x3column);
+        Output.RGBColor.xyz += mul(Output.RGBColor, m2x3row);
+        Output.RGBColor.xy += mul(Output.RGBColor, m3x2column);
+        Output.RGBColor.xy += mul(Output.RGBColor, m3x2row);
+    }
+    Output.RGBColor += tex2D(sampler1, In.TextureUV);
+    Output.RGBColor += tex2D(samplers_array[0], In.TextureUV);
+    return Output;
+}
+
+shared vertexshader vs_arr2[2] = {compile vs_3_0 RenderSceneVS(1, true), compile vs_3_0 RenderSceneVS2()};
+pixelshader ps_arr[1] = {compile ps_3_0 RenderScenePS(mb2x3row)};
+
+technique tech0
+{
+    pass p0
+    {
+        VertexShader = vs_arr2[g_iVect.w - 1];
+        PixelShader  = ps_arr[g_iVect.w - 1];
+
+        LightEnable[0] = TRUE;
+        LightEnable[1] = TRUE;
+        LightEnable[2] = TRUE;
+        LightEnable[3] = TRUE;
+        LightEnable[4] = TRUE;
+        LightEnable[5] = TRUE;
+        LightEnable[6] = TRUE;
+        LightEnable[7] = TRUE;
+        LightType[0] = POINT;
+        LightType[1] = POINT;
+        LightType[2] = POINT;
+        LightType[3] = POINT;
+        LightType[4] = POINT;
+        LightType[5] = POINT;
+        LightType[6] = POINT;
+        LightType[7] = POINT;
+        LightDiffuse[0] = 1 / opvect1;
+        LightDiffuse[1] = rsqrt(opvect1);
+        LightDiffuse[2] = opvect1 * opvect2;
+        LightDiffuse[3] = opvect1 + opvect2;
+        LightDiffuse[4] = float4(opvect1 < opvect2);
+        LightDiffuse[5] = float4(opvect1 >= opvect2);
+        LightDiffuse[6] = -opvect1;
+        LightDiffuse[7] = rcp(opvect1);
+
+        LightAmbient[0] = frac(opvect1);
+        LightAmbient[1] = min(opvect1, opvect2);
+        LightAmbient[2] = max(opvect1, opvect2);
+        LightAmbient[3] = sin(opvect1);
+        LightAmbient[4] = cos(opvect1);
+        LightAmbient[5] = 1e-2 / opvect1;
+        LightAmbient[6] = float4(0, dot(opvect1, opvect2), dot(opvect2, opvect2), 0);
+        LightAmbient[7] = opvect1 + 1e-12 * opvect2 - opvect3;
+
+        LightSpecular[0] = float4(dot(opvect1.zx, opvect2.xy), dot(opvect1.zzx, opvect2.xyz),
+                dot(opvect1.zzzx, opvect2.xxyy), 0);
+        LightSpecular[1] = float4(opvect1[g_iVect.z], g_iVect[opvect2.y + 1],
+                g_Selector[4 + g_iVect.w].x + g_Selector[7 + g_iVect.w].y,
+                g_Selector[g_iVect.w].x + g_Selector[g_iVect.x].y);
+        LightSpecular[2] = float4(dot(m4x4[3 + g_iVect.z], m4x4[g_iVect.w * 2]), ts3.ts[g_iVect.x].fv,
+                vec3[g_iVect.z], float3(1, 2, 3)[g_iVect.w]);
+
+        FogEnable = TRUE;
+        FogDensity = ts2[0].fv;
+        FogStart = ts2[1].fv;
+        PointScale_A = ts3.ts[0].fv;
+        PointScale_B = ts3.ts[1].fv;
+    }
+    pass p1
+    {
+        VertexShader = vs_arr[g_iVect.z];
+    }
+}
+#endif
+static const DWORD test_effect_preshader_effect_blob[] =
+{
+    0xfeff0901, 0x00001160, 0x00000000, 0x00000003, 0x00000001, 0x00000030, 0x00000000, 0x00000000,
+    0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000007, 0x6f505f67,
+    0x00003173, 0x00000003, 0x00000001, 0x00000068, 0x00000000, 0x00000000, 0x00000004, 0x00000001,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000007, 0x6f505f67, 0x00003273, 0x00000003,
+    0x00000001, 0x000000c0, 0x00000000, 0x00000003, 0x00000004, 0x00000001, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x41200000, 0x41200000, 0x41200000, 0x41200000, 0x459c4800, 0x459c5000,
+    0x459c5800, 0x459c6000, 0x0000000b, 0x65535f67, 0x7463656c, 0x0000726f, 0x00000003, 0x00000001,
+    0x000000fc, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x80000000, 0xc00ccccd,
+    0x7f7fffff, 0x00000008, 0x6576706f, 0x00317463, 0x00000003, 0x00000001, 0x00000134, 0x00000000,
+    0x00000000, 0x00000004, 0x00000001, 0x3f800000, 0x40000000, 0xc0400000, 0x40800000, 0x00000008,
+    0x6576706f, 0x00327463, 0x00000003, 0x00000001, 0x0000016c, 0x00000000, 0x00000000, 0x00000004,
+    0x00000001, 0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff, 0x00000008, 0x6576706f, 0x00337463,
+    0x00000003, 0x00000001, 0x000001a4, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x3f800000,
+    0x40000000, 0x40400000, 0x40800000, 0x0000000d, 0x74636576, 0x6d61735f, 0x72656c70, 0x00000000,
+    0x00000003, 0x00000001, 0x000001e0, 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x447a4000,
+    0x447a8000, 0x447ac000, 0x00000005, 0x33636576, 0x00000000, 0x00000002, 0x00000001, 0x00000218,
+    0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000004, 0x00000003, 0x00000002, 0x00000001,
+    0x00000008, 0x56695f67, 0x00746365, 0x00000010, 0x00000004, 0x00000244, 0x00000000, 0x00000003,
+    0x00000001, 0x00000002, 0x00000003, 0x00000007, 0x615f7376, 0x00007272, 0x00000003, 0x00000002,
+    0x000002ac, 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x41300000, 0x41400000, 0x41500000,
+    0x41600000, 0x41a80000, 0x41b00000, 0x41b80000, 0x41c00000, 0x41f80000, 0x42000000, 0x42040000,
+    0x42080000, 0x42240000, 0x42280000, 0x422c0000, 0x42300000, 0x00000005, 0x3478346d, 0x00000000,
+    0x00000003, 0x00000002, 0x00000304, 0x00000000, 0x00000000, 0x00000004, 0x00000003, 0x41300000,
+    0x41400000, 0x41500000, 0x41a80000, 0x41b00000, 0x41b80000, 0x41f80000, 0x42000000, 0x42040000,
+    0x42240000, 0x42280000, 0x422c0000, 0x00000008, 0x3378346d, 0x00776f72, 0x00000003, 0x00000002,
+    0x0000035c, 0x00000000, 0x00000000, 0x00000003, 0x00000004, 0x41300000, 0x41400000, 0x41500000,
+    0x41600000, 0x41a80000, 0x41b00000, 0x41b80000, 0x41c00000, 0x41f80000, 0x42000000, 0x42040000,
+    0x42080000, 0x00000008, 0x3478336d, 0x00776f72, 0x00000003, 0x00000002, 0x000003b4, 0x00000000,
+    0x00000000, 0x00000004, 0x00000003, 0x41300000, 0x41400000, 0x41500000, 0x41a80000, 0x41b00000,
+    0x41b80000, 0x41f80000, 0x42000000, 0x42040000, 0x42240000, 0x42280000, 0x422c0000, 0x0000000b,
+    0x3378346d, 0x756c6f63, 0x00006e6d, 0x00000003, 0x00000002, 0x00000410, 0x00000000, 0x00000000,
+    0x00000003, 0x00000004, 0x41300000, 0x41400000, 0x41500000, 0x41600000, 0x41a80000, 0x41b00000,
+    0x41b80000, 0x41c00000, 0x41f80000, 0x42000000, 0x42040000, 0x42080000, 0x0000000b, 0x3478336d,
+    0x756c6f63, 0x00006e6d, 0x00000003, 0x00000002, 0x0000044c, 0x00000000, 0x00000000, 0x00000002,
+    0x00000002, 0x41300000, 0x41400000, 0x41a80000, 0x41b00000, 0x00000008, 0x3278326d, 0x00776f72,
+    0x00000003, 0x00000002, 0x00000484, 0x00000000, 0x00000000, 0x00000002, 0x00000002, 0x41300000,
+    0x41400000, 0x41a80000, 0x41b00000, 0x0000000b, 0x3278326d, 0x756c6f63, 0x00006e6d, 0x00000003,
+    0x00000002, 0x000004c8, 0x00000000, 0x00000000, 0x00000002, 0x00000003, 0x41300000, 0x41400000,
+    0x41500000, 0x41a80000, 0x41b00000, 0x41b80000, 0x00000008, 0x3378326d, 0x00776f72, 0x00000003,
+    0x00000002, 0x00000508, 0x00000000, 0x00000000, 0x00000002, 0x00000003, 0x41300000, 0x41400000,
+    0x41500000, 0x41a80000, 0x41b00000, 0x41b80000, 0x0000000b, 0x3378326d, 0x756c6f63, 0x00006e6d,
+    0x00000003, 0x00000002, 0x0000054c, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x41300000,
+    0x41400000, 0x41a80000, 0x41b00000, 0x41f80000, 0x42000000, 0x00000008, 0x3278336d, 0x00776f72,
+    0x00000003, 0x00000002, 0x0000058c, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x41300000,
+    0x41400000, 0x41a80000, 0x41b00000, 0x41f80000, 0x42000000, 0x0000000b, 0x3278336d, 0x756c6f63,
+    0x00006e6d, 0x00000001, 0x00000002, 0x000005d0, 0x00000000, 0x00000000, 0x00000002, 0x00000003,
+    0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000009, 0x7832626d,
+    0x776f7233, 0x00000000, 0x00000001, 0x00000002, 0x00000614, 0x00000000, 0x00000000, 0x00000002,
+    0x00000003, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x0000000c,
+    0x7832626d, 0x6c6f6333, 0x006e6d75, 0x00000000, 0x00000005, 0x000006b0, 0x00000000, 0x00000001,
+    0x00000003, 0x00000003, 0x00000001, 0x000006b8, 0x00000000, 0x00000000, 0x00000003, 0x00000001,
+    0x00000003, 0x00000000, 0x000006c0, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000003,
+    0x00000001, 0x000006c8, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x41100000, 0x41200000,
+    0x41300000, 0x41400000, 0x41500000, 0x41600000, 0x41700000, 0x41800000, 0x00000004, 0x00317374,
+    0x00000003, 0x00003176, 0x00000003, 0x00007666, 0x00000003, 0x00003276, 0x00000000, 0x00000005,
+    0x0000077c, 0x00000000, 0x00000002, 0x00000003, 0x00000003, 0x00000001, 0x00000784, 0x00000000,
+    0x00000000, 0x00000003, 0x00000001, 0x00000003, 0x00000000, 0x0000078c, 0x00000000, 0x00000000,
+    0x00000001, 0x00000001, 0x00000003, 0x00000001, 0x00000794, 0x00000000, 0x00000000, 0x00000004,
+    0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x40a00000, 0x40c00000, 0x40e00000,
+    0x41000000, 0x00000004, 0x00327374, 0x00000003, 0x00003176, 0x00000003, 0x00007666, 0x00000003,
+    0x00003276, 0x00000000, 0x00000005, 0x00000860, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+    0x00000005, 0x00000868, 0x00000000, 0x00000002, 0x00000003, 0x00000003, 0x00000001, 0x00000870,
+    0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000003, 0x00000000, 0x00000878, 0x00000000,
+    0x00000000, 0x00000001, 0x00000001, 0x00000003, 0x00000001, 0x00000880, 0x00000000, 0x00000000,
+    0x00000004, 0x00000001, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x40a00000, 0x40c00000,
+    0x40e00000, 0x41000000, 0x41100000, 0x41200000, 0x41300000, 0x41400000, 0x41500000, 0x41600000,
+    0x41700000, 0x41800000, 0x00000004, 0x00337374, 0x00000003, 0x00007374, 0x00000003, 0x00003176,
+    0x00000003, 0x00007666, 0x00000003, 0x00003276, 0x00000003, 0x00000000, 0x000008a8, 0x00000000,
+    0x00000001, 0x00000001, 0x00000001, 0x42b60000, 0x00000005, 0x31727261, 0x00000000, 0x00000003,
+    0x00000000, 0x000008d8, 0x00000000, 0x00000002, 0x00000001, 0x00000001, 0x42b80000, 0x42ba0000,
+    0x00000005, 0x32727261, 0x00000000, 0x00000007, 0x00000004, 0x000008fc, 0x00000000, 0x00000000,
+    0x00000004, 0x00000005, 0x31786574, 0x00000000, 0x00000007, 0x00000004, 0x00000920, 0x00000000,
+    0x00000000, 0x00000005, 0x00000005, 0x32786574, 0x00000000, 0x0000000a, 0x00000004, 0x000009cc,
+    0x00000000, 0x00000000, 0x00000006, 0x00000007, 0x00000004, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001,
+    0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001,
+    0x00000003, 0x000000a4, 0x00000100, 0x00000944, 0x00000940, 0x000000aa, 0x00000100, 0x0000095c,
+    0x00000958, 0x000000a9, 0x00000100, 0x0000097c, 0x00000978, 0x00000009, 0x706d6173, 0x3172656c,
+    0x00000000, 0x0000000a, 0x00000004, 0x00000ab8, 0x00000000, 0x00000002, 0x00000001, 0x00000002,
+    0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000003,
+    0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000003,
+    0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000002, 0x000000aa,
+    0x00000100, 0x000009f4, 0x000009f0, 0x000000a9, 0x00000100, 0x00000a14, 0x00000a10, 0x00000002,
+    0x000000aa, 0x00000100, 0x00000a34, 0x00000a30, 0x000000a9, 0x00000100, 0x00000a54, 0x00000a50,
+    0x0000000f, 0x706d6173, 0x7372656c, 0x7272615f, 0x00007961, 0x00000010, 0x00000004, 0x00000ae8,
+    0x00000000, 0x00000002, 0x00000007, 0x00000008, 0x00000008, 0x615f7376, 0x00327272, 0x0000000f,
+    0x00000004, 0x00000b0c, 0x00000000, 0x00000001, 0x00000009, 0x00000007, 0x615f7370, 0x00007272,
+    0x0000000a, 0x00000010, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x0000000b, 0x0000000f,
+    0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000,
+    0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000,
+    0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
+    0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004,
+    0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000,
+    0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000,
+    0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
+    0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004,
+    0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000,
+    0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000003, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000003, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000003, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000003, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000003, 0x00003070, 0x0000000c,
+    0x00000010, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00003170, 0x00000006,
+    0x68636574, 0x00000030, 0x00000022, 0x00000001, 0x0000000e, 0x0000000d, 0x00000004, 0x00000020,
+    0x00000000, 0x00000000, 0x0000003c, 0x00000058, 0x00000000, 0x00000000, 0x00000074, 0x00000090,
+    0x00000000, 0x00000000, 0x000000d0, 0x000000ec, 0x00000000, 0x00000000, 0x00000108, 0x00000124,
+    0x00000000, 0x00000000, 0x00000140, 0x0000015c, 0x00000000, 0x00000000, 0x00000178, 0x00000194,
+    0x00000000, 0x00000000, 0x000001b8, 0x000001d4, 0x00000000, 0x00000000, 0x000001ec, 0x00000208,
+    0x00000000, 0x00000000, 0x00000224, 0x00000238, 0x00000000, 0x00000000, 0x00000250, 0x0000026c,
+    0x00000000, 0x00000000, 0x000002b8, 0x000002d4, 0x00000000, 0x00000000, 0x00000310, 0x0000032c,
+    0x00000000, 0x00000000, 0x00000368, 0x00000384, 0x00000000, 0x00000000, 0x000003c4, 0x000003e0,
+    0x00000000, 0x00000000, 0x00000420, 0x0000043c, 0x00000000, 0x00000000, 0x00000458, 0x00000474,
+    0x00000000, 0x00000000, 0x00000494, 0x000004b0, 0x00000000, 0x00000000, 0x000004d4, 0x000004f0,
+    0x00000000, 0x00000000, 0x00000518, 0x00000534, 0x00000000, 0x00000000, 0x00000558, 0x00000574,
+    0x00000000, 0x00000000, 0x0000059c, 0x000005b8, 0x00000000, 0x00000000, 0x000005e0, 0x000005fc,
+    0x00000000, 0x00000000, 0x00000624, 0x00000690, 0x00000000, 0x00000000, 0x000006d0, 0x0000073c,
+    0x00000001, 0x00000000, 0x0000079c, 0x00000820, 0x00000000, 0x00000000, 0x00000888, 0x000008a4,
+    0x00000000, 0x00000000, 0x000008b4, 0x000008d0, 0x00000001, 0x00000000, 0x000008e4, 0x000008f8,
+    0x00000000, 0x00000000, 0x00000908, 0x0000091c, 0x00000000, 0x00000000, 0x0000092c, 0x00000998,
+    0x00000000, 0x00000000, 0x000009dc, 0x00000a70, 0x00000000, 0x00000000, 0x00000acc, 0x00000ae0,
+    0x00000001, 0x00000000, 0x00000af4, 0x00000b08, 0x00000000, 0x00000000, 0x00001154, 0x00000000,
+    0x00000002, 0x0000112c, 0x00000000, 0x0000002a, 0x00000092, 0x00000000, 0x00000b1c, 0x00000b18,
+    0x00000093, 0x00000000, 0x00000b34, 0x00000b30, 0x00000091, 0x00000000, 0x00000b4c, 0x00000b48,
+    0x00000091, 0x00000001, 0x00000b6c, 0x00000b68, 0x00000091, 0x00000002, 0x00000b8c, 0x00000b88,
+    0x00000091, 0x00000003, 0x00000bac, 0x00000ba8, 0x00000091, 0x00000004, 0x00000bcc, 0x00000bc8,
+    0x00000091, 0x00000005, 0x00000bec, 0x00000be8, 0x00000091, 0x00000006, 0x00000c0c, 0x00000c08,
+    0x00000091, 0x00000007, 0x00000c2c, 0x00000c28, 0x00000084, 0x00000000, 0x00000c4c, 0x00000c48,
+    0x00000084, 0x00000001, 0x00000c6c, 0x00000c68, 0x00000084, 0x00000002, 0x00000c8c, 0x00000c88,
+    0x00000084, 0x00000003, 0x00000cac, 0x00000ca8, 0x00000084, 0x00000004, 0x00000ccc, 0x00000cc8,
+    0x00000084, 0x00000005, 0x00000cec, 0x00000ce8, 0x00000084, 0x00000006, 0x00000d0c, 0x00000d08,
+    0x00000084, 0x00000007, 0x00000d2c, 0x00000d28, 0x00000085, 0x00000000, 0x00000d58, 0x00000d48,
+    0x00000085, 0x00000001, 0x00000d84, 0x00000d74, 0x00000085, 0x00000002, 0x00000db0, 0x00000da0,
+    0x00000085, 0x00000003, 0x00000ddc, 0x00000dcc, 0x00000085, 0x00000004, 0x00000e08, 0x00000df8,
+    0x00000085, 0x00000005, 0x00000e34, 0x00000e24, 0x00000085, 0x00000006, 0x00000e60, 0x00000e50,
+    0x00000085, 0x00000007, 0x00000e8c, 0x00000e7c, 0x00000087, 0x00000000, 0x00000eb8, 0x00000ea8,
+    0x00000087, 0x00000001, 0x00000ee4, 0x00000ed4, 0x00000087, 0x00000002, 0x00000f10, 0x00000f00,
+    0x00000087, 0x00000003, 0x00000f3c, 0x00000f2c, 0x00000087, 0x00000004, 0x00000f68, 0x00000f58,
+    0x00000087, 0x00000005, 0x00000f94, 0x00000f84, 0x00000087, 0x00000006, 0x00000fc0, 0x00000fb0,
+    0x00000087, 0x00000007, 0x00000fec, 0x00000fdc, 0x00000086, 0x00000000, 0x00001018, 0x00001008,
+    0x00000086, 0x00000001, 0x00001044, 0x00001034, 0x00000086, 0x00000002, 0x00001070, 0x00001060,
+    0x0000000e, 0x00000000, 0x00001090, 0x0000108c, 0x00000014, 0x00000000, 0x000010b0, 0x000010ac,
+    0x00000012, 0x00000000, 0x000010d0, 0x000010cc, 0x00000041, 0x00000000, 0x000010f0, 0x000010ec,
+    0x00000042, 0x00000000, 0x00001110, 0x0000110c, 0x0000114c, 0x00000000, 0x00000001, 0x00000092,
+    0x00000000, 0x00001138, 0x00001134, 0x00000008, 0x0000001f, 0x00000009, 0x00000ad0, 0xffff0300,
+    0x00d9fffe, 0x42415443, 0x0000001c, 0x0000032f, 0xffff0300, 0x0000000b, 0x0000001c, 0x00000000,
+    0x00000328, 0x000000f8, 0x00000001, 0x00000001, 0x00000100, 0x00000110, 0x00000120, 0x00080002,
+    0x00000002, 0x0000012c, 0x0000013c, 0x0000015c, 0x00060002, 0x00000002, 0x00000164, 0x00000174,
+    0x00000194, 0x00000002, 0x00000003, 0x000001a0, 0x000001b0, 0x000001e0, 0x000a0002, 0x00000002,
+    0x000001e8, 0x000001f8, 0x00000218, 0x000c0002, 0x00000002, 0x00000224, 0x00000234, 0x00000254,
+    0x00030002, 0x00000003, 0x0000025c, 0x0000026c, 0x0000029c, 0x00050000, 0x00000001, 0x000002a8,
+    0x000002b8, 0x000002d0, 0x00000000, 0x00000005, 0x000002dc, 0x000002b8, 0x000002ec, 0x00000003,
+    0x00000001, 0x000002f8, 0x00000000, 0x00000308, 0x00010003, 0x00000001, 0x00000318, 0x00000000,
+    0x56695f67, 0x00746365, 0x00020001, 0x00040001, 0x00000001, 0x00000000, 0x00000004, 0x00000003,
+    0x00000002, 0x00000001, 0x3278326d, 0x756c6f63, 0xab006e6d, 0x00030003, 0x00020002, 0x00000001,
+    0x00000000, 0x41300000, 0x41a80000, 0x00000000, 0x00000000, 0x41400000, 0x41b00000, 0x00000000,
+    0x00000000, 0x3278326d, 0x00776f72, 0x00030002, 0x00020002, 0x00000001, 0x00000000, 0x41300000,
+    0x41400000, 0x00000000, 0x00000000, 0x41a80000, 0x41b00000, 0x00000000, 0x00000000, 0x3378326d,
+    0x756c6f63, 0xab006e6d, 0x00030003, 0x00030002, 0x00000001, 0x00000000, 0x41300000, 0x41a80000,
+    0x00000000, 0x00000000, 0x41400000, 0x41b00000, 0x00000000, 0x00000000, 0x41500000, 0x41b80000,
+    0x00000000, 0x00000000, 0x3378326d, 0x00776f72, 0x00030002, 0x00030002, 0x00000001, 0x00000000,
+    0x41300000, 0x41400000, 0x41500000, 0x00000000, 0x41a80000, 0x41b00000, 0x41b80000, 0x00000000,
+    0x3278336d, 0x756c6f63, 0xab006e6d, 0x00030003, 0x00020003, 0x00000001, 0x00000000, 0x41300000,
+    0x41a80000, 0x41f80000, 0x00000000, 0x41400000, 0x41b00000, 0x42000000, 0x00000000, 0x3278336d,
+    0x00776f72, 0x00030002, 0x00020003, 0x00000001, 0x00000000, 0x41300000, 0x41400000, 0x00000000,
+    0x00000000, 0x41a80000, 0x41b00000, 0x00000000, 0x00000000, 0x41f80000, 0x42000000, 0x00000000,
+    0x00000000, 0x7832626d, 0x6c6f6333, 0x006e6d75, 0x00010003, 0x00030002, 0x00000001, 0x00000000,
+    0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x7832626d, 0x776f7233,
+    0xababab00, 0x00010002, 0x00030002, 0x00000001, 0x00000000, 0x706d6173, 0x3172656c, 0xababab00,
+    0x000c0004, 0x00010001, 0x00000001, 0x00000000, 0x706d6173, 0x7372656c, 0x7272615f, 0xab007961,
+    0x000c0004, 0x00010001, 0x00000002, 0x00000000, 0x335f7370, 0x4d00305f, 0x6f726369, 0x74666f73,
+    0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932,
+    0x332e3235, 0x00313131, 0x05000051, 0xa00f000e, 0x3d2aaaa4, 0xbf000000, 0x3f800000, 0xbe22f983,
+    0x05000051, 0xa00f000f, 0x40c90fdb, 0xc0490fdb, 0xb4878163, 0x37cfb5a1, 0x05000051, 0xa00f0010,
+    0x00000000, 0x3e22f983, 0x3e800000, 0xbab609ba, 0x0200001f, 0x80000005, 0x90030000, 0x0200001f,
+    0x8000000a, 0x900f0001, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000, 0xa00f0801,
+    0x03000005, 0x80030000, 0xa0e40007, 0x90550001, 0x04000004, 0x80030000, 0x90000001, 0xa0e40006,
+    0x80e40000, 0x03000002, 0x80030000, 0x80e40000, 0x90e40001, 0x02000001, 0x80010001, 0xa0000010,
+    0x0400005a, 0x80010002, 0x90e40001, 0xa0e40008, 0x80000001, 0x0400005a, 0x80020002, 0x90e40001,
+    0xa0e40009, 0x80000001, 0x03000002, 0x80030000, 0x80e40000, 0x80e40002, 0x03000005, 0x800c0000,
+    0xa0440004, 0x90550001, 0x04000004, 0x800c0000, 0x90000001, 0xa0440003, 0x80e40000, 0x04000004,
+    0x800c0000, 0x90aa0001, 0xa0440005, 0x80e40000, 0x03000002, 0x80030000, 0x80ee0000, 0x80e40000,
+    0x03000008, 0x80010002, 0x90e40001, 0xa0e4000c, 0x03000008, 0x80020002, 0x90e40001, 0xa0e4000d,
+    0x03000002, 0x80030000, 0x80e40000, 0x80e40002, 0x03000005, 0x800e0001, 0xa090000b, 0x90550001,
+    0x04000004, 0x800e0001, 0x90000001, 0xa090000a, 0x80e40001, 0x02000001, 0x80040000, 0x90aa0001,
+    0x03000002, 0x80070000, 0x80e40000, 0x80f90001, 0x0400005a, 0x80010002, 0x90e40001, 0xa0e40000,
+    0x80000001, 0x0400005a, 0x80020002, 0x90e40001, 0xa0e40001, 0x80000001, 0x0400005a, 0x80040002,
+    0x90e40001, 0xa0e40002, 0x80000001, 0x03000002, 0x80070000, 0x80e40000, 0x80e40002, 0x02000001,
+    0x80070003, 0x80e40000, 0x01000026, 0xf0e40000, 0x03000002, 0x80070003, 0x80e40002, 0x80e40003,
+    0x00000027, 0x01000028, 0xe0e40804, 0x02000001, 0x80080003, 0x90ff0001, 0x04000004, 0x800f0000,
+    0x80e40003, 0xa0550010, 0xa0aa0010, 0x02000013, 0x800f0000, 0x80e40000, 0x04000004, 0x800f0000,
+    0x80e40000, 0xa000000f, 0xa055000f, 0x03000005, 0x800f0000, 0x80e40000, 0x80e40000, 0x04000004,
+    0x800f0002, 0x80e40000, 0xa0aa000f, 0xa0ff000f, 0x04000004, 0x800f0002, 0x80e40000, 0x80e40002,
+    0xa0ff0010, 0x04000004, 0x800f0002, 0x80e40000, 0x80e40002, 0xa000000e, 0x04000004, 0x800f0002,
+    0x80e40000, 0x80e40002, 0xa055000e, 0x04000004, 0x800f0000, 0x80e40000, 0x80e40002, 0x80e40003,
+    0x03000002, 0x800f0000, 0x80e40000, 0xa0aa000e, 0x04000004, 0x800f0002, 0x80e40000, 0xa1ff000e,
+    0xa155000e, 0x02000013, 0x800f0002, 0x80e40002, 0x04000004, 0x800f0002, 0x80e40002, 0xa000000f,
+    0xa055000f, 0x03000005, 0x800f0002, 0x80e40002, 0x80e40002, 0x04000004, 0x800f0004, 0x80e40002,
+    0xa0aa000f, 0xa0ff000f, 0x04000004, 0x800f0004, 0x80e40002, 0x80e40004, 0xa0ff0010, 0x04000004,
+    0x800f0004, 0x80e40002, 0x80e40004, 0xa000000e, 0x04000004, 0x800f0004, 0x80e40002, 0x80e40004,
+    0xa055000e, 0x04000004, 0x800f0000, 0x80e40002, 0x80e40004, 0x80e40000, 0x03000002, 0x800f0003,
+    0x80e40000, 0xa0aa000e, 0x0400005a, 0x80010000, 0x80e40003, 0xa0e40000, 0x80000001, 0x0400005a,
+    0x80020000, 0x80e40003, 0xa0e40001, 0x80000001, 0x0400005a, 0x80040000, 0x80e40003, 0xa0e40002,
+    0x80000001, 0x03000002, 0x80070000, 0x80e40000, 0x80e40003, 0x03000005, 0x800e0001, 0x80550000,
+    0xa090000b, 0x04000004, 0x800e0001, 0x80000000, 0xa090000a, 0x80e40001, 0x03000002, 0x80070003,
+    0x80e40000, 0x80f90001, 0x03000008, 0x80010000, 0x80e40003, 0xa0e4000c, 0x03000008, 0x80020000,
+    0x80e40003, 0xa0e4000d, 0x03000002, 0x80030000, 0x80e40000, 0x80e40003, 0x03000005, 0x800c0000,
+    0x80550000, 0xa0440004, 0x04000004, 0x800c0000, 0x80000000, 0xa0440003, 0x80e40000, 0x04000004,
+    0x800c0000, 0x80aa0003, 0xa0440005, 0x80e40000, 0x03000002, 0x80030003, 0x80ee0000, 0x80e40000,
+    0x0000002a, 0x02000001, 0x80080003, 0x90ff0001, 0x0000002b, 0x01000028, 0xe0e40805, 0x04000004,
+    0x800f0000, 0x80e40003, 0xa0550010, 0xa0aa0010, 0x02000013, 0x800f0000, 0x80e40000, 0x04000004,
+    0x800f0000, 0x80e40000, 0xa000000f, 0xa055000f, 0x03000005, 0x800f0000, 0x80e40000, 0x80e40000,
+    0x04000004, 0x800f0002, 0x80e40000, 0xa0aa000f, 0xa0ff000f, 0x04000004, 0x800f0002, 0x80e40000,
+    0x80e40002, 0xa0ff0010, 0x04000004, 0x800f0002, 0x80e40000, 0x80e40002, 0xa000000e, 0x04000004,
+    0x800f0002, 0x80e40000, 0x80e40002, 0xa055000e, 0x04000004, 0x800f0000, 0x80e40000, 0x80e40002,
+    0x80e40003, 0x03000002, 0x800f0000, 0x80e40000, 0xa0aa000e, 0x04000004, 0x800f0002, 0x80e40000,
+    0xa1ff000e, 0xa155000e, 0x02000013, 0x800f0002, 0x80e40002, 0x04000004, 0x800f0002, 0x80e40002,
+    0xa000000f, 0xa055000f, 0x03000005, 0x800f0002, 0x80e40002, 0x80e40002, 0x04000004, 0x800f0004,
+    0x80e40002, 0xa0aa000f, 0xa0ff000f, 0x04000004, 0x800f0004, 0x80e40002, 0x80e40004, 0xa0ff0010,
+    0x04000004, 0x800f0004, 0x80e40002, 0x80e40004, 0xa000000e, 0x04000004, 0x800f0004, 0x80e40002,
+    0x80e40004, 0xa055000e, 0x04000004, 0x800f0000, 0x80e40002, 0x80e40004, 0x80e40000, 0x03000002,
+    0x800f0003, 0x80e40000, 0xa0aa000e, 0x0400005a, 0x80010000, 0x80e40003, 0xa0e40000, 0x80000001,
+    0x0400005a, 0x80020000, 0x80e40003, 0xa0e40001, 0x80000001, 0x0400005a, 0x80040000, 0x80e40003,
+    0xa0e40002, 0x80000001, 0x03000002, 0x80070000, 0x80e40000, 0x80e40003, 0x03000005, 0x80070001,
+    0x80550000, 0xa0e4000b, 0x04000004, 0x80070001, 0x80000000, 0xa0e4000a, 0x80e40001, 0x03000002,
+    0x80070003, 0x80e40000, 0x80e40001, 0x03000008, 0x80010000, 0x80e40003, 0xa0e4000c, 0x03000008,
+    0x80020000, 0x80e40003, 0xa0e4000d, 0x03000002, 0x80030000, 0x80e40000, 0x80e40003, 0x03000005,
+    0x800c0000, 0x80550000, 0xa0440004, 0x04000004, 0x800c0000, 0x80000000, 0xa0440003, 0x80e40000,
+    0x04000004, 0x800c0000, 0x80aa0003, 0xa0440005, 0x80e40000, 0x03000002, 0x80030003, 0x80ee0000,
+    0x80e40000, 0x0000002b, 0x03000042, 0x800f0000, 0x90e40000, 0xa0e40800, 0x03000002, 0x800f0000,
+    0x80e40000, 0x80e40003, 0x03000042, 0x800f0001, 0x90e40000, 0xa0e40801, 0x03000002, 0x800f0800,
+    0x80e40000, 0x80e40001, 0x0000ffff, 0x00000007, 0x00000b6c, 0xfffe0300, 0x013cfffe, 0x42415443,
+    0x0000001c, 0x000004bb, 0xfffe0300, 0x0000000c, 0x0000001c, 0x00000000, 0x000004b4, 0x0000010c,
+    0x00200002, 0x00000001, 0x00000114, 0x00000124, 0x00000134, 0x001d0002, 0x00000002, 0x0000013c,
+    0x0000014c, 0x0000016c, 0x001f0002, 0x00000001, 0x00000174, 0x00000184, 0x00000194, 0x00100002,
+    0x00000004, 0x000001a0, 0x000001b0, 0x000001f0, 0x00140002, 0x00000003, 0x000001f8, 0x00000208,
+    0x00000238, 0x00170002, 0x00000003, 0x00000244, 0x00000254, 0x00000284, 0x000c0002, 0x00000004,
+    0x0000028c, 0x0000029c, 0x000002dc, 0x00020003, 0x00000001, 0x000002e8, 0x00000000, 0x000002f8,
+    0x00000003, 0x00000002, 0x00000308, 0x00000000, 0x00000318, 0x001a0002, 0x00000003, 0x00000370,
+    0x00000380, 0x000003b0, 0x00000002, 0x00000006, 0x000003b4, 0x000003c4, 0x00000424, 0x00060002,
+    0x00000006, 0x00000444, 0x00000454, 0x31727261, 0xababab00, 0x00030000, 0x00010001, 0x00000001,
+    0x00000000, 0x42b60000, 0x00000000, 0x00000000, 0x00000000, 0x32727261, 0xababab00, 0x00030000,
+    0x00010001, 0x00000002, 0x00000000, 0x42b80000, 0x00000000, 0x00000000, 0x00000000, 0x42ba0000,
+    0x00000000, 0x00000000, 0x00000000, 0x6f505f67, 0xab003173, 0x00030001, 0x00040001, 0x00000001,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3478336d, 0x756c6f63, 0xab006e6d,
+    0x00030003, 0x00040003, 0x00000001, 0x00000000, 0x41300000, 0x41a80000, 0x41f80000, 0x00000000,
+    0x41400000, 0x41b00000, 0x42000000, 0x00000000, 0x41500000, 0x41b80000, 0x42040000, 0x00000000,
+    0x41600000, 0x41c00000, 0x42080000, 0x00000000, 0x3478336d, 0x00776f72, 0x00030002, 0x00040003,
+    0x00000001, 0x00000000, 0x41300000, 0x41400000, 0x41500000, 0x41600000, 0x41a80000, 0x41b00000,
+    0x41b80000, 0x41c00000, 0x41f80000, 0x42000000, 0x42040000, 0x42080000, 0x3378346d, 0x756c6f63,
+    0xab006e6d, 0x00030003, 0x00030004, 0x00000001, 0x00000000, 0x41300000, 0x41a80000, 0x41f80000,
+    0x42240000, 0x41400000, 0x41b00000, 0x42000000, 0x42280000, 0x41500000, 0x41b80000, 0x42040000,
+    0x422c0000, 0x3378346d, 0x00776f72, 0x00030002, 0x00030004, 0x00000001, 0x00000000, 0x41300000,
+    0x41400000, 0x41500000, 0x00000000, 0x41a80000, 0x41b00000, 0x41b80000, 0x00000000, 0x41f80000,
+    0x42000000, 0x42040000, 0x00000000, 0x42240000, 0x42280000, 0x422c0000, 0x00000000, 0x706d6173,
+    0x3172656c, 0xababab00, 0x000c0004, 0x00010001, 0x00000001, 0x00000000, 0x706d6173, 0x7372656c,
+    0x7272615f, 0xab007961, 0x000c0004, 0x00010001, 0x00000002, 0x00000000, 0x00317374, 0xab003176,
+    0x00030001, 0x00030001, 0x00000001, 0x00000000, 0xab007666, 0x00030000, 0x00010001, 0x00000001,
+    0x00000000, 0xab003276, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x0000031c, 0x00000320,
+    0x00000330, 0x00000334, 0x00000344, 0x00000348, 0x00000005, 0x00080001, 0x00030001, 0x00000358,
+    0x41100000, 0x41200000, 0x41300000, 0x00000000, 0x41400000, 0x00000000, 0x00000000, 0x00000000,
+    0x41500000, 0x41600000, 0x41700000, 0x41800000, 0x00327374, 0x00000005, 0x00080001, 0x00030002,
+    0x00000358, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x40000000, 0x40400000,
+    0x00000000, 0x40800000, 0x00000000, 0x00000000, 0x00000000, 0x40a00000, 0x40c00000, 0x40e00000,
+    0x41000000, 0x00337374, 0xab007374, 0x00000005, 0x00080001, 0x00030002, 0x00000358, 0x00000428,
+    0x0000042c, 0x00000005, 0x00100001, 0x00010001, 0x0000043c, 0x3f800000, 0x40000000, 0x40400000,
+    0x00000000, 0x40800000, 0x00000000, 0x00000000, 0x00000000, 0x40a00000, 0x40c00000, 0x40e00000,
+    0x41000000, 0x41100000, 0x41200000, 0x41300000, 0x00000000, 0x41400000, 0x00000000, 0x00000000,
+    0x00000000, 0x41500000, 0x41600000, 0x41700000, 0x41800000, 0x335f7376, 0x4d00305f, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x00f0fffe, 0x53455250, 0x46580201, 0x0047fffe, 0x42415443,
+    0x0000001c, 0x000000e7, 0x46580201, 0x00000003, 0x0000001c, 0x00000100, 0x000000e4, 0x00000058,
+    0x00020002, 0x00000001, 0x00000060, 0x00000070, 0x00000080, 0x00030002, 0x00000001, 0x00000088,
+    0x00000070, 0x00000098, 0x00000002, 0x00000002, 0x000000a4, 0x000000b4, 0x6f505f67, 0xab003173,
+    0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x6f505f67, 0xab003273, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x65535f67, 0x7463656c,
+    0xab00726f, 0x00030001, 0x00040001, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x41200000, 0x41200000, 0x41200000, 0x41200000, 0x459c4800, 0x459c5000, 0x459c5800,
+    0x459c6000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461,
+    0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x000cfffe, 0x49535250,
+    0x00000021, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000021,
+    0x00000001, 0x00000000, 0x00000000, 0x0032fffe, 0x54494c43, 0x00000018, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3fe00000,
+    0x00000000, 0xc0000000, 0x00000000, 0xc0080000, 0x00000000, 0x00000000, 0x00000000, 0x40100000,
+    0x00000000, 0x40140000, 0x00000000, 0x40180000, 0x00000000, 0x401c0000, 0x0064fffe, 0x434c5846,
+    0x00000009, 0xa0500004, 0x00000002, 0x00000000, 0x00000001, 0x00000011, 0x00000000, 0x00000002,
+    0x00000008, 0x00000000, 0x00000007, 0x00000000, 0x20400004, 0x00000002, 0x00000000, 0x00000007,
+    0x00000000, 0x00000000, 0x00000001, 0x00000014, 0x00000000, 0x00000007, 0x00000004, 0xa0500004,
+    0x00000002, 0x00000000, 0x00000001, 0x00000012, 0x00000000, 0x00000002, 0x0000000c, 0x00000000,
+    0x00000007, 0x00000000, 0x20400004, 0x00000002, 0x00000000, 0x00000007, 0x00000000, 0x00000000,
+    0x00000001, 0x00000014, 0x00000000, 0x00000007, 0x00000008, 0x10100004, 0x00000001, 0x00000000,
+    0x00000007, 0x00000008, 0x00000000, 0x00000007, 0x00000000, 0x20400004, 0x00000002, 0x00000000,
+    0x00000007, 0x00000000, 0x00000000, 0x00000007, 0x00000004, 0x00000000, 0x00000007, 0x0000000c,
+    0xa0200001, 0x00000002, 0x00000000, 0x00000001, 0x00000010, 0x00000000, 0x00000002, 0x00000005,
+    0x00000000, 0x00000007, 0x00000000, 0xa0500004, 0x00000002, 0x00000000, 0x00000007, 0x00000000,
+    0x00000000, 0x00000007, 0x0000000c, 0x00000000, 0x00000007, 0x00000004, 0x20400004, 0x00000002,
+    0x00000000, 0x00000007, 0x00000004, 0x00000000, 0x00000007, 0x00000008, 0x00000000, 0x00000004,
+    0x00000084, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x05000051, 0xa00f0022, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x0200001f, 0x80000000, 0x900f0000, 0x0200001f, 0x90000000, 0xa00f0801,
+    0x0200001f, 0x90000000, 0xa00f0802, 0x0200001f, 0x80000000, 0xe00f0000, 0x0200001f, 0x80000005,
+    0xe0030001, 0x0200001f, 0x8000000a, 0xe00f0002, 0x03000009, 0x80010000, 0x90e40000, 0xa0e40017,
+    0x03000009, 0x80020000, 0x90e40000, 0xa0e40018, 0x03000009, 0x80040000, 0x90e40000, 0xa0e40019,
+    0x03000008, 0x80010001, 0x90e40000, 0xa0e40010, 0x03000008, 0x80020001, 0x90e40000, 0xa0e40011,
+    0x03000008, 0x80040001, 0x90e40000, 0xa0e40012, 0x03000008, 0x80080001, 0x90e40000, 0xa0e40013,
+    0x02000001, 0x80080000, 0xa0000022, 0x03000002, 0x800f0000, 0x80e40000, 0x80e40001, 0x03000005,
+    0x800f0001, 0xa0e40015, 0x90550000, 0x04000004, 0x800f0001, 0x90000000, 0xa0e40014, 0x80e40001,
+    0x04000004, 0x800f0001, 0x90aa0000, 0xa0e40016, 0x80e40001, 0x03000002, 0x800f0000, 0x80e40000,
+    0x80e40001, 0x03000005, 0x80070001, 0xa0e4000d, 0x90550000, 0x04000004, 0x80070001, 0x90000000,
+    0xa0e4000c, 0x80e40001, 0x04000004, 0x80070001, 0x90aa0000, 0xa0e4000e, 0x80e40001, 0x04000004,
+    0x80070001, 0x90ff0000, 0xa0e4000f, 0x80e40001, 0x03000002, 0x80070000, 0x80e40000, 0x80e40001,
+    0x04000004, 0x800f0000, 0x90e40000, 0xa000001b, 0x80e40000, 0x03000009, 0x80010001, 0x90e40000,
+    0xa0e4001c, 0x03000002, 0x800f0000, 0x80e40000, 0x80000001, 0x04000004, 0x800f0000, 0x90e40000,
+    0xa0000004, 0x80e40000, 0x03000009, 0x80010001, 0x90e40000, 0xa0e40005, 0x03000002, 0x800f0000,
+    0x80e40000, 0x80000001, 0x04000004, 0x800f0000, 0x90e40000, 0xa0000020, 0x80e40000, 0x04000004,
+    0x800f0000, 0x90e40000, 0xa000001e, 0x80e40000, 0x04000004, 0x800f0000, 0x90e40000, 0xa000000a,
+    0x80e40000, 0x03000009, 0x80010001, 0x90e40000, 0xa0e4000b, 0x03000002, 0x800f0000, 0x80e40000,
+    0x80000001, 0x0300005f, 0x800f0001, 0xa0e4001f, 0xa0e40802, 0x03000002, 0x800f0000, 0x80e40000,
+    0x80e40001, 0x0300005f, 0x800f0001, 0xa0e4001f, 0xa0e40801, 0x03000002, 0xe00f0002, 0x80e40000,
+    0x80e40001, 0x02000001, 0xe00f0000, 0xa0e40021, 0x02000001, 0xe0030001, 0xa0000022, 0x0000ffff,
+    0x00000008, 0x000001dc, 0xfffe0300, 0x0016fffe, 0x42415443, 0x0000001c, 0x00000023, 0xfffe0300,
+    0x00000000, 0x00000000, 0x00000000, 0x0000001c, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73,
+    0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932,
+    0x332e3235, 0x00313131, 0x0045fffe, 0x53455250, 0x46580201, 0x0024fffe, 0x42415443, 0x0000001c,
+    0x0000005b, 0x46580201, 0x00000001, 0x0000001c, 0x00000100, 0x00000058, 0x00000030, 0x00000002,
+    0x00000001, 0x00000038, 0x00000048, 0x6f505f67, 0xab003173, 0x00030001, 0x00040001, 0x00000001,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4d007874, 0x6f726369, 0x74666f73,
+    0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932,
+    0x332e3235, 0x00313131, 0x000cfffe, 0x49535250, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
+    0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x0002fffe,
+    0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846, 0x00000001, 0x10000004, 0x00000001, 0x00000000,
+    0x00000002, 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+    0x05000051, 0xa00f0001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0200001f, 0x80000000,
+    0xe00f0000, 0x0200001f, 0x80000005, 0xe0030001, 0x0200001f, 0x8000000a, 0xe00f0002, 0x02000001,
+    0xe00f0000, 0xa0e40000, 0x02000001, 0xe0030001, 0xa0000001, 0x02000001, 0xe00f0002, 0xa0000001,
+    0x0000ffff, 0x00000005, 0x00000000, 0x00000004, 0x00000000, 0x00000001, 0x0000002c, 0xfffe0101,
+    0x00000051, 0xa00f0000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000001, 0xc00f0000,
+    0xa0e40000, 0x0000ffff, 0x00000002, 0x0000002c, 0xfffe0101, 0x00000051, 0xa00f0000, 0x40000000,
+    0x40000000, 0x40000000, 0x40000000, 0x00000001, 0xc00f0000, 0xa0e40000, 0x0000ffff, 0x00000003,
+    0x0000002c, 0xfffe0200, 0x05000051, 0xa00f0000, 0x40400000, 0x40400000, 0x40400000, 0x40400000,
+    0x02000001, 0xc00f0000, 0xa0e40000, 0x0000ffff, 0x00000000, 0x00000001, 0xffffffff, 0x00000000,
+    0x00000002, 0x000000e8, 0x00000008, 0x615f7376, 0x00007272, 0x46580200, 0x0024fffe, 0x42415443,
+    0x0000001c, 0x0000005b, 0x46580200, 0x00000001, 0x0000001c, 0x00000100, 0x00000058, 0x00000030,
+    0x00000002, 0x00000001, 0x00000038, 0x00000048, 0x56695f67, 0x00746365, 0x00020001, 0x00040001,
+    0x00000001, 0x00000000, 0x40800000, 0x40400000, 0x40000000, 0x3f800000, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846,
+    0x00000001, 0x10000001, 0x00000001, 0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000004,
+    0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000029,
+    0x00000000, 0x00000198, 0x46580200, 0x0053fffe, 0x42415443, 0x0000001c, 0x00000117, 0x46580200,
+    0x00000001, 0x0000001c, 0x20000100, 0x00000114, 0x00000030, 0x00000002, 0x00000005, 0x000000a4,
+    0x000000b4, 0x00337374, 0x76007374, 0xabab0031, 0x00030001, 0x00030001, 0x00000001, 0x00000000,
+    0xab007666, 0x00030000, 0x00010001, 0x00000001, 0x00000000, 0xab003276, 0x00030001, 0x00040001,
+    0x00000001, 0x00000000, 0x00000037, 0x0000003c, 0x0000004c, 0x00000050, 0x00000060, 0x00000064,
+    0x00000005, 0x00080001, 0x00030002, 0x00000074, 0x00000034, 0x0000008c, 0x00000005, 0x00100001,
+    0x00010001, 0x0000009c, 0x3f800000, 0x40000000, 0x40400000, 0x00000000, 0x40800000, 0x00000000,
+    0x00000000, 0x00000000, 0x40a00000, 0x40c00000, 0x40e00000, 0x41000000, 0x41100000, 0x41200000,
+    0x41300000, 0x00000000, 0x41400000, 0x00000000, 0x00000000, 0x00000000, 0x41500000, 0x41600000,
+    0x41700000, 0x41800000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c,
+    0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe,
+    0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846, 0x00000001, 0x10000001, 0x00000001, 0x00000000,
+    0x00000002, 0x00000010, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+    0x00000000, 0x00000000, 0xffffffff, 0x00000028, 0x00000000, 0x00000198, 0x46580200, 0x0053fffe,
+    0x42415443, 0x0000001c, 0x00000117, 0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000114,
+    0x00000030, 0x00000002, 0x00000002, 0x000000a4, 0x000000b4, 0x00337374, 0x76007374, 0xabab0031,
+    0x00030001, 0x00030001, 0x00000001, 0x00000000, 0xab007666, 0x00030000, 0x00010001, 0x00000001,
+    0x00000000, 0xab003276, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000037, 0x0000003c,
+    0x0000004c, 0x00000050, 0x00000060, 0x00000064, 0x00000005, 0x00080001, 0x00030002, 0x00000074,
+    0x00000034, 0x0000008c, 0x00000005, 0x00100001, 0x00010001, 0x0000009c, 0x3f800000, 0x40000000,
+    0x40400000, 0x00000000, 0x40800000, 0x00000000, 0x00000000, 0x00000000, 0x40a00000, 0x40c00000,
+    0x40e00000, 0x41000000, 0x41100000, 0x41200000, 0x41300000, 0x00000000, 0x41400000, 0x00000000,
+    0x00000000, 0x00000000, 0x41500000, 0x41600000, 0x41700000, 0x41800000, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846,
+    0x00000001, 0x10000001, 0x00000001, 0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000004,
+    0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000027,
+    0x00000000, 0x0000017c, 0x46580200, 0x004cfffe, 0x42415443, 0x0000001c, 0x000000fb, 0x46580200,
+    0x00000001, 0x0000001c, 0x20000100, 0x000000f8, 0x00000030, 0x00000002, 0x00000005, 0x00000088,
+    0x00000098, 0x00327374, 0xab003176, 0x00030001, 0x00030001, 0x00000001, 0x00000000, 0xab007666,
+    0x00030000, 0x00010001, 0x00000001, 0x00000000, 0xab003276, 0x00030001, 0x00040001, 0x00000001,
+    0x00000000, 0x00000034, 0x00000038, 0x00000048, 0x0000004c, 0x0000005c, 0x00000060, 0x00000005,
+    0x00080001, 0x00030002, 0x00000070, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000,
+    0x40000000, 0x40400000, 0x00000000, 0x40800000, 0x00000000, 0x00000000, 0x00000000, 0x40a00000,
+    0x40c00000, 0x40e00000, 0x41000000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+    0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+    0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846, 0x00000001, 0x10000001, 0x00000001,
+    0x00000000, 0x00000002, 0x00000010, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f,
+    0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000026, 0x00000000, 0x0000017c, 0x46580200,
+    0x004cfffe, 0x42415443, 0x0000001c, 0x000000fb, 0x46580200, 0x00000001, 0x0000001c, 0x20000100,
+    0x000000f8, 0x00000030, 0x00000002, 0x00000002, 0x00000088, 0x00000098, 0x00327374, 0xab003176,
+    0x00030001, 0x00030001, 0x00000001, 0x00000000, 0xab007666, 0x00030000, 0x00010001, 0x00000001,
+    0x00000000, 0xab003276, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000034, 0x00000038,
+    0x00000048, 0x0000004c, 0x0000005c, 0x00000060, 0x00000005, 0x00080001, 0x00030002, 0x00000070,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x40000000, 0x40400000, 0x00000000,
+    0x40800000, 0x00000000, 0x00000000, 0x00000000, 0x40a00000, 0x40c00000, 0x40e00000, 0x41000000,
+    0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320,
+    0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000,
+    0x000cfffe, 0x434c5846, 0x00000001, 0x10000001, 0x00000001, 0x00000000, 0x00000002, 0x00000004,
+    0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000,
+    0xffffffff, 0x00000024, 0x00000000, 0x00000770, 0x46580200, 0x008cfffe, 0x42415443, 0x0000001c,
+    0x000001fb, 0x46580200, 0x00000004, 0x0000001c, 0x20000100, 0x000001f8, 0x0000006c, 0x000b0002,
+    0x00000001, 0x00000074, 0x00000084, 0x00000094, 0x00060002, 0x00000004, 0x0000009c, 0x000000ac,
+    0x000000ec, 0x00000002, 0x00000006, 0x00000160, 0x00000170, 0x000001d0, 0x000a0002, 0x00000001,
+    0x000001d8, 0x000001e8, 0x56695f67, 0x00746365, 0x00020001, 0x00040001, 0x00000001, 0x00000000,
+    0x40800000, 0x40400000, 0x40000000, 0x3f800000, 0x3478346d, 0xababab00, 0x00030003, 0x00040004,
+    0x00000001, 0x00000000, 0x41300000, 0x41a80000, 0x41f80000, 0x42240000, 0x41400000, 0x41b00000,
+    0x42000000, 0x42280000, 0x41500000, 0x41b80000, 0x42040000, 0x422c0000, 0x41600000, 0x41c00000,
+    0x42080000, 0x42300000, 0x00337374, 0x76007374, 0xabab0031, 0x00030001, 0x00030001, 0x00000001,
+    0x00000000, 0xab007666, 0x00030000, 0x00010001, 0x00000001, 0x00000000, 0xab003276, 0x00030001,
+    0x00040001, 0x00000001, 0x00000000, 0x000000f3, 0x000000f8, 0x00000108, 0x0000010c, 0x0000011c,
+    0x00000120, 0x00000005, 0x00080001, 0x00030002, 0x00000130, 0x000000f0, 0x00000148, 0x00000005,
+    0x00100001, 0x00010001, 0x00000158, 0x3f800000, 0x40000000, 0x40400000, 0x00000000, 0x40800000,
+    0x00000000, 0x00000000, 0x00000000, 0x40a00000, 0x40c00000, 0x40e00000, 0x41000000, 0x41100000,
+    0x41200000, 0x41300000, 0x00000000, 0x41400000, 0x00000000, 0x00000000, 0x00000000, 0x41500000,
+    0x41600000, 0x41700000, 0x41800000, 0x33636576, 0xababab00, 0x00030001, 0x00030001, 0x00000001,
+    0x00000000, 0x447a4000, 0x447a8000, 0x447ac000, 0x00000000, 0x4d007874, 0x6f726369, 0x74666f73,
+    0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932,
+    0x332e3235, 0x00313131, 0x008afffe, 0x54494c43, 0x00000044, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3ff00000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x3ff00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x3ff00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3ff00000, 0x00000000, 0x40080000, 0x00000000,
+    0x3ff00000, 0x00000000, 0x40000000, 0x00000000, 0x00000000, 0x00c1fffe, 0x434c5846, 0x0000000e,
+    0x50000004, 0x00000002, 0x00000000, 0x00000002, 0x00000018, 0x00000001, 0x00000002, 0x0000002e,
+    0x00000001, 0x0000003c, 0x00000000, 0x00000007, 0x00000000, 0x50000004, 0x00000002, 0x00000000,
+    0x00000002, 0x0000001c, 0x00000001, 0x00000002, 0x0000002e, 0x00000001, 0x0000003c, 0x00000000,
+    0x00000007, 0x00000001, 0x50000004, 0x00000002, 0x00000000, 0x00000002, 0x00000020, 0x00000001,
+    0x00000002, 0x0000002e, 0x00000001, 0x0000003c, 0x00000000, 0x00000007, 0x00000002, 0x50000004,
+    0x00000002, 0x00000000, 0x00000002, 0x00000024, 0x00000001, 0x00000002, 0x0000002e, 0x00000001,
+    0x0000003c, 0x00000000, 0x00000007, 0x00000003, 0xa0400001, 0x00000002, 0x00000000, 0x00000002,
+    0x0000002f, 0x00000000, 0x00000002, 0x0000002f, 0x00000000, 0x00000007, 0x00000004, 0x50000004,
+    0x00000002, 0x00000000, 0x00000002, 0x00000018, 0x00000001, 0x00000007, 0x00000004, 0x00000001,
+    0x00000030, 0x00000000, 0x00000007, 0x00000008, 0x50000004, 0x00000002, 0x00000000, 0x00000002,
+    0x0000001c, 0x00000001, 0x00000007, 0x00000004, 0x00000001, 0x00000030, 0x00000000, 0x00000007,
+    0x00000009, 0x50000004, 0x00000002, 0x00000000, 0x00000002, 0x00000020, 0x00000001, 0x00000007,
+    0x00000004, 0x00000001, 0x00000030, 0x00000000, 0x00000007, 0x0000000a, 0x50000004, 0x00000002,
+    0x00000000, 0x00000002, 0x00000024, 0x00000001, 0x00000007, 0x00000004, 0x00000001, 0x00000030,
+    0x00000000, 0x00000007, 0x0000000b, 0x50000004, 0x00000002, 0x00000000, 0x00000007, 0x00000000,
+    0x00000000, 0x00000007, 0x00000008, 0x00000000, 0x00000004, 0x00000000, 0x50000003, 0x00000002,
+    0x00000000, 0x00000002, 0x00000028, 0x00000001, 0x00000002, 0x0000002e, 0x00000001, 0x00000030,
+    0x00000000, 0x00000004, 0x00000002, 0x70e00001, 0x00000006, 0x00000000, 0x00000001, 0x00000041,
+    0x00000000, 0x00000001, 0x00000042, 0x00000000, 0x00000001, 0x00000040, 0x00000001, 0x00000002,
+    0x0000002f, 0x00000001, 0x00000030, 0x00000001, 0x00000002, 0x0000002f, 0x00000001, 0x00000031,
+    0x00000001, 0x00000002, 0x0000002f, 0x00000001, 0x00000032, 0x00000000, 0x00000004, 0x00000003,
+    0xa0500001, 0x00000002, 0x00000000, 0x00000002, 0x0000002c, 0x00000000, 0x00000001, 0x00000040,
+    0x00000000, 0x00000007, 0x00000000, 0x10000001, 0x00000001, 0x00000001, 0x00000007, 0x00000000,
+    0x00000002, 0x00000004, 0x00000000, 0x00000004, 0x00000001, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+    0x00000000, 0x00000000, 0xffffffff, 0x00000023, 0x00000000, 0x000004ec, 0x46580200, 0x005afffe,
+    0x42415443, 0x0000001c, 0x00000133, 0x46580200, 0x00000004, 0x0000001c, 0x20000100, 0x00000130,
+    0x0000006c, 0x00000002, 0x00000003, 0x00000078, 0x00000088, 0x000000b8, 0x000a0002, 0x00000001,
+    0x000000c0, 0x000000d0, 0x000000e0, 0x00080002, 0x00000001, 0x000000e8, 0x000000f8, 0x00000108,
+    0x00090002, 0x00000001, 0x00000110, 0x00000120, 0x65535f67, 0x7463656c, 0xab00726f, 0x00030001,
+    0x00040001, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x41200000,
+    0x41200000, 0x41200000, 0x41200000, 0x459c4800, 0x459c5000, 0x459c5800, 0x459c6000, 0x56695f67,
+    0x00746365, 0x00020001, 0x00040001, 0x00000001, 0x00000000, 0x40800000, 0x40400000, 0x40000000,
+    0x3f800000, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000,
+    0x80000000, 0xc00ccccd, 0x7f7fffff, 0x6576706f, 0x00327463, 0x00030001, 0x00040001, 0x00000001,
+    0x00000000, 0x3f800000, 0x40000000, 0xc0400000, 0x40800000, 0x4d007874, 0x6f726369, 0x74666f73,
+    0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932,
+    0x332e3235, 0x00313131, 0x007afffe, 0x54494c43, 0x0000003c, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3ff00000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x3ff00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x3ff00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3ff00000, 0x0062fffe, 0x434c5846, 0x00000008,
+    0x50000004, 0x00000002, 0x00000000, 0x00000002, 0x00000020, 0x00000001, 0x00000002, 0x0000002a,
+    0x00000001, 0x0000002c, 0x00000000, 0x00000004, 0x00000000, 0x10400001, 0x00000001, 0x00000000,
+    0x00000002, 0x00000025, 0x00000000, 0x00000007, 0x00000000, 0x10100001, 0x00000001, 0x00000000,
+    0x00000007, 0x00000000, 0x00000000, 0x00000007, 0x00000004, 0xa0400001, 0x00000002, 0x00000000,
+    0x00000002, 0x00000025, 0x00000000, 0x00000001, 0x0000002c, 0x00000000, 0x00000007, 0x00000000,
+    0xa0400001, 0x00000002, 0x00000000, 0x00000007, 0x00000000, 0x00000000, 0x00000007, 0x00000004,
+    0x00000000, 0x00000007, 0x00000008, 0x50000004, 0x00000002, 0x00000000, 0x00000002, 0x00000028,
+    0x00000001, 0x00000007, 0x00000008, 0x00000001, 0x0000002c, 0x00000000, 0x00000004, 0x00000001,
+    0xa0400001, 0x00000002, 0x00000001, 0x00000002, 0x0000002b, 0x00000002, 0x00000010, 0x00000001,
+    0x00000002, 0x0000002b, 0x00000002, 0x0000001d, 0x00000000, 0x00000004, 0x00000002, 0xa0400001,
+    0x00000002, 0x00000001, 0x00000002, 0x00000028, 0x00000002, 0x00000001, 0x00000001, 0x00000002,
+    0x0000002b, 0x00000002, 0x00000000, 0x00000000, 0x00000004, 0x00000003, 0xf0f0f0f0, 0x0f0f0f0f,
+    0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000022, 0x00000000, 0x000002cc, 0x46580200,
+    0x0033fffe, 0x42415443, 0x0000001c, 0x00000097, 0x46580200, 0x00000002, 0x0000001c, 0x20000100,
+    0x00000094, 0x00000044, 0x00000002, 0x00000001, 0x0000004c, 0x0000005c, 0x0000006c, 0x00010002,
+    0x00000001, 0x00000074, 0x00000084, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001,
+    0x00000000, 0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff, 0x6576706f, 0x00327463, 0x00030001,
+    0x00040001, 0x00000001, 0x00000000, 0x3f800000, 0x40000000, 0xc0400000, 0x40800000, 0x4d007874,
+    0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970,
+    0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x001afffe, 0x54494c43, 0x0000000c, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0061fffe,
+    0x434c5846, 0x00000006, 0xa0500001, 0x00000002, 0x00000000, 0x00000002, 0x00000002, 0x00000000,
+    0x00000002, 0x00000004, 0x00000000, 0x00000007, 0x00000000, 0xa0500001, 0x00000002, 0x00000000,
+    0x00000002, 0x00000000, 0x00000000, 0x00000002, 0x00000005, 0x00000000, 0x00000007, 0x00000001,
+    0xa0400001, 0x00000002, 0x00000000, 0x00000007, 0x00000001, 0x00000000, 0x00000007, 0x00000000,
+    0x00000000, 0x00000004, 0x00000000, 0x70e00001, 0x00000006, 0x00000000, 0x00000002, 0x00000002,
+    0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000002,
+    0x00000004, 0x00000000, 0x00000002, 0x00000005, 0x00000000, 0x00000002, 0x00000006, 0x00000000,
+    0x00000004, 0x00000001, 0x70e00001, 0x00000008, 0x00000000, 0x00000002, 0x00000002, 0x00000000,
+    0x00000002, 0x00000002, 0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000002, 0x00000000,
+    0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000002,
+    0x00000005, 0x00000000, 0x00000002, 0x00000005, 0x00000000, 0x00000004, 0x00000002, 0x10000001,
+    0x00000001, 0x00000000, 0x00000001, 0x00000008, 0x00000000, 0x00000004, 0x00000003, 0xf0f0f0f0,
+    0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000021, 0x00000000, 0x00000248,
+    0x46580200, 0x003efffe, 0x42415443, 0x0000001c, 0x000000c3, 0x46580200, 0x00000003, 0x0000001c,
+    0x20000100, 0x000000c0, 0x00000058, 0x00000002, 0x00000001, 0x00000060, 0x00000070, 0x00000080,
+    0x00010002, 0x00000001, 0x00000088, 0x00000098, 0x000000a8, 0x00020002, 0x00000001, 0x000000b0,
+    0x00000070, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000,
+    0x80000000, 0xc00ccccd, 0x7f7fffff, 0x6576706f, 0x00327463, 0x00030001, 0x00040001, 0x00000001,
+    0x00000000, 0x3f800000, 0x40000000, 0xc0400000, 0x40800000, 0x6576706f, 0x00337463, 0x00030001,
+    0x00040001, 0x00000001, 0x00000000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+    0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+    0x0022fffe, 0x54494c43, 0x00000010, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x812dea11, 0x3d719799, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x002dfffe, 0x434c5846, 0x00000004, 0xa0500004, 0x00000002,
+    0x00000000, 0x00000001, 0x0000000c, 0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000007,
+    0x00000000, 0x20400004, 0x00000002, 0x00000000, 0x00000007, 0x00000000, 0x00000000, 0x00000002,
+    0x00000000, 0x00000000, 0x00000007, 0x00000004, 0x10100004, 0x00000001, 0x00000000, 0x00000002,
+    0x00000008, 0x00000000, 0x00000007, 0x00000000, 0x20400004, 0x00000002, 0x00000000, 0x00000007,
+    0x00000000, 0x00000000, 0x00000007, 0x00000004, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0,
+    0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000020, 0x00000000, 0x000001f0,
+    0x46580200, 0x0033fffe, 0x42415443, 0x0000001c, 0x00000097, 0x46580200, 0x00000002, 0x0000001c,
+    0x20000100, 0x00000094, 0x00000044, 0x00000002, 0x00000001, 0x0000004c, 0x0000005c, 0x0000006c,
+    0x00010002, 0x00000001, 0x00000074, 0x00000084, 0x6576706f, 0x00317463, 0x00030001, 0x00040001,
+    0x00000001, 0x00000000, 0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff, 0x6576706f, 0x00327463,
+    0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x3f800000, 0x40000000, 0xc0400000, 0x40800000,
+    0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320,
+    0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x001afffe, 0x54494c43, 0x0000000c,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x002afffe, 0x434c5846, 0x00000004, 0x50000004, 0x00000002, 0x00000000, 0x00000002, 0x00000000,
+    0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000004, 0x00000001, 0x50000004, 0x00000002,
+    0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000004,
+    0x00000002, 0x10000001, 0x00000001, 0x00000000, 0x00000001, 0x00000008, 0x00000000, 0x00000004,
+    0x00000000, 0x10000001, 0x00000001, 0x00000000, 0x00000001, 0x00000008, 0x00000000, 0x00000004,
+    0x00000003, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x0000001f,
+    0x00000000, 0x000001a8, 0x46580200, 0x0024fffe, 0x42415443, 0x0000001c, 0x0000005b, 0x46580200,
+    0x00000001, 0x0000001c, 0x20000100, 0x00000058, 0x00000030, 0x00000002, 0x00000001, 0x00000038,
+    0x00000048, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000,
+    0x80000000, 0xc00ccccd, 0x7f7fffff, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+    0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+    0x0012fffe, 0x54494c43, 0x00000008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x47ae147b, 0x3f847ae1, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x002ffffe, 0x434c5846, 0x00000005, 0x10300001, 0x00000001,
+    0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000007, 0x00000000, 0x10300001, 0x00000001,
+    0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000007, 0x00000001, 0x10300001, 0x00000001,
+    0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000007, 0x00000002, 0x10300001, 0x00000001,
+    0x00000000, 0x00000002, 0x00000003, 0x00000000, 0x00000007, 0x00000003, 0xa0500004, 0x00000002,
+    0x00000000, 0x00000001, 0x00000004, 0x00000000, 0x00000007, 0x00000000, 0x00000000, 0x00000004,
+    0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x0000001e,
+    0x00000000, 0x000000dc, 0x46580200, 0x0024fffe, 0x42415443, 0x0000001c, 0x0000005b, 0x46580200,
+    0x00000001, 0x0000001c, 0x20000100, 0x00000058, 0x00000030, 0x00000002, 0x00000001, 0x00000038,
+    0x00000048, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000,
+    0x80000000, 0xc00ccccd, 0x7f7fffff, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+    0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+    0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846, 0x00000001, 0x10900004, 0x00000001,
+    0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f,
+    0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x0000001d, 0x00000000, 0x000000dc, 0x46580200,
+    0x0024fffe, 0x42415443, 0x0000001c, 0x0000005b, 0x46580200, 0x00000001, 0x0000001c, 0x20000100,
+    0x00000058, 0x00000030, 0x00000002, 0x00000001, 0x00000038, 0x00000048, 0x6576706f, 0x00317463,
+    0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff,
+    0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320,
+    0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000,
+    0x000cfffe, 0x434c5846, 0x00000001, 0x10800004, 0x00000001, 0x00000000, 0x00000002, 0x00000000,
+    0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000,
+    0xffffffff, 0x0000001c, 0x00000000, 0x00000124, 0x46580200, 0x0033fffe, 0x42415443, 0x0000001c,
+    0x00000097, 0x46580200, 0x00000002, 0x0000001c, 0x20000100, 0x00000094, 0x00000044, 0x00000002,
+    0x00000001, 0x0000004c, 0x0000005c, 0x0000006c, 0x00010002, 0x00000001, 0x00000074, 0x00000084,
+    0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x80000000,
+    0xc00ccccd, 0x7f7fffff, 0x6576706f, 0x00327463, 0x00030001, 0x00040001, 0x00000001, 0x00000000,
+    0x3f800000, 0x40000000, 0xc0400000, 0x40800000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820,
+    0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235,
+    0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000ffffe, 0x434c5846, 0x00000001, 0x20100004,
+    0x00000002, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000002, 0x00000004, 0x00000000,
+    0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff,
+    0x0000001b, 0x00000000, 0x00000124, 0x46580200, 0x0033fffe, 0x42415443, 0x0000001c, 0x00000097,
+    0x46580200, 0x00000002, 0x0000001c, 0x20000100, 0x00000094, 0x00000044, 0x00000002, 0x00000001,
+    0x0000004c, 0x0000005c, 0x0000006c, 0x00010002, 0x00000001, 0x00000074, 0x00000084, 0x6576706f,
+    0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x80000000, 0xc00ccccd,
+    0x7f7fffff, 0x6576706f, 0x00327463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x3f800000,
+    0x40000000, 0xc0400000, 0x40800000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+    0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+    0x0002fffe, 0x54494c43, 0x00000000, 0x000ffffe, 0x434c5846, 0x00000001, 0x20000004, 0x00000002,
+    0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000004,
+    0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x0000001a,
+    0x00000000, 0x000000dc, 0x46580200, 0x0024fffe, 0x42415443, 0x0000001c, 0x0000005b, 0x46580200,
+    0x00000001, 0x0000001c, 0x20000100, 0x00000058, 0x00000030, 0x00000002, 0x00000001, 0x00000038,
+    0x00000048, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000,
+    0x80000000, 0xc00ccccd, 0x7f7fffff, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+    0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+    0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846, 0x00000001, 0x10400004, 0x00000001,
+    0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f,
+    0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000019, 0x00000000, 0x0000013c, 0x46580200,
+    0x0024fffe, 0x42415443, 0x0000001c, 0x0000005b, 0x46580200, 0x00000001, 0x0000001c, 0x20000100,
+    0x00000058, 0x00000030, 0x00000002, 0x00000001, 0x00000038, 0x00000048, 0x6576706f, 0x00317463,
+    0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff,
+    0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320,
+    0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000,
+    0x0024fffe, 0x434c5846, 0x00000004, 0x10300001, 0x00000001, 0x00000000, 0x00000002, 0x00000000,
+    0x00000000, 0x00000004, 0x00000000, 0x10300001, 0x00000001, 0x00000000, 0x00000002, 0x00000001,
+    0x00000000, 0x00000004, 0x00000001, 0x10300001, 0x00000001, 0x00000000, 0x00000002, 0x00000002,
+    0x00000000, 0x00000004, 0x00000002, 0x10300001, 0x00000001, 0x00000000, 0x00000002, 0x00000003,
+    0x00000000, 0x00000004, 0x00000003, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000,
+    0xffffffff, 0x00000018, 0x00000000, 0x000000dc, 0x46580200, 0x0024fffe, 0x42415443, 0x0000001c,
+    0x0000005b, 0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000058, 0x00000030, 0x00000002,
+    0x00000001, 0x00000038, 0x00000048, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001,
+    0x00000000, 0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff, 0x4d007874, 0x6f726369, 0x74666f73,
+    0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932,
+    0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846, 0x00000001,
+    0x10100004, 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000004, 0x00000000,
+    0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000017, 0x00000000,
+    0x00000124, 0x46580200, 0x0033fffe, 0x42415443, 0x0000001c, 0x00000097, 0x46580200, 0x00000002,
+    0x0000001c, 0x20000100, 0x00000094, 0x00000044, 0x00000002, 0x00000001, 0x0000004c, 0x0000005c,
+    0x0000006c, 0x00010002, 0x00000001, 0x00000074, 0x00000084, 0x6576706f, 0x00317463, 0x00030001,
+    0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff, 0x6576706f,
+    0x00327463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x3f800000, 0x40000000, 0xc0400000,
+    0x40800000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461,
+    0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43,
+    0x00000000, 0x000ffffe, 0x434c5846, 0x00000001, 0x20300004, 0x00000002, 0x00000000, 0x00000002,
+    0x00000000, 0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0,
+    0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000016, 0x00000000, 0x00000124,
+    0x46580200, 0x0033fffe, 0x42415443, 0x0000001c, 0x00000097, 0x46580200, 0x00000002, 0x0000001c,
+    0x20000100, 0x00000094, 0x00000044, 0x00000002, 0x00000001, 0x0000004c, 0x0000005c, 0x0000006c,
+    0x00010002, 0x00000001, 0x00000074, 0x00000084, 0x6576706f, 0x00317463, 0x00030001, 0x00040001,
+    0x00000001, 0x00000000, 0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff, 0x6576706f, 0x00327463,
+    0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x3f800000, 0x40000000, 0xc0400000, 0x40800000,
+    0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320,
+    0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000,
+    0x000ffffe, 0x434c5846, 0x00000001, 0x20200004, 0x00000002, 0x00000000, 0x00000002, 0x00000000,
+    0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f,
+    0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000015, 0x00000000, 0x00000124, 0x46580200,
+    0x0033fffe, 0x42415443, 0x0000001c, 0x00000097, 0x46580200, 0x00000002, 0x0000001c, 0x20000100,
+    0x00000094, 0x00000044, 0x00000002, 0x00000001, 0x0000004c, 0x0000005c, 0x0000006c, 0x00010002,
+    0x00000001, 0x00000074, 0x00000084, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001,
+    0x00000000, 0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff, 0x6576706f, 0x00327463, 0x00030001,
+    0x00040001, 0x00000001, 0x00000000, 0x3f800000, 0x40000000, 0xc0400000, 0x40800000, 0x4d007874,
+    0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970,
+    0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000ffffe,
+    0x434c5846, 0x00000001, 0x20400004, 0x00000002, 0x00000000, 0x00000002, 0x00000000, 0x00000000,
+    0x00000002, 0x00000004, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+    0x00000000, 0x00000000, 0xffffffff, 0x00000014, 0x00000000, 0x00000124, 0x46580200, 0x0033fffe,
+    0x42415443, 0x0000001c, 0x00000097, 0x46580200, 0x00000002, 0x0000001c, 0x20000100, 0x00000094,
+    0x00000044, 0x00000002, 0x00000001, 0x0000004c, 0x0000005c, 0x0000006c, 0x00010002, 0x00000001,
+    0x00000074, 0x00000084, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000,
+    0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff, 0x6576706f, 0x00327463, 0x00030001, 0x00040001,
+    0x00000001, 0x00000000, 0x3f800000, 0x40000000, 0xc0400000, 0x40800000, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000ffffe, 0x434c5846,
+    0x00000001, 0x20500004, 0x00000002, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000002,
+    0x00000004, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000,
+    0x00000000, 0xffffffff, 0x00000013, 0x00000000, 0x0000013c, 0x46580200, 0x0024fffe, 0x42415443,
+    0x0000001c, 0x0000005b, 0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000058, 0x00000030,
+    0x00000002, 0x00000001, 0x00000038, 0x00000048, 0x6576706f, 0x00317463, 0x00030001, 0x00040001,
+    0x00000001, 0x00000000, 0x00000000, 0x80000000, 0xc00ccccd, 0x7f7fffff, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x0024fffe, 0x434c5846,
+    0x00000004, 0x10700001, 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000004,
+    0x00000000, 0x10700001, 0x00000001, 0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000004,
+    0x00000001, 0x10700001, 0x00000001, 0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000004,
+    0x00000002, 0x10700001, 0x00000001, 0x00000000, 0x00000002, 0x00000003, 0x00000000, 0x00000004,
+    0x00000003, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000012,
+    0x00000000, 0x0000013c, 0x46580200, 0x0024fffe, 0x42415443, 0x0000001c, 0x0000005b, 0x46580200,
+    0x00000001, 0x0000001c, 0x20000100, 0x00000058, 0x00000030, 0x00000002, 0x00000001, 0x00000038,
+    0x00000048, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000,
+    0x80000000, 0xc00ccccd, 0x7f7fffff, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+    0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+    0x0002fffe, 0x54494c43, 0x00000000, 0x0024fffe, 0x434c5846, 0x00000004, 0x10300001, 0x00000001,
+    0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0x10300001, 0x00000001,
+    0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000004, 0x00000001, 0x10300001, 0x00000001,
+    0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000004, 0x00000002, 0x10300001, 0x00000001,
+    0x00000000, 0x00000002, 0x00000003, 0x00000000, 0x00000004, 0x00000003, 0xf0f0f0f0, 0x0f0f0f0f,
+    0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000001, 0x00000002, 0x00000134, 0x00000008,
+    0x615f7370, 0x00007272, 0x46580200, 0x0024fffe, 0x42415443, 0x0000001c, 0x0000005b, 0x46580200,
+    0x00000001, 0x0000001c, 0x00000100, 0x00000058, 0x00000030, 0x00000002, 0x00000001, 0x00000038,
+    0x00000048, 0x56695f67, 0x00746365, 0x00020001, 0x00040001, 0x00000001, 0x00000000, 0x40800000,
+    0x40400000, 0x40000000, 0x3f800000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+    0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+    0x0012fffe, 0x54494c43, 0x00000008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xbff00000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x000ffffe, 0x434c5846, 0x00000001, 0xa0400001, 0x00000002,
+    0x00000000, 0x00000002, 0x00000003, 0x00000000, 0x00000001, 0x00000004, 0x00000000, 0x00000004,
+    0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000000,
+    0x00000002, 0x00000134, 0x00000008, 0x615f7376, 0x00327272, 0x46580200, 0x0024fffe, 0x42415443,
+    0x0000001c, 0x0000005b, 0x46580200, 0x00000001, 0x0000001c, 0x00000100, 0x00000058, 0x00000030,
+    0x00000002, 0x00000001, 0x00000038, 0x00000048, 0x56695f67, 0x00746365, 0x00020001, 0x00040001,
+    0x00000001, 0x00000000, 0x40800000, 0x40400000, 0x40000000, 0x3f800000, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0012fffe, 0x54494c43, 0x00000008, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xbff00000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000ffffe, 0x434c5846,
+    0x00000001, 0xa0400001, 0x00000002, 0x00000000, 0x00000002, 0x00000003, 0x00000000, 0x00000001,
+    0x00000004, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0xffffffff,
+    0x0000001f, 0x00000001, 0x00000001, 0x00000000, 0x000000e4, 0x46580200, 0x0026fffe, 0x42415443,
+    0x0000001c, 0x00000063, 0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000060, 0x00000030,
+    0x00000002, 0x00000001, 0x00000040, 0x00000050, 0x74636576, 0x6d61735f, 0x72656c70, 0xababab00,
+    0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x3f800000, 0x40000000, 0x40400000, 0x40800000,
+    0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320,
+    0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000,
+    0x000cfffe, 0x434c5846, 0x00000001, 0x10000001, 0x00000001, 0x00000000, 0x00000002, 0x00000001,
+    0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0xffffffff, 0x0000001f,
+    0x00000000, 0x00000001, 0x00000000, 0x000000e4, 0x46580200, 0x0026fffe, 0x42415443, 0x0000001c,
+    0x00000063, 0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000060, 0x00000030, 0x00000002,
+    0x00000001, 0x00000040, 0x00000050, 0x74636576, 0x6d61735f, 0x72656c70, 0xababab00, 0x00030001,
+    0x00040001, 0x00000001, 0x00000000, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x4d007874,
+    0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970,
+    0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe,
+    0x434c5846, 0x00000001, 0x10000001, 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000000,
+    0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0xffffffff, 0x0000001e, 0x00000000,
+    0x00000002, 0x00000000, 0x000000f0, 0x46580200, 0x0026fffe, 0x42415443, 0x0000001c, 0x00000063,
+    0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000060, 0x00000030, 0x00000002, 0x00000001,
+    0x00000040, 0x00000050, 0x74636576, 0x6d61735f, 0x72656c70, 0xababab00, 0x00030001, 0x00040001,
+    0x00000001, 0x00000000, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000ffffe, 0x434c5846,
+    0x00000001, 0xa0400001, 0x00000002, 0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000002,
+    0x00000000, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0xffffffff,
+    0x0000001e, 0x00000000, 0x00000001, 0x00000000, 0x000000dc, 0x46580200, 0x0024fffe, 0x42415443,
+    0x0000001c, 0x0000005b, 0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000058, 0x00000030,
+    0x00000002, 0x00000001, 0x00000038, 0x00000048, 0x56695f67, 0x00746365, 0x00020001, 0x00040001,
+    0x00000001, 0x00000000, 0x40800000, 0x40400000, 0x40000000, 0x3f800000, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846,
+    0x00000001, 0x10000001, 0x00000001, 0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000004,
+    0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0xffffffff, 0x0000001e, 0x00000000, 0x00000000,
+    0x00000001, 0x00000005, 0x31786574, 0x00000000,
+};
+#define TEST_EFFECT_PRESHADER_VSHADER_POS 2991
+#define TEST_EFFECT_PRESHADER_VSHADER_LEN 13
+
+#define test_effect_preshader_compare_shader_bytecode(a, b, c, d) \
+        test_effect_preshader_compare_shader_bytecode_(__LINE__, a, b, c, d)
+static void test_effect_preshader_compare_shader_bytecode_(unsigned int line,
+        const DWORD *bytecode, unsigned int bytecode_size, int expected_shader_index, BOOL todo)
+{
+    unsigned int i = 0;
+
+    todo_wine_if(todo)
+    ok_(__FILE__, line)(!!bytecode, "NULL shader bytecode.\n");
+
+    if (!bytecode)
+        return;
+
+    while (bytecode[i++] != 0x0000ffff)
+        ;
+
+    if (!bytecode_size)
+        bytecode_size = i * sizeof(*bytecode);
+    else
+        ok(i * sizeof(*bytecode) == bytecode_size, "Unexpected byte code size %u.\n", bytecode_size);
+
+    todo_wine_if(todo)
+    ok_(__FILE__, line)(!memcmp(bytecode, &test_effect_preshader_effect_blob[TEST_EFFECT_PRESHADER_VSHADER_POS
+            + expected_shader_index * TEST_EFFECT_PRESHADER_VSHADER_LEN], bytecode_size),
+            "Incorrect shader selected.\n");
+}
+
+#define test_effect_preshader_compare_shader(a, b, c) \
+        test_effect_preshader_compare_shader_(__LINE__, a, b, c)
+static void test_effect_preshader_compare_shader_(unsigned int line, IDirect3DDevice9 *device,
+        int expected_shader_index, BOOL todo)
+{
+    IDirect3DVertexShader9 *vshader;
+    void *byte_code;
+    unsigned int byte_code_size;
+    HRESULT hr;
+
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok_(__FILE__, line)(hr == D3D_OK, "IDirect3DDevice9_GetVertexShader result %#x.\n", hr);
+
+    todo_wine_if(todo)
+    ok_(__FILE__, line)(!!vshader, "Got NULL vshader.\n");
+    if (!vshader)
+        return;
+
+    hr = IDirect3DVertexShader9_GetFunction(vshader, NULL, &byte_code_size);
+    ok_(__FILE__, line)(hr == D3D_OK, "IDirect3DVertexShader9_GetFunction %#x.\n", hr);
+    ok_(__FILE__, line)(byte_code_size > 1, "Got unexpected byte code size %u.\n", byte_code_size);
+
+    byte_code = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, byte_code_size);
+    hr = IDirect3DVertexShader9_GetFunction(vshader, byte_code, &byte_code_size);
+    ok_(__FILE__, line)(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_effect_preshader_compare_shader_bytecode_(line, byte_code,
+            byte_code_size, expected_shader_index, todo);
+
+    HeapFree(GetProcessHeap(), 0, byte_code);
+    IDirect3DVertexShader9_Release(vshader);
+ }
+
+static const struct
+{
+    const char *comment;
+    BOOL todo[4];
+    unsigned int result[4];
+    unsigned int ulps;
+}
+test_effect_preshader_op_expected[] =
+{
+    {"1 / op", {FALSE, FALSE, FALSE, FALSE}, {0x7f800000, 0xff800000, 0xbee8ba2e, 0x00200000}},
+    {"rsq",    {FALSE, FALSE, FALSE, FALSE}, {0x7f800000, 0x7f800000, 0x3f2c985c, 0x1f800001}, 1},
+    {"mul",    {FALSE, FALSE, FALSE, FALSE}, {0x00000000, 0x80000000, 0x40d33334, 0x7f800000}},
+    {"add",    {FALSE, FALSE, FALSE, FALSE}, {0x3f800000, 0x40000000, 0xc0a66666, 0x7f7fffff}},
+    {"lt",     {FALSE, FALSE, FALSE, FALSE}, {0x3f800000, 0x3f800000, 0x00000000, 0x00000000}},
+    {"ge",     {FALSE, FALSE, FALSE, FALSE}, {0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {"neg",    {FALSE, FALSE, FALSE, FALSE}, {0x80000000, 0x00000000, 0x400ccccd, 0xff7fffff}},
+    {"rcp",    {FALSE, FALSE, FALSE, FALSE}, {0x7f800000, 0xff800000, 0xbee8ba2e, 0x00200000}},
+
+    {"frac",   {FALSE, FALSE, FALSE, FALSE}, {0x00000000, 0x00000000, 0x3f4ccccc, 0x00000000}},
+    {"min",    {FALSE, FALSE, FALSE, FALSE}, {0x00000000, 0x80000000, 0xc0400000, 0x40800000}},
+    {"max",    {FALSE, FALSE, FALSE, FALSE}, {0x3f800000, 0x40000000, 0xc00ccccd, 0x7f7fffff}},
+#if __x86_64__
+    {"sin",    {FALSE, FALSE, FALSE, FALSE}, {0x00000000, 0x80000000, 0xbf4ef99e, 0xbf0599b3}},
+    {"cos",    {FALSE, FALSE, FALSE, FALSE}, {0x3f800000, 0x3f800000, 0xbf16a803, 0x3f5a5f96}},
+#else
+    {"sin",    {FALSE, FALSE, FALSE,  TRUE}, {0x00000000, 0x80000000, 0xbf4ef99e, 0x3f792dc4}},
+    {"cos",    {FALSE, FALSE, FALSE,  TRUE}, {0x3f800000, 0x3f800000, 0xbf16a803, 0xbe6acefc}},
+#endif
+    {"den mul",{FALSE, FALSE, FALSE, FALSE}, {0x7f800000, 0xff800000, 0xbb94f209, 0x000051ec}},
+    {"dot",    {FALSE, FALSE, FALSE, FALSE}, {0x00000000, 0x7f800000, 0x41f00000, 0x00000000}},
+    {"prec",   {FALSE, FALSE,  TRUE, FALSE}, {0x2b8cbccc, 0x2c0cbccc, 0xac531800, 0x00000000}},
+
+    {"dotswiz", {FALSE, FALSE, FALSE, FALSE}, {0xc00ccccd, 0xc0d33334, 0xc10ccccd, 0}},
+    {"reladdr", {FALSE, FALSE, FALSE, FALSE}, {0xc00ccccd, 0x3f800000, 0, 0x41200000}},
+    {"reladdr2", {FALSE, FALSE, FALSE, FALSE}, {0, 0, 0x447ac000, 0x40000000}},
+};
+
+enum expected_state_update
+{
+    EXPECTED_STATE_ZERO,
+    EXPECTED_STATE_UPDATED,
+    EXPECTED_STATE_ANYTHING
+};
+
+#define test_effect_preshader_op_results(a, b, c) test_effect_preshader_op_results_(__LINE__, a, b, c)
+static void test_effect_preshader_op_results_(unsigned int line, IDirect3DDevice9 *device,
+        const enum expected_state_update *expected_state, const char *updated_param)
+{
+    static const D3DCOLORVALUE black = {0.0f};
+    unsigned int i, j;
+    D3DLIGHT9 light;
+    const float *v;
+    HRESULT hr;
+
+    for (i = 0; i < ARRAY_SIZE(test_effect_preshader_op_expected); ++i)
+    {
+        hr = IDirect3DDevice9_GetLight(device, i % 8, &light);
+        ok_(__FILE__, line)(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        v = i < 8 ? &light.Diffuse.r : (i < 16 ? &light.Ambient.r : &light.Specular.r);
+        if (!expected_state || expected_state[i] == EXPECTED_STATE_UPDATED)
+        {
+            for (j = 0; j < 4; ++j)
+            {
+                todo_wine_if(test_effect_preshader_op_expected[i].todo[j])
+                ok_(__FILE__, line)(compare_float(v[j],
+                        ((const float *)test_effect_preshader_op_expected[i].result)[j],
+                        test_effect_preshader_op_expected[i].ulps),
+                        "Operation %s, component %u, expected %#x, got %#x (%g).\n",
+                        test_effect_preshader_op_expected[i].comment, j,
+                        test_effect_preshader_op_expected[i].result[j],
+                        ((const unsigned int *)v)[j], v[j]);
+            }
+        }
+        else if (expected_state[i] == EXPECTED_STATE_ZERO)
+        {
+            ok_(__FILE__, line)(!memcmp(v, &black, sizeof(black)),
+                    "Parameter %s, test %d, operation %s, state updated unexpectedly.\n",
+                    updated_param, i, test_effect_preshader_op_expected[i].comment);
+        }
+    }
+}
+
+static const D3DXVECTOR4 fvect_filler = {-9999.0f, -9999.0f, -9999.0f, -9999.0f};
+
+static void test_effect_preshader_clear_vconsts(IDirect3DDevice9 *device)
+{
+    unsigned int i;
+    HRESULT hr;
+
+    for (i = 0; i < 256; ++i)
+    {
+        hr = IDirect3DDevice9_SetVertexShaderConstantF(device, i, &fvect_filler.x, 1);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    }
+}
+
+static const D3DXVECTOR4 test_effect_preshader_fvect_v[] =
+{
+    {0.0f,   0.0f,  0.0f,  0.0f},
+    {0.0f,   0.0f,  0.0f,  0.0f},
+    {0.0f,   0.0f,  0.0f,  0.0f},
+    {1.0f,   2.0f,  3.0f,  0.0f},
+    {4.0f,   0.0f,  0.0f,  0.0f},
+    {5.0f,   6.0f,  7.0f,  8.0f},
+    {1.0f,   2.0f,  3.0f,  0.0f},
+    {4.0f,   0.0f,  0.0f,  0.0f},
+    {5.0f,   6.0f,  7.0f,  8.0f},
+    {9.0f,  10.0f, 11.0f,  0.0f},
+    {12.0f,  0.0f,  0.0f,  0.0f},
+    {13.0f, 14.0f, 15.0f, 16.0f},
+    {11.0f, 12.0f, 13.0f,  0.0f},
+    {21.0f, 22.0f, 23.0f,  0.0f},
+    {31.0f, 32.0f, 33.0f,  0.0f},
+    {41.0f, 42.0f, 43.0f,  0.0f},
+    {11.0f, 21.0f, 31.0f,  0.0f},
+    {12.0f, 22.0f, 32.0f,  0.0f},
+    {13.0f, 23.0f, 33.0f,  0.0f},
+    {14.0f, 24.0f, 34.0f,  0.0f},
+    {11.0f, 12.0f, 13.0f, 14.0f},
+    {21.0f, 22.0f, 23.0f, 24.0f},
+    {31.0f, 32.0f, 33.0f, 34.0f},
+    {11.0f, 21.0f, 31.0f, 41.0f},
+    {12.0f, 22.0f, 32.0f, 42.0f},
+    {13.0f, 23.0f, 33.0f, 43.0f},
+    {9.0f,  10.0f, 11.0f,  0.0f},
+    {12.0f,  0.0f,  0.0f,  0.0f},
+    {13.0f, 14.0f, 15.0f, 16.0f},
+    {92.0f,  0.0f,  0.0f,  0.0f},
+    {93.0f,  0.0f,  0.0f,  0.0f},
+    {0.0f,   0.0f,  0.0f,  0.0f},
+    {91.0f,  0.0f,  0.0f,  0.0f},
+    {4.0f,   5.0f,  6.0f,  7.0f},
+};
+#define TEST_EFFECT_BITMASK_BLOCK_SIZE (sizeof(unsigned int) * 8)
+
+#define test_effect_preshader_compare_vconsts(a, b, c) \
+        test_effect_preshader_compare_vconsts_(__LINE__, a, b, c)
+static void test_effect_preshader_compare_vconsts_(unsigned int line, IDirect3DDevice9 *device,
+        const unsigned int *const_updated_mask, const char *updated_param)
+{
+    HRESULT hr;
+    unsigned int i;
+    D3DXVECTOR4 fdata[ARRAY_SIZE(test_effect_preshader_fvect_v)];
+
+    hr = IDirect3DDevice9_GetVertexShaderConstantF(device, 0, &fdata[0].x,
+            ARRAY_SIZE(test_effect_preshader_fvect_v));
+    ok_(__FILE__, line)(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    if (!const_updated_mask)
+    {
+        ok_(__FILE__, line)(!memcmp(fdata, test_effect_preshader_fvect_v, sizeof(test_effect_preshader_fvect_v)),
+                "Vertex shader float constants do not match.\n");
+    }
+    else
+    {
+        for (i = 0; i < ARRAY_SIZE(test_effect_preshader_fvect_v); ++i)
+        {
+            if (const_updated_mask[i / TEST_EFFECT_BITMASK_BLOCK_SIZE]
+                    & (1u << (i % TEST_EFFECT_BITMASK_BLOCK_SIZE)))
+            {
+                ok_(__FILE__, line)(!memcmp(&fdata[i], &test_effect_preshader_fvect_v[i], sizeof(fdata[i])),
+                        "Vertex shader float constants do not match, expected (%g, %g, %g, %g), "
+                        "got (%g, %g, %g, %g), parameter %s.\n",
+                        test_effect_preshader_fvect_v[i].x, test_effect_preshader_fvect_v[i].y,
+                        test_effect_preshader_fvect_v[i].z, test_effect_preshader_fvect_v[i].w,
+                        fdata[i].x, fdata[i].y, fdata[i].z, fdata[i].w, updated_param);
+            }
+            else
+            {
+                ok_(__FILE__, line)(!memcmp(&fdata[i], &fvect_filler, sizeof(fdata[i])),
+                        "Vertex shader float constants updated unexpectedly, parameter %s.\n", updated_param);
+            }
+        }
+    }
+
+    for (i = ARRAY_SIZE(test_effect_preshader_fvect_v); i < 256; ++i)
+    {
+        hr = IDirect3DDevice9_GetVertexShaderConstantF(device, i, &fdata[0].x, 1);
+        ok_(__FILE__, line)(hr == D3D_OK, "Got result %#x.\n", hr);
+        ok_(__FILE__, line)(!memcmp(fdata, &fvect_filler, sizeof(fvect_filler)),
+                "Vertex shader float constants do not match.\n");
+    }
+}
+
+static const BOOL test_effect_preshader_bconsts[] =
+{
+    TRUE, FALSE, TRUE, FALSE, TRUE, TRUE
+};
+
+static void test_effect_preshader_clear_pbool_consts(IDirect3DDevice9 *device)
+{
+    BOOL bval;
+    unsigned int i;
+    HRESULT hr;
+
+    for (i = 0; i < 16; ++i)
+    {
+        bval = i < ARRAY_SIZE(test_effect_preshader_bconsts) ? !test_effect_preshader_bconsts[i] : FALSE;
+        hr = IDirect3DDevice9_SetPixelShaderConstantB(device, i, &bval, 1);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    }
+}
+
+#define test_effect_preshader_compare_pbool_consts(a, b, c) \
+        test_effect_preshader_compare_pbool_consts_(__LINE__, a, b, c)
+static void test_effect_preshader_compare_pbool_consts_(unsigned int line, IDirect3DDevice9 *device,
+        const unsigned int *const_updated_mask, const char *updated_param)
+{
+    unsigned int i;
+    BOOL bdata[16];
+    HRESULT hr;
+
+    hr = IDirect3DDevice9_GetPixelShaderConstantB(device, 0, bdata, ARRAY_SIZE(bdata));
+    ok_(__FILE__, line)(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    if (!const_updated_mask)
+    {
+        for (i = 0; i < ARRAY_SIZE(test_effect_preshader_bconsts); ++i)
+        {
+            /* The negation on both sides is actually needed, sometimes you
+             * get 0xffffffff instead of 1 on native. */
+            ok_(__FILE__, line)(!bdata[i] == !test_effect_preshader_bconsts[i],
+                    "Pixel shader boolean constants do not match, expected %#x, got %#x, i %u.\n",
+                    test_effect_preshader_bconsts[i], bdata[i], i);
+        }
+    }
+    else
+    {
+        for (i = 0; i < ARRAY_SIZE(test_effect_preshader_bconsts); ++i)
+        {
+            if (const_updated_mask[i / TEST_EFFECT_BITMASK_BLOCK_SIZE]
+                    & (1u << (i % TEST_EFFECT_BITMASK_BLOCK_SIZE)))
+            {
+                /* The negation on both sides is actually needed, sometimes
+                 * you get 0xffffffff instead of 1 on native. */
+                ok_(__FILE__, line)(!bdata[i] == !test_effect_preshader_bconsts[i],
+                        "Pixel shader boolean constants do not match, expected %#x, got %#x, i %u, parameter %s.\n",
+                        test_effect_preshader_bconsts[i], bdata[i], i, updated_param);
+            }
+            else
+            {
+                ok_(__FILE__, line)(bdata[i] == !test_effect_preshader_bconsts[i],
+                        "Pixel shader boolean constants updated unexpectedly, parameter %s.\n", updated_param);
+            }
+        }
+    }
+
+    for (; i < 16; ++i)
+    {
+        ok_(__FILE__, line)(!bdata[i], "Got result %#x, boolean register value %u.\n", hr, bdata[i]);
+    }
+}
+
+static void test_effect_preshader(IDirect3DDevice9 *device)
+{
+    static const D3DXVECTOR4 test_effect_preshader_fvect_p[] =
+    {
+        {11.0f, 21.0f,  0.0f, 0.0f},
+        {12.0f, 22.0f,  0.0f, 0.0f},
+        {13.0f, 23.0f,  0.0f, 0.0f},
+        {11.0f, 12.0f,  0.0f, 0.0f},
+        {21.0f, 22.0f,  0.0f, 0.0f},
+        {31.0f, 32.0f,  0.0f, 0.0f},
+        {11.0f, 12.0f,  0.0f, 0.0f},
+        {21.0f, 22.0f,  0.0f, 0.0f},
+        {11.0f, 21.0f,  0.0f, 0.0f},
+        {12.0f, 22.0f,  0.0f, 0.0f},
+        {11.0f, 12.0f, 13.0f, 0.0f},
+        {21.0f, 22.0f, 23.0f, 0.0f},
+        {11.0f, 21.0f, 31.0f, 0.0f},
+        {12.0f, 22.0f, 32.0f, 0.0f}
+    };
+    static const int test_effect_preshader_iconsts[][4] =
+    {
+        {4, 3, 2, 1}
+    };
+    static const D3DXVECTOR4 fvect1 = {28.0f, 29.0f, 30.0f, 31.0f};
+    static const D3DXVECTOR4 fvect2 = {0.0f, 0.0f, 1.0f, 0.0f};
+    static const int ivect_empty[4] = {-1, -1, -1, -1};
+    HRESULT hr;
+    ID3DXEffect *effect;
+    D3DXHANDLE par;
+    unsigned int npasses;
+    DWORD value;
+    D3DXVECTOR4 fdata[ARRAY_SIZE(test_effect_preshader_fvect_p)];
+    int idata[ARRAY_SIZE(test_effect_preshader_iconsts)][4];
+    IDirect3DVertexShader9 *vshader;
+    unsigned int i;
+    D3DCAPS9 caps;
+
+    hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
+    ok(SUCCEEDED(hr), "Failed to get device caps, hr %#x.\n", hr);
+    if (caps.VertexShaderVersion < D3DVS_VERSION(3, 0)
+            || caps.PixelShaderVersion < D3DPS_VERSION(3, 0))
+    {
+        skip("Test requires VS >= 3 and PS >= 3, skipping.\n");
+        return;
+    }
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_effect_preshader_clear_vconsts(device);
+
+    for (i = 0; i < 224; ++i)
+    {
+        hr = IDirect3DDevice9_SetPixelShaderConstantF(device, i, &fvect_filler.x, 1);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    }
+
+    test_effect_preshader_clear_pbool_consts(device);
+
+    for (i = 0; i < 16; ++i)
+    {
+        hr = IDirect3DDevice9_SetPixelShaderConstantI(device, i, ivect_empty, 1);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    }
+
+    hr = effect->lpVtbl->Begin(effect, &npasses, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    par = effect->lpVtbl->GetParameterByName(effect, NULL, "g_Pos2");
+    ok(par != NULL, "GetParameterByName failed.\n");
+
+    hr = effect->lpVtbl->SetVector(effect, par, &fvect1);
+    ok(hr == D3D_OK, "SetVector failed, hr %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+
+    test_effect_preshader_compare_vconsts(device, NULL, NULL);
+
+    hr = IDirect3DDevice9_GetPixelShaderConstantF(device, 0, &fdata[0].x,
+            ARRAY_SIZE(test_effect_preshader_fvect_p));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!memcmp(fdata, test_effect_preshader_fvect_p, sizeof(test_effect_preshader_fvect_p)),
+            "Pixel shader float constants do not match.\n");
+    for (i = ARRAY_SIZE(test_effect_preshader_fvect_p); i < 224; ++i)
+    {
+        hr = IDirect3DDevice9_GetPixelShaderConstantF(device, i, &fdata[0].x, 1);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        ok(!memcmp(fdata, &fvect_filler, sizeof(fvect_filler)),
+                "Pixel shader float constants do not match.\n");
+    }
+    hr = IDirect3DDevice9_GetPixelShaderConstantI(device, 0, idata[0],
+            ARRAY_SIZE(test_effect_preshader_iconsts));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!memcmp(idata, test_effect_preshader_iconsts, sizeof(test_effect_preshader_iconsts)),
+            "Pixel shader integer constants do not match.\n");
+    for (i = ARRAY_SIZE(test_effect_preshader_iconsts); i < 16; ++i)
+    {
+        hr = IDirect3DDevice9_GetPixelShaderConstantI(device, i, idata[0], 1);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        ok(!memcmp(idata[0], ivect_empty, sizeof(ivect_empty)),
+                "Pixel shader integer constants do not match.\n");
+    }
+
+    test_effect_preshader_compare_pbool_consts(device, NULL, NULL);
+
+    test_effect_preshader_op_results(device, NULL, NULL);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, 0, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 3, "Unexpected sampler 0 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, 0, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine ok(value == 3, "Unexpected sampler 0 magfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, 1, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 1, "Unexpected sampler 1 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, 1, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine
+    ok(value == 1, "Unexpected sampler 1 magfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 1, "Unexpected vertex sampler 0 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine
+    ok(value == 1, "Unexpected vertex sampler 0 magfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER1, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine
+    ok(value == 0, "Unexpected vertex sampler 1 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER1, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine
+    ok(value == 0, "Unexpected vertex sampler 1 magfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER2, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 3, "Unexpected vertex sampler 2 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER2, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine ok(value == 3, "Unexpected vertex sampler 2 magfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_FOGDENSITY, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 0, "Unexpected fog density %g.\n", *(float *)&value);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_FOGSTART, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(*(float *)&value == 4.0f, "Unexpected fog start %g.\n", *(float *)&value);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_POINTSCALE_A, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(*(float *)&value == 4.0f, "Unexpected point scale A %g.\n", *(float *)&value);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_POINTSCALE_B, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(*(float *)&value == 12.0f, "Unexpected point scale B %g.\n", *(float *)&value);
+
+    hr = effect->lpVtbl->EndPass(effect);
+
+    par = effect->lpVtbl->GetParameterByName(effect, NULL, "g_iVect");
+    ok(par != NULL, "GetParameterByName failed.\n");
+    hr = effect->lpVtbl->SetVector(effect, par, &fvect2);
+    ok(hr == D3D_OK, "SetVector failed, hr %#x.\n", hr);
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_effect_preshader_compare_shader(device, 1, FALSE);
+
+    hr = IDirect3DDevice9_SetVertexShader(device, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->SetVector(effect, par, &fvect1);
+    ok(hr == D3D_OK, "SetVector failed, hr %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!vshader, "Incorrect shader selected.\n");
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    effect->lpVtbl->Release(effect);
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->Begin(effect, &npasses, D3DXFX_DONOTSAVESTATE);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, 0, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 3, "Unexpected sampler 0 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, 0, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine ok(value == 3, "Unexpected sampler 0 magfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, 1, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 1, "Unexpected sampler 1 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, 1, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine
+    ok(value == 1, "Unexpected sampler 1 magfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 1, "Unexpected vertex sampler 0 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine
+    ok(value == 1, "Unexpected vertex sampler 0 magfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER1, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 2, "Unexpected vertex sampler 1 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER1, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine
+    ok(value == 2, "Unexpected vertex sampler 1 magfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER2, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 3, "Unexpected vertex sampler 2 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER2, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine
+    ok(value == 3, "Unexpected vertex sampler 2 magfilter %u.\n", value);
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    effect->lpVtbl->Release(effect);
+}
+
+/*
+ * fxc.exe /Tfx_2_0
+ */
+#if 0
+float4 opvect1;
+float4 opvect2;
+float4 opvect3;
+
+technique tech0
+{
+    pass p0
+    {
+        LightEnable[0] = TRUE;
+        LightEnable[1] = TRUE;
+        LightEnable[2] = TRUE;
+        LightEnable[3] = TRUE;
+        LightEnable[4] = TRUE;
+        LightEnable[5] = TRUE;
+        LightEnable[6] = TRUE;
+        LightEnable[7] = TRUE;
+        LightType[0] = POINT;
+        LightType[1] = POINT;
+        LightType[2] = POINT;
+        LightType[3] = POINT;
+        LightType[4] = POINT;
+        LightType[5] = POINT;
+        LightType[6] = POINT;
+        LightType[7] = POINT;
+
+        LightDiffuse[0] = exp(opvect1);
+        LightDiffuse[1] = log(opvect1);
+        LightDiffuse[2] = asin(opvect1);
+        LightDiffuse[3] = acos(opvect1);
+        LightDiffuse[4] = atan(opvect1);
+        LightDiffuse[5] = atan2(opvect1, opvect2);
+        LightDiffuse[6] = opvect1 * opvect2;
+
+       /* Placeholder for 'div' instruction manually edited in binary blob. */
+        LightDiffuse[7] = opvect1 * opvect2;
+
+       /* Placeholder for 'cmp' instruction manually edited in binary blob. */
+        LightAmbient[0] = opvect1 + opvect2 + opvect3;
+    }
+}
+#endif
+static const DWORD test_effect_preshader_ops_blob[] =
+{
+    0xfeff0901, 0x0000044c, 0x00000000, 0x00000003, 0x00000001, 0x00000030, 0x00000000, 0x00000000,
+    0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008, 0x6576706f,
+    0x00317463, 0x00000003, 0x00000001, 0x00000068, 0x00000000, 0x00000000, 0x00000004, 0x00000001,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008, 0x6576706f, 0x00327463, 0x00000003,
+    0x00000001, 0x000000a0, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000008, 0x6576706f, 0x00337463, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000,
+    0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
+    0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004,
+    0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000,
+    0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000,
+    0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002,
+    0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001,
+    0x00000003, 0x00003070, 0x00000006, 0x68636574, 0x00000030, 0x00000003, 0x00000001, 0x00000001,
+    0x00000001, 0x00000004, 0x00000020, 0x00000000, 0x00000000, 0x0000003c, 0x00000058, 0x00000000,
+    0x00000000, 0x00000074, 0x00000090, 0x00000000, 0x00000000, 0x00000440, 0x00000000, 0x00000001,
+    0x00000438, 0x00000000, 0x00000019, 0x00000091, 0x00000000, 0x000000b0, 0x000000ac, 0x00000091,
+    0x00000001, 0x000000d0, 0x000000cc, 0x00000091, 0x00000002, 0x000000f0, 0x000000ec, 0x00000091,
+    0x00000003, 0x00000110, 0x0000010c, 0x00000091, 0x00000004, 0x00000130, 0x0000012c, 0x00000091,
+    0x00000005, 0x00000150, 0x0000014c, 0x00000091, 0x00000006, 0x00000170, 0x0000016c, 0x00000091,
+    0x00000007, 0x00000190, 0x0000018c, 0x00000084, 0x00000000, 0x000001b0, 0x000001ac, 0x00000084,
+    0x00000001, 0x000001d0, 0x000001cc, 0x00000084, 0x00000002, 0x000001f0, 0x000001ec, 0x00000084,
+    0x00000003, 0x00000210, 0x0000020c, 0x00000084, 0x00000004, 0x00000230, 0x0000022c, 0x00000084,
+    0x00000005, 0x00000250, 0x0000024c, 0x00000084, 0x00000006, 0x00000270, 0x0000026c, 0x00000084,
+    0x00000007, 0x00000290, 0x0000028c, 0x00000085, 0x00000000, 0x000002bc, 0x000002ac, 0x00000085,
+    0x00000001, 0x000002e8, 0x000002d8, 0x00000085, 0x00000002, 0x00000314, 0x00000304, 0x00000085,
+    0x00000003, 0x00000340, 0x00000330, 0x00000085, 0x00000004, 0x0000036c, 0x0000035c, 0x00000085,
+    0x00000005, 0x00000398, 0x00000388, 0x00000085, 0x00000006, 0x000003c4, 0x000003b4, 0x00000085,
+    0x00000007, 0x000003f0, 0x000003e0, 0x00000087, 0x00000000, 0x0000041c, 0x0000040c, 0x00000000,
+    0x00000009, 0x00000000, 0x00000000, 0xffffffff, 0x00000018, 0x00000000, 0x0000016c, 0x46580200,
+    0x003afffe, 0x42415443, 0x0000001c, 0x000000b3, 0x46580200, 0x00000003, 0x0000001c, 0x20000100,
+    0x000000b0, 0x00000058, 0x00000002, 0x00000001, 0x00000060, 0x00000070, 0x00000080, 0x00010002,
+    0x00000001, 0x00000088, 0x00000070, 0x00000098, 0x00020002, 0x00000001, 0x000000a0, 0x00000070,
+    0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x6576706f, 0x00327463, 0x00030001, 0x00040001, 0x00000001, 0x00000000,
+    0x6576706f, 0x00337463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000,
+    /* FXLC for LightAmbient[0] start. */
+    0x001afffe, 0x434c5846,
+    0x00000001, /* Instruction count, set to 1. */
+    0x30000004, /* Operation code (bits 20-30) set to 'cmp' opcode 0x300. */
+    0x00000003, /* Input arguments count set to 3. */
+    /* Argument 1. */
+    0x00000000, /* Relative addressing flag. */
+    0x00000002, /* Register table ("c", float constants). */
+    0x00000000, /* Register offset. */
+    /* Argument 2. */
+    0x00000000, 0x00000002, 0x00000004,
+    /* Argument 3. */
+    0x00000000, 0x00000002, 0x00000008,
+    /* Output register. */
+    0x00000000, 0x00000004, 0x00000000,
+    /* End mark. */
+    0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+    /* Padding to match placeholder length. */
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    /* FXLC for LightAmbient[0] end. */
+    0x00000000, 0x00000000, 0xffffffff, 0x00000017, 0x00000000, 0x00000114,
+    0x46580200, 0x002ffffe, 0x42415443, 0x0000001c, 0x00000087, 0x46580200, 0x00000002, 0x0000001c,
+    0x20000100, 0x00000084, 0x00000044, 0x00000002, 0x00000001, 0x0000004c, 0x0000005c, 0x0000006c,
+    0x00010002, 0x00000001, 0x00000074, 0x0000005c, 0x6576706f, 0x00317463, 0x00030001, 0x00040001,
+    0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6576706f, 0x00327463,
+    0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820,
+    0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235,
+    0x00313131, 0x0002fffe, 0x54494c43, 0x00000000,
+    /* FXLC for LightDiffuse[7] start. */
+    0x000ffffe, 0x434c5846,
+    0x00000001, /* Instruction count. */
+    0x20800004, /* Operation code (bits 20-30) set to 'div' opcode 0x208. */
+    0x00000002, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000002, 0x00000004, 0x00000000,
+    0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+    /* FXLC for LightDiffuse[7] end. */
+    0x00000000, 0x00000000, 0xffffffff,
+    0x00000016, 0x00000000, 0x00000114, 0x46580200, 0x002ffffe, 0x42415443, 0x0000001c, 0x00000087,
+    0x46580200, 0x00000002, 0x0000001c, 0x20000100, 0x00000084, 0x00000044, 0x00000002, 0x00000001,
+    0x0000004c, 0x0000005c, 0x0000006c, 0x00010002, 0x00000001, 0x00000074, 0x0000005c, 0x6576706f,
+    0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x6576706f, 0x00327463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x4d007874,
+    0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970,
+    0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000ffffe,
+    0x434c5846, 0x00000001, 0x20500004, 0x00000002, 0x00000000, 0x00000002, 0x00000000, 0x00000000,
+    0x00000002, 0x00000004, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+    0x00000000, 0x00000000, 0xffffffff, 0x00000015, 0x00000000, 0x00000114, 0x46580200, 0x002ffffe,
+    0x42415443, 0x0000001c, 0x00000087, 0x46580200, 0x00000002, 0x0000001c, 0x20000100, 0x00000084,
+    0x00000044, 0x00000002, 0x00000001, 0x0000004c, 0x0000005c, 0x0000006c, 0x00010002, 0x00000001,
+    0x00000074, 0x0000005c, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6576706f, 0x00327463, 0x00030001, 0x00040001,
+    0x00000001, 0x00000000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c,
+    0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe,
+    0x54494c43, 0x00000000, 0x000ffffe, 0x434c5846, 0x00000001, 0x20600004, 0x00000002, 0x00000000,
+    0x00000002, 0x00000000, 0x00000000, 0x00000002, 0x00000004, 0x00000000, 0x00000004, 0x00000000,
+    0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000014, 0x00000000,
+    0x000000dc, 0x46580200, 0x0024fffe, 0x42415443, 0x0000001c, 0x0000005b, 0x46580200, 0x00000001,
+    0x0000001c, 0x20000100, 0x00000058, 0x00000030, 0x00000002, 0x00000001, 0x00000038, 0x00000048,
+    0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c,
+    0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe,
+    0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846, 0x00000001, 0x10c00004, 0x00000001, 0x00000000,
+    0x00000002, 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+    0x00000000, 0x00000000, 0xffffffff, 0x00000013, 0x00000000, 0x000000dc, 0x46580200, 0x0024fffe,
+    0x42415443, 0x0000001c, 0x0000005b, 0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000058,
+    0x00000030, 0x00000002, 0x00000001, 0x00000038, 0x00000048, 0x6576706f, 0x00317463, 0x00030001,
+    0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4d007874,
+    0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970,
+    0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe,
+    0x434c5846, 0x00000001, 0x10b00004, 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000000,
+    0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff,
+    0x00000012, 0x00000000, 0x000000dc, 0x46580200, 0x0024fffe, 0x42415443, 0x0000001c, 0x0000005b,
+    0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000058, 0x00000030, 0x00000002, 0x00000001,
+    0x00000038, 0x00000048, 0x6576706f, 0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820,
+    0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235,
+    0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846, 0x00000001, 0x10a00004,
+    0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0,
+    0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000011, 0x00000000, 0x0000013c,
+    0x46580200, 0x0024fffe, 0x42415443, 0x0000001c, 0x0000005b, 0x46580200, 0x00000001, 0x0000001c,
+    0x20000100, 0x00000058, 0x00000030, 0x00000002, 0x00000001, 0x00000038, 0x00000048, 0x6576706f,
+    0x00317463, 0x00030001, 0x00040001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461,
+    0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43,
+    0x00000000, 0x0024fffe, 0x434c5846, 0x00000004, 0x10600001, 0x00000001, 0x00000000, 0x00000002,
+    0x00000000, 0x00000000, 0x00000004, 0x00000000, 0x10600001, 0x00000001, 0x00000000, 0x00000002,
+    0x00000001, 0x00000000, 0x00000004, 0x00000001, 0x10600001, 0x00000001, 0x00000000, 0x00000002,
+    0x00000002, 0x00000000, 0x00000004, 0x00000002, 0x10600001, 0x00000001, 0x00000000, 0x00000002,
+    0x00000003, 0x00000000, 0x00000004, 0x00000003, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000,
+    0x00000000, 0xffffffff, 0x00000010, 0x00000000, 0x0000013c, 0x46580200, 0x0024fffe, 0x42415443,
+    0x0000001c, 0x0000005b, 0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000058, 0x00000030,
+    0x00000002, 0x00000001, 0x00000038, 0x00000048, 0x6576706f, 0x00317463, 0x00030001, 0x00040001,
+    0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x0024fffe, 0x434c5846,
+    0x00000004, 0x10500001, 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000004,
+    0x00000000, 0x10500001, 0x00000001, 0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000004,
+    0x00000001, 0x10500001, 0x00000001, 0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000004,
+    0x00000002, 0x10500001, 0x00000001, 0x00000000, 0x00000002, 0x00000003, 0x00000000, 0x00000004,
+    0x00000003, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+};
+
+static void test_effect_preshader_ops(IDirect3DDevice9 *device)
+{
+    static D3DLIGHT9 light;
+    const struct
+    {
+        const char *mnem;
+        unsigned int expected_result[4];
+        unsigned int result_index;
+        float *result;
+        D3DXVECTOR4 opvect1, opvect2, opvect3;
+        unsigned int ulps;
+        BOOL todo[4];
+    }
+    op_tests[] =
+    {
+        {"exp", {0x3f800000, 0x3f800000, 0x3e5edc66, 0x7f800000}, 0, &light.Diffuse.r,
+                {0.0f, -0.0f, -2.2f, 3.402823466e+38f}, {1.0f, 2.0f, -3.0f, 4.0f}},
+        {"log", {0, 0x40000000, 0x3f9199b7, 0x43000000}, 1, &light.Diffuse.r,
+                {0.0f, 4.0f, -2.2f, 3.402823466e+38f}, {1.0f, 2.0f, -3.0f, 4.0f}},
+        {"asin", {0xbe9c00ad, 0xffc00000, 0xffc00000, 0xffc00000}, 2, &light.Diffuse.r,
+                {-0.3f, 4.0f, -2.2f, 3.402823466e+38f}, {1.0f, 2.0f, -3.0f, 4.0f}},
+        {"acos", {0x3ff01006, 0xffc00000, 0xffc00000, 0xffc00000}, 3, &light.Diffuse.r,
+                {-0.3f, 4.0f, -2.2f, 3.402823466e+38f}, {1.0f, 2.0f, -3.0f, 4.0f}},
+        {"atan", {0xbe9539d4, 0x3fa9b465, 0xbf927420, 0x3fc90fdb}, 4, &light.Diffuse.r,
+                {-0.3f, 4.0f, -2.2f, 3.402823466e+38f}, {1.0f, 2.0f, -3.0f, 4.0f}},
+        {"atan2 test #1", {0xbfc90fdb, 0x40490fdb, 0x80000000, 0x7fc00000}, 5, &light.Diffuse.r,
+                {-0.3f, 0.0f, -0.0f, NAN}, {0.0f, -0.0f, 0.0f, 1.0f}},
+        {"atan2 test #2", {0xbfc90fdb, 0, 0xc0490fdb, 0}, 5, &light.Diffuse.r,
+                {-0.3f, 0.0f, -0.0f, -0.0f}, {-0.0f, 0.0f, -0.0f, 1.0f}},
+        {"div", {0, 0, 0, 0}, 7, &light.Diffuse.r,
+                {-0.3f, 0.0f, -2.2f, NAN}, {0.0f, -0.0f, -3.0f, 1.0f}},
+        {"cmp", {0x40a00000, 0x40000000, 0x40400000, 0x41000000}, 0, &light.Ambient.r,
+                {-0.3f, 0.0f, 2.2f, NAN}, {1.0f, 2.0f, 3.0f, 4.0f}, {5.0f, 6.0f, 7.0f, 8.0f}},
+        {"0 * INF", {0xffc00000, 0xffc00000, 0xc0d33334, 0x7f800000}, 6, &light.Diffuse.r,
+                {0.0f, -0.0f, -2.2f, 3.402823466e+38f}, {INFINITY, INFINITY, 3.0f, 4.0f}},
+    };
+    unsigned int i, j, passes_count;
+    ID3DXEffect *effect;
+    HRESULT hr;
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_ops_blob, sizeof(test_effect_preshader_ops_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->Begin(effect, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    for (i = 0; i < ARRAY_SIZE(op_tests); ++i)
+    {
+        const float *result = op_tests[i].result;
+        const float *expected_float = (float *)op_tests[i].expected_result;
+
+        hr = effect->lpVtbl->SetVector(effect, "opvect1", &op_tests[i].opvect1);
+        ok(hr == D3D_OK, "SetVector failed, hr %#x.\n", hr);
+        hr = effect->lpVtbl->SetVector(effect, "opvect2", &op_tests[i].opvect2);
+        ok(hr == D3D_OK, "SetVector failed, hr %#x.\n", hr);
+        hr = effect->lpVtbl->SetVector(effect, "opvect3", &op_tests[i].opvect3);
+        ok(hr == D3D_OK, "SetVector failed, hr %#x.\n", hr);
+        hr = effect->lpVtbl->CommitChanges(effect);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        hr = IDirect3DDevice9_GetLight(device, op_tests[i].result_index, &light);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        for (j = 0; j < 4; ++j)
+        {
+            todo_wine_if(op_tests[i].todo[j])
+            ok(compare_float(result[j], expected_float[j], op_tests[i].ulps),
+                    "Operation %s, component %u, expected %#x (%.8e), got %#x (%.8e).\n", op_tests[i].mnem,
+                    j, op_tests[i].expected_result[j], expected_float[j],
+                    ((unsigned int *)result)[j], result[j]);
+        }
+    }
+
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    effect->lpVtbl->Release(effect);
+}
+
+static void test_isparameterused_children(unsigned int line, ID3DXEffect *effect,
+        D3DXHANDLE tech, D3DXHANDLE param)
+{
+    D3DXPARAMETER_DESC desc;
+    D3DXHANDLE param_child;
+    unsigned int i, child_count;
+    HRESULT hr;
+
+    hr = effect->lpVtbl->GetParameterDesc(effect, param, &desc);
+    ok_(__FILE__, line)(hr == D3D_OK, "GetParameterDesc failed, result %#x.\n", hr);
+    child_count = desc.Elements ? desc.Elements : desc.StructMembers;
+    for (i = 0; i < child_count; ++i)
+    {
+        param_child = desc.Elements ? effect->lpVtbl->GetParameterElement(effect, param, i)
+                : effect->lpVtbl->GetParameter(effect, param, i);
+        ok_(__FILE__, line)(!!param_child, "Failed getting child parameter %s[%u].\n", desc.Name, i);
+        ok_(__FILE__, line)(!effect->lpVtbl->IsParameterUsed(effect, param_child, tech),
+                "Unexpected IsParameterUsed() result for %s[%u].\n", desc.Name, i);
+        test_isparameterused_children(line, effect, tech, param_child);
+    }
+}
+
+#ifdef __REACTOS__
+#define test_isparameterused_param_with_children(...) \
+        test_isparameterused_param_with_children_(__LINE__, __VA_ARGS__)
+#else
+#define test_isparameterused_param_with_children(args...) \
+        test_isparameterused_param_with_children_(__LINE__, args)
+#endif
+static void test_isparameterused_param_with_children_(unsigned int line, ID3DXEffect *effect,
+        ID3DXEffect *effect2, D3DXHANDLE tech, const char *name, BOOL expected_result)
+{
+    D3DXHANDLE param;
+
+    ok_(__FILE__, line)(effect->lpVtbl->IsParameterUsed(effect, (D3DXHANDLE)name, tech)
+            == expected_result, "Unexpected IsParameterUsed() result for %s (referenced by name).\n", name);
+
+    if (effect2)
+        param = effect2->lpVtbl->GetParameterByName(effect2, NULL, name);
+    else
+        param = effect->lpVtbl->GetParameterByName(effect, NULL, name);
+    ok_(__FILE__, line)(!!param, "GetParameterByName failed for %s.\n", name);
+
+    ok_(__FILE__, line)(effect->lpVtbl->IsParameterUsed(effect, param, tech) == expected_result,
+            "Unexpected IsParameterUsed() result for %s (referenced by handle).\n", name);
+
+    test_isparameterused_children(line, effect, tech, param);
+}
+
+static void test_effect_isparameterused(IDirect3DDevice9 *device)
+{
+    static const struct
+    {
+        const char *name;
+        BOOL expected_result;
+    }
+    check_parameters[] =
+    {
+        {"g_Pos1", TRUE},
+        {"g_Pos2", TRUE},
+        {"g_Selector", TRUE},
+        {"opvect1", TRUE},
+        {"opvect2", TRUE},
+        {"opvect3", TRUE},
+        {"arr2", TRUE},
+        {"vs_arr", TRUE},
+        {"g_iVect", TRUE},
+        {"vect_sampler", TRUE},
+        {"tex1", TRUE},
+        {"tex2", FALSE},
+        {"sampler1", TRUE},
+        {"ts1", TRUE},
+        {"ts2", TRUE},
+        {"ts3", TRUE},
+    };
+    ID3DXEffect *effect, *effect2;
+    HRESULT hr;
+    D3DXHANDLE tech;
+    unsigned int i;
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    tech = effect->lpVtbl->GetTechniqueByName(effect, "tech0");
+    ok(!!tech, "GetTechniqueByName failed.\n");
+
+    for (i = 0; i < ARRAY_SIZE(check_parameters); ++i)
+        test_isparameterused_param_with_children(effect, NULL, tech, check_parameters[i].name,
+                check_parameters[i].expected_result);
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect2, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    for (i = 0; i < ARRAY_SIZE(check_parameters); ++i)
+        test_isparameterused_param_with_children(effect, effect2, tech, check_parameters[i].name,
+                check_parameters[i].expected_result);
+
+    effect2->lpVtbl->Release(effect2);
+
+    hr = D3DXCreateEffect(device, test_effect_states_effect_blob, sizeof(test_effect_states_effect_blob),
+            NULL, NULL, 0, NULL, &effect2, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_isparameterused_param_with_children(effect, effect2, tech, "sampler1", TRUE);
+    effect2->lpVtbl->Release(effect2);
+
+    effect->lpVtbl->Release(effect);
+}
+
+static void test_effect_out_of_bounds_selector(IDirect3DDevice9 *device)
+{
+    ID3DXEffect *effect;
+    HRESULT hr;
+    D3DXHANDLE param;
+    int ivect[4];
+    unsigned int passes_count;
+    IDirect3DVertexShader9 *vshader;
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+
+    hr = effect->lpVtbl->Begin(effect, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ivect[0] = ivect[1] = ivect[3] = 1;
+
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "g_iVect");
+    ok(!!param, "GetParameterByName failed.\n");
+    ivect[2] = 3;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetVertexShader(device, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
+
+    /* Second try reports success and selects array element used previously.
+     * Probably array index is not recomputed and previous index value is used. */
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_shader(device, 2, FALSE);
+
+    /* Confirm that array element selected is the previous good one and does not depend
+     * on computed (out of bound) index value. */
+    ivect[2] = 1;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_SetVertexShader(device, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_shader(device, 1, FALSE);
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ivect[2] = 3;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_SetVertexShader(device, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_shader(device, 1, FALSE);
+
+    /* End and begin effect again to ensure it will not trigger array
+     * index recompute and error return from BeginPass. */
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->Begin(effect, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_shader(device, 1, FALSE);
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+
+    hr = IDirect3DDevice9_SetVertexShader(device, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ivect[2] = -2;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!vshader, "Got non NULL vshader.\n");
+
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_effect_preshader_compare_shader(device, 1, FALSE);
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ivect[2] = -1;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_effect_preshader_compare_shader(device, 0, FALSE);
+
+    hr = IDirect3DDevice9_SetVertexShader(device, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ivect[2] = 3;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!vshader, "Got non NULL vshader.\n");
+
+    ivect[2] = -1;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!vshader, "Got non NULL vshader.\n");
+
+    ivect[2] = 1;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_effect_preshader_compare_shader(device, 1, FALSE);
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    effect->lpVtbl->Release(effect);
+}
+
+static void test_effect_commitchanges(IDirect3DDevice9 *device)
+{
+    static const struct
+    {
+        const char *param_name;
+        enum expected_state_update state_updated[ARRAY_SIZE(test_effect_preshader_op_expected)];
+    }
+    check_op_parameters[] =
+    {
+        {"opvect1", {EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED,
+                     EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED,
+                     EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED,
+                     EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_ANYTHING,
+                     EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED}},
+        {"opvect2", {EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED,
+                     EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED,
+                     EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED,
+                     EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_ANYTHING,
+                     EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED, EXPECTED_STATE_UPDATED}},
+        {"opvect3", {EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO,
+                     EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO, EXPECTED_STATE_UPDATED,
+                     EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO,
+                     EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO, EXPECTED_STATE_ANYTHING,
+                     EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO, EXPECTED_STATE_ZERO}},
+    };
+    static const struct
+    {
+        const char *param_name;
+        const unsigned int const_updated_mask[(ARRAY_SIZE(test_effect_preshader_fvect_v)
+                + TEST_EFFECT_BITMASK_BLOCK_SIZE - 1) / TEST_EFFECT_BITMASK_BLOCK_SIZE];
+    }
+    check_vconsts_parameters[] =
+    {
+        {"g_Selector", {0x00000000, 0x00000002}},
+        {"g_Pos1",     {0x80000000, 0x00000002}},
+        {"g_Pos2",     {0x00000000, 0x00000002}},
+        {"m4x3column", {0x03800000, 0x00000000}},
+        {"m3x4column", {0x000f0000, 0x00000000}},
+        {"m4x3row",    {0x0000f000, 0x00000000}},
+        {"m3x4row",    {0x00700000, 0x00000000}},
+        {"ts1",        {0x1c000000, 0x00000000}},
+        {"ts2",        {0x0000003f, 0x00000000}},
+        {"arr1",       {0x00000000, 0x00000001}},
+        {"arr2",       {0x60000000, 0x00000000}},
+        {"ts3",        {0x00000fc0, 0x00000000}},
+    };
+    static const struct
+    {
+        const char *param_name;
+        const unsigned int const_updated_mask[(ARRAY_SIZE(test_effect_preshader_bconsts)
+                + TEST_EFFECT_BITMASK_BLOCK_SIZE - 1) / TEST_EFFECT_BITMASK_BLOCK_SIZE];
+    }
+    check_bconsts_parameters[] =
+    {
+        {"mb2x3row", {0x0000001f}},
+        {"mb2x3column", {0x00000060}},
+    };
+    static const unsigned int const_no_update_mask[(ARRAY_SIZE(test_effect_preshader_fvect_v)
+            + TEST_EFFECT_BITMASK_BLOCK_SIZE - 1) / TEST_EFFECT_BITMASK_BLOCK_SIZE];
+    static const D3DLIGHT9 light_filler = {D3DLIGHT_POINT};
+
+    ID3DXEffect *effect;
+    HRESULT hr;
+    D3DXHANDLE param;
+    unsigned int i, passes_count, value;
+    int ivect[4];
+    D3DXVECTOR4 fvect;
+    IDirect3DVertexShader9 *vshader;
+    unsigned char buffer[256];
+
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "g_iVect");
+    ok(!!param, "GetParameterByName failed.\n");
+
+    hr = effect->lpVtbl->Begin(effect, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetVertexShader(device, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    for (i = 0; i < ARRAY_SIZE(check_op_parameters); ++i)
+    {
+        unsigned int j;
+
+        for (j = 0; j < 8; ++j)
+        {
+            hr = IDirect3DDevice9_SetLight(device, j, &light_filler);
+            ok(hr == D3D_OK, "Got result %#x, i %u, j %u.\n", hr, i, j);
+        }
+        param = effect->lpVtbl->GetParameterByName(effect, NULL, check_op_parameters[i].param_name);
+        ok(!!param, "Failed to get parameter (test %u).\n", i);
+        hr = effect->lpVtbl->GetValue(effect, param, &fvect, sizeof(fvect));
+        ok(hr == D3D_OK, "Failed to get parameter value, hr %#x (test %u).\n", hr, i);
+        hr = effect->lpVtbl->SetValue(effect, param, &fvect, sizeof(fvect));
+        ok(hr == D3D_OK, "Failed to set parameter value, hr %#x (test %u).\n", hr, i);
+        hr = effect->lpVtbl->CommitChanges(effect);
+        ok(hr == D3D_OK, "Failed to commit changes, hr %#x (test %u).\n", hr, i);
+
+        test_effect_preshader_op_results(device, check_op_parameters[i].state_updated,
+                check_op_parameters[i].param_name);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(check_vconsts_parameters); ++i)
+    {
+        test_effect_preshader_clear_vconsts(device);
+        param = effect->lpVtbl->GetParameterByName(effect, NULL, check_vconsts_parameters[i].param_name);
+        ok(!!param, "GetParameterByName failed.\n");
+        hr = effect->lpVtbl->GetValue(effect, param, buffer, sizeof(buffer));
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        hr = effect->lpVtbl->SetValue(effect, param, buffer, sizeof(buffer));
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        hr = effect->lpVtbl->CommitChanges(effect);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[i].const_updated_mask,
+                check_vconsts_parameters[i].param_name);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(check_bconsts_parameters); ++i)
+    {
+        test_effect_preshader_clear_pbool_consts(device);
+        param = effect->lpVtbl->GetParameterByName(effect, NULL, check_bconsts_parameters[i].param_name);
+        ok(!!param, "GetParameterByName failed.\n");
+        hr = effect->lpVtbl->GetValue(effect, param, buffer, sizeof(buffer));
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        hr = effect->lpVtbl->SetValue(effect, param, buffer, sizeof(buffer));
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        hr = effect->lpVtbl->CommitChanges(effect);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        test_effect_preshader_compare_pbool_consts(device, check_bconsts_parameters[i].const_updated_mask,
+                check_bconsts_parameters[i].param_name);
+    }
+
+    test_effect_preshader_clear_vconsts(device);
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "g_Selector");
+    ok(!!param, "GetParameterByName failed.\n");
+    fvect.x = fvect.y = fvect.z = fvect.w = 0.0f;
+    hr = effect->lpVtbl->SetVectorArray(effect, param, &fvect, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[0].const_updated_mask,
+                check_vconsts_parameters[0].param_name);
+
+    test_effect_preshader_clear_vconsts(device);
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "arr2");
+    ok(!!param, "GetParameterByName failed.\n");
+    param = effect->lpVtbl->GetParameterElement(effect, param, 0);
+    ok(!!param, "GetParameterElement failed.\n");
+    hr = effect->lpVtbl->SetFloat(effect, param, 92.0f);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_vconsts(device, const_no_update_mask,
+                check_vconsts_parameters[10].param_name);
+
+    test_effect_preshader_clear_vconsts(device);
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "arr2");
+    ok(!!param, "GetParameterByName failed.\n");
+    param = effect->lpVtbl->GetParameterElement(effect, param, 1);
+    ok(!!param, "GetParameterElement failed.\n");
+    fvect.x = 93.0f;
+    hr = effect->lpVtbl->SetValue(effect, param, &fvect.x, sizeof(fvect.x));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[10].const_updated_mask,
+                check_vconsts_parameters[10].param_name);
+
+    test_effect_preshader_clear_vconsts(device);
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "arr2");
+    ok(!!param, "GetParameterByName failed.\n");
+    fvect.x = 92.0f;
+    hr = effect->lpVtbl->SetFloatArray(effect, param, &fvect.x, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[10].const_updated_mask,
+                check_vconsts_parameters[10].param_name);
+
+    test_effect_preshader_clear_vconsts(device);
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "arr2");
+    ok(!!param, "GetParameterByName failed.\n");
+    param = effect->lpVtbl->GetParameterElement(effect, param, 1);
+    ok(!!param, "GetParameterElement failed.\n");
+    hr = effect->lpVtbl->SetInt(effect, param, 93);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_vconsts(device, const_no_update_mask,
+                check_vconsts_parameters[10].param_name);
+
+    test_effect_preshader_clear_vconsts(device);
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "g_Pos1");
+    ok(!!param, "GetParameterByName failed.\n");
+    fvect.x = fvect.y = fvect.z = fvect.w = 0.0f;
+    hr = effect->lpVtbl->SetVector(effect, param, &fvect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[1].const_updated_mask,
+                check_vconsts_parameters[1].param_name);
+
+    test_effect_preshader_clear_vconsts(device);
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "ts1");
+    ok(!!param, "GetParameterByName failed.\n");
+    param = effect->lpVtbl->GetParameterElement(effect, param, 0);
+    ok(!!param, "GetParameterByName failed.\n");
+    param = effect->lpVtbl->GetParameterByName(effect, param, "fv");
+    ok(!!param, "GetParameterByName failed.\n");
+    fvect.x = 12;
+    hr = effect->lpVtbl->SetValue(effect, param, &fvect.x, sizeof(float));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[7].const_updated_mask,
+                check_vconsts_parameters[7].param_name);
+
+    *(float *)&value = 9999.0f;
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGDENSITY, value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGSTART, value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_POINTSCALE_A, value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_POINTSCALE_B, value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_clear_vconsts(device);
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "ts2");
+    ok(!!param, "GetParameterByName failed.\n");
+    param = effect->lpVtbl->GetParameterElement(effect, param, 0);
+    ok(!!param, "GetParameterByName failed.\n");
+    param = effect->lpVtbl->GetParameterByName(effect, param, "v1");
+    ok(!!param, "GetParameterByName failed.\n");
+    hr = effect->lpVtbl->GetValue(effect, param, &fvect, sizeof(float) * 3);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->SetValue(effect, param, &fvect, sizeof(float) * 3);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_FOGDENSITY, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 0, "Unexpected fog density %g.\n", *(float *)&value);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_FOGSTART, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(*(float *)&value == 4.0f, "Unexpected fog start %g.\n", *(float *)&value);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_POINTSCALE_A, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(*(float *)&value == 9999.0f, "Unexpected point scale A %g.\n", *(float *)&value);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_POINTSCALE_B, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(*(float *)&value == 9999.0f, "Unexpected point scale B %g.\n", *(float *)&value);
+    test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[8].const_updated_mask,
+                check_vconsts_parameters[8].param_name);
+
+    *(float *)&value = 9999.0f;
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGDENSITY, value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGSTART, value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_POINTSCALE_A, value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_POINTSCALE_B, value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_clear_vconsts(device);
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "ts3");
+    ok(!!param, "GetParameterByName failed.\n");
+    param = effect->lpVtbl->GetParameterByName(effect, param, "ts");
+    ok(!!param, "GetParameterByName failed.\n");
+    param = effect->lpVtbl->GetParameterElement(effect, param, 1);
+    ok(!!param, "GetParameterByName failed.\n");
+    param = effect->lpVtbl->GetParameterByName(effect, param, "fv");
+    ok(!!param, "GetParameterByName failed.\n");
+    hr = effect->lpVtbl->GetValue(effect, param, &fvect.x, sizeof(float));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->SetValue(effect, param, &fvect.x, sizeof(float));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_FOGDENSITY, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(*(float *)&value == 9999.0f, "Unexpected fog density %g.\n", *(float *)&value);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_FOGSTART, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(*(float *)&value == 9999.0f, "Unexpected fog start %g.\n", *(float *)&value);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_POINTSCALE_A, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(*(float *)&value == 4.0f, "Unexpected point scale A %g.\n", *(float *)&value);
+    hr = IDirect3DDevice9_GetRenderState(device, D3DRS_POINTSCALE_B, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(*(float *)&value == 12.0f, "Unexpected point scale B %g.\n", *(float *)&value);
+    test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[11].const_updated_mask,
+                check_vconsts_parameters[11].param_name);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 1, "Unexpected sampler 0 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER1, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine
+    ok(value == 0, "Unexpected sampler 1 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER2, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 3, "Unexpected sampler 2 minfilter %u.\n", value);
+
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "g_iVect");
+    ok(!!param, "GetParameterByName failed.\n");
+    ivect[0] = ivect[1] = ivect[2] = ivect[3] = 1;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    for (i = 0; i < 3; ++i)
+    {
+        hr = IDirect3DDevice9_SetSamplerState(device, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MINFILTER, 0);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        hr = IDirect3DDevice9_SetSamplerState(device, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MAGFILTER, 0);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    }
+
+    hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MINFILTER, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MAGFILTER, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetVertexShader(device, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_clear_vconsts(device);
+
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!vshader, "Got non NULL vshader.\n");
+    test_effect_preshader_compare_vconsts(device, const_no_update_mask,
+            "selector g_iVect");
+
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 0, "Unexpected sampler 0 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER1, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 0, "Unexpected sampler 1 minfilter %u.\n", value);
+
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER2, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 1, "Unexpected sampler 2 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, D3DVERTEXTEXTURESAMPLER2, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 0, "Unexpected sampler 2 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, 0, D3DSAMP_MINFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 1, "Unexpected sampler 0 minfilter %u.\n", value);
+    hr = IDirect3DDevice9_GetSamplerState(device, 0, D3DSAMP_MAGFILTER, &value);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(value == 0, "Unexpected sampler 0 minfilter %u.\n", value);
+
+    ivect[3] = 2;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ivect[3] = 1;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!vshader, "Got non NULL vshader.\n");
+    test_effect_preshader_compare_vconsts(device, const_no_update_mask,
+            "selector g_iVect");
+    ivect[3] = 2;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!!vshader, "Got NULL vshader.\n");
+    IDirect3DVertexShader9_Release(vshader);
+    hr = IDirect3DDevice9_GetVertexShaderConstantF(device, 0, &fvect.x, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(fvect.x == 0.0f && fvect.y == 0.0f && fvect.z == 0.0f && fvect.w == 0.0f,
+            "Vertex shader float constants do not match.\n");
+    hr = IDirect3DDevice9_SetVertexShaderConstantF(device, 0, &fvect_filler.x, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_vconsts(device, const_no_update_mask,
+            "selector g_iVect");
+    ivect[3] = 1;
+    hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_vconsts(device, NULL, NULL);
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    effect->lpVtbl->Release(effect);
+}
+
+static void test_effect_preshader_relative_addressing(IDirect3DDevice9 *device)
+{
+    static const struct
+    {
+        D3DXVECTOR4 opvect2;
+        D3DXVECTOR4 g_ivect;
+        unsigned int expected[4];
+    }
+    test_out_of_bounds_index[] =
+    {
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {101.0f, 101.0f, 101.0f, 101.0f}, {0, 0x42ca0000, 0x3f800000, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {3333.0f, 1094.0f, 2222.0f, 3333.0f},
+                {0x447ac000, 0x45505000, 0x3f800000, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {3333.0f, 1094.0f, 2222.0f, 1.0f},
+                {0x447ac000, 0x3f800000, 0x447a8000, 0x453b9000}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {1.0f, 1094.0f, 2222.0f, 3333.0f},
+                {0x447ac000, 0x45505000, 0x3f800000, 0x453ba000}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {1111.0f, 1094.0f, 2222.0f, 1111.0f},
+                {0x447ac000, 0x448ae000, 0, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {1111.0f, 1094.0f, 2222.0f, 3333.0f},
+                {0x447ac000, 0x45505000, 0x3f800000, 0}},
+        {{-1111.0f, 1094.0f, -2222.0f, -3333.0f}, {4.0f, 3.0f, 2.0f, 1.0f},
+                {0x447ac000, 0x40800000, 0x447a8000, 0x453b9000}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-1.0f, -1.0f, -1.0f, -1.0f}, {0, 0xbf800000, 0, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-2.0f, -2.0f, -2.0f, -2.0f}, {0, 0xc0000000, 0x459c4800, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-3.0f, -3.0f, -3.0f, -3.0f}, {0, 0xc0400000, 0x453b9000, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-4.0f, -4.0f, -4.0f, -4.0f}, {0, 0xc0800000, 0x44fa2000, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-5.0f, -5.0f, -5.0f, -5.0f}, {0, 0xc0a00000, 0x459c5000, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-6.0f, -6.0f, -6.0f, -6.0f}, {0, 0xc0c00000, 0x453ba000, 0xc1400000}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-7.0f, -7.0f, -7.0f, -7.0f}, {0, 0xc0e00000, 0x44fa4000, 0x40400000}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-8.0f, -8.0f, -8.0f, -8.0f}, {0, 0xc1000000, 0, 0x44fa6000}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-9.0f, -9.0f, -9.0f, -9.0f}, {0, 0xc1100000, 0, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-10.0f, -10.0f, -10.0f, -10.0f}, {0, 0xc1200000, 0xc1200000, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-11.0f, -11.0f, -11.0f, -11.0f}, {0, 0xc1300000, 0x3f800000, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-12.0f, -12.0f, -12.0f, -12.0f}, {0, 0xc1400000, 0x447a4000, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {5.0f, 5.0f, 5.0f, 5.0f}, {0, 0x40a00000, 0x3f800000, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-1111.0f, 1094.0f, -2222.0f, -3333.0f},
+                {0x447ac000, 0xc5505000, 0x459c5000, 0x40000000}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-3333.0f, 1094.0f, -2222.0f, -1111.0f},
+                {0x447ac000, 0xc48ae000, 0x44fa4000, 0x3f800000}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-3333.0f, 1094.0f, -2222.0f, -3333.0f},
+                {0x447ac000, 0xc5505000, 0x459c5000, 0}},
+        {{1.0f, 2.0f, 3.0f, 4.0f}, {-1111.0f, 1094.0f, -2222.0f, -1111.0f},
+                {0x447ac000, 0xc48ae000, 0x44fa4000, 0x40400000}},
+    };
+    static const struct
+    {
+        unsigned int zw[2];
+    }
+    expected_light_specular[] =
+    {
+        {{0, 0x44fa2000}},
+        {{0x447a8000, 0x453b9000}},
+        {{0x40000000, 0x459c4800}},
+        {{0xbf800000, 0}},
+        {{0x447a4000, 0}},
+        {{0x3f800000, 0}},
+        {{0xbf800000, 0}},
+        {{0, 0}},
+        {{0, 0x447a4000}},
+        {{0x44fa4000, 0x3f800000}},
+        {{0x453ba000, 0xbf800000}},
+        {{0x459c5000, 0}},
+        {{0x44fa2000, 0}},
+        {{0x453b9000, 0}},
+        {{0x459c4800, 0}},
+        {{0, 0}},
+    };
+    static const struct
+    {
+        int index_value;
+        unsigned int expected[4];
+    }
+    test_index_to_immediate_table[] =
+    {
+        {-1000000, {0, 0x40800000, 0x45bbd800, 0x41300000}},
+        {-1001, {0x448d4000, 0x41300000, 0, 0}},
+        {-32, {0x448d4000, 0x40800000, 0, 0}},
+        {-31, {0x45843000, 0x41400000, 0, 0}},
+        {-30, {0x46a64000, 0x41400000, 0x447a4000, 0x3f800000}},
+        {-29, {0, 0x447a4000, 0x447a8000, 0x40000000}},
+        {-28, {0, 0, 0x447ac000, 0x40400000}},
+        {-27, {0, 0x3f800000, 0, 0}},
+        {-26, {0, 0x41100000, 0x45bbd800, 0x41300000}},
+        {-25, {0, 0x41300000, 0, 0}},
+        {-24, {0, 0x41600000, 0, 0}},
+        {-23, {0, 0, 0, 0}},
+        {-22, {0, 0, 0, 0}},
+        {-21, {0, 0x40a00000, 0, 0}},
+        {-20, {0, 0x41500000, 0, 0}},
+        {-19, {0, 0x41500000, 0, 0}},
+        {-18, {0, 0xc1900000, 0, 0}},
+        {-17, {0, 0, 0, 0}},
+        {-16, {0, 0x40800000, 0, 0}},
+        {-15, {0, 0x41400000, 0, 0}},
+        {-14, {0, 0x41400000, 0, 0}},
+        {-13, {0, 0x447a4000, 0x447a4000, 0x3f800000}},
+        {-12, {0, 0, 0, 0}},
+        {-11, {0, 0x3f800000, 0, 0}},
+        {-10, {0, 0x41100000, 0, 0}},
+        {-9, {0, 0x41300000, 0, 0}},
+        {-8, {0, 0x41600000, 0, 0}},
+        {-7, {0, 0, 0, 0}},
+        {-6, {0, 0, 0, 0}},
+        {-5, {0, 0x40a00000, 0, 0}},
+        {-4, {0, 0x41500000, 0, 0}},
+        {-3, {0, 0x41500000, 0, 0}},
+        {-2, {0, 0xc0000000, 0, 0}},
+        {-1, {0, 0, 0, 0}},
+        {0, {0x45052000, 0x40800000, 0x447a4000, 0x3f800000}},
+        {1, {0x467e6000, 0x41400000, 0x447a8000, 0x40000000}},
+        {2, {0, 0x41400000, 0x447ac000, 0x40400000}},
+        {3, {0, 0x447a4000, 0, 0}},
+        {4, {0, 0, 0x45bbd800, 0x41300000}},
+        {5, {0, 0x3f800000, 0, 0}},
+        {6, {0, 0x41100000, 0, 0}},
+        {7, {0, 0x41300000, 0, 0}},
+        {8, {0, 0x41600000, 0, 0}},
+        {9, {0, 0, 0, 0}},
+        {10, {0, 0, 0, 0}},
+        {11, {0, 0x40a00000, 0, 0}},
+        {12, {0, 0x41500000, 0, 0}},
+        {13, {0, 0x41500000, 0, 0}},
+        {14, {0, 0x41600000, 0, 0}},
+        {15, {0, 0, 0, 0}},
+        {16, {0, 0x40800000, 0, 0}},
+        {17, {0x45052000, 0x41400000, 0x447a4000, 0x3f800000}},
+        {18, {0x467e6000, 0x41400000, 0x447a8000, 0x40000000}},
+        {19, {0, 0x447a4000, 0x447ac000, 0x40400000}},
+        {20, {0, 0, 0, 0}},
+        {21, {0, 0x3f800000, 0x45bbd800, 0x41300000}},
+        {22, {0, 0x41100000, 0, 0}},
+        {23, {0, 0x41300000, 0, 0}},
+        {24, {0, 0x41600000, 0, 0}},
+        {25, {0, 0, 0, 0}},
+        {26, {0, 0, 0, 0}},
+        {27, {0, 0x40a00000, 0, 0}},
+        {28, {0, 0x41500000, 0, 0}},
+        {29, {0, 0x41500000, 0, 0}},
+        {30, {0, 0x41f00000, 0, 0}},
+        {31, {0, 0, 0, 0}},
+        {1001, {0, 0, 0, 0}},
+        {1000000, {0, 0x40800000, 0, 0}},
+    };
+    static const D3DLIGHT9 light_filler = {D3DLIGHT_POINT, {1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f},
+            {1.0f, 1.0f, 1.0f, 1.0f}};
+    unsigned int j, passes_count;
+    const unsigned int *expected;
+    const float *expected_float;
+    ID3DXEffect *effect;
+    D3DXVECTOR4 fvect;
+    D3DLIGHT9 light;
+    const float *v;
+    HRESULT hr;
+    int i;
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->Begin(effect, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    fvect.x = 1001.0f; fvect.y = 1002.0f; fvect.z = 1003.0f; fvect.w = 1004.0f;
+    hr = effect->lpVtbl->SetVector(effect, "opvect1", &fvect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    fvect.x = 2001.0f; fvect.y = 2002.0f; fvect.z = 2003.0f; fvect.w = 2004.0f;
+    hr = effect->lpVtbl->SetVector(effect, "g_Selector[0]", &fvect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    fvect.x = 3001.0f; fvect.y = 3002.0f; fvect.z = 3003.0f; fvect.w = 3004.0f;
+    hr = effect->lpVtbl->SetVector(effect, "g_Selector[1]", &fvect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    v = &light.Specular.r;
+    for (i = 0; i < ARRAY_SIZE(test_out_of_bounds_index); ++i)
+    {
+        hr = effect->lpVtbl->SetVector(effect, "opvect2", &test_out_of_bounds_index[i].opvect2);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        hr = effect->lpVtbl->SetVector(effect, "g_iVect", &test_out_of_bounds_index[i].g_ivect);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        hr = IDirect3DDevice9_SetLight(device, 1, &light_filler);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        hr = effect->lpVtbl->CommitChanges(effect);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        hr = IDirect3DDevice9_GetLight(device, 1, &light);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        expected = test_out_of_bounds_index[i].expected;
+        expected_float = (const float *)expected;
+
+        for (j = 0; j < 4; ++j)
+        {
+            ok(compare_float(v[j], expected_float[j], 0),
+                    "Test %d, component %u, expected %#x (%g), got %#x (%g).\n",
+                    i, j, expected[j], expected_float[j], ((const unsigned int *)v)[j], v[j]);
+        }
+    }
+
+    hr = effect->lpVtbl->SetVector(effect, "opvect2", &test_out_of_bounds_index[7].opvect2);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->SetVector(effect, "g_iVect", &test_out_of_bounds_index[7].g_ivect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetLight(device, 1, &light_filler);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    fvect = test_out_of_bounds_index[7].g_ivect;
+    v = &light.Specular.b;
+    for (i = -100; i < 100; ++i)
+    {
+        fvect.w = i;
+        hr = effect->lpVtbl->SetVector(effect, "g_iVect", &fvect);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        hr = effect->lpVtbl->CommitChanges(effect);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        hr = IDirect3DDevice9_GetLight(device, 1, &light);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        expected = expected_light_specular[(unsigned int)i % ARRAY_SIZE(expected_light_specular)].zw;
+        expected_float = (const float *)expected;
+
+        for (j = 0; j < 2; ++j)
+        {
+            ok(compare_float(v[j], expected_float[j], 0),
+                    "i %d, component %u, expected %#x (%g), got %#x (%g).\n",
+                    i, j + 2, expected[j], expected_float[j], ((const unsigned int *)v)[j], v[j]);
+        }
+    }
+
+    v = &light.Specular.r;
+    for (i = 0; i < ARRAY_SIZE(test_index_to_immediate_table); ++i)
+    {
+        fvect.x = fvect.y = fvect.z = fvect.w = test_index_to_immediate_table[i].index_value;
+        hr = effect->lpVtbl->SetVector(effect, "g_iVect", &fvect);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        hr = effect->lpVtbl->CommitChanges(effect);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        hr = IDirect3DDevice9_GetLight(device, 2, &light);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        expected = test_index_to_immediate_table[i].expected;
+        expected_float = (const float *)expected;
+
+        for (j = 0; j < 4; ++j)
+        {
+            ok(compare_float(v[j], expected_float[j], 0),
+                    "Test %d, component %u, expected %#x (%g), got %#x (%g).\n",
+                    i, j, expected[j], expected_float[j], ((const unsigned int *)v)[j], v[j]);
+        }
+    }
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    effect->lpVtbl->Release(effect);
+}
+
+struct test_state_manager_update
+{
+    unsigned int state_op;
+    DWORD param1;
+    DWORD param2;
+};
+
+struct test_manager
+{
+    ID3DXEffectStateManager ID3DXEffectStateManager_iface;
+    LONG ref;
+
+    IDirect3DDevice9 *device;
+    struct test_state_manager_update *update_record;
+    unsigned int update_record_count;
+    unsigned int update_record_size;
+};
+
+#define INITIAL_UPDATE_RECORD_SIZE 64
+
+static struct test_manager *impl_from_ID3DXEffectStateManager(ID3DXEffectStateManager *iface)
+{
+    return CONTAINING_RECORD(iface, struct test_manager, ID3DXEffectStateManager_iface);
+}
+
+static void free_test_effect_state_manager(struct test_manager *state_manager)
+{
+    HeapFree(GetProcessHeap(), 0, state_manager->update_record);
+    state_manager->update_record = NULL;
+
+    IDirect3DDevice9_Release(state_manager->device);
+}
+
+static ULONG WINAPI test_manager_AddRef(ID3DXEffectStateManager *iface)
+{
+    struct test_manager *state_manager = impl_from_ID3DXEffectStateManager(iface);
+
+    return InterlockedIncrement(&state_manager->ref);
+}
+
+static ULONG WINAPI test_manager_Release(ID3DXEffectStateManager *iface)
+{
+    struct test_manager *state_manager = impl_from_ID3DXEffectStateManager(iface);
+    ULONG ref = InterlockedDecrement(&state_manager->ref);
+
+    if (!ref)
+    {
+        free_test_effect_state_manager(state_manager);
+        HeapFree(GetProcessHeap(), 0, state_manager);
+    }
+    return ref;
+}
+
+static HRESULT test_process_set_state(ID3DXEffectStateManager *iface,
+    unsigned int state_op, DWORD param1, DWORD param2)
+{
+    struct test_manager *state_manager = impl_from_ID3DXEffectStateManager(iface);
+
+    if (state_manager->update_record_count == state_manager->update_record_size)
+    {
+        if (!state_manager->update_record_size)
+        {
+            state_manager->update_record_size = INITIAL_UPDATE_RECORD_SIZE;
+            state_manager->update_record = HeapAlloc(GetProcessHeap(), 0,
+                    sizeof(*state_manager->update_record) * state_manager->update_record_size);
+        }
+        else
+        {
+            state_manager->update_record_size *= 2;
+            state_manager->update_record = HeapReAlloc(GetProcessHeap(), 0, state_manager->update_record,
+                    sizeof(*state_manager->update_record) * state_manager->update_record_size);
+        }
+    }
+    state_manager->update_record[state_manager->update_record_count].state_op = state_op;
+    state_manager->update_record[state_manager->update_record_count].param1 = param1;
+    state_manager->update_record[state_manager->update_record_count].param2 = param2;
+    ++state_manager->update_record_count;
+    return D3D_OK;
+}
+
+static HRESULT WINAPI test_manager_SetTransform(ID3DXEffectStateManager *iface,
+        D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
+{
+    return test_process_set_state(iface, 0, state, 0);
+}
+
+static HRESULT WINAPI test_manager_SetMaterial(ID3DXEffectStateManager *iface,
+        const D3DMATERIAL9 *material)
+{
+    return test_process_set_state(iface, 1, 0, 0);
+}
+
+static HRESULT WINAPI test_manager_SetLight(ID3DXEffectStateManager *iface,
+        DWORD index, const D3DLIGHT9 *light)
+{
+    struct test_manager *state_manager = impl_from_ID3DXEffectStateManager(iface);
+
+    IDirect3DDevice9_SetLight(state_manager->device, index, light);
+    return test_process_set_state(iface, 2, index, 0);
+}
+
+static HRESULT WINAPI test_manager_LightEnable(ID3DXEffectStateManager *iface,
+        DWORD index, BOOL enable)
+{
+    struct test_manager *state_manager = impl_from_ID3DXEffectStateManager(iface);
+
+    IDirect3DDevice9_LightEnable(state_manager->device, index, enable);
+    return test_process_set_state(iface, 3, index, 0);
+}
+
+static HRESULT WINAPI test_manager_SetRenderState(ID3DXEffectStateManager *iface,
+        D3DRENDERSTATETYPE state, DWORD value)
+{
+    return test_process_set_state(iface, 4, state, 0);
+}
+
+static HRESULT WINAPI test_manager_SetTexture(ID3DXEffectStateManager *iface,
+        DWORD stage, struct IDirect3DBaseTexture9 *texture)
+{
+    return test_process_set_state(iface, 5, stage, 0);
+}
+
+static HRESULT WINAPI test_manager_SetTextureStageState(ID3DXEffectStateManager *iface,
+        DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
+{
+    return test_process_set_state(iface, 6, stage, type);
+}
+
+static HRESULT WINAPI test_manager_SetSamplerState(ID3DXEffectStateManager *iface,
+        DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value)
+{
+    return test_process_set_state(iface, 7, sampler, type);
+}
+
+static HRESULT WINAPI test_manager_SetNPatchMode(ID3DXEffectStateManager *iface,
+        FLOAT num_segments)
+{
+    return test_process_set_state(iface, 8, 0, 0);
+}
+
+static HRESULT WINAPI test_manager_SetFVF(ID3DXEffectStateManager *iface,
+        DWORD format)
+{
+    return test_process_set_state(iface, 9, 0, 0);
+}
+
+static HRESULT WINAPI test_manager_SetVertexShader(ID3DXEffectStateManager *iface,
+        struct IDirect3DVertexShader9 *shader)
+{
+    return test_process_set_state(iface, 10, 0, 0);
+}
+
+static HRESULT WINAPI test_manager_SetVertexShaderConstantF(ID3DXEffectStateManager *iface,
+        UINT register_index, const FLOAT *constant_data, UINT register_count)
+{
+    return test_process_set_state(iface, 11, register_index, register_count);
+}
+
+static HRESULT WINAPI test_manager_SetVertexShaderConstantI(ID3DXEffectStateManager *iface,
+        UINT register_index, const INT *constant_data, UINT register_count)
+{
+    return test_process_set_state(iface, 12, register_index, register_count);
+}
+
+static HRESULT WINAPI test_manager_SetVertexShaderConstantB(ID3DXEffectStateManager *iface,
+        UINT register_index, const BOOL *constant_data, UINT register_count)
+{
+    return test_process_set_state(iface, 13, register_index, register_count);
+}
+
+static HRESULT WINAPI test_manager_SetPixelShader(ID3DXEffectStateManager *iface,
+        struct IDirect3DPixelShader9 *shader)
+{
+    return test_process_set_state(iface, 14, 0, 0);
+}
+
+static HRESULT WINAPI test_manager_SetPixelShaderConstantF(ID3DXEffectStateManager *iface,
+        UINT register_index, const FLOAT *constant_data, UINT register_count)
+{
+    return test_process_set_state(iface, 15, register_index, register_count);
+}
+
+static HRESULT WINAPI test_manager_SetPixelShaderConstantI(ID3DXEffectStateManager *iface,
+        UINT register_index, const INT *constant_data, UINT register_count)
+{
+    return test_process_set_state(iface, 16, register_index, register_count);
+}
+
+static HRESULT WINAPI test_manager_SetPixelShaderConstantB(ID3DXEffectStateManager *iface,
+        UINT register_index, const BOOL *constant_data, UINT register_count)
+{
+    return test_process_set_state(iface, 17, register_index, register_count);
+}
+
+static void test_effect_state_manager_init(struct test_manager *state_manager,
+        IDirect3DDevice9 *device)
+{
+    static const struct ID3DXEffectStateManagerVtbl test_ID3DXEffectStateManager_Vtbl =
+    {
+        /*** IUnknown methods ***/
+        NULL,
+        test_manager_AddRef,
+        test_manager_Release,
+        /*** ID3DXEffectStateManager methods ***/
+        test_manager_SetTransform,
+        test_manager_SetMaterial,
+        test_manager_SetLight,
+        test_manager_LightEnable,
+        test_manager_SetRenderState,
+        test_manager_SetTexture,
+        test_manager_SetTextureStageState,
+        test_manager_SetSamplerState,
+        test_manager_SetNPatchMode,
+        test_manager_SetFVF,
+        test_manager_SetVertexShader,
+        test_manager_SetVertexShaderConstantF,
+        test_manager_SetVertexShaderConstantI,
+        test_manager_SetVertexShaderConstantB,
+        test_manager_SetPixelShader,
+        test_manager_SetPixelShaderConstantF,
+        test_manager_SetPixelShaderConstantI,
+        test_manager_SetPixelShaderConstantB,
+    };
+
+    state_manager->ID3DXEffectStateManager_iface.lpVtbl = &test_ID3DXEffectStateManager_Vtbl;
+    state_manager->ref = 1;
+
+    IDirect3DDevice9_AddRef(device);
+    state_manager->device = device;
+}
+
+static const char *test_effect_state_manager_state_names[] =
+{
+    "SetTransform",
+    "SetMaterial",
+    "SetLight",
+    "LightEnable",
+    "SetRenderState",
+    "SetTexture",
+    "SetTextureStageState",
+    "SetSamplerState",
+    "SetNPatchMode",
+    "SetFVF",
+    "SetVertexShader",
+    "SetVertexShaderConstantF",
+    "SetVertexShaderConstantI",
+    "SetVertexShaderConstantB",
+    "SetPixelShader",
+    "SetPixelShaderConstantF",
+    "SetPixelShaderConstantI",
+    "SetPixelShaderConstantB",
+};
+
+static int compare_update_record(const void *a, const void *b)
+{
+    const struct test_state_manager_update *r1 = (const struct test_state_manager_update *)a;
+    const struct test_state_manager_update *r2 = (const struct test_state_manager_update *)b;
+
+    if (r1->state_op != r2->state_op)
+        return r1->state_op - r2->state_op;
+    if (r1->param1 != r2->param1)
+        return r1->param1 - r2->param1;
+    return r1->param2 - r2->param2;
+}
+
+static void test_effect_state_manager(IDirect3DDevice9 *device)
+{
+    static const struct test_state_manager_update expected_updates[] =
+    {
+        {2, 0, 0},
+        {2, 1, 0},
+        {2, 2, 0},
+        {2, 3, 0},
+        {2, 4, 0},
+        {2, 5, 0},
+        {2, 6, 0},
+        {2, 7, 0},
+        {3, 0, 0},
+        {3, 1, 0},
+        {3, 2, 0},
+        {3, 3, 0},
+        {3, 4, 0},
+        {3, 5, 0},
+        {3, 6, 0},
+        {3, 7, 0},
+        {4, 28, 0},
+        {4, 36, 0},
+        {4, 38, 0},
+        {4, 158, 0},
+        {4, 159, 0},
+        {5, 0, 0},
+        {5, 259, 0},
+        {7, 0, 5},
+        {7, 0, 6},
+        {7, 1, 5},
+        {7, 1, 6},
+        {7, 257, 5},
+        {7, 257, 6},
+        {7, 258, 5},
+        {7, 258, 6},
+        {7, 259, 5},
+        {7, 259, 6},
+        {10, 0, 0},
+        {11, 0, 34},
+        {14, 0, 0},
+        {15, 0, 14},
+        {16, 0, 1},
+        {17, 0, 6},
+    };
+    static D3DLIGHT9 light_filler =
+            {D3DLIGHT_DIRECTIONAL, {0.5f, 0.5f, 0.5f, 0.5f}, {0.5f, 0.5f, 0.5f, 0.5f}, {0.5f, 0.5f, 0.5f, 0.5f}};
+    struct test_manager *state_manager;
+    unsigned int passes_count, i, n;
+    ID3DXEffect *effect;
+    ULONG refcount;
+    HRESULT hr;
+
+    state_manager = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*state_manager));
+    test_effect_state_manager_init(state_manager, device);
+
+    for (i = 0; i < 8; ++i)
+    {
+        hr = IDirect3DDevice9_SetLight(device, i, &light_filler);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    }
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->SetStateManager(effect, &state_manager->ID3DXEffectStateManager_iface);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->Begin(effect, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    effect->lpVtbl->Release(effect);
+
+    qsort(state_manager->update_record, state_manager->update_record_count,
+            sizeof(*state_manager->update_record), compare_update_record);
+
+    ok(ARRAY_SIZE(expected_updates) == state_manager->update_record_count,
+            "Got %u update records.\n", state_manager->update_record_count);
+    n = min(ARRAY_SIZE(expected_updates), state_manager->update_record_count);
+    for (i = 0; i < n; ++i)
+    {
+        ok(!memcmp(&expected_updates[i], &state_manager->update_record[i],
+                sizeof(expected_updates[i])),
+                "Update record mismatch, expected %s, %u, %u, got %s, %u, %u.\n",
+                test_effect_state_manager_state_names[expected_updates[i].state_op],
+                expected_updates[i].param1, expected_updates[i].param2,
+                test_effect_state_manager_state_names[state_manager->update_record[i].state_op],
+                state_manager->update_record[i].param1, state_manager->update_record[i].param2);
+    }
+
+    for (i = 0; i < 8; ++i)
+    {
+        D3DLIGHT9 light;
+
+        hr = IDirect3DDevice9_GetLight(device, i, &light);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+        ok(!memcmp(&light, &light_filler, sizeof(light)), "Light %u mismatch.\n", i);
+    }
+
+    refcount = state_manager->ID3DXEffectStateManager_iface.lpVtbl->Release(
+            &state_manager->ID3DXEffectStateManager_iface);
+    ok(!refcount, "State manager was not properly freed, refcount %u.\n", refcount);
+}
+
+static void test_cross_effect_handle(IDirect3DDevice9 *device)
+{
+    ID3DXEffect *effect1, *effect2;
+    D3DXHANDLE param1, param2;
+    static int expected_ivect[4] = {28, 29, 30, 31};
+    int ivect[4];
+    HRESULT hr;
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect1, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect2, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ok(effect1 != effect2, "Got same effect unexpectedly.\n");
+
+    param1 = effect1->lpVtbl->GetParameterByName(effect1, NULL, "g_iVect");
+    ok(!!param1, "GetParameterByName failed.\n");
+
+    param2 = effect2->lpVtbl->GetParameterByName(effect2, NULL, "g_iVect");
+    ok(!!param2, "GetParameterByName failed.\n");
+
+    ok(param1 != param2, "Got same parameter handle unexpectedly.\n");
+
+    hr = effect2->lpVtbl->SetValue(effect2, param1, expected_ivect, sizeof(expected_ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect1->lpVtbl->GetValue(effect1, param1, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ok(!memcmp(ivect, expected_ivect, sizeof(expected_ivect)), "Vector value mismatch.\n");
+
+    effect2->lpVtbl->Release(effect2);
+    effect1->lpVtbl->Release(effect1);
+}
+
+#if 0
+struct test_struct
+{
+    float3 v1_2;
+    float fv_2;
+    float4 v2_2;
+};
+
+shared float arr2[1];
+shared test_struct ts2[2] = {{{0, 0, 0}, 0, {0, 0, 0, 0}}, {{1, 2, 3}, 4, {5, 6, 7, 8}}};
+
+struct VS_OUTPUT
+{
+    float4 Position   : POSITION;
+};
+
+VS_OUTPUT RenderSceneVS(float4 vPos : POSITION)
+{
+    VS_OUTPUT Output;
+
+    Output.Position = arr2[0] * vPos;
+    return Output;
+}
+
+shared vertexshader vs_arr2[2] = {compile vs_3_0 RenderSceneVS(), NULL};
+
+technique tech0
+{
+    pass p0
+    {
+        FogEnable = TRUE;
+        FogDensity = arr2[0];
+        PointScale_A = ts2[0].fv_2;
+        VertexShader = vs_arr2[0];
+    }
+
+    pass p1
+    {
+        VertexShader = vs_arr2[1];
+    }
+}
+#endif
+static const DWORD test_effect_shared_parameters_blob[] =
+{
+    0xfeff0901, 0x000001dc, 0x00000000, 0x00000003, 0x00000000, 0x00000024, 0x00000000, 0x00000001,
+    0x00000001, 0x00000001, 0x00000000, 0x00000005, 0x32727261, 0x00000000, 0x00000000, 0x00000005,
+    0x000000dc, 0x00000000, 0x00000002, 0x00000003, 0x00000003, 0x00000001, 0x000000e4, 0x00000000,
+    0x00000000, 0x00000003, 0x00000001, 0x00000003, 0x00000000, 0x000000f0, 0x00000000, 0x00000000,
+    0x00000001, 0x00000001, 0x00000003, 0x00000001, 0x000000fc, 0x00000000, 0x00000000, 0x00000004,
+    0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x40a00000, 0x40c00000, 0x40e00000,
+    0x41000000, 0x00000004, 0x00327374, 0x00000005, 0x325f3176, 0x00000000, 0x00000005, 0x325f7666,
+    0x00000000, 0x00000005, 0x325f3276, 0x00000000, 0x00000010, 0x00000004, 0x00000124, 0x00000000,
+    0x00000002, 0x00000001, 0x00000002, 0x00000008, 0x615f7376, 0x00327272, 0x00000001, 0x00000002,
+    0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000003,
+    0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000003,
+    0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000003, 0x00000010,
+    0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00003070, 0x00000004, 0x00000010,
+    0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00003170, 0x00000006, 0x68636574,
+    0x00000030, 0x00000003, 0x00000001, 0x00000006, 0x00000005, 0x00000004, 0x00000020, 0x00000001,
+    0x00000000, 0x00000030, 0x0000009c, 0x00000001, 0x00000000, 0x00000108, 0x0000011c, 0x00000001,
+    0x00000000, 0x000001d0, 0x00000000, 0x00000002, 0x000001a8, 0x00000000, 0x00000004, 0x0000000e,
+    0x00000000, 0x00000134, 0x00000130, 0x00000014, 0x00000000, 0x00000154, 0x00000150, 0x00000041,
+    0x00000000, 0x00000174, 0x00000170, 0x00000092, 0x00000000, 0x00000194, 0x00000190, 0x000001c8,
+    0x00000000, 0x00000001, 0x00000092, 0x00000000, 0x000001b4, 0x000001b0, 0x00000002, 0x00000004,
+    0x00000001, 0x000000c8, 0xfffe0300, 0x0025fffe, 0x42415443, 0x0000001c, 0x0000005f, 0xfffe0300,
+    0x00000001, 0x0000001c, 0x00000000, 0x00000058, 0x00000030, 0x00000002, 0x00000001, 0x00000038,
+    0x00000048, 0x32727261, 0xababab00, 0x00030000, 0x00010001, 0x00000001, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820,
+    0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235,
+    0x00313131, 0x0200001f, 0x80000000, 0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x03000005,
+    0xe00f0000, 0xa0000000, 0x90e40000, 0x0000ffff, 0x00000002, 0x00000000, 0x00000000, 0x00000001,
+    0xffffffff, 0x00000000, 0x00000001, 0x0000000b, 0x615f7376, 0x5b327272, 0x00005d31, 0x00000000,
+    0x00000000, 0xffffffff, 0x00000003, 0x00000001, 0x0000000b, 0x615f7376, 0x5b327272, 0x00005d30,
+    0x00000000, 0x00000000, 0xffffffff, 0x00000002, 0x00000000, 0x00000188, 0x46580200, 0x004ffffe,
+    0x42415443, 0x0000001c, 0x00000107, 0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000104,
+    0x00000030, 0x00000002, 0x00000002, 0x00000094, 0x000000a4, 0x00327374, 0x325f3176, 0xababab00,
+    0x00030001, 0x00030001, 0x00000001, 0x00000000, 0x325f7666, 0xababab00, 0x00030000, 0x00010001,
+    0x00000001, 0x00000000, 0x325f3276, 0xababab00, 0x00030001, 0x00040001, 0x00000001, 0x00000000,
+    0x00000034, 0x0000003c, 0x0000004c, 0x00000054, 0x00000064, 0x0000006c, 0x00000005, 0x00080001,
+    0x00030002, 0x0000007c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x40000000,
+    0x40400000, 0x00000000, 0x40800000, 0x00000000, 0x00000000, 0x00000000, 0x40a00000, 0x40c00000,
+    0x40e00000, 0x41000000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c,
+    0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe,
+    0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846, 0x00000001, 0x10000001, 0x00000001, 0x00000000,
+    0x00000002, 0x00000004, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+    0x00000000, 0x00000000, 0xffffffff, 0x00000001, 0x00000000, 0x000000dc, 0x46580200, 0x0024fffe,
+    0x42415443, 0x0000001c, 0x0000005b, 0x46580200, 0x00000001, 0x0000001c, 0x20000100, 0x00000058,
+    0x00000030, 0x00000002, 0x00000001, 0x00000038, 0x00000048, 0x32727261, 0xababab00, 0x00030000,
+    0x00010001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4d007874,
+    0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970,
+    0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe,
+    0x434c5846, 0x00000001, 0x10000001, 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000000,
+    0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+};
+
+#ifdef __REACTOS__
+#define test_effect_shared_vs_arr_compare_helper(...) \
+        test_effect_shared_vs_arr_compare_helper_(__LINE__, __VA_ARGS__)
+#else
+#define test_effect_shared_vs_arr_compare_helper(args...) \
+        test_effect_shared_vs_arr_compare_helper_(__LINE__, args)
+#endif
+static void test_effect_shared_vs_arr_compare_helper_(unsigned int line, ID3DXEffect *effect,
+        D3DXHANDLE param_child, struct IDirect3DVertexShader9 *vshader1, unsigned int element,
+        BOOL todo)
+{
+    struct IDirect3DVertexShader9 *vshader2;
+    D3DXHANDLE param_child2;
+    HRESULT hr;
+
+    param_child2 = effect->lpVtbl->GetParameterElement(effect, "vs_arr2", element);
+    ok_(__FILE__, line)(!!param_child2, "GetParameterElement failed.\n");
+    ok_(__FILE__, line)(param_child != param_child2, "Got same parameter handle unexpectedly.\n");
+    hr = effect->lpVtbl->GetVertexShader(effect, param_child2, &vshader2);
+    ok_(__FILE__, line)(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine_if(todo)
+    ok_(__FILE__, line)(vshader1 == vshader2, "Shared shader interface pointers differ.\n");
+    if (vshader2)
+        IDirect3DVertexShader9_Release(vshader2);
+}
+
+#ifdef __REACTOS__
+#define test_effect_shared_parameters_compare_vconst(...) \
+        test_effect_shared_parameters_compare_vconst_(__LINE__, __VA_ARGS__)
+#else
+#define test_effect_shared_parameters_compare_vconst(args...) \
+        test_effect_shared_parameters_compare_vconst_(__LINE__, args)
+#endif
+static void test_effect_shared_parameters_compare_vconst_(unsigned int line, IDirect3DDevice9 *device,
+        unsigned int index, const D3DXVECTOR4 *expected_fvect, BOOL todo)
+{
+    D3DXVECTOR4 fvect;
+    HRESULT hr;
+
+    hr = IDirect3DDevice9_GetVertexShaderConstantF(device, index, &fvect.x, 1);
+    ok_(__FILE__, line)(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine_if(todo)
+    ok_(__FILE__, line)(!memcmp(&fvect, expected_fvect, sizeof(fvect)),
+            "Unexpected constant value %g, %g, %g, %g.\n", fvect.x, fvect.y, fvect.z, fvect.w);
+}
+
+static void test_effect_shared_parameters(IDirect3DDevice9 *device)
+{
+    ID3DXEffect *effect1, *effect2, *effect3, *effect4;
+    ID3DXEffectPool *pool;
+    HRESULT hr;
+    D3DXHANDLE param, param_child, param2, param_child2;
+    unsigned int i, passes_count;
+    ULONG refcount;
+    D3DXVECTOR4 fvect;
+    float fval[2];
+
+    hr = D3DXCreateEffectPool(&pool);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, pool, &effect2, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    effect2->lpVtbl->SetFloat(effect2, "arr2[0]", 28.0f);
+    effect2->lpVtbl->Release(effect2);
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, pool, &effect2, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    effect2->lpVtbl->GetFloat(effect2, "arr2[0]", &fvect.x);
+    ok(fvect.x == 92.0f, "Unexpected parameter value %g.\n", fvect.x);
+    effect2->lpVtbl->SetFloat(effect2, "arr2[0]", 28.0f);
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, pool, &effect1, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    effect1->lpVtbl->GetFloat(effect1, "arr2[0]", &fvect.x);
+    ok(fvect.x == 28.0f, "Unexpected parameter value %g.\n", fvect.x);
+
+    hr = D3DXCreateEffect(device, test_effect_shared_parameters_blob, sizeof(test_effect_shared_parameters_blob),
+            NULL, NULL, 0, pool, &effect3, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = D3DXCreateEffect(device, test_effect_shared_parameters_blob, sizeof(test_effect_shared_parameters_blob),
+            NULL, NULL, 0, pool, &effect4, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    effect2->lpVtbl->SetFloat(effect2, "arr2[0]", 3.0f);
+    effect2->lpVtbl->SetFloat(effect2, "ts2[0].fv", 3.0f);
+
+    effect3->lpVtbl->GetFloat(effect3, "arr2[0]", &fvect.x);
+    ok(fvect.x == 0.0f, "Unexpected parameter value %g.\n", fvect.x);
+    effect4->lpVtbl->SetFloat(effect4, "arr2[0]", 28.0f);
+    effect3->lpVtbl->GetFloat(effect3, "arr2[0]", &fvect.x);
+    ok(fvect.x == 28.0f, "Unexpected parameter value %g.\n", fvect.x);
+    effect1->lpVtbl->GetFloat(effect1, "arr2[0]", &fvect.x);
+    ok(fvect.x == 3.0f, "Unexpected parameter value %g.\n", fvect.x);
+
+    param = effect3->lpVtbl->GetParameterByName(effect3, NULL, "ts2[0].fv_2");
+    ok(!!param, "GetParameterByName failed.\n");
+    effect3->lpVtbl->GetFloat(effect3, param, &fvect.x);
+    ok(fvect.x == 0.0f, "Unexpected parameter value %g.\n", fvect.x);
+
+    param = effect1->lpVtbl->GetParameterByName(effect1, NULL, "arr2");
+    ok(!!param, "GetParameterByName failed.\n");
+    ok(!effect3->lpVtbl->IsParameterUsed(effect3, param, "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+
+    param = effect3->lpVtbl->GetParameterByName(effect3, NULL, "arr2");
+    ok(!!param, "GetParameterByName failed.\n");
+    ok(effect3->lpVtbl->IsParameterUsed(effect3, param, "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+
+    param = effect1->lpVtbl->GetParameterByName(effect1, NULL, "vs_arr2");
+    ok(!!param, "GetParameterByName failed.\n");
+    todo_wine
+    ok(!effect3->lpVtbl->IsParameterUsed(effect3, param, "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+
+    ok(effect3->lpVtbl->IsParameterUsed(effect3, "vs_arr2", "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+    ok(!effect3->lpVtbl->IsParameterUsed(effect3, "vs_arr2[0]", "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+    ok(!effect3->lpVtbl->IsParameterUsed(effect3, "vs_arr2[1]", "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+
+    ok(effect1->lpVtbl->IsParameterUsed(effect1, param, "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+
+    hr = effect3->lpVtbl->Begin(effect3, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    if (0)
+    {
+    /*  Native d3dx crashes in BeginPass(). This is the case of shader array declared shared
+     *  but initialized with different shaders using different parameters. */
+    hr = effect3->lpVtbl->BeginPass(effect3, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect3->lpVtbl->EndPass(effect3);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    }
+
+    test_effect_preshader_clear_vconsts(device);
+    fvect.x = fvect.y = fvect.z = fvect.w = 28.0f;
+    hr = effect2->lpVtbl->SetVector(effect2, "g_Pos1", &fvect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect1->lpVtbl->SetVector(effect1, "g_Pos1", &fvect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect3->lpVtbl->BeginPass(effect3, 1);
+    todo_wine
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_GetVertexShaderConstantF(device, 0, &fvect.x, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    todo_wine
+    ok(fvect.x == 0.0f && fvect.y == 0.0f && fvect.z == 0.0f && fvect.w == 0.0f,
+            "Unexpected vector %g, %g, %g, %g.\n", fvect.x, fvect.y, fvect.z, fvect.w);
+
+    hr = effect3->lpVtbl->EndPass(effect3);
+    todo_wine
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect3->lpVtbl->End(effect3);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    for (i = 0; i < 2; ++i)
+    {
+        struct IDirect3DVertexShader9 *vshader1;
+
+        param_child = effect1->lpVtbl->GetParameterElement(effect1, "vs_arr2", i);
+        ok(!!param_child, "GetParameterElement failed.\n");
+        hr = effect1->lpVtbl->GetVertexShader(effect1, param_child, &vshader1);
+        ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+        test_effect_shared_vs_arr_compare_helper(effect2, param_child, vshader1, i, FALSE);
+        test_effect_shared_vs_arr_compare_helper(effect3, param_child, vshader1, i, FALSE);
+        test_effect_shared_vs_arr_compare_helper(effect4, param_child, vshader1, i, FALSE);
+        IDirect3DVertexShader9_Release(vshader1);
+    }
+
+    effect3->lpVtbl->Release(effect3);
+    effect4->lpVtbl->Release(effect4);
+
+    fval[0] = 1.0f;
+    hr = effect1->lpVtbl->SetFloatArray(effect1, "arr1", fval, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    fval[0] = 0.0f;
+    hr = effect2->lpVtbl->GetFloatArray(effect2, "arr1", fval, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(fval[0] == 91.0f, "Unexpected value %g.\n", fval[0]);
+
+    param = effect1->lpVtbl->GetParameterByName(effect1, NULL, "arr2");
+    ok(!!param, "GetParameterByName failed.\n");
+    param2 = effect2->lpVtbl->GetParameterByName(effect2, NULL, "arr2");
+    ok(!!param, "GetParameterByName failed.\n");
+    ok(param != param2, "Got same parameter handle unexpectedly.\n");
+    param_child = effect1->lpVtbl->GetParameterElement(effect1, param, 0);
+    ok(!!param_child, "GetParameterElement failed.\n");
+    param_child2 = effect1->lpVtbl->GetParameterElement(effect2, param2, 0);
+    ok(!!param_child2, "GetParameterElement failed.\n");
+    ok(param_child != param_child2, "Got same parameter handle unexpectedly.\n");
+
+    fval[0] = 33.0f;
+    hr = effect1->lpVtbl->SetFloatArray(effect1, "arr2", fval, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    fval[0] = 0.0f;
+    hr = effect1->lpVtbl->GetFloatArray(effect1, "arr2", fval, 2);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(fval[0] == 33.0f && fval[1] == 93.0f, "Unexpected values %g, %g.\n", fval[0], fval[1]);
+    fval[0] = 0.0f;
+    hr = effect2->lpVtbl->GetFloatArray(effect2, "arr2", fval, 2);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(fval[0] == 33.0f && fval[1] == 93.0f, "Unexpected values %g, %g.\n", fval[0], fval[1]);
+
+    hr = effect1->lpVtbl->Begin(effect1, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect2->lpVtbl->Begin(effect2, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect1->lpVtbl->BeginPass(effect1, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    fvect.x = 1.0f;
+    fvect.y = fvect.z = fvect.w = 0.0f;
+    test_effect_shared_parameters_compare_vconst(device, 32, &fvect, FALSE);
+
+    hr = effect1->lpVtbl->BeginPass(effect2, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    fvect.x = 91.0f;
+    test_effect_shared_parameters_compare_vconst(device, 32, &fvect, FALSE);
+    fvect.x = 33.0f;
+    test_effect_shared_parameters_compare_vconst(device, 29, &fvect, FALSE);
+
+    fval[0] = 28.0f;
+    fval[1] = -1.0f;
+    hr = effect1->lpVtbl->SetFloatArray(effect1, "arr2", fval, 2);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_effect_preshader_clear_vconsts(device);
+
+    hr = effect1->lpVtbl->CommitChanges(effect1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    fvect.x = 28.0f;
+    test_effect_shared_parameters_compare_vconst(device, 29, &fvect, FALSE);
+    fvect.x = -1.0f;
+    test_effect_shared_parameters_compare_vconst(device, 30, &fvect, FALSE);
+
+    test_effect_preshader_clear_vconsts(device);
+
+    hr = effect1->lpVtbl->CommitChanges(effect1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_effect_shared_parameters_compare_vconst(device, 29, &fvect_filler, FALSE);
+    test_effect_shared_parameters_compare_vconst(device, 30, &fvect_filler, FALSE);
+
+    hr = effect2->lpVtbl->CommitChanges(effect2);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    fvect.x = 28.0f;
+    test_effect_shared_parameters_compare_vconst(device, 29, &fvect, FALSE);
+    fvect.x = -1.0f;
+    test_effect_shared_parameters_compare_vconst(device, 30, &fvect, FALSE);
+
+    fval[0] = -2.0f;
+    hr = effect2->lpVtbl->SetFloat(effect2, "arr2[0]", fval[0]);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect1->lpVtbl->CommitChanges(effect1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    fvect.x = -2.0f;
+    test_effect_shared_parameters_compare_vconst(device, 29, &fvect, FALSE);
+    fvect.x = -1.0f;
+    test_effect_shared_parameters_compare_vconst(device, 30, &fvect, FALSE);
+
+    fvect.x = fvect.y = fvect.z = fvect.w = 1111.0f;
+    hr = effect2->lpVtbl->SetVector(effect2, "g_Pos1", &fvect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect1->lpVtbl->CommitChanges(effect1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_shared_parameters_compare_vconst(device, 31, &fvect_filler, FALSE);
+
+    hr = effect1->lpVtbl->CommitChanges(effect2);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_shared_parameters_compare_vconst(device, 31, &fvect, FALSE);
+
+    hr = effect1->lpVtbl->End(effect1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect2->lpVtbl->End(effect2);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    if (0)
+    {
+        refcount = pool->lpVtbl->Release(pool);
+        ok(refcount == 2, "Unexpected refcount %u.\n", refcount);
+
+        refcount = pool->lpVtbl->Release(pool);
+        ok(refcount == 1, "Unexpected refcount %u.\n", refcount);
+
+        refcount = pool->lpVtbl->Release(pool);
+        ok(!refcount, "Unexpected refcount %u.\n", refcount);
+
+        /* Native d3dx crashes in GetFloat(). */
+        effect2->lpVtbl->GetFloat(effect2, "arr2[0]", &fvect.x);
+    }
+
+    effect1->lpVtbl->Release(effect1);
+    effect2->lpVtbl->Release(effect2);
+
+    refcount = pool->lpVtbl->Release(pool);
+    ok(!refcount, "Effect pool was not properly freed, refcount %u.\n", refcount);
+}
+
+static void test_effect_large_address_aware_flag(IDirect3DDevice9 *device)
+{
+    ID3DXEffect *effect;
+    D3DXHANDLE param;
+    static int expected_ivect[4] = {28, 29, 30, 31};
+    int ivect[4];
+    HRESULT hr;
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, D3DXFX_LARGEADDRESSAWARE, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    param = effect->lpVtbl->GetParameterByName(effect, NULL, "g_iVect");
+    ok(!!param, "GetParameterByName failed.\n");
+
+    hr = effect->lpVtbl->SetValue(effect, param, expected_ivect, sizeof(expected_ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->GetValue(effect, param, ivect, sizeof(ivect));
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ok(!memcmp(ivect, expected_ivect, sizeof(expected_ivect)), "Vector value mismatch.\n");
+
+    if (0)
+    {
+        /* Native d3dx crashes in GetValue(). */
+        hr = effect->lpVtbl->GetValue(effect, "g_iVect", ivect, sizeof(ivect));
+        ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+    }
+
+    effect->lpVtbl->Release(effect);
+}
+
+static void test_effect_get_pass_desc(IDirect3DDevice9 *device)
+{
+    unsigned int passes_count;
+    ID3DXEffect *effect;
+    D3DXPASS_DESC desc;
+    D3DXVECTOR4 fvect;
+    D3DXHANDLE pass;
+    HRESULT hr;
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    pass = effect->lpVtbl->GetPass(effect, "tech0", 1);
+    ok(!!pass, "GetPass() failed.\n");
+
+    hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_shader_bytecode(desc.pVertexShaderFunction, 0, 2, FALSE);
+
+    fvect.x = fvect.y = fvect.w = 0.0f;
+    fvect.z = 0.0f;
+    hr = effect->lpVtbl->SetVector(effect, "g_iVect", &fvect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!desc.pPixelShaderFunction, "Unexpected non null desc.pPixelShaderFunction.\n");
+
+    test_effect_preshader_compare_shader_bytecode(desc.pVertexShaderFunction, 0, 0, FALSE);
+
+    fvect.z = 3.0f;
+    hr = effect->lpVtbl->SetVector(effect, "g_iVect", &fvect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
+    ok(!desc.pVertexShaderFunction, "Unexpected non null desc.pVertexShaderFunction.\n");
+
+    /* Repeating call to confirm GetPassDesc() returns same error on the second call,
+     * as it is not the case sometimes for BeginPass() with out of bound access. */
+    hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
+    ok(!desc.pVertexShaderFunction, "Unexpected non null desc.pVertexShaderFunction.\n");
+
+    hr = effect->lpVtbl->Begin(effect, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_effect_preshader_compare_shader_bytecode(desc.pVertexShaderFunction, 0, 0, FALSE);
+
+    fvect.z = 2.0f;
+    hr = effect->lpVtbl->SetVector(effect, "g_iVect", &fvect);
+    hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    test_effect_preshader_compare_shader_bytecode(desc.pVertexShaderFunction, 0, 2, FALSE);
+
+    effect->lpVtbl->Release(effect);
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, D3DXFX_NOT_CLONEABLE, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    pass = effect->lpVtbl->GetPass(effect, "tech0", 1);
+    ok(!!pass, "GetPass() failed.\n");
+
+    hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ok(!desc.pVertexShaderFunction, "Unexpected non null desc.pVertexShaderFunction.\n");
+    ok(!desc.pPixelShaderFunction, "Unexpected non null desc.pPixelShaderFunction.\n");
+
+    effect->lpVtbl->Release(effect);
+}
+
+#if 0
+float v1 : register(c2);
+float v2 : register(c3);
+float v3;
+float v4 : register(c4);
+float v5;
+float v6[2] : register(c5) = {11, 22};
+
+struct VS_OUTPUT
+{
+    float4 Position   : POSITION;
+};
+
+VS_OUTPUT RenderSceneVS(float4 vPos : POSITION)
+{
+    VS_OUTPUT Output;
+
+    Output.Position = v1 * v2 * vPos + v2 + v3 + v4;
+    Output.Position += v6[0] + v6[1];
+    return Output;
+}
+
+technique tech0
+{
+    pass p0
+    {
+        PointScale_A = v4;
+        VertexShader = compile vs_3_0 RenderSceneVS();
+    }
+}
+#endif
+static const DWORD test_effect_skip_constants_blob[] =
+{
+    0xfeff0901, 0x00000144, 0x00000000, 0x00000003, 0x00000000, 0x00000024, 0x00000000, 0x00000000,
+    0x00000001, 0x00000001, 0x00000000, 0x00000003, 0x00003176, 0x00000003, 0x00000000, 0x0000004c,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000003, 0x00003276, 0x00000003,
+    0x00000000, 0x00000074, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000003,
+    0x00003376, 0x00000003, 0x00000000, 0x0000009c, 0x00000000, 0x00000000, 0x00000001, 0x00000001,
+    0x00000000, 0x00000003, 0x00003476, 0x00000003, 0x00000000, 0x000000c4, 0x00000000, 0x00000000,
+    0x00000001, 0x00000001, 0x00000000, 0x00000003, 0x00003576, 0x00000003, 0x00000000, 0x000000f0,
+    0x00000000, 0x00000002, 0x00000001, 0x00000001, 0x41300000, 0x41b00000, 0x00000003, 0x00003676,
+    0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001,
+    0x00000001, 0x00000010, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00003070,
+    0x00000006, 0x68636574, 0x00000030, 0x00000006, 0x00000001, 0x00000002, 0x00000002, 0x00000004,
+    0x00000020, 0x00000000, 0x00000000, 0x0000002c, 0x00000048, 0x00000000, 0x00000000, 0x00000054,
+    0x00000070, 0x00000000, 0x00000000, 0x0000007c, 0x00000098, 0x00000000, 0x00000000, 0x000000a4,
+    0x000000c0, 0x00000000, 0x00000000, 0x000000cc, 0x000000e8, 0x00000000, 0x00000000, 0x00000138,
+    0x00000000, 0x00000001, 0x00000130, 0x00000000, 0x00000002, 0x00000041, 0x00000000, 0x000000fc,
+    0x000000f8, 0x00000092, 0x00000000, 0x0000011c, 0x00000118, 0x00000000, 0x00000002, 0x00000000,
+    0x00000000, 0xffffffff, 0x00000001, 0x00000000, 0x000001bc, 0xfffe0300, 0x0047fffe, 0x42415443,
+    0x0000001c, 0x000000e7, 0xfffe0300, 0x00000005, 0x0000001c, 0x20000000, 0x000000e0, 0x00000080,
+    0x00020002, 0x000a0001, 0x00000084, 0x00000094, 0x000000a4, 0x00030002, 0x000e0001, 0x00000084,
+    0x00000094, 0x000000a7, 0x00000002, 0x00000001, 0x00000084, 0x00000094, 0x000000aa, 0x00040002,
+    0x00120001, 0x00000084, 0x00000094, 0x000000ad, 0x00050002, 0x00160002, 0x000000b0, 0x000000c0,
+    0xab003176, 0x00030000, 0x00010001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x76003276, 0x34760033, 0x00367600, 0x00030000, 0x00010001, 0x00000002, 0x00000000,
+    0x41300000, 0x00000000, 0x00000000, 0x00000000, 0x41b00000, 0x00000000, 0x00000000, 0x00000000,
+    0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461,
+    0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0200001f, 0x80000000,
+    0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x02000001, 0x80010000, 0xa0000003, 0x03000005,
+    0x80010000, 0x80000000, 0xa0000002, 0x04000004, 0x800f0000, 0x80000000, 0x90e40000, 0xa0000003,
+    0x03000002, 0x800f0000, 0x80e40000, 0xa0000000, 0x03000002, 0x800f0000, 0x80e40000, 0xa0000004,
+    0x02000001, 0x80010001, 0xa0000005, 0x03000002, 0x80010001, 0x80000001, 0xa0000006, 0x03000002,
+    0xe00f0000, 0x80e40000, 0x80000001, 0x0000ffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000000,
+    0x00000000, 0x000000d8, 0x46580200, 0x0023fffe, 0x42415443, 0x0000001c, 0x00000057, 0x46580200,
+    0x00000001, 0x0000001c, 0x20000100, 0x00000054, 0x00000030, 0x00040002, 0x00120001, 0x00000034,
+    0x00000044, 0xab003476, 0x00030000, 0x00010001, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c,
+    0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe,
+    0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846, 0x00000001, 0x10000001, 0x00000001, 0x00000000,
+    0x00000002, 0x00000010, 0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+};
+
+static void test_effect_skip_constants(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    ID3DXEffect *effect;
+    unsigned int passes_count;
+    D3DXVECTOR4 fvect;
+    unsigned int i;
+
+    hr = D3DXCreateEffectEx(device, test_effect_skip_constants_blob, sizeof(test_effect_skip_constants_blob),
+            NULL, NULL, "v3", 0, NULL, &effect, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+    hr = D3DXCreateEffectEx(device, test_effect_skip_constants_blob, sizeof(test_effect_skip_constants_blob),
+            NULL, NULL, "v4", 0, NULL, &effect, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+    hr = D3DXCreateEffectEx(device, test_effect_skip_constants_blob, sizeof(test_effect_skip_constants_blob),
+            NULL, NULL, "v1;v5;v4", 0, NULL, &effect, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+
+    hr = D3DXCreateEffectEx(device, test_effect_skip_constants_blob, sizeof(test_effect_skip_constants_blob),
+            NULL, NULL, " v1#,.+-= &\t\nv2*/!\"'v5 v6[1]", 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    ok(!effect->lpVtbl->IsParameterUsed(effect, "v1", "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+    ok(!effect->lpVtbl->IsParameterUsed(effect, "v2", "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+    ok(effect->lpVtbl->IsParameterUsed(effect, "v3", "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+    ok(effect->lpVtbl->IsParameterUsed(effect, "v4", "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+    ok(!effect->lpVtbl->IsParameterUsed(effect, "v5", "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+    ok(!effect->lpVtbl->IsParameterUsed(effect, "v6", "tech0"),
+            "Unexpected IsParameterUsed result.\n");
+
+    hr = effect->lpVtbl->SetFloat(effect, "v1", 28.0f);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->SetFloat(effect, "v2", 29.0f);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->SetFloat(effect, "v3", 30.0f);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->SetFloat(effect, "v4", 31.0f);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->SetFloat(effect, "v5", 32.0f);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    test_effect_preshader_clear_vconsts(device);
+
+    hr = effect->lpVtbl->Begin(effect, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    fvect.y = fvect.z = fvect.w = 0.0f;
+    fvect.x = 30.0f;
+    test_effect_shared_parameters_compare_vconst(device, 0, &fvect, FALSE);
+    for (i = 1; i < 4; ++i)
+        test_effect_shared_parameters_compare_vconst(device, i, &fvect_filler, FALSE);
+    fvect.x = 31.0f;
+    test_effect_shared_parameters_compare_vconst(device, 4, &fvect, FALSE);
+    for (i = 5; i < 256; ++i)
+        test_effect_shared_parameters_compare_vconst(device, i, &fvect_filler, FALSE);
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    effect->lpVtbl->Release(effect);
+}
+
+#if 0
+vertexshader vs_arr[2] =
+{
+    asm
+    {
+        vs_3_0
+        def c0, 1, 1, 1, 1
+        dcl_position o0
+        mov o0, c0
+    },
+
+    asm
+    {
+        vs_3_sw
+        def c256, 1, 1, 1, 1
+        dcl_position o0
+        mov o0, c256
+    },
+};
+
+int i;
+
+technique tech0
+{
+    pass p0
+    {
+        VertexShader = vs_arr[1];
+    }
+}
+technique tech1
+{
+    pass p0
+    {
+        VertexShader = vs_arr[i];
+    }
+}
+#endif
+static const DWORD test_effect_unsupported_shader_blob[] =
+{
+    0xfeff0901, 0x000000ac, 0x00000000, 0x00000010, 0x00000004, 0x00000020, 0x00000000, 0x00000002,
+    0x00000001, 0x00000002, 0x00000007, 0x615f7376, 0x00007272, 0x00000002, 0x00000000, 0x0000004c,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000002, 0x00000069, 0x00000003,
+    0x00000010, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00003070, 0x00000006,
+    0x68636574, 0x00000030, 0x00000004, 0x00000010, 0x00000004, 0x00000000, 0x00000000, 0x00000000,
+    0x00000003, 0x00003070, 0x00000006, 0x68636574, 0x00000031, 0x00000002, 0x00000002, 0x00000006,
+    0x00000005, 0x00000004, 0x00000018, 0x00000000, 0x00000000, 0x0000002c, 0x00000048, 0x00000000,
+    0x00000000, 0x00000074, 0x00000000, 0x00000001, 0x0000006c, 0x00000000, 0x00000001, 0x00000092,
+    0x00000000, 0x00000058, 0x00000054, 0x000000a0, 0x00000000, 0x00000001, 0x00000098, 0x00000000,
+    0x00000001, 0x00000092, 0x00000000, 0x00000084, 0x00000080, 0x00000002, 0x00000002, 0x00000001,
+    0x00000038, 0xfffe0300, 0x05000051, 0xa00f0000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
+    0x0200001f, 0x80000000, 0xe00f0000, 0x02000001, 0xe00f0000, 0xa0e40000, 0x0000ffff, 0x00000002,
+    0x00000038, 0xfffe03ff, 0x05000051, 0xa00f0100, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
+    0x0200001f, 0x80000000, 0xe00f0000, 0x02000001, 0xe00f0000, 0xa0e40100, 0x0000ffff, 0x00000001,
+    0x00000000, 0xffffffff, 0x00000000, 0x00000002, 0x000000e4, 0x00000008, 0x615f7376, 0x00007272,
+    0x46580200, 0x0023fffe, 0x42415443, 0x0000001c, 0x00000057, 0x46580200, 0x00000001, 0x0000001c,
+    0x00000100, 0x00000054, 0x00000030, 0x00000002, 0x00000001, 0x00000034, 0x00000044, 0xabab0069,
+    0x00020000, 0x00010001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320,
+    0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000,
+    0x000cfffe, 0x434c5846, 0x00000001, 0x10000001, 0x00000001, 0x00000000, 0x00000002, 0x00000000,
+    0x00000000, 0x00000004, 0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff, 0x00000000, 0x00000000,
+    0xffffffff, 0x00000000, 0x00000001, 0x0000000a, 0x615f7376, 0x315b7272, 0x0000005d,
+};
+
+#define TEST_EFFECT_UNSUPPORTED_SHADER_BYTECODE_VS_3_0_POS 81
+#define TEST_EFFECT_UNSUPPORTED_SHADER_BYTECODE_VS_3_0_LEN 14
+
+static void test_effect_unsupported_shader(void)
+{
+    IDirect3DVertexShader9 *vshader;
+    unsigned int passes_count;
+    IDirect3DDevice9 *device;
+    UINT byte_code_size;
+    ID3DXEffect *effect;
+    void *byte_code;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+
+    if (!(device = create_device(&window)))
+        return;
+
+    hr = D3DXCreateEffectEx(device, test_effect_unsupported_shader_blob, sizeof(test_effect_unsupported_shader_blob),
+            NULL, NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->ValidateTechnique(effect, "missing_technique");
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->ValidateTechnique(effect, "tech0");
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->ValidateTechnique(effect, "tech1");
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    effect->lpVtbl->SetInt(effect, "i", 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->ValidateTechnique(effect, "tech1");
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
+    effect->lpVtbl->SetInt(effect, "i", 0);
+    hr = effect->lpVtbl->ValidateTechnique(effect, "tech1");
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->SetTechnique(effect, "tech0");
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->Begin(effect, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(!vshader, "Got non NULL vshader.\n");
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->SetTechnique(effect, "tech1");
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->Begin(effect, &passes_count, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(!!vshader, "Got NULL vshader.\n");
+    hr = IDirect3DVertexShader9_GetFunction(vshader, NULL, &byte_code_size);
+    ok(hr == D3D_OK, "Got result %x.\n", hr);
+    byte_code = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, byte_code_size);
+    hr = IDirect3DVertexShader9_GetFunction(vshader, byte_code, &byte_code_size);
+    ok(hr == D3D_OK, "Got result %x.\n", hr);
+    ok(byte_code_size == TEST_EFFECT_UNSUPPORTED_SHADER_BYTECODE_VS_3_0_LEN * sizeof(DWORD),
+            "Got unexpected byte code size %u.\n", byte_code_size);
+    ok(!memcmp(byte_code,
+            &test_effect_unsupported_shader_blob[TEST_EFFECT_UNSUPPORTED_SHADER_BYTECODE_VS_3_0_POS],
+            byte_code_size), "Incorrect shader selected.\n");
+    HeapFree(GetProcessHeap(), 0, byte_code);
+    IDirect3DVertexShader9_Release(vshader);
+
+    effect->lpVtbl->SetInt(effect, "i", 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->CommitChanges(effect);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
+    ok(hr == D3D_OK, "Got result %x.\n", hr);
+    ok(!vshader, "Got non NULL vshader.\n");
+
+    effect->lpVtbl->Release(effect);
+
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
+#if 0
+vertexshader vs_arr[2];
+
+int i;
+
+technique tech0
+{
+    pass p0
+    {
+        VertexShader = null;
+    }
+}
+technique tech1
+{
+    pass p0
+    {
+        VertexShader = vs_arr[i];
+    }
+}
+#endif
+static const DWORD test_effect_null_shader_blob[] =
+{
+    0xfeff0901, 0x000000b4, 0x00000000, 0x00000010, 0x00000004, 0x00000020, 0x00000000, 0x00000002,
+    0x00000001, 0x00000002, 0x00000007, 0x615f7376, 0x00007272, 0x00000002, 0x00000000, 0x0000004c,
+    0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000002, 0x00000069, 0x00000000,
+    0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000003,
+    0x00003070, 0x00000006, 0x68636574, 0x00000030, 0x00000003, 0x00000010, 0x00000004, 0x00000000,
+    0x00000000, 0x00000000, 0x00000003, 0x00003070, 0x00000006, 0x68636574, 0x00000031, 0x00000002,
+    0x00000002, 0x00000005, 0x00000004, 0x00000004, 0x00000018, 0x00000000, 0x00000000, 0x0000002c,
+    0x00000048, 0x00000000, 0x00000000, 0x0000007c, 0x00000000, 0x00000001, 0x00000074, 0x00000000,
+    0x00000001, 0x00000092, 0x00000000, 0x00000058, 0x00000054, 0x000000a8, 0x00000000, 0x00000001,
+    0x000000a0, 0x00000000, 0x00000001, 0x00000092, 0x00000000, 0x0000008c, 0x00000088, 0x00000002,
+    0x00000001, 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000001, 0x00000000, 0xffffffff,
+    0x00000000, 0x00000002, 0x000000e4, 0x00000008, 0x615f7376, 0x00007272, 0x46580200, 0x0023fffe,
+    0x42415443, 0x0000001c, 0x00000057, 0x46580200, 0x00000001, 0x0000001c, 0x00000100, 0x00000054,
+    0x00000030, 0x00000002, 0x00000001, 0x00000034, 0x00000044, 0xabab0069, 0x00020000, 0x00010001,
+    0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4d007874, 0x6f726369,
+    0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+    0x392e3932, 0x332e3235, 0x00313131, 0x0002fffe, 0x54494c43, 0x00000000, 0x000cfffe, 0x434c5846,
+    0x00000001, 0x10000001, 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000004,
+    0x00000000, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+};
+
+static void test_effect_null_shader(void)
+{
+    IDirect3DDevice9 *device;
+    ID3DXEffect *effect;
+    D3DXPASS_DESC desc;
+    D3DXHANDLE pass;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+
+    /* Creating a fresh device because the existing device can have invalid
+     * render states from previous tests. If IDirect3DDevice9_ValidateDevice()
+     * returns certain error codes, native ValidateTechnique() fails. */
+    if (!(device = create_device(&window)))
+        return;
+
+    hr = D3DXCreateEffectEx(device, test_effect_null_shader_blob,
+            sizeof(test_effect_null_shader_blob), NULL, NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Failed to create effect, hr %#x.\n", hr);
+
+    pass = effect->lpVtbl->GetPass(effect, "tech0", 0);
+    ok(!!pass, "GetPass() failed.\n");
+    hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!desc.pVertexShaderFunction, "Got non NULL vertex function.\n");
+
+    pass = effect->lpVtbl->GetPass(effect, "tech1", 0);
+    ok(!!pass, "GetPass() failed.\n");
+    hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!desc.pVertexShaderFunction, "Got non NULL vertex function.\n");
+
+    hr = effect->lpVtbl->ValidateTechnique(effect, "tech0");
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    effect->lpVtbl->SetInt(effect, "i", 0);
+    ok(hr == D3D_OK, "Failed to set parameter, hr %#x.\n", hr);
+    hr = effect->lpVtbl->ValidateTechnique(effect, "tech1");
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    effect->lpVtbl->SetInt(effect, "i", 1);
+    ok(hr == D3D_OK, "Failed to set parameter, hr %#x.\n", hr);
+    hr = effect->lpVtbl->ValidateTechnique(effect, "tech1");
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    effect->lpVtbl->SetInt(effect, "i", 2);
+    ok(hr == D3D_OK, "Failed to set parameter, hr %#x.\n", hr);
+    hr = effect->lpVtbl->ValidateTechnique(effect, "tech1");
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
+
+    effect->lpVtbl->Release(effect);
+
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
+static void test_effect_clone(void)
+{
+    IDirect3DDevice9 *device, *device2, *device3;
+    ID3DXEffect *effect, *cloned;
+    HWND window, window2;
+    ULONG refcount;
+    HRESULT hr;
+
+    if (!(device = create_device(&window)))
+        return;
+
+    /* D3DXFX_NOT_CLONEABLE */
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, D3DXFX_NOT_CLONEABLE, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->CloneEffect(effect, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+
+    cloned = (void *)0xdeadbeef;
+    hr = effect->lpVtbl->CloneEffect(effect, NULL, &cloned);
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
+    ok(cloned == (void *)0xdeadbeef, "Unexpected effect pointer.\n");
+
+    hr = effect->lpVtbl->CloneEffect(effect, device, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+
+    cloned = (void *)0xdeadbeef;
+    hr = effect->lpVtbl->CloneEffect(effect, device, &cloned);
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
+    ok(cloned == (void *)0xdeadbeef, "Unexpected effect pointer.\n");
+
+    effect->lpVtbl->Release(effect);
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, sizeof(test_effect_preshader_effect_blob),
+            NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->CloneEffect(effect, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+
+    cloned = (void *)0xdeadbeef;
+    hr = effect->lpVtbl->CloneEffect(effect, NULL, &cloned);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+    ok(cloned == (void *)0xdeadbeef, "Unexpected effect pointer.\n");
+
+    hr = effect->lpVtbl->CloneEffect(effect, device, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->CloneEffect(effect, device, &cloned);
+todo_wine
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+if (hr == D3D_OK)
+{
+    ok(cloned != effect, "Expected new effect instance.\n");
+    cloned->lpVtbl->Release(cloned);
+}
+    /* Try with different device. */
+    device2 = create_device(&window2);
+    hr = effect->lpVtbl->CloneEffect(effect, device2, &cloned);
+todo_wine
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+if (hr == D3D_OK)
+{
+    ok(cloned != effect, "Expected new effect instance.\n");
+
+    hr = cloned->lpVtbl->GetDevice(cloned, &device3);
+    ok(hr == S_OK, "Failed to get effect device.\n");
+    ok(device3 == device2, "Unexpected device instance.\n");
+    IDirect3DDevice9_Release(device3);
+
+    cloned->lpVtbl->Release(cloned);
+}
+    IDirect3DDevice9_Release(device2);
+    DestroyWindow(window2);
+    effect->lpVtbl->Release(effect);
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
+static unsigned int get_texture_refcount(IDirect3DTexture9 *iface)
+{
+    IDirect3DTexture9_AddRef(iface);
+    return IDirect3DTexture9_Release(iface);
+}
+
+static void test_refcount(void)
+{
+    IDirect3DTexture9 *texture, *cur_texture, *managed_texture, *sysmem_texture;
+    unsigned int passes_count;
+    IDirect3DDevice9 *device;
+    ID3DXEffect *effect;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+
+    if (!(device = create_device(&window)))
+        return;
+
+    hr = IDirect3DDevice9_CreateTexture(device, 16, 16, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &texture, NULL);
+    ok(hr == D3D_OK, "Failed to create texture, hr %#x.\n", hr);
+
+    hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob,
+            sizeof(test_effect_preshader_effect_blob), NULL, NULL,
+            D3DXFX_DONOTSAVESTATE, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Failed to create effect, hr %#x.\n", hr);
+
+    hr = effect->lpVtbl->SetTexture(effect, "tex1", (IDirect3DBaseTexture9 *)texture);
+    ok(hr == D3D_OK, "Failed to set texture parameter, hr %#x.\n", hr);
+
+    hr = effect->lpVtbl->Begin(effect, &passes_count, D3DXFX_DONOTSAVESTATE);
+    ok(hr == D3D_OK, "Begin() failed, hr %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "BeginPass() failed, hr %#x.\n", hr);
+
+    IDirect3DDevice9_GetTexture(device, 0, (IDirect3DBaseTexture9 **)&cur_texture);
+    ok(cur_texture == texture, "Unexpected current texture %p.\n", cur_texture);
+    IDirect3DTexture9_Release(cur_texture);
+
+    IDirect3DDevice9_SetTexture(device, 0, NULL);
+    effect->lpVtbl->CommitChanges(effect);
+
+    IDirect3DDevice9_GetTexture(device, 0, (IDirect3DBaseTexture9 **)&cur_texture);
+    ok(cur_texture == NULL, "Unexpected current texture %p.\n", cur_texture);
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "EndPass() failed, hr %#x.\n", hr);
+
+    hr = effect->lpVtbl->BeginPass(effect, 0);
+    ok(hr == D3D_OK, "BeginPass() failed, hr %#x.\n", hr);
+
+    IDirect3DDevice9_GetTexture(device, 0, (IDirect3DBaseTexture9 **)&cur_texture);
+    ok(cur_texture == texture, "Unexpected current texture %p.\n", cur_texture);
+    IDirect3DTexture9_Release(cur_texture);
+
+    hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == D3D_OK, "EndPass() failed, hr %#x.\n", hr);
+    hr = effect->lpVtbl->End(effect);
+    ok(hr == D3D_OK, "End() failed, hr %#x.\n", hr);
+
+    IDirect3DDevice9_GetTexture(device, 0, (IDirect3DBaseTexture9 **)&cur_texture);
+    ok(cur_texture == texture, "Unexpected current texture %p.\n", cur_texture);
+    IDirect3DTexture9_Release(cur_texture);
+    refcount = get_texture_refcount(texture);
+    ok(refcount == 2, "Unexpected texture refcount %u.\n", refcount);
+
+    hr = effect->lpVtbl->OnLostDevice(effect);
+    ok(hr == D3D_OK, "OnLostDevice() failed, hr %#x.\n", hr);
+    refcount = get_texture_refcount(texture);
+    ok(refcount == 1, "Unexpected texture refcount %u.\n", refcount);
+
+    hr = IDirect3DDevice9_CreateTexture(device, 16, 16, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED,
+            &managed_texture, NULL);
+    ok(hr == D3D_OK, "Failed to create texture, hr %#x.\n", hr);
+    effect->lpVtbl->SetTexture(effect, "tex1", (IDirect3DBaseTexture9 *)managed_texture);
+
+    refcount = get_texture_refcount(managed_texture);
+    ok(refcount == 2, "Unexpected texture refcount %u.\n", refcount);
+    hr = effect->lpVtbl->OnLostDevice(effect);
+    ok(hr == D3D_OK, "OnLostDevice() failed, hr %#x.\n", hr);
+    refcount = get_texture_refcount(managed_texture);
+    ok(refcount == 2, "Unexpected texture refcount %u.\n", refcount);
+
+    hr = IDirect3DDevice9_CreateTexture(device, 16, 16, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM,
+            &sysmem_texture, NULL);
+    ok(hr == D3D_OK, "Failed to create texture, hr %#x.\n", hr);
+    effect->lpVtbl->SetTexture(effect, "tex1", (IDirect3DBaseTexture9 *)sysmem_texture);
+
+    refcount = get_texture_refcount(managed_texture);
+    ok(refcount == 1, "Unexpected texture refcount %u.\n", refcount);
+    IDirect3DTexture9_Release(managed_texture);
+    refcount = get_texture_refcount(sysmem_texture);
+    ok(refcount == 2, "Unexpected texture refcount %u.\n", refcount);
+    hr = effect->lpVtbl->OnLostDevice(effect);
+    ok(hr == D3D_OK, "OnLostDevice() failed, hr %#x.\n", hr);
+    refcount = get_texture_refcount(sysmem_texture);
+    ok(refcount == 2, "Unexpected texture refcount %u.\n", refcount);
+
+    effect->lpVtbl->Release(effect);
+
+    refcount = get_texture_refcount(sysmem_texture);
+    ok(refcount == 1, "Unexpected texture refcount %u.\n", refcount);
+    IDirect3DTexture9_Release(sysmem_texture);
+
+    IDirect3DDevice9_GetTexture(device, 0, (IDirect3DBaseTexture9 **)&cur_texture);
+    ok(cur_texture == texture, "Unexpected current texture %p.\n", cur_texture);
+    IDirect3DTexture9_Release(cur_texture);
+    refcount = get_texture_refcount(texture);
+    ok(refcount == 1, "Unexpected texture refcount %u.\n", refcount);
+    IDirect3DTexture9_Release(texture);
+
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
+static HRESULT WINAPI d3dxinclude_open(ID3DXInclude *iface, D3DXINCLUDE_TYPE include_type,
+        const char *filename, const void *parent_data, const void **data, UINT *bytes)
+{
+    static const char include1[] =
+        "float4 light;\n"
+        "float4x4 mat;\n"
+        "float4 color;\n"
+        "\n"
+        "struct vs_input\n"
+        "{\n"
+        "    float4 position : POSITION;\n"
+        "    float3 normal : NORMAL;\n"
+        "};\n"
+        "\n"
+        "struct vs_output\n"
+        "{\n"
+        "    float4 position : POSITION;\n"
+        "    float4 diffuse : COLOR;\n"
+        "};\n";
+    static const char include2[] =
+        "#include \"include1.h\"\n"
+        "\n"
+        "vs_output vs_main(const vs_input v)\n"
+        "{\n"
+        "    vs_output o;\n"
+        "    const float4 scaled_color = 0.5 * color;\n"
+        "\n"
+        "    o.position = mul(v.position, mat);\n"
+        "    o.diffuse = dot((float3)light, v.normal) * scaled_color;\n"
+        "\n"
+        "    return o;\n"
+        "}\n";
+    static const char effect2[] =
+        "#include \"include\\include2.h\"\n"
+        "\n"
+        "technique t\n"
+        "{\n"
+        "    pass p\n"
+        "    {\n"
+        "        VertexShader = compile vs_2_0 vs_main();\n"
+        "    }\n"
+        "}\n";
+    char *buffer;
+
+    trace("filename %s.\n", filename);
+    trace("parent_data %p: %s.\n", parent_data, parent_data ? (char *)parent_data : "(null)");
+
+    if (!strcmp(filename, "effect2.fx"))
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(effect2));
+        memcpy(buffer, effect2, sizeof(effect2));
+        *bytes = sizeof(effect2);
+        ok(!parent_data, "Unexpected parent_data value.\n");
+    }
+    else if (!strcmp(filename, "include1.h"))
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(include1));
+        memcpy(buffer, include1, sizeof(include1));
+        *bytes = sizeof(include1);
+        ok(!strncmp(parent_data, include2, strlen(include2)), "Unexpected parent_data value.\n");
+    }
+    else if (!strcmp(filename, "include\\include2.h"))
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(include2));
+        memcpy(buffer, include2, sizeof(include2));
+        *bytes = sizeof(include2);
+        todo_wine ok(parent_data && !strncmp(parent_data, effect2, strlen(effect2)),
+                "unexpected parent_data value.\n");
+    }
+    else
+    {
+        ok(0, "Unexpected #include for file %s.\n", filename);
+        return D3DERR_INVALIDCALL;
+    }
+    *data = buffer;
+    return S_OK;
+}
+
+static HRESULT WINAPI d3dxinclude_close(ID3DXInclude *iface, const void *data)
+{
+    HeapFree(GetProcessHeap(), 0, (void *)data);
+    return S_OK;
+}
+
+static const struct ID3DXIncludeVtbl d3dxinclude_vtbl =
+{
+    d3dxinclude_open,
+    d3dxinclude_close
+};
+
+struct d3dxinclude
+{
+    ID3DXInclude ID3DXInclude_iface;
+};
+
+static void test_create_effect_from_file(void)
+{
+    static const char effect1[] =
+        "float4 light;\n"
+        "float4x4 mat;\n"
+        "float4 color;\n"
+        "\n"
+        "struct vs_input\n"
+        "{\n"
+        "    float4 position : POSITION;\n"
+        "    float3 normal : NORMAL;\n"
+        "};\n"
+        "\n"
+        "struct vs_output\n"
+        "{\n"
+        "    float4 position : POSITION;\n"
+        "    float4 diffuse : COLOR;\n"
+        "};\n"
+        "\n"
+        "vs_output vs_main(const vs_input v)\n"
+        "{\n"
+        "    vs_output o;\n"
+        "    const float4 scaled_color = 0.5 * color;\n"
+        "\n"
+        "    o.position = mul(v.position, mat);\n"
+        "    o.diffuse = dot((float3)light, v.normal) * scaled_color;\n"
+        "\n"
+        "    return o;\n"
+        "}\n"
+        "\n"
+        "technique t\n"
+        "{\n"
+        "    pass p\n"
+        "    {\n"
+        "        VertexShader = compile vs_2_0 vs_main();\n"
+        "    }\n"
+        "}\n";
+    static const char include1[] =
+        "float4 light;\n"
+        "float4x4 mat;\n"
+        "float4 color;\n"
+        "\n"
+        "struct vs_input\n"
+        "{\n"
+        "    float4 position : POSITION;\n"
+        "    float3 normal : NORMAL;\n"
+        "};\n"
+        "\n"
+        "struct vs_output\n"
+        "{\n"
+        "    float4 position : POSITION;\n"
+        "    float4 diffuse : COLOR;\n"
+        "};\n";
+    static const char include1_wrong[] =
+        "#error \"wrong include\"\n";
+    static const char include2[] =
+        "#include \"include1.h\"\n"
+        "\n"
+        "vs_output vs_main(const vs_input v)\n"
+        "{\n"
+        "    vs_output o;\n"
+        "    const float4 scaled_color = 0.5 * color;\n"
+        "\n"
+        "    o.position = mul(v.position, mat);\n"
+        "    o.diffuse = dot((float3)light, v.normal) * scaled_color;\n"
+        "\n"
+        "    return o;\n"
+        "}\n";
+    static const char effect2[] =
+        "#include \"include\\include2.h\"\n"
+        "\n"
+        "technique t\n"
+        "{\n"
+        "    pass p\n"
+        "    {\n"
+        "        VertexShader = compile vs_2_0 vs_main();\n"
+        "    }\n"
+        "}\n";
+    static const WCHAR effect1_filename_w[] = {'e','f','f','e','c','t','1','.','f','x',0};
+    static const WCHAR effect2_filename_w[] = {'e','f','f','e','c','t','2','.','f','x',0};
+    WCHAR effect_path_w[MAX_PATH], filename_w[MAX_PATH];
+    char effect_path[MAX_PATH], filename[MAX_PATH];
+    D3DPRESENT_PARAMETERS present_parameters = {0};
+    unsigned int filename_size;
+    struct d3dxinclude include;
+    IDirect3DDevice9 *device;
+    ID3DXBuffer *messages;
+    ID3DXEffect *effect;
+    IDirect3D9 *d3d;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+
+    if (!(window = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Failed to create window.\n");
+        return;
+    }
+    if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION)))
+    {
+        skip("Failed to create IDirect3D9 object.\n");
+        DestroyWindow(window);
+        return;
+    }
+    present_parameters.Windowed = TRUE;
+    present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
+            D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_parameters, &device);
+    if (FAILED(hr))
+    {
+        skip("Failed to create IDirect3DDevice9 object, hr %#x.\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(window);
+        return;
+    }
+
+    if (!create_file("effect1.fx", effect1, sizeof(effect1) - 1, filename))
+    {
+        skip("Couldn't create temporary file, skipping test.\n");
+        return;
+    }
+
+    filename_size = strlen(filename);
+    filename_size -= sizeof("effect1.fx") - 1;
+    memcpy(effect_path, filename, filename_size);
+    effect_path[filename_size] = 0;
+    MultiByteToWideChar(CP_ACP, 0, effect_path, -1, effect_path_w, ARRAY_SIZE(effect_path_w));
+
+    create_directory("include");
+    create_file("effect2.fx", effect2, sizeof(effect2) - 1, NULL);
+    create_file("include\\include1.h", include1, sizeof(include1) - 1, NULL);
+    create_file("include\\include2.h", include2, sizeof(include2) - 1, NULL);
+    create_file("include1.h", include1_wrong, sizeof(include1_wrong) - 1, NULL);
+
+    lstrcpyW(filename_w, effect_path_w);
+    lstrcatW(filename_w, effect1_filename_w);
+    effect = NULL;
+    messages = NULL;
+    hr = D3DXCreateEffectFromFileExW(device, filename_w, NULL, NULL, NULL,
+            0, NULL, &effect, &messages);
+    todo_wine ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr);
+    if (messages)
+    {
+        trace("D3DXCreateEffectFromFileExW messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if (effect)
+        effect->lpVtbl->Release(effect);
+
+    lstrcpyW(filename_w, effect_path_w);
+    lstrcatW(filename_w, effect2_filename_w);
+    effect = NULL;
+    messages = NULL;
+    /* This is apparently broken on native, it ends up using the wrong include. */
+    hr = D3DXCreateEffectFromFileExW(device, filename_w, NULL, NULL, NULL,
+            0, NULL, &effect, &messages);
+    todo_wine ok(hr == E_FAIL, "Unexpected error, hr %#x.\n", hr);
+    if (messages)
+    {
+        trace("D3DXCreateEffectFromFileExW messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+    if (effect)
+        effect->lpVtbl->Release(effect);
+
+    delete_file("effect1.fx");
+    delete_file("effect2.fx");
+    delete_file("include\\include1.h");
+    delete_file("include\\include2.h");
+    delete_file("include2.h");
+    delete_directory("include");
+
+    lstrcpyW(filename_w, effect2_filename_w);
+    effect = NULL;
+    messages = NULL;
+    include.ID3DXInclude_iface.lpVtbl = &d3dxinclude_vtbl;
+    /* This is actually broken in native d3dx9 (manually tried multiple
+     * versions, all are affected). For reference, the message printed below
+     * is "ID3DXEffectCompiler: There were no techniques" */
+    hr = D3DXCreateEffectFromFileExW(device, filename_w, NULL, &include.ID3DXInclude_iface, NULL,
+            0, NULL, &effect, &messages);
+    todo_wine ok(hr == E_FAIL, "D3DXInclude test failed with error %#x.\n", hr);
+    if (messages)
+    {
+        trace("D3DXCreateEffectFromFileExW messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
+        ID3DXBuffer_Release(messages);
+    }
+
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    IDirect3D9_Release(d3d);
+    DestroyWindow(window);
+}
+
+#if 0
+technique tech0
+{
+    pass p0
+    {
+        LightEnable[0] = FALSE;
+        FogEnable = FALSE;
+    }
+}
+technique tech1
+{
+    pass p0
+    {
+        LightEnable[0] = TRUE;
+        FogEnable = TRUE;
+    }
+}
+#endif
+static const DWORD test_two_techniques_blob[] =
+{
+    0xfeff0901, 0x000000ac, 0x00000000, 0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000000,
+    0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000000,
+    0x00000000, 0x00000001, 0x00000001, 0x00000003, 0x00003070, 0x00000006, 0x68636574, 0x00000030,
+    0x00000001, 0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001,
+    0x00000001, 0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001,
+    0x00000003, 0x00003070, 0x00000006, 0x68636574, 0x00000031, 0x00000000, 0x00000002, 0x00000002,
+    0x00000001, 0x0000004c, 0x00000000, 0x00000001, 0x00000044, 0x00000000, 0x00000002, 0x00000091,
+    0x00000000, 0x00000008, 0x00000004, 0x0000000e, 0x00000000, 0x00000028, 0x00000024, 0x000000a0,
+    0x00000000, 0x00000001, 0x00000098, 0x00000000, 0x00000002, 0x00000091, 0x00000000, 0x0000005c,
+    0x00000058, 0x0000000e, 0x00000000, 0x0000007c, 0x00000078, 0x00000000, 0x00000000,
+};
+
+static void test_effect_find_next_valid_technique(void)
+{
+    D3DPRESENT_PARAMETERS present_parameters = {0};
+    IDirect3DDevice9 *device;
+    D3DXTECHNIQUE_DESC desc;
+    ID3DXEffect *effect;
+    IDirect3D9 *d3d;
+    D3DXHANDLE tech;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+
+    if (!(window = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Failed to create window.\n");
+        return;
+    }
+    if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION)))
+    {
+        skip("Failed to create IDirect3D9 object.\n");
+        DestroyWindow(window);
+        return;
+    }
+    present_parameters.Windowed = TRUE;
+    present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
+            D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_parameters, &device);
+    if (FAILED(hr))
+    {
+        skip("Failed to create IDirect3DDevice9 object, hr %#x.\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = D3DXCreateEffectEx(device, test_two_techniques_blob, sizeof(test_two_techniques_blob),
+            NULL, NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, NULL, &tech);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->GetTechniqueDesc(effect, tech, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!strcmp(desc.Name, "tech0"), "Got unexpected technique %s.\n", desc.Name);
+
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, tech, &tech);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->GetTechniqueDesc(effect, tech, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!strcmp(desc.Name, "tech1"), "Got unexpected technique %s.\n", desc.Name);
+
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, tech, &tech);
+    ok(hr == S_FALSE, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->GetTechniqueDesc(effect, tech, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!strcmp(desc.Name, "tech0"), "Got unexpected technique %s.\n", desc.Name);
+
+    effect->lpVtbl->Release(effect);
+
+    hr = D3DXCreateEffectEx(device, test_effect_unsupported_shader_blob, sizeof(test_effect_unsupported_shader_blob),
+            NULL, NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, NULL, &tech);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->GetTechniqueDesc(effect, tech, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!strcmp(desc.Name, "tech1"), "Got unexpected technique %s.\n", desc.Name);
+
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, tech, &tech);
+    ok(hr == S_FALSE, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->GetTechniqueDesc(effect, tech, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!strcmp(desc.Name, "tech0"), "Got unexpected technique %s.\n", desc.Name);
+
+    effect->lpVtbl->SetInt(effect, "i", 1);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+
+    tech = (D3DXHANDLE)0xdeadbeef;
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, NULL, &tech);
+    ok(hr == S_FALSE, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->GetTechniqueDesc(effect, tech, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!strcmp(desc.Name, "tech0"), "Got unexpected technique %s.\n", desc.Name);
+
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, tech, &tech);
+    ok(hr == S_FALSE, "Got result %#x.\n", hr);
+
+    effect->lpVtbl->SetInt(effect, "i", 0);
+
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, tech, &tech);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    hr = effect->lpVtbl->GetTechniqueDesc(effect, tech, &desc);
+    ok(hr == D3D_OK, "Got result %#x.\n", hr);
+    ok(!strcmp(desc.Name, "tech1"), "Got unexpected technique %s.\n", desc.Name);
+
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, tech, &tech);
+    ok(hr == S_FALSE, "Got result %#x.\n", hr);
+
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, "nope", &tech);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
+
+    effect->lpVtbl->Release(effect);
+
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    IDirect3D9_Release(d3d);
+    DestroyWindow(window);
+}
+
+START_TEST(effect)
+{
+    IDirect3DDevice9 *device;
+    ULONG refcount;
+    HWND wnd;
+
+    if (!(device = create_device(&wnd)))
+        return;
+
+    test_create_effect_and_pool(device);
+    test_create_effect_compiler();
+    test_effect_parameter_value(device);
+    test_effect_setvalue_object(device);
+    test_effect_variable_names(device);
+    test_effect_compilation_errors(device);
+    test_effect_states(device);
+    test_effect_preshader(device);
+    test_effect_preshader_ops(device);
+    test_effect_isparameterused(device);
+    test_effect_out_of_bounds_selector(device);
+    test_effect_commitchanges(device);
+    test_effect_preshader_relative_addressing(device);
+    test_effect_state_manager(device);
+    test_cross_effect_handle(device);
+    test_effect_shared_parameters(device);
+    test_effect_large_address_aware_flag(device);
+    test_effect_get_pass_desc(device);
+    test_effect_skip_constants(device);
+
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    DestroyWindow(wnd);
+
+    test_effect_unsupported_shader();
+    test_effect_null_shader();
+    test_effect_clone();
+    test_refcount();
+    test_create_effect_from_file();
+    test_effect_find_next_valid_technique();
+}
diff --git a/modules/rostests/winetests/d3dx9_36/line.c b/modules/rostests/winetests/d3dx9_36/line.c
new file mode 100644 (file)
index 0000000..ae8d07e
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2010 Christian Costa
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "wine/test.h"
+#include "d3dx9.h"
+
+#define admitted_error 0.0001f
+
+#define relative_error(exp, out) ((exp == 0.0f) ? fabs(exp - out) : (fabs(1.0f - out/ exp) ))
+
+static inline BOOL compare_matrix(const D3DXMATRIX *m1, const D3DXMATRIX *m2)
+{
+    int i, j;
+
+    for (i = 0; i < 4; ++i)
+    {
+        for (j = 0; j < 4; ++j)
+        {
+            if (relative_error(U(*m1).m[i][j], U(*m2).m[i][j]) > admitted_error)
+                return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+#define expect_mat(expectedmat, gotmat) \
+do { \
+    const D3DXMATRIX *__m1 = (expectedmat); \
+    const D3DXMATRIX *__m2 = (gotmat); \
+    ok(compare_matrix(__m1, __m2), "Expected matrix=\n(%f,%f,%f,%f\n %f,%f,%f,%f\n %f,%f,%f,%f\n %f,%f,%f,%f\n)\n\n" \
+            "Got matrix=\n(%f,%f,%f,%f\n %f,%f,%f,%f\n %f,%f,%f,%f\n %f,%f,%f,%f)\n", \
+            U(*__m1).m[0][0], U(*__m1).m[0][1], U(*__m1).m[0][2], U(*__m1).m[0][3], \
+            U(*__m1).m[1][0], U(*__m1).m[1][1], U(*__m1).m[1][2], U(*__m1).m[1][3], \
+            U(*__m1).m[2][0], U(*__m1).m[2][1], U(*__m1).m[2][2], U(*__m1).m[2][3], \
+            U(*__m1).m[3][0], U(*__m1).m[3][1], U(*__m1).m[3][2], U(*__m1).m[3][3], \
+            U(*__m2).m[0][0], U(*__m2).m[0][1], U(*__m2).m[0][2], U(*__m2).m[0][3], \
+            U(*__m2).m[1][0], U(*__m2).m[1][1], U(*__m2).m[1][2], U(*__m2).m[1][3], \
+            U(*__m2).m[2][0], U(*__m2).m[2][1], U(*__m2).m[2][2], U(*__m2).m[2][3], \
+            U(*__m2).m[3][0], U(*__m2).m[3][1], U(*__m2).m[3][2], U(*__m2).m[3][3]); \
+} while(0)
+
+static void test_create_line(IDirect3DDevice9* device)
+{
+    HRESULT hr;
+    ID3DXLine *line = NULL;
+    struct IDirect3DDevice9 *return_device;
+    D3DXMATRIX world, identity, result;
+    FLOAT r11, r12, r13, r14;
+    ULONG ref;
+
+    /* Arbitrary values for matrix tests. */
+    r11 = 0.1421; r12 = 0.2114; r13 = 0.8027; r14 = 0.4587;
+
+    hr = D3DXCreateLine(NULL, &line);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3D_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateLine(device, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3D_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateLine(device, &line);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+    if (FAILED(hr))
+    {
+        return;
+    }
+
+    hr = ID3DXLine_GetDevice(line, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3D_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = ID3DXLine_GetDevice(line, &return_device);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    ok(return_device == device, "Expected line device %p, got %p\n", device, return_device);
+
+    D3DXMatrixIdentity(&world);
+    D3DXMatrixIdentity(&identity);
+    S(U(world))._11 = r11; S(U(world))._12 = r12; S(U(world))._13 = r13; S(U(world))._14 = r14;
+
+    hr = IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &world);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+
+    hr = ID3DXLine_Begin(line);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+
+    hr = IDirect3DDevice9_GetTransform(device, D3DTS_WORLD, &result);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    expect_mat(&identity, &result);
+
+    hr = ID3DXLine_End(line);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+
+    hr = IDirect3DDevice9_GetTransform(device, D3DTS_WORLD, &result);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    expect_mat(&world, &result);
+
+    IDirect3DDevice9_Release(return_device);
+
+    ref = ID3DXLine_Release(line);
+    ok(ref == 0, "Got %x references to line %p, expected 0\n", ref, line);
+}
+
+START_TEST(line)
+{
+    HWND wnd;
+    IDirect3D9* d3d;
+    IDirect3DDevice9* device;
+    D3DPRESENT_PARAMETERS d3dpp;
+    HRESULT hr;
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window\n");
+        return;
+    }
+    if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION)))
+    {
+        skip("Couldn't create IDirect3D9 object\n");
+        DestroyWindow(wnd);
+        return;
+    }
+
+    ZeroMemory(&d3dpp, sizeof(d3dpp));
+    d3dpp.Windowed = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
+    if (FAILED(hr)) {
+        skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    test_create_line(device);
+
+    IDirect3DDevice9_Release(device);
+    IDirect3D9_Release(d3d);
+    DestroyWindow(wnd);
+}
diff --git a/modules/rostests/winetests/d3dx9_36/math.c b/modules/rostests/winetests/d3dx9_36/math.c
new file mode 100644 (file)
index 0000000..5ce5b2b
--- /dev/null
@@ -0,0 +1,3687 @@
+/*
+ * Copyright 2008 David Adam
+ * Copyright 2008 Luis Busquets
+ * Copyright 2008 Philip Nilsson
+ * Copyright 2008 Henri Verbeet
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "wine/test.h"
+#include "d3dx9.h"
+#include <math.h>
+
+static BOOL compare_float(float f, float g, unsigned int ulps)
+{
+    int x = *(int *)&f;
+    int y = *(int *)&g;
+
+    if (x < 0)
+        x = INT_MIN - x;
+    if (y < 0)
+        y = INT_MIN - y;
+
+    if (abs(x - y) > ulps)
+        return FALSE;
+
+    return TRUE;
+}
+
+static BOOL compare_vec2(const D3DXVECTOR2 *v1, const D3DXVECTOR2 *v2, unsigned int ulps)
+{
+    return compare_float(v1->x, v2->x, ulps) && compare_float(v1->y, v2->y, ulps);
+}
+
+static BOOL compare_vec3(const D3DXVECTOR3 *v1, const D3DXVECTOR3 *v2, unsigned int ulps)
+{
+    return compare_float(v1->x, v2->x, ulps)
+            && compare_float(v1->y, v2->y, ulps)
+            && compare_float(v1->z, v2->z, ulps);
+}
+
+static BOOL compare_vec4(const D3DXVECTOR4 *v1, const D3DXVECTOR4 *v2, unsigned int ulps)
+{
+    return compare_float(v1->x, v2->x, ulps)
+            && compare_float(v1->y, v2->y, ulps)
+            && compare_float(v1->z, v2->z, ulps)
+            && compare_float(v1->w, v2->w, ulps);
+}
+
+static BOOL compare_color(const D3DXCOLOR *c1, const D3DXCOLOR *c2, unsigned int ulps)
+{
+    return compare_float(c1->r, c2->r, ulps)
+            && compare_float(c1->g, c2->g, ulps)
+            && compare_float(c1->b, c2->b, ulps)
+            && compare_float(c1->a, c2->a, ulps);
+}
+
+static BOOL compare_plane(const D3DXPLANE *p1, const D3DXPLANE *p2, unsigned int ulps)
+{
+    return compare_float(p1->a, p2->a, ulps)
+            && compare_float(p1->b, p2->b, ulps)
+            && compare_float(p1->c, p2->c, ulps)
+            && compare_float(p1->d, p2->d, ulps);
+}
+
+static BOOL compare_quaternion(const D3DXQUATERNION *q1, const D3DXQUATERNION *q2, unsigned int ulps)
+{
+    return compare_float(q1->x, q2->x, ulps)
+            && compare_float(q1->y, q2->y, ulps)
+            && compare_float(q1->z, q2->z, ulps)
+            && compare_float(q1->w, q2->w, ulps);
+}
+
+static BOOL compare_matrix(const D3DXMATRIX *m1, const D3DXMATRIX *m2, unsigned int ulps)
+{
+    unsigned int i, j;
+
+    for (i = 0; i < 4; ++i)
+    {
+        for (j = 0; j < 4; ++j)
+        {
+            if (!compare_float(U(*m1).m[i][j], U(*m2).m[i][j], ulps))
+                return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+#define expect_vec2(expected, vector, ulps) expect_vec2_(__LINE__, expected, vector, ulps)
+static void expect_vec2_(unsigned int line, const D3DXVECTOR2 *expected, const D3DXVECTOR2 *vector, unsigned int ulps)
+{
+    BOOL equal = compare_vec2(expected, vector, ulps);
+    ok_(__FILE__, line)(equal,
+            "Got unexpected vector {%.8e, %.8e}, expected {%.8e, %.8e}.\n",
+            vector->x, vector->y, expected->x, expected->y);
+}
+
+#define expect_vec3(expected, vector, ulps) expect_vec3_(__LINE__, expected, vector, ulps)
+static void expect_vec3_(unsigned int line, const D3DXVECTOR3 *expected, const D3DXVECTOR3 *vector, unsigned int ulps)
+{
+    BOOL equal = compare_vec3(expected, vector, ulps);
+    ok_(__FILE__, line)(equal,
+            "Got unexpected vector {%.8e, %.8e, %.8e}, expected {%.8e, %.8e, %.8e}.\n",
+            vector->x, vector->y, vector->z, expected->x, expected->y, expected->z);
+}
+
+#define expect_vec4(expected, vector, ulps) expect_vec4_(__LINE__, expected, vector, ulps)
+static void expect_vec4_(unsigned int line, const D3DXVECTOR4 *expected, const D3DXVECTOR4 *vector, unsigned int ulps)
+{
+    BOOL equal = compare_vec4(expected, vector, ulps);
+    ok_(__FILE__, line)(equal,
+            "Got unexpected vector {%.8e, %.8e, %.8e, %.8e}, expected {%.8e, %.8e, %.8e, %.8e}.\n",
+            vector->x, vector->y, vector->z, vector->w, expected->x, expected->y, expected->z, expected->w);
+}
+
+#define expect_color(expected, color, ulps) expect_color_(__LINE__, expected, color, ulps)
+static void expect_color_(unsigned int line, const D3DXCOLOR *expected, const D3DXCOLOR *color, unsigned int ulps)
+{
+    BOOL equal = compare_color(expected, color, ulps);
+    ok_(__FILE__, line)(equal,
+            "Got unexpected color {%.8e, %.8e, %.8e, %.8e}, expected {%.8e, %.8e, %.8e, %.8e}.\n",
+            color->r, color->g, color->b, color->a, expected->r, expected->g, expected->b, expected->a);
+}
+
+#define expect_plane(expected, plane, ulps) expect_plane_(__LINE__, expected, plane, ulps)
+static void expect_plane_(unsigned int line, const D3DXPLANE *expected, const D3DXPLANE *plane, unsigned int ulps)
+{
+    BOOL equal = compare_plane(expected, plane, ulps);
+    ok_(__FILE__, line)(equal,
+            "Got unexpected plane {%.8e, %.8e, %.8e, %.8e}, expected {%.8e, %.8e, %.8e, %.8e}.\n",
+            plane->a, plane->b, plane->c, plane->d, expected->a, expected->b, expected->c, expected->d);
+}
+
+#define expect_quaternion(expected, quaternion, ulps) expect_quaternion_(__LINE__, expected, quaternion, ulps)
+static void expect_quaternion_(unsigned int line, const D3DXQUATERNION *expected,
+        const D3DXQUATERNION *quaternion, unsigned int ulps)
+{
+    BOOL equal = compare_quaternion(expected, quaternion, ulps);
+    ok_(__FILE__, line)(equal,
+            "Got unexpected quaternion {%.8e, %.8e, %.8e, %.8e}, expected {%.8e, %.8e, %.8e, %.8e}.\n",
+            quaternion->x, quaternion->y, quaternion->z, quaternion->w,
+            expected->x, expected->y, expected->z, expected->w);
+}
+
+#define expect_matrix(expected, matrix, ulps) expect_matrix_(__LINE__, expected, matrix, ulps)
+static void expect_matrix_(unsigned int line, const D3DXMATRIX *expected, const D3DXMATRIX *matrix, unsigned int ulps)
+{
+    BOOL equal = compare_matrix(expected, matrix, ulps);
+    ok_(__FILE__, line)(equal,
+            "Got unexpected matrix {%.8e, %.8e, %.8e, %.8e, %.8e, %.8e, %.8e, %.8e, "
+            "%.8e, %.8e, %.8e, %.8e, %.8e, %.8e, %.8e, %.8e}, "
+            "expected {%.8e, %.8e, %.8e, %.8e, %.8e, %.8e, %.8e, %.8e, "
+            "%.8e, %.8e, %.8e, %.8e, %.8e, %.8e, %.8e, %.8e}.\n",
+            U(*matrix).m[0][0], U(*matrix).m[0][1], U(*matrix).m[0][2], U(*matrix).m[0][3],
+            U(*matrix).m[1][0], U(*matrix).m[1][1], U(*matrix).m[1][2], U(*matrix).m[1][3],
+            U(*matrix).m[2][0], U(*matrix).m[2][1], U(*matrix).m[2][2], U(*matrix).m[2][3],
+            U(*matrix).m[3][0], U(*matrix).m[3][1], U(*matrix).m[3][2], U(*matrix).m[3][3],
+            U(*expected).m[0][0], U(*expected).m[0][1], U(*expected).m[0][2], U(*expected).m[0][3],
+            U(*expected).m[1][0], U(*expected).m[1][1], U(*expected).m[1][2], U(*expected).m[1][3],
+            U(*expected).m[2][0], U(*expected).m[2][1], U(*expected).m[2][2], U(*expected).m[2][3],
+            U(*expected).m[3][0], U(*expected).m[3][1], U(*expected).m[3][2], U(*expected).m[3][3]);
+}
+
+#define expect_vec4_array(count, expected, vector, ulps) expect_vec4_array_(__LINE__, count, expected, vector, ulps)
+static void expect_vec4_array_(unsigned int line, unsigned int count, const D3DXVECTOR4 *expected,
+        const D3DXVECTOR4 *vector, unsigned int ulps)
+{
+    BOOL equal;
+    unsigned int i;
+
+    for (i = 0; i < count; ++i)
+    {
+        equal = compare_vec4(&expected[i], &vector[i], ulps);
+        ok_(__FILE__, line)(equal,
+                "Got unexpected vector {%.8e, %.8e, %.8e, %.8e} at index %u, expected {%.8e, %.8e, %.8e, %.8e}.\n",
+                vector[i].x, vector[i].y, vector[i].z, vector[i].w, i,
+                expected[i].x, expected[i].y, expected[i].z, expected[i].w);
+        if (!equal)
+            break;
+    }
+}
+
+static void set_matrix(D3DXMATRIX* mat,
+        float m00, float m01, float m02, float m03,
+        float m10, float m11, float m12, float m13,
+        float m20, float m21, float m22, float m23,
+        float m30, float m31, float m32, float m33)
+{
+    U(mat)->m[0][0] = m00; U(mat)->m[0][1] = m01; U(mat)->m[0][2] = m02; U(mat)->m[0][3] = m03;
+    U(mat)->m[1][0] = m10; U(mat)->m[1][1] = m11; U(mat)->m[1][2] = m12; U(mat)->m[1][3] = m13;
+    U(mat)->m[2][0] = m20; U(mat)->m[2][1] = m21; U(mat)->m[2][2] = m22; U(mat)->m[2][3] = m23;
+    U(mat)->m[3][0] = m30; U(mat)->m[3][1] = m31; U(mat)->m[3][2] = m32; U(mat)->m[3][3] = m33;
+}
+
+static void D3DXColorTest(void)
+{
+    D3DXCOLOR color, color1, color2, expected, got;
+    LPD3DXCOLOR funcpointer;
+    FLOAT scale;
+
+    color.r = 0.2f; color.g = 0.75f; color.b = 0.41f; color.a = 0.93f;
+    color1.r = 0.6f; color1.g = 0.55f; color1.b = 0.23f; color1.a = 0.82f;
+    color2.r = 0.3f; color2.g = 0.5f; color2.b = 0.76f; color2.a = 0.11f;
+
+    scale = 0.3f;
+
+/*_______________D3DXColorAdd________________*/
+    expected.r = 0.9f; expected.g = 1.05f; expected.b = 0.99f, expected.a = 0.93f;
+    D3DXColorAdd(&got,&color1,&color2);
+    expect_color(&expected, &got, 1);
+    /* Test the NULL case */
+    funcpointer = D3DXColorAdd(&got,NULL,&color2);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXColorAdd(NULL,NULL,&color2);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXColorAdd(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXColorAdjustContrast______*/
+    expected.r = 0.41f; expected.g = 0.575f; expected.b = 0.473f, expected.a = 0.93f;
+    D3DXColorAdjustContrast(&got,&color,scale);
+    expect_color(&expected, &got, 0);
+
+/*_______________D3DXColorAdjustSaturation______*/
+    expected.r = 0.486028f; expected.g = 0.651028f; expected.b = 0.549028f, expected.a = 0.93f;
+    D3DXColorAdjustSaturation(&got,&color,scale);
+    expect_color(&expected, &got, 16);
+
+/*_______________D3DXColorLerp________________*/
+    expected.r = 0.32f; expected.g = 0.69f; expected.b = 0.356f; expected.a = 0.897f;
+    D3DXColorLerp(&got,&color,&color1,scale);
+    expect_color(&expected, &got, 0);
+    /* Test the NULL case */
+    funcpointer = D3DXColorLerp(&got,NULL,&color1,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXColorLerp(NULL,NULL,&color1,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXColorLerp(NULL,NULL,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXColorModulate________________*/
+    expected.r = 0.18f; expected.g = 0.275f; expected.b = 0.1748f; expected.a = 0.0902f;
+    D3DXColorModulate(&got,&color1,&color2);
+    expect_color(&expected, &got, 0);
+    /* Test the NULL case */
+    funcpointer = D3DXColorModulate(&got,NULL,&color2);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXColorModulate(NULL,NULL,&color2);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXColorModulate(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXColorNegative________________*/
+    expected.r = 0.8f; expected.g = 0.25f; expected.b = 0.59f; expected.a = 0.93f;
+    D3DXColorNegative(&got,&color);
+    expect_color(&expected, &got, 1);
+    /* Test the greater than 1 case */
+    color1.r = 0.2f; color1.g = 1.75f; color1.b = 0.41f; color1.a = 0.93f;
+    expected.r = 0.8f; expected.g = -0.75f; expected.b = 0.59f; expected.a = 0.93f;
+    D3DXColorNegative(&got,&color1);
+    expect_color(&expected, &got, 1);
+    /* Test the negative case */
+    color1.r = 0.2f; color1.g = -0.75f; color1.b = 0.41f; color1.a = 0.93f;
+    expected.r = 0.8f; expected.g = 1.75f; expected.b = 0.59f; expected.a = 0.93f;
+    D3DXColorNegative(&got,&color1);
+    expect_color(&expected, &got, 1);
+    /* Test the NULL case */
+    funcpointer = D3DXColorNegative(&got,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXColorNegative(NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXColorScale________________*/
+    expected.r = 0.06f; expected.g = 0.225f; expected.b = 0.123f; expected.a = 0.279f;
+    D3DXColorScale(&got,&color,scale);
+    expect_color(&expected, &got, 1);
+    /* Test the NULL case */
+    funcpointer = D3DXColorScale(&got,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXColorScale(NULL,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXColorSubtract_______________*/
+    expected.r = -0.1f; expected.g = 0.25f; expected.b = -0.35f, expected.a = 0.82f;
+    D3DXColorSubtract(&got,&color,&color2);
+    expect_color(&expected, &got, 1);
+    /* Test the NULL case */
+    funcpointer = D3DXColorSubtract(&got,NULL,&color2);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXColorSubtract(NULL,NULL,&color2);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXColorSubtract(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+}
+
+static void D3DXFresnelTest(void)
+{
+    float fresnel;
+    BOOL equal;
+
+    fresnel = D3DXFresnelTerm(0.5f, 1.5f);
+    equal = compare_float(fresnel, 8.91867128e-02f, 1);
+    ok(equal, "Got unexpected Fresnel term %.8e.\n", fresnel);
+}
+
+static void D3DXMatrixTest(void)
+{
+    D3DXMATRIX expectedmat, gotmat, mat, mat2, mat3;
+    BOOL expected, got, equal;
+    float angle, determinant;
+    D3DXMATRIX *funcpointer;
+    D3DXPLANE plane;
+    D3DXQUATERNION q, r;
+    D3DXVECTOR3 at, axis, eye, last;
+    D3DXVECTOR4 light;
+
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = 10.0f; U(mat).m[1][1] = 20.0f; U(mat).m[2][2] = 30.0f;
+    U(mat).m[3][3] = -40.0f;
+
+    U(mat2).m[0][0] = 1.0f; U(mat2).m[1][0] = 2.0f; U(mat2).m[2][0] = 3.0f;
+    U(mat2).m[3][0] = 4.0f; U(mat2).m[0][1] = 5.0f; U(mat2).m[1][1] = 6.0f;
+    U(mat2).m[2][1] = 7.0f; U(mat2).m[3][1] = 8.0f; U(mat2).m[0][2] = -8.0f;
+    U(mat2).m[1][2] = -7.0f; U(mat2).m[2][2] = -6.0f; U(mat2).m[3][2] = -5.0f;
+    U(mat2).m[0][3] = -4.0f; U(mat2).m[1][3] = -3.0f; U(mat2).m[2][3] = -2.0f;
+    U(mat2).m[3][3] = -1.0f;
+
+    plane.a = -3.0f; plane.b = -1.0f; plane.c = 4.0f; plane.d = 7.0f;
+
+    q.x = 1.0f; q.y = -4.0f; q.z =7.0f; q.w = -11.0f;
+    r.x = 0.87f; r.y = 0.65f; r.z =0.43f; r.w= 0.21f;
+
+    at.x = -2.0f; at.y = 13.0f; at.z = -9.0f;
+    axis.x = 1.0f; axis.y = -3.0f; axis.z = 7.0f;
+    eye.x = 8.0f; eye.y = -5.0f; eye.z = 5.75f;
+    last.x = 9.7f; last.y = -8.6; last.z = 1.3f;
+
+    light.x = 9.6f; light.y = 8.5f; light.z = 7.4; light.w = 6.3;
+
+    angle = D3DX_PI/3.0f;
+
+/*____________D3DXMatrixAffineTransformation______*/
+    set_matrix(&expectedmat,
+            -459.239990f, -576.719971f, -263.440002f, 0.0f,
+            519.760010f, -352.440002f, -277.679993f, 0.0f,
+            363.119995f, -121.040001f, -117.479996f, 0.0f,
+            -1239.0f, 667.0f, 567.0f, 1.0f);
+    D3DXMatrixAffineTransformation(&gotmat, 3.56f, &at, &q, &axis);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+    /* Test the NULL case */
+    U(expectedmat).m[3][0] = 1.0f; U(expectedmat).m[3][1] = -3.0f; U(expectedmat).m[3][2] = 7.0f; U(expectedmat).m[3][3] = 1.0f;
+    D3DXMatrixAffineTransformation(&gotmat, 3.56f, NULL, &q, &axis);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+    U(expectedmat).m[3][0] = -1240.0f; U(expectedmat).m[3][1] = 670.0f; U(expectedmat).m[3][2] = 560.0f; U(expectedmat).m[3][3] = 1.0f;
+    D3DXMatrixAffineTransformation(&gotmat, 3.56f, &at, &q, NULL);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+    U(expectedmat).m[3][0] = 0.0f; U(expectedmat).m[3][1] = 0.0f; U(expectedmat).m[3][2] = 0.0f; U(expectedmat).m[3][3] = 1.0f;
+    D3DXMatrixAffineTransformation(&gotmat, 3.56f, NULL, &q, NULL);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+    set_matrix(&expectedmat,
+            3.56f, 0.0f, 0.0f, 0.0f,
+            0.0f, 3.56f, 0.0f, 0.0f,
+            0.0f, 0.0f, 3.56f, 0.0f,
+            1.0f, -3.0f, 7.0f, 1.0f);
+    D3DXMatrixAffineTransformation(&gotmat, 3.56f, NULL, NULL, &axis);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+    D3DXMatrixAffineTransformation(&gotmat, 3.56f, &at, NULL, &axis);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+    U(expectedmat).m[3][0] = 0.0f; U(expectedmat).m[3][1] = 0.0f; U(expectedmat).m[3][2] = 0.0f; U(expectedmat).m[3][3] = 1.0f;
+    D3DXMatrixAffineTransformation(&gotmat, 3.56f, &at, NULL, NULL);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+    D3DXMatrixAffineTransformation(&gotmat, 3.56f, NULL, NULL, NULL);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+/*____________D3DXMatrixfDeterminant_____________*/
+    determinant = D3DXMatrixDeterminant(&mat);
+    equal = compare_float(determinant, -147888.0f, 0);
+    ok(equal, "Got unexpected determinant %.8e.\n", determinant);
+
+/*____________D3DXMatrixInverse______________*/
+    set_matrix(&expectedmat,
+            16067.0f/73944.0f, -10165.0f/147888.0f, -2729.0f/147888.0f, -1631.0f/49296.0f,
+            -565.0f/36972.0f, 2723.0f/73944.0f, -1073.0f/73944.0f, 289.0f/24648.0f,
+            -389.0f/2054.0f, 337.0f/4108.0f, 181.0f/4108.0f, 317.0f/4108.0f,
+            163.0f/5688.0f, -101.0f/11376.0f, -73.0f/11376.0f, -127.0f/3792.0f);
+    D3DXMatrixInverse(&gotmat, &determinant, &mat);
+    expect_matrix(&expectedmat, &gotmat, 1);
+    equal = compare_float(determinant, -147888.0f, 0);
+    ok(equal, "Got unexpected determinant %.8e.\n", determinant);
+    funcpointer = D3DXMatrixInverse(&gotmat,NULL,&mat2);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*____________D3DXMatrixIsIdentity______________*/
+    expected = FALSE;
+    memset(&mat3, 0, sizeof(mat3));
+    got = D3DXMatrixIsIdentity(&mat3);
+    ok(expected == got, "Expected : %d, Got : %d\n", expected, got);
+    D3DXMatrixIdentity(&mat3);
+    expected = TRUE;
+    got = D3DXMatrixIsIdentity(&mat3);
+    ok(expected == got, "Expected : %d, Got : %d\n", expected, got);
+    U(mat3).m[0][0] = 0.000009f;
+    expected = FALSE;
+    got = D3DXMatrixIsIdentity(&mat3);
+    ok(expected == got, "Expected : %d, Got : %d\n", expected, got);
+    /* Test the NULL case */
+    expected = FALSE;
+    got = D3DXMatrixIsIdentity(NULL);
+    ok(expected == got, "Expected : %d, Got : %d\n", expected, got);
+
+/*____________D3DXMatrixLookAtLH_______________*/
+    set_matrix(&expectedmat,
+            -0.82246518f, -0.40948939f, -0.39480308f, 0.0f,
+            -0.55585691f, 0.43128574f, 0.71064550f, 0.0f,
+            -0.12072885f, 0.80393475f, -0.58233452f, 0.0f,
+            4.4946337f, 0.80971903f, 10.060076f, 1.0f);
+    D3DXMatrixLookAtLH(&gotmat, &eye, &at, &axis);
+    expect_matrix(&expectedmat, &gotmat, 32);
+
+/*____________D3DXMatrixLookAtRH_______________*/
+    set_matrix(&expectedmat,
+            0.82246518f, -0.40948939f, 0.39480308f, 0.0f,
+            0.55585691f, 0.43128574f, -0.71064550f, 0.0f,
+            0.12072885f, 0.80393475f, 0.58233452f, 0.0f,
+            -4.4946337f, 0.80971903f, -10.060076f, 1.0f);
+    D3DXMatrixLookAtRH(&gotmat, &eye, &at, &axis);
+    expect_matrix(&expectedmat, &gotmat, 32);
+
+/*____________D3DXMatrixMultiply______________*/
+    set_matrix(&expectedmat,
+            73.0f, 193.0f, -197.0f, -77.0f,
+            231.0f, 551.0f, -489.0f, -169.0f,
+            239.0f, 523.0f, -400.0f, -116.0f,
+            -164.0f, -320.0f, 187.0f, 31.0f);
+    D3DXMatrixMultiply(&gotmat, &mat, &mat2);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+/*____________D3DXMatrixMultiplyTranspose____*/
+    set_matrix(&expectedmat,
+            73.0f, 231.0f, 239.0f, -164.0f,
+            193.0f, 551.0f, 523.0f, -320.0f,
+            -197.0f, -489.0f, -400.0f, 187.0f,
+            -77.0f, -169.0f, -116.0f, 31.0f);
+    D3DXMatrixMultiplyTranspose(&gotmat, &mat, &mat2);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+/*____________D3DXMatrixOrthoLH_______________*/
+    set_matrix(&expectedmat,
+            0.8f, 0.0f, 0.0f, 0.0f,
+            0.0f, 0.27027027f, 0.0f, 0.0f,
+            0.0f, 0.0f, -0.15151515f, 0.0f,
+            0.0f, 0.0f, -0.48484848f, 1.0f);
+    D3DXMatrixOrthoLH(&gotmat, 2.5f, 7.4f, -3.2f, -9.8f);
+    expect_matrix(&expectedmat, &gotmat, 16);
+
+/*____________D3DXMatrixOrthoOffCenterLH_______________*/
+    set_matrix(&expectedmat,
+            3.6363636f, 0.0f, 0.0f, 0.0f,
+            0.0f, 0.18018018f, 0.0f, 0.0f,
+            0.0f, 0.0f, -0.045662100f, 0.0f,
+            -1.7272727f, -0.56756757f, 0.42465753f, 1.0f);
+    D3DXMatrixOrthoOffCenterLH(&gotmat, 0.2f, 0.75f, -2.4f, 8.7f, 9.3, -12.6);
+    expect_matrix(&expectedmat, &gotmat, 32);
+
+/*____________D3DXMatrixOrthoOffCenterRH_______________*/
+    set_matrix(&expectedmat,
+            3.6363636f, 0.0f, 0.0f, 0.0f,
+            0.0f, 0.18018018f, 0.0f, 0.0f,
+            0.0f, 0.0f, 0.045662100f, 0.0f,
+            -1.7272727f, -0.56756757f, 0.42465753f, 1.0f);
+    D3DXMatrixOrthoOffCenterRH(&gotmat, 0.2f, 0.75f, -2.4f, 8.7f, 9.3, -12.6);
+    expect_matrix(&expectedmat, &gotmat, 32);
+
+/*____________D3DXMatrixOrthoRH_______________*/
+    set_matrix(&expectedmat,
+            0.8f, 0.0f, 0.0f, 0.0f,
+            0.0f, 0.27027027f, 0.0f, 0.0f,
+            0.0f, 0.0f, 0.15151515f, 0.0f,
+            0.0f, 0.0f, -0.48484848f, 1.0f);
+    D3DXMatrixOrthoRH(&gotmat, 2.5f, 7.4f, -3.2f, -9.8f);
+    expect_matrix(&expectedmat, &gotmat, 16);
+
+/*____________D3DXMatrixPerspectiveFovLH_______________*/
+    set_matrix(&expectedmat,
+            13.288858f, 0.0f, 0.0f, 0.0f,
+            0.0f, 9.9666444f, 0.0f, 0.0f,
+            0.0f, 0.0f, 0.78378378f, 1.0f,
+            0.0f, 0.0f, 1.8810811f, 0.0f);
+    D3DXMatrixPerspectiveFovLH(&gotmat, 0.2f, 0.75f, -2.4f, 8.7f);
+    expect_matrix(&expectedmat, &gotmat, 4);
+
+/*____________D3DXMatrixPerspectiveFovRH_______________*/
+    set_matrix(&expectedmat,
+            13.288858f, 0.0f, 0.0f, 0.0f,
+            0.0f, 9.9666444f, 0.0f, 0.0f,
+            0.0f, 0.0f, -0.78378378f, -1.0f,
+            0.0f, 0.0f, 1.8810811f, 0.0f);
+    D3DXMatrixPerspectiveFovRH(&gotmat, 0.2f, 0.75f, -2.4f, 8.7f);
+    expect_matrix(&expectedmat, &gotmat, 4);
+
+/*____________D3DXMatrixPerspectiveLH_______________*/
+    set_matrix(&expectedmat,
+            -24.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, -6.4f, 0.0f, 0.0f,
+            0.0f, 0.0f, 0.78378378f, 1.0f,
+            0.0f, 0.0f, 1.8810811f, 0.0f);
+    D3DXMatrixPerspectiveLH(&gotmat, 0.2f, 0.75f, -2.4f, 8.7f);
+    expect_matrix(&expectedmat, &gotmat, 4);
+
+/*____________D3DXMatrixPerspectiveOffCenterLH_______________*/
+    set_matrix(&expectedmat,
+            11.636364f, 0.0f, 0.0f, 0.0f,
+            0.0f, 0.57657658f, 0.0f, 0.0f,
+            -1.7272727f, -0.56756757f, 0.84079602f, 1.0f,
+            0.0f, 0.0f, -2.6905473f, 0.0f);
+    D3DXMatrixPerspectiveOffCenterLH(&gotmat, 0.2f, 0.75f, -2.4f, 8.7f, 3.2f, -16.9f);
+    expect_matrix(&expectedmat, &gotmat, 8);
+
+/*____________D3DXMatrixPerspectiveOffCenterRH_______________*/
+    set_matrix(&expectedmat,
+            11.636364f, 0.0f, 0.0f, 0.0f,
+            0.0f, 0.57657658f, 0.0f, 0.0f,
+            1.7272727f, 0.56756757f, -0.84079602f, -1.0f,
+            0.0f, 0.0f, -2.6905473f, 0.0f);
+    D3DXMatrixPerspectiveOffCenterRH(&gotmat, 0.2f, 0.75f, -2.4f, 8.7f, 3.2f, -16.9f);
+    expect_matrix(&expectedmat, &gotmat, 8);
+
+/*____________D3DXMatrixPerspectiveRH_______________*/
+    set_matrix(&expectedmat,
+            -24.0f, -0.0f, 0.0f, 0.0f,
+            0.0f, -6.4f, 0.0f, 0.0f,
+            0.0f, 0.0f, -0.78378378f, -1.0f,
+            0.0f, 0.0f, 1.8810811f, 0.0f);
+    D3DXMatrixPerspectiveRH(&gotmat, 0.2f, 0.75f, -2.4f, 8.7f);
+    expect_matrix(&expectedmat, &gotmat, 4);
+
+/*____________D3DXMatrixReflect______________*/
+    set_matrix(&expectedmat,
+            0.30769235f, -0.23076922f, 0.92307687f, 0.0f,
+            -0.23076922, 0.92307693f, 0.30769232f, 0.0f,
+            0.92307687f, 0.30769232f, -0.23076922f, 0.0f,
+            1.6153846f, 0.53846157f, -2.1538463f, 1.0f);
+    D3DXMatrixReflect(&gotmat, &plane);
+    expect_matrix(&expectedmat, &gotmat, 32);
+
+/*____________D3DXMatrixRotationAxis_____*/
+    set_matrix(&expectedmat,
+            0.50847453f, 0.76380461f, 0.39756277f, 0.0f,
+            -0.81465209f, 0.57627118f, -0.065219201f, 0.0f,
+            -0.27891868f, -0.29071301f, 0.91525424f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f);
+    D3DXMatrixRotationAxis(&gotmat, &axis, angle);
+    expect_matrix(&expectedmat, &gotmat, 32);
+
+/*____________D3DXMatrixRotationQuaternion______________*/
+    set_matrix(&expectedmat,
+            -129.0f, -162.0f, -74.0f, 0.0f,
+            146.0f, -99.0f, -78.0f, 0.0f,
+            102.0f, -34.0f, -33.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f);
+    D3DXMatrixRotationQuaternion(&gotmat, &q);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+/*____________D3DXMatrixRotationX______________*/
+    set_matrix(&expectedmat,
+            1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 0.5f, sqrt(3.0f)/2.0f, 0.0f,
+            0.0f, -sqrt(3.0f)/2.0f, 0.5f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f);
+    D3DXMatrixRotationX(&gotmat, angle);
+    expect_matrix(&expectedmat, &gotmat, 1);
+
+/*____________D3DXMatrixRotationY______________*/
+    set_matrix(&expectedmat,
+            0.5f, 0.0f, -sqrt(3.0f)/2.0f, 0.0f,
+            0.0f, 1.0f, 0.0f, 0.0f,
+            sqrt(3.0f)/2.0f, 0.0f, 0.5f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f);
+    D3DXMatrixRotationY(&gotmat, angle);
+    expect_matrix(&expectedmat, &gotmat, 1);
+
+/*____________D3DXMatrixRotationYawPitchRoll____*/
+    set_matrix(&expectedmat,
+            0.88877726f, 0.091874748f, -0.44903678f, 0.0f,
+            0.35171318f, 0.49148652f, 0.79670501f, 0.0f,
+            0.29389259f, -0.86602545f, 0.40450847f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f);
+    D3DXMatrixRotationYawPitchRoll(&gotmat, 3.0f * angle / 5.0f, angle, 3.0f * angle / 17.0f);
+    expect_matrix(&expectedmat, &gotmat, 64);
+
+/*____________D3DXMatrixRotationZ______________*/
+    set_matrix(&expectedmat,
+            0.5f, sqrt(3.0f)/2.0f, 0.0f, 0.0f,
+            -sqrt(3.0f)/2.0f, 0.5f, 0.0f, 0.0f,
+            0.0f, 0.0f, 1.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f);
+    D3DXMatrixRotationZ(&gotmat, angle);
+    expect_matrix(&expectedmat, &gotmat, 1);
+
+/*____________D3DXMatrixScaling______________*/
+    set_matrix(&expectedmat,
+            0.69f, 0.0f, 0.0f, 0.0f,
+            0.0f, 0.53f, 0.0f, 0.0f,
+            0.0f, 0.0f, 4.11f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f);
+    D3DXMatrixScaling(&gotmat, 0.69f, 0.53f, 4.11f);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+/*____________D3DXMatrixShadow______________*/
+    set_matrix(&expectedmat,
+            12.786773f, 5.0009613f, 4.3537784f, 3.7065949f,
+            1.8827150f, 8.8056154f, 1.4512594f, 1.2355317f,
+            -7.5308599f, -6.6679487f, 1.3335901f, -4.9421268f,
+            -13.179006f, -11.668910f, -10.158816f, -1.5100943f);
+    D3DXMatrixShadow(&gotmat, &light, &plane);
+    expect_matrix(&expectedmat, &gotmat, 8);
+
+/*____________D3DXMatrixTransformation______________*/
+    set_matrix(&expectedmat,
+            -0.21480007f, 1.3116000f, 0.47520003f, 0.0f,
+            0.95040143f, -0.88360137f, 0.92439979f, 0.0f,
+            1.0212044f, 0.19359307f, -1.3588026f, 0.0f,
+            18.298532f, -29.624001f, 15.683499f, 1.0f);
+    D3DXMatrixTransformation(&gotmat, &at, &q, NULL, &eye, &r, &last);
+    expect_matrix(&expectedmat, &gotmat, 512);
+
+/*____________D3DXMatrixTranslation______________*/
+    set_matrix(&expectedmat,
+            1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 1.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 1.0f, 0.0f,
+            0.69f, 0.53f, 4.11f, 1.0f);
+    D3DXMatrixTranslation(&gotmat, 0.69f, 0.53f, 4.11f);
+    expect_matrix(&expectedmat, &gotmat, 0);
+
+/*____________D3DXMatrixTranspose______________*/
+    set_matrix(&expectedmat,
+            10.0f, 11.0f, 19.0f, 2.0f,
+            5.0f, 20.0f, -21.0f, 3.0f,
+            7.0f, 16.0f, 30.f, -4.0f,
+            8.0f, 33.0f, 43.0f, -40.0f);
+    D3DXMatrixTranspose(&gotmat, &mat);
+    expect_matrix(&expectedmat, &gotmat, 0);
+}
+
+static void D3DXPlaneTest(void)
+{
+    D3DXMATRIX mat;
+    D3DXPLANE expectedplane, gotplane, nulplane, plane;
+    D3DXVECTOR3 expectedvec, gotvec, vec1, vec2, vec3;
+    LPD3DXVECTOR3 funcpointer;
+    D3DXVECTOR4 vec;
+    FLOAT expected, got;
+
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = 10.0f; U(mat).m[1][1] = 20.0f; U(mat).m[2][2] = 30.0f;
+    U(mat).m[3][3] = -40.0f;
+
+    plane.a = -3.0f; plane.b = -1.0f; plane.c = 4.0f; plane.d = 7.0f;
+
+    vec.x = 2.0f; vec.y = 5.0f; vec.z = -6.0f; vec.w = 11.0f;
+
+/*_______________D3DXPlaneDot________________*/
+    expected = 42.0f;
+    got = D3DXPlaneDot(&plane,&vec),
+    ok( expected == got, "Expected : %f, Got : %f\n",expected, got);
+    expected = 0.0f;
+    got = D3DXPlaneDot(NULL,&vec),
+    ok( expected == got, "Expected : %f, Got : %f\n",expected, got);
+    expected = 0.0f;
+    got = D3DXPlaneDot(NULL,NULL),
+    ok( expected == got, "Expected : %f, Got : %f\n",expected, got);
+
+/*_______________D3DXPlaneDotCoord________________*/
+    expected = -28.0f;
+    got = D3DXPlaneDotCoord(&plane,&vec),
+    ok( expected == got, "Expected : %f, Got : %f\n",expected, got);
+    expected = 0.0f;
+    got = D3DXPlaneDotCoord(NULL,&vec),
+    ok( expected == got, "Expected : %f, Got : %f\n",expected, got);
+    expected = 0.0f;
+    got = D3DXPlaneDotCoord(NULL,NULL),
+    ok( expected == got, "Expected : %f, Got : %f\n",expected, got);
+
+/*_______________D3DXPlaneDotNormal______________*/
+    expected = -35.0f;
+    got = D3DXPlaneDotNormal(&plane,&vec),
+    ok( expected == got, "Expected : %f, Got : %f\n",expected, got);
+    expected = 0.0f;
+    got = D3DXPlaneDotNormal(NULL,&vec),
+    ok( expected == got, "Expected : %f, Got : %f\n",expected, got);
+    expected = 0.0f;
+    got = D3DXPlaneDotNormal(NULL,NULL),
+    ok( expected == got, "Expected : %f, Got : %f\n",expected, got);
+
+/*_______________D3DXPlaneFromPointNormal_______*/
+    vec1.x = 11.0f; vec1.y = 13.0f; vec1.z = 15.0f;
+    vec2.x = 17.0f; vec2.y = 31.0f; vec2.z = 24.0f;
+    expectedplane.a = 17.0f; expectedplane.b = 31.0f; expectedplane.c = 24.0f; expectedplane.d = -950.0f;
+    D3DXPlaneFromPointNormal(&gotplane, &vec1, &vec2);
+    expect_plane(&expectedplane, &gotplane, 0);
+    gotplane.a = vec2.x; gotplane.b = vec2.y; gotplane.c = vec2.z;
+    D3DXPlaneFromPointNormal(&gotplane, &vec1, (D3DXVECTOR3 *)&gotplane);
+    expect_plane(&expectedplane, &gotplane, 0);
+    gotplane.a = vec1.x; gotplane.b = vec1.y; gotplane.c = vec1.z;
+    expectedplane.d = -1826.0f;
+    D3DXPlaneFromPointNormal(&gotplane, (D3DXVECTOR3 *)&gotplane, &vec2);
+    expect_plane(&expectedplane, &gotplane, 0);
+
+/*_______________D3DXPlaneFromPoints_______*/
+    vec1.x = 1.0f; vec1.y = 2.0f; vec1.z = 3.0f;
+    vec2.x = 1.0f; vec2.y = -6.0f; vec2.z = -5.0f;
+    vec3.x = 83.0f; vec3.y = 74.0f; vec3.z = 65.0f;
+    expectedplane.a = 0.085914f; expectedplane.b = -0.704492f; expectedplane.c = 0.704492f; expectedplane.d = -0.790406f;
+    D3DXPlaneFromPoints(&gotplane,&vec1,&vec2,&vec3);
+    expect_plane(&expectedplane, &gotplane, 64);
+
+/*_______________D3DXPlaneIntersectLine___________*/
+    vec1.x = 9.0f; vec1.y = 6.0f; vec1.z = 3.0f;
+    vec2.x = 2.0f; vec2.y = 5.0f; vec2.z = 8.0f;
+    expectedvec.x = 20.0f/3.0f; expectedvec.y = 17.0f/3.0f; expectedvec.z = 14.0f/3.0f;
+    D3DXPlaneIntersectLine(&gotvec,&plane,&vec1,&vec2);
+    expect_vec3(&expectedvec, &gotvec, 1);
+    /* Test a parallel line */
+    vec1.x = 11.0f; vec1.y = 13.0f; vec1.z = 15.0f;
+    vec2.x = 17.0f; vec2.y = 31.0f; vec2.z = 24.0f;
+    expectedvec.x = 20.0f/3.0f; expectedvec.y = 17.0f/3.0f; expectedvec.z = 14.0f/3.0f;
+    funcpointer = D3DXPlaneIntersectLine(&gotvec,&plane,&vec1,&vec2);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXPlaneNormalize______________*/
+    expectedplane.a = -3.0f/sqrt(26.0f); expectedplane.b = -1.0f/sqrt(26.0f); expectedplane.c = 4.0f/sqrt(26.0f); expectedplane.d = 7.0/sqrt(26.0f);
+    D3DXPlaneNormalize(&gotplane, &plane);
+    expect_plane(&expectedplane, &gotplane, 2);
+    nulplane.a = 0.0; nulplane.b = 0.0f, nulplane.c = 0.0f; nulplane.d = 0.0f;
+    expectedplane.a = 0.0f; expectedplane.b = 0.0f; expectedplane.c = 0.0f; expectedplane.d = 0.0f;
+    D3DXPlaneNormalize(&gotplane, &nulplane);
+    expect_plane(&expectedplane, &gotplane, 0);
+
+/*_______________D3DXPlaneTransform____________*/
+    expectedplane.a = 49.0f; expectedplane.b = -98.0f; expectedplane.c = 55.0f; expectedplane.d = -165.0f;
+    D3DXPlaneTransform(&gotplane,&plane,&mat);
+    expect_plane(&expectedplane, &gotplane, 0);
+}
+
+static void D3DXQuaternionTest(void)
+{
+    D3DXMATRIX mat;
+    D3DXQUATERNION expectedquat, gotquat, Nq, Nq1, nul, smallq, smallr, q, r, s, t, u;
+    BOOL expectedbool, gotbool, equal;
+    float angle, got, scale, scale2;
+    LPD3DXQUATERNION funcpointer;
+    D3DXVECTOR3 axis, expectedvec;
+
+    nul.x = 0.0f; nul.y = 0.0f; nul.z = 0.0f; nul.w = 0.0f;
+    q.x = 1.0f, q.y = 2.0f; q.z = 4.0f; q.w = 10.0f;
+    r.x = -3.0f; r.y = 4.0f; r.z = -5.0f; r.w = 7.0;
+    t.x = -1111.0f, t.y = 111.0f; t.z = -11.0f; t.w = 1.0f;
+    u.x = 91.0f; u.y = - 82.0f; u.z = 7.3f; u.w = -6.4f;
+    smallq.x = 0.1f; smallq.y = 0.2f; smallq.z= 0.3f; smallq.w = 0.4f;
+    smallr.x = 0.5f; smallr.y = 0.6f; smallr.z= 0.7f; smallr.w = 0.8f;
+
+    scale = 0.3f;
+    scale2 = 0.78f;
+
+/*_______________D3DXQuaternionBaryCentric________________________*/
+    expectedquat.x = -867.444458; expectedquat.y = 87.851111f; expectedquat.z = -9.937778f; expectedquat.w = 3.235555f;
+    D3DXQuaternionBaryCentric(&gotquat,&q,&r,&t,scale,scale2);
+    expect_quaternion(&expectedquat, &gotquat, 1);
+
+/*_______________D3DXQuaternionConjugate________________*/
+    expectedquat.x = -1.0f; expectedquat.y = -2.0f; expectedquat.z = -4.0f; expectedquat.w = 10.0f;
+    D3DXQuaternionConjugate(&gotquat,&q);
+    expect_quaternion(&expectedquat, &gotquat, 0);
+    /* Test the NULL case */
+    funcpointer = D3DXQuaternionConjugate(&gotquat,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXQuaternionConjugate(NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXQuaternionDot______________________*/
+    got = D3DXQuaternionDot(&q,&r);
+    equal = compare_float(got, 55.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+    /* Tests the case NULL */
+    got = D3DXQuaternionDot(NULL,&r);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+    got = D3DXQuaternionDot(NULL,NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+
+/*_______________D3DXQuaternionExp______________________________*/
+    expectedquat.x = -0.216382f; expectedquat.y = -0.432764f; expectedquat.z = -0.8655270f; expectedquat.w = -0.129449f;
+    D3DXQuaternionExp(&gotquat,&q);
+    expect_quaternion(&expectedquat, &gotquat, 16);
+    /* Test the null quaternion */
+    expectedquat.x = 0.0f; expectedquat.y = 0.0f; expectedquat.z = 0.0f; expectedquat.w = 1.0f;
+    D3DXQuaternionExp(&gotquat,&nul);
+    expect_quaternion(&expectedquat, &gotquat, 0);
+    /* Test the case where the norm of the quaternion is <1 */
+    Nq1.x = 0.2f; Nq1.y = 0.1f; Nq1.z = 0.3; Nq1.w= 0.9f;
+    expectedquat.x = 0.195366; expectedquat.y = 0.097683f; expectedquat.z = 0.293049f; expectedquat.w = 0.930813f;
+    D3DXQuaternionExp(&gotquat,&Nq1);
+    expect_quaternion(&expectedquat, &gotquat, 8);
+
+/*_______________D3DXQuaternionIdentity________________*/
+    expectedquat.x = 0.0f; expectedquat.y = 0.0f; expectedquat.z = 0.0f; expectedquat.w = 1.0f;
+    D3DXQuaternionIdentity(&gotquat);
+    expect_quaternion(&expectedquat, &gotquat, 0);
+    /* Test the NULL case */
+    funcpointer = D3DXQuaternionIdentity(NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXQuaternionInverse________________________*/
+    expectedquat.x = -1.0f/121.0f; expectedquat.y = -2.0f/121.0f; expectedquat.z = -4.0f/121.0f; expectedquat.w = 10.0f/121.0f;
+    D3DXQuaternionInverse(&gotquat,&q);
+    expect_quaternion(&expectedquat, &gotquat, 0);
+
+    expectedquat.x = 1.0f; expectedquat.y = 2.0f; expectedquat.z = 4.0f; expectedquat.w = 10.0f;
+    D3DXQuaternionInverse(&gotquat,&gotquat);
+    expect_quaternion(&expectedquat, &gotquat, 1);
+
+
+/*_______________D3DXQuaternionIsIdentity________________*/
+    s.x = 0.0f; s.y = 0.0f; s.z = 0.0f; s.w = 1.0f;
+    expectedbool = TRUE;
+    gotbool = D3DXQuaternionIsIdentity(&s);
+    ok( expectedbool == gotbool, "Expected boolean : %d, Got bool : %d\n", expectedbool, gotbool);
+    s.x = 2.3f; s.y = -4.2f; s.z = 1.2f; s.w=0.2f;
+    expectedbool = FALSE;
+    gotbool = D3DXQuaternionIsIdentity(&q);
+    ok( expectedbool == gotbool, "Expected boolean : %d, Got bool : %d\n", expectedbool, gotbool);
+    /* Test the NULL case */
+    gotbool = D3DXQuaternionIsIdentity(NULL);
+    ok(gotbool == FALSE, "Expected boolean: %d, Got boolean: %d\n", FALSE, gotbool);
+
+/*_______________D3DXQuaternionLength__________________________*/
+    got = D3DXQuaternionLength(&q);
+    equal = compare_float(got, 11.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+    /* Tests the case NULL. */
+    got = D3DXQuaternionLength(NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+
+/*_______________D3DXQuaternionLengthSq________________________*/
+    got = D3DXQuaternionLengthSq(&q);
+    equal = compare_float(got, 121.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+    /* Tests the case NULL */
+    got = D3DXQuaternionLengthSq(NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+
+/*_______________D3DXQuaternionLn______________________________*/
+    expectedquat.x = 1.0f; expectedquat.y = 2.0f; expectedquat.z = 4.0f; expectedquat.w = 0.0f;
+    D3DXQuaternionLn(&gotquat,&q);
+    expect_quaternion(&expectedquat, &gotquat, 0);
+    expectedquat.x = -3.0f; expectedquat.y = 4.0f; expectedquat.z = -5.0f; expectedquat.w = 0.0f;
+    D3DXQuaternionLn(&gotquat,&r);
+    expect_quaternion(&expectedquat, &gotquat, 0);
+    Nq.x = 1.0f/11.0f; Nq.y = 2.0f/11.0f; Nq.z = 4.0f/11.0f; Nq.w=10.0f/11.0f;
+    expectedquat.x = 0.093768f; expectedquat.y = 0.187536f; expectedquat.z = 0.375073f; expectedquat.w = 0.0f;
+    D3DXQuaternionLn(&gotquat,&Nq);
+    expect_quaternion(&expectedquat, &gotquat, 32);
+    Nq.x = 0.0f; Nq.y = 0.0f; Nq.z = 0.0f; Nq.w = 1.0f;
+    expectedquat.x = 0.0f; expectedquat.y = 0.0f; expectedquat.z = 0.0f; expectedquat.w = 0.0f;
+    D3DXQuaternionLn(&gotquat,&Nq);
+    expect_quaternion(&expectedquat, &gotquat, 0);
+    Nq.x = 5.4f; Nq.y = 1.2f; Nq.z = -0.3f; Nq.w = -0.3f;
+    expectedquat.x = 10.616652f; expectedquat.y = 2.359256f; expectedquat.z = -0.589814f; expectedquat.w = 0.0f;
+    D3DXQuaternionLn(&gotquat,&Nq);
+    expect_quaternion(&expectedquat, &gotquat, 1);
+    /* Test the case where the norm of the quaternion is <1 */
+    Nq1.x = 0.2f; Nq1.y = 0.1f; Nq1.z = 0.3; Nq1.w = 0.9f;
+    expectedquat.x = 0.206945f; expectedquat.y = 0.103473f; expectedquat.z = 0.310418f; expectedquat.w = 0.0f;
+    D3DXQuaternionLn(&gotquat,&Nq1);
+    expect_quaternion(&expectedquat, &gotquat, 64);
+    /* Test the case where the real part of the quaternion is -1.0f */
+    Nq1.x = 0.2f; Nq1.y = 0.1f; Nq1.z = 0.3; Nq1.w = -1.0f;
+    expectedquat.x = 0.2f; expectedquat.y = 0.1f; expectedquat.z = 0.3f; expectedquat.w = 0.0f;
+    D3DXQuaternionLn(&gotquat,&Nq1);
+    expect_quaternion(&expectedquat, &gotquat, 0);
+
+/*_______________D3DXQuaternionMultiply________________________*/
+    expectedquat.x = 3.0f; expectedquat.y = 61.0f; expectedquat.z = -32.0f; expectedquat.w = 85.0f;
+    D3DXQuaternionMultiply(&gotquat,&q,&r);
+    expect_quaternion(&expectedquat, &gotquat, 0);
+
+/*_______________D3DXQuaternionNormalize________________________*/
+    expectedquat.x = 1.0f/11.0f; expectedquat.y = 2.0f/11.0f; expectedquat.z = 4.0f/11.0f; expectedquat.w = 10.0f/11.0f;
+    D3DXQuaternionNormalize(&gotquat,&q);
+    expect_quaternion(&expectedquat, &gotquat, 1);
+
+/*_______________D3DXQuaternionRotationAxis___________________*/
+    axis.x = 2.0f; axis.y = 7.0; axis.z = 13.0f;
+    angle = D3DX_PI/3.0f;
+    expectedquat.x = 0.067116; expectedquat.y = 0.234905f; expectedquat.z = 0.436251f; expectedquat.w = 0.866025f;
+    D3DXQuaternionRotationAxis(&gotquat,&axis,angle);
+    expect_quaternion(&expectedquat, &gotquat, 64);
+ /* Test the nul quaternion */
+    axis.x = 0.0f; axis.y = 0.0; axis.z = 0.0f;
+    expectedquat.x = 0.0f; expectedquat.y = 0.0f; expectedquat.z = 0.0f; expectedquat.w = 0.866025f;
+    D3DXQuaternionRotationAxis(&gotquat,&axis,angle);
+    expect_quaternion(&expectedquat, &gotquat, 8);
+
+/*_______________D3DXQuaternionRotationMatrix___________________*/
+    /* test when the trace is >0 */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = 10.0f; U(mat).m[1][1] = 20.0f; U(mat).m[2][2] = 30.0f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 2.368682f; expectedquat.y = 0.768221f; expectedquat.z = -0.384111f; expectedquat.w = 3.905125f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 16);
+    /* test the case when the greater element is (2,2) */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = -60.0f; U(mat).m[2][2] = 40.0f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 1.233905f; expectedquat.y = -0.237290f; expectedquat.z = 5.267827f; expectedquat.w = -0.284747f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 64);
+    /* test the case when the greater element is (1,1) */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 60.0f; U(mat).m[2][2] = -80.0f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 0.651031f; expectedquat.y = 6.144103f; expectedquat.z = -0.203447f; expectedquat.w = 0.488273f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 8);
+    /* test the case when the trace is near 0 in a matrix which is not a rotation */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 10.0f; U(mat).m[2][2] = -0.9f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 1.709495f; expectedquat.y = 2.339872f; expectedquat.z = -0.534217f; expectedquat.w = 1.282122f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 8);
+    /* test the case when the trace is 0.49 in a matrix which is not a rotation */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 10.0f; U(mat).m[2][2] = -0.51f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 1.724923f; expectedquat.y = 2.318944f; expectedquat.z = -0.539039f; expectedquat.w = 1.293692f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 8);
+    /* test the case when the trace is 0.51 in a matrix which is not a rotation */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 10.0f; U(mat).m[2][2] = -0.49f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 1.725726f; expectedquat.y = 2.317865f; expectedquat.z = -0.539289f; expectedquat.w = 1.294294f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 8);
+    /* test the case when the trace is 0.99 in a matrix which is not a rotation */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 10.0f; U(mat).m[2][2] = -0.01f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 1.745328f; expectedquat.y = 2.291833f; expectedquat.z = -0.545415f; expectedquat.w = 1.308996f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 4);
+    /* test the case when the trace is 1.0 in a matrix which is not a rotation */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 10.0f; U(mat).m[2][2] = 0.0f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 1.745743f; expectedquat.y = 2.291288f; expectedquat.z = -0.545545f; expectedquat.w = 1.309307f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 8);
+    /* test the case when the trace is 1.01 in a matrix which is not a rotation */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 10.0f; U(mat).m[2][2] = 0.01f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 18.408188f; expectedquat.y = 5.970223f; expectedquat.z = -2.985111f; expectedquat.w = 0.502494f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 4);
+    /* test the case when the trace is 1.5 in a matrix which is not a rotation */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 10.0f; U(mat).m[2][2] = 0.5f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 15.105186f; expectedquat.y = 4.898980f; expectedquat.z = -2.449490f; expectedquat.w = 0.612372f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 8);
+    /* test the case when the trace is 1.7 in a matrix which is not a rotation */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 10.0f; U(mat).m[2][2] = 0.70f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 14.188852f; expectedquat.y = 4.601790f; expectedquat.z = -2.300895f; expectedquat.w = 0.651920f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 4);
+    /* test the case when the trace is 1.99 in a matrix which is not a rotation */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 10.0f; U(mat).m[2][2] = 0.99f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 13.114303f; expectedquat.y = 4.253287f; expectedquat.z = -2.126644f; expectedquat.w = 0.705337f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 4);
+    /* test the case when the trace is 2.0 in a matrix which is not a rotation */
+    U(mat).m[0][1] = 5.0f; U(mat).m[0][2] = 7.0f; U(mat).m[0][3] = 8.0f;
+    U(mat).m[1][0] = 11.0f; U(mat).m[1][2] = 16.0f; U(mat).m[1][3] = 33.0f;
+    U(mat).m[2][0] = 19.0f; U(mat).m[2][1] = -21.0f; U(mat).m[2][3] = 43.0f;
+    U(mat).m[3][0] = 2.0f; U(mat).m[3][1] = 3.0f; U(mat).m[3][2] = -4.0f;
+    U(mat).m[0][0] = -10.0f; U(mat).m[1][1] = 10.0f; U(mat).m[2][2] = 2.0f;
+    U(mat).m[3][3] = 48.0f;
+    expectedquat.x = 10.680980f; expectedquat.y = 3.464102f; expectedquat.z = -1.732051f; expectedquat.w = 0.866025f;
+    D3DXQuaternionRotationMatrix(&gotquat,&mat);
+    expect_quaternion(&expectedquat, &gotquat, 8);
+
+/*_______________D3DXQuaternionRotationYawPitchRoll__________*/
+    expectedquat.x = 0.303261f; expectedquat.y = 0.262299f; expectedquat.z = 0.410073f; expectedquat.w = 0.819190f;
+    D3DXQuaternionRotationYawPitchRoll(&gotquat,D3DX_PI/4.0f,D3DX_PI/11.0f,D3DX_PI/3.0f);
+    expect_quaternion(&expectedquat, &gotquat, 16);
+
+/*_______________D3DXQuaternionSlerp________________________*/
+    expectedquat.x = -0.2f; expectedquat.y = 2.6f; expectedquat.z = 1.3f; expectedquat.w = 9.1f;
+    D3DXQuaternionSlerp(&gotquat,&q,&r,scale);
+    expect_quaternion(&expectedquat, &gotquat, 4);
+    expectedquat.x = 334.0f; expectedquat.y = -31.9f; expectedquat.z = 6.1f; expectedquat.w = 6.7f;
+    D3DXQuaternionSlerp(&gotquat,&q,&t,scale);
+    expect_quaternion(&expectedquat, &gotquat, 2);
+    expectedquat.x = 0.239485f; expectedquat.y = 0.346580f; expectedquat.z = 0.453676f; expectedquat.w = 0.560772f;
+    D3DXQuaternionSlerp(&gotquat,&smallq,&smallr,scale);
+    expect_quaternion(&expectedquat, &gotquat, 32);
+
+/*_______________D3DXQuaternionSquad________________________*/
+    expectedquat.x = -156.296f; expectedquat.y = 30.242f; expectedquat.z = -2.5022f; expectedquat.w = 7.3576f;
+    D3DXQuaternionSquad(&gotquat,&q,&r,&t,&u,scale);
+    expect_quaternion(&expectedquat, &gotquat, 2);
+
+/*_______________D3DXQuaternionSquadSetup___________________*/
+    r.x = 1.0f, r.y = 2.0f; r.z = 4.0f; r.w = 10.0f;
+    s.x = -3.0f; s.y = 4.0f; s.z = -5.0f; s.w = 7.0;
+    t.x = -1111.0f, t.y = 111.0f; t.z = -11.0f; t.w = 1.0f;
+    u.x = 91.0f; u.y = - 82.0f; u.z = 7.3f; u.w = -6.4f;
+    D3DXQuaternionSquadSetup(&gotquat, &Nq, &Nq1, &r, &s, &t, &u);
+    expectedquat.x = 7.121285f; expectedquat.y = 2.159964f; expectedquat.z = -3.855094f; expectedquat.w = 5.362844f;
+    expect_quaternion(&expectedquat, &gotquat, 2);
+    expectedquat.x = -1113.492920f; expectedquat.y = 82.679260f; expectedquat.z = -6.696645f; expectedquat.w = -4.090050f;
+    expect_quaternion(&expectedquat, &Nq, 2);
+    expectedquat.x = -1111.0f; expectedquat.y = 111.0f; expectedquat.z = -11.0f; expectedquat.w = 1.0f;
+    expect_quaternion(&expectedquat, &Nq1, 0);
+    gotquat = s;
+    D3DXQuaternionSquadSetup(&gotquat, &Nq, &Nq1, &r, &gotquat, &t, &u);
+    expectedquat.x = -1113.492920f; expectedquat.y = 82.679260f; expectedquat.z = -6.696645f; expectedquat.w = -4.090050f;
+    expect_quaternion(&expectedquat, &Nq, 2);
+    Nq1 = u;
+    D3DXQuaternionSquadSetup(&gotquat, &Nq, &Nq1, &r, &s, &t, &Nq1);
+    expect_quaternion(&expectedquat, &Nq, 2);
+    r.x = 0.2f; r.y = 0.3f; r.z = 1.3f; r.w = -0.6f;
+    s.x = -3.0f; s.y =-2.0f; s.z = 4.0f; s.w = 0.2f;
+    t.x = 0.4f; t.y = 8.3f; t.z = -3.1f; t.w = -2.7f;
+    u.x = 1.1f; u.y = -0.7f; u.z = 9.2f; u.w = 0.0f;
+    D3DXQuaternionSquadSetup(&gotquat, &Nq, &Nq1, &r, &s, &u, &t);
+    expectedquat.x = -4.139569f; expectedquat.y = -2.469115f; expectedquat.z = 2.364477f; expectedquat.w = 0.465494f;
+    expect_quaternion(&expectedquat, &gotquat, 16);
+    expectedquat.x = 2.342533f; expectedquat.y = 2.365127f; expectedquat.z = 8.628538f; expectedquat.w = -0.898356f;
+    expect_quaternion(&expectedquat, &Nq, 16);
+    expectedquat.x = 1.1f; expectedquat.y = -0.7f; expectedquat.z = 9.2f; expectedquat.w = 0.0f;
+    expect_quaternion(&expectedquat, &Nq1, 0);
+    D3DXQuaternionSquadSetup(&gotquat, &Nq, &Nq1, &r, &s, &t, &u);
+    expectedquat.x = -3.754567f; expectedquat.y = -0.586085f; expectedquat.z = 3.815818f; expectedquat.w = -0.198150f;
+    expect_quaternion(&expectedquat, &gotquat, 32);
+    expectedquat.x = 0.140773f; expectedquat.y = -8.737090f; expectedquat.z = -0.516593f; expectedquat.w = 3.053942f;
+    expect_quaternion(&expectedquat, &Nq, 16);
+    expectedquat.x = -0.4f; expectedquat.y = -8.3f; expectedquat.z = 3.1f; expectedquat.w = 2.7f;
+    expect_quaternion(&expectedquat, &Nq1, 0);
+    r.x = -1.0f; r.y = 0.0f; r.z = 0.0f; r.w = 0.0f;
+    s.x = 1.0f; s.y =0.0f; s.z = 0.0f; s.w = 0.0f;
+    t.x = 1.0f; t.y = 0.0f; t.z = 0.0f; t.w = 0.0f;
+    u.x = -1.0f; u.y = 0.0f; u.z = 0.0f; u.w = 0.0f;
+    D3DXQuaternionSquadSetup(&gotquat, &Nq, &Nq1, &r, &s, &t, &u);
+    expectedquat.x = 1.0f; expectedquat.y = 0.0f; expectedquat.z = 0.0f; expectedquat.w = 0.0f;
+    expect_quaternion(&expectedquat, &gotquat, 0);
+    expectedquat.x = 1.0f; expectedquat.y = 0.0f; expectedquat.z = 0.0f; expectedquat.w = 0.0f;
+    expect_quaternion(&expectedquat, &Nq, 0);
+    expectedquat.x = 1.0f; expectedquat.y = 0.0f; expectedquat.z = 0.0f; expectedquat.w = 0.0f;
+    expect_quaternion(&expectedquat, &Nq1, 0);
+
+/*_______________D3DXQuaternionToAxisAngle__________________*/
+    Nq.x = 1.0f/22.0f; Nq.y = 2.0f/22.0f; Nq.z = 4.0f/22.0f; Nq.w = 10.0f/22.0f;
+    expectedvec.x = 1.0f/22.0f; expectedvec.y = 2.0f/22.0f; expectedvec.z = 4.0f/22.0f;
+    D3DXQuaternionToAxisAngle(&Nq,&axis,&angle);
+    expect_vec3(&expectedvec, &axis, 0);
+    equal = compare_float(angle, 2.197869f, 1);
+    ok(equal, "Got unexpected angle %.8e.\n", angle);
+    /* Test if |w|>1.0f */
+    expectedvec.x = 1.0f; expectedvec.y = 2.0f; expectedvec.z = 4.0f;
+    D3DXQuaternionToAxisAngle(&q,&axis,&angle);
+    expect_vec3(&expectedvec, &axis, 0);
+    /* Test the null quaternion */
+    expectedvec.x = 0.0f; expectedvec.y = 0.0f; expectedvec.z = 0.0f;
+    D3DXQuaternionToAxisAngle(&nul, &axis, &angle);
+    expect_vec3(&expectedvec, &axis, 0);
+    equal = compare_float(angle, 3.14159274e+00f, 0);
+    ok(equal, "Got unexpected angle %.8e.\n", angle);
+
+    D3DXQuaternionToAxisAngle(&nul, &axis, NULL);
+    D3DXQuaternionToAxisAngle(&nul, NULL, &angle);
+    expect_vec3(&expectedvec, &axis, 0);
+    equal = compare_float(angle, 3.14159274e+00f, 0);
+    ok(equal, "Got unexpected angle %.8e.\n", angle);
+}
+
+static void D3DXVector2Test(void)
+{
+    D3DXVECTOR2 expectedvec, gotvec, nul, u, v, w, x;
+    LPD3DXVECTOR2 funcpointer;
+    D3DXVECTOR4 expectedtrans, gottrans;
+    float coeff1, coeff2, got, scale;
+    D3DXMATRIX mat;
+    BOOL equal;
+
+    nul.x = 0.0f; nul.y = 0.0f;
+    u.x = 3.0f; u.y = 4.0f;
+    v.x = -7.0f; v.y = 9.0f;
+    w.x = 4.0f; w.y = -3.0f;
+    x.x = 2.0f; x.y = -11.0f;
+
+    set_matrix(&mat,
+            1.0f, 2.0f, 3.0f, 4.0f,
+            5.0f, 6.0f, 7.0f, 8.0f,
+            9.0f, 10.0f, 11.0f, 12.0f,
+            13.0f, 14.0f, 15.0f, 16.0f);
+
+    coeff1 = 2.0f; coeff2 = 5.0f;
+    scale = -6.5f;
+
+/*_______________D3DXVec2Add__________________________*/
+    expectedvec.x = -4.0f; expectedvec.y = 13.0f;
+    D3DXVec2Add(&gotvec,&u,&v);
+    expect_vec2(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec2Add(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec2Add(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec2BaryCentric___________________*/
+    expectedvec.x = -12.0f; expectedvec.y = -21.0f;
+    D3DXVec2BaryCentric(&gotvec,&u,&v,&w,coeff1,coeff2);
+    expect_vec2(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec2CatmullRom____________________*/
+    expectedvec.x = 5820.25f; expectedvec.y = -3654.5625f;
+    D3DXVec2CatmullRom(&gotvec,&u,&v,&w,&x,scale);
+    expect_vec2(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec2CCW__________________________*/
+    got = D3DXVec2CCW(&u, &v);
+    equal = compare_float(got, 55.0f, 0);
+    ok(equal, "Got unexpected ccw %.8e.\n", got);
+    /* Tests the case NULL. */
+    got = D3DXVec2CCW(NULL, &v);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected ccw %.8e.\n", got);
+    got = D3DXVec2CCW(NULL, NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected ccw %.8e.\n", got);
+
+/*_______________D3DXVec2Dot__________________________*/
+    got = D3DXVec2Dot(&u, &v);
+    equal = compare_float(got, 15.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+    /* Tests the case NULL */
+    got = D3DXVec2Dot(NULL, &v);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+    got = D3DXVec2Dot(NULL, NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+
+/*_______________D3DXVec2Hermite__________________________*/
+    expectedvec.x = 2604.625f; expectedvec.y = -4533.0f;
+    D3DXVec2Hermite(&gotvec,&u,&v,&w,&x,scale);
+    expect_vec2(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec2Length__________________________*/
+    got = D3DXVec2Length(&u);
+    equal = compare_float(got, 5.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+    /* Tests the case NULL. */
+    got = D3DXVec2Length(NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+
+/*_______________D3DXVec2LengthSq________________________*/
+    got = D3DXVec2LengthSq(&u);
+    equal = compare_float(got, 25.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+    /* Tests the case NULL. */
+    got = D3DXVec2LengthSq(NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+
+/*_______________D3DXVec2Lerp__________________________*/
+    expectedvec.x = 68.0f; expectedvec.y = -28.5f;
+    D3DXVec2Lerp(&gotvec, &u, &v, scale);
+    expect_vec2(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL. */
+    funcpointer = D3DXVec2Lerp(&gotvec,NULL,&v,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec2Lerp(NULL,NULL,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec2Maximize__________________________*/
+    expectedvec.x = 3.0f; expectedvec.y = 9.0f;
+    D3DXVec2Maximize(&gotvec, &u, &v);
+    expect_vec2(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL. */
+    funcpointer = D3DXVec2Maximize(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec2Maximize(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec2Minimize__________________________*/
+    expectedvec.x = -7.0f; expectedvec.y = 4.0f;
+    D3DXVec2Minimize(&gotvec,&u,&v);
+    expect_vec2(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec2Minimize(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec2Minimize(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec2Normalize_________________________*/
+    expectedvec.x = 0.6f; expectedvec.y = 0.8f;
+    D3DXVec2Normalize(&gotvec,&u);
+    expect_vec2(&expectedvec, &gotvec, 0);
+    /* Test the nul vector */
+    expectedvec.x = 0.0f; expectedvec.y = 0.0f;
+    D3DXVec2Normalize(&gotvec,&nul);
+    expect_vec2(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec2Scale____________________________*/
+    expectedvec.x = -19.5f; expectedvec.y = -26.0f;
+    D3DXVec2Scale(&gotvec,&u,scale);
+    expect_vec2(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec2Scale(&gotvec,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec2Scale(NULL,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec2Subtract__________________________*/
+    expectedvec.x = 10.0f; expectedvec.y = -5.0f;
+    D3DXVec2Subtract(&gotvec, &u, &v);
+    expect_vec2(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL. */
+    funcpointer = D3DXVec2Subtract(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec2Subtract(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec2Transform_______________________*/
+    expectedtrans.x = 36.0f; expectedtrans.y = 44.0f; expectedtrans.z = 52.0f; expectedtrans.w = 60.0f;
+    D3DXVec2Transform(&gottrans, &u, &mat);
+    expect_vec4(&expectedtrans, &gottrans, 0);
+    gottrans.x = u.x; gottrans.y = u.y;
+    D3DXVec2Transform(&gottrans, (D3DXVECTOR2 *)&gottrans, &mat);
+    expect_vec4(&expectedtrans, &gottrans, 0);
+
+/*_______________D3DXVec2TransformCoord_______________________*/
+    expectedvec.x = 0.6f; expectedvec.y = 11.0f/15.0f;
+    D3DXVec2TransformCoord(&gotvec, &u, &mat);
+    expect_vec2(&expectedvec, &gotvec, 1);
+    gotvec.x = u.x; gotvec.y = u.y;
+    D3DXVec2TransformCoord(&gotvec, (D3DXVECTOR2 *)&gotvec, &mat);
+    expect_vec2(&expectedvec, &gotvec, 1);
+
+ /*_______________D3DXVec2TransformNormal______________________*/
+    expectedvec.x = 23.0f; expectedvec.y = 30.0f;
+    D3DXVec2TransformNormal(&gotvec,&u,&mat);
+    expect_vec2(&expectedvec, &gotvec, 0);
+}
+
+static void D3DXVector3Test(void)
+{
+    D3DVIEWPORT9 viewport;
+    D3DXVECTOR3 expectedvec, gotvec, nul, u, v, w, x;
+    LPD3DXVECTOR3 funcpointer;
+    D3DXVECTOR4 expectedtrans, gottrans;
+    D3DXMATRIX mat, projection, view, world;
+    float coeff1, coeff2, got, scale;
+    BOOL equal;
+
+    nul.x = 0.0f; nul.y = 0.0f; nul.z = 0.0f;
+    u.x = 9.0f; u.y = 6.0f; u.z = 2.0f;
+    v.x = 2.0f; v.y = -3.0f; v.z = -4.0;
+    w.x = 3.0f; w.y = -5.0f; w.z = 7.0f;
+    x.x = 4.0f; x.y = 1.0f; x.z = 11.0f;
+
+    viewport.Width = 800; viewport.MinZ = 0.2f; viewport.X = 10;
+    viewport.Height = 680; viewport.MaxZ = 0.9f; viewport.Y = 5;
+
+    set_matrix(&mat,
+            1.0f, 2.0f, 3.0f, 4.0f,
+            5.0f, 6.0f, 7.0f, 8.0f,
+            9.0f, 10.0f, 11.0f, 12.0f,
+            13.0f, 14.0f, 15.0f, 16.0f);
+
+    U(view).m[0][1] = 5.0f; U(view).m[0][2] = 7.0f; U(view).m[0][3] = 8.0f;
+    U(view).m[1][0] = 11.0f; U(view).m[1][2] = 16.0f; U(view).m[1][3] = 33.0f;
+    U(view).m[2][0] = 19.0f; U(view).m[2][1] = -21.0f; U(view).m[2][3] = 43.0f;
+    U(view).m[3][0] = 2.0f; U(view).m[3][1] = 3.0f; U(view).m[3][2] = -4.0f;
+    U(view).m[0][0] = 10.0f; U(view).m[1][1] = 20.0f; U(view).m[2][2] = 30.0f;
+    U(view).m[3][3] = -40.0f;
+
+    set_matrix(&world,
+            21.0f, 2.0f, 3.0f, 4.0f,
+            5.0f, 23.0f, 7.0f, 8.0f,
+            -8.0f, -7.0f, 25.0f, -5.0f,
+            -4.0f, -3.0f, -2.0f, 27.0f);
+
+    coeff1 = 2.0f; coeff2 = 5.0f;
+    scale = -6.5f;
+
+/*_______________D3DXVec3Add__________________________*/
+    expectedvec.x = 11.0f; expectedvec.y = 3.0f; expectedvec.z = -2.0f;
+    D3DXVec3Add(&gotvec,&u,&v);
+    expect_vec3(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec3Add(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec3Add(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec3BaryCentric___________________*/
+    expectedvec.x = -35.0f; expectedvec.y = -67.0; expectedvec.z = 15.0f;
+    D3DXVec3BaryCentric(&gotvec,&u,&v,&w,coeff1,coeff2);
+    expect_vec3(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec3CatmullRom____________________*/
+    expectedvec.x = 1458.0f; expectedvec.y = 22.1875f; expectedvec.z = 4141.375f;
+    D3DXVec3CatmullRom(&gotvec,&u,&v,&w,&x,scale);
+    expect_vec3(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec3Cross________________________*/
+    expectedvec.x = -18.0f; expectedvec.y = 40.0f; expectedvec.z = -39.0f;
+    D3DXVec3Cross(&gotvec,&u,&v);
+    expect_vec3(&expectedvec, &gotvec, 0);
+    expectedvec.x = -277.0f; expectedvec.y = -150.0f; expectedvec.z = -26.0f;
+    D3DXVec3Cross(&gotvec,&gotvec,&v);
+    expect_vec3(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec3Cross(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec3Cross(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec3Dot__________________________*/
+    got = D3DXVec3Dot(&u, &v);
+    equal = compare_float(got, -8.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+    /* Tests the case NULL */
+    got = D3DXVec3Dot(NULL, &v);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+    got = D3DXVec3Dot(NULL, NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+
+/*_______________D3DXVec3Hermite__________________________*/
+    expectedvec.x = -6045.75f; expectedvec.y = -6650.0f; expectedvec.z = 1358.875f;
+    D3DXVec3Hermite(&gotvec,&u,&v,&w,&x,scale);
+    expect_vec3(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec3Length__________________________*/
+    got = D3DXVec3Length(&u);
+    equal = compare_float(got, 11.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+    /* Tests the case NULL. */
+    got = D3DXVec3Length(NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+
+/*_______________D3DXVec3LengthSq________________________*/
+    got = D3DXVec3LengthSq(&u);
+    equal = compare_float(got, 121.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+    /* Tests the case NULL. */
+    got = D3DXVec3LengthSq(NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+
+/*_______________D3DXVec3Lerp__________________________*/
+    expectedvec.x = 54.5f; expectedvec.y = 64.5f, expectedvec.z = 41.0f ;
+    D3DXVec3Lerp(&gotvec,&u,&v,scale);
+    expect_vec3(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec3Lerp(&gotvec,NULL,&v,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec3Lerp(NULL,NULL,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec3Maximize__________________________*/
+    expectedvec.x = 9.0f; expectedvec.y = 6.0f; expectedvec.z = 2.0f;
+    D3DXVec3Maximize(&gotvec,&u,&v);
+    expect_vec3(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec3Maximize(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec3Maximize(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec3Minimize__________________________*/
+    expectedvec.x = 2.0f; expectedvec.y = -3.0f; expectedvec.z = -4.0f;
+    D3DXVec3Minimize(&gotvec,&u,&v);
+    expect_vec3(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec3Minimize(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec3Minimize(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec3Normalize_________________________*/
+    expectedvec.x = 9.0f/11.0f; expectedvec.y = 6.0f/11.0f; expectedvec.z = 2.0f/11.0f;
+    D3DXVec3Normalize(&gotvec,&u);
+    expect_vec3(&expectedvec, &gotvec, 1);
+    /* Test the nul vector */
+    expectedvec.x = 0.0f; expectedvec.y = 0.0f; expectedvec.z = 0.0f;
+    D3DXVec3Normalize(&gotvec,&nul);
+    expect_vec3(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec3Scale____________________________*/
+    expectedvec.x = -58.5f; expectedvec.y = -39.0f; expectedvec.z = -13.0f;
+    D3DXVec3Scale(&gotvec,&u,scale);
+    expect_vec3(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec3Scale(&gotvec,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec3Scale(NULL,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec3Subtract_______________________*/
+    expectedvec.x = 7.0f; expectedvec.y = 9.0f; expectedvec.z = 6.0f;
+    D3DXVec3Subtract(&gotvec,&u,&v);
+    expect_vec3(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec3Subtract(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec3Subtract(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec3Transform_______________________*/
+    expectedtrans.x = 70.0f; expectedtrans.y = 88.0f; expectedtrans.z = 106.0f; expectedtrans.w = 124.0f;
+    D3DXVec3Transform(&gottrans, &u, &mat);
+    expect_vec4(&expectedtrans, &gottrans, 0);
+
+    gottrans.x = u.x; gottrans.y = u.y; gottrans.z = u.z;
+    D3DXVec3Transform(&gottrans, (D3DXVECTOR3 *)&gottrans, &mat);
+    expect_vec4(&expectedtrans, &gottrans, 0);
+
+/*_______________D3DXVec3TransformCoord_______________________*/
+    expectedvec.x = 70.0f/124.0f; expectedvec.y = 88.0f/124.0f; expectedvec.z = 106.0f/124.0f;
+    D3DXVec3TransformCoord(&gotvec,&u,&mat);
+    expect_vec3(&expectedvec, &gotvec, 1);
+
+/*_______________D3DXVec3TransformNormal______________________*/
+    expectedvec.x = 57.0f; expectedvec.y = 74.0f; expectedvec.z = 91.0f;
+    D3DXVec3TransformNormal(&gotvec,&u,&mat);
+    expect_vec3(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec3Project_________________________*/
+    expectedvec.x = 1135.721924f; expectedvec.y = 147.086914f; expectedvec.z = 0.153412f;
+    D3DXMatrixPerspectiveFovLH(&projection,D3DX_PI/4.0f,20.0f/17.0f,1.0f,1000.0f);
+    D3DXVec3Project(&gotvec,&u,&viewport,&projection,&view,&world);
+    expect_vec3(&expectedvec, &gotvec, 32);
+    /* World matrix can be omitted */
+    D3DXMatrixMultiply(&mat,&world,&view);
+    D3DXVec3Project(&gotvec,&u,&viewport,&projection,&mat,NULL);
+    expect_vec3(&expectedvec, &gotvec, 32);
+    /* Projection matrix can be omitted */
+    D3DXMatrixMultiply(&mat,&view,&projection);
+    D3DXVec3Project(&gotvec,&u,&viewport,NULL,&mat,&world);
+    expect_vec3(&expectedvec, &gotvec, 32);
+    /* View matrix can be omitted */
+    D3DXMatrixMultiply(&mat,&world,&view);
+    D3DXVec3Project(&gotvec,&u,&viewport,&projection,NULL,&mat);
+    expect_vec3(&expectedvec, &gotvec, 32);
+    /* All matrices can be omitted */
+    expectedvec.x = 4010.000000f; expectedvec.y = -1695.000000f; expectedvec.z = 1.600000f;
+    D3DXVec3Project(&gotvec,&u,&viewport,NULL,NULL,NULL);
+    expect_vec3(&expectedvec, &gotvec, 2);
+    /* Viewport can be omitted */
+    expectedvec.x = 1.814305f; expectedvec.y = 0.582097f; expectedvec.z = -0.066555f;
+    D3DXVec3Project(&gotvec,&u,NULL,&projection,&view,&world);
+    expect_vec3(&expectedvec, &gotvec, 64);
+
+/*_______________D3DXVec3Unproject_________________________*/
+    expectedvec.x = -2.913411f; expectedvec.y = 1.593215f; expectedvec.z = 0.380724f;
+    D3DXMatrixPerspectiveFovLH(&projection,D3DX_PI/4.0f,20.0f/17.0f,1.0f,1000.0f);
+    D3DXVec3Unproject(&gotvec,&u,&viewport,&projection,&view,&world);
+    expect_vec3(&expectedvec, &gotvec, 16);
+    /* World matrix can be omitted */
+    D3DXMatrixMultiply(&mat,&world,&view);
+    D3DXVec3Unproject(&gotvec,&u,&viewport,&projection,&mat,NULL);
+    expect_vec3(&expectedvec, &gotvec, 16);
+    /* Projection matrix can be omitted */
+    D3DXMatrixMultiply(&mat,&view,&projection);
+    D3DXVec3Unproject(&gotvec,&u,&viewport,NULL,&mat,&world);
+    expect_vec3(&expectedvec, &gotvec, 32);
+    /* View matrix can be omitted */
+    D3DXMatrixMultiply(&mat,&world,&view);
+    D3DXVec3Unproject(&gotvec,&u,&viewport,&projection,NULL,&mat);
+    expect_vec3(&expectedvec, &gotvec, 16);
+    /* All matrices can be omitted */
+    expectedvec.x = -1.002500f; expectedvec.y = 0.997059f; expectedvec.z = 2.571429f;
+    D3DXVec3Unproject(&gotvec,&u,&viewport,NULL,NULL,NULL);
+    expect_vec3(&expectedvec, &gotvec, 4);
+    /* Viewport can be omitted */
+    expectedvec.x = -11.018396f; expectedvec.y = 3.218991f; expectedvec.z = 1.380329f;
+    D3DXVec3Unproject(&gotvec,&u,NULL,&projection,&view,&world);
+    expect_vec3(&expectedvec, &gotvec, 8);
+}
+
+static void D3DXVector4Test(void)
+{
+    D3DXVECTOR4 expectedvec, gotvec, u, v, w, x;
+    LPD3DXVECTOR4 funcpointer;
+    D3DXVECTOR4 expectedtrans, gottrans;
+    float coeff1, coeff2, got, scale;
+    D3DXMATRIX mat;
+    BOOL equal;
+
+    u.x = 1.0f; u.y = 2.0f; u.z = 4.0f; u.w = 10.0;
+    v.x = -3.0f; v.y = 4.0f; v.z = -5.0f; v.w = 7.0;
+    w.x = 4.0f; w.y =6.0f; w.z = -2.0f; w.w = 1.0f;
+    x.x = 6.0f; x.y = -7.0f; x.z =8.0f; x.w = -9.0f;
+
+    set_matrix(&mat,
+            1.0f, 2.0f, 3.0f, 4.0f,
+            5.0f, 6.0f, 7.0f, 8.0f,
+            9.0f, 10.0f, 11.0f, 12.0f,
+            13.0f, 14.0f, 15.0f, 16.0f);
+
+    coeff1 = 2.0f; coeff2 = 5.0;
+    scale = -6.5f;
+
+/*_______________D3DXVec4Add__________________________*/
+    expectedvec.x = -2.0f; expectedvec.y = 6.0f; expectedvec.z = -1.0f; expectedvec.w = 17.0f;
+    D3DXVec4Add(&gotvec,&u,&v);
+    expect_vec4(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec4Add(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec4Add(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec4BaryCentric____________________*/
+    expectedvec.x = 8.0f; expectedvec.y = 26.0; expectedvec.z =  -44.0f; expectedvec.w = -41.0f;
+    D3DXVec4BaryCentric(&gotvec,&u,&v,&w,coeff1,coeff2);
+    expect_vec4(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec4CatmullRom____________________*/
+    expectedvec.x = 2754.625f; expectedvec.y = 2367.5625f; expectedvec.z = 1060.1875f; expectedvec.w = 131.3125f;
+    D3DXVec4CatmullRom(&gotvec,&u,&v,&w,&x,scale);
+    expect_vec4(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec4Cross_________________________*/
+    expectedvec.x = 390.0f; expectedvec.y = -393.0f; expectedvec.z = -316.0f; expectedvec.w = 166.0f;
+    D3DXVec4Cross(&gotvec,&u,&v,&w);
+    expect_vec4(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec4Dot__________________________*/
+    got = D3DXVec4Dot(&u, &v);
+    equal = compare_float(got, 55.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+    /* Tests the case NULL. */
+    got = D3DXVec4Dot(NULL, &v);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+    got = D3DXVec4Dot(NULL, NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected dot %.8e.\n", got);
+
+/*_______________D3DXVec4Hermite_________________________*/
+    expectedvec.x = 1224.625f; expectedvec.y = 3461.625f; expectedvec.z = -4758.875f; expectedvec.w = -5781.5f;
+    D3DXVec4Hermite(&gotvec,&u,&v,&w,&x,scale);
+    expect_vec4(&expectedvec, &gotvec, 0);
+
+/*_______________D3DXVec4Length__________________________*/
+    got = D3DXVec4Length(&u);
+    equal = compare_float(got, 11.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+    /* Tests the case NULL. */
+    got = D3DXVec4Length(NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+
+/*_______________D3DXVec4LengthSq________________________*/
+    got = D3DXVec4LengthSq(&u);
+    equal = compare_float(got, 121.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+    /* Tests the case NULL. */
+    got = D3DXVec4LengthSq(NULL);
+    equal = compare_float(got, 0.0f, 0);
+    ok(equal, "Got unexpected length %.8e.\n", got);
+
+/*_______________D3DXVec4Lerp__________________________*/
+    expectedvec.x = 27.0f; expectedvec.y = -11.0f; expectedvec.z = 62.5;  expectedvec.w = 29.5;
+    D3DXVec4Lerp(&gotvec,&u,&v,scale);
+    expect_vec4(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec4Lerp(&gotvec,NULL,&v,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec4Lerp(NULL,NULL,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec4Maximize__________________________*/
+    expectedvec.x = 1.0f; expectedvec.y = 4.0f; expectedvec.z = 4.0f; expectedvec.w = 10.0;
+    D3DXVec4Maximize(&gotvec,&u,&v);
+    expect_vec4(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec4Maximize(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec4Maximize(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec4Minimize__________________________*/
+    expectedvec.x = -3.0f; expectedvec.y = 2.0f; expectedvec.z = -5.0f; expectedvec.w = 7.0;
+    D3DXVec4Minimize(&gotvec,&u,&v);
+    expect_vec4(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec4Minimize(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec4Minimize(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec4Normalize_________________________*/
+    expectedvec.x = 1.0f/11.0f; expectedvec.y = 2.0f/11.0f; expectedvec.z = 4.0f/11.0f; expectedvec.w = 10.0f/11.0f;
+    D3DXVec4Normalize(&gotvec,&u);
+    expect_vec4(&expectedvec, &gotvec, 1);
+
+/*_______________D3DXVec4Scale____________________________*/
+    expectedvec.x = -6.5f; expectedvec.y = -13.0f; expectedvec.z = -26.0f; expectedvec.w = -65.0f;
+    D3DXVec4Scale(&gotvec,&u,scale);
+    expect_vec4(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec4Scale(&gotvec,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec4Scale(NULL,NULL,scale);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec4Subtract__________________________*/
+    expectedvec.x = 4.0f; expectedvec.y = -2.0f; expectedvec.z = 9.0f; expectedvec.w = 3.0f;
+    D3DXVec4Subtract(&gotvec,&u,&v);
+    expect_vec4(&expectedvec, &gotvec, 0);
+    /* Tests the case NULL */
+    funcpointer = D3DXVec4Subtract(&gotvec,NULL,&v);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+    funcpointer = D3DXVec4Subtract(NULL,NULL,NULL);
+    ok(funcpointer == NULL, "Expected: %p, Got: %p\n", NULL, funcpointer);
+
+/*_______________D3DXVec4Transform_______________________*/
+    expectedtrans.x = 177.0f; expectedtrans.y = 194.0f; expectedtrans.z = 211.0f; expectedtrans.w = 228.0f;
+    D3DXVec4Transform(&gottrans,&u,&mat);
+    expect_vec4(&expectedtrans, &gottrans, 0);
+}
+
+static void test_matrix_stack(void)
+{
+    ID3DXMatrixStack *stack;
+    ULONG refcount;
+    HRESULT hr;
+
+    const D3DXMATRIX mat1 = {{{
+         1.0f,  2.0f,  3.0f,  4.0f,
+         5.0f,  6.0f,  7.0f,  8.0f,
+         9.0f, 10.0f, 11.0f, 12.0f,
+        13.0f, 14.0f, 15.0f, 16.0f
+    }}};
+
+    const D3DXMATRIX mat2 = {{{
+        17.0f, 18.0f, 19.0f, 20.0f,
+        21.0f, 22.0f, 23.0f, 24.0f,
+        25.0f, 26.0f, 27.0f, 28.0f,
+        29.0f, 30.0f, 31.0f, 32.0f
+    }}};
+
+    hr = D3DXCreateMatrixStack(0, &stack);
+    ok(SUCCEEDED(hr), "Failed to create a matrix stack, hr %#x\n", hr);
+    if (FAILED(hr)) return;
+
+    ok(D3DXMatrixIsIdentity(ID3DXMatrixStack_GetTop(stack)),
+            "The top of an empty matrix stack should be an identity matrix\n");
+
+    hr = ID3DXMatrixStack_Pop(stack);
+    ok(SUCCEEDED(hr), "Pop failed, hr %#x\n", hr);
+
+    hr = ID3DXMatrixStack_Push(stack);
+    ok(SUCCEEDED(hr), "Push failed, hr %#x\n", hr);
+    ok(D3DXMatrixIsIdentity(ID3DXMatrixStack_GetTop(stack)), "The top should be an identity matrix\n");
+
+    hr = ID3DXMatrixStack_Push(stack);
+    ok(SUCCEEDED(hr), "Push failed, hr %#x\n", hr);
+
+    hr = ID3DXMatrixStack_LoadMatrix(stack, &mat1);
+    ok(SUCCEEDED(hr), "LoadMatrix failed, hr %#x\n", hr);
+    expect_matrix(&mat1, ID3DXMatrixStack_GetTop(stack), 0);
+
+    hr = ID3DXMatrixStack_Push(stack);
+    ok(SUCCEEDED(hr), "Push failed, hr %#x\n", hr);
+    expect_matrix(&mat1, ID3DXMatrixStack_GetTop(stack), 0);
+
+    hr = ID3DXMatrixStack_LoadMatrix(stack, &mat2);
+    ok(SUCCEEDED(hr), "LoadMatrix failed, hr %#x\n", hr);
+    expect_matrix(&mat2, ID3DXMatrixStack_GetTop(stack), 0);
+
+    hr = ID3DXMatrixStack_Push(stack);
+    ok(SUCCEEDED(hr), "Push failed, hr %#x\n", hr);
+    expect_matrix(&mat2, ID3DXMatrixStack_GetTop(stack), 0);
+
+    hr = ID3DXMatrixStack_LoadIdentity(stack);
+    ok(SUCCEEDED(hr), "LoadIdentity failed, hr %#x\n", hr);
+    ok(D3DXMatrixIsIdentity(ID3DXMatrixStack_GetTop(stack)), "The top should be an identity matrix\n");
+
+    hr = ID3DXMatrixStack_Pop(stack);
+    ok(SUCCEEDED(hr), "Pop failed, hr %#x\n", hr);
+    expect_matrix(&mat2, ID3DXMatrixStack_GetTop(stack), 0);
+
+    hr = ID3DXMatrixStack_Pop(stack);
+    ok(SUCCEEDED(hr), "Pop failed, hr %#x\n", hr);
+    expect_matrix(&mat1, ID3DXMatrixStack_GetTop(stack), 0);
+
+    hr = ID3DXMatrixStack_Pop(stack);
+    ok(SUCCEEDED(hr), "Pop failed, hr %#x\n", hr);
+    ok(D3DXMatrixIsIdentity(ID3DXMatrixStack_GetTop(stack)), "The top should be an identity matrix\n");
+
+    hr = ID3DXMatrixStack_Pop(stack);
+    ok(SUCCEEDED(hr), "Pop failed, hr %#x\n", hr);
+    ok(D3DXMatrixIsIdentity(ID3DXMatrixStack_GetTop(stack)), "The top should be an identity matrix\n");
+
+    refcount = ID3DXMatrixStack_Release(stack);
+    ok(!refcount, "Matrix stack has %u references left.\n", refcount);
+}
+
+static void test_Matrix_AffineTransformation2D(void)
+{
+    D3DXMATRIX exp_mat, got_mat;
+    D3DXVECTOR2 center, position;
+    FLOAT angle, scale;
+
+    center.x = 3.0f;
+    center.y = 4.0f;
+
+    position.x = -6.0f;
+    position.y = 7.0f;
+
+    angle = D3DX_PI/3.0f;
+
+    scale = 20.0f;
+
+    U(exp_mat).m[0][0] = 10.0f;
+    U(exp_mat).m[1][0] = -17.320507f;
+    U(exp_mat).m[2][0] = 0.0f;
+    U(exp_mat).m[3][0] = -1.035898f;
+    U(exp_mat).m[0][1] = 17.320507f;
+    U(exp_mat).m[1][1] = 10.0f;
+    U(exp_mat).m[2][1] = 0.0f;
+    U(exp_mat).m[3][1] = 6.401924f;
+    U(exp_mat).m[0][2] = 0.0f;
+    U(exp_mat).m[1][2] = 0.0f;
+    U(exp_mat).m[2][2] = 1.0f;
+    U(exp_mat).m[3][2] = 0.0f;
+    U(exp_mat).m[0][3] = 0.0f;
+    U(exp_mat).m[1][3] = 0.0f;
+    U(exp_mat).m[2][3] = 0.0f;
+    U(exp_mat).m[3][3] = 1.0f;
+
+    D3DXMatrixAffineTransformation2D(&got_mat, scale, &center, angle, &position);
+    expect_matrix(&exp_mat, &got_mat, 2);
+
+/*______________*/
+
+    center.x = 3.0f;
+    center.y = 4.0f;
+
+    angle = D3DX_PI/3.0f;
+
+    scale = 20.0f;
+
+    U(exp_mat).m[0][0] = 10.0f;
+    U(exp_mat).m[1][0] = -17.320507f;
+    U(exp_mat).m[2][0] = 0.0f;
+    U(exp_mat).m[3][0] = 4.964102f;
+    U(exp_mat).m[0][1] = 17.320507f;
+    U(exp_mat).m[1][1] = 10.0f;
+    U(exp_mat).m[2][1] = 0.0f;
+    U(exp_mat).m[3][1] = -0.598076f;
+    U(exp_mat).m[0][2] = 0.0f;
+    U(exp_mat).m[1][2] = 0.0f;
+    U(exp_mat).m[2][2] = 1.0f;
+    U(exp_mat).m[3][2] = 0.0f;
+    U(exp_mat).m[0][3] = 0.0f;
+    U(exp_mat).m[1][3] = 0.0f;
+    U(exp_mat).m[2][3] = 0.0f;
+    U(exp_mat).m[3][3] = 1.0f;
+
+    D3DXMatrixAffineTransformation2D(&got_mat, scale, &center, angle, NULL);
+    expect_matrix(&exp_mat, &got_mat, 8);
+
+/*______________*/
+
+    position.x = -6.0f;
+    position.y = 7.0f;
+
+    angle = D3DX_PI/3.0f;
+
+    scale = 20.0f;
+
+    U(exp_mat).m[0][0] = 10.0f;
+    U(exp_mat).m[1][0] = -17.320507f;
+    U(exp_mat).m[2][0] = 0.0f;
+    U(exp_mat).m[3][0] = -6.0f;
+    U(exp_mat).m[0][1] = 17.320507f;
+    U(exp_mat).m[1][1] = 10.0f;
+    U(exp_mat).m[2][1] = 0.0f;
+    U(exp_mat).m[3][1] = 7.0f;
+    U(exp_mat).m[0][2] = 0.0f;
+    U(exp_mat).m[1][2] = 0.0f;
+    U(exp_mat).m[2][2] = 1.0f;
+    U(exp_mat).m[3][2] = 0.0f;
+    U(exp_mat).m[0][3] = 0.0f;
+    U(exp_mat).m[1][3] = 0.0f;
+    U(exp_mat).m[2][3] = 0.0f;
+    U(exp_mat).m[3][3] = 1.0f;
+
+    D3DXMatrixAffineTransformation2D(&got_mat, scale, NULL, angle, &position);
+    expect_matrix(&exp_mat, &got_mat, 1);
+
+/*______________*/
+
+    angle = 5.0f * D3DX_PI/4.0f;
+
+    scale = -20.0f;
+
+    U(exp_mat).m[0][0] = 14.142133f;
+    U(exp_mat).m[1][0] = -14.142133f;
+    U(exp_mat).m[2][0] = 0.0f;
+    U(exp_mat).m[3][0] = 0.0f;
+    U(exp_mat).m[0][1] = 14.142133;
+    U(exp_mat).m[1][1] = 14.142133f;
+    U(exp_mat).m[2][1] = 0.0f;
+    U(exp_mat).m[3][1] = 0.0f;
+    U(exp_mat).m[0][2] = 0.0f;
+    U(exp_mat).m[1][2] = 0.0f;
+    U(exp_mat).m[2][2] = 1.0f;
+    U(exp_mat).m[3][2] = 0.0f;
+    U(exp_mat).m[0][3] = 0.0f;
+    U(exp_mat).m[1][3] = 0.0f;
+    U(exp_mat).m[2][3] = 0.0f;
+    U(exp_mat).m[3][3] = 1.0f;
+
+    D3DXMatrixAffineTransformation2D(&got_mat, scale, NULL, angle, NULL);
+    expect_matrix(&exp_mat, &got_mat, 8);
+}
+
+static void test_Matrix_Decompose(void)
+{
+    D3DXMATRIX pm;
+    D3DXQUATERNION exp_rotation, got_rotation;
+    D3DXVECTOR3 exp_scale, got_scale, exp_translation, got_translation;
+    HRESULT hr;
+    BOOL equal;
+
+/*___________*/
+
+    U(pm).m[0][0] = -9.23879206e-01f;
+    U(pm).m[1][0] = -2.70598412e-01f;
+    U(pm).m[2][0] =  2.70598441e-01f;
+    U(pm).m[3][0] = -5.00000000e+00f;
+    U(pm).m[0][1] =  2.70598471e-01f;
+    U(pm).m[1][1] =  3.80604863e-02f;
+    U(pm).m[2][1] =  9.61939573e-01f;
+    U(pm).m[3][1] =  0.00000000e+00f;
+    U(pm).m[0][2] = -2.70598441e-01f;
+    U(pm).m[1][2] =  9.61939573e-01f;
+    U(pm).m[2][2] =  3.80603075e-02f;
+    U(pm).m[3][2] =  1.00000000e+01f;
+    U(pm).m[0][3] =  0.00000000e+00f;
+    U(pm).m[1][3] =  0.00000000e+00f;
+    U(pm).m[2][3] =  0.00000000e+00f;
+    U(pm).m[3][3] =  1.00000000e+00f;
+
+    exp_scale.x = 9.99999881e-01f;
+    exp_scale.y = 9.99999881e-01f;
+    exp_scale.z = 9.99999881e-01f;
+
+    exp_rotation.x = 2.14862776e-08f;
+    exp_rotation.y = 6.93519890e-01f;
+    exp_rotation.z = 6.93519890e-01f;
+    exp_rotation.w = 1.95090637e-01f;
+
+    exp_translation.x = -5.0f;
+    exp_translation.y = 0.0f;
+    exp_translation.z = 10.0f;
+
+    D3DXMatrixDecompose(&got_scale, &got_rotation, &got_translation, &pm);
+    expect_vec3(&exp_scale, &got_scale, 1);
+    expect_quaternion(&exp_rotation, &got_rotation, 1);
+    expect_vec3(&exp_translation, &got_translation, 0);
+
+/*_________*/
+
+    U(pm).m[0][0] = -2.255813f;
+    U(pm).m[1][0] = 1.302324f;
+    U(pm).m[2][0] = 1.488373f;
+    U(pm).m[3][0] = 1.0f;
+    U(pm).m[0][1] = 1.302327f;
+    U(pm).m[1][1] = -0.7209296f;
+    U(pm).m[2][1] = 2.60465f;
+    U(pm).m[3][1] = 2.0f;
+    U(pm).m[0][2] = 1.488371f;
+    U(pm).m[1][2] = 2.604651f;
+    U(pm).m[2][2] = -0.02325551f;
+    U(pm).m[3][2] = 3.0f;
+    U(pm).m[0][3] = 0.0f;
+    U(pm).m[1][3] = 0.0f;
+    U(pm).m[2][3] = 0.0f;
+    U(pm).m[3][3] = 1.0f;
+
+    exp_scale.x = 2.99999928e+00f;
+    exp_scale.y = 2.99999905e+00f;
+    exp_scale.z = 2.99999952e+00f;
+
+    exp_rotation.x = 3.52180451e-01f;
+    exp_rotation.y = 6.16315663e-01f;
+    exp_rotation.z = 7.04360664e-01f;
+    exp_rotation.w = 3.38489343e-07f;
+
+    exp_translation.x = 1.0f;
+    exp_translation.y = 2.0f;
+    exp_translation.z = 3.0f;
+
+    D3DXMatrixDecompose(&got_scale, &got_rotation, &got_translation, &pm);
+    expect_vec3(&exp_scale, &got_scale, 0);
+    expect_quaternion(&exp_rotation, &got_rotation, 2);
+    expect_vec3(&exp_translation, &got_translation, 0);
+
+/*_____________*/
+
+    U(pm).m[0][0] = 2.427051f;
+    U(pm).m[1][0] = 0.0f;
+    U(pm).m[2][0] = 1.763355f;
+    U(pm).m[3][0] = 5.0f;
+    U(pm).m[0][1] = 0.0f;
+    U(pm).m[1][1] = 3.0f;
+    U(pm).m[2][1] = 0.0f;
+    U(pm).m[3][1] = 5.0f;
+    U(pm).m[0][2] = -1.763355f;
+    U(pm).m[1][2] = 0.0f;
+    U(pm).m[2][2] = 2.427051f;
+    U(pm).m[3][2] = 5.0f;
+    U(pm).m[0][3] = 0.0f;
+    U(pm).m[1][3] = 0.0f;
+    U(pm).m[2][3] = 0.0f;
+    U(pm).m[3][3] = 1.0f;
+
+    exp_scale.x = 2.99999976e+00f;
+    exp_scale.y = 3.00000000e+00f;
+    exp_scale.z = 2.99999976e+00f;
+
+    exp_rotation.x = 0.00000000e+00f;
+    exp_rotation.y = 3.09016883e-01f;
+    exp_rotation.z = 0.00000000e+00f;
+    exp_rotation.w = 9.51056540e-01f;
+
+    exp_translation.x = 5.0f;
+    exp_translation.y = 5.0f;
+    exp_translation.z = 5.0f;
+
+    D3DXMatrixDecompose(&got_scale, &got_rotation, &got_translation, &pm);
+    expect_vec3(&exp_scale, &got_scale, 1);
+    expect_quaternion(&exp_rotation, &got_rotation, 1);
+    expect_vec3(&exp_translation, &got_translation, 0);
+
+/*_____________*/
+
+    U(pm).m[0][0] = -9.23879206e-01f;
+    U(pm).m[1][0] = -2.70598412e-01f;
+    U(pm).m[2][0] =  2.70598441e-01f;
+    U(pm).m[3][0] = -5.00000000e+00f;
+    U(pm).m[0][1] =  2.70598471e-01f;
+    U(pm).m[1][1] =  3.80604863e-02f;
+    U(pm).m[2][1] =  9.61939573e-01f;
+    U(pm).m[3][1] =  0.00000000e+00f;
+    U(pm).m[0][2] = -2.70598441e-01f;
+    U(pm).m[1][2] =  9.61939573e-01f;
+    U(pm).m[2][2] =  3.80603075e-02f;
+    U(pm).m[3][2] =  1.00000000e+01f;
+    U(pm).m[0][3] =  0.00000000e+00f;
+    U(pm).m[1][3] =  0.00000000e+00f;
+    U(pm).m[2][3] =  0.00000000e+00f;
+    U(pm).m[3][3] =  1.00000000e+00f;
+
+    exp_scale.x = 9.99999881e-01f;
+    exp_scale.y = 9.99999881e-01f;
+    exp_scale.z = 9.99999881e-01f;
+
+    exp_rotation.x = 2.14862776e-08f;
+    exp_rotation.y = 6.93519890e-01f;
+    exp_rotation.z = 6.93519890e-01f;
+    exp_rotation.w = 1.95090637e-01f;
+
+    exp_translation.x = -5.0f;
+    exp_translation.y = 0.0f;
+    exp_translation.z = 10.0f;
+
+    D3DXMatrixDecompose(&got_scale, &got_rotation, &got_translation, &pm);
+    expect_vec3(&exp_scale, &got_scale, 1);
+    expect_quaternion(&exp_rotation, &got_rotation, 1);
+    expect_vec3(&exp_translation, &got_translation, 0);
+
+/*__________*/
+
+    U(pm).m[0][0] = -9.23878908e-01f;
+    U(pm).m[1][0] = -5.41196704e-01f;
+    U(pm).m[2][0] =  8.11795175e-01f;
+    U(pm).m[3][0] = -5.00000000e+00f;
+    U(pm).m[0][1] =  2.70598322e-01f;
+    U(pm).m[1][1] =  7.61209577e-02f;
+    U(pm).m[2][1] =  2.88581824e+00f;
+    U(pm).m[3][1] =  0.00000000e+00f;
+    U(pm).m[0][2] = -2.70598352e-01f;
+    U(pm).m[1][2] =  1.92387879e+00f;
+    U(pm).m[2][2] =  1.14180908e-01f;
+    U(pm).m[3][2] =  1.00000000e+01f;
+    U(pm).m[0][3] =  0.00000000e+00f;
+    U(pm).m[1][3] =  0.00000000e+00f;
+    U(pm).m[2][3] =  0.00000000e+00f;
+    U(pm).m[3][3] =  1.00000000e+00f;
+
+    exp_scale.x = 9.99999583e-01f;
+    exp_scale.y = 1.99999940e+00f;
+    exp_scale.z = 2.99999928e+00f;
+
+    exp_rotation.x = 1.07431388e-08f;
+    exp_rotation.y = 6.93519890e-01f;
+    exp_rotation.z = 6.93519831e-01f;
+    exp_rotation.w = 1.95090622e-01f;
+
+    exp_translation.x = -5.0f;
+    exp_translation.y = 0.0f;
+    exp_translation.z = 10.0f;
+
+    D3DXMatrixDecompose(&got_scale, &got_rotation, &got_translation, &pm);
+    expect_vec3(&exp_scale, &got_scale, 1);
+    equal = compare_quaternion(&exp_rotation, &got_rotation, 1);
+    exp_rotation.x = 0.0f;
+    equal |= compare_quaternion(&exp_rotation, &got_rotation, 2);
+    ok(equal, "Got unexpected quaternion {%.8e, %.8e, %.8e, %.8e}.\n",
+            got_rotation.x, got_rotation.y, got_rotation.z, got_rotation.w);
+    expect_vec3(&exp_translation, &got_translation, 0);
+
+/*__________*/
+
+    U(pm).m[0][0] = 0.7156004f;
+    U(pm).m[1][0] = -0.5098283f;
+    U(pm).m[2][0] = -0.4774843f;
+    U(pm).m[3][0] = -5.0f;
+    U(pm).m[0][1] = -0.6612288f;
+    U(pm).m[1][1] = -0.7147621f;
+    U(pm).m[2][1] = -0.2277977f;
+    U(pm).m[3][1] = 0.0f;
+    U(pm).m[0][2] = -0.2251499f;
+    U(pm).m[1][2] = 0.4787385f;
+    U(pm).m[2][2] = -0.8485972f;
+    U(pm).m[3][2] = 10.0f;
+    U(pm).m[0][3] = 0.0f;
+    U(pm).m[1][3] = 0.0f;
+    U(pm).m[2][3] = 0.0f;
+    U(pm).m[3][3] = 1.0f;
+
+    exp_scale.x = 9.99999940e-01f;
+    exp_scale.y = 1.00000012e+00f;
+    exp_scale.z = 1.00000012e+00f;
+
+    exp_rotation.x = 9.05394852e-01f;
+    exp_rotation.y = -3.23355347e-01f;
+    exp_rotation.z = -1.94013178e-01f;
+    exp_rotation.w = 1.95090592e-01f;
+
+    exp_translation.x = -5.0f;
+    exp_translation.y = 0.0f;
+    exp_translation.z = 10.0f;
+
+    D3DXMatrixDecompose(&got_scale, &got_rotation, &got_translation, &pm);
+    expect_vec3(&exp_scale, &got_scale, 0);
+    expect_quaternion(&exp_rotation, &got_rotation, 1);
+    expect_vec3(&exp_translation, &got_translation, 0);
+
+/*_____________*/
+
+    U(pm).m[0][0] = 0.06554436f;
+    U(pm).m[1][0] = -0.6873012f;
+    U(pm).m[2][0] = 0.7234092f;
+    U(pm).m[3][0] = -5.0f;
+    U(pm).m[0][1] = -0.9617381f;
+    U(pm).m[1][1] = -0.2367795f;
+    U(pm).m[2][1] = -0.1378230f;
+    U(pm).m[3][1] = 0.0f;
+    U(pm).m[0][2] = 0.2660144f;
+    U(pm).m[1][2] = -0.6866967f;
+    U(pm).m[2][2] = -0.6765233f;
+    U(pm).m[3][2] = 10.0f;
+    U(pm).m[0][3] = 0.0f;
+    U(pm).m[1][3] = 0.0f;
+    U(pm).m[2][3] = 0.0f;
+    U(pm).m[3][3] = 1.0f;
+
+    exp_scale.x = 9.99999940e-01f;
+    exp_scale.y = 9.99999940e-01f;
+    exp_scale.z = 9.99999881e-01f;
+
+    exp_rotation.x = 7.03357518e-01f;
+    exp_rotation.y = -5.86131275e-01f;
+    exp_rotation.z = 3.51678789e-01f;
+    exp_rotation.w = -1.95090577e-01f;
+
+    exp_translation.x = -5.0f;
+    exp_translation.y = 0.0f;
+    exp_translation.z = 10.0f;
+
+    D3DXMatrixDecompose(&got_scale, &got_rotation, &got_translation, &pm);
+    expect_vec3(&exp_scale, &got_scale, 1);
+    expect_quaternion(&exp_rotation, &got_rotation, 2);
+    expect_vec3(&exp_translation, &got_translation, 0);
+
+/*_________*/
+
+    U(pm).m[0][0] =  7.12104797e+00f;
+    U(pm).m[1][0] = -5.88348627e+00f;
+    U(pm).m[2][0] =  1.18184204e+01f;
+    U(pm).m[3][0] = -5.00000000e+00f;
+    U(pm).m[0][1] =  5.88348627e+00f;
+    U(pm).m[1][1] = -1.06065865e+01f;
+    U(pm).m[2][1] = -8.82523251e+00f;
+    U(pm).m[3][1] =  0.00000000e+00f;
+    U(pm).m[0][2] =  1.18184204e+01f;
+    U(pm).m[1][2] =  8.82523155e+00f;
+    U(pm).m[2][2] = -2.72764111e+00f;
+    U(pm).m[3][2] =  2.00000000e+00f;
+    U(pm).m[0][3] =  0.00000000e+00f;
+    U(pm).m[1][3] =  0.00000000e+00f;
+    U(pm).m[2][3] =  0.00000000e+00f;
+    U(pm).m[3][3] =  1.00000000e+00f;
+
+    exp_scale.x = 1.49999933e+01f;
+    exp_scale.y = 1.49999933e+01f;
+    exp_scale.z = 1.49999943e+01f;
+
+    exp_rotation.x = 7.68714130e-01f;
+    exp_rotation.y = 0.00000000e+00f;
+    exp_rotation.z = 5.12475967e-01f;
+    exp_rotation.w = 3.82683903e-01f;
+
+    exp_translation.x = -5.0f;
+    exp_translation.y = 0.0f;
+    exp_translation.z = 2.0f;
+
+    D3DXMatrixDecompose(&got_scale, &got_rotation, &got_translation, &pm);
+    expect_vec3(&exp_scale, &got_scale, 0);
+    expect_quaternion(&exp_rotation, &got_rotation, 1);
+    expect_vec3(&exp_translation, &got_translation, 0);
+
+/*__________*/
+
+    U(pm).m[0][0] = 0.0f;
+    U(pm).m[1][0] = 4.0f;
+    U(pm).m[2][0] = 5.0f;
+    U(pm).m[3][0] = -5.0f;
+    U(pm).m[0][1] = 0.0f;
+    U(pm).m[1][1] = -10.60660f;
+    U(pm).m[2][1] = -8.825232f;
+    U(pm).m[3][1] = 6.0f;
+    U(pm).m[0][2] = 0.0f;
+    U(pm).m[1][2] = 8.8252320f;
+    U(pm).m[2][2] = 2.727645;
+    U(pm).m[3][2] = 3.0f;
+    U(pm).m[0][3] = 0.0f;
+    U(pm).m[1][3] = 0.0f;
+    U(pm).m[2][3] = 0.0f;
+    U(pm).m[3][3] = 1.0f;
+
+    hr = D3DXMatrixDecompose(&got_scale, &got_rotation, &got_translation, &pm);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %x\n", hr);
+}
+
+static void test_Matrix_Transformation2D(void)
+{
+    D3DXMATRIX exp_mat, got_mat;
+    D3DXVECTOR2 rot_center, sca, sca_center, trans;
+    FLOAT rot, sca_rot;
+
+    rot_center.x = 3.0f;
+    rot_center.y = 4.0f;
+
+    sca.x = 12.0f;
+    sca.y = -3.0f;
+
+    sca_center.x = 9.0f;
+    sca_center.y = -5.0f;
+
+    trans.x = -6.0f;
+    trans.y = 7.0f;
+
+    rot = D3DX_PI/3.0f;
+
+    sca_rot = 5.0f*D3DX_PI/4.0f;
+
+    U(exp_mat).m[0][0] = -4.245192f;
+    U(exp_mat).m[1][0] = -0.147116f;
+    U(exp_mat).m[2][0] = 0.0f;
+    U(exp_mat).m[3][0] = 45.265373f;
+    U(exp_mat).m[0][1] = 7.647113f;
+    U(exp_mat).m[1][1] = 8.745192f;
+    U(exp_mat).m[2][1] = 0.0f;
+    U(exp_mat).m[3][1] = -13.401899f;
+    U(exp_mat).m[0][2] = 0.0f;
+    U(exp_mat).m[1][2] = 0.0f;
+    U(exp_mat).m[2][2] = 1.0f;
+    U(exp_mat).m[3][2] = 0.0f;
+    U(exp_mat).m[0][3] = 0.0f;
+    U(exp_mat).m[1][3] = 0.0f;
+    U(exp_mat).m[2][3] = 0.0f;
+    U(exp_mat).m[3][3] = 1.0f;
+
+    D3DXMatrixTransformation2D(&got_mat, &sca_center, sca_rot, &sca, &rot_center, rot, &trans);
+    expect_matrix(&exp_mat, &got_mat, 64);
+
+/*_________*/
+
+    sca_center.x = 9.0f;
+    sca_center.y = -5.0f;
+
+    trans.x = -6.0f;
+    trans.y = 7.0f;
+
+    rot = D3DX_PI/3.0f;
+
+    sca_rot = 5.0f*D3DX_PI/4.0f;
+
+    U(exp_mat).m[0][0] = 0.50f;
+    U(exp_mat).m[1][0] = -0.866025f;
+    U(exp_mat).m[2][0] = 0.0f;
+    U(exp_mat).m[3][0] = -6.0f;
+    U(exp_mat).m[0][1] = 0.866025f;
+    U(exp_mat).m[1][1] = 0.50f;
+    U(exp_mat).m[2][1] = 0.0f;
+    U(exp_mat).m[3][1] = 7.0f;
+    U(exp_mat).m[0][2] = 0.0f;
+    U(exp_mat).m[1][2] = 0.0f;
+    U(exp_mat).m[2][2] = 1.0f;
+    U(exp_mat).m[3][2] = 0.0f;
+    U(exp_mat).m[0][3] = 0.0f;
+    U(exp_mat).m[1][3] = 0.0f;
+    U(exp_mat).m[2][3] = 0.0f;
+    U(exp_mat).m[3][3] = 1.0f;
+
+    D3DXMatrixTransformation2D(&got_mat, &sca_center, sca_rot, NULL, NULL, rot, &trans);
+    expect_matrix(&exp_mat, &got_mat, 8);
+
+/*_________*/
+
+    U(exp_mat).m[0][0] = 0.50f;
+    U(exp_mat).m[1][0] = -0.866025f;
+    U(exp_mat).m[2][0] = 0.0f;
+    U(exp_mat).m[3][0] = 0.0f;
+    U(exp_mat).m[0][1] = 0.866025f;
+    U(exp_mat).m[1][1] = 0.50f;
+    U(exp_mat).m[2][1] = 0.0f;
+    U(exp_mat).m[3][1] = 0.0f;
+    U(exp_mat).m[0][2] = 0.0f;
+    U(exp_mat).m[1][2] = 0.0f;
+    U(exp_mat).m[2][2] = 1.0f;
+    U(exp_mat).m[3][2] = 0.0f;
+    U(exp_mat).m[0][3] = 0.0f;
+    U(exp_mat).m[1][3] = 0.0f;
+    U(exp_mat).m[2][3] = 0.0f;
+    U(exp_mat).m[3][3] = 1.0f;
+
+    D3DXMatrixTransformation2D(&got_mat, NULL, sca_rot, NULL, NULL, rot, NULL);
+    expect_matrix(&exp_mat, &got_mat, 8);
+}
+
+static void test_D3DXVec_Array(void)
+{
+    D3DXPLANE inp_plane[5], out_plane[7], exp_plane[7];
+    D3DXVECTOR4 inp_vec[5], out_vec[7], exp_vec[7];
+    D3DXMATRIX mat, projection, view, world;
+    D3DVIEWPORT9 viewport;
+    unsigned int i;
+
+    viewport.Width = 800; viewport.MinZ = 0.2f; viewport.X = 10;
+    viewport.Height = 680; viewport.MaxZ = 0.9f; viewport.Y = 5;
+
+    memset(out_vec, 0, sizeof(out_vec));
+    memset(exp_vec, 0, sizeof(exp_vec));
+    memset(out_plane, 0, sizeof(out_plane));
+    memset(exp_plane, 0, sizeof(exp_plane));
+
+    for (i = 0; i < ARRAY_SIZE(inp_vec); ++i)
+    {
+        inp_plane[i].a = inp_plane[i].c = inp_vec[i].x = inp_vec[i].z = i;
+        inp_plane[i].b = inp_plane[i].d = inp_vec[i].y = inp_vec[i].w = ARRAY_SIZE(inp_vec) - i;
+    }
+
+    set_matrix(&mat,
+            1.0f, 2.0f, 3.0f, 4.0f,
+            5.0f, 6.0f, 7.0f, 8.0f,
+            9.0f, 10.0f, 11.0f, 12.0f,
+            13.0f, 14.0f, 15.0f, 16.0f);
+
+    D3DXMatrixPerspectiveFovLH(&projection, D3DX_PI / 4.0f, 20.0f / 17.0f, 1.0f, 1000.0f);
+
+    U(view).m[0][1] = 5.0f; U(view).m[0][2] = 7.0f; U(view).m[0][3] = 8.0f;
+    U(view).m[1][0] = 11.0f; U(view).m[1][2] = 16.0f; U(view).m[1][3] = 33.0f;
+    U(view).m[2][0] = 19.0f; U(view).m[2][1] = -21.0f; U(view).m[2][3] = 43.0f;
+    U(view).m[3][0] = 2.0f; U(view).m[3][1] = 3.0f; U(view).m[3][2] = -4.0f;
+    U(view).m[0][0] = 10.0f; U(view).m[1][1] = 20.0f; U(view).m[2][2] = 30.0f;
+    U(view).m[3][3] = -40.0f;
+
+    set_matrix(&world,
+            21.0f, 2.0f, 3.0f, 4.0f,
+            5.0f, 23.0f, 7.0f, 8.0f,
+            -8.0f, -7.0f, 25.0f, -5.0f,
+            -4.0f, -3.0f, -2.0f, 27.0f);
+
+    /* D3DXVec2TransformCoordArray */
+    exp_vec[1].x = 6.78571403e-01f; exp_vec[1].y = 7.85714269e-01f;
+    exp_vec[2].x = 6.53846204e-01f; exp_vec[2].y = 7.69230783e-01f;
+    exp_vec[3].x = 6.25000000e-01f; exp_vec[3].y = 7.50000000e-01f;
+    exp_vec[4].x = 5.90909123e-01f; exp_vec[4].y = 7.27272749e-01f;
+    exp_vec[5].x = 5.49999952e-01f; exp_vec[5].y = 6.99999928e-01f;
+    D3DXVec2TransformCoordArray((D3DXVECTOR2 *)&out_vec[1], sizeof(*out_vec),
+            (D3DXVECTOR2 *)inp_vec, sizeof(*inp_vec), &mat, ARRAY_SIZE(inp_vec));
+    expect_vec4_array(ARRAY_SIZE(exp_vec), exp_vec, out_vec, 1);
+
+    /* D3DXVec2TransformNormalArray */
+    exp_vec[1].x = 25.0f; exp_vec[1].y = 30.0f;
+    exp_vec[2].x = 21.0f; exp_vec[2].y = 26.0f;
+    exp_vec[3].x = 17.0f; exp_vec[3].y = 22.0f;
+    exp_vec[4].x = 13.0f; exp_vec[4].y = 18.0f;
+    exp_vec[5].x =  9.0f; exp_vec[5].y = 14.0f;
+    D3DXVec2TransformNormalArray((D3DXVECTOR2 *)&out_vec[1], sizeof(*out_vec),
+            (D3DXVECTOR2 *)inp_vec, sizeof(*inp_vec), &mat, ARRAY_SIZE(inp_vec));
+    expect_vec4_array(ARRAY_SIZE(exp_vec), exp_vec, out_vec, 0);
+
+    /* D3DXVec3TransformCoordArray */
+    exp_vec[1].x = 6.78571403e-01f; exp_vec[1].y = 7.85714269e-01f; exp_vec[1].z = 8.92857075e-01f;
+    exp_vec[2].x = 6.71874940e-01f; exp_vec[2].y = 7.81249940e-01f; exp_vec[2].z = 8.90624940e-01f;
+    exp_vec[3].x = 6.66666627e-01f; exp_vec[3].y = 7.77777731e-01f; exp_vec[3].z = 8.88888836e-01f;
+    exp_vec[4].x = 6.62499964e-01f; exp_vec[4].y = 7.74999976e-01f; exp_vec[4].z = 8.87499928e-01f;
+    exp_vec[5].x = 6.59090877e-01f; exp_vec[5].y = 7.72727251e-01f; exp_vec[5].z = 8.86363566e-01f;
+    D3DXVec3TransformCoordArray((D3DXVECTOR3 *)&out_vec[1], sizeof(*out_vec),
+            (D3DXVECTOR3 *)inp_vec, sizeof(*inp_vec), &mat, ARRAY_SIZE(inp_vec));
+    expect_vec4_array(ARRAY_SIZE(exp_vec), exp_vec, out_vec, 1);
+
+    /* D3DXVec3TransformNormalArray */
+    exp_vec[1].x = 25.0f; exp_vec[1].y = 30.0f; exp_vec[1].z = 35.0f;
+    exp_vec[2].x = 30.0f; exp_vec[2].y = 36.0f; exp_vec[2].z = 42.0f;
+    exp_vec[3].x = 35.0f; exp_vec[3].y = 42.0f; exp_vec[3].z = 49.0f;
+    exp_vec[4].x = 40.0f; exp_vec[4].y = 48.0f; exp_vec[4].z = 56.0f;
+    exp_vec[5].x = 45.0f; exp_vec[5].y = 54.0f; exp_vec[5].z = 63.0f;
+    D3DXVec3TransformNormalArray((D3DXVECTOR3 *)&out_vec[1], sizeof(*out_vec),
+            (D3DXVECTOR3 *)inp_vec, sizeof(*inp_vec), &mat, ARRAY_SIZE(inp_vec));
+    expect_vec4_array(ARRAY_SIZE(exp_vec), exp_vec, out_vec, 0);
+
+    /* D3DXVec3ProjectArray */
+    exp_vec[1].x = 1.08955420e+03f; exp_vec[1].y = -2.26590622e+02f; exp_vec[1].z = 2.15272754e-01f;
+    exp_vec[2].x = 1.06890344e+03f; exp_vec[2].y =  1.03085144e+02f; exp_vec[2].z = 1.83049560e-01f;
+    exp_vec[3].x = 1.05177905e+03f; exp_vec[3].y =  3.76462280e+02f; exp_vec[3].z = 1.56329080e-01f;
+    exp_vec[4].x = 1.03734888e+03f; exp_vec[4].y =  6.06827393e+02f; exp_vec[4].z = 1.33812696e-01f;
+    exp_vec[5].x = 1.02502356e+03f; exp_vec[5].y =  8.03591248e+02f; exp_vec[5].z = 1.14580572e-01f;
+    D3DXVec3ProjectArray((D3DXVECTOR3 *)&out_vec[1], sizeof(*out_vec), (D3DXVECTOR3 *)inp_vec,
+            sizeof(*inp_vec), &viewport, &projection, &view, &world, ARRAY_SIZE(inp_vec));
+    expect_vec4_array(ARRAY_SIZE(exp_vec), exp_vec, out_vec, 8);
+
+    /* D3DXVec3UnprojectArray */
+    exp_vec[1].x = -6.12403107e+00f; exp_vec[1].y = 3.22536016e+00f; exp_vec[1].z = 6.20571136e-01f;
+    exp_vec[2].x = -3.80710936e+00f; exp_vec[2].y = 2.04657936e+00f; exp_vec[2].z = 4.46894377e-01f;
+    exp_vec[3].x = -2.92283988e+00f; exp_vec[3].y = 1.59668946e+00f; exp_vec[3].z = 3.80609393e-01f;
+    exp_vec[4].x = -2.45622563e+00f; exp_vec[4].y = 1.35928988e+00f; exp_vec[4].z = 3.45631927e-01f;
+    exp_vec[5].x = -2.16789746e+00f; exp_vec[5].y = 1.21259713e+00f; exp_vec[5].z = 3.24018806e-01f;
+    D3DXVec3UnprojectArray((D3DXVECTOR3 *)&out_vec[1], sizeof(*out_vec), (D3DXVECTOR3 *)inp_vec,
+            sizeof(*inp_vec), &viewport, &projection, &view, &world, ARRAY_SIZE(inp_vec));
+    expect_vec4_array(ARRAY_SIZE(exp_vec), exp_vec, out_vec, 4);
+
+    /* D3DXVec2TransformArray */
+    exp_vec[1].x = 38.0f; exp_vec[1].y = 44.0f; exp_vec[1].z = 50.0f; exp_vec[1].w = 56.0f;
+    exp_vec[2].x = 34.0f; exp_vec[2].y = 40.0f; exp_vec[2].z = 46.0f; exp_vec[2].w = 52.0f;
+    exp_vec[3].x = 30.0f; exp_vec[3].y = 36.0f; exp_vec[3].z = 42.0f; exp_vec[3].w = 48.0f;
+    exp_vec[4].x = 26.0f; exp_vec[4].y = 32.0f; exp_vec[4].z = 38.0f; exp_vec[4].w = 44.0f;
+    exp_vec[5].x = 22.0f; exp_vec[5].y = 28.0f; exp_vec[5].z = 34.0f; exp_vec[5].w = 40.0f;
+    D3DXVec2TransformArray(&out_vec[1], sizeof(*out_vec), (D3DXVECTOR2 *)inp_vec,
+            sizeof(*inp_vec), &mat, ARRAY_SIZE(inp_vec));
+    expect_vec4_array(ARRAY_SIZE(exp_vec), exp_vec, out_vec, 0);
+
+    /* D3DXVec3TransformArray */
+    exp_vec[1].x = 38.0f; exp_vec[1].y = 44.0f; exp_vec[1].z = 50.0f; exp_vec[1].w = 56.0f;
+    exp_vec[2].x = 43.0f; exp_vec[2].y = 50.0f; exp_vec[2].z = 57.0f; exp_vec[2].w = 64.0f;
+    exp_vec[3].x = 48.0f; exp_vec[3].y = 56.0f; exp_vec[3].z = 64.0f; exp_vec[3].w = 72.0f;
+    exp_vec[4].x = 53.0f; exp_vec[4].y = 62.0f; exp_vec[4].z = 71.0f; exp_vec[4].w = 80.0f;
+    exp_vec[5].x = 58.0f; exp_vec[5].y = 68.0f; exp_vec[5].z = 78.0f; exp_vec[5].w = 88.0f;
+    D3DXVec3TransformArray(&out_vec[1], sizeof(*out_vec), (D3DXVECTOR3 *)inp_vec,
+            sizeof(*inp_vec), &mat, ARRAY_SIZE(inp_vec));
+    expect_vec4_array(ARRAY_SIZE(exp_vec), exp_vec, out_vec, 0);
+
+    /* D3DXVec4TransformArray */
+    exp_vec[1].x = 90.0f; exp_vec[1].y = 100.0f; exp_vec[1].z = 110.0f; exp_vec[1].w = 120.0f;
+    exp_vec[2].x = 82.0f; exp_vec[2].y = 92.0f;  exp_vec[2].z = 102.0f; exp_vec[2].w = 112.0f;
+    exp_vec[3].x = 74.0f; exp_vec[3].y = 84.0f;  exp_vec[3].z = 94.0f;  exp_vec[3].w = 104.0f;
+    exp_vec[4].x = 66.0f; exp_vec[4].y = 76.0f;  exp_vec[4].z = 86.0f;  exp_vec[4].w = 96.0f;
+    exp_vec[5].x = 58.0f; exp_vec[5].y = 68.0f;  exp_vec[5].z = 78.0f;  exp_vec[5].w = 88.0f;
+    D3DXVec4TransformArray(&out_vec[1], sizeof(*out_vec), inp_vec, sizeof(*inp_vec), &mat, ARRAY_SIZE(inp_vec));
+    expect_vec4_array(ARRAY_SIZE(exp_vec), exp_vec, out_vec, 0);
+
+    /* D3DXPlaneTransformArray */
+    exp_plane[1].a = 90.0f; exp_plane[1].b = 100.0f; exp_plane[1].c = 110.0f; exp_plane[1].d = 120.0f;
+    exp_plane[2].a = 82.0f; exp_plane[2].b = 92.0f;  exp_plane[2].c = 102.0f; exp_plane[2].d = 112.0f;
+    exp_plane[3].a = 74.0f; exp_plane[3].b = 84.0f;  exp_plane[3].c = 94.0f;  exp_plane[3].d = 104.0f;
+    exp_plane[4].a = 66.0f; exp_plane[4].b = 76.0f;  exp_plane[4].c = 86.0f;  exp_plane[4].d = 96.0f;
+    exp_plane[5].a = 58.0f; exp_plane[5].b = 68.0f;  exp_plane[5].c = 78.0f;  exp_plane[5].d = 88.0f;
+    D3DXPlaneTransformArray(&out_plane[1], sizeof(*out_plane), inp_plane,
+            sizeof(*inp_plane), &mat, ARRAY_SIZE(inp_plane));
+    for (i = 0; i < ARRAY_SIZE(exp_plane); ++i)
+    {
+        BOOL equal = compare_plane(&exp_plane[i], &out_plane[i], 0);
+        ok(equal, "Got unexpected plane {%.8e, %.8e, %.8e, %.8e} at index %u, expected {%.8e, %.8e, %.8e, %.8e}.\n",
+                out_plane[i].a, out_plane[i].b, out_plane[i].c, out_plane[i].d, i,
+                exp_plane[i].a, exp_plane[i].b, exp_plane[i].c, exp_plane[i].d);
+        if (!equal)
+            break;
+    }
+}
+
+static void test_D3DXFloat_Array(void)
+{
+    unsigned int i;
+    void *out = NULL;
+    D3DXFLOAT16 half;
+    BOOL equal;
+
+    /* Input floats through bit patterns because compilers do not generate reliable INF and NaN values. */
+    union convert
+    {
+        DWORD d;
+        float f;
+    } single;
+
+    struct
+    {
+        union convert single_in;
+
+        /* half_ver2 occurs on WXPPROSP3 (32 bit math), WVISTAADM (32/64 bit math), W7PRO (32 bit math) */
+        WORD half_ver1, half_ver2;
+
+        /* single_out_ver2 confirms that half -> single conversion is consistent across platforms */
+        union convert single_out_ver1, single_out_ver2;
+    }
+    testdata[] =
+    {
+        { { 0x479c4000 }, 0x7c00, 0x7ce2, { 0x47800000 }, { 0x479c4000 } }, /* 80000.0f */
+        { { 0x477fdf00 }, 0x7bff, 0x7bff, { 0x477fe000 }, { 0x477fe000 } }, /* 65503.0f */
+        { { 0x477fe000 }, 0x7bff, 0x7bff, { 0x477fe000 }, { 0x477fe000 } }, /* 65504.0f */
+        { { 0x477ff000 }, 0x7bff, 0x7c00, { 0x477fe000 }, { 0x47800000 } }, /* 65520.0f */
+        { { 0x477ff100 }, 0x7c00, 0x7c00, { 0x47800000 }, { 0x47800000 } }, /* 65521.0f */
+
+        { { 0x477ffe00 }, 0x7c00, 0x7c00, { 0x47800000 }, { 0x47800000 } }, /* 65534.0f */
+        { { 0x477fff00 }, 0x7c00, 0x7c00, { 0x47800000 }, { 0x47800000 } }, /* 65535.0f */
+        { { 0x47800000 }, 0x7c00, 0x7c00, { 0x47800000 }, { 0x47800000 } }, /* 65536.0f */
+        { { 0xc79c4000 }, 0xfc00, 0xfce2, { 0xc7800000 }, { 0xc79c4000 } }, /* -80000.0f */
+        { { 0xc77fdf00 }, 0xfbff, 0xfbff, { 0xc77fe000 }, { 0xc77fe000 } }, /* -65503.0f */
+
+        { { 0xc77fe000 }, 0xfbff, 0xfbff, { 0xc77fe000 }, { 0xc77fe000 } }, /* -65504.0f */
+        { { 0xc77ff000 }, 0xfbff, 0xfc00, { 0xc77fe000 }, { 0xc7800000 } }, /* -65520.0f */
+        { { 0xc77ff100 }, 0xfc00, 0xfc00, { 0xc7800000 }, { 0xc7800000 } }, /* -65521.0f */
+        { { 0xc77ffe00 }, 0xfc00, 0xfc00, { 0xc7800000 }, { 0xc7800000 } }, /* -65534.0f */
+        { { 0xc77fff00 }, 0xfc00, 0xfc00, { 0xc7800000 }, { 0xc7800000 } }, /* -65535.0f */
+
+        { { 0xc7800000 }, 0xfc00, 0xfc00, { 0xc7800000 }, { 0xc7800000 } }, /* -65536.0f */
+        { { 0x7f800000 }, 0x7c00, 0x7fff, { 0x47800000 }, { 0x47ffe000 } }, /* INF */
+        { { 0xff800000 }, 0xffff, 0xffff, { 0xc7ffe000 }, { 0xc7ffe000 } }, /* -INF */
+        { { 0x7fc00000 }, 0x7fff, 0xffff, { 0x47ffe000 }, { 0xc7ffe000 } }, /* NaN */
+        { { 0xffc00000 }, 0xffff, 0xffff, { 0xc7ffe000 }, { 0xc7ffe000 } }, /* -NaN */
+
+        { { 0x00000000 }, 0x0000, 0x0000, { 0x00000000 }, { 0x00000000 } }, /* 0.0f */
+        { { 0x80000000 }, 0x8000, 0x8000, { 0x80000000 }, { 0x80000000 } }, /* -0.0f */
+        { { 0x330007ff }, 0x0000, 0x0000, { 0x00000000 }, { 0x00000000 } }, /* 2.9809595e-08f */
+        { { 0xb30007ff }, 0x8000, 0x8000, { 0x80000000 }, { 0x80000000 } }, /* -2.9809595e-08f */
+        { { 0x33000800 }, 0x0001, 0x0000, { 0x33800000 }, { 0x00000000 } }, /* 2.9809598e-08f */
+
+        { { 0xb3000800 }, 0x8001, 0x8000, { 0xb3800000 }, { 0x80000000 } }, /* -2.9809598e-08f */
+        { { 0x33c00000 }, 0x0002, 0x0001, { 0x34000000 }, { 0x33800000 } }, /* 8.9406967e-08f */
+    };
+
+    /* exception on NULL out or in parameter */
+    out = D3DXFloat32To16Array(&half, &single.f, 0);
+    ok(out == &half, "Got %p, expected %p.\n", out, &half);
+
+    out = D3DXFloat16To32Array(&single.f, &half, 0);
+    ok(out == &single.f, "Got %p, expected %p.\n", out, &single.f);
+
+    for (i = 0; i < ARRAY_SIZE(testdata); ++i)
+    {
+        out = D3DXFloat32To16Array(&half, &testdata[i].single_in.f, 1);
+        ok(out == &half, "Got %p, expected %p.\n", out, &half);
+        ok(half.value == testdata[i].half_ver1 || half.value == testdata[i].half_ver2,
+           "Got %x, expected %x or %x for index %d.\n", half.value, testdata[i].half_ver1,
+           testdata[i].half_ver2, i);
+
+        out = D3DXFloat16To32Array(&single.f, (D3DXFLOAT16 *)&testdata[i].half_ver1, 1);
+        ok(out == &single.f, "Got %p, expected %p.\n", out, &single.f);
+        equal = compare_float(single.f, testdata[i].single_out_ver1.f, 0);
+        ok(equal, "Got %#x, expected %#x at index %u.\n", single.d, testdata[i].single_out_ver1.d, i);
+
+        out = D3DXFloat16To32Array(&single.f, (D3DXFLOAT16 *)&testdata[i].half_ver2, 1);
+        ok(out == &single.f, "Got %p, expected %p.\n", out, &single.f);
+        equal = compare_float(single.f, testdata[i].single_out_ver2.f, 0);
+        ok(equal, "Got %#x, expected %#x at index %u.\n", single.d, testdata[i].single_out_ver2.d, i);
+    }
+}
+
+static void test_D3DXSHAdd(void)
+{
+    float out[50] = {0.0f};
+    unsigned int i, k;
+    float *ret;
+    BOOL equal;
+
+    static const float in1[50] =
+    {
+        1.11f, 1.12f, 1.13f, 1.14f, 1.15f, 1.16f, 1.17f, 1.18f,
+        1.19f, 1.20f, 1.21f, 1.22f, 1.23f, 1.24f, 1.25f, 1.26f,
+        1.27f, 1.28f, 1.29f, 1.30f, 1.31f, 1.32f, 1.33f, 1.34f,
+        1.35f, 1.36f, 1.37f, 1.38f, 1.39f, 1.40f, 1.41f, 1.42f,
+        1.43f, 1.44f, 1.45f, 1.46f, 1.47f, 1.48f, 1.49f, 1.50f,
+        1.51f, 1.52f, 1.53f, 1.54f, 1.55f, 1.56f, 1.57f, 1.58f,
+        1.59f, 1.60f,
+    };
+    static const float in2[50] =
+    {
+        2.11f, 2.12f, 2.13f, 2.14f, 2.15f, 2.16f, 2.17f, 2.18f,
+        2.19f, 2.20f, 2.21f, 2.22f, 2.23f, 2.24f, 2.25f, 2.26f,
+        2.27f, 2.28f, 2.29f, 2.30f, 2.31f, 2.32f, 2.33f, 2.34f,
+        2.35f, 2.36f, 2.37f, 2.38f, 2.39f, 2.40f, 2.41f, 2.42f,
+        2.43f, 2.44f, 2.45f, 2.46f, 2.47f, 2.48f, 2.49f, 2.50f,
+        2.51f, 2.52f, 2.53f, 2.54f, 2.55f, 2.56f, 2.57f, 2.58f,
+        2.59f, 2.60f,
+    };
+
+    /*
+     * Order is not limited by D3DXSH_MINORDER and D3DXSH_MAXORDER!
+     * All values will work, test from 0-7 [D3DXSH_MINORDER = 2, D3DXSH_MAXORDER = 6]
+     * Exceptions will show up when out, in1 or in2 is NULL
+     */
+    for (k = 0; k <= D3DXSH_MAXORDER + 1; k++)
+    {
+        UINT count = k * k;
+
+        ret = D3DXSHAdd(&out[0], k, &in1[0], &in2[0]);
+        ok(ret == out, "%u: D3DXSHAdd() failed, got %p, expected %p\n", k, out, ret);
+
+        for (i = 0; i < count; ++i)
+        {
+            equal = compare_float(in1[i] + in2[i], out[i], 0);
+            ok(equal, "%u-%u: Got %.8e, expected %.8e.\n", k, i, out[i], in1[i] + in2[i]);
+        }
+        equal = compare_float(out[count], 0.0f, 0);
+        ok(equal, "%u-%u: Got %.8e, expected 0.0.\n", k, k * k, out[count]);
+    }
+}
+
+static void test_D3DXSHDot(void)
+{
+    float a[49], b[49], got;
+    unsigned int i;
+    BOOL equal;
+
+    static const float expected[] = {0.5f, 0.5f, 25.0f, 262.5f, 1428.0f, 5362.5f, 15873.0f, 39812.5f};
+
+    for (i = 0; i < ARRAY_SIZE(a); ++i)
+    {
+        a[i] = i + 1.0f;
+        b[i] = i + 0.5f;
+    }
+
+    /* D3DXSHDot computes by using order * order elements */
+    for (i = 0; i <= D3DXSH_MAXORDER + 1; i++)
+    {
+        got = D3DXSHDot(i, a, b);
+        equal = compare_float(got, expected[i], 0);
+        ok(equal, "order %u: Got %.8e, expected %.8e.\n", i, got, expected[i]);
+    }
+}
+
+static void test_D3DXSHEvalConeLight(void)
+{
+    float bout[49], expected, gout[49], rout[49];
+    unsigned int j, l, order;
+    D3DXVECTOR3 dir;
+    HRESULT hr;
+    BOOL equal;
+
+    static const float table[] =
+    {
+    /* Red colour */
+        1.604815f, -3.131381f, 7.202175f, -2.870432f, 6.759296f, -16.959688f,
+        32.303082f, -15.546381f, -0.588878f, -5.902123f, 40.084042f, -77.423569f,
+        137.556320f, -70.971603f, -3.492171f, 7.683092f, -2.129311f, -35.971344f,
+        183.086548f, -312.414948f, 535.091064f, -286.380371f, -15.950727f, 46.825714f,
+        -12.127637f, 11.289261f, -12.417809f, -155.039566f, 681.182556f, -1079.733643f,
+        1807.650513f, -989.755798f, -59.345467f, 201.822815f, -70.726486f, 7.206529f,
+
+        3.101155f, -3.128710f, 7.196033f, -2.867984f, -0.224708f, 0.563814f,
+        -1.073895f, 0.516829f, 0.019577f, 2.059788f, -13.988971f, 27.020128f,
+        -48.005917f, 24.768450f, 1.218736f, -2.681329f, -0.088639f, -1.497410f,
+        7.621501f, -13.005165f, 22.274696f, -11.921401f, -0.663995f, 1.949254f,
+        -0.504848f, 4.168484f, -4.585193f, -57.247314f, 251.522095f, -398.684387f,
+        667.462891f, -365.460693f, -21.912912f, 74.521721f, -26.115280f, 2.660963f,
+    /* Green colour */
+        2.454422f, -4.789170f, 11.015091f, -4.390072f, 10.337747f, -25.938347f,
+        49.404713f, -23.776817f, -0.900637f, -9.026776f, 61.305000f, -118.412514f,
+        210.380249f, -108.544792f, -5.340967f, 11.750610f, -3.256593f, -55.014996f,
+        280.014709f, -477.811066f, 818.374512f, -437.993469f, -24.395227f, 71.615799f,
+        -18.548151f, 17.265928f, -18.991943f, -237.119324f, 1041.808594f, -1651.357300f,
+        2764.642090f, -1513.744141f, -90.763657f, 308.670197f, -108.169922f, 11.021750f,
+
+        4.742942f, -4.785086f, 11.005697f, -4.386329f, -0.343672f, 0.862303f,
+        -1.642427f, 0.790444f, 0.029941f, 3.150264f, -21.394896f, 41.324898f,
+        -73.420807f, 37.881153f, 1.863950f, -4.100857f, -0.135565f, -2.290156f,
+        11.656413f, -19.890251f, 34.067181f, -18.232729f, -1.015521f, 2.981212f,
+        -0.772120f, 6.375328f, -7.012648f, -87.554710f, 384.680817f, -609.752563f,
+        1020.825500f, -558.939819f, -33.513863f, 113.974388f, -39.941013f, 4.069707f,
+    /* Blue colour */
+        3.304030f, -6.446959f, 14.828006f, -5.909713f, 13.916198f, -34.917004f,
+        66.506340f, -32.007256f, -1.212396f, -12.151429f, 82.525963f, -159.401459f,
+        283.204193f, -146.117996f, -7.189764f, 15.818130f, -4.383876f, -74.058655f,
+        376.942871f, -643.207214f, 1101.658081f, -589.606628f, -32.839729f, 96.405884f,
+        -24.968664f, 23.242596f, -25.566080f, -319.199097f, 1402.434692f, -2222.980957f,
+        3721.633545f, -2037.732544f, -122.181847f, 415.517578f, -145.613358f, 14.836972f,
+
+        6.384730f, -6.441462f, 14.815362f, -5.904673f, -0.462635f, 1.160793f,
+        -2.210959f, 1.064060f, 0.040305f, 4.240739f, -28.800821f, 55.629673f,
+        -98.835709f, 50.993862f, 2.509163f, -5.520384f, -0.182491f, -3.082903f,
+        15.691326f, -26.775339f, 45.859665f, -24.544060f, -1.367048f, 4.013170f,
+        -1.039392f, 8.582172f, -9.440103f, -117.862114f, 517.839600f, -820.820740f,
+        1374.188232f, -752.419067f, -45.114819f, 153.427063f, -53.766754f, 5.478452f, };
+    const struct
+    {
+        float *red_received, *green_received, *blue_received;
+        const float *red_expected, *green_expected, *blue_expected;
+        float radius, roffset, goffset, boffset;
+    }
+    test[] =
+    {
+        { rout, gout, bout, table, &table[72], &table[144], 0.5f, 1.01f, 1.02f, 1.03f, },
+        { rout, gout, bout, &table[36], &table[108], &table[180], 1.6f, 1.01f, 1.02f, 1.03f, },
+        { rout, rout, rout, &table[144], &table[144], &table[144], 0.5f, 1.03f, 1.03f, 1.03f, },
+        { rout, rout, bout, &table[72], &table[72], &table[144], 0.5, 1.02f, 1.02f, 1.03f, },
+        { rout, gout, gout, table, &table[144], &table[144], 0.5f, 1.01f, 1.03f, 1.03f, },
+        { rout, gout, rout, &table[144], &table[72], &table[144], 0.5f, 1.03f, 1.02f, 1.03f, },
+    /* D3DXSHEvalConeLight accepts NULL green or blue colour. */
+        { rout, NULL, bout, table, NULL, &table[144], 0.5f, 1.01f, 0.0f, 1.03f, },
+        { rout, gout, NULL, table, &table[72], NULL, 0.5f, 1.01f, 1.02f, 0.0f, },
+        { rout, NULL, NULL, table, NULL, NULL, 0.5f, 1.01f, 0.0f, 0.0f, },
+    };
+
+    dir.x = 1.1f; dir.y = 1.2f; dir.z = 2.76f;
+
+    for (l = 0; l < ARRAY_SIZE(test); ++l)
+    {
+        for (order = D3DXSH_MINORDER; order <= D3DXSH_MAXORDER; order++)
+        {
+            for (j = 0; j < 49; j++)
+            {
+                test[l].red_received[j] = 1.01f + j;
+                if (test[l].green_received)
+                    test[l].green_received[j] = 1.02f + j;
+                if (test[l].blue_received)
+                    test[l].blue_received[j] = 1.03f + j;
+            }
+
+            hr = D3DXSHEvalConeLight(order, &dir, test[l].radius, 1.7f, 2.6f, 3.5f, test[l].red_received, test[l].green_received, test[l].blue_received);
+            ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+
+            for (j = 0; j < 49; j++)
+            {
+                if (j >= order * order)
+                    expected = j + test[l].roffset;
+                else
+                    expected = test[l].red_expected[j];
+                equal = compare_float(test[l].red_received[j], expected, 128);
+                ok(equal, "Red: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                        l, order, j, expected, test[l].red_received[j]);
+
+                if (test[l].green_received)
+                {
+                    if (j >= order * order)
+                        expected = j + test[l].goffset;
+                    else
+                        expected = test[l].green_expected[j];
+                    equal = compare_float(test[l].green_received[j], expected, 64);
+                    ok(equal, "Green: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                            l, order, j, expected, test[l].green_received[j]);
+                }
+
+                if (test[l].blue_received)
+                {
+                    if (j >= order * order)
+                        expected = j + test[l].boffset;
+                    else
+                        expected = test[l].blue_expected[j];
+                    equal = compare_float(test[l].blue_received[j], expected, 128);
+                    ok(equal, "Blue: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                            l, order, j, expected, test[l].blue_received[j]);
+                }
+            }
+        }
+    }
+
+    /* Cone light with radius <= 0.0f behaves as a directional light */
+    for (order = D3DXSH_MINORDER; order <= D3DXSH_MAXORDER; order++)
+    {
+        FLOAT blue[49], green[49], red[49];
+
+        for (j = 0; j < 49; j++)
+        {
+            rout[j] = 1.01f + j;
+            gout[j] = 1.02f + j;
+            bout[j] = 1.03f + j;
+            red[j] = 1.01f + j;
+            green[j] = 1.02f + j;
+            blue[j] = 1.03f + j;
+        }
+
+        hr = D3DXSHEvalConeLight(order, &dir, -0.1f, 1.7f, 2.6f, 3.5f, rout, gout, bout);
+        ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+        D3DXSHEvalDirectionalLight(order, &dir, 1.7f, 2.6f, 3.5f, red, green, blue);
+
+        for (j = 0; j < 49; j++)
+        {
+            equal = compare_float(red[j], rout[j], 0);
+            ok(equal, "Red: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                    l, order, j, red[j], rout[j]);
+
+            equal = compare_float(green[j], gout[j], 0);
+            ok(equal, "Green: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                    l, order, j, green[j], gout[j]);
+
+            equal = compare_float(blue[j], bout[j], 0);
+            ok(equal, "Blue: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                    l, order, j, blue[j], bout[j]);
+        }
+    }
+
+    /* D3DXSHEvalConeLight accepts order < D3DXSH_MINORDER or order > D3DXSH_MAXORDER. But tests in native windows show that the colour outputs are not set */
+    hr = D3DXSHEvalConeLight(7, &dir, 0.5f, 1.0f, 2.0f, 3.0f, rout, gout, bout);
+    ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+    hr = D3DXSHEvalConeLight(0, &dir, 0.5f, 1.0f, 2.0f, 3.0f, rout, gout, bout);
+    ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+    hr = D3DXSHEvalConeLight(1, &dir, 0.5f, 1.0f, 2.0f, 3.0f, rout, gout, bout);
+    ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+}
+
+static void test_D3DXSHEvalDirection(void)
+{
+    float a[49], expected, *received_ptr;
+    unsigned int i, order;
+    D3DXVECTOR3 d;
+    BOOL equal;
+
+    static const float table[36] =
+    {
+         2.82094806e-01f, -9.77205038e-01f,  1.46580756e+00f, -4.88602519e-01f,  2.18509698e+00f, -6.55529118e+00f,
+         8.20018101e+00f, -3.27764559e-00f, -1.63882279e+00f,  1.18008721e+00f,  1.73436680e+01f, -4.02200317e+01f,
+         4.70202179e+01f, -2.01100159e+01f, -1.30077515e+01f,  6.49047947e+00f, -1.50200577e+01f,  1.06207848e+01f,
+         1.17325661e+02f, -2.40856750e+02f,  2.71657288e+02f, -1.20428375e+02f, -8.79942474e+01f,  5.84143143e+01f,
+        -4.38084984e+00f,  2.49425201e+01f, -1.49447693e+02f,  7.82781296e+01f,  7.47791748e+02f, -1.42768787e+03f,
+         1.57461914e+03f, -7.13843933e+02f, -5.60843811e+02f,  4.30529724e+02f, -4.35889091e+01f, -2.69116650e+01f,
+    };
+
+    d.x = 1.0; d.y = 2.0f; d.z = 3.0f;
+
+    for (order = 0; order <= D3DXSH_MAXORDER + 1; order++)
+    {
+        for (i = 0; i < ARRAY_SIZE(a); ++i)
+            a[i] = 1.5f + i;
+
+        received_ptr = D3DXSHEvalDirection(a, order, &d);
+        ok(received_ptr == a, "Expected %p, received %p\n", a, received_ptr);
+
+        for (i = 0; i < ARRAY_SIZE(a); ++i)
+        {
+            /* if the order is < D3DXSH_MINORDER or order > D3DXSH_MAXORDER or
+             * the index of the element is greater than order * order - 1,
+             * D3DXSHEvalDirection() does not modify the output. */
+            if ((order < D3DXSH_MINORDER) || (order > D3DXSH_MAXORDER) || (i >= order * order))
+                expected = 1.5f + i;
+            else
+                expected = table[i];
+
+            equal = compare_float(a[i], expected, 2);
+            ok(equal, "order %u, index %u: Got unexpected result %.8e, expected %.8e.\n",
+                    order, i, a[i], expected);
+        }
+    }
+}
+
+static void test_D3DXSHEvalDirectionalLight(void)
+{
+    float *blue_out, bout[49], expected, gout[49], *green_out, *red_out, rout[49];
+    unsigned int j, l, order, startindex;
+    D3DXVECTOR3 dir;
+    HRESULT hr;
+    BOOL equal;
+
+    static const float table[] =
+    {
+    /* Red colour */
+      2.008781f, -4.175174f, 9.602900f, -3.827243f, 1.417963f, -2.947181f,
+      6.778517f, -2.701583f, 7.249108f, -18.188671f, 34.643921f, -16.672949f,
+      -0.631551f, 1.417963f, -2.947181f, 6.778517f, -2.701583f, 7.249108f,
+      -18.188671f, 34.643921f, -16.672949f, -0.631551f, -7.794341f, 52.934967f,
+      -102.245529f, 181.656815f, -93.725060f, -4.611760f, 10.146287f, 1.555186f,
+      -3.232392f, 7.434503f, -2.963026f, 7.950634f, -19.948866f, 37.996559f,
+      -18.286459f, -0.692669f, -8.548632f, 58.057705f, -112.140251f, 199.236496f,
+      -102.795227f, -5.058059f, 11.128186f, -4.189955f, -70.782669f, 360.268829f,
+      -614.755005f, 1052.926270f, -563.525391f, -31.387066f, 92.141365f, -23.864176f,
+      1.555186f, -3.232392f, 7.434503f, -2.963026f, 7.950634f, -19.948866f,
+      37.996559f, -18.286459f, -0.692669f, -8.548632f, 58.057705f, -112.140251f,
+      199.236496f, -102.795227f, -5.058059f, 11.128186f, -4.189955f, -70.782669f,
+      360.268829f, -614.755005f, 1052.926270f, -563.525391f, -31.387066f, 92.141365f,
+      -23.864176f, 34.868664f, -38.354366f, -478.864166f, 2103.939941f, -3334.927734f,
+      5583.213867f, -3057.017090f, -183.297836f, 623.361633f, -218.449921f, 22.258503f,
+    /* Green colour */
+      3.072254f, -6.385560f, 14.686787f, -5.853429f, 2.168650f, -4.507453f,
+      10.367143f, -4.131832f, 11.086870f, -27.817965f, 52.984818f, -25.499800f,
+      -0.965902f, 2.168650f, -4.507453f, 10.367143f, -4.131832f, 11.086870f,
+      -27.817965f, 52.984818f, -25.499800f, -0.965902f, -11.920755f, 80.959351f,
+      -156.375488f, 277.828033f, -143.344193f, -7.053278f, 15.517849f, 2.378519f,
+      -4.943659f, 11.370415f, -4.531687f, 12.159794f, -30.510029f, 58.112385f,
+      -27.967525f, -1.059376f, -13.074378f, 88.794136f, -171.508621f, 304.714630f,
+      -157.216217f, -7.735855f, 17.019577f, -6.408166f, -108.255844f, 550.999390f,
+      -940.213501f, 1610.357788f, -861.862305f, -48.003746f, 140.922089f, -36.498150f,
+      2.378519f, -4.943659f, 11.370415f, -4.531687f, 12.159794f, -30.510029f,
+      58.112385f, -27.967525f, -1.059376f, -13.074378f, 88.794136f, -171.508621f,
+      304.714630f, -157.216217f, -7.735855f, 17.019577f, -6.408166f, -108.255844f,
+      550.999390f, -940.213501f, 1610.357788f, -861.862305f, -48.003746f, 140.922089f,
+      -36.498150f, 53.328545f, -58.659618f, -732.380493f, 3217.790283f, -5100.477539f,
+      8539.033203f, -4675.437500f, -280.337860f, 953.376587f, -334.099884f, 34.042416f,
+    /* Blue colour */
+      4.135726f, -8.595945f, 19.770674f, -7.879617f, 2.919336f, -6.067726f,
+      13.955770f, -5.562082f, 14.924634f, -37.447262f, 71.325722f, -34.326656f,
+      -1.300252f, 2.919336f, -6.067726f, 13.955770f, -5.562082f, 14.924634f,
+      -37.447262f, 71.325722f, -34.326656f, -1.300252f, -16.047173f, 108.983749f,
+      -210.505493f, 373.999298f, -192.963348f, -9.494799f, 20.889414f, 3.201853f,
+      -6.654925f, 15.306328f, -6.100348f, 16.368954f, -41.071194f, 78.228210f,
+      -37.648590f, -1.426083f, -17.600124f, 119.530563f, -230.876984f, 410.192780f,
+      -211.637222f, -10.413651f, 22.910971f, -8.626378f, -145.729019f, 741.729919f,
+      -1265.671997f, 2167.789307f, -1160.199219f, -64.620430f, 189.702820f, -49.132126f,
+      3.201853f, -6.654925f, 15.306328f, -6.100348f, 16.368954f, -41.071194f,
+      78.228210f, -37.648590f, -1.426083f, -17.600124f, 119.530563f, -230.876984f,
+      410.192780f, -211.637222f, -10.413651f, 22.910971f, -8.626378f, -145.729019f,
+      741.729919f, -1265.671997f, 2167.789307f, -1160.199219f, -64.620430f, 189.702820f,
+      -49.132126f, 71.788422f, -78.964867f, -985.896790f, 4331.640625f, -6866.027344f,
+      11494.852539f, -6293.858398f, -377.377899f, 1283.391479f, -449.749817f, 45.826328f, };
+    const struct
+    {
+        float *red_in, *green_in, *blue_in;
+        const float *red_out, *green_out, *blue_out;
+        float roffset, goffset, boffset;
+    }
+    test[] =
+    {
+      { rout, gout, bout, table, &table[90], &table[180], 1.01f, 1.02f, 1.03f, },
+      { rout, rout, rout, &table[180], &table[180], &table[180], 1.03f, 1.03f, 1.03f, },
+      { rout, rout, bout, &table[90], &table[90], &table[180], 1.02f, 1.02f, 1.03f, },
+      { rout, gout, gout, table, &table[180], &table[180], 1.01f, 1.03f, 1.03f, },
+      { rout, gout, rout, &table[180], &table[90], &table[180], 1.03f, 1.02f, 1.03f, },
+    /* D3DXSHEvalDirectionaLight accepts NULL green or blue colour. */
+      { rout, NULL, bout, table, NULL, &table[180], 1.01f, 0.0f, 1.03f, },
+      { rout, gout, NULL, table, &table[90], NULL, 1.01f, 1.02f, 0.0f, },
+      { rout, NULL, NULL, table, NULL, NULL, 1.01f, 0.0f, 0.0f, },
+    };
+
+    dir.x = 1.1f; dir.y= 1.2f; dir.z = 2.76f;
+
+    for (l = 0; l < ARRAY_SIZE(test); ++l)
+    {
+        startindex = 0;
+
+        for (order = D3DXSH_MINORDER; order <= D3DXSH_MAXORDER; order++)
+        {
+            red_out = test[l].red_in;
+            green_out = test[l].green_in;
+            blue_out = test[l].blue_in;
+
+            for (j = 0; j < ARRAY_SIZE(rout); ++j)
+            {
+                red_out[j] = 1.01f + j;
+                if ( green_out )
+                    green_out[j] = 1.02f + j;
+                if ( blue_out )
+                    blue_out[j] = 1.03f + j;
+            }
+
+            hr = D3DXSHEvalDirectionalLight(order, &dir, 1.7f, 2.6f, 3.5f, red_out, green_out, blue_out);
+            ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+
+            for (j = 0; j < ARRAY_SIZE(rout); ++j)
+            {
+                if ( j >= order * order )
+                    expected = j + test[l].roffset;
+                else
+                    expected = test[l].red_out[startindex + j];
+                equal = compare_float(expected, red_out[j], 8);
+                ok(equal, "Red: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                        l, order, j, expected, red_out[j]);
+
+                if ( green_out )
+                {
+                    if ( j >= order * order )
+                        expected = j + test[l].goffset;
+                    else
+                        expected = test[l].green_out[startindex + j];
+                    equal = compare_float(expected, green_out[j], 8);
+                    ok(equal, "Green: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                            l, order, j, expected, green_out[j]);
+                }
+
+                if ( blue_out )
+                {
+                    if ( j >= order * order )
+                        expected = j + test[l].boffset;
+                    else
+                        expected = test[l].blue_out[startindex + j];
+                    equal = compare_float(expected, blue_out[j], 4);
+                    ok(equal, "Blue: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                            l, order, j, expected, blue_out[j]);
+                }
+            }
+
+            startindex += order * order;
+        }
+    }
+
+    /* D3DXSHEvalDirectionalLight accepts order < D3DXSH_MINORDER or order > D3DXSH_MAXORDER. But tests in native windows show that the colour outputs are not set*/
+    hr = D3DXSHEvalDirectionalLight(7, &dir, 1.0f, 2.0f, 3.0f, rout, gout, bout);
+    ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+    hr = D3DXSHEvalDirectionalLight(0, &dir, 1.0f, 2.0f, 3.0f, rout, gout, bout);
+    ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+    hr = D3DXSHEvalDirectionalLight(1, &dir, 1.0f, 2.0f, 3.0f, rout, gout, bout);
+    ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+}
+
+static void test_D3DXSHEvalHemisphereLight(void)
+{
+    float bout[49], expected, gout[49], rout[49];
+    unsigned int j, l, order;
+    D3DXCOLOR bottom, top;
+    D3DXVECTOR3 dir;
+    HRESULT hr;
+    BOOL equal;
+
+    static const float table[] =
+    {
+        /* Red colour. */
+        23.422981f, 15.859521f, -36.476898f, 14.537894f,
+        /* Green colour. */
+        19.966694f,  6.096982f, -14.023058f,  5.588900f,
+        /* Blue colour. */
+        24.566214f,  8.546826f, -19.657701f,  7.834591f,
+    };
+    const struct
+    {
+        float *red_received, *green_received, *blue_received;
+        const float *red_expected, *green_expected, *blue_expected;
+        const float roffset, goffset, boffset;
+    }
+    test[] =
+    {
+        { rout, gout, bout, table, &table[4], &table[8], 1.01f, 1.02f, 1.03f, },
+        { rout, rout, rout, &table[8], &table[8], &table[8], 1.03f, 1.03f, 1.03f, },
+        { rout, rout, bout, &table[4], &table[4], &table[8], 1.02f, 1.02f, 1.03f, },
+        { rout, gout, gout, table, &table[8], &table[8], 1.01f, 1.03f, 1.03f, },
+        { rout, gout, rout, &table[8], &table[4], &table[8], 1.03f, 1.02f, 1.03f, },
+    /* D3DXSHEvalHemisphereLight accepts NULL green or blue colour. */
+        { rout, NULL, bout, table, NULL, &table[8], 1.01f, 1.02f, 1.03f, },
+        { rout, gout, NULL, table, &table[4], NULL, 1.01f, 1.02f, 1.03f, },
+        { rout, NULL, NULL, table, NULL, NULL, 1.01f, 1.02f, 1.03f, },
+    };
+
+    dir.x = 1.1f; dir.y = 1.2f; dir.z = 2.76f;
+    top.r = 0.1f; top.g = 2.1f; top.b = 2.3f; top.a = 4.3f;
+    bottom.r = 8.71f; bottom.g = 5.41f; bottom.b = 6.94f; bottom.a = 8.43f;
+
+    for (l = 0; l < ARRAY_SIZE(test); ++l)
+        for (order = D3DXSH_MINORDER; order <= D3DXSH_MAXORDER + 1; order++)
+        {
+            for (j = 0; j < 49; j++)
+            {
+                test[l].red_received[j] = 1.01f + j;
+                if (test[l].green_received)
+                    test[l].green_received[j] = 1.02f + j;
+                if (test[l].blue_received)
+                    test[l].blue_received[j] = 1.03f + j;
+            }
+
+            hr = D3DXSHEvalHemisphereLight(order, &dir, top, bottom, test[l].red_received, test[l].green_received, test[l].blue_received);
+            ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+
+            for (j = 0; j < 49; j++)
+            {
+                if (j < 4)
+                    expected = test[l].red_expected[j];
+                else if (j < order * order)
+                     expected = 0.0f;
+                else
+                    expected = test[l].roffset + j;
+                equal = compare_float(test[l].red_received[j], expected, 4);
+                ok(equal, "Red: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                        l, order, j, expected, test[l].red_received[j]);
+
+                if (test[l].green_received)
+                {
+                    if (j < 4)
+                        expected = test[l].green_expected[j];
+                    else if (j < order * order)
+                         expected = 0.0f;
+                    else
+                         expected = test[l].goffset + j;
+                    equal = compare_float(expected, test[l].green_received[j], 4);
+                    ok(equal, "Green: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                            l, order, j, expected, test[l].green_received[j]);
+                }
+
+                if (test[l].blue_received)
+                {
+                    if (j < 4)
+                        expected = test[l].blue_expected[j];
+                    else if (j < order * order)
+                        expected = 0.0f;
+                    else
+                        expected = test[l].boffset + j;
+                    equal = compare_float(expected, test[l].blue_received[j], 4);
+                    ok(equal, "Blue: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                            l, order, j, expected, test[l].blue_received[j]);
+                }
+            }
+        }
+}
+
+static void test_D3DXSHEvalSphericalLight(void)
+{
+    float bout[49], expected, gout[49], rout[49];
+    unsigned int j, l, order;
+    D3DXVECTOR3 dir;
+    HRESULT hr;
+    BOOL equal;
+
+    static const float table[] =
+    {
+        /* Red colour. */
+         3.01317163e+00f, -9.77240128e-01f,  2.24765220e+00f, -8.95803434e-01f,  3.25255224e-35f, -8.16094904e-35f,
+         8.95199460e-35f, -7.48086982e-35f, -2.83366352e-36f,  6.29281376e-02f, -4.27374053e-01f,  6.19212543e-01f,
+        -3.04508915e-01f,  5.67611487e-01f,  3.72333533e-02f, -8.19167317e-02f,  1.25205729e-36f,  2.11515287e-35f,
+        -8.85884025e-35f,  8.22100105e-35f, -1.41290744e-37f,  7.53591749e-35f,  7.71793061e-36f, -2.75340121e-35f,
+         7.13117824e-36f,  1.24992691e-02f, -1.37487792e-02f, -1.48109290e-01f,  4.34345843e-01f, -2.45986100e-01f,
+        -1.51757946e-01f, -2.25487254e-01f, -3.78407442e-02f,  1.92801335e-01f, -7.83071154e-02f,  7.97894137e-03f,
+
+         4.02519645e-01f, -2.43653315e-01f,  5.60402600e-01f, -2.23348868e-01f,  1.62046875e-01f, -4.06590330e-01f,
+         4.46001368e-01f, -3.72707796e-01f, -1.41177231e-02f, -4.31995198e-02f,  2.93387896e-01f, -4.25083048e-01f,
+         2.09042241e-01f, -3.89659453e-01f, -2.55603144e-02f,  5.62349945e-02f, -4.68822967e-03f, -7.92002290e-02f,
+         3.31712278e-01f, -3.07828893e-01f,  5.29052032e-04f, -2.82176480e-01f, -2.88991817e-02f,  1.03098934e-01f,
+        -2.67021338e-02f,  7.24339502e-03f, -7.96749298e-03f, -8.58301461e-02f,  2.51705799e-01f, -1.42550295e-01f,
+        -8.79445626e-02f, -1.30671101e-01f, -2.19289189e-02f,  1.11729432e-01f, -4.53794030e-02f,  4.62384030e-03f,
+
+         1.95445306e+00f, -8.56593659e-01f,  1.97016533e+00f, -7.85210840e-01f,  2.31033385e-01f, -5.79683751e-01f,
+         6.35872835e-01f, -5.31376762e-01f, -2.01279127e-02f,  2.11104646e-02f, -1.43370917e-01f,  2.07726860e-01f,
+        -1.02153423e-01f,  1.90416285e-01f,  1.24906507e-02f, -2.74805568e-02f,  6.33162467e-03f,  1.06962790e-01f,
+        -4.47989495e-01f,  4.15734115e-01f, -7.14504011e-04f,  3.81089599e-01f,  3.90293960e-02f, -1.39238860e-01f,
+         3.60622028e-02f, -4.47359268e-03f,  4.92080277e-03f,  5.30095505e-02f, -1.55456001e-01f,  8.80404774e-02f,
+         5.43154350e-02f,  8.07037695e-02f,  1.35435180e-02f, -6.90052063e-02f,  2.80267699e-02f, -2.85572968e-03f,
+        /* Green colour. */
+         4.60837984e+00f, -1.49460245e+00f,  3.43758549e+00f, -1.37005222e+00f,  4.97449134e-35f, -1.24814507e-34f,
+         1.36912850e-34f, -1.14413296e-34f, -4.33383805e-36f,  9.62430278e-02f, -6.53630863e-01f,  9.47030887e-01f,
+        -4.65719486e-01f,  8.68111630e-01f,  5.69451249e-02f, -1.25284405e-01f,  1.91491103e-36f,  3.23493947e-35f,
+        -1.35488136e-34f,  1.25732949e-34f, -2.16091711e-37f,  1.15255201e-34f,  1.18038931e-35f, -4.21108392e-35f,
+         1.09065072e-35f,  1.91165280e-02f, -2.10275433e-02f, -2.26520076e-01f,  6.64293599e-01f, -3.76214011e-01f,
+        -2.32100374e-01f, -3.44862837e-01f, -5.78740756e-02f,  2.94872611e-01f, -1.19763816e-01f,  1.22030860e-02f,
+
+         6.15618240e-01f, -3.72646222e-01f,  8.57086273e-01f, -3.41592364e-01f,  2.47836381e-01f, -6.21843994e-01f,
+         6.82119695e-01f, -5.70023651e-01f, -2.15918104e-02f, -6.60698496e-02f,  4.48710870e-01f, -6.50126972e-01f,
+         3.19711642e-01f, -5.95949713e-01f, -3.90922430e-02f,  8.60064566e-02f, -7.17023314e-03f, -1.21129754e-01f,
+         5.07324627e-01f, -4.70797100e-01f,  8.09138350e-04f, -4.31564000e-01f, -4.41987457e-02f,  1.57680712e-01f,
+        -4.08385549e-02f,  1.10781328e-02f, -1.21855767e-02f, -1.31269627e-01f,  3.84961785e-01f, -2.18018084e-01f,
+        -1.34503440e-01f, -1.99849906e-01f, -3.35383443e-02f,  1.70880296e-01f, -6.94037884e-02f,  7.07175529e-03f,
+
+         2.98916331e+00f, -1.31008433e+00f,  3.01319384e+00f, -1.20091062e+00f,  3.53345154e-01f, -8.86575090e-01f,
+         9.72511332e-01f, -8.12693818e-01f, -3.07838645e-02f,  3.22865908e-02f, -2.19273153e-01f,  3.17699883e-01f,
+        -1.56234637e-01f,  2.91224888e-01f,  1.91033469e-02f, -4.20290842e-02f,  9.68366064e-03f,  1.63590138e-01f,
+        -6.85160360e-01f,  6.35828606e-01f, -1.09277077e-03f,  5.82842878e-01f,  5.96920135e-02f, -2.12953537e-01f,
+         5.51539537e-02f, -6.84196484e-03f,  7.52593316e-03f,  8.10734249e-02f, -2.37756221e-01f,  1.34650133e-01f,
+         8.30706600e-02f,  1.23429287e-01f,  2.07136145e-02f, -1.05537368e-01f,  4.28644688e-02f, -4.36758628e-03f,
+        /* Blue colour. */
+         6.20358848e+00f, -2.01196491e+00f,  4.62751910e+00f, -1.84430114e+00f,  6.69643089e-35f, -1.68019534e-34f,
+         1.84305766e-34f, -1.54017904e-34f, -5.83401297e-36f,  1.29557927e-01f, -8.79887732e-01f,  1.27484932e+00f,
+        -6.26930101e-01f,  1.16861185e+00f,  7.66569017e-02f, -1.68652090e-01f,  2.57776494e-36f,  4.35472637e-35f,
+        -1.82387882e-34f,  1.69255899e-34f, -2.90892699e-37f,  1.55151238e-34f,  1.58898567e-35f, -5.66876703e-35f,
+         1.46818371e-35f,  2.57337886e-02f, -2.83063093e-02f, -3.04930882e-01f,  8.94241416e-01f, -5.06441957e-01f,
+        -3.12442822e-01f, -4.64238452e-01f, -7.79074123e-02f,  3.96943914e-01f, -1.61220527e-01f,  1.64272318e-02f,
+
+         8.28716892e-01f, -5.01639163e-01f,  1.15377003e+00f, -4.59835891e-01f,  3.33625909e-01f, -8.37097715e-01f,
+         9.18238085e-01f, -7.67339558e-01f, -2.90658997e-02f, -8.89401854e-02f,  6.04033886e-01f, -8.75170956e-01f,
+         4.30381072e-01f, -8.02240028e-01f, -5.26241753e-02f,  1.15777927e-01f, -9.65223728e-03f, -1.63059290e-01f,
+         6.82937023e-01f, -6.33765350e-01f,  1.08922474e-03f, -5.80951560e-01f, -5.94983136e-02f,  2.12262505e-01f,
+        -5.49749798e-02f,  1.49128717e-02f, -1.64036616e-02f, -1.76709119e-01f,  5.18217807e-01f, -2.93485893e-01f,
+        -1.81062330e-01f, -2.69028730e-01f, -4.51477729e-02f,  2.30031176e-01f, -9.34281801e-02f,  9.51967094e-03f,
+
+         4.02387383e+00f, -1.76357513e+00f,  4.05622263e+00f, -1.61661051e+00f,  4.75656955e-01f, -1.19346651e+00f,
+         1.30914992e+00f, -1.09401095e+00f, -4.14398191e-02f,  4.34627200e-02f, -2.95175409e-01f,  4.27672935e-01f,
+        -2.10315865e-01f,  3.92033517e-01f,  2.57160448e-02f, -5.65776154e-02f,  1.30356975e-02f,  2.20217502e-01f,
+        -9.22331288e-01f,  8.55923154e-01f, -1.47103763e-03f,  7.84596211e-01f,  8.03546365e-02f, -2.86668233e-01f,
+         7.42457096e-02f, -9.21033762e-03f,  1.01310642e-02f,  1.09137307e-01f, -3.20056463e-01f,  1.81259801e-01f,
+         1.11825893e-01f,  1.66154815e-01f,  2.78837128e-02f, -1.42069538e-01f,  5.77021717e-02f, -5.87944329e-03f,
+    };
+    const struct
+    {
+        float *red_received, *green_received, *blue_received;
+        const float *red_expected, *green_expected, *blue_expected;
+        float radius, roffset, goffset, boffset;
+    }
+    test[] =
+    {
+        { rout, gout, bout, table, &table[108], &table[216], 17.4f, 1.01f, 1.02f, 1.03f, },
+        { rout, gout, bout, &table[36], &table[144], &table[252], 1.6f, 1.01f, 1.02f, 1.03f, },
+        { rout, gout, bout, &table[72], &table[180], &table[288], -3.0f, 1.01f, 1.02f, 1.03f, },
+        { rout, rout, rout, &table[216], &table[216], &table[216], 17.4f, 1.03f, 1.03f, 1.03f, },
+        { rout, rout, bout, &table[108], &table[108], &table[216], 17.4, 1.02f, 1.02f, 1.03f, },
+        { rout, gout, gout, table, &table[216], &table[216], 17.4f, 1.01f, 1.03f, 1.03f, },
+        { rout, gout, rout, &table[216], &table[108], &table[216], 17.4f, 1.03f, 1.02f, 1.03f, },
+    /* D3DXSHEvalSphericalLight accepts NULL green or blue colour. */
+        { rout, NULL, bout, table, NULL, &table[216], 17.4f, 1.01f, 0.0f, 1.03f, },
+        { rout, gout, NULL, table, &table[108], NULL, 17.4f, 1.01f, 1.02f, 0.0f, },
+        { rout, NULL, NULL, table, NULL, NULL, 17.4f, 1.01f, 0.0f, 0.0f, },
+    };
+
+    dir.x = 1.1f; dir.y = 1.2f; dir.z = 2.76f;
+
+    for (l = 0; l < ARRAY_SIZE(test); ++l)
+    {
+        for (order = D3DXSH_MINORDER; order <= D3DXSH_MAXORDER; order++)
+        {
+            for (j = 0; j < 49; j++)
+            {
+                test[l].red_received[j] = 1.01f + j;
+                if (test[l].green_received)
+                    test[l].green_received[j] = 1.02f + j;
+                if (test[l].blue_received)
+                    test[l].blue_received[j] = 1.03f + j;
+            }
+
+            hr = D3DXSHEvalSphericalLight(order, &dir, test[l].radius, 1.7f, 2.6f, 3.5f, test[l].red_received, test[l].green_received, test[l].blue_received);
+            ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+
+            for (j = 0; j < 49; j++)
+            {
+                if (j >= order * order)
+                    expected = j + test[l].roffset;
+                else
+                    expected = test[l].red_expected[j];
+                equal = compare_float(expected, test[l].red_received[j], 4096);
+                ok(equal || (fabs(expected) < 1.0e-6f && fabs(test[l].red_received[j]) < 1.0e-6f),
+                        "Red: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                        l, order, j, expected, test[l].red_received[j]);
+
+                if (test[l].green_received)
+                {
+                    if (j >= order * order)
+                        expected = j + test[l].goffset;
+                    else
+                        expected = test[l].green_expected[j];
+                    equal = compare_float(expected, test[l].green_received[j], 4096);
+                    ok(equal || (fabs(expected) < 1.0e-6f && fabs(test[l].green_received[j]) < 1.0e-6f),
+                            "Green: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                            l, order, j, expected, test[l].green_received[j]);
+                }
+
+                if (test[l].blue_received)
+                {
+                    if (j >= order * order)
+                        expected = j + test[l].boffset;
+                    else
+                        expected = test[l].blue_expected[j];
+                    equal = compare_float(expected, test[l].blue_received[j], 4096);
+                    ok(equal || (fabs(expected) < 1.0e-6f && fabs(test[l].blue_received[j]) < 1.0e-6f),
+                            "Blue: case %u, order %u: expected[%u] = %.8e, received %.8e.\n",
+                            l, order, j, expected, test[l].blue_received[j]);
+                }
+            }
+        }
+    }
+
+    /* D3DXSHEvalSphericalLight accepts order < D3DXSH_MINORDER or order > D3DXSH_MAXORDER. But tests in native windows show that the colour outputs are not set */
+    hr = D3DXSHEvalSphericalLight(7, &dir, 17.4f, 1.0f, 2.0f, 3.0f, rout, gout, bout);
+    ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+    hr = D3DXSHEvalSphericalLight(0, &dir, 17.4f, 1.0f, 2.0f, 3.0f, rout, gout, bout);
+    ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+    hr = D3DXSHEvalSphericalLight(1, &dir, 17.4f, 1.0f, 2.0f, 3.0f, rout, gout, bout);
+    ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr);
+}
+
+static void test_D3DXSHMultiply2(void)
+{
+    float a[20], b[20], c[20];
+    unsigned int i;
+    BOOL equal;
+
+    /* D3DXSHMultiply2() only modifies the first 4 elements of the array. */
+    static const float expected[20] =
+    {
+         3.41859412f,  1.69821072f,  1.70385253f,  1.70949447f,  4.0f,  5.0f,  6.0f,
+                7.0f,         8.0f,         9.0f,        10.0f, 11.0f, 12.0f, 13.0f,
+               14.0f,        15.0f,        16.0f,        17.0f, 18.0f, 19.0f,
+    };
+
+    for (i = 0; i < ARRAY_SIZE(a); ++i)
+    {
+        a[i] = 1.0f + i / 100.0f;
+        b[i] = 3.0f - i / 100.0f;
+        c[i] = i;
+    }
+
+    D3DXSHMultiply2(c, a, b);
+    for (i = 0; i < ARRAY_SIZE(expected); ++i)
+    {
+        equal = compare_float(c[i], expected[i], 2);
+        ok(equal, "Expected[%u] = %.8e, received = %.8e.\n", i, expected[i], c[i]);
+    }
+}
+
+static void test_D3DXSHMultiply3(void)
+{
+    float a[20], b[20], c[20];
+    unsigned int i;
+    BOOL equal;
+
+    /* D3DXSHMultiply3() only modifies the first 9 elements of the array. */
+    static const float expected[20] =
+    {
+        7.81391382e+00f, 2.25605774e+00f, 5.94839954e+00f, 4.97089481e+00f, 2.89985824e+00f, 3.59894633e+00f,
+        1.72657156e+00f, 5.57353783e+00f, 6.22063160e-01f, 9.00000000e+00f, 1.00000000e+01f, 1.10000000e+01f,
+        1.20000000e+01f, 1.30000000e+01f, 1.40000000e+01f, 1.50000000e+01f, 1.60000000e+01f, 1.70000000e+01f,
+        1.80000000e+01f, 1.90000000e+01f,
+    };
+    static const float expected_aliased[20] =
+    {
+        4.54092499e+02f, 2.12640405e+00f, 5.57040071e+00f, 1.53303785e+01f, 2.27960873e+01f, 4.36041260e+01f,
+        4.27384138e+00f, 1.75772034e+02f, 2.37672729e+02f, 1.09000003e+00f, 1.10000002e+00f, 1.11000001e+00f,
+        1.12000000e+00f, 1.13000000e+00f, 1.13999999e+00f, 1.14999998e+00f, 1.15999997e+00f, 1.16999996e+00f,
+        1.17999995e+00f, 1.19000006e+00f,
+    };
+
+    for (i = 0; i < ARRAY_SIZE(a); ++i)
+    {
+        a[i] = 1.0f + i / 100.0f;
+        b[i] = 3.0f - i / 100.0f;
+        c[i] = i;
+    }
+
+    D3DXSHMultiply3(c, a, b);
+    for (i = 0; i < ARRAY_SIZE(expected); ++i)
+    {
+        equal = compare_float(c[i], expected[i], 4);
+        ok(equal, "Expected[%u] = %.8e, received = %.8e.\n", i, expected[i], c[i]);
+    }
+
+    memcpy(c, a, sizeof(c));
+    D3DXSHMultiply3(c, c, b);
+    for (i = 0; i < ARRAY_SIZE(expected_aliased); ++i)
+    {
+        equal = compare_float(c[i], expected_aliased[i], 32);
+        ok(equal, "Expected[%u] = %.8e, received = %.8e.\n", i, expected_aliased[i], c[i]);
+    }
+}
+
+static void test_D3DXSHMultiply4(void)
+{
+    float a[20], b[20], c[20];
+    unsigned int i;
+    BOOL equal;
+
+    /* D3DXSHMultiply4() only modifies the first 16 elements of the array. */
+    static const float expected[] =
+    {
+        /* c, a, b */
+         1.41825991e+01f,  2.61570334e+00f,  1.28286009e+01f,  9.82059574e+00f,  3.03969646e+00f,  4.53044176e+00f,
+         5.82058382e+00f,  1.22498465e+01f,  2.19434643e+00f,  3.90015244e+00f,  5.41660881e+00f,  5.60181284e+00f,
+         9.59981740e-01f,  7.03754997e+00f,  3.62523031e+00f,  4.63601470e-01f,  1.60000000e+01f,  1.70000000e+01f,
+         1.80000000e+01f,  1.90000000e+01f,
+        /* c, c, b */
+        -2.11441266e+05f, -2.52915771e+03f, -1.00233936e+04f, -4.41277191e+02f, -1.63994385e+02f, -5.26305115e+02f,
+         2.96361875e+04f, -3.93183081e+03f, -1.35771113e+04f, -3.97897388e+03f, -1.03303418e+04f, -1.37797871e+04f,
+        -1.66851094e+04f, -4.49813750e+04f, -7.32697422e+04f, -9.52373359e+04f,  1.60000000e+01f,  1.70000000e+01f,
+         1.80000000e+01f,  1.90000000e+01f,
+        /* c, c, c */
+         2.36682415e-01f, -7.17648506e-01f, -1.80499524e-01f, -7.71235973e-02f,  1.44830629e-01f,  5.73285699e-01f,
+        -3.37959230e-01f,  5.56938872e-02f, -4.42100227e-01f,  1.47701755e-01f, -5.51566519e-02f,  8.43374059e-02f,
+         1.79876596e-01f,  9.09878965e-03f,  2.32199892e-01f,  7.41420984e-02f,  1.60000002e+00f,  1.70000005e+00f,
+         1.80000007e+00f,  1.89999998e+00f,
+    };
+
+    for (i = 0; i < ARRAY_SIZE(a); ++i)
+    {
+        a[i] = 1.0f + i / 100.0f;
+        b[i] = 3.0f - i / 100.0f;
+        c[i] = i;
+    }
+
+    D3DXSHMultiply4(c, a, b);
+    for (i = 0; i < ARRAY_SIZE(c); ++i)
+    {
+        equal = compare_float(c[i], expected[i], 16);
+        ok(equal, "Expected[%u] = %.8e, received = %.8e.\n", i, expected[i], c[i]);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(b); ++i)
+    {
+        b[i] = 3.0f - i / 100.0f;
+        c[i] = i;
+    }
+
+    D3DXSHMultiply4(c, c, b);
+    for (i = 0; i < ARRAY_SIZE(c); ++i)
+    {
+        equal = compare_float(c[i], expected[20 + i], 32);
+        ok(equal, "Expected[%u] = %.8e, received = %.8e.\n", i, expected[20 + i], c[i]);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(c); ++i)
+        c[i] = 0.1f * i;
+
+    D3DXSHMultiply4(c, c, c);
+    for (i = 0; i < ARRAY_SIZE(c); ++i)
+    {
+        equal = compare_float(c[i], expected[40 + i], 8);
+        ok(equal, "Expected[%u] = %.8e, received = %.8e.\n", i, expected[40 + i], c[i]);
+    }
+}
+
+static void test_D3DXSHRotate(void)
+{
+    float expected, in[49], out[49], *out_temp, *received_ptr;
+    unsigned int i, j, l, order;
+    D3DXMATRIX m[4];
+    BOOL equal;
+
+    static const float table[]=
+    {
+        /* Rotation around the x-axis, Ï€/2. */
+         1.00999999e+00f, -3.00999999e+00f,  2.00999975e+00f,  4.01000023e+00f, -8.01000023e+00f, -6.00999928e+00f,
+        -1.13078899e+01f,  5.00999975e+00f, -1.56583869e+00f,  1.09359801e+00f, -1.10099983e+01f,  1.98334141e+01f,
+        -1.52681913e+01f, -1.90041180e+01f, -3.36488891e+00f, -9.56262684e+00f,  1.20996542e+01f, -2.72131383e-01f,
+         3.02410126e+01f,  2.69199905e+01f,  3.92368774e+01f, -2.26324463e+01f,  6.70738792e+00f, -1.17682819e+01f,
+         3.44367194e+00f, -6.07445812e+00f,  1.16183939e+01f,  1.52756083e+00f,  3.78963356e+01f, -5.69012184e+01f,
+         4.74228935e+01f,  5.03915329e+01f,  1.06181908e+01f,  2.55010109e+01f,  4.92456071e-02f,  1.69833069e+01f,
+
+         1.00999999e+00f, -3.00999999e+00f, -3.01000023e+00f,  4.01000023e+00f, -8.01000023e+00f, -6.00999928e+00f,
+        -1.13078890e+01f, -8.01000023e+00f,  1.42979193e+01f,
+        /* Rotation around the x-axis, -Ï€/2. */
+         1.00999999e+00f,  3.00999999e+00f, -2.01000023e+00f,  4.01000023e+00f,  8.01000023e+00f, -6.01000118e+00f,
+        -1.13078880e+01f, -5.01000071e+00f, -1.56583774e+00f, -1.09359753e+00f, -1.10100021e+01f, -1.98334103e+01f,
+         1.52681961e+01f, -1.90041142e+01f,  3.36489248e+00f, -9.56262398e+00f, -1.20996523e+01f, -2.72129118e-01f,
+        -3.02410049e+01f,  2.69200020e+01f,  3.92368736e+01f,  2.26324520e+01f,  6.70738268e+00f,  1.17682877e+01f,
+         3.44367099e+00f,  6.07445717e+00f,  1.16183996e+01f, -1.52756333e+00f,  3.78963509e+01f,  5.69011993e+01f,
+        -4.74229126e+01f,  5.03915253e+01f, -1.06182041e+01f,  2.55009995e+01f, -4.92481887e-02f,  1.69833050e+01f,
+
+         1.00999999e+00f,  3.00999999e+00f, -3.01000023e+00f,  4.01000023e+00f,  8.01000023e+00f, -6.01000118e+00f,
+        -1.13078899e+01f, -8.01000023e+00f,  1.42979193e+01f,
+        /* Yaw Ï€/3, pitch Ï€/4, roll Ï€/5. */
+         1.00999999e+00f,  4.94489908e+00f,  1.44230127e+00f,  1.62728095e+00f,  2.19220325e-01f,  1.05408239e+01f,
+        -9.13690281e+00f,  2.76374960e+00f, -7.30904531e+00f, -5.87572050e+00f,  5.30312395e+00f, -8.68215370e+00f,
+        -2.56833839e+01f,  1.68027866e+00f, -1.88083878e+01f,  7.65365601e+00f,  1.69391327e+01f, -1.73280182e+01f,
+         1.46297951e+01f, -5.44671021e+01f, -1.22310352e+01f, -4.08985710e+00f, -9.44422245e+00f,  3.05603528e+00f,
+         1.79257303e-01f, -1.00418749e+01f,  2.30900917e+01f, -2.31887093e+01f,  1.17270985e+01f, -6.51830902e+01f,
+         4.86715775e+01f, -1.50732088e+01f,  3.87931709e+01f, -2.60395355e+01f,  6.19276857e+00f, -1.76722469e+01f,
+
+         1.00999999e+00f,  4.94489908e+00f, -8.91142070e-01f,  4.60769463e+00f,  2.19218358e-01f,  1.07733250e+01f,
+        -8.20476913e+00f,  1.35638294e+01f, -1.20077667e+01f,
+        /* Rotation around the z-axis, Ï€/6. */
+         1.00999999e+00f,  3.74571109e+00f,  3.00999999e+00f,  2.46776199e+00f,  1.03078890e+01f,  9.20981312e+00f,
+         7.01000023e+00f,  3.93186355e+00f,  1.66212186e-01f,  1.60099983e+01f,  1.85040417e+01f,  1.74059658e+01f,
+         1.30100002e+01f,  6.12801647e+00f, -2.02994061e+00f, -1.00100012e+01f,  1.31542921e+01f,  2.40099964e+01f,
+         2.94322453e+01f,  2.83341675e+01f,  2.10100021e+01f,  9.05622101e+00f, -4.95814323e+00f, -1.80100002e+01f,
+        -2.72360935e+01f, -4.52033186e+00f,  1.68145428e+01f,  3.40099945e+01f,  4.30924950e+01f,  4.19944229e+01f,
+         3.10100002e+01f,  1.27164707e+01f, -8.61839962e+00f, -2.80100021e+01f, -4.08963470e+01f, -4.41905708e+01f,
+
+         1.00999999e+00f,  3.74571109e+00f,  3.00999999e+00f,  1.59990644e+00f,  1.03078890e+01f,  9.20981312e+00f,
+         7.01000023e+00f,  2.33195710e+00f, -4.42189360e+00f,
+    };
+
+    D3DXMatrixRotationX(&m[0], -D3DX_PI / 2.0f);
+    D3DXMatrixRotationX(&m[1], D3DX_PI / 2.0f);
+    D3DXMatrixRotationYawPitchRoll(&m[2], D3DX_PI / 3.0f, D3DX_PI / 4.0f, D3DX_PI / 5.0f);
+    D3DXMatrixRotationZ(&m[3], D3DX_PI / 6.0f);
+
+    for (l = 0; l < 2; l++)
+    {
+        if (l == 0)
+            out_temp = out;
+        else
+            out_temp = in;
+
+        for (j = 0; j < ARRAY_SIZE(m); ++j)
+        {
+            for (order = 0; order <= D3DXSH_MAXORDER; order++)
+            {
+                for (i = 0; i < ARRAY_SIZE(out); ++i)
+                {
+                    out[i] = ( i + 1.0f ) * ( i + 1.0f );
+                    in[i] = i + 1.01f;
+                }
+
+                received_ptr = D3DXSHRotate(out_temp, order, &m[j], in);
+                ok(received_ptr == out_temp, "Order %u, expected %p, received %p.\n",
+                        order, out, received_ptr);
+
+                for (i = 0; i < ARRAY_SIZE(out); ++i)
+                {
+                    if ((i > 0) && ((i >= order * order) || (order > D3DXSH_MAXORDER)))
+                    {
+                        if (l == 0)
+                            expected = ( i + 1.0f ) * ( i + 1.0f );
+                        else
+                            expected = i + 1.01f;
+                    }
+                    else if ((l == 0) || (order > 3))
+                        expected = table[45 * j + i];
+                    else
+                        expected = table[45 * j + 36 +i];
+                    equal = compare_float(out_temp[i], expected, 4096);
+                    ok(equal, "Order %u index %u, expected %.8e, received %.8e.\n",
+                            order, i, expected, out_temp[i]);
+                }
+            }
+        }
+    }
+}
+
+static void test_D3DXSHRotateZ(void)
+{
+    float expected, in[49], out[49], *out_temp, *received_ptr;
+    unsigned int end, i, j, l, order, square;
+    BOOL equal;
+
+    static const float angle[] = {D3DX_PI / 3.0f, -D3DX_PI / 3.0f, 4.0f * D3DX_PI / 3.0f};
+    static const float table[] =
+    {
+        /* Angle Ï€/3. */
+         1.00999999e+00f,  4.47776222e+00f,  3.00999999e+00f,  2.64288902e-01f,  5.29788828e+00f,  9.94186401e+00f,
+         7.01000023e+00f, -1.19981313e+00f, -8.84378910e+00f, -1.00100021e+01f,  7.49403954e+00f,  1.81380157e+01f,
+         1.30100002e+01f, -3.39596605e+00f, -1.70399418e+01f, -1.60099983e+01f, -3.01642971e+01f, -1.80100040e+01f,
+         1.04222422e+01f,  2.90662193e+01f,  2.10100002e+01f, -6.32417059e+00f, -2.79681454e+01f, -2.40099983e+01f,
+         2.22609901e+00f, -1.81805649e+01f, -4.38245506e+01f, -2.80100040e+01f,  1.40824928e+01f,  4.27264709e+01f,
+         3.10100002e+01f, -9.98442554e+00f, -4.16283989e+01f, -3.40099945e+01f,  5.88635778e+00f,  4.05303307e+01f,
+
+         1.00999999e+00f,  4.47776222e+00f,  0.00000000e+00f, -5.81678391e+00f,  5.29788828e+00f,  6.93686390e+00f,
+         0.00000000e+00f, -9.01125050e+00f, -2.29405236e+00f, -1.00100021e+01f,  1.29990416e+01f,  1.21330166e+01f,
+         0.00000000e+00f, -1.57612505e+01f, -5.62874842e+00f,  0.00000000e+00f, -3.01642971e+01f, -3.29017075e-06f,
+         1.99272442e+01f,  1.90612202e+01f,  0.00000000e+00f, -2.47612514e+01f, -8.62874794e+00f,  0.00000000e+00f,
+        -1.30615301e+01f, -1.81805649e+01f, -3.03195534e+01f, -4.66050415e-06f,  2.85874958e+01f,  2.77214737e+01f,
+         0.00000000e+00f, -3.60112534e+01f, -1.23787460e+01f,  0.00000000e+00f, -1.31287584e+01f, -2.36172504e+01f,
+
+         1.00999999e+00f,  3.97776222e+00f,  3.97776222e+00f,  1.11419535e+00f,  7.24579096e+00f,  1.05597591e+01f,
+         1.05597591e+01f, -9.95159924e-01f, -4.67341393e-01f,  4.67339337e-01f,  1.27653713e+01f,  1.85157013e+01f,
+         1.85157013e+01f, -1.79728663e+00f,  4.93915796e-01f, -4.93915856e-01f, -2.14123421e+01f,  2.14123383e+01f,
+         9.22107220e+00f,  2.36717567e+01f,  2.36717567e+01f,  3.85019469e+00f, -2.04687271e+01f,  2.04687233e+01f,
+        -1.06621027e+01f, -3.65166283e+01f, -1.20612450e+01f,  1.20612402e+01f,  2.25568752e+01f,  3.89999084e+01f,
+         3.89999084e+01f, -3.48751247e-02f, -1.04279022e+01f,  1.04279003e+01f, -3.68382835e+01f, -2.76528034e+01f,
+        /* Angle -Ï€/3. */
+         1.00999999e+00f, -2.46776247e+00f,  3.00999999e+00f,  3.74571109e+00f, -1.03078899e+01f, -3.93186426e+00f,
+         7.01000023e+00f,  9.20981312e+00f, -1.66213632e-01f, -1.00099983e+01f, -1.85040436e+01f, -6.12801695e+00f,
+         1.30100002e+01f,  1.74059658e+01f,  2.02993774e+00f, -1.60100021e+01f,  1.31543026e+01f, -1.80099964e+01f,
+        -2.94322472e+01f, -9.05622101e+00f,  2.10100002e+01f,  2.83341694e+01f,  4.95813942e+00f, -2.40100021e+01f,
+        -2.72360916e+01f,  4.41905823e+01f,  1.68145580e+01f, -2.80099964e+01f, -4.30924988e+01f, -1.27164736e+01f,
+         3.10100002e+01f,  4.19944229e+01f,  8.61839294e+00f, -3.40100021e+01f, -4.08963470e+01f, -4.52030993e+00f,
+
+         1.00999999e+00f, -2.46776247e+00f,  0.00000000e+00f, -3.20571756e+00f, -1.03078899e+01f, -6.93686390e+00f,
+         0.00000000e+00f, -9.01125050e+00f, -4.46344614e+00f, -1.00099983e+01f, -1.29990416e+01f, -1.21330166e+01f,
+         0.00000000e+00f, -1.57612505e+01f, -5.62874842e+00f,  0.00000000e+00f,  1.31543026e+01f,  3.29017075e-06f,
+        -1.99272442e+01f, -1.90612202e+01f,  0.00000000e+00f, -2.47612514e+01f, -8.62874794e+00f,  0.00000000e+00f,
+        -5.69598293e+00f,  4.41905823e+01f,  3.03195534e+01f,  4.66050415e-06f, -2.85874958e+01f, -2.77214737e+01f,
+         0.00000000e+00f, -3.60112534e+01f, -1.23787460e+01f,  0.00000000e+00f, -1.31287584e+01f, -5.74052582e+01f,
+
+         1.00999999e+00f, -2.96776223e+00f, -2.96776223e+00f, -6.09195352e-01f, -7.49829102e+00f, -1.06860094e+01f,
+        -1.06860094e+01f, -1.18367157e+01f,  5.39078045e+00f, -5.39077854e+00f, -1.03036509e+01f, -1.72848415e+01f,
+        -1.72848415e+01f, -1.75656433e+01f,  4.11427259e+00f, -4.11427307e+00f,  2.37164364e+01f, -2.37164326e+01f,
+        -8.06902504e+00f, -2.30957317e+01f, -2.30957317e+01f, -1.85358467e+01f, -1.12711067e+01f,  1.12711039e+01f,
+        -2.07248449e+00f,  3.01493301e+01f,  1.52448931e+01f, -1.52448883e+01f, -2.09650497e+01f, -3.82039986e+01f,
+        -3.82039986e+01f, -3.72582664e+01f,  5.42667723e+00f, -5.42667913e+00f, -2.33967514e+01f, -9.90355873e+00f,
+        /* Angle 4Ï€/3. */
+         1.00999999e+00f, -4.47776222e+00f,  3.00999999e+00f, -2.64288664e-01f,  5.29788685e+00f, -9.94186401e+00f,
+         7.01000023e+00f,  1.19981360e+00f, -8.84378815e+00f,  1.00100040e+01f,  7.49403811e+00f, -1.81380157e+01f,
+         1.30100002e+01f,  3.39596677e+00f, -1.70399399e+01f,  1.60099964e+01f, -3.01642933e+01f,  1.80100060e+01f,
+         1.04222393e+01f, -2.90662193e+01f,  2.10100002e+01f,  6.32417202e+00f, -2.79681435e+01f,  2.40099926e+01f,
+         2.22610497e+00f,  1.81805515e+01f, -4.38245430e+01f,  2.80100079e+01f,  1.40824890e+01f, -4.27264709e+01f,
+         3.10100002e+01f,  9.98442745e+00f, -4.16283989e+01f,  3.40099869e+01f,  5.88636589e+00f, -4.05303268e+01f,
+
+         1.00999999e+00f, -4.47776222e+00f,  0.00000000e+00f, -1.93892837e+00f,  5.29788685e+00f, -6.93686390e+00f,
+         0.00000000e+00f, -3.00375080e+00f, -2.29405141e+00f,  1.00100040e+01f,  1.29990396e+01f, -1.21330166e+01f,
+         0.00000000e+00f, -5.25375128e+00f, -5.62874699e+00f, -5.68378528e-06f, -3.01642933e+01f,  7.00829787e-06f,
+         1.99272423e+01f, -1.90612202e+01f,  0.00000000e+00f, -8.25375271e+00f, -8.62874603e+00f, -4.09131496e-12f,
+        -1.30615349e+01f,  1.81805515e+01f, -3.03195534e+01f,  9.92720470e-06f,  2.85874920e+01f, -2.77214737e+01f,
+         0.00000000e+00f, -1.20037527e+01f, -1.23787422e+01f, -5.79531909e-12f, -1.31287651e+01f, -7.87240028e+00f,
+
+         1.00999999e+00f, -3.97776222e+00f, -3.97776222e+00f,  2.86356640e+00f,  6.37110424e+00f, -1.01224155e+01f,
+        -1.01224155e+01f,  1.05787458e+01f, -7.76929522e+00f, -7.76928997e+00f,  1.68836861e+01f, -2.05748577e+01f,
+        -2.05748577e+01f,  2.49091301e+01f, -5.72616625e+00f, -5.72616386e+00f, -1.87962208e+01f, -1.87962112e+01f,
+         2.93253498e+01f, -3.37238922e+01f, -3.37238922e+01f,  4.22584419e+01f, -4.85123205e+00f, -4.85122633e+00f,
+        -2.53339314e+00f,  3.24522591e+01f, -4.65456696e+01f, -4.65456543e+01f,  5.18603249e+01f, -5.36516304e+01f,
+        -5.36516304e+01f,  7.17381744e+01f,  4.44061565e+00f,  4.44062901e+00f,  2.58841743e+01f, -1.07481155e+01f,
+    };
+
+    for (l = 0; l < 3; l++)
+    {
+        if (l == 0)
+            out_temp = out;
+        else
+            out_temp = &in[l - 1];
+
+        if (l < 2)
+            end = 49;
+        else
+            end = 48;
+
+        for (j = 0; j < ARRAY_SIZE(angle); ++j)
+        {
+            for (order = 0; order <= D3DXSH_MAXORDER + 1; order++)
+            {
+                for (i = 0; i < ARRAY_SIZE(out); ++i)
+                {
+                    out[i] = ( i + 1.0f ) * ( i + 1.0f );
+                    in[i] = i + 1.01f;
+                }
+
+                received_ptr = D3DXSHRotateZ(out_temp, order, angle[j], in);
+                ok(received_ptr == out_temp, "angle %f, order %u, expected %p, received %p\n", angle[j], order, out_temp, received_ptr);
+
+                for (i = 0; i < end; i++)
+                {
+                    /* order = 0 or order = 1 behaves like order = D3DXSH_MINORDER */
+                    square = (order <= D3DXSH_MINORDER) ? D3DXSH_MINORDER * D3DXSH_MINORDER : order * order;
+                    if (i >= square || ((order >= D3DXSH_MAXORDER) && (i >= D3DXSH_MAXORDER * D3DXSH_MAXORDER)))
+                        if (l > 0)
+                            expected = i + l + 0.01f;
+                        else
+                            expected = ( i + 1.0f ) * ( i + 1.0f );
+                    else
+                        expected = table[36 * (l + 3 * j) + i];
+                    equal = compare_float(expected, out_temp[i], 256);
+                    ok(equal || (fabs(expected) < 2.0e-5f && fabs(out_temp[i]) < 2.0e-5f),
+                            "angle %.8e, order %u index %u, expected %.8e, received %.8e.\n",
+                            angle[j], order, i, expected, out_temp[i]);
+                }
+            }
+        }
+    }
+}
+
+static void test_D3DXSHScale(void)
+{
+    float a[49], b[49], expected, *received_array;
+    unsigned int i, order;
+    BOOL equal;
+
+    for (i = 0; i < ARRAY_SIZE(a); ++i)
+    {
+        a[i] = i;
+        b[i] = i;
+    }
+
+    for (order = 0; order <= D3DXSH_MAXORDER + 1; order++)
+    {
+        received_array = D3DXSHScale(b, order, a, 5.0f);
+        ok(received_array == b, "Expected %p, received %p\n", b, received_array);
+
+        for (i = 0; i < ARRAY_SIZE(b); ++i)
+        {
+            if (i < order * order)
+                expected = 5.0f * a[i];
+            /* D3DXSHScale does not modify the elements of the array after the order * order-th element */
+            else
+                expected = a[i];
+            equal = compare_float(b[i], expected, 0);
+            ok(equal, "order %u, element %u, expected %.8e, received %.8e.\n", order, i, expected, b[i]);
+        }
+    }
+}
+
+START_TEST(math)
+{
+    D3DXColorTest();
+    D3DXFresnelTest();
+    D3DXMatrixTest();
+    D3DXPlaneTest();
+    D3DXQuaternionTest();
+    D3DXVector2Test();
+    D3DXVector3Test();
+    D3DXVector4Test();
+    test_matrix_stack();
+    test_Matrix_AffineTransformation2D();
+    test_Matrix_Decompose();
+    test_Matrix_Transformation2D();
+    test_D3DXVec_Array();
+    test_D3DXFloat_Array();
+    test_D3DXSHAdd();
+    test_D3DXSHDot();
+    test_D3DXSHEvalConeLight();
+    test_D3DXSHEvalDirection();
+    test_D3DXSHEvalDirectionalLight();
+    test_D3DXSHEvalHemisphereLight();
+    test_D3DXSHEvalSphericalLight();
+    test_D3DXSHMultiply2();
+    test_D3DXSHMultiply3();
+    test_D3DXSHMultiply4();
+    test_D3DXSHRotate();
+    test_D3DXSHRotateZ();
+    test_D3DXSHScale();
+}
diff --git a/modules/rostests/winetests/d3dx9_36/mesh.c b/modules/rostests/winetests/d3dx9_36/mesh.c
new file mode 100644 (file)
index 0000000..1b0f86e
--- /dev/null
@@ -0,0 +1,11256 @@
+/*
+ * Copyright 2008 David Adam
+ * Copyright 2008 Luis Busquets
+ * Copyright 2009 Henri Verbeet for CodeWeavers
+ * Copyright 2011 Michael Mc Donnell
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include <stdio.h>
+#include <float.h>
+#include <limits.h>
+#include "wine/test.h"
+#include "d3dx9.h"
+
+#ifndef NAN
+/* From wine/port.h */
+static inline float __port_nan(void)
+{
+    static const unsigned __nan_bytes = 0x7fc00000;
+    return *(const float *)&__nan_bytes;
+}
+#define NAN __port_nan()
+#endif
+
+/* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose
+ * function call traces of ID3DXAllocateHierarchy callbacks. */
+#define TRACECALLBACK if(winetest_debug > 1) trace
+
+#define admitted_error 0.0001f
+
+#define compare_vertex_sizes(type, exp) \
+    got=D3DXGetFVFVertexSize(type); \
+    ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
+
+#define compare_float(got, exp) \
+    do { \
+        float _got = (got); \
+        float _exp = (exp); \
+        ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
+    } while (0)
+
+static BOOL compare(FLOAT u, FLOAT v)
+{
+    return (fabs(u-v) < admitted_error);
+}
+
+static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
+{
+    return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
+}
+
+static BOOL compare_vec4(D3DXVECTOR4 u, D3DXVECTOR4 v)
+{
+    return compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) && compare(u.w, v.w);
+}
+
+#define check_floats(got, exp, dim) check_floats_(__LINE__, "", got, exp, dim)
+static void check_floats_(int line, const char *prefix, const float *got, const float *exp, int dim)
+{
+    int i;
+    char exp_buffer[256] = "";
+    char got_buffer[256] = "";
+    char *exp_buffer_ptr = exp_buffer;
+    char *got_buffer_ptr = got_buffer;
+    BOOL equal = TRUE;
+
+    for (i = 0; i < dim; i++) {
+        if (i) {
+            exp_buffer_ptr += sprintf(exp_buffer_ptr, ", ");
+            got_buffer_ptr += sprintf(got_buffer_ptr, ", ");
+        }
+        equal = equal && compare(*exp, *got);
+        exp_buffer_ptr += sprintf(exp_buffer_ptr, "%g", *exp);
+        got_buffer_ptr += sprintf(got_buffer_ptr, "%g", *got);
+        exp++, got++;
+    }
+    ok_(__FILE__,line)(equal, "%sExpected (%s), got (%s)", prefix, exp_buffer, got_buffer);
+}
+
+struct vertex
+{
+    D3DXVECTOR3 position;
+    D3DXVECTOR3 normal;
+};
+
+typedef WORD face[3];
+
+static BOOL compare_face(face a, face b)
+{
+    return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
+}
+
+struct test_context
+{
+    HWND hwnd;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *device;
+};
+
+/* Initializes a test context struct. Use it to initialize DirectX.
+ *
+ * Returns NULL if an error occurred.
+ */
+static struct test_context *new_test_context(void)
+{
+    HRESULT hr;
+    HWND hwnd = NULL;
+    IDirect3D9 *d3d = NULL;
+    IDirect3DDevice9 *device = NULL;
+    D3DPRESENT_PARAMETERS d3dpp = {0};
+    struct test_context *test_context;
+
+    if (!(hwnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window\n");
+        goto error;
+    }
+
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    if (!d3d)
+    {
+        skip("Couldn't create IDirect3D9 object\n");
+        goto error;
+    }
+
+    memset(&d3dpp, 0, sizeof(d3dpp));
+    d3dpp.Windowed = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
+                                 D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
+    if (FAILED(hr))
+    {
+        skip("Couldn't create IDirect3DDevice9 object %#x\n", hr);
+        goto error;
+    }
+
+    test_context = HeapAlloc(GetProcessHeap(), 0, sizeof(*test_context));
+    if (!test_context)
+    {
+        skip("Couldn't allocate memory for test_context\n");
+        goto error;
+    }
+    test_context->hwnd = hwnd;
+    test_context->d3d = d3d;
+    test_context->device = device;
+
+    return test_context;
+
+error:
+    if (device)
+        IDirect3DDevice9_Release(device);
+
+    if (d3d)
+        IDirect3D9_Release(d3d);
+
+    if (hwnd)
+        DestroyWindow(hwnd);
+
+    return NULL;
+}
+
+static void free_test_context(struct test_context *test_context)
+{
+    if (!test_context)
+        return;
+
+    if (test_context->device)
+        IDirect3DDevice9_Release(test_context->device);
+
+    if (test_context->d3d)
+        IDirect3D9_Release(test_context->d3d);
+
+    if (test_context->hwnd)
+        DestroyWindow(test_context->hwnd);
+
+    HeapFree(GetProcessHeap(), 0, test_context);
+}
+
+struct mesh
+{
+    DWORD number_of_vertices;
+    struct vertex *vertices;
+
+    DWORD number_of_faces;
+    face *faces;
+
+    DWORD fvf;
+    UINT vertex_size;
+};
+
+static void free_mesh(struct mesh *mesh)
+{
+    HeapFree(GetProcessHeap(), 0, mesh->faces);
+    HeapFree(GetProcessHeap(), 0, mesh->vertices);
+}
+
+static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
+{
+    mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
+    if (!mesh->vertices)
+    {
+        return FALSE;
+    }
+    mesh->number_of_vertices = number_of_vertices;
+
+    mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
+    if (!mesh->faces)
+    {
+        HeapFree(GetProcessHeap(), 0, mesh->vertices);
+        return FALSE;
+    }
+    mesh->number_of_faces = number_of_faces;
+
+    return TRUE;
+}
+
+static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
+{
+    HRESULT hr;
+    DWORD number_of_vertices, number_of_faces;
+    IDirect3DVertexBuffer9 *vertex_buffer;
+    IDirect3DIndexBuffer9 *index_buffer;
+    D3DVERTEXBUFFER_DESC vertex_buffer_description;
+    D3DINDEXBUFFER_DESC index_buffer_description;
+    struct vertex *vertices;
+    face *faces;
+    int expected, i;
+
+    number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
+    ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
+       name, number_of_vertices, mesh->number_of_vertices);
+
+    number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
+    ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
+       name, number_of_faces, mesh->number_of_faces);
+
+    /* vertex buffer */
+    hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
+    ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
+
+    if (hr != D3D_OK)
+    {
+        skip("Couldn't get vertex buffer\n");
+    }
+    else
+    {
+        hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
+        ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
+
+        if (hr != D3D_OK)
+        {
+            skip("Couldn't get vertex buffer description\n");
+        }
+        else
+        {
+            ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
+               name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
+            ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
+               name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
+            ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
+            ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
+               name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
+            ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
+               name, vertex_buffer_description.FVF, mesh->fvf);
+            if (mesh->fvf == 0)
+            {
+                expected = number_of_vertices * mesh->vertex_size;
+            }
+            else
+            {
+                expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
+            }
+            ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
+               name, vertex_buffer_description.Size, expected);
+        }
+
+        /* specify offset and size to avoid potential overruns */
+        hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
+                (void **)&vertices, D3DLOCK_DISCARD);
+        ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
+
+        if (hr != D3D_OK)
+        {
+            skip("Couldn't lock vertex buffer\n");
+        }
+        else
+        {
+            for (i = 0; i < number_of_vertices; i++)
+            {
+                ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
+                   "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
+                   vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
+                   mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
+                ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
+                   "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
+                   vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
+                   mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
+            }
+
+            IDirect3DVertexBuffer9_Unlock(vertex_buffer);
+        }
+
+        IDirect3DVertexBuffer9_Release(vertex_buffer);
+    }
+
+    /* index buffer */
+    hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
+    ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
+
+    if (!index_buffer)
+    {
+        skip("Couldn't get index buffer\n");
+    }
+    else
+    {
+        hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
+        ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
+
+        if (hr != D3D_OK)
+        {
+            skip("Couldn't get index buffer description\n");
+        }
+        else
+        {
+            ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
+               name, index_buffer_description.Format, D3DFMT_INDEX16);
+            ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
+               name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
+            ok(index_buffer_description.Usage == 0, "Test %s, result %#x, expected %#x.\n",
+                    name, index_buffer_description.Usage, 0);
+            ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
+               name, index_buffer_description.Pool, D3DPOOL_MANAGED);
+            expected = number_of_faces * sizeof(WORD) * 3;
+            ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
+               name, index_buffer_description.Size, expected);
+        }
+
+        /* specify offset and size to avoid potential overruns */
+        hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
+                (void **)&faces, D3DLOCK_DISCARD);
+        ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
+
+        if (hr != D3D_OK)
+        {
+            skip("Couldn't lock index buffer\n");
+        }
+        else
+        {
+            for (i = 0; i < number_of_faces; i++)
+            {
+                ok(compare_face(faces[i], mesh->faces[i]),
+                   "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
+                   faces[i][0], faces[i][1], faces[i][2],
+                   mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
+            }
+
+            IDirect3DIndexBuffer9_Unlock(index_buffer);
+        }
+
+        IDirect3DIndexBuffer9_Release(index_buffer);
+    }
+}
+
+static void D3DXBoundProbeTest(void)
+{
+    BOOL result;
+    D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
+    FLOAT radius;
+
+/*____________Test the Box case___________________________*/
+    bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
+    top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
+
+    raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
+    rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
+    result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
+    ok(result == TRUE, "expected TRUE, received FALSE\n");
+
+    raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
+    rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
+    result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
+    ok(result == FALSE, "expected FALSE, received TRUE\n");
+
+    rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
+    result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
+    ok(result == TRUE, "expected TRUE, received FALSE\n");
+
+    bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
+    top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
+    rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
+    raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
+    result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
+    ok(result == FALSE, "expected FALSE, received TRUE\n");
+
+    bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
+    top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
+
+    raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
+    rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
+    result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
+    ok(result == TRUE, "expected TRUE, received FALSE\n");
+
+    bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
+    top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
+
+    raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
+    rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
+    result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
+    ok(result == FALSE, "expected FALSE, received TRUE\n");
+
+    raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
+    rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
+    result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
+    ok(result == TRUE, "expected TRUE, received FALSE\n");
+
+/*____________Test the Sphere case________________________*/
+    radius = sqrt(77.0f);
+    center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
+    raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
+
+    rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
+    result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
+    ok(result == TRUE, "expected TRUE, received FALSE\n");
+
+    rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
+    result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
+    ok(result == FALSE, "expected FALSE, received TRUE\n");
+
+    rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
+    result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
+    ok(result == FALSE, "expected FALSE, received TRUE\n");
+}
+
+static void D3DXComputeBoundingBoxTest(void)
+{
+    D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
+    HRESULT hr;
+
+    vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
+    vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
+    vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
+    vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
+    vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
+
+    exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
+    exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
+
+    hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
+
+    ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
+    ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
+
+/*________________________*/
+
+    vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
+    vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
+    vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
+    vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
+    vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
+
+    exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
+    exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
+
+    hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
+
+    ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
+    ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
+
+/*________________________*/
+
+    vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
+    vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
+    vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
+    vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
+    vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
+
+    exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
+    exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
+
+    hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
+
+    ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
+    ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
+
+/*________________________*/
+    hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
+    ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+/*________________________*/
+    hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
+    ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+/*________________________*/
+    hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
+    ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+}
+
+static void D3DXComputeBoundingSphereTest(void)
+{
+    D3DXVECTOR3 exp_cen, got_cen, vertex[5];
+    FLOAT exp_rad, got_rad;
+    HRESULT hr;
+
+    vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
+    vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
+    vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
+    vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
+    vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
+
+    exp_rad = 6.928203f;
+    exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
+
+    hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
+
+    ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
+    ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
+
+/*________________________*/
+
+    vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
+    vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
+    vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
+    vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
+    vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
+
+    exp_rad = 13.707883f;
+    exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
+
+    hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
+
+    ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
+    ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
+
+/*________________________*/
+    hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
+    ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+/*________________________*/
+    hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
+    ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+/*________________________*/
+    hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
+    ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+}
+
+static void print_elements(const D3DVERTEXELEMENT9 *elements)
+{
+    D3DVERTEXELEMENT9 last = D3DDECL_END();
+    const 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 void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
+        unsigned int line, unsigned int test_id)
+{
+    D3DVERTEXELEMENT9 last = D3DDECL_END();
+    unsigned int i;
+
+    for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
+    {
+        int end1 = memcmp(&elements[i], &last, sizeof(last));
+        int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
+        int status;
+
+        if (!end1 && !end2) break;
+
+        status = !end1 ^ !end2;
+        ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
+                line, test_id, end1 ? "shorter" : "longer");
+        if (status)
+        {
+            print_elements(elements);
+            break;
+        }
+
+        status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
+        ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
+        if (status)
+        {
+            print_elements(elements);
+            break;
+        }
+    }
+}
+
+static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
+        HRESULT expected_hr, unsigned int line, unsigned int test_id)
+{
+    HRESULT hr;
+    D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
+
+    hr = D3DXDeclaratorFromFVF(test_fvf, decl);
+    ok(hr == expected_hr,
+            "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
+            line, test_id, hr, expected_hr);
+    if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
+}
+
+static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
+        HRESULT expected_hr, unsigned int line, unsigned int test_id)
+{
+    HRESULT hr;
+    DWORD result_fvf = 0xdeadbeef;
+
+    hr = D3DXFVFFromDeclarator(decl, &result_fvf);
+    ok(hr == expected_hr,
+       "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
+       line, test_id, hr, expected_hr);
+    if (SUCCEEDED(hr))
+    {
+        ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
+                line, test_id, result_fvf, expected_fvf);
+    }
+}
+
+static void test_fvf_decl_conversion(void)
+{
+    static const struct
+    {
+        D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
+        DWORD fvf;
+    }
+    test_data[] =
+    {
+        {{
+            D3DDECL_END(),
+        }, 0},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            D3DDECL_END(),
+        }, D3DFVF_XYZ},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
+            D3DDECL_END(),
+        }, D3DFVF_XYZRHW},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
+            D3DDECL_END(),
+        }, D3DFVF_XYZRHW},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
+            D3DDECL_END(),
+        }, D3DFVF_XYZB1},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
+            D3DDECL_END(),
+        }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
+            D3DDECL_END(),
+        }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
+            D3DDECL_END(),
+        }, D3DFVF_XYZB2},
+        {{
+            {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(),
+        }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
+            {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
+            D3DDECL_END(),
+        }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
+            D3DDECL_END(),
+        }, D3DFVF_XYZB3},
+        {{
+            {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(),
+        }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
+        {{
+            {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(),
+        }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
+            D3DDECL_END(),
+        }, D3DFVF_XYZB4},
+        {{
+            {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(),
+        }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
+        {{
+            {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(),
+        }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
+        {{
+            {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(),
+        }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
+        {{
+            {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(),
+        }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
+            D3DDECL_END(),
+        }, D3DFVF_NORMAL},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
+            {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
+            D3DDECL_END(),
+        }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
+            D3DDECL_END(),
+        }, D3DFVF_PSIZE},
+        {{
+            {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
+            D3DDECL_END(),
+        }, D3DFVF_DIFFUSE},
+        {{
+            {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
+            D3DDECL_END(),
+        }, D3DFVF_SPECULAR},
+        /* Make sure textures of different sizes work. */
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
+            D3DDECL_END(),
+        }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
+            D3DDECL_END(),
+        }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
+            D3DDECL_END(),
+        }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
+            D3DDECL_END(),
+        }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
+        /* Make sure the TEXCOORD index works correctly - try several textures. */
+        {{
+            {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(),
+        }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
+                | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
+        /* Now try some combination tests. */
+        {{
+            {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(),
+        }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
+                | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
+        {{
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 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, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
+            D3DDECL_END(),
+        }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
+                | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
+    };
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(test_data); ++i)
+    {
+        test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
+        test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
+    }
+
+    /* Usage indices for position and normal are apparently ignored. */
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
+    }
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
+    }
+    /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
+     * there are no blend matrices. */
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            D3DDECL_END(),
+        };
+        test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
+    }
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            D3DDECL_END(),
+        };
+        test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
+    }
+    /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {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(),
+        };
+        test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
+                decl, D3D_OK, __LINE__, 0);
+    }
+    /* These are supposed to fail, both ways. */
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
+        test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
+    }
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
+            {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
+        test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
+    }
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {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(),
+        };
+        test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
+        test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
+    }
+    /* Test a declaration that can't be converted to an FVF. */
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 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},
+            /* 8 bytes padding */
+            {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
+    }
+    /* Elements must be ordered by offset. */
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
+    }
+    /* Basic tests for element order. */
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
+            {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
+    }
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
+            {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
+    }
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
+            {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
+    }
+    /* Textures must be ordered by texcoords. */
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
+            {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
+            {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
+            {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
+    }
+    /* Duplicate elements are not allowed. */
+    {
+        const D3DVERTEXELEMENT9 decl[] =
+        {
+            {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+            {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
+            {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
+            D3DDECL_END(),
+        };
+        test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
+    }
+    /* Invalid FVFs cannot be converted to a declarator. */
+    test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
+}
+
+static void D3DXGetFVFVertexSizeTest(void)
+{
+    UINT got;
+
+    compare_vertex_sizes (D3DFVF_XYZ, 12);
+
+    compare_vertex_sizes (D3DFVF_XYZB3, 24);
+
+    compare_vertex_sizes (D3DFVF_XYZB5, 32);
+
+    compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
+
+    compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX1 |
+        D3DFVF_TEXCOORDSIZE1(0), 16);
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX2 |
+        D3DFVF_TEXCOORDSIZE1(0) |
+        D3DFVF_TEXCOORDSIZE1(1), 20);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX1 |
+        D3DFVF_TEXCOORDSIZE2(0), 20);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX2 |
+        D3DFVF_TEXCOORDSIZE2(0) |
+        D3DFVF_TEXCOORDSIZE2(1), 28);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX6 |
+        D3DFVF_TEXCOORDSIZE2(0) |
+        D3DFVF_TEXCOORDSIZE2(1) |
+        D3DFVF_TEXCOORDSIZE2(2) |
+        D3DFVF_TEXCOORDSIZE2(3) |
+        D3DFVF_TEXCOORDSIZE2(4) |
+        D3DFVF_TEXCOORDSIZE2(5), 60);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX8 |
+        D3DFVF_TEXCOORDSIZE2(0) |
+        D3DFVF_TEXCOORDSIZE2(1) |
+        D3DFVF_TEXCOORDSIZE2(2) |
+        D3DFVF_TEXCOORDSIZE2(3) |
+        D3DFVF_TEXCOORDSIZE2(4) |
+        D3DFVF_TEXCOORDSIZE2(5) |
+        D3DFVF_TEXCOORDSIZE2(6) |
+        D3DFVF_TEXCOORDSIZE2(7), 76);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX1 |
+        D3DFVF_TEXCOORDSIZE3(0), 24);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX4 |
+        D3DFVF_TEXCOORDSIZE3(0) |
+        D3DFVF_TEXCOORDSIZE3(1) |
+        D3DFVF_TEXCOORDSIZE3(2) |
+        D3DFVF_TEXCOORDSIZE3(3), 60);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX1 |
+        D3DFVF_TEXCOORDSIZE4(0), 28);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX2 |
+        D3DFVF_TEXCOORDSIZE4(0) |
+        D3DFVF_TEXCOORDSIZE4(1), 44);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZ |
+        D3DFVF_TEX3 |
+        D3DFVF_TEXCOORDSIZE4(0) |
+        D3DFVF_TEXCOORDSIZE4(1) |
+        D3DFVF_TEXCOORDSIZE4(2), 60);
+
+    compare_vertex_sizes (
+        D3DFVF_XYZB5 |
+        D3DFVF_NORMAL |
+        D3DFVF_DIFFUSE |
+        D3DFVF_SPECULAR |
+        D3DFVF_TEX8 |
+        D3DFVF_TEXCOORDSIZE4(0) |
+        D3DFVF_TEXCOORDSIZE4(1) |
+        D3DFVF_TEXCOORDSIZE4(2) |
+        D3DFVF_TEXCOORDSIZE4(3) |
+        D3DFVF_TEXCOORDSIZE4(4) |
+        D3DFVF_TEXCOORDSIZE4(5) |
+        D3DFVF_TEXCOORDSIZE4(6) |
+        D3DFVF_TEXCOORDSIZE4(7), 180);
+}
+
+static void D3DXIntersectTriTest(void)
+{
+    BOOL exp_res, got_res;
+    D3DXVECTOR3 position, ray, vertex[3];
+    FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
+
+    vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
+    vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
+    vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
+
+    position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
+
+    ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
+
+    exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
+
+    got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
+    ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
+    ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
+    ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
+    ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
+
+    got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
+    ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
+
+    vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
+    vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
+    vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 0.0f;
+
+    got_u = got_v = got_dist = 0.0f;
+    got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
+    ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
+    ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
+    ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
+    ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
+
+    vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
+    vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = -0.5f;
+    vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = -1.0f;
+    exp_u = 0.375f;
+    exp_v = 0.5625f;
+    exp_dist = 7.9375f;
+    got_u = got_v = got_dist = 0.0f;
+    got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
+    ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
+    ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
+    ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
+    ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
+
+
+/*Only positive ray is taken in account*/
+
+    vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
+    vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
+    vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
+
+    position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
+
+    ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
+
+    exp_res = FALSE;
+
+    got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
+    ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
+
+    got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
+    ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
+
+/*Intersection between ray and triangle in a same plane is considered as empty*/
+
+    vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
+    vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
+    vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
+
+    position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
+
+    ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
+
+    exp_res = FALSE;
+
+    got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
+    ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
+
+    got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
+    ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
+}
+
+static void D3DXCreateMeshTest(void)
+{
+    HRESULT hr;
+    IDirect3DDevice9 *device, *test_device;
+    ID3DXMesh *d3dxmesh;
+    int i, size;
+    D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
+    DWORD options;
+    struct mesh mesh;
+    struct test_context *test_context;
+
+    static const D3DVERTEXELEMENT9 decl1[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END(),
+    };
+
+    static const D3DVERTEXELEMENT9 decl2[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
+        {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
+        {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        /* 8 bytes padding */
+        {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
+        D3DDECL_END(),
+    };
+
+    static const D3DVERTEXELEMENT9 decl3[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END(),
+    };
+
+    hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    test_context = new_test_context();
+    if (!test_context)
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+
+    if (hr == D3D_OK)
+    {
+        d3dxmesh->lpVtbl->Release(d3dxmesh);
+    }
+
+    hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+    if (hr == D3D_OK)
+    {
+        /* device */
+        hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+        hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
+        ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+        ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
+
+        if (hr == D3D_OK)
+        {
+            IDirect3DDevice9_Release(device);
+        }
+
+        /* declaration */
+        hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+        hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+        if (hr == D3D_OK)
+        {
+            size = ARRAY_SIZE(decl1);
+            for (i = 0; i < size - 1; i++)
+            {
+                ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
+                ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
+                ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
+                ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
+                ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
+                ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
+            }
+            ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
+        }
+
+        /* options */
+        options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
+        ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
+
+        /* rest */
+        if (!new_mesh(&mesh, 3, 1))
+        {
+            skip("Couldn't create mesh\n");
+        }
+        else
+        {
+            memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
+            memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
+            mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
+
+            compare_mesh("createmesh1", d3dxmesh, &mesh);
+
+            free_mesh(&mesh);
+        }
+
+        d3dxmesh->lpVtbl->Release(d3dxmesh);
+    }
+
+    /* Test a declaration that can't be converted to an FVF. */
+    hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+    if (hr == D3D_OK)
+    {
+        /* device */
+        hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+        hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
+        ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+        ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
+
+        if (hr == D3D_OK)
+        {
+            IDirect3DDevice9_Release(device);
+        }
+
+        /* declaration */
+        hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+        if (hr == D3D_OK)
+        {
+            size = ARRAY_SIZE(decl2);
+            for (i = 0; i < size - 1; i++)
+            {
+                ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
+                ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
+                ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
+                ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
+                ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
+                ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
+            }
+            ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
+        }
+
+        /* options */
+        options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
+        ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
+
+        /* rest */
+        if (!new_mesh(&mesh, 3, 1))
+        {
+            skip("Couldn't create mesh\n");
+        }
+        else
+        {
+            memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
+            memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
+            mesh.fvf = 0;
+            mesh.vertex_size = 60;
+
+            compare_mesh("createmesh2", d3dxmesh, &mesh);
+
+            free_mesh(&mesh);
+        }
+
+        mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
+        ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
+
+        d3dxmesh->lpVtbl->Release(d3dxmesh);
+    }
+
+    /* Test a declaration with multiple streams. */
+    hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    free_test_context(test_context);
+}
+
+static void D3DXCreateMeshFVFTest(void)
+{
+    HRESULT hr;
+    IDirect3DDevice9 *device, *test_device;
+    ID3DXMesh *d3dxmesh;
+    int i, size;
+    D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
+    DWORD options;
+    struct mesh mesh;
+    struct test_context *test_context;
+
+    static const D3DVERTEXELEMENT9 decl[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END(),
+    };
+
+    hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    test_context = new_test_context();
+    if (!test_context)
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateMeshFVF(1, 0, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+
+    if (hr == D3D_OK)
+    {
+        d3dxmesh->lpVtbl->Release(d3dxmesh);
+    }
+
+    hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+    if (hr == D3D_OK)
+    {
+        /* device */
+        hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+        hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
+        ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+        ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
+
+        if (hr == D3D_OK)
+        {
+            IDirect3DDevice9_Release(device);
+        }
+
+        /* declaration */
+        hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+        hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+        if (hr == D3D_OK)
+        {
+            size = ARRAY_SIZE(decl);
+            for (i = 0; i < size - 1; i++)
+            {
+                ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
+                ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
+                ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
+                ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
+                ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
+                   test_decl[i].UsageIndex, decl[i].UsageIndex);
+                ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
+            }
+            ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
+        }
+
+        /* options */
+        options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
+        ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
+
+        /* rest */
+        if (!new_mesh(&mesh, 3, 1))
+        {
+            skip("Couldn't create mesh\n");
+        }
+        else
+        {
+            memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
+            memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
+            mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
+
+            compare_mesh("createmeshfvf", d3dxmesh, &mesh);
+
+            free_mesh(&mesh);
+        }
+
+        d3dxmesh->lpVtbl->Release(d3dxmesh);
+    }
+
+    free_test_context(test_context);
+}
+
+#define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
+    check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
+static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
+{
+    DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
+    DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
+    const void *mesh_vertices;
+    HRESULT hr;
+
+    ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
+    ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
+       "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
+
+    hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
+    ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    if (FAILED(hr))
+        return;
+
+    if (mesh_fvf == fvf) {
+        DWORD vertex_size = D3DXGetFVFVertexSize(fvf), i;
+
+        for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
+        {
+            const FLOAT *exp_float = vertices;
+            const FLOAT *got_float = mesh_vertices;
+            DWORD texcount;
+            DWORD pos_dim = 0;
+            int j;
+            BOOL last_beta_dword = FALSE;
+            char prefix[128];
+
+            switch (fvf & D3DFVF_POSITION_MASK) {
+                case D3DFVF_XYZ: pos_dim = 3; break;
+                case D3DFVF_XYZRHW: pos_dim = 4; break;
+                case D3DFVF_XYZB1:
+                case D3DFVF_XYZB2:
+                case D3DFVF_XYZB3:
+                case D3DFVF_XYZB4:
+                case D3DFVF_XYZB5:
+                    pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
+                    if (fvf & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
+                    {
+                        pos_dim--;
+                        last_beta_dword = TRUE;
+                    }
+                    break;
+                case D3DFVF_XYZW: pos_dim = 4; break;
+            }
+            sprintf(prefix, "vertex[%u] position, ", i);
+            check_floats_(line, prefix, got_float, exp_float, pos_dim);
+            exp_float += pos_dim;
+            got_float += pos_dim;
+
+            if (last_beta_dword) {
+                ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
+                    "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
+                exp_float++;
+                got_float++;
+            }
+
+            if (fvf & D3DFVF_NORMAL) {
+                sprintf(prefix, "vertex[%u] normal, ", i);
+                check_floats_(line, prefix, got_float, exp_float, 3);
+                exp_float += 3;
+                got_float += 3;
+            }
+            if (fvf & D3DFVF_PSIZE) {
+                ok_(__FILE__,line)(compare(*exp_float, *got_float),
+                        "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
+                exp_float++;
+                got_float++;
+            }
+            if (fvf & D3DFVF_DIFFUSE) {
+                ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
+                    "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
+                exp_float++;
+                got_float++;
+            }
+            if (fvf & D3DFVF_SPECULAR) {
+                ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
+                    "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
+                exp_float++;
+                got_float++;
+            }
+
+            texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
+            for (j = 0; j < texcount; j++) {
+                DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
+                sprintf(prefix, "vertex[%u] texture, ", i);
+                check_floats_(line, prefix, got_float, exp_float, dim);
+                exp_float += dim;
+                got_float += dim;
+            }
+
+            vertices = (BYTE*)vertices + vertex_size;
+            mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
+        }
+    }
+
+    mesh->lpVtbl->UnlockVertexBuffer(mesh);
+}
+
+#define check_index_buffer(mesh, indices, num_indices, index_size) \
+    check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
+static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
+{
+    DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
+    DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
+    const void *mesh_indices;
+    HRESULT hr;
+    DWORD i;
+
+    ok_(__FILE__,line)(index_size == mesh_index_size,
+        "Expected index size %u, got %u\n", index_size, mesh_index_size);
+    ok_(__FILE__,line)(num_indices == mesh_num_indices,
+        "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
+
+    hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
+    ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    if (FAILED(hr))
+        return;
+
+    if (mesh_index_size == index_size) {
+        for (i = 0; i < min(num_indices, mesh_num_indices); i++)
+        {
+            if (index_size == 4)
+                ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
+                    "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
+            else
+                ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
+                    "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
+            indices = (BYTE*)indices + index_size;
+            mesh_indices = (BYTE*)mesh_indices + index_size;
+        }
+    }
+    mesh->lpVtbl->UnlockIndexBuffer(mesh);
+}
+
+#define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
+static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
+{
+    int i, j;
+    for (i = 0; i < 4; i++) {
+        for (j = 0; j < 4; j++) {
+            ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
+                    "matrix[%u][%u]: expected %g, got %g\n",
+                    i, j, U(*expected).m[i][j], U(*got).m[i][j]);
+        }
+    }
+}
+
+static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
+{
+    ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
+            "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
+            expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
+}
+
+#define check_materials(got, got_count, expected, expected_count) \
+    check_materials_(__LINE__, got, got_count, expected, expected_count)
+static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
+{
+    int i;
+    ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
+    if (!expected) {
+        ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
+        return;
+    }
+    for (i = 0; i < min(expected_count, got_count); i++)
+    {
+        if (!expected[i].pTextureFilename)
+            ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
+                    "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
+        else
+            ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
+                    "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
+        check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
+        check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
+        check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
+        check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
+        ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
+                "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
+    }
+}
+
+#define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
+static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
+{
+    DWORD *expected;
+    DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
+    HRESULT hr;
+
+    expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
+    if (!expected) {
+        skip_(__FILE__, line)("Out of memory\n");
+        return;
+    }
+    hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
+    ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    if (SUCCEEDED(hr))
+    {
+        int i;
+        for (i = 0; i < num_faces; i++)
+        {
+            ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
+                    expected[i * 3 + 1] == got[i * 3 + 1] &&
+                    expected[i * 3 + 2] == got[i * 3 + 2],
+                    "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
+                    expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
+                    got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
+        }
+    }
+    HeapFree(GetProcessHeap(), 0, expected);
+}
+
+#define check_generated_effects(materials, num_materials, effects) \
+    check_generated_effects_(__LINE__, materials, num_materials, effects)
+static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
+{
+    int i;
+    static const struct {
+        const char *name;
+        DWORD name_size;
+        DWORD num_bytes;
+        DWORD value_offset;
+    } params[] = {
+#define EFFECT_TABLE_ENTRY(str, field) \
+    {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
+        EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
+        EFFECT_TABLE_ENTRY("Power", Power),
+        EFFECT_TABLE_ENTRY("Specular", Specular),
+        EFFECT_TABLE_ENTRY("Emissive", Emissive),
+        EFFECT_TABLE_ENTRY("Ambient", Ambient),
+#undef EFFECT_TABLE_ENTRY
+    };
+
+    if (!num_materials) {
+        ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
+        return;
+    }
+    for (i = 0; i < num_materials; i++)
+    {
+        int j;
+        DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
+
+        ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
+                "effect[%u] NumDefaults: Expected %u, got %u\n", i,
+                expected_num_defaults, effects[i].NumDefaults);
+        for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
+        {
+            int k;
+            D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
+            ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
+               "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
+               params[j].name, got_param->pParamName);
+            ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
+               "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
+               D3DXEDT_FLOATS, got_param->Type);
+            ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
+               "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
+               params[j].num_bytes, got_param->NumBytes);
+            for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
+            {
+                FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
+                FLOAT got = ((FLOAT*)got_param->pValue)[k];
+                ok_(__FILE__,line)(compare(expected, got),
+                   "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
+            }
+        }
+        if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
+            D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
+            static const char *expected_name = "Texture0@Name";
+
+            ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
+               "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
+               expected_name, got_param->pParamName);
+            ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
+               "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
+               D3DXEDT_STRING, got_param->Type);
+            if (materials[i].pTextureFilename) {
+                ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
+                   "effect[%u] texture filename length: Expected %u, got %u\n", i,
+                   (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
+                ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
+                   "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
+                   materials[i].pTextureFilename, (char*)got_param->pValue);
+            }
+        }
+    }
+}
+
+static char *strdupA(const char *p)
+{
+    char *ret;
+    if (!p) return NULL;
+    ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
+    if (ret) strcpy(ret, p);
+    return ret;
+}
+
+static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
+{
+    TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
+    if (frame) {
+        HeapFree(GetProcessHeap(), 0, frame->Name);
+        HeapFree(GetProcessHeap(), 0, frame);
+    }
+    return D3D_OK;
+}
+
+static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface,
+        const char *name, D3DXFRAME **new_frame)
+{
+    D3DXFRAME *frame;
+
+    TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
+    frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
+    if (!frame)
+        return E_OUTOFMEMORY;
+    if (name) {
+        frame->Name = strdupA(name);
+        if (!frame->Name) {
+            HeapFree(GetProcessHeap(), 0, frame);
+            return E_OUTOFMEMORY;
+        }
+    }
+    *new_frame = frame;
+    return D3D_OK;
+}
+
+static HRESULT destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)
+{
+    int i;
+
+    if (!mesh_container)
+        return D3D_OK;
+    HeapFree(GetProcessHeap(), 0, mesh_container->Name);
+    if (U(mesh_container->MeshData).pMesh)
+        IUnknown_Release(U(mesh_container->MeshData).pMesh);
+    if (mesh_container->pMaterials) {
+        for (i = 0; i < mesh_container->NumMaterials; i++)
+            HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
+        HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
+    }
+    if (mesh_container->pEffects) {
+        for (i = 0; i < mesh_container->NumMaterials; i++) {
+            HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
+            if (mesh_container->pEffects[i].pDefaults) {
+                int j;
+                for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
+                    HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
+                    HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
+                }
+                HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
+            }
+        }
+        HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
+    }
+    HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
+    if (mesh_container->pSkinInfo)
+        IUnknown_Release(mesh_container->pSkinInfo);
+    HeapFree(GetProcessHeap(), 0, mesh_container);
+    return D3D_OK;
+}
+
+static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyMeshContainer(ID3DXAllocateHierarchy *iface, LPD3DXMESHCONTAINER mesh_container)
+{
+    TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
+    return destroy_mesh_container(mesh_container);
+}
+
+static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateMeshContainer(ID3DXAllocateHierarchy *iface,
+        const char *name, const D3DXMESHDATA *mesh_data, const D3DXMATERIAL *materials,
+        const D3DXEFFECTINSTANCE *effects, DWORD num_materials, const DWORD *adjacency,
+        ID3DXSkinInfo *skin_info, D3DXMESHCONTAINER **new_mesh_container)
+{
+    LPD3DXMESHCONTAINER mesh_container = NULL;
+    int i;
+
+    TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
+            iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
+            num_materials, adjacency, skin_info, *new_mesh_container);
+
+    mesh_container = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mesh_container));
+    if (!mesh_container)
+        return E_OUTOFMEMORY;
+
+    if (name) {
+        mesh_container->Name = strdupA(name);
+        if (!mesh_container->Name)
+            goto error;
+    }
+
+    mesh_container->NumMaterials = num_materials;
+    if (num_materials) {
+        mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
+        if (!mesh_container->pMaterials)
+            goto error;
+
+        memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
+        for (i = 0; i < num_materials; i++)
+            mesh_container->pMaterials[i].pTextureFilename = NULL;
+        for (i = 0; i < num_materials; i++) {
+            if (materials[i].pTextureFilename) {
+                mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
+                if (!mesh_container->pMaterials[i].pTextureFilename)
+                    goto error;
+            }
+        }
+
+        mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
+        if (!mesh_container->pEffects)
+            goto error;
+        for (i = 0; i < num_materials; i++) {
+            int j;
+            const D3DXEFFECTINSTANCE *effect_src = &effects[i];
+            D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
+
+            if (effect_src->pEffectFilename) {
+                effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
+                if (!effect_dest->pEffectFilename)
+                    goto error;
+            }
+            effect_dest->pDefaults = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                    effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
+            if (!effect_dest->pDefaults)
+                goto error;
+            effect_dest->NumDefaults = effect_src->NumDefaults;
+            for (j = 0; j < effect_src->NumDefaults; j++) {
+                const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
+                D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
+
+                if (default_src->pParamName) {
+                    default_dest->pParamName = strdupA(default_src->pParamName);
+                    if (!default_dest->pParamName)
+                        goto error;
+                }
+                default_dest->NumBytes = default_src->NumBytes;
+                default_dest->Type = default_src->Type;
+                default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
+                memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
+            }
+        }
+    }
+
+    ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
+    if (adjacency) {
+        if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
+            ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
+            DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
+            size_t size = num_faces * sizeof(DWORD) * 3;
+            mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
+            if (!mesh_container->pAdjacency)
+                goto error;
+            memcpy(mesh_container->pAdjacency, adjacency, size);
+        } else {
+            ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
+            if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
+                trace("FIXME: copying adjacency data for patch mesh not implemented\n");
+        }
+    }
+
+    memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
+    if (U(*mesh_data).pMesh)
+        IUnknown_AddRef(U(*mesh_data).pMesh);
+    if (skin_info) {
+        mesh_container->pSkinInfo = skin_info;
+        skin_info->lpVtbl->AddRef(skin_info);
+    }
+    *new_mesh_container = mesh_container;
+
+    return S_OK;
+error:
+    destroy_mesh_container(mesh_container);
+    return E_OUTOFMEMORY;
+}
+
+static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
+    ID3DXAllocateHierarchyImpl_CreateFrame,
+    ID3DXAllocateHierarchyImpl_CreateMeshContainer,
+    ID3DXAllocateHierarchyImpl_DestroyFrame,
+    ID3DXAllocateHierarchyImpl_DestroyMeshContainer,
+};
+static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
+
+#define test_LoadMeshFromX(device, xfile_str, vertex_array, fvf, index_array, materials_array, check_adjacency) \
+    test_LoadMeshFromX_(__LINE__, device, xfile_str, sizeof(xfile_str) - 1, vertex_array, ARRAY_SIZE(vertex_array), fvf, \
+            index_array, ARRAY_SIZE(index_array), sizeof(*index_array), materials_array, ARRAY_SIZE(materials_array), \
+            check_adjacency);
+static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char *xfile_str, size_t xfile_strlen,
+        const void *vertices, DWORD num_vertices, DWORD fvf, const void *indices, DWORD num_indices, size_t index_size,
+        const D3DXMATERIAL *expected_materials, DWORD expected_num_materials, BOOL check_adjacency)
+{
+    HRESULT hr;
+    ID3DXBuffer *materials = NULL;
+    ID3DXBuffer *effects = NULL;
+    ID3DXBuffer *adjacency = NULL;
+    ID3DXMesh *mesh = NULL;
+    DWORD num_materials = 0;
+
+    /* Adjacency is not checked when the X file contains multiple meshes,
+     * since calling GenerateAdjacency on the merged mesh is not equivalent
+     * to calling GenerateAdjacency on the individual meshes and then merging
+     * the adjacency data. */
+    hr = D3DXLoadMeshFromXInMemory(xfile_str, xfile_strlen, D3DXMESH_MANAGED, device,
+            check_adjacency ? &adjacency : NULL, &materials, &effects, &num_materials, &mesh);
+    ok_(__FILE__,line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    if (SUCCEEDED(hr)) {
+        D3DXMATERIAL *materials_ptr = materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL;
+        D3DXEFFECTINSTANCE *effects_ptr = effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL;
+        DWORD *adjacency_ptr = check_adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL;
+
+        check_vertex_buffer_(line, mesh, vertices, num_vertices, fvf);
+        check_index_buffer_(line, mesh, indices, num_indices, index_size);
+        check_materials_(line, materials_ptr, num_materials, expected_materials, expected_num_materials);
+        check_generated_effects_(line, materials_ptr, num_materials, effects_ptr);
+        if (check_adjacency)
+            check_generated_adjacency_(line, mesh, adjacency_ptr, 0.0f);
+
+        if (materials) ID3DXBuffer_Release(materials);
+        if (effects) ID3DXBuffer_Release(effects);
+        if (adjacency) ID3DXBuffer_Release(adjacency);
+        IUnknown_Release(mesh);
+    }
+}
+
+static void D3DXLoadMeshTest(void)
+{
+    static const char empty_xfile[] = "xof 0303txt 0032";
+    /*________________________*/
+    static const char simple_xfile[] =
+        "xof 0303txt 0032"
+        "Mesh {"
+            "3;"
+            "0.0; 0.0; 0.0;,"
+            "0.0; 1.0; 0.0;,"
+            "1.0; 1.0; 0.0;;"
+            "1;"
+            "3; 0, 1, 2;;"
+        "}";
+    static const WORD simple_index_buffer[] = {0, 1, 2};
+    static const D3DXVECTOR3 simple_vertex_buffer[] = {
+        {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
+    };
+    const DWORD simple_fvf = D3DFVF_XYZ;
+    static const char framed_xfile[] =
+        "xof 0303txt 0032"
+        "Frame {"
+            "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 1.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
+            "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
+              "1.0, 0.0, 0.0, 0.0,"
+              "0.0, 1.0, 0.0, 0.0,"
+              "0.0, 0.0, 1.0, 0.0,"
+              "0.0, 0.0, 2.0, 1.0;;"
+            "}"
+            "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 2.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
+            "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
+              "1.0, 0.0, 0.0, 0.0,"
+              "0.0, 1.0, 0.0, 0.0,"
+              "0.0, 0.0, 1.0, 0.0,"
+              "0.0, 0.0, 3.0, 1.0;;"
+            "}"
+            "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 3.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
+        "}";
+    static const WORD framed_index_buffer[] = { 0, 1, 2 };
+    static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
+        {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
+        {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
+        {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
+    };
+    static const WORD merged_index_buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+    /* frame transforms accumulates for D3DXLoadMeshFromX */
+    static const D3DXVECTOR3 merged_vertex_buffer[] = {
+        {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
+        {0.0, 0.0, 2.0}, {0.0, 1.0, 2.0}, {2.0, 1.0, 2.0},
+        {0.0, 0.0, 5.0}, {0.0, 1.0, 5.0}, {3.0, 1.0, 5.0},
+    };
+    const DWORD framed_fvf = D3DFVF_XYZ;
+    /*________________________*/
+    static const char box_xfile[] =
+        "xof 0303txt 0032"
+        "Mesh {"
+            "8;" /* DWORD nVertices; */
+            /* array Vector vertices[nVertices]; */
+            "0.0; 0.0; 0.0;,"
+            "0.0; 0.0; 1.0;,"
+            "0.0; 1.0; 0.0;,"
+            "0.0; 1.0; 1.0;,"
+            "1.0; 0.0; 0.0;,"
+            "1.0; 0.0; 1.0;,"
+            "1.0; 1.0; 0.0;,"
+            "1.0; 1.0; 1.0;;"
+            "6;" /* DWORD nFaces; */
+            /* array MeshFace faces[nFaces]; */
+            "4; 0, 1, 3, 2;," /* (left side) */
+            "4; 2, 3, 7, 6;," /* (top side) */
+            "4; 6, 7, 5, 4;," /* (right side) */
+            "4; 1, 0, 4, 5;," /* (bottom side) */
+            "4; 1, 5, 7, 3;," /* (back side) */
+            "4; 0, 2, 6, 4;;" /* (front side) */
+            "MeshNormals {"
+              "6;" /* DWORD nNormals; */
+              /* array Vector normals[nNormals]; */
+              "-1.0; 0.0; 0.0;,"
+              "0.0; 1.0; 0.0;,"
+              "1.0; 0.0; 0.0;,"
+              "0.0; -1.0; 0.0;,"
+              "0.0; 0.0; 1.0;,"
+              "0.0; 0.0; -1.0;;"
+              "6;" /* DWORD nFaceNormals; */
+              /* array MeshFace faceNormals[nFaceNormals]; */
+              "4; 0, 0, 0, 0;,"
+              "4; 1, 1, 1, 1;,"
+              "4; 2, 2, 2, 2;,"
+              "4; 3, 3, 3, 3;,"
+              "4; 4, 4, 4, 4;,"
+              "4; 5, 5, 5, 5;;"
+            "}"
+            "MeshMaterialList materials {"
+              "2;" /* DWORD nMaterials; */
+              "6;" /* DWORD nFaceIndexes; */
+              /* array DWORD faceIndexes[nFaceIndexes]; */
+              "0, 0, 0, 1, 1, 1;;"
+              "Material {"
+                /* ColorRGBA faceColor; */
+                "0.0; 0.0; 1.0; 1.0;;"
+                /* FLOAT power; */
+                "0.5;"
+                /* ColorRGB specularColor; */
+                "1.0; 1.0; 1.0;;"
+                /* ColorRGB emissiveColor; */
+                "0.0; 0.0; 0.0;;"
+              "}"
+              "Material {"
+                /* ColorRGBA faceColor; */
+                "1.0; 1.0; 1.0; 1.0;;"
+                /* FLOAT power; */
+                "1.0;"
+                /* ColorRGB specularColor; */
+                "1.0; 1.0; 1.0;;"
+                /* ColorRGB emissiveColor; */
+                "0.0; 0.0; 0.0;;"
+                "TextureFilename { \"texture.jpg\"; }"
+              "}"
+            "}"
+            "MeshVertexColors {"
+              "8;" /* DWORD nVertexColors; */
+              /* array IndexedColor vertexColors[nVertexColors]; */
+              "0; 0.0; 0.0; 0.0; 0.0;;"
+              "1; 0.0; 0.0; 1.0; 0.1;;"
+              "2; 0.0; 1.0; 0.0; 0.2;;"
+              "3; 0.0; 1.0; 1.0; 0.3;;"
+              "4; 1.0; 0.0; 0.0; 0.4;;"
+              "5; 1.0; 0.0; 1.0; 0.5;;"
+              "6; 1.0; 1.0; 0.0; 0.6;;"
+              "7; 1.0; 1.0; 1.0; 0.7;;"
+            "}"
+            "MeshTextureCoords {"
+              "8;" /* DWORD nTextureCoords; */
+              /* array Coords2d textureCoords[nTextureCoords]; */
+              "0.0; 1.0;,"
+              "1.0; 1.0;,"
+              "0.0; 0.0;,"
+              "1.0; 0.0;,"
+              "1.0; 1.0;,"
+              "0.0; 1.0;,"
+              "1.0; 0.0;,"
+              "0.0; 0.0;;"
+            "}"
+          "}";
+    static const WORD box_index_buffer[] = {
+        0, 1, 3,
+        0, 3, 2,
+        8, 9, 7,
+        8, 7, 6,
+        10, 11, 5,
+        10, 5, 4,
+        12, 13, 14,
+        12, 14, 15,
+        16, 17, 18,
+        16, 18, 19,
+        20, 21, 22,
+        20, 22, 23,
+    };
+    static const struct {
+        D3DXVECTOR3 position;
+        D3DXVECTOR3 normal;
+        D3DCOLOR diffuse;
+        D3DXVECTOR2 tex_coords;
+    } box_vertex_buffer[] = {
+        {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, 0x00000000, {0.0, 1.0}},
+        {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
+        {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
+        {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
+        {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
+        {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
+        {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
+        {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
+        {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
+        {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
+        {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
+        {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
+        {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
+        {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x00000000, {0.0, 1.0}},
+        {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
+        {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
+        {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x1a0000ff, {1.0, 1.0}},
+        {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x80ff00ff, {0.0, 1.0}},
+        {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0xb3ffffff, {0.0, 0.0}},
+        {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0x4d00ffff, {1.0, 0.0}},
+        {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x00000000, {0.0, 1.0}},
+        {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x3300ff00, {0.0, 0.0}},
+        {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x99ffff00, {1.0, 0.0}},
+        {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x66ff0000, {1.0, 1.0}},
+    };
+    static const D3DXMATERIAL box_materials[] = {
+        {
+            {
+                {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
+                {0.0, 0.0, 0.0, 1.0}, /* Ambient */
+                {1.0, 1.0, 1.0, 1.0}, /* Specular */
+                {0.0, 0.0, 0.0, 1.0}, /* Emissive */
+                0.5, /* Power */
+            },
+            NULL, /* pTextureFilename */
+        },
+        {
+            {
+                {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
+                {0.0, 0.0, 0.0, 1.0}, /* Ambient */
+                {1.0, 1.0, 1.0, 1.0}, /* Specular */
+                {0.0, 0.0, 0.0, 1.0}, /* Emissive */
+                1.0, /* Power */
+            },
+            (char *)"texture.jpg", /* pTextureFilename */
+        },
+    };
+    static const char box_anim_xfile[] =
+        "xof 0303txt 0032"
+        "Mesh CubeMesh {"
+        "8;" /* DWORD nVertices; */
+        /* array Vector vertices[nVertices]; */
+        "0.0; 0.0; 0.0;,"
+        "0.0; 0.0; 1.0;,"
+        "0.0; 1.0; 0.0;,"
+        "0.0; 1.0; 1.0;,"
+        "1.0; 0.0; 0.0;,"
+        "1.0; 0.0; 1.0;,"
+        "1.0; 1.0; 0.0;,"
+        "1.0; 1.0; 1.0;;"
+        "6;" /* DWORD nFaces; */
+        /* array MeshFace faces[nFaces]; */
+        "4; 0, 1, 3, 2;," /* left side */
+        "4; 2, 3, 7, 6;," /* top side */
+        "4; 6, 7, 5, 4;," /* right side */
+        "4; 1, 0, 4, 5;," /* bottom side */
+        "4; 1, 5, 7, 3;," /* back side */
+        "4; 0, 2, 6, 4;;" /* front side */
+        "MeshNormals {"
+        "6;" /* DWORD nNormals; */
+        /* array Vector normals[nNormals]; */
+        "-1.0; 0.0; 0.0;,"
+        "0.0; 1.0; 0.0;,"
+        "1.0; 0.0; 0.0;,"
+        "0.0; -1.0; 0.0;,"
+        "0.0; 0.0; 1.0;,"
+        "0.0; 0.0; -1.0;;"
+        "6;" /* DWORD nFaceNormals; */
+        /* array MeshFace faceNormals[nFaceNormals]; */
+        "4; 0, 0, 0, 0;,"
+        "4; 1, 1, 1, 1;,"
+        "4; 2, 2, 2, 2;,"
+        "4; 3, 3, 3, 3;,"
+        "4; 4, 4, 4, 4;,"
+        "4; 5, 5, 5, 5;;"
+        "}"
+        "MeshMaterialList materials {"
+        "2;" /* DWORD nMaterials; */
+        "6;" /* DWORD nFaceIndexes; */
+        /* array DWORD faceIndexes[nFaceIndexes]; */
+        "0, 0, 0, 1, 1, 1;;"
+        "Material {"
+        /* ColorRGBA faceColor; */
+        "0.0; 0.0; 1.0; 1.0;;"
+        /* FLOAT power; */
+        "0.5;"
+        /* ColorRGB specularColor; */
+        "1.0; 1.0; 1.0;;"
+        /* ColorRGB emissiveColor; */
+        "0.0; 0.0; 0.0;;"
+        "}"
+        "Material {"
+        /* ColorRGBA faceColor; */
+        "1.0; 1.0; 1.0; 1.0;;"
+        /* FLOAT power; */
+        "1.0;"
+        /* ColorRGB specularColor; */
+        "1.0; 1.0; 1.0;;"
+        /* ColorRGB emissiveColor; */
+        "0.0; 0.0; 0.0;;"
+        "TextureFilename { \"texture.jpg\"; }"
+        "}"
+        "}"
+        "MeshVertexColors {"
+        "8;" /* DWORD nVertexColors; */
+        /* array IndexedColor vertexColors[nVertexColors]; */
+        "0; 0.0; 0.0; 0.0; 0.0;;"
+        "1; 0.0; 0.0; 1.0; 0.1;;"
+        "2; 0.0; 1.0; 0.0; 0.2;;"
+        "3; 0.0; 1.0; 1.0; 0.3;;"
+        "4; 1.0; 0.0; 0.0; 0.4;;"
+        "5; 1.0; 0.0; 1.0; 0.5;;"
+        "6; 1.0; 1.0; 0.0; 0.6;;"
+        "7; 1.0; 1.0; 1.0; 0.7;;"
+        "}"
+        "MeshTextureCoords {"
+        "8;" /* DWORD nTextureCoords; */
+        /* array Coords2d textureCoords[nTextureCoords]; */
+        "0.0; 1.0;,"
+        "1.0; 1.0;,"
+        "0.0; 0.0;,"
+        "1.0; 0.0;,"
+        "1.0; 1.0;,"
+        "0.0; 1.0;,"
+        "1.0; 0.0;,"
+        "0.0; 0.0;;"
+        "}"
+        "}"
+        "Frame CubeFrame {"
+        "FrameTransformMatrix {"
+        /* Matrix4x4 frameMatrix; */
+        "1.0, 0.0, 0.0, 0.0,"
+        "0.0, 1.0, 0.0, 0.0,"
+        "0.0, 0.0, 1.0, 0.0,"
+        "0.0, 0.0, 0.0, 1.0;;"
+        "}"
+        "{CubeMesh}"
+        "}"
+        "AnimationSet AnimationSet0 {"
+        "Animation Animation0 {"
+        "{CubeFrame}"
+        "AnimationKey {"
+        "2;" /* DWORD keyType; */
+        "9;" /* DWORD nKeys; */
+        /* array TimedFloatKeys keys[nKeys]; */
+        "10; 3; -100.0, 0.0, 0.0;;,"
+        "20; 3; -75.0,  0.0, 0.0;;,"
+        "30; 3; -50.0,  0.0, 0.0;;,"
+        "40; 3; -25.5,  0.0, 0.0;;,"
+        "50; 3; 0.0,    0.0, 0.0;;,"
+        "60; 3; 25.5,   0.0, 0.0;;,"
+        "70; 3; 50.0,   0.0, 0.0;;,"
+        "80; 3; 75.5,   0.0, 0.0;;,"
+        "90; 3; 100.0,  0.0, 0.0;;;"
+        "}"
+        "}"
+        "}";
+
+    const DWORD box_fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
+    /*________________________*/
+    static const D3DXMATERIAL default_materials[] = {
+        {
+            {
+                {0.5, 0.5, 0.5, 0.0}, /* Diffuse */
+                {0.0, 0.0, 0.0, 0.0}, /* Ambient */
+                {0.5, 0.5, 0.5, 0.0}, /* Specular */
+                {0.0, 0.0, 0.0, 0.0}, /* Emissive */
+                0.0, /* Power */
+            },
+            NULL, /* pTextureFilename */
+        }
+    };
+    HRESULT hr;
+    IDirect3DDevice9 *device = NULL;
+    ID3DXMesh *mesh = NULL;
+    D3DXFRAME *frame_hier = NULL;
+    D3DXMATRIX transform;
+    struct test_context *test_context;
+    ID3DXAnimationController *controller;
+
+    if (!(test_context = new_test_context()))
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
+            D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
+            D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
+            D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
+            D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
+            D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
+    ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
+            D3DXMESH_MANAGED, device, &alloc_hier, NULL, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
+            D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
+    ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    if (SUCCEEDED(hr)) {
+        D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
+
+        ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
+        D3DXMatrixIdentity(&transform);
+        check_matrix(&frame_hier->TransformationMatrix, &transform);
+
+        ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
+        ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
+           D3DXMESHTYPE_MESH, container->MeshData.Type);
+        mesh = U(container->MeshData).pMesh;
+        check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
+        check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
+        check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
+        check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
+        check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
+        hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
+        ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+        frame_hier = NULL;
+    }
+
+    controller = (ID3DXAnimationController *)0xdeadbeef;
+    hr = D3DXLoadMeshHierarchyFromXInMemory(box_anim_xfile, sizeof(box_anim_xfile) - 1,
+            D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
+    todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
+    if (SUCCEEDED(hr))
+    {
+        ok(controller != NULL, "Animation Controller NULL.\n");
+
+        hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
+        ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
+        if (controller)
+            controller->lpVtbl->Release(controller);
+
+        frame_hier = NULL;
+    }
+
+    controller = (ID3DXAnimationController *)0xdeadbeef;
+    hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
+            D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
+    ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    if (SUCCEEDED(hr))
+    {
+        D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
+
+        ok(!controller, "Animation Controller returned.\n");
+        ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
+        D3DXMatrixIdentity(&transform);
+        check_matrix(&frame_hier->TransformationMatrix, &transform);
+
+        ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
+        ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
+           D3DXMESHTYPE_MESH, container->MeshData.Type);
+        mesh = U(container->MeshData).pMesh;
+        check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
+        check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
+        check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
+        check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
+        check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
+        hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
+        ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+        frame_hier = NULL;
+    }
+
+    hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
+            D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
+    ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    if (SUCCEEDED(hr)) {
+        D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
+        int i;
+
+        ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
+        /* last frame transform replaces the first */
+        D3DXMatrixIdentity(&transform);
+        U(transform).m[3][2] = 3.0;
+        check_matrix(&frame_hier->TransformationMatrix, &transform);
+
+        for (i = 0; i < 3; i++) {
+            ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
+            ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
+               D3DXMESHTYPE_MESH, container->MeshData.Type);
+            mesh = U(container->MeshData).pMesh;
+            check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
+            check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
+            check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
+            check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
+            check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
+            container = container->pNextMeshContainer;
+        }
+        ok(container == NULL, "Expected NULL, got %p\n", container);
+        hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
+        ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+        frame_hier = NULL;
+    }
+
+
+    hr = D3DXLoadMeshFromXInMemory(NULL, 0, D3DXMESH_MANAGED,
+                                   device, NULL, NULL, NULL, NULL, &mesh);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshFromXInMemory(NULL, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
+                                   device, NULL, NULL, NULL, NULL, &mesh);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshFromXInMemory(simple_xfile, 0, D3DXMESH_MANAGED,
+                                   device, NULL, NULL, NULL, NULL, &mesh);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
+                                   device, NULL, NULL, NULL, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
+                                   NULL, NULL, NULL, NULL, NULL, &mesh);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1, D3DXMESH_MANAGED,
+                                   device, NULL, NULL, NULL, NULL, &mesh);
+    ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
+
+    hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
+                                   device, NULL, NULL, NULL, NULL, &mesh);
+    ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    if (SUCCEEDED(hr))
+        IUnknown_Release(mesh);
+
+    test_LoadMeshFromX(device, simple_xfile, simple_vertex_buffer, simple_fvf, simple_index_buffer, default_materials, TRUE);
+    test_LoadMeshFromX(device, box_xfile, box_vertex_buffer, box_fvf, box_index_buffer, box_materials, TRUE);
+    test_LoadMeshFromX(device, framed_xfile, merged_vertex_buffer, framed_fvf, merged_index_buffer, default_materials, FALSE);
+
+    free_test_context(test_context);
+}
+
+static BOOL compute_box(struct mesh *mesh, float width, float height, float depth)
+{
+    unsigned int i, face;
+    static const D3DXVECTOR3 unit_box[] =
+    {
+        {-1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f,  1.0f}, {-1.0f,  1.0f,  1.0f}, {-1.0f,  1.0f, -1.0f},
+        {-1.0f,  1.0f, -1.0f}, {-1.0f,  1.0f,  1.0f}, { 1.0f,  1.0f,  1.0f}, { 1.0f,  1.0f, -1.0f},
+        { 1.0f,  1.0f, -1.0f}, { 1.0f,  1.0f,  1.0f}, { 1.0f, -1.0f,  1.0f}, { 1.0f, -1.0f, -1.0f},
+        {-1.0f, -1.0f,  1.0f}, {-1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f,  1.0f},
+        {-1.0f, -1.0f,  1.0f}, { 1.0f, -1.0f,  1.0f}, { 1.0f,  1.0f,  1.0f}, {-1.0f,  1.0f,  1.0f},
+        {-1.0f, -1.0f, -1.0f}, {-1.0f,  1.0f, -1.0f}, { 1.0f,  1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}
+    };
+    static const D3DXVECTOR3 normals[] =
+    {
+        {-1.0f,  0.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f,  0.0f},
+        { 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, -1.0f}
+    };
+
+    if (!new_mesh(mesh, 24, 12))
+    {
+        return FALSE;
+    }
+
+    width /= 2.0f;
+    height /= 2.0f;
+    depth /= 2.0f;
+
+    for (i = 0; i < 24; i++)
+    {
+        mesh->vertices[i].position.x = width * unit_box[i].x;
+        mesh->vertices[i].position.y = height * unit_box[i].y;
+        mesh->vertices[i].position.z = depth * unit_box[i].z;
+        mesh->vertices[i].normal.x = normals[i / 4].x;
+        mesh->vertices[i].normal.y = normals[i / 4].y;
+        mesh->vertices[i].normal.z = normals[i / 4].z;
+    }
+
+    face = 0;
+    for (i = 0; i < 12; i++)
+    {
+        mesh->faces[i][0] = face++;
+        mesh->faces[i][1] = face++;
+        mesh->faces[i][2] = (i % 2) ? face - 4 : face;
+    }
+
+    return TRUE;
+}
+
+static void test_box(IDirect3DDevice9 *device, float width, float height, float depth)
+{
+    HRESULT hr;
+    ID3DXMesh *box;
+    struct mesh mesh;
+    char name[256];
+
+    hr = D3DXCreateBox(device, width, height, depth, &box, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    if (hr != D3D_OK)
+    {
+        skip("Couldn't create box\n");
+        return;
+    }
+
+    if (!compute_box(&mesh, width, height, depth))
+    {
+        skip("Couldn't create mesh\n");
+        box->lpVtbl->Release(box);
+        return;
+    }
+
+    mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
+
+    sprintf(name, "box (%g, %g, %g)", width, height, depth);
+    compare_mesh(name, box, &mesh);
+
+    free_mesh(&mesh);
+
+    box->lpVtbl->Release(box);
+}
+static void D3DXCreateBoxTest(void)
+{
+    HRESULT hr;
+    IDirect3DDevice9* device;
+    ID3DXMesh* box;
+    ID3DXBuffer* ppBuffer;
+    DWORD *buffer;
+    static const DWORD adjacency[36]=
+        {6, 9, 1, 2, 10, 0,
+         1, 9, 3, 4, 10, 2,
+         3, 8, 5, 7, 11, 4,
+         0, 11, 7, 5, 8, 6,
+         7, 4, 9, 2, 0, 8,
+         1, 3, 11, 5, 6, 10};
+    unsigned int i;
+    struct test_context *test_context;
+
+    if (!(test_context = new_test_context()))
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
+    ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
+
+    hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
+    ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
+
+    hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
+    ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
+
+    hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
+    ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
+
+    hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
+    ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
+
+    ppBuffer = NULL;
+    hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
+    ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
+
+    buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
+    for(i=0; i<36; i++)
+        ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
+
+    box->lpVtbl->Release(box);
+    ID3DXBuffer_Release(ppBuffer);
+
+    test_box(device, 10.9f, 20.0f, 4.9f);
+
+    free_test_context(test_context);
+}
+
+static BOOL compute_polygon(struct mesh *mesh, float length, unsigned int sides)
+{
+    unsigned int i;
+    float angle, scale;
+
+    if (!new_mesh(mesh, sides + 1, sides))
+        return FALSE;
+
+    angle = D3DX_PI / sides;
+    scale = 0.5f * length / sinf(angle);
+    angle *= 2.0f;
+
+    mesh->vertices[0].position.x = 0.0f;
+    mesh->vertices[0].position.y = 0.0f;
+    mesh->vertices[0].position.z = 0.0f;
+    mesh->vertices[0].normal.x = 0.0f;
+    mesh->vertices[0].normal.y = 0.0f;
+    mesh->vertices[0].normal.z = 1.0f;
+
+    for (i = 0; i < sides; ++i)
+    {
+        mesh->vertices[i + 1].position.x = cosf(angle * i) * scale;
+        mesh->vertices[i + 1].position.y = sinf(angle * i) * scale;
+        mesh->vertices[i + 1].position.z = 0.0f;
+        mesh->vertices[i + 1].normal.x = 0.0f;
+        mesh->vertices[i + 1].normal.y = 0.0f;
+        mesh->vertices[i + 1].normal.z = 1.0f;
+
+        mesh->faces[i][0] = 0;
+        mesh->faces[i][1] = i + 1;
+        mesh->faces[i][2] = i + 2;
+    }
+
+    mesh->faces[sides - 1][2] = 1;
+
+    return TRUE;
+}
+
+static void test_polygon(IDirect3DDevice9 *device, float length, unsigned int sides)
+{
+    HRESULT hr;
+    ID3DXMesh *polygon;
+    struct mesh mesh;
+    char name[64];
+
+    hr = D3DXCreatePolygon(device, length, sides, &polygon, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    if (hr != D3D_OK)
+    {
+        skip("Couldn't create polygon\n");
+        return;
+    }
+
+    if (!compute_polygon(&mesh, length, sides))
+    {
+        skip("Couldn't create mesh\n");
+        polygon->lpVtbl->Release(polygon);
+        return;
+    }
+
+    mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
+
+    sprintf(name, "polygon (%g, %u)", length, sides);
+    compare_mesh(name, polygon, &mesh);
+
+    free_mesh(&mesh);
+
+    polygon->lpVtbl->Release(polygon);
+}
+
+static void D3DXCreatePolygonTest(void)
+{
+    HRESULT hr;
+    IDirect3DDevice9 *device;
+    ID3DXMesh *polygon;
+    ID3DXBuffer *adjacency;
+    DWORD (*buffer)[3], buffer_size;
+    unsigned int i;
+    struct test_context *test_context;
+
+    if (!(test_context = new_test_context()))
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hr = D3DXCreatePolygon(device, 2.0f, 11, NULL, &adjacency);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
+
+    hr = D3DXCreatePolygon(NULL, 2.0f, 11, &polygon, &adjacency);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
+
+    hr = D3DXCreatePolygon(device, -2.0f, 11, &polygon, &adjacency);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
+
+    polygon = (void *)0xdeadbeef;
+    adjacency = (void *)0xdeadbeef;
+    hr = D3DXCreatePolygon(device, 2.0f, 0, &polygon, &adjacency);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
+    ok(polygon == (void *)0xdeadbeef, "Polygon was changed to %p\n", polygon);
+    ok(adjacency == (void *)0xdeadbeef, "Adjacency was changed to %p\n", adjacency);
+
+    hr = D3DXCreatePolygon(device, 2.0f, 2, &polygon, &adjacency);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
+
+    adjacency = NULL;
+    hr = D3DXCreatePolygon(device, 3.0f, 11, &polygon, &adjacency);
+    ok(hr == D3D_OK, "Expected D3D_OK, received %#x\n", hr);
+
+    buffer_size = ID3DXBuffer_GetBufferSize(adjacency);
+    ok(buffer_size == 33 * sizeof(DWORD), "Wrong adjacency buffer size %u\n", buffer_size);
+
+    buffer = ID3DXBuffer_GetBufferPointer(adjacency);
+    for (i = 0; i < 11; ++i)
+    {
+        ok(buffer[i][0] == (i + 10) % 11, "Wrong adjacency[%d][0] = %u\n", i, buffer[i][0]);
+        ok(buffer[i][1] == ~0U, "Wrong adjacency[%d][1] = %u\n", i, buffer[i][1]);
+        ok(buffer[i][2] == (i + 1) % 11, "Wrong adjacency[%d][2] = %u\n", i, buffer[i][2]);
+    }
+
+    polygon->lpVtbl->Release(polygon);
+    ID3DXBuffer_Release(adjacency);
+
+    test_polygon(device, 2.0f, 3);
+    test_polygon(device, 10.0f, 3);
+    test_polygon(device, 10.0f, 5);
+    test_polygon(device, 10.0f, 10);
+    test_polygon(device, 20.0f, 10);
+    test_polygon(device, 20.0f, 32000);
+
+    free_test_context(test_context);
+}
+
+struct sincos_table
+{
+    float *sin;
+    float *cos;
+};
+
+static void free_sincos_table(struct sincos_table *sincos_table)
+{
+    HeapFree(GetProcessHeap(), 0, sincos_table->cos);
+    HeapFree(GetProcessHeap(), 0, sincos_table->sin);
+}
+
+/* pre compute sine and cosine tables; caller must free */
+static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
+{
+    float angle;
+    int i;
+
+    sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
+    if (!sincos_table->sin)
+    {
+        return FALSE;
+    }
+    sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
+    if (!sincos_table->cos)
+    {
+        HeapFree(GetProcessHeap(), 0, sincos_table->sin);
+        return FALSE;
+    }
+
+    angle = angle_start;
+    for (i = 0; i < n; i++)
+    {
+        sincos_table->sin[i] = sin(angle);
+        sincos_table->cos[i] = cos(angle);
+        angle += angle_step;
+    }
+
+    return TRUE;
+}
+
+static WORD vertex_index(UINT slices, int slice, int stack)
+{
+    return stack*slices+slice+1;
+}
+
+/* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
+static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
+{
+    float theta_step, theta_start;
+    struct sincos_table theta;
+    float phi_step, phi_start;
+    struct sincos_table phi;
+    DWORD number_of_vertices, number_of_faces;
+    DWORD vertex, face;
+    int slice, stack;
+
+    /* theta = angle on xy plane wrt x axis */
+    theta_step = D3DX_PI / stacks;
+    theta_start = theta_step;
+
+    /* phi = angle on xz plane wrt z axis */
+    phi_step = -2 * D3DX_PI / slices;
+    phi_start = D3DX_PI / 2;
+
+    if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
+    {
+        return FALSE;
+    }
+    if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
+    {
+        free_sincos_table(&theta);
+        return FALSE;
+    }
+
+    number_of_vertices = 2 + slices * (stacks-1);
+    number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
+
+    if (!new_mesh(mesh, number_of_vertices, number_of_faces))
+    {
+        free_sincos_table(&phi);
+        free_sincos_table(&theta);
+        return FALSE;
+    }
+
+    vertex = 0;
+    face = 0;
+
+    mesh->vertices[vertex].normal.x = 0.0f;
+    mesh->vertices[vertex].normal.y = 0.0f;
+    mesh->vertices[vertex].normal.z = 1.0f;
+    mesh->vertices[vertex].position.x = 0.0f;
+    mesh->vertices[vertex].position.y = 0.0f;
+    mesh->vertices[vertex].position.z = radius;
+    vertex++;
+
+    for (stack = 0; stack < stacks - 1; stack++)
+    {
+        for (slice = 0; slice < slices; slice++)
+        {
+            mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
+            mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
+            mesh->vertices[vertex].normal.z = theta.cos[stack];
+            mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
+            mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
+            mesh->vertices[vertex].position.z = radius * theta.cos[stack];
+            vertex++;
+
+            if (slice > 0)
+            {
+                if (stack == 0)
+                {
+                    /* top stack is triangle fan */
+                    mesh->faces[face][0] = 0;
+                    mesh->faces[face][1] = slice + 1;
+                    mesh->faces[face][2] = slice;
+                    face++;
+                }
+                else
+                {
+                    /* stacks in between top and bottom are quad strips */
+                    mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
+                    mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
+                    mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
+                    face++;
+
+                    mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
+                    mesh->faces[face][1] = vertex_index(slices, slice, stack);
+                    mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
+                    face++;
+                }
+            }
+        }
+
+        if (stack == 0)
+        {
+            mesh->faces[face][0] = 0;
+            mesh->faces[face][1] = 1;
+            mesh->faces[face][2] = slice;
+            face++;
+        }
+        else
+        {
+            mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
+            mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
+            mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
+            face++;
+
+            mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
+            mesh->faces[face][1] = vertex_index(slices, 0, stack);
+            mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
+            face++;
+        }
+    }
+
+    mesh->vertices[vertex].position.x = 0.0f;
+    mesh->vertices[vertex].position.y = 0.0f;
+    mesh->vertices[vertex].position.z = -radius;
+    mesh->vertices[vertex].normal.x = 0.0f;
+    mesh->vertices[vertex].normal.y = 0.0f;
+    mesh->vertices[vertex].normal.z = -1.0f;
+
+    /* bottom stack is triangle fan */
+    for (slice = 1; slice < slices; slice++)
+    {
+        mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
+        mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
+        mesh->faces[face][2] = vertex;
+        face++;
+    }
+
+    mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
+    mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
+    mesh->faces[face][2] = vertex;
+
+    free_sincos_table(&phi);
+    free_sincos_table(&theta);
+
+    return TRUE;
+}
+
+static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
+{
+    HRESULT hr;
+    ID3DXMesh *sphere;
+    struct mesh mesh;
+    char name[256];
+
+    hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    if (hr != D3D_OK)
+    {
+        skip("Couldn't create sphere\n");
+        return;
+    }
+
+    if (!compute_sphere(&mesh, radius, slices, stacks))
+    {
+        skip("Couldn't create mesh\n");
+        sphere->lpVtbl->Release(sphere);
+        return;
+    }
+
+    mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
+
+    sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
+    compare_mesh(name, sphere, &mesh);
+
+    free_mesh(&mesh);
+
+    sphere->lpVtbl->Release(sphere);
+}
+
+static void D3DXCreateSphereTest(void)
+{
+    HRESULT hr;
+    IDirect3DDevice9* device;
+    ID3DXMesh* sphere = NULL;
+    struct test_context *test_context;
+
+    hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    if (!(test_context = new_test_context()))
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    test_sphere(device, 0.0f, 2, 2);
+    test_sphere(device, 1.0f, 2, 2);
+    test_sphere(device, 1.0f, 3, 2);
+    test_sphere(device, 1.0f, 4, 4);
+    test_sphere(device, 1.0f, 3, 4);
+    test_sphere(device, 5.0f, 6, 7);
+    test_sphere(device, 10.0f, 11, 12);
+
+    free_test_context(test_context);
+}
+
+static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
+{
+    float theta_step, theta_start;
+    struct sincos_table theta;
+    FLOAT delta_radius, radius, radius_step;
+    FLOAT z, z_step, z_normal;
+    DWORD number_of_vertices, number_of_faces;
+    DWORD vertex, face;
+    int slice, stack;
+
+    /* theta = angle on xy plane wrt x axis */
+    theta_step = -2 * D3DX_PI / slices;
+    theta_start = D3DX_PI / 2;
+
+    if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
+    {
+        return FALSE;
+    }
+
+    number_of_vertices = 2 + (slices * (3 + stacks));
+    number_of_faces = 2 * slices + stacks * (2 * slices);
+
+    if (!new_mesh(mesh, number_of_vertices, number_of_faces))
+    {
+        free_sincos_table(&theta);
+        return FALSE;
+    }
+
+    vertex = 0;
+    face = 0;
+
+    delta_radius = radius1 - radius2;
+    radius = radius1;
+    radius_step = delta_radius / stacks;
+
+    z = -length / 2;
+    z_step = length / stacks;
+    z_normal = delta_radius / length;
+    if (isnan(z_normal))
+    {
+        z_normal = 0.0f;
+    }
+
+    mesh->vertices[vertex].normal.x = 0.0f;
+    mesh->vertices[vertex].normal.y = 0.0f;
+    mesh->vertices[vertex].normal.z = -1.0f;
+    mesh->vertices[vertex].position.x = 0.0f;
+    mesh->vertices[vertex].position.y = 0.0f;
+    mesh->vertices[vertex++].position.z = z;
+
+    for (slice = 0; slice < slices; slice++, vertex++)
+    {
+        mesh->vertices[vertex].normal.x = 0.0f;
+        mesh->vertices[vertex].normal.y = 0.0f;
+        mesh->vertices[vertex].normal.z = -1.0f;
+        mesh->vertices[vertex].position.x = radius * theta.cos[slice];
+        mesh->vertices[vertex].position.y = radius * theta.sin[slice];
+        mesh->vertices[vertex].position.z = z;
+
+        if (slice > 0)
+        {
+            mesh->faces[face][0] = 0;
+            mesh->faces[face][1] = slice;
+            mesh->faces[face++][2] = slice + 1;
+        }
+    }
+
+    mesh->faces[face][0] = 0;
+    mesh->faces[face][1] = slice;
+    mesh->faces[face++][2] = 1;
+
+    for (stack = 1; stack <= stacks+1; stack++)
+    {
+        for (slice = 0; slice < slices; slice++, vertex++)
+        {
+            mesh->vertices[vertex].normal.x = theta.cos[slice];
+            mesh->vertices[vertex].normal.y = theta.sin[slice];
+            mesh->vertices[vertex].normal.z = z_normal;
+            D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
+            mesh->vertices[vertex].position.x = radius * theta.cos[slice];
+            mesh->vertices[vertex].position.y = radius * theta.sin[slice];
+            mesh->vertices[vertex].position.z = z;
+
+            if (stack > 1 && slice > 0)
+            {
+                mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
+                mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
+                mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
+
+                mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
+                mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
+                mesh->faces[face++][2] = vertex_index(slices, slice, stack);
+            }
+        }
+
+        if (stack > 1)
+        {
+            mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
+            mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
+            mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
+
+            mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
+            mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
+            mesh->faces[face++][2] = vertex_index(slices, 0, stack);
+        }
+
+        if (stack < stacks + 1)
+        {
+            z += z_step;
+            radius -= radius_step;
+        }
+    }
+
+    for (slice = 0; slice < slices; slice++, vertex++)
+    {
+        mesh->vertices[vertex].normal.x = 0.0f;
+        mesh->vertices[vertex].normal.y = 0.0f;
+        mesh->vertices[vertex].normal.z = 1.0f;
+        mesh->vertices[vertex].position.x = radius * theta.cos[slice];
+        mesh->vertices[vertex].position.y = radius * theta.sin[slice];
+        mesh->vertices[vertex].position.z = z;
+
+        if (slice > 0)
+        {
+            mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
+            mesh->faces[face][1] = number_of_vertices - 1;
+            mesh->faces[face++][2] = vertex_index(slices, slice, stack);
+        }
+    }
+
+    mesh->vertices[vertex].position.x = 0.0f;
+    mesh->vertices[vertex].position.y = 0.0f;
+    mesh->vertices[vertex].position.z = z;
+    mesh->vertices[vertex].normal.x = 0.0f;
+    mesh->vertices[vertex].normal.y = 0.0f;
+    mesh->vertices[vertex].normal.z = 1.0f;
+
+    mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
+    mesh->faces[face][1] = number_of_vertices - 1;
+    mesh->faces[face][2] = vertex_index(slices, 0, stack);
+
+    free_sincos_table(&theta);
+
+    return TRUE;
+}
+
+static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
+{
+    HRESULT hr;
+    ID3DXMesh *cylinder;
+    struct mesh mesh;
+    char name[256];
+
+    hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    if (hr != D3D_OK)
+    {
+        skip("Couldn't create cylinder\n");
+        return;
+    }
+
+    if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
+    {
+        skip("Couldn't create mesh\n");
+        cylinder->lpVtbl->Release(cylinder);
+        return;
+    }
+
+    mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
+
+    sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
+    compare_mesh(name, cylinder, &mesh);
+
+    free_mesh(&mesh);
+
+    cylinder->lpVtbl->Release(cylinder);
+}
+
+static void D3DXCreateCylinderTest(void)
+{
+    HRESULT hr;
+    IDirect3DDevice9* device;
+    ID3DXMesh* cylinder = NULL;
+    struct test_context *test_context;
+
+    hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    if (!(test_context = new_test_context()))
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
+
+    if (SUCCEEDED(hr) && cylinder)
+    {
+        cylinder->lpVtbl->Release(cylinder);
+    }
+
+    hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
+
+    if (SUCCEEDED(hr) && cylinder)
+    {
+        cylinder->lpVtbl->Release(cylinder);
+    }
+
+    hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    /* Test with length == 0.0f succeeds */
+    hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
+
+    if (SUCCEEDED(hr) && cylinder)
+    {
+        cylinder->lpVtbl->Release(cylinder);
+    }
+
+    hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
+
+    test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
+    test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
+    test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
+    test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
+    test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
+    test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
+
+    free_test_context(test_context);
+}
+
+static BOOL compute_torus(struct mesh *mesh, float innerradius, float outerradius, UINT sides, UINT rings)
+{
+    float phi, phi_step, sin_phi, cos_phi;
+    float theta, theta_step, sin_theta, cos_theta;
+    unsigned int numvert, numfaces, i, j;
+
+    numvert = sides * rings;
+    numfaces = numvert * 2;
+
+    if (!new_mesh(mesh, numvert, numfaces))
+        return FALSE;
+
+    phi_step = D3DX_PI / sides * 2.0f;
+    theta_step = D3DX_PI / rings * -2.0f;
+
+    theta = 0.0f;
+
+    for (i = 0; i < rings; ++i)
+    {
+        phi = 0.0f;
+
+        cos_theta = cosf(theta);
+        sin_theta = sinf(theta);
+
+        for (j = 0; j < sides; ++j)
+        {
+            sin_phi = sinf(phi);
+            cos_phi = cosf(phi);
+
+            mesh->vertices[i * sides + j].position.x = (innerradius * cos_phi + outerradius) * cos_theta;
+            mesh->vertices[i * sides + j].position.y = (innerradius * cos_phi + outerradius) * sin_theta;
+            mesh->vertices[i * sides + j].position.z = innerradius * sin_phi;
+            mesh->vertices[i * sides + j].normal.x = cos_phi * cos_theta;
+            mesh->vertices[i * sides + j].normal.y = cos_phi * sin_theta;
+            mesh->vertices[i * sides + j].normal.z = sin_phi;
+
+            phi += phi_step;
+        }
+
+        theta += theta_step;
+    }
+
+    for (i = 0; i < numfaces - sides * 2; ++i)
+    {
+        mesh->faces[i][0] = i % 2 ? i / 2 + sides : i / 2;
+        mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
+        mesh->faces[i][2] = (i + 1) % (sides * 2) ? (i + 1) / 2 + sides : (i + 1) / 2;
+    }
+
+    for (j = 0; i < numfaces; ++i, ++j)
+    {
+        mesh->faces[i][0] = i % 2 ? j / 2 : i / 2;
+        mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
+        mesh->faces[i][2] = i == numfaces - 1 ? 0 : (j + 1) / 2;
+    }
+
+    return TRUE;
+}
+
+static void test_torus(IDirect3DDevice9 *device, float innerradius, float outerradius, UINT sides, UINT rings)
+{
+    HRESULT hr;
+    ID3DXMesh *torus;
+    struct mesh mesh;
+    char name[256];
+
+    hr = D3DXCreateTorus(device, innerradius, outerradius, sides, rings, &torus, NULL);
+    ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK)\n", hr);
+    if (hr != D3D_OK)
+    {
+        skip("Couldn't create torus\n");
+        return;
+    }
+
+    if (!compute_torus(&mesh, innerradius, outerradius, sides, rings))
+    {
+        skip("Couldn't create mesh\n");
+        torus->lpVtbl->Release(torus);
+        return;
+    }
+
+    mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
+
+    sprintf(name, "torus (%g, %g, %u, %u)", innerradius, outerradius, sides, rings);
+    compare_mesh(name, torus, &mesh);
+
+    free_mesh(&mesh);
+
+    torus->lpVtbl->Release(torus);
+}
+
+static void D3DXCreateTorusTest(void)
+{
+    HRESULT hr;
+    IDirect3DDevice9* device;
+    ID3DXMesh* torus = NULL;
+    struct test_context *test_context;
+
+    if (!(test_context = new_test_context()))
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hr = D3DXCreateTorus(NULL, 0.0f, 0.0f, 3, 3, &torus, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTorus(device, -1.0f, 0.0f, 3, 3, &torus, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTorus(device, 0.0f, -1.0f, 3, 3, &torus, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTorus(device, 0.0f, 0.0f, 2, 3, &torus, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 2, &torus, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 3, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    test_torus(device, 0.0f, 0.0f, 3, 3);
+    test_torus(device, 1.0f, 1.0f, 3, 3);
+    test_torus(device, 1.0f, 1.0f, 32, 64);
+    test_torus(device, 0.0f, 1.0f, 5, 5);
+    test_torus(device, 1.0f, 0.0f, 5, 5);
+    test_torus(device, 5.0f, 0.2f, 8, 8);
+    test_torus(device, 0.2f, 1.0f, 60, 3);
+    test_torus(device, 0.2f, 1.0f, 8, 70);
+
+    free_test_context(test_context);
+}
+
+struct dynamic_array
+{
+    int count, capacity;
+    void *items;
+};
+
+enum pointtype {
+    POINTTYPE_CURVE = 0,
+    POINTTYPE_CORNER,
+    POINTTYPE_CURVE_START,
+    POINTTYPE_CURVE_END,
+    POINTTYPE_CURVE_MIDDLE,
+};
+
+struct point2d
+{
+    D3DXVECTOR2 pos;
+    enum pointtype corner;
+};
+
+/* is a dynamic_array */
+struct outline
+{
+    int count, capacity;
+    struct point2d *items;
+};
+
+/* is a dynamic_array */
+struct outline_array
+{
+    int count, capacity;
+    struct outline *items;
+};
+
+struct glyphinfo
+{
+    struct outline_array outlines;
+    float offset_x;
+};
+
+static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
+{
+    if (count > array->capacity) {
+        void *new_buffer;
+        int new_capacity;
+        if (array->items && array->capacity) {
+            new_capacity = max(array->capacity * 2, count);
+            new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
+        } else {
+            new_capacity = max(16, count);
+            new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
+        }
+        if (!new_buffer)
+            return FALSE;
+        array->items = new_buffer;
+        array->capacity = new_capacity;
+    }
+    return TRUE;
+}
+
+static struct point2d *add_point(struct outline *array)
+{
+    struct point2d *item;
+
+    if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
+        return NULL;
+
+    item = &array->items[array->count++];
+    ZeroMemory(item, sizeof(*item));
+    return item;
+}
+
+static struct outline *add_outline(struct outline_array *array)
+{
+    struct outline *item;
+
+    if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
+        return NULL;
+
+    item = &array->items[array->count++];
+    ZeroMemory(item, sizeof(*item));
+    return item;
+}
+
+static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
+{
+    D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
+    while (count--) {
+        D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
+        pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
+        pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
+        pt++;
+    }
+    return ret;
+}
+
+static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
+                                 const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
+                                 float max_deviation)
+{
+    D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
+    float deviation;
+
+    D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
+    D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
+    D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
+
+    deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
+    if (deviation < max_deviation) {
+        struct point2d *pt = add_point(outline);
+        if (!pt) return E_OUTOFMEMORY;
+        pt->pos = *p2;
+        pt->corner = POINTTYPE_CURVE;
+        /* the end point is omitted because the end line merges into the next segment of
+         * the split bezier curve, and the end of the split bezier curve is added outside
+         * this recursive function. */
+    } else {
+        HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
+        if (hr != S_OK) return hr;
+        hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
+        if (hr != S_OK) return hr;
+    }
+
+    return S_OK;
+}
+
+static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
+{
+    /* dot product = cos(theta) */
+    return D3DXVec2Dot(dir1, dir2) > cos_theta;
+}
+
+static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
+{
+    return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
+}
+
+static BOOL attempt_line_merge(struct outline *outline,
+                               int pt_index,
+                               const D3DXVECTOR2 *nextpt,
+                               BOOL to_curve)
+{
+    D3DXVECTOR2 curdir, lastdir;
+    struct point2d *prevpt, *pt;
+    BOOL ret = FALSE;
+    const float cos_half = cos(D3DXToRadian(0.5f));
+
+    pt = &outline->items[pt_index];
+    pt_index = (pt_index - 1 + outline->count) % outline->count;
+    prevpt = &outline->items[pt_index];
+
+    if (to_curve)
+        pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
+
+    if (outline->count < 2)
+        return FALSE;
+
+    /* remove last point if the next line continues the last line */
+    unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
+    unit_vec2(&curdir, &pt->pos, nextpt);
+    if (is_direction_similar(&lastdir, &curdir, cos_half))
+    {
+        outline->count--;
+        if (pt->corner == POINTTYPE_CURVE_END)
+            prevpt->corner = pt->corner;
+        if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
+            prevpt->corner = POINTTYPE_CURVE_MIDDLE;
+        pt = prevpt;
+
+        ret = TRUE;
+        if (outline->count < 2)
+            return ret;
+
+        pt_index = (pt_index - 1 + outline->count) % outline->count;
+        prevpt = &outline->items[pt_index];
+        unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
+        unit_vec2(&curdir, &pt->pos, nextpt);
+    }
+    return ret;
+}
+
+static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
+                              float max_deviation, float emsquare)
+{
+    const float cos_45 = cos(D3DXToRadian(45.0f));
+    const float cos_90 = cos(D3DXToRadian(90.0f));
+    TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
+
+    while ((char *)header < (char *)raw_outline + datasize)
+    {
+        TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
+        struct point2d *lastpt, *pt;
+        D3DXVECTOR2 lastdir;
+        D3DXVECTOR2 *pt_flt;
+        int j;
+        struct outline *outline = add_outline(&glyph->outlines);
+
+        if (!outline)
+            return E_OUTOFMEMORY;
+
+        pt = add_point(outline);
+        if (!pt)
+            return E_OUTOFMEMORY;
+        pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
+        pt->pos = *pt_flt;
+        pt->corner = POINTTYPE_CORNER;
+
+        if (header->dwType != TT_POLYGON_TYPE)
+            trace("Unknown header type %d\n", header->dwType);
+
+        while ((char *)curve < (char *)header + header->cb)
+        {
+            D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
+            BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
+
+            if (!curve->cpfx) {
+                curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
+                continue;
+            }
+
+            pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
+
+            attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
+
+            if (to_curve)
+            {
+                HRESULT hr;
+                int count = curve->cpfx;
+                j = 0;
+
+                while (count > 2)
+                {
+                    D3DXVECTOR2 bezier_end;
+
+                    D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
+                    hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
+                    if (hr != S_OK)
+                        return hr;
+                    bezier_start = bezier_end;
+                    count--;
+                    j++;
+                }
+                hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
+                if (hr != S_OK)
+                    return hr;
+
+                pt = add_point(outline);
+                if (!pt)
+                    return E_OUTOFMEMORY;
+                j++;
+                pt->pos = pt_flt[j];
+                pt->corner = POINTTYPE_CURVE_END;
+            } else {
+                for (j = 0; j < curve->cpfx; j++)
+                {
+                    pt = add_point(outline);
+                    if (!pt)
+                        return E_OUTOFMEMORY;
+                    pt->pos = pt_flt[j];
+                    pt->corner = POINTTYPE_CORNER;
+                }
+            }
+
+            curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
+        }
+
+        /* remove last point if the next line continues the last line */
+        if (outline->count >= 3) {
+            BOOL to_curve;
+
+            lastpt = &outline->items[outline->count - 1];
+            pt = &outline->items[0];
+            if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
+                if (lastpt->corner == POINTTYPE_CURVE_END)
+                {
+                    if (pt->corner == POINTTYPE_CURVE_START)
+                        pt->corner = POINTTYPE_CURVE_MIDDLE;
+                    else
+                        pt->corner = POINTTYPE_CURVE_END;
+                }
+                outline->count--;
+            } else {
+                /* outline closed with a line from end to start point */
+                attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
+            }
+            lastpt = &outline->items[0];
+            to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
+            if (lastpt->corner == POINTTYPE_CURVE_START)
+                lastpt->corner = POINTTYPE_CORNER;
+            pt = &outline->items[1];
+            if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
+                *lastpt = outline->items[outline->count];
+        }
+
+        lastpt = &outline->items[outline->count - 1];
+        pt = &outline->items[0];
+        unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
+        for (j = 0; j < outline->count; j++)
+        {
+            D3DXVECTOR2 curdir;
+
+            lastpt = pt;
+            pt = &outline->items[(j + 1) % outline->count];
+            unit_vec2(&curdir, &lastpt->pos, &pt->pos);
+
+            switch (lastpt->corner)
+            {
+                case POINTTYPE_CURVE_START:
+                case POINTTYPE_CURVE_END:
+                    if (!is_direction_similar(&lastdir, &curdir, cos_45))
+                        lastpt->corner = POINTTYPE_CORNER;
+                    break;
+                case POINTTYPE_CURVE_MIDDLE:
+                    if (!is_direction_similar(&lastdir, &curdir, cos_90))
+                        lastpt->corner = POINTTYPE_CORNER;
+                    else
+                        lastpt->corner = POINTTYPE_CURVE;
+                    break;
+                default:
+                    break;
+            }
+            lastdir = curdir;
+        }
+
+        header = (TTPOLYGONHEADER *)((char *)header + header->cb);
+    }
+    return S_OK;
+}
+
+static void free_outline(struct outline *outline)
+{
+    HeapFree(GetProcessHeap(), 0, outline->items);
+}
+
+static void free_glyphinfo(struct glyphinfo *glyph)
+{
+    unsigned int i;
+
+    for (i = 0; i < glyph->outlines.count; ++i)
+        free_outline(&glyph->outlines.items[i]);
+    HeapFree(GetProcessHeap(), 0, glyph->outlines.items);
+}
+
+static void compute_text_mesh(struct mesh *mesh, const char *text,
+        float deviation, float extrusion, float otmEMSquare, const struct glyphinfo *glyphs)
+{
+    DWORD nb_vertices, nb_faces;
+    DWORD nb_corners, nb_outline_points;
+    int textlen = 0;
+    int i;
+    struct vertex *vertex_ptr;
+    face *face_ptr;
+
+    textlen = strlen(text);
+
+    /* corner points need an extra vertex for the different side faces normals */
+    nb_corners = 0;
+    nb_outline_points = 0;
+    for (i = 0; i < textlen; i++)
+    {
+        int j;
+        for (j = 0; j < glyphs[i].outlines.count; j++)
+        {
+            int k;
+            struct outline *outline = &glyphs[i].outlines.items[j];
+            nb_outline_points += outline->count;
+            nb_corners++; /* first outline point always repeated as a corner */
+            for (k = 1; k < outline->count; k++)
+                if (outline->items[k].corner)
+                    nb_corners++;
+        }
+    }
+
+    nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
+    nb_faces = nb_outline_points * 2;
+
+    ok(new_mesh(mesh, nb_vertices, nb_faces), "Failed to create reference text mesh.\n");
+
+    /* convert 2D vertices and faces into 3D mesh */
+    vertex_ptr = mesh->vertices;
+    face_ptr = mesh->faces;
+    for (i = 0; i < textlen; i++)
+    {
+        int j;
+
+        /* side vertices and faces */
+        for (j = 0; j < glyphs[i].outlines.count; j++)
+        {
+            struct vertex *outline_vertices = vertex_ptr;
+            struct outline *outline = &glyphs[i].outlines.items[j];
+            int k;
+            struct point2d *prevpt = &outline->items[outline->count - 1];
+            struct point2d *pt = &outline->items[0];
+
+            for (k = 1; k <= outline->count; k++)
+            {
+                struct vertex vtx;
+                struct point2d *nextpt = &outline->items[k % outline->count];
+                WORD vtx_idx = vertex_ptr - mesh->vertices;
+                D3DXVECTOR2 vec;
+
+                if (pt->corner == POINTTYPE_CURVE_START)
+                    D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
+                else if (pt->corner)
+                    D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
+                else
+                    D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
+                D3DXVec2Normalize(&vec, &vec);
+                vtx.normal.x = -vec.y;
+                vtx.normal.y = vec.x;
+                vtx.normal.z = 0;
+
+                vtx.position.x = pt->pos.x + glyphs[i].offset_x;
+                vtx.position.y = pt->pos.y;
+                vtx.position.z = 0;
+                *vertex_ptr++ = vtx;
+
+                vtx.position.z = -extrusion;
+                *vertex_ptr++ = vtx;
+
+                vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
+                vtx.position.y = nextpt->pos.y;
+                if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
+                    vtx.position.z = -extrusion;
+                    *vertex_ptr++ = vtx;
+                    vtx.position.z = 0;
+                    *vertex_ptr++ = vtx;
+
+                    (*face_ptr)[0] = vtx_idx;
+                    (*face_ptr)[1] = vtx_idx + 2;
+                    (*face_ptr)[2] = vtx_idx + 1;
+                    face_ptr++;
+
+                    (*face_ptr)[0] = vtx_idx;
+                    (*face_ptr)[1] = vtx_idx + 3;
+                    (*face_ptr)[2] = vtx_idx + 2;
+                    face_ptr++;
+                } else {
+                    if (nextpt->corner) {
+                        if (nextpt->corner == POINTTYPE_CURVE_END) {
+                            struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
+                            D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
+                        } else {
+                            D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
+                        }
+                        D3DXVec2Normalize(&vec, &vec);
+                        vtx.normal.x = -vec.y;
+                        vtx.normal.y = vec.x;
+
+                        vtx.position.z = 0;
+                        *vertex_ptr++ = vtx;
+                        vtx.position.z = -extrusion;
+                        *vertex_ptr++ = vtx;
+                    }
+
+                    (*face_ptr)[0] = vtx_idx;
+                    (*face_ptr)[1] = vtx_idx + 3;
+                    (*face_ptr)[2] = vtx_idx + 1;
+                    face_ptr++;
+
+                    (*face_ptr)[0] = vtx_idx;
+                    (*face_ptr)[1] = vtx_idx + 2;
+                    (*face_ptr)[2] = vtx_idx + 3;
+                    face_ptr++;
+                }
+
+                prevpt = pt;
+                pt = nextpt;
+            }
+            if (!pt->corner) {
+                *vertex_ptr++ = *outline_vertices++;
+                *vertex_ptr++ = *outline_vertices++;
+            }
+        }
+
+        /* FIXME: compute expected faces */
+        /* Add placeholder to separate glyph outlines */
+        vertex_ptr->position.x = 0;
+        vertex_ptr->position.y = 0;
+        vertex_ptr->position.z = 0;
+        vertex_ptr->normal.x = 0;
+        vertex_ptr->normal.y = 0;
+        vertex_ptr->normal.z = 1;
+        vertex_ptr++;
+    }
+}
+
+static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh,
+        size_t textlen, float extrusion, const struct glyphinfo *glyphs)
+{
+    HRESULT hr;
+    DWORD number_of_vertices, number_of_faces;
+    IDirect3DVertexBuffer9 *vertex_buffer = NULL;
+    IDirect3DIndexBuffer9 *index_buffer = NULL;
+    D3DVERTEXBUFFER_DESC vertex_buffer_description;
+    D3DINDEXBUFFER_DESC index_buffer_description;
+    struct vertex *vertices = NULL;
+    face *faces = NULL;
+    int expected, i;
+    int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
+
+    number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
+    number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
+
+    hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
+    ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
+    hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
+    ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
+    ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, unexpected format %u.\n",
+            name, vertex_buffer_description.Format);
+    ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, unexpected resource type %u.\n",
+            name, vertex_buffer_description.Type);
+    ok(!vertex_buffer_description.Usage, "Test %s, unexpected usage %#x.\n", name, vertex_buffer_description.Usage);
+    ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, unexpected pool %u.\n",
+            name, vertex_buffer_description.Pool);
+    ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, unexpected FVF %#x (expected %#x).\n",
+            name, vertex_buffer_description.FVF, mesh->fvf);
+    if (!mesh->fvf)
+        expected = number_of_vertices * mesh->vertex_size;
+    else
+        expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
+    ok(vertex_buffer_description.Size == expected, "Test %s, unexpected size %u (expected %u).\n",
+            name, vertex_buffer_description.Size, expected);
+
+    hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
+    ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
+    hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
+    ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
+    ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, unexpected format %u.\n",
+            name, index_buffer_description.Format);
+    ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, unexpected resource type %u.\n",
+            name, index_buffer_description.Type);
+    ok(!index_buffer_description.Usage, "Test %s, unexpected usage %#x.\n",
+            name, index_buffer_description.Usage);
+    ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, unexpected pool %u.\n",
+            name, index_buffer_description.Pool);
+    expected = number_of_faces * sizeof(WORD) * 3;
+    ok(index_buffer_description.Size == expected, "Test %s, unexpected size %u.\n",
+            name, index_buffer_description.Size);
+
+    hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
+            (void **)&vertices, D3DLOCK_DISCARD);
+    ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
+    hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
+            (void **)&faces, D3DLOCK_DISCARD);
+    ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
+    face_idx1 = 0;
+    vtx_idx2 = 0;
+    face_idx2 = 0;
+    vtx_idx1 = 0;
+    for (i = 0; i < textlen; i++)
+    {
+        int nb_outline_vertices1, nb_outline_faces1;
+        int nb_outline_vertices2, nb_outline_faces2;
+        int nb_back_vertices, nb_back_faces;
+        int first_vtx1, first_vtx2;
+        int first_face1, first_face2;
+        int j;
+
+        first_vtx1 = vtx_idx1;
+        first_vtx2 = vtx_idx2;
+        /* Glyphs without outlines do not generate any vertices. */
+        if (glyphs[i].outlines.count > 0)
+        {
+            for (; vtx_idx1 < number_of_vertices; vtx_idx1++)
+            {
+                if (vertices[vtx_idx1].normal.z != 0)
+                    break;
+            }
+
+            for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++)
+            {
+                if (mesh->vertices[vtx_idx2].normal.z != 0)
+                    break;
+            }
+        }
+        nb_outline_vertices1 = vtx_idx1 - first_vtx1;
+        nb_outline_vertices2 = vtx_idx2 - first_vtx2;
+        ok(nb_outline_vertices1 == nb_outline_vertices2,
+           "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
+           nb_outline_vertices1, nb_outline_vertices2);
+
+        for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
+        {
+            vtx_idx1 = first_vtx1 + j;
+            vtx_idx2 = first_vtx2 + j;
+            ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
+               "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
+               vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
+               mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
+            ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
+               "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
+               vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
+               mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
+        }
+        vtx_idx1 = first_vtx1 + nb_outline_vertices1;
+        vtx_idx2 = first_vtx2 + nb_outline_vertices2;
+
+        first_face1 = face_idx1;
+        first_face2 = face_idx2;
+        for (; face_idx1 < number_of_faces; face_idx1++)
+        {
+            if (faces[face_idx1][0] >= vtx_idx1 ||
+                faces[face_idx1][1] >= vtx_idx1 ||
+                faces[face_idx1][2] >= vtx_idx1)
+                break;
+        }
+        for (; face_idx2 < mesh->number_of_faces; face_idx2++)
+        {
+            if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
+                mesh->faces[face_idx2][1] >= vtx_idx2 ||
+                mesh->faces[face_idx2][2] >= vtx_idx2)
+                break;
+        }
+        nb_outline_faces1 = face_idx1 - first_face1;
+        nb_outline_faces2 = face_idx2 - first_face2;
+        ok(nb_outline_faces1 == nb_outline_faces2,
+           "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
+           nb_outline_faces1, nb_outline_faces2);
+
+        for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
+        {
+            face_idx1 = first_face1 + j;
+            face_idx2 = first_face2 + j;
+            ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
+               faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
+               faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
+               "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
+               faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
+               mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
+               mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
+               mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
+        }
+        face_idx1 = first_face1 + nb_outline_faces1;
+        face_idx2 = first_face2 + nb_outline_faces2;
+
+        /* partial test on back vertices and faces  */
+        first_vtx1 = vtx_idx1;
+        for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
+            struct vertex vtx;
+
+            if (vertices[vtx_idx1].normal.z != 1.0f)
+                break;
+
+            vtx.position.z = 0.0f;
+            vtx.normal.x = 0.0f;
+            vtx.normal.y = 0.0f;
+            vtx.normal.z = 1.0f;
+            ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
+               "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
+               vertices[vtx_idx1].position.z, vtx.position.z);
+            ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
+               "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
+               vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
+               vtx.normal.x, vtx.normal.y, vtx.normal.z);
+        }
+        nb_back_vertices = vtx_idx1 - first_vtx1;
+        first_face1 = face_idx1;
+        for (; face_idx1 < number_of_faces; face_idx1++)
+        {
+            const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
+            D3DXVECTOR3 normal;
+            D3DXVECTOR3 v1 = {0, 0, 0};
+            D3DXVECTOR3 v2 = {0, 0, 0};
+            D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
+
+            if (faces[face_idx1][0] >= vtx_idx1 ||
+                faces[face_idx1][1] >= vtx_idx1 ||
+                faces[face_idx1][2] >= vtx_idx1)
+                break;
+
+            vtx1 = &vertices[faces[face_idx1][0]].position;
+            vtx2 = &vertices[faces[face_idx1][1]].position;
+            vtx3 = &vertices[faces[face_idx1][2]].position;
+
+            D3DXVec3Subtract(&v1, vtx2, vtx1);
+            D3DXVec3Subtract(&v2, vtx3, vtx2);
+            D3DXVec3Cross(&normal, &v1, &v2);
+            D3DXVec3Normalize(&normal, &normal);
+            ok(!D3DXVec3Length(&normal) || compare_vec3(normal, forward),
+               "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
+               normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
+        }
+        nb_back_faces = face_idx1 - first_face1;
+
+        /* compare front and back faces & vertices */
+        if (extrusion == 0.0f) {
+            /* Oddly there are only back faces in this case */
+            nb_back_vertices /= 2;
+            nb_back_faces /= 2;
+            face_idx1 -= nb_back_faces;
+            vtx_idx1 -= nb_back_vertices;
+        }
+        for (j = 0; j < nb_back_vertices; j++)
+        {
+            struct vertex vtx = vertices[first_vtx1];
+            vtx.position.z = -extrusion;
+            vtx.normal.x = 0.0f;
+            vtx.normal.y = 0.0f;
+            vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
+            ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
+               "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
+               vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
+               vtx.position.x, vtx.position.y, vtx.position.z);
+            ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
+               "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
+               vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
+               vtx.normal.x, vtx.normal.y, vtx.normal.z);
+            vtx_idx1++;
+            first_vtx1++;
+        }
+        for (j = 0; j < nb_back_faces; j++)
+        {
+            int f1, f2;
+            if (extrusion == 0.0f) {
+                f1 = 1;
+                f2 = 2;
+            } else {
+                f1 = 2;
+                f2 = 1;
+            }
+            ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
+               faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
+               faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
+               "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
+               faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
+               faces[first_face1][0] - nb_back_faces,
+               faces[first_face1][f1] - nb_back_faces,
+               faces[first_face1][f2] - nb_back_faces);
+            first_face1++;
+            face_idx1++;
+        }
+
+        /* skip to the outline for the next glyph */
+        for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
+            if (mesh->vertices[vtx_idx2].normal.z == 0)
+                break;
+        }
+        for (; face_idx2 < mesh->number_of_faces; face_idx2++)
+        {
+            if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
+                mesh->faces[face_idx2][1] >= vtx_idx2 ||
+                mesh->faces[face_idx2][2] >= vtx_idx2) break;
+        }
+    }
+
+    IDirect3DIndexBuffer9_Unlock(index_buffer);
+    IDirect3DVertexBuffer9_Unlock(vertex_buffer);
+    IDirect3DIndexBuffer9_Release(index_buffer);
+    IDirect3DVertexBuffer9_Release(vertex_buffer);
+}
+
+static void test_createtext(IDirect3DDevice9 *device, HDC hdc, const char *text, float deviation, float extrusion)
+{
+    static const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
+    HRESULT hr;
+    ID3DXMesh *d3dxmesh = NULL;
+    struct mesh mesh = {0};
+    char name[256];
+    OUTLINETEXTMETRICA otm;
+    GLYPHMETRICS gm;
+    struct glyphinfo *glyphs;
+    GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
+    int i;
+    LOGFONTA lf;
+    float offset_x;
+    size_t textlen;
+    HFONT font = NULL, oldfont = NULL;
+    char *raw_outline;
+
+    sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
+
+    hr = D3DXCreateTextA(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+
+    /* must select a modified font having lfHeight = otm.otmEMSquare before
+     * calling GetGlyphOutline to get the expected values */
+    ok(GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf), "Failed to get current DC font.\n");
+    ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "Failed to get DC font outline.\n");
+    lf.lfHeight = otm.otmEMSquare;
+    lf.lfWidth = 0;
+    ok(!!(font = CreateFontIndirectA(&lf)), "Failed to create font.\n");
+
+    textlen = strlen(text);
+    glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
+    oldfont = SelectObject(hdc, font);
+
+    for (i = 0; i < textlen; i++)
+    {
+        GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
+        compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
+        compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
+        compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
+        compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
+        compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
+        compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
+    }
+
+    if (deviation == 0.0f)
+        deviation = 1.0f / otm.otmEMSquare;
+
+    offset_x = 0.0f;
+    for (i = 0; i < textlen; i++)
+    {
+        DWORD datasize;
+
+        glyphs[i].offset_x = offset_x;
+
+        datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
+        ok(datasize != GDI_ERROR, "Failed to retrieve GDI glyph outline size.\n");
+        raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
+        datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
+        ok(datasize != GDI_ERROR, "Failed to retrieve GDI glyph outline.\n");
+        create_outline(&glyphs[i], raw_outline, datasize, deviation, otm.otmEMSquare);
+        HeapFree(GetProcessHeap(), 0, raw_outline);
+
+        offset_x += gm.gmCellIncX / (float)otm.otmEMSquare;
+    }
+
+    SelectObject(hdc, oldfont);
+
+    compute_text_mesh(&mesh, text, deviation, extrusion, otm.otmEMSquare, glyphs);
+    mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
+
+    compare_text_outline_mesh(name, d3dxmesh, &mesh, textlen, extrusion, glyphs);
+
+    free_mesh(&mesh);
+    d3dxmesh->lpVtbl->Release(d3dxmesh);
+    DeleteObject(font);
+    HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
+
+    for (i = 0; i < textlen; i++)
+        free_glyphinfo(&glyphs[i]);
+    HeapFree(GetProcessHeap(), 0, glyphs);
+}
+
+static void D3DXCreateTextTest(void)
+{
+    HRESULT hr;
+    HDC hdc;
+    IDirect3DDevice9* device;
+    ID3DXMesh* d3dxmesh = NULL;
+    HFONT hFont;
+    OUTLINETEXTMETRICA otm;
+    int number_of_vertices;
+    int number_of_faces;
+    struct test_context *test_context;
+
+    if (!(test_context = new_test_context()))
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hdc = CreateCompatibleDC(NULL);
+
+    hFont = CreateFontA(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
+            CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
+    SelectObject(hdc, hFont);
+    GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
+
+    hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    /* D3DXCreateTextA page faults from passing NULL text */
+
+    hr = D3DXCreateTextW(device, hdc, NULL, 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTextA(device, hdc, "", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTextA(device, hdc, " ", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTextA(NULL, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTextA(device, NULL, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTextA(device, hdc, "wine", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
+    hr = D3DXCreateTextA(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
+    number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
+    d3dxmesh->lpVtbl->Release(d3dxmesh);
+
+    hr = D3DXCreateTextA(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
+       "Got %d vertices, expected %d\n",
+       d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
+    ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
+       "Got %d faces, expected %d\n",
+       d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
+    d3dxmesh->lpVtbl->Release(d3dxmesh);
+
+if (0)
+{
+    /* too much detail requested, so will appear to hang */
+    trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
+    hr = D3DXCreateTextA(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
+    trace("D3DXCreateText finish with deviation = FLT_MIN\n");
+}
+
+    hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
+
+    test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
+    test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
+    test_createtext(device, hdc, "wine", 0.001f, 0.0f);
+    test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
+    test_createtext(device, hdc, "wine", 0.0f, 1.0f);
+    test_createtext(device, hdc, " wine", 1.0f, 0.0f);
+    test_createtext(device, hdc, "wine ", 1.0f, 0.0f);
+    test_createtext(device, hdc, "wi ne", 1.0f, 0.0f);
+
+    DeleteDC(hdc);
+    DeleteObject(hFont);
+
+    free_test_context(test_context);
+}
+
+static void test_get_decl_length(void)
+{
+    static const D3DVERTEXELEMENT9 declaration1[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        D3DDECL_END(),
+    };
+    static const D3DVERTEXELEMENT9 declaration2[] =
+    {
+        {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        D3DDECL_END(),
+    };
+    UINT size;
+
+    size = D3DXGetDeclLength(declaration1);
+    ok(size == 15, "Got size %u, expected 15.\n", size);
+
+    size = D3DXGetDeclLength(declaration2);
+    ok(size == 16, "Got size %u, expected 16.\n", size);
+}
+
+static void test_get_decl_vertex_size(void)
+{
+    static const D3DVERTEXELEMENT9 declaration1[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        D3DDECL_END(),
+    };
+    static const D3DVERTEXELEMENT9 declaration2[] =
+    {
+        {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        D3DDECL_END(),
+    };
+    static const UINT sizes1[] =
+    {
+        4,  8,  12, 16,
+        4,  4,  4,  8,
+        4,  4,  8,  4,
+        4,  4,  8,  0,
+    };
+    static const UINT sizes2[] =
+    {
+        12, 16, 20, 24,
+        12, 12, 16, 16,
+    };
+    unsigned int i;
+    UINT size;
+
+    size = D3DXGetDeclVertexSize(NULL, 0);
+    ok(size == 0, "Got size %#x, expected 0.\n", size);
+
+    for (i = 0; i < 16; ++i)
+    {
+        size = D3DXGetDeclVertexSize(declaration1, i);
+        ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
+    }
+
+    for (i = 0; i < 8; ++i)
+    {
+        size = D3DXGetDeclVertexSize(declaration2, i);
+        ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
+    }
+}
+
+static void D3DXGenerateAdjacencyTest(void)
+{
+    HRESULT hr;
+    IDirect3DDevice9 *device;
+    ID3DXMesh *d3dxmesh = NULL;
+    D3DXVECTOR3 *vertices = NULL;
+    WORD *indices = NULL;
+    int i;
+    struct {
+        DWORD num_vertices;
+        D3DXVECTOR3 vertices[6];
+        DWORD num_faces;
+        WORD indices[3 * 3];
+        FLOAT epsilon;
+        DWORD adjacency[3 * 3];
+    } test_data[] = {
+        { /* for epsilon < 0, indices must match for faces to be adjacent */
+            4, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
+            2, {0, 1, 2,  0, 2, 3},
+            -1.0,
+            {-1, -1, 1,  0, -1, -1},
+        },
+        {
+            6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
+            2, {0, 1, 2,  3, 4, 5},
+            -1.0,
+            {-1, -1, -1,  -1, -1, -1},
+        },
+        { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
+            6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
+            2, {0, 1, 2,  3, 4, 5},
+            0.0,
+            {-1, -1, 1,  0, -1, -1},
+        },
+        { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
+            6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.25}, {1.0, 1.0, 0.25}, {0.0, 1.0, 0.25}},
+            2, {0, 1, 2,  3, 4, 5},
+            0.25,
+            {-1, -1, -1,  -1, -1, -1},
+        },
+        { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
+            6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.25}, {1.0, 1.0, 0.25}, {0.0, 1.0, 0.25}},
+            2, {0, 1, 2,  3, 4, 5},
+            0.250001,
+            {-1, -1, 1,  0, -1, -1},
+        },
+        { /* length between vertices are compared to epsilon, not the individual dimension deltas */
+            6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.25, 0.25}, {1.0, 1.25, 0.25}, {0.0, 1.25, 0.25}},
+            2, {0, 1, 2,  3, 4, 5},
+            0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
+            {-1, -1, -1,  -1, -1, -1},
+        },
+        {
+            6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.25, 0.25}, {1.0, 1.25, 0.25}, {0.0, 1.25, 0.25}},
+            2, {0, 1, 2,  3, 4, 5},
+            0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
+            {-1, -1, 1,  0, -1, -1},
+        },
+        { /* adjacent faces must have opposite winding orders at the shared edge */
+            4, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
+            2, {0, 1, 2,  0, 3, 2},
+            0.0,
+            {-1, -1, -1,  -1, -1, -1},
+        },
+    };
+    struct test_context *test_context;
+
+    if (!(test_context = new_test_context()))
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    for (i = 0; i < ARRAY_SIZE(test_data); i++)
+    {
+        DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
+        int j;
+
+        if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
+        d3dxmesh = NULL;
+
+        hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
+        ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+
+        hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
+        ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
+        if (FAILED(hr)) continue;
+        CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
+        d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
+
+        hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
+        ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
+        if (FAILED(hr)) continue;
+        CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
+        d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
+
+        if (i == 0) {
+            hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+        }
+
+        hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
+        ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+        if (FAILED(hr)) continue;
+
+        for (j = 0; j < test_data[i].num_faces * 3; j++)
+            ok(adjacency[j] == test_data[i].adjacency[j],
+               "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
+               adjacency[j], test_data[i].adjacency[j]);
+    }
+    if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
+
+    free_test_context(test_context);
+}
+
+static void test_update_semantics(void)
+{
+    HRESULT hr;
+    struct test_context *test_context = NULL;
+    ID3DXMesh *mesh = NULL;
+    D3DVERTEXELEMENT9 declaration0[] =
+    {
+         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_pos_type_color[] =
+    {
+         {0, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_smaller[] =
+    {
+         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_larger[] =
+    {
+         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         {0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_multiple_streams[] =
+    {
+         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_double_usage[] =
+    {
+         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_undefined_type[] =
+    {
+         {0, 0, D3DDECLTYPE_UNUSED+1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_not_4_byte_aligned_offset[] =
+    {
+         {0, 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         D3DDECL_END()
+    };
+    static const struct
+    {
+        D3DXVECTOR3 position0;
+        D3DXVECTOR3 position1;
+        D3DXVECTOR3 normal;
+        DWORD color;
+    }
+    vertices[] =
+    {
+        { { 0.0f,  1.0f,  0.f}, { 1.0f,  0.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xffff0000 },
+        { { 1.0f, -1.0f,  0.f}, {-1.0f, -1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff00ff00 },
+        { {-1.0f, -1.0f,  0.f}, {-1.0f,  1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff0000ff },
+    };
+    unsigned int faces[] = {0, 1, 2};
+    unsigned int attributes[] = {0};
+    unsigned int num_faces = ARRAY_SIZE(faces) / 3;
+    unsigned int num_vertices = ARRAY_SIZE(vertices);
+    int offset = sizeof(D3DXVECTOR3);
+    DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
+    void *vertex_buffer;
+    void *index_buffer;
+    DWORD *attributes_buffer;
+    D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
+    D3DVERTEXELEMENT9 *decl_ptr;
+    DWORD exp_vertex_size = sizeof(*vertices);
+    DWORD vertex_size = 0;
+    int equal;
+    int i = 0;
+    int *decl_mem;
+    int filler_a = 0xaaaaaaaa;
+    int filler_b = 0xbbbbbbbb;
+
+    test_context = new_test_context();
+    if (!test_context)
+    {
+        skip("Couldn't create a test_context\n");
+        goto cleanup;
+    }
+
+    hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration0,
+                        test_context->device, &mesh);
+    if (FAILED(hr))
+    {
+        skip("Couldn't create test mesh %#x\n", hr);
+        goto cleanup;
+    }
+
+    mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
+    memcpy(vertex_buffer, vertices, sizeof(vertices));
+    mesh->lpVtbl->UnlockVertexBuffer(mesh);
+
+    mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
+    memcpy(index_buffer, faces, sizeof(faces));
+    mesh->lpVtbl->UnlockIndexBuffer(mesh);
+
+    mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
+    memcpy(attributes_buffer, attributes, sizeof(attributes));
+    mesh->lpVtbl->UnlockAttributeBuffer(mesh);
+
+    /* Get the declaration and try to change it */
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    if (FAILED(hr))
+    {
+        skip("Couldn't get vertex declaration %#x\n", hr);
+        goto cleanup;
+    }
+    equal = memcmp(declaration, declaration0, sizeof(declaration0));
+    ok(equal == 0, "Vertex declarations were not equal\n");
+
+    for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
+    {
+        if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
+        {
+            /* Use second vertex position instead of first */
+            decl_ptr->Offset = offset;
+        }
+    }
+
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
+    ok(hr == D3D_OK, "Test UpdateSemantics, got %#x expected %#x\n", hr, D3D_OK);
+
+    /* Check that declaration was written by getting it again */
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    if (FAILED(hr))
+    {
+        skip("Couldn't get vertex declaration %#x\n", hr);
+        goto cleanup;
+    }
+
+    for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
+    {
+        if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
+        {
+            ok(decl_ptr->Offset == offset, "Test UpdateSemantics, got offset %d expected %d\n",
+               decl_ptr->Offset, offset);
+        }
+    }
+
+    /* Check that GetDeclaration only writes up to the D3DDECL_END() marker and
+     * not the full MAX_FVF_DECL_SIZE elements.
+     */
+    memset(declaration, filler_a, sizeof(declaration));
+    memcpy(declaration, declaration0, sizeof(declaration0));
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
+    ok(hr == D3D_OK, "Test UpdateSemantics, "
+       "got %#x expected D3D_OK\n", hr);
+    memset(declaration, filler_b, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
+    decl_mem = (int*)declaration;
+    for (i = sizeof(declaration0)/sizeof(*decl_mem); i < sizeof(declaration)/sizeof(*decl_mem); i++)
+    {
+        equal = memcmp(&decl_mem[i], &filler_b, sizeof(filler_b));
+        ok(equal == 0,
+           "GetDeclaration wrote past the D3DDECL_END() marker. "
+           "Got %#x, expected  %#x\n", decl_mem[i], filler_b);
+        if (equal != 0) break;
+    }
+
+    /* UpdateSemantics does not check for overlapping fields */
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    if (FAILED(hr))
+    {
+        skip("Couldn't get vertex declaration %#x\n", hr);
+        goto cleanup;
+    }
+
+    for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
+    {
+        if (decl_ptr->Type == D3DDECLTYPE_FLOAT3)
+        {
+            decl_ptr->Type = D3DDECLTYPE_FLOAT4;
+        }
+    }
+
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
+    ok(hr == D3D_OK, "Test UpdateSemantics for overlapping fields, "
+       "got %#x expected D3D_OK\n", hr);
+
+    /* Set the position type to color instead of float3 */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_pos_type_color);
+    ok(hr == D3D_OK, "Test UpdateSemantics position type color, "
+       "got %#x expected D3D_OK\n", hr);
+
+    /* The following test cases show that NULL, smaller or larger declarations,
+     * and declarations with non-zero Stream values are not accepted.
+     * UpdateSemantics returns D3DERR_INVALIDCALL and the previously set
+     * declaration will be used by DrawSubset, GetNumBytesPerVertex, and
+     * GetDeclaration.
+     */
+
+    /* Null declaration (invalid declaration) */
+    mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics null pointer declaration, "
+       "got %#x expected D3DERR_INVALIDCALL\n", hr);
+    vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+    ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
+       vertex_size, exp_vertex_size);
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
+    equal = memcmp(declaration, declaration0, sizeof(declaration0));
+    ok(equal == 0, "Vertex declarations were not equal\n");
+
+    /* Smaller vertex declaration (invalid declaration) */
+    mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_smaller);
+    ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics for smaller vertex declaration, "
+       "got %#x expected D3DERR_INVALIDCALL\n", hr);
+    vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+    ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
+       vertex_size, exp_vertex_size);
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
+    equal = memcmp(declaration, declaration0, sizeof(declaration0));
+    ok(equal == 0, "Vertex declarations were not equal\n");
+
+    /* Larger vertex declaration (invalid declaration) */
+    mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_larger);
+    ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics for larger vertex declaration, "
+       "got %#x expected D3DERR_INVALIDCALL\n", hr);
+    vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+    ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
+       vertex_size, exp_vertex_size);
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
+    equal = memcmp(declaration, declaration0, sizeof(declaration0));
+    ok(equal == 0, "Vertex declarations were not equal\n");
+
+    /* Use multiple streams and keep the same vertex size (invalid declaration) */
+    mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_multiple_streams);
+    ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics using multiple streams, "
+                 "got %#x expected D3DERR_INVALIDCALL\n", hr);
+    vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+    ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
+       vertex_size, exp_vertex_size);
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
+    equal = memcmp(declaration, declaration0, sizeof(declaration0));
+    ok(equal == 0, "Vertex declarations were not equal\n");
+
+    /* The next following test cases show that some invalid declarations are
+     * accepted with a D3D_OK. An access violation is thrown on Windows if
+     * DrawSubset is called. The methods GetNumBytesPerVertex and GetDeclaration
+     * are not affected, which indicates that the declaration is cached.
+     */
+
+    /* Double usage (invalid declaration) */
+    mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
+    ok(hr == D3D_OK, "Test UpdateSemantics double usage, "
+       "got %#x expected D3D_OK\n", hr);
+    vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+    ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
+       vertex_size, exp_vertex_size);
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
+    equal = memcmp(declaration, declaration_double_usage, sizeof(declaration_double_usage));
+    ok(equal == 0, "Vertex declarations were not equal\n");
+
+    /* Set the position to an undefined type (invalid declaration) */
+    mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_undefined_type);
+    ok(hr == D3D_OK, "Test UpdateSemantics undefined type, "
+       "got %#x expected D3D_OK\n", hr);
+    vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+    ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
+       vertex_size, exp_vertex_size);
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
+    equal = memcmp(declaration, declaration_undefined_type, sizeof(declaration_undefined_type));
+    ok(equal == 0, "Vertex declarations were not equal\n");
+
+    /* Use a not 4 byte aligned offset (invalid declaration) */
+    mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_not_4_byte_aligned_offset);
+    ok(hr == D3D_OK, "Test UpdateSemantics not 4 byte aligned offset, "
+       "got %#x expected D3D_OK\n", hr);
+    vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+    ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
+       vertex_size, exp_vertex_size);
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
+    equal = memcmp(declaration, declaration_not_4_byte_aligned_offset,
+                   sizeof(declaration_not_4_byte_aligned_offset));
+    ok(equal == 0, "Vertex declarations were not equal\n");
+
+cleanup:
+    if (mesh)
+        mesh->lpVtbl->Release(mesh);
+
+    free_test_context(test_context);
+}
+
+static void test_create_skin_info(void)
+{
+    HRESULT hr;
+    ID3DXSkinInfo *skininfo = NULL;
+    D3DVERTEXELEMENT9 empty_declaration[] = { D3DDECL_END() };
+    D3DVERTEXELEMENT9 declaration_out[MAX_FVF_DECL_SIZE];
+    const D3DVERTEXELEMENT9 declaration_with_nonzero_stream[] = {
+        {1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
+        D3DDECL_END()
+    };
+
+    hr = D3DXCreateSkinInfo(0, empty_declaration, 0, &skininfo);
+    ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    if (skininfo) IUnknown_Release(skininfo);
+    skininfo = NULL;
+
+    hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXCreateSkinInfo(1, declaration_with_nonzero_stream, 1, &skininfo);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXCreateSkinInfoFVF(1, 0, 1, &skininfo);
+    ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+    if (skininfo)
+    {
+        DWORD dword_result;
+        float flt_result;
+        const char *string_result;
+        D3DXMATRIX *transform;
+        D3DXMATRIX identity_matrix;
+
+        /* test initial values */
+        hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
+        ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+        if (SUCCEEDED(hr))
+            compare_elements(declaration_out, empty_declaration, __LINE__, 0);
+
+        dword_result = skininfo->lpVtbl->GetNumBones(skininfo);
+        ok(dword_result == 1, "Expected 1, got %u\n", dword_result);
+
+        flt_result = skininfo->lpVtbl->GetMinBoneInfluence(skininfo);
+        ok(flt_result == 0.0f, "Expected 0.0, got %g\n", flt_result);
+
+        string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
+        ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
+
+        dword_result = skininfo->lpVtbl->GetFVF(skininfo);
+        ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
+
+        dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 0);
+        ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
+
+        dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 1);
+        ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
+
+        transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, -1);
+        ok(transform == NULL, "Expected NULL, got %p\n", transform);
+
+        {
+            /* test [GS]etBoneOffsetMatrix */
+            hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 1, &identity_matrix);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            D3DXMatrixIdentity(&identity_matrix);
+            hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, &identity_matrix);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+
+            transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, 0);
+            check_matrix(transform, &identity_matrix);
+        }
+
+        {
+            /* test [GS]etBoneName */
+            const char *name_in = "testBoneName";
+            const char *string_result2;
+
+            hr = skininfo->lpVtbl->SetBoneName(skininfo, 1, name_in);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, name_in);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+
+            string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
+            ok(string_result != NULL, "Expected non-NULL string, got %p\n", string_result);
+            ok(!strcmp(string_result, name_in), "Expected '%s', got '%s'\n", name_in, string_result);
+
+            string_result2 = skininfo->lpVtbl->GetBoneName(skininfo, 0);
+            ok(string_result == string_result2, "Expected %p, got %p\n", string_result, string_result2);
+
+            string_result = skininfo->lpVtbl->GetBoneName(skininfo, 1);
+            ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
+        }
+
+        {
+            /* test [GS]etBoneInfluence */
+            DWORD vertices[2];
+            FLOAT weights[2];
+            int i;
+            DWORD num_influences;
+            DWORD exp_vertices[2];
+            FLOAT exp_weights[2];
+
+            /* vertex and weight arrays untouched when num_influences is 0 */
+            vertices[0] = 0xdeadbeef;
+            weights[0] = FLT_MAX;
+            hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+            ok(vertices[0] == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", vertices[0]);
+            ok(weights[0] == FLT_MAX, "expected %g, got %g\n", FLT_MAX, weights[0]);
+
+            hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 1, vertices, weights);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, NULL);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, weights);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+
+            /* no vertex or weight value checking */
+            exp_vertices[0] = 0;
+            exp_vertices[1] = 0x87654321;
+            exp_weights[0] = 0.5;
+            exp_weights[1] = NAN;
+            num_influences = 2;
+
+            hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 1, num_influences, vertices, weights);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, weights);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, vertices, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, exp_vertices, exp_weights);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+
+            memset(vertices, 0, sizeof(vertices));
+            memset(weights, 0, sizeof(weights));
+            hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+            for (i = 0; i < num_influences; i++) {
+                ok(exp_vertices[i] == vertices[i],
+                   "influence[%d]: expected vertex %u, got %u\n", i, exp_vertices[i], vertices[i]);
+                ok((isnan(exp_weights[i]) && isnan(weights[i])) || exp_weights[i] == weights[i],
+                   "influence[%d]: expected weights %g, got %g\n", i, exp_weights[i], weights[i]);
+            }
+
+            /* vertices and weights aren't returned after setting num_influences to 0 */
+            memset(vertices, 0, sizeof(vertices));
+            memset(weights, 0, sizeof(weights));
+            hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, 0, vertices, weights);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+
+            vertices[0] = 0xdeadbeef;
+            weights[0] = FLT_MAX;
+            hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+            ok(vertices[0] == 0xdeadbeef, "expected vertex 0xdeadbeef, got %u\n", vertices[0]);
+            ok(weights[0] == FLT_MAX, "expected weight %g, got %g\n", FLT_MAX, weights[0]);
+        }
+
+        {
+            /* test [GS]etFVF and [GS]etDeclaration */
+            D3DVERTEXELEMENT9 declaration_in[MAX_FVF_DECL_SIZE];
+            DWORD fvf = D3DFVF_XYZ;
+            DWORD got_fvf;
+
+            hr = skininfo->lpVtbl->SetDeclaration(skininfo, NULL);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_with_nonzero_stream);
+            ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+            hr = skininfo->lpVtbl->SetFVF(skininfo, 0);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+
+            hr = D3DXDeclaratorFromFVF(fvf, declaration_in);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+            hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_in);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+            got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
+            ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
+            hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+            compare_elements(declaration_out, declaration_in, __LINE__, 0);
+
+            hr = skininfo->lpVtbl->SetDeclaration(skininfo, empty_declaration);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+            got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
+            ok(got_fvf == 0, "Expected 0, got %#x\n", got_fvf);
+            hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+            compare_elements(declaration_out, empty_declaration, __LINE__, 0);
+
+            hr = skininfo->lpVtbl->SetFVF(skininfo, fvf);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+            got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
+            ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
+            hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
+            ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+            compare_elements(declaration_out, declaration_in, __LINE__, 0);
+        }
+    }
+    if (skininfo) IUnknown_Release(skininfo);
+    skininfo = NULL;
+
+    hr = D3DXCreateSkinInfoFVF(1, D3DFVF_XYZ, 1, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+
+    hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
+    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
+}
+
+static void test_convert_adjacency_to_point_reps(void)
+{
+    HRESULT hr;
+    struct test_context *test_context = NULL;
+    const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
+    const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
+    const D3DVERTEXELEMENT9 declaration[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+        D3DDECL_END()
+    };
+    const unsigned int VERTS_PER_FACE = 3;
+    void *vertex_buffer;
+    void *index_buffer;
+    DWORD *attributes_buffer;
+    int i, j;
+    enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
+    struct vertex_pnc
+    {
+        D3DXVECTOR3 position;
+        D3DXVECTOR3 normal;
+        enum color color; /* In case of manual visual inspection */
+    };
+#ifndef __REACTOS__
+    D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
+#else
+#define up {0.0f, 0.0f, 1.0f}
+#endif
+    /* mesh0 (one face)
+     *
+     * 0--1
+     * | /
+     * |/
+     * 2
+     */
+    const struct vertex_pnc vertices0[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices0[] = {0, 1, 2};
+    const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
+    const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
+    const DWORD adjacency0[] = {-1, -1, -1};
+    const DWORD exp_point_rep0[] = {0, 1, 2};
+    /* mesh1 (right)
+     *
+     * 0--1 3
+     * | / /|
+     * |/ / |
+     * 2 5--4
+     */
+    const struct vertex_pnc vertices1[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
+    const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
+    const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
+    const DWORD exp_point_rep1[] = {0, 1, 2, 1, 4, 2};
+    /* mesh2 (left)
+     *
+     *    3 0--1
+     *   /| | /
+     *  / | |/
+     * 5--4 2
+     */
+    const struct vertex_pnc vertices2[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{-1.0f,  3.0f,  0.f}, up, RED},
+        {{-1.0f,  0.0f,  0.f}, up, GREEN},
+        {{-3.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
+    const unsigned int num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
+    const DWORD adjacency2[] = {-1, -1, 1, 0, -1, -1};
+    const DWORD exp_point_rep2[] = {0, 1, 2, 0, 2, 5};
+    /* mesh3 (above)
+     *
+     *    3
+     *   /|
+     *  / |
+     * 5--4
+     * 0--1
+     * | /
+     * |/
+     * 2
+     */
+    struct vertex_pnc vertices3[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 2.0f,  7.0f,  0.f}, up, BLUE},
+        {{ 2.0f,  4.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  4.0f,  0.f}, up, RED},
+    };
+    const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
+    const unsigned int num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
+    const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
+    const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
+    /* mesh4 (below, tip against tip)
+     *
+     * 0--1
+     * | /
+     * |/
+     * 2
+     * 3
+     * |\
+     * | \
+     * 5--4
+     */
+    struct vertex_pnc vertices4[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 0.0f, -4.0f,  0.f}, up, BLUE},
+        {{ 2.0f, -7.0f,  0.f}, up, GREEN},
+        {{ 0.0f, -7.0f,  0.f}, up, RED},
+    };
+    const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
+    const unsigned int num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
+    const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
+    const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
+    /* mesh5 (gap in mesh)
+     *
+     *    0      3-----4  15
+     *   / \      \   /  /  \
+     *  /   \      \ /  /    \
+     * 2-----1      5 17-----16
+     * 6-----7      9 12-----13
+     *  \   /      / \  \    /
+     *   \ /      /   \  \  /
+     *    8     10-----11 14
+     *
+     */
+    const struct vertex_pnc vertices5[] =
+    {
+        {{ 0.0f,  1.0f,  0.f}, up, RED},
+        {{ 1.0f, -1.0f,  0.f}, up, GREEN},
+        {{-1.0f, -1.0f,  0.f}, up, BLUE},
+
+        {{ 0.1f,  1.0f,  0.f}, up, RED},
+        {{ 2.1f,  1.0f,  0.f}, up, BLUE},
+        {{ 1.1f, -1.0f,  0.f}, up, GREEN},
+
+        {{-1.0f, -1.1f,  0.f}, up, BLUE},
+        {{ 1.0f, -1.1f,  0.f}, up, GREEN},
+        {{ 0.0f, -3.1f,  0.f}, up, RED},
+
+        {{ 1.1f, -1.1f,  0.f}, up, GREEN},
+        {{ 2.1f, -3.1f,  0.f}, up, BLUE},
+        {{ 0.1f, -3.1f,  0.f}, up, RED},
+
+        {{ 1.2f, -1.1f,  0.f}, up, GREEN},
+        {{ 3.2f, -1.1f,  0.f}, up, RED},
+        {{ 2.2f, -3.1f,  0.f}, up, BLUE},
+
+        {{ 2.2f,  1.0f,  0.f}, up, BLUE},
+        {{ 3.2f, -1.0f,  0.f}, up, RED},
+        {{ 1.2f, -1.0f,  0.f}, up, GREEN},
+    };
+    const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
+    const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
+    const unsigned int num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
+    const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
+    const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
+    const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
+    /* mesh6 (indices re-ordering)
+     *
+     * 0--1 6 3
+     * | / /| |\
+     * |/ / | | \
+     * 2 8--7 5--4
+     */
+    const struct vertex_pnc vertices6[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 4.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 6.0f,  0.0f,  0.f}, up, BLUE},
+        {{ 4.0f,  0.0f,  0.f}, up, RED},
+    };
+    const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
+    const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
+    const unsigned int num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
+    const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
+    const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
+    /* mesh7 (expands collapsed triangle)
+     *
+     * 0--1 3
+     * | / /|
+     * |/ / |
+     * 2 5--4
+     */
+    const struct vertex_pnc vertices7[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
+    const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
+    const unsigned int num_faces7 = ARRAY_SIZE(indices7) / VERTS_PER_FACE;
+    const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
+    const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
+    /* mesh8 (indices re-ordering and double replacement)
+     *
+     * 0--1 9  6
+     * | / /|  |\
+     * |/ / |  | \
+     * 2 11-10 8--7
+     *         3--4
+     *         | /
+     *         |/
+     *         5
+     */
+    const struct vertex_pnc vertices8[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 4.0,  -4.0,  0.f}, up, RED},
+        {{ 6.0,  -4.0,  0.f}, up, BLUE},
+        {{ 4.0,  -7.0,  0.f}, up, GREEN},
+
+        {{ 4.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 6.0f,  0.0f,  0.f}, up, BLUE},
+        {{ 4.0f,  0.0f,  0.f}, up, RED},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
+    const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
+    const unsigned int num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
+    const DWORD adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
+    const DWORD exp_point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
+    /* mesh9 (right, shared vertices)
+     *
+     * 0--1
+     * | /|
+     * |/ |
+     * 2--3
+     */
+    const struct vertex_pnc vertices9[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 2.0f,  0.0f,  0.f}, up, RED},
+    };
+    const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
+    const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
+    const unsigned int num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
+    const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
+    const DWORD exp_point_rep9[] = {0, 1, 2, 3};
+    /* All mesh data */
+    ID3DXMesh *mesh = NULL;
+    ID3DXMesh *mesh_null_check = NULL;
+    unsigned int attributes[] = {0};
+    struct
+    {
+        const struct vertex_pnc *vertices;
+        const DWORD *indices;
+        const DWORD num_vertices;
+        const DWORD num_faces;
+        const DWORD *adjacency;
+        const DWORD *exp_point_reps;
+        const DWORD options;
+    }
+    tc[] =
+    {
+        {
+            vertices0,
+            indices0,
+            num_vertices0,
+            num_faces0,
+            adjacency0,
+            exp_point_rep0,
+            options
+        },
+        {
+            vertices1,
+            indices1,
+            num_vertices1,
+            num_faces1,
+            adjacency1,
+            exp_point_rep1,
+            options
+        },
+        {
+            vertices2,
+            indices2,
+            num_vertices2,
+            num_faces2,
+            adjacency2,
+            exp_point_rep2,
+            options
+        },
+        {
+            vertices3,
+            indices3,
+            num_vertices3,
+            num_faces3,
+            adjacency3,
+            exp_point_rep3,
+            options
+        },
+        {
+            vertices4,
+            indices4,
+            num_vertices4,
+            num_faces4,
+            adjacency4,
+            exp_point_rep4,
+            options
+        },
+        {
+            vertices5,
+            indices5,
+            num_vertices5,
+            num_faces5,
+            adjacency5,
+            exp_point_rep5,
+            options
+        },
+        {
+            vertices6,
+            indices6,
+            num_vertices6,
+            num_faces6,
+            adjacency6,
+            exp_point_rep6,
+            options
+        },
+        {
+            vertices7,
+            indices7,
+            num_vertices7,
+            num_faces7,
+            adjacency7,
+            exp_point_rep7,
+            options
+        },
+        {
+            vertices8,
+            indices8,
+            num_vertices8,
+            num_faces8,
+            adjacency8,
+            exp_point_rep8,
+            options
+        },
+        {
+            vertices9,
+            indices9,
+            num_vertices9,
+            num_faces9,
+            adjacency9,
+            exp_point_rep9,
+            options
+        },
+        {
+            vertices5,
+            (DWORD*)indices5_16bit,
+            num_vertices5,
+            num_faces5,
+            adjacency5,
+            exp_point_rep5,
+            options_16bit
+        },
+    };
+    DWORD *point_reps = NULL;
+
+    test_context = new_test_context();
+    if (!test_context)
+    {
+        skip("Couldn't create test context\n");
+        goto cleanup;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(tc); i++)
+    {
+        hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options, declaration,
+                            test_context->device, &mesh);
+        if (FAILED(hr))
+        {
+            skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
+            goto cleanup;
+        }
+
+        if (i == 0) /* Save first mesh for later NULL checks */
+            mesh_null_check = mesh;
+
+        point_reps = HeapAlloc(GetProcessHeap(), 0, tc[i].num_vertices * sizeof(*point_reps));
+        if (!point_reps)
+        {
+            skip("Couldn't allocate point reps array.\n");
+            goto cleanup;
+        }
+
+        hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
+        if (FAILED(hr))
+        {
+            skip("Couldn't lock vertex buffer.\n");
+            goto cleanup;
+        }
+        memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
+        hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
+        if (FAILED(hr))
+        {
+            skip("Couldn't unlock vertex buffer.\n");
+            goto cleanup;
+        }
+
+        hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
+        if (FAILED(hr))
+        {
+            skip("Couldn't lock index buffer.\n");
+            goto cleanup;
+        }
+        if (tc[i].options & D3DXMESH_32BIT)
+        {
+            memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
+        }
+        else
+        {
+            memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
+        }
+        hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
+        if (FAILED(hr)) {
+            skip("Couldn't unlock index buffer.\n");
+            goto cleanup;
+        }
+
+        hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
+        if (FAILED(hr))
+        {
+            skip("Couldn't lock attributes buffer.\n");
+            goto cleanup;
+        }
+        memcpy(attributes_buffer, attributes, sizeof(attributes));
+        hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
+        if (FAILED(hr))
+        {
+            skip("Couldn't unlock attributes buffer.\n");
+            goto cleanup;
+        }
+
+        /* Convert adjacency to point representation */
+        for (j = 0; j < tc[i].num_vertices; j++) point_reps[j] = -1;
+        hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps);
+        ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
+           "Got %x expected D3D_OK\n", i, hr);
+
+        /* Check point representation */
+        for (j = 0; j < tc[i].num_vertices; j++)
+        {
+            ok(point_reps[j] == tc[i].exp_point_reps[j],
+               "Unexpected point representation at (%d, %d)."
+               " Got %d expected %d\n",
+               i, j, point_reps[j], tc[i].exp_point_reps[j]);
+        }
+
+        HeapFree(GetProcessHeap(), 0, point_reps);
+        point_reps = NULL;
+
+        if (i != 0) /* First mesh will be freed during cleanup */
+            mesh->lpVtbl->Release(mesh);
+    }
+
+    /* NULL checks */
+    hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
+       "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. "
+       "Got %x expected D3DERR_INVALIDCALL\n", hr);
+
+cleanup:
+    if (mesh_null_check)
+        mesh_null_check->lpVtbl->Release(mesh_null_check);
+    HeapFree(GetProcessHeap(), 0, point_reps);
+    free_test_context(test_context);
+#ifdef __REACTOS__
+#undef up
+#endif
+}
+
+static void test_convert_point_reps_to_adjacency(void)
+{
+    HRESULT hr;
+    struct test_context *test_context = NULL;
+    const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
+    const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
+    const D3DVERTEXELEMENT9 declaration[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+        D3DDECL_END()
+    };
+    const unsigned int VERTS_PER_FACE = 3;
+    void *vertex_buffer;
+    void *index_buffer;
+    DWORD *attributes_buffer;
+    int i, j;
+    enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
+    struct vertex_pnc
+    {
+        D3DXVECTOR3 position;
+        D3DXVECTOR3 normal;
+        enum color color; /* In case of manual visual inspection */
+    };
+#ifndef __REACTOS__
+    D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
+#else
+#define up {0.0f, 0.0f, 1.0f}
+#endif
+
+    /* mesh0 (one face)
+     *
+     * 0--1
+     * | /
+     * |/
+     * 2
+     */
+    const struct vertex_pnc vertices0[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices0[] = {0, 1, 2};
+    const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
+    const unsigned int num_faces0 = num_vertices0 / VERTS_PER_FACE;
+    const DWORD exp_adjacency0[] = {-1, -1, -1};
+    const DWORD exp_id_adjacency0[] = {-1, -1, -1};
+    const DWORD point_rep0[] = {0, 1, 2};
+    /* mesh1 (right)
+     *
+     * 0--1 3
+     * | / /|
+     * |/ / |
+     * 2 5--4
+     */
+    const struct vertex_pnc vertices1[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
+    const unsigned int num_faces1 = num_vertices1 / VERTS_PER_FACE;
+    const DWORD exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
+    const DWORD exp_id_adjacency1[] = {-1, -1, -1, -1, -1, -1};
+    const DWORD point_rep1[] = {0, 1, 2, 1, 4, 2};
+    /* mesh2 (left)
+     *
+     *    3 0--1
+     *   /| | /
+     *  / | |/
+     * 5--4 2
+     */
+    const struct vertex_pnc vertices2[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{-1.0f,  3.0f,  0.f}, up, RED},
+        {{-1.0f,  0.0f,  0.f}, up, GREEN},
+        {{-3.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
+    const unsigned int num_faces2 = num_vertices2 / VERTS_PER_FACE;
+    const DWORD exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
+    const DWORD exp_id_adjacency2[] = {-1, -1, -1, -1, -1, -1};
+    const DWORD point_rep2[] = {0, 1, 2, 0, 2, 5};
+    /* mesh3 (above)
+     *
+     *    3
+     *   /|
+     *  / |
+     * 5--4
+     * 0--1
+     * | /
+     * |/
+     * 2
+     */
+    struct vertex_pnc vertices3[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 2.0f,  7.0f,  0.f}, up, BLUE},
+        {{ 2.0f,  4.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  4.0f,  0.f}, up, RED},
+    };
+    const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
+    const unsigned int num_faces3 = num_vertices3 / VERTS_PER_FACE;
+    const DWORD exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
+    const DWORD exp_id_adjacency3[] = {-1, -1, -1, -1, -1, -1};
+    const DWORD point_rep3[] = {0, 1, 2, 3, 1, 0};
+    /* mesh4 (below, tip against tip)
+     *
+     * 0--1
+     * | /
+     * |/
+     * 2
+     * 3
+     * |\
+     * | \
+     * 5--4
+     */
+    struct vertex_pnc vertices4[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 0.0f, -4.0f,  0.f}, up, BLUE},
+        {{ 2.0f, -7.0f,  0.f}, up, GREEN},
+        {{ 0.0f, -7.0f,  0.f}, up, RED},
+    };
+    const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
+    const unsigned int num_faces4 = num_vertices4 / VERTS_PER_FACE;
+    const DWORD exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
+    const DWORD exp_id_adjacency4[] = {-1, -1, -1, -1, -1, -1};
+    const DWORD point_rep4[] = {0, 1, 2, 3, 4, 5};
+    /* mesh5 (gap in mesh)
+     *
+     *    0      3-----4  15
+     *   / \      \   /  /  \
+     *  /   \      \ /  /    \
+     * 2-----1      5 17-----16
+     * 6-----7      9 12-----13
+     *  \   /      / \  \    /
+     *   \ /      /   \  \  /
+     *    8     10-----11 14
+     *
+     */
+    const struct vertex_pnc vertices5[] =
+    {
+        {{ 0.0f,  1.0f,  0.f}, up, RED},
+        {{ 1.0f, -1.0f,  0.f}, up, GREEN},
+        {{-1.0f, -1.0f,  0.f}, up, BLUE},
+
+        {{ 0.1f,  1.0f,  0.f}, up, RED},
+        {{ 2.1f,  1.0f,  0.f}, up, BLUE},
+        {{ 1.1f, -1.0f,  0.f}, up, GREEN},
+
+        {{-1.0f, -1.1f,  0.f}, up, BLUE},
+        {{ 1.0f, -1.1f,  0.f}, up, GREEN},
+        {{ 0.0f, -3.1f,  0.f}, up, RED},
+
+        {{ 1.1f, -1.1f,  0.f}, up, GREEN},
+        {{ 2.1f, -3.1f,  0.f}, up, BLUE},
+        {{ 0.1f, -3.1f,  0.f}, up, RED},
+
+        {{ 1.2f, -1.1f,  0.f}, up, GREEN},
+        {{ 3.2f, -1.1f,  0.f}, up, RED},
+        {{ 2.2f, -3.1f,  0.f}, up, BLUE},
+
+        {{ 2.2f,  1.0f,  0.f}, up, BLUE},
+        {{ 3.2f, -1.0f,  0.f}, up, RED},
+        {{ 1.2f, -1.0f,  0.f}, up, GREEN},
+    };
+    const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
+    const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
+    const unsigned int num_faces5 = num_vertices5 / VERTS_PER_FACE;
+    const DWORD exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
+    const DWORD exp_id_adjacency5[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+    const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
+    /* mesh6 (indices re-ordering)
+     *
+     * 0--1 6 3
+     * | / /| |\
+     * |/ / | | \
+     * 2 8--7 5--4
+     */
+    const struct vertex_pnc vertices6[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 4.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 6.0f,  0.0f,  0.f}, up, BLUE},
+        {{ 4.0f,  0.0f,  0.f}, up, RED},
+    };
+    const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
+    const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
+    const unsigned int num_faces6 = num_vertices6 / VERTS_PER_FACE;
+    const DWORD exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
+    const DWORD exp_id_adjacency6[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
+    const DWORD point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
+    /* mesh7 (expands collapsed triangle)
+     *
+     * 0--1 3
+     * | / /|
+     * |/ / |
+     * 2 5--4
+     */
+    const struct vertex_pnc vertices7[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
+    const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
+    const unsigned int num_faces7 = num_vertices7 / VERTS_PER_FACE;
+    const DWORD exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
+    const DWORD exp_id_adjacency7[] = {-1, -1, -1, -1, -1, -1};
+    const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
+    /* mesh8 (indices re-ordering and double replacement)
+     *
+     * 0--1 9  6
+     * | / /|  |\
+     * |/ / |  | \
+     * 2 11-10 8--7
+     *         3--4
+     *         | /
+     *         |/
+     *         5
+     */
+    const struct vertex_pnc vertices8[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 4.0,  -4.0,  0.f}, up, RED},
+        {{ 6.0,  -4.0,  0.f}, up, BLUE},
+        {{ 4.0,  -7.0,  0.f}, up, GREEN},
+
+        {{ 4.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 6.0f,  0.0f,  0.f}, up, BLUE},
+        {{ 4.0f,  0.0f,  0.f}, up, RED},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
+    const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
+    const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
+    const unsigned int num_faces8 = num_vertices8 / VERTS_PER_FACE;
+    const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
+    const DWORD exp_id_adjacency8[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+    const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
+     /* mesh9 (right, shared vertices)
+     *
+     * 0--1
+     * | /|
+     * |/ |
+     * 2--3
+     */
+    const struct vertex_pnc vertices9[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 2.0f,  0.0f,  0.f}, up, RED},
+    };
+    const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
+    const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
+    const unsigned int num_faces9 = 2;
+    const DWORD exp_adjacency9[] = {-1, 1, -1, -1, -1, 0};
+    const DWORD exp_id_adjacency9[] = {-1, 1, -1, -1, -1, 0};
+    const DWORD point_rep9[] = {0, 1, 2, 3};
+    /* All mesh data */
+    ID3DXMesh *mesh = NULL;
+    ID3DXMesh *mesh_null_check = NULL;
+    unsigned int attributes[] = {0};
+    struct
+    {
+        const struct vertex_pnc *vertices;
+        const DWORD *indices;
+        const DWORD num_vertices;
+        const DWORD num_faces;
+        const DWORD *point_reps;
+        const DWORD *exp_adjacency;
+        const DWORD *exp_id_adjacency;
+        const DWORD options;
+    }
+    tc[] =
+    {
+        {
+            vertices0,
+            indices0,
+            num_vertices0,
+            num_faces0,
+            point_rep0,
+            exp_adjacency0,
+            exp_id_adjacency0,
+            options
+        },
+        {
+            vertices1,
+            indices1,
+            num_vertices1,
+            num_faces1,
+            point_rep1,
+            exp_adjacency1,
+            exp_id_adjacency1,
+            options
+        },
+        {
+            vertices2,
+            indices2,
+            num_vertices2,
+            num_faces2,
+            point_rep2,
+            exp_adjacency2,
+            exp_id_adjacency2,
+            options
+        },
+        {
+            vertices3,
+            indices3,
+            num_vertices3,
+            num_faces3,
+            point_rep3,
+            exp_adjacency3,
+            exp_id_adjacency3,
+            options
+        },
+        {
+            vertices4,
+            indices4,
+            num_vertices4,
+            num_faces4,
+            point_rep4,
+            exp_adjacency4,
+            exp_id_adjacency4,
+            options
+        },
+        {
+            vertices5,
+            indices5,
+            num_vertices5,
+            num_faces5,
+            point_rep5,
+            exp_adjacency5,
+            exp_id_adjacency5,
+            options
+        },
+        {
+            vertices6,
+            indices6,
+            num_vertices6,
+            num_faces6,
+            point_rep6,
+            exp_adjacency6,
+            exp_id_adjacency6,
+            options
+        },
+        {
+            vertices7,
+            indices7,
+            num_vertices7,
+            num_faces7,
+            point_rep7,
+            exp_adjacency7,
+            exp_id_adjacency7,
+            options
+        },
+        {
+            vertices8,
+            indices8,
+            num_vertices8,
+            num_faces8,
+            point_rep8,
+            exp_adjacency8,
+            exp_id_adjacency8,
+            options
+        },
+        {
+            vertices9,
+            indices9,
+            num_vertices9,
+            num_faces9,
+            point_rep9,
+            exp_adjacency9,
+            exp_id_adjacency9,
+            options
+        },
+        {
+            vertices8,
+            (DWORD*)indices8_16bit,
+            num_vertices8,
+            num_faces8,
+            point_rep8,
+            exp_adjacency8,
+            exp_id_adjacency8,
+            options_16bit
+        },
+    };
+    DWORD *adjacency = NULL;
+#ifdef __REACTOS__
+#undef up
+#endif
+
+    test_context = new_test_context();
+    if (!test_context)
+    {
+        skip("Couldn't create test context\n");
+        goto cleanup;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(tc); i++)
+    {
+        hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
+                            declaration, test_context->device, &mesh);
+        if (FAILED(hr))
+        {
+            skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
+            goto cleanup;
+        }
+
+        if (i == 0) /* Save first mesh for later NULL checks */
+            mesh_null_check = mesh;
+
+        adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
+        if (!adjacency)
+        {
+            skip("Couldn't allocate adjacency array.\n");
+            goto cleanup;
+        }
+
+        hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
+        if (FAILED(hr))
+        {
+            skip("Couldn't lock vertex buffer.\n");
+            goto cleanup;
+        }
+        memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
+        hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
+        if (FAILED(hr))
+        {
+            skip("Couldn't unlock vertex buffer.\n");
+            goto cleanup;
+        }
+        hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
+        if (FAILED(hr))
+        {
+            skip("Couldn't lock index buffer.\n");
+            goto cleanup;
+        }
+        if (tc[i].options & D3DXMESH_32BIT)
+        {
+            memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
+        }
+        else
+        {
+            memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
+        }
+        hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
+        if (FAILED(hr)) {
+            skip("Couldn't unlock index buffer.\n");
+            goto cleanup;
+        }
+
+        hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
+        if (FAILED(hr))
+        {
+            skip("Couldn't lock attributes buffer.\n");
+            goto cleanup;
+        }
+        memcpy(attributes_buffer, attributes, sizeof(attributes));
+        hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
+        if (FAILED(hr))
+        {
+            skip("Couldn't unlock attributes buffer.\n");
+            goto cleanup;
+        }
+
+        /* Convert point representation to adjacency*/
+        for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
+
+        hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
+        ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
+           "Got %x expected D3D_OK\n", i, hr);
+        /* Check adjacency */
+        for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
+        {
+            ok(adjacency[j] == tc[i].exp_adjacency[j],
+               "Unexpected adjacency information at (%d, %d)."
+               " Got %d expected %d\n",
+               i, j, adjacency[j], tc[i].exp_adjacency[j]);
+        }
+
+        /* NULL point representation is considered identity. */
+        for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
+        hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
+        ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
+                     "Got %x expected D3D_OK\n", hr);
+        for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
+        {
+            ok(adjacency[j] == tc[i].exp_id_adjacency[j],
+               "Unexpected adjacency information (id) at (%d, %d)."
+               " Got %d expected %d\n",
+               i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
+        }
+
+        HeapFree(GetProcessHeap(), 0, adjacency);
+        adjacency = NULL;
+        if (i != 0) /* First mesh will be freed during cleanup */
+            mesh->lpVtbl->Release(mesh);
+    }
+
+    /* NULL checks */
+    hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
+       "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
+       "Got %x expected D3DERR_INVALIDCALL\n", hr);
+
+cleanup:
+    if (mesh_null_check)
+        mesh_null_check->lpVtbl->Release(mesh_null_check);
+    HeapFree(GetProcessHeap(), 0, adjacency);
+    free_test_context(test_context);
+}
+
+static HRESULT init_test_mesh(const DWORD num_faces, const DWORD num_vertices,
+                              const DWORD options,
+                              const D3DVERTEXELEMENT9 *declaration,
+                              IDirect3DDevice9 *device, ID3DXMesh **mesh_ptr,
+                              const void *vertices, const DWORD vertex_size,
+                              const DWORD *indices, const DWORD *attributes)
+{
+    HRESULT hr;
+    void *vertex_buffer;
+    void *index_buffer;
+    DWORD *attributes_buffer;
+    ID3DXMesh *mesh = NULL;
+
+    hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration, device, mesh_ptr);
+    if (FAILED(hr))
+    {
+        skip("Couldn't create mesh. Got %x expected D3D_OK\n", hr);
+        goto cleanup;
+    }
+    mesh = *mesh_ptr;
+
+    hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
+    if (FAILED(hr))
+    {
+        skip("Couldn't lock vertex buffer.\n");
+        goto cleanup;
+    }
+    memcpy(vertex_buffer, vertices, num_vertices * vertex_size);
+    hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
+    if (FAILED(hr))
+    {
+        skip("Couldn't unlock vertex buffer.\n");
+        goto cleanup;
+    }
+
+    hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
+    if (FAILED(hr))
+    {
+        skip("Couldn't lock index buffer.\n");
+        goto cleanup;
+    }
+    if (options & D3DXMESH_32BIT)
+    {
+        if (indices)
+            memcpy(index_buffer, indices, 3 * num_faces * sizeof(DWORD));
+        else
+        {
+            /* Fill index buffer with 0, 1, 2, ...*/
+            DWORD *indices_32bit = (DWORD*)index_buffer;
+            UINT i;
+            for (i = 0; i < 3 * num_faces; i++)
+                indices_32bit[i] = i;
+        }
+    }
+    else
+    {
+        if (indices)
+            memcpy(index_buffer, indices, 3 * num_faces * sizeof(WORD));
+        else
+        {
+            /* Fill index buffer with 0, 1, 2, ...*/
+            WORD *indices_16bit = (WORD*)index_buffer;
+            UINT i;
+            for (i = 0; i < 3 * num_faces; i++)
+                indices_16bit[i] = i;
+        }
+    }
+    hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
+    if (FAILED(hr)) {
+        skip("Couldn't unlock index buffer.\n");
+        goto cleanup;
+    }
+
+    hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
+    if (FAILED(hr))
+    {
+        skip("Couldn't lock attributes buffer.\n");
+        goto cleanup;
+    }
+
+    if (attributes)
+        memcpy(attributes_buffer, attributes, num_faces * sizeof(*attributes));
+    else
+        memset(attributes_buffer, 0, num_faces * sizeof(*attributes));
+
+    hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
+    if (FAILED(hr))
+    {
+        skip("Couldn't unlock attributes buffer.\n");
+        goto cleanup;
+    }
+
+    hr = D3D_OK;
+cleanup:
+    return hr;
+}
+
+/* Using structs instead of bit-fields in order to avoid compiler issues. */
+struct udec3
+{
+    UINT x;
+    UINT y;
+    UINT z;
+    UINT w;
+};
+
+struct dec3n
+{
+    INT x;
+    INT y;
+    INT z;
+    INT w;
+};
+
+static DWORD init_udec3_dword(UINT x, UINT y, UINT z, UINT w)
+{
+    DWORD d = 0;
+
+    d |= x & 0x3ff;
+    d |= (y << 10) & 0xffc00;
+    d |= (z << 20) & 0x3ff00000;
+    d |= (w << 30) & 0xc0000000;
+
+    return d;
+}
+
+static DWORD init_dec3n_dword(INT x, INT y, INT z, INT w)
+{
+    DWORD d = 0;
+
+    d |= x & 0x3ff;
+    d |= (y << 10) & 0xffc00;
+    d |= (z << 20) & 0x3ff00000;
+    d |= (w << 30) & 0xc0000000;
+
+    return d;
+}
+
+static struct udec3 dword_to_udec3(DWORD d)
+{
+    struct udec3 v;
+
+    v.x = d & 0x3ff;
+    v.y = (d & 0xffc00) >> 10;
+    v.z = (d & 0x3ff00000) >> 20;
+    v.w = (d & 0xc0000000) >> 30;
+
+    return v;
+}
+
+static struct dec3n dword_to_dec3n(DWORD d)
+{
+    struct dec3n v;
+
+    v.x = d & 0x3ff;
+    v.y = (d & 0xffc00) >> 10;
+    v.z = (d & 0x3ff00000) >> 20;
+    v.w = (d & 0xc0000000) >> 30;
+
+    return v;
+}
+
+static void check_vertex_components(int line, int mesh_number, int vertex_number, BYTE *got_ptr, const BYTE *exp_ptr, D3DVERTEXELEMENT9 *declaration)
+{
+    const char *usage_strings[] =
+    {
+        "position",
+        "blend weight",
+        "blend indices",
+        "normal",
+        "point size",
+        "texture coordinates",
+        "tangent",
+        "binormal",
+        "tessellation factor",
+        "position transformed",
+        "color",
+        "fog",
+        "depth",
+        "sample"
+    };
+    D3DVERTEXELEMENT9 *decl_ptr;
+    const float PRECISION = 1e-5f;
+
+    for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
+    {
+        switch (decl_ptr->Type)
+        {
+            case D3DDECLTYPE_FLOAT1:
+            {
+                FLOAT *got = (FLOAT*)(got_ptr + decl_ptr->Offset);
+                FLOAT *exp = (FLOAT*)(exp_ptr + decl_ptr->Offset);
+                FLOAT diff = fabsf(*got - *exp);
+                ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got %f for vertex %d %s, expected %f.\n",
+                    mesh_number, *got, vertex_number, usage_strings[decl_ptr->Usage], *exp);
+                break;
+            }
+            case D3DDECLTYPE_FLOAT2:
+            {
+                D3DXVECTOR2 *got = (D3DXVECTOR2*)(got_ptr + decl_ptr->Offset);
+                D3DXVECTOR2 *exp = (D3DXVECTOR2*)(exp_ptr + decl_ptr->Offset);
+                FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
+                ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f) for vertex %d %s, expected (%f, %f).\n",
+                    mesh_number, got->x, got->y, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y);
+                break;
+            }
+            case D3DDECLTYPE_FLOAT3:
+            {
+                D3DXVECTOR3 *got = (D3DXVECTOR3*)(got_ptr + decl_ptr->Offset);
+                D3DXVECTOR3 *exp = (D3DXVECTOR3*)(exp_ptr + decl_ptr->Offset);
+                FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
+                diff = max(diff, fabsf(got->z - exp->z));
+                ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f) for vertex %d %s, expected (%f, %f, %f).\n",
+                    mesh_number, got->x, got->y, got->z, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z);
+                break;
+            }
+            case D3DDECLTYPE_FLOAT4:
+            {
+                D3DXVECTOR4 *got = (D3DXVECTOR4*)(got_ptr + decl_ptr->Offset);
+                D3DXVECTOR4 *exp = (D3DXVECTOR4*)(exp_ptr + decl_ptr->Offset);
+                FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
+                diff = max(diff, fabsf(got->z - exp->z));
+                diff = max(diff, fabsf(got->w - exp->w));
+                ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f, %f) for vertex %d %s, expected (%f, %f, %f, %f).\n",
+                    mesh_number, got->x, got->y, got->z, got->w, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z, got->w);
+                break;
+            }
+            case D3DDECLTYPE_D3DCOLOR:
+            {
+                BYTE *got = got_ptr + decl_ptr->Offset;
+                const BYTE *exp = exp_ptr + decl_ptr->Offset;
+                BOOL same_color = got[0] == exp[0] && got[1] == exp[1]
+                                  && got[2] == exp[2] && got[3] == exp[3];
+                const char *color_types[] = {"diffuse", "specular", "undefined color"};
+                BYTE usage_index = decl_ptr->UsageIndex;
+                if (usage_index > 1) usage_index = 2;
+                ok_(__FILE__,line)(same_color, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
+                    mesh_number, got[0], got[1], got[2], got[3], vertex_number, color_types[usage_index], exp[0], exp[1], exp[2], exp[3]);
+                break;
+            }
+            case D3DDECLTYPE_UBYTE4:
+            case D3DDECLTYPE_UBYTE4N:
+            {
+                BYTE *got = got_ptr + decl_ptr->Offset;
+                const BYTE *exp = exp_ptr + decl_ptr->Offset;
+                BOOL same = got[0] == exp[0] && got[1] == exp[1]
+                            && got[2] == exp[2] && got[3] == exp[3];
+                ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
+                    mesh_number, got[0], got[1], got[2], got[3], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1], exp[2], exp[3]);
+                break;
+            }
+            case D3DDECLTYPE_SHORT2:
+            case D3DDECLTYPE_SHORT2N:
+            {
+                SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
+                SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
+                BOOL same = got[0] == exp[0] && got[1] == exp[1];
+                ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd) for vertex %d %s, expected (%hd, %hd).\n",
+                    mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
+                break;
+            }
+            case D3DDECLTYPE_SHORT4:
+            case D3DDECLTYPE_SHORT4N:
+            {
+                SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
+                SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
+                BOOL same = got[0] == exp[0] && got[1] == exp[1]
+                            && got[2] == exp[2] && got[3] == exp[3];
+                ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd, %hd, %hd) for vertex %d %s, expected (%hd, %hd, %hd, %hd).\n",
+                    mesh_number, got[0], got[1], got[2], got[3], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1], exp[2], exp[3]);
+                break;
+            }
+            case D3DDECLTYPE_USHORT2N:
+            {
+                USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
+                USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
+                BOOL same = got[0] == exp[0] && got[1] == exp[1];
+                ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu) for vertex %d %s, expected (%hu, %hu).\n",
+                    mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
+                break;
+            }
+            case D3DDECLTYPE_USHORT4N:
+            {
+                USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
+                USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
+                BOOL same = got[0] == exp[0] && got[1] == exp[1]
+                            && got[2] == exp[2] && got[3] == exp[3];
+                ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu, %hu, %hu) for vertex %d %s, expected (%hu, %hu, %hu, %hu).\n",
+                    mesh_number, got[0], got[1], got[2], got[3], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1], exp[2], exp[3]);
+                break;
+            }
+            case D3DDECLTYPE_UDEC3:
+            {
+                DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
+                DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
+                BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
+                struct udec3 got_udec3 = dword_to_udec3(*got);
+                struct udec3 exp_udec3 = dword_to_udec3(*exp);
+                ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
+                    mesh_number, got_udec3.x, got_udec3.y, got_udec3.z, got_udec3.w, vertex_number, usage_strings[decl_ptr->Usage], exp_udec3.x, exp_udec3.y, exp_udec3.z, exp_udec3.w);
+
+                break;
+            }
+            case D3DDECLTYPE_DEC3N:
+            {
+                DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
+                DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
+                BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
+                struct dec3n got_dec3n = dword_to_dec3n(*got);
+                struct dec3n exp_dec3n = dword_to_dec3n(*exp);
+                ok_(__FILE__,line)(same, "Mesh %d: Got (%d, %d, %d, %d) for vertex %d %s, expected (%d, %d, %d, %d).\n",
+                    mesh_number, got_dec3n.x, got_dec3n.y, got_dec3n.z, got_dec3n.w, vertex_number, usage_strings[decl_ptr->Usage], exp_dec3n.x, exp_dec3n.y, exp_dec3n.z, exp_dec3n.w);
+                break;
+            }
+            case D3DDECLTYPE_FLOAT16_2:
+            {
+                WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
+                WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
+                BOOL same = got[0] == exp[0] && got[1] == exp[1];
+                ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx) for vertex %d %s, expected (%hx, %hx).\n",
+                    mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
+                break;
+            }
+            case D3DDECLTYPE_FLOAT16_4:
+            {
+                WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
+                WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
+                BOOL same = got[0] == exp[0] && got[1] == exp[1]
+                            && got[2] == exp[2] && got[3] == exp[3];
+                ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx, %hx, %hx) for vertex %d %s, expected (%hx, %hx, %hx, %hx).\n",
+                    mesh_number, got[0], got[1], got[2], got[3], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1], exp[3], exp[4]);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}
+
+static void test_weld_vertices(void)
+{
+    HRESULT hr;
+    struct test_context *test_context = NULL;
+    DWORD i;
+    const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
+    const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
+    BYTE *vertices = NULL;
+    DWORD *indices = NULL;
+    WORD *indices_16bit = NULL;
+    const UINT VERTS_PER_FACE = 3;
+#ifndef __REACTOS__
+    const D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
+#else
+#define up {0.0f, 0.0f, 1.0f}
+#endif
+    struct vertex_normal
+    {
+        D3DXVECTOR3 position;
+        D3DXVECTOR3 normal;
+    };
+    struct vertex_blendweight
+    {
+        D3DXVECTOR3 position;
+        FLOAT blendweight;
+    };
+    struct vertex_texcoord
+    {
+        D3DXVECTOR3 position;
+        D3DXVECTOR2 texcoord;
+    };
+    struct vertex_color
+    {
+        D3DXVECTOR3 position;
+        DWORD color;
+    };
+    struct vertex_color_ubyte4
+    {
+        D3DXVECTOR3 position;
+        BYTE color[4];
+    };
+    struct vertex_texcoord_short2
+    {
+        D3DXVECTOR3 position;
+        SHORT texcoord[2];
+    };
+    struct vertex_texcoord_ushort2n
+    {
+        D3DXVECTOR3 position;
+        USHORT texcoord[2];
+    };
+    struct vertex_normal_short4
+    {
+        D3DXVECTOR3 position;
+        SHORT normal[4];
+    };
+    struct vertex_texcoord_float16_2
+    {
+        D3DXVECTOR3 position;
+        WORD texcoord[2];
+    };
+    struct vertex_texcoord_float16_4
+    {
+        D3DXVECTOR3 position;
+        WORD texcoord[4];
+    };
+    struct vertex_normal_udec3
+    {
+        D3DXVECTOR3 position;
+        DWORD normal;
+    };
+    struct vertex_normal_dec3n
+    {
+        D3DXVECTOR3 position;
+        DWORD normal;
+    };
+    UINT vertex_size_normal = sizeof(struct vertex_normal);
+    UINT vertex_size_blendweight = sizeof(struct vertex_blendweight);
+    UINT vertex_size_texcoord = sizeof(struct vertex_texcoord);
+    UINT vertex_size_color = sizeof(struct vertex_color);
+    UINT vertex_size_color_ubyte4 = sizeof(struct vertex_color_ubyte4);
+    UINT vertex_size_texcoord_short2 = sizeof(struct vertex_texcoord_short2);
+    UINT vertex_size_normal_short4 = sizeof(struct vertex_normal_short4);
+    UINT vertex_size_texcoord_float16_2 = sizeof(struct vertex_texcoord_float16_2);
+    UINT vertex_size_texcoord_float16_4 = sizeof(struct vertex_texcoord_float16_4);
+    UINT vertex_size_normal_udec3 = sizeof(struct vertex_normal_udec3);
+    UINT vertex_size_normal_dec3n = sizeof(struct vertex_normal_dec3n);
+    D3DVERTEXELEMENT9 declaration_normal[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_normal3[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 3},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_blendweight[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_texcoord[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_color[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_color_ubyte4n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_color_ubyte4[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_texcoord_short2[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_texcoord_short2n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_texcoord_ushort2n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_normal_short4[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_normal_short4n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_normal_ushort4n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_texcoord10[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 10},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_color2[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_color1[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_texcoord_float16_2[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_texcoord_float16_4[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_normal_udec3[] =
+   {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_normal_dec3n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END()
+    };
+    /* Test 0. One face and no welding.
+     *
+     * 0--1
+     * | /
+     * |/
+     * 2
+     */
+    const struct vertex vertices0[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+    };
+    const DWORD indices0[] = {0, 1, 2};
+    const DWORD attributes0[] = {0};
+    const DWORD exp_indices0[] = {0, 1, 2};
+    const UINT num_vertices0 = ARRAY_SIZE(vertices0);
+    const UINT num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
+    const DWORD flags0 = D3DXWELDEPSILONS_WELDALL;
+    /* epsilons0 is NULL */
+    const DWORD adjacency0[] = {-1, -1, -1};
+    const struct vertex exp_vertices0[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+    };
+    const DWORD exp_face_remap0[] = {0};
+    const DWORD exp_vertex_remap0[] = {0, 1, 2};
+    const DWORD exp_new_num_vertices0 = ARRAY_SIZE(exp_vertices0);
+    /* Test 1. Two vertices should be removed without regard to epsilon.
+     *
+     * 0--1 3
+     * | / /|
+     * |/ / |
+     * 2 5--4
+     */
+    const struct vertex_normal vertices1[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, up},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, up},
+    };
+    const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes1[] = {0, 0};
+    const UINT num_vertices1 = ARRAY_SIZE(vertices1);
+    const UINT num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
+    const DWORD flags1 = D3DXWELDEPSILONS_WELDALL;
+    /* epsilons1 is NULL */
+    const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal exp_vertices1[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  0.0f,  0.f}, up}
+    };
+    const DWORD exp_indices1[] = {0, 1, 2, 1, 3, 2};
+    const DWORD exp_face_remap1[] = {0, 1};
+    const DWORD exp_vertex_remap1[] = {0, 1, 2, 4, -1, -1};
+    const DWORD exp_new_num_vertices1 = ARRAY_SIZE(exp_vertices1);
+    /* Test 2. Two faces. No vertices should be removed because of normal
+     * epsilon, but the positions should be replaced. */
+    const struct vertex_normal vertices2[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
+    };
+    const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes2[] = {0, 0};
+    const UINT num_vertices2 = ARRAY_SIZE(vertices2);
+    const UINT num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
+    DWORD flags2 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons2 = {1.0f, 0.0f, 0.499999f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency2[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal exp_vertices2[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
+    };
+    const DWORD exp_indices2[] = {0, 1, 2, 3, 4, 5};
+    const DWORD exp_face_remap2[] = {0, 1};
+    const DWORD exp_vertex_remap2[] = {0, 1, 2, 3, 4, 5};
+    const DWORD exp_new_num_vertices2 = ARRAY_SIZE(exp_vertices2);
+    /* Test 3. Two faces. One vertex should be removed because of normal epsilon. */
+    const struct vertex_normal vertices3[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
+    };
+    const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes3[] = {0, 0};
+    const UINT num_vertices3 = ARRAY_SIZE(vertices3);
+    const UINT num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
+    DWORD flags3 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons3 = {1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency3[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal exp_vertices3[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
+    };
+    const DWORD exp_indices3[] = {0, 1, 2, 1, 3, 4};
+    const DWORD exp_face_remap3[] = {0, 1};
+    const DWORD exp_vertex_remap3[] = {0, 1, 2, 4, 5, -1};
+    const DWORD exp_new_num_vertices3 = ARRAY_SIZE(exp_vertices3);
+    /* Test 4  Two faces. Two vertices should be removed. */
+    const struct vertex_normal vertices4[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
+    };
+    const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes4[] = {0, 0};
+    const UINT num_vertices4 = ARRAY_SIZE(vertices4);
+    const UINT num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
+    DWORD flags4 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons4 = {1.0f, 0.0f, 0.6f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency4[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal exp_vertices4[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  0.0f,  0.f}, up},
+    };
+    const DWORD exp_indices4[] = {0, 1, 2, 1, 3, 2};
+    const DWORD exp_face_remap4[] = {0, 1};
+    const DWORD exp_vertex_remap4[] = {0, 1, 2, 4, -1, -1};
+    const DWORD exp_new_num_vertices4 = ARRAY_SIZE(exp_vertices4);
+    /* Test 5. Odd face ordering.
+     *
+     * 0--1 6 3
+     * | / /| |\
+     * |/ / | | \
+     * 2 8--7 5--4
+     */
+    const struct vertex_normal vertices5[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, up},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, up},
+
+        {{ 4.0f,  3.0f,  0.f}, up},
+        {{ 6.0f,  0.0f,  0.f}, up},
+        {{ 4.0f,  0.0f,  0.f}, up},
+    };
+    const DWORD indices5[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
+    const DWORD exp_indices5[] = {0, 1, 2, 1, 4, 2, 1, 3, 4};
+    const DWORD attributes5[] = {0, 0, 0};
+    const UINT num_vertices5 = ARRAY_SIZE(vertices5);
+    const UINT num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
+    DWORD flags5 = D3DXWELDEPSILONS_WELDALL;
+    const DWORD adjacency5[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
+    const struct vertex_normal exp_vertices5[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, up},
+    };
+    const DWORD exp_face_remap5[] = {0, 1, 2};
+    const DWORD exp_vertex_remap5[] = {0, 1, 2, 4, 5, -1, -1, -1, -1};
+    const DWORD exp_new_num_vertices5 = ARRAY_SIZE(exp_vertices5);
+    /* Test 6. Two faces. Do not remove flag is used, so no vertices should be
+     * removed. */
+    const struct vertex_normal vertices6[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
+    };
+    const DWORD indices6[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes6[] = {0, 0};
+    const UINT num_vertices6 = ARRAY_SIZE(vertices6);
+    const UINT num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
+    DWORD flags6 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTREMOVEVERTICES;
+    const D3DXWELDEPSILONS epsilons6 = {1.0f, 0.0f, 0.6f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency6[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal exp_vertices6[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+    };
+    const DWORD exp_indices6[] = {0, 1, 2, 3, 4, 5};
+    const DWORD exp_face_remap6[] = {0, 1};
+    const DWORD exp_vertex_remap6[] = {0, 1, 2, 3, 4, 5};
+    const DWORD exp_new_num_vertices6 = ARRAY_SIZE(exp_vertices6);
+    /* Test 7. Same as test 6 but with 16 bit indices. */
+    const WORD indices6_16bit[] = {0, 1, 2, 3, 4, 5};
+    /* Test 8. No flags. Same result as D3DXWELDEPSILONS_WELDPARTIALMATCHES. */
+    const struct vertex_normal vertices8[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
+    };
+    const DWORD indices8[] = {0, 1, 2, 1, 3, 4};
+    const DWORD attributes8[] = {0, 0};
+    const UINT num_vertices8 = ARRAY_SIZE(vertices8);
+    const UINT num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
+    DWORD flags8 = 0;
+    const D3DXWELDEPSILONS epsilons8 = {1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency8[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal exp_vertices8[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, up},
+    };
+    const DWORD exp_indices8[] = {0, 1, 2, 1, 3, 4};
+    const DWORD exp_face_remap8[] = {0, 1};
+    const DWORD exp_vertex_remap8[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices8 = ARRAY_SIZE(exp_vertices8);
+    /* Test 9. Vertices are removed even though they belong to separate
+     * attribute groups if D3DXWELDEPSILONS_DONOTSPLIT is set. */
+    const struct vertex_normal vertices9[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
+    };
+    const DWORD indices9[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes9[] = {0, 1};
+    const UINT num_vertices9 = ARRAY_SIZE(vertices9);
+    const UINT num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
+    DWORD flags9 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTSPLIT;
+    const D3DXWELDEPSILONS epsilons9 = {1.0f, 0.0f, 0.6f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal exp_vertices9[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  0.0f,  0.f}, up},
+    };
+    const DWORD exp_indices9[] = {0, 1, 2, 1, 3, 2};
+    const DWORD exp_face_remap9[] = {0, 1};
+    const DWORD exp_vertex_remap9[] = {0, 1, 2, 4, -1, -1};
+    const DWORD exp_new_num_vertices9 = ARRAY_SIZE(exp_vertices9);
+    /* Test 10. Weld blendweight (FLOAT1). */
+    const struct vertex_blendweight vertices10[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, 1.0f},
+        {{ 2.0f,  3.0f,  0.f}, 1.0f},
+        {{ 0.0f,  0.0f,  0.f}, 1.0f},
+
+        {{ 3.0f,  3.0f,  0.f}, 0.9},
+        {{ 3.0f,  0.0f,  0.f}, 1.0},
+        {{ 1.0f,  0.0f,  0.f}, 0.4},
+    };
+    const DWORD indices10[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes10[] = {0, 0};
+    const UINT num_vertices10 = ARRAY_SIZE(vertices10);
+    const UINT num_faces10 = ARRAY_SIZE(indices10) / VERTS_PER_FACE;
+    DWORD flags10 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons10 = {1.0f, 0.1f + FLT_EPSILON, 0.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency10[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_blendweight exp_vertices10[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, 1.0f},
+        {{ 2.0f,  3.0f,  0.f}, 1.0f},
+        {{ 0.0f,  0.0f,  0.f}, 1.0f},
+
+        {{ 3.0f,  0.0f,  0.f}, 1.0},
+        {{ 0.0f,  0.0f,  0.f}, 0.4},
+    };
+    const DWORD exp_indices10[] = {0, 1, 2, 1, 3, 4};
+    const DWORD exp_face_remap10[] = {0, 1};
+    const DWORD exp_vertex_remap10[] = {0, 1, 2, 4, 5, -1};
+    const DWORD exp_new_num_vertices10 = ARRAY_SIZE(exp_vertices10);
+    /* Test 11. Weld texture coordinates. */
+    const struct vertex_texcoord vertices11[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
+    };
+    const DWORD indices11[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes11[] = {0, 0};
+    const UINT num_vertices11 = ARRAY_SIZE(vertices11);
+    const UINT num_faces11 = ARRAY_SIZE(indices11) / VERTS_PER_FACE;
+    DWORD flags11 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons11 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {0.4f + FLT_EPSILON, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency11[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_texcoord exp_vertices11[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
+    };
+    const DWORD exp_indices11[] = {0, 1, 2, 1, 3, 4};
+    const DWORD exp_face_remap11[] = {0, 1};
+    const DWORD exp_vertex_remap11[] = {0, 1, 2, 4, 5, -1};
+    const DWORD exp_new_num_vertices11 = ARRAY_SIZE(exp_vertices11);
+    /* Test 12. Weld with color. */
+    const struct vertex_color vertices12[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+
+        {{ 3.0f,  3.0f,  0.f}, 0x00000000},
+        {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+        {{ 1.0f,  0.0f,  0.f}, 0x88888888},
+    };
+    const DWORD indices12[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes12[] = {0, 0};
+    const UINT num_vertices12 = ARRAY_SIZE(vertices12);
+    const UINT num_faces12 = ARRAY_SIZE(indices12) / VERTS_PER_FACE;
+    DWORD flags12 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons12 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency12[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_color exp_vertices12[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+
+        {{ 2.0f,  3.0f,  0.f}, 0x00000000},
+        {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+    };
+    const DWORD exp_indices12[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap12[] = {0, 1};
+    const DWORD exp_vertex_remap12[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices12 = ARRAY_SIZE(exp_vertices12);
+    /* Test 13. Two faces. One vertex should be removed because of normal epsilon.
+     * This is similar to test 3, but the declaration has been changed to NORMAL3.
+     */
+    const struct vertex_normal vertices13[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
+    };
+    const DWORD indices13[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes13[] = {0, 0};
+    const UINT num_vertices13 = ARRAY_SIZE(vertices3);
+    const UINT num_faces13 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
+    DWORD flags13 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons13 = {1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency13[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal exp_vertices13[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
+    };
+    const DWORD exp_indices13[] = {0, 1, 2, 1, 3, 4};
+    const DWORD exp_face_remap13[] = {0, 1};
+    const DWORD exp_vertex_remap13[] = {0, 1, 2, 4, 5, -1};
+    const DWORD exp_new_num_vertices13 = ARRAY_SIZE(exp_vertices13);
+    /* Test 14. Another test for welding with color. */
+    const struct vertex_color vertices14[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+
+        {{ 3.0f,  3.0f,  0.f}, 0x00000000},
+        {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+        {{ 1.0f,  0.0f,  0.f}, 0x01010101},
+    };
+    const DWORD indices14[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes14[] = {0, 0};
+    const UINT num_vertices14 = ARRAY_SIZE(vertices14);
+    const UINT num_faces14 = ARRAY_SIZE(indices14) / VERTS_PER_FACE;
+    DWORD flags14 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons14 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 254.0f/255.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency14[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_color exp_vertices14[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+
+        {{ 2.0f,  3.0f,  0.f}, 0x00000000},
+        {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+    };
+    const DWORD exp_indices14[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap14[] = {0, 1};
+    const DWORD exp_vertex_remap14[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices14 = ARRAY_SIZE(exp_vertices14);
+    /* Test 15. Weld with color, but as UBYTE4N instead of D3DCOLOR. It shows
+     * that UBYTE4N and D3DCOLOR are compared the same way.
+     */
+    const struct vertex_color_ubyte4 vertices15[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
+        {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
+        {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
+
+        {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
+        {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
+        {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
+    };
+    const DWORD indices15[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes15[] = {0, 0};
+    const UINT num_vertices15 = ARRAY_SIZE(vertices15);
+    const UINT num_faces15 = ARRAY_SIZE(indices15) / VERTS_PER_FACE;
+    DWORD flags15 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons15 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 254.0f/255.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency15[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_color_ubyte4 exp_vertices15[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
+        {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
+        {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
+
+        {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
+        {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
+    };
+    const DWORD exp_indices15[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap15[] = {0, 1};
+    const DWORD exp_vertex_remap15[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices15 = ARRAY_SIZE(exp_vertices15);
+    /* Test 16. Weld with color, but as UBYTE4 instead of D3DCOLOR. It shows
+     * that UBYTE4 is not normalized and that epsilon is truncated and compared
+     * directly to each of the four bytes.
+     */
+    const struct vertex_color_ubyte4 vertices16[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
+        {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
+        {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
+
+        {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
+        {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
+        {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
+    };
+    const DWORD indices16[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes16[] = {0, 0};
+    const UINT num_vertices16 = ARRAY_SIZE(vertices16);
+    const UINT num_faces16 = ARRAY_SIZE(indices16) / VERTS_PER_FACE;
+    DWORD flags16 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons16 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 254.9f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency16[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_color_ubyte4 exp_vertices16[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
+        {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
+        {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
+
+        {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
+        {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
+    };
+    const DWORD exp_indices16[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap16[] = {0, 1};
+    const DWORD exp_vertex_remap16[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices16 = ARRAY_SIZE(exp_vertices16);
+    /* Test 17. Weld texture coordinates but as SHORT2 instead of D3DXVECTOR2.*/
+    const struct vertex_texcoord_short2 vertices17[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0}},
+        {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
+    };
+    const DWORD indices17[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes17[] = {0, 0};
+    const UINT num_vertices17 = ARRAY_SIZE(vertices17);
+    const UINT num_faces17 = ARRAY_SIZE(indices17) / VERTS_PER_FACE;
+    DWORD flags17 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons17 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {32766.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency17[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_texcoord_short2 exp_vertices17[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
+
+        {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0}},
+    };
+    const DWORD exp_indices17[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap17[] = {0, 1};
+    const DWORD exp_vertex_remap17[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices17 = ARRAY_SIZE(exp_vertices17);
+    /* Test 18. Weld texture coordinates but as SHORT2N instead of D3DXVECTOR2. */
+    const struct vertex_texcoord_short2 vertices18[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0}},
+        {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
+    };
+    const DWORD indices18[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes18[] = {0, 0};
+    const UINT num_vertices18 = ARRAY_SIZE(vertices18);
+    const UINT num_faces18 = ARRAY_SIZE(indices18) / VERTS_PER_FACE;
+    DWORD flags18 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons18 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {32766.0f/32767.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency18[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_texcoord_short2 exp_vertices18[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
+
+        {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0}},
+    };
+    const DWORD exp_indices18[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap18[] = {0, 1};
+    const DWORD exp_vertex_remap18[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices18 = ARRAY_SIZE(exp_vertices18);
+    /* Test 19.  Weld texture coordinates but as USHORT2N instead of D3DXVECTOR2. */
+    const struct vertex_texcoord_ushort2n vertices19[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {65535, 65535}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0}},
+        {{ 1.0f,  0.0f,  0.f}, {65534, 65534}},
+    };
+    const DWORD indices19[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes19[] = {0, 0};
+    const UINT num_vertices19 = ARRAY_SIZE(vertices19);
+    const UINT num_faces19 = ARRAY_SIZE(indices19) / VERTS_PER_FACE;
+    DWORD flags19 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons19 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {65534.0f/65535.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency19[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_texcoord_ushort2n exp_vertices19[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
+
+        {{ 2.0f,  3.0f,  0.f}, {65535, 65535}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0}},
+    };
+    const DWORD exp_indices19[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap19[] = {0, 1};
+    const DWORD exp_vertex_remap19[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices19 = ARRAY_SIZE(exp_vertices19);
+    /* Test 20.  Weld normal as SHORT4 instead of D3DXVECTOR3. */
+    const struct vertex_normal_short4 vertices20[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
+    };
+    const DWORD indices20[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes20[] = {0, 0};
+    const UINT num_vertices20 = ARRAY_SIZE(vertices20);
+    const UINT num_faces20 = ARRAY_SIZE(indices20) / VERTS_PER_FACE;
+    DWORD flags20 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons20 = {1.0f, 0.0f, 32766.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency20[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal_short4 exp_vertices20[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+
+        {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+    };
+    const DWORD exp_indices20[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap20[] = {0, 1};
+    const DWORD exp_vertex_remap20[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices20 = ARRAY_SIZE(exp_vertices20);
+    /* Test 21.  Weld normal as SHORT4N instead of D3DXVECTOR3. */
+    const struct vertex_normal_short4 vertices21[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
+    };
+    const DWORD indices21[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes21[] = {0, 0};
+    const UINT num_vertices21 = ARRAY_SIZE(vertices21);
+    const UINT num_faces21 = ARRAY_SIZE(indices21) / VERTS_PER_FACE;
+    DWORD flags21 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons21 = {1.0f, 0.0f, 32766.0f/32767.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency21[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal_short4 exp_vertices21[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+
+        {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+    };
+    const DWORD exp_indices21[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap21[] = {0, 1};
+    const DWORD exp_vertex_remap21[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices21 = ARRAY_SIZE(exp_vertices21);
+    /* Test 22.  Weld normal as USHORT4N instead of D3DXVECTOR3. */
+    const struct vertex_normal_short4 vertices22[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 1.0f,  0.0f,  0.f}, {65534, 65534, 65534, 65534}},
+    };
+    const DWORD indices22[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes22[] = {0, 0};
+    const UINT num_vertices22 = ARRAY_SIZE(vertices22);
+    const UINT num_faces22 = ARRAY_SIZE(indices22) / VERTS_PER_FACE;
+    DWORD flags22 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons22 = {1.0f, 0.0f, 65534.0f/65535.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency22[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal_short4 exp_vertices22[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+
+        {{ 2.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
+    };
+    const DWORD exp_indices22[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap22[] = {0, 1};
+    const DWORD exp_vertex_remap22[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices22 = ARRAY_SIZE(exp_vertices22);
+    /* Test 23. Weld texture coordinates as FLOAT16_2. Similar to test 11, but
+     * with texture coordinates converted to float16 in hex. */
+    const struct vertex_texcoord_float16_2 vertices23[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
+        {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
+        {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
+
+        {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
+        {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
+        {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
+    };
+    const DWORD indices23[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes23[] = {0, 0};
+    const UINT num_vertices23 = ARRAY_SIZE(vertices23);
+    const UINT num_faces23 = ARRAY_SIZE(indices23) / VERTS_PER_FACE;
+    DWORD flags23 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons23 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {0.41f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency23[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_texcoord_float16_2 exp_vertices23[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
+        {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
+        {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
+
+        {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
+        {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
+    };
+    const DWORD exp_indices23[] = {0, 1, 2, 1, 3, 4};
+    const DWORD exp_face_remap23[] = {0, 1};
+    const DWORD exp_vertex_remap23[] = {0, 1, 2, 4, 5, -1};
+    const DWORD exp_new_num_vertices23 = ARRAY_SIZE(exp_vertices23);
+    /* Test 24. Weld texture coordinates as FLOAT16_4. Similar to test 24. */
+    const struct vertex_texcoord_float16_4 vertices24[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
+        {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
+        {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0x3266, 0x34cd}},
+        {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
+        {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
+    };
+    const DWORD indices24[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes24[] = {0, 0};
+    const UINT num_vertices24 = ARRAY_SIZE(vertices24);
+    const UINT num_faces24 = ARRAY_SIZE(indices24) / VERTS_PER_FACE;
+    DWORD flags24 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons24 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {0.41f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency24[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_texcoord_float16_4 exp_vertices24[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
+        {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
+        {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
+
+        {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
+        {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
+    };
+    const DWORD exp_indices24[] = {0, 1, 2, 1, 3, 4};
+    const DWORD exp_face_remap24[] = {0, 1};
+    const DWORD exp_vertex_remap24[] = {0, 1, 2, 4, 5, -1};
+    const DWORD exp_new_num_vertices24 = ARRAY_SIZE(exp_vertices24);
+    /* Test 25. Weld texture coordinates with usage index 10 (TEXCOORD10). The
+     * usage index is capped at 7, so the epsilon for TEXCOORD7 is used instead.
+     */
+    const struct vertex_texcoord vertices25[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
+    };
+    const DWORD indices25[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes25[] = {0, 0};
+    const UINT num_vertices25 = ARRAY_SIZE(vertices25);
+    const UINT num_faces25 = ARRAY_SIZE(indices25) / VERTS_PER_FACE;
+    DWORD flags25 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons25 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f + FLT_EPSILON}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency25[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_texcoord exp_vertices25[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
+    };
+    const DWORD exp_indices25[] = {0, 1, 2, 1, 3, 4};
+    const DWORD exp_face_remap25[] = {0, 1};
+    const DWORD exp_vertex_remap25[] = {0, 1, 2, 4, 5, -1};
+    const DWORD exp_new_num_vertices25 = ARRAY_SIZE(exp_vertices25);
+    /* Test 26. Weld color with usage index larger than 1. Shows that none of
+     * the epsilon values are used. */
+    const struct vertex_color vertices26[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+
+        {{ 3.0f,  3.0f,  0.f}, 0x00000000},
+        {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+        {{ 1.0f,  0.0f,  0.f}, 0x01010101},
+    };
+    const DWORD indices26[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes26[] = {0, 0};
+    const UINT num_vertices26 = ARRAY_SIZE(vertices26);
+    const UINT num_faces26 = ARRAY_SIZE(indices26) / VERTS_PER_FACE;
+    DWORD flags26 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons26 = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, 1.0f, 1.0f, 1.0f};
+    const DWORD adjacency26[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_color exp_vertices26[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
+        {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+
+        {{ 2.0f,  3.0f,  0.f}, 0x00000000},
+        {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
+        {{ 0.0f,  0.0f,  0.f}, 0x01010101},
+    };
+    const DWORD exp_indices26[] = {0, 1, 2, 3, 4, 5};
+    const DWORD exp_face_remap26[] = {0, 1};
+    const DWORD exp_vertex_remap26[] = {0, 1, 2, 3, 4, 5};
+    const DWORD exp_new_num_vertices26 = ARRAY_SIZE(exp_vertices26);
+    /* Test 27. Weld color with usage index 1 (specular). */
+    /* Previously this test used float color values and index > 1 but that case
+     * appears to be effectively unhandled in native so the test gave
+     * inconsistent results. */
+    const struct vertex_color vertices27[] =
+    {
+        {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
+        {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
+        {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
+
+        {{ 3.0f,  3.0f,  0.0f}, 0x11213141},
+        {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
+        {{ 1.0f,  0.0f,  0.0f}, 0x51617181},
+    };
+    const DWORD indices27[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes27[] = {0, 0};
+    const UINT num_vertices27 = ARRAY_SIZE(vertices27);
+    const UINT num_faces27 = ARRAY_SIZE(indices27) / VERTS_PER_FACE;
+    DWORD flags27 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons27 =
+    {
+        1.1f, 0.0f, 0.0f, 0.0f, 2.0f / 255.0f, 0.0f,
+        {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f
+    };
+    const DWORD adjacency27[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_color exp_vertices27[] =
+    {
+        {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
+        {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
+        {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
+
+        {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
+    };
+    const DWORD exp_indices27[] = {0, 1, 2, 1, 3, 2};
+    const DWORD exp_face_remap27[] = {0, 1};
+    const DWORD exp_vertex_remap27[] = {0, 1, 2, 4, -1, -1};
+    const DWORD exp_new_num_vertices27 = ARRAY_SIZE(exp_vertices27);
+    /* Test 28. Weld one normal with UDEC3. */
+    const DWORD dword_udec3_zero = init_udec3_dword(0, 0, 0, 1);
+    const DWORD dword_udec3_1023 = init_udec3_dword(1023, 1023, 1023, 1);
+    const DWORD dword_udec3_1022 = init_udec3_dword(1022, 1022, 1022, 1);
+    const struct vertex_normal_udec3 vertices28[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
+        {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
+        {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
+
+        {{ 3.0f,  3.0f,  0.f}, dword_udec3_1023},
+        {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
+        {{ 1.0f,  0.0f,  0.f}, dword_udec3_1022},
+    };
+    const DWORD indices28[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes28[] = {0, 0};
+    const UINT num_vertices28 = ARRAY_SIZE(vertices28);
+    const UINT num_faces28 = ARRAY_SIZE(indices28) / VERTS_PER_FACE;
+    DWORD flags28 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons28 = {1.0f, 0.0f, 1022.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency28[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal_udec3 exp_vertices28[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
+        {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
+        {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
+
+        {{ 2.0f,  3.0f,  0.f}, dword_udec3_1023},
+        {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
+    };
+    const DWORD exp_indices28[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap28[] = {0, 1};
+    const DWORD exp_vertex_remap28[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices28 = ARRAY_SIZE(exp_vertices28);
+    /* Test 29. Weld one normal with DEC3N. */
+    const DWORD dword_dec3n_zero = init_dec3n_dword(0, 0, 0, 1);
+    const DWORD dword_dec3n_511 = init_dec3n_dword(511, 511, 511, 1);
+    const DWORD dword_dec3n_510 = init_dec3n_dword(510, 510, 510, 1);
+    const struct vertex_normal_dec3n vertices29[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
+        {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
+        {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
+
+        {{ 3.0f,  3.0f,  0.f}, dword_dec3n_511},
+        {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
+        {{ 1.0f,  0.0f,  0.f}, dword_dec3n_510},
+    };
+    const DWORD indices29[] = {0, 1, 2, 3, 4, 5};
+    const DWORD attributes29[] = {0, 0};
+    const UINT num_vertices29 = ARRAY_SIZE(vertices29);
+    const UINT num_faces29 = ARRAY_SIZE(indices29) / VERTS_PER_FACE;
+    DWORD flags29 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
+    const D3DXWELDEPSILONS epsilons29 = {1.0f, 0.0f, 510.0f/511.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, .0f}, 0.0f, 0.0f, 0.0f};
+    const DWORD adjacency29[] = {-1, 1, -1, -1, -1, 0};
+    const struct vertex_normal_dec3n exp_vertices29[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
+        {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
+        {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
+
+        {{ 2.0f,  3.0f,  0.f}, dword_dec3n_511},
+        {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
+    };
+    const DWORD exp_indices29[] = {0, 1, 2, 3, 4, 2};
+    const DWORD exp_face_remap29[] = {0, 1};
+    const DWORD exp_vertex_remap29[] = {0, 1, 2, 3, 4, -1};
+    const DWORD exp_new_num_vertices29 = ARRAY_SIZE(exp_vertices29);
+    /* All mesh data */
+    DWORD *adjacency_out = NULL;
+    DWORD *face_remap = NULL;
+    ID3DXMesh *mesh = NULL;
+    ID3DXBuffer *vertex_remap = NULL;
+    struct
+    {
+        const BYTE *vertices;
+        const DWORD *indices;
+        const DWORD *attributes;
+        const DWORD num_vertices;
+        const DWORD num_faces;
+        const DWORD options;
+        D3DVERTEXELEMENT9 *declaration;
+        const UINT vertex_size;
+        const DWORD flags;
+        const D3DXWELDEPSILONS *epsilons;
+        const DWORD *adjacency;
+        const BYTE *exp_vertices;
+        const DWORD *exp_indices;
+        const DWORD *exp_face_remap;
+        const DWORD *exp_vertex_remap;
+        const DWORD exp_new_num_vertices;
+    }
+    tc[] =
+    {
+        {
+            (BYTE*)vertices0,
+            indices0,
+            attributes0,
+            num_vertices0,
+            num_faces0,
+            options,
+            declaration_normal,
+            vertex_size_normal,
+            flags0,
+            NULL,
+            adjacency0,
+            (BYTE*)exp_vertices0,
+            exp_indices0,
+            exp_face_remap0,
+            exp_vertex_remap0,
+            exp_new_num_vertices0
+        },
+        {
+            (BYTE*)vertices1,
+            indices1,
+            attributes1,
+            num_vertices1,
+            num_faces1,
+            options,
+            declaration_normal,
+            vertex_size_normal,
+            flags1,
+            NULL,
+            adjacency1,
+            (BYTE*)exp_vertices1,
+            exp_indices1,
+            exp_face_remap1,
+            exp_vertex_remap1,
+            exp_new_num_vertices1
+        },
+        {
+            (BYTE*)vertices2,
+            indices2,
+            attributes2,
+            num_vertices2,
+            num_faces2,
+            options,
+            declaration_normal,
+            vertex_size_normal,
+            flags2,
+            &epsilons2,
+            adjacency2,
+            (BYTE*)exp_vertices2,
+            exp_indices2,
+            exp_face_remap2,
+            exp_vertex_remap2,
+            exp_new_num_vertices2
+        },
+        {
+            (BYTE*)vertices3,
+            indices3,
+            attributes3,
+            num_vertices3,
+            num_faces3,
+            options,
+            declaration_normal,
+            vertex_size_normal,
+            flags3,
+            &epsilons3,
+            adjacency3,
+            (BYTE*)exp_vertices3,
+            exp_indices3,
+            exp_face_remap3,
+            exp_vertex_remap3,
+            exp_new_num_vertices3
+        },
+        {
+            (BYTE*)vertices4,
+            indices4,
+            attributes4,
+            num_vertices4,
+            num_faces4,
+            options,
+            declaration_normal,
+            vertex_size_normal,
+            flags4,
+            &epsilons4,
+            adjacency4,
+            (BYTE*)exp_vertices4,
+            exp_indices4,
+            exp_face_remap4,
+            exp_vertex_remap4,
+            exp_new_num_vertices4
+        },
+        /* Unusual ordering. */
+        {
+            (BYTE*)vertices5,
+            indices5,
+            attributes5,
+            num_vertices5,
+            num_faces5,
+            options,
+            declaration_normal,
+            vertex_size_normal,
+            flags5,
+            NULL,
+            adjacency5,
+            (BYTE*)exp_vertices5,
+            exp_indices5,
+            exp_face_remap5,
+            exp_vertex_remap5,
+            exp_new_num_vertices5
+        },
+        {
+            (BYTE*)vertices6,
+            indices6,
+            attributes6,
+            num_vertices6,
+            num_faces6,
+            options,
+            declaration_normal,
+            vertex_size_normal,
+            flags6,
+            &epsilons6,
+            adjacency6,
+            (BYTE*)exp_vertices6,
+            exp_indices6,
+            exp_face_remap6,
+            exp_vertex_remap6,
+            exp_new_num_vertices6
+        },
+        {
+            (BYTE*)vertices6,
+            (DWORD*)indices6_16bit,
+            attributes6,
+            num_vertices6,
+            num_faces6,
+            options_16bit,
+            declaration_normal,
+            vertex_size_normal,
+            flags6,
+            &epsilons6,
+            adjacency6,
+            (BYTE*)exp_vertices6,
+            exp_indices6,
+            exp_face_remap6,
+            exp_vertex_remap6,
+            exp_new_num_vertices6
+        },
+        {
+            (BYTE*)vertices8,
+            indices8,
+            attributes8,
+            num_vertices8,
+            num_faces8,
+            options,
+            declaration_normal,
+            vertex_size_normal,
+            flags8,
+            &epsilons8,
+            adjacency8,
+            (BYTE*)exp_vertices8,
+            exp_indices8,
+            exp_face_remap8,
+            exp_vertex_remap8,
+            exp_new_num_vertices8
+        },
+        {
+            (BYTE*)vertices9,
+            indices9,
+            attributes9,
+            num_vertices9,
+            num_faces9,
+            options,
+            declaration_normal,
+            vertex_size_normal,
+            flags9,
+            &epsilons9,
+            adjacency9,
+            (BYTE*)exp_vertices9,
+            exp_indices9,
+            exp_face_remap9,
+            exp_vertex_remap9,
+            exp_new_num_vertices9
+        },
+        {
+            (BYTE*)vertices10,
+            indices10,
+            attributes10,
+            num_vertices10,
+            num_faces10,
+            options,
+            declaration_blendweight,
+            vertex_size_blendweight,
+            flags10,
+            &epsilons10,
+            adjacency10,
+            (BYTE*)exp_vertices10,
+            exp_indices10,
+            exp_face_remap10,
+            exp_vertex_remap10,
+            exp_new_num_vertices10
+        },
+        {
+            (BYTE*)vertices11,
+            indices11,
+            attributes11,
+            num_vertices11,
+            num_faces11,
+            options,
+            declaration_texcoord,
+            vertex_size_texcoord,
+            flags11,
+            &epsilons11,
+            adjacency11,
+            (BYTE*)exp_vertices11,
+            exp_indices11,
+            exp_face_remap11,
+            exp_vertex_remap11,
+            exp_new_num_vertices11
+        },
+        {
+            (BYTE*)vertices12,
+            indices12,
+            attributes12,
+            num_vertices12,
+            num_faces12,
+            options,
+            declaration_color,
+            vertex_size_color,
+            flags12,
+            &epsilons12,
+            adjacency12,
+            (BYTE*)exp_vertices12,
+            exp_indices12,
+            exp_face_remap12,
+            exp_vertex_remap12,
+            exp_new_num_vertices12
+        },
+        {
+            (BYTE*)vertices13,
+            indices13,
+            attributes13,
+            num_vertices13,
+            num_faces13,
+            options,
+            declaration_normal3,
+            vertex_size_normal,
+            flags13,
+            &epsilons13,
+            adjacency13,
+            (BYTE*)exp_vertices13,
+            exp_indices13,
+            exp_face_remap13,
+            exp_vertex_remap13,
+            exp_new_num_vertices13
+        },
+        {
+            (BYTE*)vertices14,
+            indices14,
+            attributes14,
+            num_vertices14,
+            num_faces14,
+            options,
+            declaration_color,
+            vertex_size_color,
+            flags14,
+            &epsilons14,
+            adjacency14,
+            (BYTE*)exp_vertices14,
+            exp_indices14,
+            exp_face_remap14,
+            exp_vertex_remap14,
+            exp_new_num_vertices14
+        },
+        {
+            (BYTE*)vertices15,
+            indices15,
+            attributes15,
+            num_vertices15,
+            num_faces15,
+            options,
+            declaration_color_ubyte4n,
+            vertex_size_color_ubyte4, /* UBYTE4 same size as UBYTE4N */
+            flags15,
+            &epsilons15,
+            adjacency15,
+            (BYTE*)exp_vertices15,
+            exp_indices15,
+            exp_face_remap15,
+            exp_vertex_remap15,
+            exp_new_num_vertices15
+        },
+        {
+            (BYTE*)vertices16,
+            indices16,
+            attributes16,
+            num_vertices16,
+            num_faces16,
+            options,
+            declaration_color_ubyte4,
+            vertex_size_color_ubyte4,
+            flags16,
+            &epsilons16,
+            adjacency16,
+            (BYTE*)exp_vertices16,
+            exp_indices16,
+            exp_face_remap16,
+            exp_vertex_remap16,
+            exp_new_num_vertices16
+        },
+        {
+            (BYTE*)vertices17,
+            indices17,
+            attributes17,
+            num_vertices17,
+            num_faces17,
+            options,
+            declaration_texcoord_short2,
+            vertex_size_texcoord_short2,
+            flags17,
+            &epsilons17,
+            adjacency17,
+            (BYTE*)exp_vertices17,
+            exp_indices17,
+            exp_face_remap17,
+            exp_vertex_remap17,
+            exp_new_num_vertices17
+        },
+        {
+            (BYTE*)vertices18,
+            indices18,
+            attributes18,
+            num_vertices18,
+            num_faces18,
+            options,
+            declaration_texcoord_short2n,
+            vertex_size_texcoord_short2, /* SHORT2 same size as SHORT2N */
+            flags18,
+            &epsilons18,
+            adjacency18,
+            (BYTE*)exp_vertices18,
+            exp_indices18,
+            exp_face_remap18,
+            exp_vertex_remap18,
+            exp_new_num_vertices18
+        },
+        {
+            (BYTE*)vertices19,
+            indices19,
+            attributes19,
+            num_vertices19,
+            num_faces19,
+            options,
+            declaration_texcoord_ushort2n,
+            vertex_size_texcoord_short2, /* SHORT2 same size as USHORT2N */
+            flags19,
+            &epsilons19,
+            adjacency19,
+            (BYTE*)exp_vertices19,
+            exp_indices19,
+            exp_face_remap19,
+            exp_vertex_remap19,
+            exp_new_num_vertices19
+        },
+        {
+            (BYTE*)vertices20,
+            indices20,
+            attributes20,
+            num_vertices20,
+            num_faces20,
+            options,
+            declaration_normal_short4,
+            vertex_size_normal_short4,
+            flags20,
+            &epsilons20,
+            adjacency20,
+            (BYTE*)exp_vertices20,
+            exp_indices20,
+            exp_face_remap20,
+            exp_vertex_remap20,
+            exp_new_num_vertices20
+        },
+        {
+            (BYTE*)vertices21,
+            indices21,
+            attributes21,
+            num_vertices21,
+            num_faces21,
+            options,
+            declaration_normal_short4n,
+            vertex_size_normal_short4, /* SHORT4 same size as SHORT4N */
+            flags21,
+            &epsilons21,
+            adjacency21,
+            (BYTE*)exp_vertices21,
+            exp_indices21,
+            exp_face_remap21,
+            exp_vertex_remap21,
+            exp_new_num_vertices21
+        },
+        {
+            (BYTE*)vertices22,
+            indices22,
+            attributes22,
+            num_vertices22,
+            num_faces22,
+            options,
+            declaration_normal_ushort4n,
+            vertex_size_normal_short4, /* SHORT4 same size as USHORT4N */
+            flags22,
+            &epsilons22,
+            adjacency22,
+            (BYTE*)exp_vertices22,
+            exp_indices22,
+            exp_face_remap22,
+            exp_vertex_remap22,
+            exp_new_num_vertices22
+        },
+        {
+            (BYTE*)vertices23,
+            indices23,
+            attributes23,
+            num_vertices23,
+            num_faces23,
+            options,
+            declaration_texcoord_float16_2,
+            vertex_size_texcoord_float16_2,
+            flags23,
+            &epsilons23,
+            adjacency23,
+            (BYTE*)exp_vertices23,
+            exp_indices23,
+            exp_face_remap23,
+            exp_vertex_remap23,
+            exp_new_num_vertices23
+        },
+        {
+            (BYTE*)vertices24,
+            indices24,
+            attributes24,
+            num_vertices24,
+            num_faces24,
+            options,
+            declaration_texcoord_float16_4,
+            vertex_size_texcoord_float16_4,
+            flags24,
+            &epsilons24,
+            adjacency24,
+            (BYTE*)exp_vertices24,
+            exp_indices24,
+            exp_face_remap24,
+            exp_vertex_remap24,
+            exp_new_num_vertices24
+        },
+        {
+            (BYTE*)vertices25,
+            indices25,
+            attributes25,
+            num_vertices25,
+            num_faces25,
+            options,
+            declaration_texcoord10,
+            vertex_size_texcoord,
+            flags25,
+            &epsilons25,
+            adjacency25,
+            (BYTE*)exp_vertices25,
+            exp_indices25,
+            exp_face_remap25,
+            exp_vertex_remap25,
+            exp_new_num_vertices25
+        },
+        {
+            (BYTE*)vertices26,
+            indices26,
+            attributes26,
+            num_vertices26,
+            num_faces26,
+            options,
+            declaration_color2,
+            vertex_size_color,
+            flags26,
+            &epsilons26,
+            adjacency26,
+            (BYTE*)exp_vertices26,
+            exp_indices26,
+            exp_face_remap26,
+            exp_vertex_remap26,
+            exp_new_num_vertices26
+        },
+        {
+            (BYTE*)vertices27,
+            indices27,
+            attributes27,
+            num_vertices27,
+            num_faces27,
+            options,
+            declaration_color1,
+            vertex_size_color,
+            flags27,
+            &epsilons27,
+            adjacency27,
+            (BYTE*)exp_vertices27,
+            exp_indices27,
+            exp_face_remap27,
+            exp_vertex_remap27,
+            exp_new_num_vertices27
+        },
+        {
+            (BYTE*)vertices28,
+            indices28,
+            attributes28,
+            num_vertices28,
+            num_faces28,
+            options,
+            declaration_normal_udec3,
+            vertex_size_normal_udec3,
+            flags28,
+            &epsilons28,
+            adjacency28,
+            (BYTE*)exp_vertices28,
+            exp_indices28,
+            exp_face_remap28,
+            exp_vertex_remap28,
+            exp_new_num_vertices28
+        },
+        {
+            (BYTE*)vertices29,
+            indices29,
+            attributes29,
+            num_vertices29,
+            num_faces29,
+            options,
+            declaration_normal_dec3n,
+            vertex_size_normal_dec3n,
+            flags29,
+            &epsilons29,
+            adjacency29,
+            (BYTE*)exp_vertices29,
+            exp_indices29,
+            exp_face_remap29,
+            exp_vertex_remap29,
+            exp_new_num_vertices29
+        }
+    };
+#ifdef __REACTOS__
+#undef up
+#endif
+
+    test_context = new_test_context();
+    if (!test_context)
+    {
+        skip("Couldn't create test context\n");
+        goto cleanup;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(tc); i++)
+    {
+        DWORD j;
+        DWORD *vertex_remap_ptr;
+        DWORD new_num_vertices;
+
+        hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
+                            tc[i].declaration, test_context->device, &mesh,
+                            tc[i].vertices, tc[i].vertex_size,
+                            tc[i].indices, tc[i].attributes);
+        if (FAILED(hr))
+        {
+            skip("Couldn't initialize test mesh %d.\n", i);
+            goto cleanup;
+        }
+
+        /* Allocate out parameters */
+        adjacency_out = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency_out));
+        if (!adjacency_out)
+        {
+            skip("Couldn't allocate adjacency_out array.\n");
+            goto cleanup;
+        }
+        face_remap = HeapAlloc(GetProcessHeap(), 0, tc[i].num_faces * sizeof(*face_remap));
+        if (!face_remap)
+        {
+            skip("Couldn't allocate face_remap array.\n");
+            goto cleanup;
+        }
+
+        hr = D3DXWeldVertices(mesh, tc[i].flags, tc[i].epsilons, tc[i].adjacency,
+                              adjacency_out, face_remap, &vertex_remap);
+        ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
+        /* Check number of vertices*/
+        new_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
+        ok(new_num_vertices == tc[i].exp_new_num_vertices,
+           "Mesh %d: new_num_vertices == %d, expected %d.\n",
+           i, new_num_vertices, tc[i].exp_new_num_vertices);
+        /* Check index buffer */
+        if (tc[i].options & D3DXMESH_32BIT)
+        {
+            hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices);
+            if (FAILED(hr))
+            {
+                skip("Couldn't lock index buffer.\n");
+                goto cleanup;
+            }
+            for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
+            {
+                ok(indices[j] == tc[i].exp_indices[j],
+                   "Mesh %d: indices[%d] == %d, expected %d\n",
+                   i, j, indices[j], tc[i].exp_indices[j]);
+            }
+        }
+        else
+        {
+            hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices_16bit);
+            if (FAILED(hr))
+            {
+                skip("Couldn't lock index buffer.\n");
+                goto cleanup;
+            }
+            for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
+            {
+                ok(indices_16bit[j] == tc[i].exp_indices[j],
+                   "Mesh %d: indices_16bit[%d] == %d, expected %d\n",
+                   i, j, indices_16bit[j], tc[i].exp_indices[j]);
+            }
+        }
+        mesh->lpVtbl->UnlockIndexBuffer(mesh);
+        indices = NULL;
+        indices_16bit = NULL;
+        /* Check adjacency_out */
+        for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
+        {
+            ok(adjacency_out[j] == tc[i].adjacency[j],
+               "Mesh %d: adjacency_out[%d] == %d, expected %d\n",
+               i, j, adjacency_out[j], tc[i].adjacency[j]);
+        }
+        /* Check face_remap */
+        for (j = 0; j < tc[i].num_faces; j++)
+        {
+            ok(face_remap[j] == tc[i].exp_face_remap[j],
+               "Mesh %d: face_remap[%d] == %d, expected %d\n",
+               i, j, face_remap[j], tc[i].exp_face_remap[j]);
+        }
+        /* Check vertex_remap */
+        vertex_remap_ptr = vertex_remap->lpVtbl->GetBufferPointer(vertex_remap);
+        for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
+        {
+            ok(vertex_remap_ptr[j] == tc[i].exp_vertex_remap[j],
+               "Mesh %d: vertex_remap_ptr[%d] == %d, expected %d\n",
+               i, j, vertex_remap_ptr[j], tc[i].exp_vertex_remap[j]);
+        }
+        /* Check vertex buffer */
+        hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void*)&vertices);
+        if (FAILED(hr))
+        {
+            skip("Couldn't lock vertex buffer.\n");
+            goto cleanup;
+        }
+        /* Check contents of re-ordered vertex buffer */
+        for (j = 0; j < tc[i].exp_new_num_vertices; j++)
+        {
+            int index = tc[i].vertex_size*j;
+            check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].declaration);
+        }
+        mesh->lpVtbl->UnlockVertexBuffer(mesh);
+        vertices = NULL;
+
+        /* Free mesh and output data */
+        HeapFree(GetProcessHeap(), 0, adjacency_out);
+        adjacency_out = NULL;
+        HeapFree(GetProcessHeap(), 0, face_remap);
+        face_remap = NULL;
+        vertex_remap->lpVtbl->Release(vertex_remap);
+        vertex_remap = NULL;
+        mesh->lpVtbl->Release(mesh);
+        mesh = NULL;
+    }
+
+cleanup:
+    HeapFree(GetProcessHeap(), 0, adjacency_out);
+    HeapFree(GetProcessHeap(), 0, face_remap);
+    if (indices) mesh->lpVtbl->UnlockIndexBuffer(mesh);
+    if (indices_16bit) mesh->lpVtbl->UnlockIndexBuffer(mesh);
+    if (mesh) mesh->lpVtbl->Release(mesh);
+    if (vertex_remap) vertex_remap->lpVtbl->Release(vertex_remap);
+    if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
+    free_test_context(test_context);
+}
+
+static void test_clone_mesh(void)
+{
+    HRESULT hr;
+    struct test_context *test_context = NULL;
+    const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
+    D3DVERTEXELEMENT9 declaration_pn[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_pntc[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptcn[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        {0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_float16_2[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_float16_4[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_float1[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_float3[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_float4[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_d3dcolor[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_ubyte4[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_ubyte4n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_short2[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_short4[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_short2n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_short4n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_ushort2n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_ushort4n[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_ptc_float16_2_partialu[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_PARTIALU, D3DDECLUSAGE_TEXCOORD, 0},
+        D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_pntc1[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
+        D3DDECL_END()
+    };
+    const unsigned int VERTS_PER_FACE = 3;
+    BYTE *vertices = NULL;
+    INT i;
+    struct vertex_pn
+    {
+        D3DXVECTOR3 position;
+        D3DXVECTOR3 normal;
+    };
+    struct vertex_pntc
+    {
+        D3DXVECTOR3 position;
+        D3DXVECTOR3 normal;
+        D3DXVECTOR2 texcoords;
+    };
+    struct vertex_ptcn
+    {
+        D3DXVECTOR3 position;
+        D3DXVECTOR2 texcoords;
+        D3DXVECTOR3 normal;
+    };
+    struct vertex_ptc
+    {
+        D3DXVECTOR3 position;
+        D3DXVECTOR2 texcoords;
+    };
+    struct vertex_ptc_float16_2
+    {
+        D3DXVECTOR3 position;
+        WORD texcoords[2]; /* float16_2 */
+    };
+    struct vertex_ptc_float16_4
+    {
+        D3DXVECTOR3 position;
+        WORD texcoords[4]; /* float16_4 */
+    };
+    struct vertex_ptc_float1
+    {
+        D3DXVECTOR3 position;
+        FLOAT texcoords;
+    };
+    struct vertex_ptc_float3
+    {
+        D3DXVECTOR3 position;
+        FLOAT texcoords[3];
+    };
+    struct vertex_ptc_float4
+    {
+        D3DXVECTOR3 position;
+        FLOAT texcoords[4];
+    };
+    struct vertex_ptc_d3dcolor
+    {
+        D3DXVECTOR3 position;
+        BYTE texcoords[4];
+    };
+    struct vertex_ptc_ubyte4
+    {
+        D3DXVECTOR3 position;
+        BYTE texcoords[4];
+    };
+    struct vertex_ptc_ubyte4n
+    {
+        D3DXVECTOR3 position;
+        BYTE texcoords[4];
+    };
+    struct vertex_ptc_short2
+    {
+        D3DXVECTOR3 position;
+        SHORT texcoords[2];
+    };
+    struct vertex_ptc_short4
+    {
+        D3DXVECTOR3 position;
+        SHORT texcoords[4];
+    };
+    struct vertex_ptc_ushort2n
+    {
+        D3DXVECTOR3 position;
+        USHORT texcoords[2];
+    };
+    struct vertex_ptc_ushort4n
+    {
+        D3DXVECTOR3 position;
+        USHORT texcoords[4];
+    };
+    struct vertex_ptc_udec3
+    {
+        D3DXVECTOR3 position;
+        DWORD texcoords;
+    };
+    struct vertex_ptc_dec3n
+    {
+        D3DXVECTOR3 position;
+        DWORD texcoords;
+    };
+#ifndef __REACTOS__
+    D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
+    D3DXVECTOR2 zero_vec2 = {0.0f, 0.0f};
+#else
+#define up {0.0f, 0.0f, 1.0f}
+#define zero_vec2 {0.0f, 0.0f}
+#endif
+    /* Test 0. Check that a mesh can be cloned if the new declaration is the
+     * same as the one used to create the mesh.
+     *
+     * 0--1 3
+     * | / /|
+     * |/ / |
+     * 2 5--4
+     */
+    const struct vertex_pn vertices0[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+
+        {{ 3.0f,  3.0f,  0.f}, up},
+        {{ 3.0f,  0.0f,  0.f}, up},
+        {{ 1.0f,  0.0f,  0.f}, up},
+    };
+    const UINT num_vertices0 = ARRAY_SIZE(vertices0);
+    const UINT num_faces0 = ARRAY_SIZE(vertices0) / VERTS_PER_FACE;
+    const UINT vertex_size0 = sizeof(*vertices0);
+    /* Test 1. Check that 16-bit indices are handled. */
+    const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
+    /* Test 2. Check that the size of each vertex is increased and the data
+     * moved if the new declaration adds an element after the original elements.
+     */
+    const struct vertex_pntc exp_vertices2[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
+        {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
+        {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
+
+        {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
+        {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
+        {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
+    };
+    const UINT exp_vertex_size2 = sizeof(*exp_vertices2);
+    /* Test 3. Check that the size of each vertex is increased and the data
+     * moved if the new declaration adds an element between the original
+     * elements.
+     */
+    const struct vertex_ptcn exp_vertices3[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, zero_vec2, up},
+        {{ 2.0f,  3.0f,  0.f}, zero_vec2, up},
+        {{ 0.0f,  0.0f,  0.f}, zero_vec2, up},
+
+        {{ 3.0f,  3.0f,  0.f}, zero_vec2, up},
+        {{ 3.0f,  0.0f,  0.f}, zero_vec2, up},
+        {{ 1.0f,  0.0f,  0.f}, zero_vec2, up},
+    };
+    const UINT exp_vertex_size3 = sizeof(*exp_vertices3);
+    /* Test 4. Test that data types can be converted, e.g. FLOAT2 to FLOAT16_2. */
+    const struct vertex_ptc vertices4[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
+    };
+    const UINT num_vertices4 = ARRAY_SIZE(vertices4);
+    const UINT num_faces4 = ARRAY_SIZE(vertices4) / VERTS_PER_FACE;
+    const UINT vertex_size4 = sizeof(*vertices4);
+    const struct vertex_ptc_float16_2 exp_vertices4[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
+        {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
+        {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
+
+        {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
+        {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
+        {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
+    };
+    const UINT exp_vertex_size4 = sizeof(*exp_vertices4);
+    /* Test 5. Convert FLOAT2 to FLOAT16_4. */
+    const struct vertex_ptc vertices5[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
+    };
+    const UINT num_vertices5 = ARRAY_SIZE(vertices5);
+    const UINT num_faces5 = ARRAY_SIZE(vertices5) / VERTS_PER_FACE;
+    const UINT vertex_size5 = sizeof(*vertices5);
+    const struct vertex_ptc_float16_4 exp_vertices5[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
+        {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0, 0x3c00}}, /* {0.5f, 0.7f, 0.0f, 1.0f} */
+        {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0, 0x3c00}}, /* {-0.2f, -0.3f, 0.0f, 1.0f} */
+
+        {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0, 0x3c00}}, /* {0.2f, 0.3f, 0.0f, 1.0f} */
+        {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
+        {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0, 0x3c00}}, /* {0.1f, 0.2f, 0.0f, 1.0f} */
+    };
+    const UINT exp_vertex_size5 = sizeof(*exp_vertices5);
+    /* Test 6. Convert FLOAT2 to FLOAT1. */
+    const struct vertex_ptc vertices6[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
+    };
+    const UINT num_vertices6 = ARRAY_SIZE(vertices6);
+    const UINT num_faces6 = ARRAY_SIZE(vertices6) / VERTS_PER_FACE;
+    const UINT vertex_size6 = sizeof(*vertices6);
+    const struct vertex_ptc_float1 exp_vertices6[] =
+    {
+        {{ 0.0f,  3.0f,  0.f},  1.0f},
+        {{ 2.0f,  3.0f,  0.f},  0.5f},
+        {{ 0.0f,  0.0f,  0.f}, -0.2f},
+
+        {{ 3.0f,  3.0f,  0.f},  0.2f},
+        {{ 3.0f,  0.0f,  0.f},  1.0f},
+        {{ 1.0f,  0.0f,  0.f},  0.1f},
+    };
+    const UINT exp_vertex_size6 = sizeof(*exp_vertices6);
+    /* Test 7. Convert FLOAT2 to FLOAT3. */
+    const struct vertex_ptc vertices7[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
+    };
+    const UINT num_vertices7 = ARRAY_SIZE(vertices7);
+    const UINT num_faces7 = ARRAY_SIZE(vertices7) / VERTS_PER_FACE;
+    const UINT vertex_size7 = sizeof(*vertices7);
+    const struct vertex_ptc_float3 exp_vertices7[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f}},
+    };
+    const UINT exp_vertex_size7 = sizeof(*exp_vertices7);
+    /* Test 8. Convert FLOAT2 to FLOAT4. */
+    const struct vertex_ptc vertices8[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
+    };
+    const UINT num_vertices8 = ARRAY_SIZE(vertices8);
+    const UINT num_faces8 = ARRAY_SIZE(vertices8) / VERTS_PER_FACE;
+    const UINT vertex_size8 = sizeof(*vertices8);
+    const struct vertex_ptc_float4 exp_vertices8[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f, 1.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f, 1.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f, 1.0f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f, 1.0f}},
+    };
+    const UINT exp_vertex_size8 = sizeof(*exp_vertices8);
+    /* Test 9. Convert FLOAT2 to D3DCOLOR. */
+    const struct vertex_ptc vertices9[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.6f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, { 2.0f, 256.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.11f,  0.2f}},
+    };
+    const UINT num_vertices9 = ARRAY_SIZE(vertices9);
+    const UINT num_faces9 = ARRAY_SIZE(vertices9) / VERTS_PER_FACE;
+    const UINT vertex_size9 = sizeof(*vertices9);
+    const struct vertex_ptc_d3dcolor exp_vertices9[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 255, 255, 255}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 179, 128, 255}},
+        {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0, 77, 51, 255}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 255, 255, 255}},
+        {{ 1.0f,  0.0f,  0.f}, {0, 51, 28, 255}},
+    };
+    const UINT exp_vertex_size9 = sizeof(*exp_vertices9);
+    /* Test 10. Convert FLOAT2 to UBYTE4. */
+    const struct vertex_ptc vertices10[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 0.0f,  1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 2.0f,  3.0f}},
+        {{ 0.0f,  0.0f,  0.f}, { 254.0f,  255.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 256.0f, 257.0f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.4f, 1.5f}},
+        {{ 1.0f,  0.0f,  0.f}, {-4.0f, -5.0f}},
+    };
+    const UINT num_vertices10 = ARRAY_SIZE(vertices10);
+    const UINT num_faces10 = ARRAY_SIZE(vertices10) / VERTS_PER_FACE;
+    const UINT vertex_size10 = sizeof(*vertices10);
+    const struct vertex_ptc_ubyte4 exp_vertices10[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
+        {{ 2.0f,  3.0f,  0.f}, {2, 3, 0, 1}},
+        {{ 0.0f,  0.0f,  0.f}, {254, 255, 0, 1}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
+        {{ 3.0f,  0.0f,  0.f}, {1, 2, 0, 1}},
+        {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
+    };
+    const UINT exp_vertex_size10 = sizeof(*exp_vertices10);
+    /* Test 11. Convert FLOAT2 to SHORT2. */
+    const struct vertex_ptc vertices11[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
+        {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
+
+        {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
+        {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
+        {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
+    };
+    const UINT num_vertices11 = ARRAY_SIZE(vertices11);
+    const UINT num_faces11 = ARRAY_SIZE(vertices11) / VERTS_PER_FACE;
+    const UINT vertex_size11 = sizeof(*vertices11);
+    const struct vertex_ptc_short2 exp_vertices11[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 1}},
+        {{ 0.0f,  0.0f,  0.f}, {0, -4}},
+
+        {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1}},
+        {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN}},
+        {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
+
+        {{ 4.0f,  3.0f,  0.f}, {-2, 1}},
+        {{ 6.0f,  0.0f,  0.f}, {32765, -32767}},
+        {{ 4.0f,  0.0f,  0.f}, {-4, 1}},
+    };
+    const UINT exp_vertex_size11 = sizeof(*exp_vertices11);
+    /* Test 12. Convert FLOAT2 to SHORT4. */
+    const struct vertex_ptc vertices12[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
+        {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
+
+        {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
+        {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
+        {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
+    };
+    const UINT num_vertices12 = ARRAY_SIZE(vertices12);
+    const UINT num_faces12 = ARRAY_SIZE(vertices12) / VERTS_PER_FACE;
+    const UINT vertex_size12 = sizeof(*vertices12);
+    const struct vertex_ptc_short4 exp_vertices12[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
+        {{ 0.0f,  0.0f,  0.f}, {0, -4, 0, 1}},
+
+        {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1, 0, 1}},
+        {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN, 0, 1}},
+        {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, 0, 1}},
+
+        {{ 4.0f,  3.0f,  0.f}, {-2, 1, 0, 1}},
+        {{ 6.0f,  0.0f,  0.f}, {32765, -32767, 0, 1}},
+        {{ 4.0f,  0.0f,  0.f}, {-4, 1, 0, 1}},
+    };
+    const UINT exp_vertex_size12 = sizeof(*exp_vertices12);
+    /* Test 13. Convert FLOAT2 to UBYTE4N. */
+    const struct vertex_ptc vertices13[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f,  2.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.5f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {-0.6f,  -1.0f}},
+        {{ 3.0f,  0.0f,  0.f}, {UCHAR_MAX,  UCHAR_MAX + 1}},
+        {{ 1.0f,  0.0f,  0.f}, {2 * UCHAR_MAX, -UCHAR_MAX}},
+    };
+    const UINT num_vertices13 = ARRAY_SIZE(vertices13);
+    const UINT num_faces13 = ARRAY_SIZE(vertices13) / VERTS_PER_FACE;
+    const UINT vertex_size13 = sizeof(*vertices13);
+    const struct vertex_ptc_ubyte4n exp_vertices13[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {255, 255, 0, 255}},
+        {{ 2.0f,  3.0f,  0.f}, {128, 179, 0, 255}},
+        {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, 255}},
+        {{ 3.0f,  0.0f,  0.f}, {255, 255, 0, 255}},
+        {{ 1.0f,  0.0f,  0.f}, {255, 0, 0, 255}},
+    };
+    const UINT exp_vertex_size13 = sizeof(*exp_vertices13);
+    /* Test 14. Convert FLOAT2 to SHORT2N. */
+    const struct vertex_ptc vertices14[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
+        {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
+        {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
+    };
+    const UINT num_vertices14 = ARRAY_SIZE(vertices14);
+    const UINT num_faces14 = ARRAY_SIZE(vertices14) / VERTS_PER_FACE;
+    const UINT vertex_size14 = sizeof(*vertices14);
+    const struct vertex_ptc_short2 exp_vertices14[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX}},
+        {{ 2.0f,  3.0f,  0.f}, {13107, 16384}},
+        {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2}},
+
+        {{ 3.0f,  3.0f,  0.f}, {-13106, -16383}},
+        {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3}},
+        {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2}},
+    };
+    const UINT exp_vertex_size14 = sizeof(*exp_vertices14);
+    /* Test 15. Convert FLOAT2 to SHORT4N. */
+    const struct vertex_ptc vertices15[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
+        {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
+        {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
+    };
+    const UINT num_vertices15 = ARRAY_SIZE(vertices15);
+    const UINT num_faces15 = ARRAY_SIZE(vertices15) / VERTS_PER_FACE;
+    const UINT vertex_size15 = sizeof(*vertices15);
+    const struct vertex_ptc_short4 exp_vertices15[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX, 0, SHRT_MAX}},
+        {{ 2.0f,  3.0f,  0.f}, {13107, 16384, 0, SHRT_MAX}},
+        {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2, 0, SHRT_MAX}},
+
+        {{ 3.0f,  3.0f,  0.f}, {-13106, -16383, 0, SHRT_MAX}},
+        {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3, 0, SHRT_MAX}},
+        {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2, 0, SHRT_MAX}},
+    };
+    const UINT exp_vertex_size15 = sizeof(*exp_vertices15);
+    /* Test 16. Convert FLOAT2 to USHORT2N. */
+    const struct vertex_ptc vertices16[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
+        {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
+        {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
+    };
+    const UINT num_vertices16 = ARRAY_SIZE(vertices16);
+    const UINT num_faces16 = ARRAY_SIZE(vertices16) / VERTS_PER_FACE;
+    const UINT vertex_size16 = sizeof(*vertices16);
+    const struct vertex_ptc_ushort2n exp_vertices16[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX}},
+        {{ 2.0f,  3.0f,  0.f}, {26214, 32768}},
+        {{ 0.0f,  0.0f,  0.f}, {39321, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0, 0}},
+        {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1}},
+        {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0}},
+    };
+    const UINT exp_vertex_size16 = sizeof(*exp_vertices16);
+    /* Test 17. Convert FLOAT2 to USHORT4N. */
+    const struct vertex_ptc vertices17[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
+        {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
+        {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
+        {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
+    };
+    const UINT num_vertices17 = ARRAY_SIZE(vertices17);
+    const UINT num_faces17 = ARRAY_SIZE(vertices17) / VERTS_PER_FACE;
+    const UINT vertex_size17 = sizeof(*vertices17);
+    const struct vertex_ptc_ushort4n exp_vertices17[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX, 0, USHRT_MAX}},
+        {{ 2.0f,  3.0f,  0.f}, {26214, 32768, 0, USHRT_MAX}},
+        {{ 0.0f,  0.0f,  0.f}, {39321, 0, 0, USHRT_MAX}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, USHRT_MAX}},
+        {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1, 0, USHRT_MAX}},
+        {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0, 0, USHRT_MAX}},
+    };
+    const UINT exp_vertex_size17 = sizeof(*exp_vertices17);
+    /* Test 18. Test that the method field is compared by converting a FLOAT2 to
+     * FLOAT16_2. where the method field has been change from
+     * D3DDECLMETHOD_DEFAULT to D3DDECLMETHOD_PARTIALU. */
+    const struct vertex_ptc vertices18[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
+    };
+    const UINT num_vertices18 = ARRAY_SIZE(vertices18);
+    const UINT num_faces18 = ARRAY_SIZE(vertices18) / VERTS_PER_FACE;
+    const UINT vertex_size18 = sizeof(*vertices18);
+    const struct vertex_ptc_float16_2 exp_vertices18[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
+        {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
+        {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
+
+        {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
+        {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
+        {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
+    };
+    const UINT exp_vertex_size18 = sizeof(*exp_vertices18);
+    /* Test 19. Test that data is lost if usage index changes, e.g. TEXCOORD0
+     * TEXCOORD1. */
+    const struct vertex_pntc vertices19[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
+    };
+    const UINT num_vertices19 = ARRAY_SIZE(vertices19);
+    const UINT num_faces19 = ARRAY_SIZE(vertices19) / VERTS_PER_FACE;
+    const UINT vertex_size19 = sizeof(*vertices19);
+    const struct vertex_pntc exp_vertices19[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
+        {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
+        {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
+
+        {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
+        {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
+        {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
+    };
+    const UINT exp_vertex_size19 = sizeof(*exp_vertices19);
+    /* Test 20. Another test that data is lost if usage index changes, e.g.
+     * TEXCOORD1 to TEXCOORD0. */
+    const struct vertex_pntc vertices20[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
+        {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
+
+        {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
+        {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
+    };
+    const UINT num_vertices20 = ARRAY_SIZE(vertices20);
+    const UINT num_faces20 = ARRAY_SIZE(vertices20) / VERTS_PER_FACE;
+    const UINT vertex_size20 = sizeof(*vertices20);
+    const struct vertex_pntc exp_vertices20[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
+        {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
+        {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
+
+        {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
+        {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
+        {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
+    };
+    const UINT exp_vertex_size20 = sizeof(*exp_vertices20);
+    /* Test 21. Convert FLOAT1 to FLOAT2. */
+    const struct vertex_ptc_float1 vertices21[] =
+    {
+        {{ 0.0f,  3.0f,  0.f},  1.0f},
+        {{ 2.0f,  3.0f,  0.f},  0.5f},
+        {{ 0.0f,  0.0f,  0.f}, -0.2f},
+
+        {{ 3.0f,  3.0f,  0.f},  0.2f},
+        {{ 3.0f,  0.0f,  0.f},  1.0f},
+        {{ 1.0f,  0.0f,  0.f},  0.1f},
+    };
+    const UINT num_vertices21 = ARRAY_SIZE(vertices21);
+    const UINT num_faces21 = ARRAY_SIZE(vertices21) / VERTS_PER_FACE;
+    const UINT vertex_size21 = sizeof(*vertices21);
+    const struct vertex_ptc exp_vertices21[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f}},
+    };
+    const UINT exp_vertex_size21 = sizeof(*exp_vertices21);
+    /* Test 22. Convert FLOAT1 to FLOAT3. */
+    const struct vertex_ptc_float1 vertices22[] =
+    {
+        {{ 0.0f,  3.0f,  0.f},  1.0f},
+        {{ 2.0f,  3.0f,  0.f},  0.5f},
+        {{ 0.0f,  0.0f,  0.f}, -0.2f},
+
+        {{ 3.0f,  3.0f,  0.f},  0.2f},
+        {{ 3.0f,  0.0f,  0.f},  1.0f},
+        {{ 1.0f,  0.0f,  0.f},  0.1f},
+    };
+    const UINT num_vertices22 = ARRAY_SIZE(vertices22);
+    const UINT num_faces22 = ARRAY_SIZE(vertices22) / VERTS_PER_FACE;
+    const UINT vertex_size22 = sizeof(*vertices22);
+    const struct vertex_ptc_float3 exp_vertices22[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f}},
+    };
+    const UINT exp_vertex_size22 = sizeof(*exp_vertices22);
+    /* Test 23. Convert FLOAT1 to FLOAT4. */
+    const struct vertex_ptc_float1 vertices23[] =
+    {
+        {{ 0.0f,  3.0f,  0.f},  1.0f},
+        {{ 2.0f,  3.0f,  0.f},  0.5f},
+        {{ 0.0f,  0.0f,  0.f}, -0.2f},
+
+        {{ 3.0f,  3.0f,  0.f},  0.2f},
+        {{ 3.0f,  0.0f,  0.f},  1.0f},
+        {{ 1.0f,  0.0f,  0.f},  0.1f},
+    };
+    const UINT num_vertices23 = ARRAY_SIZE(vertices23);
+    const UINT num_faces23 = ARRAY_SIZE(vertices23) / VERTS_PER_FACE;
+    const UINT vertex_size23 = sizeof(*vertices23);
+    const struct vertex_ptc_float4 exp_vertices23[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f, 1.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f, 1.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f, 1.0f}},
+        {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f, 1.0f}},
+    };
+    const UINT exp_vertex_size23 = sizeof(*exp_vertices23);
+    /* Test 24. Convert FLOAT1 to D3DCOLOR. */
+    const struct vertex_ptc_float1 vertices24[] =
+    {
+        {{ 0.0f,  3.0f,  0.f},  1.0f},
+        {{ 2.0f,  3.0f,  0.f},  0.5f},
+        {{ 0.0f,  0.0f,  0.f}, -0.2f},
+
+        {{ 3.0f,  3.0f,  0.f},  0.2f},
+        {{ 3.0f,  0.0f,  0.f},  1.0f},
+        {{ 1.0f,  0.0f,  0.f},  0.11f},
+    };
+    const UINT num_vertices24 = ARRAY_SIZE(vertices24);
+    const UINT num_faces24 = ARRAY_SIZE(vertices24) / VERTS_PER_FACE;
+    const UINT vertex_size24 = sizeof(*vertices24);
+    const struct vertex_ptc_d3dcolor exp_vertices24[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 255, 255}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 0, 128, 255}},
+        {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0, 0, 51, 255}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0, 255, 255}},
+        {{ 1.0f,  0.0f,  0.f}, {0, 0, 28, 255}},
+    };
+    const UINT exp_vertex_size24 = sizeof(*exp_vertices24);
+    /* Test 25. Convert FLOAT1 to ubyte4. */
+    const struct vertex_ptc_float1 vertices25[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, 0.0f},
+        {{ 2.0f,  3.0f,  0.f}, 1.4f},
+        {{ 0.0f,  0.0f,  0.f}, 1.5f},
+
+        {{ 3.0f,  3.0f,  0.f}, 255.0f},
+        {{ 3.0f,  0.0f,  0.f}, 256.0f},
+        {{ 1.0f,  0.0f,  0.f}, -1.0f},
+    };
+    const UINT num_vertices25 = ARRAY_SIZE(vertices25);
+    const UINT num_faces25 = ARRAY_SIZE(vertices25) / VERTS_PER_FACE;
+    const UINT vertex_size25 = sizeof(*vertices25);
+    const struct vertex_ptc_ubyte4 exp_vertices25[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 1}},
+        {{ 2.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
+        {{ 0.0f,  0.0f,  0.f}, {2, 0, 0, 1}},
+
+        {{ 3.0f,  3.0f,  0.f}, {255, 0, 0, 1}},
+        {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
+        {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
+    };
+    const UINT exp_vertex_size25 = sizeof(*exp_vertices25);
+    /* Test 26. Convert FLOAT4 to D3DCOLOR. */
+    const struct vertex_ptc_float4 vertices26[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.5f}},
+        {{ 2.0f,  3.0f,  0.f}, {-0.4f, -0.5f, -1.0f, -2.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {254.0f, 255.0f, 256.0f, 257.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.1f, 0.2f, 0.3f, 0.4f}},
+        {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.6f, 0.7f, 0.8f}},
+        {{ 1.0f,  0.0f,  0.f}, {0.9f, 0.99f, 0.995f, 0.999f}},
+    };
+    const UINT num_vertices26 = ARRAY_SIZE(vertices26);
+    const UINT num_faces26 = ARRAY_SIZE(vertices26) / VERTS_PER_FACE;
+    const UINT vertex_size26 = sizeof(*vertices26);
+    const struct vertex_ptc_d3dcolor exp_vertices26[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
+
+        {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
+        {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
+        {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
+    };
+    const UINT exp_vertex_size26 = sizeof(*exp_vertices26);
+    /* Test 27. Convert D3DCOLOR to FLOAT4. */
+    const struct vertex_ptc_d3dcolor vertices27[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
+
+        {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
+        {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
+        {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
+    };
+    const UINT num_vertices27 = ARRAY_SIZE(vertices27);
+    const UINT num_faces27 = ARRAY_SIZE(vertices27) / VERTS_PER_FACE;
+    const UINT vertex_size27 = sizeof(*vertices27);
+    const struct vertex_ptc_float4 exp_vertices27[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.501961f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.101961f, 0.2f, 0.301961f, 0.4f}},
+        {{ 3.0f,  0.0f,  0.f}, {0.501961f, 0.6f, 0.701961f, 0.8f}},
+        {{ 1.0f,  0.0f,  0.f}, {0.901961f, 0.988235f, 0.996078f, 1.0f}},
+    };
+    const UINT exp_vertex_size27 = sizeof(*exp_vertices27);
+    /* Test 28. Convert UBYTE4 to FLOAT4. */
+    const struct vertex_ptc_ubyte4 vertices28[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
+        {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
+        {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
+        {{ 1.0f,  0.0f,  0.f}, {50, 60, 127, 255}},
+    };
+    const UINT num_vertices28 = ARRAY_SIZE(vertices28);
+    const UINT num_faces28 = ARRAY_SIZE(vertices28) / VERTS_PER_FACE;
+    const UINT vertex_size28 = sizeof(*vertices28);
+    const struct vertex_ptc_float4 exp_vertices28[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {1.0f,  0.0f, 1.0f, 0.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
+        {{ 3.0f,  0.0f,  0.f}, {10.0f, 20.0f, 30.0f, 40.0f}},
+        {{ 1.0f,  0.0f,  0.f}, {50.0f, 60.0f, 127.0f, 255.0f}},
+    };
+    const UINT exp_vertex_size28 = sizeof(*exp_vertices28);
+    /* Test 29. Convert SHORT2 to FLOAT4. */
+    const struct vertex_ptc_short2 vertices29[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 1}},
+        {{ 0.0f,  0.0f,  0.f}, {1, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {1, 1}},
+        {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX}},
+        {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
+    };
+    const UINT num_vertices29 = ARRAY_SIZE(vertices29);
+    const UINT num_faces29 = ARRAY_SIZE(vertices29) / VERTS_PER_FACE;
+    const UINT vertex_size29 = sizeof(*vertices29);
+    const struct vertex_ptc_float4 exp_vertices29[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
+        {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 0.0f, 1.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
+        {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 0.0f, 1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, 0.0f, 1.0f}},
+    };
+    const UINT exp_vertex_size29 = sizeof(*exp_vertices29);
+    /* Test 29. Convert SHORT4 to FLOAT4. */
+    const struct vertex_ptc_short4 vertices30[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
+        {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
+        {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1, 0}},
+        {{ 1.0f,  0.0f,  0.f}, {-42, 42, SHRT_MAX, SHRT_MIN}},
+    };
+    const UINT num_vertices30 = ARRAY_SIZE(vertices30);
+    const UINT num_faces30 = ARRAY_SIZE(vertices30) / VERTS_PER_FACE;
+    const UINT vertex_size30 = sizeof(*vertices30);
+    const struct vertex_ptc_float4 exp_vertices30[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
+        {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
+        {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1.0f, 0.0f}},
+        {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, SHRT_MAX, SHRT_MIN}},
+    };
+    const UINT exp_vertex_size30 = sizeof(*exp_vertices30);
+    /* Test 31. Convert UBYTE4N to FLOAT4. */
+    const struct vertex_ptc_ubyte4n vertices31[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
+        {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
+        {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
+        {{ 1.0f,  0.0f,  0.f}, {50, 60, 70, UCHAR_MAX}},
+    };
+    const UINT num_vertices31 = ARRAY_SIZE(vertices31);
+    const UINT num_faces31 = ARRAY_SIZE(vertices31) / VERTS_PER_FACE;
+    const UINT vertex_size31 = sizeof(*vertices31);
+    const struct vertex_ptc_float4 exp_vertices31[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX}},
+        {{ 0.0f,  0.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX, 0.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, (FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX}},
+        {{ 3.0f,  0.0f,  0.f}, {(FLOAT)10/UCHAR_MAX, (FLOAT)20/UCHAR_MAX, (FLOAT)30/UCHAR_MAX, (FLOAT)40/UCHAR_MAX}},
+        {{ 1.0f,  0.0f,  0.f}, {(FLOAT)50/UCHAR_MAX, (FLOAT)60/UCHAR_MAX, (FLOAT)70/UCHAR_MAX, 1.0f}},
+    };
+    const UINT exp_vertex_size31 = sizeof(*exp_vertices31);
+    /* Test 32. Convert SHORT2N to FLOAT4. */
+    const struct vertex_ptc_short2 vertices32[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 1}},
+        {{ 0.0f,  0.0f,  0.f}, {1, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {1, 1}},
+        {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
+        {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
+    };
+    const UINT num_vertices32 = ARRAY_SIZE(vertices32);
+    const UINT num_faces32 = ARRAY_SIZE(vertices32) / VERTS_PER_FACE;
+    const UINT vertex_size32 = sizeof(*vertices32);
+    const struct vertex_ptc_float4 exp_vertices32[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 0.0f, 1.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
+        {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, 0.0f, 1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 0.0f, 1.0f}},
+    };
+    const UINT exp_vertex_size32 = sizeof(*exp_vertices32);
+    /* Test 33. Convert SHORT4N to FLOAT4. */
+    const struct vertex_ptc_short4 vertices33[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
+        {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
+        {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
+
+        {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
+        {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, SHRT_MIN + 1, SHRT_MAX}},
+        {{ 1.0f,  0.0f,  0.f}, {-42, 42, 1, 1}},
+    };
+    const UINT num_vertices33 = ARRAY_SIZE(vertices33);
+    const UINT num_faces33 = ARRAY_SIZE(vertices33) / VERTS_PER_FACE;
+    const UINT vertex_size33 = sizeof(*vertices33);
+    const struct vertex_ptc_float4 exp_vertices33[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX}},
+        {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX, 0.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
+        {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, -1.0f, 1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
+    };
+    const UINT exp_vertex_size33 = sizeof(*exp_vertices33);
+    /* Test 34. Convert FLOAT16_2 to FLOAT4. */
+    const struct vertex_ptc_float16_2 vertices34[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
+        {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
+        {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
+
+        {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
+        {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
+        {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
+    };
+    const UINT num_vertices34 = ARRAY_SIZE(vertices34);
+    const UINT num_faces34 = ARRAY_SIZE(vertices34) / VERTS_PER_FACE;
+    const UINT vertex_size34 = sizeof(*vertices34);
+    const struct vertex_ptc_float4 exp_vertices34[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.700195f, 0.0f, 1.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {-0.199951f, -0.300049f, 0.0f, 1.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.199951f, 0.300049f, 0.0f, 1.0f}},
+        {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
+        {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.0f, 1.0f}},
+    };
+    const UINT exp_vertex_size34 = sizeof(*exp_vertices34);
+    /* Test 35. Convert FLOAT16_4 to FLOAT4. */
+    const struct vertex_ptc_float16_4 vertices35[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0x0000, 0x0000, 0x0000, 0x0000}},
+        {{ 2.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
+        {{ 0.0f,  0.0f,  0.f}, {0x3c00, 0x0000, 0x3c00, 0x0000}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0x0000, 0x3c00, 0x0000, 0x3c00}},
+        {{ 3.0f,  0.0f,  0.f}, {0x3800, 0x399a, 0xb266, 0xb4cd}},
+        {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
+    };
+    const UINT num_vertices35 = ARRAY_SIZE(vertices35);
+    const UINT num_faces35 = ARRAY_SIZE(vertices35) / VERTS_PER_FACE;
+    const UINT vertex_size35 = sizeof(*vertices35);
+    const struct vertex_ptc_float4 exp_vertices35[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
+        {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
+        {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
+
+        {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
+        {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.700195f, -0.199951f, -0.300049f}},
+        {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.099976f, 0.199951f}},
+    };
+    const UINT exp_vertex_size35 = sizeof(*exp_vertices35);
+    /* Test 36. Check that vertex buffer sharing is ok. */
+    const struct vertex_pn vertices36[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up},
+        {{ 2.0f,  3.0f,  0.f}, up},
+        {{ 0.0f,  0.0f,  0.f}, up},
+    };
+    const UINT num_vertices36 = ARRAY_SIZE(vertices36);
+    const UINT num_faces36 = ARRAY_SIZE(vertices36) / VERTS_PER_FACE;
+    const UINT vertex_size36 = sizeof(*vertices36);
+    const DWORD clone_options36 = options | D3DXMESH_VB_SHARE;
+    /* Common mesh data */
+    ID3DXMesh *mesh = NULL;
+    ID3DXMesh *mesh_clone = NULL;
+    struct
+    {
+        const BYTE *vertices;
+        const DWORD *indices;
+        const DWORD *attributes;
+        const UINT num_vertices;
+        const UINT num_faces;
+        const UINT vertex_size;
+        const DWORD create_options;
+        const DWORD clone_options;
+        D3DVERTEXELEMENT9 *declaration;
+        D3DVERTEXELEMENT9 *new_declaration;
+        const BYTE *exp_vertices;
+        const UINT exp_vertex_size;
+    }
+    tc[] =
+    {
+        {
+            (BYTE*)vertices0,
+            NULL,
+            NULL,
+            num_vertices0,
+            num_faces0,
+            vertex_size0,
+            options,
+            options,
+            declaration_pn,
+            declaration_pn,
+            (BYTE*)vertices0,
+            vertex_size0
+        },
+        {
+            (BYTE*)vertices0,
+            NULL,
+            NULL,
+            num_vertices0,
+            num_faces0,
+            vertex_size0,
+            options_16bit,
+            options_16bit,
+            declaration_pn,
+            declaration_pn,
+            (BYTE*)vertices0,
+            vertex_size0
+        },
+        {
+            (BYTE*)vertices0,
+            NULL,
+            NULL,
+            num_vertices0,
+            num_faces0,
+            vertex_size0,
+            options,
+            options,
+            declaration_pn,
+            declaration_pntc,
+            (BYTE*)exp_vertices2,
+            exp_vertex_size2
+        },
+        {
+            (BYTE*)vertices0,
+            NULL,
+            NULL,
+            num_vertices0,
+            num_faces0,
+            vertex_size0,
+            options,
+            options,
+            declaration_pn,
+            declaration_ptcn,
+            (BYTE*)exp_vertices3,
+            exp_vertex_size3
+        },
+        {
+            (BYTE*)vertices4,
+            NULL,
+            NULL,
+            num_vertices4,
+            num_faces4,
+            vertex_size4,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_float16_2,
+            (BYTE*)exp_vertices4,
+            exp_vertex_size4
+        },
+        {
+            (BYTE*)vertices5,
+            NULL,
+            NULL,
+            num_vertices5,
+            num_faces5,
+            vertex_size5,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_float16_4,
+            (BYTE*)exp_vertices5,
+            exp_vertex_size5
+        },
+        {
+            (BYTE*)vertices6,
+            NULL,
+            NULL,
+            num_vertices6,
+            num_faces6,
+            vertex_size6,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_float1,
+            (BYTE*)exp_vertices6,
+            exp_vertex_size6
+        },
+        {
+            (BYTE*)vertices7,
+            NULL,
+            NULL,
+            num_vertices7,
+            num_faces7,
+            vertex_size7,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_float3,
+            (BYTE*)exp_vertices7,
+            exp_vertex_size7
+        },
+        {
+            (BYTE*)vertices8,
+            NULL,
+            NULL,
+            num_vertices8,
+            num_faces8,
+            vertex_size8,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices8,
+            exp_vertex_size8
+        },
+        {
+            (BYTE*)vertices9,
+            NULL,
+            NULL,
+            num_vertices9,
+            num_faces9,
+            vertex_size9,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_d3dcolor,
+            (BYTE*)exp_vertices9,
+            exp_vertex_size9
+        },
+        {
+            (BYTE*)vertices10,
+            NULL,
+            NULL,
+            num_vertices10,
+            num_faces10,
+            vertex_size10,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_ubyte4,
+            (BYTE*)exp_vertices10,
+            exp_vertex_size10
+        },
+        {
+            (BYTE*)vertices11,
+            NULL,
+            NULL,
+            num_vertices11,
+            num_faces11,
+            vertex_size11,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_short2,
+            (BYTE*)exp_vertices11,
+            exp_vertex_size11
+        },
+        {
+            (BYTE*)vertices12,
+            NULL,
+            NULL,
+            num_vertices12,
+            num_faces12,
+            vertex_size12,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_short4,
+            (BYTE*)exp_vertices12,
+            exp_vertex_size12
+        },
+        {
+            (BYTE*)vertices13,
+            NULL,
+            NULL,
+            num_vertices13,
+            num_faces13,
+            vertex_size13,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_ubyte4n,
+            (BYTE*)exp_vertices13,
+            exp_vertex_size13
+        },
+        {
+            (BYTE*)vertices14,
+            NULL,
+            NULL,
+            num_vertices14,
+            num_faces14,
+            vertex_size14,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_short2n,
+            (BYTE*)exp_vertices14,
+            exp_vertex_size14
+        },
+        {
+            (BYTE*)vertices15,
+            NULL,
+            NULL,
+            num_vertices15,
+            num_faces15,
+            vertex_size15,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_short4n,
+            (BYTE*)exp_vertices15,
+            exp_vertex_size15
+        },
+        {
+            (BYTE*)vertices16,
+            NULL,
+            NULL,
+            num_vertices16,
+            num_faces16,
+            vertex_size16,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_ushort2n,
+            (BYTE*)exp_vertices16,
+            exp_vertex_size16
+        },
+        {
+            (BYTE*)vertices17,
+            NULL,
+            NULL,
+            num_vertices17,
+            num_faces17,
+            vertex_size17,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_ushort4n,
+            (BYTE*)exp_vertices17,
+            exp_vertex_size17
+        },
+        {
+            (BYTE*)vertices18,
+            NULL,
+            NULL,
+            num_vertices18,
+            num_faces18,
+            vertex_size18,
+            options,
+            options,
+            declaration_ptc,
+            declaration_ptc_float16_2_partialu,
+            (BYTE*)exp_vertices18,
+            exp_vertex_size18
+        },
+        {
+            (BYTE*)vertices19,
+            NULL,
+            NULL,
+            num_vertices19,
+            num_faces19,
+            vertex_size19,
+            options,
+            options,
+            declaration_pntc,
+            declaration_pntc1,
+            (BYTE*)exp_vertices19,
+            exp_vertex_size19
+        },
+        {
+            (BYTE*)vertices20,
+            NULL,
+            NULL,
+            num_vertices20,
+            num_faces20,
+            vertex_size20,
+            options,
+            options,
+            declaration_pntc1,
+            declaration_pntc,
+            (BYTE*)exp_vertices20,
+            exp_vertex_size20
+        },
+        {
+            (BYTE*)vertices21,
+            NULL,
+            NULL,
+            num_vertices21,
+            num_faces21,
+            vertex_size21,
+            options,
+            options,
+            declaration_ptc_float1,
+            declaration_ptc,
+            (BYTE*)exp_vertices21,
+            exp_vertex_size21
+        },
+        {
+            (BYTE*)vertices22,
+            NULL,
+            NULL,
+            num_vertices22,
+            num_faces22,
+            vertex_size22,
+            options,
+            options,
+            declaration_ptc_float1,
+            declaration_ptc_float3,
+            (BYTE*)exp_vertices22,
+            exp_vertex_size22
+        },
+        {
+            (BYTE*)vertices23,
+            NULL,
+            NULL,
+            num_vertices23,
+            num_faces23,
+            vertex_size23,
+            options,
+            options,
+            declaration_ptc_float1,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices23,
+            exp_vertex_size23
+        },
+        {
+            (BYTE*)vertices24,
+            NULL,
+            NULL,
+            num_vertices24,
+            num_faces24,
+            vertex_size24,
+            options,
+            options,
+            declaration_ptc_float1,
+            declaration_ptc_d3dcolor,
+            (BYTE*)exp_vertices24,
+            exp_vertex_size24
+        },
+        {
+            (BYTE*)vertices25,
+            NULL,
+            NULL,
+            num_vertices25,
+            num_faces25,
+            vertex_size25,
+            options,
+            options,
+            declaration_ptc_float1,
+            declaration_ptc_ubyte4,
+            (BYTE*)exp_vertices25,
+            exp_vertex_size25
+        },
+        {
+            (BYTE*)vertices26,
+            NULL,
+            NULL,
+            num_vertices26,
+            num_faces26,
+            vertex_size26,
+            options,
+            options,
+            declaration_ptc_float4,
+            declaration_ptc_d3dcolor,
+            (BYTE*)exp_vertices26,
+            exp_vertex_size26
+        },
+        {
+            (BYTE*)vertices27,
+            NULL,
+            NULL,
+            num_vertices27,
+            num_faces27,
+            vertex_size27,
+            options,
+            options,
+            declaration_ptc_d3dcolor,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices27,
+            exp_vertex_size27
+        },
+        {
+            (BYTE*)vertices28,
+            NULL,
+            NULL,
+            num_vertices28,
+            num_faces28,
+            vertex_size28,
+            options,
+            options,
+            declaration_ptc_ubyte4,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices28,
+            exp_vertex_size28
+        },
+        {
+            (BYTE*)vertices29,
+            NULL,
+            NULL,
+            num_vertices29,
+            num_faces29,
+            vertex_size29,
+            options,
+            options,
+            declaration_ptc_short2,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices29,
+            exp_vertex_size29
+        },
+        {
+            (BYTE*)vertices30,
+            NULL,
+            NULL,
+            num_vertices30,
+            num_faces30,
+            vertex_size30,
+            options,
+            options,
+            declaration_ptc_short4,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices30,
+            exp_vertex_size30
+        },
+        {
+            (BYTE*)vertices31,
+            NULL,
+            NULL,
+            num_vertices31,
+            num_faces31,
+            vertex_size31,
+            options,
+            options,
+            declaration_ptc_ubyte4n,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices31,
+            exp_vertex_size31
+        },
+        {
+            (BYTE*)vertices32,
+            NULL,
+            NULL,
+            num_vertices32,
+            num_faces32,
+            vertex_size32,
+            options,
+            options,
+            declaration_ptc_short2n,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices32,
+            exp_vertex_size32
+        },
+        {
+            (BYTE*)vertices33,
+            NULL,
+            NULL,
+            num_vertices33,
+            num_faces33,
+            vertex_size33,
+            options,
+            options,
+            declaration_ptc_short4n,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices33,
+            exp_vertex_size33
+        },
+        {
+            (BYTE*)vertices34,
+            NULL,
+            NULL,
+            num_vertices34,
+            num_faces34,
+            vertex_size34,
+            options,
+            options,
+            declaration_ptc_float16_2,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices34,
+            exp_vertex_size34
+        },
+        {
+            (BYTE*)vertices35,
+            NULL,
+            NULL,
+            num_vertices35,
+            num_faces35,
+            vertex_size35,
+            options,
+            options,
+            declaration_ptc_float16_4,
+            declaration_ptc_float4,
+            (BYTE*)exp_vertices35,
+            exp_vertex_size35
+        },
+        {
+            (BYTE*)vertices36,
+            NULL,
+            NULL,
+            num_vertices36,
+            num_faces36,
+            vertex_size36,
+            options,
+            clone_options36,
+            declaration_pn,
+            declaration_pn,
+            (BYTE*)vertices36,
+            vertex_size36
+        },
+    };
+#ifdef __REACTOS__
+#undef up
+#undef zero_vec2
+#endif
+
+    test_context = new_test_context();
+    if (!test_context)
+    {
+        skip("Couldn't create test context\n");
+        goto cleanup;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(tc); i++)
+    {
+        UINT j;
+        D3DVERTEXELEMENT9 new_declaration[MAX_FVF_DECL_SIZE];
+        UINT exp_new_decl_length, new_decl_length;
+        UINT exp_new_decl_size, new_decl_size;
+
+        hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
+                              tc[i].create_options,
+                              tc[i].declaration,
+                              test_context->device, &mesh,
+                              tc[i].vertices, tc[i].vertex_size,
+                              tc[i].indices, tc[i].attributes);
+        if (FAILED(hr))
+        {
+            skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
+            goto cleanup;
+        }
+
+        hr = mesh->lpVtbl->CloneMesh(mesh, tc[i].clone_options, tc[i].new_declaration,
+                                     test_context->device, &mesh_clone);
+        ok(hr == D3D_OK, "CloneMesh test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
+
+        hr = mesh_clone->lpVtbl->GetDeclaration(mesh_clone, new_declaration);
+        ok(hr == D3D_OK, "GetDeclaration test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
+        /* Check declaration elements */
+        for (j = 0; tc[i].new_declaration[j].Stream != 0xFF; j++)
+        {
+            ok(memcmp(&tc[i].new_declaration[j], &new_declaration[j], sizeof(*new_declaration)) == 0,
+               "Test case %d failed. Declaration element %d did not match.\n", i, j);
+        }
+
+        /* Check declaration length */
+        exp_new_decl_length = D3DXGetDeclLength(tc[i].new_declaration);
+        new_decl_length = D3DXGetDeclLength(new_declaration);
+        ok(new_decl_length == exp_new_decl_length,
+           "Test case %d failed. Got new declaration length %d, expected %d\n",
+           i, new_decl_length, exp_new_decl_length);
+
+        /* Check declaration size */
+        exp_new_decl_size = D3DXGetDeclVertexSize(tc[i].new_declaration, 0);
+        new_decl_size = D3DXGetDeclVertexSize(new_declaration, 0);
+        ok(new_decl_size == exp_new_decl_size,
+           "Test case %d failed. Got new declaration size %d, expected %d\n",
+           i, new_decl_size, exp_new_decl_size);
+
+        /* Check vertex data in cloned mesh */
+        hr = mesh_clone->lpVtbl->LockVertexBuffer(mesh_clone, 0, (void**)&vertices);
+        if (FAILED(hr))
+        {
+            skip("Couldn't lock cloned vertex buffer.\n");
+            goto cleanup;
+        }
+        for (j = 0; j < tc[i].num_vertices; j++)
+        {
+            UINT index = tc[i].exp_vertex_size * j;
+            check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].new_declaration);
+        }
+        hr = mesh_clone->lpVtbl->UnlockVertexBuffer(mesh_clone);
+        if (FAILED(hr))
+        {
+            skip("Couldn't unlock vertex buffer.\n");
+            goto cleanup;
+        }
+        vertices = NULL;
+        mesh->lpVtbl->Release(mesh);
+        mesh = NULL;
+        mesh_clone->lpVtbl->Release(mesh_clone);
+        mesh_clone = NULL;
+    }
+
+    /* The following test shows that it is not possible to share a vertex buffer
+     * with D3DXMESH_VB_SHARE and change the vertex declaration at the same
+     * time. It reuses the test data from test 2.
+     */
+    hr = init_test_mesh(tc[2].num_faces, tc[2].num_vertices,
+                        tc[2].create_options,
+                        tc[2].declaration,
+                        test_context->device, &mesh,
+                        tc[2].vertices, tc[2].vertex_size,
+                        tc[2].indices, tc[2].attributes);
+    if (FAILED(hr))
+    {
+        skip("Couldn't initialize test mesh for D3DXMESH_VB_SHARE case."
+             " Got %x expected D3D_OK\n", hr);
+        goto cleanup;
+    }
+
+    hr = mesh->lpVtbl->CloneMesh(mesh, tc[2].create_options | D3DXMESH_VB_SHARE,
+                                 tc[2].new_declaration, test_context->device,
+                                 &mesh_clone);
+    ok(hr == D3DERR_INVALIDCALL, "CloneMesh D3DXMESH_VB_SHARE with new"
+       " declaration. Got %x, expected D3DERR_INVALIDCALL\n",
+       hr);
+    mesh->lpVtbl->Release(mesh);
+    mesh = NULL;
+    mesh_clone = NULL;
+
+cleanup:
+    if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
+    if (mesh) mesh->lpVtbl->Release(mesh);
+    if (mesh_clone) mesh_clone->lpVtbl->Release(mesh_clone);
+    free_test_context(test_context);
+}
+
+static void test_valid_mesh(void)
+{
+    HRESULT hr;
+    struct test_context *test_context = NULL;
+    UINT i;
+    const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
+    const D3DVERTEXELEMENT9 declaration[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        D3DDECL_END()
+    };
+    const unsigned int VERTS_PER_FACE = 3;
+    /* mesh0 (one face)
+     *
+     * 0--1
+     * | /
+     * |/
+     * 2
+     */
+    const D3DXVECTOR3 vertices0[] =
+    {
+        { 0.0f,  3.0f,  0.f},
+        { 2.0f,  3.0f,  0.f},
+        { 0.0f,  0.0f,  0.f},
+    };
+    const DWORD indices0[] = {0, 1, 2};
+    const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
+    const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
+    const DWORD adjacency0[] = {-1, -1, -1};
+    const HRESULT exp_hr0 = D3D_OK;
+    /* mesh1 (Simple bow-tie)
+     *
+     * 0--1 1--3
+     * | /   \ |
+     * |/     \|
+     * 2       4
+     */
+    const D3DXVECTOR3 vertices1[] =
+    {
+        { 0.0f,  3.0f,  0.f},
+        { 2.0f,  3.0f,  0.f},
+        { 0.0f,  0.0f,  0.f},
+
+        { 4.0f,  3.0f,  0.f},
+        { 4.0f,  0.0f,  0.f},
+    };
+    const DWORD indices1[] = {0, 1, 2, 1, 3, 4};
+    const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
+    const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
+    const DWORD adjacency1[] = {-1, -1, -1, -1, -1, -1};
+    const HRESULT exp_hr1 = D3DXERR_INVALIDMESH;
+    /* Common mesh data */
+    ID3DXMesh *mesh = NULL;
+    UINT vertex_size = sizeof(D3DXVECTOR3);
+    ID3DXBuffer *errors_and_warnings = NULL;
+    struct
+    {
+        const D3DXVECTOR3 *vertices;
+        const DWORD *indices;
+        const UINT num_vertices;
+        const UINT num_faces;
+        const DWORD *adjacency;
+        const HRESULT exp_hr;
+    }
+    tc[] =
+    {
+        {
+            vertices0,
+            indices0,
+            num_vertices0,
+            num_faces0,
+            adjacency0,
+            exp_hr0,
+        },
+        {
+            vertices1,
+            indices1,
+            num_vertices1,
+            num_faces1,
+            adjacency1,
+            exp_hr1,
+        },
+    };
+
+    test_context = new_test_context();
+    if (!test_context)
+    {
+        skip("Couldn't create test context\n");
+        goto cleanup;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(tc); i++)
+    {
+        hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
+                            options, declaration,
+                            test_context->device, &mesh,
+                            tc[i].vertices, vertex_size,
+                            tc[i].indices, NULL);
+        if (FAILED(hr))
+        {
+            skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
+            goto cleanup;
+        }
+
+        hr = D3DXValidMesh(mesh, tc[i].adjacency, &errors_and_warnings);
+        todo_wine ok(hr == tc[i].exp_hr, "D3DXValidMesh test case %d failed. "
+                     "Got %x\n, expected %x\n", i, hr, tc[i].exp_hr);
+
+        /* Note errors_and_warnings is deliberately not checked because that
+         * would require copying wast amounts of the text output. */
+        if (errors_and_warnings)
+        {
+            ID3DXBuffer_Release(errors_and_warnings);
+            errors_and_warnings = NULL;
+        }
+        mesh->lpVtbl->Release(mesh);
+        mesh = NULL;
+    }
+
+cleanup:
+    if (mesh) mesh->lpVtbl->Release(mesh);
+    free_test_context(test_context);
+}
+
+static void test_optimize_faces(void)
+{
+    HRESULT hr;
+    UINT i;
+    DWORD smallest_face_remap;
+    /* mesh0
+     *
+     * 0--1
+     * | /
+     * |/
+     * 2
+     */
+    const DWORD indices0[] = {0, 1, 2};
+    const UINT num_faces0 = 1;
+    const UINT num_vertices0 = 3;
+    const DWORD exp_face_remap0[] = {0};
+    /* mesh1
+     *
+     * 0--1 3
+     * | / /|
+     * |/ / |
+     * 2 5--4
+     */
+    const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
+    const UINT num_faces1 = 2;
+    const UINT num_vertices1 = 6;
+    const DWORD exp_face_remap1[] = {1, 0};
+    /* mesh2
+     *
+     * 0--1
+     * | /|
+     * |/ |
+     * 2--3
+     */
+    const DWORD indices2[] = {0, 1, 2, 1, 3, 2};
+    const UINT num_faces2 = 2;
+    const UINT num_vertices2 = 4;
+    const DWORD exp_face_remap2[] = {1, 0};
+    /* mesh3
+     *
+     * 0--1
+     * | /|
+     * |/ |
+     * 2--3
+     * | /|
+     * |/ |
+     * 4--5
+     */
+    const DWORD indices3[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
+    const UINT num_faces3 = 4;
+    const UINT num_vertices3 = 6;
+    const DWORD exp_face_remap3[] = {3, 2, 1, 0};
+    /* mesh4
+     *
+     * 0--1
+     * | /|
+     * |/ |
+     * 2--3
+     * | /|
+     * |/ |
+     * 4--5
+     */
+    const WORD indices4[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
+    const UINT num_faces4 = 4;
+    const UINT num_vertices4 = 6;
+    const DWORD exp_face_remap4[] = {3, 2, 1, 0};
+    /* Test cases are stored in the tc array */
+    struct
+    {
+        const VOID *indices;
+        const UINT num_faces;
+        const UINT num_vertices;
+        const BOOL indices_are_32bit;
+        const DWORD *exp_face_remap;
+    }
+    tc[] =
+    {
+        {
+            indices0,
+            num_faces0,
+            num_vertices0,
+            TRUE,
+            exp_face_remap0
+        },
+        {
+            indices1,
+            num_faces1,
+            num_vertices1,
+            TRUE,
+            exp_face_remap1
+        },
+        {
+            indices2,
+            num_faces2,
+            num_vertices2,
+            TRUE,
+            exp_face_remap2
+        },
+        {
+            indices3,
+            num_faces3,
+            num_vertices3,
+            TRUE,
+            exp_face_remap3
+        },
+        {
+            indices4,
+            num_faces4,
+            num_vertices4,
+            FALSE,
+            exp_face_remap4
+        },
+    };
+
+    /* Go through all test cases */
+    for (i = 0; i < ARRAY_SIZE(tc); i++)
+    {
+        DWORD j;
+        DWORD *face_remap;
+        face_remap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                               tc[i].num_faces*sizeof(*face_remap));
+
+        hr = D3DXOptimizeFaces(tc[i].indices, tc[i].num_faces,
+                               tc[i].num_vertices, tc[i].indices_are_32bit,
+                               face_remap);
+        ok(hr == D3D_OK, "D3DXOptimizeFaces test case %d failed. "
+           "Got %x\n, expected D3D_OK\n", i, hr);
+
+        /* Compare face remap with expected face remap */
+        for (j = 0; j < tc[i].num_faces; j++)
+        {
+            ok(tc[i].exp_face_remap[j] == face_remap[j],
+               "Test case %d: Got face %d at %d, expected %d\n", i,
+               face_remap[j], j, tc[i].exp_face_remap[j]);
+        }
+
+        HeapFree(GetProcessHeap(), 0, face_remap);
+    }
+
+    /* face_remap must not be NULL */
+    hr = D3DXOptimizeFaces(tc[0].indices, tc[0].num_faces,
+                           tc[0].num_vertices, tc[0].indices_are_32bit,
+                           NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeFaces passed NULL face_remap "
+       "pointer. Got %x\n, expected D3DERR_INVALIDCALL\n", hr);
+
+    /* Number of faces must be smaller than 2^15 */
+    hr = D3DXOptimizeFaces(tc[0].indices, 2 << 15,
+                           tc[0].num_vertices, FALSE,
+                           &smallest_face_remap);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeFaces should not accept 2^15 "
+    "faces when using 16-bit indices. Got %x\n, expected D3DERR_INVALIDCALL\n", hr);
+}
+
+static HRESULT clear_normals(ID3DXMesh *mesh)
+{
+    HRESULT hr;
+    BYTE *vertices;
+    size_t normal_size;
+    DWORD i, num_vertices, vertex_stride;
+    const D3DXVECTOR4 normal = {NAN, NAN, NAN, NAN};
+    D3DVERTEXELEMENT9 *normal_declaration = NULL;
+    D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
+
+    if (FAILED(hr = mesh->lpVtbl->GetDeclaration(mesh, declaration)))
+        return hr;
+
+    for (i = 0; declaration[i].Stream != 0xff; i++)
+    {
+        if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
+        {
+            normal_declaration = &declaration[i];
+            break;
+        }
+    }
+
+    if (!normal_declaration)
+        return D3DERR_INVALIDCALL;
+
+    if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
+    {
+        normal_size = sizeof(D3DXVECTOR3);
+    }
+    else if (normal_declaration->Type == D3DDECLTYPE_FLOAT4)
+    {
+        normal_size = sizeof(D3DXVECTOR4);
+    }
+    else
+    {
+        trace("Cannot clear normals\n");
+        return E_NOTIMPL;
+    }
+
+    num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
+    vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+
+    if (FAILED(hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
+        return hr;
+
+    vertices += normal_declaration->Offset;
+
+    for (i = 0; i < num_vertices; i++, vertices += vertex_stride)
+        memcpy(vertices, &normal, normal_size);
+
+    return mesh->lpVtbl->UnlockVertexBuffer(mesh);
+}
+
+static void compare_normals(unsigned int line, const char *test_name,
+        ID3DXMesh *mesh, const D3DXVECTOR3 *normals, unsigned int num_normals)
+{
+    unsigned int i;
+    BYTE *vertices;
+    DWORD num_vertices, vertex_stride;
+    D3DVERTEXELEMENT9 *normal_declaration = NULL;
+    D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
+
+    if (FAILED(mesh->lpVtbl->GetDeclaration(mesh, declaration)))
+    {
+        ok_(__FILE__, line)(0, "%s: Failed to get declaration\n", test_name);
+        return;
+    }
+
+    for (i = 0; declaration[i].Stream != 0xff; i++)
+    {
+        if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
+        {
+            normal_declaration = &declaration[i];
+            break;
+        }
+    }
+
+    if (!normal_declaration)
+    {
+        ok_(__FILE__, line)(0, "%s: Mesh has no normals\n", test_name);
+        return;
+    }
+
+    if (normal_declaration->Type != D3DDECLTYPE_FLOAT3 && normal_declaration->Type != D3DDECLTYPE_FLOAT4)
+    {
+        ok_(__FILE__, line)(0, "%s: Mesh has invalid normals type\n", test_name);
+        return;
+    }
+
+    num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
+    vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+
+    ok_(__FILE__, line)(num_vertices == num_normals, "%s: Expected %u vertices, got %u\n", test_name,
+            num_normals, num_vertices);
+
+    if (FAILED(mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
+    {
+        ok_(__FILE__, line)(0, "%s: Failed to compare normals\n", test_name);
+        return;
+    }
+
+    vertices += normal_declaration->Offset;
+
+    for (i = 0; i < min(num_vertices, num_normals); i++, vertices += vertex_stride)
+    {
+        if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
+        {
+            const D3DXVECTOR3 *n = (D3DXVECTOR3 *)vertices;
+            ok_(__FILE__, line)(compare_vec3(*n, normals[i]),
+                    "%s: normal %2u, expected (%f, %f, %f), got (%f, %f, %f)\n",
+                    test_name, i, normals[i].x, normals[i].y, normals[i].z, n->x, n->y, n->z);
+        }
+        else
+        {
+            const D3DXVECTOR4 *n = (D3DXVECTOR4 *)vertices;
+            const D3DXVECTOR4 normal = {normals[i].x, normals[i].y, normals[i].z, 1.0f};
+            ok_(__FILE__, line)(compare_vec4(*n, normal),
+                    "%s: normal %2u, expected (%f, %f, %f, %f), got (%f, %f, %f, %f)\n",
+                    test_name, i, normals[i].x, normals[i].y, normals[i].z, 1.0f,
+                    n->x, n->y, n->z, n->w);
+        }
+    }
+
+    mesh->lpVtbl->UnlockVertexBuffer(mesh);
+}
+
+static HRESULT compute_normals_D3DXComputeNormals(ID3DXMesh *mesh, const DWORD *adjacency)
+{
+    return D3DXComputeNormals((ID3DXBaseMesh *)mesh, adjacency);
+}
+
+static HRESULT compute_normals_D3DXComputeTangentFrameEx(ID3DXMesh *mesh, const DWORD *adjacency)
+{
+    return D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
+            adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL);
+}
+
+static void test_compute_normals(void)
+{
+    HRESULT hr;
+    ULONG refcount;
+    ID3DXMesh *mesh, *cloned_mesh;
+    ID3DXBuffer *adjacency;
+    IDirect3DDevice9 *device;
+    struct test_context *test_context;
+    unsigned int i;
+
+    static const struct compute_normals_func
+    {
+        const char *name;
+        HRESULT (*apply)(ID3DXMesh *mesh, const DWORD *adjacency);
+    }
+    compute_normals_funcs[] =
+    {
+        {"D3DXComputeNormals",        compute_normals_D3DXComputeNormals       },
+        {"D3DXComputeTangentFrameEx", compute_normals_D3DXComputeTangentFrameEx}
+    };
+
+    static const D3DXVECTOR3 box_normals[24] =
+    {
+        {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f},
+        { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f},
+        { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f},
+        { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f},
+        { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f},
+        { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}
+    };
+    const float box_normal_component = 1.0f / sqrtf(3.0f);
+    const D3DXVECTOR3 box_normals_adjacency[24] =
+    {
+        {-box_normal_component, -box_normal_component, -box_normal_component},
+        {-box_normal_component, -box_normal_component,  box_normal_component},
+        {-box_normal_component,  box_normal_component,  box_normal_component},
+        {-box_normal_component,  box_normal_component, -box_normal_component},
+        {-box_normal_component,  box_normal_component, -box_normal_component},
+        {-box_normal_component,  box_normal_component,  box_normal_component},
+        { box_normal_component,  box_normal_component,  box_normal_component},
+        { box_normal_component,  box_normal_component, -box_normal_component},
+        { box_normal_component,  box_normal_component, -box_normal_component},
+        { box_normal_component,  box_normal_component,  box_normal_component},
+        { box_normal_component, -box_normal_component,  box_normal_component},
+        { box_normal_component, -box_normal_component, -box_normal_component},
+        {-box_normal_component, -box_normal_component,  box_normal_component},
+        {-box_normal_component, -box_normal_component, -box_normal_component},
+        { box_normal_component, -box_normal_component, -box_normal_component},
+        { box_normal_component, -box_normal_component,  box_normal_component},
+        {-box_normal_component, -box_normal_component,  box_normal_component},
+        { box_normal_component, -box_normal_component,  box_normal_component},
+        { box_normal_component,  box_normal_component,  box_normal_component},
+        {-box_normal_component,  box_normal_component,  box_normal_component},
+        {-box_normal_component, -box_normal_component, -box_normal_component},
+        {-box_normal_component,  box_normal_component, -box_normal_component},
+        { box_normal_component,  box_normal_component, -box_normal_component},
+        { box_normal_component, -box_normal_component, -box_normal_component}
+    };
+    static const D3DXVECTOR3 box_normals_adjacency_area[24] =
+    {
+        {-0.666667f, -0.333333f, -0.666667f}, {-0.333333f, -0.666667f,  0.666667f},
+        {-0.816496f,  0.408248f,  0.408248f}, {-0.408248f,  0.816496f, -0.408248f},
+        {-0.408248f,  0.816496f, -0.408248f}, {-0.816496f,  0.408248f,  0.408248f},
+        { 0.333333f,  0.666667f,  0.666667f}, { 0.666667f,  0.333333f, -0.666667f},
+        { 0.666667f,  0.333333f, -0.666667f}, { 0.333333f,  0.666667f,  0.666667f},
+        { 0.816496f, -0.408248f,  0.408248f}, { 0.408248f, -0.816496f, -0.408248f},
+        {-0.333333f, -0.666667f,  0.666667f}, {-0.666667f, -0.333333f, -0.666667f},
+        { 0.408248f, -0.816496f, -0.408248f}, { 0.816496f, -0.408248f,  0.408248f},
+        {-0.333333f, -0.666667f,  0.666667f}, { 0.816497f, -0.408248f,  0.408248f},
+        { 0.333333f,  0.666667f,  0.666667f}, {-0.816497f,  0.408248f,  0.408248f},
+        {-0.666667f, -0.333333f, -0.666667f}, {-0.408248f,  0.816497f, -0.408248f},
+        { 0.666667f,  0.333333f, -0.666667f}, { 0.408248f, -0.816496f, -0.408248f}
+    };
+    static const D3DXVECTOR3 box_normals_position1f[24] = {{0}};
+    static const D3DXVECTOR3 box_normals_position2f[24] =
+    {
+        {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
+        {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f},
+        {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
+        {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
+        {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
+        {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
+        {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
+        {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}
+    };
+
+    static const D3DXVECTOR3 sphere_normals[22] =
+    {
+        { 0.000000f, -0.000000f,  1.000000f}, { 0.000000f,  0.582244f,  0.813014f},
+        { 0.582244f, -0.000000f,  0.813014f}, {-0.000000f, -0.582244f,  0.813014f},
+        {-0.582244f,  0.000000f,  0.813014f}, {-0.000000f,  0.890608f,  0.454772f},
+        { 0.890608f,  0.000000f,  0.454772f}, { 0.000000f, -0.890608f,  0.454772f},
+        {-0.890608f, -0.000000f,  0.454772f}, { 0.000000f,  1.000000f, -0.000000f},
+        { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
+        {-1.000000f,  0.000000f, -0.000000f}, { 0.000000f,  0.890608f, -0.454773f},
+        { 0.890608f, -0.000000f, -0.454772f}, {-0.000000f, -0.890608f, -0.454773f},
+        {-0.890608f,  0.000000f, -0.454773f}, { 0.000000f,  0.582244f, -0.813015f},
+        { 0.582244f, -0.000000f, -0.813015f}, { 0.000000f, -0.582244f, -0.813015f},
+        {-0.582243f,  0.000000f, -0.813015f}, { 0.000000f,  0.000000f, -1.000000f}
+    };
+    static const D3DXVECTOR3 sphere_normals_area[22] =
+    {
+        { 0.000000f, -0.000000f,  1.000000f}, {-0.215311f,  0.554931f,  0.803550f},
+        { 0.554931f,  0.215311f,  0.803550f}, { 0.215311f, -0.554931f,  0.803550f},
+        {-0.554931f, -0.215311f,  0.803550f}, {-0.126638f,  0.872121f,  0.472618f},
+        { 0.872121f,  0.126638f,  0.472618f}, { 0.126638f, -0.872121f,  0.472618f},
+        {-0.872121f, -0.126637f,  0.472618f}, { 0.000000f,  1.000000f, -0.000000f},
+        { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
+        {-1.000000f,  0.000000f, -0.000000f}, { 0.126638f,  0.872121f, -0.472618f},
+        { 0.872121f, -0.126638f, -0.472618f}, {-0.126638f, -0.872121f, -0.472618f},
+        {-0.872121f,  0.126638f, -0.472618f}, { 0.215311f,  0.554931f, -0.803550f},
+        { 0.554931f, -0.215311f, -0.803550f}, {-0.215311f, -0.554931f, -0.803550f},
+        {-0.554931f,  0.215311f, -0.803550f}, { 0.000000f,  0.000000f, -1.000000f}
+    };
+    static const D3DXVECTOR3 sphere_normals_equal[22] =
+    {
+        { 0.000000f, -0.000000f,  1.000000f}, {-0.134974f,  0.522078f,  0.842150f},
+        { 0.522078f,  0.134974f,  0.842150f}, { 0.134974f, -0.522078f,  0.842150f},
+        {-0.522078f, -0.134974f,  0.842150f}, {-0.026367f,  0.857121f,  0.514440f},
+        { 0.857121f,  0.026367f,  0.514440f}, { 0.026367f, -0.857121f,  0.514440f},
+        {-0.857121f, -0.026367f,  0.514440f}, { 0.000000f,  1.000000f, -0.000000f},
+        { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
+        {-1.000000f,  0.000000f, -0.000000f}, { 0.026367f,  0.857121f, -0.514440f},
+        { 0.857121f, -0.026367f, -0.514440f}, {-0.026367f, -0.857121f, -0.514440f},
+        {-0.857121f,  0.026367f, -0.514440f}, { 0.134975f,  0.522078f, -0.842150f},
+        { 0.522078f, -0.134975f, -0.842150f}, {-0.134974f, -0.522078f, -0.842150f},
+        {-0.522078f,  0.134974f, -0.842150f}, { 0.000000f,  0.000000f, -1.000000f}
+    };
+
+    static const D3DVERTEXELEMENT9 position3f_normal1f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 position3f_normal2f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 normal4f_position3f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 position1f_normal3f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, sizeof(float),       D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 position2f_normal3f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, sizeof(D3DXVECTOR2), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 position4f_normal3f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        D3DDECL_END()
+    };
+
+    for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
+    {
+        hr = compute_normals_funcs[i].apply(NULL, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", compute_normals_funcs[i].name, hr);
+    }
+
+    if (!(test_context = new_test_context()))
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hr = D3DXCreateBox(device, 1.0f, 1.0f, 1.0f, &mesh, &adjacency);
+    ok(SUCCEEDED(hr), "D3DXCreateBox failed %#x\n", hr);
+
+    /* Check wrong input */
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DDECLUSAGE_NORMAL, 0,
+            D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA | D3DXTANGENT_WEIGHT_EQUAL,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, 0, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 1, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DX_DEFAULT, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_CALCULATE_NORMALS,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
+    {
+        const struct compute_normals_func *func = &compute_normals_funcs[i];
+
+        /* Mesh without normals */
+        hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_XYZ, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh without positions */
+        hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_NORMAL, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh with D3DDECLTYPE_FLOAT1 normals */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal1f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh with D3DDECLTYPE_FLOAT2 normals */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal2f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh without adjacency data */
+        hr = clear_normals(mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(mesh, NULL);
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, mesh, box_normals, ARRAY_SIZE(box_normals));
+
+        /* Mesh with adjacency data */
+        hr = clear_normals(mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
+
+        /* Mesh with custom vertex format, D3DDECLTYPE_FLOAT4 normals and adjacency */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, normal4f_position3f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = clear_normals(cloned_mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh with D3DDECLTYPE_FLOAT1 positions and D3DDECLTYPE_FLOAT3 normals */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, position1f_normal3f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = clear_normals(cloned_mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position1f, ARRAY_SIZE(box_normals_position1f));
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh with D3DDECLTYPE_FLOAT2 positions and D3DDECLTYPE_FLOAT3 normals */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, position2f_normal3f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = clear_normals(cloned_mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position2f, ARRAY_SIZE(box_normals_position2f));
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh with D3DDECLTYPE_FLOAT4 positions and D3DDECLTYPE_FLOAT3 normals */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, position4f_normal3f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = clear_normals(cloned_mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+    }
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
+            ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
+            ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
+
+    refcount = mesh->lpVtbl->Release(mesh);
+    ok(!refcount, "Mesh has %u references left\n", refcount);
+    refcount = ID3DXBuffer_Release(adjacency);
+    ok(!refcount, "Buffer has %u references left\n", refcount);
+
+    hr = D3DXCreateSphere(device, 1.0f, 4, 6, &mesh, &adjacency);
+    ok(SUCCEEDED(hr), "D3DXCreateSphere failed %#x\n", hr);
+
+    for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
+    {
+        const struct compute_normals_func *func = &compute_normals_funcs[i];
+
+        /* Sphere without adjacency data */
+        hr = clear_normals(mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(mesh, NULL);
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
+
+        /* Sphere with adjacency data */
+        hr = clear_normals(mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
+    }
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
+            ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
+            ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
+
+    refcount = mesh->lpVtbl->Release(mesh);
+    ok(!refcount, "Mesh has %u references left\n", refcount);
+    refcount = ID3DXBuffer_Release(adjacency);
+    ok(!refcount, "Buffer has %u references left\n", refcount);
+
+    free_test_context(test_context);
+}
+
+static void D3DXCreateAnimationControllerTest(void)
+{
+    HRESULT hr;
+    ID3DXAnimationController *animation;
+    UINT value;
+
+    hr = D3DXCreateAnimationController(0, 0, 0, 0, NULL);
+    ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
+
+    animation = (void*)0xdeadbeef;
+    hr = D3DXCreateAnimationController(0, 1, 1, 1, &animation);
+    ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
+    ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
+
+    animation = (void*)0xdeadbeef;
+    hr = D3DXCreateAnimationController(1, 0, 1, 1, &animation);
+    ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
+    ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
+
+    animation = (void*)0xdeadbeef;
+    hr = D3DXCreateAnimationController(1, 1, 0, 1, &animation);
+    ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
+    ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
+
+    animation = (void*)0xdeadbeef;
+    hr = D3DXCreateAnimationController(1, 1, 1, 0, &animation);
+    ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
+    ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
+
+    hr = D3DXCreateAnimationController(1, 1, 1, 1, &animation);
+    ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
+
+    value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
+    ok(value == 1, "Got unexpected value %u.\n", value);
+
+    value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
+    ok(value == 1, "Got unexpected value %u.\n", value);
+
+    value = animation->lpVtbl->GetMaxNumTracks(animation);
+    ok(value == 1, "Got unexpected value %u.\n", value);
+
+    value = animation->lpVtbl->GetMaxNumEvents(animation);
+    ok(value == 1, "Got unexpected value %u.\n", value);
+
+    animation->lpVtbl->Release(animation);
+
+    hr = D3DXCreateAnimationController(100, 101, 102, 103, &animation);
+    ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
+
+    value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
+    ok(value == 100, "Got unexpected value %u.\n", value);
+
+    value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
+    ok(value == 101, "Got unexpected value %u.\n", value);
+
+    value = animation->lpVtbl->GetMaxNumTracks(animation);
+    ok(value == 102, "Got unexpected value %u.\n", value);
+
+    value = animation->lpVtbl->GetMaxNumEvents(animation);
+    ok(value == 103, "Got unexpected value %u.\n", value);
+
+    animation->lpVtbl->Release(animation);
+}
+
+static void test_D3DXFrameFind(void)
+{
+    static char n1[] = "name1";
+    static char n2[] = "name2";
+    static char n3[] = "name3";
+    static char n4[] = "name4";
+    static char n5[] = "name5";
+    static char n6[] = "name6";
+    static char N1[] = "Name1";
+    D3DXFRAME root, sibling, sibling2, child, *ret;
+    D3DXFRAME child2, child3;
+
+    ret = D3DXFrameFind(NULL, NULL);
+    ok(ret == NULL, "Unexpected frame, %p.\n", ret);
+
+    ret = D3DXFrameFind(NULL, "test");
+    ok(ret == NULL, "Unexpected frame, %p.\n", ret);
+
+    memset(&root, 0, sizeof(root));
+
+    ret = D3DXFrameFind(&root, NULL);
+    ok(ret == &root, "Unexpected frame, %p.\n", ret);
+
+    root.Name = n1;
+    ret = D3DXFrameFind(&root, NULL);
+    ok(ret == NULL, "Unexpected frame, %p.\n", ret);
+
+    ret = D3DXFrameFind(&root, n1);
+    ok(ret == &root, "Unexpected frame, %p.\n", ret);
+
+    ret = D3DXFrameFind(&root, N1);
+    ok(ret == NULL, "Unexpected frame, %p.\n", ret);
+
+    /* Test siblings order traversal. */
+    memset(&sibling, 0, sizeof(sibling));
+    sibling.Name = n2;
+    root.pFrameSibling = &sibling;
+    ret = D3DXFrameFind(&root, n2);
+    ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
+
+    memset(&sibling2, 0, sizeof(sibling2));
+    sibling2.Name = n2;
+    sibling.pFrameSibling = &sibling2;
+    ret = D3DXFrameFind(&root, n2);
+    ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
+
+    sibling2.Name = n3;
+    ret = D3DXFrameFind(&root, n3);
+    ok(ret == &sibling2, "Unexpected frame, %p.\n", ret);
+
+    /* Siblings first. */
+    memset(&child, 0, sizeof(child));
+    child.Name = n2;
+    root.pFrameFirstChild = &child;
+    ret = D3DXFrameFind(&root, n2);
+    ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
+
+    child.Name = n4;
+    ret = D3DXFrameFind(&root, n4);
+    ok(ret == &child, "Unexpected frame, %p.\n", ret);
+
+    /* Link a grandchild and another one for sibling. */
+    memset(&child2, 0, sizeof(child2));
+    memset(&child3, 0, sizeof(child3));
+    child2.Name = child3.Name = n5;
+    sibling.pFrameFirstChild = &child2;
+    child.pFrameFirstChild = &child3;
+    ret = D3DXFrameFind(&root, n5);
+    ok(ret == &child2, "Unexpected frame, %p.\n", ret);
+
+    child3.Name = n6;
+    ret = D3DXFrameFind(&root, n6);
+    ok(ret == &child3, "Unexpected frame, %p.\n", ret);
+}
+
+START_TEST(mesh)
+{
+    D3DXBoundProbeTest();
+    D3DXComputeBoundingBoxTest();
+    D3DXComputeBoundingSphereTest();
+    D3DXGetFVFVertexSizeTest();
+    D3DXIntersectTriTest();
+    D3DXCreateMeshTest();
+    D3DXCreateMeshFVFTest();
+    D3DXLoadMeshTest();
+    D3DXCreateBoxTest();
+    D3DXCreatePolygonTest();
+    D3DXCreateSphereTest();
+    D3DXCreateCylinderTest();
+    D3DXCreateTextTest();
+    D3DXCreateTorusTest();
+    D3DXCreateAnimationControllerTest();
+    test_get_decl_length();
+    test_get_decl_vertex_size();
+    test_fvf_decl_conversion();
+    D3DXGenerateAdjacencyTest();
+    test_update_semantics();
+    test_create_skin_info();
+    test_convert_adjacency_to_point_reps();
+    test_convert_point_reps_to_adjacency();
+    test_weld_vertices();
+    test_clone_mesh();
+    test_valid_mesh();
+    test_optimize_faces();
+    test_compute_normals();
+    test_D3DXFrameFind();
+}
diff --git a/modules/rostests/winetests/d3dx9_36/res.vsh b/modules/rostests/winetests/d3dx9_36/res.vsh
new file mode 100644 (file)
index 0000000..9683748
--- /dev/null
@@ -0,0 +1,2 @@
+#define REGISTER r0
+vs.1.1
diff --git a/modules/rostests/winetests/d3dx9_36/resources.h b/modules/rostests/winetests/d3dx9_36/resources.h
new file mode 100644 (file)
index 0000000..44e64b3
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2009 Tony Wasserka
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_D3DX9_36_TEST_RESOURCES_H
+#define __WINE_D3DX9_36_TEST_RESOURCES_H
+
+#define IDB_BITMAP_1x1       10
+#define IDD_BITMAPDATA_1x1   11
+#define IDS_STRING           12
+
+#define IDB_ASMSHADER        20
+
+#endif  /* __WINE_D3DX9_36_TEST_RESOURCES_H */
diff --git a/modules/rostests/winetests/d3dx9_36/rsrc.rc b/modules/rostests/winetests/d3dx9_36/rsrc.rc
new file mode 100644 (file)
index 0000000..6b282a2
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2009 Tony Wasserka
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "resources.h"
+
+STRINGTABLE
+{
+    IDS_STRING "nobitmap"
+}
+
+/* @makedep: bmp1x1.bmp */
+IDB_BITMAP_1x1 BITMAP bmp1x1.bmp
+IDD_BITMAPDATA_1x1 RCDATA bmp1x1.bmp
+
+/* @makedep: res.vsh */
+IDB_ASMSHADER RCDATA res.vsh
diff --git a/modules/rostests/winetests/d3dx9_36/shader.c b/modules/rostests/winetests/d3dx9_36/shader.c
new file mode 100644 (file)
index 0000000..b67ffb2
--- /dev/null
@@ -0,0 +1,6592 @@
+/*
+ * Copyright 2008 Luis Busquets
+ * Copyright 2011 Travis Athougies
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "wine/test.h"
+#include "d3dx9.h"
+
+#define FCC_TEXT MAKEFOURCC('T','E','X','T')
+#define FCC_CTAB MAKEFOURCC('C','T','A','B')
+
+static const DWORD shader_zero[] = {0x0};
+
+static const DWORD shader_invalid[] = {0xeeee0100};
+
+static const DWORD shader_empty[] = {0xfffe0200, 0x0000ffff};
+
+static const DWORD simple_fx[] = {0x46580000, 0x0002fffe, FCC_TEXT, 0x00000000, 0x0000ffff};
+
+static const DWORD simple_tx[] = {0x54580000, 0x0002fffe, FCC_TEXT, 0x00000000, 0x0000ffff};
+
+static const DWORD simple_7ffe[] = {0x7ffe0000, 0x0002fffe, FCC_TEXT, 0x00000000, 0x0000ffff};
+
+static const DWORD simple_7fff[] = {0x7fff0000, 0x0002fffe, FCC_TEXT, 0x00000000, 0x0000ffff};
+
+static const DWORD simple_vs[] = {
+    0xfffe0101,                                                             /* vs_1_1                       */
+    0x0000001f, 0x80000000, 0x900f0000,                                     /* dcl_position0 v0             */
+    0x00000009, 0xc0010000, 0x90e40000, 0xa0e40000,                         /* dp4 oPos.x, v0, c0           */
+    0x00000009, 0xc0020000, 0x90e40000, 0xa0e40001,                         /* dp4 oPos.y, v0, c1           */
+    0x00000009, 0xc0040000, 0x90e40000, 0xa0e40002,                         /* dp4 oPos.z, v0, c2           */
+    0x00000009, 0xc0080000, 0x90e40000, 0xa0e40003,                         /* dp4 oPos.w, v0, c3           */
+    0x0000ffff};                                                            /* END                          */
+
+static const DWORD simple_ps[] = {
+    0xffff0101,                                                             /* ps_1_1                       */
+    0x00000051, 0xa00f0001, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, /* def c1 = 1.0, 0.0, 0.0, 0.0  */
+    0x00000042, 0xb00f0000,                                                 /* tex t0                       */
+    0x00000008, 0x800f0000, 0xa0e40001, 0xa0e40000,                         /* dp3 r0, c1, c0               */
+    0x00000005, 0x800f0000, 0x90e40000, 0x80e40000,                         /* mul r0, v0, r0               */
+    0x00000005, 0x800f0000, 0xb0e40000, 0x80e40000,                         /* mul r0, t0, r0               */
+    0x0000ffff};                                                            /* END                          */
+
+static const DWORD shader_with_ctab[] = {
+    0xfffe0300,                                                             /* vs_3_0                       */
+    0x0002fffe, FCC_TEXT,   0x00000000,                                     /* TEXT comment                 */
+    0x0008fffe, FCC_CTAB,   0x0000001c, 0x00000010, 0xfffe0300, 0x00000000, /* CTAB comment                 */
+                0x00000000, 0x00000000, 0x00000000,
+    0x0004fffe, FCC_TEXT,   0x00000000, 0x00000000, 0x00000000,             /* TEXT comment                 */
+    0x0000ffff};                                                            /* END                          */
+
+static const DWORD shader_with_invalid_ctab[] = {
+    0xfffe0300,                                                             /* vs_3_0                       */
+    0x0005fffe, FCC_CTAB,                                                   /* CTAB comment                 */
+                0x0000001c, 0x000000a9, 0xfffe0300,
+                0x00000000, 0x00000000,
+    0x0000ffff};                                                            /* END                          */
+
+static const DWORD shader_with_ctab_constants[] = {
+    0xfffe0300,                                                             /* vs_3_0                       */
+    0x002efffe, FCC_CTAB,                                                   /* CTAB comment                 */
+    0x0000001c, 0x000000a4, 0xfffe0300, 0x00000003, 0x0000001c, 0x20008100, /* Header                       */
+    0x0000009c,
+    0x00000058, 0x00070002, 0x00000001, 0x00000064, 0x00000000,             /* Constant 1 desc              */
+    0x00000074, 0x00000002, 0x00000004, 0x00000080, 0x00000000,             /* Constant 2 desc              */
+    0x00000090, 0x00040002, 0x00000003, 0x00000080, 0x00000000,             /* Constant 3 desc              */
+    0x736e6f43, 0x746e6174, 0xabab0031,                                     /* Constant 1 name string       */
+    0x00030001, 0x00040001, 0x00000001, 0x00000000,                         /* Constant 1 type desc         */
+    0x736e6f43, 0x746e6174, 0xabab0032,                                     /* Constant 2 name string       */
+    0x00030003, 0x00040004, 0x00000001, 0x00000000,                         /* Constant 2 & 3 type desc     */
+    0x736e6f43, 0x746e6174, 0xabab0033,                                     /* Constant 3 name string       */
+    0x335f7376, 0xab00305f,                                                 /* Target name string           */
+    0x656e6957, 0x6f727020, 0x7463656a, 0xababab00,                         /* Creator name string          */
+    0x0000ffff};                                                            /* END                          */
+
+static const DWORD ctab_basic[] = {
+    0xfffe0300,                                                             /* vs_3_0                       */
+    0x0040fffe, FCC_CTAB,                                                   /* CTAB comment                 */
+    0x0000001c, 0x000000ec, 0xfffe0300, 0x00000005, 0x0000001c, 0x20008100, /* Header                       */
+    0x000000e4,
+    0x00000080, 0x00060002, 0x00000001, 0x00000084, 0x00000000,             /* Constant 1 desc (f)          */
+    0x00000094, 0x00070002, 0x00000001, 0x00000098, 0x00000000,             /* Constant 2 desc (f4)         */
+    0x000000A8, 0x00040002, 0x00000001, 0x000000AC, 0x00000000,             /* Constant 3 desc (i)          */
+    0x000000BC, 0x00050002, 0x00000001, 0x000000C0, 0x00000000,             /* Constant 4 desc (i4)         */
+    0x000000D0, 0x00000002, 0x00000004, 0x000000D4, 0x00000000,             /* Constant 5 desc (mvp)        */
+    0xabab0066, 0x00030000, 0x00010001, 0x00000001, 0x00000000,             /* Constant 1 name/type desc    */
+    0xab003466, 0x00030001, 0x00040001, 0x00000001, 0x00000000,             /* Constant 2 name/type desc    */
+    0xabab0069, 0x00020000, 0x00010001, 0x00000001, 0x00000000,             /* Constant 3 name/type desc    */
+    0xab003469, 0x00020001, 0x00040001, 0x00000001, 0x00000000,             /* Constant 4 name/type desc    */
+    0x0070766d, 0x00030003, 0x00040004, 0x00000001, 0x00000000,             /* Constant 5 name/type desc    */
+    0x335f7376, 0xab00305f,                                                 /* Target name string           */
+    0x656e6957, 0x6f727020, 0x7463656a, 0xababab00,                         /* Creator name string          */
+    0x0000ffff};                                                            /* END                          */
+
+static const D3DXCONSTANT_DESC ctab_basic_expected[] = {
+    {"mvp", D3DXRS_FLOAT4, 0, 4, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 4, 4, 1, 0, 64, NULL},
+    {"i",   D3DXRS_FLOAT4, 4, 1, D3DXPC_SCALAR,         D3DXPT_INT,   1, 1, 1, 0,  4, NULL},
+    {"i4",  D3DXRS_FLOAT4, 5, 1, D3DXPC_VECTOR,         D3DXPT_INT,   1, 4, 1, 0, 16, NULL},
+    {"f",   D3DXRS_FLOAT4, 6, 1, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1, 1, 1, 0,  4, NULL},
+    {"f4",  D3DXRS_FLOAT4, 7, 1, D3DXPC_VECTOR,         D3DXPT_FLOAT, 1, 4, 1, 0, 16, NULL}};
+
+static const DWORD ctab_matrices[] = {
+    0xfffe0300,                                                             /* vs_3_0                       */
+    0x0032fffe, FCC_CTAB,                                                   /* CTAB comment                 */
+    0x0000001c, 0x000000b4, 0xfffe0300, 0x00000003, 0x0000001c, 0x20008100, /* Header                       */
+    0x000000ac,
+    0x00000058, 0x00070002, 0x00000001, 0x00000064, 0x00000000,             /* Constant 1 desc (fmatrix3x1) */
+    0x00000074, 0x00000002, 0x00000004, 0x00000080, 0x00000000,             /* Constant 2 desc (fmatrix4x4) */
+    0x00000090, 0x00040002, 0x00000002, 0x0000009c, 0x00000000,             /* Constant 3 desc (imatrix2x3) */
+    0x74616D66, 0x33786972, 0xab003178,                                     /* Constant 1 name              */
+    0x00030003, 0x00010003, 0x00000001, 0x00000000,                         /* Constant 1 type desc         */
+    0x74616D66, 0x34786972, 0xab003478,                                     /* Constant 2 name              */
+    0x00030003, 0x00040004, 0x00000001, 0x00000000,                         /* Constant 2 type desc         */
+    0x74616D69, 0x32786972, 0xab003378,                                     /* Constant 3 name              */
+    0x00020002, 0x00030002, 0x00000001, 0x00000000,                         /* Constant 3 type desc         */
+    0x335f7376, 0xab00305f,                                                 /* Target name string           */
+    0x656e6957, 0x6f727020, 0x7463656a, 0xababab00,                         /* Creator name string          */
+    0x0000ffff};                                                            /* END                          */
+
+static const D3DXCONSTANT_DESC ctab_matrices_expected[] = {
+    {"fmatrix4x4", D3DXRS_FLOAT4, 0, 4, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 4, 4, 1, 0, 64, NULL},
+    {"imatrix2x3", D3DXRS_FLOAT4, 4, 2, D3DXPC_MATRIX_ROWS,    D3DXPT_INT,   2, 3, 1, 0, 24, NULL},
+    {"fmatrix3x1", D3DXRS_FLOAT4, 7, 1, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 3, 1, 1, 0, 12, NULL},
+};
+
+static const DWORD ctab_matrices2[] = {
+    0xfffe0200,                                                             /* vs_2_0                        */
+    0x0058fffe, FCC_CTAB,                                                   /* CTAB comment                  */
+    0x0000001c, 0x0000012b, 0xfffe0200, 0x00000006, 0x0000001c, 0x00000100, /* Header                        */
+    0x00000124,
+    0x00000094, 0x00070002, 0x00000003, 0x0000009c, 0x00000000,             /* Constant 1 desc (c2x3)        */
+    0x000000ac, 0x000d0002, 0x00000002, 0x000000b4, 0x00000000,             /* Constant 2 desc (c3x2)        */
+    0x000000c4, 0x000a0002, 0x00000003, 0x000000cc, 0x00000000,             /* Constant 3 desc (c3x3)        */
+    0x000000dc, 0x000f0002, 0x00000002, 0x000000e4, 0x00000000,             /* Constant 4 desc (r2x3)        */
+    0x000000f4, 0x00040002, 0x00000003, 0x000000fc, 0x00000000,             /* Constant 5 desc (r3x2)        */
+    0x0000010c, 0x00000002, 0x00000004, 0x00000114, 0x00000000,             /* Constant 6 desc (r4x4)        */
+    0x33783263, 0xababab00,                                                 /* Constant 1 name               */
+    0x00030003, 0x00030002, 0x00000001, 0x00000000,                         /* Constant 1 type desc          */
+    0x32783363, 0xababab00,                                                 /* Constant 2 name               */
+    0x00030003, 0x00020003, 0x00000001, 0x00000000,                         /* Constant 2 type desc          */
+    0x33783363, 0xababab00,                                                 /* Constant 3 name               */
+    0x00030003, 0x00030003, 0x00000001, 0x00000000,                         /* Constant 3 type desc          */
+    0x33783272, 0xababab00,                                                 /* Constant 4 name               */
+    0x00030002, 0x00030002, 0x00000001, 0x00000000,                         /* Constant 4 type desc          */
+    0x32783372, 0xababab00,                                                 /* Constant 5 name               */
+    0x00030002, 0x00020003, 0x00000001, 0x00000000,                         /* Constant 5 type desc          */
+    0x34783472, 0xababab00,                                                 /* Constant 6 name               */
+    0x00030002, 0x00040004, 0x00000001, 0x00000000,                         /* Constant 6 type desc          */
+    0x325f7376, 0x4100305f, 0x41414141, 0x00414141,                         /* Target and Creator name       */
+    0x0000ffff};                                                            /* END                           */
+
+static const D3DXCONSTANT_DESC ctab_matrices2_expected[] = {
+    {"c2x3", D3DXRS_FLOAT4,  7, 3, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 2, 3, 1, 0, 24, NULL},
+    {"c3x2", D3DXRS_FLOAT4, 13, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 3, 2, 1, 0, 24, NULL},
+    {"c3x3", D3DXRS_FLOAT4, 10, 3, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 3, 3, 1, 0, 36, NULL},
+    {"r2x3", D3DXRS_FLOAT4, 15, 2, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 2, 3, 1, 0, 24, NULL},
+    {"r3x2", D3DXRS_FLOAT4,  4, 3, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 3, 2, 1, 0, 24, NULL},
+    {"r4x4", D3DXRS_FLOAT4,  0, 4, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 4, 4, 1, 0, 64, NULL}};
+
+static const DWORD ctab_arrays[] = {
+    0xfffe0300,                                                             /* vs_3_0                       */
+    0x0052fffe, FCC_CTAB,                                                   /* CTAB comment                 */
+    0x0000001c, 0x0000013c, 0xfffe0300, 0x00000006, 0x0000001c, 0x20008100, /* Header                       */
+    0x00000134,
+    0x00000094, 0x000E0002, 0x00000002, 0x0000009c, 0x00000000,             /* Constant 1 desc (barray)     */
+    0x000000ac, 0x00100002, 0x00000002, 0x000000b8, 0x00000000,             /* Constant 2 desc (bvecarray)  */
+    0x000000c8, 0x00080002, 0x00000004, 0x000000d0, 0x00000000,             /* Constant 3 desc (farray)     */
+    0x000000e0, 0x00000002, 0x00000008, 0x000000ec, 0x00000000,             /* Constant 4 desc (fmtxarray)  */
+    0x000000fc, 0x000C0002, 0x00000002, 0x00000108, 0x00000000,             /* Constant 5 desc (fvecarray)  */
+    0x00000118, 0x00120002, 0x00000001, 0x00000124, 0x00000000,             /* Constant 6 desc (ivecarray)  */
+    0x72726162, 0xab007961,                                                 /* Constant 1 name              */
+    0x00010000, 0x00010001, 0x00000002, 0x00000000,                         /* Constant 1 type desc         */
+    0x63657662, 0x61727261, 0xabab0079,                                     /* Constant 2 name              */
+    0x00010001, 0x00030001, 0x00000003, 0x00000000,                         /* Constant 2 type desc         */
+    0x72726166, 0xab007961,                                                 /* Constant 3 name              */
+    0x00030000, 0x00010001, 0x00000004, 0x00000000,                         /* constant 3 type desc         */
+    0x78746d66, 0x61727261, 0xabab0079,                                     /* Constant 4 name              */
+    0x00030002, 0x00040004, 0x00000002, 0x00000000,                         /* Constant 4 type desc         */
+    0x63657666, 0x61727261, 0xabab0079,                                     /* Constant 5 name              */
+    0x00030001, 0x00040001, 0x00000002, 0x00000000,                         /* Constant 5 type desc         */
+    0x63657669, 0x61727261, 0xabab0079,                                     /* Constant 6 name              */
+    0x00020001, 0x00040001, 0x00000001, 0x00000000,                         /* Constant 6 type desc         */
+    0x335f7376, 0xab00305f,                                                 /* Target name string           */
+    0x656e6957, 0x6f727020, 0x7463656a, 0xababab00,                         /* Creator name string          */
+    0x0000ffff};                                                            /* END                          */
+
+static const D3DXCONSTANT_DESC ctab_arrays_expected[] = {
+    {"fmtxarray", D3DXRS_FLOAT4,  0, 8, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 4, 2, 0, 128, NULL},
+    {"farray",    D3DXRS_FLOAT4,  8, 4, D3DXPC_SCALAR,      D3DXPT_FLOAT, 1, 1, 4, 0,  16, NULL},
+    {"fvecarray", D3DXRS_FLOAT4, 12, 2, D3DXPC_VECTOR,      D3DXPT_FLOAT, 1, 4, 2, 0,  32, NULL},
+    {"barray",    D3DXRS_FLOAT4, 14, 2, D3DXPC_SCALAR,      D3DXPT_BOOL,  1, 1, 2, 0,   8, NULL},
+    {"bvecarray", D3DXRS_FLOAT4, 16, 2, D3DXPC_VECTOR,      D3DXPT_BOOL,  1, 3, 3, 0,  36, NULL},
+    {"ivecarray", D3DXRS_FLOAT4, 18, 1, D3DXPC_VECTOR,      D3DXPT_INT,   1, 4, 1, 0,  16, NULL}};
+
+static const DWORD ctab_with_default_values[] = {
+    0xfffe0200,                                                 /* vs_2_0 */
+    0x007bfffe, FCC_CTAB,                                       /* CTAB comment */
+    0x0000001c, 0x000001b7, 0xfffe0200, 0x00000005, 0x0000001c, /* header */
+    0x00000100, 0x000001b0,
+    0x00000080, 0x00080002, 0x00000003, 0x00000084, 0x00000094, /* constant 1 desc (arr) */
+    0x000000c4, 0x000c0002, 0x00000001, 0x000000c8, 0x000000d8, /* constant 2 desc (flt) */
+    0x000000e8, 0x00040002, 0x00000004, 0x000000f0, 0x00000100, /* constant 3 desc (mat3) */
+    0x00000140, 0x00000002, 0x00000004, 0x000000f0, 0x00000148, /* constant 4 desc (mat4) */
+    0x00000188, 0x000b0002, 0x00000001, 0x00000190, 0x000001a0, /* constant 5 desc (vec4) */
+    0x00727261,                                                 /* constant 1 name */
+    0x00030000, 0x00010001, 0x00000003, 0x00000000,             /* constant 1 type desc */
+    0x42c80000, 0x00000000, 0x00000000, 0x00000000,             /* constant 1 default value */
+    0x43480000, 0x00000000, 0x00000000, 0x00000000,
+    0x43960000, 0x00000000, 0x00000000, 0x00000000,
+    0x00746c66,                                                 /* constant 2 name */
+    0x00030000, 0x00010001, 0x00000001, 0x00000000,             /* constant 2 type desc */
+    0x411fd70a, 0x00000000, 0x00000000, 0x00000000,             /* constant 2 default value */
+    0x3374616d,                                                 /* constant 3 name */
+    0xababab00,
+    0x00030003, 0x00040004, 0x00000001, 0x00000000,             /* constant 3 & 4 type desc */
+    0x41300000, 0x425c0000, 0x42c60000, 0x44a42000,             /* constat 3 default value */
+    0x41b00000, 0x42840000, 0x447c8000, 0x44b0c000,
+    0x42040000, 0x429a0000, 0x448ae000, 0x44bd6000,
+    0x42300000, 0x42b00000, 0x44978000, 0x44ca0000,
+    0x3474616d,                                                 /* constant 4 name */
+    0xababab00,
+    0x3f800000, 0x40a00000, 0x41100000, 0x41500000,             /* constant 4 default value */
+    0x40000000, 0x40c00000, 0x41200000, 0x41600000,
+    0x40400000, 0x40e00000, 0x41300000, 0x41700000,
+    0x40800000, 0x41000000, 0x41400000, 0x41800000,
+    0x34636576,                                                 /* constant 5 name */
+    0xababab00,
+    0x00030001, 0x00040001, 0x00000001, 0x00000000,             /* constant 5 type desc */
+    0x41200000, 0x41a00000, 0x41f00000, 0x42200000,             /* constant 5 default value */
+    0x325f7376, 0x4d004141, 0x41414141, 0x00000000,             /* target & creator string */
+    0x0000ffff};                                                /* END */
+
+static const float mat4_default_value[] = {1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16};
+static const float mat3_default_value[] = {11, 55, 99, 1313, 22, 66, 1010, 1414, 33, 77, 1111, 1515, 44, 88, 1212, 1616};
+static const float arr_default_value[] = {100, 0, 0, 0, 200, 0, 0, 0, 300, 0, 0, 0};
+static const float vec4_default_value[] = {10, 20, 30, 40};
+static const float flt_default_value[] = {9.99, 0, 0, 0};
+
+static const D3DXCONSTANT_DESC ctab_with_default_values_expected[] = {
+    {"mat4", D3DXRS_FLOAT4,  0, 4, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 4, 4, 1, 0, 64, mat4_default_value},
+    {"mat3", D3DXRS_FLOAT4,  4, 4, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 4, 4, 1, 0, 64, mat3_default_value},
+    {"arr",  D3DXRS_FLOAT4,  8, 3, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1, 1, 3, 0, 12, arr_default_value},
+    {"vec4", D3DXRS_FLOAT4, 11, 1, D3DXPC_VECTOR,         D3DXPT_FLOAT, 1, 4, 1, 0, 16, vec4_default_value},
+    {"flt",  D3DXRS_FLOAT4, 12, 1, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1, 1, 1, 0,  4, flt_default_value}};
+
+static const DWORD ctab_samplers[] = {
+    0xfffe0300,                                                             /* vs_3_0                        */
+    0x0032fffe, FCC_CTAB,                                                   /* CTAB comment                  */
+    0x0000001c, 0x000000b4, 0xfffe0300, 0x00000003, 0x0000001c, 0x20008100, /* Header                        */
+    0x000000ac,
+    0x00000058, 0x00020002, 0x00000001, 0x00000064, 0x00000000,             /* Constant 1 desc (notsampler)  */
+    0x00000074, 0x00000003, 0x00000001, 0x00000080, 0x00000000,             /* Constant 2 desc (sampler1)    */
+    0x00000090, 0x00030003, 0x00000001, 0x0000009c, 0x00000000,             /* Constant 3 desc (sampler2)    */
+    0x73746f6e, 0x6c706d61, 0xab007265,                                     /* Constant 1 name               */
+    0x00030001, 0x00040001, 0x00000001, 0x00000000,                         /* Constant 1 type desc          */
+    0x706d6173, 0x3172656c, 0xababab00,                                     /* Constant 2 name               */
+    0x000c0004, 0x00010001, 0x00000001, 0x00000000,                         /* Constant 2 type desc          */
+    0x706d6173, 0x3272656c, 0xababab00,                                     /* Constant 3 name               */
+    0x000d0004, 0x00010001, 0x00000001, 0x00000000,                         /* Constant 3 type desc          */
+    0x335f7376, 0xab00305f,                                                 /* Target name string            */
+    0x656e6957, 0x6f727020, 0x7463656a, 0xababab00,                         /* Creator name string           */
+    0x0000ffff};                                                            /* END                           */
+
+static const D3DXCONSTANT_DESC ctab_samplers_expected[] = {
+    {"sampler1",   D3DXRS_SAMPLER, 0, 1, D3DXPC_OBJECT, D3DXPT_SAMPLER2D, 1, 1, 1, 0, 4,  NULL},
+    {"sampler2",   D3DXRS_SAMPLER, 3, 1, D3DXPC_OBJECT, D3DXPT_SAMPLER3D, 1, 1, 1, 0, 4,  NULL},
+    {"notsampler", D3DXRS_FLOAT4,  2, 1, D3DXPC_VECTOR, D3DXPT_FLOAT,     1, 4, 1, 0, 16, NULL}};
+
+static const DWORD fx_shader_with_ctab[] =
+{
+    0x46580200,                                                             /* FX20                     */
+    0x002efffe, FCC_CTAB,                                                   /* CTAB comment             */
+    0x0000001c, 0x000000a4, 0xfffe0300, 0x00000003, 0x0000001c, 0x20008100, /* Header                   */
+    0x0000009c,
+    0x00000058, 0x00070002, 0x00000001, 0x00000064, 0x00000000,             /* Constant 1 desc          */
+    0x00000074, 0x00000002, 0x00000004, 0x00000080, 0x00000000,             /* Constant 2 desc          */
+    0x00000090, 0x00040002, 0x00000003, 0x00000080, 0x00000000,             /* Constant 3 desc          */
+    0x736e6f43, 0x746e6174, 0xabab0031,                                     /* Constant 1 name string   */
+    0x00030001, 0x00040001, 0x00000001, 0x00000000,                         /* Constant 1 type desc     */
+    0x736e6f43, 0x746e6174, 0xabab0032,                                     /* Constant 2 name string   */
+    0x00030003, 0x00040004, 0x00000001, 0x00000000,                         /* Constant 2 & 3 type desc */
+    0x736e6f43, 0x746e6174, 0xabab0033,                                     /* Constant 3 name string   */
+    0x335f7376, 0xab00305f,                                                 /* Target name string       */
+    0x656e6957, 0x6f727020, 0x7463656a, 0xababab00,                         /* Creator name string      */
+    0x0000ffff                                                              /* END                      */
+};
+
+static void test_get_shader_size(void)
+{
+    UINT shader_size, expected;
+
+    shader_size = D3DXGetShaderSize(simple_vs);
+    expected = sizeof(simple_vs);
+    ok(shader_size == expected, "Got shader size %u, expected %u\n", shader_size, expected);
+
+    shader_size = D3DXGetShaderSize(simple_ps);
+    expected = sizeof(simple_ps);
+    ok(shader_size == expected, "Got shader size %u, expected %u\n", shader_size, expected);
+
+    shader_size = D3DXGetShaderSize(NULL);
+    ok(shader_size == 0, "Got shader size %u, expected 0\n", shader_size);
+}
+
+static void test_get_shader_version(void)
+{
+    DWORD shader_version;
+
+    shader_version = D3DXGetShaderVersion(simple_vs);
+    ok(shader_version == D3DVS_VERSION(1, 1), "Got shader version 0x%08x, expected 0x%08x\n",
+            shader_version, D3DVS_VERSION(1, 1));
+
+    shader_version = D3DXGetShaderVersion(simple_ps);
+    ok(shader_version == D3DPS_VERSION(1, 1), "Got shader version 0x%08x, expected 0x%08x\n",
+            shader_version, D3DPS_VERSION(1, 1));
+
+    shader_version = D3DXGetShaderVersion(NULL);
+    ok(shader_version == 0, "Got shader version 0x%08x, expected 0\n", shader_version);
+}
+
+static void test_find_shader_comment(void)
+{
+    const void *data = (void *)0xdeadbeef;
+    HRESULT hr;
+    UINT size = 100;
+
+    hr = D3DXFindShaderComment(NULL, MAKEFOURCC('C','T','A','B'), &data, &size);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+    ok(!data, "Got %p, expected NULL\n", data);
+    ok(!size, "Got %u, expected 0\n", size);
+
+    hr = D3DXFindShaderComment(shader_with_ctab, MAKEFOURCC('C','T','A','B'), NULL, &size);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    ok(size == 28, "Got %u, expected 28\n", size);
+
+    hr = D3DXFindShaderComment(shader_with_ctab, MAKEFOURCC('C','T','A','B'), &data, NULL);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    ok(data == shader_with_ctab + 6, "Got result %p, expected %p\n", data, shader_with_ctab + 6);
+
+    hr = D3DXFindShaderComment(shader_with_ctab, 0, &data, &size);
+    ok(hr == S_FALSE, "Got result %x, expected 1 (S_FALSE)\n", hr);
+    ok(!data, "Got %p, expected NULL\n", data);
+    ok(!size, "Got %u, expected 0\n", size);
+
+    hr = D3DXFindShaderComment(shader_with_ctab, MAKEFOURCC('X','X','X','X'), &data, &size);
+    ok(hr == S_FALSE, "Got result %x, expected 1 (S_FALSE)\n", hr);
+    ok(!data, "Got %p, expected NULL\n", data);
+    ok(!size, "Got %u, expected 0\n", size);
+
+    hr = D3DXFindShaderComment(shader_with_ctab, MAKEFOURCC('C','T','A','B'), &data, &size);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    ok(data == shader_with_ctab + 6, "Got result %p, expected %p\n", data, shader_with_ctab + 6);
+    ok(size == 28, "Got result %u, expected 28\n", size);
+
+    hr = D3DXFindShaderComment(shader_zero, MAKEFOURCC('C','T','A','B'), &data, &size);
+    ok(hr == D3DXERR_INVALIDDATA, "Got result %x, expected %x (D3DXERR_INVALIDDATA)\n", hr, D3DXERR_INVALIDDATA);
+    ok(!data, "Got %p, expected NULL\n", data);
+    ok(!size, "Got %u, expected 0\n", size);
+
+    hr = D3DXFindShaderComment(shader_invalid, MAKEFOURCC('C','T','A','B'), &data, &size);
+    ok(hr == D3DXERR_INVALIDDATA, "Got result %x, expected %x (D3DXERR_INVALIDDATA)\n", hr, D3DXERR_INVALIDDATA);
+    ok(!data, "Got %p, expected NULL\n", data);
+    ok(!size, "Got %u, expected 0\n", size);
+
+    hr = D3DXFindShaderComment(shader_empty, MAKEFOURCC('C','T','A','B'), &data, &size);
+    ok(hr == S_FALSE, "Got result %x, expected %x (S_FALSE)\n", hr, S_FALSE);
+    ok(!data, "Got %p, expected NULL\n", data);
+    ok(!size, "Got %u, expected 0\n", size);
+
+    hr = D3DXFindShaderComment(simple_fx, FCC_TEXT, &data, &size);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    ok(data == simple_fx + 3, "Got result %p, expected %p\n", data, simple_fx + 3);
+    ok(size == 4, "Got result %u, expected 4\n", size);
+
+    hr = D3DXFindShaderComment(simple_tx, FCC_TEXT, &data, &size);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    ok(data == simple_tx + 3, "Got result %p, expected %p\n", data, simple_tx + 3);
+    ok(size == 4, "Got result %u, expected 4\n", size);
+
+    hr = D3DXFindShaderComment(simple_7ffe, FCC_TEXT, &data, &size);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    ok(data == simple_7ffe + 3, "Got result %p, expected %p\n", data, simple_7ffe + 3);
+    ok(size == 4, "Got result %u, expected 4\n", size);
+
+    hr = D3DXFindShaderComment(simple_7fff, FCC_TEXT, &data, &size);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    ok(data == simple_7fff + 3, "Got result %p, expected %p\n", data, simple_7fff + 3);
+    ok(size == 4, "Got result %u, expected 4\n", size);
+}
+
+static void test_get_shader_constant_table_ex(void)
+{
+    ID3DXConstantTable *constant_table;
+    HRESULT hr;
+    void *data;
+    DWORD size;
+    D3DXCONSTANTTABLE_DESC desc;
+
+    constant_table = (ID3DXConstantTable *)0xdeadbeef;
+    hr = D3DXGetShaderConstantTableEx(NULL, 0, &constant_table);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+    ok(constant_table == NULL, "D3DXGetShaderConstantTableEx() failed, got %p\n", constant_table);
+
+    constant_table = (ID3DXConstantTable *)0xdeadbeef;
+    hr = D3DXGetShaderConstantTableEx(shader_zero, 0, &constant_table);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    ok(constant_table == NULL, "D3DXGetShaderConstantTableEx() failed, got %p\n", constant_table);
+
+    constant_table = (ID3DXConstantTable *)0xdeadbeef;
+    hr = D3DXGetShaderConstantTableEx(shader_invalid, 0, &constant_table);
+    ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
+    ok(constant_table == NULL, "D3DXGetShaderConstantTableEx() failed, got %p\n", constant_table);
+
+    constant_table = (ID3DXConstantTable *)0xdeadbeef;
+    hr = D3DXGetShaderConstantTableEx(shader_empty, 0, &constant_table);
+    ok(hr == D3DXERR_INVALIDDATA, "Got result %x, expected %x (D3DXERR_INVALIDDATA)\n", hr, D3DXERR_INVALIDDATA);
+    ok(constant_table == NULL, "D3DXGetShaderConstantTableEx() failed, got %p\n", constant_table);
+
+    /* No CTAB data */
+    constant_table = (ID3DXConstantTable *)0xdeadbeef;
+    hr = D3DXGetShaderConstantTableEx(simple_ps, 0, &constant_table);
+    ok(hr == D3DXERR_INVALIDDATA, "Got result %x, expected %x (D3DXERR_INVALIDDATA)\n", hr, D3DXERR_INVALIDDATA);
+    ok(constant_table == NULL, "D3DXGetShaderConstantTableEx() failed, got %p\n", constant_table);
+
+    /* With invalid CTAB data */
+    hr = D3DXGetShaderConstantTableEx(shader_with_invalid_ctab, 0, &constant_table);
+    ok(hr == D3DXERR_INVALIDDATA || broken(hr == D3D_OK), /* winxp 64-bit, w2k3 64-bit */
+       "Got result %x, expected %x (D3DXERR_INVALIDDATA)\n", hr, D3DXERR_INVALIDDATA);
+    if (constant_table) ID3DXConstantTable_Release(constant_table);
+
+    hr = D3DXGetShaderConstantTableEx(simple_fx, 0, &constant_table);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(!constant_table, "D3DXGetShaderConstantTableEx() returned a non-NULL constant table.\n");
+
+    hr = D3DXGetShaderConstantTableEx(simple_tx, 0, &constant_table);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(!constant_table, "D3DXGetShaderConstantTableEx() returned a non-NULL constant table.\n");
+
+    hr = D3DXGetShaderConstantTableEx(shader_with_ctab, 0, &constant_table);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    ok(constant_table != NULL, "D3DXGetShaderConstantTableEx() failed, got NULL\n");
+
+    if (constant_table)
+    {
+        size = ID3DXConstantTable_GetBufferSize(constant_table);
+        ok(size == 28, "Got result %x, expected 28\n", size);
+
+        data = ID3DXConstantTable_GetBufferPointer(constant_table);
+        ok(!memcmp(data, shader_with_ctab + 6, size), "Retrieved wrong CTAB data\n");
+
+        hr = ID3DXConstantTable_GetDesc(constant_table, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+        hr = ID3DXConstantTable_GetDesc(constant_table, &desc);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+        ok(desc.Creator == (const char *)data + 0x10, "Got result %p, expected %p\n",
+                desc.Creator, (const char *)data + 0x10);
+        ok(desc.Version == D3DVS_VERSION(3, 0), "Got result %x, expected %x\n", desc.Version, D3DVS_VERSION(3, 0));
+        ok(desc.Constants == 0, "Got result %x, expected 0\n", desc.Constants);
+
+        ID3DXConstantTable_Release(constant_table);
+    }
+
+    hr = D3DXGetShaderConstantTableEx(shader_with_ctab_constants, 0, &constant_table);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+    ok(constant_table != NULL, "D3DXGetShaderConstantTableEx() failed, got NULL\n");
+
+    if (constant_table)
+    {
+        D3DXHANDLE constant;
+        D3DXCONSTANT_DESC constant_desc;
+        D3DXCONSTANT_DESC constant_desc_save;
+        UINT nb;
+
+        /* Test GetDesc */
+        hr = ID3DXConstantTable_GetDesc(constant_table, &desc);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+        ok(!strcmp(desc.Creator, "Wine project"), "Got result '%s', expected 'Wine project'\n", desc.Creator);
+        ok(desc.Version == D3DVS_VERSION(3, 0), "Got result %x, expected %x\n", desc.Version, D3DVS_VERSION(3, 0));
+        ok(desc.Constants == 3, "Got result %x, expected 3\n", desc.Constants);
+
+        /* Test GetConstant */
+        constant = ID3DXConstantTable_GetConstant(constant_table, NULL, 0);
+        ok(constant != NULL, "No constant found\n");
+        hr = ID3DXConstantTable_GetConstantDesc(constant_table, constant, &constant_desc, &nb);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+        ok(!strcmp(constant_desc.Name, "Constant1"), "Got result '%s', expected 'Constant1'\n",
+            constant_desc.Name);
+        ok(constant_desc.Class == D3DXPC_VECTOR, "Got result %x, expected %u (D3DXPC_VECTOR)\n",
+            constant_desc.Class, D3DXPC_VECTOR);
+        ok(constant_desc.Type == D3DXPT_FLOAT, "Got result %x, expected %u (D3DXPT_FLOAT)\n",
+            constant_desc.Type, D3DXPT_FLOAT);
+        ok(constant_desc.Rows == 1, "Got result %x, expected 1\n", constant_desc.Rows);
+        ok(constant_desc.Columns == 4, "Got result %x, expected 4\n", constant_desc.Columns);
+
+        constant = ID3DXConstantTable_GetConstant(constant_table, NULL, 1);
+        ok(constant != NULL, "No constant found\n");
+        hr = ID3DXConstantTable_GetConstantDesc(constant_table, constant, &constant_desc, &nb);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+        ok(!strcmp(constant_desc.Name, "Constant2"), "Got result '%s', expected 'Constant2'\n",
+            constant_desc.Name);
+        ok(constant_desc.Class == D3DXPC_MATRIX_COLUMNS, "Got result %x, expected %u (D3DXPC_MATRIX_COLUMNS)\n",
+            constant_desc.Class, D3DXPC_MATRIX_COLUMNS);
+        ok(constant_desc.Type == D3DXPT_FLOAT, "Got result %x, expected %u (D3DXPT_FLOAT)\n",
+            constant_desc.Type, D3DXPT_FLOAT);
+        ok(constant_desc.Rows == 4, "Got result %x, expected 1\n", constant_desc.Rows);
+        ok(constant_desc.Columns == 4, "Got result %x, expected 4\n", constant_desc.Columns);
+
+        constant = ID3DXConstantTable_GetConstant(constant_table, NULL, 2);
+        ok(constant != NULL, "No constant found\n");
+        hr = ID3DXConstantTable_GetConstantDesc(constant_table, constant, &constant_desc, &nb);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+        ok(!strcmp(constant_desc.Name, "Constant3"), "Got result '%s', expected 'Constant3'\n",
+            constant_desc.Name);
+        ok(constant_desc.Class == D3DXPC_MATRIX_COLUMNS, "Got result %x, expected %u (D3DXPC_MATRIX_COLUMNS)\n",
+            constant_desc.Class, D3DXPC_MATRIX_COLUMNS);
+        ok(constant_desc.Type == D3DXPT_FLOAT, "Got result %x, expected %u (D3DXPT_FLOAT)\n",
+            constant_desc.Type, D3DXPT_FLOAT);
+        ok(constant_desc.Rows == 4, "Got result %x, expected 1\n", constant_desc.Rows);
+        ok(constant_desc.Columns == 4, "Got result %x, expected 4\n", constant_desc.Columns);
+        constant_desc_save = constant_desc; /* For GetConstantDesc test */
+
+        constant = ID3DXConstantTable_GetConstant(constant_table, NULL, 3);
+        ok(constant == NULL, "Got result %p, expected NULL\n", constant);
+
+        /* Test GetConstantByName */
+        constant = ID3DXConstantTable_GetConstantByName(constant_table, NULL, "Constant unknown");
+        ok(constant == NULL, "Got result %p, expected NULL\n", constant);
+        constant = ID3DXConstantTable_GetConstantByName(constant_table, NULL, "Constant3");
+        ok(constant != NULL, "No constant found\n");
+        hr = ID3DXConstantTable_GetConstantDesc(constant_table, constant, &constant_desc, &nb);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+        ok(!memcmp(&constant_desc, &constant_desc_save, sizeof(D3DXCONSTANT_DESC)), "Got different constant data\n");
+
+        /* Test GetConstantDesc */
+        constant = ID3DXConstantTable_GetConstant(constant_table, NULL, 0);
+        ok(constant != NULL, "No constant found\n");
+        hr = ID3DXConstantTable_GetConstantDesc(constant_table, NULL, &constant_desc, &nb);
+        ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+        hr = ID3DXConstantTable_GetConstantDesc(constant_table, constant, NULL, &nb);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+        hr = ID3DXConstantTable_GetConstantDesc(constant_table, constant, &constant_desc, NULL);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+        hr = ID3DXConstantTable_GetConstantDesc(constant_table, "Constant unknown", &constant_desc, &nb);
+        ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+        hr = ID3DXConstantTable_GetConstantDesc(constant_table, "Constant3", &constant_desc, &nb);
+        ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
+        ok(!memcmp(&constant_desc, &constant_desc_save, sizeof(D3DXCONSTANT_DESC)), "Got different constant data\n");
+
+        ID3DXConstantTable_Release(constant_table);
+    }
+
+    hr = D3DXGetShaderConstantTableEx(fx_shader_with_ctab, 0, &constant_table);
+    ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK).\n", hr);
+    ok(!constant_table, "D3DXGetShaderConstantTableEx() returned a non-NULL constant table.\n");
+}
+
+static void test_constant_table(const char *test_name, const DWORD *ctable_fn,
+        const D3DXCONSTANT_DESC *expecteds, UINT count)
+{
+    UINT i;
+    ID3DXConstantTable *ctable;
+
+    HRESULT res;
+
+    /* Get the constant table from the shader itself */
+    res = D3DXGetShaderConstantTable(ctable_fn, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed on %s: got %08x\n", test_name, res);
+
+    for (i = 0; i < count; i++)
+    {
+        const D3DXCONSTANT_DESC *expected = &expecteds[i];
+        D3DXHANDLE const_handle;
+        D3DXCONSTANT_DESC actual;
+        UINT pCount = 1;
+
+        const_handle = ID3DXConstantTable_GetConstantByName(ctable, NULL, expected->Name);
+
+        res = ID3DXConstantTable_GetConstantDesc(ctable, const_handle, &actual, &pCount);
+        ok(SUCCEEDED(res), "%s in %s: ID3DXConstantTable_GetConstantDesc returned %08x\n", expected->Name,
+                test_name, res);
+        ok(pCount == 1, "%s in %s: Got more or less descriptions: %d\n", expected->Name, test_name, pCount);
+
+        ok(strcmp(actual.Name, expected->Name) == 0,
+           "%s in %s: Got different names: Got %s, expected %s\n", expected->Name,
+           test_name, actual.Name, expected->Name);
+        ok(actual.RegisterSet == expected->RegisterSet,
+           "%s in %s: Got different register sets: Got %d, expected %d\n",
+           expected->Name, test_name, actual.RegisterSet, expected->RegisterSet);
+        ok(actual.RegisterIndex == expected->RegisterIndex,
+           "%s in %s: Got different register indices: Got %d, expected %d\n",
+           expected->Name, test_name, actual.RegisterIndex, expected->RegisterIndex);
+        ok(actual.RegisterCount == expected->RegisterCount,
+           "%s in %s: Got different register counts: Got %d, expected %d\n",
+           expected->Name, test_name, actual.RegisterCount, expected->RegisterCount);
+        ok(actual.Class == expected->Class,
+           "%s in %s: Got different classes: Got %d, expected %d\n", expected->Name,
+           test_name, actual.Class, expected->Class);
+        ok(actual.Type == expected->Type,
+           "%s in %s: Got different types: Got %d, expected %d\n", expected->Name,
+           test_name, actual.Type, expected->Type);
+        ok(actual.Rows == expected->Rows && actual.Columns == expected->Columns,
+           "%s in %s: Got different dimensions: Got (%d, %d), expected (%d, %d)\n",
+           expected->Name, test_name, actual.Rows, actual.Columns, expected->Rows,
+           expected->Columns);
+        ok(actual.Elements == expected->Elements,
+           "%s in %s: Got different element count: Got %d, expected %d\n",
+           expected->Name, test_name, actual.Elements, expected->Elements);
+        ok(actual.StructMembers == expected->StructMembers,
+           "%s in %s: Got different struct member count: Got %d, expected %d\n",
+           expected->Name, test_name, actual.StructMembers, expected->StructMembers);
+        ok(actual.Bytes == expected->Bytes,
+           "%s in %s: Got different byte count: Got %d, expected %d\n",
+           expected->Name, test_name, actual.Bytes, expected->Bytes);
+
+        if (!expected->DefaultValue)
+        {
+            ok(actual.DefaultValue == NULL,
+                "%s in %s: Got different default value: expected NULL\n",
+                expected->Name, test_name);
+        }
+        else
+        {
+            ok(actual.DefaultValue != NULL,
+                "%s in %s: Got different default value: expected non-NULL\n",
+                expected->Name, test_name);
+            ok(memcmp(actual.DefaultValue, expected->DefaultValue, expected->Bytes) == 0,
+                "%s in %s: Got different default value\n", expected->Name, test_name);
+        }
+    }
+
+    /* Finally, release the constant table */
+    ID3DXConstantTable_Release(ctable);
+}
+
+static void test_constant_tables(void)
+{
+    test_constant_table("test_basic", ctab_basic, ctab_basic_expected,
+            ARRAY_SIZE(ctab_basic_expected));
+    test_constant_table("test_matrices", ctab_matrices, ctab_matrices_expected,
+            ARRAY_SIZE(ctab_matrices_expected));
+    test_constant_table("test_matrices2", ctab_matrices2, ctab_matrices2_expected,
+            ARRAY_SIZE(ctab_matrices2_expected));
+    test_constant_table("test_arrays", ctab_arrays, ctab_arrays_expected,
+            ARRAY_SIZE(ctab_arrays_expected));
+    test_constant_table("test_default_values", ctab_with_default_values, ctab_with_default_values_expected,
+            ARRAY_SIZE(ctab_with_default_values_expected));
+    test_constant_table("test_samplers", ctab_samplers, ctab_samplers_expected,
+            ARRAY_SIZE(ctab_samplers_expected));
+}
+
+static void test_setting_basic_table(IDirect3DDevice9 *device)
+{
+    static const D3DXMATRIX mvp = {{{
+        0.514f, 0.626f, 0.804f, 0.786f,
+        0.238f, 0.956f, 0.374f, 0.483f,
+        0.109f, 0.586f, 0.900f, 0.255f,
+        0.898f, 0.411f, 0.932f, 0.275f}}};
+    static const D3DXVECTOR4 f4 = {0.350f, 0.526f, 0.925f, 0.021f};
+    static const float f = 0.12543f;
+    static const int i = 321;
+    static const D3DXMATRIX *matrix_pointer[] = {&mvp};
+
+    ID3DXConstantTable *ctable;
+
+    HRESULT res;
+    float out[16];
+    ULONG refcnt;
+
+    /* Get the constant table from the shader itself */
+    res = D3DXGetShaderConstantTable(ctab_basic, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed: got 0x%08x\n", res);
+
+    /* Set constants */
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "mvp", &mvp);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed on variable mvp: got 0x%08x\n", res);
+
+    res = ID3DXConstantTable_SetInt(ctable, device, "i", i + 1);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetInt failed on variable i: got 0x%08x\n", res);
+
+    /* Check that setting i again will overwrite the previous value */
+    res = ID3DXConstantTable_SetInt(ctable, device, "i", i);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetInt failed on variable i: got 0x%08x\n", res);
+
+    res = ID3DXConstantTable_SetFloat(ctable, device, "f", f);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetFloat failed on variable f: got 0x%08x\n", res);
+
+    res = ID3DXConstantTable_SetVector(ctable, device, "f4", &f4);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetVector failed on variable f4: got 0x%08x\n", res);
+
+    /* Get constants back and validate */
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 0, out, 4);
+    ok(out[0] == S(U(mvp))._11 && out[4] == S(U(mvp))._12 && out[8] == S(U(mvp))._13 && out[12] == S(U(mvp))._14,
+            "The first row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[4], out[8], out[12], S(U(mvp))._11, S(U(mvp))._12, S(U(mvp))._13, S(U(mvp))._14);
+    ok(out[1] == S(U(mvp))._21 && out[5] == S(U(mvp))._22 && out[9] == S(U(mvp))._23 && out[13] == S(U(mvp))._24,
+            "The second row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[1], out[5], out[9], out[13], S(U(mvp))._21, S(U(mvp))._22, S(U(mvp))._23, S(U(mvp))._24);
+    ok(out[2] == S(U(mvp))._31 && out[6] == S(U(mvp))._32 && out[10] == S(U(mvp))._33 && out[14] == S(U(mvp))._34,
+            "The third row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[2], out[6], out[10], out[14], S(U(mvp))._31, S(U(mvp))._32, S(U(mvp))._33, S(U(mvp))._34);
+    ok(out[3] == S(U(mvp))._41 && out[7] == S(U(mvp))._42 && out[11] == S(U(mvp))._43 && out[15] == S(U(mvp))._44,
+            "The fourth row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[3], out[7], out[11], out[15], S(U(mvp))._41, S(U(mvp))._42, S(U(mvp))._43, S(U(mvp))._44);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 4, out, 1);
+    ok(out[0] == (float)i && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f,
+            "The variable i was not set correctly, out={%f, %f, %f, %f}, should be {%d, 0.0, 0.0, 0.0}\n",
+            out[0], out[1], out[2], out[3], i);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 6, out, 1);
+    ok(out[0] == f && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f,
+            "The variable f was not set correctly, out={%f, %f, %f, %f}, should be {%f, 0.0, 0.0, 0.0}\n",
+            out[0], out[1], out[2], out[3], f);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 1);
+    ok(memcmp(out, &f4, sizeof(f4)) == 0,
+            "The variable f4 was not set correctly, out={%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], f4.x, f4.y, f4.z, f4.w);
+
+    /* Finally test using a set* function for one type to set a variable of another type (should succeed) */
+    res = ID3DXConstantTable_SetVector(ctable, device, "f", &f4);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetVector failed on variable f: 0x%08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 6, out, 1);
+    ok(out[0] == f4.x && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f,
+            "The variable f was not set correctly by ID3DXConstantTable_SetVector, got %f, should be %f\n",
+            out[0], f4.x);
+
+    memset(out, 0, sizeof(out));
+    IDirect3DDevice9_SetVertexShaderConstantF(device, 6, out, 1);
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "f", &mvp);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed on variable f: 0x%08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 6, out, 1);
+    ok(out[0] == S(U(mvp))._11 && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f,
+            "The variable f was not set correctly by ID3DXConstantTable_SetMatrix, got %f, should be %f\n",
+            out[0], S(U(mvp))._11);
+
+    /* Clear registers */
+    memset(out, 0, sizeof(out));
+    IDirect3DDevice9_SetVertexShaderConstantF(device, 0, out, 4);
+    IDirect3DDevice9_SetVertexShaderConstantF(device, 6, out, 1);
+    IDirect3DDevice9_SetVertexShaderConstantF(device, 7, out, 1);
+
+    /* SetVector shouldn't change the value of a matrix constant */
+    res = ID3DXConstantTable_SetVector(ctable, device, "mvp", &f4);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetVector failed on variable f: 0x%08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 0, out, 4);
+    ok(out[0] == 0.0f && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f
+            && out[4] == 0.0f && out[5] == 0.0f && out[6] == 0.0f && out[7] == 0.0f
+            && out[8] == 0.0f && out[9] == 0.0f && out[10] == 0.0f && out[11] == 0.0f
+            && out[12] == 0.0f && out[13] == 0.0f && out[14] == 0.0f && out[15] == 0.0f,
+            "The variable mvp was not set correctly by ID3DXConstantTable_SetVector, "
+            "got {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f %f; %f, %f, %f, %f}, "
+            "should be all 0.0f\n",
+            out[0], out[1], out[2], out[3],
+            out[4], out[5], out[6], out[7],
+            out[8], out[9], out[10], out[11],
+            out[12], out[13], out[14], out[15]);
+
+    res = ID3DXConstantTable_SetFloat(ctable, device, "mvp", f);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetFloat failed on variable mvp: 0x%08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 0, out, 4);
+    ok(out[0] == 0.0f && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f
+            && out[4] == 0.0f && out[5] == 0.0f && out[6] == 0.0f && out[7] == 0.0f
+            && out[8] == 0.0f && out[9] == 0.0f && out[10] == 0.0f && out[11] == 0.0f
+            && out[12] == 0.0f && out[13] == 0.0f && out[14] == 0.0f && out[15] == 0.0f,
+            "The variable mvp was not set correctly by ID3DXConstantTable_SetFloat, "
+            "got {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f %f; %f, %f, %f, %f}, "
+            "should be all 0.0f\n",
+            out[0], out[1], out[2], out[3],
+            out[4], out[5], out[6], out[7],
+            out[8], out[9], out[10], out[11],
+            out[12], out[13], out[14], out[15]);
+
+    res = ID3DXConstantTable_SetFloat(ctable, device, "f4", f);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetFloat failed on variable f4: 0x%08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 1);
+    ok(out[0] == 0.0f && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f,
+            "The variable f4 was not set correctly by ID3DXConstantTable_SetFloat, "
+            "got {%f, %f, %f, %f}, should be all 0.0f\n",
+            out[0], out[1], out[2], out[3]);
+
+    res = ID3DXConstantTable_SetMatrixTranspose(ctable, device, "f", &mvp);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixTranspose failed on variable f: 0x%08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 6, out, 1);
+    ok(out[0] == S(U(mvp))._11 && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f,
+            "The variable f was not set correctly by ID3DXConstantTable_SetMatrixTranspose, got %f, should be %f\n",
+            out[0], S(U(mvp))._11);
+
+    res = ID3DXConstantTable_SetMatrixTranspose(ctable, device, "f4", &mvp);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixTranspose failed on variable f4: 0x%08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 1);
+    ok(out[0] == S(U(mvp))._11 && out[1] == S(U(mvp))._21 && out[2] == S(U(mvp))._31 && out[3] == S(U(mvp))._41,
+            "The variable f4 was not set correctly by ID3DXConstantTable_SetMatrixTranspose, "
+            "got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3],
+            S(U(mvp))._11, S(U(mvp))._21, S(U(mvp))._31, S(U(mvp))._41);
+
+    memset(out, 0, sizeof(out));
+    IDirect3DDevice9_SetVertexShaderConstantF(device, 6, out, 1);
+    res = ID3DXConstantTable_SetMatrixPointerArray(ctable, device, "f", matrix_pointer, 1);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixPointerArray failed on variable f: got %#x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 6, out, 1);
+    ok(out[0] == S(U(mvp))._11 && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f,
+            "The variable f was not set correctly by ID3DXConstantTable_SetMatrixPointerArray, "
+            "got %f, should be %f\n",
+            out[0], S(U(mvp))._11);
+
+    res = ID3DXConstantTable_SetMatrixPointerArray(ctable, device, "f4", matrix_pointer, 1);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixPointerArray failed on variable f4: got %#x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 1);
+    ok(out[0] == S(U(mvp))._11 && out[1] == S(U(mvp))._12 && out[2] == S(U(mvp))._13 && out[3] == S(U(mvp))._14,
+            "The variable f4 was not set correctly by ID3DXConstantTable_SetMatrixPointerArray, "
+            "got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3],
+            S(U(mvp))._11, S(U(mvp))._12, S(U(mvp))._13, S(U(mvp))._14);
+
+    memset(out, 0, sizeof(out));
+    IDirect3DDevice9_SetVertexShaderConstantF(device, 6, out, 1);
+    res = ID3DXConstantTable_SetMatrixTransposePointerArray(ctable, device, "f", matrix_pointer, 1);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixTransposePointerArray failed on variable f: got %#x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 6, out, 1);
+    ok(out[0] == S(U(mvp))._11 && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f,
+            "The variable f was not set correctly by ID3DXConstantTable_SetMatrixTransposePointerArray, "
+            "got %f, should be %f\n",
+            out[0], S(U(mvp))._11);
+
+    res = ID3DXConstantTable_SetMatrixTransposePointerArray(ctable, device, "f4", matrix_pointer, 1);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixTransposePointerArray failed on variable f4: got %#x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 1);
+    ok(out[0] == S(U(mvp))._11 && out[1] == S(U(mvp))._21 && out[2] == S(U(mvp))._31 && out[3] == S(U(mvp))._41,
+            "The variable f4 was not set correctly by ID3DXConstantTable_SetMatrixTransposePointerArray, "
+            "got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3],
+            S(U(mvp))._11, S(U(mvp))._21, S(U(mvp))._31, S(U(mvp))._41);
+
+    refcnt = ID3DXConstantTable_Release(ctable);
+    ok(refcnt == 0, "The constant table reference count was %u, should be 0\n", refcnt);
+}
+
+static void test_setting_matrices_table(IDirect3DDevice9 *device)
+{
+    static const D3DXMATRIX fmatrix =
+        {{{2.001f, 1.502f, 9.003f, 1.004f,
+           5.005f, 3.006f, 3.007f, 6.008f,
+           9.009f, 5.010f, 7.011f, 1.012f,
+           5.013f, 5.014f, 5.015f, 9.016f}}};
+    static const D3DXMATRIX *matrix_pointer[] = {&fmatrix};
+
+    ID3DXConstantTable *ctable;
+
+    HRESULT res;
+    float out[32];
+
+    res = D3DXGetShaderConstantTable(ctab_matrices, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed: got %#x\n", res);
+
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "imatrix2x3", &fmatrix);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed on variable imatrix2x3: got %#x\n", res);
+
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "fmatrix3x1", &fmatrix);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed on variable fmatrix3x1: got %#x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 4, out, 2);
+    ok(out[0] == (int)S(U(fmatrix))._11 && out[1] == (int)S(U(fmatrix))._12 && out[2] == (int)S(U(fmatrix))._13
+            && out[3] == 0
+            && out[4] == (int)S(U(fmatrix))._21 && out[5] == (int)S(U(fmatrix))._22 && out[6] == (int)S(U(fmatrix))._23
+            && out[7] == 0,
+            "The variable imatrix2x3 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%d, %d, %d, %d; %d, %d, %d, %d}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            (int)S(U(fmatrix))._11, (int)S(U(fmatrix))._12, (int)S(U(fmatrix))._13, 0,
+            (int)S(U(fmatrix))._21, (int)S(U(fmatrix))._22, (int)S(U(fmatrix))._23, 0);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 1);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._21 && out[2] == S(U(fmatrix))._31 && out[3] == 0.0f,
+            "The variable fmatrix3x1 was not set correctly, out={%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3],
+            S(U(fmatrix))._11, S(U(fmatrix))._21, S(U(fmatrix))._31, 0.0f);
+
+    ID3DXConstantTable_Release(ctable);
+
+    res = D3DXGetShaderConstantTable(ctab_matrices2, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed: got %#x\n", res);
+
+    /* SetMatrix */
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "c2x3", &fmatrix);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed on variable c2x3: got %#x\n", res);
+
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "r2x3", &fmatrix);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed on variable r2x3: got %#x\n", res);
+
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "c3x2", &fmatrix);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed on variable c3x2: got %#x\n", res);
+
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "r3x2", &fmatrix);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed on variable r3x2: got %#x\n", res);
+
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "c3x3", &fmatrix);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed on variable c3x3: got %#x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 3);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._21 && out[2] == 0.0f && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._12 && out[5] == S(U(fmatrix))._22 && out[6] == 0.0f && out[7] == 0.0f
+            && out[8] == S(U(fmatrix))._13 && out[9] == S(U(fmatrix))._23 && out[10] == 0.0f && out[11] == 0.0f,
+            "The variable c2x3 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3],
+            out[4], out[5], out[6], out[7],
+            out[8], out[9], out[10], out[11],
+            S(U(fmatrix))._11, S(U(fmatrix))._21, 0.0f, 0.0f,
+            S(U(fmatrix))._12, S(U(fmatrix))._22, 0.0f, 0.0f,
+            S(U(fmatrix))._13, S(U(fmatrix))._23, 0.0f, 0.0f);
+
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "r4x4", &fmatrix);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed on variable r4x4: got %#x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 15, out, 2);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._12 && out[2] == S(U(fmatrix))._13 && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._21 && out[5] == S(U(fmatrix))._22 && out[6] == S(U(fmatrix))._23 && out[7] == 0.0f,
+            "The variable r2x3 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            S(U(fmatrix))._11, S(U(fmatrix))._12, S(U(fmatrix))._13, 0.0f,
+            S(U(fmatrix))._21, S(U(fmatrix))._22, S(U(fmatrix))._23, 0.0f);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 13, out, 2);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._21 && out[2] == S(U(fmatrix))._31 && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._12 && out[5] == S(U(fmatrix))._22 && out[6] == S(U(fmatrix))._32 && out[7] == 0.0f,
+            "The variable c3x2 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            S(U(fmatrix))._11, S(U(fmatrix))._21, S(U(fmatrix))._31, 0.0f,
+            S(U(fmatrix))._12, S(U(fmatrix))._22, S(U(fmatrix))._32, 0.0f);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 4, out, 3);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._12 && out[2] == 0.0f && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._21 && out[5] == S(U(fmatrix))._22 && out[6] == 0.0f && out[7] == 0.0f
+            && out[8] == S(U(fmatrix))._31 && out[9] == S(U(fmatrix))._32 && out[10] == 0.0f && out[11] == 0.0f,
+            "The variable r3x2 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7], out[8], out[9], out[10], out[11],
+            S(U(fmatrix))._11, S(U(fmatrix))._12, 0.0f, 0.0f,
+            S(U(fmatrix))._21, S(U(fmatrix))._22, 0.0f, 0.0f,
+            S(U(fmatrix))._31, S(U(fmatrix))._32, 0.0f, 0.0f);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 10, out, 3);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._21 && out[2] == S(U(fmatrix))._31 && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._12 && out[5] == S(U(fmatrix))._22 && out[6] == S(U(fmatrix))._32 && out[7] == 0.0f
+            && out[8] == S(U(fmatrix))._13 && out[9] == S(U(fmatrix))._23 && out[10] == S(U(fmatrix))._33 && out[11] == 0.0f,
+            "The variable c3x3 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7], out[8], out[9], out[10], out[11],
+            S(U(fmatrix))._11, S(U(fmatrix))._21, S(U(fmatrix))._31, 0.0f,
+            S(U(fmatrix))._12, S(U(fmatrix))._22, S(U(fmatrix))._32, 0.0f,
+            S(U(fmatrix))._13, S(U(fmatrix))._23, S(U(fmatrix))._33, 0.0f);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 0, out, 4);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._12 && out[2] == S(U(fmatrix))._13 && out[3] == S(U(fmatrix))._14
+            && out[4] == S(U(fmatrix))._21 && out[5] == S(U(fmatrix))._22 && out[6] == S(U(fmatrix))._23 && out[7] == S(U(fmatrix))._24
+            && out[8] == S(U(fmatrix))._31 && out[9] == S(U(fmatrix))._32 && out[10] == S(U(fmatrix))._33 && out[11] == S(U(fmatrix))._34
+            && out[12] == S(U(fmatrix))._41 && out[13] == S(U(fmatrix))._42 && out[14] == S(U(fmatrix))._43 && out[15] == S(U(fmatrix))._44,
+            "The variable r4x4 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            out[8], out[9], out[10], out[11], out[12], out[13], out[14], out[15],
+            S(U(fmatrix))._11, S(U(fmatrix))._12, S(U(fmatrix))._13, S(U(fmatrix))._14,
+            S(U(fmatrix))._21, S(U(fmatrix))._22, S(U(fmatrix))._23, S(U(fmatrix))._24,
+            S(U(fmatrix))._31, S(U(fmatrix))._32, S(U(fmatrix))._33, S(U(fmatrix))._34,
+            S(U(fmatrix))._41, S(U(fmatrix))._42, S(U(fmatrix))._43, S(U(fmatrix))._44);
+
+    /* SetMatrixTranspose */
+    res = ID3DXConstantTable_SetMatrixTranspose(ctable, device, "c2x3", &fmatrix);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixTranspose failed on variable c2x3: got %#x\n", res);
+
+    res = ID3DXConstantTable_SetMatrixTranspose(ctable, device, "r2x3", &fmatrix);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixTranspose failed on variable r2x3: got %#x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 3);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._12 && out[2] == 0.0f && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._21 && out[5] == S(U(fmatrix))._22 && out[6] == 0.0f && out[7] == 0.0f
+            && out[8] == S(U(fmatrix))._31 && out[9] == S(U(fmatrix))._32 && out[10] == 0.0f && out[11] == 0.0f,
+            "The variable c2x3 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3],
+            out[4], out[5], out[6], out[7],
+            out[8], out[9], out[10], out[11],
+            S(U(fmatrix))._11, S(U(fmatrix))._12, 0.0f, 0.0f,
+            S(U(fmatrix))._21, S(U(fmatrix))._22, 0.0f, 0.0f,
+            S(U(fmatrix))._31, S(U(fmatrix))._32, 0.0f, 0.0f);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 15, out, 2);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._21 && out[2] == S(U(fmatrix))._31 && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._12 && out[5] == S(U(fmatrix))._22 && out[6] == S(U(fmatrix))._32 && out[7] == 0.0f,
+            "The variable r2x3 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            S(U(fmatrix))._11, S(U(fmatrix))._21, S(U(fmatrix))._31, 0.0f,
+            S(U(fmatrix))._12, S(U(fmatrix))._22, S(U(fmatrix))._32, 0.0f);
+
+    /* SetMatrixPointerArray */
+    res = ID3DXConstantTable_SetMatrixPointerArray(ctable, device, "c2x3", matrix_pointer, 1);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixPointerArray failed on variable c2x3: got %#x\n", res);
+
+    res = ID3DXConstantTable_SetMatrixPointerArray(ctable, device, "r2x3", matrix_pointer, 1);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixPointerArray failed on variable r2x3: got %#x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 3);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._21 && out[2] == 0.0f && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._12 && out[5] == S(U(fmatrix))._22 && out[6] == 0.0f && out[7] == 0.0f
+            && out[8] == S(U(fmatrix))._13 && out[9] == S(U(fmatrix))._23 && out[10] == 0.0f && out[11] == 0.0f,
+            "The variable c2x3 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3],
+            out[4], out[5], out[6], out[7],
+            out[8], out[9], out[10], out[11],
+            S(U(fmatrix))._11, S(U(fmatrix))._21, 0.0f, 0.0f,
+            S(U(fmatrix))._12, S(U(fmatrix))._22, 0.0f, 0.0f,
+            S(U(fmatrix))._13, S(U(fmatrix))._23, 0.0f, 0.0f);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 15, out, 2);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._12 && out[2] == S(U(fmatrix))._13 && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._21 && out[5] == S(U(fmatrix))._22 && out[6] == S(U(fmatrix))._23 && out[7] == 0.0f,
+            "The variable r2x3 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            S(U(fmatrix))._11, S(U(fmatrix))._12, S(U(fmatrix))._13, 0.0f,
+            S(U(fmatrix))._21, S(U(fmatrix))._22, S(U(fmatrix))._23, 0.0f);
+
+    /* SetMatrixTransposePointerArray */
+    res = ID3DXConstantTable_SetMatrixTransposePointerArray(ctable, device, "c2x3", matrix_pointer, 1);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixTransposePointerArray failed on variable c2x3: got %#x\n", res);
+
+    res = ID3DXConstantTable_SetMatrixTransposePointerArray(ctable, device, "r2x3", matrix_pointer, 1);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixTransposePointerArray failed on variable r2x3: got %#x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 3);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._12 && out[2] == 0.0f && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._21 && out[5] == S(U(fmatrix))._22 && out[6] == 0.0f && out[7] == 0.0f
+            && out[8] == S(U(fmatrix))._31 && out[9] == S(U(fmatrix))._32 && out[10] == 0.0f && out[11] == 0.0f,
+            "The variable c2x3 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3],
+            out[4], out[5], out[6], out[7],
+            out[8], out[9], out[10], out[11],
+            S(U(fmatrix))._11, S(U(fmatrix))._12, 0.0f, 0.0f,
+            S(U(fmatrix))._21, S(U(fmatrix))._22, 0.0f, 0.0f,
+            S(U(fmatrix))._31, S(U(fmatrix))._32, 0.0f, 0.0f);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 15, out, 2);
+    ok(out[0] == S(U(fmatrix))._11 && out[1] == S(U(fmatrix))._21 && out[2] == S(U(fmatrix))._31 && out[3] == 0.0f
+            && out[4] == S(U(fmatrix))._12 && out[5] == S(U(fmatrix))._22 && out[6] == S(U(fmatrix))._32 && out[7] == 0.0f,
+            "The variable r2x3 was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            S(U(fmatrix))._11, S(U(fmatrix))._21, S(U(fmatrix))._31, 0.0f,
+            S(U(fmatrix))._12, S(U(fmatrix))._22, S(U(fmatrix))._32, 0.0f);
+
+    ID3DXConstantTable_Release(ctable);
+}
+
+static void test_setting_arrays_table(IDirect3DDevice9 *device)
+{
+    static const float farray[8] = {
+        0.005f, 0.745f, 0.973f, 0.264f,
+        0.010f, 0.020f, 0.030f, 0.040f};
+    static const D3DXMATRIX fmtxarray[2] = {
+        {{{0.001f, 0.002f, 0.003f, 0.004f,
+           0.005f, 0.006f, 0.007f, 0.008f,
+           0.009f, 0.010f, 0.011f, 0.012f,
+           0.013f, 0.014f, 0.015f, 0.016f}}},
+        {{{0.010f, 0.020f, 0.030f, 0.040f,
+           0.050f, 0.060f, 0.070f, 0.080f,
+           0.090f, 0.100f, 0.110f, 0.120f,
+           0.130f, 0.140f, 0.150f, 0.160f}}}};
+    static const int iarray[4] = {1, 2, 3, 4};
+    static const D3DXVECTOR4 fvecarray[2] = {
+        {0.745f, 0.997f, 0.353f, 0.237f},
+        {0.060f, 0.455f, 0.333f, 0.983f}};
+    static BOOL barray[4] = {FALSE, 100, TRUE, TRUE};
+
+    ID3DXConstantTable *ctable;
+
+    HRESULT res;
+    float out[32];
+    ULONG refcnt;
+
+    /* Clear registers */
+    memset(out, 0, sizeof(out));
+    IDirect3DDevice9_SetVertexShaderConstantF(device,  8, out, 4);
+    IDirect3DDevice9_SetVertexShaderConstantF(device, 12, out, 4);
+
+    /* Get the constant table from the shader */
+    res = D3DXGetShaderConstantTable(ctab_arrays, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed: got 0x%08x\n", res);
+
+    /* Set constants */
+
+    /* Make sure that we cannot set registers that do not belong to this constant */
+    res = ID3DXConstantTable_SetFloatArray(ctable, device, "farray", farray, 8);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetFloatArray failed: got 0x%08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 8, out, 8);
+    ok(out[0] == farray[0] && out[4] == farray[1] && out[8] == farray[2] && out[12] == farray[3],
+            "The in-bounds elements of the array were not set, out={%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[4], out[8], out[12], farray[0], farray[1], farray[2], farray[3]);
+    ok(out[16] == 0.0f && out[20] == 0.0f && out[24] == 0.0f && out[28] == 0.0f,
+            "The excess elements of the array were set, out={%f, %f, %f, %f}, should be all 0.0f\n",
+            out[16], out[20], out[24], out[28]);
+
+    /* ivecarray takes up only 1 register, but a matrix takes up 4, so no elements should be set */
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "ivecarray", &fmtxarray[0]);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed: got 0x%08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 18, out, 4);
+    ok(out[0] == 0.0f && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f,
+       "The array was set, out={%f, %f, %f, %f}, should be all 0.0f\n", out[0], out[1], out[2], out[3]);
+
+    /* Try setting an integer array to an array declared as a float array */
+    res = ID3DXConstantTable_SetIntArray(ctable, device, "farray", iarray, 4);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetIntArray failed: got 0x%08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 8, out, 4);
+    ok(out[0] == iarray[0] && out[4] == iarray[1] && out[8] == iarray[2] && out[12] == iarray[3],
+           "SetIntArray did not properly set a float array: out={%f, %f, %f, %f}, should be {%d, %d, %d, %d}\n",
+            out[0], out[4], out[8], out[12], iarray[0], iarray[1], iarray[2], iarray[3]);
+
+    res = ID3DXConstantTable_SetFloatArray(ctable, device, "farray", farray, 4);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetFloatArray failed: got x0%08x\n", res);
+
+    res = ID3DXConstantTable_SetVectorArray(ctable, device, "fvecarray", fvecarray, 2);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetVectorArray failed: got 0x%08x\n", res);
+
+    res = ID3DXConstantTable_SetMatrixArray(ctable, device, "fmtxarray", fmtxarray, 2);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrixArray failed: got 0x%08x\n", res);
+
+    res = ID3DXConstantTable_SetBoolArray(ctable, device, "barray", barray, 2);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetBoolArray failed: got 0x%08x\n", res);
+
+    /* Read back constants */
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 8, out, 4);
+    ok(out[0] == farray[0] && out[4] == farray[1] && out[8] == farray[2] && out[12] == farray[3],
+            "The variable farray was not set correctly, out={%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[4], out[8], out[12], farray[0], farray[1], farray[2], farray[3]);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 12, out, 2);
+    ok(out[0] == fvecarray[0].x && out[1] == fvecarray[0].y && out[2] == fvecarray[0].z && out[3] == fvecarray[0].w &&
+            out[4] == fvecarray[1].x && out[5] == fvecarray[1].y && out[6] == fvecarray[1].z && out[7] == fvecarray[1].w,
+            "The variable fvecarray was not set correctly, out={{%f, %f, %f, %f}, {%f, %f, %f, %f}}, should be "
+            "{{%f, %f, %f, %f}, {%f, %f, %f, %f}}\n", out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            fvecarray[0].x, fvecarray[0].y, fvecarray[0].z, fvecarray[0].w, fvecarray[1].x, fvecarray[1].y,
+            fvecarray[1].z, fvecarray[1].w);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 14, out, 2);
+    ok(out[0] == 0.0f && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f
+            && out[4] == 1.0f && out[5] == 0.0f && out[6] == 0.0f && out[7] == 0.0f,
+            "The variable barray was not set correctly, out={%f, %f %f, %f; %f, %f, %f, %f}, should be {%f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 0, out, 8);
+    /* Just check a few elements in each matrix to make sure fmtxarray was set row-major */
+    ok(out[0] == S(U(fmtxarray[0]))._11 && out[1] == S(U(fmtxarray[0]))._12 && out[2] == S(U(fmtxarray[0]))._13 && out[3] == S(U(fmtxarray[0]))._14,
+           "The variable fmtxarray was not set row-major, out={%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+           out[0], out[1], out[2], out[3], S(U(fmtxarray[0]))._11, S(U(fmtxarray[0]))._12, S(U(fmtxarray[0]))._13, S(U(fmtxarray[0]))._14);
+    ok(out[16] == S(U(fmtxarray[1]))._11 && out[17] == S(U(fmtxarray[1]))._12 && out[18] == S(U(fmtxarray[1]))._13 && out[19] == S(U(fmtxarray[1]))._14,
+           "The variable fmtxarray was not set row-major, out={%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+           out[16], out[17], out[18], out[19], S(U(fmtxarray[1]))._11, S(U(fmtxarray[1]))._12, S(U(fmtxarray[1]))._13, S(U(fmtxarray[1]))._14);
+
+    refcnt = ID3DXConstantTable_Release(ctable);
+    ok(refcnt == 0, "The constant table reference count was %u, should be 0\n", refcnt);
+}
+
+static void test_SetDefaults(IDirect3DDevice9 *device)
+{
+    static const D3DXMATRIX mvp = {{{
+        0.51f, 0.62f, 0.80f, 0.78f,
+        0.23f, 0.95f, 0.37f, 0.48f,
+        0.10f, 0.58f, 0.90f, 0.25f,
+        0.89f, 0.41f, 0.93f, 0.27f}}};
+    static const D3DXVECTOR4 f4 = {0.2f, 0.4f, 0.8f, 1.2f};
+
+    float out[16];
+
+    HRESULT res;
+    ID3DXConstantTable *ctable;
+
+    res = D3DXGetShaderConstantTable(ctab_basic, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed: got %08x\n", res);
+
+    res = ID3DXConstantTable_SetVector(ctable, device, "f4", &f4);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetVector failed: got %08x\n", res);
+
+    res = ID3DXConstantTable_SetMatrix(ctable, device, "mvp", &mvp);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetMatrix failed: got %08x\n", res);
+
+    res = ID3DXConstantTable_SetDefaults(ctable, device);
+    ok(res == D3D_OK, "ID3dXConstantTable_SetDefaults failed: got %08x\n", res);
+
+    /* SetDefaults doesn't change constants without default values */
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 0, out, 4);
+    ok(out[0] == S(U(mvp))._11 && out[4] == S(U(mvp))._12 && out[8] == S(U(mvp))._13 && out[12] == S(U(mvp))._14,
+            "The first row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[4], out[8], out[12], S(U(mvp))._11, S(U(mvp))._12, S(U(mvp))._13, S(U(mvp))._14);
+    ok(out[1] == S(U(mvp))._21 && out[5] == S(U(mvp))._22 && out[9] == S(U(mvp))._23 && out[13] == S(U(mvp))._24,
+            "The second row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[1], out[5], out[9], out[13], S(U(mvp))._21, S(U(mvp))._22, S(U(mvp))._23, S(U(mvp))._24);
+    ok(out[2] == S(U(mvp))._31 && out[6] == S(U(mvp))._32 && out[10] == S(U(mvp))._33 && out[14] == S(U(mvp))._34,
+            "The third row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[2], out[6], out[10], out[14], S(U(mvp))._31, S(U(mvp))._32, S(U(mvp))._33, S(U(mvp))._34);
+    ok(out[3] == S(U(mvp))._41 && out[7] == S(U(mvp))._42 && out[11] == S(U(mvp))._43 && out[15] == S(U(mvp))._44,
+            "The fourth row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[3], out[7], out[11], out[15], S(U(mvp))._41, S(U(mvp))._42, S(U(mvp))._43, S(U(mvp))._44);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 1);
+    ok(memcmp(out, &f4, sizeof(f4)) == 0,
+            "The variable f4 was not set correctly, out={%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], f4.x, f4.y, f4.z, f4.w);
+
+    ID3DXConstantTable_Release(ctable);
+
+    res = D3DXGetShaderConstantTable(ctab_with_default_values, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed: got %08x\n", res);
+
+    res = ID3DXConstantTable_SetDefaults(ctable, device);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetDefaults failed: got %08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 0, out, 4);
+    ok(memcmp(out, mat4_default_value, sizeof(mat4_default_value)) == 0,
+            "The variable mat4 was not set correctly to default value\n");
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 4, out, 4);
+    ok(memcmp(out, mat3_default_value, sizeof(mat3_default_value)) == 0,
+            "The variable mat3 was not set correctly to default value\n");
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 8, out, 3);
+    ok(memcmp(out, arr_default_value, sizeof(arr_default_value)) == 0,
+        "The variable array was not set correctly to default value\n");
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 11, out, 1);
+    ok(memcmp(out, vec4_default_value, sizeof(vec4_default_value)) == 0,
+        "The variable vec4 was not set correctly to default value\n");
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 12, out, 1);
+    ok(memcmp(out, flt_default_value, sizeof(flt_default_value)) == 0,
+        "The variable flt was not set correctly to default value\n");
+
+    ID3DXConstantTable_Release(ctable);
+}
+
+static void test_SetValue(IDirect3DDevice9 *device)
+{
+    static const D3DXMATRIX mvp = {{{
+        0.51f, 0.62f, 0.80f, 0.78f,
+        0.23f, 0.95f, 0.37f, 0.48f,
+        0.10f, 0.58f, 0.90f, 0.25f,
+        0.89f, 0.41f, 0.93f, 0.27f}}};
+    static const D3DXVECTOR4 f4 = {0.2f, 0.4f, 0.8f, 1.2f};
+    static const FLOAT arr[] = {0.33f, 0.55f, 0.96f, 1.00f,
+                                1.00f, 1.00f, 1.00f, 1.00f,
+                                1.00f, 1.00f, 1.00f, 1.00f};
+    static int imatrix[] = {1, 2, 3, 4, 5, 6};
+    static float fmatrix[] = {1.1f, 2.2f, 3.3f, 4.4f};
+    static BOOL barray[] = {TRUE, FALSE};
+    static float fvecarray[] = {9.1f, 9.2f, 9.3f, 9.4f, 9.5f, 9.6f, 9.7f, 9.8f};
+    static float farray[] = {2.2f, 3.3f};
+
+    static const float def[16] = {5.5f, 5.5f, 5.5f, 5.5f,
+                                  5.5f, 5.5f, 5.5f, 5.5f,
+                                  5.5f, 5.5f, 5.5f, 5.5f,
+                                  5.5f, 5.5f, 5.5f, 5.5f};
+    float out[16];
+
+    HRESULT res;
+    ID3DXConstantTable *ctable;
+
+    res = D3DXGetShaderConstantTable(ctab_basic, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed: got %08x\n", res);
+
+    IDirect3DDevice9_SetVertexShaderConstantF(device, 7, def, 1);
+
+    /* SetValue called with 0 bytes size doesn't change value */
+    res = ID3DXConstantTable_SetValue(ctable, device, "f4", &f4, 0);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetValue failed: got %08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 1);
+    ok(memcmp(out, def, sizeof(f4)) == 0,
+            "The variable f4 was not set correctly, out={%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], def[0], def[1], def[2], def[3]);
+
+    res = ID3DXConstantTable_SetValue(ctable, device, "f4", &f4, sizeof(f4));
+    ok(res == D3D_OK, "ID3DXConstantTable_SetValue failed: got %08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 1);
+    ok(memcmp(out, &f4, sizeof(f4)) == 0,
+            "The variable f4 was not set correctly, out={%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], f4.x, f4.y, f4.z, f4.w);
+
+    IDirect3DDevice9_SetVertexShaderConstantF(device, 0, def, 4);
+
+    /* SetValue called with size smaller than constant size doesn't change value */
+    res = ID3DXConstantTable_SetValue(ctable, device, "mvp", &mvp, sizeof(mvp) / 2);
+    ok(res == D3D_OK, "ID3DXConstantTable_SetValue returned %08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 0, out, 4);
+    ok(memcmp(out, def, sizeof(def)) == 0,
+            "The variable mvp was not set correctly, out={%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[4], out[ 8], out[12],
+            out[1], out[5], out[ 9], out[13],
+            out[2], out[6], out[10], out[14],
+            out[3], out[7], out[11], out[15],
+            def[0], def[4], def[ 8], def[12],
+            def[1], def[5], def[ 9], def[13],
+            def[2], def[6], def[10], def[14],
+            def[3], def[7], def[11], def[15]);
+
+    res = ID3DXConstantTable_SetValue(ctable, device, "mvp", &mvp, sizeof(mvp));
+    ok(res == D3D_OK, "ID3DXConstantTable_SetValue failed: got %08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 0, out, 4);
+    ok(out[0] == S(U(mvp))._11 && out[4] == S(U(mvp))._12 && out[8] == S(U(mvp))._13 && out[12] == S(U(mvp))._14,
+            "The first row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[4], out[8], out[12], S(U(mvp))._11, S(U(mvp))._12, S(U(mvp))._13, S(U(mvp))._14);
+    ok(out[1] == S(U(mvp))._21 && out[5] == S(U(mvp))._22 && out[9] == S(U(mvp))._23 && out[13] == S(U(mvp))._24,
+            "The second row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[1], out[5], out[9], out[13], S(U(mvp))._21, S(U(mvp))._22, S(U(mvp))._23, S(U(mvp))._24);
+    ok(out[2] == S(U(mvp))._31 && out[6] == S(U(mvp))._32 && out[10] == S(U(mvp))._33 && out[14] == S(U(mvp))._34,
+            "The third row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[2], out[6], out[10], out[14], S(U(mvp))._31, S(U(mvp))._32, S(U(mvp))._33, S(U(mvp))._34);
+    ok(out[3] == S(U(mvp))._41 && out[7] == S(U(mvp))._42 && out[11] == S(U(mvp))._43 && out[15] == S(U(mvp))._44,
+            "The fourth row of mvp was not set correctly, got {%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[3], out[7], out[11], out[15], S(U(mvp))._41, S(U(mvp))._42, S(U(mvp))._43, S(U(mvp))._44);
+
+    ID3DXConstantTable_Release(ctable);
+
+    res = D3DXGetShaderConstantTable(ctab_with_default_values, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed: got %08x\n", res);
+
+    res = ID3DXConstantTable_SetValue(ctable, device, "arr", arr, sizeof(arr));
+    ok(res == D3D_OK, "ID3DXConstantTable_SetValue failed: got %08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 8, out, 3);
+    ok(out[0] == arr[0] && out[4] == arr[1] && out[8] == arr[2]
+            && out[1] == 0 &&  out[2] == 0 && out[3] == 0 && out[5] == 0 && out[6] == 0 && out[7] == 0
+            && out[9] == 0 && out[10] == 0 && out[11] == 0,
+            "The variable arr was not set correctly, out={%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f}, "
+            "should be {0.33, 0, 0, 0, 0.55, 0, 0, 0, 0.96, 0, 0, 0}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7], out[8], out[9], out[10], out[11]);
+
+    ID3DXConstantTable_Release(ctable);
+
+    res = D3DXGetShaderConstantTable(ctab_matrices, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed: got %08x\n", res);
+
+    res = ID3DXConstantTable_SetValue(ctable, device, "fmatrix3x1", fmatrix, sizeof(fmatrix));
+    ok(res == D3D_OK, "ID3DXConstantTable_SetValue failed: got %08x\n", res);
+
+    res = ID3DXConstantTable_SetValue(ctable, device, "imatrix2x3", imatrix, sizeof(imatrix));
+    ok(res == D3D_OK, "ID3DXConstantTable_SetValue failed: got %08x\n", res);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 4, out, 2);
+    ok(out[0] == imatrix[0] && out[1] == imatrix[1] && out[2] == imatrix[2] && out[3] == 0.0f
+            && out[4] == imatrix[3] && out[5] == imatrix[4] && out[6] == imatrix[5] && out[7] == 0.0f,
+            "The variable imatrix2x3 was not set correctly, out={%f, %f, %f, %f, %f, %f, %f, %f}, "
+            "should be {%d, %d, %d, 0, %d, %d, %d, 0}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            imatrix[0], imatrix[1], imatrix[2], imatrix[3], imatrix[4], imatrix[5]);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 7, out, 2);
+    ok(out[0] == fmatrix[0] && out[1] == fmatrix[1] && out[2] == fmatrix[2] && out[3] == 0.0f,
+            "The variable fmatrix3x1 was not set correctly, out={%f, %f, %f, %f}, should be {%f, %f, %f, %f}\n",
+            out[0], out[1] ,out[2], out[4],
+            fmatrix[0], fmatrix[1], fmatrix[2], 0.0f);
+
+    ID3DXConstantTable_Release(ctable);
+
+    res = D3DXGetShaderConstantTable(ctab_arrays, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed: got %08x\n", res);
+
+    res = ID3DXConstantTable_SetValue(ctable, device, "barray", barray, sizeof(barray));
+    ok(res == D3D_OK, "ID3DXConstantTable_SetValue failed: got %08x\n", res);
+
+    res = ID3DXConstantTable_SetValue(ctable, device, "fvecarray", fvecarray, sizeof(fvecarray));
+    ok(res == D3D_OK, "ID3DXConstantTable_SetValue failed: got %08x\n", res);
+
+    IDirect3DDevice9_SetVertexShaderConstantF(device, 8, def, 4);
+    res = ID3DXConstantTable_SetValue(ctable, device, "farray", farray, sizeof(farray));
+    ok(res == D3D_OK, "ID3DXConstantTable_SetValue failed: got %08x\n", res);
+
+    /* 2 elements of farray were set */
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 8, out, 4);
+    ok(out[0] == farray[0] && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f
+            && out[4] == farray[1] && out[5] == 0.0f && out[6] == 0.0f && out[7] == 0.0f
+            && out[8] == def[8] && out[9] == def[9] && out[10] == def[10] && out[11] == def[11]
+            && out[12] == def[12] && out[13] == def[13] && out[14] == def[14] && out[15] == def[15],
+            "The variable farray was not set correctly, should be {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f; %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            out[8], out[9], out[10], out[11], out[12], out[13], out[14], out[15],
+            farray[0], 0.0f, 0.0f, 0.0f,
+            farray[1], 0.0f, 0.0f, 0.0f,
+            def[8], def[9], def[10], def[11],
+            def[12], def[13], def[14], def[15]);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 12, out, 2);
+    ok(out[0] == fvecarray[0] && out[1] == fvecarray[1] && out[2] == fvecarray[2] && out[3] == fvecarray[3]
+            && out[4] == fvecarray[4] && out[5] == fvecarray[5] && out[6] == fvecarray[6] && out[7] == fvecarray[7],
+            "The variable fvecarray was not set correctly, out ={%f, %f, %f, %f, %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f, %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            fvecarray[0], fvecarray[1], fvecarray[2], fvecarray[3], fvecarray[4], fvecarray[5], fvecarray[6], fvecarray[7]);
+
+    IDirect3DDevice9_GetVertexShaderConstantF(device, 14, out, 2);
+    ok(out[0] == 1.0f && out[1] == 0.0f && out[2] == 0.0f && out[3] == 0.0f
+            && out[4] == 0.0f && out[5] == 0.0f && out[6] == 0.0f && out[7] == 0.0f,
+            "The variable barray was not set correctly, out={%f, %f, %f, %f, %f, %f, %f, %f}, "
+            "should be {%f, %f, %f, %f, %f, %f, %f, %f}\n",
+            out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
+            1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+    ID3DXConstantTable_Release(ctable);
+}
+
+static void test_setting_constants(void)
+{
+    HWND wnd;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *device;
+    D3DPRESENT_PARAMETERS d3dpp;
+    HRESULT hr;
+    ULONG refcnt;
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window\n");
+        return;
+    }
+    if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION)))
+    {
+        skip("Couldn't create IDirect3D9 object\n");
+        DestroyWindow(wnd);
+        return;
+    }
+
+    ZeroMemory(&d3dpp, sizeof(d3dpp));
+    d3dpp.Windowed   = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
+    if (FAILED(hr))
+    {
+        skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    test_setting_basic_table(device);
+    test_setting_matrices_table(device);
+    test_setting_arrays_table(device);
+    test_SetDefaults(device);
+    test_SetValue(device);
+
+    /* Release resources */
+    refcnt = IDirect3DDevice9_Release(device);
+    ok(refcnt == 0, "The Direct3D device reference count was %u, should be 0\n", refcnt);
+
+    refcnt = IDirect3D9_Release(d3d);
+    ok(refcnt == 0, "The Direct3D object referenct count was %u, should be 0\n", refcnt);
+
+    if (wnd) DestroyWindow(wnd);
+}
+
+static void test_get_sampler_index(void)
+{
+    ID3DXConstantTable *ctable;
+
+    HRESULT res;
+    UINT index;
+
+    ULONG refcnt;
+
+    res = D3DXGetShaderConstantTable(ctab_samplers, &ctable);
+    ok(res == D3D_OK, "D3DXGetShaderConstantTable failed on ctab_samplers: got %08x\n", res);
+
+    index = ID3DXConstantTable_GetSamplerIndex(ctable, "sampler1");
+    ok(index == 0, "ID3DXConstantTable_GetSamplerIndex returned wrong index: Got %d, expected 0\n", index);
+
+    index = ID3DXConstantTable_GetSamplerIndex(ctable, "sampler2");
+    ok(index == 3, "ID3DXConstantTable_GetSamplerIndex returned wrong index: Got %d, expected 3\n", index);
+
+    index = ID3DXConstantTable_GetSamplerIndex(ctable, "nonexistent");
+    ok(index == -1, "ID3DXConstantTable_GetSamplerIndex found nonexistent sampler: Got %d\n",
+            index);
+
+    index = ID3DXConstantTable_GetSamplerIndex(ctable, "notsampler");
+    ok(index == -1, "ID3DXConstantTable_GetSamplerIndex succeeded on non-sampler constant: Got %d\n",
+            index);
+
+    refcnt = ID3DXConstantTable_Release(ctable);
+    ok(refcnt == 0, "The ID3DXConstantTable reference count was %u, should be 0\n", refcnt);
+}
+
+/*
+ * fxc.exe /Tps_3_0
+ */
+#if 0
+sampler s;
+sampler1D s1D;
+sampler2D s2D;
+sampler3D s3D;
+samplerCUBE scube;
+float4 init;
+float4 main(float3 tex : TEXCOORD0) : COLOR
+{
+    float4 tmp = init;
+    tmp = tmp + tex1D(s1D, tex.x);
+    tmp = tmp + tex1D(s1D, tex.y);
+    tmp = tmp + tex3D(s3D, tex.xyz);
+    tmp = tmp + tex1D(s, tex.x);
+    tmp = tmp + tex2D(s2D, tex.xy);
+    tmp = tmp + texCUBE(scube, tex.xyz);
+    return tmp;
+}
+#endif
+static const DWORD get_shader_samplers_blob[] =
+{
+    0xffff0300,                                                             /* ps_3_0                        */
+    0x0054fffe, FCC_CTAB,                                                   /* CTAB comment                  */
+    0x0000001c, 0x0000011b, 0xffff0300, 0x00000006, 0x0000001c, 0x00000100, /* Header                        */
+    0x00000114,
+    0x00000094, 0x00000002, 0x00000001, 0x0000009c, 0x00000000,             /* Constant 1 desc (init)        */
+    0x000000ac, 0x00040003, 0x00000001, 0x000000b0, 0x00000000,             /* Constant 2 desc (s)           */
+    0x000000c0, 0x00000003, 0x00000001, 0x000000c4, 0x00000000,             /* Constant 3 desc (s1D)         */
+    0x000000d4, 0x00010003, 0x00000001, 0x000000d8, 0x00000000,             /* Constant 4 desc (s2D)         */
+    0x000000e8, 0x00030003, 0x00000001, 0x000000ec, 0x00000000,             /* Constant 5 desc (s3D)         */
+    0x000000fc, 0x00020003, 0x00000001, 0x00000104, 0x00000000,             /* Constant 6 desc (scube)       */
+    0x74696e69, 0xababab00,                                                 /* Constant 1 name               */
+    0x00030001, 0x00040001, 0x00000001, 0x00000000,                         /* Constant 1 type desc          */
+    0xabab0073,                                                             /* Constant 2 name               */
+    0x000c0004, 0x00010001, 0x00000001, 0x00000000,                         /* Constant 2 type desc          */
+    0x00443173,                                                             /* Constant 3 name               */
+    0x000b0004, 0x00010001, 0x00000001, 0x00000000,                         /* Constant 3 type desc          */
+    0x00443273,                                                             /* Constant 4 name               */
+    0x000c0004, 0x00010001, 0x00000001, 0x00000000,                         /* Constant 4 type desc          */
+    0x00443373,                                                             /* Constant 5 name               */
+    0x000d0004, 0x00010001, 0x00000001, 0x00000000,                         /* Constant 5 type desc          */
+    0x62756373, 0xabab0065,                                                 /* Constant 6 name               */
+    0x000e0004, 0x00010001, 0x00000001, 0x00000000,                         /* Constant 6 type desc          */
+    0x335f7370, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, /* Target/Creator name string    */
+    0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932,
+    0x332e3235, 0x00313131,
+    0x0200001f, 0x80000005, 0x90070000, 0x0200001f, 0x90000000, 0xa00f0800, /* shader                        */
+    0x0200001f, 0x90000000, 0xa00f0801, 0x0200001f, 0x98000000, 0xa00f0802,
+    0x0200001f, 0xa0000000, 0xa00f0803, 0x0200001f, 0x90000000, 0xa00f0804,
+    0x03000042, 0x800f0000, 0x90e40000, 0xa0e40800, 0x03000002, 0x800f0000,
+    0x80e40000, 0xa0e40000, 0x03000042, 0x800f0001, 0x90550000, 0xa0e40800,
+    0x03000002, 0x800f0000, 0x80e40000, 0x80e40001, 0x03000042, 0x800f0001,
+    0x90e40000, 0xa0e40803, 0x03000002, 0x800f0000, 0x80e40000, 0x80e40001,
+    0x03000042, 0x800f0001, 0x90e40000, 0xa0e40804, 0x03000002, 0x800f0000,
+    0x80e40000, 0x80e40001, 0x03000042, 0x800f0001, 0x90e40000, 0xa0e40801,
+    0x03000002, 0x800f0000, 0x80e40000, 0x80e40001, 0x03000042, 0x800f0001,
+    0x90e40000, 0xa0e40802, 0x03000002, 0x800f0800, 0x80e40000, 0x80e40001,
+    0x0000ffff,                                                             /* END                           */
+};
+
+static void test_get_shader_samplers(void)
+{
+    const char *samplers[16] = {NULL}; /* maximum number of sampler registers v/ps 3.0 = 16 */
+    const char *sampler_orig;
+    UINT count = 2;
+    HRESULT hr;
+
+if (0)
+{
+    /* crashes if bytecode is NULL */
+    hr = D3DXGetShaderSamplers(NULL, NULL, &count);
+    ok(hr == D3D_OK, "D3DXGetShaderSamplers failed, got %x, expected %x\n", hr, D3D_OK);
+}
+
+    hr = D3DXGetShaderSamplers(get_shader_samplers_blob, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXGetShaderSamplers failed, got %x, expected %x\n", hr, D3D_OK);
+
+    samplers[5] = "dummy";
+
+    hr = D3DXGetShaderSamplers(get_shader_samplers_blob, samplers, NULL);
+    ok(hr == D3D_OK, "D3DXGetShaderSamplers failed, got %x, expected %x\n", hr, D3D_OK);
+
+    /* check that sampler points to shader blob */
+    sampler_orig = (const char *)&get_shader_samplers_blob[0x2e];
+    ok(sampler_orig == samplers[0], "D3DXGetShaderSamplers failed, got %p, expected %p\n", samplers[0], sampler_orig);
+
+    sampler_orig = (const char *)&get_shader_samplers_blob[0x33];
+    ok(sampler_orig == samplers[1], "D3DXGetShaderSamplers failed, got %p, expected %p\n", samplers[1], sampler_orig);
+
+    sampler_orig = (const char *)&get_shader_samplers_blob[0x38];
+    ok(sampler_orig == samplers[2], "D3DXGetShaderSamplers failed, got %p, expected %p\n", samplers[2], sampler_orig);
+
+    sampler_orig = (const char *)&get_shader_samplers_blob[0x3d];
+    ok(sampler_orig == samplers[3], "D3DXGetShaderSamplers failed, got %p, expected %p\n", samplers[3], sampler_orig);
+
+    sampler_orig = (const char *)&get_shader_samplers_blob[0x42];
+    ok(sampler_orig == samplers[4], "D3DXGetShaderSamplers failed, got %p, expected %p\n", samplers[4], sampler_orig);
+
+    ok(!strcmp(samplers[5], "dummy"), "D3DXGetShaderSamplers failed, got \"%s\", expected \"%s\"\n", samplers[5], "dummy");
+
+    /* reset samplers */
+    memset(samplers, 0, sizeof(samplers));
+    samplers[5] = "dummy";
+
+    hr = D3DXGetShaderSamplers(get_shader_samplers_blob, NULL, &count);
+    ok(hr == D3D_OK, "D3DXGetShaderSamplers failed, got %x, expected %x\n", hr, D3D_OK);
+    ok(count == 5, "D3DXGetShaderSamplers failed, got %u, expected %u\n", count, 5);
+
+    hr = D3DXGetShaderSamplers(get_shader_samplers_blob, samplers, &count);
+    ok(hr == D3D_OK, "D3DXGetShaderSamplers failed, got %x, expected %x\n", hr, D3D_OK);
+    ok(count == 5, "D3DXGetShaderSamplers failed, got %u, expected %u\n", count, 5);
+
+    /* check that sampler points to shader blob */
+    sampler_orig = (const char *)&get_shader_samplers_blob[0x2e];
+    ok(sampler_orig == samplers[0], "D3DXGetShaderSamplers failed, got %p, expected %p\n", samplers[0], sampler_orig);
+
+    sampler_orig = (const char *)&get_shader_samplers_blob[0x33];
+    ok(sampler_orig == samplers[1], "D3DXGetShaderSamplers failed, got %p, expected %p\n", samplers[1], sampler_orig);
+
+    sampler_orig = (const char *)&get_shader_samplers_blob[0x38];
+    ok(sampler_orig == samplers[2], "D3DXGetShaderSamplers failed, got %p, expected %p\n", samplers[2], sampler_orig);
+
+    sampler_orig = (const char *)&get_shader_samplers_blob[0x3d];
+    ok(sampler_orig == samplers[3], "D3DXGetShaderSamplers failed, got %p, expected %p\n", samplers[3], sampler_orig);
+
+    sampler_orig = (const char *)&get_shader_samplers_blob[0x42];
+    ok(sampler_orig == samplers[4], "D3DXGetShaderSamplers failed, got %p, expected %p\n", samplers[4], sampler_orig);
+
+    ok(!strcmp(samplers[5], "dummy"), "D3DXGetShaderSamplers failed, got \"%s\", expected \"%s\"\n", samplers[5], "dummy");
+
+    /* check without ctab */
+    hr = D3DXGetShaderSamplers(simple_vs, samplers, &count);
+    ok(hr == D3D_OK, "D3DXGetShaderSamplers failed, got %x, expected %x\n", hr, D3D_OK);
+    ok(count == 0, "D3DXGetShaderSamplers failed, got %u, expected %u\n", count, 0);
+
+    /* check invalid ctab */
+    hr = D3DXGetShaderSamplers(shader_with_invalid_ctab, samplers, &count);
+    ok(hr == D3D_OK, "D3DXGetShaderSamplers failed, got %x, expected %x\n", hr, D3D_OK);
+    ok(count == 0, "D3DXGetShaderSamplers failed, got %u, expected %u\n", count, 0);
+}
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+float f = {1.1f}, f_2[2] = {2.1f, 2.2f};
+struct {float f; int i;} s = {3.1f, 31},
+s_2[2] = {{4.1f, 41}, {4.2f, 42}},
+s_3[3] = {{5.1f, 51}, {5.2f, 52}, {5.3f, 53}};
+struct {int i1; int i2; float2 f_2; row_major float3x1 r[2];}
+p[2] = {{11, 12, {13.1, 14.1}, {{3.11, 3.21, 3.31}, {3.41, 3.51, 3.61}}},
+        {15, 16, {17.1, 18.1}, {{4.11, 4.21, 4.31}, {4.41, 4.51, 4.61}}}};
+int i[1] = {6};
+float2x3 f23[2] = {{0.11, 0.21, 0.31, 0.41, 0.51, 0.61}, {0.12, 0.22, 0.32, 0.42, 0.52, 0.62}};
+float3x2 f32[2] = {{1.11, 1.21, 1.31, 1.41, 1.51, 1.61}, {1.12, 1.22, 1.32, 1.42, 1.52, 1.62}};
+float3 v[2] = {{2.11, 2.21, 2.31}, {2.41, 2.51, 2.61}};
+row_major float3x1 r31[2] = {{3.11, 3.21, 3.31}, {3.41, 3.51, 3.61}};
+row_major float1x3 r13[2] = {{4.11, 4.21, 4.31}, {4.41, 4.51, 4.61}};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0.0f;
+    tmp.zyw = v[1] + r13[1] + r31[1] + p[1].r[1];
+    tmp.x += f * f_2[1] * pos.x * p[1].f_2.y;
+    tmp.y += s.f * pos.y * s_2[0].i;
+    tmp.z += s_3[0].f * pos.z * s_3[2].f * i[0] * f23[1]._11 * f32[1]._32;
+    return tmp;
+}
+#endif
+static const DWORD test_get_shader_constant_variables_blob[] =
+{
+0xfffe0300, 0x0185fffe, 0x42415443, 0x0000001c, 0x000005df, 0xfffe0300, 0x0000000c, 0x0000001c,
+0x00000100, 0x000005d8, 0x0000010c, 0x002d0002, 0x00000001, 0x00000110, 0x00000120, 0x00000130,
+0x001d0002, 0x00000004, 0x00000134, 0x00000144, 0x000001a4, 0x00210002, 0x00000004, 0x000001a8,
+0x000001b8, 0x000001f8, 0x00250002, 0x00000002, 0x000001fc, 0x0000020c, 0x0000022c, 0x002f0002,
+0x00000001, 0x00000230, 0x00000240, 0x00000250, 0x00000002, 0x00000012, 0x000002b0, 0x000002c0,
+0x000003e0, 0x002b0002, 0x00000002, 0x000003e4, 0x000003f4, 0x00000414, 0x00120002, 0x00000006,
+0x00000418, 0x00000428, 0x00000488, 0x002e0002, 0x00000001, 0x000004ac, 0x000004bc, 0x000004dc,
+0x00270002, 0x00000002, 0x000004e0, 0x000004f0, 0x00000530, 0x00180002, 0x00000005, 0x00000534,
+0x00000544, 0x000005a4, 0x00290002, 0x00000002, 0x000005a8, 0x000005b8, 0xabab0066, 0x00030000,
+0x00010001, 0x00000001, 0x00000000, 0x3f8ccccd, 0x00000000, 0x00000000, 0x00000000, 0x00333266,
+0x00030003, 0x00030002, 0x00000002, 0x00000000, 0x3de147ae, 0x3ed1eb85, 0x00000000, 0x00000000,
+0x3e570a3d, 0x3f028f5c, 0x00000000, 0x00000000, 0x3e9eb852, 0x3f1c28f6, 0x00000000, 0x00000000,
+0x3df5c28f, 0x3ed70a3d, 0x00000000, 0x00000000, 0x3e6147ae, 0x3f051eb8, 0x00000000, 0x00000000,
+0x3ea3d70a, 0x3f1eb852, 0x00000000, 0x00000000, 0x00323366, 0x00030003, 0x00020003, 0x00000002,
+0x00000000, 0x3f8e147b, 0x3fa7ae14, 0x3fc147ae, 0x00000000, 0x3f9ae148, 0x3fb47ae1, 0x3fce147b,
+0x00000000, 0x3f8f5c29, 0x3fa8f5c3, 0x3fc28f5c, 0x00000000, 0x3f9c28f6, 0x3fb5c28f, 0x3fcf5c29,
+0x00000000, 0x00325f66, 0x00030000, 0x00010001, 0x00000002, 0x00000000, 0x40066666, 0x00000000,
+0x00000000, 0x00000000, 0x400ccccd, 0x00000000, 0x00000000, 0x00000000, 0xabab0069, 0x00020000,
+0x00010001, 0x00000001, 0x00000000, 0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x31690070,
+0xababab00, 0x00020000, 0x00010001, 0x00000001, 0x00000000, 0xab003269, 0x00030001, 0x00020001,
+0x00000001, 0x00000000, 0xabab0072, 0x00030002, 0x00010003, 0x00000002, 0x00000000, 0x00000252,
+0x00000258, 0x00000268, 0x00000258, 0x000001f8, 0x0000026c, 0x0000027c, 0x00000280, 0x00000005,
+0x000a0001, 0x00040002, 0x00000290, 0x41300000, 0x00000000, 0x00000000, 0x00000000, 0x41400000,
+0x00000000, 0x00000000, 0x00000000, 0x4151999a, 0x4161999a, 0x00000000, 0x00000000, 0x40470a3d,
+0x00000000, 0x00000000, 0x00000000, 0x404d70a4, 0x00000000, 0x00000000, 0x00000000, 0x4053d70a,
+0x00000000, 0x00000000, 0x00000000, 0x405a3d71, 0x00000000, 0x00000000, 0x00000000, 0x4060a3d7,
+0x00000000, 0x00000000, 0x00000000, 0x40670a3d, 0x00000000, 0x00000000, 0x00000000, 0x41700000,
+0x00000000, 0x00000000, 0x00000000, 0x41800000, 0x00000000, 0x00000000, 0x00000000, 0x4188cccd,
+0x4190cccd, 0x00000000, 0x00000000, 0x4083851f, 0x00000000, 0x00000000, 0x00000000, 0x4086b852,
+0x00000000, 0x00000000, 0x00000000, 0x4089eb85, 0x00000000, 0x00000000, 0x00000000, 0x408d1eb8,
+0x00000000, 0x00000000, 0x00000000, 0x409051ec, 0x00000000, 0x00000000, 0x00000000, 0x4093851f,
+0x00000000, 0x00000000, 0x00000000, 0x00333172, 0x00030002, 0x00030001, 0x00000002, 0x00000000,
+0x4083851f, 0x4086b852, 0x4089eb85, 0x00000000, 0x408d1eb8, 0x409051ec, 0x4093851f, 0x00000000,
+0x00313372, 0x00030002, 0x00010003, 0x00000002, 0x00000000, 0x40470a3d, 0x00000000, 0x00000000,
+0x00000000, 0x404d70a4, 0x00000000, 0x00000000, 0x00000000, 0x4053d70a, 0x00000000, 0x00000000,
+0x00000000, 0x405a3d71, 0x00000000, 0x00000000, 0x00000000, 0x4060a3d7, 0x00000000, 0x00000000,
+0x00000000, 0x40670a3d, 0x00000000, 0x00000000, 0x00000000, 0xabab0073, 0x00030000, 0x00010001,
+0x00000001, 0x00000000, 0x0000010c, 0x0000048c, 0x0000022c, 0x00000258, 0x00000005, 0x00020001,
+0x00020001, 0x0000049c, 0x40466666, 0x00000000, 0x00000000, 0x00000000, 0x41f80000, 0x00000000,
+0x00000000, 0x00000000, 0x00325f73, 0x00000005, 0x00020001, 0x00020002, 0x0000049c, 0x40833333,
+0x00000000, 0x00000000, 0x00000000, 0x42240000, 0x00000000, 0x00000000, 0x00000000, 0x40866666,
+0x00000000, 0x00000000, 0x00000000, 0x42280000, 0x00000000, 0x00000000, 0x00000000, 0x00335f73,
+0x00000005, 0x00020001, 0x00020003, 0x0000049c, 0x40a33333, 0x00000000, 0x00000000, 0x00000000,
+0x424c0000, 0x00000000, 0x00000000, 0x00000000, 0x40a66666, 0x00000000, 0x00000000, 0x00000000,
+0x42500000, 0x00000000, 0x00000000, 0x00000000, 0x40a9999a, 0x00000000, 0x00000000, 0x00000000,
+0x42540000, 0x00000000, 0x00000000, 0x00000000, 0xabab0076, 0x00030001, 0x00030001, 0x00000002,
+0x00000000, 0x40070a3d, 0x400d70a4, 0x4013d70a, 0x00000000, 0x401a3d71, 0x4020a3d7, 0x40270a3d,
+0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c,
+0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x0200001f,
+0x80000000, 0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x02000001, 0x80070000, 0xa0e4002a,
+0x03000002, 0x80070000, 0x80e40000, 0xa0e4002c, 0x03000002, 0x80040000, 0x80aa0000, 0xa0000017,
+0x03000002, 0xe0080000, 0x80aa0000, 0xa0000011, 0x02000001, 0x80010001, 0xa000002d, 0x03000005,
+0x80040000, 0x80000001, 0xa0000026, 0x03000005, 0x80040000, 0x80aa0000, 0x90000000, 0x03000005,
+0xe0010000, 0x80aa0000, 0xa055000b, 0x03000002, 0x80020000, 0x80550000, 0xa0000016, 0x03000002,
+0x80010000, 0x80000000, 0xa0000015, 0x03000002, 0x80010000, 0x80000000, 0xa000000f, 0x03000002,
+0x80020000, 0x80550000, 0xa0000010, 0x03000005, 0x80040000, 0xa000002e, 0x90550000, 0x04000004,
+0xe0020000, 0x80aa0000, 0xa0000028, 0x80550000, 0x03000005, 0x80020000, 0xa0000018, 0x90aa0000,
+0x03000005, 0x80020000, 0x80550000, 0xa000001c, 0x03000005, 0x80020000, 0x80550000, 0xa000002f,
+0x03000005, 0x80020000, 0x80550000, 0xa0000020, 0x04000004, 0xe0040000, 0x80550000, 0xa0aa0024,
+0x80000000, 0x0000ffff,
+};
+
+const struct
+{
+    const char *fullname;
+    D3DXCONSTANT_DESC desc;
+    UINT ctaboffset;
+}
+test_get_shader_constant_variables_data[] =
+{
+    {"f",         {"f",   D3DXRS_FLOAT4, 45,  1, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1,  1, 1, 0,  4, NULL},  72},
+    {"f23",       {"f23", D3DXRS_FLOAT4, 29,  4, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 2,  3, 2, 0, 48, NULL},  81},
+    {"f23[0]",    {"f23", D3DXRS_FLOAT4, 29,  3, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 2,  3, 1, 0, 24, NULL},  81},
+    {"f23[1]",    {"f23", D3DXRS_FLOAT4, 32,  1, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 2,  3, 1, 0, 24, NULL},  93},
+    {"f32",       {"f32", D3DXRS_FLOAT4, 33,  4, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 3,  2, 2, 0, 48, NULL}, 110},
+    {"f32[0]",    {"f32", D3DXRS_FLOAT4, 33,  2, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 3,  2, 1, 0, 24, NULL}, 110},
+    {"f32[1]",    {"f32", D3DXRS_FLOAT4, 35,  2, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 3,  2, 1, 0, 24, NULL}, 118},
+    {"f_2",       {"f_2", D3DXRS_FLOAT4, 37,  2, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1,  1, 2, 0,  8, NULL}, 131},
+    {"f_2[0]",    {"f_2", D3DXRS_FLOAT4, 37,  1, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1,  1, 1, 0,  4, NULL}, 131},
+    {"f_2[1]",    {"f_2", D3DXRS_FLOAT4, 38,  1, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1,  1, 1, 0,  4, NULL}, 135},
+    {"i",         {"i",   D3DXRS_FLOAT4, 47,  1, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 144},
+    {"i[0]",      {"i",   D3DXRS_FLOAT4, 47,  1, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 144},
+    {"p",         {"p",   D3DXRS_FLOAT4,  0, 18, D3DXPC_STRUCT,         D3DXPT_VOID,  1, 10, 2, 4, 80, NULL}, 176},
+    {"p[0]",      {"p",   D3DXRS_FLOAT4,  0,  9, D3DXPC_STRUCT,         D3DXPT_VOID,  1, 10, 1, 4, 40, NULL}, 176},
+    {"p[0].i1",   {"i1",  D3DXRS_FLOAT4,  0,  1, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 176},
+    {"p[0].i2",   {"i2",  D3DXRS_FLOAT4,  1,  1, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 180},
+    {"p[0].f_2",  {"f_2", D3DXRS_FLOAT4,  2,  1, D3DXPC_VECTOR,         D3DXPT_FLOAT, 1,  2, 1, 0,  8, NULL}, 184},
+    {"p[0].r",    {"r",   D3DXRS_FLOAT4,  3,  6, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 3,  1, 2, 0, 24, NULL}, 188},
+    {"p[0].r[0]", {"r",   D3DXRS_FLOAT4,  3,  3, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 3,  1, 1, 0, 12, NULL}, 188},
+    {"p[0].r[1]", {"r",   D3DXRS_FLOAT4,  6,  3, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 3,  1, 1, 0, 12, NULL}, 200},
+    {"p[1]",      {"p",   D3DXRS_FLOAT4,  9,  9, D3DXPC_STRUCT,         D3DXPT_VOID,  1, 10, 1, 4, 40, NULL}, 212},
+    {"p[1].i1",   {"i1",  D3DXRS_FLOAT4,  9,  1, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 212},
+    {"p[1].i2",   {"i2",  D3DXRS_FLOAT4, 10,  1, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 216},
+    {"p[1].f_2",  {"f_2", D3DXRS_FLOAT4, 11,  1, D3DXPC_VECTOR,         D3DXPT_FLOAT, 1,  2, 1, 0,  8, NULL}, 220},
+    {"p[1].r",    {"r",   D3DXRS_FLOAT4, 12,  6, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 3,  1, 2, 0, 24, NULL}, 224},
+    {"p[1].r[0]", {"r",   D3DXRS_FLOAT4, 12,  3, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 3,  1, 1, 0, 12, NULL}, 224},
+    {"p[1].r[1]", {"r",   D3DXRS_FLOAT4, 15,  3, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 3,  1, 1, 0, 12, NULL}, 236},
+    {"r13",       {"r13", D3DXRS_FLOAT4, 43,  2, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 1,  3, 2, 0, 24, NULL}, 253},
+    {"r13[0]",    {"r13", D3DXRS_FLOAT4, 43,  1, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 1,  3, 1, 0, 12, NULL}, 253},
+    {"r13[1]",    {"r13", D3DXRS_FLOAT4, 44,  1, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 1,  3, 1, 0, 12, NULL}, 257},
+    {"r31",       {"r31", D3DXRS_FLOAT4, 18,  6, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 3,  1, 2, 0, 24, NULL}, 266},
+    {"r31[0]",    {"r31", D3DXRS_FLOAT4, 18,  3, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 3,  1, 1, 0, 12, NULL}, 266},
+    {"r31[1]",    {"r31", D3DXRS_FLOAT4, 21,  3, D3DXPC_MATRIX_ROWS,    D3DXPT_FLOAT, 3,  1, 1, 0, 12, NULL}, 278},
+    {"s",         {"s",   D3DXRS_FLOAT4, 46,  1, D3DXPC_STRUCT,         D3DXPT_VOID,  1,  2, 1, 2,  8, NULL}, 303},
+    {"s.f",       {"f",   D3DXRS_FLOAT4, 46,  1, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1,  1, 1, 0,  4, NULL}, 303},
+    {"s.i",       {"i",   D3DXRS_FLOAT4, 47,  0, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 307},
+    {"s_2",       {"s_2", D3DXRS_FLOAT4, 39,  2, D3DXPC_STRUCT,         D3DXPT_VOID,  1,  2, 2, 2, 16, NULL}, 316},
+    {"s_2[0]",    {"s_2", D3DXRS_FLOAT4, 39,  2, D3DXPC_STRUCT,         D3DXPT_VOID,  1,  2, 1, 2,  8, NULL}, 316},
+    {"s_2[0].f",  {"f",   D3DXRS_FLOAT4, 39,  1, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1,  1, 1, 0,  4, NULL}, 316},
+    {"s_2[0].i",  {"i",   D3DXRS_FLOAT4, 40,  1, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 320},
+    {"s_2[1]",    {"s_2", D3DXRS_FLOAT4, 41,  0, D3DXPC_STRUCT,         D3DXPT_VOID,  1,  2, 1, 2,  8, NULL}, 324},
+    {"s_2[1].f",  {"f",   D3DXRS_FLOAT4, 41,  0, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1,  1, 1, 0,  4, NULL}, 324},
+    {"s_2[1].i",  {"i",   D3DXRS_FLOAT4, 41,  0, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 328},
+    {"s_3",       {"s_3", D3DXRS_FLOAT4, 24,  5, D3DXPC_STRUCT,         D3DXPT_VOID,  1,  2, 3, 2, 24, NULL}, 337},
+    {"s_3[0]",    {"s_3", D3DXRS_FLOAT4, 24,  2, D3DXPC_STRUCT,         D3DXPT_VOID,  1,  2, 1, 2,  8, NULL}, 337},
+    {"s_3[0].f",  {"f",   D3DXRS_FLOAT4, 24,  1, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1,  1, 1, 0,  4, NULL}, 337},
+    {"s_3[0].i",  {"i",   D3DXRS_FLOAT4, 25,  1, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 341},
+    {"s_3[1]",    {"s_3", D3DXRS_FLOAT4, 26,  2, D3DXPC_STRUCT,         D3DXPT_VOID,  1,  2, 1, 2,  8, NULL}, 345},
+    {"s_3[1].f",  {"f",   D3DXRS_FLOAT4, 26,  1, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1,  1, 1, 0,  4, NULL}, 345},
+    {"s_3[1].i",  {"i",   D3DXRS_FLOAT4, 27,  1, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 349},
+    {"s_3[2]",    {"s_3", D3DXRS_FLOAT4, 28,  1, D3DXPC_STRUCT,         D3DXPT_VOID,  1,  2, 1, 2,  8, NULL}, 353},
+    {"s_3[2].f",  {"f",   D3DXRS_FLOAT4, 28,  1, D3DXPC_SCALAR,         D3DXPT_FLOAT, 1,  1, 1, 0,  4, NULL}, 353},
+    {"s_3[2].i",  {"i",   D3DXRS_FLOAT4, 29,  0, D3DXPC_SCALAR,         D3DXPT_INT,   1,  1, 1, 0,  4, NULL}, 357},
+    {"v",         {"v",   D3DXRS_FLOAT4, 41,  2, D3DXPC_VECTOR,         D3DXPT_FLOAT, 1,  3, 2, 0, 24, NULL}, 366},
+    {"v[0]",      {"v",   D3DXRS_FLOAT4, 41,  1, D3DXPC_VECTOR,         D3DXPT_FLOAT, 1,  3, 1, 0, 12, NULL}, 366},
+    {"v[1]",      {"v",   D3DXRS_FLOAT4, 42,  1, D3DXPC_VECTOR,         D3DXPT_FLOAT, 1,  3, 1, 0, 12, NULL}, 370},
+};
+
+static void test_get_shader_constant_variables(void)
+{
+    ID3DXConstantTable *ctable;
+    HRESULT hr;
+    ULONG count;
+    UINT i;
+    UINT nr = 1;
+    D3DXHANDLE constant, element;
+    D3DXCONSTANT_DESC desc;
+    DWORD *ctab;
+
+    hr = D3DXGetShaderConstantTable(test_get_shader_constant_variables_blob, &ctable);
+    ok(hr == D3D_OK, "D3DXGetShaderConstantTable failed, got %08x, expected %08x\n", hr, D3D_OK);
+
+    ctab = ID3DXConstantTable_GetBufferPointer(ctable);
+    ok(ctab[0] == test_get_shader_constant_variables_blob[3], "ID3DXConstantTable_GetBufferPointer failed\n");
+
+    for (i = 0; i < ARRAY_SIZE(test_get_shader_constant_variables_data); ++i)
+    {
+        const char *fullname = test_get_shader_constant_variables_data[i].fullname;
+        const D3DXCONSTANT_DESC *expected_desc = &test_get_shader_constant_variables_data[i].desc;
+        UINT ctaboffset = test_get_shader_constant_variables_data[i].ctaboffset;
+
+        constant = ID3DXConstantTable_GetConstantByName(ctable, NULL, fullname);
+        ok(constant != NULL, "GetConstantByName \"%s\" failed\n", fullname);
+
+        hr = ID3DXConstantTable_GetConstantDesc(ctable, constant, &desc, &nr);
+        ok(hr == D3D_OK, "GetConstantDesc \"%s\" failed, got %08x, expected %08x\n", fullname, hr, D3D_OK);
+
+        ok(!strcmp(expected_desc->Name, desc.Name), "GetConstantDesc \"%s\" failed, got \"%s\", expected \"%s\"\n",
+                fullname, desc.Name, expected_desc->Name);
+        ok(expected_desc->RegisterSet == desc.RegisterSet, "GetConstantDesc \"%s\" failed, got %#x, expected %#x\n",
+                fullname, desc.RegisterSet, expected_desc->RegisterSet);
+        ok(expected_desc->RegisterIndex == desc.RegisterIndex, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                fullname, desc.RegisterIndex, expected_desc->RegisterIndex);
+        ok(expected_desc->RegisterCount == desc.RegisterCount, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                fullname, desc.RegisterCount, expected_desc->RegisterCount);
+        ok(expected_desc->Class == desc.Class, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                fullname, desc.Class, expected_desc->Class);
+        ok(expected_desc->Type == desc.Type, "GetConstantDesc \"%s\" failed, got %#x, expected %#x\n",
+                fullname, desc.Type, expected_desc->Type);
+        ok(expected_desc->Rows == desc.Rows, "GetConstantDesc \"%s\" failed, got %#x, expected %#x\n",
+                fullname, desc.Rows, expected_desc->Rows);
+        ok(expected_desc->Columns == desc.Columns, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                fullname, desc.Columns, expected_desc->Columns);
+        ok(expected_desc->Elements == desc.Elements, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                fullname, desc.Elements, expected_desc->Elements);
+        ok(expected_desc->StructMembers == desc.StructMembers, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                fullname, desc.StructMembers, expected_desc->StructMembers);
+        ok(expected_desc->Bytes == desc.Bytes, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                fullname, desc.Bytes, expected_desc->Bytes);
+        ok(ctaboffset == (DWORD *)desc.DefaultValue - ctab, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+           fullname, (UINT)((DWORD *)desc.DefaultValue - ctab), ctaboffset);
+    }
+
+    element = ID3DXConstantTable_GetConstantElement(ctable, NULL, 0);
+    ok(element == NULL, "GetConstantElement failed\n");
+
+    constant = ID3DXConstantTable_GetConstantByName(ctable, NULL, "i");
+    ok(constant != NULL, "GetConstantByName failed\n");
+
+    element = ID3DXConstantTable_GetConstantByName(ctable, NULL, "i[0]");
+    ok(constant == element, "GetConstantByName failed, got %p, expected %p\n", element, constant);
+
+    element = ID3DXConstantTable_GetConstantElement(ctable, "i", 0);
+    ok(element == constant, "GetConstantElement failed, got %p, expected %p\n", element, constant);
+
+    constant = ID3DXConstantTable_GetConstantByName(ctable, NULL, "f");
+    ok(constant != NULL, "GetConstantByName failed\n");
+
+    element = ID3DXConstantTable_GetConstant(ctable, NULL, 0);
+    ok(element == constant, "GetConstant failed, got %p, expected %p\n", element, constant);
+
+    element = ID3DXConstantTable_GetConstant(ctable, "invalid", 0);
+    ok(element == NULL, "GetConstant failed\n");
+
+    element = ID3DXConstantTable_GetConstant(ctable, "f", 0);
+    ok(element == NULL, "GetConstant failed\n");
+
+    element = ID3DXConstantTable_GetConstantByName(ctable, NULL, "f[0]");
+    ok(constant == element, "GetConstantByName failed, got %p, expected %p\n", element, constant);
+
+    element = ID3DXConstantTable_GetConstantByName(ctable, NULL, "f[1]");
+    ok(NULL == element, "GetConstantByName failed\n");
+
+    element = ID3DXConstantTable_GetConstantByName(ctable, NULL, "f[0][0]");
+    ok(constant == element, "GetConstantByName failed, got %p, expected %p\n", element, constant);
+
+    element = ID3DXConstantTable_GetConstantByName(ctable, NULL, "f.");
+    ok(element == NULL, "GetConstantByName failed\n");
+
+    element = ID3DXConstantTable_GetConstantElement(ctable, "f", 0);
+    ok(element == constant, "GetConstantElement failed, got %p, expected %p\n", element, constant);
+
+    element = ID3DXConstantTable_GetConstantElement(ctable, "f", 1);
+    ok(element == NULL, "GetConstantElement failed\n");
+
+    constant = ID3DXConstantTable_GetConstantByName(ctable, NULL, "f_2[0]");
+    ok(constant != NULL, "GetConstantByName failed\n");
+
+    element = ID3DXConstantTable_GetConstantByName(ctable, NULL, "f_2");
+    ok(element != constant, "GetConstantByName failed, got %p, expected %p\n", element, constant);
+
+    element = ID3DXConstantTable_GetConstantElement(ctable, "f_2", 0);
+    ok(element == constant, "GetConstantElement failed, got %p, expected %p\n", element, constant);
+
+    constant = ID3DXConstantTable_GetConstantByName(ctable, NULL, "f_2[1]");
+    ok(constant != NULL, "GetConstantByName failed\n");
+
+    element = ID3DXConstantTable_GetConstantElement(ctable, "f_2", 1);
+    ok(element == constant, "GetConstantElement failed, got %p, expected %p\n", element, constant);
+
+    constant = ID3DXConstantTable_GetConstantByName(ctable, NULL, "s_2[0].f");
+    ok(constant != NULL, "GetConstantByName failed\n");
+
+    element = ID3DXConstantTable_GetConstant(ctable, "s_2[0]", 0);
+    ok(element == constant, "GetConstant failed, got %p, expected %p\n", element, constant);
+
+    element = ID3DXConstantTable_GetConstantByName(ctable, "s_2[0]", "f");
+    ok(element == constant, "GetConstantByName failed, got %p, expected %p\n", element, constant);
+
+    element = ID3DXConstantTable_GetConstantByName(ctable, "s_2[0]", "invalid");
+    ok(element == NULL, "GetConstantByName failed\n");
+
+    constant = ID3DXConstantTable_GetConstantByName(ctable, NULL, "s_2[0]");
+    ok(constant != NULL, "GetConstantByName failed\n");
+
+    element = ID3DXConstantTable_GetConstantElement(ctable, "s_2[0]", 0);
+    ok(constant == element, "GetConstantByName failed, got %p, expected %p\n", element, constant);
+
+    count = ID3DXConstantTable_Release(ctable);
+    ok(count == 0, "Release failed, got %u, expected %u\n", count, 0);
+}
+
+#define REGISTER_OUTPUT_SIZE 48
+
+enum Type {SetFloat, SetInt, SetBool, SetIntArray, SetBoolArray, SetFloatArray, SetMatrix,
+    SetMatrixTranspose, SetMatrixArray, SetMatrixTransposeArray, SetVector, SetVectorArray,
+    SetValue, SetMatrixPointerArray, SetMatrixTransposePointerArray};
+
+struct registerset_test
+{
+    enum Type type;
+    UINT in_index;
+    UINT in_count_min;
+    UINT in_count_max;
+    UINT out_count;
+    DWORD out[REGISTER_OUTPUT_SIZE];
+};
+
+struct registerset_constants
+{
+    const char *fullname;
+    D3DXCONSTANT_DESC desc;
+    UINT ctaboffset;
+};
+
+static const DWORD registerset_test_input[][REGISTER_OUTPUT_SIZE] =
+{
+    /* float */
+    {0x40000123, 0x00000000, 0x40800123, 0x40a00123,
+    0x40c00123, 0x40e00123, 0x41000123, 0x41100123,
+    0x41200123, 0x41300123, 0x41400123, 0x41500123,
+    0x41600123, 0x41700123, 0x41800123, 0x41900123,
+    0x41a00123, 0x41b00123, 0x41c00123, 0x41d00123,
+    0x00000000, 0x41f00123, 0x42000123, 0x42100123,
+    0x00000000, 0x42300123, 0x42400123, 0x42500123,
+    0x42600123, 0x42700123, 0x42800123, 0x42900123,
+    0x43000123, 0x43100123, 0x43200123, 0x43300123,
+    0x43400123, 0x43500123, 0x43600123, 0x43700123,
+    0x43800123, 0x43900123, 0x43a00123, 0x43b00123,
+    0x43c00123, 0x43d00123, 0x43e00123, 0x43f00123},
+    /* int */
+    {0x00000002, 0x00000003, 0x00000004, 0x00000005,
+    0x00000000, 0x00000007, 0x00000008, 0x00000009,
+    0x0000000a, 0x0000000b, 0x0000000c, 0x0000000d,
+    0x0000000e, 0x0000000f, 0x00000010, 0x00000011,
+    0x00000012, 0x00000000, 0x00000000, 0x00000015,
+    0x00000016, 0x00000017, 0x00000018, 0x00000019,
+    0x0000001a, 0x0000001b, 0x0000001c, 0x0000001d,
+    0x0000001e, 0x0000001f, 0x00000020, 0x00000021,
+    0x00000022, 0x00000023, 0x00000024, 0x00000025,
+    0x00000026, 0x00000027, 0x00000028, 0x00000029,
+    0x0000002a, 0x0000002b, 0x0000002c, 0x0000002d,
+    0x0000002e, 0x0000002f, 0x00000030, 0x00000031},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+bool b = 1;
+int n = 8;
+float f = 5.1;
+int nf = 11;
+bool bf = 1;
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (b) for (i = 0; i < n; i++) tmp.x += pos.z * f * nf;
+    else for (i = 0; i < n; i++) tmp.y += pos.y * f * bf;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_scalar[] =
+{
+0xfffe0300, 0x0051fffe, 0x42415443, 0x0000001c, 0x0000010f, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x00000108, 0x00000080, 0x00000000, 0x00000001, 0x00000084, 0x00000094, 0x00000098,
+0x00020002, 0x00000001, 0x00000084, 0x0000009c, 0x000000ac, 0x00000002, 0x00000001, 0x000000b0,
+0x000000c0, 0x000000d0, 0x00000001, 0x00000001, 0x000000d4, 0x000000e4, 0x000000f4, 0x00010002,
+0x00000001, 0x000000d4, 0x000000f8, 0xabab0062, 0x00010000, 0x00010001, 0x00000001, 0x00000000,
+0xffffffff, 0xab006662, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0xabab0066, 0x00030000,
+0x00010001, 0x00000001, 0x00000000, 0x40a33333, 0x00000000, 0x00000000, 0x00000000, 0xabab006e,
+0x00020000, 0x00010001, 0x00000001, 0x00000000, 0x00000008, 0x00000000, 0x00000001, 0x00000000,
+0xab00666e, 0x41300000, 0x00000000, 0x00000000, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369,
+0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072,
+0x392e3932, 0x332e3235, 0x00313131, 0x05000051, 0xa00f0003, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x0200001f, 0x80000000, 0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x01000028,
+0xe0e40800, 0x03000005, 0x80010000, 0xa0000000, 0x90aa0000, 0x02000001, 0x80010001, 0xa0000003,
+0x01000026, 0xf0e40000, 0x04000004, 0x80010001, 0x80000000, 0xa0000001, 0x80000001, 0x00000027,
+0x02000001, 0x80020001, 0xa0000003, 0x0000002a, 0x03000005, 0x80010000, 0xa0000000, 0x90550000,
+0x02000001, 0x80020001, 0xa0000003, 0x01000026, 0xf0e40000, 0x04000004, 0x80020001, 0x80000000,
+0xa0000002, 0x80550001, 0x00000027, 0x02000001, 0x80010001, 0xa0000003, 0x0000002b, 0x02000001,
+0xe0030000, 0x80e40001, 0x02000001, 0xe00c0000, 0xa0000003, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_scalar_float[] =
+{
+    {"f", {"f", D3DXRS_FLOAT4, 0, 1, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 1, 0, 4, NULL}, 48},
+};
+
+static const struct registerset_test registerset_test_scalar_float[] =
+{
+    {SetFloat, 0, 0, 0, 4, {0x40000123}},
+    {SetInt, 1, 0, 0, 4, {0x40000000}},
+    {SetBool, 1, 0, 0, 4, {0x3f800000}},
+    {SetIntArray},
+    {SetIntArray, 1, 1, REGISTER_OUTPUT_SIZE, 4, {0x40000000}},
+    {SetBoolArray},
+    {SetBoolArray, 1, 1, REGISTER_OUTPUT_SIZE, 4, {0x3f800000}},
+    {SetFloatArray},
+    {SetFloatArray, 0, 1, REGISTER_OUTPUT_SIZE, 4, {0x40000123}},
+    {SetValue, 0, 0, 3},
+    {SetValue, 0, 4, REGISTER_OUTPUT_SIZE * 4, 4, {0x40000123}},
+    {SetVector, 0, 0, 0, 4, {0x40000123}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 4, {0x40000123}},
+    {SetMatrix, 0, 0, 0, 4, {0x40000123},},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000123}},
+    {SetMatrixTranspose, 0, 0, 0, 4, {0x40000123},},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000123}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000123}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000123}},
+};
+
+static const struct registerset_constants registerset_constants_scalar_int[] =
+{
+    {"n", {"n", D3DXRS_INT4, 0, 1, D3DXPC_SCALAR, D3DXPT_INT, 1, 1, 1, 0, 4, NULL}, 57},
+};
+
+static const struct registerset_test registerset_test_scalar_int[] =
+{
+    {SetFloat, 0, 0, 0, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetInt, 1, 0, 0, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetBool, 1, 0, 0, 4,
+        {0x00000001, 0x00000000, 0x00000001}},
+    {SetIntArray},
+    {SetIntArray, 1, 1, REGISTER_OUTPUT_SIZE, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetBoolArray},
+    {SetBoolArray, 1, 1, REGISTER_OUTPUT_SIZE, 4,
+        {0x00000001, 0x00000000, 0x00000001}},
+    {SetFloatArray},
+    {SetFloatArray, 0, 1, REGISTER_OUTPUT_SIZE, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetValue, 1, 0, 3},
+    {SetValue, 1, 4, REGISTER_OUTPUT_SIZE * 4, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetVector, 0, 0, 0, 4,
+        {0x00000002, 0x00000000, 0x00000001},},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000002, 0x00000000, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_scalar_int_float[] =
+{
+    {"nf", {"nf", D3DXRS_FLOAT4, 1, 1, D3DXPC_SCALAR, D3DXPT_INT, 1, 1, 1, 0, 4, NULL}, 62},
+};
+
+static const struct registerset_test registerset_test_scalar_int_float[] =
+{
+    {SetFloat, 0, 0, 0, 4, {0x40000000}},
+    {SetInt, 1, 0, 0, 4, {0x40000000}},
+    {SetBool, 1, 0, 0, 4, {0x3f800000}},
+    {SetIntArray},
+    {SetIntArray, 1, 1, REGISTER_OUTPUT_SIZE, 4, {0x40000000}},
+    {SetBoolArray},
+    {SetBoolArray, 1, 1, REGISTER_OUTPUT_SIZE, 4, {0x3f800000}},
+    {SetFloatArray},
+    {SetFloatArray, 0, 1, REGISTER_OUTPUT_SIZE, 4, {0x40000000}},
+    {SetValue, 1, 0, 3},
+    {SetValue, 1, 4, REGISTER_OUTPUT_SIZE * 4, 4, {0x40000000}},
+    {SetVector, 0, 0, 0, 4, {0x40000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 4, {0x40000000}},
+    {SetMatrix, 0, 0, 0, 4, {0x40000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000000}},
+    {SetMatrixTranspose, 0, 0, 0, 4, {0x40000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000000}},
+};
+
+static const struct registerset_constants registerset_constants_scalar_bool_float[] =
+{
+    {"bf", {"bf", D3DXRS_FLOAT4, 2, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0, 4, NULL}, 39},
+};
+
+static const struct registerset_test registerset_test_scalar_bool_float[] =
+{
+    {SetFloat, 0, 0, 0, 4, {0x3f800000}},
+    {SetInt, 1, 0, 0, 4, {0x3f800000}},
+    {SetBool, 1, 0, 0, 4, {0x3f800000}},
+    {SetIntArray},
+    {SetIntArray, 1, 1, REGISTER_OUTPUT_SIZE, 4, {0x3f800000}},
+    {SetBoolArray},
+    {SetBoolArray, 1, 1, REGISTER_OUTPUT_SIZE, 4, {0x3f800000}},
+    {SetFloatArray},
+    {SetFloatArray, 0, 1, REGISTER_OUTPUT_SIZE, 4, {0x3f800000}},
+    {SetValue, 1, 0, 3},
+    {SetValue, 1, 4, REGISTER_OUTPUT_SIZE * 4, 4, {0x3f800000}},
+    {SetVector, 0, 0, 0, 4, {0x3f800000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 4, {0x3f800000}},
+    {SetMatrix, 0, 0, 0, 4, {0x3f800000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x3f800000}},
+    {SetMatrixTranspose, 0, 0, 0, 4, {0x3f800000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x3f800000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x3f800000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x3f800000}},
+};
+
+static const struct registerset_constants registerset_constants_scalar_bool[] =
+{
+    {"b", {"b", D3DXRS_BOOL, 0, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0, 4, NULL}, 37},
+};
+
+static const struct registerset_test registerset_test_scalar_bool[] =
+{
+    {SetFloat, 0, 0, 0, 1, {0x00000001}},
+    {SetInt, 1, 0, 0, 1, {0x00000001}},
+    {SetBool, 1, 0, 0, 1, {0x00000002}},
+    {SetIntArray},
+    {SetIntArray, 1, 1, REGISTER_OUTPUT_SIZE, 1, {0x00000001}},
+    {SetBoolArray},
+    {SetBoolArray, 1, 1, REGISTER_OUTPUT_SIZE, 1, {0x00000002}},
+    {SetFloatArray},
+    {SetFloatArray, 0, 1, REGISTER_OUTPUT_SIZE, 1, {0x00000001}},
+    {SetValue, 1, 0, 3},
+    {SetValue, 1, 4, REGISTER_OUTPUT_SIZE * 4, 1, {0x00000002}},
+    {SetVector, 0, 0, 0, 1, {0x00000001}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 1, {0x00000001}},
+    {SetMatrix, 0, 0, 0, 1, {0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 1, {0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 1, {0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 1, {0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 1, {0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 1, {0x00000001}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+bool ab[2] = {1, 0};
+int an[2] = {32, 33};
+float af[2] = {3.1, 3.2};
+int anf[2] = {14, 15};
+bool abf[2] = {1, 1};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (ab[1]) for (i = 0; i < an[1]; i++) tmp.x += pos.z * af[0] * anf[1];
+    else for (i = 0; i < an[0]; i++) tmp.y += pos.y * af[1] * abf[1];
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_scalar_array[] =
+{
+0xfffe0300, 0x006afffe, 0x42415443, 0x0000001c, 0x00000173, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x0000016c, 0x00000080, 0x00000000, 0x00000002, 0x00000084, 0x00000094, 0x0000009c,
+0x00040002, 0x00000002, 0x000000a0, 0x000000b0, 0x000000d0, 0x00000002, 0x00000002, 0x000000d4,
+0x000000e4, 0x00000104, 0x00000001, 0x00000002, 0x00000108, 0x00000118, 0x00000138, 0x00020002,
+0x00000002, 0x0000013c, 0x0000014c, 0xab006261, 0x00010000, 0x00010001, 0x00000002, 0x00000000,
+0xffffffff, 0x00000000, 0x00666261, 0x00010000, 0x00010001, 0x00000002, 0x00000000, 0x3f800000,
+0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0xab006661,
+0x00030000, 0x00010001, 0x00000002, 0x00000000, 0x40466666, 0x00000000, 0x00000000, 0x00000000,
+0x404ccccd, 0x00000000, 0x00000000, 0x00000000, 0xab006e61, 0x00020000, 0x00010001, 0x00000002,
+0x00000000, 0x00000020, 0x00000000, 0x00000001, 0x00000000, 0x00000021, 0x00000000, 0x00000001,
+0x00000000, 0x00666e61, 0x00020000, 0x00010001, 0x00000002, 0x00000000, 0x41600000, 0x00000000,
+0x00000000, 0x00000000, 0x41700000, 0x00000000, 0x00000000, 0x00000000, 0x335f7376, 0x4d00305f,
+0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970,
+0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x05000051, 0xa00f0006, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x0200001f, 0x80000000, 0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000,
+0x01000028, 0xe0e40801, 0x03000005, 0x80010000, 0xa0000000, 0x90aa0000, 0x02000001, 0x80010001,
+0xa0000006, 0x01000026, 0xf0e40001, 0x04000004, 0x80010001, 0x80000000, 0xa0000003, 0x80000001,
+0x00000027, 0x02000001, 0x80020001, 0xa0000006, 0x0000002a, 0x03000005, 0x80010000, 0xa0000001,
+0x90550000, 0x02000001, 0x80020001, 0xa0000006, 0x01000026, 0xf0e40000, 0x04000004, 0x80020001,
+0x80000000, 0xa0000005, 0x80550001, 0x00000027, 0x02000001, 0x80010001, 0xa0000006, 0x0000002b,
+0x02000001, 0xe0030000, 0x80e40001, 0x02000001, 0xe00c0000, 0xa0000006, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_scalar_array_float[] =
+{
+    {"af",    {"af", D3DXRS_FLOAT4, 0, 2, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 2, 0, 8, NULL}, 57},
+    {"af[0]", {"af", D3DXRS_FLOAT4, 0, 1, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 1, 0, 4, NULL}, 57},
+    {"af[1]", {"af", D3DXRS_FLOAT4, 1, 1, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 1, 0, 4, NULL}, 61},
+};
+
+static const struct registerset_test registerset_test_scalar_array_float[] =
+{
+    {SetFloat, 0, 0, 0, 4, {0x40000123}},
+    {SetInt, 1, 0, 0, 4, {0x40000000}},
+    {SetBool, 1, 0, 0, 4, {0x3f800000}},
+    {SetIntArray},
+    {SetIntArray, 1, 1, 1, 4, {0x40000000}},
+    {SetIntArray, 1, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000}},
+    {SetBoolArray},
+    {SetBoolArray, 1, 1, 1, 4, {0x3f800000}},
+    {SetBoolArray, 1, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetFloatArray},
+    {SetFloatArray, 0, 1, 1, 4, {0x40000123}},
+    {SetFloatArray, 0, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetValue, 0, 0, 3},
+    {SetValue, 0, 4, 7, 4, {0x40000123}},
+    {SetValue, 0, 8, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123}},
+};
+
+static const struct registerset_constants registerset_constants_scalar_array_int[] =
+{
+    {"an",    {"an", D3DXRS_INT4, 0, 2, D3DXPC_SCALAR, D3DXPT_INT, 1, 1, 2, 0, 8, NULL}, 70},
+    {"an[0]", {"an", D3DXRS_INT4, 0, 1, D3DXPC_SCALAR, D3DXPT_INT, 1, 1, 1, 0, 4, NULL}, 70},
+    {"an[1]", {"an", D3DXRS_INT4, 1, 1, D3DXPC_SCALAR, D3DXPT_INT, 1, 1, 1, 0, 4, NULL}, 74},
+};
+
+static const struct registerset_test registerset_test_scalar_array_int[] =
+{
+    {SetFloat, 0, 0, 0, 4, {0x00000002, 0x00000000, 0x00000001}},
+    {SetInt, 1, 0, 0, 4, {0x00000002, 0x00000000, 0x00000001}},
+    {SetBool, 1, 0, 0, 4, {0x00000001, 0x00000000, 0x00000001}},
+    {SetIntArray},
+    {SetIntArray, 1, 1, 1, 4, {0x00000002, 0x00000000, 0x00000001}},
+    {SetIntArray, 1, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x00000000, 0x00000001}},
+    {SetBoolArray},
+    {SetBoolArray, 1, 1, 1, 4, {0x00000001, 0x00000000, 0x00000001}},
+    {SetBoolArray, 1, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001}},
+    {SetFloatArray},
+    {SetFloatArray, 0, 1, 1, 4, {0x00000002, 0x00000000, 0x00000001}},
+    {SetFloatArray, 0, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001}},
+    {SetValue, 1, 0, 3},
+    {SetValue, 1, 4, 7, 4, {0x00000002, 0x00000000, 0x00000001}},
+    {SetValue, 1, 8, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x00000000, 0x00000001}},
+    {SetVector, 0, 0, 0, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000000, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000000, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000000, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_scalar_array_bool[] =
+{
+    {"ab",    {"ab", D3DXRS_BOOL, 0, 2, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 2, 0, 8, NULL}, 37},
+    {"ab[0]", {"ab", D3DXRS_BOOL, 0, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0, 4, NULL}, 37},
+    {"ab[1]", {"ab", D3DXRS_BOOL, 1, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0, 4, NULL}, 38},
+};
+
+static const struct registerset_test registerset_test_scalar_array_bool[] =
+{
+    {SetFloat, 0, 0, 0, 1, {0x00000001}},
+    {SetInt, 1, 0, 0, 1, {0x00000001}},
+    {SetBool, 1, 0, 0, 1, {0x00000002}},
+    {SetIntArray},
+    {SetIntArray, 1, 1, 1, 1, {0x00000001}},
+    {SetIntArray, 1, 2, REGISTER_OUTPUT_SIZE, 2, {0x00000001, 0x00000001}},
+    {SetBoolArray},
+    {SetBoolArray, 1, 1, 1, 1, {0x00000002}},
+    {SetBoolArray, 1, 2, REGISTER_OUTPUT_SIZE, 2, {0x00000002, 0x00000003}},
+    {SetFloatArray},
+    {SetFloatArray, 0, 1, 1, 1, {0x00000001}},
+    {SetFloatArray, 0, 2, REGISTER_OUTPUT_SIZE, 2, {0x00000001, 0x00000000}},
+    {SetValue, 1, 0, 3},
+    {SetValue, 1, 4, 7, 1, {0x00000002}},
+    {SetValue, 1, 8, REGISTER_OUTPUT_SIZE * 4, 2, {0x00000002, 0x00000003}},
+    {SetVector, 0, 0, 0, 2, {0x00000001, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 2, {0x00000001, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 2, {0x00000001, 0x00000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 2, {0x00000001, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 2, {0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 2, {0x00000001, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 2, {0x00000001, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 2, {0x00000001, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_scalar_array_bool_float[] =
+{
+    {"abf",    {"abf", D3DXRS_FLOAT4, 4, 2, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 2, 0, 8, NULL}, 44},
+    {"abf[0]", {"abf", D3DXRS_FLOAT4, 4, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0, 4, NULL}, 44},
+    {"abf[1]", {"abf", D3DXRS_FLOAT4, 5, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0, 4, NULL}, 48},
+};
+
+static const struct registerset_test registerset_test_scalar_array_bool_float[] =
+{
+    {SetFloat, 0, 0, 0, 4, {0x3f800000}},
+    {SetInt, 1, 0, 0, 4, {0x3f800000}},
+    {SetBool, 1, 0, 0, 4, {0x3f800000}},
+    {SetIntArray},
+    {SetIntArray, 1, 1, 1, 4, {0x3f800000}},
+    {SetIntArray, 1, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetBoolArray},
+    {SetBoolArray, 1, 1, 1, 4, {0x3f800000}},
+    {SetBoolArray, 1, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetFloatArray},
+    {SetFloatArray, 0, 1, 1, 4, {0x3f800000}},
+    {SetFloatArray, 0, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetValue, 1, 0, 3},
+    {SetValue, 1, 4, 7, 4, {0x3f800000}},
+    {SetValue, 1, 8, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetVectorArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000}},
+};
+
+static const struct registerset_constants registerset_constants_scalar_array_int_float[] =
+{
+    {"anf",    {"anf", D3DXRS_FLOAT4, 2, 2, D3DXPC_SCALAR, D3DXPT_INT, 1, 1, 2, 0, 8, NULL}, 83},
+    {"anf[0]", {"anf", D3DXRS_FLOAT4, 2, 1, D3DXPC_SCALAR, D3DXPT_INT, 1, 1, 1, 0, 4, NULL}, 83},
+    {"anf[1]", {"anf", D3DXRS_FLOAT4, 3, 1, D3DXPC_SCALAR, D3DXPT_INT, 1, 1, 1, 0, 4, NULL}, 87},
+};
+
+static const struct registerset_test registerset_test_scalar_array_int_float[] =
+{
+    {SetFloat, 0, 0, 0, 4, {0x40000000}},
+    {SetInt, 1, 0, 0, 4, {0x40000000}},
+    {SetBool, 1, 0, 0, 4, {0x3f800000}},
+    {SetIntArray},
+    {SetIntArray, 1, 1, 1, 4, {0x40000000}},
+    {SetIntArray, 1, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000}},
+    {SetBoolArray},
+    {SetBoolArray, 1, 1, 1, 4, {0x3f800000}},
+    {SetBoolArray, 1, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetFloatArray},
+    {SetFloatArray, 0, 1, 1, 4, {0x40000000}},
+    {SetFloatArray, 0, 2, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetValue, 1, 0, 3},
+    {SetValue, 1, 4, 7, 4, {0x40000000}},
+    {SetValue, 1, 8, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+bool3 vb = {1, 0, 1};
+int3 vn = {7, 8, 9};
+float3 vf = {5.1, 5.2, 5.3};
+int3 vnf = {11, 85, 62};
+bool3 vbf = {1, 1, 1};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (vb.z) for (i = 0; i < vn.z; i++) tmp.x += pos.z * vf.z * vnf.z;
+    else for (i = 0; i < vn.y; i++) tmp.y += pos.y * vf.y * vbf.z;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_vector[] =
+{
+0xfffe0300, 0x0053fffe, 0x42415443, 0x0000001c, 0x00000117, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x00000110, 0x00000080, 0x00000000, 0x00000003, 0x00000084, 0x00000094, 0x000000a0,
+0x00020002, 0x00000001, 0x00000084, 0x000000a4, 0x000000b4, 0x00000002, 0x00000001, 0x000000b8,
+0x000000c8, 0x000000d8, 0x00000001, 0x00000003, 0x000000dc, 0x000000ec, 0x000000fc, 0x00010002,
+0x00000001, 0x000000dc, 0x00000100, 0xab006276, 0x00010001, 0x00030001, 0x00000001, 0x00000000,
+0xffffffff, 0x00000000, 0xffffffff, 0x00666276, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+0xab006676, 0x00030001, 0x00030001, 0x00000001, 0x00000000, 0x40a33333, 0x40a66666, 0x40a9999a,
+0x00000000, 0xab006e76, 0x00020001, 0x00030001, 0x00000001, 0x00000000, 0x00000007, 0x00000008,
+0x00000009, 0x00000000, 0x00666e76, 0x41300000, 0x42aa0000, 0x42780000, 0x00000000, 0x335f7376,
+0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320,
+0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x05000051, 0xa00f0003, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x0200001f, 0x80000000, 0x900f0000, 0x0200001f, 0x80000000,
+0xe00f0000, 0x01000028, 0xe0e40802, 0x03000005, 0x80010000, 0xa0aa0000, 0x90aa0000, 0x02000001,
+0x80010001, 0xa0000003, 0x01000026, 0xf0e40002, 0x04000004, 0x80010001, 0x80000000, 0xa0aa0001,
+0x80000001, 0x00000027, 0x02000001, 0x80020001, 0xa0000003, 0x0000002a, 0x03000005, 0x80010000,
+0xa0550000, 0x90550000, 0x02000001, 0x80020001, 0xa0000003, 0x01000026, 0xf0e40001, 0x04000004,
+0x80020001, 0x80000000, 0xa0aa0002, 0x80550001, 0x00000027, 0x02000001, 0x80010001, 0xa0000003,
+0x0000002b, 0x02000001, 0xe0030000, 0x80e40001, 0x02000001, 0xe00c0000, 0xa0000003, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_vector_float[] =
+{
+    {"vf", {"vf", D3DXRS_FLOAT4, 0, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3, 1, 0, 12, NULL}, 50},
+};
+
+static const struct registerset_test registerset_test_vector_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 2},
+    {SetIntArray, 1, 3, REGISTER_OUTPUT_SIZE, 4, {0x40000000, 0x40400000, 0x40800000}},
+    {SetBoolArray, 1, 0, 2},
+    {SetBoolArray, 1, 3, REGISTER_OUTPUT_SIZE, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 2},
+    {SetFloatArray, 0, 3, REGISTER_OUTPUT_SIZE, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetValue, 0, 0, 11},
+    {SetValue, 0, 12, REGISTER_OUTPUT_SIZE * 4, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetVector, 0, 0, 0, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetMatrix, 0, 0, 0, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetMatrixTranspose, 0, 0, 0, 4, {0x40000123, 0x40c00123, 0x41200123}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000123, 0x40c00123, 0x41200123}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000123, 0x40c00123, 0x41200123}},
+};
+
+static const struct registerset_constants registerset_constants_vector_int[] =
+{
+    {"vn", {"vn", D3DXRS_INT4, 0, 3, D3DXPC_VECTOR, D3DXPT_INT, 1, 3, 1, 0, 12, NULL}, 59},
+};
+
+static const struct registerset_test registerset_test_vector_int[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 2},
+    {SetIntArray, 1, 3, REGISTER_OUTPUT_SIZE, 4, {0x00000002, 0x00000003, 0x00000004}},
+    {SetBoolArray, 1, 0, 2},
+    {SetBoolArray, 1, 3, REGISTER_OUTPUT_SIZE, 4, {0x00000001, 0x00000001, 0x00000001}},
+    {SetFloatArray, 0, 0, 2},
+    {SetFloatArray, 0, 3, REGISTER_OUTPUT_SIZE, 4, {0x00000002, 0x00000000, 0x00000004}},
+    {SetValue, 1, 0, 11},
+    {SetValue, 1, 12, REGISTER_OUTPUT_SIZE * 4, 4, {0x00000002, 0x00000003, 0x00000004}},
+    {SetVector, 0, 0, 0, 4, {0x00000002, 0x00000000, 0x00000004}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 4, {0x00000002, 0x00000000, 0x00000004}},
+    {SetMatrix, 0, 0, 0, 4, {0x00000002, 0x00000000, 0x00000004}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x00000002, 0x00000000, 0x00000004}},
+    {SetMatrixTranspose, 0, 0, 0, 4, {0x00000002, 0x00000006, 0x0000000a}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x00000002, 0x00000006, 0x0000000a}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x00000002, 0x00000000, 0x00000004}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x00000002, 0x00000006, 0x0000000a}},
+};
+
+static const struct registerset_constants registerset_constants_vector_bool[] =
+{
+    {"vb", {"vb", D3DXRS_BOOL, 0, 3, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 37},
+};
+
+static const struct registerset_test registerset_test_vector_bool[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 2},
+    {SetIntArray, 1, 3, REGISTER_OUTPUT_SIZE, 3, {0x00000001, 0x00000001, 0x00000001}},
+    {SetBoolArray, 1, 0, 2},
+    {SetBoolArray, 1, 3, REGISTER_OUTPUT_SIZE, 3, {0x00000002, 0x00000003, 0x00000004}},
+    {SetFloatArray, 0, 0, 2},
+    {SetFloatArray, 0, 3, REGISTER_OUTPUT_SIZE, 3, {0x00000001, 0x00000000, 0x00000001}},
+    {SetValue, 1, 0, 11},
+    {SetValue, 1, 12, REGISTER_OUTPUT_SIZE * 4, 3, {0x00000002, 0x00000003, 0x00000004}},
+    {SetVector, 0, 0, 0, 3, {0x00000001, 0x00000000, 0x00000001}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 3, {0x00000001, 0x00000000, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 3, {0x00000001, 0x00000000, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 3, {0x00000001, 0x00000000, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 3, {0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 3, {0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 3, {0x00000001, 0x00000000, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 3, {0x00000001, 0x00000001, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_vector_bool_float[] =
+{
+    {"vbf", {"vbf", D3DXRS_FLOAT4, 2, 1, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 41},
+};
+
+static const struct registerset_test registerset_test_vector_bool_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 2},
+    {SetIntArray, 1, 3, REGISTER_OUTPUT_SIZE, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetBoolArray, 1, 0, 2},
+    {SetBoolArray, 1, 3, REGISTER_OUTPUT_SIZE, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 2},
+    {SetFloatArray, 0, 3, REGISTER_OUTPUT_SIZE, 4, {0x3f800000, 0x00000000, 0x3f800000}},
+    {SetValue, 1, 0, 11},
+    {SetValue, 1, 12, REGISTER_OUTPUT_SIZE * 4, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetVector, 0, 0, 0, 4, {0x3f800000, 0x00000000, 0x3f800000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 4, {0x3f800000, 0x00000000, 0x3f800000}},
+    {SetMatrix, 0, 0, 0, 4, {0x3f800000, 0x00000000, 0x3f800000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x3f800000, 0x00000000, 0x3f800000}},
+    {SetMatrixTranspose, 0, 0, 0, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x3f800000, 0x00000000, 0x3f800000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+};
+
+static const struct registerset_constants registerset_constants_vector_int_float[] =
+{
+    {"vnf", {"vnf", D3DXRS_FLOAT4, 1, 1, D3DXPC_VECTOR, D3DXPT_INT, 1, 3, 1, 0, 12, NULL}, 64},
+};
+
+static const struct registerset_test registerset_test_vector_int_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 2},
+    {SetIntArray, 1, 3, REGISTER_OUTPUT_SIZE, 4, {0x40000000, 0x40400000, 0x40800000}},
+    {SetBoolArray, 1, 0, 2},
+    {SetBoolArray, 1, 3, REGISTER_OUTPUT_SIZE, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 2},
+    {SetFloatArray, 0, 3, REGISTER_OUTPUT_SIZE, 4, {0x40000000, 0x00000000, 0x40800000}},
+    {SetValue, 1, 0, 11},
+    {SetValue, 1, 12, REGISTER_OUTPUT_SIZE * 4, 4, {0x40000000, 0x40400000, 0x40800000}},
+    {SetVector, 0, 0, 0, 4, {0x40000000, 0x00000000, 0x40800000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 4, {0x40000000, 0x00000000, 0x40800000}},
+    {SetMatrix, 0, 0, 0, 4, {0x40000000, 0x00000000, 0x40800000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000000, 0x00000000, 0x40800000}},
+    {SetMatrixTranspose, 0, 0, 0, 4, {0x40000000, 0x40c00000, 0x41200000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000000, 0x40c00000, 0x41200000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000000, 0x00000000, 0x40800000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4, {0x40000000, 0x40c00000, 0x41200000}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+bool3 vab[2] = {1, 0, 1, 1, 0, 1};
+int3 van[2] = {70, 80, 90, 100, 110, 120};
+float3 vaf[2] = {55.1, 55.2, 55.3, 55.4, 55.5, 55.6};
+int3 vanf[2] = {130, 140, 150, 160, 170, 180};
+bool3 vabf[2] = {1, 1, 1, 1, 1, 1};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (vab[1].z) for (i = 0; i < van[1].z; i++) tmp.x += pos.z * vaf[1].z * vanf[1].z;
+    else for (i = 0; i < van[1].y; i++) tmp.y += pos.y * vaf[0].y * vabf[1].z;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_vector_array[] =
+{
+0xfffe0300, 0x0070fffe, 0x42415443, 0x0000001c, 0x0000018b, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x00000184, 0x00000080, 0x00000000, 0x00000006, 0x00000084, 0x00000094, 0x000000ac,
+0x00040002, 0x00000002, 0x000000b4, 0x000000c4, 0x000000e4, 0x00000002, 0x00000002, 0x000000e8,
+0x000000f8, 0x00000118, 0x00000001, 0x00000006, 0x0000011c, 0x0000012c, 0x0000014c, 0x00020002,
+0x00000002, 0x00000154, 0x00000164, 0x00626176, 0x00010001, 0x00030001, 0x00000002, 0x00000000,
+0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x66626176, 0xababab00,
+0x00010001, 0x00030001, 0x00000002, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00666176, 0x00030001, 0x00030001, 0x00000002,
+0x00000000, 0x425c6666, 0x425ccccd, 0x425d3333, 0x00000000, 0x425d999a, 0x425e0000, 0x425e6666,
+0x00000000, 0x006e6176, 0x00020001, 0x00030001, 0x00000002, 0x00000000, 0x00000046, 0x00000050,
+0x0000005a, 0x00000000, 0x00000064, 0x0000006e, 0x00000078, 0x00000000, 0x666e6176, 0xababab00,
+0x00020001, 0x00030001, 0x00000002, 0x00000000, 0x43020000, 0x430c0000, 0x43160000, 0x00000000,
+0x43200000, 0x432a0000, 0x43340000, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73,
+0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932,
+0x332e3235, 0x00313131, 0x05000051, 0xa00f0006, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x0200001f, 0x80000000, 0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x01000028, 0xe0e40805,
+0x03000005, 0x80010000, 0xa0aa0001, 0x90aa0000, 0x02000001, 0x80010001, 0xa0000006, 0x01000026,
+0xf0e40005, 0x04000004, 0x80010001, 0x80000000, 0xa0aa0003, 0x80000001, 0x00000027, 0x02000001,
+0x80020001, 0xa0000006, 0x0000002a, 0x03000005, 0x80010000, 0xa0550000, 0x90550000, 0x02000001,
+0x80020001, 0xa0000006, 0x01000026, 0xf0e40004, 0x04000004, 0x80020001, 0x80000000, 0xa0aa0005,
+0x80550001, 0x00000027, 0x02000001, 0x80010001, 0xa0000006, 0x0000002b, 0x02000001, 0xe0030000,
+0x80e40001, 0x02000001, 0xe00c0000, 0xa0000006, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_vector_array_float[] =
+{
+    {"vaf",    {"vaf", D3DXRS_FLOAT4, 0, 2, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3, 2, 0, 24, NULL}, 62},
+    {"vaf[0]", {"vaf", D3DXRS_FLOAT4, 0, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3, 1, 0, 12, NULL}, 62},
+    {"vaf[1]", {"vaf", D3DXRS_FLOAT4, 1, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3, 1, 0, 12, NULL}, 66},
+};
+
+static const struct registerset_test registerset_test_vector_array_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 2},
+    {SetIntArray, 1, 3, 5, 4, {0x40000000, 0x40400000, 0x40800000}},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x40400000, 0x40800000, 0x00000000, 0x40a00000, 0x00000000, 0x40e00000}},
+    {SetBoolArray, 1, 0, 2},
+    {SetBoolArray, 1, 3, 5, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 2},
+    {SetFloatArray, 0, 3, 5, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40a00123, 0x40c00123, 0x40e00123}},
+    {SetValue, 0, 0, 11},
+    {SetValue, 0, 12, 23, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetValue, 0, 24, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40a00123, 0x40c00123, 0x40e00123}},
+    {SetVector, 0, 0, 0, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, 1, 4, {0x40000123, 0x00000000, 0x40800123}},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+};
+
+static const struct registerset_constants registerset_constants_vector_array_int[] =
+{
+    {"van",    {"van", D3DXRS_INT4, 0, 6, D3DXPC_VECTOR, D3DXPT_INT, 1, 3, 2, 0, 24, NULL}, 75},
+    {"van[0]", {"van", D3DXRS_INT4, 0, 1, D3DXPC_VECTOR, D3DXPT_INT, 1, 3, 1, 0, 12, NULL}, 75},
+    {"van[1]", {"van", D3DXRS_INT4, 1, 1, D3DXPC_VECTOR, D3DXPT_INT, 1, 3, 1, 0, 12, NULL}, 79},
+};
+
+static const struct registerset_test registerset_test_vector_array_int[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 2},
+    {SetIntArray, 1, 3, 5, 4, {0x00000002, 0x00000003, 0x00000004}},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000000, 0x00000005, 0x00000000, 0x00000007}},
+    {SetBoolArray, 1, 0, 2},
+    {SetBoolArray, 1, 3, 5, 4, {0x00000001, 0x00000001, 0x00000001}},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001}},
+    {SetFloatArray, 0, 0, 2},
+    {SetFloatArray, 0, 3, 5, 4, {0x00000002, 0x00000000, 0x00000004}},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000005, 0x00000006, 0x00000007}},
+    {SetValue, 1, 0, 11},
+    {SetValue, 1, 12, 23, 4, {0x00000002, 0x00000003, 0x00000004}},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000000, 0x00000005, 0x00000000, 0x00000007}},
+    {SetVector, 0, 0, 0, 4, {0x00000002, 0x00000000, 0x00000004}},
+    {SetVectorArray, 0, 0, 0},
+    {SetVectorArray, 0, 1, 1, 4, {0x00000002, 0x00000000, 0x00000004}},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+};
+
+static const struct registerset_constants registerset_constants_vector_array_bool[] =
+{
+    {"vab",    {"vab", D3DXRS_BOOL, 0, 6, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 2, 0, 24, NULL}, 37},
+    {"vab[0]", {"vab", D3DXRS_BOOL, 0, 3, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 37},
+    {"vab[1]", {"vab", D3DXRS_BOOL, 3, 3, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 40},
+};
+
+static const struct registerset_test registerset_test_vector_array_bool[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 2},
+    {SetIntArray, 1, 3, 5, 3, {0x00000001, 0x00000001, 0x00000001}},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001}},
+    {SetBoolArray, 1, 0},
+    {SetBoolArray, 1, 3, 5, 3, {0x00000002, 0x00000003, 0x00000004}},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000000, 0x00000007}},
+    {SetFloatArray, 0, 0, 2},
+    {SetFloatArray, 0, 3, 5, 3, {0x00000001, 0x00000000, 0x00000001}},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetValue, 1, 0, 11},
+    {SetValue, 1, 12, 23, 3, {0x00000002, 0x00000003, 0x00000004}},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 6,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000000, 0x00000007}},
+    {SetVector, 0, 0, 0, 3, {0x00000001, 0x00000000, 0x00000001}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, 1, 3, {0x00000001, 0x00000000, 0x00000001}},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_vector_array_bool_float[] =
+{
+    {"vabf",    {"vabf", D3DXRS_FLOAT4, 4, 2, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 2, 0, 24, NULL}, 49},
+    {"vabf[0]", {"vabf", D3DXRS_FLOAT4, 4, 1, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 49},
+    {"vabf[1]", {"vabf", D3DXRS_FLOAT4, 5, 1, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 53},
+};
+
+static const struct registerset_test registerset_test_vector_array_bool_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 2},
+    {SetIntArray, 1, 3, 5, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000}},
+    {SetBoolArray, 1, 0, 2},
+    {SetBoolArray, 1, 3, 5, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 2},
+    {SetFloatArray, 0, 3, 5, 4, {0x3f800000, 0x00000000, 0x3f800000}},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetValue, 1, 0, 11},
+    {SetValue, 1, 12, 23, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000}},
+    {SetVector, 0, 0, 0, 4, {0x3f800000, 0x00000000, 0x3f800000},},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, 1, 4, {0x3f800000, 0x00000000, 0x3f800000}},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+};
+
+static const struct registerset_constants registerset_constants_vector_array_int_float[] =
+{
+    {"vanf",    {"vanf", D3DXRS_FLOAT4, 2, 2, D3DXPC_VECTOR, D3DXPT_INT, 1, 3, 2, 0, 24, NULL}, 89},
+    {"vanf[0]", {"vanf", D3DXRS_FLOAT4, 2, 1, D3DXPC_VECTOR, D3DXPT_INT, 1, 3, 1, 0, 12, NULL}, 89},
+    {"vanf[1]", {"vanf", D3DXRS_FLOAT4, 3, 1, D3DXPC_VECTOR, D3DXPT_INT, 1, 3, 1, 0, 12, NULL}, 93},
+};
+
+static const struct registerset_test registerset_test_vector_array_int_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 2},
+    {SetIntArray, 1, 3, 5, 4, {0x40000000, 0x40400000, 0x40800000}},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x40400000, 0x40800000, 0x00000000, 0x40a00000, 0x00000000, 0x40e00000}},
+    {SetBoolArray, 1, 0, 2},
+    {SetBoolArray, 1, 3, 5, 4, {0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000}},
+    {SetFloatArray, 2, 0, 2,},
+    {SetFloatArray, 0, 3, 5, 4, {0x40000000, 0x00000000, 0x40800000}},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40a00000, 0x40c00000, 0x40e00000}},
+    {SetValue, 1, 0, 11},
+    {SetValue, 1, 12, 23, 4, {0x40000000, 0x40400000, 0x40800000}},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x40000000, 0x40400000, 0x40800000, 0x00000000, 0x40a00000, 0x00000000, 0x40e00000}},
+    {SetVector, 0, 0, 0, 4, {0x40000000, 0x00000000, 0x40800000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, 1, 4, {0x40000000, 0x00000000, 0x40800000}},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+bool3x2 cb = {1, 0, 1, 1, 0, 1};
+int3x2 cn = {4, 5, 6, 7, 8, 9};
+float3x2 cf = {15.1, 15.2, 15.3, 15.4, 15.5, 15.6};
+bool3x2 cbf = {1, 1, 0, 1, 0, 1};
+int3x2 cnf = {30, 31, 33, 32, 34, 36};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (cb._32) for (i = 0; i < cn._31; i++) tmp.x += pos.z * cf._31 * cbf._32;
+    else for (i = 0; i < cn._32; i++) tmp.y += pos.y * cf._32 * cnf._32;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_column[] =
+{
+0xfffe0300, 0x0066fffe, 0x42415443, 0x0000001c, 0x00000163, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x0000015c, 0x00000080, 0x00000000, 0x00000006, 0x00000084, 0x00000094, 0x000000ac,
+0x00020002, 0x00000002, 0x00000084, 0x000000b0, 0x000000d0, 0x00000002, 0x00000002, 0x000000d4,
+0x000000e4, 0x00000104, 0x00000001, 0x00000006, 0x00000108, 0x00000118, 0x00000138, 0x00040002,
+0x00000002, 0x00000108, 0x0000013c, 0xab006263, 0x00010003, 0x00020003, 0x00000001, 0x00000000,
+0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00666263, 0x3f800000,
+0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0xab006663,
+0x00030003, 0x00020003, 0x00000001, 0x00000000, 0x4171999a, 0x4174cccd, 0x41780000, 0x00000000,
+0x41733333, 0x41766666, 0x4179999a, 0x00000000, 0xab006e63, 0x00020003, 0x00020003, 0x00000001,
+0x00000000, 0x00000004, 0x00000006, 0x00000008, 0x00000000, 0x00000005, 0x00000007, 0x00000009,
+0x00000000, 0x00666e63, 0x41f00000, 0x42040000, 0x42080000, 0x00000000, 0x41f80000, 0x42000000,
+0x42100000, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+0x05000051, 0xa00f0006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0200001f, 0x80000000,
+0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x01000028, 0xe0e40805, 0x03000005, 0x80010000,
+0xa0aa0000, 0x90aa0000, 0x02000001, 0x80010001, 0xa0000006, 0x01000026, 0xf0e40004, 0x04000004,
+0x80010001, 0x80000000, 0xa0aa0003, 0x80000001, 0x00000027, 0x02000001, 0x80020001, 0xa0000006,
+0x0000002a, 0x03000005, 0x80010000, 0xa0aa0001, 0x90550000, 0x02000001, 0x80020001, 0xa0000006,
+0x01000026, 0xf0e40005, 0x04000004, 0x80020001, 0x80000000, 0xa0aa0005, 0x80550001, 0x00000027,
+0x02000001, 0x80010001, 0xa0000006, 0x0000002b, 0x02000001, 0xe0030000, 0x80e40001, 0x02000001,
+0xe00c0000, 0xa0000006, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_column_float[] =
+{
+    {"cf", {"cf", D3DXRS_FLOAT4, 0, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 3, 2, 1, 0, 24, NULL}, 57},
+};
+
+static const struct registerset_test registerset_test_column_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x40800000, 0x00000000, 0x00000000, 0x40400000, 0x40a00000, 0x40e00000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000123, 0x40800123, 0x40c00123, 0x00000000, 0x00000000, 0x40a00123, 0x40e00123}},
+    {SetValue, 0, 0, 23},
+    {SetValue, 0, 24, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x40000123, 0x40800123, 0x40c00123, 0x00000000, 0x00000000, 0x40a00123, 0x40e00123}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123}},
+};
+
+static const struct registerset_constants registerset_constants_column_int[] =
+{
+    {"cn", {"cn", D3DXRS_INT4, 0, 6, D3DXPC_MATRIX_COLUMNS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 70},
+};
+
+static const struct registerset_test registerset_test_column_int[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000000, 0x00000003, 0x00000005, 0x00000007}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000002, 0x00000004, 0x00000006, 0x00000000, 0x00000000, 0x00000005, 0x00000007}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000000, 0x00000003, 0x00000005, 0x00000007}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008}},
+};
+
+static const struct registerset_constants registerset_constants_column_bool[] =
+{
+    {"cb", {"cb", D3DXRS_BOOL, 0, 6, D3DXPC_MATRIX_COLUMNS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 37},
+};
+
+static const struct registerset_test registerset_test_column_bool[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x00000005, 0x00000007}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 6,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x00000005, 0x00000007}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_column_int_float[] =
+{
+    {"cnf", {"cnf", D3DXRS_FLOAT4, 4, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 79},
+};
+
+static const struct registerset_test registerset_test_column_int_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x40800000, 0x00000000, 0x00000000, 0x40400000, 0x40a00000, 0x40e00000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x40800000, 0x40c00000, 0x00000000, 0x00000000, 0x40a00000, 0x40e00000}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x40000000, 0x40800000, 0x00000000, 0x00000000, 0x40400000, 0x40a00000, 0x40e00000}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetValue, 0, 0, 23},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000}},
+};
+
+static const struct registerset_constants registerset_constants_column_bool_float[] =
+{
+    {"cbf", {"cbf", D3DXRS_FLOAT4, 2, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 44},
+};
+
+static const struct registerset_test registerset_test_column_bool_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+bool3x2 cab[2] = {1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1};
+int3x2 can[2] = {14, 15, 16, 71, 18, 19, 55, 63, 96, 96, 97, 13};
+float3x2 caf[2] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 1.2, 1.3, 1.4};
+bool3x2 cabf[2] = {1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1};
+int3x2 canf[2] = {300, 301, 303, 302, 304, 306, 350, 365, 654, 612, 326, 999};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (cab[1]._32) for (i = 0; i < can[1]._31; i++) tmp.x += pos.z * caf[1]._31 * cabf[1]._32;
+    else for (i = 0; i < can[1]._32; i++) tmp.y += pos.y * caf[1]._32 * canf[1]._32;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_column_array[] =
+{
+0xfffe0300, 0x0096fffe, 0x42415443, 0x0000001c, 0x00000223, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x0000021c, 0x00000080, 0x00000000, 0x0000000c, 0x00000084, 0x00000094, 0x000000c4,
+0x00040002, 0x00000004, 0x000000cc, 0x000000dc, 0x0000011c, 0x00000002, 0x00000004, 0x00000120,
+0x00000130, 0x00000170, 0x00000001, 0x0000000c, 0x00000174, 0x00000184, 0x000001c4, 0x00080002,
+0x00000004, 0x000001cc, 0x000001dc, 0x00626163, 0x00010003, 0x00020003, 0x00000002, 0x00000000,
+0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x66626163, 0xababab00, 0x00010003, 0x00020003,
+0x00000002, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000,
+0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000,
+0x3f800000, 0x00000000, 0x00666163, 0x00030003, 0x00020003, 0x00000002, 0x00000000, 0x3f8ccccd,
+0x40533333, 0x40b00000, 0x00000000, 0x400ccccd, 0x408ccccd, 0x40d33333, 0x00000000, 0x40f66666,
+0x411e6666, 0x3fa66666, 0x00000000, 0x410ccccd, 0x3f99999a, 0x3fb33333, 0x00000000, 0x006e6163,
+0x00020003, 0x00020003, 0x00000002, 0x00000000, 0x0000000e, 0x00000010, 0x00000012, 0x00000000,
+0x0000000f, 0x00000047, 0x00000013, 0x00000000, 0x00000037, 0x00000060, 0x00000061, 0x00000000,
+0x0000003f, 0x00000060, 0x0000000d, 0x00000000, 0x666e6163, 0xababab00, 0x00020003, 0x00020003,
+0x00000002, 0x00000000, 0x43960000, 0x43978000, 0x43980000, 0x00000000, 0x43968000, 0x43970000,
+0x43990000, 0x00000000, 0x43af0000, 0x44238000, 0x43a30000, 0x00000000, 0x43b68000, 0x44190000,
+0x4479c000, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+0x05000051, 0xa00f000c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0200001f, 0x80000000,
+0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x01000028, 0xe0e4080b, 0x03000005, 0x80010000,
+0xa0aa0002, 0x90aa0000, 0x02000001, 0x80010001, 0xa000000c, 0x01000026, 0xf0e4000a, 0x04000004,
+0x80010001, 0x80000000, 0xa0aa0007, 0x80000001, 0x00000027, 0x02000001, 0x80020001, 0xa000000c,
+0x0000002a, 0x03000005, 0x80010000, 0xa0aa0003, 0x90550000, 0x02000001, 0x80020001, 0xa000000c,
+0x01000026, 0xf0e4000b, 0x04000004, 0x80020001, 0x80000000, 0xa0aa000b, 0x80550001, 0x00000027,
+0x02000001, 0x80010001, 0xa000000c, 0x0000002b, 0x02000001, 0xe0030000, 0x80e40001, 0x02000001,
+0xe00c0000, 0xa000000c, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_column_array_float[] =
+{
+    {"caf",    {"caf", D3DXRS_FLOAT4, 0, 4, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 3, 2, 2, 0, 48, NULL}, 76},
+    {"caf[0]", {"caf", D3DXRS_FLOAT4, 0, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 3, 2, 1, 0, 24, NULL}, 76},
+    {"caf[1]", {"caf", D3DXRS_FLOAT4, 2, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 3, 2, 1, 0, 24, NULL}, 84},
+};
+
+static const struct registerset_test registerset_test_column_array_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, 11, 8,
+        {0x40000000, 0x40800000, 0x00000000, 0x00000000, 0x40400000, 0x40a00000, 0x40e00000}},
+    {SetIntArray, 1, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x40000000, 0x40800000, 0x00000000, 0x00000000, 0x40400000, 0x40a00000, 0x40e00000, 0x00000000,
+        0x41000000, 0x41200000, 0x41400000, 0x00000000, 0x41100000, 0x41300000, 0x41500000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, 11, 8,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetBoolArray, 1, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, 11, 8,
+        {0x40000123, 0x40800123, 0x40c00123, 0x00000000, 0x00000000, 0x40a00123, 0x40e00123}},
+    {SetFloatArray, 0, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x40000123, 0x40800123, 0x40c00123, 0x00000000, 0x00000000, 0x40a00123, 0x40e00123, 0x00000000,
+        0x41000123, 0x41200123, 0x41400123, 0x00000000, 0x41100123, 0x41300123, 0x41500123}},
+    {SetValue, 0, 0, 23},
+    {SetValue, 0, 24, 47, 8,
+        {0x40000123, 0x40800123, 0x40c00123, 0x00000000, 0x00000000, 0x40a00123, 0x40e00123}},
+    {SetValue, 0, 48, REGISTER_OUTPUT_SIZE * 4, 16,
+        {0x40000123, 0x40800123, 0x40c00123, 0x00000000, 0x00000000, 0x40a00123, 0x40e00123, 0x00000000,
+        0x41000123, 0x41200123, 0x41400123, 0x00000000, 0x41100123, 0x41300123, 0x41500123}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, 3, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+    {SetVectorArray, 0, 4, REGISTER_OUTPUT_SIZE / 4, 16,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123, 0x00000000,
+        0x41600123, 0x41a00123, 0x00000000, 0x00000000, 0x41700123, 0x41b00123, 0x41f00123}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+    {SetMatrixArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123, 0x00000000,
+        0x41a00123, 0x00000000, 0x00000000, 0x00000000, 0x41b00123, 0x41f00123, 0x42300123}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123}},
+    {SetMatrixTransposeArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123, 0x00000000,
+        0x41a00123, 0x41b00123, 0x41c00123, 0x00000000, 0x00000000, 0x41f00123, 0x42000123}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123}},
+    {SetMatrixPointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123, 0x00000000,
+        0x41900123, 0x41d00123, 0x42100123, 0x00000000, 0x41a00123, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 8,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123}},
+    {SetMatrixTransposePointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123, 0x00000000,
+        0x41900123, 0x41a00123, 0x41b00123, 0x00000000, 0x41d00123, 0x00000000, 0x41f00123}},
+};
+
+static const struct registerset_constants registerset_constants_column_array_int[] =
+{
+    {"can",    {"can", D3DXRS_INT4, 0, 12, D3DXPC_MATRIX_COLUMNS, D3DXPT_INT, 3, 2, 2, 0, 48, NULL},  97},
+    {"can[0]", {"can", D3DXRS_INT4, 0,  2, D3DXPC_MATRIX_COLUMNS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL},  97},
+    {"can[1]", {"can", D3DXRS_INT4, 2,  2, D3DXPC_MATRIX_COLUMNS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 105},
+};
+
+static const struct registerset_test registerset_test_column_array_int[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, 11, 8,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000000, 0x00000003, 0x00000005, 0x00000007}},
+    {SetIntArray, 1, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000000, 0x00000003, 0x00000005, 0x00000007, 0x00000000,
+        0x00000008, 0x0000000a, 0x0000000c, 0x00000000, 0x00000009, 0x0000000b, 0x0000000d}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, 11, 8,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetBoolArray, 1, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000,
+        0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, 11, 8,
+        {0x00000002, 0x00000004, 0x00000006, 0x00000000, 0x00000000, 0x00000005, 0x00000007}},
+    {SetFloatArray, 0, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x00000002, 0x00000004, 0x00000006, 0x00000000, 0x00000000, 0x00000005, 0x00000007, 0x00000000,
+        0x00000008, 0x0000000a, 0x0000000c, 0x00000000, 0x00000009, 0x0000000b, 0x0000000d}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, 47, 8,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000000, 0x00000003, 0x00000005, 0x00000007}},
+    {SetValue, 1, 48, REGISTER_OUTPUT_SIZE * 4, 16,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000000, 0x00000003, 0x00000005, 0x00000007, 0x00000000,
+        0x00000008, 0x0000000a, 0x0000000c, 0x00000000, 0x00000009, 0x0000000b, 0x0000000d}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, 3, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+    {SetVectorArray, 0, 4, REGISTER_OUTPUT_SIZE / 4, 16,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b, 0x00000000,
+        0x0000000e, 0x00000014, 0x00000000, 0x00000000, 0x0000000f, 0x00000016, 0x0000001e}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+    {SetMatrixArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b, 0x00000000,
+        0x00000014, 0x00000000, 0x00000000, 0x00000000, 0x00000016, 0x0000001e, 0x0000002c}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008}},
+    {SetMatrixTransposeArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008, 0x00000000,
+        0x00000014, 0x00000016, 0x00000018, 0x00000000, 0x00000000, 0x0000001e, 0x00000020}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 8,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b}},
+    {SetMatrixPointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x00000002, 0x00000006, 0x0000000a, 0x00000000, 0x00000000, 0x00000007, 0x0000000b, 0x00000000,
+        0x00000012, 0x0000001a, 0x00000024, 0x00000000, 0x00000014, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 8,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008}},
+    {SetMatrixTransposePointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000007, 0x00000008, 0x00000000,
+        0x00000012, 0x00000014, 0x00000016, 0x00000000, 0x0000001a, 0x00000000, 0x0000001e}},
+};
+
+static const struct registerset_constants registerset_constants_column_array_bool[] =
+{
+    {"cab",    {"cab", D3DXRS_BOOL, 0, 12, D3DXPC_MATRIX_COLUMNS, D3DXPT_BOOL, 3, 2, 2, 0, 48, NULL}, 37},
+    {"cab[0]", {"cab", D3DXRS_BOOL, 0,  6, D3DXPC_MATRIX_COLUMNS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 37},
+    {"cab[1]", {"cab", D3DXRS_BOOL, 6,  6, D3DXPC_MATRIX_COLUMNS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 43},
+};
+
+static const struct registerset_test registerset_test_column_array_bool[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, 11, 6,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetIntArray, 1, 12, REGISTER_OUTPUT_SIZE, 12,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, 11, 6,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x00000005, 0x00000007}},
+    {SetBoolArray, 1, 12, REGISTER_OUTPUT_SIZE, 12,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x00000005, 0x00000007, 0x00000008, 0x0000000a,
+        0x0000000c, 0x00000009, 0x0000000b, 0x0000000d}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, 11, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetFloatArray, 0, 12, REGISTER_OUTPUT_SIZE, 12,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, 47, 6,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x00000005, 0x00000007}},
+    {SetValue, 1, 48, REGISTER_OUTPUT_SIZE * 4, 12,
+        {0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x00000005, 0x00000007, 0x00000008, 0x0000000a,
+        0x0000000c, 0x00000009, 0x0000000b, 0x0000000d}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, 3, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetVectorArray, 0, 4, REGISTER_OUTPUT_SIZE / 4, 12,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000,
+        0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixPointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000001, 0x00000001, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposePointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000001, 0x00000001, 0x00000000, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_column_array_int_float[] =
+{
+    {"canf",    {"canf", D3DXRS_FLOAT4,  8, 4, D3DXPC_MATRIX_COLUMNS, D3DXPT_INT, 3, 2, 2, 0, 48, NULL}, 119},
+    {"canf[0]", {"canf", D3DXRS_FLOAT4,  8, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 119},
+    {"canf[1]", {"canf", D3DXRS_FLOAT4, 10, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 127},
+};
+
+static const struct registerset_test registerset_test_column_array_int_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, 11, 8,
+        {0x40000000, 0x40800000, 0x00000000, 0x00000000, 0x40400000, 0x40a00000, 0x40e00000}},
+    {SetIntArray, 1, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x40000000, 0x40800000, 0x00000000, 0x00000000, 0x40400000, 0x40a00000, 0x40e00000, 0x00000000,
+        0x41000000, 0x41200000, 0x41400000, 0x00000000, 0x41100000, 0x41300000, 0x41500000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, 11, 8,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetBoolArray, 1, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, 11, 8,
+        {0x40000000, 0x40800000, 0x40c00000, 0x00000000, 0x00000000, 0x40a00000, 0x40e00000}},
+    {SetFloatArray, 0, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x40000000, 0x40800000, 0x40c00000, 0x00000000, 0x00000000, 0x40a00000, 0x40e00000, 0x00000000,
+        0x41000000, 0x41200000, 0x41400000, 0x00000000, 0x41100000, 0x41300000, 0x41500000}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, 47, 8,
+        {0x40000000, 0x40800000, 0x00000000, 0x00000000, 0x40400000, 0x40a00000, 0x40e00000}},
+    {SetValue, 1, 48, REGISTER_OUTPUT_SIZE * 4, 16,
+        {0x40000000, 0x40800000, 0x00000000, 0x00000000, 0x40400000, 0x40a00000, 0x40e00000, 0x00000000,
+        0x41000000, 0x41200000, 0x41400000, 0x00000000, 0x41100000, 0x41300000, 0x41500000}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},/*16*/
+    {SetVectorArray, 0, 2, 3, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+    {SetVectorArray, 0, 4, REGISTER_OUTPUT_SIZE / 4, 16,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000, 0x00000000,
+        0x41600000, 0x41a00000, 0x00000000, 0x00000000, 0x41700000, 0x41b00000, 0x41f00000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+    {SetMatrixArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000, 0x00000000,
+        0x41a00000, 0x00000000, 0x00000000, 0x00000000, 0x41b00000, 0x41f00000, 0x42300000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000}},
+    {SetMatrixTransposeArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000, 0x00000000,
+        0x41a00000, 0x41b00000, 0x41c00000, 0x00000000, 0x00000000, 0x41f00000, 0x42000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 8,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000}},
+    {SetMatrixPointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x40000000, 0x40c00000, 0x41200000, 0x00000000, 0x00000000, 0x40e00000, 0x41300000, 0x00000000,
+        0x41900000, 0x41d00000, 0x42100000, 0x00000000, 0x41a00000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 8,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000}},
+    {SetMatrixTransposePointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x40000000, 0x00000000, 0x40800000, 0x00000000, 0x40c00000, 0x40e00000, 0x41000000, 0x00000000,
+        0x41900000, 0x41a00000, 0x41b00000, 0x00000000, 0x41d00000, 0x00000000, 0x41f00000}},
+};
+
+static const struct registerset_constants registerset_constants_column_array_bool_float[] =
+{
+    {"cabf",    {"cabf", D3DXRS_FLOAT4, 4, 4, D3DXPC_MATRIX_COLUMNS, D3DXPT_BOOL, 3, 2, 2, 0, 48, NULL}, 55},
+    {"cabf[0]", {"cabf", D3DXRS_FLOAT4, 4, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 55},
+    {"cabf[1]", {"cabf", D3DXRS_FLOAT4, 6, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 63},
+};
+
+static const struct registerset_test registerset_test_column_array_bool_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, 11, 8,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetIntArray, 1, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, 11, 8,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetBoolArray, 1, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, 11, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 12, REGISTER_OUTPUT_SIZE, 16,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, 47, 8,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetValue, 1, 48, REGISTER_OUTPUT_SIZE * 4, 16,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, 3, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetVectorArray, 0, 4, REGISTER_OUTPUT_SIZE / 4, 16,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrixArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTransposeArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 8,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrixPointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 8,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000}},
+    {SetMatrixTransposePointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+row_major bool3x2 rb = {1, 1, 0, 0, 1, 1};
+row_major int3x2 rn = {80, 81, 82, 83, 84, 85};
+row_major float3x2 rf = {95.1, 95.2, 95.3, 95.4, 95.5, 95.6};
+row_major bool3x2 rbf = {1, 1, 1, 1, 0, 1};
+row_major int3x2 rnf = {37, 13, 98, 54, 77, 36};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (rb._32) for (i = 0; i < rn._31; i++) tmp.x += pos.z * rf._31 * rbf._32;
+    else for (i = 0; i < rn._32; i++) tmp.y += pos.y * rf._32 * rnf._32;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_row[] =
+{
+0xfffe0300, 0x0076fffe, 0x42415443, 0x0000001c, 0x000001a3, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x0000019c, 0x00000080, 0x00000000, 0x00000006, 0x00000084, 0x00000094, 0x000000ac,
+0x00030002, 0x00000003, 0x00000084, 0x000000b0, 0x000000e0, 0x00000002, 0x00000003, 0x000000e4,
+0x000000f4, 0x00000124, 0x00000001, 0x00000006, 0x00000128, 0x00000138, 0x00000168, 0x00060002,
+0x00000003, 0x00000128, 0x0000016c, 0xab006272, 0x00010002, 0x00020003, 0x00000001, 0x00000000,
+0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00666272, 0x3f800000,
+0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000,
+0x3f800000, 0x00000000, 0x00000000, 0xab006672, 0x00030002, 0x00020003, 0x00000001, 0x00000000,
+0x42be3333, 0x42be6666, 0x00000000, 0x00000000, 0x42be999a, 0x42becccd, 0x00000000, 0x00000000,
+0x42bf0000, 0x42bf3333, 0x00000000, 0x00000000, 0xab006e72, 0x00020002, 0x00020003, 0x00000001,
+0x00000000, 0x00000050, 0x00000051, 0x00000001, 0x00000000, 0x00000052, 0x00000053, 0x00000001,
+0x00000000, 0x00000054, 0x00000055, 0x00000001, 0x00000000, 0x00666e72, 0x42140000, 0x41500000,
+0x00000000, 0x00000000, 0x42c40000, 0x42580000, 0x00000000, 0x00000000, 0x429a0000, 0x42100000,
+0x00000000, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+0x05000051, 0xa00f0009, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0200001f, 0x80000000,
+0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x01000028, 0xe0e40805, 0x03000005, 0x80010000,
+0xa0000002, 0x90aa0000, 0x02000001, 0x80010001, 0xa0000009, 0x01000026, 0xf0e40004, 0x04000004,
+0x80010001, 0x80000000, 0xa0550005, 0x80000001, 0x00000027, 0x02000001, 0x80020001, 0xa0000009,
+0x0000002a, 0x03000005, 0x80010000, 0xa0550002, 0x90550000, 0x02000001, 0x80020001, 0xa0000009,
+0x01000026, 0xf0e40005, 0x04000004, 0x80020001, 0x80000000, 0xa0550008, 0x80550001, 0x00000027,
+0x02000001, 0x80010001, 0xa0000009, 0x0000002b, 0x02000001, 0xe0030000, 0x80e40001, 0x02000001,
+0xe00c0000, 0xa0000009, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_row_float[] =
+{
+    {"rf", {"rf", D3DXRS_FLOAT4, 0, 3, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 2, 1, 0, 24, NULL}, 61},
+};
+
+static const struct registerset_test registerset_test_row_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x40000000, 0x40400000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x00000000, 0x40e00000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000, 0x00000000,
+        0x40c00123, 0x40e00123}},
+    {SetValue, 0, 0, 23},
+    {SetValue, 0, 24, REGISTER_OUTPUT_SIZE * 4, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000, 0x00000000,
+        0x40c00123, 0x40e00123}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 2},
+    {SetVectorArray, 0, 3, REGISTER_OUTPUT_SIZE / 4, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123}},
+    {SetMatrix, 0, 0, 0, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123}},
+    {SetMatrixTranspose, 0, 0, 0, 12,
+        {0x40000123, 0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x00000000, 0x00000000,
+        0x40800123, 0x41000123}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x40000123, 0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x00000000, 0x00000000,
+        0x40800123, 0x41000123}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x40000123, 0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x00000000, 0x00000000,
+        0x40800123, 0x41000123}},
+};
+
+static const struct registerset_constants registerset_constants_row_int[] =
+{
+    {"rn", {"rn", D3DXRS_INT4, 0, 6, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 78},
+};
+
+static const struct registerset_test registerset_test_row_int[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x00000002, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+        0x00000000, 0x00000007, 0x00000001}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000,
+        0x00000000, 0x00000001, 0x00000001}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+        0x00000006, 0x00000007, 0x00000001}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 12,
+        {0x00000002, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+        0x00000000, 0x00000007, 0x00000001}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 2},
+    {SetVectorArray, 0, 3, REGISTER_OUTPUT_SIZE / 4, 12,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 12,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 12,
+        {0x00000002, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000007, 0x00000001, 0x00000000,
+        0x00000004, 0x00000008, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000002, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000007, 0x00000001, 0x00000000,
+        0x00000004, 0x00000008, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000002, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000007, 0x00000001, 0x00000000,
+        0x00000004, 0x00000008, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_row_bool[] =
+{
+    {"rb", {"rb", D3DXRS_BOOL, 0, 6, D3DXPC_MATRIX_ROWS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 37},
+};
+
+static const struct registerset_test registerset_test_row_bool[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 0, 0, 5,},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001}},
+    {SetBoolArray, 0, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000000, 0x00000007}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetValue, 0, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 6,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000000, 0x00000007}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 2},
+    {SetVectorArray, 0, 3, REGISTER_OUTPUT_SIZE / 4, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001},},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 6,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_row_int_float[] =
+{
+    {"rnf", {"rnf", D3DXRS_FLOAT4, 6, 3, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 91},
+};
+
+static const struct registerset_test registerset_test_row_int_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x40000000, 0x40400000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x00000000, 0x40e00000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x40c00000, 0x40e00000}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 12,
+        {0x40000000, 0x40400000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x00000000, 0x40e00000}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 2},
+    {SetVectorArray, 0, 3, REGISTER_OUTPUT_SIZE / 4, 12,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000}},
+    {SetMatrix, 0, 0, 0, 12,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000}},
+    {SetMatrixTranspose, 0, 0, 0, 12,
+        {0x40000000, 0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x00000000, 0x00000000,
+        0x40800000, 0x41000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x40000000, 0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x00000000, 0x00000000,
+        0x40800000, 0x41000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x40000000, 0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x00000000, 0x00000000,
+        0x40800000, 0x41000000}},
+};
+
+static const struct registerset_constants registerset_constants_row_bool_float[] =
+{
+    {"rbf", {"rbf", D3DXRS_FLOAT4, 3, 3, D3DXPC_MATRIX_ROWS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 44},
+};
+
+static const struct registerset_test registerset_test_row_bool_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 12,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 2},
+    {SetVectorArray, 0, 3, REGISTER_OUTPUT_SIZE / 4, 12,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrix, 0, 0, 0, 12,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixTranspose, 0, 0, 0, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+row_major bool3x2 rab[2] = {1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1};
+row_major int3x2 ran[2] = {4, 5, 6, 1, 8, 1, 5, 3, 9, 6, 7, 3};
+row_major float3x2 raf[2] = {1.5, 2.8, 3.3, 4.9, 5.9, 6.8, 7.9, 8.5, 9.4, 1.3, 1.2, 1.1};
+row_major bool3x2 rabf[2] = {1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1};
+row_major int3x2 ranf[2] = {35, 40, 60, 80, 70, 56, 37, 13, 98, 54, 77, 36};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (rab[1]._32) for (i = 0; i < ran[1]._31; i++) tmp.x += pos.z * raf[1]._31 * rabf[1]._32;
+    else for (i = 0; i < ran[1]._32; i++) tmp.y += pos.y * raf[1]._32 * ranf[1]._32;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_row_array[] =
+{
+0xfffe0300, 0x00b6fffe, 0x42415443, 0x0000001c, 0x000002a3, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x0000029c, 0x00000080, 0x00000000, 0x0000000c, 0x00000084, 0x00000094, 0x000000c4,
+0x00060002, 0x00000006, 0x000000cc, 0x000000dc, 0x0000013c, 0x00000002, 0x00000006, 0x00000140,
+0x00000150, 0x000001b0, 0x00000001, 0x0000000c, 0x000001b4, 0x000001c4, 0x00000224, 0x000c0002,
+0x00000006, 0x0000022c, 0x0000023c, 0x00626172, 0x00010002, 0x00020003, 0x00000002, 0x00000000,
+0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0x00000000,
+0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x66626172, 0xababab00, 0x00010002, 0x00020003,
+0x00000002, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000,
+0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000,
+0x00000000, 0x00000000, 0x00666172, 0x00030002, 0x00020003, 0x00000002, 0x00000000, 0x3fc00000,
+0x40333333, 0x00000000, 0x00000000, 0x40533333, 0x409ccccd, 0x00000000, 0x00000000, 0x40bccccd,
+0x40d9999a, 0x00000000, 0x00000000, 0x40fccccd, 0x41080000, 0x00000000, 0x00000000, 0x41166666,
+0x3fa66666, 0x00000000, 0x00000000, 0x3f99999a, 0x3f8ccccd, 0x00000000, 0x00000000, 0x006e6172,
+0x00020002, 0x00020003, 0x00000002, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+0x00000006, 0x00000001, 0x00000001, 0x00000000, 0x00000008, 0x00000001, 0x00000001, 0x00000000,
+0x00000005, 0x00000003, 0x00000001, 0x00000000, 0x00000009, 0x00000006, 0x00000001, 0x00000000,
+0x00000007, 0x00000003, 0x00000001, 0x00000000, 0x666e6172, 0xababab00, 0x00020002, 0x00020003,
+0x00000002, 0x00000000, 0x420c0000, 0x42200000, 0x00000000, 0x00000000, 0x42700000, 0x42a00000,
+0x00000000, 0x00000000, 0x428c0000, 0x42600000, 0x00000000, 0x00000000, 0x42140000, 0x41500000,
+0x00000000, 0x00000000, 0x42c40000, 0x42580000, 0x00000000, 0x00000000, 0x429a0000, 0x42100000,
+0x00000000, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+0x05000051, 0xa00f0012, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0200001f, 0x80000000,
+0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x01000028, 0xe0e4080b, 0x03000005, 0x80010000,
+0xa0000005, 0x90aa0000, 0x02000001, 0x80010001, 0xa0000012, 0x01000026, 0xf0e4000a, 0x04000004,
+0x80010001, 0x80000000, 0xa055000b, 0x80000001, 0x00000027, 0x02000001, 0x80020001, 0xa0000012,
+0x0000002a, 0x03000005, 0x80010000, 0xa0550005, 0x90550000, 0x02000001, 0x80020001, 0xa0000012,
+0x01000026, 0xf0e4000b, 0x04000004, 0x80020001, 0x80000000, 0xa0550011, 0x80550001, 0x00000027,
+0x02000001, 0x80010001, 0xa0000012, 0x0000002b, 0x02000001, 0xe0030000, 0x80e40001, 0x02000001,
+0xe00c0000, 0xa0000012, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_row_array_float[] =
+{
+    {"raf",    {"raf", D3DXRS_FLOAT4, 0, 6, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 2, 2, 0, 48, NULL}, 84},
+    {"raf[0]", {"raf", D3DXRS_FLOAT4, 0, 3, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 2, 1, 0, 24, NULL}, 84},
+    {"raf[1]", {"raf", D3DXRS_FLOAT4, 3, 3, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 3, 2, 1, 0, 24, NULL}, 96},
+};
+
+static const struct registerset_test registerset_test_row_array_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, 11, 12,
+        {0x40000000, 0x40400000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x00000000, 0x40e00000}},
+    {SetIntArray, 1, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x40000000, 0x40400000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x00000000, 0x40e00000, 0x00000000, 0x00000000, 0x41000000, 0x41100000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000, 0x00000000, 0x00000000, 0x41400000, 0x41500000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, 11, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000}},
+    {SetBoolArray, 1, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, 11, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000, 0x00000000,
+        0x40c00123, 0x40e00123}},
+    {SetFloatArray, 0, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000, 0x00000000,
+        0x40c00123, 0x40e00123, 0x00000000, 0x00000000, 0x41000123, 0x41100123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123, 0x00000000, 0x00000000, 0x41400123, 0x41500123}},
+    {SetValue, 0, 0, 23},
+    {SetValue, 0, 24, 47, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000, 0x00000000,
+        0x40c00123, 0x40e00123}},
+    {SetValue, 0, 48, REGISTER_OUTPUT_SIZE * 4, 24,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000, 0x00000000,
+        0x40c00123, 0x40e00123, 0x00000000, 0x00000000, 0x41000123, 0x41100123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123, 0x00000000, 0x00000000, 0x41400123, 0x41500123}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 2},
+    {SetVectorArray, 0, 3, 5, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123}},
+    {SetVectorArray, 0, 6, REGISTER_OUTPUT_SIZE / 4, 24,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123, 0x00000000, 0x00000000, 0x41600123, 0x41700123, 0x00000000, 0x00000000,
+        0x41a00123, 0x41b00123, 0x00000000, 0x00000000, 0x00000000, 0x41f00123}},
+    {SetMatrix, 0, 0, 0, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123}},
+    {SetMatrixArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123, 0x00000000, 0x00000000, 0x41a00123, 0x41b00123, 0x00000000, 0x00000000,
+        0x00000000, 0x41f00123, 0x00000000, 0x00000000, 0x00000000, 0x42300123}},
+    {SetMatrixTranspose, 0, 0, 0, 12,
+        {0x40000123, 0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x00000000, 0x00000000,
+        0x40800123, 0x41000123}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 12,
+        {0x40000123, 0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x00000000, 0x00000000,
+        0x40800123, 0x41000123}},
+    {SetMatrixTransposeArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x40000123, 0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x00000000, 0x00000000,
+        0x40800123, 0x41000123, 0x00000000, 0x00000000, 0x41a00123, 0x00000000, 0x00000000, 0x00000000,
+        0x41b00123, 0x41f00123, 0x00000000, 0x00000000, 0x41c00123, 0x42000123}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 12,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123}},
+    {SetMatrixPointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x40c00123, 0x40e00123, 0x00000000, 0x00000000,
+        0x41200123, 0x41300123, 0x00000000, 0x00000000, 0x41900123, 0x41a00123, 0x00000000, 0x00000000,
+        0x41d00123, 0x00000000, 0x00000000, 0x00000000, 0x42100123, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 12,
+        {0x40000123, 0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x00000000, 0x00000000,
+        0x40800123, 0x41000123}},
+    {SetMatrixTransposePointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x40000123, 0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x00000000, 0x00000000,
+        0x40800123, 0x41000123, 0x00000000, 0x00000000, 0x41900123, 0x41d00123, 0x00000000, 0x00000000,
+        0x41a00123, 0x00000000, 0x00000000, 0x00000000, 0x41b00123, 0x41f00123}},
+};
+
+static const struct registerset_constants registerset_constants_row_array_int[] =
+{
+    {"ran",    {"ran", D3DXRS_INT4, 0, 12, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 2, 2, 0, 48, NULL}, 113},
+    {"ran[0]", {"ran", D3DXRS_INT4, 0,  3, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 113},
+    {"ran[1]", {"ran", D3DXRS_INT4, 3,  3, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 125},
+};
+
+static const struct registerset_test registerset_test_row_array_int[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, 11, 12,
+        {0x00000002, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+        0x00000000, 0x00000007, 0x00000001}},
+    {SetIntArray, 1, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x00000002, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+        0x00000000, 0x00000007, 0x00000001, 0x00000000, 0x00000008, 0x00000009, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001, 0x00000000, 0x0000000c, 0x0000000d, 0x00000001}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, 11, 12,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000,
+        0x00000000, 0x00000001, 0x00000001}},
+    {SetBoolArray, 1, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000,
+        0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000,
+        0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, 11, 12,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+        0x00000006, 0x00000007, 0x00000001}},
+    {SetFloatArray, 0, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+        0x00000006, 0x00000007, 0x00000001, 0x00000000, 0x00000008, 0x00000009, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001, 0x00000000, 0x0000000c, 0x0000000d, 0x00000001}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, 47, 12,
+        {0x00000002, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+        0x00000000, 0x00000007, 0x00000001}},
+    {SetValue, 1, 48, REGISTER_OUTPUT_SIZE * 4, 24,
+        {0x00000002, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+        0x00000000, 0x00000007, 0x00000001, 0x00000000, 0x00000008, 0x00000009, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001, 0x00000000, 0x0000000c, 0x0000000d, 0x00000001}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 2},
+    {SetVectorArray, 0, 3, 5, 12,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001}},
+    {SetVectorArray, 0, 6, REGISTER_OUTPUT_SIZE / 4, 24,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001, 0x00000000, 0x0000000e, 0x0000000f, 0x00000001, 0x00000000,
+        0x00000014, 0x00000016, 0x00000001, 0x00000000, 0x00000000, 0x0000001e, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 12,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 12,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001}},
+    {SetMatrixArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001, 0x00000000, 0x00000014, 0x00000016, 0x00000001, 0x00000000,
+        0x00000000, 0x0000001e, 0x00000001, 0x00000000, 0x00000000, 0x0000002c, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 12,
+        {0x00000002, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000007, 0x00000001, 0x00000000,
+        0x00000004, 0x00000008, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 12,
+        {0x00000002, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000007, 0x00000001, 0x00000000,
+        0x00000004, 0x00000008, 0x00000001}},
+    {SetMatrixTransposeArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x00000002, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000007, 0x00000001, 0x00000000,
+        0x00000004, 0x00000008, 0x00000001, 0x00000000, 0x00000014, 0x00000000, 0x00000001, 0x00000000,
+        0x00000016, 0x0000001e, 0x00000001, 0x00000000, 0x00000018, 0x00000020, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 12,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001}},
+    {SetMatrixPointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000006, 0x00000007, 0x00000001, 0x00000000,
+        0x0000000a, 0x0000000b, 0x00000001, 0x00000000, 0x00000012, 0x00000014, 0x00000001, 0x00000000,
+        0x0000001a, 0x00000000, 0x00000001, 0x00000000, 0x00000024, 0x00000000, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 12,
+        {0x00000002, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000007, 0x00000001, 0x00000000,
+        0x00000004, 0x00000008, 0x00000001}},
+    {SetMatrixTransposePointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x00000002, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000007, 0x00000001, 0x00000000,
+        0x00000004, 0x00000008, 0x00000001, 0x00000000, 0x00000012, 0x0000001a, 0x00000001, 0x00000000,
+        0x00000014, 0x00000000, 0x00000001, 0x00000000, 0x00000016, 0x0000001e, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_row_array_bool[] =
+{
+    {"rab",    {"rab", D3DXRS_BOOL, 0, 12, D3DXPC_MATRIX_ROWS, D3DXPT_BOOL, 3, 2, 2, 0, 48, NULL}, 37},
+    {"rab[0]", {"rab", D3DXRS_BOOL, 0,  6, D3DXPC_MATRIX_ROWS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 37},
+    {"rab[1]", {"rab", D3DXRS_BOOL, 6,  6, D3DXPC_MATRIX_ROWS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 43},
+};
+
+static const struct registerset_test registerset_test_row_array_bool[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5,},
+    {SetIntArray, 1, 6, 11, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001}},
+    {SetIntArray, 1, 12, REGISTER_OUTPUT_SIZE, 12,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001,
+        0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, 11, 6,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000000, 0x00000007}},
+    {SetBoolArray, 1, 12, REGISTER_OUTPUT_SIZE, 12,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000000, 0x00000007, 0x00000008, 0x00000009,
+        0x0000000a, 0x0000000b, 0x0000000c, 0x0000000d}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, 11, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetFloatArray, 0, 12, REGISTER_OUTPUT_SIZE, 12,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, 47, 6,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000000, 0x00000007}},
+    {SetValue, 1, 48, REGISTER_OUTPUT_SIZE * 4, 12,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000000, 0x00000007, 0x00000008, 0x00000009,
+        0x0000000a, 0x0000000b, 0x0000000c, 0x0000000d}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 2},
+    {SetVectorArray, 0, 3, 5, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetVectorArray, 0, 6, REGISTER_OUTPUT_SIZE / 4, 12,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000001, 0x00000001, 0x00000000, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000000, 0x00000001, 0x00000000, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 6,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 6,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000,
+        0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixPointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000001, 0x00000000, 0x00000001, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 6,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposePointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 12,
+        {0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+        0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_row_array_int_float[] =
+{
+    {"ranf",    {"ranf", D3DXRS_FLOAT4, 12, 6, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 2, 2, 0, 48, NULL}, 143},
+    {"ranf[0]", {"ranf", D3DXRS_FLOAT4, 12, 3, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 143},
+    {"ranf[1]", {"ranf", D3DXRS_FLOAT4, 15, 3, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3, 2, 1, 0, 24, NULL}, 155},
+};
+
+static const struct registerset_test registerset_test_row_array_int_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, 11, 12,
+        {0x40000000, 0x40400000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x00000000, 0x40e00000,}},
+    {SetIntArray, 1, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x40000000, 0x40400000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x00000000, 0x40e00000, 0x00000000, 0x00000000, 0x41000000, 0x41100000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000, 0x00000000, 0x00000000, 0x41400000, 0x41500000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, 11, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000}},
+    {SetBoolArray, 1, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, 11, 12,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x40c00000, 0x40e00000}},
+    {SetFloatArray, 0, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x40c00000, 0x40e00000, 0x00000000, 0x00000000, 0x41000000, 0x41100000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000, 0x00000000, 0x00000000, 0x41400000, 0x41500000}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, 47, 12,
+        {0x40000000, 0x40400000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x00000000, 0x40e00000}},
+    {SetValue, 1, 48, REGISTER_OUTPUT_SIZE * 4, 24,
+        {0x40000000, 0x40400000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000, 0x00000000,
+        0x00000000, 0x40e00000, 0x00000000, 0x00000000, 0x41000000, 0x41100000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000, 0x00000000, 0x00000000, 0x41400000, 0x41500000}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 2},
+    {SetVectorArray, 0, 3, 5, 12,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000}},
+    {SetVectorArray, 0, 6, REGISTER_OUTPUT_SIZE / 4, 24,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000, 0x00000000, 0x00000000, 0x41600000, 0x41700000, 0x00000000, 0x00000000,
+        0x41a00000, 0x41b00000, 0x00000000, 0x00000000, 0x00000000, 0x41f00000}},
+    {SetMatrix, 0, 0, 0, 12,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 12,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000}},
+    {SetMatrixArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000, 0x00000000, 0x00000000, 0x41a00000, 0x41b00000, 0x00000000, 0x00000000,
+        0x00000000, 0x41f00000, 0x00000000, 0x00000000, 0x00000000, 0x42300000}},
+    {SetMatrixTranspose, 0, 0, 0, 12,
+        {0x40000000, 0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x00000000, 0x00000000,
+        0x40800000, 0x41000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 12,
+        {0x40000000, 0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x00000000, 0x00000000,
+        0x40800000, 0x41000000}},
+    {SetMatrixTransposeArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x40000000, 0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x00000000, 0x00000000,
+        0x40800000, 0x41000000, 0x00000000, 0x00000000, 0x41a00000, 0x00000000, 0x00000000, 0x00000000,
+        0x41b00000, 0x41f00000, 0x00000000, 0x00000000, 0x41c00000, 0x42000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 12,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000}},
+    {SetMatrixPointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40c00000, 0x40e00000, 0x00000000, 0x00000000,
+        0x41200000, 0x41300000, 0x00000000, 0x00000000, 0x41900000, 0x41a00000, 0x00000000, 0x00000000,
+        0x41d00000, 0x00000000, 0x00000000, 0x00000000, 0x42100000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 12,
+        {0x40000000, 0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x00000000, 0x00000000,
+        0x40800000, 0x41000000}},
+    {SetMatrixTransposePointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x40000000, 0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x00000000, 0x00000000,
+        0x40800000, 0x41000000, 0x00000000, 0x00000000, 0x41900000, 0x41d00000, 0x00000000, 0x00000000,
+        0x41a00000, 0x00000000, 0x00000000, 0x00000000, 0x41b00000, 0x41f00000}},
+};
+
+static const struct registerset_constants registerset_constants_row_array_bool_float[] =
+{
+    {"rabf",    {"rabf", D3DXRS_FLOAT4, 6, 6, D3DXPC_MATRIX_ROWS, D3DXPT_BOOL, 3, 2, 2, 0, 48, NULL}, 55},
+    {"rabf[0]", {"rabf", D3DXRS_FLOAT4, 6, 3, D3DXPC_MATRIX_ROWS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 55},
+    {"rabf[1]", {"rabf", D3DXRS_FLOAT4, 9, 3, D3DXPC_MATRIX_ROWS, D3DXPT_BOOL, 3, 2, 1, 0, 24, NULL}, 67},
+};
+
+static const struct registerset_test registerset_test_row_array_bool_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, 11, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000}},
+    {SetIntArray, 1, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, 11, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000}},
+    {SetBoolArray, 1, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, 11, 12,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetFloatArray, 0, 12, REGISTER_OUTPUT_SIZE, 24,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, 47, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000}},
+    {SetValue, 1, 48, REGISTER_OUTPUT_SIZE * 4, 24,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 2},
+    {SetVectorArray, 0, 3, 5, 12,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetVectorArray, 0, 6, REGISTER_OUTPUT_SIZE / 4, 24,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetMatrix, 0, 0, 0, 12,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 12,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetMatrixTranspose, 0, 0, 0, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixTransposeArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 12,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixPointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 12,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000}},
+    {SetMatrixTransposePointerArray, 0, 2, REGISTER_OUTPUT_SIZE / 16, 24,
+        {0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+struct {bool b; bool3 vb;} sb = {1, 1, 0, 1};
+struct {int n; int3 vn;} sn = {11, 12, 13, 14};
+struct {float f; float3 vf;} sf = {1.1f, 2.2f, 3.3f, 4.4f};
+struct {int nf; int3 vnf;} snf = {31, 32, 33, 34};
+struct {bool bf; bool3 vbf;} sbf = {1, 0, 0, 1};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (sb.vb.z) for (i = 0; i < sn.n; i++) tmp.x += pos.z * sf.vf.x * snf.vnf.z;
+    else for (i = 0; i < sn.vn.z; i++) tmp.y += pos.y * sf.vf.z * sbf.vbf.y;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_struct[] =
+{
+0xfffe0300, 0x00a2fffe, 0x42415443, 0x0000001c, 0x00000253, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x0000024c, 0x00000080, 0x00000000, 0x00000004, 0x000000bc, 0x000000cc, 0x000000dc,
+0x00040002, 0x00000002, 0x000000f8, 0x00000108, 0x00000128, 0x00000002, 0x00000002, 0x00000164,
+0x00000174, 0x00000194, 0x00000001, 0x00000004, 0x000001d0, 0x000001e0, 0x00000200, 0x00020002,
+0x00000002, 0x0000021c, 0x0000022c, 0x62006273, 0xababab00, 0x00010000, 0x00010001, 0x00000001,
+0x00000000, 0xab006276, 0x00010001, 0x00030001, 0x00000001, 0x00000000, 0x00000083, 0x00000088,
+0x00000098, 0x0000009c, 0x00000005, 0x00040001, 0x00020001, 0x000000ac, 0xffffffff, 0xffffffff,
+0x00000000, 0xffffffff, 0x00666273, 0x76006662, 0xab006662, 0x000000e0, 0x00000088, 0x000000e3,
+0x0000009c, 0x00000005, 0x00040001, 0x00020001, 0x000000e8, 0x3f800000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x66006673, 0xababab00, 0x00030000,
+0x00010001, 0x00000001, 0x00000000, 0xab006676, 0x00030001, 0x00030001, 0x00000001, 0x00000000,
+0x0000012b, 0x00000130, 0x00000140, 0x00000144, 0x00000005, 0x00040001, 0x00020001, 0x00000154,
+0x3f8ccccd, 0x00000000, 0x00000000, 0x00000000, 0x400ccccd, 0x40533333, 0x408ccccd, 0x00000000,
+0x6e006e73, 0xababab00, 0x00020000, 0x00010001, 0x00000001, 0x00000000, 0xab006e76, 0x00020001,
+0x00030001, 0x00000001, 0x00000000, 0x00000197, 0x0000019c, 0x000001ac, 0x000001b0, 0x00000005,
+0x00040001, 0x00020001, 0x000001c0, 0x0000000b, 0x00000000, 0x00000001, 0x00000000, 0x0000000c,
+0x0000000d, 0x0000000e, 0x00000000, 0x00666e73, 0x7600666e, 0xab00666e, 0x00000204, 0x0000019c,
+0x00000207, 0x000001b0, 0x00000005, 0x00040001, 0x00020001, 0x0000020c, 0x41f80000, 0x00000000,
+0x00000000, 0x00000000, 0x42000000, 0x42040000, 0x42080000, 0x00000000, 0x335f7376, 0x4d00305f,
+0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970,
+0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x05000051, 0xa00f0006, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x0200001f, 0x80000000, 0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000,
+0x01000028, 0xe0e40803, 0x03000005, 0x80010000, 0xa0000001, 0x90aa0000, 0x02000001, 0x80010001,
+0xa0000006, 0x01000026, 0xf0e40000, 0x04000004, 0x80010001, 0x80000000, 0xa0aa0003, 0x80000001,
+0x00000027, 0x02000001, 0x80020001, 0xa0000006, 0x0000002a, 0x03000005, 0x80010000, 0xa0aa0001,
+0x90550000, 0x02000001, 0x80020001, 0xa0000006, 0x01000026, 0xf0e40003, 0x04000004, 0x80020001,
+0x80000000, 0xa0550005, 0x80550001, 0x00000027, 0x02000001, 0x80010001, 0xa0000006, 0x0000002b,
+0x02000001, 0xe0030000, 0x80e40001, 0x02000001, 0xe00c0000, 0xa0000006, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_struct_float[] =
+{
+    {"sf",    {"sf", D3DXRS_FLOAT4, 0, 2, D3DXPC_STRUCT, D3DXPT_VOID,  1, 4, 1, 2, 16, NULL}, 93},
+    {"sf.f",  {"f",  D3DXRS_FLOAT4, 0, 1, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 1, 0,  4, NULL}, 93},
+    {"sf.vf", {"vf", D3DXRS_FLOAT4, 1, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3, 1, 0, 12, NULL}, 97},
+};
+
+static const struct registerset_test registerset_test_struct_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 3},
+    {SetIntArray, 1, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetBoolArray, 1, 0, 3},
+    {SetBoolArray, 1, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetFloatArray, 0, 0, 3},
+    {SetFloatArray, 0, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000}},
+    {SetValue, 0, 0, 15},
+    {SetValue, 0, 16, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+};
+
+static const struct registerset_constants registerset_constants_struct_int[] =
+{
+    {"sn",    {"sn", D3DXRS_INT4, 0, 4, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 120},
+    {"sn.n",  {"n",  D3DXRS_INT4, 0, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 120},
+    {"sn.vn", {"vn", D3DXRS_INT4, 1, 1, D3DXPC_VECTOR, D3DXPT_INT,  1, 3, 1, 0, 12, NULL}, 124},
+};
+
+static const struct registerset_test registerset_test_struct_int[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 3},
+    {SetIntArray, 1, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x00000004, 0x00000005, 0x00000000}},
+    {SetBoolArray, 1, 0, 3},
+    {SetBoolArray, 1, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000}},
+    {SetFloatArray, 0, 0, 3},
+    {SetFloatArray, 0, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0x00000005, 0x00000000}},
+    {SetValue, 1, 0, 15},
+    {SetValue, 1, 16, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x00000004, 0x00000005, 0x00000000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0x00000005, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0x00000005, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0x00000005, 0x00000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0x00000005, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+};
+
+static const struct registerset_constants registerset_constants_struct_bool[] =
+{
+    {"sb",    {"sb", D3DXRS_BOOL, 0, 4, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 51},
+    {"sb.b",  {"b",  D3DXRS_BOOL, 0, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL}, 51},
+    {"sb.vb", {"vb", D3DXRS_BOOL, 1, 3, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 52},
+};
+
+static const struct registerset_test registerset_test_struct_bool[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 3},
+    {SetIntArray, 1, 4, REGISTER_OUTPUT_SIZE, 4,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetBoolArray, 1, 0, 3},
+    {SetBoolArray, 1, 4, REGISTER_OUTPUT_SIZE, 4,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005}},
+    {SetFloatArray, 0, 0, 3},
+    {SetFloatArray, 0, 4, REGISTER_OUTPUT_SIZE, 4,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetValue, 1, 0, 15},
+    {SetValue, 1, 16, REGISTER_OUTPUT_SIZE * 4, 4,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005}},
+    {SetVector, 0, 0, 0, 4,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 4,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 4,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 4,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_struct_int_float[] =
+{
+    {"snf",     {"snf", D3DXRS_FLOAT4, 2, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 139},
+    {"snf.nf",  {"nf",  D3DXRS_FLOAT4, 2, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 139},
+    {"snf.vnf", {"vnf", D3DXRS_FLOAT4, 3, 1, D3DXPC_VECTOR, D3DXPT_INT,  1, 3, 1, 0, 12, NULL}, 143},
+};
+
+static const struct registerset_test registerset_test_struct_int_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 3},
+    {SetIntArray, 1, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetBoolArray, 1, 0, 3},
+    {SetBoolArray, 1, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetFloatArray, 0, 0, 3},
+    {SetFloatArray, 0, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetValue, 1, 0, 15},
+    {SetValue, 1, 16, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+};
+
+static const struct registerset_constants registerset_constants_struct_bool_float[] =
+{
+    {"sbf",     {"sbf", D3DXRS_FLOAT4, 4, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 66},
+    {"sbf.bf",  {"bf",  D3DXRS_FLOAT4, 4, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL}, 66},
+    {"sbf.vbf", {"vbf", D3DXRS_FLOAT4, 5, 1, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 70},
+};
+
+static const struct registerset_test registerset_test_struct_bool_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 3},
+    {SetIntArray, 1, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetBoolArray, 1, 0, 3},
+    {SetBoolArray, 1, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetFloatArray, 0, 0, 3},
+    {SetFloatArray, 0, 4, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetValue, 1, 0, 15},
+    {SetValue, 1, 16, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+struct {bool b; bool3 vb;} sab[2] = {1, 1, 0, 1, 0, 1, 0, 1};
+struct {int n; int3 vn;} san[2] = {21, 22, 23, 24, 25, 26, 27, 28};
+struct {float f; float3 vf;} saf[2] = {1.1f, 2.1f, 3.1f, 4.1f, 5.1f, 6.1f, 7.1f, 8.1f};
+struct {int nf; int3 vnf;} sanf[2] = {41, 0, 43, 44, 41, 42, 43, 44};
+struct {bool bf; bool3 vbf;} sabf[2] = {1, 0, 0, 1, 1, 1, 0, 1};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (sab[1].vb.z) for (i = 0; i < san[1].n; i++) tmp.x += pos.z * saf[1].vf.x * sanf[1].vnf.z;
+    else for (i = 0; i < san[1].vn.z; i++) tmp.y += pos.y * saf[1].vf.z * sabf[1].vbf.y;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_struct_array[] =
+{
+0xfffe0300, 0x00c6fffe, 0x42415443, 0x0000001c, 0x000002e3, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x000002dc, 0x00000080, 0x00000000, 0x00000008, 0x000000bc, 0x000000cc, 0x000000ec,
+0x00080002, 0x00000004, 0x00000108, 0x00000118, 0x00000158, 0x00000002, 0x00000004, 0x00000194,
+0x000001a4, 0x000001e4, 0x00000001, 0x00000008, 0x00000220, 0x00000230, 0x00000270, 0x00040002,
+0x00000004, 0x0000028c, 0x0000029c, 0x00626173, 0xabab0062, 0x00010000, 0x00010001, 0x00000001,
+0x00000000, 0xab006276, 0x00010001, 0x00030001, 0x00000001, 0x00000000, 0x00000084, 0x00000088,
+0x00000098, 0x0000009c, 0x00000005, 0x00040001, 0x00020002, 0x000000ac, 0xffffffff, 0xffffffff,
+0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x66626173, 0x00666200,
+0x00666276, 0x000000f1, 0x00000088, 0x000000f4, 0x0000009c, 0x00000005, 0x00040001, 0x00020002,
+0x000000f8, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000,
+0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000,
+0x00000000, 0x00666173, 0xabab0066, 0x00030000, 0x00010001, 0x00000001, 0x00000000, 0xab006676,
+0x00030001, 0x00030001, 0x00000001, 0x00000000, 0x0000015c, 0x00000160, 0x00000170, 0x00000174,
+0x00000005, 0x00040001, 0x00020002, 0x00000184, 0x3f8ccccd, 0x00000000, 0x00000000, 0x00000000,
+0x40066666, 0x40466666, 0x40833333, 0x00000000, 0x40a33333, 0x00000000, 0x00000000, 0x00000000,
+0x40c33333, 0x40e33333, 0x4101999a, 0x00000000, 0x006e6173, 0xabab006e, 0x00020000, 0x00010001,
+0x00000001, 0x00000000, 0xab006e76, 0x00020001, 0x00030001, 0x00000001, 0x00000000, 0x000001e8,
+0x000001ec, 0x000001fc, 0x00000200, 0x00000005, 0x00040001, 0x00020002, 0x00000210, 0x00000015,
+0x00000000, 0x00000001, 0x00000000, 0x00000016, 0x00000017, 0x00000018, 0x00000000, 0x00000019,
+0x00000000, 0x00000001, 0x00000000, 0x0000001a, 0x0000001b, 0x0000001c, 0x00000000, 0x666e6173,
+0x00666e00, 0x00666e76, 0x00000275, 0x000001ec, 0x00000278, 0x00000200, 0x00000005, 0x00040001,
+0x00020002, 0x0000027c, 0x42240000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x422c0000,
+0x42300000, 0x00000000, 0x42240000, 0x00000000, 0x00000000, 0x00000000, 0x42280000, 0x422c0000,
+0x42300000, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+0x05000051, 0xa00f000c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0200001f, 0x80000000,
+0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x01000028, 0xe0e40807, 0x03000005, 0x80010000,
+0xa0000003, 0x90aa0000, 0x02000001, 0x80010001, 0xa000000c, 0x01000026, 0xf0e40004, 0x04000004,
+0x80010001, 0x80000000, 0xa0aa0007, 0x80000001, 0x00000027, 0x02000001, 0x80020001, 0xa000000c,
+0x0000002a, 0x03000005, 0x80010000, 0xa0aa0003, 0x90550000, 0x02000001, 0x80020001, 0xa000000c,
+0x01000026, 0xf0e40007, 0x04000004, 0x80020001, 0x80000000, 0xa055000b, 0x80550001, 0x00000027,
+0x02000001, 0x80010001, 0xa000000c, 0x0000002b, 0x02000001, 0xe0030000, 0x80e40001, 0x02000001,
+0xe00c0000, 0xa000000c, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_struct_array_float[] =
+{
+    {"saf",       {"saf", D3DXRS_FLOAT4, 0, 4, D3DXPC_STRUCT, D3DXPT_VOID,  1, 4, 2, 2, 32, NULL}, 105},
+    {"saf[0]",    {"saf", D3DXRS_FLOAT4, 0, 2, D3DXPC_STRUCT, D3DXPT_VOID,  1, 4, 1, 2, 16, NULL}, 105},
+    {"saf[0].f",  {"f",   D3DXRS_FLOAT4, 0, 1, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 1, 0,  4, NULL}, 105},
+    {"saf[0].vf", {"vf",  D3DXRS_FLOAT4, 1, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3, 1, 0, 12, NULL}, 109},
+    {"saf[1]",    {"saf", D3DXRS_FLOAT4, 2, 2, D3DXPC_STRUCT, D3DXPT_VOID,  1, 4, 1, 2, 16, NULL}, 113},
+    {"saf[1].f",  {"f",   D3DXRS_FLOAT4, 2, 1, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 1, 0,  4, NULL}, 113},
+    {"saf[1].vf", {"vf",  D3DXRS_FLOAT4, 3, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3, 1, 0, 12, NULL}, 117},
+};
+
+static const struct registerset_test registerset_test_struct_array_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 3},
+    {SetIntArray, 1, 4, 7, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetIntArray, 1, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x41000000, 0x41100000, 0x00000000}},
+    {SetBoolArray, 1, 0, 3},
+    {SetBoolArray, 1, 4, 7, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetBoolArray, 1, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetFloatArray, 0, 0, 3},
+    {SetFloatArray, 0, 4, 7, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000}},
+    {SetFloatArray, 0, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x41000123, 0x41100123, 0x00000000}},
+    {SetValue, 0, 0, 15},
+    {SetValue, 0, 16, 31, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000}},
+    {SetValue, 0, 32, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x41000123, 0x41100123, 0x00000000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, 1, 8,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800123, 0x40a00123, 0x00000000}},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x41000123, 0x41100123, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x41000123, 0x41100123, 0x00000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40c00123, 0x00000000, 0x00000000, 0x00000000, 0x40e00123, 0x41000123, 0x41100123, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8},
+};
+
+static const struct registerset_constants registerset_constants_struct_array_int[] =
+{
+    {"san",       {"san", D3DXRS_INT4, 0, 8, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 2, 2, 32, NULL}, 140},
+    {"san[0]",    {"san", D3DXRS_INT4, 0, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 140},
+    {"san[0].n",  {"n",   D3DXRS_INT4, 0, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 140},
+    {"san[0].vn", {"vn",  D3DXRS_INT4, 1, 1, D3DXPC_VECTOR, D3DXPT_INT,  1, 3, 1, 0, 12, NULL}, 144},
+    {"san[1]",    {"san", D3DXRS_INT4, 2, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 148},
+    {"san[1].n",  {"n",   D3DXRS_INT4, 2, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 148},
+    {"san[1].vn", {"vn",  D3DXRS_INT4, 3, 1, D3DXPC_VECTOR, D3DXPT_INT,  1, 3, 1, 0, 12, NULL}, 152},
+};
+
+static const struct registerset_test registerset_test_struct_array_int[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 3},
+    {SetIntArray, 1, 4, 7, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x00000004, 0x00000005, 0x00000000}},
+    {SetIntArray, 1, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000007, 0x00000008, 0x00000009, 0x00000000}},
+    {SetBoolArray, 1, 0, 3},
+    {SetBoolArray, 1, 4, 7, 8,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000}},
+    {SetBoolArray, 1, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000}},
+    {SetFloatArray, 0, 0, 3},
+    {SetFloatArray, 0, 4, 7, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0x00000005, 0x00000000}},
+    {SetFloatArray, 0, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000006, 0x00000000, 0x00000001, 0x00000000, 0x00000007, 0x00000008, 0x00000009, 0x00000000}},
+    {SetValue, 1, 0, 15},
+    {SetValue, 1, 16, 31, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x00000004, 0x00000005, 0x00000000}},
+    {SetValue, 1, 32, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000007, 0x00000008, 0x00000009, 0x00000000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0x00000005, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, 1, 8,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0x00000005, 0x00000000}},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x00000006, 0x00000000, 0x00000001, 0x00000000, 0x00000007, 0x00000008, 0x00000009, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x00000006, 0x00000000, 0x00000001, 0x00000000, 0x00000007, 0x00000008, 0x00000009, 0x00000000},},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000006, 0x00000000, 0x00000001, 0x00000000, 0x00000007, 0x00000008, 0x00000009, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+};
+
+static const struct registerset_constants registerset_constants_struct_array_bool[] =
+{
+    {"sab",       {"sab", D3DXRS_BOOL, 0, 8, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 2, 2, 32, NULL}, 51},
+    {"sab[0]",    {"sab", D3DXRS_BOOL, 0, 4, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 51},
+    {"sab[0].b",  {"b",   D3DXRS_BOOL, 0, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL}, 51},
+    {"sab[0].vb", {"vb",  D3DXRS_BOOL, 1, 3, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 52},
+    {"sab[1]",    {"sab", D3DXRS_BOOL, 4, 4, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 55},
+    {"sab[1].b",  {"b",   D3DXRS_BOOL, 4, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL}, 55},
+    {"sab[1].vb", {"vb",  D3DXRS_BOOL, 5, 3, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 56},
+};
+
+static const struct registerset_test registerset_test_struct_array_bool[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 3},
+    {SetIntArray, 1, 4, 7, 4,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetIntArray, 1, 8, REGISTER_OUTPUT_SIZE, 4,
+        {0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetBoolArray, 1, 0, 3},
+    {SetBoolArray, 1, 4, 7, 4,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005}},
+    {SetBoolArray, 1, 8, REGISTER_OUTPUT_SIZE, 4,
+        {0x00000000, 0x00000007, 0x00000008, 0x00000009}},
+    {SetFloatArray, 0, 0, 3},
+    {SetFloatArray, 0, 4, 7, 4,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetFloatArray, 0, 8, REGISTER_OUTPUT_SIZE, 4,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetValue, 1, 0, 15},
+    {SetValue, 1, 16, 31, 4,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005}},
+    {SetValue, 1, 32, REGISTER_OUTPUT_SIZE * 4, 4,
+        {0x00000000, 0x00000007, 0x00000008, 0x00000009}},
+    {SetVector, 0, 0, 0, 4,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, 1, 4,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001}},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 4,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 4,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 4,
+        {0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 4,
+        {0x00000000, 0x00000001, 0x00000001, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_struct_array_int_float[] =
+{
+    {"sanf",        {"sanf", D3DXRS_FLOAT4, 4, 4, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 2, 2, 32, NULL}, 167},
+    {"sanf[0]",     {"sanf", D3DXRS_FLOAT4, 4, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 167},
+    {"sanf[0].nf",  {"nf",   D3DXRS_FLOAT4, 4, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 167},
+    {"sanf[0].vnf", {"vnf",  D3DXRS_FLOAT4, 5, 1, D3DXPC_VECTOR, D3DXPT_INT,  1, 3, 1, 0, 12, NULL}, 171},
+    {"sanf[1]",     {"sanf", D3DXRS_FLOAT4, 6, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 175},
+    {"sanf[1].nf",  {"nf",   D3DXRS_FLOAT4, 6, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 175},
+    {"sanf[1].vnf", {"vnf",  D3DXRS_FLOAT4, 7, 1, D3DXPC_VECTOR, D3DXPT_INT,  1, 3, 1, 0, 12, NULL}, 179},
+};
+
+static const struct registerset_test registerset_test_struct_array_int_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 3},
+    {SetIntArray, 1, 4, 7, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetIntArray, 1, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x41000000, 0x41100000, 0x00000000}},
+    {SetBoolArray, 1, 0, 3},
+    {SetBoolArray, 1, 4, 7, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetBoolArray, 1, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetFloatArray, 0, 0, 3},
+    {SetFloatArray, 0, 4, 7, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetFloatArray, 0, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x41000000, 0x41100000, 0x00000000}},
+    {SetValue, 1, 0, 15},
+    {SetValue, 1, 16, 31, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetValue, 1, 32, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x41000000, 0x41100000, 0x00000000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, 1, 8,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40800000, 0x40a00000, 0x00000000}},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x41000000, 0x41100000, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x41000000, 0x41100000, 0x00000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x40c00000, 0x00000000, 0x00000000, 0x00000000, 0x40e00000, 0x41000000, 0x41100000, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8},
+};
+
+static const struct registerset_constants registerset_constants_struct_array_bool_float[] =
+{
+    {"sabf",        {"sabf", D3DXRS_FLOAT4,  8, 4, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 2, 2, 32, NULL}, 70},
+    {"sabf[0]",     {"sabf", D3DXRS_FLOAT4,  8, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 70},
+    {"sabf[0].bf",  {"bf",   D3DXRS_FLOAT4,  8, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL}, 70},
+    {"sabf[0].vbf", {"vbf",  D3DXRS_FLOAT4,  9, 1, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 74},
+    {"sabf[1]",     {"sabf", D3DXRS_FLOAT4, 10, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 78},
+    {"sabf[1].bf",  {"bf",   D3DXRS_FLOAT4, 10, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL}, 78},
+    {"sabf[1].vbf", {"vbf",  D3DXRS_FLOAT4, 11, 1, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 82},
+};
+
+static const struct registerset_test registerset_test_struct_array_bool_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 3},
+    {SetIntArray, 1, 4, 7, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetIntArray, 1, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetBoolArray, 1, 0, 3},
+    {SetBoolArray, 1, 4, 7, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetBoolArray, 1, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetFloatArray, 0, 0, 3},
+    {SetFloatArray, 0, 4, 7, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetFloatArray, 0, 8, REGISTER_OUTPUT_SIZE, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetValue, 1, 0, 15},
+    {SetValue, 1, 16, 31, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetValue, 1, 32, REGISTER_OUTPUT_SIZE * 4, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetVector, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetVectorArray},
+    {SetVectorArray, 0, 1, 1, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetMatrix, 0, 0, 0, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000}},
+    {SetMatrixTranspose, 0, 0, 0, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8,
+        {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 8},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+struct {bool b; struct {bool b; bool3 vb;} s; bool b1;} ssb = {1, 1, 0, 1, 1, 0};
+struct {int n; struct {int n; int3 vn;} s; int n1;} ssn = {71, 72, 73, 74, 75, 76};
+struct {float f; struct {float f; float3 vf;} s; float f1;} ssf = {1.1f, 2.1f, 3.1f, 4.1f, 5.1f, 6.1f};
+struct {int nf; struct {int nf; int3 vnf;} s; int nf1;} ssnf = {41, 0, 43, 44, 41, 42};
+struct {bool bf; struct {bool bf; bool3 vbf;} s; bool bf1;} ssbf = {1, 0, 0, 1, 1, 0};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int i;
+    if (ssb.b1) for (i = 0; i < ssn.n1; i++) tmp.x += pos.z * ssf.f1 * ssnf.nf1;
+    else for (i = 0; i < ssn.s.vn.z; i++) tmp.y += pos.y * ssf.s.vf.z * ssbf.bf1;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_struct_struct[] =
+{
+0xfffe0300, 0x00fcfffe, 0x42415443, 0x0000001c, 0x000003bb, 0xfffe0300, 0x00000005, 0x0000001c,
+0x00000100, 0x000003b4, 0x00000080, 0x00000000, 0x00000006, 0x000000ec, 0x000000fc, 0x00000114,
+0x00080002, 0x00000004, 0x0000015c, 0x0000016c, 0x000001ac, 0x00000002, 0x00000004, 0x00000214,
+0x00000224, 0x00000264, 0x00000001, 0x00000006, 0x000002cc, 0x000002dc, 0x0000031c, 0x00040002,
+0x00000004, 0x00000364, 0x00000374, 0x00627373, 0xabab0062, 0x00010000, 0x00010001, 0x00000001,
+0x00000000, 0x62760073, 0xababab00, 0x00010001, 0x00030001, 0x00000001, 0x00000000, 0x00000084,
+0x00000088, 0x0000009a, 0x000000a0, 0x00000005, 0x00040001, 0x00020001, 0x000000b0, 0xab003162,
+0x00000084, 0x00000088, 0x00000098, 0x000000c0, 0x000000d0, 0x00000088, 0x00000005, 0x00060001,
+0x00030001, 0x000000d4, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+0x66627373, 0x00666200, 0x00666276, 0x00000119, 0x00000088, 0x0000011c, 0x000000a0, 0x00000005,
+0x00040001, 0x00020001, 0x00000120, 0x00316662, 0x00000119, 0x00000088, 0x00000098, 0x00000130,
+0x00000140, 0x00000088, 0x00000005, 0x00060001, 0x00030001, 0x00000144, 0x3f800000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000,
+0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00667373, 0xabab0066,
+0x00030000, 0x00010001, 0x00000001, 0x00000000, 0xab006676, 0x00030001, 0x00030001, 0x00000001,
+0x00000000, 0x000001b0, 0x000001b4, 0x000001c4, 0x000001c8, 0x00000005, 0x00040001, 0x00020001,
+0x000001d8, 0xab003166, 0x000001b0, 0x000001b4, 0x00000098, 0x000001e8, 0x000001f8, 0x000001b4,
+0x00000005, 0x00060001, 0x00030001, 0x000001fc, 0x3f8ccccd, 0x00000000, 0x00000000, 0x00000000,
+0x40066666, 0x00000000, 0x00000000, 0x00000000, 0x40466666, 0x40833333, 0x40a33333, 0x00000000,
+0x40c33333, 0x00000000, 0x00000000, 0x00000000, 0x006e7373, 0xabab006e, 0x00020000, 0x00010001,
+0x00000001, 0x00000000, 0xab006e76, 0x00020001, 0x00030001, 0x00000001, 0x00000000, 0x00000268,
+0x0000026c, 0x0000027c, 0x00000280, 0x00000005, 0x00040001, 0x00020001, 0x00000290, 0xab00316e,
+0x00000268, 0x0000026c, 0x00000098, 0x000002a0, 0x000002b0, 0x0000026c, 0x00000005, 0x00060001,
+0x00030001, 0x000002b4, 0x00000047, 0x00000000, 0x00000001, 0x00000000, 0x00000048, 0x00000000,
+0x00000001, 0x00000000, 0x00000049, 0x0000004a, 0x0000004b, 0x00000000, 0x0000004c, 0x00000000,
+0x00000001, 0x00000000, 0x666e7373, 0x00666e00, 0x00666e76, 0x00000321, 0x0000026c, 0x00000324,
+0x00000280, 0x00000005, 0x00040001, 0x00020001, 0x00000328, 0x0031666e, 0x00000321, 0x0000026c,
+0x00000098, 0x00000338, 0x00000348, 0x0000026c, 0x00000005, 0x00060001, 0x00030001, 0x0000034c,
+0x42240000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x422c0000, 0x42300000, 0x42240000, 0x00000000, 0x42280000, 0x00000000, 0x00000000, 0x00000000,
+0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461,
+0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x05000051, 0xa00f000c,
+0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0200001f, 0x80000000, 0x900f0000, 0x0200001f,
+0x80000000, 0xe00f0000, 0x01000028, 0xe0e40805, 0x03000005, 0x80010000, 0xa0000003, 0x90aa0000,
+0x02000001, 0x80010001, 0xa000000c, 0x01000026, 0xf0e40005, 0x04000004, 0x80010001, 0x80000000,
+0xa0000007, 0x80000001, 0x00000027, 0x02000001, 0x80020001, 0xa000000c, 0x0000002a, 0x03000005,
+0x80010000, 0xa0aa0002, 0x90550000, 0x02000001, 0x80020001, 0xa000000c, 0x01000026, 0xf0e40004,
+0x04000004, 0x80020001, 0x80000000, 0xa000000b, 0x80550001, 0x00000027, 0x02000001, 0x80010001,
+0xa000000c, 0x0000002b, 0x02000001, 0xe0030000, 0x80e40001, 0x02000001, 0xe00c0000, 0xa000000c,
+0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_struct_struct_float[] =
+{
+    {"ssf",      {"ssf", D3DXRS_FLOAT4, 0, 4, D3DXPC_STRUCT, D3DXPT_VOID,  1, 6, 1, 3, 24, NULL}, 137},
+    {"ssf.f",    {"f",   D3DXRS_FLOAT4, 0, 1, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 1, 0,  4, NULL}, 137},
+    {"ssf.s",    {"s",   D3DXRS_FLOAT4, 1, 2, D3DXPC_STRUCT, D3DXPT_VOID,  1, 4, 1, 2, 16, NULL}, 141},
+    {"ssf.s.f",  {"f",   D3DXRS_FLOAT4, 1, 1, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 1, 0,  4, NULL}, 141},
+    {"ssf.s.vf", {"vf",  D3DXRS_FLOAT4, 2, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3, 1, 0, 12, NULL}, 145},
+    {"ssf.f1",   {"f1",  D3DXRS_FLOAT4, 3, 1, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 1, 0,  4, NULL}, 149},
+};
+
+static const struct registerset_test registerset_test_struct_struct_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800000, 0x40a00000, 0x00000000, 0x00000000, 0x40e00000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800123, 0x40a00123, 0x40c00123, 0x00000000, 0x40e00123}},
+    {SetValue, 0, 0, 23},
+    {SetValue, 0, 24, REGISTER_OUTPUT_SIZE * 4, 16,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800123, 0x40a00123, 0x40c00123, 0x00000000, 0x40e00123}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 16,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800123, 0x40a00123, 0x40c00123, 0x00000000, 0x40e00123}},
+    {SetMatrix, 0, 0, 0, 16,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800123, 0x40a00123, 0x40c00123, 0x00000000, 0x40e00123}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x40000123, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800123, 0x40a00123, 0x40c00123, 0x00000000, 0x40e00123}},
+    {SetMatrixTranspose, 0, 0, 0, 16, {0x40000123}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16, {0x40000123}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16, {0x40000123}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16, {0x40000123}},
+};
+
+static const struct registerset_constants registerset_constants_struct_struct_int[] =
+{
+    {"ssn",      {"ssn", D3DXRS_INT4, 0, 6, D3DXPC_STRUCT, D3DXPT_VOID, 1, 6, 1, 3, 24, NULL}, 183},
+    {"ssn.n",    {"n",   D3DXRS_INT4, 0, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 183},
+    {"ssn.s",    {"s",   D3DXRS_INT4, 1, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 187},
+    {"ssn.s.n",  {"n",   D3DXRS_INT4, 1, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 187},
+    {"ssn.s.vn", {"vn",  D3DXRS_INT4, 2, 1, D3DXPC_VECTOR, D3DXPT_INT,  1, 3, 1, 0, 12, NULL}, 191},
+    {"ssn.n1",   {"n1",  D3DXRS_INT4, 3, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 195},
+};
+
+static const struct registerset_test registerset_test_struct_struct_int[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x00000000, 0x00000001, 0x00000000,
+        0x00000004, 0x00000005, 0x00000000, 0x00000000, 0x00000007, 0x00000000, 0x00000001}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000,
+        0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000001}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+        0x00000004, 0x00000005, 0x00000006, 0x00000000, 0x00000007, 0x00000000, 0x00000001}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 16,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x00000000, 0x00000001, 0x00000000,
+        0x00000004, 0x00000005, 0x00000000, 0x00000000, 0x00000007, 0x00000000, 0x00000001}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 16,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+        0x00000004, 0x00000005, 0x00000006, 0x00000000, 0x00000007, 0x00000000, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 16,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+        0x00000004, 0x00000005, 0x00000006, 0x00000000, 0x00000007, 0x00000000, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+        0x00000004, 0x00000005, 0x00000006, 0x00000000, 0x00000007, 0x00000000, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 16,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x00000002, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_struct_struct_bool[] =
+{
+    {"ssb",      {"ssb", D3DXRS_BOOL, 0, 6, D3DXPC_STRUCT, D3DXPT_VOID, 1, 6, 1, 3, 24, NULL}, 63},
+    {"ssb.b",    {"b",   D3DXRS_BOOL, 0, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL}, 63},
+    {"ssb.s",    {"s",   D3DXRS_BOOL, 1, 4, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 64},
+    {"ssb.s.b",  {"b",   D3DXRS_BOOL, 1, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL}, 64},
+    {"ssb.s.vb", {"vb",  D3DXRS_BOOL, 2, 3, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL}, 65},
+    {"ssb.b1",   {"b1",  D3DXRS_BOOL, 5, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL}, 68},
+};
+
+static const struct registerset_test registerset_test_struct_struct_bool[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000000, 0x00000007}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 6,
+        {0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000000, 0x00000007}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrix, 0, 0, 0, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTranspose, 0, 0, 0, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 6,
+        {0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001}},
+};
+
+static const struct registerset_constants registerset_constants_struct_struct_int_float[] =
+{
+    {"ssnf",       {"ssnf", D3DXRS_FLOAT4, 4, 4, D3DXPC_STRUCT, D3DXPT_VOID, 1, 6, 1, 3, 24, NULL}, 221},
+    {"ssnf.nf",    {"nf",   D3DXRS_FLOAT4, 4, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 221},
+    {"ssnf.s",     {"s",    D3DXRS_FLOAT4, 5, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL}, 225},
+    {"ssnf.s.nf",  {"nf",   D3DXRS_FLOAT4, 5, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 225},
+    {"ssnf.s.vnf", {"vnf",  D3DXRS_FLOAT4, 6, 1, D3DXPC_VECTOR, D3DXPT_INT,  1, 3, 1, 0, 12, NULL}, 229},
+    {"ssnf.nf1",   {"nf1",  D3DXRS_FLOAT4, 7, 1, D3DXPC_SCALAR, D3DXPT_INT,  1, 1, 1, 0,  4, NULL}, 233},
+};
+
+static const struct registerset_test registerset_test_struct_struct_int_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800000, 0x40a00000, 0x00000000, 0x00000000, 0x40e00000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800000, 0x40a00000, 0x40c00000, 0x00000000, 0x40e00000}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 16,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x40400000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800000, 0x40a00000, 0x00000000, 0x00000000, 0x40e00000}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 16,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800000, 0x40a00000, 0x40c00000, 0x00000000, 0x40e00000}},
+    {SetMatrix, 0, 0, 0, 16,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800000, 0x40a00000, 0x40c00000, 0x00000000, 0x40e00000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x40800000, 0x40a00000, 0x40c00000, 0x00000000, 0x40e00000}},
+    {SetMatrixTranspose, 0, 0, 0, 16, {0x40000000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16, {0x40000000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16, {0x40000000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16, {0x40000000}},
+};
+
+static const struct registerset_constants registerset_constants_struct_struct_bool_float[] =
+{
+    {"ssbf",       {"ssbf", D3DXRS_FLOAT4,  8, 4, D3DXPC_STRUCT, D3DXPT_VOID, 1, 6, 1, 3, 24, NULL},  91},
+    {"ssbf.bf",    {"bf",   D3DXRS_FLOAT4,  8, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL},  91},
+    {"ssbf.s",     {"s",    D3DXRS_FLOAT4,  9, 2, D3DXPC_STRUCT, D3DXPT_VOID, 1, 4, 1, 2, 16, NULL},  95},
+    {"ssbf.s.bf",  {"bf",   D3DXRS_FLOAT4,  9, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL},  95},
+    {"ssbf.s.vbf", {"vbf",  D3DXRS_FLOAT4, 10, 1, D3DXPC_VECTOR, D3DXPT_BOOL, 1, 3, 1, 0, 12, NULL},  99},
+    {"ssbf.bf1",   {"bf1",  D3DXRS_FLOAT4, 11, 1, D3DXPC_SCALAR, D3DXPT_BOOL, 1, 1, 1, 0,  4, NULL}, 103},
+};
+
+static const struct registerset_test registerset_test_struct_struct_bool_float[] =
+{
+    {SetInt},
+    {SetBool},
+    {SetFloat},
+    {SetIntArray, 1, 0, 5},
+    {SetIntArray, 1, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetBoolArray, 1, 0, 5},
+    {SetBoolArray, 1, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetFloatArray, 0, 0, 5},
+    {SetFloatArray, 0, 6, REGISTER_OUTPUT_SIZE, 16,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000}},
+    {SetValue, 1, 0, 23},
+    {SetValue, 1, 24, REGISTER_OUTPUT_SIZE * 4, 16,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000}},
+    {SetVector},
+    {SetVectorArray, 0, 0, 1},
+    {SetVectorArray, 0, 2, REGISTER_OUTPUT_SIZE / 4, 16,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000}},
+    {SetMatrix, 0, 0, 0, 16,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16,
+        {0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000}},
+    {SetMatrixTranspose, 0, 0, 0, 16, {0x3f800000}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16, {0x3f800000}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16, {0x3f800000}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, REGISTER_OUTPUT_SIZE / 16, 16, {0x3f800000}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+row_major int3x2 ran[2] = {4, 5, 6, 1, 8, 1, 2, 3, 4, 7, 9, 1};
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    int k;
+    for (k = 0; k < ran[1]._21; k++)
+        tmp.y += pos.y + tmp.x;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_special_int[] =
+{
+0xfffe0300, 0x0038fffe, 0x42415443, 0x0000001c, 0x000000ab, 0xfffe0300, 0x00000001, 0x0000001c,
+0x00000100, 0x000000a4, 0x00000030, 0x00000001, 0x00000009, 0x00000034, 0x00000044, 0x006e6172,
+0x00020002, 0x00020003, 0x00000002, 0x00000000, 0x00000004, 0x00000005, 0x00000001, 0x00000000,
+0x00000006, 0x00000001, 0x00000001, 0x00000000, 0x00000008, 0x00000001, 0x00000001, 0x00000000,
+0x00000002, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x00000007, 0x00000001, 0x00000000,
+0x00000009, 0x00000001, 0x00000001, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73,
+0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932,
+0x332e3235, 0x00313131, 0x05000051, 0xa00f0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x0200001f, 0x80000000, 0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x02000001, 0x80010000,
+0xa0000000, 0x01000026, 0xf0e40008, 0x03000002, 0x80010000, 0x80000000, 0x90550000, 0x00000027,
+0x02000001, 0xe0020000, 0x80000000, 0x02000001, 0xe00d0000, 0xa0000000, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_special_int[] =
+{
+    {"ran",    {"ran", D3DXRS_INT4, 0, 9, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3,  2, 2, 0, 48, NULL}, 17},
+    {"ran[0]", {"ran", D3DXRS_INT4, 0, 3, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3,  2, 1, 0, 24, NULL}, 17},
+    {"ran[1]", {"ran", D3DXRS_INT4, 3, 3, D3DXPC_MATRIX_ROWS, D3DXPT_INT, 3,  2, 1, 0, 24, NULL}, 29},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+float3 vaf[10];
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    tmp.y += pos.y + vaf[8].x;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_bigvec[] =
+{
+0xfffe0300, 0x0020fffe, 0x42415443, 0x0000001c, 0x0000004b, 0xfffe0300, 0x00000001, 0x0000001c,
+0x00000100, 0x00000044, 0x00000030, 0x00000002, 0x00000009, 0x00000034, 0x00000000, 0x00666176,
+0x00030001, 0x00030001, 0x0000000a, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73,
+0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932,
+0x332e3235, 0x00313131, 0x05000051, 0xa00f0009, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x0200001f, 0x80000000, 0x900f0000, 0x0200001f, 0x80000000, 0xe00f0000, 0x03000002, 0xe0020000,
+0xa0000008, 0x90550000, 0x02000001, 0xe00d0000, 0xa0000009, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_bigvec_float[] =
+{
+    {"vaf",    {"vaf", D3DXRS_FLOAT4, 0, 9, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3, 10, 0, 120, NULL}, 0},
+    {"vaf[0]", {"vaf", D3DXRS_FLOAT4, 0, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3,  1, 0,  12, NULL}, 0},
+    {"vaf[1]", {"vaf", D3DXRS_FLOAT4, 1, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3,  1, 0,  12, NULL}, 0},
+    {"vaf[2]", {"vaf", D3DXRS_FLOAT4, 2, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3,  1, 0,  12, NULL}, 0},
+    {"vaf[3]", {"vaf", D3DXRS_FLOAT4, 3, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3,  1, 0,  12, NULL}, 0},
+    {"vaf[4]", {"vaf", D3DXRS_FLOAT4, 4, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3,  1, 0,  12, NULL}, 0},
+    {"vaf[5]", {"vaf", D3DXRS_FLOAT4, 5, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3,  1, 0,  12, NULL}, 0},
+    {"vaf[6]", {"vaf", D3DXRS_FLOAT4, 6, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3,  1, 0,  12, NULL}, 0},
+    {"vaf[7]", {"vaf", D3DXRS_FLOAT4, 7, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3,  1, 0,  12, NULL}, 0},
+    {"vaf[8]", {"vaf", D3DXRS_FLOAT4, 8, 1, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3,  1, 0,  12, NULL}, 0},
+    {"vaf[9]", {"vaf", D3DXRS_FLOAT4, 9, 0, D3DXPC_VECTOR, D3DXPT_FLOAT, 1, 3,  1, 0,  12, NULL}, 0},
+};
+
+static const struct registerset_test registerset_test_bigvec_float[] =
+{
+    {SetMatrix, 0, 0, 0, 16,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123, 0x00000000,
+        0x41200123, 0x41300123, 0x41400123, 0x00000000, 0x41600123, 0x41700123, 0x41800123}},
+    {SetMatrixArray},
+    {SetMatrixArray, 0, 1, 1, 16,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123, 0x00000000,
+        0x41200123, 0x41300123, 0x41400123, 0x00000000, 0x41600123, 0x41700123, 0x41800123}},
+    {SetMatrixArray, 0, 2, 2, 32,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123, 0x00000000,
+        0x41200123, 0x41300123, 0x41400123, 0x00000000, 0x41600123, 0x41700123, 0x41800123, 0x00000000,
+        0x41a00123, 0x41b00123, 0x41c00123, 0x00000000, 0x00000000, 0x41f00123, 0x42000123, 0x00000000,
+        0x00000000, 0x42300123, 0x42400123, 0x00000000, 0x42600123, 0x42700123, 0x42800123}},
+    {SetMatrixArray, 0, 3, REGISTER_OUTPUT_SIZE / 16, 36,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123, 0x00000000,
+        0x41200123, 0x41300123, 0x41400123, 0x00000000, 0x41600123, 0x41700123, 0x41800123, 0x00000000,
+        0x41a00123, 0x41b00123, 0x41c00123, 0x00000000, 0x00000000, 0x41f00123, 0x42000123, 0x00000000,
+        0x00000000, 0x42300123, 0x42400123, 0x00000000, 0x42600123, 0x42700123, 0x42800123, 0x00000000,
+        0x43000123, 0x43100123, 0x43200123}},
+    {SetMatrixTranspose, 0, 0, 0, 16,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123, 0x00000000,
+        0x40800123, 0x41000123, 0x41400123, 0x00000000, 0x40a00123, 0x41100123, 0x41500123}},
+    {SetMatrixTransposeArray},
+    {SetMatrixTransposeArray, 0, 1, 1, 16,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123, 0x00000000,
+        0x40800123, 0x41000123, 0x41400123, 0x00000000, 0x40a00123, 0x41100123, 0x41500123}},
+    {SetMatrixTransposeArray, 0, 2, 2, 32,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123, 0x00000000,
+        0x40800123, 0x41000123, 0x41400123, 0x00000000, 0x40a00123, 0x41100123, 0x41500123, 0x00000000,
+        0x41a00123, 0x00000000, 0x00000000, 0x00000000, 0x41b00123, 0x41f00123, 0x42300123, 0x00000000,
+        0x41c00123, 0x42000123, 0x42400123, 0x00000000, 0x41d00123, 0x42100123, 0x42500123}},
+    {SetMatrixTransposeArray, 0, 3, REGISTER_OUTPUT_SIZE / 16, 36,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123, 0x00000000,
+        0x40800123, 0x41000123, 0x41400123, 0x00000000, 0x40a00123, 0x41100123, 0x41500123, 0x00000000,
+        0x41a00123, 0x00000000, 0x00000000, 0x00000000, 0x41b00123, 0x41f00123, 0x42300123, 0x00000000,
+        0x41c00123, 0x42000123, 0x42400123, 0x00000000, 0x41d00123, 0x42100123, 0x42500123, 0x00000000,
+        0x43000123, 0x43400123, 0x43800123}},
+    {SetMatrixPointerArray},
+    {SetMatrixPointerArray, 0, 1, 1, 16,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123, 0x00000000,
+        0x41200123, 0x41300123, 0x41400123, 0x00000000, 0x41600123, 0x41700123, 0x41800123}},
+    {SetMatrixPointerArray, 0, 2, 2, 32,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123, 0x00000000,
+        0x41200123, 0x41300123, 0x41400123, 0x00000000, 0x41600123, 0x41700123, 0x41800123, 0x00000000,
+        0x41900123, 0x41a00123, 0x41b00123, 0x00000000, 0x41d00123, 0x00000000, 0x41f00123, 0x00000000,
+        0x42100123, 0x00000000, 0x42300123, 0x00000000, 0x42500123, 0x42600123, 0x42700123}},
+    {SetMatrixPointerArray, 0, 3, REGISTER_OUTPUT_SIZE / 16, 36,
+        {0x40000123, 0x00000000, 0x40800123, 0x00000000, 0x40c00123, 0x40e00123, 0x41000123, 0x00000000,
+        0x41200123, 0x41300123, 0x41400123, 0x00000000, 0x41600123, 0x41700123, 0x41800123, 0x00000000,
+        0x41900123, 0x41a00123, 0x41b00123, 0x00000000, 0x41d00123, 0x00000000, 0x41f00123, 0x00000000,
+        0x42100123, 0x00000000, 0x42300123, 0x00000000, 0x42500123, 0x42600123, 0x42700123, 0x00000000,
+        0x42800123, 0x42900123, 0x43000123}},
+    {SetMatrixTransposePointerArray},
+    {SetMatrixTransposePointerArray, 0, 1, 1, 16,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123, 0x00000000,
+        0x40800123, 0x41000123, 0x41400123, 0x00000000, 0x40a00123, 0x41100123, 0x41500123}},
+    {SetMatrixTransposePointerArray, 0, 2, 2, 32,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123, 0x00000000,
+        0x40800123, 0x41000123, 0x41400123, 0x00000000, 0x40a00123, 0x41100123, 0x41500123, 0x00000000,
+        0x41900123, 0x41d00123, 0x42100123, 0x00000000, 0x41a00123, 0x00000000, 0x00000000, 0x00000000,
+        0x41b00123, 0x41f00123, 0x42300123, 0x00000000, 0x41c00123, 0x42000123, 0x42400123}},
+    {SetMatrixTransposePointerArray, 0, 3, REGISTER_OUTPUT_SIZE / 16, 36,
+        {0x40000123, 0x40c00123, 0x41200123, 0x00000000, 0x00000000, 0x40e00123, 0x41300123, 0x00000000,
+        0x40800123, 0x41000123, 0x41400123, 0x00000000, 0x40a00123, 0x41100123, 0x41500123, 0x00000000,
+        0x41900123, 0x41d00123, 0x42100123, 0x00000000, 0x41a00123, 0x00000000, 0x00000000, 0x00000000,
+        0x41b00123, 0x41f00123, 0x42300123, 0x00000000, 0x41c00123, 0x42000123, 0x42400123, 0x00000000,
+        0x42800123, 0x43200123, 0x43600123}},
+};
+
+/*
+ * fxc.exe /Tvs_3_0
+ */
+#if 0
+float4x4 cf = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8};
+float f = 33.33;
+float4 main(float4 pos : POSITION) : POSITION
+{
+    float4 tmp = 0;
+    tmp.y += cf._22;
+    tmp.z = f;
+    return tmp;
+}
+#endif
+static const DWORD registerset_blob_matrix_column_clamp[] =
+{
+0xfffe0300, 0x003efffe, 0x42415443, 0x0000001c, 0x000000c3, 0xfffe0300, 0x00000002, 0x0000001c,
+0x00000100, 0x000000bc, 0x00000044, 0x00000002, 0x00000002, 0x00000048, 0x00000058, 0x00000098,
+0x00020002, 0x00000001, 0x0000009c, 0x000000ac, 0xab006663, 0x00030003, 0x00040004, 0x00000001,
+0x00000000, 0x3f8ccccd, 0x40b00000, 0x411e6666, 0x3fc00000, 0x400ccccd, 0x40d33333, 0x3f99999a,
+0x3fcccccd, 0x40533333, 0x40f66666, 0x3fa66666, 0x3fd9999a, 0x408ccccd, 0x410ccccd, 0x3fb33333,
+0x3fe66666, 0xabab0066, 0x00030000, 0x00010001, 0x00000001, 0x00000000, 0x420551ec, 0x00000000,
+0x00000000, 0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
+0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131,
+0x05000051, 0xa00f0003, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x0200001f, 0x80000000,
+0xe00f0000, 0x02000001, 0x80020000, 0xa0550001, 0x03000005, 0xe00b0000, 0x80550000, 0xa0240003,
+0x02000001, 0xe0040000, 0xa0000002, 0x0000ffff,
+};
+
+static const struct registerset_constants registerset_constants_matrix_column_clamp[] =
+{
+    {"cf", {"cf", D3DXRS_FLOAT4, 0, 2, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 4, 4, 1, 0, 64, NULL}, 0},
+    {"f", {"f", D3DXRS_FLOAT4, 2, 1, D3DXPC_SCALAR, D3DXPT_FLOAT, 1, 1, 1, 0, 4, NULL}, 0},
+};
+
+static const struct registerset_test registerset_test_matrix_column_clamp[] =
+{
+    {SetMatrix, 0, 0, 0, 8,
+        {0x40000123, 0x40c00123, 0x41200123, 0x41600123, 0x00000000, 0x40e00123, 0x41300123, 0x41700123}},
+};
+
+static const struct
+{
+    const char *name;
+    const char *var;
+    UINT start;
+    D3DXREGISTER_SET regset;
+    const DWORD *blob;
+    const struct registerset_test *tests;
+    UINT test_count;
+    const struct registerset_constants *constants;
+    UINT constant_count;
+}
+registerset_data[] =
+{
+    /* scalar */
+    {"float", "f", 0, D3DXRS_FLOAT4, registerset_blob_scalar,
+        registerset_test_scalar_float, ARRAY_SIZE(registerset_test_scalar_float),
+        registerset_constants_scalar_float, ARRAY_SIZE(registerset_constants_scalar_float)},
+    {"int", "n", 0, D3DXRS_INT4, registerset_blob_scalar,
+        registerset_test_scalar_int, ARRAY_SIZE(registerset_test_scalar_int),
+        registerset_constants_scalar_int, ARRAY_SIZE(registerset_constants_scalar_int)},
+    {"int float", "nf", 4, D3DXRS_FLOAT4, registerset_blob_scalar,
+        registerset_test_scalar_int_float, ARRAY_SIZE(registerset_test_scalar_int_float),
+        registerset_constants_scalar_int_float, ARRAY_SIZE(registerset_constants_scalar_int_float)},
+    {"bool float", "bf", 8, D3DXRS_FLOAT4, registerset_blob_scalar,
+        registerset_test_scalar_bool_float, ARRAY_SIZE(registerset_test_scalar_bool_float),
+        registerset_constants_scalar_bool_float, ARRAY_SIZE(registerset_constants_scalar_bool_float)},
+    {"bool", "b", 0, D3DXRS_BOOL, registerset_blob_scalar,
+        registerset_test_scalar_bool, ARRAY_SIZE(registerset_test_scalar_bool),
+        registerset_constants_scalar_bool, ARRAY_SIZE(registerset_constants_scalar_bool)},
+    /* scalar array */
+    {"float [2]", "af", 0, D3DXRS_FLOAT4, registerset_blob_scalar_array,
+        registerset_test_scalar_array_float, ARRAY_SIZE(registerset_test_scalar_array_float),
+        registerset_constants_scalar_array_float, ARRAY_SIZE(registerset_constants_scalar_array_float)},
+    {"int [2]", "an", 0, D3DXRS_INT4, registerset_blob_scalar_array,
+        registerset_test_scalar_array_int, ARRAY_SIZE(registerset_test_scalar_array_int),
+        registerset_constants_scalar_array_int, ARRAY_SIZE(registerset_constants_scalar_array_int)},
+    {"bool [2]", "ab", 0, D3DXRS_BOOL, registerset_blob_scalar_array,
+        registerset_test_scalar_array_bool, ARRAY_SIZE(registerset_test_scalar_array_bool),
+        registerset_constants_scalar_array_bool, ARRAY_SIZE(registerset_constants_scalar_array_bool)},
+    {"int float [2]", "anf", 8, D3DXRS_FLOAT4, registerset_blob_scalar_array,
+        registerset_test_scalar_array_int_float, ARRAY_SIZE(registerset_test_scalar_array_int_float),
+        registerset_constants_scalar_array_int_float, ARRAY_SIZE(registerset_constants_scalar_array_int_float)},
+    {"bool float [2]", "abf", 16, D3DXRS_FLOAT4, registerset_blob_scalar_array,
+        registerset_test_scalar_array_bool_float, ARRAY_SIZE(registerset_test_scalar_array_bool_float),
+        registerset_constants_scalar_array_bool_float, ARRAY_SIZE(registerset_constants_scalar_array_bool_float)},
+    /* vector */
+    {"float 3", "vf", 0, D3DXRS_FLOAT4, registerset_blob_vector,
+        registerset_test_vector_float, ARRAY_SIZE(registerset_test_vector_float),
+        registerset_constants_vector_float, ARRAY_SIZE(registerset_constants_vector_float)},
+    {"int 3", "vn", 0, D3DXRS_INT4, registerset_blob_vector,
+        registerset_test_vector_int, ARRAY_SIZE(registerset_test_vector_int),
+        registerset_constants_vector_int, ARRAY_SIZE(registerset_constants_vector_int)},
+    {"bool 3", "vb", 0, D3DXRS_BOOL, registerset_blob_vector,
+        registerset_test_vector_bool, ARRAY_SIZE(registerset_test_vector_bool),
+        registerset_constants_vector_bool, ARRAY_SIZE(registerset_constants_vector_bool)},
+    {"bool float 3", "vbf", 8, D3DXRS_FLOAT4, registerset_blob_vector,
+        registerset_test_vector_bool_float, ARRAY_SIZE(registerset_test_vector_bool_float),
+        registerset_constants_vector_bool_float, ARRAY_SIZE(registerset_constants_vector_bool_float)},
+    {"int float 3", "vnf", 4, D3DXRS_FLOAT4, registerset_blob_vector,
+        registerset_test_vector_int_float, ARRAY_SIZE(registerset_test_vector_int_float),
+        registerset_constants_vector_int_float, ARRAY_SIZE(registerset_constants_vector_int_float)},
+    /* vector array */
+    {"float 3 [2]", "vaf", 0, D3DXRS_FLOAT4, registerset_blob_vector_array,
+        registerset_test_vector_array_float, ARRAY_SIZE(registerset_test_vector_array_float),
+        registerset_constants_vector_array_float, ARRAY_SIZE(registerset_constants_vector_array_float)},
+    {"int 3 [2]", "van", 0, D3DXRS_INT4, registerset_blob_vector_array,
+        registerset_test_vector_array_int, ARRAY_SIZE(registerset_test_vector_array_int),
+        registerset_constants_vector_array_int, ARRAY_SIZE(registerset_constants_vector_array_int)},
+    {"bool 3 [2]", "vab", 0, D3DXRS_BOOL, registerset_blob_vector_array,
+        registerset_test_vector_array_bool, ARRAY_SIZE(registerset_test_vector_array_bool),
+        registerset_constants_vector_array_bool, ARRAY_SIZE(registerset_constants_vector_array_bool)},
+    {"bool float 3 [2]", "vabf", 16, D3DXRS_FLOAT4, registerset_blob_vector_array,
+        registerset_test_vector_array_bool_float, ARRAY_SIZE(registerset_test_vector_array_bool_float),
+        registerset_constants_vector_array_bool_float, ARRAY_SIZE(registerset_constants_vector_array_bool_float)},
+    {"int float 3 [2]", "vanf", 8, D3DXRS_FLOAT4, registerset_blob_vector_array,
+        registerset_test_vector_array_int_float, ARRAY_SIZE(registerset_test_vector_array_int_float),
+        registerset_constants_vector_array_int_float, ARRAY_SIZE(registerset_constants_vector_array_int_float)},
+    /* matrix column */
+    {"float c3x2", "cf", 0, D3DXRS_FLOAT4, registerset_blob_column,
+        registerset_test_column_float, ARRAY_SIZE(registerset_test_column_float),
+        registerset_constants_column_float, ARRAY_SIZE(registerset_constants_column_float)},
+    {"int c3x2", "cn", 0, D3DXRS_INT4, registerset_blob_column,
+        registerset_test_column_int, ARRAY_SIZE(registerset_test_column_int),
+        registerset_constants_column_int, ARRAY_SIZE(registerset_constants_column_int)},
+    {"bool c3x2", "cb", 0, D3DXRS_BOOL, registerset_blob_column,
+        registerset_test_column_bool, ARRAY_SIZE(registerset_test_column_bool),
+        registerset_constants_column_bool, ARRAY_SIZE(registerset_constants_column_bool)},
+    {"bool float c3x2", "cbf", 8, D3DXRS_FLOAT4, registerset_blob_column,
+        registerset_test_column_bool_float, ARRAY_SIZE(registerset_test_column_bool_float),
+        registerset_constants_column_bool_float, ARRAY_SIZE(registerset_constants_column_bool_float)},
+    {"int float c3x2", "cnf", 16, D3DXRS_FLOAT4, registerset_blob_column,
+        registerset_test_column_int_float, ARRAY_SIZE(registerset_test_column_int_float),
+        registerset_constants_column_int_float, ARRAY_SIZE(registerset_constants_column_int_float)},
+    /* matrix column array */
+    {"float c3x2 [2]", "caf", 0, D3DXRS_FLOAT4, registerset_blob_column_array,
+        registerset_test_column_array_float, ARRAY_SIZE(registerset_test_column_array_float),
+        registerset_constants_column_array_float, ARRAY_SIZE(registerset_constants_column_array_float)},
+    {"int c3x2 [2]", "can", 0, D3DXRS_INT4, registerset_blob_column_array,
+        registerset_test_column_array_int, ARRAY_SIZE(registerset_test_column_array_int),
+        registerset_constants_column_array_int, ARRAY_SIZE(registerset_constants_column_array_int)},
+    {"bool c3x2 [2]", "cab", 0, D3DXRS_BOOL, registerset_blob_column_array,
+        registerset_test_column_array_bool, ARRAY_SIZE(registerset_test_column_array_bool),
+        registerset_constants_column_array_bool, ARRAY_SIZE(registerset_constants_column_array_bool)},
+    {"bool float c3x2 [2]", "cabf", 16, D3DXRS_FLOAT4, registerset_blob_column_array,
+        registerset_test_column_array_bool_float, ARRAY_SIZE(registerset_test_column_array_bool_float),
+        registerset_constants_column_array_bool_float, ARRAY_SIZE(registerset_constants_column_array_bool_float)},
+    {"int float c3x2 [2]", "canf", 32, D3DXRS_FLOAT4, registerset_blob_column_array,
+        registerset_test_column_array_int_float, ARRAY_SIZE(registerset_test_column_array_int_float),
+        registerset_constants_column_array_int_float, ARRAY_SIZE(registerset_constants_column_array_int_float)},
+    /* matrix row */
+    {"float r3x2", "rf", 0, D3DXRS_FLOAT4, registerset_blob_row,
+        registerset_test_row_float, ARRAY_SIZE(registerset_test_row_float),
+        registerset_constants_row_float, ARRAY_SIZE(registerset_constants_row_float)},
+    {"int r3x2", "rn", 0, D3DXRS_INT4, registerset_blob_row,
+        registerset_test_row_int, ARRAY_SIZE(registerset_test_row_int),
+        registerset_constants_row_int, ARRAY_SIZE(registerset_constants_row_int)},
+    {"bool r3x2", "rb", 0, D3DXRS_BOOL, registerset_blob_row,
+        registerset_test_row_bool, ARRAY_SIZE(registerset_test_row_bool),
+        registerset_constants_row_bool, ARRAY_SIZE(registerset_constants_row_bool)},
+    {"bool float r3x2", "rbf", 12, D3DXRS_FLOAT4, registerset_blob_row,
+        registerset_test_row_bool_float, ARRAY_SIZE(registerset_test_row_bool_float),
+        registerset_constants_row_bool_float, ARRAY_SIZE(registerset_constants_row_bool_float)},
+    {"int float r3x2", "rnf", 24, D3DXRS_FLOAT4, registerset_blob_row,
+        registerset_test_row_int_float, ARRAY_SIZE(registerset_test_row_int_float),
+        registerset_constants_row_int_float, ARRAY_SIZE(registerset_constants_row_int_float)},
+    /* matrix row array */
+    {"float 3x2 [2]", "raf", 0, D3DXRS_FLOAT4, registerset_blob_row_array,
+        registerset_test_row_array_float, ARRAY_SIZE(registerset_test_row_array_float),
+        registerset_constants_row_array_float, ARRAY_SIZE(registerset_constants_row_array_float)},
+    {"int 3x2 [2]", "ran", 0, D3DXRS_INT4, registerset_blob_row_array,
+        registerset_test_row_array_int, ARRAY_SIZE(registerset_test_row_array_int),
+        registerset_constants_row_array_int, ARRAY_SIZE(registerset_constants_row_array_int)},
+    {"bool 3x2 [2]", "rab", 0, D3DXRS_BOOL, registerset_blob_row_array,
+        registerset_test_row_array_bool, ARRAY_SIZE(registerset_test_row_array_bool),
+        registerset_constants_row_array_bool, ARRAY_SIZE(registerset_constants_row_array_bool)},
+    {"bool float 3x2 [2]", "rabf", 24, D3DXRS_FLOAT4, registerset_blob_row_array,
+        registerset_test_row_array_bool_float, ARRAY_SIZE(registerset_test_row_array_bool_float),
+        registerset_constants_row_array_bool_float, ARRAY_SIZE(registerset_constants_row_array_bool_float)},
+    {"int float 3x2 [2]", "ranf", 48, D3DXRS_FLOAT4, registerset_blob_row_array,
+        registerset_test_row_array_int_float, ARRAY_SIZE(registerset_test_row_array_int_float),
+        registerset_constants_row_array_int_float, ARRAY_SIZE(registerset_constants_row_array_int_float)},
+    /* struct */
+    {"struct float", "sf", 0, D3DXRS_FLOAT4, registerset_blob_struct,
+        registerset_test_struct_float, ARRAY_SIZE(registerset_test_struct_float),
+        registerset_constants_struct_float, ARRAY_SIZE(registerset_constants_struct_float)},
+    {"struct int", "sn", 0, D3DXRS_INT4, registerset_blob_struct,
+        registerset_test_struct_int, ARRAY_SIZE(registerset_test_struct_int),
+        registerset_constants_struct_int, ARRAY_SIZE(registerset_constants_struct_int)},
+    {"struct bool", "sb", 0, D3DXRS_BOOL, registerset_blob_struct,
+        registerset_test_struct_bool, ARRAY_SIZE(registerset_test_struct_bool),
+        registerset_constants_struct_bool, ARRAY_SIZE(registerset_constants_struct_bool)},
+    {"struct bool float", "sbf", 16, D3DXRS_FLOAT4, registerset_blob_struct,
+        registerset_test_struct_bool_float, ARRAY_SIZE(registerset_test_struct_bool_float),
+        registerset_constants_struct_bool_float, ARRAY_SIZE(registerset_constants_struct_bool_float)},
+    {"struct int float", "snf", 8, D3DXRS_FLOAT4, registerset_blob_struct,
+        registerset_test_struct_int_float, ARRAY_SIZE(registerset_test_struct_int_float),
+        registerset_constants_struct_int_float, ARRAY_SIZE(registerset_constants_struct_int_float)},
+    /* struct array */
+    {"struct float [2]", "saf", 0, D3DXRS_FLOAT4, registerset_blob_struct_array,
+        registerset_test_struct_array_float, ARRAY_SIZE(registerset_test_struct_array_float),
+        registerset_constants_struct_array_float, ARRAY_SIZE(registerset_constants_struct_array_float)},
+    {"struct int [2]", "san", 0, D3DXRS_INT4, registerset_blob_struct_array,
+        registerset_test_struct_array_int, ARRAY_SIZE(registerset_test_struct_array_int),
+        registerset_constants_struct_array_int, ARRAY_SIZE(registerset_constants_struct_array_int)},
+    {"struct bool [2]", "sab", 0, D3DXRS_BOOL, registerset_blob_struct_array,
+        registerset_test_struct_array_bool, ARRAY_SIZE(registerset_test_struct_array_bool),
+        registerset_constants_struct_array_bool, ARRAY_SIZE(registerset_constants_struct_array_bool)},
+    {"struct bool float [2]", "sabf", 32, D3DXRS_FLOAT4, registerset_blob_struct_array,
+        registerset_test_struct_array_bool_float, ARRAY_SIZE(registerset_test_struct_array_bool_float),
+        registerset_constants_struct_array_bool_float, ARRAY_SIZE(registerset_constants_struct_array_bool_float)},
+    {"struct int float [2]", "sanf", 16, D3DXRS_FLOAT4, registerset_blob_struct_array,
+        registerset_test_struct_array_int_float, ARRAY_SIZE(registerset_test_struct_array_int_float),
+        registerset_constants_struct_array_int_float, ARRAY_SIZE(registerset_constants_struct_array_int_float)},
+    /* struct struct */
+    {"struct struct float", "ssf", 0, D3DXRS_FLOAT4, registerset_blob_struct_struct,
+        registerset_test_struct_struct_float, ARRAY_SIZE(registerset_test_struct_struct_float),
+        registerset_constants_struct_struct_float, ARRAY_SIZE(registerset_constants_struct_struct_float)},
+    {"struct struct int", "ssn", 0, D3DXRS_INT4, registerset_blob_struct_struct,
+        registerset_test_struct_struct_int, ARRAY_SIZE(registerset_test_struct_struct_int),
+        registerset_constants_struct_struct_int, ARRAY_SIZE(registerset_constants_struct_struct_int)},
+    {"struct struct bool", "ssb", 0, D3DXRS_BOOL, registerset_blob_struct_struct,
+        registerset_test_struct_struct_bool, ARRAY_SIZE(registerset_test_struct_struct_bool),
+        registerset_constants_struct_struct_bool, ARRAY_SIZE(registerset_constants_struct_struct_bool)},
+    {"struct struct bool float", "ssbf", 32, D3DXRS_FLOAT4, registerset_blob_struct_struct,
+        registerset_test_struct_struct_bool_float, ARRAY_SIZE(registerset_test_struct_struct_bool_float),
+        registerset_constants_struct_struct_bool_float, ARRAY_SIZE(registerset_constants_struct_struct_bool_float)},
+    {"struct struct int float", "ssnf", 16, D3DXRS_FLOAT4, registerset_blob_struct_struct,
+        registerset_test_struct_struct_int_float, ARRAY_SIZE(registerset_test_struct_struct_int_float),
+        registerset_constants_struct_struct_int_float, ARRAY_SIZE(registerset_constants_struct_struct_int_float)},
+    /* special */
+    {"int ran", "ran", 0, D3DXRS_INT4, registerset_blob_special_int, NULL, 0,
+        registerset_constants_special_int, ARRAY_SIZE(registerset_constants_special_int)},
+    {"bigvec", "vaf", 0, D3DXRS_FLOAT4, registerset_blob_bigvec,
+        registerset_test_bigvec_float, ARRAY_SIZE(registerset_test_bigvec_float),
+        registerset_constants_bigvec_float, ARRAY_SIZE(registerset_constants_bigvec_float)},
+    {"cf", "cf", 0, D3DXRS_FLOAT4, registerset_blob_matrix_column_clamp,
+        registerset_test_matrix_column_clamp, ARRAY_SIZE(registerset_test_matrix_column_clamp),
+        registerset_constants_matrix_column_clamp, ARRAY_SIZE(registerset_constants_matrix_column_clamp)},
+};
+
+static void registerset_clear(IDirect3DDevice9 *device)
+{
+    DWORD zero[1024];
+    HRESULT hr;
+
+    memset(zero, 0xde, 4096);
+
+    hr = IDirect3DDevice9_SetVertexShaderConstantF(device, 0, (FLOAT*)zero, 256);
+    ok(hr == D3D_OK, "Clear failed, got %08x, expected %08x\n", hr, D3D_OK);
+
+    hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 0, (FLOAT*)zero, 224);
+    ok(hr == D3D_OK, "Clear failed, got %08x, expected %08x\n", hr, D3D_OK);
+
+    hr = IDirect3DDevice9_SetVertexShaderConstantB(device, 0, (BOOL*)zero, 16);
+    ok(hr == D3D_OK, "Clear failed, got %08x, expected %08x\n", hr, D3D_OK);
+
+    hr = IDirect3DDevice9_SetPixelShaderConstantB(device, 0, (BOOL*)zero, 16);
+    ok(hr == D3D_OK, "Clear failed, got %08x, expected %08x\n", hr, D3D_OK);
+
+    hr = IDirect3DDevice9_SetVertexShaderConstantI(device, 0, (INT*)zero, 16);
+    ok(hr == D3D_OK, "Clear failed, got %08x, expected %08x\n", hr, D3D_OK);
+
+    hr = IDirect3DDevice9_SetPixelShaderConstantI(device, 0, (INT*)zero, 16);
+    ok(hr == D3D_OK, "Clear failed, got %08x, expected %08x\n", hr, D3D_OK);
+}
+
+static UINT registerset_compare(IDirect3DDevice9 *device, BOOL is_vs, D3DXREGISTER_SET regset,
+        UINT start, UINT in_count, const DWORD *expected)
+{
+    DWORD ret[1024] = {0};
+    HRESULT hr;
+    UINT count = 1024, i, err = 0;
+
+    memset(ret, 0xde, 4096);
+
+    /* get shader constants */
+    switch (regset)
+    {
+        case D3DXRS_BOOL:
+            count = 16;
+            if (is_vs) hr = IDirect3DDevice9_GetVertexShaderConstantB(device, 0, (BOOL*)ret, 16);
+            else hr = IDirect3DDevice9_GetPixelShaderConstantB(device, 0, (BOOL*)ret, 16);
+            ok(hr == D3D_OK, "Get*ShaderConstantB failed, got %08x\n", hr);
+            break;
+
+        case D3DXRS_INT4:
+            count = 256;
+            if (is_vs) hr = IDirect3DDevice9_GetVertexShaderConstantI(device, 0, (INT*)ret, 16);
+            else hr = IDirect3DDevice9_GetPixelShaderConstantI(device, 0, (INT*)ret, 16);
+            ok(hr == D3D_OK, "Get*ShaderConstantI failed, got %08x\n", hr);
+            break;
+
+        case D3DXRS_FLOAT4:
+            if (is_vs) hr = IDirect3DDevice9_GetVertexShaderConstantF(device, 0, (FLOAT*)ret, 256);
+            else
+            {
+                count = 896;
+                hr = IDirect3DDevice9_GetPixelShaderConstantF(device, 0, (FLOAT*)ret, 224);
+            }
+            ok(hr == D3D_OK, "Get*ShaderConstantF failed, got %08x\n", hr);
+            break;
+
+        default:
+            ok(0, "This should not happen!\n");
+            break;
+    }
+
+    /* compare shader constants */
+    for (i = 0; i < count; ++i)
+    {
+        DWORD value = 0xdededede;
+        if (i >= start && i < start + in_count) value = expected[i - start];
+
+        ok(ret[i] == value, "Get*ShaderConstant failed, %u got 0x%x(%f) expected 0x%x(%f)\n", i,
+                ret[i], ((FLOAT *)ret)[i], value, *((FLOAT *)&value));
+        if (ret[i] != value) err++;
+    }
+
+    return err;
+}
+
+static UINT registerset_compare_all(IDirect3DDevice9 *device, BOOL is_vs, D3DXREGISTER_SET regset,
+        UINT start, UINT in_count, const DWORD *expected)
+{
+    D3DXREGISTER_SET regsets[] = {D3DXRS_BOOL, D3DXRS_INT4, D3DXRS_FLOAT4};
+    UINT err = 0, i;
+
+    for (i = 0; i < ARRAY_SIZE(regsets); i++)
+    {
+        if (regset == regsets[i])
+            err += registerset_compare(device, is_vs, regset, start, in_count, expected);
+        else
+            err += registerset_compare(device, is_vs, regsets[i], 0, 0, NULL);
+
+        err += registerset_compare(device, !is_vs, regsets[i], 0, 0, NULL);
+    }
+
+    return err;
+}
+
+static HRESULT registerset_apply(ID3DXConstantTable *ctable, IDirect3DDevice9 *device, D3DXHANDLE constant,
+        UINT index, DWORD count, enum Type type)
+{
+    const DWORD *in = registerset_test_input[index];
+    const D3DXMATRIX *inp[REGISTER_OUTPUT_SIZE / 16];
+    unsigned int i;
+
+    /* overlap, to see the difference between Array and PointerArray */
+    for (i = 0; i < REGISTER_OUTPUT_SIZE / 16; i++)
+    {
+        inp[i] = (D3DXMATRIX *)&in[i * 15];
+    }
+
+    switch (type)
+    {
+        case SetInt:
+            return ID3DXConstantTable_SetInt(ctable, device, constant, *((INT *)in));
+        case SetFloat:
+            return ID3DXConstantTable_SetFloat(ctable, device, constant, *((FLOAT *)in));
+        case SetBool:
+            return ID3DXConstantTable_SetBool(ctable, device, constant, *((BOOL *)in));
+        case SetIntArray:
+            return ID3DXConstantTable_SetIntArray(ctable, device, constant, (INT *)in, count);
+        case SetBoolArray:
+            return ID3DXConstantTable_SetBoolArray(ctable, device, constant, (BOOL *)in, count);
+        case SetFloatArray:
+            return ID3DXConstantTable_SetFloatArray(ctable, device, constant, (FLOAT *)in, count);
+        case SetMatrix:
+            return ID3DXConstantTable_SetMatrix(ctable, device, constant, (D3DXMATRIX *)in);
+        case SetMatrixTranspose:
+            return ID3DXConstantTable_SetMatrixTranspose(ctable, device, constant, (D3DXMATRIX *)in);
+        case SetMatrixArray:
+            return ID3DXConstantTable_SetMatrixArray(ctable, device, constant, (D3DXMATRIX *)in, count);
+        case SetMatrixTransposeArray:
+            return ID3DXConstantTable_SetMatrixTransposeArray(ctable, device, constant, (D3DXMATRIX *)in, count);
+        case SetVector:
+            return ID3DXConstantTable_SetVector(ctable, device, constant, (D3DXVECTOR4 *)in);
+        case SetVectorArray:
+            return ID3DXConstantTable_SetVectorArray(ctable, device, constant, (D3DXVECTOR4 *)in, count);
+        case SetValue:
+            return ID3DXConstantTable_SetValue(ctable, device, constant, in, count);
+        case SetMatrixPointerArray:
+            return ID3DXConstantTable_SetMatrixPointerArray(ctable, device, constant, inp, count);
+        case SetMatrixTransposePointerArray:
+            return ID3DXConstantTable_SetMatrixTransposePointerArray(ctable, device, constant, inp, count);
+    }
+
+    ok(0, "This should not happen!\n");
+    return D3D_OK;
+}
+
+static void test_registerset(void)
+{
+    UINT k;
+    HWND wnd;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *device;
+    D3DPRESENT_PARAMETERS d3dpp;
+    HRESULT hr;
+    ULONG count;
+    D3DCAPS9 caps;
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window\n");
+        return;
+    }
+    if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION)))
+    {
+        skip("Couldn't create IDirect3D9 object\n");
+        DestroyWindow(wnd);
+        return;
+    }
+
+    ZeroMemory(&d3dpp, sizeof(d3dpp));
+    d3dpp.Windowed   = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
+    if (FAILED(hr))
+    {
+        skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
+    ok(SUCCEEDED(hr), "Failed to get device caps, hr %#x.\n", hr);
+    if (caps.VertexShaderVersion < D3DVS_VERSION(3, 0)
+            || caps.PixelShaderVersion < D3DPS_VERSION(3, 0))
+    {
+        skip("Skipping: Test requires VS >= 3 and PS >= 3.\n");
+        IDirect3DDevice9_Release(device);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    for (k = 0; k < ARRAY_SIZE(registerset_data); ++k)
+    {
+        const char *tablename = registerset_data[k].name;
+        const char *name = registerset_data[k].var;
+        ID3DXConstantTable *ctable;
+        D3DXCONSTANTTABLE_DESC tdesc;
+        D3DXHANDLE constant;
+        UINT i;
+        BOOL is_vs;
+        DWORD *ctab;
+
+        hr = D3DXGetShaderConstantTable(registerset_data[k].blob, &ctable);
+        ok(hr == D3D_OK, "D3DXGetShaderConstantTable \"%s\" failed, got %08x, expected %08x\n", tablename, hr, D3D_OK);
+
+        hr = ID3DXConstantTable_GetDesc(ctable, &tdesc);
+        ok(hr == D3D_OK, "GetDesc \"%s\" failed, got %08x, expected %08x\n", tablename, hr, D3D_OK);
+
+        ctab = ID3DXConstantTable_GetBufferPointer(ctable);
+        ok(ctab[0] == registerset_data[k].blob[3], "ID3DXConstantTable_GetBufferPointer failed\n");
+
+        is_vs = (tdesc.Version & 0xFFFF0000) == 0xFFFE0000;
+
+        for (i = 0; i < registerset_data[k].constant_count; ++i)
+        {
+            const char *fullname = registerset_data[k].constants[i].fullname;
+            const D3DXCONSTANT_DESC *expected_desc = &registerset_data[k].constants[i].desc;
+            D3DXCONSTANT_DESC desc;
+            UINT nr = 0;
+            UINT ctaboffset = registerset_data[k].constants[i].ctaboffset;
+
+            constant = ID3DXConstantTable_GetConstantByName(ctable, NULL, fullname);
+            ok(constant != NULL, "GetConstantByName \"%s\" failed\n", fullname);
+
+            hr = ID3DXConstantTable_GetConstantDesc(ctable, constant, &desc, &nr);
+            ok(hr == D3D_OK, "GetConstantDesc \"%s\" failed, got %08x, expected %08x\n", fullname, hr, D3D_OK);
+
+            ok(!strcmp(expected_desc->Name, desc.Name), "GetConstantDesc \"%s\" failed, got \"%s\", expected \"%s\"\n",
+                    fullname, desc.Name, expected_desc->Name);
+            ok(expected_desc->RegisterSet == desc.RegisterSet, "GetConstantDesc \"%s\" failed, got %#x, expected %#x\n",
+                    fullname, desc.RegisterSet, expected_desc->RegisterSet);
+            ok(expected_desc->RegisterIndex == desc.RegisterIndex,
+                    "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                    fullname, desc.RegisterIndex, expected_desc->RegisterIndex);
+            ok(expected_desc->RegisterCount == desc.RegisterCount,
+                    "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                    fullname, desc.RegisterCount, expected_desc->RegisterCount);
+            ok(expected_desc->Class == desc.Class, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                    fullname, desc.Class, expected_desc->Class);
+            ok(expected_desc->Type == desc.Type, "GetConstantDesc \"%s\" failed, got %#x, expected %#x\n",
+                    fullname, desc.Type, expected_desc->Type);
+            ok(expected_desc->Rows == desc.Rows, "GetConstantDesc \"%s\" failed, got %#x, expected %#x\n",
+                    fullname, desc.Rows, expected_desc->Rows);
+            ok(expected_desc->Columns == desc.Columns, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                    fullname, desc.Columns, expected_desc->Columns);
+            ok(expected_desc->Elements == desc.Elements, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                    fullname, desc.Elements, expected_desc->Elements);
+            ok(expected_desc->StructMembers == desc.StructMembers,
+                    "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                    fullname, desc.StructMembers, expected_desc->StructMembers);
+            ok(expected_desc->Bytes == desc.Bytes, "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                    fullname, desc.Bytes, expected_desc->Bytes);
+            if (ctaboffset)
+            {
+                ok(ctaboffset == (DWORD *)desc.DefaultValue - ctab,
+                        "GetConstantDesc \"%s\" failed, got %u, expected %u\n",
+                        fullname, (UINT)((DWORD *)desc.DefaultValue - ctab), ctaboffset);
+            }
+        }
+
+        constant = ID3DXConstantTable_GetConstantByName(ctable, NULL, name);
+        ok(constant != NULL, "GetConstantByName \"%s\" \"%s\" failed\n", tablename, name);
+
+        for (i = 0; i < registerset_data[k].test_count; ++i)
+        {
+            const struct registerset_test *test = &registerset_data[k].tests[i];
+            UINT ret;
+
+            registerset_clear(device);
+
+            hr = registerset_apply(ctable, device, constant, test->in_index, test->in_count_min, test->type);
+            ok(hr == D3D_OK, "Set* \"%s\" index %u, count %u failed, got %x, expected %x\n", tablename, i,
+                    test->in_count_min, hr, D3D_OK);
+
+            ret = registerset_compare_all(device, is_vs, registerset_data[k].regset,
+                    registerset_data[k].start, test->out_count, test->out);
+            ok(ret == 0, "Get*ShaderConstant \"%s\" index %u, count %u failed\n", tablename, i, test->in_count_min);
+
+            if (test->in_count_max > test->in_count_min)
+            {
+                registerset_clear(device);
+
+                hr = registerset_apply(ctable, device, constant, test->in_index, test->in_count_max, test->type);
+                ok(hr == D3D_OK, "Set* \"%s\" index %u, count %u failed, got %x, expected %x\n", tablename, i,
+                        test->in_count_max, hr, D3D_OK);
+
+                ret = registerset_compare_all(device, is_vs, registerset_data[k].regset,
+                        registerset_data[k].start, test->out_count, test->out);
+                ok(ret == 0, "Get*ShaderConstant \"%s\" index %u, count %u failed\n", tablename, i, test->in_count_max);
+            }
+        }
+
+        count = ID3DXConstantTable_Release(ctable);
+        ok(count == 0, "Release \"%s\" failed, got %u, expected %u\n", tablename, count, 0);
+    }
+
+    /* Release resources */
+    count = IDirect3DDevice9_Release(device);
+    ok(count == 0, "The Direct3D device reference count was %u, should be 0\n", count);
+
+    count = IDirect3D9_Release(d3d);
+    ok(count == 0, "The Direct3D object referenct count was %u, should be 0\n", count);
+
+    if (wnd) DestroyWindow(wnd);
+}
+
+/*
+ * For D3DXRS_INT4 (int_count, ints[]):
+ *      Native seems to just set the following shader blob up to the register count, which in bad cases is up
+ *      to 4 times larger than the actual correct value. This explanes where the "bogus" values for these cases
+ *      come from. Somehow they forgot that the registers are INT4 and not INT.
+ */
+static const struct
+{
+    const char *name;
+    const DWORD *blob;
+    unsigned int float_count;
+    unsigned int int_count;
+    unsigned int bool_count;
+    const DWORD floats[1024];
+    const DWORD ints[256];
+    const DWORD bools[16];
+}
+registerset_defaults_data[] =
+{
+    {"scalar", registerset_blob_scalar, 12, 4, 1,
+        {0x40a33333, 0x00000000, 0x00000000, 0x00000000, 0x41300000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000},
+        {0x00000008, 0x00000000, 0x00000001},
+        {0xffffffff}},
+    {"scalar array", registerset_blob_scalar_array, 24, 8, 2,
+        {0x40466666, 0x00000000, 0x00000000, 0x00000000, 0x404ccccd, 0x00000000, 0x00000000, 0x00000000,
+        0x41600000, 0x00000000, 0x00000000, 0x00000000, 0x41700000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000},
+        {0x00000020, 0x00000000, 0x00000001, 0x00000000, 0x00000021, 0x00000000, 0x00000001, 0x00000000},
+        {0xffffffff, 0x00000000}},
+    {"vector", registerset_blob_vector, 12, 12, 3,
+        {0x40a33333, 0x40a66666, 0x40a9999a, 0x00000000, 0x41300000, 0x42aa0000, 0x42780000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000},
+        {0x00000007, 0x00000008, 0x00000009, 0x00000000, 0x00666e76, 0x41300000, 0x42aa0000, 0x42780000,
+        0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369},
+        {0xffffffff, 0x00000000, 0xffffffff}},
+    {"vector array", registerset_blob_vector_array, 24, 24, 6,
+        {0x425c6666, 0x425ccccd, 0x425d3333, 0x00000000, 0x425d999a, 0x425e0000, 0x425e6666, 0x00000000,
+        0x43020000, 0x430c0000, 0x43160000, 0x00000000, 0x43200000, 0x432a0000, 0x43340000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x3f800000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000},
+        {0x00000046, 0x00000050, 0x0000005a, 0x00000000, 0x00000064, 0x0000006e, 0x00000078, 0x00000000,
+        0x666e6176, 0xababab00, 0x00020001, 0x00030001, 0x00000002, 0x00000000, 0x43020000, 0x430c0000,
+        0x43160000, 0x00000000, 0x43200000, 0x432a0000, 0x43340000, 0x00000000, 0x335f7376, 0x4d00305f},
+        {0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff}},
+    {"column", registerset_blob_column, 24, 24, 6,
+        {0x4171999a, 0x4174cccd, 0x41780000, 0x00000000, 0x41733333, 0x41766666, 0x4179999a, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x41f00000, 0x42040000, 0x42080000, 0x00000000, 0x41f80000, 0x42000000, 0x42100000, 0x00000000},
+        {0x00000004, 0x00000006, 0x00000008, 0x00000000, 0x00000005, 0x00000007, 0x00000009, 0x00000000,
+        0x00666e63, 0x41f00000, 0x42040000, 0x42080000, 0x00000000, 0x41f80000, 0x42000000, 0x42100000,
+        0x00000000, 0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c},
+        {0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff}},
+    {"column array", registerset_blob_column_array, 48, 48, 12,
+        {0x3f8ccccd, 0x40533333, 0x40b00000, 0x00000000, 0x400ccccd, 0x408ccccd, 0x40d33333, 0x00000000,
+        0x40f66666, 0x411e6666, 0x3fa66666, 0x00000000, 0x410ccccd, 0x3f99999a, 0x3fb33333, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x3f800000, 0x00000000,
+        0x43960000, 0x43978000, 0x43980000, 0x00000000, 0x43968000, 0x43970000, 0x43990000, 0x00000000,
+        0x43af0000, 0x44238000, 0x43a30000, 0x00000000, 0x43b68000, 0x44190000, 0x4479c000, 0x00000000},
+        {0x0000000e, 0x00000010, 0x00000012, 0x00000000, 0x0000000f, 0x00000047, 0x00000013, 0x00000000,
+        0x00000037, 0x00000060, 0x00000061, 0x00000000, 0x0000003f, 0x00000060, 0x0000000d, 0x00000000,
+        0x666e6163, 0xababab00, 0x00020003, 0x00020003, 0x00000002, 0x00000000, 0x43960000, 0x43978000,
+        0x43980000, 0x00000000, 0x43968000, 0x43970000, 0x43990000, 0x00000000, 0x43af0000, 0x44238000,
+        0x43a30000, 0x00000000, 0x43b68000, 0x44190000, 0x4479c000, 0x00000000, 0x335f7376, 0x4d00305f,
+        0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970},
+        {0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+        0xffffffff, 0xffffffff, 0x00000000, 0xffffffff}},
+    {"row", registerset_blob_row, 36, 24, 6,
+        {0x42be3333, 0x42be6666, 0x00000000, 0x00000000, 0x42be999a, 0x42becccd, 0x00000000, 0x00000000,
+        0x42bf0000, 0x42bf3333, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000,
+        0x42140000, 0x41500000, 0x00000000, 0x00000000, 0x42c40000, 0x42580000, 0x00000000, 0x00000000,
+        0x429a0000, 0x42100000, 0x00000000, 0x00000000},
+        {0x00000050, 0x00000051, 0x00000001, 0x00000000, 0x00000052, 0x00000053, 0x00000001, 0x00000000,
+        0x00000054, 0x00000055, 0x00000001, 0x00000000, 0x00666e72, 0x42140000, 0x41500000, 0x00000000,
+        0x00000000, 0x42c40000, 0x42580000, 0x00000000, 0x00000000, 0x429a0000, 0x42100000, 0x00000000},
+        {0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff}},
+    {"row array", registerset_blob_row_array, 72, 48, 12,
+        {0x3fc00000, 0x40333333, 0x00000000, 0x00000000, 0x40533333, 0x409ccccd, 0x00000000, 0x00000000,
+        0x40bccccd, 0x40d9999a, 0x00000000, 0x00000000, 0x40fccccd, 0x41080000, 0x00000000, 0x00000000,
+        0x41166666, 0x3fa66666, 0x00000000, 0x00000000, 0x3f99999a, 0x3f8ccccd, 0x00000000, 0x00000000,
+        0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000,
+        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x00000000,
+        0x420c0000, 0x42200000, 0x00000000, 0x00000000, 0x42700000, 0x42a00000, 0x00000000, 0x00000000,
+        0x428c0000, 0x42600000, 0x00000000, 0x00000000, 0x42140000, 0x41500000, 0x00000000, 0x00000000,
+        0x42c40000, 0x42580000, 0x00000000, 0x00000000, 0x429a0000, 0x42100000, 0x00000000, 0x00000000},
+        {0x00000004, 0x00000005, 0x00000001, 0x00000000, 0x00000006, 0x00000001, 0x00000001, 0x00000000,
+        0x00000008, 0x00000001, 0x00000001, 0x00000000, 0x00000005, 0x00000003, 0x00000001, 0x00000000,
+        0x00000009, 0x00000006, 0x00000001, 0x00000000, 0x00000007, 0x00000003, 0x00000001, 0x00000000,
+        0x666e6172, 0xababab00, 0x00020002, 0x00020003, 0x00000002, 0x00000000, 0x420c0000, 0x42200000,
+        0x00000000, 0x00000000, 0x42700000, 0x42a00000, 0x00000000, 0x00000000, 0x428c0000, 0x42600000,
+        0x00000000, 0x00000000, 0x42140000, 0x41500000, 0x00000000, 0x00000000, 0x42c40000, 0x42580000},
+        {0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0x00000000,
+        0xffffffff, 0xffffffff, 0x00000000, 0xffffffff}},
+    {"struct", registerset_blob_struct, 24, 16, 4,
+        {0x3f8ccccd, 0x00000000, 0x00000000, 0x00000000, 0x400ccccd, 0x40533333, 0x408ccccd, 0x00000000,
+        0x41f80000, 0x00000000, 0x00000000, 0x00000000, 0x42000000, 0x42040000, 0x42080000, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000},
+        {0x0000000b, 0x00000000, 0x00000001, 0x00000000, 0x0000000c, 0x0000000d, 0x0000000e, 0x00000000,
+        0x00666e73, 0x7600666e, 0xab00666e, 0x00000204, 0x0000019c, 0x00000207, 0x000001b0, 0x00000005},
+        {0xffffffff, 0xffffffff, 0x00000000, 0xffffffff}},
+    {"struct array", registerset_blob_struct_array, 48, 32, 8,
+        {0x3f8ccccd, 0x00000000, 0x00000000, 0x00000000, 0x40066666, 0x40466666, 0x40833333, 0x00000000,
+        0x40a33333, 0x00000000, 0x00000000, 0x00000000, 0x40c33333, 0x40e33333, 0x4101999a, 0x00000000,
+        0x42240000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x422c0000, 0x42300000, 0x00000000,
+        0x42240000, 0x00000000, 0x00000000, 0x00000000, 0x42280000, 0x422c0000, 0x42300000, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x00000000},
+        {0x00000015, 0x00000000, 0x00000001, 0x00000000, 0x00000016, 0x00000017, 0x00000018, 0x00000000,
+        0x00000019, 0x00000000, 0x00000001, 0x00000000, 0x0000001a, 0x0000001b, 0x0000001c, 0x00000000,
+        0x666e6173, 0x00666e00, 0x00666e76, 0x00000275, 0x000001ec, 0x00000278, 0x00000200, 0x00000005,
+        0x00040001, 0x00020002, 0x0000027c, 0x42240000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+        {0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff}},
+    {"struct struct", registerset_blob_struct_struct, 48, 24, 6,
+        {0x3f8ccccd, 0x00000000, 0x00000000, 0x00000000, 0x40066666, 0x00000000, 0x00000000, 0x00000000,
+        0x40466666, 0x40833333, 0x40a33333, 0x00000000, 0x40c33333, 0x00000000, 0x00000000, 0x00000000,
+        0x42240000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x422c0000, 0x42300000, 0x42240000, 0x00000000, 0x42280000, 0x00000000, 0x00000000, 0x00000000,
+        0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x00000000, 0x3f800000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+        {0x00000047, 0x00000000, 0x00000001, 0x00000000, 0x00000048, 0x00000000, 0x00000001, 0x00000000,
+        0x00000049, 0x0000004a, 0x0000004b, 0x00000000, 0x0000004c, 0x00000000, 0x00000001, 0x00000000,
+        0x666e7373, 0x00666e00, 0x00666e76, 0x00000321, 0x0000026c, 0x00000324, 0x00000280, 0x00000005},
+        {0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000}},
+    {"int ran", registerset_blob_special_int, 0, 36, 0,
+        {0x00000000},
+        {0x00000004, 0x00000005, 0x00000001, 0x00000000, 0x00000006, 0x00000001, 0x00000001, 0x00000000,
+        0x00000008, 0x00000001, 0x00000001, 0x00000000, 0x00000002, 0x00000003, 0x00000001, 0x00000000,
+        0x00000004, 0x00000007, 0x00000001, 0x00000000, 0x00000009, 0x00000001, 0x00000001, 0x00000000,
+        0x335f7376, 0x4d00305f, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461,
+        0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932},
+        {0x00000000}},
+    /* DefaultValue = NULL */
+    {"big vector", registerset_blob_bigvec},
+    {"matrix column clamp", registerset_blob_matrix_column_clamp, 12, 0, 0,
+        {0x3f8ccccd, 0x40b00000, 0x411e6666, 0x3fc00000, 0x400ccccd, 0x40d33333, 0x3f99999a, 0x3fcccccd,
+        0x420551ec, 0x00000000, 0x00000000, 0x00000000},
+        {0x00000000},
+        {0x00000000}},
+};
+
+static void test_registerset_defaults(void)
+{
+    UINT k;
+    HWND wnd;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *device;
+    D3DPRESENT_PARAMETERS d3dpp;
+    HRESULT hr;
+    ULONG count;
+    D3DCAPS9 caps;
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window\n");
+        return;
+    }
+    if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION)))
+    {
+        skip("Couldn't create IDirect3D9 object\n");
+        DestroyWindow(wnd);
+        return;
+    }
+
+    ZeroMemory(&d3dpp, sizeof(d3dpp));
+    d3dpp.Windowed   = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
+    if (FAILED(hr))
+    {
+        skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
+    ok(SUCCEEDED(hr), "Failed to get device caps, hr %#x.\n", hr);
+    if (caps.VertexShaderVersion < D3DVS_VERSION(3, 0)
+            || caps.PixelShaderVersion < D3DPS_VERSION(3, 0))
+    {
+        skip("Skipping: Test requires VS >= 3 and PS >= 3.\n");
+        IDirect3DDevice9_Release(device);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    for (k = 0; k < ARRAY_SIZE(registerset_defaults_data); ++k)
+    {
+        const char *tablename = registerset_defaults_data[k].name;
+        ID3DXConstantTable *ctable;
+        D3DXCONSTANTTABLE_DESC tdesc;
+        BOOL is_vs;
+        UINT ret;
+
+        hr = D3DXGetShaderConstantTable(registerset_defaults_data[k].blob, &ctable);
+        ok(hr == D3D_OK, "D3DXGetShaderConstantTable \"%s\" failed, got %08x, expected %08x\n", tablename, hr, D3D_OK);
+
+        hr = ID3DXConstantTable_GetDesc(ctable, &tdesc);
+        ok(hr == D3D_OK, "GetDesc \"%s\" failed, got %08x, expected %08x\n", tablename, hr, D3D_OK);
+
+        is_vs = (tdesc.Version & 0xFFFF0000) == 0xFFFE0000;
+
+        registerset_clear(device);
+
+        hr = ID3DXConstantTable_SetDefaults(ctable, device);
+        ok(hr == D3D_OK, "SetDefaults \"%s\" failed, got %08x, expected %08x\n", tablename, hr, D3D_OK);
+
+        ret = registerset_compare(device, is_vs, D3DXRS_FLOAT4, 0, registerset_defaults_data[k].float_count,
+                registerset_defaults_data[k].floats);
+        ok(ret == 0, "Get*ShaderConstantF \"%s\" failed\n", tablename);
+
+        ret = registerset_compare(device, is_vs, D3DXRS_INT4, 0, registerset_defaults_data[k].int_count,
+                registerset_defaults_data[k].ints);
+        ok(ret == 0, "Get*ShaderConstantI \"%s\" failed\n", tablename);
+
+        ret = registerset_compare(device, is_vs, D3DXRS_BOOL, 0, registerset_defaults_data[k].bool_count,
+                registerset_defaults_data[k].bools);
+        ok(ret == 0, "Get*ShaderConstantB \"%s\" failed\n", tablename);
+
+        count = ID3DXConstantTable_Release(ctable);
+        ok(count == 0, "Release \"%s\" failed, got %u, expected %u\n", tablename, count, 0);
+    }
+
+    /* Release resources */
+    count = IDirect3DDevice9_Release(device);
+    ok(count == 0, "The Direct3D device reference count was %u, should be 0\n", count);
+
+    count = IDirect3D9_Release(d3d);
+    ok(count == 0, "The Direct3D object referenct count was %u, should be 0\n", count);
+
+    if (wnd) DestroyWindow(wnd);
+}
+
+static void test_shader_semantics(void)
+{
+    static const DWORD invalid_1[] =
+    {
+        0x00000200
+    },
+    invalid_2[] =
+    {
+        0xfffe0400
+    },
+    invalid_3[] =
+    {
+        0xfffe0000
+    },
+    vs_1_1[] =
+    {
+        0xfffe0101,                         /* vs_1_1 */
+        0x0000001f, 0x80000000, 0x900f0000, /* dcl_position v0 */
+        0x0000001f, 0x80000003, 0x900f0001, /* dcl_normal v1 */
+        0x0000001f, 0x8001000a, 0x900f0002, /* dcl_color1 v2 */
+        0x0000001f, 0x80000005, 0x900f0003, /* dcl_texcoord0 v3 */
+        0x00000001, 0xc00f0000, 0x90e40000, /* mov oPos, v0 */
+        0x00000001, 0xd00f0001, 0x90e40002, /* mov oD1, v2 */
+        0x00000001, 0xe0070000, 0x90e40001, /* mov oT0.xyz, v1 */
+        0x00000001, 0xc00f0001, 0x90ff0002, /* mov oFog, v2.w */
+        0x00000001, 0xc00f0002, 0x90ff0001, /* mov oPts, v1.w */
+        0x0000ffff
+    },
+    vs_2_0[] =
+    {
+        0xfffe0200,                         /* vs_2_0 */
+        0x0200001f, 0x80000000, 0x900f0000, /* dcl_position v0 */
+        0x0200001f, 0x80000003, 0x900f0001, /* dcl_normal v1 */
+        0x0200001f, 0x8001000a, 0x900f0002, /* dcl_color1 v2 */
+        0x0200001f, 0x80000005, 0x900f0003, /* dcl_texcoord0 v3 */
+        0x02000001, 0xc00f0000, 0x90e40000, /* mov oPos, v0 */
+        0x02000001, 0xd00f0001, 0x90e40002, /* mov oD1, v2 */
+        0x02000001, 0xe0070000, 0x90e40003, /* mov oT0.xyz, v3 */
+        0x02000001, 0xc00f0001, 0x90ff0002, /* mov oFog, v2.w */
+        0x02000001, 0xc00f0002, 0x90ff0001, /* mov oPts, v1.w */
+        0x0000ffff
+    },
+    vs_3_0[] =
+    {
+        0xfffe0300,                         /* vs_3_0 */
+        0x0002fffe, 0x0200000f, 0x00000000, /* comment */
+        0x0200001f, 0x80000000, 0x900f0000, /* dcl_position v0 */
+        0x0200001f, 0x80000003, 0x900f0001, /* dcl_normal v1 */
+        0x0200001f, 0x8001000a, 0x900f0002, /* dcl_color1 v2 */
+        0x0200001f, 0x80000005, 0x900f0003, /* dcl_texcoord0 v3 */
+        0x0200001f, 0x80000000, 0xe00f0000, /* dcl_position o0 */
+        0x0200001f, 0x8001000a, 0xe00f0001, /* dcl_color1 o1 */
+        0x0200001f, 0x80000005, 0xe00f0002, /* dcl_texcoord0 o2 */
+        0x0200001f, 0x8000000b, 0xe00f0003, /* dcl_fog o3 */
+        0x0200001f, 0x80000004, 0xe00f0004, /* dcl_psize o4 */
+        0x02000001, 0xe00f0000, 0x90e40000, /* mov o0, v0 */
+        0x02000001, 0xe00f0001, 0x90e40002, /* mov o1, v2 */
+        0x02000001, 0xe0070002, 0x90e40003, /* mov o2.xyz, v3 */
+        0x02000001, 0xe00f0003, 0x90ff0002, /* mov o3, v2.w */
+        0x02000001, 0xe00f0004, 0x90ff0001, /* mov o4, v1.w */
+        0x0000ffff
+    },
+    ps_1_1[] =
+    {
+        0xffff0101,                                     /* ps_1_1 */
+        0x00000042, 0xb00f0000,                         /* tex t0 */
+        0x00000002, 0x800f0000, 0x90e40000, 0xb0e40000, /* add r0, v0, t0 */
+        0x0000ffff
+    },
+    ps_2_0[] =
+    {
+        0xffff0200,                         /* ps_2_0 */
+        0x0200001f, 0x80000000, 0x900f0000, /* dcl v0 */
+        0x0200001f, 0x80000000, 0xb00f0000, /* dcl t0 */
+        0x02000001, 0x800f0800, 0x90e40000, /* mov oC0, v0 */
+        0x0000ffff
+    },
+    ps_3_0[] =
+    {
+        0xffff0300,                                                             /* ps_3_0 */
+        0x0200001f, 0x8001000a, 0x900f0000,                                     /* dcl_color1 v0 */
+        0x0200001f, 0x80000003, 0x900f0001,                                     /* dcl_normal v1 */
+        0x0200001f, 0x80000005, 0x900f0002,                                     /* dcl_texcoord0 v2 */
+        0x0200001f, 0x8000000b, 0x900f0003,                                     /* dcl_fog v3 */
+        0x0200001f, 0x80000000, 0x90031000,                                     /* dcl vPos.xy */
+        0x0200001f, 0x80000000, 0x900f1001,                                     /* dcl vFace */
+        0x05000051, 0xa00f0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 0.0, 0.0, 0.0, 0.0 */
+        0x02000001, 0x800f0000, 0x90e40000,                                     /* mov r0, v0 */
+        0x03000002, 0x800f0800, 0x80e40000, 0x90e40003,                         /* add oC0, r0, v3 */
+        0x02000001, 0x800f0001, 0x90e40001,                                     /* mov r1, v1 */
+        0x03000005, 0x800f0801, 0x80e40001, 0x90e40002,                         /* mul oC1, r1, v2 */
+        0x02000001, 0x800f0802, 0x90441000,                                     /* mov oC2, vPos.xyxy */
+        0x04000058, 0x800f0803, 0x90e41001, 0x90e40000, 0xa0e40000,             /* cmp oC3, vFace, v0, c0 */
+        0x02000001, 0x900f0800, 0x90ff0001,                                     /* mov oDepth, v1.w */
+        0x0000ffff
+    };
+    static const struct
+    {
+        const DWORD *shader;
+        D3DXSEMANTIC expected_input[MAXD3DDECLLENGTH];
+        D3DXSEMANTIC expected_output[MAXD3DDECLLENGTH];
+    }
+    tests[] =
+    {
+        {vs_1_1, {{0, 0}, {3, 0}, {10, 1}, {5, 0}, {~0, ~0}}, {{5, 0}, {10, 1}, {0, 0}, {11, 0}, {4, 0}, {~0, ~0}}},
+        {vs_2_0, {{0, 0}, {3, 0}, {10, 1}, {5, 0}, {~0, ~0}}, {{5, 0}, {10, 1}, {0, 0}, {11, 0}, {4, 0}, {~0, ~0}}},
+        {vs_3_0, {{0, 0}, {3, 0}, {10, 1}, {5, 0}, {~0, ~0}}, {{0, 0}, {10, 1}, {5, 0}, {11, 0}, {4, 0}, {~0, ~0}}},
+        {ps_1_1, {{5, 0}, {10, 0}, {~0, ~0}}, {{10, 0}, {~0, ~0}}},
+        {ps_2_0, {{10, 0}, {5, 0}, {~0, ~0}}, {{10, 0}, {~0, ~0}}},
+        {ps_3_0, {{10, 1}, {3,0}, {5, 0}, {11, 0}, {~0, ~0}}, {{10, 0}, {10, 1}, {10, 2}, {10, 3}, {12, 0}, {~0, ~0}}},
+    };
+    D3DXSEMANTIC semantics[MAXD3DDECLLENGTH];
+    unsigned int count, count2;
+    unsigned int i, j;
+    HRESULT hr;
+
+    hr = D3DXGetShaderInputSemantics(invalid_1, NULL, NULL);
+    ok(hr == D3DXERR_INVALIDDATA, "Unexpected hr %#x.\n", hr);
+    hr = D3DXGetShaderInputSemantics(invalid_2, NULL, NULL);
+    ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr);
+    hr = D3DXGetShaderInputSemantics(invalid_3, NULL, NULL);
+    ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = D3DXGetShaderInputSemantics(vs_1_1, NULL, NULL);
+    ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr);
+    hr = D3DXGetShaderInputSemantics(vs_1_1, semantics, NULL);
+    ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr);
+
+    for (i = 0; i < ARRAY_SIZE(tests); ++i)
+    {
+        const DWORD *shader = tests[i].shader;
+
+        hr = D3DXGetShaderInputSemantics(shader, NULL, &count);
+        ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr);
+        hr = D3DXGetShaderInputSemantics(shader, semantics, &count2);
+        ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr);
+        ok(count == count2, "Semantics count %u differs from previous count %u.\n", count2, count);
+        for (j = 0; j < count; ++j)
+        {
+            ok(semantics[j].Usage == tests[i].expected_input[j].Usage
+                    && semantics[j].UsageIndex == tests[i].expected_input[j].UsageIndex,
+                    "Unexpected semantic %u, %u, test %u, idx %u.\n",
+                    semantics[j].Usage, semantics[j].UsageIndex, i, j);
+        }
+        ok(tests[i].expected_input[j].Usage == ~0 && tests[i].expected_input[j].UsageIndex == ~0,
+                "Unexpected semantics count %u.\n", count);
+        hr = D3DXGetShaderOutputSemantics(shader, NULL, &count);
+        ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr);
+        hr = D3DXGetShaderOutputSemantics(shader, semantics, &count2);
+        ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr);
+        ok(count == count2, "Semantics count %u differs from previous count %u.\n", count2, count);
+        for (j = 0; j < count; ++j)
+        {
+            ok(semantics[j].Usage == tests[i].expected_output[j].Usage
+                    && semantics[j].UsageIndex == tests[i].expected_output[j].UsageIndex,
+                    "Unexpected semantic %u, %u, test %u, idx %u.\n",
+                    semantics[j].Usage, semantics[j].UsageIndex, i, j);
+        }
+        ok(tests[i].expected_output[j].Usage == ~0 && tests[i].expected_output[j].UsageIndex == ~0,
+                "Unexpected semantics count %u.\n", count);
+    }
+}
+
+START_TEST(shader)
+{
+    test_get_shader_size();
+    test_get_shader_version();
+    test_find_shader_comment();
+    test_get_shader_constant_table_ex();
+    test_constant_tables();
+    test_setting_constants();
+    test_get_sampler_index();
+    test_get_shader_samplers();
+    test_get_shader_constant_variables();
+    test_registerset();
+    test_registerset_defaults();
+    test_shader_semantics();
+}
diff --git a/modules/rostests/winetests/d3dx9_36/surface.c b/modules/rostests/winetests/d3dx9_36/surface.c
new file mode 100644 (file)
index 0000000..d345072
--- /dev/null
@@ -0,0 +1,1465 @@
+/*
+ * Tests for the D3DX9 surface functions
+ *
+ * Copyright 2009 Tony Wasserka
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include <assert.h>
+#include "wine/test.h"
+#include "d3dx9tex.h"
+#include "resources.h"
+
+#define check_release(obj, exp) _check_release(__LINE__, obj, exp)
+static inline void _check_release(unsigned int line, IUnknown *obj, int exp)
+{
+    int ref = IUnknown_Release(obj);
+    ok_(__FILE__, line)(ref == exp, "Invalid refcount. Expected %d, got %d\n", exp, ref);
+}
+
+/* 1x1 bmp (1 bpp) */
+static const unsigned char bmp_1bpp[] = {
+0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
+0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
+0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
+0x00,0x00,0x02,0x00,0x00,0x00,0xf1,0xf2,0xf3,0x80,0xf4,0xf5,0xf6,0x81,0x00,0x00,
+0x00,0x00
+};
+
+/* 1x1 bmp (2 bpp) */
+static const unsigned char bmp_2bpp[] = {
+0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
+0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,
+0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
+0x00,0x00,0x02,0x00,0x00,0x00,0xf1,0xf2,0xf3,0x80,0xf4,0xf5,0xf6,0x81,0x00,0x00,
+0x00,0x00
+};
+
+/* 1x1 bmp (4 bpp) */
+static const unsigned char bmp_4bpp[] = {
+0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
+0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,
+0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
+0x00,0x00,0x02,0x00,0x00,0x00,0xf1,0xf2,0xf3,0x80,0xf4,0xf5,0xf6,0x81,0x00,0x00,
+0x00,0x00
+};
+
+/* 1x1 bmp (8 bpp) */
+static const unsigned char bmp_8bpp[] = {
+0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
+0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x00,0x00,
+0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
+0x00,0x00,0x02,0x00,0x00,0x00,0xf1,0xf2,0xf3,0x80,0xf4,0xf5,0xf6,0x81,0x00,0x00,
+0x00,0x00
+};
+
+static const unsigned char png_grayscale[] =
+{
+    0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49,
+    0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x3a, 0x7e, 0x9b, 0x55, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44,
+    0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0x0f, 0x00, 0x01, 0x01, 0x01, 0x00, 0x1b,
+    0xb6, 0xee, 0x56, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
+    0x60, 0x82
+};
+
+/* 2x2 A8R8G8B8 pixel data */
+static const unsigned char pixdata[] = {
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+};
+
+/* invalid image file */
+static const unsigned char noimage[4] = {
+0x11,0x22,0x33,0x44
+};
+
+/* 2x2 24-bit dds, 2 mipmaps */
+static const unsigned char dds_24bit[] = {
+0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x0a,0x00,0x02,0x00,0x00,0x00,
+0x02,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0xff,0x00,
+0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+};
+
+/* 2x2 16-bit dds, no mipmaps */
+static const unsigned char dds_16bit[] = {
+0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x08,0x00,0x02,0x00,0x00,0x00,
+0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,
+0xe0,0x03,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0x7f
+};
+
+/* 4x4 cube map dds */
+static const unsigned char dds_cube_map[] = {
+0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x08,0x00,0x04,0x00,0x00,0x00,
+0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+0x04,0x00,0x00,0x00,0x44,0x58,0x54,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x00,0x00,
+0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50
+};
+
+/* 4x4x2 volume map dds, 2 mipmaps */
+static const unsigned char dds_volume_map[] = {
+0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x8a,0x00,0x04,0x00,0x00,0x00,
+0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+0x04,0x00,0x00,0x00,0x44,0x58,0x54,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00,
+0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x2f,0x7e,0xcf,0x79,0x01,0x54,0x5c,0x5c,
+0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x84,0xef,0x7b,0xaa,0xab,0xab,0xab
+};
+
+static HRESULT create_file(const char *filename, const unsigned char *data, const unsigned int size)
+{
+    DWORD received;
+    HANDLE hfile;
+
+    hfile = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+    if(hfile == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(GetLastError());
+
+    if(WriteFile(hfile, data, size, &received, NULL))
+    {
+        CloseHandle(hfile);
+        return D3D_OK;
+    }
+
+    CloseHandle(hfile);
+    return D3DERR_INVALIDCALL;
+}
+
+/* dds_header.flags */
+#define DDS_CAPS 0x00000001
+#define DDS_HEIGHT 0x00000002
+#define DDS_WIDTH 0x00000004
+#define DDS_PITCH 0x00000008
+#define DDS_PIXELFORMAT 0x00001000
+#define DDS_MIPMAPCOUNT 0x00020000
+#define DDS_LINEARSIZE 0x00080000
+
+/* dds_header.caps */
+#define DDSCAPS_ALPHA    0x00000002
+#define DDS_CAPS_TEXTURE 0x00001000
+
+/* dds_pixel_format.flags */
+#define DDS_PF_ALPHA 0x00000001
+#define DDS_PF_ALPHA_ONLY 0x00000002
+#define DDS_PF_FOURCC 0x00000004
+#define DDS_PF_RGB 0x00000040
+#define DDS_PF_LUMINANCE 0x00020000
+#define DDS_PF_BUMPDUDV 0x00080000
+
+struct dds_pixel_format
+{
+    DWORD size;
+    DWORD flags;
+    DWORD fourcc;
+    DWORD bpp;
+    DWORD rmask;
+    DWORD gmask;
+    DWORD bmask;
+    DWORD amask;
+};
+
+struct dds_header
+{
+    DWORD size;
+    DWORD flags;
+    DWORD height;
+    DWORD width;
+    DWORD pitch_or_linear_size;
+    DWORD depth;
+    DWORD miplevels;
+    DWORD reserved[11];
+    struct dds_pixel_format pixel_format;
+    DWORD caps;
+    DWORD caps2;
+    DWORD caps3;
+    DWORD caps4;
+    DWORD reserved2;
+};
+
+/* fills dds_header with reasonable default values */
+static void fill_dds_header(struct dds_header *header)
+{
+    memset(header, 0, sizeof(*header));
+
+    header->size = sizeof(*header);
+    header->flags = DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT;
+    header->height = 4;
+    header->width = 4;
+    header->pixel_format.size = sizeof(header->pixel_format);
+    /* X8R8G8B8 */
+    header->pixel_format.flags = DDS_PF_RGB;
+    header->pixel_format.fourcc = 0;
+    header->pixel_format.bpp = 32;
+    header->pixel_format.rmask = 0xff0000;
+    header->pixel_format.gmask = 0x00ff00;
+    header->pixel_format.bmask = 0x0000ff;
+    header->pixel_format.amask = 0;
+    header->caps = DDS_CAPS_TEXTURE;
+}
+
+#define check_dds_pixel_format(flags, fourcc, bpp, rmask, gmask, bmask, amask, format) \
+        check_dds_pixel_format_(__LINE__, flags, fourcc, bpp, rmask, gmask, bmask, amask, format)
+static void check_dds_pixel_format_(unsigned int line,
+                                    DWORD flags, DWORD fourcc, DWORD bpp,
+                                    DWORD rmask, DWORD gmask, DWORD bmask, DWORD amask,
+                                    D3DFORMAT expected_format)
+{
+    HRESULT hr;
+    D3DXIMAGE_INFO info;
+    struct
+    {
+        DWORD magic;
+        struct dds_header header;
+        BYTE data[256];
+    } dds;
+
+    dds.magic = MAKEFOURCC('D','D','S',' ');
+    fill_dds_header(&dds.header);
+    dds.header.pixel_format.flags = flags;
+    dds.header.pixel_format.fourcc = fourcc;
+    dds.header.pixel_format.bpp = bpp;
+    dds.header.pixel_format.rmask = rmask;
+    dds.header.pixel_format.gmask = gmask;
+    dds.header.pixel_format.bmask = bmask;
+    dds.header.pixel_format.amask = amask;
+    memset(dds.data, 0, sizeof(dds.data));
+
+    hr = D3DXGetImageInfoFromFileInMemory(&dds, sizeof(dds), &info);
+    ok_(__FILE__, line)(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x for pixel format %#x, expected %#x\n",
+            hr, expected_format, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        ok_(__FILE__, line)(info.Format == expected_format, "D3DXGetImageInfoFromFileInMemory returned format %#x, expected %#x\n",
+                info.Format, expected_format);
+    }
+}
+
+static void test_dds_header_handling(void)
+{
+    int i;
+    HRESULT hr;
+    D3DXIMAGE_INFO info;
+    struct
+    {
+        DWORD magic;
+        struct dds_header header;
+        BYTE data[4096 * 1024];
+    } *dds;
+
+    struct
+    {
+        struct dds_pixel_format pixel_format;
+        DWORD flags;
+        DWORD width;
+        DWORD height;
+        DWORD pitch;
+        DWORD miplevels;
+        DWORD pixel_data_size;
+        struct
+        {
+            HRESULT hr;
+            UINT miplevels;
+        }
+        expected;
+    } tests[] = {
+        /* pitch is ignored */
+        { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, 0, 4, 4, 0, 0,
+          63 /* pixel data size */, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, DDS_PITCH, 4, 4, 0 /* pitch */, 0,
+          64, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, DDS_PITCH, 4, 4, 1 /* pitch */, 0,
+          64, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, DDS_PITCH, 4, 4, 2 /* pitch */, 0,
+          64, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, DDS_PITCH, 4, 4, 3 /* pitch */, 0,
+          64, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, DDS_PITCH, 4, 4, 4 /* pitch */, 0,
+          64, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, DDS_PITCH, 4, 4, 16 /* pitch */, 0,
+          64, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, DDS_PITCH, 4, 4, 1024 /* pitch */, 0,
+          64, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, DDS_PITCH, 4, 4, -1 /* pitch */, 0,
+          64, { D3D_OK, 1 } },
+        /* linear size is ignored */
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, 0, 4, 4, 0, 0,
+          7 /* pixel data size */, { D3DXERR_INVALIDDATA, 1 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_LINEARSIZE, 4, 4, 0 /* linear size */, 0,
+          8, { D3D_OK, 1 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_LINEARSIZE, 4, 4, 1 /* linear size */, 0,
+          8, { D3D_OK, 1 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_LINEARSIZE, 4, 4, 2 /* linear size */, 0,
+          8, { D3D_OK, 1 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_LINEARSIZE, 4, 4, 9 /* linear size */, 0,
+          8, { D3D_OK, 1 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_LINEARSIZE, 4, 4, 16 /* linear size */, 0,
+          8, { D3D_OK, 1 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_LINEARSIZE, 4, 4, -1 /* linear size */, 0,
+          8, { D3D_OK, 1 } },
+        /* integer overflows */
+        { { 32, DDS_PF_RGB, 0, 32, 0xff0000, 0x00ff00, 0x0000ff, 0 }, 0, 0x80000000, 0x80000000 /* 0x80000000 * 0x80000000 * 4 = 0 */, 0, 0,
+          64, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB, 0, 32, 0xff0000, 0x00ff00, 0x0000ff, 0 }, 0, 0x8000100, 0x800100 /* 0x8000100 * 0x800100 * 4 = 262144 */, 0, 0,
+          64, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB, 0, 32, 0xff0000, 0x00ff00, 0x0000ff, 0 }, 0, 0x80000001, 0x80000001 /* 0x80000001 * 0x80000001 * 4 = 4 */, 0, 0,
+          4, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB, 0, 32, 0xff0000, 0x00ff00, 0x0000ff, 0 }, 0, 0x80000001, 0x80000001 /* 0x80000001 * 0x80000001 * 4 = 4 */, 0, 0,
+          3 /* pixel data size */, { D3DXERR_INVALIDDATA, 0 } },
+        /* file size is validated */
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, 0, 256, 64, 0, 0, 49151, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, 0, 256, 64, 0, 0, 49152, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 64, 0, 4, 65279, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 64, 0, 4, 65280, { D3D_OK, 4 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 64, 0, 9, 65540, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 64, 0, 9, 65541, { D3D_OK, 9 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, 0, 256, 256, 0, 0, 196607, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, 0, 256, 256, 0, 0, 196608, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, 0, 256, 256, 0, 0, 196609, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 1, 196607, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 1, 196608, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 0, 196607, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 0, 196608, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 0, 400000, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 9, 262142, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 9, 262143, { D3D_OK, 9 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 10, 262145, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 10, 262146, { D3D_OK, 10 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 20, 262175, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, DDS_MIPMAPCOUNT, 256, 256, 0, 20, 262176, { D3D_OK, 20 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, 0, 256, 256, 0, 0, 32767, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, 0, 256, 256, 0, 0, 32768, { D3D_OK, 1 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 0, 32767, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 0, 32768, { D3D_OK, 1 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 9, 43703, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 9, 43704, { D3D_OK, 9 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 20, 43791, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 20, 43792, { D3D_OK, 20 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 }, 0, 256, 256, 0, 0, 65535, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 }, 0, 256, 256, 0, 0, 65536, { D3D_OK, 1 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 0, 65535, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 0, 65536, { D3D_OK, 1 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 9, 87407, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 9, 87408, { D3D_OK, 9 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 20, 87583, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 256, 0, 20, 87584, { D3D_OK, 20 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 64, 0, 4, 21759, { D3DXERR_INVALIDDATA, 0 } },
+        { { 32, DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 }, DDS_MIPMAPCOUNT, 256, 64, 0, 4, 21760, { D3D_OK, 4 } },
+        /* DDS_MIPMAPCOUNT is ignored */
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, 0, 256, 256, 0, 0, 262146, { D3D_OK, 1 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, 0, 256, 256, 0, 2, 262146, { D3D_OK, 2 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, 0, 256, 256, 0, 9, 262146, { D3D_OK, 9 } },
+        { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, 0, 256, 256, 0, 10, 262146, { D3D_OK, 10 } },
+    };
+
+    dds = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dds));
+    if (!dds)
+    {
+        skip("Failed to allocate memory.\n");
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(tests); i++)
+    {
+        DWORD file_size = sizeof(dds->magic) + sizeof(dds->header) + tests[i].pixel_data_size;
+        assert(file_size <= sizeof(*dds));
+
+        dds->magic = MAKEFOURCC('D','D','S',' ');
+        fill_dds_header(&dds->header);
+        dds->header.flags |= tests[i].flags;
+        dds->header.width = tests[i].width;
+        dds->header.height = tests[i].height;
+        dds->header.pitch_or_linear_size = tests[i].pitch;
+        dds->header.miplevels = tests[i].miplevels;
+        dds->header.pixel_format = tests[i].pixel_format;
+
+        hr = D3DXGetImageInfoFromFileInMemory(dds, file_size, &info);
+        ok(hr == tests[i].expected.hr, "%d: D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n",
+                i, hr, tests[i].expected.hr);
+        if (SUCCEEDED(hr))
+        {
+            ok(info.MipLevels == tests[i].expected.miplevels, "%d: Got MipLevels %u, expected %u\n",
+                    i, info.MipLevels, tests[i].expected.miplevels);
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, dds);
+}
+
+static void test_D3DXGetImageInfo(void)
+{
+    HRESULT hr;
+    D3DXIMAGE_INFO info;
+    BOOL testdummy_ok, testbitmap_ok;
+
+    hr = create_file("testdummy.bmp", noimage, sizeof(noimage));  /* invalid image */
+    testdummy_ok = SUCCEEDED(hr);
+
+    hr = create_file("testbitmap.bmp", bmp_1bpp, sizeof(bmp_1bpp));  /* valid image */
+    testbitmap_ok = SUCCEEDED(hr);
+
+    /* D3DXGetImageInfoFromFile */
+    if(testbitmap_ok) {
+        hr = D3DXGetImageInfoFromFileA("testbitmap.bmp", &info);
+        ok(hr == D3D_OK, "D3DXGetImageInfoFromFile returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXGetImageInfoFromFileA("testbitmap.bmp", NULL); /* valid image, second parameter is NULL */
+        ok(hr == D3D_OK, "D3DXGetImageInfoFromFile returned %#x, expected %#x\n", hr, D3D_OK);
+    } else skip("Couldn't create \"testbitmap.bmp\"\n");
+
+    if(testdummy_ok) {
+        hr = D3DXGetImageInfoFromFileA("testdummy.bmp", NULL); /* invalid image, second parameter is NULL */
+        ok(hr == D3D_OK, "D3DXGetImageInfoFromFile returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXGetImageInfoFromFileA("testdummy.bmp", &info);
+        ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFile returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+    } else skip("Couldn't create \"testdummy.bmp\"\n");
+
+    hr = D3DXGetImageInfoFromFileA("filedoesnotexist.bmp", &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFile returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromFileA("filedoesnotexist.bmp", NULL);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFile returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromFileA("", &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFile returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromFileA(NULL, &info);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXGetImageInfoFromFile returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXGetImageInfoFromFileA(NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXGetImageInfoFromFile returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+
+    /* D3DXGetImageInfoFromResource */
+    hr = D3DXGetImageInfoFromResourceA(NULL, MAKEINTRESOURCEA(IDB_BITMAP_1x1), &info); /* RT_BITMAP */
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromResource returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXGetImageInfoFromResourceA(NULL, MAKEINTRESOURCEA(IDB_BITMAP_1x1), NULL);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromResource returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXGetImageInfoFromResourceA(NULL, MAKEINTRESOURCEA(IDD_BITMAPDATA_1x1), &info); /* RT_RCDATA */
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromResource returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXGetImageInfoFromResourceA(NULL, MAKEINTRESOURCEA(IDS_STRING), &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromResource returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromResourceA(NULL, MAKEINTRESOURCEA(IDS_STRING), NULL);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromResource returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromResourceA(NULL, "resourcedoesnotexist", &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromResource returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromResourceA(NULL, "resourcedoesnotexist", NULL);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromResource returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromResourceA(NULL, NULL, NULL);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromResource returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+
+    /* D3DXGetImageInfoFromFileInMemory */
+    hr = D3DXGetImageInfoFromFileInMemory(bmp_1bpp, sizeof(bmp_1bpp), &info);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXGetImageInfoFromFileInMemory(bmp_1bpp, sizeof(bmp_1bpp)+5, &info); /* too large size */
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXGetImageInfoFromFileInMemory(bmp_1bpp, sizeof(bmp_1bpp), NULL);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXGetImageInfoFromFileInMemory(noimage, sizeof(noimage), NULL);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromResource returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXGetImageInfoFromFileInMemory(noimage, sizeof(noimage), &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    todo_wine {
+        hr = D3DXGetImageInfoFromFileInMemory(bmp_1bpp, sizeof(bmp_1bpp)-1, &info);
+        ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+    }
+
+    hr = D3DXGetImageInfoFromFileInMemory(bmp_1bpp+1, sizeof(bmp_1bpp)-1, &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromFileInMemory(bmp_1bpp, 0, &info);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXGetImageInfoFromFileInMemory(bmp_1bpp, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXGetImageInfoFromFileInMemory(noimage, 0, &info);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXGetImageInfoFromFileInMemory(noimage, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXGetImageInfoFromFileInMemory(NULL, 0, &info);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXGetImageInfoFromFileInMemory(NULL, 4, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXGetImageInfoFromFileInMemory(NULL, 4, &info);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXGetImageInfoFromFileInMemory(NULL, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    /* test BMP support */
+    hr = D3DXGetImageInfoFromFileInMemory(bmp_1bpp, sizeof(bmp_1bpp), &info);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(info.Depth == 1, "Got depth %u, expected 1\n", info.Depth);
+    ok(info.Format == D3DFMT_P8, "Got format %u, expected %u\n", info.Format, D3DFMT_P8);
+    hr = D3DXGetImageInfoFromFileInMemory(bmp_2bpp, sizeof(bmp_2bpp), &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+    hr = D3DXGetImageInfoFromFileInMemory(bmp_4bpp, sizeof(bmp_4bpp), &info);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(info.Depth == 1, "Got depth %u, expected 1\n", info.Depth);
+    ok(info.Format == D3DFMT_P8, "Got format %u, expected %u\n", info.Format, D3DFMT_P8);
+    hr = D3DXGetImageInfoFromFileInMemory(bmp_8bpp, sizeof(bmp_8bpp), &info);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(info.Depth == 1, "Got depth %u, expected 1\n", info.Depth);
+    ok(info.Format == D3DFMT_P8, "Got format %u, expected %u\n", info.Format, D3DFMT_P8);
+
+    /* Grayscale PNG */
+    hr = D3DXGetImageInfoFromFileInMemory(png_grayscale, sizeof(png_grayscale), &info);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(info.Depth == 1, "Got depth %u, expected 1\n", info.Depth);
+    ok(info.Format == D3DFMT_L8, "Got format %u, expected %u\n", info.Format, D3DFMT_L8);
+
+    /* test DDS support */
+    hr = D3DXGetImageInfoFromFileInMemory(dds_24bit, sizeof(dds_24bit), &info);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (hr == D3D_OK) {
+        ok(info.Width == 2, "Got width %u, expected 2\n", info.Width);
+        ok(info.Height == 2, "Got height %u, expected 2\n", info.Height);
+        ok(info.Depth == 1, "Got depth %u, expected 1\n", info.Depth);
+        ok(info.MipLevels == 2, "Got miplevels %u, expected 2\n", info.MipLevels);
+        ok(info.Format == D3DFMT_R8G8B8, "Got format %#x, expected %#x\n", info.Format, D3DFMT_R8G8B8);
+        ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE);
+        ok(info.ImageFileFormat == D3DXIFF_DDS, "Got image file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS);
+    } else skip("Couldn't get image info from 24-bit DDS file in memory\n");
+
+    hr = D3DXGetImageInfoFromFileInMemory(dds_16bit, sizeof(dds_16bit), &info);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (hr == D3D_OK) {
+        ok(info.Width == 2, "Got width %u, expected 2\n", info.Width);
+        ok(info.Height == 2, "Got height %u, expected 2\n", info.Height);
+        ok(info.Depth == 1, "Got depth %u, expected 1\n", info.Depth);
+        ok(info.MipLevels == 1, "Got miplevels %u, expected 1\n", info.MipLevels);
+        ok(info.Format == D3DFMT_X1R5G5B5, "Got format %#x, expected %#x\n", info.Format, D3DFMT_X1R5G5B5);
+        ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE);
+        ok(info.ImageFileFormat == D3DXIFF_DDS, "Got image file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS);
+    } else skip("Couldn't get image info from 16-bit DDS file in memory\n");
+
+    hr = D3DXGetImageInfoFromFileInMemory(dds_cube_map, sizeof(dds_cube_map), &info);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (hr == D3D_OK) {
+        ok(info.Width == 4, "Got width %u, expected 4\n", info.Width);
+        ok(info.Height == 4, "Got height %u, expected 4\n", info.Height);
+        ok(info.Depth == 1, "Got depth %u, expected 1\n", info.Depth);
+        ok(info.MipLevels == 1, "Got miplevels %u, expected 1\n", info.MipLevels);
+        ok(info.Format == D3DFMT_DXT5, "Got format %#x, expected %#x\n", info.Format, D3DFMT_DXT5);
+        ok(info.ResourceType == D3DRTYPE_CUBETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_CUBETEXTURE);
+        ok(info.ImageFileFormat == D3DXIFF_DDS, "Got image file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS);
+    } else skip("Couldn't get image info from cube map in memory\n");
+
+    hr = D3DXGetImageInfoFromFileInMemory(dds_volume_map, sizeof(dds_volume_map), &info);
+    ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (hr == D3D_OK) {
+        ok(info.Width == 4, "Got width %u, expected 4\n", info.Width);
+        ok(info.Height == 4, "Got height %u, expected 4\n", info.Height);
+        ok(info.Depth == 2, "Got depth %u, expected 2\n", info.Depth);
+        ok(info.MipLevels == 3, "Got miplevels %u, expected 3\n", info.MipLevels);
+        ok(info.Format == D3DFMT_DXT3, "Got format %#x, expected %#x\n", info.Format, D3DFMT_DXT3);
+        ok(info.ResourceType == D3DRTYPE_VOLUMETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_VOLUMETEXTURE);
+        ok(info.ImageFileFormat == D3DXIFF_DDS, "Got image file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS);
+    } else skip("Couldn't get image info from volume map in memory\n");
+
+    check_dds_pixel_format(DDS_PF_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0, D3DFMT_DXT1);
+    check_dds_pixel_format(DDS_PF_FOURCC, D3DFMT_DXT2, 0, 0, 0, 0, 0, D3DFMT_DXT2);
+    check_dds_pixel_format(DDS_PF_FOURCC, D3DFMT_DXT3, 0, 0, 0, 0, 0, D3DFMT_DXT3);
+    check_dds_pixel_format(DDS_PF_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0, D3DFMT_DXT4);
+    check_dds_pixel_format(DDS_PF_FOURCC, D3DFMT_DXT5, 0, 0, 0, 0, 0, D3DFMT_DXT5);
+    check_dds_pixel_format(DDS_PF_FOURCC, D3DFMT_R8G8_B8G8, 0, 0, 0, 0, 0, D3DFMT_R8G8_B8G8);
+    check_dds_pixel_format(DDS_PF_FOURCC, D3DFMT_G8R8_G8B8, 0, 0, 0, 0, 0, D3DFMT_G8R8_G8B8);
+    check_dds_pixel_format(DDS_PF_FOURCC, D3DFMT_UYVY, 0, 0, 0, 0, 0, D3DFMT_UYVY);
+    check_dds_pixel_format(DDS_PF_FOURCC, D3DFMT_YUY2, 0, 0, 0, 0, 0, D3DFMT_YUY2);
+    check_dds_pixel_format(DDS_PF_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0, D3DFMT_R5G6B5);
+    check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000, D3DFMT_A1R5G5B5);
+    check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000, D3DFMT_A4R4G4B4);
+    check_dds_pixel_format(DDS_PF_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0, D3DFMT_R3G3B2);
+    check_dds_pixel_format(DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff, D3DFMT_A8);
+    check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00, D3DFMT_A8R3G3B2);
+    check_dds_pixel_format(DDS_PF_RGB, 0, 16, 0xf00, 0x0f0, 0x00f, 0, D3DFMT_X4R4G4B4);
+    check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000, D3DFMT_A2B10G10R10);
+    check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000, D3DFMT_A2R10G10B10);
+    check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, D3DFMT_A8R8G8B8);
+    check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, D3DFMT_A8B8G8R8);
+    check_dds_pixel_format(DDS_PF_RGB, 0, 32, 0xff0000, 0x00ff00, 0x0000ff, 0, D3DFMT_X8R8G8B8);
+    check_dds_pixel_format(DDS_PF_RGB, 0, 32, 0x0000ff, 0x00ff00, 0xff0000, 0, D3DFMT_X8B8G8R8);
+    check_dds_pixel_format(DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0, D3DFMT_R8G8B8);
+    check_dds_pixel_format(DDS_PF_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0, 0, D3DFMT_G16R16);
+    check_dds_pixel_format(DDS_PF_LUMINANCE, 0, 8, 0xff, 0, 0, 0, D3DFMT_L8);
+    check_dds_pixel_format(DDS_PF_LUMINANCE, 0, 16, 0xffff, 0, 0, 0, D3DFMT_L16);
+    check_dds_pixel_format(DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 16, 0x00ff, 0, 0, 0xff00, D3DFMT_A8L8);
+    check_dds_pixel_format(DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x0f, 0, 0, 0xf0, D3DFMT_A4L4);
+    check_dds_pixel_format(DDS_PF_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0, 0, D3DFMT_V8U8);
+    check_dds_pixel_format(DDS_PF_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0, 0, D3DFMT_V16U16);
+
+    test_dds_header_handling();
+
+    hr = D3DXGetImageInfoFromFileInMemory(dds_16bit, sizeof(dds_16bit) - 1, &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromFileInMemory(dds_24bit, sizeof(dds_24bit) - 1, &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromFileInMemory(dds_cube_map, sizeof(dds_cube_map) - 1, &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXGetImageInfoFromFileInMemory(dds_volume_map, sizeof(dds_volume_map) - 1, &info);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+
+    /* cleanup */
+    if(testdummy_ok) DeleteFileA("testdummy.bmp");
+    if(testbitmap_ok) DeleteFileA("testbitmap.bmp");
+}
+
+#define check_pixel_2bpp(lockrect, x, y, color) _check_pixel_2bpp(__LINE__, lockrect, x, y, color)
+static inline void _check_pixel_2bpp(unsigned int line, const D3DLOCKED_RECT *lockrect, int x, int y, WORD expected_color)
+{
+    WORD color = ((WORD*)lockrect->pBits)[x + y * lockrect->Pitch / 2];
+    ok_(__FILE__, line)(color == expected_color, "Got color 0x%04x, expected 0x%04x\n", color, expected_color);
+}
+
+#define check_pixel_4bpp(lockrect, x, y, color) _check_pixel_4bpp(__LINE__, lockrect, x, y, color)
+static inline void _check_pixel_4bpp(unsigned int line, const D3DLOCKED_RECT *lockrect, int x, int y, DWORD expected_color)
+{
+   DWORD color = ((DWORD*)lockrect->pBits)[x + y * lockrect->Pitch / 4];
+   ok_(__FILE__, line)(color == expected_color, "Got color 0x%08x, expected 0x%08x\n", color, expected_color);
+}
+
+static void test_D3DXLoadSurface(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    BOOL testdummy_ok, testbitmap_ok;
+    IDirect3DTexture9 *tex;
+    IDirect3DSurface9 *surf, *newsurf;
+    RECT rect, destrect;
+    D3DLOCKED_RECT lockrect;
+    const WORD pixdata_a8r3g3b2[] = { 0x57df, 0x98fc, 0xacdd, 0xc891 };
+    const WORD pixdata_a1r5g5b5[] = { 0x46b5, 0x99c8, 0x06a2, 0x9431 };
+    const WORD pixdata_r5g6b5[] = { 0x9ef6, 0x658d, 0x0aee, 0x42ee };
+    const WORD pixdata_a8l8[] = { 0xff00, 0x00ff, 0xff30, 0x7f7f };
+    const DWORD pixdata_g16r16[] = { 0x07d23fbe, 0xdc7f44a4, 0xe4d8976b, 0x9a84fe89 };
+    const DWORD pixdata_a8b8g8r8[] = { 0xc3394cf0, 0x235ae892, 0x09b197fd, 0x8dc32bf6 };
+    const DWORD pixdata_a2r10g10b10[] = { 0x57395aff, 0x5b7668fd, 0xb0d856b5, 0xff2c61d6 };
+
+    hr = create_file("testdummy.bmp", noimage, sizeof(noimage));  /* invalid image */
+    testdummy_ok = SUCCEEDED(hr);
+
+    hr = create_file("testbitmap.bmp", bmp_1bpp, sizeof(bmp_1bpp));  /* valid image */
+    testbitmap_ok = SUCCEEDED(hr);
+
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 256, 256, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &surf, NULL);
+    if(FAILED(hr)) {
+        skip("Failed to create a surface (%#x)\n", hr);
+        if(testdummy_ok) DeleteFileA("testdummy.bmp");
+        if(testbitmap_ok) DeleteFileA("testbitmap.bmp");
+        return;
+    }
+
+    /* D3DXLoadSurfaceFromFile */
+    if(testbitmap_ok) {
+        hr = D3DXLoadSurfaceFromFileA(surf, NULL, NULL, "testbitmap.bmp", NULL, D3DX_DEFAULT, 0, NULL);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromFile returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXLoadSurfaceFromFileA(NULL, NULL, NULL, "testbitmap.bmp", NULL, D3DX_DEFAULT, 0, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromFile returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    } else skip("Couldn't create \"testbitmap.bmp\"\n");
+
+    if(testdummy_ok) {
+        hr = D3DXLoadSurfaceFromFileA(surf, NULL, NULL, "testdummy.bmp", NULL, D3DX_DEFAULT, 0, NULL);
+        ok(hr == D3DXERR_INVALIDDATA, "D3DXLoadSurfaceFromFile returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+    } else skip("Couldn't create \"testdummy.bmp\"\n");
+
+    hr = D3DXLoadSurfaceFromFileA(surf, NULL, NULL, NULL, NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromFile returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadSurfaceFromFileA(surf, NULL, NULL, "", NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXLoadSurfaceFromFile returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+
+    /* D3DXLoadSurfaceFromResource */
+    hr = D3DXLoadSurfaceFromResourceA(surf, NULL, NULL, NULL,
+            MAKEINTRESOURCEA(IDB_BITMAP_1x1), NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3D_OK, "D3DXLoadSurfaceFromResource returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXLoadSurfaceFromResourceA(surf, NULL, NULL, NULL,
+            MAKEINTRESOURCEA(IDD_BITMAPDATA_1x1), NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3D_OK, "D3DXLoadSurfaceFromResource returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXLoadSurfaceFromResourceA(surf, NULL, NULL, NULL, NULL, NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXLoadSurfaceFromResource returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXLoadSurfaceFromResourceA(NULL, NULL, NULL, NULL,
+            MAKEINTRESOURCEA(IDB_BITMAP_1x1), NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromResource returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadSurfaceFromResourceA(surf, NULL, NULL, NULL,
+            MAKEINTRESOURCEA(IDS_STRING), NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXLoadSurfaceFromResource returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+
+    /* D3DXLoadSurfaceFromFileInMemory */
+    hr = D3DXLoadSurfaceFromFileInMemory(surf, NULL, NULL, bmp_1bpp, sizeof(bmp_1bpp), NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3D_OK, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXLoadSurfaceFromFileInMemory(surf, NULL, NULL, noimage, sizeof(noimage), NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXLoadSurfaceFromFileInMemory(surf, NULL, NULL, bmp_1bpp, 0, NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadSurfaceFromFileInMemory(NULL, NULL, NULL, bmp_1bpp, sizeof(bmp_1bpp), NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadSurfaceFromFileInMemory(surf, NULL, NULL, NULL, 8, NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadSurfaceFromFileInMemory(surf, NULL, NULL, NULL, 0, NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadSurfaceFromFileInMemory(NULL, NULL, NULL, NULL, 0, NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+
+    /* D3DXLoadSurfaceFromMemory */
+    SetRect(&rect, 0, 0, 2, 2);
+
+    hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata, D3DFMT_A8R8G8B8, sizeof(pixdata), NULL, &rect, D3DX_FILTER_NONE, 0);
+    ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata, D3DFMT_A8R8G8B8, 0, NULL, &rect, D3DX_FILTER_NONE, 0);
+    ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, NULL, D3DFMT_A8R8G8B8, sizeof(pixdata), NULL, &rect, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadSurfaceFromMemory(NULL, NULL, NULL, pixdata, D3DFMT_A8R8G8B8, sizeof(pixdata), NULL, &rect, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata, D3DFMT_A8R8G8B8, sizeof(pixdata), NULL, NULL, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata, D3DFMT_UNKNOWN, sizeof(pixdata), NULL, &rect, D3DX_DEFAULT, 0);
+    ok(hr == E_FAIL, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, E_FAIL);
+
+    SetRect(&destrect, -1, -1, 1, 1); /* destination rect is partially outside texture boundaries */
+    hr = D3DXLoadSurfaceFromMemory(surf, NULL, &destrect, pixdata, D3DFMT_A8R8G8B8, sizeof(pixdata), NULL, &rect, D3DX_FILTER_NONE, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    SetRect(&destrect, 255, 255, 257, 257); /* destination rect is partially outside texture boundaries */
+    hr = D3DXLoadSurfaceFromMemory(surf, NULL, &destrect, pixdata, D3DFMT_A8R8G8B8, sizeof(pixdata), NULL, &rect, D3DX_FILTER_NONE, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    SetRect(&destrect, 1, 1, 0, 0); /* left > right, top > bottom */
+    hr = D3DXLoadSurfaceFromMemory(surf, NULL, &destrect, pixdata, D3DFMT_A8R8G8B8, sizeof(pixdata), NULL, &rect, D3DX_FILTER_NONE, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    SetRect(&destrect, 1, 2, 1, 2); /* left = right, top = bottom */
+    hr = D3DXLoadSurfaceFromMemory(surf, NULL, &destrect, pixdata, D3DFMT_A8R8G8B8, sizeof(pixdata), NULL, &rect, D3DX_FILTER_NONE, 0);
+    /* fails when debug version of d3d9 is used */
+    ok(hr == D3D_OK || broken(hr == D3DERR_INVALIDCALL), "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    SetRect(&destrect, 257, 257, 257, 257); /* left = right, top = bottom, but invalid values */
+    hr = D3DXLoadSurfaceFromMemory(surf, NULL, &destrect, pixdata, D3DFMT_A8R8G8B8, sizeof(pixdata), NULL, &rect, D3DX_FILTER_NONE, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+
+    /* D3DXLoadSurfaceFromSurface */
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 256, 256, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &newsurf, NULL);
+    if(SUCCEEDED(hr)) {
+        hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_DEFAULT, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXLoadSurfaceFromSurface(NULL, NULL, NULL, surf, NULL, NULL, D3DX_DEFAULT, 0);
+        ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, NULL, NULL, NULL, D3DX_DEFAULT, 0);
+        ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        check_release((IUnknown*)newsurf, 0);
+    } else skip("Failed to create a second surface\n");
+
+    hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tex, NULL);
+    if (SUCCEEDED(hr))
+    {
+        IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf);
+
+        hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_DEFAULT, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x\n", hr, D3D_OK);
+
+        IDirect3DSurface9_Release(newsurf);
+        IDirect3DTexture9_Release(tex);
+    } else skip("Failed to create texture\n");
+
+    /* non-lockable render target */
+    hr = IDirect3DDevice9_CreateRenderTarget(device, 256, 256, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &newsurf, NULL);
+    if (SUCCEEDED(hr)) {
+        hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, NULL, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x\n", hr, D3D_OK);
+
+        IDirect3DSurface9_Release(newsurf);
+    } else skip("Failed to create render target surface\n");
+
+    /* non-lockable multisampled render target */
+    hr = IDirect3DDevice9_CreateRenderTarget(device, 256, 256, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_2_SAMPLES, 0, FALSE, &newsurf, NULL);
+    if (SUCCEEDED(hr)) {
+       hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, NULL, D3DX_FILTER_NONE, 0);
+       ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x\n", hr, D3D_OK);
+
+       IDirect3DSurface9_Release(newsurf);
+    } else skip("Failed to create multisampled render target.\n");
+
+    hr = IDirect3DDevice9_GetRenderTarget(device, 0, &newsurf);
+    ok(hr == D3D_OK, "IDirect3DDevice9_GetRenderTarget returned %#x, expected %#x.\n", hr, D3D_OK);
+
+    hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0);
+    ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3D_OK);
+    hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, NULL, D3DX_FILTER_NONE, 0);
+    ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3D_OK);
+    hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, NULL, D3DX_FILTER_NONE, 0xff000000);
+    ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3D_OK);
+    hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, NULL, D3DX_FILTER_TRIANGLE | D3DX_FILTER_MIRROR, 0);
+    ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3D_OK);
+    hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, NULL, D3DX_FILTER_LINEAR, 0);
+    ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3D_OK);
+
+    IDirect3DSurface9_Release(newsurf);
+
+    check_release((IUnknown*)surf, 0);
+
+
+    /* test color conversion */
+    /* A8R8G8B8 */
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 2, 2, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &surf, NULL);
+    if(FAILED(hr)) skip("Failed to create a surface (%#x)\n", hr);
+    else {
+        PALETTEENTRY palette;
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8r3g3b2, D3DFMT_A8R3G3B2, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        check_pixel_4bpp(&lockrect, 0, 0, 0x57dbffff);
+        check_pixel_4bpp(&lockrect, 1, 0, 0x98ffff00);
+        check_pixel_4bpp(&lockrect, 0, 1, 0xacdbff55);
+        check_pixel_4bpp(&lockrect, 1, 1, 0xc8929255);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a1r5g5b5, D3DFMT_A1R5G5B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        check_pixel_4bpp(&lockrect, 0, 0, 0x008cadad);
+        check_pixel_4bpp(&lockrect, 1, 0, 0xff317342);
+        check_pixel_4bpp(&lockrect, 0, 1, 0x0008ad10);
+        check_pixel_4bpp(&lockrect, 1, 1, 0xff29088c);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_r5g6b5, D3DFMT_R5G6B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        check_pixel_4bpp(&lockrect, 0, 0, 0xff9cdfb5);
+        check_pixel_4bpp(&lockrect, 1, 0, 0xff63b26b);
+        check_pixel_4bpp(&lockrect, 0, 1, 0xff085d73);
+        check_pixel_4bpp(&lockrect, 1, 1, 0xff425d73);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_g16r16, D3DFMT_G16R16, 8, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        todo_wine {
+            check_pixel_4bpp(&lockrect, 0, 0, 0xff3f08ff);
+        }
+        check_pixel_4bpp(&lockrect, 1, 0, 0xff44dcff);
+        check_pixel_4bpp(&lockrect, 0, 1, 0xff97e4ff);
+        check_pixel_4bpp(&lockrect, 1, 1, 0xfffe9aff);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8, D3DFMT_A8B8G8R8, 8, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        check_pixel_4bpp(&lockrect, 0, 0, 0xc3f04c39);
+        check_pixel_4bpp(&lockrect, 1, 0, 0x2392e85a);
+        check_pixel_4bpp(&lockrect, 0, 1, 0x09fd97b1);
+        check_pixel_4bpp(&lockrect, 1, 1, 0x8df62bc3);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a2r10g10b10, D3DFMT_A2R10G10B10, 8, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        check_pixel_4bpp(&lockrect, 0, 0, 0x555c95bf);
+        check_pixel_4bpp(&lockrect, 1, 0, 0x556d663f);
+        check_pixel_4bpp(&lockrect, 0, 1, 0xaac385ad);
+        todo_wine {
+            check_pixel_4bpp(&lockrect, 1, 1, 0xfffcc575);
+        }
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8l8,
+                D3DFMT_A8L8, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(SUCCEEDED(hr), "Failed to load surface, hr %#x.\n", hr);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        check_pixel_4bpp(&lockrect, 0, 0, 0xff000000);
+        check_pixel_4bpp(&lockrect, 1, 0, 0x00ffffff);
+        check_pixel_4bpp(&lockrect, 0, 1, 0xff303030);
+        check_pixel_4bpp(&lockrect, 1, 1, 0x7f7f7f7f);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        /* Test D3DXLoadSurfaceFromMemory with indexed color image */
+        if (0)
+        {
+        /* Crashes on Nvidia Win10. */
+        palette.peRed   = bmp_1bpp[56];
+        palette.peGreen = bmp_1bpp[55];
+        palette.peBlue  = bmp_1bpp[54];
+        palette.peFlags = bmp_1bpp[57]; /* peFlags is the alpha component in DX8 and higher */
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, &bmp_1bpp[62],
+                D3DFMT_P8, 1, (const PALETTEENTRY *)&palette, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x\n", hr);
+        ok(*(DWORD*)lockrect.pBits == 0x80f3f2f1, "Pixel color mismatch: got %#x, expected 0x80f3f2f1\n", *(DWORD*)lockrect.pBits);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x\n", hr);
+        }
+
+        /* Test D3DXLoadSurfaceFromFileInMemory with indexed color image (alpha is not taken into account for bmp file) */
+        hr = D3DXLoadSurfaceFromFileInMemory(surf, NULL, NULL, bmp_1bpp, sizeof(bmp_1bpp), NULL, D3DX_FILTER_NONE, 0, NULL);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x\n", hr);
+        ok(*(DWORD*)lockrect.pBits == 0xfff3f2f1, "Pixel color mismatch: got %#x, expected 0xfff3f2f1\n", *(DWORD*)lockrect.pBits);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x\n", hr);
+
+        check_release((IUnknown*)surf, 0);
+    }
+
+    /* A1R5G5B5 */
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 2, 2, D3DFMT_A1R5G5B5, D3DPOOL_DEFAULT, &surf, NULL);
+    if(FAILED(hr)) skip("Failed to create a surface (%#x)\n", hr);
+    else {
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8r3g3b2, D3DFMT_A8R3G3B2, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        check_pixel_2bpp(&lockrect, 0, 0, 0x6fff);
+        check_pixel_2bpp(&lockrect, 1, 0, 0xffe0);
+        check_pixel_2bpp(&lockrect, 0, 1, 0xefea);
+        check_pixel_2bpp(&lockrect, 1, 1, 0xca4a);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a1r5g5b5, D3DFMT_A1R5G5B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        check_pixel_2bpp(&lockrect, 0, 0, 0x46b5);
+        check_pixel_2bpp(&lockrect, 1, 0, 0x99c8);
+        check_pixel_2bpp(&lockrect, 0, 1, 0x06a2);
+        check_pixel_2bpp(&lockrect, 1, 1, 0x9431);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_r5g6b5, D3DFMT_R5G6B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        check_pixel_2bpp(&lockrect, 0, 0, 0xcf76);
+        check_pixel_2bpp(&lockrect, 1, 0, 0xb2cd);
+        check_pixel_2bpp(&lockrect, 0, 1, 0x856e);
+        check_pixel_2bpp(&lockrect, 1, 1, 0xa16e);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_g16r16, D3DFMT_G16R16, 8, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        todo_wine {
+            check_pixel_2bpp(&lockrect, 0, 0, 0xa03f);
+        }
+        check_pixel_2bpp(&lockrect, 1, 0, 0xa37f);
+        check_pixel_2bpp(&lockrect, 0, 1, 0xcb9f);
+        check_pixel_2bpp(&lockrect, 1, 1, 0xfe7f);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8, D3DFMT_A8B8G8R8, 8, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        todo_wine {
+            check_pixel_2bpp(&lockrect, 0, 0, 0xf527);
+            check_pixel_2bpp(&lockrect, 1, 0, 0x4b8b);
+        }
+        check_pixel_2bpp(&lockrect, 0, 1, 0x7e56);
+        check_pixel_2bpp(&lockrect, 1, 1, 0xf8b8);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a2r10g10b10, D3DFMT_A2R10G10B10, 8, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        check_pixel_2bpp(&lockrect, 0, 0, 0x2e57);
+        todo_wine {
+            check_pixel_2bpp(&lockrect, 1, 0, 0x3588);
+        }
+        check_pixel_2bpp(&lockrect, 0, 1, 0xe215);
+        check_pixel_2bpp(&lockrect, 1, 1, 0xff0e);
+        IDirect3DSurface9_UnlockRect(surf);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8l8,
+                D3DFMT_A8L8, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(SUCCEEDED(hr), "Failed to load surface, hr %#x.\n", hr);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        check_pixel_2bpp(&lockrect, 0, 0, 0x8000);
+        check_pixel_2bpp(&lockrect, 1, 0, 0x7fff);
+        check_pixel_2bpp(&lockrect, 0, 1, 0x98c6);
+        check_pixel_2bpp(&lockrect, 1, 1, 0x3def);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        check_release((IUnknown*)surf, 0);
+    }
+
+    /* A8L8 */
+    hr = IDirect3DDevice9_CreateTexture(device, 2, 2, 1, 0, D3DFMT_A8L8, D3DPOOL_MANAGED, &tex, NULL);
+    if (FAILED(hr))
+        skip("Failed to create A8L8 texture, hr %#x.\n", hr);
+    else
+    {
+        hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &surf);
+        ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8r3g3b2,
+                D3DFMT_A8R3G3B2, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(SUCCEEDED(hr), "Failed to load surface, hr %#x.\n", hr);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        check_pixel_2bpp(&lockrect, 0, 0, 0x57f7);
+        check_pixel_2bpp(&lockrect, 1, 0, 0x98ed);
+        check_pixel_2bpp(&lockrect, 0, 1, 0xaceb);
+        check_pixel_2bpp(&lockrect, 1, 1, 0xc88d);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a1r5g5b5,
+                D3DFMT_A1R5G5B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        check_pixel_2bpp(&lockrect, 0, 0, 0x00a6);
+        check_pixel_2bpp(&lockrect, 1, 0, 0xff62);
+        check_pixel_2bpp(&lockrect, 0, 1, 0x007f);
+        check_pixel_2bpp(&lockrect, 1, 1, 0xff19);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_r5g6b5,
+                D3DFMT_R5G6B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(SUCCEEDED(hr), "Failed to load surface, hr %#x.\n", hr);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        check_pixel_2bpp(&lockrect, 0, 0, 0xffce);
+        check_pixel_2bpp(&lockrect, 1, 0, 0xff9c);
+        check_pixel_2bpp(&lockrect, 0, 1, 0xff4d);
+        check_pixel_2bpp(&lockrect, 1, 1, 0xff59);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_g16r16,
+                D3DFMT_G16R16, 8, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(SUCCEEDED(hr), "Failed to load surface, hr %#x.\n", hr);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        check_pixel_2bpp(&lockrect, 0, 0, 0xff25);
+        check_pixel_2bpp(&lockrect, 1, 0, 0xffbe);
+        check_pixel_2bpp(&lockrect, 0, 1, 0xffd6);
+        check_pixel_2bpp(&lockrect, 1, 1, 0xffb6);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8,
+                D3DFMT_A8B8G8R8, 8, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(SUCCEEDED(hr), "Failed to load surface, hr %#x.\n", hr);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        check_pixel_2bpp(&lockrect, 0, 0, 0xc36d);
+        check_pixel_2bpp(&lockrect, 1, 0, 0x23cb);
+        check_pixel_2bpp(&lockrect, 0, 1, 0x09af);
+        check_pixel_2bpp(&lockrect, 1, 1, 0x8d61);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a2r10g10b10,
+                D3DFMT_A2R10G10B10, 8, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(SUCCEEDED(hr), "Failed to load surface, hr %#x.\n", hr);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        check_pixel_2bpp(&lockrect, 0, 0, 0x558c);
+        check_pixel_2bpp(&lockrect, 1, 0, 0x5565);
+        check_pixel_2bpp(&lockrect, 0, 1, 0xaa95);
+        check_pixel_2bpp(&lockrect, 1, 1, 0xffcb);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8l8,
+                D3DFMT_A8L8, 4, NULL, &rect, D3DX_FILTER_NONE, 0);
+        ok(SUCCEEDED(hr), "Failed to load surface, hr %#x.\n", hr);
+        hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        check_pixel_2bpp(&lockrect, 0, 0, 0xff00);
+        check_pixel_2bpp(&lockrect, 1, 0, 0x00ff);
+        check_pixel_2bpp(&lockrect, 0, 1, 0xff30);
+        check_pixel_2bpp(&lockrect, 1, 1, 0x7f7f);
+        hr = IDirect3DSurface9_UnlockRect(surf);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        check_release((IUnknown*)surf, 1);
+        check_release((IUnknown*)tex, 0);
+    }
+
+    /* DXT1, DXT2, DXT3, DXT4, DXT5 */
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surf, NULL);
+    if (FAILED(hr))
+        skip("Failed to create R8G8B8 surface, hr %#x.\n", hr);
+    else
+    {
+        hr = D3DXLoadSurfaceFromFileInMemory(surf, NULL, NULL, dds_24bit, sizeof(dds_24bit), NULL, D3DX_FILTER_NONE, 0, NULL);
+        ok(SUCCEEDED(hr), "Failed to load surface, hr %#x.\n", hr);
+
+        hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_DXT2, D3DPOOL_SYSTEMMEM, &tex, NULL);
+        if (FAILED(hr))
+            skip("Failed to create DXT2 texture, hr %#x.\n", hr);
+        else
+        {
+            hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf);
+            ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr);
+            hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0);
+            todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels to DXT2 format.\n");
+            check_release((IUnknown*)newsurf, 1);
+            check_release((IUnknown*)tex, 0);
+        }
+
+        hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_DXT3, D3DPOOL_SYSTEMMEM, &tex, NULL);
+        if (FAILED(hr))
+            skip("Failed to create DXT3 texture, hr %#x.\n", hr);
+        else
+        {
+            hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf);
+            ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr);
+            hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0);
+            todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels to DXT3 format.\n");
+            check_release((IUnknown*)newsurf, 1);
+            check_release((IUnknown*)tex, 0);
+        }
+
+        hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_DXT4, D3DPOOL_SYSTEMMEM, &tex, NULL);
+        if (FAILED(hr))
+            skip("Failed to create DXT4 texture, hr %#x.\n", hr);
+        else
+        {
+            hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf);
+            ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr);
+            hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0);
+            todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels to DXT4 format.\n");
+            check_release((IUnknown*)newsurf, 1);
+            check_release((IUnknown*)tex, 0);
+        }
+
+        hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_DXT5, D3DPOOL_SYSTEMMEM, &tex, NULL);
+        if (FAILED(hr))
+            skip("Failed to create DXT5 texture, hr %#x.\n", hr);
+        else
+        {
+            hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf);
+            ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr);
+            hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0);
+            todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels to DXT5 format.\n");
+            check_release((IUnknown*)newsurf, 1);
+            check_release((IUnknown*)tex, 0);
+        }
+
+        hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_DXT1, D3DPOOL_SYSTEMMEM, &tex, NULL);
+        if (FAILED(hr))
+            skip("Failed to create DXT1 texture, hr %#x.\n", hr);
+        else
+        {
+            hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf);
+            ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr);
+            hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0);
+            todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels to DXT1 format.\n");
+
+            hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, NULL, D3DX_FILTER_NONE, 0);
+            todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels from DXT1 format.\n");
+
+            check_release((IUnknown*)newsurf, 1);
+            check_release((IUnknown*)tex, 0);
+        }
+
+        check_release((IUnknown*)surf, 0);
+    }
+
+    /* cleanup */
+    if(testdummy_ok) DeleteFileA("testdummy.bmp");
+    if(testbitmap_ok) DeleteFileA("testbitmap.bmp");
+}
+
+static void test_D3DXSaveSurfaceToFileInMemory(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    RECT rect;
+    ID3DXBuffer *buffer;
+    IDirect3DSurface9 *surface;
+    struct
+    {
+         DWORD magic;
+         struct dds_header header;
+         BYTE *data;
+    } *dds;
+
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surface, NULL);
+    if (FAILED(hr)) {
+       skip("Couldn't create surface\n");
+       return;
+    }
+
+    SetRectEmpty(&rect);
+    hr = D3DXSaveSurfaceToFileInMemory(&buffer, D3DXIFF_BMP, surface, NULL, &rect);
+    /* fails with the debug version of d3d9 */
+    ok(hr == D3D_OK || broken(hr == D3DERR_INVALIDCALL), "D3DXSaveSurfaceToFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr)) {
+        DWORD size = ID3DXBuffer_GetBufferSize(buffer);
+        ok(size > 0, "ID3DXBuffer_GetBufferSize returned %u, expected > 0\n", size);
+        ID3DXBuffer_Release(buffer);
+    }
+
+    SetRectEmpty(&rect);
+    hr = D3DXSaveSurfaceToFileInMemory(&buffer, D3DXIFF_DDS, surface, NULL, &rect);
+    todo_wine ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+    if (SUCCEEDED(hr))
+    {
+        dds = ID3DXBuffer_GetBufferPointer(buffer);
+
+        ok(dds->magic == MAKEFOURCC('D','D','S',' '), "Got unexpected DDS signature %#x.\n", dds->magic);
+        ok(dds->header.size == sizeof(dds->header), "Got unexpected DDS size %u.\n", dds->header.size);
+        ok(!dds->header.height, "Got unexpected height %u.\n", dds->header.height);
+        ok(!dds->header.width, "Got unexpected width %u.\n", dds->header.width);
+        ok(!dds->header.depth, "Got unexpected depth %u.\n", dds->header.depth);
+        ok(!dds->header.miplevels, "Got unexpected miplevels %u.\n", dds->header.miplevels);
+        ok(!dds->header.pitch_or_linear_size, "Got unexpected pitch_or_linear_size %u.\n", dds->header.pitch_or_linear_size);
+        ok(dds->header.caps == (DDS_CAPS_TEXTURE | DDSCAPS_ALPHA), "Got unexpected caps %#x.\n", dds->header.caps);
+        ok(dds->header.flags == (DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_PIXELFORMAT),
+                "Got unexpected flags %#x.\n", dds->header.flags);
+        ID3DXBuffer_Release(buffer);
+    }
+
+    hr = D3DXSaveSurfaceToFileInMemory(&buffer, D3DXIFF_DDS, surface, NULL, NULL);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    dds = ID3DXBuffer_GetBufferPointer(buffer);
+    ok(dds->magic == MAKEFOURCC('D','D','S',' '), "Got unexpected DDS signature %#x.\n", dds->magic);
+    ok(dds->header.size == sizeof(dds->header), "Got unexpected DDS size %u.\n", dds->header.size);
+    ok(dds->header.height == 4, "Got unexpected height %u.\n", dds->header.height);
+    ok(dds->header.width == 4, "Got unexpected width %u.\n", dds->header.width);
+    ok(!dds->header.depth, "Got unexpected depth %u.\n", dds->header.depth);
+    ok(!dds->header.miplevels, "Got unexpected miplevels %u.\n", dds->header.miplevels);
+    ok(!dds->header.pitch_or_linear_size, "Got unexpected pitch_or_linear_size %u.\n", dds->header.pitch_or_linear_size);
+    todo_wine ok(dds->header.caps == (DDS_CAPS_TEXTURE | DDSCAPS_ALPHA), "Got unexpected caps %#x.\n", dds->header.caps);
+    ok(dds->header.flags == (DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_PIXELFORMAT),
+            "Got unexpected flags %#x.\n", dds->header.flags);
+    ID3DXBuffer_Release(buffer);
+
+    IDirect3DSurface9_Release(surface);
+}
+
+static void test_D3DXSaveSurfaceToFile(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    IDirect3DSurface9 *surface;
+    RECT rect;
+    D3DLOCKED_RECT lock_rect;
+    D3DXIMAGE_INFO image_info;
+    const BYTE pixels[] = { 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+                            0x00, 0x00, 0xff, 0x00, 0x00, 0xff };
+    DWORD pitch = sizeof(pixels) / 2;
+
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 2, 2, D3DFMT_R8G8B8, D3DPOOL_SCRATCH, &surface, NULL);
+    if (FAILED(hr)) {
+       skip("Couldn't create surface\n");
+       return;
+    }
+
+    SetRect(&rect, 0, 0, 2, 2);
+    hr = D3DXLoadSurfaceFromMemory(surface, NULL, NULL, pixels, D3DFMT_R8G8B8, pitch, NULL, &rect, D3DX_FILTER_NONE, 0);
+    if (SUCCEEDED(hr)) {
+        hr = D3DXSaveSurfaceToFileA("saved_surface.bmp", D3DXIFF_BMP, surface, NULL, NULL);
+        ok(hr == D3D_OK, "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXLoadSurfaceFromFileA(surface, NULL, NULL, "saved_surface.bmp", NULL, D3DX_FILTER_NONE, 0, &image_info);
+        ok(hr == D3D_OK, "Couldn't load saved surface %#x\n", hr);
+        if (FAILED(hr)) goto next_tests;
+
+        ok(image_info.Width == 2, "Wrong width %u\n", image_info.Width);
+        ok(image_info.Height == 2, "Wrong height %u\n", image_info.Height);
+        ok(image_info.Format == D3DFMT_R8G8B8, "Wrong format %#x\n", image_info.Format);
+        ok(image_info.ImageFileFormat == D3DXIFF_BMP, "Wrong file format %u\n", image_info.ImageFileFormat);
+
+        hr = IDirect3DSurface9_LockRect(surface, &lock_rect, NULL, D3DLOCK_READONLY);
+        ok(hr == D3D_OK, "Couldn't lock surface %#x\n", hr);
+        if (FAILED(hr)) goto next_tests;
+
+        ok(!memcmp(lock_rect.pBits, pixels, pitch), "Pixel data mismatch in first row\n");
+        ok(!memcmp((BYTE *)lock_rect.pBits + lock_rect.Pitch, pixels + pitch, pitch), "Pixel data mismatch in second row\n");
+
+        IDirect3DSurface9_UnlockRect(surface);
+    } else skip("Couldn't fill surface\n");
+
+next_tests:
+    hr = D3DXSaveSurfaceToFileA(NULL, D3DXIFF_BMP, surface, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    /* PPM and TGA are supported, even though MSDN claims they aren't */
+    todo_wine {
+    hr = D3DXSaveSurfaceToFileA("saved_surface.ppm", D3DXIFF_PPM, surface, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3D_OK);
+    hr = D3DXSaveSurfaceToFileA("saved_surface.tga", D3DXIFF_TGA, surface, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3D_OK);
+    }
+
+    hr = D3DXSaveSurfaceToFileA("saved_surface.dds", D3DXIFF_DDS, surface, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr)) {
+        hr = D3DXLoadSurfaceFromFileA(surface, NULL, NULL, "saved_surface.dds", NULL, D3DX_FILTER_NONE, 0, &image_info);
+        ok(hr == D3D_OK, "Couldn't load saved surface %#x\n", hr);
+
+        if (SUCCEEDED(hr)) {
+            ok(image_info.Width == 2, "Wrong width %u\n", image_info.Width);
+            ok(image_info.Format == D3DFMT_R8G8B8, "Wrong format %#x\n", image_info.Format);
+            ok(image_info.ImageFileFormat == D3DXIFF_DDS, "Wrong file format %u\n", image_info.ImageFileFormat);
+
+            hr = IDirect3DSurface9_LockRect(surface, &lock_rect, NULL, D3DLOCK_READONLY);
+            ok(hr == D3D_OK, "Couldn't lock surface %#x\n", hr);
+            if (SUCCEEDED(hr)) {
+                ok(!memcmp(lock_rect.pBits, pixels, pitch), "Pixel data mismatch in first row\n");
+                ok(!memcmp((BYTE *)lock_rect.pBits + lock_rect.Pitch, pixels + pitch, pitch), "Pixel data mismatch in second row\n");
+                IDirect3DSurface9_UnlockRect(surface);
+            }
+        }
+    } else skip("Couldn't save surface\n");
+
+    hr = D3DXSaveSurfaceToFileA("saved_surface", D3DXIFF_PFM + 1, surface, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    SetRect(&rect, 0, 0, 4, 4);
+    hr = D3DXSaveSurfaceToFileA("saved_surface.bmp", D3DXIFF_BMP, surface, NULL, &rect);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    SetRect(&rect, 2, 0, 1, 4);
+    hr = D3DXSaveSurfaceToFileA("saved_surface.bmp", D3DXIFF_BMP, surface, NULL, &rect);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    SetRect(&rect, 0, 2, 4, 1);
+    hr = D3DXSaveSurfaceToFileA("saved_surface.bmp", D3DXIFF_BMP, surface, NULL, &rect);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    SetRect(&rect, -1, -1, 2, 2);
+    hr = D3DXSaveSurfaceToFileA("saved_surface.bmp", D3DXIFF_BMP, surface, NULL, &rect);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+    SetRectEmpty(&rect);
+    hr = D3DXSaveSurfaceToFileA("saved_surface.bmp", D3DXIFF_BMP, surface, NULL, &rect);
+    /* fails when debug version of d3d9 is used */
+    ok(hr == D3D_OK || broken(hr == D3DERR_INVALIDCALL), "D3DXSaveSurfaceToFileA returned %#x, expected %#x\n", hr, D3D_OK);
+
+    DeleteFileA("saved_surface.bmp");
+    DeleteFileA("saved_surface.ppm");
+    DeleteFileA("saved_surface.tga");
+    DeleteFileA("saved_surface.dds");
+
+    IDirect3DSurface9_Release(surface);
+}
+
+START_TEST(surface)
+{
+    HWND wnd;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *device;
+    D3DPRESENT_PARAMETERS d3dpp;
+    HRESULT hr;
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window\n");
+        return;
+    }
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    if (!d3d) {
+        skip("Couldn't create IDirect3D9 object\n");
+        DestroyWindow(wnd);
+        return;
+    }
+
+    ZeroMemory(&d3dpp, sizeof(d3dpp));
+    d3dpp.Windowed   = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
+    if(FAILED(hr)) {
+        skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    test_D3DXGetImageInfo();
+    test_D3DXLoadSurface(device);
+    test_D3DXSaveSurfaceToFileInMemory(device);
+    test_D3DXSaveSurfaceToFile(device);
+
+    check_release((IUnknown*)device, 0);
+    check_release((IUnknown*)d3d, 0);
+    DestroyWindow(wnd);
+}
diff --git a/modules/rostests/winetests/d3dx9_36/testlist.c b/modules/rostests/winetests/d3dx9_36/testlist.c
new file mode 100644 (file)
index 0000000..9fc068c
--- /dev/null
@@ -0,0 +1,32 @@
+/* Automatically generated by make depend; DO NOT EDIT!! */
+
+#define STANDALONE
+#include <wine/test.h>
+
+extern void func_asm(void);
+extern void func_core(void);
+extern void func_effect(void);
+extern void func_line(void);
+extern void func_math(void);
+extern void func_mesh(void);
+extern void func_shader(void);
+extern void func_surface(void);
+extern void func_texture(void);
+extern void func_volume(void);
+extern void func_xfile(void);
+
+const struct test winetest_testlist[] =
+{
+    { "asm", func_asm },
+    { "core", func_core },
+    { "effect", func_effect },
+    { "line", func_line },
+    { "math", func_math },
+    { "mesh", func_mesh },
+    { "shader", func_shader },
+    { "surface", func_surface },
+    { "texture", func_texture },
+    { "volume", func_volume },
+    { "xfile", func_xfile },
+    { 0, 0 }
+};
diff --git a/modules/rostests/winetests/d3dx9_36/texture.c b/modules/rostests/winetests/d3dx9_36/texture.c
new file mode 100644 (file)
index 0000000..79cddc7
--- /dev/null
@@ -0,0 +1,2264 @@
+/*
+ * Tests for the D3DX9 texture functions
+ *
+ * Copyright 2009 Tony Wasserka
+ * Copyright 2010 Owen Rudge for CodeWeavers
+ * Copyright 2010 Matteo Bruni for CodeWeavers
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include "wine/test.h"
+#include "d3dx9tex.h"
+#include "resources.h"
+
+static int has_2d_dxt3, has_2d_dxt5, has_cube_dxt5, has_3d_dxt3;
+
+/* 2x2 16-bit dds, no mipmaps */
+static const unsigned char dds_16bit[] = {
+0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x08,0x00,0x02,0x00,0x00,0x00,
+0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,
+0xe0,0x03,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0x7f
+};
+
+/* 2x2 24-bit dds, 2 mipmaps */
+static const unsigned char dds_24bit[] = {
+0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x0a,0x00,0x02,0x00,0x00,0x00,
+0x02,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0xff,0x00,
+0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+};
+
+/* 4x4 cube map dds */
+static const unsigned char dds_cube_map[] = {
+0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x08,0x00,0x04,0x00,0x00,0x00,
+0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+0x04,0x00,0x00,0x00,0x44,0x58,0x54,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x00,0x00,
+0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x51,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x52,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x53,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x54,
+0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x55
+};
+
+/* 4x4x2 volume map dds, 2 mipmaps */
+static const unsigned char dds_volume_map[] = {
+0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x8a,0x00,0x04,0x00,0x00,0x00,
+0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+0x04,0x00,0x00,0x00,0x44,0x58,0x54,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00,
+0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x2f,0x7e,0xcf,0x79,0x01,0x54,0x5c,0x5c,
+0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x84,0xef,0x7b,0xaa,0xab,0xab,0xab
+};
+
+static const unsigned char png_grayscale[] =
+{
+    0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49,
+    0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x3a, 0x7e, 0x9b, 0x55, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44,
+    0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0x0f, 0x00, 0x01, 0x01, 0x01, 0x00, 0x1b,
+    0xb6, 0xee, 0x56, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
+    0x60, 0x82
+};
+
+#define ADMITTED_ERROR 0.0001f
+
+static inline float relative_error(float expected, float got)
+{
+    return expected == 0.0f ? fabs(expected - got) : fabs(1.0f - got / expected);
+}
+
+#define expect_vec4(expected, got) expect_vec4_(__LINE__, expected, got)
+static inline void expect_vec4_(unsigned int line, const D3DXVECTOR4 *expected, const D3DXVECTOR4 *got)
+{
+    ok_(__FILE__, line)(relative_error(expected->x, got->x) < ADMITTED_ERROR
+        && relative_error(expected->y, got->y) < ADMITTED_ERROR
+        && relative_error(expected->z, got->z) < ADMITTED_ERROR
+        && relative_error(expected->w, got->w) < ADMITTED_ERROR,
+        "Expected (%f, %f, %f, %f), got (%f, %f, %f, %f)\n",
+        expected->x, expected->y, expected->z, expected->w,
+        got->x, got->y, got->z, got->w);
+}
+
+static BOOL compare_color(DWORD c1, DWORD c2, BYTE max_diff)
+{
+    if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff)
+        return FALSE;
+    c1 >>= 8; c2 >>= 8;
+    if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff)
+        return FALSE;
+    c1 >>= 8; c2 >>= 8;
+    if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff)
+        return FALSE;
+    c1 >>= 8; c2 >>= 8;
+    if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff)
+        return FALSE;
+    return TRUE;
+}
+
+static BOOL is_autogenmipmap_supported(IDirect3DDevice9 *device, D3DRESOURCETYPE resource_type)
+{
+    HRESULT hr;
+    D3DCAPS9 caps;
+    IDirect3D9 *d3d9;
+    D3DDISPLAYMODE mode;
+    D3DDEVICE_CREATION_PARAMETERS params;
+
+    IDirect3DDevice9_GetDeviceCaps(device, &caps);
+    IDirect3DDevice9_GetDirect3D(device, &d3d9);
+    IDirect3DDevice9_GetCreationParameters(device, &params);
+    IDirect3DDevice9_GetDisplayMode(device, 0, &mode);
+
+    if (!(caps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP))
+        return FALSE;
+
+    hr = IDirect3D9_CheckDeviceFormat(d3d9, params.AdapterOrdinal, params.DeviceType,
+        mode.Format, D3DUSAGE_AUTOGENMIPMAP, resource_type, D3DFMT_A8R8G8B8);
+
+    IDirect3D9_Release(d3d9);
+    return hr == D3D_OK;
+}
+
+static void test_D3DXCheckTextureRequirements(IDirect3DDevice9 *device)
+{
+    UINT width, height, mipmaps;
+    D3DFORMAT format, expected;
+    D3DCAPS9 caps;
+    HRESULT hr;
+    IDirect3D9 *d3d;
+    D3DDEVICE_CREATION_PARAMETERS params;
+    D3DDISPLAYMODE mode;
+
+    IDirect3DDevice9_GetDeviceCaps(device, &caps);
+
+    /* general tests */
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, D3DX_DEFAULT, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXCheckTextureRequirements(NULL, NULL, NULL, NULL, D3DX_DEFAULT, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    /* width & height */
+    width = height = D3DX_DEFAULT;
+    hr = D3DXCheckTextureRequirements(device, &width, &height, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == 256, "Returned width %d, expected %d\n", width, 256);
+    ok(height == 256, "Returned height %d, expected %d\n", height, 256);
+
+    width = D3DX_DEFAULT;
+    hr = D3DXCheckTextureRequirements(device, &width, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == 256, "Returned width %d, expected %d\n", width, 256);
+
+    if (caps.TextureCaps & D3DPTEXTURECAPS_POW2)
+        skip("Hardware only supports pow2 textures\n");
+    else
+    {
+        width = 62;
+        hr = D3DXCheckTextureRequirements(device, &width, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+        ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(width == 62, "Returned width %d, expected %d\n", width, 62);
+
+        width = D3DX_DEFAULT; height = 63;
+        hr = D3DXCheckTextureRequirements(device, &width, &height, NULL, 0, NULL, D3DPOOL_DEFAULT);
+        ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(width == height, "Returned width %d, expected %d\n", width, height);
+        ok(height == 63, "Returned height %d, expected %d\n", height, 63);
+    }
+
+    width = D3DX_DEFAULT; height = 0;
+    hr = D3DXCheckTextureRequirements(device, &width, &height, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == 1, "Returned width %d, expected %d\n", width, 1);
+    ok(height == 1, "Returned height %d, expected %d\n", height, 1);
+
+    width = 0; height = 0;
+    hr = D3DXCheckTextureRequirements(device, &width, &height, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == 1, "Returned width %d, expected %d\n", width, 1);
+    ok(height == 1, "Returned height %d, expected %d\n", height, 1);
+
+    width = 0;
+    hr = D3DXCheckTextureRequirements(device, &width, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == 1, "Returned width %d, expected %d\n", width, 1);
+
+    width = 0xFFFFFFFE;
+    hr = D3DXCheckTextureRequirements(device, &width, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == caps.MaxTextureWidth, "Returned width %d, expected %d\n", width, caps.MaxTextureWidth);
+
+    width = caps.MaxTextureWidth-1;
+    hr = D3DXCheckTextureRequirements(device, &width, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    if (caps.TextureCaps & D3DPTEXTURECAPS_POW2)
+        ok(width == caps.MaxTextureWidth, "Returned width %d, expected %d\n", width, caps.MaxTextureWidth);
+    else
+        ok(width == caps.MaxTextureWidth-1, "Returned width %d, expected %d\n", width, caps.MaxTextureWidth-1);
+
+    /* mipmaps */
+    width = 64; height = 63;
+    mipmaps = 9;
+    hr = D3DXCheckTextureRequirements(device, &width, &height, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(mipmaps == 7, "Returned mipmaps %d, expected %d\n", mipmaps, 7);
+
+    if (!(caps.TextureCaps & D3DPTEXTURECAPS_POW2))
+    {
+        width = 284; height = 137;
+        mipmaps = 20;
+        hr = D3DXCheckTextureRequirements(device, &width, &height, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+        ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(mipmaps == 9, "Returned mipmaps %d, expected %d\n", mipmaps, 9);
+
+        width = height = 63;
+        mipmaps = 9;
+        hr = D3DXCheckTextureRequirements(device, &width, &height, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+        ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(mipmaps == 6, "Returned mipmaps %d, expected %d\n", mipmaps, 6);
+    }
+    else
+        skip("Skipping some tests, npot2 textures unsupported\n");
+
+    mipmaps = 20;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(mipmaps == 9, "Returned mipmaps %d, expected %d\n", mipmaps, 9);
+
+    mipmaps = 0;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(mipmaps == 9, "Returned mipmaps %d, expected %d\n", mipmaps, 9);
+
+    /* mipmaps when D3DUSAGE_AUTOGENMIPMAP is set */
+    if (is_autogenmipmap_supported(device, D3DRTYPE_TEXTURE))
+    {
+        mipmaps = 0;
+        hr = D3DXCheckTextureRequirements(device, NULL, NULL, &mipmaps, D3DUSAGE_AUTOGENMIPMAP, NULL, D3DPOOL_DEFAULT);
+        ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(mipmaps == 0, "Returned mipmaps %d, expected %d\n", mipmaps, 0);
+        mipmaps = 1;
+        hr = D3DXCheckTextureRequirements(device, NULL, NULL, &mipmaps, D3DUSAGE_AUTOGENMIPMAP, NULL, D3DPOOL_DEFAULT);
+        ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(mipmaps == 1, "Returned mipmaps %d, expected %d\n", mipmaps, 1);
+        mipmaps = 2;
+        hr = D3DXCheckTextureRequirements(device, NULL, NULL, &mipmaps, D3DUSAGE_AUTOGENMIPMAP, NULL, D3DPOOL_DEFAULT);
+        ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(mipmaps == 0, "Returned mipmaps %d, expected %d\n", mipmaps, 0);
+        mipmaps = 6;
+        hr = D3DXCheckTextureRequirements(device, NULL, NULL, &mipmaps, D3DUSAGE_AUTOGENMIPMAP, NULL, D3DPOOL_DEFAULT);
+        ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(mipmaps == 0, "Returned mipmaps %d, expected %d\n", mipmaps, 0);
+    }
+    else
+        skip("No D3DUSAGE_AUTOGENMIPMAP support for textures\n");
+
+    /* usage */
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, D3DUSAGE_WRITEONLY, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckTextureRequirements succeeded, but should've failed.\n");
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, D3DUSAGE_DONOTCLIP, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckTextureRequirements succeeded, but should've failed.\n");
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, D3DUSAGE_POINTS, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckTextureRequirements succeeded, but should've failed.\n");
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, D3DUSAGE_RTPATCHES, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckTextureRequirements succeeded, but should've failed.\n");
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, D3DUSAGE_NPATCHES, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckTextureRequirements succeeded, but should've failed.\n");
+
+    /* format */
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+
+    format = D3DFMT_UNKNOWN;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8);
+
+    format = D3DX_DEFAULT;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8);
+
+    format = D3DFMT_R8G8B8;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == D3DFMT_X8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_X8R8G8B8);
+
+    IDirect3DDevice9_GetDirect3D(device, &d3d);
+    IDirect3DDevice9_GetCreationParameters(device, &params);
+    IDirect3DDevice9_GetDisplayMode(device, 0, &mode);
+
+    if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
+                                               mode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_R3G3B2)))
+        expected = D3DFMT_R3G3B2;
+    else if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
+                                                    mode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_X4R4G4B4)))
+        expected = D3DFMT_X4R4G4B4;
+    else if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
+                                                    mode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_X1R5G5B5)))
+        expected = D3DFMT_X1R5G5B5;
+    else
+        expected = D3DFMT_R5G6B5;
+
+    format = D3DFMT_R3G3B2;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == expected, "Returned format %u, expected %u\n", format, expected);
+
+    if(SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
+                                              mode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R3G3B2)))
+        expected = D3DFMT_A8R3G3B2;
+    else
+        expected = D3DFMT_A8R8G8B8;
+
+    format = D3DFMT_A8R3G3B2;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == expected, "Returned format %u, expected %u\n", format, expected);
+
+    if(SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
+                                              mode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_P8)))
+        expected = D3DFMT_P8;
+    else
+        expected = D3DFMT_A8R8G8B8;
+
+    format = D3DFMT_P8;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == expected, "Returned format %u, expected %u\n", format, expected);
+
+    if(SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
+            mode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, D3DFMT_L8)))
+        expected = D3DFMT_L8;
+    else
+        expected = D3DFMT_X8R8G8B8;
+
+    format = D3DFMT_L8;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, D3DUSAGE_RENDERTARGET, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == expected, "Returned format %u, expected %u\n", format, expected);
+
+    if(SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
+            mode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, D3DFMT_L16)))
+        expected = D3DFMT_L16;
+    else
+        expected = D3DFMT_A16B16G16R16;
+
+    format = D3DFMT_L16;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, D3DUSAGE_RENDERTARGET, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == expected, "Returned format %u, expected %u\n", format, expected);
+
+    /* Block-based texture formats and size < block size. */
+    if (has_2d_dxt5)
+    {
+        format = D3DFMT_DXT5;
+        width = 2; height = 2;
+        mipmaps = 1;
+        hr = D3DXCheckTextureRequirements(device, &width, &height, &mipmaps, 0, &format, D3DPOOL_DEFAULT);
+        ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(width == 4, "Returned width %d, expected %d\n", width, 4);
+        ok(height == 4, "Returned height %d, expected %d\n", height, 4);
+        ok(mipmaps == 1, "Returned mipmaps %d, expected %d\n", mipmaps, 1);
+        ok(format == D3DFMT_DXT5, "Returned format %u, expected %u\n", format, D3DFMT_DXT5);
+    }
+    else
+    {
+        skip("D3DFMT_DXT5 textures are not supported, skipping a test.\n");
+    }
+
+    IDirect3D9_Release(d3d);
+}
+
+static void test_D3DXCheckCubeTextureRequirements(IDirect3DDevice9 *device)
+{
+    UINT size, mipmaps, expected;
+    D3DFORMAT format;
+    D3DCAPS9 caps;
+    HRESULT hr;
+
+    IDirect3DDevice9_GetDeviceCaps(device, &caps);
+
+    if (!(caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP))
+    {
+        skip("No cube textures support\n");
+        return;
+    }
+
+    /* general tests */
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, D3DX_DEFAULT, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXCheckCubeTextureRequirements(NULL, NULL, NULL, D3DX_DEFAULT, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    /* size */
+    size = D3DX_DEFAULT;
+    hr = D3DXCheckCubeTextureRequirements(device, &size, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(size == 256, "Returned size %d, expected %d\n", size, 256);
+
+    /* mipmaps */
+    size = 64;
+    mipmaps = 9;
+    hr = D3DXCheckCubeTextureRequirements(device, &size, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(mipmaps == 7, "Returned mipmaps %d, expected %d\n", mipmaps, 7);
+
+    size = 284;
+    mipmaps = 20;
+    expected = caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2 ? 10 : 9;
+    expected = caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP ? expected : 1;
+    hr = D3DXCheckCubeTextureRequirements(device, &size, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(mipmaps == expected, "Returned mipmaps %d, expected %d\n", mipmaps, expected);
+
+    size = 63;
+    mipmaps = 9;
+    expected = caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2 ? 7 : 6;
+    expected = caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP ? expected : 1;
+    hr = D3DXCheckCubeTextureRequirements(device, &size, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(mipmaps == expected, "Returned mipmaps %d, expected %d\n", mipmaps, expected);
+
+    mipmaps = 0;
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(mipmaps == 9, "Returned mipmaps %d, expected %d\n", mipmaps, 9);
+
+    if (is_autogenmipmap_supported(device, D3DRTYPE_CUBETEXTURE))
+    {
+        mipmaps = 3;
+        hr = D3DXCheckCubeTextureRequirements(device, NULL,  &mipmaps, D3DUSAGE_AUTOGENMIPMAP, NULL, D3DPOOL_DEFAULT);
+        ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(mipmaps == 0, "Returned mipmaps %d, expected %d\n", mipmaps, 0);
+    }
+    else
+        skip("No D3DUSAGE_AUTOGENMIPMAP support for cube textures\n");
+
+    /* usage */
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, D3DUSAGE_WRITEONLY, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckCubeTextureRequirements succeeded, but should've failed.\n");
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, D3DUSAGE_DONOTCLIP, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckCubeTextureRequirements succeeded, but should've failed.\n");
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, D3DUSAGE_POINTS, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckCubeTextureRequirements succeeded, but should've failed.\n");
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, D3DUSAGE_RTPATCHES, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckCubeTextureRequirements succeeded, but should've failed.\n");
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, D3DUSAGE_NPATCHES, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckCubeTextureRequirements succeeded, but should've failed.\n");
+
+    /* format */
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+
+    format = D3DFMT_UNKNOWN;
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8);
+
+    format = D3DX_DEFAULT;
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8);
+
+    format = D3DFMT_R8G8B8;
+    hr = D3DXCheckCubeTextureRequirements(device, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckCubeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == D3DFMT_X8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_X8R8G8B8);
+}
+
+static void test_D3DXCheckVolumeTextureRequirements(IDirect3DDevice9 *device)
+{
+    UINT width, height, depth, mipmaps, expected;
+    D3DFORMAT format;
+    D3DCAPS9 caps;
+    HRESULT hr;
+
+    IDirect3DDevice9_GetDeviceCaps(device, &caps);
+
+    if (!(caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) || (caps.MaxVolumeExtent < 256))
+    {
+        skip("Limited or no volume textures support.\n");
+        return;
+    }
+
+    /* general tests */
+    hr = D3DXCheckVolumeTextureRequirements(device, NULL, NULL, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXCheckVolumeTextureRequirements(device, NULL, NULL, NULL, NULL, D3DX_DEFAULT, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXCheckVolumeTextureRequirements(NULL, NULL, NULL, NULL, NULL, D3DX_DEFAULT, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    /* width, height, depth */
+    width = height = depth = D3DX_DEFAULT;
+    hr = D3DXCheckVolumeTextureRequirements(device, &width, &height, &depth, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == 256, "Returned width %d, expected %d\n", width, 256);
+    ok(height == 256, "Returned height %d, expected %d\n", height, 256);
+    ok(depth == 1, "Returned depth %d, expected %d\n", depth, 1);
+
+    width = D3DX_DEFAULT;
+    hr = D3DXCheckVolumeTextureRequirements(device, &width, NULL, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == 256, "Returned width %d, expected %d\n", width, 256);
+
+    width = D3DX_DEFAULT; height = 0; depth = 0;
+    hr = D3DXCheckVolumeTextureRequirements(device, &width, &height, &depth, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == 1, "Returned width %d, expected %d\n", width, 1);
+    ok(height == 1, "Returned height %d, expected %d\n", height, 1);
+    ok(depth == 1, "Returned height %d, expected %d\n", depth, 1);
+
+    width = 0; height = 0; depth = 0;
+    hr = D3DXCheckVolumeTextureRequirements(device, &width, &height, &depth, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == 1, "Returned width %d, expected %d\n", width, 1);
+    ok(height == 1, "Returned height %d, expected %d\n", height, 1);
+    ok(depth == 1, "Returned height %d, expected %d\n", depth, 1);
+
+    width = 0;
+    hr = D3DXCheckVolumeTextureRequirements(device, &width, NULL, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == 1, "Returned width %d, expected %d\n", width, 1);
+
+    width = 0xFFFFFFFE;
+    hr = D3DXCheckVolumeTextureRequirements(device, &width, NULL, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(width == caps.MaxVolumeExtent, "Returned width %d, expected %d\n", width, caps.MaxVolumeExtent);
+
+    /* format */
+    hr = D3DXCheckVolumeTextureRequirements(device, NULL, NULL, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+
+    format = D3DFMT_UNKNOWN;
+    hr = D3DXCheckVolumeTextureRequirements(device, NULL, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8);
+
+    format = D3DX_DEFAULT;
+    hr = D3DXCheckVolumeTextureRequirements(device, NULL, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8);
+
+    format = D3DFMT_R8G8B8;
+    hr = D3DXCheckVolumeTextureRequirements(device, NULL, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == D3DFMT_X8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_X8R8G8B8);
+
+    format = D3DFMT_DXT3;
+    hr = D3DXCheckVolumeTextureRequirements(device, NULL, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    if (has_3d_dxt3)
+        ok(format == D3DFMT_DXT3, "Returned format %u, expected %u\n", format, D3DFMT_DXT3);
+    else
+        todo_wine ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8);
+
+    /* mipmaps */
+    if (!(caps.TextureCaps & D3DPTEXTURECAPS_MIPVOLUMEMAP))
+    {
+        skip("No volume textures mipmapping support\n");
+        return;
+    }
+
+    width = height = depth = 64;
+    mipmaps = 9;
+    hr = D3DXCheckVolumeTextureRequirements(device, &width, &height, &depth, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(mipmaps == 7, "Returned mipmaps %d, expected %d\n", mipmaps, 7);
+
+    width = 284;
+    height = 143;
+    depth = 55;
+    mipmaps = 20;
+    expected = (caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2 && caps.MaxVolumeExtent >= 512) ? 10 : 9;
+    hr = D3DXCheckVolumeTextureRequirements(device, &width, &height, &depth, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(mipmaps == expected, "Returned mipmaps %d, expected %d\n", mipmaps, expected);
+
+    mipmaps = 0;
+    hr = D3DXCheckVolumeTextureRequirements(device, NULL, NULL, NULL, &mipmaps, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckVolumeTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(mipmaps == 9, "Returned mipmaps %d, expected %d\n", mipmaps, 9);
+
+    /* D3DUSAGE_AUTOGENMIPMAP is never supported for volume textures. */
+    ok(!is_autogenmipmap_supported(device, D3DRTYPE_VOLUMETEXTURE),
+            "D3DUSAGE_AUTOGENMIPMAP is unexpectedly supported on volume textures.\n");
+}
+
+static void test_D3DXCreateTexture(IDirect3DDevice9 *device)
+{
+    IDirect3DTexture9 *texture;
+    D3DSURFACE_DESC desc;
+    D3DCAPS9 caps;
+    UINT mipmaps;
+    HRESULT hr;
+
+    IDirect3DDevice9_GetDeviceCaps(device, &caps);
+
+    hr = D3DXCreateTexture(NULL, 0, 0, 0, 0, D3DX_DEFAULT, D3DPOOL_DEFAULT, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateTexture returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    /* width and height tests */
+
+    hr = D3DXCreateTexture(device, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+    if (texture)
+    {
+        hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
+        ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(desc.Format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", desc.Format, D3DFMT_A8R8G8B8);
+
+        ok(desc.Width == 256, "Returned width %d, expected %d\n", desc.Width, 256);
+        ok(desc.Height == 256, "Returned height %d, expected %d\n", desc.Height, 256);
+
+        IDirect3DTexture9_Release(texture);
+    }
+
+
+    hr = D3DXCreateTexture(device, 0, 0, 0, 0, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+    if (texture)
+    {
+        hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
+        ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(desc.Format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", desc.Format, D3DFMT_A8R8G8B8);
+
+        ok(desc.Width == 1, "Returned width %d, expected %d\n", desc.Width, 1);
+        ok(desc.Height == 1, "Returned height %d, expected %d\n", desc.Height, 1);
+
+        IDirect3DTexture9_Release(texture);
+    }
+
+
+    if (caps.TextureCaps & D3DPTEXTURECAPS_POW2)
+        skip("Hardware only supports pow2 textures\n");
+    else
+    {
+        hr = D3DXCreateTexture(device, D3DX_DEFAULT, 63, 0, 0, 0, D3DPOOL_DEFAULT, &texture);
+        ok((hr == D3D_OK) ||
+           /* may not work with conditional NPOT */
+           ((hr != D3D_OK) && (caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)),
+           "D3DXCreateTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        if (texture)
+        {
+            hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
+            ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK);
+            ok(desc.Format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", desc.Format, D3DFMT_A8R8G8B8);
+
+            /* Conditional NPOT may create a texture with different dimensions, so allow those
+               situations instead of returning a fail */
+
+            ok(desc.Width == 63 ||
+               (caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL),
+               "Returned width %d, expected %d\n", desc.Width, 63);
+
+            ok(desc.Height == 63 ||
+               (caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL),
+               "Returned height %d, expected %d\n", desc.Height, 63);
+
+            IDirect3DTexture9_Release(texture);
+        }
+    }
+
+    /* mipmaps */
+
+    hr = D3DXCreateTexture(device, 64, 63, 9, 0, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+    if (texture)
+    {
+        mipmaps = IDirect3DTexture9_GetLevelCount(texture);
+        ok(mipmaps == 7, "Returned mipmaps %d, expected %d\n", mipmaps, 7);
+
+        IDirect3DTexture9_Release(texture);
+    }
+
+
+    hr = D3DXCreateTexture(device, 284, 137, 9, 0, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+    if (texture)
+    {
+        mipmaps = IDirect3DTexture9_GetLevelCount(texture);
+        ok(mipmaps == 9, "Returned mipmaps %d, expected %d\n", mipmaps, 9);
+
+        IDirect3DTexture9_Release(texture);
+    }
+
+
+    hr = D3DXCreateTexture(device, 0, 0, 20, 0, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+    if (texture)
+    {
+        mipmaps = IDirect3DTexture9_GetLevelCount(texture);
+        ok(mipmaps == 1, "Returned mipmaps %d, expected %d\n", mipmaps, 1);
+
+        IDirect3DTexture9_Release(texture);
+    }
+
+
+    hr = D3DXCreateTexture(device, 64, 64, 1, 0, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+    if (texture)
+    {
+        mipmaps = IDirect3DTexture9_GetLevelCount(texture);
+        ok(mipmaps == 1, "Returned mipmaps %d, expected %d\n", mipmaps, 1);
+
+        IDirect3DTexture9_Release(texture);
+    }
+
+    /* usage */
+
+    hr = D3DXCreateTexture(device, 0, 0, 0, D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateTexture succeeded, but should have failed.\n");
+    hr = D3DXCreateTexture(device, 0, 0, 0, D3DUSAGE_DONOTCLIP, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateTexture succeeded, but should have failed.\n");
+    hr = D3DXCreateTexture(device, 0, 0, 0, D3DUSAGE_POINTS, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateTexture succeeded, but should have failed.\n");
+    hr = D3DXCreateTexture(device, 0, 0, 0, D3DUSAGE_RTPATCHES, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateTexture succeeded, but should have failed.\n");
+    hr = D3DXCreateTexture(device, 0, 0, 0, D3DUSAGE_NPATCHES, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateTexture succeeded, but should have failed.\n");
+
+    /* format */
+
+    hr = D3DXCreateTexture(device, 0, 0, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+    if (texture)
+    {
+        hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
+        ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(desc.Format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", desc.Format, D3DFMT_A8R8G8B8);
+
+        IDirect3DTexture9_Release(texture);
+    }
+
+
+    hr = D3DXCreateTexture(device, 0, 0, 0, 0, 0, D3DPOOL_DEFAULT, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+    if (texture)
+    {
+        hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
+        ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(desc.Format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", desc.Format, D3DFMT_A8R8G8B8);
+
+        IDirect3DTexture9_Release(texture);
+    }
+
+    /* D3DXCreateTextureFromResource */
+    hr = D3DXCreateTextureFromResourceA(device, NULL, MAKEINTRESOURCEA(IDB_BITMAP_1x1), &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromResource returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr)) IDirect3DTexture9_Release(texture);
+
+    hr = D3DXCreateTextureFromResourceA(device, NULL, MAKEINTRESOURCEA(IDD_BITMAPDATA_1x1), &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromResource returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr)) IDirect3DTexture9_Release(texture);
+
+    hr = D3DXCreateTextureFromResourceA(device, NULL, MAKEINTRESOURCEA(IDS_STRING), &texture);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXCreateTextureFromResource returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXCreateTextureFromResourceA(NULL, NULL, MAKEINTRESOURCEA(IDD_BITMAPDATA_1x1), &texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateTextureFromResource returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTextureFromResourceA(device, NULL, NULL, &texture);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXCreateTextureFromResource returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXCreateTextureFromResourceA(device, NULL, MAKEINTRESOURCEA(IDD_BITMAPDATA_1x1), NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateTextureFromResource returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+
+    /* D3DXCreateTextureFromResourceEx */
+    hr = D3DXCreateTextureFromResourceExA(device, NULL, MAKEINTRESOURCEA(IDD_BITMAPDATA_1x1), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromResourceEx returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr)) IDirect3DTexture9_Release(texture);
+
+    hr = D3DXCreateTextureFromResourceExA(device, NULL, MAKEINTRESOURCEA(IDS_STRING), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &texture);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXCreateTextureFromResourceEx returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXCreateTextureFromResourceExA(NULL, NULL, MAKEINTRESOURCEA(IDD_BITMAPDATA_1x1), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateTextureFromResourceEx returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTextureFromResourceExA(device, NULL, NULL, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &texture);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXCreateTextureFromResourceEx returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    hr = D3DXCreateTextureFromResourceExA(device, NULL, MAKEINTRESOURCEA(IDD_BITMAPDATA_1x1), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateTextureFromResourceEx returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+}
+
+static void test_D3DXFilterTexture(IDirect3DDevice9 *device)
+{
+    IDirect3DTexture9 *tex;
+    IDirect3DCubeTexture9 *cubetex;
+    IDirect3DVolumeTexture9 *voltex;
+    HRESULT hr;
+
+    hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 5, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, NULL, D3DX_DEFAULT, D3DX_FILTER_NONE);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, NULL, 0, D3DX_FILTER_NONE);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, NULL, 0, D3DX_FILTER_BOX + 1); /* Invalid filter */
+        ok(hr == D3DERR_INVALIDCALL, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, NULL, 5, D3DX_FILTER_NONE); /* Invalid miplevel */
+        ok(hr == D3DERR_INVALIDCALL, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    hr = D3DXFilterTexture(NULL, NULL, 0, D3DX_FILTER_NONE);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    /* Test different pools */
+    hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, NULL, 0, D3DX_FILTER_NONE);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, NULL, 0, D3DX_FILTER_NONE);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tex, NULL);
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, NULL, 0, D3DX_FILTER_POINT);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 0, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tex, NULL);
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, NULL, 0, D3DX_FILTER_POINT);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    /* Cube texture test */
+    hr = IDirect3DDevice9_CreateCubeTexture(device, 256, 5, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &cubetex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) cubetex, NULL, 0, D3DX_FILTER_NONE);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) cubetex, NULL, 0, D3DX_FILTER_BOX + 1); /* Invalid filter */
+        ok(hr == D3DERR_INVALIDCALL, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) cubetex, NULL, 5, D3DX_FILTER_NONE); /* Invalid miplevel */
+        ok(hr == D3DERR_INVALIDCALL, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+        IDirect3DCubeTexture9_Release(cubetex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    /* Volume texture test */
+    hr = IDirect3DDevice9_CreateVolumeTexture(device, 256, 256, 4, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &voltex, NULL);
+    if (SUCCEEDED(hr))
+    {
+        DWORD level_count = IDirect3DVolumeTexture9_GetLevelCount(voltex);
+
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) voltex, NULL, 0, D3DX_FILTER_NONE);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) voltex, NULL, 0, D3DX_DEFAULT);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) voltex, NULL, 0, D3DX_FILTER_BOX);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) voltex, NULL, level_count - 1, D3DX_DEFAULT);
+        ok(hr == D3D_OK, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) voltex, NULL, level_count, D3DX_DEFAULT);
+        ok(hr == D3DERR_INVALIDCALL, "D3DXFilterTexture returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+        IDirect3DVolumeTexture9_Release(voltex);
+    }
+    else
+        skip("Failed to create volume texture\n");
+
+    /* Test textures with D3DUSAGE_AUTOGENMIPMAP usage */
+    if (!is_autogenmipmap_supported(device, D3DRTYPE_TEXTURE))
+    {
+        skip("No D3DUSAGE_AUTOGENMIPMAP supported for textures\n");
+        return;
+    }
+
+    hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 0, D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tex, NULL);
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, NULL, 0, D3DX_FILTER_NONE);
+        ok(hr == D3D_OK, "D3dXFilteTexture returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 1, D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tex, NULL);
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, NULL, 0, D3DX_FILTER_NONE);
+        ok(hr == D3D_OK, "D3dXFilteTexture returned %#x, expected %#x\n", hr, D3D_OK);
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+}
+
+static BOOL color_match(const DWORD *value, const DWORD *expected)
+{
+    int i;
+
+    for (i = 0; i < 4; i++)
+    {
+        DWORD diff = value[i] > expected[i] ? value[i] - expected[i] : expected[i] - value[i];
+        if (diff > 1) return FALSE;
+    }
+    return TRUE;
+}
+
+static void WINAPI fillfunc(D3DXVECTOR4 *value, const D3DXVECTOR2 *texcoord,
+                            const D3DXVECTOR2 *texelsize, void *data)
+{
+    value->x = texcoord->x;
+    value->y = texcoord->y;
+    value->z = texelsize->x;
+    value->w = 1.0f;
+}
+
+static void test_D3DXFillTexture(IDirect3DDevice9 *device)
+{
+    IDirect3DTexture9 *tex;
+    HRESULT hr;
+    D3DLOCKED_RECT lock_rect;
+    DWORD x, y, m;
+    DWORD v[4], e[4];
+    DWORD value, expected, size, pitch;
+
+    size = 4;
+    hr = IDirect3DDevice9_CreateTexture(device, size, size, 0, 0, D3DFMT_A8R8G8B8,
+                                        D3DPOOL_MANAGED, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFillTexture(tex, fillfunc, NULL);
+        ok(hr == D3D_OK, "D3DXFillTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        for (m = 0; m < 3; m++)
+        {
+            hr = IDirect3DTexture9_LockRect(tex, m, &lock_rect, NULL, D3DLOCK_READONLY);
+            ok(hr == D3D_OK, "Couldn't lock the texture, error %#x\n", hr);
+            if (SUCCEEDED(hr))
+            {
+                pitch = lock_rect.Pitch / sizeof(DWORD);
+                for (y = 0; y < size; y++)
+                {
+                    for (x = 0; x < size; x++)
+                    {
+                        value = ((DWORD *)lock_rect.pBits)[y * pitch + x];
+                        v[0] = (value >> 24) & 0xff;
+                        v[1] = (value >> 16) & 0xff;
+                        v[2] = (value >> 8) & 0xff;
+                        v[3] = value & 0xff;
+
+                        e[0] = 0xff;
+                        e[1] = (x + 0.5f) / size * 255.0f + 0.5f;
+                        e[2] = (y + 0.5f) / size * 255.0f + 0.5f;
+                        e[3] = 255.0f / size + 0.5f;
+                        expected = e[0] << 24 | e[1] << 16 | e[2] << 8 | e[3];
+
+                        ok(color_match(v, e),
+                           "Texel at (%u, %u) doesn't match: %#x, expected %#x\n",
+                           x, y, value, expected);
+                    }
+                }
+                IDirect3DTexture9_UnlockRect(tex, m);
+            }
+            size >>= 1;
+        }
+
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_A1R5G5B5,
+                                        D3DPOOL_MANAGED, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFillTexture(tex, fillfunc, NULL);
+        ok(hr == D3D_OK, "D3DXFillTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = IDirect3DTexture9_LockRect(tex, 0, &lock_rect, NULL, D3DLOCK_READONLY);
+        ok(hr == D3D_OK, "Couldn't lock the texture, error %#x\n", hr);
+        if (SUCCEEDED(hr))
+        {
+            pitch = lock_rect.Pitch / sizeof(WORD);
+            for (y = 0; y < 4; y++)
+            {
+                for (x = 0; x < 4; x++)
+                {
+                    value = ((WORD *)lock_rect.pBits)[y * pitch + x];
+                    v[0] = value >> 15;
+                    v[1] = value >> 10 & 0x1f;
+                    v[2] = value >> 5 & 0x1f;
+                    v[3] = value & 0x1f;
+
+                    e[0] = 1;
+                    e[1] = (x + 0.5f) / 4.0f * 31.0f + 0.5f;
+                    e[2] = (y + 0.5f) / 4.0f * 31.0f + 0.5f;
+                    e[3] = 8;
+                    expected = e[0] << 15 | e[1] << 10 | e[2] << 5 | e[3];
+
+                    ok(color_match(v, e),
+                       "Texel at (%u, %u) doesn't match: %#x, expected %#x\n",
+                       x, y, value, expected);
+                }
+            }
+            IDirect3DTexture9_UnlockRect(tex, 0);
+        }
+
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    /* test floating-point textures */
+    hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_A16B16G16R16F,
+                                        D3DPOOL_MANAGED, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFillTexture(tex, fillfunc, NULL);
+        ok(hr == D3D_OK, "D3DXFillTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = IDirect3DTexture9_LockRect(tex, 0, &lock_rect, NULL, D3DLOCK_READONLY);
+        if (SUCCEEDED(hr))
+        {
+            pitch = lock_rect.Pitch / sizeof(WORD);
+            for (y = 0; y < 4; y++)
+            {
+                WORD *ptr = (WORD *)lock_rect.pBits + y * pitch;
+                for (x = 0; x < 4; x++)
+                {
+                    D3DXVECTOR4 got, expected;
+
+                    D3DXFloat16To32Array((FLOAT *)&got, (D3DXFLOAT16 *)ptr, 4);
+                    ptr += 4;
+
+                    expected.x = (x + 0.5f) / 4.0f;
+                    expected.y = (y + 0.5f) / 4.0f;
+                    expected.z = 1.0f / 4.0f;
+                    expected.w = 1.0f;
+
+                    expect_vec4(&expected, &got);
+                }
+            }
+
+            IDirect3DTexture9_UnlockRect(tex, 0);
+        }
+        else
+            skip("Failed to lock texture\n");
+
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create D3DFMT_A16B16G16R16F texture\n");
+
+    hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_A32B32G32R32F,
+                                        D3DPOOL_MANAGED, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFillTexture(tex, fillfunc, NULL);
+        ok(hr == D3D_OK, "D3DXFillTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        hr = IDirect3DTexture9_LockRect(tex, 0, &lock_rect, NULL, D3DLOCK_READONLY);
+        if (SUCCEEDED(hr))
+        {
+            pitch = lock_rect.Pitch / sizeof(float);
+            for (y = 0; y < 4; y++)
+            {
+                float *ptr = (float *)lock_rect.pBits + y * pitch;
+                for (x = 0; x < 4; x++)
+                {
+                    D3DXVECTOR4 got, expected;
+
+                    got.x = *ptr++;
+                    got.y = *ptr++;
+                    got.z = *ptr++;
+                    got.w = *ptr++;
+
+                    expected.x = (x + 0.5f) / 4.0f;
+                    expected.y = (y + 0.5f) / 4.0f;
+                    expected.z = 1.0f / 4.0f;
+                    expected.w = 1.0f;
+
+                    expect_vec4(&expected, &got);
+                }
+            }
+
+            IDirect3DTexture9_UnlockRect(tex, 0);
+        }
+        else
+            skip("Failed to lock texture\n");
+
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create D3DFMT_A32B32G32R32F texture\n");
+
+    /* test a compressed texture */
+    hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_DXT1,
+                                        D3DPOOL_MANAGED, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFillTexture(tex, fillfunc, NULL);
+        todo_wine ok(hr == D3D_OK, "D3DXFillTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        IDirect3DTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create D3DFMT_DXT1 texture\n");
+}
+
+static void WINAPI fillfunc_cube(D3DXVECTOR4 *value, const D3DXVECTOR3 *texcoord,
+                                 const D3DXVECTOR3 *texelsize, void *data)
+{
+    value->x = (texcoord->x + 1.0f) / 2.0f;
+    value->y = (texcoord->y + 1.0f) / 2.0f;
+    value->z = (texcoord->z + 1.0f) / 2.0f;
+    value->w = texelsize->x;
+}
+
+enum cube_coord
+{
+    XCOORD = 0,
+    XCOORDINV = 1,
+    YCOORD = 2,
+    YCOORDINV = 3,
+    ZERO = 4,
+    ONE = 5
+};
+
+static float get_cube_coord(enum cube_coord coord, unsigned int x, unsigned int y, unsigned int size)
+{
+    switch (coord)
+    {
+        case XCOORD:
+            return x + 0.5f;
+        case XCOORDINV:
+            return size - x - 0.5f;
+        case YCOORD:
+            return y + 0.5f;
+        case YCOORDINV:
+            return size - y - 0.5f;
+        case ZERO:
+            return 0.0f;
+        case ONE:
+            return size;
+        default:
+           trace("Unexpected coordinate value\n");
+           return 0.0f;
+    }
+}
+
+static void test_D3DXFillCubeTexture(IDirect3DDevice9 *device)
+{
+    IDirect3DCubeTexture9 *tex;
+    HRESULT hr;
+    D3DLOCKED_RECT lock_rect;
+    DWORD x, y, f, m;
+    DWORD v[4], e[4];
+    DWORD value, expected, size, pitch;
+    enum cube_coord coordmap[6][3] =
+        {
+            {ONE, YCOORDINV, XCOORDINV},
+            {ZERO, YCOORDINV, XCOORD},
+            {XCOORD, ONE, YCOORD},
+            {XCOORD, ZERO, YCOORDINV},
+            {XCOORD, YCOORDINV, ONE},
+            {XCOORDINV, YCOORDINV, ZERO}
+        };
+
+    size = 4;
+    hr = IDirect3DDevice9_CreateCubeTexture(device, size, 0, 0, D3DFMT_A8R8G8B8,
+                                            D3DPOOL_MANAGED, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFillCubeTexture(tex, fillfunc_cube, NULL);
+        ok(hr == D3D_OK, "D3DXFillCubeTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        for (m = 0; m < 3; m++)
+        {
+            for (f = 0; f < 6; f++)
+            {
+                hr = IDirect3DCubeTexture9_LockRect(tex, f, m, &lock_rect, NULL, D3DLOCK_READONLY);
+                ok(hr == D3D_OK, "Couldn't lock the texture, error %#x\n", hr);
+                if (SUCCEEDED(hr))
+                {
+                    pitch = lock_rect.Pitch / sizeof(DWORD);
+                    for (y = 0; y < size; y++)
+                    {
+                        for (x = 0; x < size; x++)
+                        {
+                            value = ((DWORD *)lock_rect.pBits)[y * pitch + x];
+                            v[0] = (value >> 24) & 0xff;
+                            v[1] = (value >> 16) & 0xff;
+                            v[2] = (value >> 8) & 0xff;
+                            v[3] = value & 0xff;
+
+                            e[0] = (f == 0) || (f == 1) ?
+                                0 : (BYTE)(255.0f / size * 2.0f + 0.5f);
+                            e[1] = get_cube_coord(coordmap[f][0], x, y, size) / size * 255.0f + 0.5f;
+                            e[2] = get_cube_coord(coordmap[f][1], x, y, size) / size * 255.0f + 0.5f;
+                            e[3] = get_cube_coord(coordmap[f][2], x, y, size) / size * 255.0f + 0.5f;
+                            expected = e[0] << 24 | e[1] << 16 | e[2] << 8 | e[3];
+
+                            ok(color_match(v, e),
+                               "Texel at face %u (%u, %u) doesn't match: %#x, expected %#x\n",
+                               f, x, y, value, expected);
+                        }
+                    }
+                    IDirect3DCubeTexture9_UnlockRect(tex, f, m);
+                }
+            }
+            size >>= 1;
+        }
+
+        IDirect3DCubeTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    hr = IDirect3DDevice9_CreateCubeTexture(device, 4, 1, 0, D3DFMT_A1R5G5B5,
+                                            D3DPOOL_MANAGED, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFillCubeTexture(tex, fillfunc_cube, NULL);
+        ok(hr == D3D_OK, "D3DXFillTexture returned %#x, expected %#x\n", hr, D3D_OK);
+        for (f = 0; f < 6; f++)
+        {
+            hr = IDirect3DCubeTexture9_LockRect(tex, f, 0, &lock_rect, NULL, D3DLOCK_READONLY);
+            ok(hr == D3D_OK, "Couldn't lock the texture, error %#x\n", hr);
+            if (SUCCEEDED(hr))
+            {
+                pitch = lock_rect.Pitch / sizeof(WORD);
+                for (y = 0; y < 4; y++)
+                {
+                    for (x = 0; x < 4; x++)
+                    {
+                        value = ((WORD *)lock_rect.pBits)[y * pitch + x];
+                        v[0] = value >> 15;
+                        v[1] = value >> 10 & 0x1f;
+                        v[2] = value >> 5 & 0x1f;
+                        v[3] = value & 0x1f;
+
+                        e[0] = (f == 0) || (f == 1) ?
+                            0 : (BYTE)(1.0f / size * 2.0f + 0.5f);
+                        e[1] = get_cube_coord(coordmap[f][0], x, y, 4) / 4 * 31.0f + 0.5f;
+                        e[2] = get_cube_coord(coordmap[f][1], x, y, 4) / 4 * 31.0f + 0.5f;
+                        e[3] = get_cube_coord(coordmap[f][2], x, y, 4) / 4 * 31.0f + 0.5f;
+                        expected = e[0] << 15 | e[1] << 10 | e[2] << 5 | e[3];
+
+                        ok(color_match(v, e),
+                           "Texel at face %u (%u, %u) doesn't match: %#x, expected %#x\n",
+                           f, x, y, value, expected);
+                    }
+                }
+                IDirect3DCubeTexture9_UnlockRect(tex, f, 0);
+            }
+        }
+
+        IDirect3DCubeTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+}
+
+static void WINAPI fillfunc_volume(D3DXVECTOR4 *value, const D3DXVECTOR3 *texcoord,
+                                   const D3DXVECTOR3 *texelsize, void *data)
+{
+    value->x = texcoord->x;
+    value->y = texcoord->y;
+    value->z = texcoord->z;
+    value->w = texelsize->x;
+}
+
+static void test_D3DXFillVolumeTexture(IDirect3DDevice9 *device)
+{
+    IDirect3DVolumeTexture9 *tex;
+    HRESULT hr;
+    D3DLOCKED_BOX lock_box;
+    DWORD x, y, z, m;
+    DWORD v[4], e[4];
+    DWORD value, expected, size, row_pitch, slice_pitch;
+
+    size = 4;
+    hr = IDirect3DDevice9_CreateVolumeTexture(device, size, size, size, 0, 0, D3DFMT_A8R8G8B8,
+                                              D3DPOOL_MANAGED, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFillVolumeTexture(tex, fillfunc_volume, NULL);
+        ok(hr == D3D_OK, "D3DXFillVolumeTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+        for (m = 0; m < 3; m++)
+        {
+            hr = IDirect3DVolumeTexture9_LockBox(tex, m, &lock_box, NULL, D3DLOCK_READONLY);
+            ok(hr == D3D_OK, "Couldn't lock the texture, error %#x\n", hr);
+            if (SUCCEEDED(hr))
+            {
+                row_pitch = lock_box.RowPitch / sizeof(DWORD);
+                slice_pitch = lock_box.SlicePitch / sizeof(DWORD);
+                for (z = 0; z < size; z++)
+                {
+                    for (y = 0; y < size; y++)
+                    {
+                        for (x = 0; x < size; x++)
+                        {
+                            value = ((DWORD *)lock_box.pBits)[z * slice_pitch + y * row_pitch + x];
+                            v[0] = (value >> 24) & 0xff;
+                            v[1] = (value >> 16) & 0xff;
+                            v[2] = (value >> 8) & 0xff;
+                            v[3] = value & 0xff;
+
+                            e[0] = 255.0f / size + 0.5f;
+                            e[1] = (x + 0.5f) / size * 255.0f + 0.5f;
+                            e[2] = (y + 0.5f) / size * 255.0f + 0.5f;
+                            e[3] = (z + 0.5f) / size * 255.0f + 0.5f;
+                            expected = e[0] << 24 | e[1] << 16 | e[2] << 8 | e[3];
+
+                            ok(color_match(v, e),
+                               "Texel at (%u, %u, %u) doesn't match: %#x, expected %#x\n",
+                               x, y, z, value, expected);
+                        }
+                    }
+                }
+                IDirect3DVolumeTexture9_UnlockBox(tex, m);
+            }
+            size >>= 1;
+        }
+
+        IDirect3DVolumeTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+
+    hr = IDirect3DDevice9_CreateVolumeTexture(device, 4, 4, 4, 1, 0, D3DFMT_A1R5G5B5,
+                                              D3DPOOL_MANAGED, &tex, NULL);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = D3DXFillVolumeTexture(tex, fillfunc_volume, NULL);
+        ok(hr == D3D_OK, "D3DXFillTexture returned %#x, expected %#x\n", hr, D3D_OK);
+        hr = IDirect3DVolumeTexture9_LockBox(tex, 0, &lock_box, NULL, D3DLOCK_READONLY);
+        ok(hr == D3D_OK, "Couldn't lock the texture, error %#x\n", hr);
+        if (SUCCEEDED(hr))
+        {
+            row_pitch = lock_box.RowPitch / sizeof(WORD);
+            slice_pitch = lock_box.SlicePitch / sizeof(WORD);
+            for (z = 0; z < 4; z++)
+            {
+                for (y = 0; y < 4; y++)
+                {
+                    for (x = 0; x < 4; x++)
+                    {
+                        value = ((WORD *)lock_box.pBits)[z * slice_pitch + y * row_pitch + x];
+                        v[0] = value >> 15;
+                        v[1] = value >> 10 & 0x1f;
+                        v[2] = value >> 5 & 0x1f;
+                        v[3] = value & 0x1f;
+
+                        e[0] = 1;
+                        e[1] = (x + 0.5f) / 4 * 31.0f + 0.5f;
+                        e[2] = (y + 0.5f) / 4 * 31.0f + 0.5f;
+                        e[3] = (z + 0.5f) / 4 * 31.0f + 0.5f;
+                        expected = e[0] << 15 | e[1] << 10 | e[2] << 5 | e[3];
+
+                        ok(color_match(v, e),
+                           "Texel at (%u, %u, %u) doesn't match: %#x, expected %#x\n",
+                           x, y, z, value, expected);
+                    }
+                }
+            }
+            IDirect3DVolumeTexture9_UnlockBox(tex, 0);
+        }
+
+        IDirect3DVolumeTexture9_Release(tex);
+    }
+    else
+        skip("Failed to create texture\n");
+}
+
+static void test_D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    IDirect3DTexture9 *texture;
+    D3DRESOURCETYPE type;
+    D3DSURFACE_DESC desc;
+    D3DLOCKED_RECT lock_rect;
+    int i;
+    DWORD level_count;
+
+    hr = D3DXCreateTextureFromFileInMemory(device, dds_16bit, sizeof(dds_16bit), &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr)) IDirect3DTexture9_Release(texture);
+
+    hr = D3DXCreateTextureFromFileInMemory(device, dds_24bit, sizeof(dds_24bit), &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr)) IDirect3DTexture9_Release(texture);
+
+    hr = D3DXCreateTextureFromFileInMemory(device, dds_24bit, sizeof(dds_24bit) - 1, &texture);
+    ok(hr == D3DXERR_INVALIDDATA, "D3DXCreateTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DXERR_INVALIDDATA);
+
+    /* Check that D3DXCreateTextureFromFileInMemory accepts cube texture dds file (only first face texture is loaded) */
+    hr = D3DXCreateTextureFromFileInMemory(device, dds_cube_map, sizeof(dds_cube_map), &texture);
+    todo_wine_if (!has_2d_dxt5)
+        ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemory returned %#x, expected %#x.\n", hr, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        type = IDirect3DTexture9_GetType(texture);
+        ok(type == D3DRTYPE_TEXTURE, "IDirect3DTexture9_GetType returned %u, expected %u\n", type, D3DRTYPE_TEXTURE);
+        hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
+        ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(desc.Width == 4, "Width is %u, expected 4\n", desc.Width);
+        ok(desc.Height == 4, "Height is %u, expected 4\n", desc.Height);
+        hr = IDirect3DTexture9_LockRect(texture, 0, &lock_rect, NULL, D3DLOCK_READONLY);
+        ok(hr == D3D_OK, "IDirect3DTexture9_LockRect returned %#x, expected %#x\n", hr, D3D_OK);
+        if (SUCCEEDED(hr))
+        {
+            for (i = 0; i < 16; i++)
+                ok(((BYTE *)lock_rect.pBits)[i] == dds_cube_map[128 + i],
+                        "Byte at index %u is 0x%02x, expected 0x%02x.\n",
+                        i, ((BYTE *)lock_rect.pBits)[i], dds_cube_map[128 + i]);
+            IDirect3DTexture9_UnlockRect(texture, 0);
+        }
+        IDirect3DTexture9_Release(texture);
+
+    }
+
+    /* Volume textures work too. */
+    hr = D3DXCreateTextureFromFileInMemory(device, dds_volume_map, sizeof(dds_volume_map), &texture);
+    todo_wine_if (!has_2d_dxt3)
+        ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemory returned %#x, expected %#x.\n", hr, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        type = IDirect3DTexture9_GetType(texture);
+        ok(type == D3DRTYPE_TEXTURE, "IDirect3DTexture9_GetType returned %u, expected %u.\n", type, D3DRTYPE_TEXTURE);
+        level_count = IDirect3DBaseTexture9_GetLevelCount((IDirect3DBaseTexture9 *)texture);
+        todo_wine ok(level_count == 3, "Texture has %u mip levels, 3 expected.\n", level_count);
+        hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
+        ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc returned %#x, expected %#x.\n", hr, D3D_OK);
+        ok(desc.Width == 4, "Width is %u, expected 4.\n", desc.Width);
+        ok(desc.Height == 4, "Height is %u, expected 4.\n", desc.Height);
+
+        hr = IDirect3DTexture9_LockRect(texture, 0, &lock_rect, NULL, D3DLOCK_READONLY);
+        ok(hr == D3D_OK, "IDirect3DTexture9_LockRect returned %#x, expected %#x.\n", hr, D3D_OK);
+        if (SUCCEEDED(hr))
+        {
+            for (i = 0; i < 16; ++i)
+                ok(((BYTE *)lock_rect.pBits)[i] == dds_volume_map[128 + i],
+                        "Byte at index %u is 0x%02x, expected 0x%02x.\n",
+                        i, ((BYTE *)lock_rect.pBits)[i], dds_volume_map[128 + i]);
+            IDirect3DTexture9_UnlockRect(texture, 0);
+        }
+        /* The lower texture levels are apparently generated by filtering the level 0 surface
+         * I.e. following levels from the file are ignored. */
+        IDirect3DTexture9_Release(texture);
+    }
+}
+
+static void test_D3DXCreateTextureFromFileInMemoryEx(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    IDirect3DTexture9 *texture;
+    unsigned int miplevels;
+    IDirect3DSurface9 *surface;
+    D3DSURFACE_DESC desc;
+
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_16bit, sizeof(dds_16bit), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
+        0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x\n", hr, D3D_OK);
+    IDirect3DTexture9_Release(texture);
+
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_16bit, sizeof(dds_16bit), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
+        D3DUSAGE_DYNAMIC, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x\n", hr, D3D_OK);
+    IDirect3DTexture9_Release(texture);
+
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_24bit, sizeof(dds_24bit), D3DX_DEFAULT,
+            D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_DYNAMIC, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
+            D3DX_DEFAULT, D3DX_SKIP_DDS_MIP_LEVELS(1, D3DX_FILTER_POINT), 0, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x\n", hr, D3D_OK);
+    miplevels = IDirect3DTexture9_GetLevelCount(texture);
+    ok(miplevels == 1, "Got miplevels %u, expected %u.\n", miplevels, 1);
+    IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
+    IDirect3DSurface9_GetDesc(surface, &desc);
+    ok(desc.Width == 1 && desc.Height == 1,
+            "Surface dimensions are %ux%u, expected 1x1.\n", desc.Width, desc.Height);
+    IDirect3DSurface9_Release(surface);
+    IDirect3DTexture9_Release(texture);
+
+    if (!is_autogenmipmap_supported(device, D3DRTYPE_TEXTURE))
+    {
+        skip("No D3DUSAGE_AUTOGENMIPMAP support for textures\n");
+        return;
+    }
+
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_16bit, sizeof(dds_16bit), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
+        D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x\n", hr, D3D_OK);
+    IDirect3DTexture9_Release(texture);
+
+    /* Checking for color key format overrides. */
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_16bit, sizeof(dds_16bit),
+            D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
+            D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK);
+    IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
+    IDirect3DSurface9_GetDesc(surface, &desc);
+    ok(desc.Format == D3DFMT_X1R5G5B5, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_X1R5G5B5);
+    IDirect3DSurface9_Release(surface);
+    IDirect3DTexture9_Release(texture);
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_16bit, sizeof(dds_16bit),
+            D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
+            D3DX_DEFAULT, D3DX_DEFAULT, 0xff000000, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK);
+    IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
+    IDirect3DSurface9_GetDesc(surface, &desc);
+    ok(desc.Format == D3DFMT_A1R5G5B5, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_A1R5G5B5);
+    IDirect3DSurface9_Release(surface);
+    IDirect3DTexture9_Release(texture);
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_16bit, sizeof(dds_16bit),
+            D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_X1R5G5B5, D3DPOOL_DEFAULT,
+            D3DX_DEFAULT, D3DX_DEFAULT, 0xff000000, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK);
+    IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
+    IDirect3DSurface9_GetDesc(surface, &desc);
+    ok(desc.Format == D3DFMT_X1R5G5B5, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_X1R5G5B5);
+    IDirect3DSurface9_Release(surface);
+    IDirect3DTexture9_Release(texture);
+
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_24bit, sizeof(dds_24bit),
+            D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
+            D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK);
+    IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
+    IDirect3DSurface9_GetDesc(surface, &desc);
+    ok(desc.Format == D3DFMT_X8R8G8B8, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_X8R8G8B8);
+    IDirect3DSurface9_Release(surface);
+    IDirect3DTexture9_Release(texture);
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_24bit, sizeof(dds_24bit),
+            D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
+            D3DX_DEFAULT, D3DX_DEFAULT, 0xff000000, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK);
+    IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
+    IDirect3DSurface9_GetDesc(surface, &desc);
+    ok(desc.Format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_A8R8G8B8);
+    IDirect3DSurface9_Release(surface);
+    IDirect3DTexture9_Release(texture);
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_24bit, sizeof(dds_24bit),
+            D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT,
+            D3DX_DEFAULT, D3DX_DEFAULT, 0xff000000, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK);
+    IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
+    IDirect3DSurface9_GetDesc(surface, &desc);
+    ok(desc.Format == D3DFMT_X8R8G8B8, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_X8R8G8B8);
+    IDirect3DSurface9_Release(surface);
+    IDirect3DTexture9_Release(texture);
+
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, png_grayscale, sizeof(png_grayscale),
+            D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
+            D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK);
+    IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
+    IDirect3DSurface9_GetDesc(surface, &desc);
+    ok(desc.Format == D3DFMT_L8, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_L8);
+    IDirect3DSurface9_Release(surface);
+    IDirect3DTexture9_Release(texture);
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, png_grayscale, sizeof(png_grayscale),
+            D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
+            D3DX_DEFAULT, D3DX_DEFAULT, 0xff000000, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK);
+    IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
+    IDirect3DSurface9_GetDesc(surface, &desc);
+    ok(desc.Format == D3DFMT_A8L8, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_A8L8);
+    IDirect3DSurface9_Release(surface);
+    IDirect3DTexture9_Release(texture);
+    hr = D3DXCreateTextureFromFileInMemoryEx(device, png_grayscale, sizeof(png_grayscale),
+            D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
+            D3DX_DEFAULT, D3DX_DEFAULT, 0xff000000, NULL, NULL, &texture);
+    ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK);
+    IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
+    IDirect3DSurface9_GetDesc(surface, &desc);
+    ok(desc.Format == D3DFMT_L8, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_L8);
+    IDirect3DSurface9_Release(surface);
+    IDirect3DTexture9_Release(texture);
+}
+
+static void test_D3DXCreateCubeTextureFromFileInMemory(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    ULONG ref;
+    DWORD levelcount;
+    IDirect3DCubeTexture9 *cube_texture;
+    D3DSURFACE_DESC surface_desc;
+
+    hr = D3DXCreateCubeTextureFromFileInMemory(NULL, dds_cube_map, sizeof(dds_cube_map), &cube_texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateCubeTextureFromFileInMemory(device, NULL, sizeof(dds_cube_map), &cube_texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateCubeTextureFromFileInMemory(device, dds_cube_map, 0, &cube_texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateCubeTextureFromFileInMemory(device, dds_cube_map, sizeof(dds_cube_map), NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateCubeTextureFromFileInMemory(device, dds_cube_map, sizeof(dds_cube_map), &cube_texture);
+    if (SUCCEEDED(hr))
+    {
+        levelcount = IDirect3DCubeTexture9_GetLevelCount(cube_texture);
+        todo_wine ok(levelcount == 3, "GetLevelCount returned %u, expected 3\n", levelcount);
+
+        hr = IDirect3DCubeTexture9_GetLevelDesc(cube_texture, 0, &surface_desc);
+        ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(surface_desc.Width == 4, "Got width %u, expected 4\n", surface_desc.Width);
+        ok(surface_desc.Height == 4, "Got height %u, expected 4\n", surface_desc.Height);
+
+        ref = IDirect3DCubeTexture9_Release(cube_texture);
+        ok(ref == 0, "Invalid reference count. Got %u, expected 0\n", ref);
+    } else skip("Couldn't create cube texture\n");
+}
+
+static void test_D3DXCreateCubeTextureFromFileInMemoryEx(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    IDirect3DCubeTexture9 *cube_texture;
+
+    if (!is_autogenmipmap_supported(device, D3DRTYPE_CUBETEXTURE))
+    {
+        skip("No D3DUSAGE_AUTOGENMIPMAP support for cube textures\n");
+        return;
+    }
+
+    hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, dds_cube_map, sizeof(dds_cube_map), D3DX_DEFAULT, D3DX_DEFAULT,
+        D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &cube_texture);
+    todo_wine_if (!has_cube_dxt5)
+        ok(hr == D3D_OK, "D3DXCreateCubeTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK);
+    if (SUCCEEDED(hr)) IDirect3DCubeTexture9_Release(cube_texture);
+}
+
+static void test_D3DXCreateVolumeTextureFromFileInMemory(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    ULONG ref;
+    DWORD levelcount;
+    IDirect3DVolumeTexture9 *volume_texture;
+    D3DVOLUME_DESC volume_desc;
+
+    hr = D3DXCreateVolumeTextureFromFileInMemory(NULL, dds_volume_map, sizeof(dds_volume_map), &volume_texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateVolumeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateVolumeTextureFromFileInMemory(device, NULL, sizeof(dds_volume_map), &volume_texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateVolumeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateVolumeTextureFromFileInMemory(device, dds_volume_map, 0, &volume_texture);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateVolumeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateVolumeTextureFromFileInMemory(device, dds_volume_map, sizeof(dds_volume_map), NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXCreateVolumeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateVolumeTextureFromFileInMemory(device, dds_volume_map, sizeof(dds_volume_map), &volume_texture);
+    todo_wine_if (!has_3d_dxt3)
+        ok(hr == D3D_OK, "D3DXCreateVolumeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        levelcount = IDirect3DVolumeTexture9_GetLevelCount(volume_texture);
+        ok(levelcount == 3, "GetLevelCount returned %u, expected 3\n", levelcount);
+
+        hr = IDirect3DVolumeTexture9_GetLevelDesc(volume_texture, 0, &volume_desc);
+        ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(volume_desc.Width == 4, "Got width %u, expected 4\n", volume_desc.Width);
+        ok(volume_desc.Height == 4, "Got height %u, expected 4\n", volume_desc.Height);
+        ok(volume_desc.Depth == 2, "Got depth %u, expected 2\n", volume_desc.Depth);
+        ok(volume_desc.Pool == D3DPOOL_MANAGED, "Got pool %u, expected D3DPOOL_MANAGED\n", volume_desc.Pool);
+
+        hr = IDirect3DVolumeTexture9_GetLevelDesc(volume_texture, 1, &volume_desc);
+        ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK);
+        ok(volume_desc.Width == 2, "Got width %u, expected 2\n", volume_desc.Width);
+        ok(volume_desc.Height == 2, "Got height %u, expected 2\n", volume_desc.Height);
+        ok(volume_desc.Depth == 1, "Got depth %u, expected 1\n", volume_desc.Depth);
+
+        ref = IDirect3DVolumeTexture9_Release(volume_texture);
+        ok(ref == 0, "Invalid reference count. Got %u, expected 0\n", ref);
+    }
+}
+
+/* fills positive x face with red color */
+static void WINAPI fill_cube_positive_x(D3DXVECTOR4 *out, const D3DXVECTOR3 *tex_coord, const D3DXVECTOR3 *texel_size, void *data)
+{
+    memset(out, 0, sizeof(*out));
+    if (tex_coord->x > 0 && fabs(tex_coord->x) > fabs(tex_coord->y) && fabs(tex_coord->x) > fabs(tex_coord->z))
+        out->x = 1;
+}
+
+static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    IDirect3DTexture9 *texture;
+    IDirect3DCubeTexture9 *cube_texture;
+    IDirect3DVolumeTexture9 *volume_texture;
+    ID3DXBuffer *buffer;
+    void *buffer_pointer;
+    DWORD buffer_size;
+    D3DXIMAGE_INFO info;
+    D3DXIMAGE_FILEFORMAT file_format;
+
+    /* textures */
+    hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 0, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &texture, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create texture\n");
+        return;
+    }
+
+    for (file_format = D3DXIFF_BMP; file_format <= D3DXIFF_JPG; file_format++)
+    {
+        hr = D3DXSaveTextureToFileInMemory(&buffer, file_format, (IDirect3DBaseTexture9 *)texture, NULL);
+        ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+        if (SUCCEEDED(hr))
+        {
+            buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer);
+            buffer_size = ID3DXBuffer_GetBufferSize(buffer);
+            hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info);
+            ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+            ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256);
+            ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256);
+            ok(info.MipLevels == 1, "Got miplevels %u, expected %u\n", info.MipLevels, 1);
+            ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE);
+            ok(info.ImageFileFormat == file_format, "Got file format %#x, expected %#x\n", info.ImageFileFormat, file_format);
+            ID3DXBuffer_Release(buffer);
+        }
+    }
+
+    todo_wine {
+    hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, (IDirect3DBaseTexture9 *)texture, NULL);
+    ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer);
+        buffer_size = ID3DXBuffer_GetBufferSize(buffer);
+        hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info);
+        ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+        ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256);
+        ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256);
+        ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9);
+        ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE);
+        ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS);
+        ID3DXBuffer_Release(buffer);
+    }
+    }
+
+    IDirect3DTexture9_Release(texture);
+
+    /* cube textures */
+    hr = IDirect3DDevice9_CreateCubeTexture(device, 256, 0, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &cube_texture, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create cube texture\n");
+        return;
+    }
+
+    hr = D3DXFillCubeTexture(cube_texture, fill_cube_positive_x, NULL);
+    ok(hr == D3D_OK, "D3DXFillCubeTexture returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_BMP, (IDirect3DBaseTexture9 *)cube_texture, NULL);
+    ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        IDirect3DSurface9 *surface;
+
+        buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer);
+        buffer_size = ID3DXBuffer_GetBufferSize(buffer);
+        hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info);
+        ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+        ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256);
+        ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256);
+        ok(info.MipLevels == 1, "Got miplevels %u, expected %u\n", info.MipLevels, 1);
+        ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE);
+        ok(info.ImageFileFormat == D3DXIFF_BMP, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_BMP);
+
+        /* positive x face is saved */
+        hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 256, 256, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, NULL);
+        if (SUCCEEDED(hr))
+        {
+            D3DLOCKED_RECT locked_rect;
+
+            hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, buffer_pointer, buffer_size, NULL, D3DX_FILTER_NONE, 0, NULL);
+            ok(hr == D3D_OK, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+            hr = IDirect3DSurface9_LockRect(surface, &locked_rect, NULL, D3DLOCK_READONLY);
+            if (SUCCEEDED(hr))
+            {
+                DWORD *color = locked_rect.pBits;
+                ok(*color == 0x00ff0000, "Got color %#x, expected %#x\n", *color, 0x00ff0000);
+                IDirect3DSurface9_UnlockRect(surface);
+            }
+
+            IDirect3DSurface9_Release(surface);
+        } else skip("Failed to create surface\n");
+
+        ID3DXBuffer_Release(buffer);
+    }
+
+    todo_wine {
+    hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, (IDirect3DBaseTexture9 *)cube_texture, NULL);
+    ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer);
+        buffer_size = ID3DXBuffer_GetBufferSize(buffer);
+        hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info);
+        ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+        ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256);
+        ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256);
+        ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9);
+        ok(info.ResourceType == D3DRTYPE_CUBETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_CUBETEXTURE);
+        ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS);
+        ID3DXBuffer_Release(buffer);
+    }
+    }
+
+    IDirect3DCubeTexture9_Release(cube_texture);
+
+    /* volume textures */
+    hr = IDirect3DDevice9_CreateVolumeTexture(device, 256, 256, 256, 0, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &volume_texture, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create volume texture\n");
+        return;
+    }
+
+    todo_wine {
+    hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_BMP, (IDirect3DBaseTexture9 *)volume_texture, NULL);
+    ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer);
+        buffer_size = ID3DXBuffer_GetBufferSize(buffer);
+        hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info);
+        ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+        ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256);
+        ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256);
+        ok(info.Depth == 1, "Got depth %u, expected %u\n", info.Depth, 1);
+        ok(info.MipLevels == 1, "Got miplevels %u, expected %u\n", info.MipLevels, 1);
+        ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE);
+        ok(info.ImageFileFormat == D3DXIFF_BMP, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_BMP);
+        ID3DXBuffer_Release(buffer);
+    }
+
+    hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, (IDirect3DBaseTexture9 *)volume_texture, NULL);
+    ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+    if (SUCCEEDED(hr))
+    {
+        buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer);
+        buffer_size = ID3DXBuffer_GetBufferSize(buffer);
+        hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info);
+        ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+        ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256);
+        ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256);
+        ok(info.Depth == 256, "Got depth %u, expected %u\n", info.Depth, 256);
+        ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9);
+        ok(info.ResourceType == D3DRTYPE_VOLUMETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_VOLUMETEXTURE);
+        ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS);
+        ID3DXBuffer_Release(buffer);
+    }
+    }
+
+    IDirect3DVolumeTexture9_Release(volume_texture);
+}
+
+static void test_texture_shader(void)
+{
+    static const DWORD shader_zero[] = {0x0};
+    static const DWORD shader_invalid[] = {0xeeee0100};
+    static const DWORD shader_empty[] = {0xfffe0200, 0x0000ffff};
+#if 0
+float4 main(float3 pos : POSITION, float3 size : PSIZE) : COLOR
+{
+    return float4(pos, 1.0);
+}
+#endif
+    static const DWORD shader_code[] =
+    {
+        0x54580100, 0x0015fffe, 0x42415443, 0x0000001c, 0x0000001f, 0x54580100, 0x00000000, 0x00000000,
+        0x00000100, 0x0000001c, 0x4d007874, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820, 0x6853204c,
+        0x72656461, 0x6d6f4320, 0x656c6970, 0x2e392072, 0x392e3932, 0x332e3235, 0x00313131, 0x000afffe,
+        0x54494c43, 0x00000004, 0x00000000, 0x3ff00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0x00000000, 0x00000000, 0x0014fffe, 0x434c5846, 0x00000002, 0x10000003, 0x00000001, 0x00000000,
+        0x00000003, 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0x10000001, 0x00000001, 0x00000000,
+        0x00000001, 0x00000000, 0x00000000, 0x00000004, 0x00000003, 0xf0f0f0f0, 0x0f0f0f0f, 0x0000ffff,
+    };
+    IDirect3DVolumeTexture9 *volume_texture;
+    IDirect3DCubeTexture9 *cube_texture;
+    D3DPRESENT_PARAMETERS d3dpp;
+    IDirect3DTexture9 *texture;
+    IDirect3DDevice9 *device;
+    ID3DXTextureShader *tx;
+    unsigned int x, y, z;
+    ID3DXBuffer *buffer;
+    unsigned int *data;
+    D3DLOCKED_RECT lr;
+    D3DLOCKED_BOX lb;
+    IDirect3D9 *d3d;
+    D3DCAPS9 caps;
+    HRESULT hr;
+    HWND wnd;
+
+    hr = D3DXCreateTextureShader(NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#x.\n", hr);
+
+    hr = D3DXCreateTextureShader(NULL, &tx);
+    ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#x.\n", hr);
+
+    hr = D3DXCreateTextureShader(shader_invalid, &tx);
+    todo_wine ok(hr == D3DXERR_INVALIDDATA, "Got unexpected hr %#x.\n", hr);
+
+    hr = D3DXCreateTextureShader(shader_zero, &tx);
+    todo_wine ok(hr == D3DXERR_INVALIDDATA, "Got unexpected hr %#x.\n", hr);
+
+    hr = D3DXCreateTextureShader(shader_empty, &tx);
+    todo_wine ok(hr == D3DXERR_INVALIDDATA, "Got unexpected hr %#x.\n", hr);
+
+    hr = D3DXCreateTextureShader(shader_code, &tx);
+    ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
+
+    hr = tx->lpVtbl->GetFunction(tx, &buffer);
+    todo_wine ok(SUCCEEDED(hr), "Failed to get texture shader bytecode.\n");
+    if (FAILED(hr))
+    {
+        skip("Texture shaders not supported, skipping further tests.\n");
+        IUnknown_Release(tx);
+        return;
+    }
+    ID3DXBuffer_Release(buffer);
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window.\n");
+        IUnknown_Release(tx);
+        return;
+    }
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    if (!d3d)
+    {
+        skip("Couldn't create IDirect3D9 object.\n");
+        DestroyWindow(wnd);
+        IUnknown_Release(tx);
+        return;
+    }
+
+    ZeroMemory(&d3dpp, sizeof(d3dpp));
+    d3dpp.Windowed = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+            D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
+    if (FAILED(hr))
+    {
+        skip("Failed to create IDirect3DDevice9 object, hr %#x.\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        IUnknown_Release(tx);
+        return;
+    }
+
+    IDirect3DDevice9_GetDeviceCaps(device, &caps);
+
+    hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM,
+            &texture, NULL);
+    ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
+
+    hr = D3DXFillTextureTX(texture, tx);
+    ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DTexture9_LockRect(texture, 0, &lr, NULL, D3DLOCK_READONLY);
+    ok(SUCCEEDED(hr), "Locking texture failed, hr %#x.\n", hr);
+    data = lr.pBits;
+    for (y = 0; y < 256; ++y)
+    {
+        for (x = 0; x < 256; ++x)
+        {
+            unsigned int expected = 0xff000000 | x << 16 | y << 8;
+            /* The third position coordinate is apparently undefined for 2D textures. */
+            unsigned int color = data[y * lr.Pitch / sizeof(*data) + x] & 0xffffff00;
+
+            ok(compare_color(color, expected, 1), "Unexpected color %08x at (%u, %u).\n", color, x, y);
+        }
+    }
+    hr = IDirect3DTexture9_UnlockRect(texture, 0);
+    ok(SUCCEEDED(hr), "Unlocking texture failed, hr %#x.\n", hr);
+
+    IDirect3DTexture9_Release(texture);
+
+    if (!(caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP))
+    {
+        skip("Cube textures not supported, skipping tests.\n");
+        goto cleanup;
+    }
+
+    hr = IDirect3DDevice9_CreateCubeTexture(device, 256, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM,
+            &cube_texture, NULL);
+    ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
+
+    hr = D3DXFillCubeTextureTX(cube_texture, tx);
+    ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
+
+    for (z = 0; z < 6; ++z)
+    {
+        static const char * const mapping[6][3] =
+        {
+            {"-x", "-y", "1"},
+            {"+x", "-y", "0"},
+            {"+y", "1", "+x"},
+            {"-y", "0", "+x"},
+            {"1", "-y", "+x"},
+            {"0", "-y", "-x"},
+        };
+
+        hr = IDirect3DCubeTexture9_LockRect(cube_texture, z, 0, &lr, NULL, D3DLOCK_READONLY);
+        ok(SUCCEEDED(hr), "Locking texture failed, hr %#x.\n", hr);
+        data = lr.pBits;
+        for (y = 0; y < 256; ++y)
+        {
+            for (x = 0; x < 256; ++x)
+            {
+                unsigned int color = data[y * lr.Pitch / sizeof(*data) + x];
+                unsigned int expected = 0xff000000;
+                unsigned int i;
+
+                for (i = 0; i < 3; ++i)
+                {
+                    int component;
+
+                    if (mapping[z][i][0] == '0')
+                        component = 0;
+                    else if (mapping[z][i][0] == '1')
+                        component = 255;
+                    else
+                        component = mapping[z][i][1] == 'x' ? x * 2 - 255 : y * 2 - 255;
+                    if (mapping[z][i][0] == '-')
+                        component = -component;
+                    expected |= max(component, 0) << i * 8;
+                }
+                ok(compare_color(color, expected, 1), "Unexpected color %08x at (%u, %u, %u).\n",
+                        color, x, y, z);
+            }
+        }
+        hr = IDirect3DCubeTexture9_UnlockRect(cube_texture, z, 0);
+        ok(SUCCEEDED(hr), "Unlocking texture failed, hr %#x.\n", hr);
+    }
+
+    IDirect3DCubeTexture9_Release(cube_texture);
+
+    if (!(caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) || caps.MaxVolumeExtent < 64)
+    {
+        skip("Volume textures not supported, skipping test.\n");
+        goto cleanup;
+    }
+    hr = IDirect3DDevice9_CreateVolumeTexture(device, 64, 64, 64, 1, 0, D3DFMT_A8R8G8B8,
+            D3DPOOL_SYSTEMMEM, &volume_texture, NULL);
+    ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
+
+    hr = D3DXFillVolumeTextureTX(volume_texture, tx);
+    ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DVolumeTexture9_LockBox(volume_texture, 0, &lb, NULL, D3DLOCK_READONLY);
+    ok(SUCCEEDED(hr), "Locking texture failed, hr %#x.\n", hr);
+    data = lb.pBits;
+    for (z = 0; z < 64; ++z)
+    {
+        for (y = 0; y < 64; ++y)
+        {
+            for (x = 0; x < 64; ++x)
+            {
+                unsigned int expected = 0xff000000 | ((x * 4 + 2) << 16) | ((y * 4 + 2) << 8) | (z * 4 + 2);
+                unsigned int color = data[z * lb.SlicePitch / sizeof(*data) + y * lb.RowPitch / sizeof(*data) + x];
+
+                ok(compare_color(color, expected, 1), "Unexpected color %08x at (%u, %u, %u).\n",
+                        color, x, y, z);
+            }
+        }
+    }
+    hr = IDirect3DVolumeTexture9_UnlockBox(volume_texture, 0);
+    ok(SUCCEEDED(hr), "Unlocking texture failed, hr %#x.\n", hr);
+
+    IDirect3DVolumeTexture9_Release(volume_texture);
+
+ cleanup:
+    IDirect3DDevice9_Release(device);
+    IDirect3D9_Release(d3d);
+    DestroyWindow(wnd);
+    IUnknown_Release(tx);
+}
+
+START_TEST(texture)
+{
+    HWND wnd;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *device;
+    D3DPRESENT_PARAMETERS d3dpp;
+    HRESULT hr;
+    ULONG ref;
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window\n");
+        return;
+    }
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    if (!d3d) {
+        skip("Couldn't create IDirect3D9 object\n");
+        DestroyWindow(wnd);
+        return;
+    }
+
+    ZeroMemory(&d3dpp, sizeof(d3dpp));
+    d3dpp.Windowed   = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
+    if (FAILED(hr)) {
+        skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    /* Check whether DXTn textures are supported. */
+    has_2d_dxt3 = SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
+            D3DFMT_X8R8G8B8, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3));
+    hr = IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
+            D3DFMT_X8R8G8B8, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5);
+    has_2d_dxt5 = SUCCEEDED(hr);
+    hr = IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
+            D3DFMT_X8R8G8B8, 0, D3DRTYPE_CUBETEXTURE, D3DFMT_DXT5);
+    has_cube_dxt5 = SUCCEEDED(hr);
+    has_3d_dxt3 = SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
+            D3DFMT_X8R8G8B8, 0, D3DRTYPE_VOLUMETEXTURE, D3DFMT_DXT3));
+
+    test_D3DXCheckTextureRequirements(device);
+    test_D3DXCheckCubeTextureRequirements(device);
+    test_D3DXCheckVolumeTextureRequirements(device);
+    test_D3DXCreateTexture(device);
+    test_D3DXFilterTexture(device);
+    test_D3DXFillTexture(device);
+    test_D3DXFillCubeTexture(device);
+    test_D3DXFillVolumeTexture(device);
+    test_D3DXCreateTextureFromFileInMemory(device);
+    test_D3DXCreateTextureFromFileInMemoryEx(device);
+    test_D3DXCreateCubeTextureFromFileInMemory(device);
+    test_D3DXCreateCubeTextureFromFileInMemoryEx(device);
+    test_D3DXCreateVolumeTextureFromFileInMemory(device);
+    test_D3DXSaveTextureToFileInMemory(device);
+
+    ref = IDirect3DDevice9_Release(device);
+    ok(!ref, "Device has %u references left.\n", ref);
+
+    IDirect3D9_Release(d3d);
+    DestroyWindow(wnd);
+
+    test_texture_shader();
+}
diff --git a/modules/rostests/winetests/d3dx9_36/volume.c b/modules/rostests/winetests/d3dx9_36/volume.c
new file mode 100644 (file)
index 0000000..53260c1
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Tests for the D3DX9 volume functions
+ *
+ * Copyright 2012 Józef Kucia
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include "wine/test.h"
+#include "d3dx9tex.h"
+
+/* 4x4x2 volume map dds, 2 mipmaps */
+static const unsigned char dds_volume_map[] =
+{
+    0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x8a,0x00,0x04,0x00,0x00,0x00,
+    0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+    0x04,0x00,0x00,0x00,0x44,0x58,0x54,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00,
+    0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x87,0x0f,0x78,0x05,0x05,0x50,0x50,
+    0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x2f,0x7e,0xcf,0x79,0x01,0x54,0x5c,0x5c,
+    0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x84,0xef,0x7b,0xaa,0xab,0xab,0xab
+};
+
+#define check_pixel_4bpp(box, x, y, z, color) _check_pixel_4bpp(__LINE__, box, x, y, z, color)
+static inline void _check_pixel_4bpp(unsigned int line, const D3DLOCKED_BOX *box, int x, int y, int z, DWORD expected_color)
+{
+   DWORD color = ((DWORD *)box->pBits)[x + (y * box->RowPitch + z * box->SlicePitch) / 4];
+   ok_(__FILE__, line)(color == expected_color, "Got color 0x%08x, expected 0x%08x\n", color, expected_color);
+}
+
+static inline void set_box(D3DBOX *box, UINT left, UINT top, UINT right, UINT bottom, UINT front, UINT back)
+{
+    box->Left = left;
+    box->Top = top;
+    box->Right = right;
+    box->Bottom = bottom;
+    box->Front = front;
+    box->Back = back;
+}
+
+static void test_D3DXLoadVolumeFromMemory(IDirect3DDevice9 *device)
+{
+    int i, x, y, z;
+    HRESULT hr;
+    D3DBOX src_box, dst_box;
+    D3DLOCKED_BOX locked_box;
+    IDirect3DVolume9 *volume;
+    IDirect3DVolumeTexture9 *volume_texture;
+    const DWORD pixels[] = { 0xc3394cf0, 0x235ae892, 0x09b197fd, 0x8dc32bf6,
+                             0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+                             0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+                             0xffffffff, 0x00000000, 0xffffffff, 0x00000000 };
+
+    hr = IDirect3DDevice9_CreateVolumeTexture(device, 256, 256, 4, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
+            &volume_texture, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create volume texture.\n");
+        return;
+    }
+
+    IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, 0, &volume);
+
+    set_box(&src_box, 0, 0, 4, 1, 0, 4);
+    set_box(&dst_box, 0, 0, 4, 1, 0, 4);
+
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    if (FAILED(hr))
+    {
+        win_skip("D3DXLoadVolumeFromMemory failed with error %#x, skipping some tests.\n", hr);
+        return;
+    }
+
+    IDirect3DVolume9_LockBox(volume, &locked_box, &dst_box, D3DLOCK_READONLY);
+    for (i = 0; i < 16; i++) check_pixel_4bpp(&locked_box, i % 4, 0, i / 4, pixels[i]);
+    IDirect3DVolume9_UnlockBox(volume);
+
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_UNKNOWN, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == E_FAIL, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, E_FAIL);
+
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, NULL, pixels, D3DFMT_A8R8G8B8, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3D_OK, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, NULL, D3DFMT_A8R8G8B8, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 16, NULL, NULL, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    set_box(&src_box, 0, 0, 4, 4, 0, 1);
+    set_box(&dst_box, 0, 0, 4, 4, 0, 1);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, sizeof(pixels), NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3D_OK, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    IDirect3DVolume9_LockBox(volume, &locked_box, &dst_box, D3DLOCK_READONLY);
+    for (i = 0; i < 16; i++) check_pixel_4bpp(&locked_box, i % 4, i / 4, 0, pixels[i]);
+    IDirect3DVolume9_UnlockBox(volume);
+
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, NULL, pixels, D3DFMT_A8R8G8B8, 16, sizeof(pixels), NULL, &src_box, D3DX_FILTER_NONE, 0);
+    ok(hr == D3D_OK, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    IDirect3DVolume9_LockBox(volume, &locked_box, NULL, D3DLOCK_READONLY);
+    for (i = 0; i < 16; i++) check_pixel_4bpp(&locked_box, i % 4, i / 4, 0, pixels[i]);
+    for (z = 0; z < 4; z++)
+    {
+        for (y = 0; y < 256; y++)
+        {
+            for (x = 0; x < 256; x++)
+                if (z != 0 || y >= 4 || x >= 4) check_pixel_4bpp(&locked_box, x, y, z, 0);
+        }
+    }
+    IDirect3DVolume9_UnlockBox(volume);
+
+    set_box(&src_box, 0, 0, 2, 2, 1, 2);
+    set_box(&dst_box, 0, 0, 2, 2, 0, 1);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 8, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3D_OK, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    IDirect3DVolume9_LockBox(volume, &locked_box, &dst_box, D3DLOCK_READONLY);
+    for (i = 0; i < 4; i++) check_pixel_4bpp(&locked_box, i % 2, i / 2, 0, pixels[i + 4]);
+    IDirect3DVolume9_UnlockBox(volume);
+
+    set_box(&src_box, 0, 0, 2, 2, 2, 3);
+    set_box(&dst_box, 0, 0, 2, 2, 1, 2);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 8, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3D_OK, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    IDirect3DVolume9_LockBox(volume, &locked_box, &dst_box, D3DLOCK_READONLY);
+    for (i = 0; i < 4; i++) check_pixel_4bpp(&locked_box, i % 2, i / 2, 0, pixels[i + 8]);
+    IDirect3DVolume9_UnlockBox(volume);
+
+    set_box(&src_box, 0, 0, 4, 1, 0, 4);
+
+    set_box(&dst_box, -1, -1, 3, 0, 0, 4);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    set_box(&dst_box, 254, 254, 258, 255, 0, 4);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    set_box(&dst_box, 4, 1, 0, 0, 0, 4);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    set_box(&dst_box, 0, 0, 0, 0, 0, 0);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    set_box(&dst_box, 0, 0, 0, 0, 0, 1);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    set_box(&dst_box, 300, 300, 300, 300, 0, 0);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    IDirect3DVolume9_Release(volume);
+    IDirect3DVolumeTexture9_Release(volume_texture);
+
+    hr = IDirect3DDevice9_CreateVolumeTexture(device, 256, 256, 4, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &volume_texture, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create volume texture\n");
+        return;
+    }
+
+    IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, 0, &volume);
+
+    set_box(&src_box, 0, 0, 4, 1, 0, 4);
+    set_box(&dst_box, 0, 0, 4, 1, 0, 4);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 16, NULL, &src_box, D3DX_DEFAULT, 0);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    IDirect3DVolume9_Release(volume);
+    IDirect3DVolumeTexture9_Release(volume_texture);
+
+    hr = IDirect3DDevice9_CreateVolumeTexture(device, 8, 8, 1, 1, D3DUSAGE_DYNAMIC, D3DFMT_DXT1, D3DPOOL_DEFAULT, &volume_texture, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create volume texture\n");
+        return;
+    }
+
+    IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, 0, &volume);
+
+    set_box(&src_box, 1, 1, 7, 7, 0, 1);
+    set_box(&dst_box, 1, 1, 7, 7, 0, 1);
+    hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 32, NULL, &src_box, D3DX_DEFAULT, 0);
+    todo_wine ok(hr == D3D_OK, "D3DXLoadVolumeFromMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    IDirect3DVolume9_Release(volume);
+    IDirect3DVolumeTexture9_Release(volume_texture);
+}
+
+static void test_D3DXLoadVolumeFromFileInMemory(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    D3DBOX src_box;
+    IDirect3DVolume9 *volume;
+    IDirect3DVolumeTexture9 *volume_texture;
+
+    hr = IDirect3DDevice9_CreateVolumeTexture(device, 4, 4, 2, 1, D3DUSAGE_DYNAMIC, D3DFMT_DXT3, D3DPOOL_DEFAULT,
+            &volume_texture, NULL);
+    if (FAILED(hr))
+    {
+        skip("Failed to create volume texture\n");
+        return;
+    }
+
+    IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, 0, &volume);
+
+    hr = D3DXLoadVolumeFromFileInMemory(volume, NULL, NULL, dds_volume_map, sizeof(dds_volume_map), NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3D_OK, "D3DXLoadVolumeFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    hr = D3DXLoadVolumeFromFileInMemory(volume, NULL, NULL, NULL, sizeof(dds_volume_map), NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadVolumeFromFileInMemory(volume, NULL, NULL, NULL, 0, NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadVolumeFromFileInMemory(volume, NULL, NULL, dds_volume_map, 0, NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXLoadVolumeFromFileInMemory(NULL, NULL, NULL, dds_volume_map, sizeof(dds_volume_map), NULL, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    set_box(&src_box, 0, 0, 4, 4, 0, 2);
+    hr = D3DXLoadVolumeFromFileInMemory(volume, NULL, NULL, dds_volume_map, sizeof(dds_volume_map), &src_box, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3D_OK, "D3DXLoadVolumeFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
+
+    set_box(&src_box, 0, 0, 0, 0, 0, 0);
+    hr = D3DXLoadVolumeFromFileInMemory(volume, NULL, NULL, dds_volume_map, sizeof(dds_volume_map), &src_box, D3DX_DEFAULT, 0, NULL);
+    ok(hr == E_FAIL, "D3DXLoadVolumeFromFileInMemory returned %#x, expected %#x\n", hr, E_FAIL);
+
+    set_box(&src_box, 0, 0, 5, 4, 0, 2);
+    hr = D3DXLoadVolumeFromFileInMemory(volume, NULL, NULL, dds_volume_map, sizeof(dds_volume_map), &src_box, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    set_box(&src_box, 0, 0, 4, 4, 0, 3);
+    hr = D3DXLoadVolumeFromFileInMemory(volume, NULL, NULL, dds_volume_map, sizeof(dds_volume_map), &src_box, D3DX_DEFAULT, 0, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXLoadVolumeFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    IDirect3DVolume9_Release(volume);
+    IDirect3DVolumeTexture9_Release(volume_texture);
+}
+
+START_TEST(volume)
+{
+    HWND wnd;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *device;
+    D3DPRESENT_PARAMETERS d3dpp;
+    HRESULT hr;
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window\n");
+        return;
+    }
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    if (!d3d)
+    {
+        skip("Couldn't create IDirect3D9 object\n");
+        DestroyWindow(wnd);
+        return;
+    }
+
+    ZeroMemory(&d3dpp, sizeof(d3dpp));
+    d3dpp.Windowed   = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
+    if(FAILED(hr))
+    {
+        skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    test_D3DXLoadVolumeFromMemory(device);
+    test_D3DXLoadVolumeFromFileInMemory(device);
+
+    IDirect3DDevice9_Release(device);
+    IDirect3D9_Release(d3d);
+    DestroyWindow(wnd);
+}
diff --git a/modules/rostests/winetests/d3dx9_36/xfile.c b/modules/rostests/winetests/d3dx9_36/xfile.c
new file mode 100644 (file)
index 0000000..46b4ee2
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2012 Christian Costa
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "d3dx9.h"
+#include "d3dx9xof.h"
+
+static const char templates_bad_file_type1[] =
+"xOf 0302txt 0064\n";
+
+static const char templates_bad_file_version[] =
+"xof 0102txt 0064\n";
+
+static const char templates_bad_file_type2[] =
+"xof 0302foo 0064\n";
+
+static const char templates_bad_file_float_size[] =
+"xof 0302txt 0050\n";
+
+static const char templates_parse_error[] =
+"xof 0302txt 0064"
+"foobar;\n";
+
+static const char templates[] =
+"xof 0302txt 0064"
+"template Header"
+"{"
+"<3D82AB43-62DA-11CF-AB39-0020AF71E433>"
+"WORD major;"
+"WORD minor;"
+"DWORD flags;"
+"}\n";
+
+static char objects[] =
+"xof 0302txt 0064\n"
+"Header Object\n"
+"{\n"
+"1; 2; 3;\n"
+"}\n";
+
+static char object_noname[] =
+"xof 0302txt 0064\n"
+"Header\n"
+"{\n"
+"1; 2; 3;\n"
+"}\n";
+
+static char template_using_index_color_lower[] =
+"xof 0302txt 0064\n"
+"template MeshVertexColors\n"
+"{\n"
+"<1630B821-7842-11cf-8F52-0040333594A3>\n"
+"DWORD nVertexColors;\n"
+"array indexColor vertexColors[nVertexColors];\n"
+"}\n";
+
+static char template_using_index_color_upper[] =
+"xof 0302txt 0064\n"
+"template MeshVertexColors\n"
+"{\n"
+"<1630B821-7842-11cf-8F52-0040333594A3>\n"
+"DWORD nVertexColors;\n"
+"array IndexColor vertexColors[nVertexColors];\n"
+"}\n";
+
+static void test_templates(void)
+{
+    ID3DXFile *d3dxfile;
+    HRESULT ret;
+
+    ret = D3DXFileCreate(NULL);
+    ok(ret == E_POINTER, "D3DXCreateFile returned %#x, expected %#x\n", ret, E_POINTER);
+
+    ret = D3DXFileCreate(&d3dxfile);
+    ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret);
+
+    ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_type1, sizeof(templates_bad_file_type1) - 1);
+    ok(ret == D3DXFERR_BADFILETYPE, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILETYPE);
+
+    ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_version, sizeof(templates_bad_file_version) - 1);
+    ok(ret == D3DXFERR_BADFILEVERSION, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILEVERSION);
+
+    ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_type2, sizeof(templates_bad_file_type2) - 1);
+    ok(ret == D3DXFERR_BADFILETYPE, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILETYPE);
+
+    ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_bad_file_float_size, sizeof(templates_bad_file_float_size) - 1);
+    ok(ret == D3DXFERR_BADFILEFLOATSIZE, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_BADFILEFLOATSIZE);
+
+    ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates_parse_error, sizeof(templates_parse_error) - 1);
+    ok(ret == D3DXFERR_PARSEERROR, "RegisterTemplates returned %#x, expected %#x\n", ret, D3DXFERR_PARSEERROR);
+
+    ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates, sizeof(templates) - 1);
+    ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret);
+
+    d3dxfile->lpVtbl->Release(d3dxfile);
+}
+
+static void test_lock_unlock(void)
+{
+    ID3DXFile *d3dxfile;
+    D3DXF_FILELOADMEMORY memory;
+    ID3DXFileEnumObject *enum_object;
+    ID3DXFileData *data_object;
+    const void *data;
+    SIZE_T size;
+    HRESULT ret;
+
+    ret = D3DXFileCreate(&d3dxfile);
+    ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret);
+
+    ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates, sizeof(templates) - 1);
+    ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret);
+
+    memory.lpMemory = objects;
+    memory.dSize = sizeof(objects) - 1;
+
+    ret = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &memory, D3DXF_FILELOAD_FROMMEMORY, &enum_object);
+    ok(ret == S_OK, "CreateEnumObject failed with %#x\n", ret);
+
+    ret = enum_object->lpVtbl->GetChild(enum_object, 0, &data_object);
+    ok(ret == S_OK, "GetChild failed with %#x\n", ret);
+
+    ret = data_object->lpVtbl->Unlock(data_object);
+    ok(ret == S_OK, "Unlock failed with %#x\n", ret);
+    ret = data_object->lpVtbl->Lock(data_object, &size, &data);
+    ok(ret == S_OK, "Lock failed with %#x\n", ret);
+    ret = data_object->lpVtbl->Lock(data_object, &size, &data);
+    ok(ret == S_OK, "Lock failed with %#x\n", ret);
+    ret = data_object->lpVtbl->Unlock(data_object);
+    ok(ret == S_OK, "Unlock failed with %#x\n", ret);
+    ret = data_object->lpVtbl->Unlock(data_object);
+    ok(ret == S_OK, "Unlock failed with %#x\n", ret);
+
+    data_object->lpVtbl->Release(data_object);
+    enum_object->lpVtbl->Release(enum_object);
+    d3dxfile->lpVtbl->Release(d3dxfile);
+}
+
+static void test_getname(void)
+{
+    ID3DXFile *d3dxfile;
+    D3DXF_FILELOADMEMORY memory;
+    ID3DXFileEnumObject *enum_object;
+    ID3DXFileData *data_object;
+    SIZE_T length;
+    char name[100];
+    HRESULT ret;
+
+    ret = D3DXFileCreate(&d3dxfile);
+    ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret);
+
+    ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, templates, sizeof(templates) - 1);
+    ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret);
+
+    /* Check object with name */
+    memory.lpMemory = objects;
+    memory.dSize = sizeof(objects) - 1;
+    ret = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &memory, D3DXF_FILELOAD_FROMMEMORY, &enum_object);
+    ok(ret == S_OK, "CreateEnumObject failed with %#x\n", ret);
+    ret = enum_object->lpVtbl->GetChild(enum_object, 0, &data_object);
+    ok(ret == S_OK, "GetChild failed with %#x\n", ret);
+
+    ret = data_object->lpVtbl->GetName(data_object, NULL, NULL);
+    ok(ret == D3DXFERR_BADVALUE, "GetName returned %#x, expected %#x\n", ret, D3DXFERR_BADVALUE);
+    ret = data_object->lpVtbl->GetName(data_object, name, NULL);
+    ok(ret == D3DXFERR_BADVALUE, "GetName returned %#x, expected %#x\n", ret, D3DXFERR_BADVALUE);
+    ret = data_object->lpVtbl->GetName(data_object, NULL, &length);
+    ok(ret == S_OK, "GetName failed with %#x\n", ret);
+    ok(length == 7, "Returned length should be 7 instead of %ld\n", length);
+    length = sizeof(name);
+    ret = data_object->lpVtbl->GetName(data_object, name, &length);
+    ok(ret == S_OK, "GetName failed with %#x\n", ret);
+    ok(length == 7, "Returned length should be 7 instead of %ld\n", length);
+    ok(!strcmp(name, "Object"), "Returned string should be 'Object' instead of '%s'\n", name);
+    length = 3;
+    ret = data_object->lpVtbl->GetName(data_object, name, &length);
+    ok(ret== D3DXFERR_BADVALUE, "GetName returned %#x, expected %#x\n", ret, D3DXFERR_BADVALUE);
+
+    data_object->lpVtbl->Release(data_object);
+    enum_object->lpVtbl->Release(enum_object);
+
+    /* Check object without name */
+    memory.lpMemory = object_noname;
+    memory.dSize = sizeof(object_noname) - 1;
+    ret = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &memory, D3DXF_FILELOAD_FROMMEMORY, &enum_object);
+    ok(ret == S_OK, "CreateEnumObject failed with %#x\n", ret);
+    ret = enum_object->lpVtbl->GetChild(enum_object, 0, &data_object);
+    ok(ret == S_OK, "GetChild failed with %#x\n", ret);
+
+    /* Contrary to d3dxof, d3dx9_36 returns an empty string with a null byte when no name is available.
+     * If the input size is 0, it returns a length of 1 without touching the buffer */
+    ret = data_object->lpVtbl->GetName(data_object, NULL, &length);
+    ok(ret == S_OK, "GetName failed with %#x\n", ret);
+    ok(length == 1, "Returned length should be 1 instead of %ld\n", length);
+    length = 0;
+    name[0] = 0x7f;
+    ret = data_object->lpVtbl->GetName(data_object, name, &length);
+    ok(ret == S_OK, "GetName failed with %#x\n", ret);
+    ok(length == 1, "Returned length should be 1 instead of %ld\n", length);
+    ok(name[0] == 0x7f, "First character is %#x instead of 0x7f\n", name[0]);
+    length = sizeof(name);
+    name[0] = 0x7f;
+    ret = data_object->lpVtbl->GetName(data_object, name, &length);
+    ok(ret == S_OK, "GetName failed with %#x\n", ret);
+    ok(length == 1, "Returned length should be 1 instead of %ld\n", length);
+    ok(name[0] == 0, "First character is %#x instead of 0x00\n", name[0]);
+
+    data_object->lpVtbl->Release(data_object);
+    enum_object->lpVtbl->Release(enum_object);
+    d3dxfile->lpVtbl->Release(d3dxfile);
+}
+
+static void test_type_index_color(void)
+{
+    ID3DXFile *d3dxfile;
+    HRESULT ret;
+
+    ret = D3DXFileCreate(&d3dxfile);
+    ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret);
+
+    /* Test that 'indexColor' can be used (same as IndexedColor in standard templates) and is case sensitive */
+    ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, template_using_index_color_lower, sizeof(template_using_index_color_lower) - 1);
+    ok(ret == S_OK, "RegisterTemplates failed with %#x\n", ret);
+    ret = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, template_using_index_color_upper, sizeof(template_using_index_color_upper) - 1);
+    ok(ret == D3DXFERR_PARSEERROR, "RegisterTemplates returned %#x instead of %#x\n", ret, D3DXFERR_PARSEERROR);
+
+    d3dxfile->lpVtbl->Release(d3dxfile);
+}
+
+static void process_data(ID3DXFileData *xfile_data, int level)
+{
+    HRESULT ret;
+    char name[100];
+    GUID clsid;
+    GUID clsid_type;
+    SIZE_T len = sizeof(name);
+    int i;
+    const BYTE *data;
+    SIZE_T size;
+    SIZE_T children;
+
+    ret = xfile_data->lpVtbl->GetId(xfile_data, &clsid);
+    ok(ret == S_OK, "ID3DXFileData_GetId failed with %#x\n", ret);
+    ret = xfile_data->lpVtbl->GetName(xfile_data, name, &len);
+    ok(ret == S_OK, "ID3DXFileData_GetName failed with %#x\n", ret);
+    ret = xfile_data->lpVtbl->GetType(xfile_data, &clsid_type);
+    ok(ret == S_OK, "IDirectXFileData_GetType failed with %#x\n", ret);
+    ret = xfile_data->lpVtbl->Lock(xfile_data, &size, (const void**)&data);
+    ok(ret == S_OK, "IDirectXFileData_Lock failed with %#x\n", ret);
+
+    for (i = 0; i < level; i++)
+        printf("  ");
+
+    printf("Found object '%s' - %s - %s - %lu\n",
+           len ? name : "", wine_dbgstr_guid(&clsid), wine_dbgstr_guid(&clsid_type), size);
+
+    if (size)
+    {
+        int j;
+        for (j = 0; j < size; j++)
+        {
+            if (j && !(j%16))
+                printf("\n");
+            printf("%02x ", data[j]);
+        }
+        printf("\n");
+    }
+
+    ret = xfile_data->lpVtbl->Unlock(xfile_data);
+    ok(ret == S_OK, "ID3DXFileData_Unlock failed with %#x\n", ret);
+
+    ret = xfile_data->lpVtbl->GetChildren(xfile_data, &children);
+    ok(ret == S_OK, "ID3DXFileData_GetChildren failed with %#x\n", ret);
+
+    level++;
+
+    for (i = 0; i < children; i++)
+    {
+        ID3DXFileData *child;
+        int j;
+
+        ret = xfile_data->lpVtbl->GetChild(xfile_data, i, &child);
+        ok(ret == S_OK, "ID3DXFileData_GetChild failed with %#x\n", ret);
+        for (j = 0; j < level; j++)
+            printf("  ");
+        if (child->lpVtbl->IsReference(child))
+            printf("Found Data Reference (%d)\n", i + 1);
+        else
+            printf("Found Data (%d)\n", i + 1);
+
+        process_data(child, level);
+
+        child->lpVtbl->Release(child);
+    }
+}
+
+/* Dump an X file 'objects.x' and its related templates file 'templates.x' if they are both presents
+ * Useful for debug by comparing outputs from native and builtin dlls */
+static void test_dump(void)
+{
+    HRESULT ret;
+    ULONG ref;
+    ID3DXFile *xfile = NULL;
+    ID3DXFileEnumObject *xfile_enum_object = NULL;
+    HANDLE file;
+    void *data;
+    DWORD size;
+    SIZE_T children;
+    int i;
+
+    /* Dump data only if there is an object and a template */
+    file = CreateFileA("objects.x", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+    if (file == INVALID_HANDLE_VALUE)
+        return;
+    CloseHandle(file);
+
+    file = CreateFileA("templates.x", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+    if (file == INVALID_HANDLE_VALUE)
+        return;
+
+    data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 10000);
+
+    if (!ReadFile(file, data, 10000, &size, NULL))
+    {
+        skip("Templates file is too big\n");
+        goto exit;
+    }
+
+    printf("Load templates file (%u bytes)\n", size);
+
+    ret = D3DXFileCreate(&xfile);
+    ok(ret == S_OK, "D3DXCreateFile failed with %#x\n", ret);
+
+    ret = xfile->lpVtbl->RegisterTemplates(xfile, data, size);
+    ok(ret == S_OK, "ID3DXFileImpl_RegisterTemplates failed with %#x\n", ret);
+
+    ret = xfile->lpVtbl->CreateEnumObject(xfile, (void*)"objects.x", D3DXF_FILELOAD_FROMFILE, &xfile_enum_object);
+    ok(ret == S_OK, "ID3DXFile_CreateEnumObject failed with %#x\n", ret);
+
+    ret = xfile_enum_object->lpVtbl->GetChildren(xfile_enum_object, &children);
+    ok(ret == S_OK, "ID3DXFileEnumObject_GetChildren failed with %#x\n", ret);
+
+    for (i = 0; i < children; i++)
+    {
+        ID3DXFileData *child;
+        ret = xfile_enum_object->lpVtbl->GetChild(xfile_enum_object, i, &child);
+        ok(ret == S_OK, "ID3DXFileEnumObject_GetChild failed with %#x\n", ret);
+        printf("\n");
+        process_data(child, 0);
+        child->lpVtbl->Release(child);
+    }
+
+    ref = xfile_enum_object->lpVtbl->Release(xfile_enum_object);
+    ok(ref == 0, "Got refcount %u, expected 0\n", ref);
+
+    ref = xfile->lpVtbl->Release(xfile);
+    ok(ref == 0, "Got refcount %u, expected 0\n", ref);
+
+
+exit:
+    CloseHandle(file);
+    HeapFree(GetProcessHeap(), 0, data);
+}
+
+START_TEST(xfile)
+{
+    test_templates();
+    test_lock_unlock();
+    test_getname();
+    test_type_index_color();
+    test_dump();
+}