[AMSTREAM] We don't need to define WIDL_C_INLINE_WRAPPERS here anymore.
[reactos.git] / dll / directx / wine / d3dx9_36 / shader.c
index 1ef3159..71c0122 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright 2008 Luis Busquets
  * Copyright 2009 Matteo Bruni
+ * Copyright 2010, 2013, 2016 Christian Costa
  * Copyright 2011 Travis Athougies
  *
  * This library is free software; you can redistribute it and/or
  */
 
 #include "d3dx9_36_private.h"
+
+#include <stdio.h>
+
 #include "d3dcompiler.h"
 
-/* This function is not declared in the SDK headers yet */
-HRESULT WINAPI D3DAssemble(LPCVOID data, SIZE_T datasize, LPCSTR filename,
-                           const D3D_SHADER_MACRO *defines, ID3DInclude *include,
-                           UINT flags,
-                           ID3DBlob **shader, ID3DBlob **error_messages);
+/* This function is not declared in the SDK headers yet. */
+HRESULT WINAPI D3DAssemble(const void *data, SIZE_T datasize, const char *filename,
+        const D3D_SHADER_MACRO *defines, ID3DInclude *include, UINT flags,
+        ID3DBlob **shader, ID3DBlob **error_messages);
 
 static inline BOOL is_valid_bytecode(DWORD token)
 {
@@ -142,6 +145,7 @@ const char * WINAPI D3DXGetVertexShaderProfile(struct IDirect3DDevice9 *device)
 HRESULT WINAPI D3DXFindShaderComment(const DWORD *byte_code, DWORD fourcc, const void **data, UINT *size)
 {
     const DWORD *ptr = byte_code;
+    DWORD version;
 
     TRACE("byte_code %p, fourcc %x, data %p, size %p\n", byte_code, fourcc, data, size);
 
@@ -149,7 +153,18 @@ HRESULT WINAPI D3DXFindShaderComment(const DWORD *byte_code, DWORD fourcc, const
     if (size) *size = 0;
 
     if (!byte_code) return D3DERR_INVALIDCALL;
-    if (!is_valid_bytecode(*byte_code)) return D3DXERR_INVALIDDATA;
+
+    version = *ptr >> 16;
+    if (version != 0x4658         /* FX */
+            && version != 0x5458  /* TX */
+            && version != 0x7ffe
+            && version != 0x7fff
+            && version != 0xfffe  /* VS */
+            && version != 0xffff) /* PS */
+    {
+        WARN("Invalid data supplied\n");
+        return D3DXERR_INVALIDDATA;
+    }
 
     while (*++ptr != D3DSIO_END)
     {
@@ -162,7 +177,7 @@ HRESULT WINAPI D3DXFindShaderComment(const DWORD *byte_code, DWORD fourcc, const
             if (*(ptr + 1) == fourcc)
             {
                 UINT ctab_size = (comment_size - 1) * sizeof(DWORD);
-                LPCVOID ctab_data = ptr + 2;
+                const void *ctab_data = ptr + 2;
                 if (size)
                     *size = ctab_size;
                 if (data)
@@ -195,34 +210,63 @@ HRESULT WINAPI D3DXAssembleShader(const char *data, UINT data_len, const D3DXMAC
     return hr;
 }
 
+static const void *main_file_data;
+
+static CRITICAL_SECTION from_file_mutex;
+static CRITICAL_SECTION_DEBUG from_file_mutex_debug =
+{
+    0, 0, &from_file_mutex,
+    {
+        &from_file_mutex_debug.ProcessLocksList,
+        &from_file_mutex_debug.ProcessLocksList
+    },
+    0, 0, {(DWORD_PTR)(__FILE__ ": from_file_mutex")}
+};
+static CRITICAL_SECTION from_file_mutex = {&from_file_mutex_debug, -1, 0, 0, 0, 0};
+
 /* D3DXInclude private implementation, used to implement
-   D3DXAssembleShaderFromFile from D3DXAssembleShader */
-/* To be able to correctly resolve include search paths we have to store
-   the pathname of each include file. We store the pathname pointer right
-   before the file data. */
-static HRESULT WINAPI d3dincludefromfile_open(ID3DXInclude *iface,
-                                              D3DXINCLUDE_TYPE include_type,
-                                              LPCSTR filename, LPCVOID parent_data,
-                                              LPCVOID *data, UINT *bytes) {
+ * D3DXAssembleShaderFromFile() from D3DXAssembleShader(). */
+/* To be able to correctly resolve include search paths we have to store the
+ * pathname of each include file. We store the pathname pointer right before
+ * the file data. */
+static HRESULT WINAPI d3dincludefromfile_open(ID3DXInclude *iface, D3DXINCLUDE_TYPE include_type,
+        const char *filename, const void *parent_data, const void **data, UINT *bytes)
+{
     const char *p, *parent_name = "";
-    char *pathname = NULL;
+    char *pathname = NULL, *ptr;
     char **buffer = NULL;
     HANDLE file;
     UINT size;
 
-    if(parent_data != NULL)
+    if (parent_data)
+    {
         parent_name = *((const char **)parent_data - 1);
+    }
+    else
+    {
+        if (main_file_data)
+            parent_name = *((const char **)main_file_data - 1);
+    }
 
     TRACE("Looking up for include file %s, parent %s\n", debugstr_a(filename), debugstr_a(parent_name));
 
-    if ((p = strrchr(parent_name, '\\')) || (p = strrchr(parent_name, '/'))) p++;
-    else p = parent_name;
+    if ((p = strrchr(parent_name, '\\')))
+        ++p;
+    else
+        p = parent_name;
     pathname = HeapAlloc(GetProcessHeap(), 0, (p - parent_name) + strlen(filename) + 1);
     if(!pathname)
         return HRESULT_FROM_WIN32(GetLastError());
 
     memcpy(pathname, parent_name, p - parent_name);
     strcpy(pathname + (p - parent_name), filename);
+    ptr = pathname + (p - parent_name);
+    while (*ptr)
+    {
+        if (*ptr == '/')
+            *ptr = '\\';
+        ++ptr;
+    }
 
     file = CreateFileA(pathname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
     if(file == INVALID_HANDLE_VALUE)
@@ -242,6 +286,8 @@ static HRESULT WINAPI d3dincludefromfile_open(ID3DXInclude *iface,
         goto error;
 
     *data = buffer + 1;
+    if (!main_file_data)
+        main_file_data = *data;
 
     CloseHandle(file);
     return S_OK;
@@ -253,9 +299,12 @@ error:
     return HRESULT_FROM_WIN32(GetLastError());
 }
 
-static HRESULT WINAPI d3dincludefromfile_close(ID3DXInclude *iface, LPCVOID data) {
+static HRESULT WINAPI d3dincludefromfile_close(ID3DXInclude *iface, const void *data)
+{
     HeapFree(GetProcessHeap(), 0, *((char **)data - 1));
     HeapFree(GetProcessHeap(), 0, (char **)data - 1);
+    if (main_file_data == data)
+        main_file_data = NULL;
     return S_OK;
 }
 
@@ -271,10 +320,13 @@ struct D3DXIncludeImpl {
 HRESULT WINAPI D3DXAssembleShaderFromFileA(const char *filename, const D3DXMACRO *defines,
         ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
 {
-    LPWSTR filename_w = NULL;
+    WCHAR *filename_w;
     DWORD len;
     HRESULT ret;
 
+    TRACE("filename %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
+            debugstr_a(filename), defines, include, flags, shader, error_messages);
+
     if (!filename) return D3DXERR_INVALIDDATA;
 
     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
@@ -291,13 +343,14 @@ HRESULT WINAPI D3DXAssembleShaderFromFileA(const char *filename, const D3DXMACRO
 HRESULT WINAPI D3DXAssembleShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
         ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
 {
-    void *buffer;
+    const void *buffer;
     DWORD len;
     HRESULT hr;
     struct D3DXIncludeImpl includefromfile;
+    char *filename_a;
 
-    if(FAILED(map_view_of_file(filename, &buffer, &len)))
-        return D3DXERR_INVALIDDATA;
+    TRACE("filename %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
+            debugstr_w(filename), defines, include, flags, shader, error_messages);
 
     if(!include)
     {
@@ -305,10 +358,26 @@ HRESULT WINAPI D3DXAssembleShaderFromFileW(const WCHAR *filename, const D3DXMACR
         include = &includefromfile.ID3DXInclude_iface;
     }
 
-    hr = D3DXAssembleShader(buffer, len, defines, include, flags,
-                            shader, error_messages);
+    len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
+    filename_a = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
+    if (!filename_a)
+        return E_OUTOFMEMORY;
+    WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, len, NULL, NULL);
 
-    UnmapViewOfFile(buffer);
+    EnterCriticalSection(&from_file_mutex);
+    hr = ID3DXInclude_Open(include, D3DXINC_LOCAL, filename_a, NULL, &buffer, &len);
+    if (FAILED(hr))
+    {
+        LeaveCriticalSection(&from_file_mutex);
+        HeapFree(GetProcessHeap(), 0, filename_a);
+        return D3DXERR_INVALIDDATA;
+    }
+
+    hr = D3DXAssembleShader(buffer, len, defines, include, flags, shader, error_messages);
+
+    ID3DXInclude_Close(include, buffer);
+    LeaveCriticalSection(&from_file_mutex);
+    HeapFree(GetProcessHeap(), 0, filename_a);
     return hr;
 }
 
@@ -319,7 +388,10 @@ HRESULT WINAPI D3DXAssembleShaderFromResourceA(HMODULE module, const char *resou
     HRSRC res;
     DWORD len;
 
-    if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
+    TRACE("module %p, resource %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
+            module, debugstr_a(resource), defines, include, flags, shader, error_messages);
+
+    if (!(res = FindResourceA(module, resource, (const char *)RT_RCDATA)))
         return D3DXERR_INVALIDDATA;
     if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
         return D3DXERR_INVALIDDATA;
@@ -351,8 +423,10 @@ HRESULT WINAPI D3DXCompileShader(const char *data, UINT length, const D3DXMACRO
 {
     HRESULT hr;
 
-    TRACE("data %p, length %u, defines %p, include %p, function %s, profile %s, flags %#x, shader %p, error_msgs %p, constant_table %p\n",
-          data, length, defines, include, function, profile, flags, shader, error_msgs, constant_table);
+    TRACE("data %s, length %u, defines %p, include %p, function %s, profile %s, "
+            "flags %#x, shader %p, error_msgs %p, constant_table %p.\n",
+            debugstr_a(data), length, defines, include, debugstr_a(function), debugstr_a(profile),
+            flags, shader, error_msgs, constant_table);
 
     hr = D3DCompile(data, length, NULL, (D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
                     function, profile, flags, 0, (ID3DBlob **)shader, (ID3DBlob **)error_msgs);
@@ -367,6 +441,41 @@ HRESULT WINAPI D3DXCompileShader(const char *data, UINT length, const D3DXMACRO
         }
     }
 
+    /* Filter out D3DCompile warning messages that are not present with D3DCompileShader */
+    if (SUCCEEDED(hr) && error_msgs && *error_msgs)
+    {
+        char *messages = ID3DXBuffer_GetBufferPointer(*error_msgs);
+        DWORD size     = ID3DXBuffer_GetBufferSize(*error_msgs);
+
+        /* Ensure messages are null terminated for safe processing */
+        if (size) messages[size - 1] = 0;
+
+        while (size > 1)
+        {
+            char *prev, *next;
+
+            /* Warning has the form "warning X3206: ... implicit truncation of vector type"
+               but we only search for "X3206:" in case d3dcompiler_43 has localization */
+            prev = next = strstr(messages, "X3206:");
+            if (!prev) break;
+
+            /* get pointer to beginning and end of current line */
+            while (prev > messages && *(prev - 1) != '\n') prev--;
+            while (next < messages + size - 1 && *next != '\n') next++;
+            if (next < messages + size - 1 && *next == '\n') next++;
+
+            memmove(prev, next, messages + size - next);
+            size -= (next - prev);
+        }
+
+        /* Only return a buffer if the resulting string is not empty as some apps depend on that */
+        if (size <= 1)
+        {
+            ID3DXBuffer_Release(*error_msgs);
+            *error_msgs = NULL;
+        }
+    }
+
     return hr;
 }
 
@@ -374,10 +483,15 @@ HRESULT WINAPI D3DXCompileShaderFromFileA(const char *filename, const D3DXMACRO
         ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
         ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
 {
-    LPWSTR filename_w = NULL;
+    WCHAR *filename_w;
     DWORD len;
     HRESULT ret;
 
+    TRACE("filename %s, defines %p, include %p, entrypoint %s, profile %s, "
+            "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
+            debugstr_a(filename), defines, include, debugstr_a(entrypoint),
+            debugstr_a(profile), flags, shader, error_messages, constant_table);
+
     if (!filename) return D3DXERR_INVALIDDATA;
 
     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
@@ -397,14 +511,16 @@ HRESULT WINAPI D3DXCompileShaderFromFileW(const WCHAR *filename, const D3DXMACRO
         ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
         ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
 {
-    void *buffer;
+    const void *buffer;
     DWORD len, filename_len;
     HRESULT hr;
     struct D3DXIncludeImpl includefromfile;
     char *filename_a;
 
-    if (FAILED(map_view_of_file(filename, &buffer, &len)))
-        return D3DXERR_INVALIDDATA;
+    TRACE("filename %s, defines %p, include %p, entrypoint %s, profile %s, "
+            "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
+            debugstr_w(filename), defines, include, debugstr_a(entrypoint), debugstr_a(profile),
+            flags, shader, error_messages, constant_table);
 
     if (!include)
     {
@@ -415,12 +531,18 @@ HRESULT WINAPI D3DXCompileShaderFromFileW(const WCHAR *filename, const D3DXMACRO
     filename_len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
     filename_a = HeapAlloc(GetProcessHeap(), 0, filename_len * sizeof(char));
     if (!filename_a)
-    {
-        UnmapViewOfFile(buffer);
         return E_OUTOFMEMORY;
-    }
     WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, filename_len, NULL, NULL);
 
+    EnterCriticalSection(&from_file_mutex);
+    hr = ID3DXInclude_Open(include, D3DXINC_LOCAL, filename_a, NULL, &buffer, &len);
+    if (FAILED(hr))
+    {
+        LeaveCriticalSection(&from_file_mutex);
+        HeapFree(GetProcessHeap(), 0, filename_a);
+        return D3DXERR_INVALIDDATA;
+    }
+
     hr = D3DCompile(buffer, len, filename_a, (const D3D_SHADER_MACRO *)defines,
                     (ID3DInclude *)include, entrypoint, profile, flags, 0,
                     (ID3DBlob **)shader, (ID3DBlob **)error_messages);
@@ -429,8 +551,9 @@ HRESULT WINAPI D3DXCompileShaderFromFileW(const WCHAR *filename, const D3DXMACRO
         hr = D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*shader),
                                         constant_table);
 
+    ID3DXInclude_Close(include, buffer);
+    LeaveCriticalSection(&from_file_mutex);
     HeapFree(GetProcessHeap(), 0, filename_a);
-    UnmapViewOfFile(buffer);
     return hr;
 }
 
@@ -442,7 +565,12 @@ HRESULT WINAPI D3DXCompileShaderFromResourceA(HMODULE module, const char *resour
     HRSRC res;
     DWORD len;
 
-    if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
+    TRACE("module %p, resource %s, defines %p, include %p, entrypoint %s, profile %s, "
+            "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
+            module, debugstr_a(resource), defines, include, debugstr_a(entrypoint), debugstr_a(profile),
+            flags, shader, error_messages, constant_table);
+
+    if (!(res = FindResourceA(module, resource, (const char *)RT_RCDATA)))
         return D3DXERR_INVALIDDATA;
     if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
         return D3DXERR_INVALIDDATA;
@@ -474,7 +602,9 @@ HRESULT WINAPI D3DXCompileShaderFromResourceW(HMODULE module, const WCHAR *resou
 HRESULT WINAPI D3DXPreprocessShader(const char *data, UINT data_len, const D3DXMACRO *defines,
         ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
 {
-    TRACE("Forward to D3DPreprocess\n");
+    TRACE("data %s, data_len %u, defines %p, include %p, shader %p, error_messages %p.\n",
+            debugstr_a(data), data_len, defines, include, shader, error_messages);
+
     return D3DPreprocess(data, data_len, NULL,
                          (const D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
                          (ID3DBlob **)shader, (ID3DBlob **)error_messages);
@@ -487,6 +617,9 @@ HRESULT WINAPI D3DXPreprocessShaderFromFileA(const char *filename, const D3DXMAC
     DWORD len;
     HRESULT ret;
 
+    TRACE("filename %s, defines %p, include %p, shader %p, error_messages %p.\n",
+            debugstr_a(filename), defines, include, shader, error_messages);
+
     if (!filename) return D3DXERR_INVALIDDATA;
 
     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
@@ -503,13 +636,14 @@ HRESULT WINAPI D3DXPreprocessShaderFromFileA(const char *filename, const D3DXMAC
 HRESULT WINAPI D3DXPreprocessShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
         ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
 {
-    void *buffer;
+    const void *buffer;
     DWORD len;
     HRESULT hr;
     struct D3DXIncludeImpl includefromfile;
+    char *filename_a;
 
-    if (FAILED(map_view_of_file(filename, &buffer, &len)))
-        return D3DXERR_INVALIDDATA;
+    TRACE("filename %s, defines %p, include %p, shader %p, error_messages %p.\n",
+            debugstr_w(filename), defines, include, shader, error_messages);
 
     if (!include)
     {
@@ -517,12 +651,29 @@ HRESULT WINAPI D3DXPreprocessShaderFromFileW(const WCHAR *filename, const D3DXMA
         include = &includefromfile.ID3DXInclude_iface;
     }
 
+    len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
+    filename_a = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
+    if (!filename_a)
+        return E_OUTOFMEMORY;
+    WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, len, NULL, NULL);
+
+    EnterCriticalSection(&from_file_mutex);
+    hr = ID3DXInclude_Open(include, D3DXINC_LOCAL, filename_a, NULL, &buffer, &len);
+    if (FAILED(hr))
+    {
+        LeaveCriticalSection(&from_file_mutex);
+        HeapFree(GetProcessHeap(), 0, filename_a);
+        return D3DXERR_INVALIDDATA;
+    }
+
     hr = D3DPreprocess(buffer, len, NULL,
                        (const D3D_SHADER_MACRO *)defines,
                        (ID3DInclude *) include,
                        (ID3DBlob **)shader, (ID3DBlob **)error_messages);
 
-    UnmapViewOfFile(buffer);
+    ID3DXInclude_Close(include, buffer);
+    LeaveCriticalSection(&from_file_mutex);
+    HeapFree(GetProcessHeap(), 0, filename_a);
     return hr;
 }
 
@@ -533,7 +684,10 @@ HRESULT WINAPI D3DXPreprocessShaderFromResourceA(HMODULE module, const char *res
     HRSRC res;
     DWORD len;
 
-    if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
+    TRACE("module %p, resource %s, defines %p, include %p, shader %p, error_messages %p.\n",
+            module, debugstr_a(resource), defines, include, shader, error_messages);
+
+    if (!(res = FindResourceA(module, resource, (const char *)RT_RCDATA)))
         return D3DXERR_INVALIDDATA;
     if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
         return D3DXERR_INVALIDDATA;
@@ -548,6 +702,9 @@ HRESULT WINAPI D3DXPreprocessShaderFromResourceW(HMODULE module, const WCHAR *re
     HRSRC res;
     DWORD len;
 
+    TRACE("module %p, resource %s, defines %p, include %p, shader %p, error_messages %p.\n",
+            module, debugstr_w(resource), defines, include, shader, error_messages);
+
     if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
         return D3DXERR_INVALIDDATA;
     if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
@@ -557,11 +714,6 @@ HRESULT WINAPI D3DXPreprocessShaderFromResourceW(HMODULE module, const WCHAR *re
 
 }
 
-struct ctab_constant {
-    D3DXCONSTANT_DESC desc;
-    struct ctab_constant *constants;
-};
-
 struct ID3DXConstantTableImpl {
     ID3DXConstantTable ID3DXConstantTable_iface;
     LONG ref;
@@ -615,12 +767,13 @@ static inline D3DXHANDLE handle_from_constant(struct ctab_constant *constant)
     return (D3DXHANDLE)constant;
 }
 
-static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *, struct ctab_constant *, LPCSTR);
+static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *table,
+        struct ctab_constant *constant, const char *name);
 
-static struct ctab_constant *get_constant_element_by_name(struct ctab_constant *constant, LPCSTR name)
+static struct ctab_constant *get_constant_element_by_name(struct ctab_constant *constant, const char *name)
 {
+    const char *part;
     UINT element;
-    LPCSTR part;
 
     TRACE("constant %p, name %s\n", constant, debugstr_a(name));
 
@@ -656,11 +809,11 @@ static struct ctab_constant *get_constant_element_by_name(struct ctab_constant *
 }
 
 static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *table,
-        struct ctab_constant *constant, LPCSTR name)
+        struct ctab_constant *constant, const char *name)
 {
     UINT i, count, length;
     struct ctab_constant *handles;
-    LPCSTR part;
+    const char *part;
 
     TRACE("table %p, constant %p, name %s\n", table, constant, debugstr_a(name));
 
@@ -788,13 +941,13 @@ static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable *iface)
 }
 
 /*** ID3DXBuffer methods ***/
-static LPVOID WINAPI ID3DXConstantTableImpl_GetBufferPointer(ID3DXConstantTable *iface)
+static void * WINAPI ID3DXConstantTableImpl_GetBufferPointer(ID3DXConstantTable *iface)
 {
-    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
+    struct ID3DXConstantTableImpl *table = impl_from_ID3DXConstantTable(iface);
 
-    TRACE("(%p)->()\n", This);
+    TRACE("iface %p.\n", iface);
 
-    return This->ctab;
+    return table->ctab;
 }
 
 static DWORD WINAPI ID3DXConstantTableImpl_GetBufferSize(ID3DXConstantTable *iface)
@@ -821,13 +974,20 @@ static HRESULT WINAPI ID3DXConstantTableImpl_GetDesc(ID3DXConstantTable *iface,
     return D3D_OK;
 }
 
+const struct ctab_constant *d3dx_shader_get_ctab_constant(ID3DXConstantTable *iface, D3DXHANDLE constant)
+{
+    struct ID3DXConstantTableImpl *ctab = impl_from_ID3DXConstantTable(iface);
+
+    return get_valid_constant(ctab, constant);
+}
+
 static HRESULT WINAPI ID3DXConstantTableImpl_GetConstantDesc(ID3DXConstantTable *iface, D3DXHANDLE constant,
                                                              D3DXCONSTANT_DESC *desc, UINT *count)
 {
-    struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
-    struct ctab_constant *c = get_valid_constant(This, constant);
+    struct ID3DXConstantTableImpl *ctab = impl_from_ID3DXConstantTable(iface);
+    struct ctab_constant *c = get_valid_constant(ctab, constant);
 
-    TRACE("(%p)->(%p, %p, %p)\n", This, constant, desc, count);
+    TRACE("(%p)->(%p, %p, %p)\n", ctab, constant, desc, count);
 
     if (!c)
     {
@@ -889,12 +1049,13 @@ static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstant(ID3DXConstantTable *
     return NULL;
 }
 
-static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable *iface, D3DXHANDLE constant, LPCSTR name)
+static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable *iface,
+        D3DXHANDLE constant, const char *name)
 {
     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
     struct ctab_constant *c = get_valid_constant(This, constant);
 
-    TRACE("(%p)->(%p, %s)\n", This, constant, name);
+    TRACE("iface %p, constant %p, name %s.\n", iface, constant, debugstr_a(name));
 
     c = get_constant_by_name(This, c, name);
     TRACE("Returning constant %p\n", c);
@@ -939,7 +1100,7 @@ static UINT set(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device,
     UINT l, i, regcount = 1, regsize = 1, cin = 1, rin = 1, ret, last = 0;
     DWORD tmp;
 
-    /* size to small to set anything */
+    /* size too small to set anything */
     if (*size < desc->Rows * desc->Columns)
     {
         *size = 0;
@@ -965,7 +1126,7 @@ static UINT set(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device,
             offset = min(desc->Elements - 1, offset);
             last = offset * desc->Rows * desc->Columns;
 
-            if ((is_pointer || (!is_pointer && inclass == D3DXPC_MATRIX_ROWS)) && desc->RegisterSet != D3DXRS_BOOL)
+            if ((is_pointer || inclass == D3DXPC_MATRIX_ROWS) && desc->RegisterSet != D3DXRS_BOOL)
             {
                 set(table, device, &constant->constants[0], NULL, intype, size, incol, inclass, 0, is_pointer);
             }
@@ -1005,7 +1166,7 @@ static UINT set(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device,
              * E.g.: struct {int i; int n} s;
              *       SetValue(device, "s", [1, 2], 8) => s = {1, 0};
              */
-            else if ((is_pointer || (!is_pointer && inclass == D3DXPC_MATRIX_ROWS)) && desc->RegisterSet != D3DXRS_BOOL)
+            else if ((is_pointer || inclass == D3DXPC_MATRIX_ROWS) && desc->RegisterSet != D3DXRS_BOOL)
             {
                 last = set(table, device, &constant->constants[0], indata, intype, size, incol, inclass,
                         index + last, is_pointer);
@@ -1059,7 +1220,7 @@ static UINT set(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device,
             break;
 
         case D3DXPC_MATRIX_COLUMNS:
-            regcount = desc->Columns;
+            regcount = min(desc->RegisterCount, desc->Columns);
             if (inclass == D3DXPC_MATRIX_ROWS) rin = incol;
             else cin = incol;
             regsize = desc->Rows;
@@ -1685,7 +1846,7 @@ static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl =
 };
 
 static HRESULT parse_ctab_constant_type(const char *ctab, DWORD typeoffset, struct ctab_constant *constant,
-        BOOL is_element, WORD index, WORD max, DWORD *offset, DWORD nameoffset, UINT regset)
+        BOOL is_element, WORD index, WORD max_index, DWORD *offset, DWORD nameoffset, UINT regset)
 {
     const D3DXSHADER_TYPEINFO *type = (LPD3DXSHADER_TYPEINFO)(ctab + typeoffset);
     const D3DXSHADER_STRUCTMEMBERINFO *memberinfo = NULL;
@@ -1734,7 +1895,7 @@ static HRESULT parse_ctab_constant_type(const char *ctab, DWORD typeoffset, stru
         for (i = 0; i < count; ++i)
         {
             hr = parse_ctab_constant_type(ctab, memberinfo ? memberinfo[i].TypeInfo : typeoffset,
-                    &constant->constants[i], memberinfo == NULL, index + size, max, offset,
+                    &constant->constants[i], memberinfo == NULL, index + size, max_index, offset,
                     memberinfo ? memberinfo[i].Name : nameoffset, regset);
             if (hr != D3D_OK)
                 goto error;
@@ -1769,7 +1930,7 @@ static HRESULT parse_ctab_constant_type(const char *ctab, DWORD typeoffset, stru
 
                     case D3DXPC_MATRIX_ROWS:
                         offsetdiff = type->Rows * 4;
-                        size = is_element ? type->Rows : max(type->Rows, type->Columns);
+                        size = type->Rows;
                         break;
 
                     case D3DXPC_MATRIX_COLUMNS:
@@ -1803,7 +1964,7 @@ static HRESULT parse_ctab_constant_type(const char *ctab, DWORD typeoffset, stru
         if (offset) *offset += offsetdiff * 4;
     }
 
-    constant->desc.RegisterCount = max(0, min(max - index, size));
+    constant->desc.RegisterCount = max(0, min(max_index - index, size));
     constant->desc.Bytes = 4 * constant->desc.Elements * type->Rows * type->Columns;
 
     return D3D_OK;
@@ -1825,8 +1986,8 @@ error:
 HRESULT WINAPI D3DXGetShaderConstantTableEx(const DWORD *byte_code, DWORD flags, ID3DXConstantTable **constant_table)
 {
     struct ID3DXConstantTableImpl *object = NULL;
+    const void *data;
     HRESULT hr;
-    LPCVOID data;
     UINT size;
     const D3DXSHADER_CONSTANTTABLE *ctab_header;
     const D3DXSHADER_CONSTANTINFO *constant_info;
@@ -1926,6 +2087,7 @@ HRESULT WINAPI D3DXGetShaderConstantTableEx(const DWORD *byte_code, DWORD flags,
         {
             object->constants[i].desc.RegisterCount = constant_info[i].RegisterCount;
         }
+        object->constants[i].constantinfo_reserved = constant_info[i].Reserved;
     }
 
     *constant_table = &object->ID3DXConstantTable_iface;
@@ -1946,6 +2108,27 @@ HRESULT WINAPI D3DXGetShaderConstantTable(const DWORD *byte_code, ID3DXConstantT
     return D3DXGetShaderConstantTableEx(byte_code, 0, constant_table);
 }
 
+HRESULT WINAPI D3DXCreateFragmentLinker(IDirect3DDevice9 *device, UINT size, ID3DXFragmentLinker **linker)
+{
+    FIXME("device %p, size %u, linker %p: stub.\n", device, size, linker);
+
+    if (linker)
+        *linker = NULL;
+
+
+    return E_NOTIMPL;
+}
+
+HRESULT WINAPI D3DXCreateFragmentLinkerEx(IDirect3DDevice9 *device, UINT size, DWORD flags, ID3DXFragmentLinker **linker)
+{
+    FIXME("device %p, size %u, flags %#x, linker %p: stub.\n", device, size, flags, linker);
+
+    if (linker)
+        *linker = NULL;
+
+    return E_NOTIMPL;
+}
+
 HRESULT WINAPI D3DXGetShaderSamplers(const DWORD *byte_code, const char **samplers, UINT *count)
 {
     UINT i, sampler_count = 0;
@@ -1993,3 +2176,710 @@ HRESULT WINAPI D3DXGetShaderSamplers(const DWORD *byte_code, const char **sample
 
     return D3D_OK;
 }
+
+
+static const char *decl_usage[] = { "position", "blendweight", "blendindices", "normal", "psize", "texcoord",
+                                    "tangent", "binormal", "tessfactor", "positiont", "color" };
+
+static const char *tex_type[] = { "", "1d", "2d", "cube", "volume" };
+
+static int add_modifier(char *buffer, DWORD param)
+{
+    char *buf = buffer;
+    DWORD dst_mod = param & D3DSP_DSTMOD_MASK;
+
+    if (dst_mod & D3DSPDM_SATURATE)
+        buf += sprintf(buf, "_sat");
+    if (dst_mod & D3DSPDM_PARTIALPRECISION)
+        buf += sprintf(buf, "_pp");
+    if (dst_mod & D3DSPDM_MSAMPCENTROID)
+        buf += sprintf(buf, "_centroid");
+
+    return buf - buffer;
+}
+
+static int add_register(char *buffer, DWORD param, BOOL dst, BOOL ps)
+{
+    char *buf = buffer;
+    DWORD reg_type = ((param & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2)
+                   | ((param & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT);
+    DWORD reg_num = param & D3DSP_REGNUM_MASK;
+
+    if (reg_type == D3DSPR_INPUT)
+        buf += sprintf(buf, "v%d", reg_num);
+    else if (reg_type == D3DSPR_CONST)
+        buf += sprintf(buf, "c%d", reg_num);
+    else if (reg_type == D3DSPR_TEMP)
+        buf += sprintf(buf, "r%d", reg_num);
+    else if (reg_type == D3DSPR_ADDR)
+        buf += sprintf(buf, "%s%d", ps ? "t" : "a", reg_num);
+    else if (reg_type == D3DSPR_SAMPLER)
+        buf += sprintf(buf, "s%d", reg_num);
+    else if (reg_type == D3DSPR_RASTOUT)
+        buf += sprintf(buf, "oPos");
+    else if (reg_type == D3DSPR_COLOROUT)
+        buf += sprintf(buf, "oC%d", reg_num);
+    else if (reg_type == D3DSPR_TEXCRDOUT)
+        buf += sprintf(buf, "oT%d", reg_num);
+    else if (reg_type == D3DSPR_ATTROUT)
+        buf += sprintf(buf, "oD%d", reg_num);
+    else
+        buf += sprintf(buf, "? (%d)", reg_type);
+
+    if (dst)
+    {
+        if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL)
+        {
+            buf += sprintf(buf, ".%s%s%s%s", param & D3DSP_WRITEMASK_0 ? "x" : "",
+                                             param & D3DSP_WRITEMASK_1 ? "y" : "",
+                                             param & D3DSP_WRITEMASK_2 ? "z" : "",
+                                             param & D3DSP_WRITEMASK_3 ? "w" : "");
+        }
+    }
+    else
+    {
+        if ((param & D3DVS_SWIZZLE_MASK) != D3DVS_NOSWIZZLE)
+        {
+            if ( ((param & D3DSP_SWIZZLE_MASK) == (D3DVS_X_X | D3DVS_Y_X | D3DVS_Z_X | D3DVS_W_X)) ||
+                 ((param & D3DSP_SWIZZLE_MASK) == (D3DVS_X_Y | D3DVS_Y_Y | D3DVS_Z_Y | D3DVS_W_Y)) ||
+                 ((param & D3DSP_SWIZZLE_MASK) == (D3DVS_X_Z | D3DVS_Y_Z | D3DVS_Z_Z | D3DVS_W_Z)) ||
+                 ((param & D3DSP_SWIZZLE_MASK) == (D3DVS_X_W | D3DVS_Y_W | D3DVS_Z_W | D3DVS_W_W)) )
+                buf += sprintf(buf, ".%c", 'w' + (((param >> D3DVS_SWIZZLE_SHIFT) + 1) & 0x3));
+            else
+                buf += sprintf(buf, ".%c%c%c%c", 'w' + (((param >> (D3DVS_SWIZZLE_SHIFT+0)) + 1) & 0x3),
+                                                 'w' + (((param >> (D3DVS_SWIZZLE_SHIFT+2)) + 1) & 0x3),
+                                                 'w' + (((param >> (D3DVS_SWIZZLE_SHIFT+4)) + 1) & 0x3),
+                                                 'w' + (((param >> (D3DVS_SWIZZLE_SHIFT+6)) + 1) & 0x3));
+        }
+    }
+
+    return buf - buffer;
+}
+
+struct instr_info
+{
+    DWORD opcode;
+    const char *name;
+    int length;
+    int (*function)(const struct instr_info *info, DWORD **ptr, char *buffer, BOOL ps);
+    WORD min_version;
+    WORD max_version;
+};
+
+static int instr_comment(const struct instr_info *info, DWORD **ptr, char *buffer, BOOL ps)
+{
+    *ptr += 1 + ((**ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
+    return 0;
+}
+
+static int instr_def(const struct instr_info *info, DWORD **ptr, char *buffer, BOOL ps)
+{
+    int len = sprintf(buffer, "    def c%d, %g, %g, %g, %g\n", *(*ptr+1) & D3DSP_REGNUM_MASK,
+                      (double)*(float*)(*ptr+2), (double)*(float*)(*ptr+3),
+                      (double)*(float*)(*ptr+4), (double)*(float*)(*ptr+5));
+    *ptr += 6;
+    return len;
+}
+
+static int instr_dcl(const struct instr_info *info, DWORD **ptr, char *buffer, BOOL ps)
+{
+    DWORD param1 = *++*ptr;
+    DWORD param2 = *++*ptr;
+    DWORD usage = (param1 & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
+    DWORD usage_index = (param1 & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
+    char *buf = buffer;
+
+    buf += sprintf(buf, "    dcl");
+    if (ps)
+    {
+        if (param1 & D3DSP_TEXTURETYPE_MASK)
+            buf += sprintf(buf, "_%s", (usage <= D3DSTT_VOLUME) ?
+                tex_type[(param1 & D3DSP_TEXTURETYPE_MASK) >> D3DSP_TEXTURETYPE_SHIFT] : "???");
+    }
+    else
+    {
+        buf += sprintf(buf, "_%s", (usage <= D3DDECLUSAGE_COLOR) ? decl_usage[usage] : "???");
+        if (usage_index)
+            buf += sprintf(buf, "%d", usage_index);
+    }
+
+    buf += add_modifier(buf, param2);
+    buf += sprintf(buf, " ");
+    buf += add_register(buf, param2, TRUE, TRUE);
+    buf += sprintf(buf, "\n");
+    (*ptr)++;
+    return buf - buffer;
+}
+
+static int instr_generic(const struct instr_info *info, DWORD **ptr, char *buffer, BOOL ps)
+{
+    char *buf = buffer;
+    int j;
+
+    buf += sprintf(buf, "    %s", info->name);
+    (*ptr)++;
+
+    if (info->length)
+    {
+        buf += add_modifier(buf, **ptr);
+
+        for (j = 0; j < info->length; j++)
+        {
+            buf += sprintf(buf, "%s ", j ? "," : "");
+
+            if ((j != 0) && ((**ptr & D3DSP_SRCMOD_MASK) != D3DSPSM_NONE))
+            {
+                if ((**ptr & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG)
+                    buf += sprintf(buf, "-");
+                else
+                    buf += sprintf(buf, "*");
+            }
+
+            buf += add_register(buf, **ptr, j == 0, ps);
+
+            if (*(*ptr)++ & D3DVS_ADDRESSMODE_MASK)
+            {
+                buf += sprintf(buf, "[");
+                buf += add_register(buf, **ptr, FALSE, FALSE);
+                buf += sprintf(buf, "]");
+                (*ptr)++;
+            }
+        }
+    }
+    buf += sprintf(buf, "\n");
+    return buf - buffer;
+}
+
+const struct instr_info instructions[] =
+{
+    { D3DSIO_NOP,          "nop",           0, instr_generic, 0x0100, 0xFFFF },
+    { D3DSIO_MOV,          "mov",           2, instr_generic, 0x0100, 0xFFFF },
+    { D3DSIO_ADD,          "add",           3, instr_generic, 0x0100, 0xFFFF },
+    { D3DSIO_SUB,          "sub",           3, instr_generic, 0x0100, 0xFFFF },
+    { D3DSIO_MAD,          "mad",           4, instr_generic, 0x0100, 0xFFFF },
+    { D3DSIO_MUL,          "mul",           3, instr_generic, 0x0100, 0xFFFF },
+    { D3DSIO_RCP,          "rcp",           2, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_RSQ,          "rsq",           2, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_DP3,          "dp3",           3, instr_generic, 0x0100, 0xFFFF },
+    { D3DSIO_DP4,          "dp4",           3, instr_generic, 0x0100, 0xFFFF }, /* >= 1.2 for PS */
+    { D3DSIO_MIN,          "min",           3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_MAX,          "max",           3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_SLT,          "slt",           3, instr_generic, 0x0100, 0xFFFF },
+    { D3DSIO_SGE,          "sge",           3, instr_generic, 0x0100, 0xFFFF }, /* VS only */
+    { D3DSIO_EXP,          "exp",           2, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_LOG,          "log",           2, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_LIT,          "lit",           2, instr_generic, 0x0100, 0xFFFF }, /* VS only */
+    { D3DSIO_DST,          "dst",           3, instr_generic, 0x0100, 0xFFFF }, /* VS only */
+    { D3DSIO_LRP,          "lrp",           4, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for VS */
+    { D3DSIO_FRC,          "frc",           2, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_M4x4,         "m4x4",          3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_M4x3,         "m4x3",          3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_M3x4,         "m3x4",          3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_M3x3,         "m3x3",          3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_M3x2,         "m3x2",          3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
+    { D3DSIO_CALL,         "call",          1, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
+    { D3DSIO_CALLNZ,       "callnz",        2, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
+    { D3DSIO_LOOP,         "loop",          2, instr_generic, 0x0200, 0xFFFF }, /* >= 3.0 for PS */
+    { D3DSIO_RET,          "ret",           0, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
+    { D3DSIO_ENDLOOP,      "endloop",       1, instr_generic, 0x0200, 0xFFFF }, /* >= 3.0 for PS */
+    { D3DSIO_LABEL,        "label",         1, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
+    { D3DSIO_DCL,          "dcl",           1, instr_dcl,     0x0100, 0xFFFF },
+    { D3DSIO_POW,          "pow",           3, instr_generic, 0x0200, 0xFFFF },
+    { D3DSIO_CRS,          "crs",           3, instr_generic, 0x0200, 0xFFFF },
+    { D3DSIO_SGN,          "sgn",           4, instr_generic, 0x0200, 0xFFFF }, /* VS only */
+    { D3DSIO_ABS,          "abs",           2, instr_generic, 0x0200, 0xFFFF },
+    { D3DSIO_NRM,          "nrm",           2, instr_generic, 0x0200, 0xFFFF },
+    { D3DSIO_SINCOS,       "sincos",        4, instr_generic, 0x0200, 0x02FF },
+    { D3DSIO_SINCOS,       "sincos",        2, instr_generic, 0x0300, 0xFFFF },
+    { D3DSIO_REP,          "rep",           1, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
+    { D3DSIO_ENDREP,       "endrep",        0, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
+    { D3DSIO_IF,           "if",            1, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
+    { D3DSIO_IFC,          "if_comp",       2, instr_generic, 0x0200, 0xFFFF },
+    { D3DSIO_ELSE,         "else",          0, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
+    { D3DSIO_ENDIF,        "endif",         0, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
+    { D3DSIO_BREAK,        "break",         0, instr_generic, 0x0201, 0xFFFF },
+    { D3DSIO_BREAKC,       "break_comp",    2, instr_generic, 0x0201, 0xFFFF },
+    { D3DSIO_MOVA,         "mova",          2, instr_generic, 0x0200, 0xFFFF }, /* VS only */
+    { D3DSIO_DEFB,         "defb",          2, instr_generic, 0x0100, 0xFFFF },
+    { D3DSIO_DEFI,         "defi",          2, instr_generic, 0x0100, 0xFFFF },
+    { D3DSIO_TEXCOORD,     "texcoord",      1, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_TEXCOORD,     "texcrd",        2, instr_generic, 0x0104, 0x0104 }, /* PS only */
+    { D3DSIO_TEXKILL,      "texkill",       1, instr_generic, 0x0100, 0xFFFF }, /* PS only */
+    { D3DSIO_TEX,          "tex",           1, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_TEX,          "texld",         2, instr_generic, 0x0104, 0x0104 }, /* PS only */
+    { D3DSIO_TEX,          "texld",         3, instr_generic, 0x0200, 0xFFFF }, /* PS only */
+    { D3DSIO_TEXBEM,       "texbem",        2, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_TEXBEML,      "texbeml",       2, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_TEXREG2AR,    "texreg2ar",     2, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_TEXREG2GB,    "texreg2gb",     2, instr_generic, 0x0102, 0x0103 }, /* PS only */
+    { D3DSIO_TEXM3x2PAD,   "texm3x2pad",    2, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_TEXM3x2TEX,   "texm3x2tex",    2, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_TEXM3x3PAD,   "texm3x3pad",    2, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_TEXM3x3TEX,   "texm3x3tex",    2, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_TEXM3x3DIFF,  "texm3x3diff",   2, instr_generic, 0x0100, 0xFFFF }, /* PS only - Not documented */
+    { D3DSIO_TEXM3x3SPEC,  "texm3x3spec",   3, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_TEXM3x3VSPEC, "texm3x3vspec",  2, instr_generic, 0x0100, 0x0103 }, /* PS only */
+    { D3DSIO_EXPP,         "expp",          2, instr_generic, 0x0100, 0xFFFF }, /* VS only */
+    { D3DSIO_LOGP,         "logp",          2, instr_generic, 0x0100, 0xFFFF }, /* VS only */
+    { D3DSIO_CND,          "cnd",           4, instr_generic, 0x0100, 0x0104 }, /* PS only */
+    { D3DSIO_DEF,          "def",           5, instr_def,     0x0100, 0xFFFF },
+    { D3DSIO_TEXREG2RGB,   "texreg2rgb",    2, instr_generic, 0x0102, 0x0103 }, /* PS only */
+    { D3DSIO_TEXDP3TEX,    "texdp3tex",     2, instr_generic, 0x0102, 0x0103 }, /* PS only */
+    { D3DSIO_TEXM3x2DEPTH, "texm3x2depth",  2, instr_generic, 0x0103, 0x0103 }, /* PS only */
+    { D3DSIO_TEXDP3,       "texdp3",        2, instr_generic, 0x0102, 0x0103 }, /* PS only */
+    { D3DSIO_TEXM3x3,      "texm3x3",       2, instr_generic, 0x0102, 0x0103 }, /* PS only */
+    { D3DSIO_TEXDEPTH,     "texdepth",      1, instr_generic, 0x0104, 0x0104 }, /* PS only */
+    { D3DSIO_CMP,          "cmp",           4, instr_generic, 0x0102, 0xFFFF }, /* PS only */
+    { D3DSIO_BEM,          "bem",           3, instr_generic, 0x0104, 0x0104 }, /* PS only */
+    { D3DSIO_DP2ADD,       "dp2add",        4, instr_generic, 0x0200, 0xFFFF }, /* PS only */
+    { D3DSIO_DSX,          "dsx",           2, instr_generic, 0x0201, 0xFFFF }, /* PS only */
+    { D3DSIO_DSY,          "dsy",           2, instr_generic, 0x0201, 0xFFFF }, /* PS only */
+    { D3DSIO_TEXLDD,       "texldd",        5, instr_generic, 0x0201, 0xFFFF }, /* PS only - not existing for 2.b */
+    { D3DSIO_SETP,         "setp_comp",     3, instr_generic, 0x0201, 0xFFFF },
+    { D3DSIO_TEXLDL,       "texldl",        3, instr_generic, 0x0300, 0xFFFF },
+    { D3DSIO_BREAKP,       "breakp",        1, instr_generic, 0x0201, 0xFFFF },
+    { D3DSIO_PHASE,        "phase",         0, instr_generic, 0x0104, 0x0104 },  /* PS only */
+    { D3DSIO_COMMENT,      "",              0, instr_comment, 0x0100, 0xFFFF }
+};
+
+HRESULT WINAPI D3DXDisassembleShader(const DWORD *shader, BOOL colorcode, const char *comments, ID3DXBuffer **disassembly)
+{
+    DWORD *ptr = (DWORD *)shader;
+    char *buffer, *buf;
+    UINT capacity = 4096;
+    BOOL ps;
+    WORD version;
+    HRESULT hr;
+
+    TRACE("%p %d %s %p\n", shader, colorcode, debugstr_a(comments), disassembly);
+
+    if (!shader || !disassembly)
+        return D3DERR_INVALIDCALL;
+
+    buf = buffer = HeapAlloc(GetProcessHeap(), 0, capacity);
+    if (!buffer)
+        return E_OUTOFMEMORY;
+
+    ps = (*ptr >> 16) & 1;
+    version = *ptr & 0xFFFF;
+    buf += sprintf(buf, "    %s_%d_%d\n", ps ? "ps" : "vs", D3DSHADER_VERSION_MAJOR(*ptr), D3DSHADER_VERSION_MINOR(*ptr));
+    ptr++;
+
+    while (*ptr != D3DSIO_END)
+    {
+        DWORD index;
+
+        if ((buf - buffer + 128) > capacity)
+        {
+            UINT count = buf - buffer;
+            char *new_buffer = HeapReAlloc(GetProcessHeap(), 0, buffer, capacity * 2);
+            if (!new_buffer)
+            {
+                HeapFree(GetProcessHeap(), 0, buffer);
+                return E_OUTOFMEMORY;
+            }
+            capacity *= 2;
+            buffer = new_buffer;
+            buf = buffer + count;
+        }
+
+        for (index = 0; index < sizeof(instructions)/sizeof(instructions[0]); index++)
+            if (((*ptr & D3DSI_OPCODE_MASK) == instructions[index].opcode) &&
+                (version >= instructions[index].min_version) && (version <= instructions[index].max_version))
+                break;
+
+        if (index != sizeof(instructions)/sizeof(instructions[0]))
+        {
+            buf += instructions[index].function(&(instructions[index]), &ptr, buf, ps);
+        }
+        else
+        {
+            buf += sprintf(buf, "    ??? (Unknown opcode %x)\n", *ptr);
+            while (*++ptr & (1u << 31));
+        }
+    }
+
+    hr = D3DXCreateBuffer(buf - buffer + 1 , disassembly);
+    if (SUCCEEDED(hr))
+        strcpy(ID3DXBuffer_GetBufferPointer(*disassembly), buffer);
+    HeapFree(GetProcessHeap(), 0, buffer);
+
+    return hr;
+}
+
+struct d3dx9_texture_shader
+{
+    ID3DXTextureShader ID3DXTextureShader_iface;
+    LONG ref;
+};
+
+static inline struct d3dx9_texture_shader *impl_from_ID3DXTextureShader(ID3DXTextureShader *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3dx9_texture_shader, ID3DXTextureShader_iface);
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_QueryInterface(ID3DXTextureShader *iface, REFIID riid, void **out)
+{
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_ID3DXTextureShader))
+    {
+        iface->lpVtbl->AddRef(iface);
+        *out = iface;
+        return D3D_OK;
+    }
+
+    WARN("Interface %s not found.\n", debugstr_guid(riid));
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI d3dx9_texture_shader_AddRef(ID3DXTextureShader *iface)
+{
+    struct d3dx9_texture_shader *texture_shader = impl_from_ID3DXTextureShader(iface);
+    ULONG refcount = InterlockedIncrement(&texture_shader->ref);
+
+    TRACE("%p increasing refcount to %u.\n", texture_shader, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3dx9_texture_shader_Release(ID3DXTextureShader *iface)
+{
+    struct d3dx9_texture_shader *texture_shader = impl_from_ID3DXTextureShader(iface);
+    ULONG refcount = InterlockedDecrement(&texture_shader->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", texture_shader, refcount);
+
+    if (!refcount)
+    {
+        HeapFree(GetProcessHeap(), 0, texture_shader);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_GetFunction(ID3DXTextureShader *iface, struct ID3DXBuffer **function)
+{
+    FIXME("iface %p, function %p stub.\n", iface, function);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_GetConstantBuffer(ID3DXTextureShader *iface, struct ID3DXBuffer **constant_buffer)
+{
+    FIXME("iface %p, constant_buffer %p stub.\n", iface, constant_buffer);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_GetDesc(ID3DXTextureShader *iface, D3DXCONSTANTTABLE_DESC *desc)
+{
+    FIXME("iface %p, desc %p stub.\n", iface, desc);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_GetConstantDesc(ID3DXTextureShader *iface, D3DXHANDLE constant, D3DXCONSTANT_DESC *constant_desc, UINT *count)
+{
+    FIXME("iface %p, constant %p, constant_desc %p, count %p stub.\n", iface, constant, constant_desc, count);
+
+    return E_NOTIMPL;
+}
+
+static D3DXHANDLE WINAPI d3dx9_texture_shader_GetConstant(ID3DXTextureShader *iface, D3DXHANDLE constant, UINT index)
+{
+    FIXME("iface %p, constant %p, index %u stub.\n", iface, constant, index);
+
+    return NULL;
+}
+
+static D3DXHANDLE WINAPI d3dx9_texture_shader_GetConstantByName(ID3DXTextureShader *iface, D3DXHANDLE constant, const char *name)
+{
+    FIXME("iface %p, constant %p, name %s stub.\n", iface, constant, debugstr_a(name));
+
+    return NULL;
+}
+
+static D3DXHANDLE WINAPI d3dx9_texture_shader_GetConstantElement(ID3DXTextureShader *iface, D3DXHANDLE constant, UINT index)
+{
+    FIXME("iface %p, constant %p, index %u stub.\n", iface, constant, index);
+
+    return NULL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetDefaults(ID3DXTextureShader *iface)
+{
+    FIXME("iface %p stub.\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetValue(ID3DXTextureShader *iface, D3DXHANDLE constant, const void *data, UINT bytes)
+{
+    FIXME("iface %p, constant %p, data %p, bytes %u stub.\n", iface, constant, data, bytes);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetBool(ID3DXTextureShader *iface, D3DXHANDLE constant, BOOL b)
+{
+    FIXME("iface %p, constant %p, b %u stub.\n", iface, constant, b);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetBoolArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const BOOL *b, UINT count)
+{
+    FIXME("iface %p, constant %p, b %p, count %u stub.\n", iface, constant, b, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetInt(ID3DXTextureShader *iface, D3DXHANDLE constant, INT n)
+{
+    FIXME("iface %p, constant %p, n %d stub.\n", iface, constant, n);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetIntArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const INT *n, UINT count)
+{
+    FIXME("iface %p, constant %p, n %p, count %u stub.\n", iface, constant, n, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetFloat(ID3DXTextureShader *iface, D3DXHANDLE constant, FLOAT f)
+{
+    FIXME("iface %p, constant %p, f %f stub.\n", iface, constant, f);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetFloatArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const FLOAT *f, UINT count)
+{
+    FIXME("iface %p, constant %p, f %p, count %u stub.\n", iface, constant, f, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetVector(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXVECTOR4 *vector)
+{
+    FIXME("iface %p, constant %p, vector %p stub.\n", iface, constant, vector);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetVectorArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXVECTOR4 *vector, UINT count)
+{
+    FIXME("iface %p, constant %p, vector %p, count %u stub.\n", iface, constant, vector, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetMatrix(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX *matrix)
+{
+    FIXME("iface %p, constant %p, matrix %p stub.\n", iface, constant, matrix);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetMatrixArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX *matrix, UINT count)
+{
+    FIXME("iface %p, constant %p, matrix %p, count %u stub.\n", iface, constant, matrix, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetMatrixPointerArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX **matrix, UINT count)
+{
+    FIXME("iface %p, constant %p, matrix %p, count %u stub.\n", iface, constant, matrix, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetMatrixTranspose(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX *matrix)
+{
+    FIXME("iface %p, constant %p, matrix %p stub.\n", iface, constant, matrix);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetMatrixTransposeArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX *matrix, UINT count)
+{
+    FIXME("iface %p, constant %p, matrix %p, count %u stub.\n", iface, constant, matrix, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3dx9_texture_shader_SetMatrixTransposePointerArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX **matrix, UINT count)
+{
+    FIXME("iface %p, constant %p, matrix %p, count %u stub.\n", iface, constant, matrix, count);
+
+    return E_NOTIMPL;
+}
+
+static const struct ID3DXTextureShaderVtbl d3dx9_texture_shader_vtbl =
+{
+    /*** IUnknown methods ***/
+    d3dx9_texture_shader_QueryInterface,
+    d3dx9_texture_shader_AddRef,
+    d3dx9_texture_shader_Release,
+    /*** ID3DXTextureShader methods ***/
+    d3dx9_texture_shader_GetFunction,
+    d3dx9_texture_shader_GetConstantBuffer,
+    d3dx9_texture_shader_GetDesc,
+    d3dx9_texture_shader_GetConstantDesc,
+    d3dx9_texture_shader_GetConstant,
+    d3dx9_texture_shader_GetConstantByName,
+    d3dx9_texture_shader_GetConstantElement,
+    d3dx9_texture_shader_SetDefaults,
+    d3dx9_texture_shader_SetValue,
+    d3dx9_texture_shader_SetBool,
+    d3dx9_texture_shader_SetBoolArray,
+    d3dx9_texture_shader_SetInt,
+    d3dx9_texture_shader_SetIntArray,
+    d3dx9_texture_shader_SetFloat,
+    d3dx9_texture_shader_SetFloatArray,
+    d3dx9_texture_shader_SetVector,
+    d3dx9_texture_shader_SetVectorArray,
+    d3dx9_texture_shader_SetMatrix,
+    d3dx9_texture_shader_SetMatrixArray,
+    d3dx9_texture_shader_SetMatrixPointerArray,
+    d3dx9_texture_shader_SetMatrixTranspose,
+    d3dx9_texture_shader_SetMatrixTransposeArray,
+    d3dx9_texture_shader_SetMatrixTransposePointerArray
+};
+
+HRESULT WINAPI D3DXCreateTextureShader(const DWORD *function, ID3DXTextureShader **texture_shader)
+{
+    struct d3dx9_texture_shader *object;
+
+    TRACE("function %p, texture_shader %p.\n", function, texture_shader);
+
+    if (!function || !texture_shader)
+        return D3DERR_INVALIDCALL;
+
+    object = HeapAlloc(GetProcessHeap(), 0, sizeof(*object));
+    if (!object)
+        return E_OUTOFMEMORY;
+
+    object->ID3DXTextureShader_iface.lpVtbl = &d3dx9_texture_shader_vtbl;
+    object->ref = 1;
+
+    *texture_shader = &object->ID3DXTextureShader_iface;
+
+    return D3D_OK;
+}
+
+static const DWORD* skip_instruction(const DWORD *byte_code, UINT shader_model)
+{
+    TRACE("Shader model %u\n", shader_model);
+
+    /* Handle all special instructions whose arguments may contain D3DSIO_DCL */
+    if ((*byte_code & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
+    {
+        byte_code += 1 + ((*byte_code & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
+    }
+    else if (shader_model >= 2)
+    {
+        byte_code += 1 + ((*byte_code & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT);
+    }
+    else if ((*byte_code & D3DSI_OPCODE_MASK) == D3DSIO_DEF)
+    {
+        byte_code += 1 + 5;
+    }
+    else
+    {
+        /* Handle remaining safe instructions */
+        while (*++byte_code & (1u << 31));
+    }
+
+    return byte_code;
+}
+
+static UINT get_shader_semantics(const DWORD *byte_code, D3DXSEMANTIC *semantics, DWORD type)
+{
+    const DWORD *ptr = byte_code;
+    UINT shader_model = (*ptr >> 8) & 0xff;
+    UINT i = 0;
+
+    TRACE("Shader version: %#x\n", *ptr);
+    ptr++;
+
+    while (*ptr != D3DSIO_END)
+    {
+        if (*ptr & (1u << 31))
+        {
+            FIXME("Opcode expected but got %#x\n", *ptr);
+            return 0;
+        }
+        else if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_DCL)
+        {
+            DWORD param1 = *++ptr;
+            DWORD param2 = *++ptr;
+            DWORD usage = (param1 & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
+            DWORD usage_index = (param1 & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
+            DWORD reg_type = ((param2 & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2)
+                    | ((param2 & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT);
+
+            TRACE("D3DSIO_DCL param1: %#x, param2: %#x, usage: %u, usage_index: %u, reg_type: %u\n",
+                   param1, param2, usage, usage_index, reg_type);
+
+            if (reg_type == type)
+            {
+                if (semantics)
+                {
+                    semantics[i].Usage = usage;
+                    semantics[i].UsageIndex = usage_index;
+                }
+                i++;
+            }
+
+            ptr++;
+        }
+        else
+        {
+            ptr = skip_instruction(ptr, shader_model);
+        }
+    }
+
+    return i;
+}
+
+HRESULT WINAPI D3DXGetShaderInputSemantics(const DWORD *byte_code, D3DXSEMANTIC *semantics, UINT *count)
+{
+    UINT nb_semantics;
+
+    TRACE("byte_code %p, semantics %p, count %p\n", byte_code, semantics, count);
+
+    if (!byte_code)
+        return D3DERR_INVALIDCALL;
+
+    nb_semantics = get_shader_semantics(byte_code, semantics, D3DSPR_INPUT);
+
+    if (count)
+        *count = nb_semantics;
+
+    return D3D_OK;
+}
+
+
+HRESULT WINAPI D3DXGetShaderOutputSemantics(const DWORD *byte_code, D3DXSEMANTIC *semantics, UINT *count)
+{
+    UINT nb_semantics;
+
+    TRACE("byte_code %p, semantics %p, count %p\n", byte_code, semantics, count);
+
+    if (!byte_code)
+        return D3DERR_INVALIDCALL;
+
+    nb_semantics = get_shader_semantics(byte_code, semantics, D3DSPR_OUTPUT);
+
+    if (count)
+        *count = nb_semantics;
+
+    return D3D_OK;
+}