xref: /reactos/dll/directx/wine/d3dx9_36/shader.c (revision 58588b76)
1 /*
2  * Copyright 2008 Luis Busquets
3  * Copyright 2009 Matteo Bruni
4  * Copyright 2010, 2013, 2016 Christian Costa
5  * Copyright 2011 Travis Athougies
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "config.h"
23 #include "wine/port.h"
24 #include <stdio.h>
25 
26 #include "d3dx9_private.h"
27 #include "d3dcommon.h"
28 #include "d3dcompiler.h"
29 
30 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
31 
32 /* This function is not declared in the SDK headers yet. */
33 HRESULT WINAPI D3DAssemble(const void *data, SIZE_T datasize, const char *filename,
34         const D3D_SHADER_MACRO *defines, ID3DInclude *include, UINT flags,
35         ID3DBlob **shader, ID3DBlob **error_messages);
36 
37 static inline BOOL is_valid_bytecode(DWORD token)
38 {
39     return (token & 0xfffe0000) == 0xfffe0000;
40 }
41 
42 const char * WINAPI D3DXGetPixelShaderProfile(struct IDirect3DDevice9 *device)
43 {
44     D3DCAPS9 caps;
45 
46     TRACE("device %p\n", device);
47 
48     if (!device) return NULL;
49 
50     IDirect3DDevice9_GetDeviceCaps(device,&caps);
51 
52     switch (caps.PixelShaderVersion)
53     {
54     case D3DPS_VERSION(1, 1):
55         return "ps_1_1";
56 
57     case D3DPS_VERSION(1, 2):
58         return "ps_1_2";
59 
60     case D3DPS_VERSION(1, 3):
61         return "ps_1_3";
62 
63     case D3DPS_VERSION(1, 4):
64         return "ps_1_4";
65 
66     case D3DPS_VERSION(2, 0):
67         if ((caps.PS20Caps.NumTemps>=22)                          &&
68             (caps.PS20Caps.Caps&D3DPS20CAPS_ARBITRARYSWIZZLE)     &&
69             (caps.PS20Caps.Caps&D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
70             (caps.PS20Caps.Caps&D3DPS20CAPS_PREDICATION)          &&
71             (caps.PS20Caps.Caps&D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
72             (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
73         {
74             return "ps_2_a";
75         }
76         if ((caps.PS20Caps.NumTemps>=32)                          &&
77             (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
78         {
79             return "ps_2_b";
80         }
81         return "ps_2_0";
82 
83     case D3DPS_VERSION(3, 0):
84         return "ps_3_0";
85     }
86 
87     return NULL;
88 }
89 
90 UINT WINAPI D3DXGetShaderSize(const DWORD *byte_code)
91 {
92     const DWORD *ptr = byte_code;
93 
94     TRACE("byte_code %p\n", byte_code);
95 
96     if (!ptr) return 0;
97 
98     /* Look for the END token, skipping the VERSION token */
99     while (*++ptr != D3DSIO_END)
100     {
101         /* Skip comments */
102         if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
103         {
104             ptr += ((*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
105         }
106     }
107     ++ptr;
108 
109     /* Return the shader size in bytes */
110     return (ptr - byte_code) * sizeof(*ptr);
111 }
112 
113 DWORD WINAPI D3DXGetShaderVersion(const DWORD *byte_code)
114 {
115     TRACE("byte_code %p\n", byte_code);
116 
117     return byte_code ? *byte_code : 0;
118 }
119 
120 const char * WINAPI D3DXGetVertexShaderProfile(struct IDirect3DDevice9 *device)
121 {
122     D3DCAPS9 caps;
123 
124     TRACE("device %p\n", device);
125 
126     if (!device) return NULL;
127 
128     IDirect3DDevice9_GetDeviceCaps(device,&caps);
129 
130     switch (caps.VertexShaderVersion)
131     {
132     case D3DVS_VERSION(1, 1):
133         return "vs_1_1";
134     case D3DVS_VERSION(2, 0):
135         if ((caps.VS20Caps.NumTemps>=13) &&
136             (caps.VS20Caps.DynamicFlowControlDepth==24) &&
137             (caps.VS20Caps.Caps&D3DPS20CAPS_PREDICATION))
138         {
139             return "vs_2_a";
140         }
141         return "vs_2_0";
142     case D3DVS_VERSION(3, 0):
143         return "vs_3_0";
144     }
145 
146     return NULL;
147 }
148 
149 HRESULT WINAPI D3DXFindShaderComment(const DWORD *byte_code, DWORD fourcc, const void **data, UINT *size)
150 {
151     const DWORD *ptr = byte_code;
152     DWORD version;
153 
154     TRACE("byte_code %p, fourcc %x, data %p, size %p\n", byte_code, fourcc, data, size);
155 
156     if (data) *data = NULL;
157     if (size) *size = 0;
158 
159     if (!byte_code) return D3DERR_INVALIDCALL;
160 
161     version = *ptr >> 16;
162     if (version != 0x4658         /* FX */
163             && version != 0x5458  /* TX */
164             && version != 0x7ffe
165             && version != 0x7fff
166             && version != 0xfffe  /* VS */
167             && version != 0xffff) /* PS */
168     {
169         WARN("Invalid data supplied\n");
170         return D3DXERR_INVALIDDATA;
171     }
172 
173     while (*++ptr != D3DSIO_END)
174     {
175         /* Check if it is a comment */
176         if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
177         {
178             DWORD comment_size = (*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
179 
180             /* Check if this is the comment we are looking for */
181             if (*(ptr + 1) == fourcc)
182             {
183                 UINT ctab_size = (comment_size - 1) * sizeof(DWORD);
184                 const void *ctab_data = ptr + 2;
185                 if (size)
186                     *size = ctab_size;
187                 if (data)
188                     *data = ctab_data;
189                 TRACE("Returning comment data at %p with size %d\n", ctab_data, ctab_size);
190                 return D3D_OK;
191             }
192             ptr += comment_size;
193         }
194     }
195 
196     return S_FALSE;
197 }
198 
199 HRESULT WINAPI D3DXAssembleShader(const char *data, UINT data_len, const D3DXMACRO *defines,
200         ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
201 {
202     HRESULT hr;
203 
204     TRACE("data %p, data_len %u, defines %p, include %p, flags %#x, shader %p, error_messages %p\n",
205           data, data_len, defines, include, flags, shader, error_messages);
206 
207     /* Forward to d3dcompiler: the parameter types aren't really different,
208        the actual data types are equivalent */
209     hr = D3DAssemble(data, data_len, NULL, (D3D_SHADER_MACRO *)defines,
210                      (ID3DInclude *)include, flags, (ID3DBlob **)shader,
211                      (ID3DBlob **)error_messages);
212 
213     if(hr == E_FAIL) hr = D3DXERR_INVALIDDATA;
214     return hr;
215 }
216 
217 static const void *main_file_data;
218 
219 static CRITICAL_SECTION_DEBUG from_file_mutex_debug =
220 {
221     0, 0, &from_file_mutex,
222     {
223         &from_file_mutex_debug.ProcessLocksList,
224         &from_file_mutex_debug.ProcessLocksList
225     },
226     0, 0, {(DWORD_PTR)(__FILE__ ": from_file_mutex")}
227 };
228 CRITICAL_SECTION from_file_mutex = {&from_file_mutex_debug, -1, 0, 0, 0, 0};
229 
230 /* D3DXInclude private implementation, used to implement
231  * D3DXAssembleShaderFromFile() from D3DXAssembleShader(). */
232 /* To be able to correctly resolve include search paths we have to store the
233  * pathname of each include file. We store the pathname pointer right before
234  * the file data. */
235 static HRESULT WINAPI d3dx_include_from_file_open(ID3DXInclude *iface, D3DXINCLUDE_TYPE include_type,
236         const char *filename, const void *parent_data, const void **data, UINT *bytes)
237 {
238     const char *p, *parent_name = "";
239     char *pathname = NULL, *ptr;
240     char **buffer = NULL;
241     HANDLE file;
242     UINT size;
243 
244     if (parent_data)
245     {
246         parent_name = *((const char **)parent_data - 1);
247     }
248     else
249     {
250         if (main_file_data)
251             parent_name = *((const char **)main_file_data - 1);
252     }
253 
254     TRACE("Looking up include file %s, parent %s.\n", debugstr_a(filename), debugstr_a(parent_name));
255 
256     if ((p = strrchr(parent_name, '\\')))
257         ++p;
258     else
259         p = parent_name;
260     pathname = HeapAlloc(GetProcessHeap(), 0, (p - parent_name) + strlen(filename) + 1);
261     if(!pathname)
262         return HRESULT_FROM_WIN32(GetLastError());
263 
264     memcpy(pathname, parent_name, p - parent_name);
265     strcpy(pathname + (p - parent_name), filename);
266     ptr = pathname + (p - parent_name);
267     while (*ptr)
268     {
269         if (*ptr == '/')
270             *ptr = '\\';
271         ++ptr;
272     }
273 
274     file = CreateFileA(pathname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
275     if(file == INVALID_HANDLE_VALUE)
276         goto error;
277 
278     TRACE("Include file found at pathname = %s\n", debugstr_a(pathname));
279 
280     size = GetFileSize(file, NULL);
281     if(size == INVALID_FILE_SIZE)
282         goto error;
283 
284     buffer = HeapAlloc(GetProcessHeap(), 0, size + sizeof(char *));
285     if(!buffer)
286         goto error;
287     *buffer = pathname;
288     if(!ReadFile(file, buffer + 1, size, bytes, NULL))
289         goto error;
290 
291     *data = buffer + 1;
292     if (!main_file_data)
293         main_file_data = *data;
294 
295     CloseHandle(file);
296     return S_OK;
297 
298 error:
299     CloseHandle(file);
300     HeapFree(GetProcessHeap(), 0, pathname);
301     HeapFree(GetProcessHeap(), 0, buffer);
302     return HRESULT_FROM_WIN32(GetLastError());
303 }
304 
305 static HRESULT WINAPI d3dx_include_from_file_close(ID3DXInclude *iface, const void *data)
306 {
307     HeapFree(GetProcessHeap(), 0, *((char **)data - 1));
308     HeapFree(GetProcessHeap(), 0, (char **)data - 1);
309     if (main_file_data == data)
310         main_file_data = NULL;
311     return S_OK;
312 }
313 
314 const struct ID3DXIncludeVtbl d3dx_include_from_file_vtbl =
315 {
316     d3dx_include_from_file_open,
317     d3dx_include_from_file_close
318 };
319 
320 HRESULT WINAPI D3DXAssembleShaderFromFileA(const char *filename, const D3DXMACRO *defines,
321         ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
322 {
323     WCHAR *filename_w;
324     DWORD len;
325     HRESULT ret;
326 
327     TRACE("filename %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
328             debugstr_a(filename), defines, include, flags, shader, error_messages);
329 
330     if (!filename) return D3DXERR_INVALIDDATA;
331 
332     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
333     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
334     if (!filename_w) return E_OUTOFMEMORY;
335     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
336 
337     ret = D3DXAssembleShaderFromFileW(filename_w, defines, include, flags, shader, error_messages);
338 
339     HeapFree(GetProcessHeap(), 0, filename_w);
340     return ret;
341 }
342 
343 HRESULT WINAPI D3DXAssembleShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
344         ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
345 {
346     const void *buffer;
347     DWORD len;
348     HRESULT hr;
349     struct d3dx_include_from_file include_from_file;
350     char *filename_a;
351 
352     TRACE("filename %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
353             debugstr_w(filename), defines, include, flags, shader, error_messages);
354 
355     if(!include)
356     {
357         include_from_file.ID3DXInclude_iface.lpVtbl = &d3dx_include_from_file_vtbl;
358         include = &include_from_file.ID3DXInclude_iface;
359     }
360 
361     len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
362     filename_a = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
363     if (!filename_a)
364         return E_OUTOFMEMORY;
365     WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, len, NULL, NULL);
366 
367     EnterCriticalSection(&from_file_mutex);
368     hr = ID3DXInclude_Open(include, D3DXINC_LOCAL, filename_a, NULL, &buffer, &len);
369     if (FAILED(hr))
370     {
371         LeaveCriticalSection(&from_file_mutex);
372         HeapFree(GetProcessHeap(), 0, filename_a);
373         return D3DXERR_INVALIDDATA;
374     }
375 
376     hr = D3DXAssembleShader(buffer, len, defines, include, flags, shader, error_messages);
377 
378     ID3DXInclude_Close(include, buffer);
379     LeaveCriticalSection(&from_file_mutex);
380     HeapFree(GetProcessHeap(), 0, filename_a);
381     return hr;
382 }
383 
384 HRESULT WINAPI D3DXAssembleShaderFromResourceA(HMODULE module, const char *resource, const D3DXMACRO *defines,
385         ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
386 {
387     void *buffer;
388     HRSRC res;
389     DWORD len;
390 
391     TRACE("module %p, resource %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
392             module, debugstr_a(resource), defines, include, flags, shader, error_messages);
393 
394     if (!(res = FindResourceA(module, resource, (const char *)RT_RCDATA)))
395         return D3DXERR_INVALIDDATA;
396     if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
397         return D3DXERR_INVALIDDATA;
398     return D3DXAssembleShader(buffer, len, defines, include, flags,
399                               shader, error_messages);
400 }
401 
402 HRESULT WINAPI D3DXAssembleShaderFromResourceW(HMODULE module, const WCHAR *resource, const D3DXMACRO *defines,
403         ID3DXInclude *include, DWORD flags, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
404 {
405     void *buffer;
406     HRSRC res;
407     DWORD len;
408 
409     TRACE("module %p, resource %s, defines %p, include %p, flags %#x, shader %p, error_messages %p.\n",
410             module, debugstr_w(resource), defines, include, flags, shader, error_messages);
411 
412     if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
413         return D3DXERR_INVALIDDATA;
414     if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
415         return D3DXERR_INVALIDDATA;
416     return D3DXAssembleShader(buffer, len, defines, include, flags,
417                               shader, error_messages);
418 }
419 
420 HRESULT WINAPI D3DXCompileShader(const char *data, UINT length, const D3DXMACRO *defines,
421         ID3DXInclude *include, const char *function, const char *profile, DWORD flags,
422         ID3DXBuffer **shader, ID3DXBuffer **error_msgs, ID3DXConstantTable **constant_table)
423 {
424     HRESULT hr;
425 
426     TRACE("data %s, length %u, defines %p, include %p, function %s, profile %s, "
427             "flags %#x, shader %p, error_msgs %p, constant_table %p.\n",
428             debugstr_a(data), length, defines, include, debugstr_a(function), debugstr_a(profile),
429             flags, shader, error_msgs, constant_table);
430 
431     hr = D3DCompile(data, length, NULL, (D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
432                     function, profile, flags, 0, (ID3DBlob **)shader, (ID3DBlob **)error_msgs);
433 
434     if (SUCCEEDED(hr) && constant_table)
435     {
436         hr = D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*shader), constant_table);
437         if (FAILED(hr))
438         {
439             ID3DXBuffer_Release(*shader);
440             *shader = NULL;
441         }
442     }
443 
444     /* Filter out D3DCompile warning messages that are not present with D3DCompileShader */
445     if (SUCCEEDED(hr) && error_msgs && *error_msgs)
446     {
447         char *messages = ID3DXBuffer_GetBufferPointer(*error_msgs);
448         DWORD size     = ID3DXBuffer_GetBufferSize(*error_msgs);
449 
450         /* Ensure messages are null terminated for safe processing */
451         if (size) messages[size - 1] = 0;
452 
453         while (size > 1)
454         {
455             char *prev, *next;
456 
457             /* Warning has the form "warning X3206: ... implicit truncation of vector type"
458                but we only search for "X3206:" in case d3dcompiler_43 has localization */
459             prev = next = strstr(messages, "X3206:");
460             if (!prev) break;
461 
462             /* get pointer to beginning and end of current line */
463             while (prev > messages && *(prev - 1) != '\n') prev--;
464             while (next < messages + size - 1 && *next != '\n') next++;
465             if (next < messages + size - 1 && *next == '\n') next++;
466 
467             memmove(prev, next, messages + size - next);
468             size -= (next - prev);
469         }
470 
471         /* Only return a buffer if the resulting string is not empty as some apps depend on that */
472         if (size <= 1)
473         {
474             ID3DXBuffer_Release(*error_msgs);
475             *error_msgs = NULL;
476         }
477     }
478 
479     return hr;
480 }
481 
482 HRESULT WINAPI D3DXCompileShaderFromFileA(const char *filename, const D3DXMACRO *defines,
483         ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
484         ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
485 {
486     WCHAR *filename_w;
487     DWORD len;
488     HRESULT ret;
489 
490     TRACE("filename %s, defines %p, include %p, entrypoint %s, profile %s, "
491             "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
492             debugstr_a(filename), defines, include, debugstr_a(entrypoint),
493             debugstr_a(profile), flags, shader, error_messages, constant_table);
494 
495     if (!filename) return D3DXERR_INVALIDDATA;
496 
497     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
498     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
499     if (!filename_w) return E_OUTOFMEMORY;
500     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
501 
502     ret = D3DXCompileShaderFromFileW(filename_w, defines, include,
503                                      entrypoint, profile, flags,
504                                      shader, error_messages, constant_table);
505 
506     HeapFree(GetProcessHeap(), 0, filename_w);
507     return ret;
508 }
509 
510 HRESULT WINAPI D3DXCompileShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
511         ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
512         ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
513 {
514     const void *buffer;
515     DWORD len, filename_len;
516     HRESULT hr;
517     struct d3dx_include_from_file include_from_file;
518     char *filename_a;
519 
520     TRACE("filename %s, defines %p, include %p, entrypoint %s, profile %s, "
521             "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
522             debugstr_w(filename), defines, include, debugstr_a(entrypoint), debugstr_a(profile),
523             flags, shader, error_messages, constant_table);
524 
525     if (!include)
526     {
527         include_from_file.ID3DXInclude_iface.lpVtbl = &d3dx_include_from_file_vtbl;
528         include = &include_from_file.ID3DXInclude_iface;
529     }
530 
531     filename_len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
532     filename_a = HeapAlloc(GetProcessHeap(), 0, filename_len * sizeof(char));
533     if (!filename_a)
534         return E_OUTOFMEMORY;
535     WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, filename_len, NULL, NULL);
536 
537     EnterCriticalSection(&from_file_mutex);
538     hr = ID3DXInclude_Open(include, D3DXINC_LOCAL, filename_a, NULL, &buffer, &len);
539     if (FAILED(hr))
540     {
541         LeaveCriticalSection(&from_file_mutex);
542         HeapFree(GetProcessHeap(), 0, filename_a);
543         return D3DXERR_INVALIDDATA;
544     }
545 
546     hr = D3DCompile(buffer, len, filename_a, (const D3D_SHADER_MACRO *)defines,
547                     (ID3DInclude *)include, entrypoint, profile, flags, 0,
548                     (ID3DBlob **)shader, (ID3DBlob **)error_messages);
549 
550     if (SUCCEEDED(hr) && constant_table)
551         hr = D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*shader),
552                                         constant_table);
553 
554     ID3DXInclude_Close(include, buffer);
555     LeaveCriticalSection(&from_file_mutex);
556     HeapFree(GetProcessHeap(), 0, filename_a);
557     return hr;
558 }
559 
560 HRESULT WINAPI D3DXCompileShaderFromResourceA(HMODULE module, const char *resource, const D3DXMACRO *defines,
561         ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
562         ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
563 {
564     void *buffer;
565     HRSRC res;
566     DWORD len;
567 
568     TRACE("module %p, resource %s, defines %p, include %p, entrypoint %s, profile %s, "
569             "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
570             module, debugstr_a(resource), defines, include, debugstr_a(entrypoint), debugstr_a(profile),
571             flags, shader, error_messages, constant_table);
572 
573     if (!(res = FindResourceA(module, resource, (const char *)RT_RCDATA)))
574         return D3DXERR_INVALIDDATA;
575     if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
576         return D3DXERR_INVALIDDATA;
577     return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
578                              flags, shader, error_messages, constant_table);
579 }
580 
581 HRESULT WINAPI D3DXCompileShaderFromResourceW(HMODULE module, const WCHAR *resource, const D3DXMACRO *defines,
582         ID3DXInclude *include, const char *entrypoint, const char *profile, DWORD flags,
583         ID3DXBuffer **shader, ID3DXBuffer **error_messages, ID3DXConstantTable **constant_table)
584 {
585     void *buffer;
586     HRSRC res;
587     DWORD len;
588 
589     TRACE("module %p, resource %s, defines %p, include %p, entrypoint %s, profile %s, "
590             "flags %#x, shader %p, error_messages %p, constant_table %p.\n",
591             module, debugstr_w(resource), defines, include, debugstr_a(entrypoint), debugstr_a(profile),
592             flags, shader, error_messages, constant_table);
593 
594     if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
595         return D3DXERR_INVALIDDATA;
596     if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
597         return D3DXERR_INVALIDDATA;
598     return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
599                              flags, shader, error_messages, constant_table);
600 }
601 
602 HRESULT WINAPI D3DXPreprocessShader(const char *data, UINT data_len, const D3DXMACRO *defines,
603         ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
604 {
605     TRACE("data %s, data_len %u, defines %p, include %p, shader %p, error_messages %p.\n",
606             debugstr_a(data), data_len, defines, include, shader, error_messages);
607 
608     return D3DPreprocess(data, data_len, NULL,
609                          (const D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
610                          (ID3DBlob **)shader, (ID3DBlob **)error_messages);
611 }
612 
613 HRESULT WINAPI D3DXPreprocessShaderFromFileA(const char *filename, const D3DXMACRO *defines,
614         ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
615 {
616     WCHAR *filename_w = NULL;
617     DWORD len;
618     HRESULT ret;
619 
620     TRACE("filename %s, defines %p, include %p, shader %p, error_messages %p.\n",
621             debugstr_a(filename), defines, include, shader, error_messages);
622 
623     if (!filename) return D3DXERR_INVALIDDATA;
624 
625     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
626     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
627     if (!filename_w) return E_OUTOFMEMORY;
628     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
629 
630     ret = D3DXPreprocessShaderFromFileW(filename_w, defines, include, shader, error_messages);
631 
632     HeapFree(GetProcessHeap(), 0, filename_w);
633     return ret;
634 }
635 
636 HRESULT WINAPI D3DXPreprocessShaderFromFileW(const WCHAR *filename, const D3DXMACRO *defines,
637         ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
638 {
639     const void *buffer;
640     DWORD len;
641     HRESULT hr;
642     struct d3dx_include_from_file include_from_file;
643     char *filename_a;
644 
645     TRACE("filename %s, defines %p, include %p, shader %p, error_messages %p.\n",
646             debugstr_w(filename), defines, include, shader, error_messages);
647 
648     if (!include)
649     {
650         include_from_file.ID3DXInclude_iface.lpVtbl = &d3dx_include_from_file_vtbl;
651         include = &include_from_file.ID3DXInclude_iface;
652     }
653 
654     len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
655     filename_a = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
656     if (!filename_a)
657         return E_OUTOFMEMORY;
658     WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, len, NULL, NULL);
659 
660     EnterCriticalSection(&from_file_mutex);
661     hr = ID3DXInclude_Open(include, D3DXINC_LOCAL, filename_a, NULL, &buffer, &len);
662     if (FAILED(hr))
663     {
664         LeaveCriticalSection(&from_file_mutex);
665         HeapFree(GetProcessHeap(), 0, filename_a);
666         return D3DXERR_INVALIDDATA;
667     }
668 
669     hr = D3DPreprocess(buffer, len, NULL,
670                        (const D3D_SHADER_MACRO *)defines,
671                        (ID3DInclude *) include,
672                        (ID3DBlob **)shader, (ID3DBlob **)error_messages);
673 
674     ID3DXInclude_Close(include, buffer);
675     LeaveCriticalSection(&from_file_mutex);
676     HeapFree(GetProcessHeap(), 0, filename_a);
677     return hr;
678 }
679 
680 HRESULT WINAPI D3DXPreprocessShaderFromResourceA(HMODULE module, const char *resource, const D3DXMACRO *defines,
681         ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
682 {
683     void *buffer;
684     HRSRC res;
685     DWORD len;
686 
687     TRACE("module %p, resource %s, defines %p, include %p, shader %p, error_messages %p.\n",
688             module, debugstr_a(resource), defines, include, shader, error_messages);
689 
690     if (!(res = FindResourceA(module, resource, (const char *)RT_RCDATA)))
691         return D3DXERR_INVALIDDATA;
692     if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
693         return D3DXERR_INVALIDDATA;
694     return D3DXPreprocessShader(buffer, len, defines, include,
695                                 shader, error_messages);
696 }
697 
698 HRESULT WINAPI D3DXPreprocessShaderFromResourceW(HMODULE module, const WCHAR *resource, const D3DXMACRO *defines,
699         ID3DXInclude *include, ID3DXBuffer **shader, ID3DXBuffer **error_messages)
700 {
701     void *buffer;
702     HRSRC res;
703     DWORD len;
704 
705     TRACE("module %p, resource %s, defines %p, include %p, shader %p, error_messages %p.\n",
706             module, debugstr_w(resource), defines, include, shader, error_messages);
707 
708     if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
709         return D3DXERR_INVALIDDATA;
710     if (FAILED(load_resource_into_memory(module, res, &buffer, &len)))
711         return D3DXERR_INVALIDDATA;
712     return D3DXPreprocessShader(buffer, len, defines, include,
713                                 shader, error_messages);
714 
715 }
716 
717 struct ID3DXConstantTableImpl {
718     ID3DXConstantTable ID3DXConstantTable_iface;
719     LONG ref;
720     char *ctab;
721     DWORD size;
722     D3DXCONSTANTTABLE_DESC desc;
723     struct ctab_constant *constants;
724 };
725 
726 static void free_constant(struct ctab_constant *constant)
727 {
728     if (constant->constants)
729     {
730         UINT i, count = constant->desc.Elements > 1 ? constant->desc.Elements : constant->desc.StructMembers;
731 
732         for (i = 0; i < count; ++i)
733         {
734             free_constant(&constant->constants[i]);
735         }
736         HeapFree(GetProcessHeap(), 0, constant->constants);
737     }
738 }
739 
740 static void free_constant_table(struct ID3DXConstantTableImpl *table)
741 {
742     if (table->constants)
743     {
744         UINT i;
745 
746         for (i = 0; i < table->desc.Constants; ++i)
747         {
748             free_constant(&table->constants[i]);
749         }
750         HeapFree(GetProcessHeap(), 0, table->constants);
751     }
752     HeapFree(GetProcessHeap(), 0, table->ctab);
753 }
754 
755 static inline struct ID3DXConstantTableImpl *impl_from_ID3DXConstantTable(ID3DXConstantTable *iface)
756 {
757     return CONTAINING_RECORD(iface, struct ID3DXConstantTableImpl, ID3DXConstantTable_iface);
758 }
759 
760 static inline BOOL is_vertex_shader(DWORD version)
761 {
762     return (version & 0xffff0000) == 0xfffe0000;
763 }
764 
765 static inline D3DXHANDLE handle_from_constant(struct ctab_constant *constant)
766 {
767     return (D3DXHANDLE)constant;
768 }
769 
770 static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *table,
771         struct ctab_constant *constant, const char *name);
772 
773 static struct ctab_constant *get_constant_element_by_name(struct ctab_constant *constant, const char *name)
774 {
775     const char *part;
776     UINT element;
777 
778     TRACE("constant %p, name %s\n", constant, debugstr_a(name));
779 
780     if (!name || !*name) return NULL;
781 
782     element = atoi(name);
783     part = strchr(name, ']') + 1;
784 
785     if (constant->desc.Elements > element)
786     {
787         struct ctab_constant *c = constant->constants ? &constant->constants[element] : constant;
788 
789         switch (*part++)
790         {
791             case '.':
792                 return get_constant_by_name(NULL, c, part);
793 
794             case '[':
795                 return get_constant_element_by_name(c, part);
796 
797             case '\0':
798                 TRACE("Returning parameter %p\n", c);
799                 return c;
800 
801             default:
802                 FIXME("Unhandled case \"%c\"\n", *--part);
803                 break;
804         }
805     }
806 
807     TRACE("Constant not found\n");
808     return NULL;
809 }
810 
811 static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *table,
812         struct ctab_constant *constant, const char *name)
813 {
814     UINT i, count, length;
815     struct ctab_constant *handles;
816     const char *part;
817 
818     TRACE("table %p, constant %p, name %s\n", table, constant, debugstr_a(name));
819 
820     if (!name || !*name) return NULL;
821 
822     if (!constant)
823     {
824         count = table->desc.Constants;
825         handles = table->constants;
826     }
827     else
828     {
829         count = constant->desc.StructMembers;
830         handles = constant->constants;
831     }
832 
833     length = strcspn(name, "[.");
834     part = name + length;
835 
836     for (i = 0; i < count; i++)
837     {
838         if (strlen(handles[i].desc.Name) == length && !strncmp(handles[i].desc.Name, name, length))
839         {
840             switch (*part++)
841             {
842                 case '.':
843                     return get_constant_by_name(NULL, &handles[i], part);
844 
845                 case '[':
846                     return get_constant_element_by_name(&handles[i], part);
847 
848                 default:
849                     TRACE("Returning parameter %p\n", &handles[i]);
850                     return &handles[i];
851             }
852         }
853     }
854 
855     TRACE("Constant not found\n");
856     return NULL;
857 }
858 
859 static struct ctab_constant *is_valid_sub_constant(struct ctab_constant *parent, D3DXHANDLE handle)
860 {
861     struct ctab_constant *c;
862     UINT i, count;
863 
864     /* all variable have at least elements = 1, but not always elements */
865     if (!parent->constants) return NULL;
866 
867     count = parent->desc.Elements > 1 ? parent->desc.Elements : parent->desc.StructMembers;
868     for (i = 0; i < count; ++i)
869     {
870         if (handle_from_constant(&parent->constants[i]) == handle)
871             return &parent->constants[i];
872 
873         c = is_valid_sub_constant(&parent->constants[i], handle);
874         if (c) return c;
875     }
876 
877     return NULL;
878 }
879 
880 static inline struct ctab_constant *get_valid_constant(struct ID3DXConstantTableImpl *table, D3DXHANDLE handle)
881 {
882     struct ctab_constant *c;
883     UINT i;
884 
885     if (!handle) return NULL;
886 
887     for (i = 0; i < table->desc.Constants; ++i)
888     {
889         if (handle_from_constant(&table->constants[i]) == handle)
890             return &table->constants[i];
891 
892         c = is_valid_sub_constant(&table->constants[i], handle);
893         if (c) return c;
894     }
895 
896     return get_constant_by_name(table, NULL, handle);
897 }
898 
899 /*** IUnknown methods ***/
900 static HRESULT WINAPI ID3DXConstantTableImpl_QueryInterface(ID3DXConstantTable *iface, REFIID riid, void **out)
901 {
902     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
903 
904     if (IsEqualGUID(riid, &IID_IUnknown) ||
905         IsEqualGUID(riid, &IID_ID3DXBuffer) ||
906         IsEqualGUID(riid, &IID_ID3DXConstantTable))
907     {
908         ID3DXConstantTable_AddRef(iface);
909         *out = iface;
910         return S_OK;
911     }
912 
913     WARN("Interface %s not found.\n", debugstr_guid(riid));
914 
915     return E_NOINTERFACE;
916 }
917 
918 static ULONG WINAPI ID3DXConstantTableImpl_AddRef(ID3DXConstantTable *iface)
919 {
920     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
921 
922     TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
923 
924     return InterlockedIncrement(&This->ref);
925 }
926 
927 static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable *iface)
928 {
929     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
930     ULONG ref = InterlockedDecrement(&This->ref);
931 
932     TRACE("(%p)->(): Release from %d\n", This, ref + 1);
933 
934     if (!ref)
935     {
936         free_constant_table(This);
937         HeapFree(GetProcessHeap(), 0, This);
938     }
939 
940     return ref;
941 }
942 
943 /*** ID3DXBuffer methods ***/
944 static void * WINAPI ID3DXConstantTableImpl_GetBufferPointer(ID3DXConstantTable *iface)
945 {
946     struct ID3DXConstantTableImpl *table = impl_from_ID3DXConstantTable(iface);
947 
948     TRACE("iface %p.\n", iface);
949 
950     return table->ctab;
951 }
952 
953 static DWORD WINAPI ID3DXConstantTableImpl_GetBufferSize(ID3DXConstantTable *iface)
954 {
955     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
956 
957     TRACE("(%p)->()\n", This);
958 
959     return This->size;
960 }
961 
962 /*** ID3DXConstantTable methods ***/
963 static HRESULT WINAPI ID3DXConstantTableImpl_GetDesc(ID3DXConstantTable *iface, D3DXCONSTANTTABLE_DESC *desc)
964 {
965     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
966 
967     TRACE("(%p)->(%p)\n", This, desc);
968 
969     if (!desc)
970         return D3DERR_INVALIDCALL;
971 
972     *desc = This->desc;
973 
974     return D3D_OK;
975 }
976 
977 const struct ctab_constant *d3dx_shader_get_ctab_constant(ID3DXConstantTable *iface, D3DXHANDLE constant)
978 {
979     struct ID3DXConstantTableImpl *ctab = impl_from_ID3DXConstantTable(iface);
980 
981     return get_valid_constant(ctab, constant);
982 }
983 
984 static HRESULT WINAPI ID3DXConstantTableImpl_GetConstantDesc(ID3DXConstantTable *iface, D3DXHANDLE constant,
985                                                              D3DXCONSTANT_DESC *desc, UINT *count)
986 {
987     struct ID3DXConstantTableImpl *ctab = impl_from_ID3DXConstantTable(iface);
988     struct ctab_constant *c = get_valid_constant(ctab, constant);
989 
990     TRACE("(%p)->(%p, %p, %p)\n", ctab, constant, desc, count);
991 
992     if (!c)
993     {
994         WARN("Invalid argument specified\n");
995         return D3DERR_INVALIDCALL;
996     }
997 
998     if (desc) *desc = c->desc;
999     if (count) *count = 1;
1000 
1001     return D3D_OK;
1002 }
1003 
1004 static UINT WINAPI ID3DXConstantTableImpl_GetSamplerIndex(ID3DXConstantTable *iface, D3DXHANDLE constant)
1005 {
1006     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1007     struct ctab_constant *c = get_valid_constant(This, constant);
1008 
1009     TRACE("(%p)->(%p)\n", This, constant);
1010 
1011     if (!c || c->desc.RegisterSet != D3DXRS_SAMPLER)
1012     {
1013         WARN("Invalid argument specified\n");
1014         return (UINT)-1;
1015     }
1016 
1017     TRACE("Returning RegisterIndex %u\n", c->desc.RegisterIndex);
1018     return c->desc.RegisterIndex;
1019 }
1020 
1021 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstant(ID3DXConstantTable *iface, D3DXHANDLE constant, UINT index)
1022 {
1023     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1024     struct ctab_constant *c;
1025 
1026     TRACE("(%p)->(%p, %d)\n", This, constant, index);
1027 
1028     if (constant)
1029     {
1030         c = get_valid_constant(This, constant);
1031         if (c && index < c->desc.StructMembers)
1032         {
1033             c = &c->constants[index];
1034             TRACE("Returning constant %p\n", c);
1035             return handle_from_constant(c);
1036         }
1037     }
1038     else
1039     {
1040         if (index < This->desc.Constants)
1041         {
1042             c = &This->constants[index];
1043             TRACE("Returning constant %p\n", c);
1044             return handle_from_constant(c);
1045         }
1046     }
1047 
1048     WARN("Index out of range\n");
1049     return NULL;
1050 }
1051 
1052 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable *iface,
1053         D3DXHANDLE constant, const char *name)
1054 {
1055     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1056     struct ctab_constant *c = get_valid_constant(This, constant);
1057 
1058     TRACE("iface %p, constant %p, name %s.\n", iface, constant, debugstr_a(name));
1059 
1060     c = get_constant_by_name(This, c, name);
1061     TRACE("Returning constant %p\n", c);
1062 
1063     return handle_from_constant(c);
1064 }
1065 
1066 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantElement(ID3DXConstantTable *iface, D3DXHANDLE constant, UINT index)
1067 {
1068     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1069     struct ctab_constant *c = get_valid_constant(This, constant);
1070 
1071     TRACE("(%p)->(%p, %d)\n", This, constant, index);
1072 
1073     if (c && index < c->desc.Elements)
1074     {
1075         if (c->desc.Elements > 1) c = &c->constants[index];
1076         TRACE("Returning constant %p\n", c);
1077         return handle_from_constant(c);
1078     }
1079 
1080     WARN("Invalid argument specified\n");
1081     return NULL;
1082 }
1083 
1084 static inline DWORD get_index(const void **indata, UINT index, BOOL is_pointer)
1085 {
1086     if (!indata)
1087         return 0;
1088 
1089     if (is_pointer)
1090         return ((DWORD **)indata)[index / 16][index % 16];
1091 
1092     return (*((DWORD **)indata))[index];
1093 }
1094 
1095 static UINT set(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, struct ctab_constant *constant,
1096         const void **indata, D3DXPARAMETER_TYPE intype, UINT *size, UINT incol, D3DXPARAMETER_CLASS inclass, UINT index,
1097         BOOL is_pointer)
1098 {
1099     D3DXCONSTANT_DESC *desc = &constant->desc;
1100     UINT l, i, regcount = 1, regsize = 1, cin = 1, rin = 1, ret, last = 0;
1101     DWORD tmp;
1102 
1103     /* size too small to set anything */
1104     if (*size < desc->Rows * desc->Columns)
1105     {
1106         *size = 0;
1107         return 0;
1108     }
1109 
1110     /* D3DXPC_STRUCT is somewhat special */
1111     if (desc->Class == D3DXPC_STRUCT)
1112     {
1113         /*
1114          * Struct array sets the last complete input to the first struct element, all other
1115          * elements are not set.
1116          * E.g.: struct {int i;} s1[2];
1117          *       SetValue(device, "s1", [1, 2], 8) => s1 = {2, x};
1118          *
1119          *       struct {int i; int n} s2[2];
1120          *       SetValue(device, "s2", [1, 2, 3, 4, 5], 20) => s1 = {{3, 4}, {x, x}};
1121          */
1122         if (desc->Elements > 1)
1123         {
1124             UINT offset = *size / (desc->Rows * desc->Columns) - 1;
1125 
1126             offset = min(desc->Elements - 1, offset);
1127             last = offset * desc->Rows * desc->Columns;
1128 
1129             if ((is_pointer || inclass == D3DXPC_MATRIX_ROWS) && desc->RegisterSet != D3DXRS_BOOL)
1130             {
1131                 set(table, device, &constant->constants[0], NULL, intype, size, incol, inclass, 0, is_pointer);
1132             }
1133             else
1134             {
1135                 last += set(table, device, &constant->constants[0], indata, intype, size, incol, inclass,
1136                         index + last, is_pointer);
1137             }
1138         }
1139         else
1140         {
1141             /*
1142              * D3DXRS_BOOL is always set. As there are only 16 bools and there are
1143              * exactly 16 input values, use matrix transpose.
1144              */
1145             if (inclass == D3DXPC_MATRIX_ROWS && desc->RegisterSet == D3DXRS_BOOL)
1146             {
1147                 D3DXMATRIX mat, *m, min;
1148                 D3DXMatrixTranspose(&mat, &min);
1149 
1150                 if (is_pointer)
1151                     min = *(D3DXMATRIX *)(indata[index / 16]);
1152                 else
1153                     min = **(D3DXMATRIX **)indata;
1154 
1155                 D3DXMatrixTranspose(&mat, &min);
1156                 m = &mat;
1157                 for (i = 0; i < desc->StructMembers; ++i)
1158                 {
1159                     last += set(table, device, &constant->constants[i], (const void **)&m, intype, size, incol,
1160                             D3DXPC_SCALAR, index + last, is_pointer);
1161                 }
1162             }
1163             /*
1164              * For pointers or for matrix rows, only the first member is set.
1165              * All other members are set to 0. This is not true for D3DXRS_BOOL.
1166              * E.g.: struct {int i; int n} s;
1167              *       SetValue(device, "s", [1, 2], 8) => s = {1, 0};
1168              */
1169             else if ((is_pointer || inclass == D3DXPC_MATRIX_ROWS) && desc->RegisterSet != D3DXRS_BOOL)
1170             {
1171                 last = set(table, device, &constant->constants[0], indata, intype, size, incol, inclass,
1172                         index + last, is_pointer);
1173 
1174                 for (i = 1; i < desc->StructMembers; ++i)
1175                 {
1176                     set(table, device, &constant->constants[i], NULL, intype, size, incol, inclass, 0, is_pointer);
1177                 }
1178             }
1179             else
1180             {
1181                 for (i = 0; i < desc->StructMembers; ++i)
1182                 {
1183                     last += set(table, device, &constant->constants[i], indata, intype, size, incol, D3DXPC_SCALAR,
1184                             index + last, is_pointer);
1185                 }
1186             }
1187         }
1188 
1189         return last;
1190     }
1191 
1192     /* elements */
1193     if (desc->Elements > 1)
1194     {
1195         for (i = 0; i < desc->Elements && *size > 0; ++i)
1196         {
1197             last += set(table, device, &constant->constants[i], indata, intype, size, incol, inclass,
1198                     index + last, is_pointer);
1199 
1200             /* adjust the vector size for matrix rows */
1201             if (inclass == D3DXPC_MATRIX_ROWS && desc->Class == D3DXPC_VECTOR && (i % 4) == 3)
1202             {
1203                 last += 12;
1204                 *size = *size < 12 ? 0 : *size - 12;
1205             }
1206         }
1207 
1208         return last;
1209     }
1210 
1211     switch (desc->Class)
1212     {
1213         case D3DXPC_SCALAR:
1214         case D3DXPC_VECTOR:
1215         case D3DXPC_MATRIX_ROWS:
1216             regcount = min(desc->RegisterCount, desc->Rows);
1217             if (inclass == D3DXPC_MATRIX_ROWS) cin = incol;
1218             else rin = incol;
1219             regsize = desc->Columns;
1220             break;
1221 
1222         case D3DXPC_MATRIX_COLUMNS:
1223             regcount = min(desc->RegisterCount, desc->Columns);
1224             if (inclass == D3DXPC_MATRIX_ROWS) rin = incol;
1225             else cin = incol;
1226             regsize = desc->Rows;
1227             break;
1228 
1229         default:
1230             FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
1231             return 0;
1232     }
1233 
1234     /* specific stuff for different in types */
1235     switch (inclass)
1236     {
1237         case D3DXPC_SCALAR:
1238             ret = desc->Columns * desc->Rows;
1239             *size -= desc->Columns * desc->Rows;
1240             break;
1241 
1242         case D3DXPC_VECTOR:
1243             switch (desc->Class)
1244             {
1245                 case D3DXPC_MATRIX_ROWS:
1246                     if (*size < regcount * 4)
1247                     {
1248                         *size = 0;
1249                         return 0;
1250                     }
1251                     ret = 4 * regcount;
1252                     *size -= 4 * regcount;
1253                     break;
1254 
1255                 case D3DXPC_MATRIX_COLUMNS:
1256                     ret = 4 * regsize;
1257                     *size -= 4 * regcount;
1258                     break;
1259 
1260                 case D3DXPC_SCALAR:
1261                     ret = 1;
1262                     *size -= ret;
1263                     break;
1264 
1265                 case D3DXPC_VECTOR:
1266                     ret = 4;
1267                     *size -= ret;
1268                     break;
1269 
1270                 default:
1271                     FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
1272                     return 0;
1273             }
1274             break;
1275 
1276         case D3DXPC_MATRIX_ROWS:
1277             switch (desc->Class)
1278             {
1279                 case D3DXPC_MATRIX_ROWS:
1280                 case D3DXPC_MATRIX_COLUMNS:
1281                     if (*size < 16)
1282                     {
1283                         *size = 0;
1284                         return 0;
1285                     }
1286                     ret = 16;
1287                     break;
1288 
1289                 case D3DXPC_SCALAR:
1290                     ret = 4;
1291                     break;
1292 
1293                 case D3DXPC_VECTOR:
1294                     ret = 1;
1295                     break;
1296 
1297                 default:
1298                     FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
1299                     return 0;
1300             }
1301             *size -= ret;
1302             break;
1303 
1304         case D3DXPC_MATRIX_COLUMNS:
1305             switch (desc->Class)
1306             {
1307                 case D3DXPC_MATRIX_ROWS:
1308                 case D3DXPC_MATRIX_COLUMNS:
1309                     if (*size < 16)
1310                     {
1311                         *size = 0;
1312                         return 0;
1313                     }
1314                     ret = 16;
1315                     break;
1316 
1317                 case D3DXPC_SCALAR:
1318                     ret = 1;
1319                     break;
1320 
1321                 case D3DXPC_VECTOR:
1322                     ret = 4;
1323                     break;
1324 
1325                 default:
1326                     FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
1327                     return 0;
1328             }
1329             *size -= ret;
1330             break;
1331 
1332         default:
1333             FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(inclass));
1334             return 0;
1335     }
1336 
1337     /* set the registers */
1338     switch (desc->RegisterSet)
1339     {
1340         case D3DXRS_BOOL:
1341             regcount = min(desc->RegisterCount, desc->Columns * desc->Rows);
1342             l = 0;
1343             for (i = 0; i < regcount; ++i)
1344             {
1345                 BOOL out;
1346                 DWORD t = get_index(indata, index + i / regsize * rin + l * cin, is_pointer);
1347 
1348                 set_number(&tmp, desc->Type, &t, intype);
1349                 set_number(&out, D3DXPT_BOOL, &tmp, desc->Type);
1350                 if (is_vertex_shader(table->desc.Version))
1351                     IDirect3DDevice9_SetVertexShaderConstantB(device, desc->RegisterIndex + i, &out, 1);
1352                 else
1353                     IDirect3DDevice9_SetPixelShaderConstantB(device, desc->RegisterIndex + i, &out, 1);
1354 
1355                 if (++l >= regsize) l = 0;
1356             }
1357             return ret;
1358 
1359         case D3DXRS_INT4:
1360             for (i = 0; i < regcount; ++i)
1361             {
1362                 INT vec[4] = {0, 0, 1, 0};
1363 
1364                 for (l = 0; l < regsize; ++l)
1365                 {
1366                     DWORD t = get_index(indata, index + i * rin + l * cin, is_pointer);
1367 
1368                     set_number(&tmp, desc->Type, &t, intype);
1369                     set_number(&vec[l], D3DXPT_INT, &tmp, desc->Type);
1370                 }
1371                 if (is_vertex_shader(table->desc.Version))
1372                     IDirect3DDevice9_SetVertexShaderConstantI(device, desc->RegisterIndex + i, vec, 1);
1373                 else
1374                     IDirect3DDevice9_SetPixelShaderConstantI(device, desc->RegisterIndex + i, vec, 1);
1375             }
1376             return ret;
1377 
1378         case D3DXRS_FLOAT4:
1379             for (i = 0; i < regcount; ++i)
1380             {
1381                 FLOAT vec[4] = {0};
1382 
1383                 for (l = 0; l < regsize; ++l)
1384                 {
1385                     DWORD t = get_index(indata, index + i * rin + l * cin, is_pointer);
1386 
1387                     set_number(&tmp, desc->Type, &t, intype);
1388                     set_number(&vec[l], D3DXPT_FLOAT, &tmp, desc->Type);
1389                 }
1390                 if (is_vertex_shader(table->desc.Version))
1391                     IDirect3DDevice9_SetVertexShaderConstantF(device, desc->RegisterIndex + i, vec, 1);
1392                 else
1393                     IDirect3DDevice9_SetPixelShaderConstantF(device, desc->RegisterIndex + i, vec, 1);
1394             }
1395             return ret;
1396 
1397         default:
1398             FIXME("Unhandled register set %s\n", debug_d3dxparameter_registerset(desc->RegisterSet));
1399             return 0;
1400     }
1401 }
1402 
1403 static HRESULT set_scalar(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
1404         const void *indata, D3DXPARAMETER_TYPE intype)
1405 {
1406     struct ctab_constant *c = get_valid_constant(table, constant);
1407     UINT count = 1;
1408 
1409     if (!c)
1410     {
1411         WARN("Invalid argument specified\n");
1412         return D3DERR_INVALIDCALL;
1413     }
1414 
1415     switch (c->desc.Class)
1416     {
1417         case D3DXPC_SCALAR:
1418             set(table, device, c, &indata, intype, &count, c->desc.Columns, D3DXPC_SCALAR, 0, FALSE);
1419             return D3D_OK;
1420 
1421         case D3DXPC_VECTOR:
1422         case D3DXPC_MATRIX_ROWS:
1423         case D3DXPC_MATRIX_COLUMNS:
1424         case D3DXPC_STRUCT:
1425             return D3D_OK;
1426 
1427         default:
1428             FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1429             return D3DERR_INVALIDCALL;
1430     }
1431 }
1432 
1433 static HRESULT set_scalar_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
1434         const void *indata, UINT count, D3DXPARAMETER_TYPE intype)
1435 {
1436     struct ctab_constant *c = get_valid_constant(table, constant);
1437 
1438     if (!c)
1439     {
1440         WARN("Invalid argument specified\n");
1441         return D3DERR_INVALIDCALL;
1442     }
1443 
1444     switch (c->desc.Class)
1445     {
1446         case D3DXPC_SCALAR:
1447         case D3DXPC_VECTOR:
1448         case D3DXPC_MATRIX_ROWS:
1449         case D3DXPC_MATRIX_COLUMNS:
1450         case D3DXPC_STRUCT:
1451             set(table, device, c, &indata, intype, &count, c->desc.Columns, D3DXPC_SCALAR, 0, FALSE);
1452             return D3D_OK;
1453 
1454         default:
1455             FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1456             return D3DERR_INVALIDCALL;
1457     }
1458 }
1459 
1460 static HRESULT set_vector(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
1461         const void *indata, D3DXPARAMETER_TYPE intype)
1462 {
1463     struct ctab_constant *c = get_valid_constant(table, constant);
1464     UINT count = 4;
1465 
1466     if (!c)
1467     {
1468         WARN("Invalid argument specified\n");
1469         return D3DERR_INVALIDCALL;
1470     }
1471 
1472     switch (c->desc.Class)
1473     {
1474         case D3DXPC_SCALAR:
1475         case D3DXPC_VECTOR:
1476         case D3DXPC_STRUCT:
1477             set(table, device, c, &indata, intype, &count, 4, D3DXPC_VECTOR, 0, FALSE);
1478             return D3D_OK;
1479 
1480         case D3DXPC_MATRIX_ROWS:
1481         case D3DXPC_MATRIX_COLUMNS:
1482             return D3D_OK;
1483 
1484         default:
1485             FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1486             return D3DERR_INVALIDCALL;
1487     }
1488 }
1489 
1490 static HRESULT set_vector_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
1491         const void *indata, UINT count, D3DXPARAMETER_TYPE intype)
1492 {
1493     struct ctab_constant *c = get_valid_constant(table, constant);
1494 
1495     if (!c)
1496     {
1497         WARN("Invalid argument specified\n");
1498         return D3DERR_INVALIDCALL;
1499     }
1500 
1501     switch (c->desc.Class)
1502     {
1503         case D3DXPC_SCALAR:
1504         case D3DXPC_VECTOR:
1505         case D3DXPC_MATRIX_ROWS:
1506         case D3DXPC_MATRIX_COLUMNS:
1507         case D3DXPC_STRUCT:
1508             count *= 4;
1509             set(table, device, c, &indata, intype, &count, 4, D3DXPC_VECTOR, 0, FALSE);
1510             return D3D_OK;
1511 
1512         default:
1513             FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1514             return D3DERR_INVALIDCALL;
1515     }
1516 }
1517 
1518 static HRESULT set_matrix_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device, D3DXHANDLE constant,
1519         const void *indata, UINT count, BOOL transpose)
1520 {
1521     struct ctab_constant *c = get_valid_constant(table, constant);
1522 
1523     if (!c)
1524     {
1525         WARN("Invalid argument specified\n");
1526         return D3DERR_INVALIDCALL;
1527     }
1528 
1529     switch (c->desc.Class)
1530     {
1531         case D3DXPC_SCALAR:
1532         case D3DXPC_VECTOR:
1533         case D3DXPC_MATRIX_ROWS:
1534         case D3DXPC_MATRIX_COLUMNS:
1535         case D3DXPC_STRUCT:
1536             count *= 16;
1537             set(table, device, c, &indata, D3DXPT_FLOAT, &count, 4,
1538                     transpose ? D3DXPC_MATRIX_ROWS : D3DXPC_MATRIX_COLUMNS, 0, FALSE);
1539             return D3D_OK;
1540 
1541         default:
1542             FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1543             return D3DERR_INVALIDCALL;
1544     }
1545 }
1546 
1547 static HRESULT set_matrix_pointer_array(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device,
1548         D3DXHANDLE constant, const void **indata, UINT count, BOOL transpose)
1549 {
1550     struct ctab_constant *c = get_valid_constant(table, constant);
1551 
1552     if (!c)
1553     {
1554         WARN("Invalid argument specified\n");
1555         return D3DERR_INVALIDCALL;
1556     }
1557 
1558     switch (c->desc.Class)
1559     {
1560         case D3DXPC_SCALAR:
1561         case D3DXPC_VECTOR:
1562         case D3DXPC_MATRIX_ROWS:
1563         case D3DXPC_MATRIX_COLUMNS:
1564         case D3DXPC_STRUCT:
1565             count *= 16;
1566             set(table, device, c, indata, D3DXPT_FLOAT, &count, 4,
1567                     transpose ? D3DXPC_MATRIX_ROWS : D3DXPC_MATRIX_COLUMNS, 0, TRUE);
1568             return D3D_OK;
1569 
1570         default:
1571             FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(c->desc.Class));
1572             return D3DERR_INVALIDCALL;
1573     }
1574 }
1575 
1576 static HRESULT WINAPI ID3DXConstantTableImpl_SetDefaults(struct ID3DXConstantTable *iface,
1577         struct IDirect3DDevice9 *device)
1578 {
1579     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1580     UINT i;
1581 
1582     TRACE("iface %p, device %p\n", iface, device);
1583 
1584     if (!device)
1585     {
1586         WARN("Invalid argument specified\n");
1587         return D3DERR_INVALIDCALL;
1588     }
1589 
1590     for (i = 0; i < This->desc.Constants; i++)
1591     {
1592         D3DXCONSTANT_DESC *desc = &This->constants[i].desc;
1593         HRESULT hr;
1594 
1595         if (!desc->DefaultValue)
1596             continue;
1597 
1598         switch (desc->RegisterSet)
1599         {
1600             case D3DXRS_BOOL:
1601                 if (is_vertex_shader(This->desc.Version))
1602                     hr = IDirect3DDevice9_SetVertexShaderConstantB(device, desc->RegisterIndex, desc->DefaultValue,
1603                             desc->RegisterCount);
1604                 else
1605                     hr = IDirect3DDevice9_SetPixelShaderConstantB(device, desc->RegisterIndex, desc->DefaultValue,
1606                             desc->RegisterCount);
1607                 break;
1608 
1609             case D3DXRS_INT4:
1610                 if (is_vertex_shader(This->desc.Version))
1611                     hr = IDirect3DDevice9_SetVertexShaderConstantI(device, desc->RegisterIndex, desc->DefaultValue,
1612                             desc->RegisterCount);
1613                 else
1614                     hr = IDirect3DDevice9_SetPixelShaderConstantI(device, desc->RegisterIndex, desc->DefaultValue,
1615                         desc->RegisterCount);
1616                 break;
1617 
1618             case D3DXRS_FLOAT4:
1619                 if (is_vertex_shader(This->desc.Version))
1620                     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, desc->RegisterIndex, desc->DefaultValue,
1621                             desc->RegisterCount);
1622                 else
1623                     hr = IDirect3DDevice9_SetPixelShaderConstantF(device, desc->RegisterIndex, desc->DefaultValue,
1624                         desc->RegisterCount);
1625                 break;
1626 
1627             default:
1628                 FIXME("Unhandled register set %s\n", debug_d3dxparameter_registerset(desc->RegisterSet));
1629                 hr = E_NOTIMPL;
1630                 break;
1631         }
1632 
1633         if (hr != D3D_OK)
1634             return hr;
1635     }
1636 
1637     return D3D_OK;
1638 }
1639 
1640 static HRESULT WINAPI ID3DXConstantTableImpl_SetValue(struct ID3DXConstantTable *iface,
1641         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const void *data, unsigned int bytes)
1642 {
1643     struct ID3DXConstantTableImpl *table = impl_from_ID3DXConstantTable(iface);
1644     struct ctab_constant *c = get_valid_constant(table, constant);
1645     D3DXCONSTANT_DESC *desc;
1646 
1647     TRACE("iface %p, device %p, constant %p, data %p, bytes %u\n", iface, device, constant, data, bytes);
1648 
1649     if (!device || !c || !data)
1650     {
1651         WARN("Invalid argument specified\n");
1652         return D3DERR_INVALIDCALL;
1653     }
1654 
1655     desc = &c->desc;
1656 
1657     switch (desc->Class)
1658     {
1659         case D3DXPC_SCALAR:
1660         case D3DXPC_VECTOR:
1661         case D3DXPC_MATRIX_ROWS:
1662         case D3DXPC_MATRIX_COLUMNS:
1663         case D3DXPC_STRUCT:
1664             bytes /= 4;
1665             set(table, device, c, &data, desc->Type, &bytes, desc->Columns, D3DXPC_SCALAR, 0, FALSE);
1666             return D3D_OK;
1667 
1668         default:
1669             FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(desc->Class));
1670             return D3DERR_INVALIDCALL;
1671     }
1672 }
1673 
1674 static HRESULT WINAPI ID3DXConstantTableImpl_SetBool(struct ID3DXConstantTable *iface,
1675         struct IDirect3DDevice9 *device, D3DXHANDLE constant, BOOL b)
1676 {
1677     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1678 
1679     TRACE("iface %p, device %p, constant %p, b %d\n", iface, device, constant, b);
1680 
1681     return set_scalar(This, device, constant, &b, D3DXPT_BOOL);
1682 }
1683 
1684 static HRESULT WINAPI ID3DXConstantTableImpl_SetBoolArray(struct ID3DXConstantTable *iface,
1685         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const BOOL *b, UINT count)
1686 {
1687     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1688 
1689     TRACE("iface %p, device %p, constant %p, b %p, count %d\n", iface, device, constant, b, count);
1690 
1691     return set_scalar_array(This, device, constant, b, count, D3DXPT_BOOL);
1692 }
1693 
1694 static HRESULT WINAPI ID3DXConstantTableImpl_SetInt(struct ID3DXConstantTable *iface,
1695         struct IDirect3DDevice9 *device, D3DXHANDLE constant, INT n)
1696 {
1697     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1698 
1699     TRACE("iface %p, device %p, constant %p, n %d\n", iface, device, constant, n);
1700 
1701     return set_scalar(This, device, constant, &n, D3DXPT_INT);
1702 }
1703 
1704 static HRESULT WINAPI ID3DXConstantTableImpl_SetIntArray(struct ID3DXConstantTable *iface,
1705         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const INT *n, UINT count)
1706 {
1707     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1708 
1709     TRACE("iface %p, device %p, constant %p, n %p, count %d\n", iface, device, constant, n, count);
1710 
1711     return set_scalar_array(This, device, constant, n, count, D3DXPT_INT);
1712 }
1713 
1714 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloat(struct ID3DXConstantTable *iface,
1715         struct IDirect3DDevice9 *device, D3DXHANDLE constant, float f)
1716 {
1717     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1718 
1719     TRACE("iface %p, device %p, constant %p, f %f\n", iface, device, constant, f);
1720 
1721     return set_scalar(This, device, constant, &f, D3DXPT_FLOAT);
1722 }
1723 
1724 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloatArray(struct ID3DXConstantTable *iface,
1725         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const float *f, UINT count)
1726 {
1727     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1728 
1729     TRACE("iface %p, device %p, constant %p, f %p, count %d\n", iface, device, constant, f, count);
1730 
1731     return set_scalar_array(This, device, constant, f, count, D3DXPT_FLOAT);
1732 }
1733 
1734 static HRESULT WINAPI ID3DXConstantTableImpl_SetVector(struct ID3DXConstantTable *iface,
1735         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXVECTOR4 *vector)
1736 {
1737     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1738 
1739     TRACE("iface %p, device %p, constant %p, vector %p\n", iface, device, constant, vector);
1740 
1741     return set_vector(This, device, constant, vector, D3DXPT_FLOAT);
1742 }
1743 
1744 static HRESULT WINAPI ID3DXConstantTableImpl_SetVectorArray(struct ID3DXConstantTable *iface,
1745         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXVECTOR4 *vector, UINT count)
1746 {
1747     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1748 
1749     TRACE("iface %p, device %p, constant %p, vector %p, count %u\n", iface, device, constant, vector, count);
1750 
1751     return set_vector_array(This, device, constant, vector, count, D3DXPT_FLOAT);
1752 }
1753 
1754 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrix(struct ID3DXConstantTable *iface,
1755         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix)
1756 {
1757     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1758 
1759     TRACE("iface %p, device %p, constant %p, matrix %p\n", iface, device, constant, matrix);
1760 
1761     return set_matrix_array(This, device, constant, matrix, 1, FALSE);
1762 }
1763 
1764 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixArray(struct ID3DXConstantTable *iface,
1765         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix, UINT count)
1766 {
1767     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1768 
1769     TRACE("iface %p, device %p, constant %p, matrix %p, count %u\n", iface, device, constant, matrix, count);
1770 
1771     return set_matrix_array(This, device, constant, matrix, count, FALSE);
1772 }
1773 
1774 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixPointerArray(struct ID3DXConstantTable *iface,
1775         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX **matrix, UINT count)
1776 {
1777     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1778 
1779     TRACE("iface %p, device %p, constant %p, matrix %p, count %u)\n", iface, device, constant, matrix, count);
1780 
1781     return set_matrix_pointer_array(This, device, constant, (const void **)matrix, count, FALSE);
1782 }
1783 
1784 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTranspose(struct ID3DXConstantTable *iface,
1785         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix)
1786 {
1787     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1788 
1789     TRACE("iface %p, device %p, constant %p, matrix %p\n", iface, device, constant, matrix);
1790 
1791     return set_matrix_array(This, device, constant, matrix, 1, TRUE);
1792 }
1793 
1794 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposeArray(struct ID3DXConstantTable *iface,
1795         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX *matrix, UINT count)
1796 {
1797     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1798 
1799     TRACE("iface %p, device %p, constant %p, matrix %p, count %u\n", iface, device, constant, matrix, count);
1800 
1801     return set_matrix_array(This, device, constant, matrix, count, TRUE);
1802 }
1803 
1804 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposePointerArray(struct ID3DXConstantTable *iface,
1805         struct IDirect3DDevice9 *device, D3DXHANDLE constant, const D3DXMATRIX **matrix, UINT count)
1806 {
1807     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1808 
1809     TRACE("iface %p, device %p, constant %p, matrix %p, count %u)\n", iface, device, constant, matrix, count);
1810 
1811     return set_matrix_pointer_array(This, device, constant, (const void **)matrix, count, TRUE);
1812 }
1813 
1814 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl =
1815 {
1816     /*** IUnknown methods ***/
1817     ID3DXConstantTableImpl_QueryInterface,
1818     ID3DXConstantTableImpl_AddRef,
1819     ID3DXConstantTableImpl_Release,
1820     /*** ID3DXBuffer methods ***/
1821     ID3DXConstantTableImpl_GetBufferPointer,
1822     ID3DXConstantTableImpl_GetBufferSize,
1823     /*** ID3DXConstantTable methods ***/
1824     ID3DXConstantTableImpl_GetDesc,
1825     ID3DXConstantTableImpl_GetConstantDesc,
1826     ID3DXConstantTableImpl_GetSamplerIndex,
1827     ID3DXConstantTableImpl_GetConstant,
1828     ID3DXConstantTableImpl_GetConstantByName,
1829     ID3DXConstantTableImpl_GetConstantElement,
1830     ID3DXConstantTableImpl_SetDefaults,
1831     ID3DXConstantTableImpl_SetValue,
1832     ID3DXConstantTableImpl_SetBool,
1833     ID3DXConstantTableImpl_SetBoolArray,
1834     ID3DXConstantTableImpl_SetInt,
1835     ID3DXConstantTableImpl_SetIntArray,
1836     ID3DXConstantTableImpl_SetFloat,
1837     ID3DXConstantTableImpl_SetFloatArray,
1838     ID3DXConstantTableImpl_SetVector,
1839     ID3DXConstantTableImpl_SetVectorArray,
1840     ID3DXConstantTableImpl_SetMatrix,
1841     ID3DXConstantTableImpl_SetMatrixArray,
1842     ID3DXConstantTableImpl_SetMatrixPointerArray,
1843     ID3DXConstantTableImpl_SetMatrixTranspose,
1844     ID3DXConstantTableImpl_SetMatrixTransposeArray,
1845     ID3DXConstantTableImpl_SetMatrixTransposePointerArray
1846 };
1847 
1848 static HRESULT parse_ctab_constant_type(const char *ctab, DWORD typeoffset, struct ctab_constant *constant,
1849         BOOL is_element, WORD index, WORD max_index, DWORD *offset, DWORD nameoffset, UINT regset)
1850 {
1851     const D3DXSHADER_TYPEINFO *type = (LPD3DXSHADER_TYPEINFO)(ctab + typeoffset);
1852     const D3DXSHADER_STRUCTMEMBERINFO *memberinfo = NULL;
1853     HRESULT hr = D3D_OK;
1854     UINT i, count = 0;
1855     WORD size = 0;
1856 
1857     constant->desc.DefaultValue = offset ? ctab + *offset : NULL;
1858     constant->desc.Class = type->Class;
1859     constant->desc.Type = type->Type;
1860     constant->desc.Rows = type->Rows;
1861     constant->desc.Columns = type->Columns;
1862     constant->desc.Elements = is_element ? 1 : type->Elements;
1863     constant->desc.StructMembers = type->StructMembers;
1864     constant->desc.Name = ctab + nameoffset;
1865     constant->desc.RegisterSet = regset;
1866     constant->desc.RegisterIndex = index;
1867 
1868     TRACE("name %s, elements %u, index %u, defaultvalue %p, regset %s\n", constant->desc.Name,
1869             constant->desc.Elements, index, constant->desc.DefaultValue,
1870             debug_d3dxparameter_registerset(regset));
1871     TRACE("class %s, type %s, rows %d, columns %d, elements %d, struct_members %d\n",
1872             debug_d3dxparameter_class(type->Class), debug_d3dxparameter_type(type->Type),
1873             type->Rows, type->Columns, type->Elements, type->StructMembers);
1874 
1875     if (type->Elements > 1 && !is_element)
1876     {
1877         count = type->Elements;
1878     }
1879     else if ((type->Class == D3DXPC_STRUCT) && type->StructMembers)
1880     {
1881         memberinfo = (D3DXSHADER_STRUCTMEMBERINFO*)(ctab + type->StructMemberInfo);
1882         count = type->StructMembers;
1883     }
1884 
1885     if (count)
1886     {
1887         constant->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*constant->constants) * count);
1888         if (!constant->constants)
1889         {
1890              ERR("Out of memory\n");
1891              hr = E_OUTOFMEMORY;
1892              goto error;
1893         }
1894 
1895         for (i = 0; i < count; ++i)
1896         {
1897             hr = parse_ctab_constant_type(ctab, memberinfo ? memberinfo[i].TypeInfo : typeoffset,
1898                     &constant->constants[i], memberinfo == NULL, index + size, max_index, offset,
1899                     memberinfo ? memberinfo[i].Name : nameoffset, regset);
1900             if (hr != D3D_OK)
1901                 goto error;
1902 
1903             size += constant->constants[i].desc.RegisterCount;
1904         }
1905     }
1906     else
1907     {
1908         WORD offsetdiff = type->Columns * type->Rows;
1909         BOOL fail = FALSE;
1910 
1911         size = type->Columns * type->Rows;
1912 
1913         switch (regset)
1914         {
1915             case D3DXRS_BOOL:
1916                 fail = type->Class != D3DXPC_SCALAR && type->Class != D3DXPC_VECTOR
1917                         && type->Class != D3DXPC_MATRIX_ROWS && type->Class != D3DXPC_MATRIX_COLUMNS;
1918                 break;
1919 
1920             case D3DXRS_FLOAT4:
1921             case D3DXRS_INT4:
1922                 switch (type->Class)
1923                 {
1924                     case D3DXPC_VECTOR:
1925                         size = 1;
1926                         /* fall through */
1927                     case D3DXPC_SCALAR:
1928                         offsetdiff = type->Rows * 4;
1929                         break;
1930 
1931                     case D3DXPC_MATRIX_ROWS:
1932                         offsetdiff = type->Rows * 4;
1933                         size = type->Rows;
1934                         break;
1935 
1936                     case D3DXPC_MATRIX_COLUMNS:
1937                         offsetdiff = type->Columns * 4;
1938                         size = type->Columns;
1939                         break;
1940 
1941                     default:
1942                         fail = TRUE;
1943                         break;
1944                 }
1945                 break;
1946 
1947             case D3DXRS_SAMPLER:
1948                 size = 1;
1949                 fail = type->Class != D3DXPC_OBJECT;
1950                 break;
1951 
1952             default:
1953                 fail = TRUE;
1954                 break;
1955         }
1956 
1957         if (fail)
1958         {
1959             FIXME("Unhandled register set %s, type class %s\n", debug_d3dxparameter_registerset(regset),
1960                     debug_d3dxparameter_class(type->Class));
1961         }
1962 
1963         /* offset in bytes => offsetdiff * sizeof(DWORD) */
1964         if (offset) *offset += offsetdiff * 4;
1965     }
1966 
1967     constant->desc.RegisterCount = max(0, min(max_index - index, size));
1968     constant->desc.Bytes = 4 * constant->desc.Elements * type->Rows * type->Columns;
1969 
1970     return D3D_OK;
1971 
1972 error:
1973     if (constant->constants)
1974     {
1975         for (i = 0; i < count; ++i)
1976         {
1977             free_constant(&constant->constants[i]);
1978         }
1979         HeapFree(GetProcessHeap(), 0, constant->constants);
1980         constant->constants = NULL;
1981     }
1982 
1983     return hr;
1984 }
1985 
1986 HRESULT WINAPI D3DXGetShaderConstantTableEx(const DWORD *byte_code, DWORD flags, ID3DXConstantTable **constant_table)
1987 {
1988     struct ID3DXConstantTableImpl *object = NULL;
1989     const void *data;
1990     HRESULT hr;
1991     UINT size;
1992     const D3DXSHADER_CONSTANTTABLE *ctab_header;
1993     const D3DXSHADER_CONSTANTINFO *constant_info;
1994     DWORD i;
1995 
1996     TRACE("byte_code %p, flags %x, constant_table %p\n", byte_code, flags, constant_table);
1997 
1998     if (constant_table) *constant_table = NULL;
1999 
2000     if (!byte_code || !constant_table)
2001     {
2002         WARN("Invalid argument specified.\n");
2003         return D3DERR_INVALIDCALL;
2004     }
2005 
2006     if (!is_valid_bytecode(*byte_code))
2007     {
2008         WARN("Invalid byte_code specified.\n");
2009         return D3D_OK;
2010     }
2011 
2012     if (flags) FIXME("Flags (%#x) are not handled, yet!\n", flags);
2013 
2014     hr = D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), &data, &size);
2015     if (hr != D3D_OK)
2016     {
2017         WARN("CTAB not found.\n");
2018         return D3DXERR_INVALIDDATA;
2019     }
2020 
2021     if (size < sizeof(*ctab_header))
2022     {
2023         WARN("Invalid CTAB size.\n");
2024         return D3DXERR_INVALIDDATA;
2025     }
2026 
2027     ctab_header = (const D3DXSHADER_CONSTANTTABLE *)data;
2028     if (ctab_header->Size != sizeof(*ctab_header))
2029     {
2030         WARN("Invalid D3DXSHADER_CONSTANTTABLE size.\n");
2031         return D3DXERR_INVALIDDATA;
2032     }
2033 
2034     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2035     if (!object)
2036         return E_OUTOFMEMORY;
2037 
2038     object->ID3DXConstantTable_iface.lpVtbl = &ID3DXConstantTable_Vtbl;
2039     object->ref = 1;
2040 
2041     object->ctab = HeapAlloc(GetProcessHeap(), 0, size);
2042     if (!object->ctab)
2043     {
2044         ERR("Out of memory\n");
2045         HeapFree(GetProcessHeap(), 0, object);
2046         return E_OUTOFMEMORY;
2047     }
2048     object->size = size;
2049     memcpy(object->ctab, data, object->size);
2050 
2051     object->desc.Creator = ctab_header->Creator ? object->ctab + ctab_header->Creator : NULL;
2052     object->desc.Version = ctab_header->Version;
2053     object->desc.Constants = ctab_header->Constants;
2054     TRACE("Creator %s, Version %x, Constants %u, Target %s\n",
2055             debugstr_a(object->desc.Creator), object->desc.Version, object->desc.Constants,
2056             debugstr_a(ctab_header->Target ? object->ctab + ctab_header->Target : NULL));
2057 
2058     object->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2059                                   sizeof(*object->constants) * object->desc.Constants);
2060     if (!object->constants)
2061     {
2062          ERR("Out of memory\n");
2063          hr = E_OUTOFMEMORY;
2064          goto error;
2065     }
2066 
2067     constant_info = (const D3DXSHADER_CONSTANTINFO *)(object->ctab + ctab_header->ConstantInfo);
2068     for (i = 0; i < ctab_header->Constants; i++)
2069     {
2070         DWORD offset = constant_info[i].DefaultValue;
2071 
2072         hr = parse_ctab_constant_type(object->ctab, constant_info[i].TypeInfo,
2073                 &object->constants[i], FALSE, constant_info[i].RegisterIndex,
2074                 constant_info[i].RegisterIndex + constant_info[i].RegisterCount,
2075                 offset ? &offset : NULL, constant_info[i].Name, constant_info[i].RegisterSet);
2076         if (hr != D3D_OK)
2077             goto error;
2078 
2079         /*
2080          * Set the register count, it may differ for D3DXRS_INT4, because somehow
2081          * it makes the assumption that the register size is 1 instead of 4, so the
2082          * count is 4 times bigger. This holds true only for toplevel shader
2083          * constants. The count of elements and members is always based on a
2084          * register size of 4.
2085          */
2086         if (object->constants[i].desc.RegisterSet == D3DXRS_INT4)
2087         {
2088             object->constants[i].desc.RegisterCount = constant_info[i].RegisterCount;
2089         }
2090         object->constants[i].constantinfo_reserved = constant_info[i].Reserved;
2091     }
2092 
2093     *constant_table = &object->ID3DXConstantTable_iface;
2094 
2095     return D3D_OK;
2096 
2097 error:
2098     free_constant_table(object);
2099     HeapFree(GetProcessHeap(), 0, object);
2100 
2101     return hr;
2102 }
2103 
2104 HRESULT WINAPI D3DXGetShaderConstantTable(const DWORD *byte_code, ID3DXConstantTable **constant_table)
2105 {
2106     TRACE("(%p, %p): Forwarded to D3DXGetShaderConstantTableEx\n", byte_code, constant_table);
2107 
2108     return D3DXGetShaderConstantTableEx(byte_code, 0, constant_table);
2109 }
2110 
2111 HRESULT WINAPI D3DXCreateFragmentLinker(IDirect3DDevice9 *device, UINT size, ID3DXFragmentLinker **linker)
2112 {
2113     FIXME("device %p, size %u, linker %p: stub.\n", device, size, linker);
2114 
2115     if (linker)
2116         *linker = NULL;
2117 
2118 
2119     return E_NOTIMPL;
2120 }
2121 
2122 HRESULT WINAPI D3DXCreateFragmentLinkerEx(IDirect3DDevice9 *device, UINT size, DWORD flags, ID3DXFragmentLinker **linker)
2123 {
2124     FIXME("device %p, size %u, flags %#x, linker %p: stub.\n", device, size, flags, linker);
2125 
2126     if (linker)
2127         *linker = NULL;
2128 
2129     return E_NOTIMPL;
2130 }
2131 
2132 HRESULT WINAPI D3DXGetShaderSamplers(const DWORD *byte_code, const char **samplers, UINT *count)
2133 {
2134     UINT i, sampler_count = 0;
2135     UINT size;
2136     const char *data;
2137     const D3DXSHADER_CONSTANTTABLE *ctab_header;
2138     const D3DXSHADER_CONSTANTINFO *constant_info;
2139 
2140     TRACE("byte_code %p, samplers %p, count %p\n", byte_code, samplers, count);
2141 
2142     if (count) *count = 0;
2143 
2144     if (D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), (const void **)&data, &size) != D3D_OK)
2145         return D3D_OK;
2146 
2147     if (size < sizeof(*ctab_header)) return D3D_OK;
2148 
2149     ctab_header = (const D3DXSHADER_CONSTANTTABLE *)data;
2150     if (ctab_header->Size != sizeof(*ctab_header)) return D3D_OK;
2151 
2152     constant_info = (const D3DXSHADER_CONSTANTINFO *)(data + ctab_header->ConstantInfo);
2153     for (i = 0; i < ctab_header->Constants; i++)
2154     {
2155         const D3DXSHADER_TYPEINFO *type;
2156 
2157         TRACE("name = %s\n", data + constant_info[i].Name);
2158 
2159         type = (const D3DXSHADER_TYPEINFO *)(data + constant_info[i].TypeInfo);
2160 
2161         if (type->Type == D3DXPT_SAMPLER
2162                 || type->Type == D3DXPT_SAMPLER1D
2163                 || type->Type == D3DXPT_SAMPLER2D
2164                 || type->Type == D3DXPT_SAMPLER3D
2165                 || type->Type == D3DXPT_SAMPLERCUBE)
2166         {
2167             if (samplers) samplers[sampler_count] = data + constant_info[i].Name;
2168 
2169             ++sampler_count;
2170         }
2171     }
2172 
2173     TRACE("Found %u samplers\n", sampler_count);
2174 
2175     if (count) *count = sampler_count;
2176 
2177     return D3D_OK;
2178 }
2179 
2180 
2181 static const char *decl_usage[] = { "position", "blendweight", "blendindices", "normal", "psize", "texcoord",
2182                                     "tangent", "binormal", "tessfactor", "positiont", "color" };
2183 
2184 static const char *tex_type[] = { "", "1d", "2d", "cube", "volume" };
2185 
2186 static int add_modifier(char *buffer, DWORD param)
2187 {
2188     char *buf = buffer;
2189     DWORD dst_mod = param & D3DSP_DSTMOD_MASK;
2190 
2191     if (dst_mod & D3DSPDM_SATURATE)
2192         buf += sprintf(buf, "_sat");
2193     if (dst_mod & D3DSPDM_PARTIALPRECISION)
2194         buf += sprintf(buf, "_pp");
2195     if (dst_mod & D3DSPDM_MSAMPCENTROID)
2196         buf += sprintf(buf, "_centroid");
2197 
2198     return buf - buffer;
2199 }
2200 
2201 static int add_register(char *buffer, DWORD param, BOOL dst, BOOL ps)
2202 {
2203     char *buf = buffer;
2204     DWORD reg_type = ((param & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2)
2205                    | ((param & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT);
2206     DWORD reg_num = param & D3DSP_REGNUM_MASK;
2207 
2208     if (reg_type == D3DSPR_INPUT)
2209         buf += sprintf(buf, "v%d", reg_num);
2210     else if (reg_type == D3DSPR_CONST)
2211         buf += sprintf(buf, "c%d", reg_num);
2212     else if (reg_type == D3DSPR_TEMP)
2213         buf += sprintf(buf, "r%d", reg_num);
2214     else if (reg_type == D3DSPR_ADDR)
2215         buf += sprintf(buf, "%s%d", ps ? "t" : "a", reg_num);
2216     else if (reg_type == D3DSPR_SAMPLER)
2217         buf += sprintf(buf, "s%d", reg_num);
2218     else if (reg_type == D3DSPR_RASTOUT)
2219         buf += sprintf(buf, "oPos");
2220     else if (reg_type == D3DSPR_COLOROUT)
2221         buf += sprintf(buf, "oC%d", reg_num);
2222     else if (reg_type == D3DSPR_TEXCRDOUT)
2223         buf += sprintf(buf, "oT%d", reg_num);
2224     else if (reg_type == D3DSPR_ATTROUT)
2225         buf += sprintf(buf, "oD%d", reg_num);
2226     else
2227         buf += sprintf(buf, "? (%d)", reg_type);
2228 
2229     if (dst)
2230     {
2231         if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL)
2232         {
2233             buf += sprintf(buf, ".%s%s%s%s", param & D3DSP_WRITEMASK_0 ? "x" : "",
2234                                              param & D3DSP_WRITEMASK_1 ? "y" : "",
2235                                              param & D3DSP_WRITEMASK_2 ? "z" : "",
2236                                              param & D3DSP_WRITEMASK_3 ? "w" : "");
2237         }
2238     }
2239     else
2240     {
2241         if ((param & D3DVS_SWIZZLE_MASK) != D3DVS_NOSWIZZLE)
2242         {
2243             if ( ((param & D3DSP_SWIZZLE_MASK) == (D3DVS_X_X | D3DVS_Y_X | D3DVS_Z_X | D3DVS_W_X)) ||
2244                  ((param & D3DSP_SWIZZLE_MASK) == (D3DVS_X_Y | D3DVS_Y_Y | D3DVS_Z_Y | D3DVS_W_Y)) ||
2245                  ((param & D3DSP_SWIZZLE_MASK) == (D3DVS_X_Z | D3DVS_Y_Z | D3DVS_Z_Z | D3DVS_W_Z)) ||
2246                  ((param & D3DSP_SWIZZLE_MASK) == (D3DVS_X_W | D3DVS_Y_W | D3DVS_Z_W | D3DVS_W_W)) )
2247                 buf += sprintf(buf, ".%c", 'w' + (((param >> D3DVS_SWIZZLE_SHIFT) + 1) & 0x3));
2248             else
2249                 buf += sprintf(buf, ".%c%c%c%c", 'w' + (((param >> (D3DVS_SWIZZLE_SHIFT+0)) + 1) & 0x3),
2250                                                  'w' + (((param >> (D3DVS_SWIZZLE_SHIFT+2)) + 1) & 0x3),
2251                                                  'w' + (((param >> (D3DVS_SWIZZLE_SHIFT+4)) + 1) & 0x3),
2252                                                  'w' + (((param >> (D3DVS_SWIZZLE_SHIFT+6)) + 1) & 0x3));
2253         }
2254     }
2255 
2256     return buf - buffer;
2257 }
2258 
2259 struct instr_info
2260 {
2261     DWORD opcode;
2262     const char *name;
2263     int length;
2264     int (*function)(const struct instr_info *info, DWORD **ptr, char *buffer, BOOL ps);
2265     WORD min_version;
2266     WORD max_version;
2267 };
2268 
2269 static int instr_comment(const struct instr_info *info, DWORD **ptr, char *buffer, BOOL ps)
2270 {
2271     *ptr += 1 + ((**ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
2272     return 0;
2273 }
2274 
2275 static int instr_def(const struct instr_info *info, DWORD **ptr, char *buffer, BOOL ps)
2276 {
2277     int len = sprintf(buffer, "    def c%d, %g, %g, %g, %g\n", *(*ptr+1) & D3DSP_REGNUM_MASK,
2278                       (double)*(float*)(*ptr+2), (double)*(float*)(*ptr+3),
2279                       (double)*(float*)(*ptr+4), (double)*(float*)(*ptr+5));
2280     *ptr += 6;
2281     return len;
2282 }
2283 
2284 static int instr_dcl(const struct instr_info *info, DWORD **ptr, char *buffer, BOOL ps)
2285 {
2286     DWORD param1 = *++*ptr;
2287     DWORD param2 = *++*ptr;
2288     DWORD usage = (param1 & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
2289     DWORD usage_index = (param1 & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
2290     char *buf = buffer;
2291 
2292     buf += sprintf(buf, "    dcl");
2293     if (ps)
2294     {
2295         if (param1 & D3DSP_TEXTURETYPE_MASK)
2296             buf += sprintf(buf, "_%s", (usage <= D3DSTT_VOLUME) ?
2297                 tex_type[(param1 & D3DSP_TEXTURETYPE_MASK) >> D3DSP_TEXTURETYPE_SHIFT] : "???");
2298     }
2299     else
2300     {
2301         buf += sprintf(buf, "_%s", (usage <= D3DDECLUSAGE_COLOR) ? decl_usage[usage] : "???");
2302         if (usage_index)
2303             buf += sprintf(buf, "%d", usage_index);
2304     }
2305 
2306     buf += add_modifier(buf, param2);
2307     buf += sprintf(buf, " ");
2308     buf += add_register(buf, param2, TRUE, TRUE);
2309     buf += sprintf(buf, "\n");
2310     (*ptr)++;
2311     return buf - buffer;
2312 }
2313 
2314 static int instr_generic(const struct instr_info *info, DWORD **ptr, char *buffer, BOOL ps)
2315 {
2316     char *buf = buffer;
2317     int j;
2318 
2319     buf += sprintf(buf, "    %s", info->name);
2320     (*ptr)++;
2321 
2322     if (info->length)
2323     {
2324         buf += add_modifier(buf, **ptr);
2325 
2326         for (j = 0; j < info->length; j++)
2327         {
2328             buf += sprintf(buf, "%s ", j ? "," : "");
2329 
2330             if ((j != 0) && ((**ptr & D3DSP_SRCMOD_MASK) != D3DSPSM_NONE))
2331             {
2332                 if ((**ptr & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG)
2333                     buf += sprintf(buf, "-");
2334                 else
2335                     buf += sprintf(buf, "*");
2336             }
2337 
2338             buf += add_register(buf, **ptr, j == 0, ps);
2339 
2340             if (*(*ptr)++ & D3DVS_ADDRESSMODE_MASK)
2341             {
2342                 buf += sprintf(buf, "[");
2343                 buf += add_register(buf, **ptr, FALSE, FALSE);
2344                 buf += sprintf(buf, "]");
2345                 (*ptr)++;
2346             }
2347         }
2348     }
2349     buf += sprintf(buf, "\n");
2350     return buf - buffer;
2351 }
2352 
2353 const struct instr_info instructions[] =
2354 {
2355     { D3DSIO_NOP,          "nop",           0, instr_generic, 0x0100, 0xFFFF },
2356     { D3DSIO_MOV,          "mov",           2, instr_generic, 0x0100, 0xFFFF },
2357     { D3DSIO_ADD,          "add",           3, instr_generic, 0x0100, 0xFFFF },
2358     { D3DSIO_SUB,          "sub",           3, instr_generic, 0x0100, 0xFFFF },
2359     { D3DSIO_MAD,          "mad",           4, instr_generic, 0x0100, 0xFFFF },
2360     { D3DSIO_MUL,          "mul",           3, instr_generic, 0x0100, 0xFFFF },
2361     { D3DSIO_RCP,          "rcp",           2, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2362     { D3DSIO_RSQ,          "rsq",           2, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2363     { D3DSIO_DP3,          "dp3",           3, instr_generic, 0x0100, 0xFFFF },
2364     { D3DSIO_DP4,          "dp4",           3, instr_generic, 0x0100, 0xFFFF }, /* >= 1.2 for PS */
2365     { D3DSIO_MIN,          "min",           3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2366     { D3DSIO_MAX,          "max",           3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2367     { D3DSIO_SLT,          "slt",           3, instr_generic, 0x0100, 0xFFFF },
2368     { D3DSIO_SGE,          "sge",           3, instr_generic, 0x0100, 0xFFFF }, /* VS only */
2369     { D3DSIO_EXP,          "exp",           2, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2370     { D3DSIO_LOG,          "log",           2, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2371     { D3DSIO_LIT,          "lit",           2, instr_generic, 0x0100, 0xFFFF }, /* VS only */
2372     { D3DSIO_DST,          "dst",           3, instr_generic, 0x0100, 0xFFFF }, /* VS only */
2373     { D3DSIO_LRP,          "lrp",           4, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for VS */
2374     { D3DSIO_FRC,          "frc",           2, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2375     { D3DSIO_M4x4,         "m4x4",          3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2376     { D3DSIO_M4x3,         "m4x3",          3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2377     { D3DSIO_M3x4,         "m3x4",          3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2378     { D3DSIO_M3x3,         "m3x3",          3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2379     { D3DSIO_M3x2,         "m3x2",          3, instr_generic, 0x0100, 0xFFFF }, /* >= 2.0 for PS */
2380     { D3DSIO_CALL,         "call",          1, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
2381     { D3DSIO_CALLNZ,       "callnz",        2, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
2382     { D3DSIO_LOOP,         "loop",          2, instr_generic, 0x0200, 0xFFFF }, /* >= 3.0 for PS */
2383     { D3DSIO_RET,          "ret",           0, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
2384     { D3DSIO_ENDLOOP,      "endloop",       1, instr_generic, 0x0200, 0xFFFF }, /* >= 3.0 for PS */
2385     { D3DSIO_LABEL,        "label",         1, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
2386     { D3DSIO_DCL,          "dcl",           1, instr_dcl,     0x0100, 0xFFFF },
2387     { D3DSIO_POW,          "pow",           3, instr_generic, 0x0200, 0xFFFF },
2388     { D3DSIO_CRS,          "crs",           3, instr_generic, 0x0200, 0xFFFF },
2389     { D3DSIO_SGN,          "sgn",           4, instr_generic, 0x0200, 0xFFFF }, /* VS only */
2390     { D3DSIO_ABS,          "abs",           2, instr_generic, 0x0200, 0xFFFF },
2391     { D3DSIO_NRM,          "nrm",           2, instr_generic, 0x0200, 0xFFFF },
2392     { D3DSIO_SINCOS,       "sincos",        4, instr_generic, 0x0200, 0x02FF },
2393     { D3DSIO_SINCOS,       "sincos",        2, instr_generic, 0x0300, 0xFFFF },
2394     { D3DSIO_REP,          "rep",           1, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
2395     { D3DSIO_ENDREP,       "endrep",        0, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
2396     { D3DSIO_IF,           "if",            1, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
2397     { D3DSIO_IFC,          "if_comp",       2, instr_generic, 0x0200, 0xFFFF },
2398     { D3DSIO_ELSE,         "else",          0, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
2399     { D3DSIO_ENDIF,        "endif",         0, instr_generic, 0x0200, 0xFFFF }, /* >= 2.a for PS */
2400     { D3DSIO_BREAK,        "break",         0, instr_generic, 0x0201, 0xFFFF },
2401     { D3DSIO_BREAKC,       "break_comp",    2, instr_generic, 0x0201, 0xFFFF },
2402     { D3DSIO_MOVA,         "mova",          2, instr_generic, 0x0200, 0xFFFF }, /* VS only */
2403     { D3DSIO_DEFB,         "defb",          2, instr_generic, 0x0100, 0xFFFF },
2404     { D3DSIO_DEFI,         "defi",          2, instr_generic, 0x0100, 0xFFFF },
2405     { D3DSIO_TEXCOORD,     "texcoord",      1, instr_generic, 0x0100, 0x0103 }, /* PS only */
2406     { D3DSIO_TEXCOORD,     "texcrd",        2, instr_generic, 0x0104, 0x0104 }, /* PS only */
2407     { D3DSIO_TEXKILL,      "texkill",       1, instr_generic, 0x0100, 0xFFFF }, /* PS only */
2408     { D3DSIO_TEX,          "tex",           1, instr_generic, 0x0100, 0x0103 }, /* PS only */
2409     { D3DSIO_TEX,          "texld",         2, instr_generic, 0x0104, 0x0104 }, /* PS only */
2410     { D3DSIO_TEX,          "texld",         3, instr_generic, 0x0200, 0xFFFF }, /* PS only */
2411     { D3DSIO_TEXBEM,       "texbem",        2, instr_generic, 0x0100, 0x0103 }, /* PS only */
2412     { D3DSIO_TEXBEML,      "texbeml",       2, instr_generic, 0x0100, 0x0103 }, /* PS only */
2413     { D3DSIO_TEXREG2AR,    "texreg2ar",     2, instr_generic, 0x0100, 0x0103 }, /* PS only */
2414     { D3DSIO_TEXREG2GB,    "texreg2gb",     2, instr_generic, 0x0102, 0x0103 }, /* PS only */
2415     { D3DSIO_TEXM3x2PAD,   "texm3x2pad",    2, instr_generic, 0x0100, 0x0103 }, /* PS only */
2416     { D3DSIO_TEXM3x2TEX,   "texm3x2tex",    2, instr_generic, 0x0100, 0x0103 }, /* PS only */
2417     { D3DSIO_TEXM3x3PAD,   "texm3x3pad",    2, instr_generic, 0x0100, 0x0103 }, /* PS only */
2418     { D3DSIO_TEXM3x3TEX,   "texm3x3tex",    2, instr_generic, 0x0100, 0x0103 }, /* PS only */
2419     { D3DSIO_TEXM3x3DIFF,  "texm3x3diff",   2, instr_generic, 0x0100, 0xFFFF }, /* PS only - Not documented */
2420     { D3DSIO_TEXM3x3SPEC,  "texm3x3spec",   3, instr_generic, 0x0100, 0x0103 }, /* PS only */
2421     { D3DSIO_TEXM3x3VSPEC, "texm3x3vspec",  2, instr_generic, 0x0100, 0x0103 }, /* PS only */
2422     { D3DSIO_EXPP,         "expp",          2, instr_generic, 0x0100, 0xFFFF }, /* VS only */
2423     { D3DSIO_LOGP,         "logp",          2, instr_generic, 0x0100, 0xFFFF }, /* VS only */
2424     { D3DSIO_CND,          "cnd",           4, instr_generic, 0x0100, 0x0104 }, /* PS only */
2425     { D3DSIO_DEF,          "def",           5, instr_def,     0x0100, 0xFFFF },
2426     { D3DSIO_TEXREG2RGB,   "texreg2rgb",    2, instr_generic, 0x0102, 0x0103 }, /* PS only */
2427     { D3DSIO_TEXDP3TEX,    "texdp3tex",     2, instr_generic, 0x0102, 0x0103 }, /* PS only */
2428     { D3DSIO_TEXM3x2DEPTH, "texm3x2depth",  2, instr_generic, 0x0103, 0x0103 }, /* PS only */
2429     { D3DSIO_TEXDP3,       "texdp3",        2, instr_generic, 0x0102, 0x0103 }, /* PS only */
2430     { D3DSIO_TEXM3x3,      "texm3x3",       2, instr_generic, 0x0102, 0x0103 }, /* PS only */
2431     { D3DSIO_TEXDEPTH,     "texdepth",      1, instr_generic, 0x0104, 0x0104 }, /* PS only */
2432     { D3DSIO_CMP,          "cmp",           4, instr_generic, 0x0102, 0xFFFF }, /* PS only */
2433     { D3DSIO_BEM,          "bem",           3, instr_generic, 0x0104, 0x0104 }, /* PS only */
2434     { D3DSIO_DP2ADD,       "dp2add",        4, instr_generic, 0x0200, 0xFFFF }, /* PS only */
2435     { D3DSIO_DSX,          "dsx",           2, instr_generic, 0x0201, 0xFFFF }, /* PS only */
2436     { D3DSIO_DSY,          "dsy",           2, instr_generic, 0x0201, 0xFFFF }, /* PS only */
2437     { D3DSIO_TEXLDD,       "texldd",        5, instr_generic, 0x0201, 0xFFFF }, /* PS only - not existing for 2.b */
2438     { D3DSIO_SETP,         "setp_comp",     3, instr_generic, 0x0201, 0xFFFF },
2439     { D3DSIO_TEXLDL,       "texldl",        3, instr_generic, 0x0300, 0xFFFF },
2440     { D3DSIO_BREAKP,       "breakp",        1, instr_generic, 0x0201, 0xFFFF },
2441     { D3DSIO_PHASE,        "phase",         0, instr_generic, 0x0104, 0x0104 },  /* PS only */
2442     { D3DSIO_COMMENT,      "",              0, instr_comment, 0x0100, 0xFFFF }
2443 };
2444 
2445 HRESULT WINAPI D3DXDisassembleShader(const DWORD *shader, BOOL colorcode, const char *comments, ID3DXBuffer **disassembly)
2446 {
2447     DWORD *ptr = (DWORD *)shader;
2448     char *buffer, *buf;
2449     UINT capacity = 4096;
2450     BOOL ps;
2451     WORD version;
2452     HRESULT hr;
2453 
2454     TRACE("%p %d %s %p\n", shader, colorcode, debugstr_a(comments), disassembly);
2455 
2456     if (!shader || !disassembly)
2457         return D3DERR_INVALIDCALL;
2458 
2459     buf = buffer = HeapAlloc(GetProcessHeap(), 0, capacity);
2460     if (!buffer)
2461         return E_OUTOFMEMORY;
2462 
2463     ps = (*ptr >> 16) & 1;
2464     version = *ptr & 0xFFFF;
2465     buf += sprintf(buf, "    %s_%d_%d\n", ps ? "ps" : "vs", D3DSHADER_VERSION_MAJOR(*ptr), D3DSHADER_VERSION_MINOR(*ptr));
2466     ptr++;
2467 
2468     while (*ptr != D3DSIO_END)
2469     {
2470         DWORD index;
2471 
2472         if ((buf - buffer + 128) > capacity)
2473         {
2474             UINT count = buf - buffer;
2475             char *new_buffer = HeapReAlloc(GetProcessHeap(), 0, buffer, capacity * 2);
2476             if (!new_buffer)
2477             {
2478                 HeapFree(GetProcessHeap(), 0, buffer);
2479                 return E_OUTOFMEMORY;
2480             }
2481             capacity *= 2;
2482             buffer = new_buffer;
2483             buf = buffer + count;
2484         }
2485 
2486         for (index = 0; index < sizeof(instructions)/sizeof(instructions[0]); index++)
2487             if (((*ptr & D3DSI_OPCODE_MASK) == instructions[index].opcode) &&
2488                 (version >= instructions[index].min_version) && (version <= instructions[index].max_version))
2489                 break;
2490 
2491         if (index != sizeof(instructions)/sizeof(instructions[0]))
2492         {
2493             buf += instructions[index].function(&(instructions[index]), &ptr, buf, ps);
2494         }
2495         else
2496         {
2497             buf += sprintf(buf, "    ??? (Unknown opcode %x)\n", *ptr);
2498             while (*++ptr & (1u << 31));
2499         }
2500     }
2501 
2502     hr = D3DXCreateBuffer(buf - buffer + 1 , disassembly);
2503     if (SUCCEEDED(hr))
2504         strcpy(ID3DXBuffer_GetBufferPointer(*disassembly), buffer);
2505     HeapFree(GetProcessHeap(), 0, buffer);
2506 
2507     return hr;
2508 }
2509 
2510 struct d3dx9_texture_shader
2511 {
2512     ID3DXTextureShader ID3DXTextureShader_iface;
2513     LONG ref;
2514 };
2515 
2516 static inline struct d3dx9_texture_shader *impl_from_ID3DXTextureShader(ID3DXTextureShader *iface)
2517 {
2518     return CONTAINING_RECORD(iface, struct d3dx9_texture_shader, ID3DXTextureShader_iface);
2519 }
2520 
2521 static HRESULT WINAPI d3dx9_texture_shader_QueryInterface(ID3DXTextureShader *iface, REFIID riid, void **out)
2522 {
2523     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
2524 
2525     if (IsEqualGUID(riid, &IID_IUnknown) ||
2526         IsEqualGUID(riid, &IID_ID3DXTextureShader))
2527     {
2528         iface->lpVtbl->AddRef(iface);
2529         *out = iface;
2530         return D3D_OK;
2531     }
2532 
2533     WARN("Interface %s not found.\n", debugstr_guid(riid));
2534     *out = NULL;
2535     return E_NOINTERFACE;
2536 }
2537 
2538 static ULONG WINAPI d3dx9_texture_shader_AddRef(ID3DXTextureShader *iface)
2539 {
2540     struct d3dx9_texture_shader *texture_shader = impl_from_ID3DXTextureShader(iface);
2541     ULONG refcount = InterlockedIncrement(&texture_shader->ref);
2542 
2543     TRACE("%p increasing refcount to %u.\n", texture_shader, refcount);
2544 
2545     return refcount;
2546 }
2547 
2548 static ULONG WINAPI d3dx9_texture_shader_Release(ID3DXTextureShader *iface)
2549 {
2550     struct d3dx9_texture_shader *texture_shader = impl_from_ID3DXTextureShader(iface);
2551     ULONG refcount = InterlockedDecrement(&texture_shader->ref);
2552 
2553     TRACE("%p decreasing refcount to %u.\n", texture_shader, refcount);
2554 
2555     if (!refcount)
2556     {
2557         HeapFree(GetProcessHeap(), 0, texture_shader);
2558     }
2559 
2560     return refcount;
2561 }
2562 
2563 static HRESULT WINAPI d3dx9_texture_shader_GetFunction(ID3DXTextureShader *iface, struct ID3DXBuffer **function)
2564 {
2565     FIXME("iface %p, function %p stub.\n", iface, function);
2566 
2567     return E_NOTIMPL;
2568 }
2569 
2570 static HRESULT WINAPI d3dx9_texture_shader_GetConstantBuffer(ID3DXTextureShader *iface, struct ID3DXBuffer **constant_buffer)
2571 {
2572     FIXME("iface %p, constant_buffer %p stub.\n", iface, constant_buffer);
2573 
2574     return E_NOTIMPL;
2575 }
2576 
2577 static HRESULT WINAPI d3dx9_texture_shader_GetDesc(ID3DXTextureShader *iface, D3DXCONSTANTTABLE_DESC *desc)
2578 {
2579     FIXME("iface %p, desc %p stub.\n", iface, desc);
2580 
2581     return E_NOTIMPL;
2582 }
2583 
2584 static HRESULT WINAPI d3dx9_texture_shader_GetConstantDesc(ID3DXTextureShader *iface, D3DXHANDLE constant, D3DXCONSTANT_DESC *constant_desc, UINT *count)
2585 {
2586     FIXME("iface %p, constant %p, constant_desc %p, count %p stub.\n", iface, constant, constant_desc, count);
2587 
2588     return E_NOTIMPL;
2589 }
2590 
2591 static D3DXHANDLE WINAPI d3dx9_texture_shader_GetConstant(ID3DXTextureShader *iface, D3DXHANDLE constant, UINT index)
2592 {
2593     FIXME("iface %p, constant %p, index %u stub.\n", iface, constant, index);
2594 
2595     return NULL;
2596 }
2597 
2598 static D3DXHANDLE WINAPI d3dx9_texture_shader_GetConstantByName(ID3DXTextureShader *iface, D3DXHANDLE constant, const char *name)
2599 {
2600     FIXME("iface %p, constant %p, name %s stub.\n", iface, constant, debugstr_a(name));
2601 
2602     return NULL;
2603 }
2604 
2605 static D3DXHANDLE WINAPI d3dx9_texture_shader_GetConstantElement(ID3DXTextureShader *iface, D3DXHANDLE constant, UINT index)
2606 {
2607     FIXME("iface %p, constant %p, index %u stub.\n", iface, constant, index);
2608 
2609     return NULL;
2610 }
2611 
2612 static HRESULT WINAPI d3dx9_texture_shader_SetDefaults(ID3DXTextureShader *iface)
2613 {
2614     FIXME("iface %p stub.\n", iface);
2615 
2616     return E_NOTIMPL;
2617 }
2618 
2619 static HRESULT WINAPI d3dx9_texture_shader_SetValue(ID3DXTextureShader *iface, D3DXHANDLE constant, const void *data, UINT bytes)
2620 {
2621     FIXME("iface %p, constant %p, data %p, bytes %u stub.\n", iface, constant, data, bytes);
2622 
2623     return E_NOTIMPL;
2624 }
2625 
2626 static HRESULT WINAPI d3dx9_texture_shader_SetBool(ID3DXTextureShader *iface, D3DXHANDLE constant, BOOL b)
2627 {
2628     FIXME("iface %p, constant %p, b %u stub.\n", iface, constant, b);
2629 
2630     return E_NOTIMPL;
2631 }
2632 
2633 static HRESULT WINAPI d3dx9_texture_shader_SetBoolArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const BOOL *b, UINT count)
2634 {
2635     FIXME("iface %p, constant %p, b %p, count %u stub.\n", iface, constant, b, count);
2636 
2637     return E_NOTIMPL;
2638 }
2639 
2640 static HRESULT WINAPI d3dx9_texture_shader_SetInt(ID3DXTextureShader *iface, D3DXHANDLE constant, INT n)
2641 {
2642     FIXME("iface %p, constant %p, n %d stub.\n", iface, constant, n);
2643 
2644     return E_NOTIMPL;
2645 }
2646 
2647 static HRESULT WINAPI d3dx9_texture_shader_SetIntArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const INT *n, UINT count)
2648 {
2649     FIXME("iface %p, constant %p, n %p, count %u stub.\n", iface, constant, n, count);
2650 
2651     return E_NOTIMPL;
2652 }
2653 
2654 static HRESULT WINAPI d3dx9_texture_shader_SetFloat(ID3DXTextureShader *iface, D3DXHANDLE constant, FLOAT f)
2655 {
2656     FIXME("iface %p, constant %p, f %f stub.\n", iface, constant, f);
2657 
2658     return E_NOTIMPL;
2659 }
2660 
2661 static HRESULT WINAPI d3dx9_texture_shader_SetFloatArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const FLOAT *f, UINT count)
2662 {
2663     FIXME("iface %p, constant %p, f %p, count %u stub.\n", iface, constant, f, count);
2664 
2665     return E_NOTIMPL;
2666 }
2667 
2668 static HRESULT WINAPI d3dx9_texture_shader_SetVector(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXVECTOR4 *vector)
2669 {
2670     FIXME("iface %p, constant %p, vector %p stub.\n", iface, constant, vector);
2671 
2672     return E_NOTIMPL;
2673 }
2674 
2675 static HRESULT WINAPI d3dx9_texture_shader_SetVectorArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXVECTOR4 *vector, UINT count)
2676 {
2677     FIXME("iface %p, constant %p, vector %p, count %u stub.\n", iface, constant, vector, count);
2678 
2679     return E_NOTIMPL;
2680 }
2681 
2682 static HRESULT WINAPI d3dx9_texture_shader_SetMatrix(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX *matrix)
2683 {
2684     FIXME("iface %p, constant %p, matrix %p stub.\n", iface, constant, matrix);
2685 
2686     return E_NOTIMPL;
2687 }
2688 
2689 static HRESULT WINAPI d3dx9_texture_shader_SetMatrixArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX *matrix, UINT count)
2690 {
2691     FIXME("iface %p, constant %p, matrix %p, count %u stub.\n", iface, constant, matrix, count);
2692 
2693     return E_NOTIMPL;
2694 }
2695 
2696 static HRESULT WINAPI d3dx9_texture_shader_SetMatrixPointerArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX **matrix, UINT count)
2697 {
2698     FIXME("iface %p, constant %p, matrix %p, count %u stub.\n", iface, constant, matrix, count);
2699 
2700     return E_NOTIMPL;
2701 }
2702 
2703 static HRESULT WINAPI d3dx9_texture_shader_SetMatrixTranspose(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX *matrix)
2704 {
2705     FIXME("iface %p, constant %p, matrix %p stub.\n", iface, constant, matrix);
2706 
2707     return E_NOTIMPL;
2708 }
2709 
2710 static HRESULT WINAPI d3dx9_texture_shader_SetMatrixTransposeArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX *matrix, UINT count)
2711 {
2712     FIXME("iface %p, constant %p, matrix %p, count %u stub.\n", iface, constant, matrix, count);
2713 
2714     return E_NOTIMPL;
2715 }
2716 
2717 static HRESULT WINAPI d3dx9_texture_shader_SetMatrixTransposePointerArray(ID3DXTextureShader *iface, D3DXHANDLE constant, const D3DXMATRIX **matrix, UINT count)
2718 {
2719     FIXME("iface %p, constant %p, matrix %p, count %u stub.\n", iface, constant, matrix, count);
2720 
2721     return E_NOTIMPL;
2722 }
2723 
2724 static const struct ID3DXTextureShaderVtbl d3dx9_texture_shader_vtbl =
2725 {
2726     /*** IUnknown methods ***/
2727     d3dx9_texture_shader_QueryInterface,
2728     d3dx9_texture_shader_AddRef,
2729     d3dx9_texture_shader_Release,
2730     /*** ID3DXTextureShader methods ***/
2731     d3dx9_texture_shader_GetFunction,
2732     d3dx9_texture_shader_GetConstantBuffer,
2733     d3dx9_texture_shader_GetDesc,
2734     d3dx9_texture_shader_GetConstantDesc,
2735     d3dx9_texture_shader_GetConstant,
2736     d3dx9_texture_shader_GetConstantByName,
2737     d3dx9_texture_shader_GetConstantElement,
2738     d3dx9_texture_shader_SetDefaults,
2739     d3dx9_texture_shader_SetValue,
2740     d3dx9_texture_shader_SetBool,
2741     d3dx9_texture_shader_SetBoolArray,
2742     d3dx9_texture_shader_SetInt,
2743     d3dx9_texture_shader_SetIntArray,
2744     d3dx9_texture_shader_SetFloat,
2745     d3dx9_texture_shader_SetFloatArray,
2746     d3dx9_texture_shader_SetVector,
2747     d3dx9_texture_shader_SetVectorArray,
2748     d3dx9_texture_shader_SetMatrix,
2749     d3dx9_texture_shader_SetMatrixArray,
2750     d3dx9_texture_shader_SetMatrixPointerArray,
2751     d3dx9_texture_shader_SetMatrixTranspose,
2752     d3dx9_texture_shader_SetMatrixTransposeArray,
2753     d3dx9_texture_shader_SetMatrixTransposePointerArray
2754 };
2755 
2756 HRESULT WINAPI D3DXCreateTextureShader(const DWORD *function, ID3DXTextureShader **texture_shader)
2757 {
2758     struct d3dx9_texture_shader *object;
2759 
2760     TRACE("function %p, texture_shader %p.\n", function, texture_shader);
2761 
2762     if (!function || !texture_shader)
2763         return D3DERR_INVALIDCALL;
2764 
2765     object = HeapAlloc(GetProcessHeap(), 0, sizeof(*object));
2766     if (!object)
2767         return E_OUTOFMEMORY;
2768 
2769     object->ID3DXTextureShader_iface.lpVtbl = &d3dx9_texture_shader_vtbl;
2770     object->ref = 1;
2771 
2772     *texture_shader = &object->ID3DXTextureShader_iface;
2773 
2774     return D3D_OK;
2775 }
2776 
2777 static unsigned int get_instr_length(const DWORD *byte_code, unsigned int major, unsigned int minor)
2778 {
2779     DWORD opcode = *byte_code & 0xffff;
2780     unsigned int len = 0;
2781 
2782     if (opcode == D3DSIO_COMMENT)
2783         return (*byte_code & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
2784 
2785     if (major > 1)
2786         return (*byte_code & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT;
2787 
2788     switch (opcode)
2789     {
2790         case D3DSIO_END:
2791             ERR("Unexpected END token.\n");
2792             return 0;
2793         case D3DSIO_DEF:
2794         case D3DSIO_DEFI:
2795             return 5;
2796         case D3DSIO_DEFB:
2797             return 2;
2798         default:
2799             ++byte_code;
2800             while (*byte_code & 0x80000000)
2801             {
2802                 ++byte_code;
2803                 ++len;
2804             }
2805     }
2806 
2807     return len;
2808 }
2809 
2810 static HRESULT get_shader_semantics(const DWORD *byte_code, D3DXSEMANTIC *semantics, UINT *count, BOOL output)
2811 {
2812     static const D3DDECLUSAGE regtype_usage[] =
2813     {
2814         D3DDECLUSAGE_COLOR,
2815         D3DDECLUSAGE_COLOR,
2816         0,
2817         D3DDECLUSAGE_TEXCOORD,
2818         0,
2819         D3DDECLUSAGE_COLOR,
2820         D3DDECLUSAGE_TEXCOORD,
2821         0,
2822         0,
2823         D3DDECLUSAGE_DEPTH
2824     };
2825     static const D3DDECLUSAGE rast_usage[] =
2826     {
2827         D3DDECLUSAGE_POSITION,
2828         D3DDECLUSAGE_FOG,
2829         D3DDECLUSAGE_PSIZE
2830     };
2831     DWORD reg_type, usage, index, version_token = *byte_code;
2832     BOOL is_ps = version_token >> 16 == 0xffff;
2833     unsigned int major, minor, i = 0, j;
2834     BYTE colors = 0, rastout = 0;
2835     BOOL has_dcl, depth = 0;
2836     WORD texcoords = 0;
2837 
2838     if ((version_token & 0xffff0000) != 0xfffe0000 && (version_token & 0xffff0000) != 0xffff0000)
2839         return D3DXERR_INVALIDDATA;
2840 
2841     major = version_token >> 8 & 0xff;
2842     minor = version_token & 0xff;
2843 
2844     TRACE("%s shader, version %u.%u.\n", is_ps ? "Pixel" : "Vertex", major, minor);
2845     ++byte_code;
2846 
2847     has_dcl = (!is_ps && (!output || major == 3)) || (is_ps && !output && major >= 2);
2848 
2849     while (*byte_code != D3DSIO_END)
2850     {
2851         if (has_dcl && (*byte_code & 0xffff) == D3DSIO_DCL)
2852         {
2853             DWORD usage_token = byte_code[1];
2854             DWORD reg = byte_code[2];
2855 
2856             reg_type = ((reg & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT)
2857                     | ((reg & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2);
2858 
2859             if (is_ps && !output && major == 2)
2860             {
2861                 /* dcl with no explicit usage, look at the register. */
2862                 reg_type = ((reg & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT)
2863                         | ((reg & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2);
2864                 index = reg & D3DSP_REGNUM_MASK;
2865                 if (reg_type >= ARRAY_SIZE(regtype_usage))
2866                 {
2867                     WARN("Invalid register type %u.\n", reg_type);
2868                     reg_type = 0;
2869                 }
2870                 usage = regtype_usage[reg_type];
2871                 if (semantics)
2872                 {
2873                     semantics[i].Usage = usage;
2874                     semantics[i].UsageIndex = index;
2875                 }
2876                 ++i;
2877             }
2878             else if ((!output && reg_type == D3DSPR_INPUT) || (output && reg_type == D3DSPR_OUTPUT))
2879             {
2880                 if (semantics)
2881                 {
2882                     semantics[i].Usage =
2883                             (usage_token & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
2884                     semantics[i].UsageIndex =
2885                             (usage_token & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
2886                 }
2887                 ++i;
2888             }
2889             byte_code += 3;
2890         }
2891         else if (!has_dcl)
2892         {
2893             unsigned int len = get_instr_length(byte_code, major, minor) + 1;
2894 
2895             switch (*byte_code & 0xffff)
2896             {
2897                 case D3DSIO_COMMENT:
2898                 case D3DSIO_DEF:
2899                 case D3DSIO_DEFB:
2900                 case D3DSIO_DEFI:
2901                     byte_code += len;
2902                     break;
2903                 default:
2904                     ++byte_code;
2905                     while (*byte_code & 0x80000000)
2906                     {
2907                         reg_type = ((*byte_code & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT)
2908                                 | ((*byte_code & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2);
2909                         index = *byte_code & D3DSP_REGNUM_MASK;
2910 
2911                         if ((reg_type == D3DSPR_TEMP && is_ps && major == 1)
2912                                 || (reg_type == D3DSPR_INPUT && is_ps)
2913                                 || (reg_type == D3DSPR_TEXTURE && is_ps && !output)
2914                                 || reg_type == D3DSPR_RASTOUT
2915                                 || reg_type == D3DSPR_ATTROUT
2916                                 || reg_type == D3DSPR_OUTPUT
2917                                 || reg_type == D3DSPR_DEPTHOUT)
2918                         {
2919                             if (reg_type == D3DSPR_RASTOUT)
2920                                 rastout |= 1u << index;
2921                             else if (reg_type == D3DSPR_DEPTHOUT)
2922                                 depth = TRUE;
2923                             else if (reg_type == D3DSPR_TEXTURE || reg_type == D3DSPR_OUTPUT)
2924                                 texcoords |= 1u << index;
2925                             else
2926                                 colors |= 1u << index;
2927                         }
2928                         ++byte_code;
2929                     }
2930             }
2931         }
2932         else
2933         {
2934             byte_code += get_instr_length(byte_code, major, minor) + 1;
2935         }
2936     }
2937 
2938     if (!has_dcl)
2939     {
2940         i = j = 0;
2941         while (texcoords)
2942         {
2943             if (texcoords & 1)
2944             {
2945                 if (semantics)
2946                 {
2947                     semantics[i].Usage = D3DDECLUSAGE_TEXCOORD;
2948                     semantics[i].UsageIndex = j;
2949                 }
2950                 ++i;
2951             }
2952             texcoords >>= 1;
2953             ++j;
2954         }
2955         j = 0;
2956         while (colors)
2957         {
2958             if (colors & 1)
2959             {
2960                 if (semantics)
2961                 {
2962                     semantics[i].Usage = D3DDECLUSAGE_COLOR;
2963                     semantics[i].UsageIndex = j;
2964                 }
2965                 ++i;
2966             }
2967             colors >>= 1;
2968             ++j;
2969         }
2970         j = 0;
2971         while (rastout)
2972         {
2973             if (rastout & 1)
2974             {
2975                 if (j >= ARRAY_SIZE(rast_usage))
2976                 {
2977                     WARN("Invalid RASTOUT register index.\n");
2978                     usage = 0;
2979                 }
2980                 else
2981                 {
2982                     usage = rast_usage[j];
2983                 }
2984                 if (semantics)
2985                 {
2986                     semantics[i].Usage = usage;
2987                     semantics[i].UsageIndex = 0;
2988                 }
2989                 ++i;
2990             }
2991             rastout >>= 1;
2992             ++j;
2993         }
2994         if (depth)
2995         {
2996             if (semantics)
2997             {
2998                 semantics[i].Usage = D3DDECLUSAGE_DEPTH;
2999                 semantics[i].UsageIndex = 0;
3000             }
3001             ++i;
3002         }
3003     }
3004 
3005     if (count)
3006         *count = i;
3007 
3008     return D3D_OK;
3009 }
3010 
3011 HRESULT WINAPI D3DXGetShaderInputSemantics(const DWORD *byte_code, D3DXSEMANTIC *semantics, UINT *count)
3012 {
3013     TRACE("byte_code %p, semantics %p, count %p.\n", byte_code, semantics, count);
3014 
3015     return get_shader_semantics(byte_code, semantics, count, FALSE);
3016 }
3017 
3018 HRESULT WINAPI D3DXGetShaderOutputSemantics(const DWORD *byte_code, D3DXSEMANTIC *semantics, UINT *count)
3019 {
3020     TRACE("byte_code %p, semantics %p, count %p.\n", byte_code, semantics, count);
3021 
3022     return get_shader_semantics(byte_code, semantics, count, TRUE);
3023 }
3024