itss: Convert protocol registration to the IRegistrar format.
[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     const ID3DXIncludeVtbl *lpVtbl;
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.lpVtbl = &D3DXInclude_Vtbl;
314         include = (LPD3DXINCLUDE)&includefromfile;
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.lpVtbl = &D3DXInclude_Vtbl;
437         include = (LPD3DXINCLUDE)&includefromfile;
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.lpVtbl = &D3DXInclude_Vtbl;
561         include = (LPD3DXINCLUDE)&includefromfile;
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     const ID3DXConstantTableVtbl *lpVtbl;
621     LONG ref;
622     char *ctab;
623     DWORD size;
624     D3DXCONSTANTTABLE_DESC desc;
625     ctab_constant *constants;
626 } ID3DXConstantTableImpl;
627
628 /*** IUnknown methods ***/
629 static HRESULT WINAPI ID3DXConstantTableImpl_QueryInterface(ID3DXConstantTable* iface, REFIID riid, void** ppvObject)
630 {
631     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
632
633     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
634
635     if (IsEqualGUID(riid, &IID_IUnknown) ||
636         IsEqualGUID(riid, &IID_ID3DXBuffer) ||
637         IsEqualGUID(riid, &IID_ID3DXConstantTable))
638     {
639         ID3DXConstantTable_AddRef(iface);
640         *ppvObject = This;
641         return S_OK;
642     }
643
644     WARN("Interface %s not found.\n", debugstr_guid(riid));
645
646     return E_NOINTERFACE;
647 }
648
649 static ULONG WINAPI ID3DXConstantTableImpl_AddRef(ID3DXConstantTable* iface)
650 {
651     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
652
653     TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
654
655     return InterlockedIncrement(&This->ref);
656 }
657
658 static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable* iface)
659 {
660     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
661     ULONG ref = InterlockedDecrement(&This->ref);
662
663     TRACE("(%p)->(): Release from %d\n", This, ref + 1);
664
665     if (!ref)
666     {
667         HeapFree(GetProcessHeap(), 0, This->constants);
668         HeapFree(GetProcessHeap(), 0, This->ctab);
669         HeapFree(GetProcessHeap(), 0, This);
670     }
671
672     return ref;
673 }
674
675 /*** ID3DXBuffer methods ***/
676 static LPVOID WINAPI ID3DXConstantTableImpl_GetBufferPointer(ID3DXConstantTable* iface)
677 {
678     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
679
680     TRACE("(%p)->()\n", This);
681
682     return This->ctab;
683 }
684
685 static DWORD WINAPI ID3DXConstantTableImpl_GetBufferSize(ID3DXConstantTable* iface)
686 {
687     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
688
689     TRACE("(%p)->()\n", This);
690
691     return This->size;
692 }
693
694 /*** ID3DXConstantTable methods ***/
695 static HRESULT WINAPI ID3DXConstantTableImpl_GetDesc(ID3DXConstantTable* iface, D3DXCONSTANTTABLE_DESC *desc)
696 {
697     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
698
699     TRACE("(%p)->(%p)\n", This, desc);
700
701     if (!desc)
702         return D3DERR_INVALIDCALL;
703
704     memcpy(desc, &This->desc, sizeof(This->desc));
705
706     return D3D_OK;
707 }
708
709 static HRESULT WINAPI ID3DXConstantTableImpl_GetConstantDesc(ID3DXConstantTable* iface, D3DXHANDLE constant,
710                                                              D3DXCONSTANT_DESC *desc, UINT *count)
711 {
712     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
713     ctab_constant *constant_info;
714
715     TRACE("(%p)->(%p, %p, %p)\n", This, constant, desc, count);
716
717     if (!constant)
718         return D3DERR_INVALIDCALL;
719
720     /* Applications can pass the name of the constant in place of the handle */
721     if (!((UINT_PTR)constant >> 16))
722         constant_info = &This->constants[(UINT_PTR)constant - 1];
723     else
724     {
725         D3DXHANDLE c = ID3DXConstantTable_GetConstantByName(iface, NULL, constant);
726         if (!c)
727             return D3DERR_INVALIDCALL;
728
729         constant_info = &This->constants[(UINT_PTR)c - 1];
730     }
731
732     if (desc)
733         *desc = constant_info->desc;
734     if (count)
735         *count = 1;
736
737     return D3D_OK;
738 }
739
740 static UINT WINAPI ID3DXConstantTableImpl_GetSamplerIndex(LPD3DXCONSTANTTABLE iface, D3DXHANDLE constant)
741 {
742     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
743
744     FIXME("(%p)->(%p): stub\n", This, constant);
745
746     return (UINT)-1;
747 }
748
749 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstant(ID3DXConstantTable* iface, D3DXHANDLE constant, UINT index)
750 {
751     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
752
753     TRACE("(%p)->(%p, %d)\n", This, constant, index);
754
755     if (constant)
756     {
757         FIXME("Only top level constants supported\n");
758         return NULL;
759     }
760
761     if (index >= This->desc.Constants)
762         return NULL;
763
764     return (D3DXHANDLE)(DWORD_PTR)(index + 1);
765 }
766
767 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable* iface, D3DXHANDLE constant, LPCSTR name)
768 {
769     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
770     UINT i;
771
772     TRACE("(%p)->(%p, %s)\n", This, constant, name);
773
774     if (!name)
775         return NULL;
776
777     if (constant)
778     {
779         FIXME("Only top level constants supported\n");
780         return NULL;
781     }
782
783     for (i = 0; i < This->desc.Constants; i++)
784         if (!strcmp(This->constants[i].desc.Name, name))
785             return (D3DXHANDLE)(DWORD_PTR)(i + 1);
786
787     return NULL;
788 }
789
790 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantElement(ID3DXConstantTable* iface, D3DXHANDLE constant, UINT index)
791 {
792     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
793
794     FIXME("(%p)->(%p, %d): stub\n", This, constant, index);
795
796     return NULL;
797 }
798
799 static HRESULT WINAPI ID3DXConstantTableImpl_SetDefaults(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device)
800 {
801     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
802
803     FIXME("(%p)->(%p): stub\n", This, device);
804
805     return E_NOTIMPL;
806 }
807
808 static HRESULT WINAPI ID3DXConstantTableImpl_SetValue(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
809                                                       D3DXHANDLE constant, LPCVOID data, UINT bytes)
810 {
811     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
812
813     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, data, bytes);
814
815     return E_NOTIMPL;
816 }
817
818 static HRESULT WINAPI ID3DXConstantTableImpl_SetBool(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
819                                                      D3DXHANDLE constant, BOOL b)
820 {
821     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
822
823     FIXME("(%p)->(%p, %p, %d): stub\n", This, device, constant, b);
824
825     return E_NOTIMPL;
826 }
827
828 static HRESULT WINAPI ID3DXConstantTableImpl_SetBoolArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
829                                                           D3DXHANDLE constant, CONST BOOL* b, UINT count)
830 {
831     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
832
833     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, b, count);
834
835     return E_NOTIMPL;
836 }
837
838 static HRESULT WINAPI ID3DXConstantTableImpl_SetInt(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device, D3DXHANDLE constant, INT n)
839 {
840     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
841
842     FIXME("(%p)->(%p, %p, %d): stub\n", This, device, constant, n);
843
844     return E_NOTIMPL;
845 }
846
847 static HRESULT WINAPI ID3DXConstantTableImpl_SetIntArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
848                                                          D3DXHANDLE constant, CONST INT* n, UINT count)
849 {
850     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
851
852     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, n, count);
853
854     return E_NOTIMPL;
855 }
856
857 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloat(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
858                                                       D3DXHANDLE constant, FLOAT f)
859 {
860     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
861
862     FIXME("(%p)->(%p, %p, %f): stub\n", This, device, constant, f);
863
864     return E_NOTIMPL;
865 }
866
867 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloatArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
868                                                            D3DXHANDLE constant, CONST FLOAT* f, UINT count)
869 {
870     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
871
872     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, f, count);
873
874     return E_NOTIMPL;
875 }
876
877 static HRESULT WINAPI ID3DXConstantTableImpl_SetVector(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
878                                                        D3DXHANDLE constant, CONST D3DXVECTOR4* vector)
879 {
880     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
881
882     FIXME("(%p)->(%p, %p, %p): stub\n", This, device, constant, vector);
883
884     return E_NOTIMPL;
885 }
886
887 static HRESULT WINAPI ID3DXConstantTableImpl_SetVectorArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
888                                                             D3DXHANDLE constant, CONST D3DXVECTOR4* vector, UINT count)
889 {
890     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
891
892     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, vector, count);
893
894     return E_NOTIMPL;
895 }
896
897 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrix(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
898                                                        D3DXHANDLE constant, CONST D3DXMATRIX* matrix)
899 {
900     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
901
902     FIXME("(%p)->(%p, %p, %p): stub\n", This, device, constant, matrix);
903
904     return E_NOTIMPL;
905 }
906
907 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
908                                                             D3DXHANDLE constant, CONST D3DXMATRIX* matrix, UINT count)
909 {
910     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
911
912     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
913
914     return E_NOTIMPL;
915 }
916
917 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixPointerArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
918                                                                    D3DXHANDLE constant, CONST D3DXMATRIX** matrix, UINT count)
919 {
920     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
921
922     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
923
924     return E_NOTIMPL;
925 }
926
927 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTranspose(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
928                                                                 D3DXHANDLE constant, CONST D3DXMATRIX* matrix)
929 {
930     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
931
932     FIXME("(%p)->(%p, %p, %p): stub\n", This, device, constant, matrix);
933
934     return E_NOTIMPL;
935 }
936
937 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposeArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
938                                                                      D3DXHANDLE constant, CONST D3DXMATRIX* matrix, UINT count)
939 {
940     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
941
942     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
943
944     return E_NOTIMPL;
945 }
946
947 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposePointerArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
948                                                                             D3DXHANDLE constant, CONST D3DXMATRIX** matrix, UINT count)
949 {
950     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
951
952     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
953
954     return E_NOTIMPL;
955 }
956
957 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl =
958 {
959     /*** IUnknown methods ***/
960     ID3DXConstantTableImpl_QueryInterface,
961     ID3DXConstantTableImpl_AddRef,
962     ID3DXConstantTableImpl_Release,
963     /*** ID3DXBuffer methods ***/
964     ID3DXConstantTableImpl_GetBufferPointer,
965     ID3DXConstantTableImpl_GetBufferSize,
966     /*** ID3DXConstantTable methods ***/
967     ID3DXConstantTableImpl_GetDesc,
968     ID3DXConstantTableImpl_GetConstantDesc,
969     ID3DXConstantTableImpl_GetSamplerIndex,
970     ID3DXConstantTableImpl_GetConstant,
971     ID3DXConstantTableImpl_GetConstantByName,
972     ID3DXConstantTableImpl_GetConstantElement,
973     ID3DXConstantTableImpl_SetDefaults,
974     ID3DXConstantTableImpl_SetValue,
975     ID3DXConstantTableImpl_SetBool,
976     ID3DXConstantTableImpl_SetBoolArray,
977     ID3DXConstantTableImpl_SetInt,
978     ID3DXConstantTableImpl_SetIntArray,
979     ID3DXConstantTableImpl_SetFloat,
980     ID3DXConstantTableImpl_SetFloatArray,
981     ID3DXConstantTableImpl_SetVector,
982     ID3DXConstantTableImpl_SetVectorArray,
983     ID3DXConstantTableImpl_SetMatrix,
984     ID3DXConstantTableImpl_SetMatrixArray,
985     ID3DXConstantTableImpl_SetMatrixPointerArray,
986     ID3DXConstantTableImpl_SetMatrixTranspose,
987     ID3DXConstantTableImpl_SetMatrixTransposeArray,
988     ID3DXConstantTableImpl_SetMatrixTransposePointerArray
989 };
990
991 static HRESULT parse_ctab_constant_type(const D3DXSHADER_TYPEINFO *type, ctab_constant *constant)
992 {
993     constant->desc.Class = type->Class;
994     constant->desc.Type = type->Type;
995     constant->desc.Rows = type->Rows;
996     constant->desc.Columns = type->Columns;
997     constant->desc.Elements = type->Elements;
998     constant->desc.StructMembers = type->StructMembers;
999
1000     TRACE("class = %d, type = %d, rows = %d, columns = %d, elements = %d, struct_members = %d\n",
1001           constant->desc.Class, constant->desc.Type, constant->desc.Elements,
1002           constant->desc.Rows, constant->desc.Columns, constant->desc.StructMembers);
1003
1004     if ((constant->desc.Class == D3DXPC_STRUCT) && constant->desc.StructMembers)
1005     {
1006         FIXME("Struct not supported yet\n");
1007         return E_NOTIMPL;
1008     }
1009
1010     return D3D_OK;
1011 }
1012
1013 HRESULT WINAPI D3DXGetShaderConstantTableEx(CONST DWORD* byte_code,
1014                                             DWORD flags,
1015                                             LPD3DXCONSTANTTABLE* constant_table)
1016 {
1017     ID3DXConstantTableImpl* object = NULL;
1018     HRESULT hr;
1019     LPCVOID data;
1020     UINT size;
1021     const D3DXSHADER_CONSTANTTABLE* ctab_header;
1022     D3DXSHADER_CONSTANTINFO* constant_info;
1023     DWORD i;
1024
1025     TRACE("(%p, %x, %p)\n", byte_code, flags, constant_table);
1026
1027     if (!byte_code || !constant_table)
1028         return D3DERR_INVALIDCALL;
1029
1030     hr = D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), &data, &size);
1031     if (hr != D3D_OK)
1032         return D3DXERR_INVALIDDATA;
1033
1034     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID3DXConstantTableImpl));
1035     if (!object)
1036     {
1037         ERR("Out of memory\n");
1038         return E_OUTOFMEMORY;
1039     }
1040
1041     object->lpVtbl = &ID3DXConstantTable_Vtbl;
1042     object->ref = 1;
1043
1044     if (size < sizeof(D3DXSHADER_CONSTANTTABLE))
1045     {
1046         hr = D3DXERR_INVALIDDATA;
1047         goto error;
1048     }
1049
1050     object->ctab = HeapAlloc(GetProcessHeap(), 0, size);
1051     if (!object->ctab)
1052     {
1053         ERR("Out of memory\n");
1054         hr = E_OUTOFMEMORY;
1055         goto error;
1056     }
1057     object->size = size;
1058     memcpy(object->ctab, data, object->size);
1059
1060     ctab_header = (const D3DXSHADER_CONSTANTTABLE*)data;
1061     if (ctab_header->Size != sizeof(D3DXSHADER_CONSTANTTABLE))
1062     {
1063         hr = D3DXERR_INVALIDDATA;
1064         goto error;
1065     }
1066     object->desc.Creator = ctab_header->Creator ? object->ctab + ctab_header->Creator : NULL;
1067     object->desc.Version = ctab_header->Version;
1068     object->desc.Constants = ctab_header->Constants;
1069     if (object->desc.Creator)
1070         TRACE("Creator = %s\n", object->desc.Creator);
1071     TRACE("Version = %x\n", object->desc.Version);
1072     TRACE("Constants = %d\n", ctab_header->Constants);
1073     if (ctab_header->Target)
1074         TRACE("Target = %s\n", object->ctab + ctab_header->Target);
1075
1076     if (object->desc.Constants > 65535)
1077     {
1078         FIXME("Too many constants (%u)\n", object->desc.Constants);
1079         hr = E_NOTIMPL;
1080         goto error;
1081     }
1082
1083     object->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1084                                   sizeof(*object->constants) * object->desc.Constants);
1085     if (!object->constants)
1086     {
1087          ERR("Out of memory\n");
1088          hr = E_OUTOFMEMORY;
1089          goto error;
1090     }
1091
1092     constant_info = (LPD3DXSHADER_CONSTANTINFO)(object->ctab + ctab_header->ConstantInfo);
1093     for (i = 0; i < ctab_header->Constants; i++)
1094     {
1095         TRACE("name = %s\n", object->ctab + constant_info[i].Name);
1096         object->constants[i].desc.Name = object->ctab + constant_info[i].Name;
1097         object->constants[i].desc.RegisterSet = constant_info[i].RegisterSet;
1098         object->constants[i].desc.RegisterIndex = constant_info[i].RegisterIndex;
1099         object->constants[i].desc.RegisterCount = constant_info[i].RegisterCount;
1100         object->constants[i].desc.DefaultValue = object->ctab + constant_info[i].DefaultValue;
1101
1102         hr = parse_ctab_constant_type((LPD3DXSHADER_TYPEINFO)(object->ctab + constant_info[i].TypeInfo),
1103              &object->constants[i]);
1104         if (hr != D3D_OK)
1105             goto error;
1106
1107         if (constant_info[i].RegisterSet != D3DXRS_FLOAT4)
1108             FIXME("Don't know how to calculate Bytes for non D3DXRS_FLOAT4 constants\n");
1109
1110         /* D3DXRS_FLOAT4 has a base size of 4 (not taking into account dimensions and element count) */
1111         object->constants[i].desc.Bytes = 4;
1112
1113         /* Take into account dimensions and elements */
1114         object->constants[i].desc.Bytes *= object->constants[i].desc.Elements;
1115         object->constants[i].desc.Bytes *= object->constants[i].desc.Rows *
1116                 object->constants[i].desc.Columns;
1117     }
1118
1119     *constant_table = (LPD3DXCONSTANTTABLE)object;
1120
1121     return D3D_OK;
1122
1123 error:
1124
1125     HeapFree(GetProcessHeap(), 0, object->constants);
1126     HeapFree(GetProcessHeap(), 0, object->ctab);
1127     HeapFree(GetProcessHeap(), 0, object);
1128
1129     return hr;
1130 }
1131
1132 HRESULT WINAPI D3DXGetShaderConstantTable(CONST DWORD* byte_code,
1133                                           LPD3DXCONSTANTTABLE* constant_table)
1134 {
1135     TRACE("(%p, %p): Forwarded to D3DXGetShaderConstantTableEx\n", byte_code, constant_table);
1136
1137     return D3DXGetShaderConstantTableEx(byte_code, 0, constant_table);
1138 }