d3dx9/tests: Test effect generation and material loading for X files.
[wine] / dlls / d3dx9_36 / shader.c
1 /*
2  * Copyright 2008 Luis Busquets
3  * Copyright 2009 Matteo Bruni
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include "config.h"
21 #include "wine/port.h"
22 #include "wine/debug.h"
23 #include "wine/unicode.h"
24 #include "windef.h"
25 #include "wingdi.h"
26 #include "objbase.h"
27 #include "d3dcommon.h"
28 #include "d3dcompiler.h"
29 #include "d3dx9_36_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
32
33 /* This function is not declared in the SDK headers yet */
34 HRESULT WINAPI D3DAssemble(LPCVOID data, SIZE_T datasize, LPCSTR filename,
35                            const D3D_SHADER_MACRO *defines, ID3DInclude *include,
36                            UINT flags,
37                            ID3DBlob **shader, ID3DBlob **error_messages);
38
39 LPCSTR WINAPI D3DXGetPixelShaderProfile(LPDIRECT3DDEVICE9 device)
40 {
41     D3DCAPS9 caps;
42
43     TRACE("device %p\n", device);
44
45     if (!device) return NULL;
46
47     IDirect3DDevice9_GetDeviceCaps(device,&caps);
48
49     switch (caps.PixelShaderVersion)
50     {
51     case D3DPS_VERSION(1, 1):
52         return "ps_1_1";
53
54     case D3DPS_VERSION(1, 2):
55         return "ps_1_2";
56
57     case D3DPS_VERSION(1, 3):
58         return "ps_1_3";
59
60     case D3DPS_VERSION(1, 4):
61         return "ps_1_4";
62
63     case D3DPS_VERSION(2, 0):
64         if ((caps.PS20Caps.NumTemps>=22)                          &&
65             (caps.PS20Caps.Caps&D3DPS20CAPS_ARBITRARYSWIZZLE)     &&
66             (caps.PS20Caps.Caps&D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
67             (caps.PS20Caps.Caps&D3DPS20CAPS_PREDICATION)          &&
68             (caps.PS20Caps.Caps&D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
69             (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
70         {
71             return "ps_2_a";
72         }
73         if ((caps.PS20Caps.NumTemps>=32)                          &&
74             (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
75         {
76             return "ps_2_b";
77         }
78         return "ps_2_0";
79
80     case D3DPS_VERSION(3, 0):
81         return "ps_3_0";
82     }
83
84     return NULL;
85 }
86
87 UINT WINAPI D3DXGetShaderSize(const DWORD *byte_code)
88 {
89     const DWORD *ptr = byte_code;
90
91     TRACE("byte_code %p\n", byte_code);
92
93     if (!ptr) return 0;
94
95     /* Look for the END token, skipping the VERSION token */
96     while (*++ptr != D3DSIO_END)
97     {
98         /* Skip comments */
99         if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
100         {
101             ptr += ((*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
102         }
103     }
104     ++ptr;
105
106     /* Return the shader size in bytes */
107     return (ptr - byte_code) * sizeof(*ptr);
108 }
109
110 DWORD WINAPI D3DXGetShaderVersion(const DWORD *byte_code)
111 {
112     TRACE("byte_code %p\n", byte_code);
113
114     return byte_code ? *byte_code : 0;
115 }
116
117 LPCSTR WINAPI D3DXGetVertexShaderProfile(LPDIRECT3DDEVICE9 device)
118 {
119     D3DCAPS9 caps;
120
121     TRACE("device %p\n", device);
122
123     if (!device) return NULL;
124
125     IDirect3DDevice9_GetDeviceCaps(device,&caps);
126
127     switch (caps.VertexShaderVersion)
128     {
129     case D3DVS_VERSION(1, 1):
130         return "vs_1_1";
131     case D3DVS_VERSION(2, 0):
132         if ((caps.VS20Caps.NumTemps>=13) &&
133             (caps.VS20Caps.DynamicFlowControlDepth==24) &&
134             (caps.VS20Caps.Caps&D3DPS20CAPS_PREDICATION))
135         {
136             return "vs_2_a";
137         }
138         return "vs_2_0";
139     case D3DVS_VERSION(3, 0):
140         return "vs_3_0";
141     }
142
143     return NULL;
144 }
145
146 HRESULT WINAPI D3DXFindShaderComment(CONST DWORD* byte_code, DWORD fourcc, LPCVOID* data, UINT* size)
147 {
148     CONST DWORD *ptr = byte_code;
149
150     TRACE("(%p, %x, %p, %p)\n", byte_code, fourcc, data, size);
151
152     if (!byte_code)
153         return D3DERR_INVALIDCALL;
154
155     while (*++ptr != D3DSIO_END)
156     {
157         /* Check if it is a comment */
158         if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
159         {
160             DWORD comment_size = (*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
161
162             /* Check if this is the comment we are looking for */
163             if (*(ptr + 1) == fourcc)
164             {
165                 UINT ctab_size = (comment_size - 1) * sizeof(DWORD);
166                 LPCVOID ctab_data = ptr + 2;
167                 if (size)
168                     *size = ctab_size;
169                 if (data)
170                     *data = ctab_data;
171                 TRACE("Returning comment data at %p with size %d\n", ctab_data, ctab_size);
172                 return D3D_OK;
173             }
174             ptr += comment_size;
175         }
176     }
177
178     return S_FALSE;
179 }
180
181 HRESULT WINAPI D3DXAssembleShader(LPCSTR data,
182                                   UINT data_len,
183                                   CONST D3DXMACRO* defines,
184                                   LPD3DXINCLUDE include,
185                                   DWORD flags,
186                                   LPD3DXBUFFER* shader,
187                                   LPD3DXBUFFER* error_messages)
188 {
189     /* Forward to d3dcompiler: the parameter types aren't really different,
190        the actual data types are equivalent */
191     HRESULT hr = D3DAssemble(data, data_len, NULL, (D3D_SHADER_MACRO *)defines,
192                              (ID3DInclude *)include, flags, (ID3DBlob **)shader,
193                              (ID3DBlob **)error_messages);
194
195     if(hr == E_FAIL) hr = D3DXERR_INVALIDDATA;
196     return hr;
197 }
198
199 /* D3DXInclude private implementation, used to implement
200    D3DXAssembleShaderFromFile from D3DXAssembleShader */
201 /* To be able to correctly resolve include search paths we have to store
202    the pathname of each include file. We store the pathname pointer right
203    before the file data. */
204 static HRESULT WINAPI d3dincludefromfile_open(ID3DXInclude *iface,
205                                               D3DXINCLUDE_TYPE include_type,
206                                               LPCSTR filename, LPCVOID parent_data,
207                                               LPCVOID *data, UINT *bytes) {
208     const char *p, *parent_name = "";
209     char *pathname = NULL;
210     char **buffer = NULL;
211     HANDLE file;
212     UINT size;
213
214     if(parent_data != NULL)
215         parent_name = *((const char **)parent_data - 1);
216
217     TRACE("Looking up for include file %s, parent %s\n", debugstr_a(filename), debugstr_a(parent_name));
218
219     if ((p = strrchr(parent_name, '\\')) || (p = strrchr(parent_name, '/'))) p++;
220     else p = parent_name;
221     pathname = HeapAlloc(GetProcessHeap(), 0, (p - parent_name) + strlen(filename) + 1);
222     if(!pathname)
223         return HRESULT_FROM_WIN32(GetLastError());
224
225     memcpy(pathname, parent_name, p - parent_name);
226     strcpy(pathname + (p - parent_name), filename);
227
228     file = CreateFileA(pathname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
229     if(file == INVALID_HANDLE_VALUE)
230         goto error;
231
232     TRACE("Include file found at pathname = %s\n", debugstr_a(pathname));
233
234     size = GetFileSize(file, NULL);
235     if(size == INVALID_FILE_SIZE)
236         goto error;
237
238     buffer = HeapAlloc(GetProcessHeap(), 0, size + sizeof(char *));
239     if(!buffer)
240         goto error;
241     *buffer = pathname;
242     if(!ReadFile(file, buffer + 1, size, bytes, NULL))
243         goto error;
244
245     *data = buffer + 1;
246
247     CloseHandle(file);
248     return S_OK;
249
250 error:
251     CloseHandle(file);
252     HeapFree(GetProcessHeap(), 0, pathname);
253     HeapFree(GetProcessHeap(), 0, buffer);
254     return HRESULT_FROM_WIN32(GetLastError());
255 }
256
257 static HRESULT WINAPI d3dincludefromfile_close(ID3DXInclude *iface, LPCVOID data) {
258     HeapFree(GetProcessHeap(), 0, *((char **)data - 1));
259     HeapFree(GetProcessHeap(), 0, (char **)data - 1);
260     return S_OK;
261 }
262
263 static const struct ID3DXIncludeVtbl D3DXInclude_Vtbl = {
264     d3dincludefromfile_open,
265     d3dincludefromfile_close
266 };
267
268 struct D3DXIncludeImpl {
269     ID3DXInclude ID3DXInclude_iface;
270 };
271
272 HRESULT WINAPI D3DXAssembleShaderFromFileA(LPCSTR filename,
273                                            CONST D3DXMACRO* defines,
274                                            LPD3DXINCLUDE include,
275                                            DWORD flags,
276                                            LPD3DXBUFFER* shader,
277                                            LPD3DXBUFFER* error_messages)
278 {
279     LPWSTR filename_w = NULL;
280     DWORD len;
281     HRESULT ret;
282
283     if (!filename) return D3DXERR_INVALIDDATA;
284
285     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
286     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
287     if (!filename_w) return E_OUTOFMEMORY;
288     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
289
290     ret = D3DXAssembleShaderFromFileW(filename_w, defines, include, flags, shader, error_messages);
291
292     HeapFree(GetProcessHeap(), 0, filename_w);
293     return ret;
294 }
295
296 HRESULT WINAPI D3DXAssembleShaderFromFileW(LPCWSTR filename,
297                                            CONST D3DXMACRO* defines,
298                                            LPD3DXINCLUDE include,
299                                            DWORD flags,
300                                            LPD3DXBUFFER* shader,
301                                            LPD3DXBUFFER* error_messages)
302 {
303     void *buffer;
304     DWORD len;
305     HRESULT hr;
306     struct D3DXIncludeImpl includefromfile;
307
308     if(FAILED(map_view_of_file(filename, &buffer, &len)))
309         return D3DXERR_INVALIDDATA;
310
311     if(!include)
312     {
313         includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
314         include = &includefromfile.ID3DXInclude_iface;
315     }
316
317     hr = D3DXAssembleShader(buffer, len, defines, include, flags,
318                             shader, error_messages);
319
320     UnmapViewOfFile(buffer);
321     return hr;
322 }
323
324 HRESULT WINAPI D3DXAssembleShaderFromResourceA(HMODULE module,
325                                                LPCSTR resource,
326                                                CONST D3DXMACRO* defines,
327                                                LPD3DXINCLUDE include,
328                                                DWORD flags,
329                                                LPD3DXBUFFER* shader,
330                                                LPD3DXBUFFER* error_messages)
331 {
332     HRSRC res;
333     LPCSTR buffer;
334     DWORD len;
335
336     if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
337         return D3DXERR_INVALIDDATA;
338     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
339         return D3DXERR_INVALIDDATA;
340     return D3DXAssembleShader(buffer, len, defines, include, flags,
341                               shader, error_messages);
342 }
343
344 HRESULT WINAPI D3DXAssembleShaderFromResourceW(HMODULE module,
345                                                LPCWSTR resource,
346                                                CONST D3DXMACRO* defines,
347                                                LPD3DXINCLUDE include,
348                                                DWORD flags,
349                                                LPD3DXBUFFER* shader,
350                                                LPD3DXBUFFER* error_messages)
351 {
352     HRSRC res;
353     LPCSTR buffer;
354     DWORD len;
355
356     if (!(res = FindResourceW(module, resource, (LPCWSTR)RT_RCDATA)))
357         return D3DXERR_INVALIDDATA;
358     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
359         return D3DXERR_INVALIDDATA;
360     return D3DXAssembleShader(buffer, len, defines, include, flags,
361                               shader, error_messages);
362 }
363
364 HRESULT WINAPI D3DXCompileShader(LPCSTR pSrcData,
365                                  UINT srcDataLen,
366                                  CONST D3DXMACRO* pDefines,
367                                  LPD3DXINCLUDE pInclude,
368                                  LPCSTR pFunctionName,
369                                  LPCSTR pProfile,
370                                  DWORD Flags,
371                                  LPD3DXBUFFER* ppShader,
372                                  LPD3DXBUFFER* ppErrorMsgs,
373                                  LPD3DXCONSTANTTABLE * ppConstantTable)
374 {
375     HRESULT hr = D3DCompile(pSrcData, srcDataLen, NULL,
376                             (D3D_SHADER_MACRO *)pDefines, (ID3DInclude *)pInclude,
377                             pFunctionName, pProfile, Flags, 0,
378                             (ID3DBlob **)ppShader, (ID3DBlob **)ppErrorMsgs);
379
380     if(SUCCEEDED(hr) && ppConstantTable)
381         return D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*ppShader),
382                                           ppConstantTable);
383     return hr;
384 }
385
386 HRESULT WINAPI D3DXCompileShaderFromFileA(LPCSTR filename,
387                                           CONST D3DXMACRO* defines,
388                                           LPD3DXINCLUDE include,
389                                           LPCSTR entrypoint,
390                                           LPCSTR profile,
391                                           DWORD flags,
392                                           LPD3DXBUFFER* shader,
393                                           LPD3DXBUFFER* error_messages,
394                                           LPD3DXCONSTANTTABLE* constant_table)
395 {
396     LPWSTR filename_w = NULL;
397     DWORD len;
398     HRESULT ret;
399
400     if (!filename) return D3DXERR_INVALIDDATA;
401
402     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
403     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
404     if (!filename_w) return E_OUTOFMEMORY;
405     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
406
407     ret = D3DXCompileShaderFromFileW(filename_w, defines, include,
408                                      entrypoint, profile, flags,
409                                      shader, error_messages, constant_table);
410
411     HeapFree(GetProcessHeap(), 0, filename_w);
412     return ret;
413 }
414
415 HRESULT WINAPI D3DXCompileShaderFromFileW(LPCWSTR filename,
416                                           CONST D3DXMACRO* defines,
417                                           LPD3DXINCLUDE include,
418                                           LPCSTR entrypoint,
419                                           LPCSTR profile,
420                                           DWORD flags,
421                                           LPD3DXBUFFER* shader,
422                                           LPD3DXBUFFER* error_messages,
423                                           LPD3DXCONSTANTTABLE* constant_table)
424 {
425     void *buffer;
426     DWORD len, filename_len;
427     HRESULT hr;
428     struct D3DXIncludeImpl includefromfile;
429     char *filename_a;
430
431     if (FAILED(map_view_of_file(filename, &buffer, &len)))
432         return D3DXERR_INVALIDDATA;
433
434     if (!include)
435     {
436         includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
437         include = &includefromfile.ID3DXInclude_iface;
438     }
439
440     filename_len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
441     filename_a = HeapAlloc(GetProcessHeap(), 0, filename_len * sizeof(char));
442     if (!filename_a)
443     {
444         UnmapViewOfFile(buffer);
445         return E_OUTOFMEMORY;
446     }
447     WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, filename_len, NULL, NULL);
448
449     hr = D3DCompile(buffer, len, filename_a, (const D3D_SHADER_MACRO *)defines,
450                     (ID3DInclude *)include, entrypoint, profile, flags, 0,
451                     (ID3DBlob **)shader, (ID3DBlob **)error_messages);
452
453     if (SUCCEEDED(hr) && constant_table)
454         hr = D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*shader),
455                                         constant_table);
456
457     HeapFree(GetProcessHeap(), 0, filename_a);
458     UnmapViewOfFile(buffer);
459     return hr;
460 }
461
462 HRESULT WINAPI D3DXCompileShaderFromResourceA(HMODULE module,
463                                               LPCSTR resource,
464                                               CONST D3DXMACRO* defines,
465                                               LPD3DXINCLUDE include,
466                                               LPCSTR entrypoint,
467                                               LPCSTR profile,
468                                               DWORD flags,
469                                               LPD3DXBUFFER* shader,
470                                               LPD3DXBUFFER* error_messages,
471                                               LPD3DXCONSTANTTABLE* constant_table)
472 {
473     HRSRC res;
474     LPCSTR buffer;
475     DWORD len;
476
477     if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
478         return D3DXERR_INVALIDDATA;
479     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
480         return D3DXERR_INVALIDDATA;
481     return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
482                              flags, shader, error_messages, constant_table);
483 }
484
485 HRESULT WINAPI D3DXCompileShaderFromResourceW(HMODULE module,
486                                               LPCWSTR resource,
487                                               CONST D3DXMACRO* defines,
488                                               LPD3DXINCLUDE include,
489                                               LPCSTR entrypoint,
490                                               LPCSTR profile,
491                                               DWORD flags,
492                                               LPD3DXBUFFER* shader,
493                                               LPD3DXBUFFER* error_messages,
494                                               LPD3DXCONSTANTTABLE* constant_table)
495 {
496     HRSRC res;
497     LPCSTR buffer;
498     DWORD len;
499
500     if (!(res = FindResourceW(module, resource, (LPCWSTR)RT_RCDATA)))
501         return D3DXERR_INVALIDDATA;
502     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
503         return D3DXERR_INVALIDDATA;
504     return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
505                              flags, shader, error_messages, constant_table);
506 }
507
508 HRESULT WINAPI D3DXPreprocessShader(LPCSTR data,
509                                     UINT data_len,
510                                     CONST D3DXMACRO* defines,
511                                     LPD3DXINCLUDE include,
512                                     LPD3DXBUFFER* shader,
513                                     LPD3DXBUFFER* error_messages)
514 {
515     TRACE("Forward to D3DPreprocess\n");
516     return D3DPreprocess(data, data_len, NULL,
517                          (const D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
518                          (ID3DBlob **)shader, (ID3DBlob **)error_messages);
519 }
520
521 HRESULT WINAPI D3DXPreprocessShaderFromFileA(LPCSTR filename,
522                                              CONST D3DXMACRO* defines,
523                                              LPD3DXINCLUDE include,
524                                              LPD3DXBUFFER* shader,
525                                              LPD3DXBUFFER* error_messages)
526 {
527     WCHAR *filename_w = NULL;
528     DWORD len;
529     HRESULT ret;
530
531     if (!filename) return D3DXERR_INVALIDDATA;
532
533     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
534     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
535     if (!filename_w) return E_OUTOFMEMORY;
536     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
537
538     ret = D3DXPreprocessShaderFromFileW(filename_w, defines, include, shader, error_messages);
539
540     HeapFree(GetProcessHeap(), 0, filename_w);
541     return ret;
542 }
543
544 HRESULT WINAPI D3DXPreprocessShaderFromFileW(LPCWSTR filename,
545                                              CONST D3DXMACRO* defines,
546                                              LPD3DXINCLUDE include,
547                                              LPD3DXBUFFER* shader,
548                                              LPD3DXBUFFER* error_messages)
549 {
550     void *buffer;
551     DWORD len;
552     HRESULT hr;
553     struct D3DXIncludeImpl includefromfile;
554
555     if (FAILED(map_view_of_file(filename, &buffer, &len)))
556         return D3DXERR_INVALIDDATA;
557
558     if (!include)
559     {
560         includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
561         include = &includefromfile.ID3DXInclude_iface;
562     }
563
564     hr = D3DPreprocess(buffer, len, NULL,
565                        (const D3D_SHADER_MACRO *)defines,
566                        (ID3DInclude *) include,
567                        (ID3DBlob **)shader, (ID3DBlob **)error_messages);
568
569     UnmapViewOfFile(buffer);
570     return hr;
571 }
572
573 HRESULT WINAPI D3DXPreprocessShaderFromResourceA(HMODULE module,
574                                                  LPCSTR resource,
575                                                  CONST D3DXMACRO* defines,
576                                                  LPD3DXINCLUDE include,
577                                                  LPD3DXBUFFER* shader,
578                                                  LPD3DXBUFFER* error_messages)
579 {
580     HRSRC res;
581     const char *buffer;
582     DWORD len;
583
584     if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
585         return D3DXERR_INVALIDDATA;
586     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
587         return D3DXERR_INVALIDDATA;
588     return D3DXPreprocessShader(buffer, len, defines, include,
589                                 shader, error_messages);
590 }
591
592 HRESULT WINAPI D3DXPreprocessShaderFromResourceW(HMODULE module,
593                                                  LPCWSTR resource,
594                                                  CONST D3DXMACRO* defines,
595                                                  LPD3DXINCLUDE include,
596                                                  LPD3DXBUFFER* shader,
597                                                  LPD3DXBUFFER* error_messages)
598 {
599     HRSRC res;
600     const char *buffer;
601     DWORD len;
602
603     if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
604         return D3DXERR_INVALIDDATA;
605     if (FAILED(load_resource_into_memory(module, res, (void **)&buffer, &len)))
606         return D3DXERR_INVALIDDATA;
607     return D3DXPreprocessShader(buffer, len, defines, include,
608                                 shader, error_messages);
609
610 }
611
612 typedef struct ctab_constant {
613     D3DXCONSTANT_DESC desc;
614     struct ctab_constant *members;
615 } ctab_constant;
616
617 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl;
618
619 typedef struct ID3DXConstantTableImpl {
620     ID3DXConstantTable ID3DXConstantTable_iface;
621     LONG ref;
622     char *ctab;
623     DWORD size;
624     D3DXCONSTANTTABLE_DESC desc;
625     ctab_constant *constants;
626 } ID3DXConstantTableImpl;
627
628 static inline ID3DXConstantTableImpl *impl_from_ID3DXConstantTable(ID3DXConstantTable *iface)
629 {
630     return CONTAINING_RECORD(iface, ID3DXConstantTableImpl, ID3DXConstantTable_iface);
631 }
632
633 /*** IUnknown methods ***/
634 static HRESULT WINAPI ID3DXConstantTableImpl_QueryInterface(ID3DXConstantTable* iface, REFIID riid, void** ppvObject)
635 {
636     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
637
638     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
639
640     if (IsEqualGUID(riid, &IID_IUnknown) ||
641         IsEqualGUID(riid, &IID_ID3DXBuffer) ||
642         IsEqualGUID(riid, &IID_ID3DXConstantTable))
643     {
644         ID3DXConstantTable_AddRef(iface);
645         *ppvObject = This;
646         return S_OK;
647     }
648
649     WARN("Interface %s not found.\n", debugstr_guid(riid));
650
651     return E_NOINTERFACE;
652 }
653
654 static ULONG WINAPI ID3DXConstantTableImpl_AddRef(ID3DXConstantTable* iface)
655 {
656     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
657
658     TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
659
660     return InterlockedIncrement(&This->ref);
661 }
662
663 static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable* iface)
664 {
665     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
666     ULONG ref = InterlockedDecrement(&This->ref);
667
668     TRACE("(%p)->(): Release from %d\n", This, ref + 1);
669
670     if (!ref)
671     {
672         HeapFree(GetProcessHeap(), 0, This->constants);
673         HeapFree(GetProcessHeap(), 0, This->ctab);
674         HeapFree(GetProcessHeap(), 0, This);
675     }
676
677     return ref;
678 }
679
680 /*** ID3DXBuffer methods ***/
681 static LPVOID WINAPI ID3DXConstantTableImpl_GetBufferPointer(ID3DXConstantTable* iface)
682 {
683     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
684
685     TRACE("(%p)->()\n", This);
686
687     return This->ctab;
688 }
689
690 static DWORD WINAPI ID3DXConstantTableImpl_GetBufferSize(ID3DXConstantTable* iface)
691 {
692     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
693
694     TRACE("(%p)->()\n", This);
695
696     return This->size;
697 }
698
699 /*** ID3DXConstantTable methods ***/
700 static HRESULT WINAPI ID3DXConstantTableImpl_GetDesc(ID3DXConstantTable* iface, D3DXCONSTANTTABLE_DESC *desc)
701 {
702     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
703
704     TRACE("(%p)->(%p)\n", This, desc);
705
706     if (!desc)
707         return D3DERR_INVALIDCALL;
708
709     memcpy(desc, &This->desc, sizeof(This->desc));
710
711     return D3D_OK;
712 }
713
714 static HRESULT WINAPI ID3DXConstantTableImpl_GetConstantDesc(ID3DXConstantTable* iface, D3DXHANDLE constant,
715                                                              D3DXCONSTANT_DESC *desc, UINT *count)
716 {
717     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
718     ctab_constant *constant_info;
719
720     TRACE("(%p)->(%p, %p, %p)\n", This, constant, desc, count);
721
722     if (!constant)
723         return D3DERR_INVALIDCALL;
724
725     /* Applications can pass the name of the constant in place of the handle */
726     if (!((UINT_PTR)constant >> 16))
727         constant_info = &This->constants[(UINT_PTR)constant - 1];
728     else
729     {
730         D3DXHANDLE c = ID3DXConstantTable_GetConstantByName(iface, NULL, constant);
731         if (!c)
732             return D3DERR_INVALIDCALL;
733
734         constant_info = &This->constants[(UINT_PTR)c - 1];
735     }
736
737     if (desc)
738         *desc = constant_info->desc;
739     if (count)
740         *count = 1;
741
742     return D3D_OK;
743 }
744
745 static UINT WINAPI ID3DXConstantTableImpl_GetSamplerIndex(LPD3DXCONSTANTTABLE iface, D3DXHANDLE constant)
746 {
747     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
748
749     FIXME("(%p)->(%p): stub\n", This, constant);
750
751     return (UINT)-1;
752 }
753
754 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstant(ID3DXConstantTable* iface, D3DXHANDLE constant, UINT index)
755 {
756     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
757
758     TRACE("(%p)->(%p, %d)\n", This, constant, index);
759
760     if (constant)
761     {
762         FIXME("Only top level constants supported\n");
763         return NULL;
764     }
765
766     if (index >= This->desc.Constants)
767         return NULL;
768
769     return (D3DXHANDLE)(DWORD_PTR)(index + 1);
770 }
771
772 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable* iface, D3DXHANDLE constant, LPCSTR name)
773 {
774     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
775     UINT i;
776
777     TRACE("(%p)->(%p, %s)\n", This, constant, name);
778
779     if (!name)
780         return NULL;
781
782     if (constant)
783     {
784         FIXME("Only top level constants supported\n");
785         return NULL;
786     }
787
788     for (i = 0; i < This->desc.Constants; i++)
789         if (!strcmp(This->constants[i].desc.Name, name))
790             return (D3DXHANDLE)(DWORD_PTR)(i + 1);
791
792     return NULL;
793 }
794
795 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantElement(ID3DXConstantTable* iface, D3DXHANDLE constant, UINT index)
796 {
797     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
798
799     FIXME("(%p)->(%p, %d): stub\n", This, constant, index);
800
801     return NULL;
802 }
803
804 static HRESULT WINAPI ID3DXConstantTableImpl_SetDefaults(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device)
805 {
806     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
807
808     FIXME("(%p)->(%p): stub\n", This, device);
809
810     return E_NOTIMPL;
811 }
812
813 static HRESULT WINAPI ID3DXConstantTableImpl_SetValue(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
814                                                       D3DXHANDLE constant, LPCVOID data, UINT bytes)
815 {
816     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
817
818     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, data, bytes);
819
820     return E_NOTIMPL;
821 }
822
823 static HRESULT WINAPI ID3DXConstantTableImpl_SetBool(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
824                                                      D3DXHANDLE constant, BOOL b)
825 {
826     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
827
828     FIXME("(%p)->(%p, %p, %d): stub\n", This, device, constant, b);
829
830     return E_NOTIMPL;
831 }
832
833 static HRESULT WINAPI ID3DXConstantTableImpl_SetBoolArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
834                                                           D3DXHANDLE constant, CONST BOOL* b, UINT count)
835 {
836     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
837
838     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, b, count);
839
840     return E_NOTIMPL;
841 }
842
843 static HRESULT WINAPI ID3DXConstantTableImpl_SetInt(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device, D3DXHANDLE constant, INT n)
844 {
845     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
846
847     FIXME("(%p)->(%p, %p, %d): stub\n", This, device, constant, n);
848
849     return E_NOTIMPL;
850 }
851
852 static HRESULT WINAPI ID3DXConstantTableImpl_SetIntArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
853                                                          D3DXHANDLE constant, CONST INT* n, UINT count)
854 {
855     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
856
857     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, n, count);
858
859     return E_NOTIMPL;
860 }
861
862 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloat(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
863                                                       D3DXHANDLE constant, FLOAT f)
864 {
865     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
866
867     FIXME("(%p)->(%p, %p, %f): stub\n", This, device, constant, f);
868
869     return E_NOTIMPL;
870 }
871
872 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloatArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
873                                                            D3DXHANDLE constant, CONST FLOAT* f, UINT count)
874 {
875     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
876
877     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, f, count);
878
879     return E_NOTIMPL;
880 }
881
882 static HRESULT WINAPI ID3DXConstantTableImpl_SetVector(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
883                                                        D3DXHANDLE constant, CONST D3DXVECTOR4* vector)
884 {
885     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
886
887     FIXME("(%p)->(%p, %p, %p): stub\n", This, device, constant, vector);
888
889     return E_NOTIMPL;
890 }
891
892 static HRESULT WINAPI ID3DXConstantTableImpl_SetVectorArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
893                                                             D3DXHANDLE constant, CONST D3DXVECTOR4* vector, UINT count)
894 {
895     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
896
897     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, vector, count);
898
899     return E_NOTIMPL;
900 }
901
902 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrix(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
903                                                        D3DXHANDLE constant, CONST D3DXMATRIX* matrix)
904 {
905     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
906
907     FIXME("(%p)->(%p, %p, %p): stub\n", This, device, constant, matrix);
908
909     return E_NOTIMPL;
910 }
911
912 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
913                                                             D3DXHANDLE constant, CONST D3DXMATRIX* matrix, UINT count)
914 {
915     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
916
917     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
918
919     return E_NOTIMPL;
920 }
921
922 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixPointerArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
923                                                                    D3DXHANDLE constant, CONST D3DXMATRIX** matrix, UINT count)
924 {
925     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
926
927     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
928
929     return E_NOTIMPL;
930 }
931
932 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTranspose(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
933                                                                 D3DXHANDLE constant, CONST D3DXMATRIX* matrix)
934 {
935     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
936
937     FIXME("(%p)->(%p, %p, %p): stub\n", This, device, constant, matrix);
938
939     return E_NOTIMPL;
940 }
941
942 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposeArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
943                                                                      D3DXHANDLE constant, CONST D3DXMATRIX* matrix, UINT count)
944 {
945     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
946
947     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
948
949     return E_NOTIMPL;
950 }
951
952 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposePointerArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
953                                                                             D3DXHANDLE constant, CONST D3DXMATRIX** matrix, UINT count)
954 {
955     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
956
957     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
958
959     return E_NOTIMPL;
960 }
961
962 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl =
963 {
964     /*** IUnknown methods ***/
965     ID3DXConstantTableImpl_QueryInterface,
966     ID3DXConstantTableImpl_AddRef,
967     ID3DXConstantTableImpl_Release,
968     /*** ID3DXBuffer methods ***/
969     ID3DXConstantTableImpl_GetBufferPointer,
970     ID3DXConstantTableImpl_GetBufferSize,
971     /*** ID3DXConstantTable methods ***/
972     ID3DXConstantTableImpl_GetDesc,
973     ID3DXConstantTableImpl_GetConstantDesc,
974     ID3DXConstantTableImpl_GetSamplerIndex,
975     ID3DXConstantTableImpl_GetConstant,
976     ID3DXConstantTableImpl_GetConstantByName,
977     ID3DXConstantTableImpl_GetConstantElement,
978     ID3DXConstantTableImpl_SetDefaults,
979     ID3DXConstantTableImpl_SetValue,
980     ID3DXConstantTableImpl_SetBool,
981     ID3DXConstantTableImpl_SetBoolArray,
982     ID3DXConstantTableImpl_SetInt,
983     ID3DXConstantTableImpl_SetIntArray,
984     ID3DXConstantTableImpl_SetFloat,
985     ID3DXConstantTableImpl_SetFloatArray,
986     ID3DXConstantTableImpl_SetVector,
987     ID3DXConstantTableImpl_SetVectorArray,
988     ID3DXConstantTableImpl_SetMatrix,
989     ID3DXConstantTableImpl_SetMatrixArray,
990     ID3DXConstantTableImpl_SetMatrixPointerArray,
991     ID3DXConstantTableImpl_SetMatrixTranspose,
992     ID3DXConstantTableImpl_SetMatrixTransposeArray,
993     ID3DXConstantTableImpl_SetMatrixTransposePointerArray
994 };
995
996 static HRESULT parse_ctab_constant_type(const D3DXSHADER_TYPEINFO *type, ctab_constant *constant)
997 {
998     constant->desc.Class = type->Class;
999     constant->desc.Type = type->Type;
1000     constant->desc.Rows = type->Rows;
1001     constant->desc.Columns = type->Columns;
1002     constant->desc.Elements = type->Elements;
1003     constant->desc.StructMembers = type->StructMembers;
1004
1005     TRACE("class = %d, type = %d, rows = %d, columns = %d, elements = %d, struct_members = %d\n",
1006           constant->desc.Class, constant->desc.Type, constant->desc.Elements,
1007           constant->desc.Rows, constant->desc.Columns, constant->desc.StructMembers);
1008
1009     if ((constant->desc.Class == D3DXPC_STRUCT) && constant->desc.StructMembers)
1010     {
1011         FIXME("Struct not supported yet\n");
1012         return E_NOTIMPL;
1013     }
1014
1015     return D3D_OK;
1016 }
1017
1018 HRESULT WINAPI D3DXGetShaderConstantTableEx(CONST DWORD* byte_code,
1019                                             DWORD flags,
1020                                             LPD3DXCONSTANTTABLE* constant_table)
1021 {
1022     ID3DXConstantTableImpl* object = NULL;
1023     HRESULT hr;
1024     LPCVOID data;
1025     UINT size;
1026     const D3DXSHADER_CONSTANTTABLE* ctab_header;
1027     D3DXSHADER_CONSTANTINFO* constant_info;
1028     DWORD i;
1029
1030     TRACE("(%p, %x, %p)\n", byte_code, flags, constant_table);
1031
1032     if (!byte_code || !constant_table)
1033         return D3DERR_INVALIDCALL;
1034
1035     hr = D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), &data, &size);
1036     if (hr != D3D_OK)
1037         return D3DXERR_INVALIDDATA;
1038
1039     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID3DXConstantTableImpl));
1040     if (!object)
1041     {
1042         ERR("Out of memory\n");
1043         return E_OUTOFMEMORY;
1044     }
1045
1046     object->ID3DXConstantTable_iface.lpVtbl = &ID3DXConstantTable_Vtbl;
1047     object->ref = 1;
1048
1049     if (size < sizeof(D3DXSHADER_CONSTANTTABLE))
1050     {
1051         hr = D3DXERR_INVALIDDATA;
1052         goto error;
1053     }
1054
1055     object->ctab = HeapAlloc(GetProcessHeap(), 0, size);
1056     if (!object->ctab)
1057     {
1058         ERR("Out of memory\n");
1059         hr = E_OUTOFMEMORY;
1060         goto error;
1061     }
1062     object->size = size;
1063     memcpy(object->ctab, data, object->size);
1064
1065     ctab_header = (const D3DXSHADER_CONSTANTTABLE*)data;
1066     if (ctab_header->Size != sizeof(D3DXSHADER_CONSTANTTABLE))
1067     {
1068         hr = D3DXERR_INVALIDDATA;
1069         goto error;
1070     }
1071     object->desc.Creator = ctab_header->Creator ? object->ctab + ctab_header->Creator : NULL;
1072     object->desc.Version = ctab_header->Version;
1073     object->desc.Constants = ctab_header->Constants;
1074     if (object->desc.Creator)
1075         TRACE("Creator = %s\n", object->desc.Creator);
1076     TRACE("Version = %x\n", object->desc.Version);
1077     TRACE("Constants = %d\n", ctab_header->Constants);
1078     if (ctab_header->Target)
1079         TRACE("Target = %s\n", object->ctab + ctab_header->Target);
1080
1081     if (object->desc.Constants > 65535)
1082     {
1083         FIXME("Too many constants (%u)\n", object->desc.Constants);
1084         hr = E_NOTIMPL;
1085         goto error;
1086     }
1087
1088     object->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1089                                   sizeof(*object->constants) * object->desc.Constants);
1090     if (!object->constants)
1091     {
1092          ERR("Out of memory\n");
1093          hr = E_OUTOFMEMORY;
1094          goto error;
1095     }
1096
1097     constant_info = (LPD3DXSHADER_CONSTANTINFO)(object->ctab + ctab_header->ConstantInfo);
1098     for (i = 0; i < ctab_header->Constants; i++)
1099     {
1100         TRACE("name = %s\n", object->ctab + constant_info[i].Name);
1101         object->constants[i].desc.Name = object->ctab + constant_info[i].Name;
1102         object->constants[i].desc.RegisterSet = constant_info[i].RegisterSet;
1103         object->constants[i].desc.RegisterIndex = constant_info[i].RegisterIndex;
1104         object->constants[i].desc.RegisterCount = constant_info[i].RegisterCount;
1105         object->constants[i].desc.DefaultValue = object->ctab + constant_info[i].DefaultValue;
1106
1107         hr = parse_ctab_constant_type((LPD3DXSHADER_TYPEINFO)(object->ctab + constant_info[i].TypeInfo),
1108              &object->constants[i]);
1109         if (hr != D3D_OK)
1110             goto error;
1111
1112         if (constant_info[i].RegisterSet != D3DXRS_FLOAT4)
1113             FIXME("Don't know how to calculate Bytes for non D3DXRS_FLOAT4 constants\n");
1114
1115         /* D3DXRS_FLOAT4 has a base size of 4 (not taking into account dimensions and element count) */
1116         object->constants[i].desc.Bytes = 4;
1117
1118         /* Take into account dimensions and elements */
1119         object->constants[i].desc.Bytes *= object->constants[i].desc.Elements;
1120         object->constants[i].desc.Bytes *= object->constants[i].desc.Rows *
1121                 object->constants[i].desc.Columns;
1122     }
1123
1124     *constant_table = &object->ID3DXConstantTable_iface;
1125
1126     return D3D_OK;
1127
1128 error:
1129
1130     HeapFree(GetProcessHeap(), 0, object->constants);
1131     HeapFree(GetProcessHeap(), 0, object->ctab);
1132     HeapFree(GetProcessHeap(), 0, object);
1133
1134     return hr;
1135 }
1136
1137 HRESULT WINAPI D3DXGetShaderConstantTable(CONST DWORD* byte_code,
1138                                           LPD3DXCONSTANTTABLE* constant_table)
1139 {
1140     TRACE("(%p, %p): Forwarded to D3DXGetShaderConstantTableEx\n", byte_code, constant_table);
1141
1142     return D3DXGetShaderConstantTableEx(byte_code, 0, constant_table);
1143 }