d3dx9: Implement D3DXAssembleShaderFromFile.
[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 "wine/wpp.h"
27 #include "d3dx9_36_private.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
30
31 LPCSTR WINAPI D3DXGetPixelShaderProfile(LPDIRECT3DDEVICE9 device)
32 {
33     D3DCAPS9 caps;
34
35     TRACE("device %p\n", device);
36
37     if (!device) return NULL;
38
39     IDirect3DDevice9_GetDeviceCaps(device,&caps);
40
41     switch (caps.PixelShaderVersion)
42     {
43     case D3DPS_VERSION(1, 1):
44         return "ps_1_1";
45
46     case D3DPS_VERSION(1, 2):
47         return "ps_1_2";
48
49     case D3DPS_VERSION(1, 3):
50         return "ps_1_3";
51
52     case D3DPS_VERSION(1, 4):
53         return "ps_1_4";
54
55     case D3DPS_VERSION(2, 0):
56         if ((caps.PS20Caps.NumTemps>=22)                          &&
57             (caps.PS20Caps.Caps&D3DPS20CAPS_ARBITRARYSWIZZLE)     &&
58             (caps.PS20Caps.Caps&D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
59             (caps.PS20Caps.Caps&D3DPS20CAPS_PREDICATION)          &&
60             (caps.PS20Caps.Caps&D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
61             (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
62         {
63             return "ps_2_a";
64         }
65         if ((caps.PS20Caps.NumTemps>=32)                          &&
66             (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
67         {
68             return "ps_2_b";
69         }
70         return "ps_2_0";
71
72     case D3DPS_VERSION(3, 0):
73         return "ps_3_0";
74     }
75
76     return NULL;
77 }
78
79 UINT WINAPI D3DXGetShaderSize(const DWORD *byte_code)
80 {
81     const DWORD *ptr = byte_code;
82
83     TRACE("byte_code %p\n", byte_code);
84
85     if (!ptr) return 0;
86
87     /* Look for the END token, skipping the VERSION token */
88     while (*++ptr != D3DSIO_END)
89     {
90         /* Skip comments */
91         if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
92         {
93             ptr += ((*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
94         }
95     }
96     ++ptr;
97
98     /* Return the shader size in bytes */
99     return (ptr - byte_code) * sizeof(*ptr);
100 }
101
102 DWORD WINAPI D3DXGetShaderVersion(const DWORD *byte_code)
103 {
104     TRACE("byte_code %p\n", byte_code);
105
106     return byte_code ? *byte_code : 0;
107 }
108
109 LPCSTR WINAPI D3DXGetVertexShaderProfile(LPDIRECT3DDEVICE9 device)
110 {
111     D3DCAPS9 caps;
112
113     TRACE("device %p\n", device);
114
115     if (!device) return NULL;
116
117     IDirect3DDevice9_GetDeviceCaps(device,&caps);
118
119     switch (caps.VertexShaderVersion)
120     {
121     case D3DVS_VERSION(1, 1):
122         return "vs_1_1";
123     case D3DVS_VERSION(2, 0):
124         if ((caps.VS20Caps.NumTemps>=13) &&
125             (caps.VS20Caps.DynamicFlowControlDepth==24) &&
126             (caps.VS20Caps.Caps&D3DPS20CAPS_PREDICATION))
127         {
128             return "vs_2_a";
129         }
130         return "vs_2_0";
131     case D3DVS_VERSION(3, 0):
132         return "vs_3_0";
133     }
134
135     return NULL;
136 }
137
138 HRESULT WINAPI D3DXFindShaderComment(CONST DWORD* byte_code, DWORD fourcc, LPCVOID* data, UINT* size)
139 {
140     CONST DWORD *ptr = byte_code;
141
142     TRACE("(%p, %x, %p, %p)\n", byte_code, fourcc, data, size);
143
144     if (!byte_code)
145         return D3DERR_INVALIDCALL;
146
147     while (*++ptr != D3DSIO_END)
148     {
149         /* Check if it is a comment */
150         if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
151         {
152             DWORD comment_size = (*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
153
154             /* Check if this is the comment we are looking for */
155             if (*(ptr + 1) == fourcc)
156             {
157                 UINT ctab_size = (comment_size - 1) * sizeof(DWORD);
158                 LPCVOID ctab_data = ptr + 2;
159                 if (size)
160                     *size = ctab_size;
161                 if (data)
162                     *data = ctab_data;
163                 TRACE("Returning comment data at %p with size %d\n", ctab_data, ctab_size);
164                 return D3D_OK;
165             }
166             ptr += comment_size;
167         }
168     }
169
170     return S_FALSE;
171 }
172
173 #define BUFFER_INITIAL_CAPACITY 256
174
175 struct mem_file_desc
176 {
177     const char *buffer;
178     unsigned int size;
179     unsigned int pos;
180 };
181
182 struct mem_file_desc current_shader;
183 LPD3DXINCLUDE current_include;
184
185 #define INCLUDES_INITIAL_CAPACITY 4
186
187 struct loaded_include
188 {
189     const char *name;
190     const char *data;
191 };
192
193 struct loaded_include *includes;
194 int includes_capacity, includes_size;
195 const char *parent_include;
196
197 char *wpp_output;
198 int wpp_output_capacity, wpp_output_size;
199
200 char *wpp_messages;
201 int wpp_messages_capacity, wpp_messages_size;
202
203 /* Mutex used to guarantee a single invocation
204    of the D3DXAssembleShader function (or its variants) at a time.
205    This is needed as wpp isn't thread-safe */
206 static CRITICAL_SECTION wpp_mutex;
207 static CRITICAL_SECTION_DEBUG wpp_mutex_debug =
208 {
209     0, 0, &wpp_mutex,
210     { &wpp_mutex_debug.ProcessLocksList,
211       &wpp_mutex_debug.ProcessLocksList },
212       0, 0, { (DWORD_PTR)(__FILE__ ": wpp_mutex") }
213 };
214 static CRITICAL_SECTION wpp_mutex = { &wpp_mutex_debug, -1, 0, 0, 0, 0 };
215
216 /* Preprocessor error reporting functions */
217 static void wpp_write_message(const char *fmt, va_list args)
218 {
219     char* newbuffer;
220     int rc, newsize;
221
222     if(wpp_messages_capacity == 0)
223     {
224         wpp_messages = HeapAlloc(GetProcessHeap(), 0, MESSAGEBUFFER_INITIAL_SIZE);
225         if(wpp_messages == NULL)
226         {
227             ERR("Error allocating memory for parser messages\n");
228             return;
229         }
230         wpp_messages_capacity = MESSAGEBUFFER_INITIAL_SIZE;
231     }
232
233     while(1)
234     {
235         rc = vsnprintf(wpp_messages + wpp_messages_size,
236                        wpp_messages_capacity - wpp_messages_size, fmt, args);
237
238         if (rc < 0 ||                                           /* C89 */
239             rc >= wpp_messages_capacity - wpp_messages_size) {  /* C99 */
240             /* Resize the buffer */
241             newsize = wpp_messages_capacity * 2;
242             newbuffer = HeapReAlloc(GetProcessHeap(), 0, wpp_messages, newsize);
243             if(newbuffer == NULL)
244             {
245                 ERR("Error reallocating memory for parser messages\n");
246                 return;
247             }
248             wpp_messages = newbuffer;
249             wpp_messages_capacity = newsize;
250         }
251         else
252         {
253             wpp_messages_size += rc;
254             return;
255         }
256     }
257 }
258
259 static void PRINTF_ATTR(1,2) wpp_write_message_var(const char *fmt, ...)
260 {
261     va_list args;
262
263     va_start(args, fmt);
264     wpp_write_message(fmt, args);
265     va_end(args);
266 }
267
268 static void wpp_error(const char *file, int line, int col, const char *near,
269                       const char *msg, va_list ap)
270 {
271     wpp_write_message_var("%s:%d:%d: %s: ", file ? file : "'main file'",
272                           line, col, "Error");
273     wpp_write_message(msg, ap);
274     wpp_write_message_var("\n");
275 }
276
277 static void wpp_warning(const char *file, int line, int col, const char *near,
278                         const char *msg, va_list ap)
279 {
280     wpp_write_message_var("%s:%d:%d: %s: ", file ? file : "'main file'",
281                           line, col, "Warning");
282     wpp_write_message(msg, ap);
283     wpp_write_message_var("\n");
284 }
285
286 static char *wpp_lookup_mem(const char *filename, const char *parent_name,
287                             char **include_path, int include_path_count)
288 {
289     /* Here we return always ok. We will maybe fail on the next wpp_open_mem */
290     char *path;
291     int i;
292
293     parent_include = NULL;
294     if(parent_name[0] != '\0')
295     {
296         for(i = 0; i < includes_size; i++)
297         {
298             if(!strcmp(parent_name, includes[i].name))
299             {
300                 parent_include = includes[i].data;
301                 break;
302             }
303         }
304         if(parent_include == NULL)
305         {
306             ERR("Parent include file missing\n");
307             return NULL;
308         }
309     }
310
311     path = malloc(strlen(filename) + 1);
312     if(path)
313         memcpy(path, filename, strlen(filename) + 1);
314     return path;
315 }
316
317 static void *wpp_open_mem(const char *filename, int type)
318 {
319     struct mem_file_desc *desc;
320     HRESULT hr;
321
322     if(filename[0] == '\0') /* "" means to load the initial shader */
323     {
324         current_shader.pos = 0;
325         return &current_shader;
326     }
327
328     if(current_include == NULL) return NULL;
329     desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*desc));
330     if(!desc)
331     {
332         ERR("Error allocating memory\n");
333         return NULL;
334     }
335     hr = ID3DXInclude_Open(current_include,
336                            type ? D3DXINC_SYSTEM : D3DXINC_LOCAL,
337                            filename, parent_include, (LPCVOID *)&desc->buffer,
338                            &desc->size);
339     if(FAILED(hr))
340     {
341         HeapFree(GetProcessHeap(), 0, desc);
342         return NULL;
343     }
344
345     if(includes_capacity == includes_size)
346     {
347         if(includes_capacity == 0)
348         {
349             includes = HeapAlloc(GetProcessHeap(), 0, INCLUDES_INITIAL_CAPACITY);
350             if(includes == NULL)
351             {
352                 ERR("Error allocating memory for the loaded includes structure\n");
353                 goto error;
354             }
355             includes_capacity = INCLUDES_INITIAL_CAPACITY;
356         }
357         else
358         {
359             int newcapacity = includes_capacity * 2;
360             struct loaded_include *newincludes =
361                 HeapReAlloc(GetProcessHeap(), 0, includes, newcapacity);
362             if(newincludes == NULL)
363             {
364                 ERR("Error reallocating memory for the loaded includes structure\n");
365                 goto error;
366             }
367             includes = newincludes;
368             includes_capacity = newcapacity;
369         }
370     }
371     includes[includes_size].name = filename;
372     includes[includes_size++].data = desc->buffer;
373
374     desc->pos = 0;
375     return desc;
376
377 error:
378     ID3DXInclude_Close(current_include, desc->buffer);
379     HeapFree(GetProcessHeap(), 0, desc);
380     return NULL;
381 }
382
383 static void wpp_close_mem(void *file)
384 {
385     struct mem_file_desc *desc = file;
386
387     if(desc != &current_shader)
388     {
389         if(current_include)
390             ID3DXInclude_Close(current_include, desc->buffer);
391         else
392             ERR("current_include == NULL, desc == %p, buffer = %s\n",
393                 desc, desc->buffer);
394
395         HeapFree(GetProcessHeap(), 0, desc);
396     }
397 }
398
399 static int wpp_read_mem(void *file, char *buffer, unsigned int len)
400 {
401     struct mem_file_desc *desc = file;
402
403     len = min(len, desc->size - desc->pos);
404     memcpy(buffer, desc->buffer + desc->pos, len);
405     desc->pos += len;
406     return len;
407 }
408
409 static void wpp_write_mem(const char *buffer, unsigned int len)
410 {
411     char *new_wpp_output;
412
413     if(wpp_output_capacity == 0)
414     {
415         wpp_output = HeapAlloc(GetProcessHeap(), 0, BUFFER_INITIAL_CAPACITY);
416         if(!wpp_output)
417         {
418             ERR("Error allocating memory\n");
419             return;
420         }
421         wpp_output_capacity = BUFFER_INITIAL_CAPACITY;
422     }
423     if(len > wpp_output_capacity - wpp_output_size)
424     {
425         while(len > wpp_output_capacity - wpp_output_size)
426         {
427             wpp_output_capacity *= 2;
428         }
429         new_wpp_output = HeapReAlloc(GetProcessHeap(), 0, wpp_output,
430                                      wpp_output_capacity);
431         if(!new_wpp_output)
432         {
433             ERR("Error allocating memory\n");
434             return;
435         }
436         wpp_output = new_wpp_output;
437     }
438     memcpy(wpp_output + wpp_output_size, buffer, len);
439     wpp_output_size += len;
440 }
441
442 static int wpp_close_output(void)
443 {
444     char *new_wpp_output = HeapReAlloc(GetProcessHeap(), 0, wpp_output,
445                                        wpp_output_size + 1);
446     if(!new_wpp_output) return 0;
447     wpp_output = new_wpp_output;
448     wpp_output[wpp_output_size]='\0';
449     return 1;
450 }
451
452 static HRESULT assemble_shader(const char *preprocShader, const char *preprocMessages,
453                         LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs)
454 {
455     struct bwriter_shader *shader;
456     char *messages = NULL;
457     HRESULT hr;
458     DWORD *res;
459     LPD3DXBUFFER buffer;
460     int size;
461     char *pos;
462
463     shader = SlAssembleShader(preprocShader, &messages);
464
465     if(messages || preprocMessages)
466     {
467         if(preprocMessages)
468         {
469             TRACE("Preprocessor messages:\n");
470             TRACE("%s", preprocMessages);
471         }
472         if(messages)
473         {
474             TRACE("Assembler messages:\n");
475             TRACE("%s", messages);
476         }
477
478         TRACE("Shader source:\n");
479         TRACE("%s\n", debugstr_a(preprocShader));
480
481         if(ppErrorMsgs)
482         {
483             size = (messages ? strlen(messages) : 0) +
484                 (preprocMessages ? strlen(preprocMessages) : 0) + 1;
485             hr = D3DXCreateBuffer(size, &buffer);
486             if(FAILED(hr))
487             {
488                 HeapFree(GetProcessHeap(), 0, messages);
489                 if(shader) SlDeleteShader(shader);
490                 return hr;
491             }
492             pos = ID3DXBuffer_GetBufferPointer(buffer);
493             if(preprocMessages)
494             {
495                 CopyMemory(pos, preprocMessages, strlen(preprocMessages) + 1);
496                 pos += strlen(preprocMessages);
497             }
498             if(messages)
499                 CopyMemory(pos, messages, strlen(messages) + 1);
500
501             *ppErrorMsgs = buffer;
502         }
503
504         HeapFree(GetProcessHeap(), 0, messages);
505     }
506
507     if(shader == NULL)
508     {
509         ERR("Asm reading failed\n");
510         return D3DXERR_INVALIDDATA;
511     }
512
513     hr = SlWriteBytecode(shader, 9, &res);
514     SlDeleteShader(shader);
515     if(FAILED(hr))
516     {
517         ERR("SlWriteBytecode failed with 0x%08x\n", hr);
518         return D3DXERR_INVALIDDATA;
519     }
520
521     if(ppShader)
522     {
523         size = HeapSize(GetProcessHeap(), 0, res);
524         hr = D3DXCreateBuffer(size, &buffer);
525         if(FAILED(hr))
526         {
527             HeapFree(GetProcessHeap(), 0, res);
528             return hr;
529         }
530         CopyMemory(ID3DXBuffer_GetBufferPointer(buffer), res, size);
531         *ppShader = buffer;
532     }
533
534     HeapFree(GetProcessHeap(), 0, res);
535
536     return D3D_OK;
537 }
538
539 HRESULT WINAPI D3DXAssembleShader(LPCSTR data,
540                                   UINT data_len,
541                                   CONST D3DXMACRO* defines,
542                                   LPD3DXINCLUDE include,
543                                   DWORD flags,
544                                   LPD3DXBUFFER* shader,
545                                   LPD3DXBUFFER* error_messages)
546 {
547     int ret;
548     HRESULT hr;
549     CONST D3DXMACRO* def = defines;
550
551     static const struct wpp_callbacks wpp_callbacks = {
552         wpp_lookup_mem,
553         wpp_open_mem,
554         wpp_close_mem,
555         wpp_read_mem,
556         wpp_write_mem,
557         wpp_error,
558         wpp_warning,
559     };
560
561     EnterCriticalSection(&wpp_mutex);
562
563     /* TODO: flags */
564     if(flags) FIXME("flags: %x\n", flags);
565
566     if(def != NULL)
567     {
568         while(def->Name != NULL)
569         {
570             wpp_add_define(def->Name, def->Definition);
571             def++;
572         }
573     }
574     current_include = include;
575     includes_size = 0;
576
577     if(shader) *shader = NULL;
578     if(error_messages) *error_messages = NULL;
579     wpp_output_size = wpp_output_capacity = 0;
580     wpp_output = NULL;
581
582     /* Preprocess shader */
583     wpp_set_callbacks(&wpp_callbacks);
584     wpp_messages_size = wpp_messages_capacity = 0;
585     wpp_messages = NULL;
586     current_shader.buffer = data;
587     current_shader.size = data_len;
588
589     ret = wpp_parse("", NULL);
590     if(!wpp_close_output())
591         ret = 1;
592     if(ret)
593     {
594         TRACE("Error during shader preprocessing\n");
595         if(wpp_messages)
596         {
597             int size;
598             LPD3DXBUFFER buffer;
599
600             TRACE("Preprocessor messages:\n");
601             TRACE("%s", wpp_messages);
602
603             if(error_messages)
604             {
605                 size = strlen(wpp_messages) + 1;
606                 hr = D3DXCreateBuffer(size, &buffer);
607                 if(FAILED(hr)) goto cleanup;
608                 CopyMemory(ID3DXBuffer_GetBufferPointer(buffer), wpp_messages, size);
609                 *error_messages = buffer;
610             }
611         }
612         if(data)
613         {
614             TRACE("Shader source:\n");
615             TRACE("%s\n", debugstr_an(data, data_len));
616         }
617         hr = D3DXERR_INVALIDDATA;
618         goto cleanup;
619     }
620
621     hr = assemble_shader(wpp_output, wpp_messages, shader, error_messages);
622
623 cleanup:
624     /* Remove the previously added defines */
625     if(defines != NULL)
626     {
627         while(defines->Name != NULL)
628         {
629             wpp_del_define(defines->Name);
630             defines++;
631         }
632     }
633     HeapFree(GetProcessHeap(), 0, wpp_messages);
634     HeapFree(GetProcessHeap(), 0, wpp_output);
635     LeaveCriticalSection(&wpp_mutex);
636     return hr;
637 }
638
639 /* D3DXInclude private implementation, used to implement
640    D3DXAssembleShaderFromFile from D3DXAssembleShader */
641 /* To be able to correctly resolve include search paths we have to store
642    the pathname of each include file. We store the pathname pointer right
643    before the file data. */
644 static HRESULT WINAPI d3dincludefromfile_open(ID3DXInclude *iface,
645                                               D3DXINCLUDE_TYPE include_type,
646                                               LPCSTR filename, LPCVOID parent_data,
647                                               LPCVOID *data, UINT *bytes) {
648     const char *p, *parent_name = "";
649     char *pathname = NULL;
650     char **buffer = NULL;
651     HANDLE file;
652     UINT size;
653
654     if(parent_data != NULL)
655         parent_name = *((const char **)parent_data - 1);
656
657     TRACE("Looking up for include file %s, parent %s\n", debugstr_a(filename), debugstr_a(parent_name));
658
659     if ((p = strrchr(parent_name, '\\')) || (p = strrchr(parent_name, '/'))) p++;
660     else p = parent_name;
661     pathname = HeapAlloc(GetProcessHeap(), 0, (p - parent_name) + strlen(filename) + 1);
662     if(!pathname)
663         return HRESULT_FROM_WIN32(GetLastError());
664
665     memcpy(pathname, parent_name, p - parent_name);
666     strcpy(pathname + (p - parent_name), filename);
667
668     file = CreateFileA(pathname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
669     if(file == INVALID_HANDLE_VALUE)
670         goto error;
671
672     TRACE("Include file found at pathname = %s\n", debugstr_a(pathname));
673
674     size = GetFileSize(file, NULL);
675     if(size == INVALID_FILE_SIZE)
676         goto error;
677
678     buffer = HeapAlloc(GetProcessHeap(), 0, size + sizeof(char *));
679     if(!buffer)
680         goto error;
681     *buffer = pathname;
682     if(!ReadFile(file, buffer + 1, size, bytes, NULL))
683         goto error;
684
685     *data = buffer + 1;
686
687     CloseHandle(file);
688     return S_OK;
689
690 error:
691     CloseHandle(file);
692     HeapFree(GetProcessHeap(), 0, pathname);
693     HeapFree(GetProcessHeap(), 0, buffer);
694     return HRESULT_FROM_WIN32(GetLastError());
695 }
696
697 static HRESULT WINAPI d3dincludefromfile_close(ID3DXInclude *iface, LPCVOID data) {
698     HeapFree(GetProcessHeap(), 0, *((char **)data - 1));
699     HeapFree(GetProcessHeap(), 0, (char **)data - 1);
700     return S_OK;
701 }
702
703 static const struct ID3DXIncludeVtbl D3DXInclude_Vtbl = {
704     d3dincludefromfile_open,
705     d3dincludefromfile_close
706 };
707
708 struct D3DXIncludeImpl {
709     const ID3DXIncludeVtbl *lpVtbl;
710 };
711
712 HRESULT WINAPI D3DXAssembleShaderFromFileA(LPCSTR filename,
713                                            CONST D3DXMACRO* defines,
714                                            LPD3DXINCLUDE include,
715                                            DWORD flags,
716                                            LPD3DXBUFFER* shader,
717                                            LPD3DXBUFFER* error_messages)
718 {
719     LPWSTR filename_w = NULL;
720     DWORD len;
721     HRESULT ret;
722
723     if (!filename) return D3DXERR_INVALIDDATA;
724
725     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
726     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
727     if (!filename_w) return E_OUTOFMEMORY;
728     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
729
730     ret = D3DXAssembleShaderFromFileW(filename_w, defines, include, flags, shader, error_messages);
731
732     HeapFree(GetProcessHeap(), 0, filename_w);
733     return ret;
734 }
735
736 HRESULT WINAPI D3DXAssembleShaderFromFileW(LPCWSTR filename,
737                                            CONST D3DXMACRO* defines,
738                                            LPD3DXINCLUDE include,
739                                            DWORD flags,
740                                            LPD3DXBUFFER* shader,
741                                            LPD3DXBUFFER* error_messages)
742 {
743     void *buffer;
744     DWORD len;
745     HRESULT hr;
746     struct D3DXIncludeImpl includefromfile;
747
748     if(FAILED(map_view_of_file(filename, &buffer, &len)))
749         return D3DXERR_INVALIDDATA;
750
751     if(!include)
752     {
753         includefromfile.lpVtbl = &D3DXInclude_Vtbl;
754         include = (LPD3DXINCLUDE)&includefromfile;
755     }
756
757     hr = D3DXAssembleShader(buffer, len, defines, include, flags,
758                             shader, error_messages);
759
760     UnmapViewOfFile(buffer);
761     return hr;
762 }
763
764 HRESULT WINAPI D3DXAssembleShaderFromResourceA(HMODULE module,
765                                                LPCSTR resource,
766                                                CONST D3DXMACRO* defines,
767                                                LPD3DXINCLUDE include,
768                                                DWORD flags,
769                                                LPD3DXBUFFER* shader,
770                                                LPD3DXBUFFER* error_messages)
771 {
772     HRSRC res;
773     LPCSTR buffer;
774     DWORD len;
775
776     if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
777         return D3DXERR_INVALIDDATA;
778     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
779         return D3DXERR_INVALIDDATA;
780     return D3DXAssembleShader(buffer, len, defines, include, flags,
781                               shader, error_messages);
782 }
783
784 HRESULT WINAPI D3DXAssembleShaderFromResourceW(HMODULE module,
785                                                LPCWSTR resource,
786                                                CONST D3DXMACRO* defines,
787                                                LPD3DXINCLUDE include,
788                                                DWORD flags,
789                                                LPD3DXBUFFER* shader,
790                                                LPD3DXBUFFER* error_messages)
791 {
792     HRSRC res;
793     LPCSTR buffer;
794     DWORD len;
795
796     if (!(res = FindResourceW(module, resource, (LPCWSTR)RT_RCDATA)))
797         return D3DXERR_INVALIDDATA;
798     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
799         return D3DXERR_INVALIDDATA;
800     return D3DXAssembleShader(buffer, len, defines, include, flags,
801                               shader, error_messages);
802 }
803
804 HRESULT WINAPI D3DXCompileShader(LPCSTR pSrcData,
805                                  UINT srcDataLen,
806                                  CONST D3DXMACRO* pDefines,
807                                  LPD3DXINCLUDE pInclude,
808                                  LPCSTR pFunctionName,
809                                  LPCSTR pProfile,
810                                  DWORD Flags,
811                                  LPD3DXBUFFER* ppShader,
812                                  LPD3DXBUFFER* ppErrorMsgs,
813                                  LPD3DXCONSTANTTABLE * ppConstantTable)
814 {
815     FIXME("(%p, %d, %p, %p, %s, %s, %x, %p, %p, %p): stub\n",
816           pSrcData, srcDataLen, pDefines, pInclude, debugstr_a(pFunctionName),
817           debugstr_a(pProfile), Flags, ppShader, ppErrorMsgs, ppConstantTable);
818
819     TRACE("Shader source:\n");
820     TRACE("%s\n", debugstr_an(pSrcData, srcDataLen));
821
822     if (ppErrorMsgs)
823         D3DXCreateBuffer(1, ppErrorMsgs); /* zero fill used as string end */
824     return D3DERR_INVALIDCALL;
825 }
826
827 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl;
828
829 typedef struct ID3DXConstantTableImpl {
830     const ID3DXConstantTableVtbl *lpVtbl;
831     LONG ref;
832     LPVOID ctab;
833     DWORD size;
834     D3DXCONSTANTTABLE_DESC desc;
835 } ID3DXConstantTableImpl;
836
837 /*** IUnknown methods ***/
838 static HRESULT WINAPI ID3DXConstantTableImpl_QueryInterface(ID3DXConstantTable* iface, REFIID riid, void** ppvObject)
839 {
840     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
841
842     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
843
844     if (IsEqualGUID(riid, &IID_IUnknown) ||
845         IsEqualGUID(riid, &IID_ID3DXBuffer) ||
846         IsEqualGUID(riid, &IID_ID3DXConstantTable))
847     {
848         ID3DXConstantTable_AddRef(iface);
849         *ppvObject = This;
850         return S_OK;
851     }
852
853     WARN("Interface %s not found.\n", debugstr_guid(riid));
854
855     return E_NOINTERFACE;
856 }
857
858 static ULONG WINAPI ID3DXConstantTableImpl_AddRef(ID3DXConstantTable* iface)
859 {
860     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
861
862     TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
863
864     return InterlockedIncrement(&This->ref);
865 }
866
867 static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable* iface)
868 {
869     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
870     ULONG ref = InterlockedDecrement(&This->ref);
871
872     TRACE("(%p)->(): Release from %d\n", This, ref + 1);
873
874     if (!ref)
875     {
876         HeapFree(GetProcessHeap(), 0, This->ctab);
877         HeapFree(GetProcessHeap(), 0, This);
878     }
879
880     return ref;
881 }
882
883 /*** ID3DXBuffer methods ***/
884 static LPVOID WINAPI ID3DXConstantTableImpl_GetBufferPointer(ID3DXConstantTable* iface)
885 {
886     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
887
888     TRACE("(%p)->()\n", This);
889
890     return This->ctab;
891 }
892
893 static DWORD WINAPI ID3DXConstantTableImpl_GetBufferSize(ID3DXConstantTable* iface)
894 {
895     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
896
897     TRACE("(%p)->()\n", This);
898
899     return This->size;
900 }
901
902 /*** ID3DXConstantTable methods ***/
903 static HRESULT WINAPI ID3DXConstantTableImpl_GetDesc(ID3DXConstantTable* iface, D3DXCONSTANTTABLE_DESC *desc)
904 {
905     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
906
907     TRACE("(%p)->(%p)\n", This, desc);
908
909     if (!desc)
910         return D3DERR_INVALIDCALL;
911
912     memcpy(desc, &This->desc, sizeof(This->desc));
913
914     return D3D_OK;
915 }
916
917 static HRESULT WINAPI ID3DXConstantTableImpl_GetConstantDesc(ID3DXConstantTable* iface, D3DXHANDLE constant,
918                                                              D3DXCONSTANT_DESC *desc, UINT *count)
919 {
920     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
921
922     FIXME("(%p)->(%p, %p, %p): stub\n", This, constant, desc, count);
923
924     return E_NOTIMPL;
925 }
926
927 static UINT WINAPI ID3DXConstantTableImpl_GetSamplerIndex(LPD3DXCONSTANTTABLE iface, D3DXHANDLE constant)
928 {
929     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
930
931     FIXME("(%p)->(%p): stub\n", This, constant);
932
933     return (UINT)-1;
934 }
935
936 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstant(ID3DXConstantTable* iface, D3DXHANDLE constant, UINT index)
937 {
938     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
939
940     FIXME("(%p)->(%p, %d): stub\n", This, constant, index);
941
942     return NULL;
943 }
944
945 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable* iface, D3DXHANDLE constant, LPCSTR name)
946 {
947     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
948
949     FIXME("(%p)->(%p, %s): stub\n", This, constant, name);
950
951     return NULL;
952 }
953
954 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantElement(ID3DXConstantTable* iface, D3DXHANDLE constant, UINT index)
955 {
956     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
957
958     FIXME("(%p)->(%p, %d): stub\n", This, constant, index);
959
960     return NULL;
961 }
962
963 static HRESULT WINAPI ID3DXConstantTableImpl_SetDefaults(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device)
964 {
965     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
966
967     FIXME("(%p)->(%p): stub\n", This, device);
968
969     return E_NOTIMPL;
970 }
971
972 static HRESULT WINAPI ID3DXConstantTableImpl_SetValue(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
973                                                       D3DXHANDLE constant, LPCVOID data, UINT bytes)
974 {
975     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
976
977     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, data, bytes);
978
979     return E_NOTIMPL;
980 }
981
982 static HRESULT WINAPI ID3DXConstantTableImpl_SetBool(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
983                                                      D3DXHANDLE constant, BOOL b)
984 {
985     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
986
987     FIXME("(%p)->(%p, %p, %d): stub\n", This, device, constant, b);
988
989     return E_NOTIMPL;
990 }
991
992 static HRESULT WINAPI ID3DXConstantTableImpl_SetBoolArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
993                                                           D3DXHANDLE constant, CONST BOOL* b, UINT count)
994 {
995     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
996
997     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, b, count);
998
999     return E_NOTIMPL;
1000 }
1001
1002 static HRESULT WINAPI ID3DXConstantTableImpl_SetInt(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device, D3DXHANDLE constant, INT n)
1003 {
1004     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1005
1006     FIXME("(%p)->(%p, %p, %d): stub\n", This, device, constant, n);
1007
1008     return E_NOTIMPL;
1009 }
1010
1011 static HRESULT WINAPI ID3DXConstantTableImpl_SetIntArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1012                                                          D3DXHANDLE constant, CONST INT* n, UINT count)
1013 {
1014     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1015
1016     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, n, count);
1017
1018     return E_NOTIMPL;
1019 }
1020
1021 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloat(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1022                                                       D3DXHANDLE constant, FLOAT f)
1023 {
1024     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1025
1026     FIXME("(%p)->(%p, %p, %f): stub\n", This, device, constant, f);
1027
1028     return E_NOTIMPL;
1029 }
1030
1031 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloatArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1032                                                            D3DXHANDLE constant, CONST FLOAT* f, UINT count)
1033 {
1034     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1035
1036     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, f, count);
1037
1038     return E_NOTIMPL;
1039 }
1040
1041 static HRESULT WINAPI ID3DXConstantTableImpl_SetVector(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1042                                                        D3DXHANDLE constant, CONST D3DXVECTOR4* vector)
1043 {
1044     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1045
1046     FIXME("(%p)->(%p, %p, %p): stub\n", This, device, constant, vector);
1047
1048     return E_NOTIMPL;
1049 }
1050
1051 static HRESULT WINAPI ID3DXConstantTableImpl_SetVectorArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1052                                                             D3DXHANDLE constant, CONST D3DXVECTOR4* vector, UINT count)
1053 {
1054     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1055
1056     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, vector, count);
1057
1058     return E_NOTIMPL;
1059 }
1060
1061 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrix(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1062                                                        D3DXHANDLE constant, CONST D3DXMATRIX* matrix)
1063 {
1064     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1065
1066     FIXME("(%p)->(%p, %p, %p): stub\n", This, device, constant, matrix);
1067
1068     return E_NOTIMPL;
1069 }
1070
1071 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1072                                                             D3DXHANDLE constant, CONST D3DXMATRIX* matrix, UINT count)
1073 {
1074     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1075
1076     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
1077
1078     return E_NOTIMPL;
1079 }
1080
1081 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixPointerArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1082                                                                    D3DXHANDLE constant, CONST D3DXMATRIX** matrix, UINT count)
1083 {
1084     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1085
1086     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
1087
1088     return E_NOTIMPL;
1089 }
1090
1091 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTranspose(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1092                                                                 D3DXHANDLE constant, CONST D3DXMATRIX* matrix)
1093 {
1094     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1095
1096     FIXME("(%p)->(%p, %p, %p): stub\n", This, device, constant, matrix);
1097
1098     return E_NOTIMPL;
1099 }
1100
1101 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposeArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1102                                                                      D3DXHANDLE constant, CONST D3DXMATRIX* matrix, UINT count)
1103 {
1104     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1105
1106     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
1107
1108     return E_NOTIMPL;
1109 }
1110
1111 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposePointerArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1112                                                                             D3DXHANDLE constant, CONST D3DXMATRIX** matrix, UINT count)
1113 {
1114     ID3DXConstantTableImpl *This = (ID3DXConstantTableImpl *)iface;
1115
1116     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
1117
1118     return E_NOTIMPL;
1119 }
1120
1121 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl =
1122 {
1123     /*** IUnknown methods ***/
1124     ID3DXConstantTableImpl_QueryInterface,
1125     ID3DXConstantTableImpl_AddRef,
1126     ID3DXConstantTableImpl_Release,
1127     /*** ID3DXBuffer methods ***/
1128     ID3DXConstantTableImpl_GetBufferPointer,
1129     ID3DXConstantTableImpl_GetBufferSize,
1130     /*** ID3DXConstantTable methods ***/
1131     ID3DXConstantTableImpl_GetDesc,
1132     ID3DXConstantTableImpl_GetConstantDesc,
1133     ID3DXConstantTableImpl_GetSamplerIndex,
1134     ID3DXConstantTableImpl_GetConstant,
1135     ID3DXConstantTableImpl_GetConstantByName,
1136     ID3DXConstantTableImpl_GetConstantElement,
1137     ID3DXConstantTableImpl_SetDefaults,
1138     ID3DXConstantTableImpl_SetValue,
1139     ID3DXConstantTableImpl_SetBool,
1140     ID3DXConstantTableImpl_SetBoolArray,
1141     ID3DXConstantTableImpl_SetInt,
1142     ID3DXConstantTableImpl_SetIntArray,
1143     ID3DXConstantTableImpl_SetFloat,
1144     ID3DXConstantTableImpl_SetFloatArray,
1145     ID3DXConstantTableImpl_SetVector,
1146     ID3DXConstantTableImpl_SetVectorArray,
1147     ID3DXConstantTableImpl_SetMatrix,
1148     ID3DXConstantTableImpl_SetMatrixArray,
1149     ID3DXConstantTableImpl_SetMatrixPointerArray,
1150     ID3DXConstantTableImpl_SetMatrixTranspose,
1151     ID3DXConstantTableImpl_SetMatrixTransposeArray,
1152     ID3DXConstantTableImpl_SetMatrixTransposePointerArray
1153 };
1154
1155 HRESULT WINAPI D3DXGetShaderConstantTableEx(CONST DWORD* byte_code,
1156                                             DWORD flags,
1157                                             LPD3DXCONSTANTTABLE* constant_table)
1158 {
1159     ID3DXConstantTableImpl* object = NULL;
1160     HRESULT hr;
1161     LPCVOID data;
1162     UINT size;
1163     const D3DXSHADER_CONSTANTTABLE* ctab_header;
1164
1165     FIXME("(%p, %x, %p): semi-stub\n", byte_code, flags, constant_table);
1166
1167     if (!byte_code || !constant_table)
1168         return D3DERR_INVALIDCALL;
1169
1170     hr = D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), &data, &size);
1171     if (hr != D3D_OK)
1172         return D3DXERR_INVALIDDATA;
1173
1174     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID3DXConstantTableImpl));
1175     if (!object)
1176     {
1177         ERR("Out of memory\n");
1178         return E_OUTOFMEMORY;
1179     }
1180
1181     object->lpVtbl = &ID3DXConstantTable_Vtbl;
1182     object->ref = 1;
1183
1184     if (size < sizeof(D3DXSHADER_CONSTANTTABLE))
1185         goto error;
1186
1187     object->ctab = HeapAlloc(GetProcessHeap(), 0, size);
1188     if (!object->ctab)
1189     {
1190         HeapFree(GetProcessHeap(), 0, object);
1191         ERR("Out of memory\n");
1192         return E_OUTOFMEMORY;
1193     }
1194     object->size = size;
1195     memcpy(object->ctab, data, object->size);
1196
1197     ctab_header = (const D3DXSHADER_CONSTANTTABLE*)data;
1198     if (ctab_header->Size != sizeof(D3DXSHADER_CONSTANTTABLE))
1199         goto error;
1200     object->desc.Creator = ctab_header->Creator ? (LPCSTR)object->ctab + ctab_header->Creator : NULL;
1201     object->desc.Version = ctab_header->Version;
1202     object->desc.Constants = ctab_header->Constants;
1203
1204     *constant_table = (LPD3DXCONSTANTTABLE)object;
1205
1206     return D3D_OK;
1207
1208 error:
1209
1210     HeapFree(GetProcessHeap(), 0, object->ctab);
1211     HeapFree(GetProcessHeap(), 0, object);
1212
1213     return D3DXERR_INVALIDDATA;
1214 }
1215
1216 HRESULT WINAPI D3DXGetShaderConstantTable(CONST DWORD* byte_code,
1217                                           LPD3DXCONSTANTTABLE* constant_table)
1218 {
1219     TRACE("(%p, %p): Forwarded to D3DXGetShaderConstantTableEx\n", byte_code, constant_table);
1220
1221     return D3DXGetShaderConstantTableEx(byte_code, 0, constant_table);
1222 }