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