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