1 /*
2  * Copyright (C) 2008 Stefan Dösinger
3  * Copyright (C) 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 #define COBJMACROS
20 #define CONST_VTABLE
21 #include "wine/test.h"
22 
23 #include <d3dx9.h>
24 
25 #include "resources.h"
26 
27 static char temp_path[MAX_PATH];
28 
29 static BOOL create_file(const char *filename, const char *data, const unsigned int size, char *out_path)
30 {
31     DWORD written;
32     HANDLE hfile;
33     char path[MAX_PATH];
34 
35     if (!*temp_path)
36         GetTempPathA(sizeof(temp_path), temp_path);
37 
38     strcpy(path, temp_path);
39     strcat(path, filename);
40     hfile = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
41     if (hfile == INVALID_HANDLE_VALUE)
42         return FALSE;
43 
44     if (WriteFile(hfile, data, size, &written, NULL))
45     {
46         CloseHandle(hfile);
47 
48         if (out_path)
49             strcpy(out_path, path);
50         return TRUE;
51     }
52 
53     CloseHandle(hfile);
54     return FALSE;
55 }
56 
57 static void delete_file(const char *filename)
58 {
59     char path[MAX_PATH];
60 
61     strcpy(path, temp_path);
62     strcat(path, filename);
63     DeleteFileA(path);
64 }
65 
66 static BOOL create_directory(const char *name)
67 {
68     char path[MAX_PATH];
69 
70     strcpy(path, temp_path);
71     strcat(path, name);
72     return CreateDirectoryA(path, NULL);
73 }
74 
75 static void delete_directory(const char *name)
76 {
77     char path[MAX_PATH];
78 
79     strcpy(path, temp_path);
80     strcat(path, name);
81     RemoveDirectoryA(path);
82 }
83 
84 static HRESULT WINAPI testD3DXInclude_open(ID3DXInclude *iface, D3DXINCLUDE_TYPE include_type,
85         const char *filename, const void *parent_data, const void **data, UINT *bytes)
86 {
87     char *buffer;
88     static const char shader[] =
89             "#include \"incl.vsh\"\n"
90             "mov REGISTER, v0\n";
91     static const char include[] = "#define REGISTER r0\nvs.1.1\n";
92     static const char include2[] = "#include \"incl3.vsh\"\n";
93     static const char include3[] = "vs.1.1\n";
94 
95     trace("filename %s.\n", filename);
96     trace("parent_data %p: %s.\n", parent_data, parent_data ? (char *)parent_data : "(null)");
97 
98     if (!strcmp(filename, "shader.vsh"))
99     {
100         buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(shader));
101         memcpy(buffer, shader, sizeof(shader));
102         *bytes = sizeof(shader);
103     }
104     else if (!strcmp(filename, "incl.vsh"))
105     {
106         buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(include));
107         memcpy(buffer, include, sizeof(include));
108         *bytes = sizeof(include);
109         /* This is included from the first D3DXAssembleShader with non-null ID3DXInclude test
110          * (parent_data == NULL) and from shader.vsh / shader[] (with matching parent_data).
111          * Allow both cases. */
112         ok(parent_data == NULL || !strncmp(shader, parent_data, strlen(shader)), "wrong parent_data value\n");
113     }
114     else if (!strcmp(filename, "incl2.vsh"))
115     {
116         buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(include2));
117         memcpy(buffer, include2, sizeof(include2));
118         *bytes = sizeof(include2);
119     }
120     else if (!strcmp(filename, "incl3.vsh"))
121     {
122         buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(include3));
123         memcpy(buffer, include3, sizeof(include3));
124         *bytes = sizeof(include3);
125         /* Also check for the correct parent_data content */
126         ok(parent_data != NULL && !strncmp(include2, parent_data, strlen(include2)), "wrong parent_data value\n");
127     }
128     else if (!strcmp(filename, "include/incl3.vsh"))
129     {
130         buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(include));
131         memcpy(buffer, include, sizeof(include));
132         *bytes = sizeof(include);
133         ok(!parent_data, "wrong parent_data value\n");
134     }
135     else
136     {
137         ok(0, "Unexpected #include for file %s.\n", filename);
138         return D3DERR_INVALIDCALL;
139     }
140     *data = buffer;
141     return S_OK;
142 }
143 
144 static HRESULT WINAPI testD3DXInclude_close(ID3DXInclude *iface, const void *data)
145 {
146     HeapFree(GetProcessHeap(), 0, (void *)data);
147     return S_OK;
148 }
149 
150 static const struct ID3DXIncludeVtbl D3DXInclude_Vtbl = {
151     testD3DXInclude_open,
152     testD3DXInclude_close
153 };
154 
155 struct D3DXIncludeImpl {
156     ID3DXInclude ID3DXInclude_iface;
157 };
158 
159 static void assembleshader_test(void)
160 {
161     static const char test1[] =
162         "vs.1.1\n"
163         "mov DEF2, v0\n";
164     static const char testincl[] =
165         "#define REGISTER r0\n"
166         "vs.1.1\n";
167     static const char testshader[] =
168         "#include \"incl.vsh\"\n"
169         "mov REGISTER, v0\n";
170     static const char testshader2[] =
171         "#include \"incl2.vsh\"\n"
172         "mov REGISTER, v0\n";
173     static const char testshader3[] =
174         "#include \"include/incl3.vsh\"\n"
175         "mov REGISTER, v0\n";
176     static const char testincl3[] =
177         "#include \"incl4.vsh\"\n";
178     static const char testincl4_ok[] =
179         "#define REGISTER r0\n"
180         "vs.1.1\n";
181     static const char testincl4_wrong[] =
182         "#error \"wrong include\"\n";
183     HRESULT hr;
184     ID3DXBuffer *shader, *messages;
185     static const D3DXMACRO defines[] = {
186         {
187             "DEF1", "10 + 15"
188         },
189         {
190             "DEF2", "r0"
191         },
192         {
193             NULL, NULL
194         }
195     };
196     struct D3DXIncludeImpl include;
197     char shader_vsh_path[MAX_PATH], shader3_vsh_path[MAX_PATH];
198     static const WCHAR shader_filename_w[] = {'s','h','a','d','e','r','.','v','s','h',0};
199 
200     /* pDefines test */
201     shader = NULL;
202     messages = NULL;
203     hr = D3DXAssembleShader(test1, strlen(test1),
204                             defines, NULL, D3DXSHADER_SKIPVALIDATION,
205                             &shader, &messages);
206     ok(hr == D3D_OK, "pDefines test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
207     if(messages) {
208         trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
209         ID3DXBuffer_Release(messages);
210     }
211     if(shader) ID3DXBuffer_Release(shader);
212 
213     /* NULL messages test */
214     shader = NULL;
215     hr = D3DXAssembleShader(test1, strlen(test1),
216                             defines, NULL, D3DXSHADER_SKIPVALIDATION,
217                             &shader, NULL);
218     ok(hr == D3D_OK, "NULL messages test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
219     if(shader) ID3DXBuffer_Release(shader);
220 
221     /* NULL shader test */
222     messages = NULL;
223     hr = D3DXAssembleShader(test1, strlen(test1),
224                             defines, NULL, D3DXSHADER_SKIPVALIDATION,
225                             NULL, &messages);
226     ok(hr == D3D_OK, "NULL shader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
227     if(messages) {
228         trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
229         ID3DXBuffer_Release(messages);
230     }
231 
232     /* pInclude test */
233     shader = NULL;
234     messages = NULL;
235     include.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
236     hr = D3DXAssembleShader(testshader, strlen(testshader), NULL, &include.ID3DXInclude_iface,
237                             D3DXSHADER_SKIPVALIDATION, &shader, &messages);
238     ok(hr == D3D_OK, "pInclude test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
239     if(messages) {
240         trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
241         ID3DXBuffer_Release(messages);
242     }
243     if(shader) ID3DXBuffer_Release(shader);
244 
245     /* "unexpected #include file from memory" test */
246     shader = NULL;
247     messages = NULL;
248     hr = D3DXAssembleShader(testshader, strlen(testshader),
249                             NULL, NULL, D3DXSHADER_SKIPVALIDATION,
250                             &shader, &messages);
251     ok(hr == D3DXERR_INVALIDDATA, "D3DXAssembleShader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
252     if(messages) {
253         trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
254         ID3DXBuffer_Release(messages);
255     }
256     if(shader) ID3DXBuffer_Release(shader);
257 
258     /* recursive #include test */
259     shader = NULL;
260     messages = NULL;
261     hr = D3DXAssembleShader(testshader2, strlen(testshader2), NULL, &include.ID3DXInclude_iface,
262                             D3DXSHADER_SKIPVALIDATION, &shader, &messages);
263     ok(hr == D3D_OK, "D3DXAssembleShader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
264     if(messages) {
265         trace("recursive D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
266         ID3DXBuffer_Release(messages);
267     }
268     if(shader) ID3DXBuffer_Release(shader);
269 
270     /* #include with a path. */
271     shader = NULL;
272     messages = NULL;
273     hr = D3DXAssembleShader(testshader3, strlen(testshader3), NULL, &include.ID3DXInclude_iface,
274             D3DXSHADER_SKIPVALIDATION, &shader, &messages);
275     ok(hr == D3D_OK, "D3DXAssembleShader test failed with error 0x%x - %d\n", hr, hr & 0x0000ffff);
276     if (messages)
277     {
278         trace("Path search D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
279         ID3DXBuffer_Release(messages);
280     }
281     if (shader)
282         ID3DXBuffer_Release(shader);
283 
284     if (create_file("shader.vsh", testshader, sizeof(testshader) - 1, shader_vsh_path))
285     {
286         create_file("incl.vsh", testincl, sizeof(testincl) - 1, NULL);
287 
288         /* D3DXAssembleShaderFromFile + #include test */
289         shader = NULL;
290         messages = NULL;
291         hr = D3DXAssembleShaderFromFileA(shader_vsh_path,
292                                          NULL, NULL, D3DXSHADER_SKIPVALIDATION,
293                                          &shader, &messages);
294         ok(hr == D3D_OK, "D3DXAssembleShaderFromFile test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
295         if(messages) {
296             trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
297             ID3DXBuffer_Release(messages);
298         }
299         if(shader) ID3DXBuffer_Release(shader);
300 
301         /* D3DXAssembleShaderFromFile + pInclude test */
302         shader = NULL;
303         messages = NULL;
304         hr = D3DXAssembleShaderFromFileA("shader.vsh", NULL, &include.ID3DXInclude_iface,
305                                          D3DXSHADER_SKIPVALIDATION, &shader, &messages);
306         ok(hr == D3D_OK, "D3DXAssembleShaderFromFile + pInclude test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
307         if(messages) {
308             trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
309             ID3DXBuffer_Release(messages);
310         }
311         if(shader) ID3DXBuffer_Release(shader);
312 
313         create_file("shader3.vsh", testshader3, sizeof(testshader3) - 1, shader3_vsh_path);
314         create_file("incl4.vsh", testincl4_wrong, sizeof(testincl4_wrong) - 1, NULL);
315         if (create_directory("include"))
316         {
317             create_file("include\\incl3.vsh", testincl3, sizeof(testincl3) - 1, NULL);
318             create_file("include\\incl4.vsh", testincl4_ok, sizeof(testincl4_ok) - 1, NULL);
319 
320             /* path search #include test */
321             shader = NULL;
322             messages = NULL;
323             hr = D3DXAssembleShaderFromFileA(shader3_vsh_path, NULL, NULL,
324                                              D3DXSHADER_SKIPVALIDATION,
325                                              &shader, &messages);
326             ok(hr == D3D_OK, "D3DXAssembleShaderFromFile path search test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
327             if(messages) {
328                 trace("D3DXAssembleShaderFromFile path search messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
329                 ID3DXBuffer_Release(messages);
330             }
331             if(shader) ID3DXBuffer_Release(shader);
332         } else skip("Couldn't create \"include\" directory\n");
333 
334         delete_file("shader.vsh");
335         delete_file("incl.vsh");
336         delete_file("shader3.vsh");
337         delete_file("incl4.vsh");
338         delete_file("include\\incl3.vsh");
339         delete_file("include\\incl4.vsh");
340         delete_directory("include");
341 
342         /* The main shader is also to be loaded through the ID3DXInclude object. */
343         shader = NULL;
344         messages = NULL;
345         hr = D3DXAssembleShaderFromFileA("shader.vsh", NULL, &include.ID3DXInclude_iface,
346                 D3DXSHADER_SKIPVALIDATION, &shader, &messages);
347         ok(hr == D3D_OK, "D3DXAssembleShaderFromFile + pInclude main shader test failed with error 0x%x - %d\n",
348                 hr, hr & 0x0000ffff);
349         if (messages)
350         {
351             trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
352             ID3DXBuffer_Release(messages);
353         }
354         if (shader)
355             ID3DXBuffer_Release(shader);
356 
357         shader = NULL;
358         messages = NULL;
359         hr = D3DXAssembleShaderFromFileW(shader_filename_w, NULL, &include.ID3DXInclude_iface,
360                 D3DXSHADER_SKIPVALIDATION, &shader, &messages);
361         ok(hr == D3D_OK, "D3DXAssembleShaderFromFile + pInclude main shader test failed with error 0x%x - %d\n",
362                 hr, hr & 0x0000ffff);
363         if (messages)
364         {
365             trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
366             ID3DXBuffer_Release(messages);
367         }
368         if (shader)
369             ID3DXBuffer_Release(shader);
370     } else skip("Couldn't create \"shader.vsh\"\n");
371 
372     /* NULL shader tests */
373     shader = NULL;
374     messages = NULL;
375     hr = D3DXAssembleShader(NULL, 0,
376                             NULL, NULL, D3DXSHADER_SKIPVALIDATION,
377                             &shader, &messages);
378     ok(hr == D3DXERR_INVALIDDATA, "NULL shader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
379     if(messages) {
380         trace("D3DXAssembleShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
381         ID3DXBuffer_Release(messages);
382     }
383     if(shader) ID3DXBuffer_Release(shader);
384 
385     shader = NULL;
386     messages = NULL;
387     hr = D3DXAssembleShaderFromFileA("nonexistent.vsh",
388                                      NULL, NULL, D3DXSHADER_SKIPVALIDATION,
389                                      &shader, &messages);
390     ok(hr == D3DXERR_INVALIDDATA || hr == E_FAIL, /* I get this on WinXP */
391         "D3DXAssembleShaderFromFile nonexistent file test failed with error 0x%x - %d\n",
392         hr, hr & 0x0000FFFF);
393     if(messages) {
394         trace("D3DXAssembleShaderFromFile messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
395         ID3DXBuffer_Release(messages);
396     }
397     if(shader) ID3DXBuffer_Release(shader);
398 
399     /* D3DXAssembleShaderFromResource test */
400     shader = NULL;
401     messages = NULL;
402     hr = D3DXAssembleShaderFromResourceA(NULL, MAKEINTRESOURCEA(IDB_ASMSHADER),
403                                          NULL, NULL, D3DXSHADER_SKIPVALIDATION,
404                                          &shader, &messages);
405     ok(hr == D3D_OK, "D3DXAssembleShaderFromResource test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
406     if(messages) {
407         trace("D3DXAssembleShaderFromResource messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
408         ID3DXBuffer_Release(messages);
409     }
410     if(shader) ID3DXBuffer_Release(shader);
411 
412     /* D3DXAssembleShaderFromResource with missing shader resource test */
413     shader = NULL;
414     messages = NULL;
415     hr = D3DXAssembleShaderFromResourceA(NULL, "notexisting",
416                                          NULL, NULL, D3DXSHADER_SKIPVALIDATION,
417                                          &shader, &messages);
418     ok(hr == D3DXERR_INVALIDDATA, "D3DXAssembleShaderFromResource NULL shader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
419     if(messages) {
420         trace("D3DXAssembleShaderFromResource messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
421         ID3DXBuffer_Release(messages);
422     }
423     if(shader) ID3DXBuffer_Release(shader);
424 }
425 
426 static void d3dxpreprocess_test(void)
427 {
428     static const char testincl[] =
429             "#define REGISTER r0\n"
430             "vs.1.1\n";
431     static const char testshader[] =
432             "#include \"incl.vsh\"\n"
433             "mov REGISTER, v0\n";
434     static const char testshader3[] =
435             "#include \"include/incl3.vsh\"\n"
436             "mov REGISTER, v0\n";
437     static const char testincl3[] =
438             "#include \"incl4.vsh\"\n";
439     static const char testincl4_ok[] =
440             "#define REGISTER r0\n"
441             "vs.1.1\n";
442     static const char testincl4_wrong[] =
443             "#error \"wrong include\"\n";
444     HRESULT hr;
445     ID3DXBuffer *shader, *messages;
446     char shader_vsh_path[MAX_PATH], shader3_vsh_path[MAX_PATH];
447     static struct D3DXIncludeImpl include = {{&D3DXInclude_Vtbl}};
448     static const WCHAR shader_filename_w[] = {'s','h','a','d','e','r','.','v','s','h',0};
449 
450     if (create_file("shader.vsh", testshader, sizeof(testshader) - 1, shader_vsh_path))
451     {
452         create_file("incl.vsh", testincl, sizeof(testincl) - 1, NULL);
453         create_file("shader3.vsh", testshader3, sizeof(testshader3) - 1, shader3_vsh_path);
454         create_file("incl4.vsh", testincl4_wrong, sizeof(testincl4_wrong) - 1, NULL);
455         if (create_directory("include"))
456         {
457             create_file("include\\incl3.vsh", testincl3, sizeof(testincl3) - 1, NULL);
458             create_file("include\\incl4.vsh", testincl4_ok, sizeof(testincl4_ok) - 1, NULL);
459 
460             /* path search #include test */
461             shader = NULL;
462             messages = NULL;
463             hr = D3DXPreprocessShaderFromFileA(shader3_vsh_path, NULL, NULL,
464                                                &shader, &messages);
465             ok(hr == D3D_OK, "D3DXPreprocessShaderFromFile path search test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
466             if(messages) {
467                 trace("D3DXPreprocessShaderFromFile path search messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
468                 ID3DXBuffer_Release(messages);
469             }
470             if(shader) ID3DXBuffer_Release(shader);
471         } else skip("Couldn't create \"include\" directory\n");
472 
473         /* D3DXPreprocessShaderFromFile + #include test */
474         shader = NULL;
475         messages = NULL;
476         hr = D3DXPreprocessShaderFromFileA(shader_vsh_path,
477                                            NULL, NULL,
478                                            &shader, &messages);
479         ok(hr == D3D_OK, "D3DXPreprocessShaderFromFile test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
480         if(messages) {
481             trace("D3DXPreprocessShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
482             ID3DXBuffer_Release(messages);
483         }
484         if(shader) ID3DXBuffer_Release(shader);
485 
486         /* D3DXPreprocessShaderFromFile + pInclude test */
487         shader = NULL;
488         messages = NULL;
489         hr = D3DXPreprocessShaderFromFileA("shader.vsh", NULL, &include.ID3DXInclude_iface,
490                                            &shader, &messages);
491         ok(hr == D3D_OK, "D3DXPreprocessShaderFromFile + pInclude test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
492         if(messages) {
493             trace("D3DXPreprocessShader messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
494             ID3DXBuffer_Release(messages);
495         }
496         if(shader) ID3DXBuffer_Release(shader);
497 
498         delete_file("shader.vsh");
499         delete_file("incl.vsh");
500         delete_file("shader3.vsh");
501         delete_file("incl4.vsh");
502         delete_file("include\\incl3.vsh");
503         delete_file("include\\incl4.vsh");
504         delete_directory("include");
505 
506         /* The main shader is also to be loaded through the ID3DXInclude object. */
507         shader = NULL;
508         messages = NULL;
509         hr = D3DXPreprocessShaderFromFileA("shader.vsh", NULL, &include.ID3DXInclude_iface,
510                 &shader, &messages);
511         ok(hr == D3D_OK, "D3DXPreprocessShaderFromFile + pInclude main shader test failed with error 0x%x - %d\n",
512                 hr, hr & 0x0000ffff);
513         if (messages)
514         {
515             trace("D3DXPreprocessShaderFromFile messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
516             ID3DXBuffer_Release(messages);
517         }
518         if (shader)
519             ID3DXBuffer_Release(shader);
520 
521         shader = NULL;
522         messages = NULL;
523         hr = D3DXPreprocessShaderFromFileW(shader_filename_w, NULL, &include.ID3DXInclude_iface,
524                 &shader, &messages);
525         ok(hr == D3D_OK, "D3DXPreprocessShaderFromFile + pInclude main shader test failed with error 0x%x - %d\n",
526                 hr, hr & 0x0000ffff);
527         if (messages)
528         {
529             trace("D3DXPreprocessShaderFromFile messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
530             ID3DXBuffer_Release(messages);
531         }
532         if (shader)
533             ID3DXBuffer_Release(shader);
534     } else skip("Couldn't create \"shader.vsh\"\n");
535 
536     /* NULL shader tests */
537     shader = NULL;
538     messages = NULL;
539     hr = D3DXPreprocessShaderFromFileA("nonexistent.vsh",
540                                        NULL, NULL,
541                                        &shader, &messages);
542     ok(hr == D3DXERR_INVALIDDATA || hr == E_FAIL, /* I get this on WinXP */
543         "D3DXPreprocessShaderFromFile nonexistent file test failed with error 0x%x - %d\n",
544         hr, hr & 0x0000FFFF);
545     if(messages) {
546         trace("D3DXPreprocessShaderFromFile messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
547         ID3DXBuffer_Release(messages);
548     }
549     if(shader) ID3DXBuffer_Release(shader);
550 
551     /* D3DXPreprocessShaderFromResource test */
552     shader = NULL;
553     messages = NULL;
554     hr = D3DXPreprocessShaderFromResourceA(NULL, MAKEINTRESOURCEA(IDB_ASMSHADER),
555                                            NULL, NULL,
556                                            &shader, &messages);
557     ok(hr == D3D_OK, "D3DXPreprocessShaderFromResource test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
558     if(messages) {
559         trace("D3DXPreprocessShaderFromResource messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
560         ID3DXBuffer_Release(messages);
561     }
562     if(shader) ID3DXBuffer_Release(shader);
563 
564     /* D3DXPreprocessShaderFromResource with missing shader resource test */
565     shader = NULL;
566     messages = NULL;
567     hr = D3DXPreprocessShaderFromResourceA(NULL, "notexisting",
568                                            NULL, NULL,
569                                            &shader, &messages);
570     ok(hr == D3DXERR_INVALIDDATA, "D3DXPreprocessShaderFromResource NULL shader test failed with error 0x%x - %d\n", hr, hr & 0x0000FFFF);
571     if(messages) {
572         trace("D3DXPreprocessShaderFromResource messages:\n%s", (char *)ID3DXBuffer_GetBufferPointer(messages));
573         ID3DXBuffer_Release(messages);
574     }
575     if(shader) ID3DXBuffer_Release(shader);
576 }
577 
578 START_TEST(asm)
579 {
580     assembleshader_test();
581 
582     d3dxpreprocess_test();
583 }
584