1 /*---------------------------------------------------------------------------*
2
3 Copyright 2010-2014 Nintendo. All rights reserved.
4
5 These coded instructions, statements, and computer programs contain
6 proprietary information of Nintendo of America Inc. and/or Nintendo
7 Company Ltd., and are protected by Federal copyright law. They may
8 not be disclosed to third parties or copied or duplicated in any form,
9 in whole or in part, without the prior written consent of Nintendo.
10
11 *---------------------------------------------------------------------------*/
12 // ------------------------------------------------------------------
13 // gshCompile.cpp
14 // ------------------------------------------------------------------
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <windows.h>
19 #include "gshCompile.h"
20
21 typedef DWORD64 uint64;
22
23 #define GSH_DUMP_FILENAME_SIZE 256
24 #define GSH_FULL_FILE_NAME_SIZE 512
25
26 static char vs_name_buffer[GSH_FULL_FILE_NAME_SIZE];
27 static char ps_name_buffer[GSH_FULL_FILE_NAME_SIZE];
28 static char gs_name_buffer[GSH_FULL_FILE_NAME_SIZE];
29 static char cs_name_buffer[GSH_FULL_FILE_NAME_SIZE];
30
31 //
32 // structure describing optimization flags
33 //
34 static struct oflagdefS {
35 const char *name;
36 const char *help;
37 uint64 flagbits;
38 } oflagdef[] = {
39 OFLAGDEF_CONTENTS
40 };
41
Help(char ** argv)42 static void Help(char** argv)
43 {
44 int i;
45 printf("\n");
46 printf("gshCompile\n");
47 printf("\n");
48 printf("Usage: gshCompile -v vs_file -p ps_file -g gs_file -o output_file -force_uniformblock\n");
49 printf(" gshCompile -c cs_file -o output_file -force_uniformblock\n");
50 printf(" gshCompile -version\n\n");
51 printf("-v : Vertex Shader file\n");
52 printf("-p : Pixel Shader file\n");
53 printf("-g : Geometry Shader file\n");
54 printf("-c : Compute Shader file\n");
55 printf("-so : Stream Out Varings file\n");
56 printf("-o : Output file name\n");
57 printf("-oa : Existing output file name to append shaders.\n");
58 printf("-oh : Output header file name to write shaders as code.\n");
59 printf("-force_uniformblock : Force uniform block usage\n");
60 printf("-no_limit_array_syms : Create symbols all elements of uniform arrays (not just the first 2 and last 1)\n");
61 printf("-endianbugfix : Performs 8-in-32 byte swap on the output texture\n");
62 printf(" data. This is a bug workaround for the prototype\n");
63 printf(" hardware.\n");
64 printf("-align : Adds alignment padding blocks between the header\n");
65 printf(" and the image. The amount of padding depends \n");
66 printf(" upon hardware requirements.\n");
67 printf("-h : Show this help message\n");
68 printf("-d : Dump Debug Information to a file\n");
69 printf(" Dump files:\n");
70 printf(" <output_file>_vs.dmp\n");
71 printf(" <output_file>_gs.dmp\n");
72 printf(" <output_file>_ps.dmp\n");
73 printf("-istats : Dump shader instruction statistics to a file\n");
74 printf(" File names: <output_file>_vs.stat, <output_file>_ps.stat, etc.\n");
75 printf("-nospark : Omit Spark debug information. Without this option a\n");
76 printf(" 16 byte hash is appended to each shader, and a debug\n");
77 printf(" information file is written to directory\n");
78 printf(" $(LOCALAPPDATA)\\Temp\\Nintendo\\Cafe\\ShaderSymbols\n");
79 printf(" or the directory specified via -sparkdir option.\n");
80 printf("-sparkdir path : Override the default Spark debug information\n");
81 printf(" directory.\n");
82 printf("-O<options> : Perform additional optimizations:\n");
83 printf(" <options> is a comma separated list of optimizations to enable:\n");
84 for (i = 0; oflagdef[i].name; i++) {
85 if (oflagdef[i].help) {
86 printf(" %-12s : %s\n", oflagdef[i].name, oflagdef[i].help);
87 }
88 }
89 printf(" Any of the optimizations may be disabled by prefixing them with ! or no-\n");
90 printf(" For example:\n");
91 printf(" -Oall,no-fastmath\n");
92 printf(" will enable all optimizations except fastmath.\n");
93 printf(" Just plain -O is equivalent to -Oall.\n");
94 printf("\n");
95 }
96
LoadDLLs(HMODULE * hShaderUtilDLL,GSH2Func * fpGSH2,HMODULE * hGfdDLL,GFDFunc * fpGFD)97 void LoadDLLs(HMODULE *hShaderUtilDLL, GSH2Func *fpGSH2, HMODULE *hGfdDLL, GFDFunc *fpGFD)
98 {
99 *hShaderUtilDLL = LoadLibrary(LIB_DLL_SHADERUTILS);
100 if ( !*hShaderUtilDLL )
101 {
102 printf("Failed to load DLL %ws. Exiting.", LIB_DLL_SHADERUTILS);
103 FreeLibrary(*hShaderUtilDLL);
104 exit(EC_LOADINGDLLFAILED);
105 }
106
107 *hGfdDLL = LoadLibrary(LIB_DLL_GFD);
108 if ( !*hGfdDLL )
109 {
110 printf("Failed to load DLL %ws. Exiting.", LIB_DLL_GFD);
111 FreeLibrary(*hGfdDLL);
112 exit(EC_LOADINGDLLFAILED);
113 }
114
115 // Get function
116 fpGSH2->Initialize = reinterpret_cast<PGSH2Initialize>(GetProcAddress(*hShaderUtilDLL, "GSH2Initialize"));
117 fpGSH2->Destroy = reinterpret_cast<PGSH2Destroy>(GetProcAddress(*hShaderUtilDLL, "GSH2Destroy"));
118 fpGSH2->CompileProgram3 = reinterpret_cast<PGSH2CompileProgram3>(GetProcAddress(*hShaderUtilDLL, "GSH2CompileProgram3"));
119 fpGSH2->DestroyGX2Program3 = reinterpret_cast<PGSH2DestroyGX2Program3>(GetProcAddress(*hShaderUtilDLL, "GSH2DestroyGX2Program3"));
120 fpGSH2->CalcFetchShaderSizeEx = reinterpret_cast<PGSH2CalcFetchShaderSizeEx>(GetProcAddress(*hShaderUtilDLL, "GSH2CalcFetchShaderSizeEx"));
121 fpGSH2->InitFetchShaderEx = reinterpret_cast<PGSH2InitFetchShaderEx>(GetProcAddress(*hShaderUtilDLL, "GSH2InitFetchShaderEx"));
122 fpGSH2->GetVertexShaderGPRs = reinterpret_cast<PGSH2GetVertexShaderGPRs>(GetProcAddress(*hShaderUtilDLL, "GSH2GetVertexShaderGPRs"));
123 fpGSH2->GetGeometryShaderGPRs = reinterpret_cast<PGSH2GetGeometryShaderGPRs>(GetProcAddress(*hShaderUtilDLL, "GSH2GetGeometryShaderGPRs"));
124 fpGSH2->GetPixelShaderGPRs = reinterpret_cast<PGSH2GetPixelShaderGPRs>(GetProcAddress(*hShaderUtilDLL, "GSH2GetPixelShaderGPRs"));
125 fpGSH2->GetVertexShaderStackEntries = reinterpret_cast<PGSH2GetVertexShaderStackEntries>(GetProcAddress(*hShaderUtilDLL, "GSH2GetVertexShaderStackEntries"));
126 fpGSH2->GetGeometryShaderStackEntries = reinterpret_cast<PGSH2GetGeometryShaderStackEntries>(GetProcAddress(*hShaderUtilDLL, "GSH2GetGeometryShaderStackEntries"));
127 fpGSH2->GetPixelShaderStackEntries = reinterpret_cast<PGSH2GetPixelShaderStackEntries>(GetProcAddress(*hShaderUtilDLL, "GSH2GetPixelShaderStackEntries"));
128 fpGSH2->GetABIVersion = reinterpret_cast<PGSH2GetABIVersion>(GetProcAddress(*hShaderUtilDLL, "GSH2GetABIVersion"));
129
130 fpGFD->WriteFileShaderAsCode = reinterpret_cast<PGFDWriteFileShaderAsCode>(GetProcAddress(*hGfdDLL, "GFDWriteFileShaderAsCode"));
131 fpGFD->WriteFileShader = reinterpret_cast<PGFDWriteFileShader>(GetProcAddress(*hGfdDLL, "GFDWriteFileShader"));
132 fpGFD->AppendWriteFileShader = reinterpret_cast<PGFDAppendWriteFileShader>(GetProcAddress(*hGfdDLL, "GFDAppendWriteFileShader"));
133 fpGFD->WriteFileShaderAsCode2 = reinterpret_cast<PGFDWriteFileShaderAsCode2>(GetProcAddress(*hGfdDLL, "GFDWriteFileShaderAsCode2"));
134 fpGFD->WriteFileShader2 = reinterpret_cast<PGFDWriteFileShader2>(GetProcAddress(*hGfdDLL, "GFDWriteFileShader2"));
135 fpGFD->AppendWriteFileShader2 = reinterpret_cast<PGFDAppendWriteFileShader2>(GetProcAddress(*hGfdDLL, "GFDAppendWriteFileShader2"));
136 fpGFD->WriteFileShaderAsCodeWithSource = reinterpret_cast<PGFDWriteFileShaderAsCodeWithSource>(GetProcAddress(*hGfdDLL, "GFDWriteFileShaderAsCodeWithSource"));
137 }
138
FreeDLLs(HMODULE * hShaderUtilDLL,HMODULE * hGfdDLL)139 void FreeDLLs(HMODULE *hShaderUtilDLL, HMODULE *hGfdDLL)
140 {
141 FreeLibrary(*hShaderUtilDLL);
142 FreeLibrary(*hGfdDLL);
143 }
144
DeleteShaderSource(char ** ppShaders)145 bool DeleteShaderSource(char** ppShaders)
146 {
147 if (*ppShaders)
148 {
149 delete[] *ppShaders;
150 *ppShaders = NULL;
151 }
152
153 return true;
154 }
155
156 #define INCLUDE_SUPPORT
157 #ifdef INCLUDE_SUPPORT
158 /*
159 * append a string to another, reallocating memory if necessary
160 * origData is the original source
161 * appendData is the new string to append
162 * *pCurLen is the current length of the string
163 * *pMaxLen is the maximum allocated space for the string
164 */
165 static char *
appendBuffer(char * origData,char * appendData,size_t * pMaxLen,size_t * pCurLen)166 appendBuffer(char *origData, char *appendData, size_t *pMaxLen, size_t *pCurLen)
167 {
168 size_t maxLen = *pMaxLen;
169 size_t curLen = *pCurLen;
170 size_t newLen = curLen + strlen(appendData);
171 char *newData = origData;
172 bool origNull = origData == NULL;
173
174 if (newLen > maxLen) {
175 maxLen = newLen + BUFSIZ;
176 newData = (char *)realloc(origData, maxLen+1); /* remember space for trailing null!! */
177 if (!newData) {
178 fprintf(stderr, "Ran out of memory while reading data!\n");
179 exit(2);
180 }
181 *pMaxLen = maxLen;
182 }
183 //strcat(newData, appendData);
184 if( origNull )
185 strcpy_s(newData, maxLen, appendData);
186 else
187 strcat_s(newData, maxLen+1, appendData);
188 *pCurLen = newLen;
189 return newData;
190 }
191
192 /*
193 * structure to hold a file processing state
194 * used for printing error messages
195 */
196 typedef struct fileState {
197 FILE *fp;
198 const char *fname;
199 int linenum;
200 } FileState;
201
202 // forward declaration
203 static char *processInclude(FileState *curfs, char *strbuf, char *includeline, size_t *pMaxSize, size_t *pCurSize);
204
205 //
206 // append an error message to the string
207 //
appendError(FileState * fs,char * msg,char * strbuf,size_t * pMaxSize,size_t * pCurSize)208 static char *appendError(FileState *fs, char *msg, char *strbuf, size_t *pMaxSize, size_t *pCurSize)
209 {
210 char temp[32];
211 strbuf = appendBuffer(strbuf, "#error \"", pMaxSize, pCurSize);
212 strbuf = appendBuffer(strbuf, fs->fname ? fs->fname : "(unknown)", pMaxSize, pCurSize);
213 strbuf = appendBuffer(strbuf, ": ", pMaxSize, pCurSize);
214 sprintf_s(temp, sizeof(temp), "%d", fs->linenum);
215 strbuf = appendBuffer(strbuf, temp, pMaxSize, pCurSize);
216 strbuf = appendBuffer(strbuf, ": ", pMaxSize, pCurSize);
217 strbuf = appendBuffer(strbuf, msg, pMaxSize, pCurSize);
218 strbuf = appendBuffer(strbuf, "\"\n", pMaxSize, pCurSize);
219 return strbuf;
220 }
221
222 //
223 // append a whole file to a string
224 // strbuf is a pointer to the string to be appended to
225 // pCurSize points to the current size
226 // pMaxSize points to the maximum size currently allocated to the buffer
227 //
228 static char *
getFile(FileState * fs,char * strbuf,size_t * pMaxSize,size_t * pCurSize)229 getFile(FileState *fs, char *strbuf, size_t *pMaxSize, size_t *pCurSize)
230 {
231 char linebuf[BUFSIZ];
232 char *ptr;
233 FILE *fp = fs->fp;
234
235 // check for byte order mark indicating UTF-8
236 // if found, just strip it off
237 {
238 int c1, c2, c3;
239
240 c1 = fgetc(fp); c2 = fgetc(fp); c3 = fgetc(fp);
241 if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) {
242 // byte order mark; ignore these and keep going
243 } else {
244 // rewind and start again
245 fseek(fp, 0, SEEK_SET);
246 }
247 }
248 // now process lines from the file
249 for(;;) {
250 char *word;
251
252 ptr = fgets(linebuf, sizeof(linebuf), fp);
253 word = NULL;
254 if (!ptr) break;
255 // check for #include lines
256 while (*ptr == ' ' || *ptr=='\t') ptr++;
257 if (*ptr == '#') {
258 ptr++;
259 while (*ptr == ' ' || *ptr == '\t') ptr++;
260 word = ptr;
261 }
262 if (word && !strncmp(word, "include", 7) && isspace(word[7])) {
263 strbuf = processInclude(fs, strbuf, ptr+8, pMaxSize, pCurSize);
264 } else {
265 strbuf = appendBuffer(strbuf, linebuf, pMaxSize, pCurSize);
266 }
267 while (*ptr) {
268 if (*ptr == '\n')
269 fs->linenum++;
270 ptr++;
271 }
272 }
273 // make sure to end with a newline
274 strbuf = appendBuffer(strbuf, "\n", pMaxSize, pCurSize);
275 return strbuf;
276 }
277
278 // don't make this too big, or the preprocessor won't report errors from #includes inside nested
279 // #ifs
280 #define MAX_INCLUDE_DEPTH 24
281
processInclude(FileState * oldfs,char * strbuf,char * includeline,size_t * pMaxSize,size_t * pCurSize)282 static char *processInclude(FileState *oldfs, char *strbuf, char *includeline, size_t *pMaxSize, size_t *pCurSize)
283 {
284 char *fname;
285 char *fullfname;
286 char *ptr;
287 char *dirsuffix;
288 FILE *fp;
289 FileState fs;
290 size_t bufsiz;
291 static int includeDepth = 0;
292
293 // check for #include nested too far
294 if (includeDepth >= MAX_INCLUDE_DEPTH) {
295 strbuf = appendError(oldfs, "#includes nested too deeply", strbuf, pMaxSize, pCurSize);
296 //fprintf(stderr, "#includes nest too deeply\n");
297 return strbuf;
298 }
299 // find the file name
300 fname = includeline;
301 while (isspace(*fname)) fname++;
302 if (*fname != '"') {
303 strbuf = appendError(oldfs, "expected quote after #include", strbuf, pMaxSize, pCurSize);
304 return strbuf;
305 }
306 fname++;
307 ptr = fname;
308 while (*ptr && *ptr != '"') ptr++;
309 if (!*ptr) {
310 strbuf = appendError(oldfs, "missing quote at end of #include", strbuf, pMaxSize, pCurSize);
311 return strbuf;
312 }
313 *ptr = 0;
314
315 // at this point "fname" contains the file name
316 // we need to prepend the directory of the originating file
317 bufsiz = strlen(fname) + strlen(oldfs->fname) + 1;
318 fullfname = (char *)calloc(strlen(fname) + strlen(oldfs->fname) + 1, 1);
319 strcpy_s(fullfname, bufsiz, oldfs->fname);
320
321 // find the part (if any) of the full file name that contains a directory
322 dirsuffix = NULL;
323 for (ptr = fullfname; *ptr; ptr++) {
324 if (*ptr == '/' || *ptr == '\\')
325 dirsuffix = ptr;
326 }
327 if (dirsuffix) {
328 *++dirsuffix = 0;
329 } else {
330 *fullfname = 0;
331 }
332 // now append the specific file name so it will be relative to the file
333 // that included this one
334 strcat_s(fullfname, bufsiz, fname);
335
336 // try to open it
337 //fprintf(stderr, "include of %s (old file name=%s, new=%s)\n", fullfname, oldfs->fname, fname);
338 fopen_s(&fp, fullfname, "rb");
339 if (!fp) {
340 // this could be inside a #if, so we can't throw an error immediately
341 // instead, insert a #error into the text
342 char *temp;
343 size_t tempsiz = strlen(fname) + 80;
344 free(fullfname);
345 temp = (char *)calloc(1, tempsiz);
346 if (!temp) {
347 temp = "Out of memory";
348 } else {
349 sprintf_s(temp, tempsiz, "unable to open file %s", fname);
350 }
351 strbuf = appendError(oldfs, temp, strbuf, pMaxSize, pCurSize);
352 free(temp);
353 return strbuf;
354 }
355 fs.fname = fullfname;
356 fs.linenum = 1;
357 fs.fp = fp;
358 ++includeDepth;
359 strbuf = getFile(&fs, strbuf, pCurSize, pMaxSize);
360 --includeDepth;
361 fclose(fp);
362 return strbuf;
363 }
364
AppendShaderSource(char * pFilename,char ** ppSource)365 bool AppendShaderSource(char* pFilename, char** ppSource)
366 {
367 FILE *fp = NULL;
368 FileState fs;
369 size_t totalLen = 0;
370 size_t curLen = 0;
371 size_t fileLen;
372
373 fopen_s(&fp, pFilename, "rb");
374
375 if (!fp)
376 {
377 return false;
378 }
379
380 // Get file size
381 fseek(fp, 0, SEEK_END);
382 fileLen = ftell(fp);
383 fseek(fp, 0, SEEK_SET);
384
385
386 if (!(*ppSource))
387 {
388 curLen = 0;
389 totalLen = fileLen + 1; // for a trailing newline
390 *ppSource = (char *)malloc(totalLen+1); // add space for a trailing 0
391
392 if (!(*ppSource))
393 {
394 return false;
395 }
396
397 *ppSource[0] = '\0';
398 }
399 else
400 {
401 curLen = strlen(*ppSource);
402 totalLen = curLen; // this is, unfortunatley, just a guess, but it's a safe one
403 }
404
405 fs.fp = fp;
406 fs.linenum = 1;
407 fs.fname = pFilename;
408 *ppSource = getFile(&fs, *ppSource, &curLen, &totalLen);
409 fclose(fp);
410 return true;
411 }
412 #else
413
AppendShaderSource(char * pFilename,char ** ppSource)414 bool AppendShaderSource(char* pFilename, char** ppSource)
415 {
416 FILE *fp = NULL;
417 u32 totalLen = 0;
418 u32 offset = 0;
419 u32 fileLen = 0;
420
421 fopen_s(&fp, pFilename, "rb");
422
423 if (!fp)
424 {
425 return false;
426 }
427
428 // Get file size
429 fseek(fp, 0, SEEK_END);
430 fileLen = ftell(fp);
431 fseek(fp, 0, SEEK_SET);
432
433 // check for byte order mark indicating UTF-8
434 // if found, just strip it off
435 {
436 int c1, c2, c3;
437
438 c1 = fgetc(fp); c2 = fgetc(fp); c3 = fgetc(fp);
439 if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) {
440 // byte order mark; ignore these, reduce
441 // the file size accordingly
442 fileLen -= 3;
443 } else {
444 // rewind and start again
445 fseek(fp, 0, SEEK_SET);
446 }
447 }
448
449 if (!(*ppSource))
450 {
451 offset = 0;
452 totalLen = fileLen + 1;
453 *ppSource = new char[totalLen];
454
455 if (!(*ppSource))
456 {
457 return false;
458 }
459
460 *ppSource[0] = '\0';
461 }
462 else
463 {
464 offset = (u32)(strlen(*ppSource) + 1); // + 1 for appending "\n"
465 totalLen = offset + fileLen + 1; // + 1 for appending "\0"
466 char* pTemp = new char[totalLen];
467
468 if (!pTemp)
469 {
470 return false;
471 }
472
473 assert(totalLen >= 2);
474 strcpy_s(pTemp, totalLen, (*ppSource));
475 strcat_s(pTemp, totalLen, "\n");
476 delete [] (*ppSource);
477 *ppSource = pTemp;
478 }
479
480 fread(((*ppSource) + offset), fileLen, 1, fp);
481 (*ppSource)[totalLen - 1] = '\0';
482 fclose(fp);
483 return true;
484 }
485 #endif
486
DeleteSOVaryings(char ** pSOVaryings,u32 numVaryings)487 void DeleteSOVaryings(char** pSOVaryings, u32 numVaryings)
488 {
489 if (pSOVaryings != NULL)
490 {
491 for (u32 idx = 0; idx < numVaryings; idx++)
492 {
493 delete[] (pSOVaryings[idx]);
494 }
495 delete [] (pSOVaryings);
496 }
497 }
498
499 #define MIN_NUM_VARYINGS 50
500
GetStreamOutVaryings(char * pFilename,u32 * pNumSOVaryings)501 char** GetStreamOutVaryings(char* pFilename, u32* pNumSOVaryings)
502 {
503 FILE *fp = NULL;
504 u32 totalLen = 0;
505 u32 offset = 0;
506 u32 fileLen = 0;
507 char varying[256];
508 char** pSOVaryings = NULL;
509 char** pTemp;
510 u32 varyingsSize;
511 u32 numVaryings = 0;
512
513 fopen_s(&fp, pFilename, "r");
514
515 if (!fp)
516 {
517 return NULL;
518 }
519
520 *pNumSOVaryings = 0;
521 pSOVaryings = new char*[MIN_NUM_VARYINGS];
522 varyingsSize = MIN_NUM_VARYINGS;
523
524 if (pSOVaryings != NULL)
525 {
526 while (fgets(varying, 256, fp) != NULL)
527 {
528 size_t varyingLen;
529
530 if (numVaryings >= varyingsSize)
531 {
532 varyingsSize += MIN_NUM_VARYINGS;
533 pTemp = new char*[varyingsSize];
534
535 if (pTemp == NULL)
536 {
537 DeleteSOVaryings(pSOVaryings, numVaryings);
538 return NULL;
539 }
540
541 memcpy(pTemp, pSOVaryings, (numVaryings * sizeof(char *)));
542
543 delete [] (pSOVaryings);
544
545 pSOVaryings = pTemp;
546 }
547 varyingLen = strlen(varying) + 1;
548 varying[varyingLen - 2] = '\0';
549
550 pSOVaryings[numVaryings] = new char[varyingLen];
551
552 if (pSOVaryings[numVaryings] == NULL)
553 {
554 DeleteSOVaryings(pSOVaryings, numVaryings);
555 return NULL;
556 }
557
558 strcpy_s(pSOVaryings[numVaryings], varyingLen, varying);
559
560 numVaryings++;
561 }
562 }
563
564 *pNumSOVaryings = numVaryings;
565 fclose(fp);
566
567 return pSOVaryings;
568 }
569
Destroy(ShaderSourceInfo * pConfig)570 bool Destroy(ShaderSourceInfo* pConfig)
571 {
572 DeleteShaderSource(&pConfig->vs_source);
573 DeleteShaderSource(&pConfig->ps_source);
574 DeleteShaderSource(&pConfig->gs_source);
575 DeleteSOVaryings(pConfig->so_varyings, pConfig->numSOVaryings);
576
577 return true;
578 }
579
matchword(const char * word,const char * str)580 static bool matchword(const char *word, const char *str)
581 {
582 // see if word appears first in str
583 while (*word && *word == *str)
584 {
585 word++, str++;
586 }
587 if (*word) return false;
588 if (*str && *str != ',') return false;
589 return true;
590 }
591
592 //
593 // process a string and add/subtract optimization flags from origFlags,
594 // returning the new set of flags
595 //
596
parseOptFlags(uint64 mask,const char * str)597 static uint64 parseOptFlags(uint64 mask, const char *str)
598 {
599 bool invert, found;
600 int i;
601
602 if (!str)
603 return mask;
604 while (*str) {
605 invert = false;
606 if (!strncmp(str, "no-", 3)) {
607 str += 3;
608 invert = true;
609 } else if (str[0] == '!') {
610 str++;
611 invert = true;
612 }
613 found = false;
614 for (i = 0; oflagdef[i].name; i++) {
615 if (matchword(oflagdef[i].name, str)) {
616 found = true;
617 break;
618 }
619 }
620 if (!found) {
621 fprintf(stderr, "Unknown optimization option: %s\n", str);
622 return mask;
623 }
624 if (oflagdef[i].flagbits == 0) {
625 mask = 0; /* turn off everything */
626 } else if (invert) {
627 mask &= ~oflagdef[i].flagbits;
628 } else {
629 mask |= oflagdef[i].flagbits;
630 }
631 str += strlen(oflagdef[i].name);
632 while (*str == ',') str++;
633 }
634
635 return mask;
636 }
637
638 void
PrintVersion(u32 abiVersion)639 PrintVersion(u32 abiVersion)
640 {
641 printf("gshCompile compiled on %s\n", __DATE__);
642 if (abiVersion) {
643 printf("shaderUtils version: 0x%08lX\n", (unsigned long)abiVersion);
644 } else {
645 printf("shaderUtils version unknown\n");
646 }
647 }
648
Initialize(s32 argc,char ** argv,ShaderSourceInfo * pConfig,u32 abiVersion)649 bool Initialize(s32 argc, char** argv, ShaderSourceInfo* pConfig, u32 abiVersion)
650 {
651 s32 count = 0;
652
653 memset(pConfig, 0, sizeof(*pConfig));
654
655 // initalize defaults
656 pConfig->pOutFilename = DEFAULT_OUTFILENAME;
657 pConfig->gpu = DEFAULT_GPU;
658 pConfig->lang = DEFAULT_SHADINGLANGUAGE;
659 pConfig->forceUniformBlock = DEFAULT_FORCEUNIFORMBLOCK;
660 pConfig->outfilealign = DEFAULT_ALIGNMODE;
661 pConfig->append = DEFAULT_APPENDMODE;
662 pConfig->ascode = DEFAULT_ASCODEMODE;
663 pConfig->endianbugfix = DEFAULT_ENDIANBUGFIX;
664 pConfig->noSparkInfo = DEFAULT_NOSPARKINFO;
665
666 if (argc == 1)
667 {
668 Help(argv);
669 exit(EC_SUCCESS);
670 }
671
672 for (count = 1; count < argc; count++)
673 {
674 if (!strcmp(argv[count], "-gpu"))
675 {
676 if ((count + 1) < argc)
677 {
678 switch(atoi(argv[count + 1]))
679 {
680 case 1:
681 pConfig->gpu = GPU_VERSION_1;
682 break;
683 case 2:
684 pConfig->gpu = GPU_VERSION_GPU7;
685 break;
686 default:
687 printf("Error: Unsupported GPU version\n");
688 exit(EC_UNSUPPORTEDGPU);
689 break;
690 }
691 count++;
692 }
693 else
694 {
695 printf("Missing parameter argument %s <arg>\n", argv[count]);
696 exit(EC_BADPARAM);
697 }
698 }
699 // -v source vertex shader
700 else if (!strcmp(argv[count], "-v"))
701 {
702 if ((count + 1) < argc)
703 {
704 if (!AppendShaderSource(argv[count + 1], &pConfig->vs_source))
705 {
706 printf("Problem opening file \"%s\".\n", argv[count + 1]);
707 exit(EC_INPUTFILEERROR);
708 }
709 pConfig->vs_source_filename = _fullpath( vs_name_buffer, argv[count + 1], GSH_FULL_FILE_NAME_SIZE );
710 if( !pConfig->vs_source_filename )
711 pConfig->vs_source_filename = argv[count + 1];
712 count++;
713 }
714 else
715 {
716 printf("Missing parameter argument %s <arg>\n", argv[count]);
717 exit(EC_BADPARAM);
718 }
719 }
720 // -p source pixel shader
721 else if (!strcmp(argv[count], "-p"))
722 {
723 if ((count + 1) < argc)
724 {
725 if (!AppendShaderSource(argv[count + 1], &pConfig->ps_source))
726 {
727 printf("Problem opening file \"%s\".\n", argv[count + 1]);
728 exit(EC_INPUTFILEERROR);
729 }
730 pConfig->ps_source_filename = _fullpath( ps_name_buffer, argv[count + 1], GSH_FULL_FILE_NAME_SIZE );
731 if( !pConfig->ps_source_filename )
732 pConfig->ps_source_filename = argv[count + 1];
733 count++;
734 }
735 else
736 {
737 printf("Missing parameter argument %s <arg>\n", argv[count]);
738 exit(EC_BADPARAM);
739 }
740 }
741 // -g source geometry shader
742 else if (!strcmp(argv[count], "-g"))
743 {
744 if ((count + 1) < argc)
745 {
746 if (!AppendShaderSource(argv[count + 1], &pConfig->gs_source))
747 {
748 printf("Problem opening file \"%s\".\n", argv[count + 1]);
749 exit(EC_INPUTFILEERROR);
750 }
751 pConfig->gs_source_filename = _fullpath( gs_name_buffer, argv[count + 1], GSH_FULL_FILE_NAME_SIZE );
752 if( !pConfig->gs_source_filename )
753 pConfig->gs_source_filename = argv[count + 1];
754 count++;
755 }
756 else
757 {
758 printf("Missing parameter argument %s <arg>\n", argv[count]);
759 exit(EC_BADPARAM);
760 }
761 }
762 // -c compute shader
763 else if (!strcmp(argv[count], "-c"))
764 {
765 if ((count + 1) < argc)
766 {
767 if (!AppendShaderSource(argv[count + 1], &pConfig->cs_source))
768 {
769 printf("Problem opening file \"%s\".\n", argv[count + 1]);
770 exit(EC_INPUTFILEERROR);
771 }
772 pConfig->cs_source_filename = _fullpath( cs_name_buffer, argv[count + 1], GSH_FULL_FILE_NAME_SIZE );
773 if( !pConfig->cs_source_filename )
774 pConfig->cs_source_filename = argv[count + 1];
775 count++;
776 }
777 else
778 {
779 printf("Missing parameter argument %s <arg>\n", argv[count]);
780 exit(EC_BADPARAM);
781 }
782 }
783 // -so stream out varyings
784 else if (!strcmp(argv[count], "-so"))
785 {
786 if ((count + 1) < argc)
787 {
788 pConfig->so_varyings = GetStreamOutVaryings(argv[count + 1], &pConfig->numSOVaryings);
789 if (pConfig->so_varyings == NULL)
790 {
791 printf("Problem opening file \"%s\".\n", argv[count + 1]);
792 exit(EC_INPUTFILEERROR);
793 }
794 count++;
795 }
796 else
797 {
798 printf("Missing parameter argument %s <arg>\n", argv[count]);
799 exit(EC_BADPARAM);
800 }
801 }
802
803 // -o destination filename
804 else if (!strcmp(argv[count], "-o"))
805 {
806 if ((count + 1) < argc)
807 {
808 pConfig->pOutFilename = argv[count + 1];
809 count++;
810 }
811 }
812
813 // -oa destination filename
814 else if (!strcmp(argv[count], "-oa"))
815 {
816 pConfig->append = true;
817
818 if ((count + 1) < argc)
819 {
820 pConfig->pOutFilename = argv[count + 1];
821 count++;
822 }
823 }
824
825 // -oh destination filename
826 else if (!strcmp(argv[count], "-oh"))
827 {
828 pConfig->ascode = true;
829
830 if ((count + 1) < argc)
831 {
832 pConfig->pOutFilename = argv[count + 1];
833 count++;
834 }
835 }
836 // -? or -help print help
837 else if (!strcmp(argv[count], "-?") || !strcmp(argv[count], "-help"))
838 {
839 Help(argv);
840 exit(EC_SUCCESS);
841 }
842
843 // -force_uniformblock
844 else if (!strcmp(argv[count], "-force_uniformblock"))
845 {
846 pConfig->forceUniformBlock = true;
847 }
848 else if (!strncmp(argv[count], "-O", 2))
849 {
850 if (argv[count][2])
851 pConfig->optimizeFlags = parseOptFlags(pConfig->optimizeFlags, argv[count]+2);
852 else
853 pConfig->optimizeFlags = GSH2_OPTFLAGS_ALL;
854 }
855 // -t (language)
856 else if (!strcmp(argv[count], "-t"))
857 {
858 if ((count + 1) < argc)
859 {
860 if (!strcmp(argv[count + 1], "essl"))
861 {
862 pConfig->lang = SHADERLANG_ESSL;
863 }
864 else if (!strcmp(argv[count + 1], "glsl"))
865 {
866 pConfig->lang = SHADERLANG_GLSL;
867 }
868 else
869 {
870 printf("Unsupported shader language type specified\n");
871 exit(EC_UNSUPPORTEDSHADERTYPE);
872 }
873 count++;
874 }
875 else
876 {
877 printf("Missing parameter argument %s <arg>\n", argv[count]);
878 exit(EC_BADPARAM);
879 }
880 }
881
882 // -align (file alignment)
883 else if (!strcmp(argv[count], "-align"))
884 {
885 pConfig->outfilealign = true;
886 }
887
888 // -endianbugfix (endian bug hw workaround)
889 else if (!strcmp(argv[count], "-endianbugfix"))
890 {
891 pConfig->endianbugfix = true;
892 }
893
894 // -gx2 - ignored but here for backward compatibility
895 // so users don't get an error
896 else if (!strcmp(argv[count], "-gx2"))
897 {
898 continue;
899 }
900
901
902 // -d (dump shaders)
903 else if (!strcmp(argv[count], "-d"))
904 {
905 pConfig->dumpShaders = true;
906 }
907
908 // -nospark: leave out Spark debug info
909 else if (!strcmp(argv[count], "-nospark"))
910 {
911 pConfig->noSparkInfo = true;
912 }
913
914 // -sparkdir: directory to write the Spark debug info
915 else if (!strcmp(argv[count], "-sparkdir"))
916 {
917 if ((count + 1) < argc)
918 {
919 pConfig->pSparkDir = argv[count + 1];
920 count++;
921 }
922 else
923 {
924 printf("Missing parameter argument %s <arg>\n", argv[count]);
925 exit(EC_BADPARAM);
926 }
927 }
928
929 // -istats: write out instruction stats
930 else if (!strcmp(argv[count], "-istats"))
931 {
932 pConfig->istats = 1;
933 }
934 // -no_limit_array_syms: write out all symbols for each uniform array
935 else if (!strcmp(argv[count], "-no_limit_array_syms"))
936 {
937 pConfig->noArrayLimit = 1;
938 }
939 // -version: print version of shaderUtils (and gshCompile??)
940 else if (!strcmp(argv[count], "-version"))
941 {
942 PrintVersion(abiVersion);
943 exit(EC_SUCCESS);
944 }
945 // command line parameter not recognized
946 else
947 {
948 printf("Unrecognized command line parameter \"%s\". Exiting.", argv[count]);
949 exit(EC_BADPARAM);
950 }
951 }
952
953 return true;
954 }
955
DumpShaderData(const char * pFileName,const char * pShaderDump)956 void DumpShaderData(const char* pFileName, const char* pShaderDump)
957 {
958 FILE* fp = NULL;
959
960 if (pShaderDump != NULL)
961 {
962 fopen_s(&fp, pFileName, "w");
963 assert(fp);
964
965 if (fp != NULL)
966 {
967 fputs(pShaderDump, fp);
968 fflush(fp);
969 fclose(fp);
970 }
971 }
972 }
973
DumpShaderStats(const char * pFileName,GSH2ShaderStats * pStats)974 void DumpShaderStats(const char *pFileName, GSH2ShaderStats *pStats)
975 {
976 FILE *fp = NULL;
977
978 if (pStats != NULL)
979 {
980 fopen_s(&fp, pFileName, "w");
981 assert(fp);
982 if (fp != NULL)
983 {
984 fprintf(fp, "Hardware Usage Statistics\n\n");
985 fprintf(fp, "Total HW instructions used: %5d\n", pStats->uNumInst);
986 fprintf(fp, " ALU instructions used: %5d\n", pStats->uNumALUInst);
987 fprintf(fp, " Tfetch instructions used: %5d\n", pStats->uNumTfetchInst);
988 fprintf(fp, " Vfetch instructions used: %5d\n", pStats->uNumVfetchInst);
989 fprintf(fp, " Control flow instructions: %5d\n", pStats->uNumCflowInst);
990 fprintf(fp, "GPR pool size: %5d\n", pStats->uGPRPoolSize);
991 fprintf(fp, "Num HW GPRs used: %5d\n", pStats->uNumTempReg);
992 fprintf(fp, "Num HW clause temps used: %5d\n", pStats->uNumClauseTempReg);
993 fprintf(fp, "External (API) ALU consts: %5d\n", pStats->uNumALUConstReg);
994 fclose(fp);
995 }
996 }
997 }
998
999 static GX2Boolean
WriteFileShader(GFDFunc * pgfd,char * pFilename,GFDGPUVersion gpuVer,GFDEndianSwapMode swapMode,GFDAlignMode alignMode,u32 numShader,GFDShaders2 * pShaders)1000 WriteFileShader(GFDFunc *pgfd, char* pFilename, GFDGPUVersion gpuVer, GFDEndianSwapMode swapMode, GFDAlignMode alignMode, u32 numShader, GFDShaders2 *pShaders)
1001 {
1002 GFDShaders shader1;
1003
1004 if (pgfd->WriteFileShader2) {
1005 return (*pgfd->WriteFileShader2)(pFilename, gpuVer, swapMode, alignMode, numShader, pShaders);
1006 }
1007
1008 if (pShaders->pComputeShader != NULL) {
1009 fprintf(stderr, "ERROR: This version of gfd.dll is unable to handle compute shaders\n");
1010 return GX2_FALSE;
1011 }
1012 if (!pgfd->WriteFileShader) {
1013 fprintf(stderr, "ERROR: Unable to find WriteFileShader function in gfd.dll\n");
1014 return GX2_FALSE;
1015 }
1016 shader1.pGeometryShader = pShaders->pGeometryShader;
1017 shader1.pPixelShader = pShaders->pPixelShader;
1018 shader1.pVertexShader = pShaders->pVertexShader;
1019 return (*pgfd->WriteFileShader)(pFilename, gpuVer, swapMode, alignMode, numShader, &shader1);
1020 }
1021
1022 static GX2Boolean
AppendWriteFileShader(GFDFunc * pgfd,char * pFilename,GFDGPUVersion gpuVer,GFDEndianSwapMode swapMode,GFDAlignMode alignMode,u32 numShader,GFDShaders2 * pShaders)1023 AppendWriteFileShader(GFDFunc *pgfd, char* pFilename, GFDGPUVersion gpuVer, GFDEndianSwapMode swapMode, GFDAlignMode alignMode, u32 numShader, GFDShaders2 *pShaders)
1024 {
1025 GFDShaders shader1;
1026
1027 if (pgfd->AppendWriteFileShader2) {
1028 return (*pgfd->AppendWriteFileShader2)(pFilename, gpuVer, swapMode, alignMode, numShader, pShaders);
1029 }
1030
1031 if (pShaders->pComputeShader != NULL) {
1032 fprintf(stderr, "ERROR: This version of gfd.dll is unable to handle compute shaders\n");
1033 return GX2_FALSE;
1034 }
1035 if (!pgfd->AppendWriteFileShader) {
1036 fprintf(stderr, "ERROR: Unable to find AppendWriteFileShader function in gfd.dll\n");
1037 return GX2_FALSE;
1038 }
1039 shader1.pGeometryShader = pShaders->pGeometryShader;
1040 shader1.pPixelShader = pShaders->pPixelShader;
1041 shader1.pVertexShader = pShaders->pVertexShader;
1042 return (*pgfd->AppendWriteFileShader)(pFilename, gpuVer, swapMode, alignMode, numShader, &shader1);
1043 }
1044
1045 static GX2Boolean
WriteFileShaderAsCode(GFDFunc * pgfd,char * pFilename,GFDEndianSwapMode swapMode,GFDShaders2 * pShaders)1046 WriteFileShaderAsCode(GFDFunc *pgfd, char* pFilename, GFDEndianSwapMode swapMode, GFDShaders2 *pShaders)
1047 {
1048 GFDShaders shader1;
1049
1050 if (pgfd->WriteFileShaderAsCode2) {
1051 return (*pgfd->WriteFileShaderAsCode2)(pFilename, swapMode, pShaders);
1052 }
1053
1054 if (pShaders->pComputeShader != NULL) {
1055 fprintf(stderr, "ERROR: This version of gfd.dll is unable to handle compute shaders\n");
1056 return GX2_FALSE;
1057 }
1058 if (!pgfd->WriteFileShaderAsCode) {
1059 fprintf(stderr, "ERROR: Unable to find WriteFileShaderAsCode function in gfd.dll\n");
1060 return GX2_FALSE;
1061 }
1062 shader1.pGeometryShader = pShaders->pGeometryShader;
1063 shader1.pPixelShader = pShaders->pPixelShader;
1064 shader1.pVertexShader = pShaders->pVertexShader;
1065 return (*pgfd->WriteFileShaderAsCode)(pFilename, swapMode, &shader1);
1066 }
1067
main(int argc,char ** argv)1068 s32 main(int argc, char** argv)
1069 {
1070 HMODULE hShaderUtilDLL;
1071 HMODULE hGfdDLL;
1072 GSH2Func fpGSH2;
1073 GFDFunc fpGFD;
1074 GFDShaders2 shaders;
1075 GSH2Setup libSetup;
1076 GSH2CompileSetup3 compileSetup;
1077 GSH2Handle hShaderUtils = NULL;
1078 GSH2CompileOutput3 compileOutput;
1079 ShaderSourceInfo sourceInfo;
1080
1081 s32 retCode = EC_SUCCESS;
1082 u32 abiVersion = 0;
1083
1084 // Loade DLLs
1085 LoadDLLs(&hShaderUtilDLL, &fpGSH2, &hGfdDLL, &fpGFD);
1086 if (fpGSH2.GetABIVersion)
1087 abiVersion = (*fpGSH2.GetABIVersion)();
1088
1089 memset(&sourceInfo, 0, sizeof(sourceInfo));
1090 memset(&compileOutput, 0, sizeof(compileOutput));
1091 memset(&shaders, 0, sizeof(shaders));
1092 memset(&libSetup, 0, sizeof(libSetup));
1093 memset(&compileSetup, 0, sizeof(compileSetup));
1094
1095 compileSetup.abi_version = GSH2_ABI_VERSION_CURRENT;
1096 compileOutput.abi_version = GSH2_ABI_VERSION_CURRENT;
1097 compileOutput.gx2Program.abi_version = GSH2_ABI_VERSION_CURRENT;
1098
1099 // get parameters from command line
1100 Initialize(argc, argv, &sourceInfo, abiVersion);
1101 libSetup.gpu = sourceInfo.gpu;
1102
1103 // Initialize shaderUtils lib
1104 if (!(hShaderUtils = fpGSH2.Initialize(&libSetup)))
1105 {
1106 FreeDLLs(&hShaderUtilDLL, &hGfdDLL);
1107 exit(EC_GSH2INITFAILED);
1108 }
1109
1110 // add optimizations from environment variables
1111 char *env = getenv("GSHCOMPILE_OPTIMIZE");
1112 if (env != NULL) {
1113 sourceInfo.optimizeFlags = parseOptFlags(sourceInfo.optimizeFlags, env);
1114 }
1115 // Compile shaders
1116 compileSetup.vs_source = (const char*)sourceInfo.vs_source;
1117 compileSetup.ps_source = (const char*)sourceInfo.ps_source;
1118 compileSetup.gs_source = (const char*)sourceInfo.gs_source;
1119 compileSetup.so_varyings = (const char**)sourceInfo.so_varyings;
1120 compileSetup.cs_source = (const char*)sourceInfo.cs_source;
1121 compileSetup.numSOVaryings = sourceInfo.numSOVaryings;
1122 compileSetup.lang = sourceInfo.lang;
1123 compileSetup.options.dumpShaders = (sourceInfo.dumpShaders) ? 1 : 0;
1124 compileSetup.options.forceUniformBlock = (sourceInfo.forceUniformBlock) ? 1 : 0;
1125 compileSetup.options.optimize = (sourceInfo.optimizeFlags != 0) ? 1 : 0;
1126 compileSetup.options.skipSparkDebug = (sourceInfo.noSparkInfo) ? 1 : 0;
1127 compileSetup.options.optFlags = 1;
1128 compileSetup.optimizeFlags = sourceInfo.optimizeFlags;
1129
1130 // limit number of symbols generated for arrays (default, can be overridden with -no_limit_array_syms)
1131 if (sourceInfo.noArrayLimit == 0)
1132 GSH2_OPTFLAG_SETBIT(compileSetup.optimizeFlags, GSH2_OPTFLAG_LIMITARRAYSYMS);
1133
1134 compileSetup.spark_output_dir = (const char*)sourceInfo.pSparkDir;
1135 if (sourceInfo.istats)
1136 compileSetup.options.getStats = 1;
1137
1138 if (sourceInfo.cs_source) {
1139 if (compileSetup.vs_source || compileSetup.ps_source || compileSetup.gs_source)
1140 {
1141 fprintf(stderr, "Error: compute shader must be compiled on its own.\n");
1142 exit(1);
1143 }
1144 compileSetup.cs_source_filename = (const char *)sourceInfo.cs_source_filename;
1145 if (compileSetup.options.getStats)
1146 compileSetup.cs_stats = new GSH2ShaderStats;
1147 } else {
1148 compileSetup.vs_source_filename = (const char*)sourceInfo.vs_source_filename;
1149 compileSetup.ps_source_filename = (const char*)sourceInfo.ps_source_filename;
1150 compileSetup.gs_source_filename = (const char*)sourceInfo.gs_source_filename;
1151 compileSetup.cs_source_filename = NULL;
1152 if (compileSetup.options.getStats)
1153 {
1154 if (compileSetup.vs_source)
1155 compileSetup.vs_stats = new GSH2ShaderStats;
1156 if (compileSetup.ps_source)
1157 compileSetup.ps_stats = new GSH2ShaderStats;
1158 if (compileSetup.gs_source)
1159 compileSetup.gs_stats = new GSH2ShaderStats;
1160 }
1161 }
1162 if (fpGSH2.CompileProgram3(hShaderUtils, &compileSetup, &compileOutput))
1163 {
1164 shaders.abiVersion = GFD_DLL_ABI_VERSION;
1165 if (sourceInfo.vs_source) {
1166 shaders.pVertexShader = &compileOutput.gx2Program.vs;
1167 }
1168 if (sourceInfo.ps_source) {
1169 shaders.pPixelShader = &compileOutput.gx2Program.ps;
1170 }
1171 if (sourceInfo.gs_source) {
1172 shaders.pGeometryShader = &compileOutput.gx2Program.gs;
1173 }
1174 if (sourceInfo.cs_source) {
1175 shaders.pComputeShader = &compileOutput.gx2Program.cs;
1176 }
1177
1178 if (sourceInfo.dumpShaders)
1179 {
1180 char baseName[GSH_DUMP_FILENAME_SIZE];
1181 char fileName[GSH_DUMP_FILENAME_SIZE];
1182 char* pDot;
1183
1184 strncpy_s(baseName, GSH_DUMP_FILENAME_SIZE, sourceInfo.pOutFilename,
1185 strlen(sourceInfo.pOutFilename));
1186 // search for the last "." in the output name and replace it with a NULL char to terminate
1187 // the string.
1188 pDot = strrchr(baseName, '.');
1189 if (pDot != NULL)
1190 {
1191 *pDot = '\0';
1192 }
1193
1194 // Dump the shader debug data
1195 sprintf_s(fileName, GSH_DUMP_FILENAME_SIZE, "%s_vs.dmp", baseName);
1196 DumpShaderData(fileName, compileOutput.pVSDump);
1197
1198 sprintf_s(fileName, GSH_DUMP_FILENAME_SIZE, "%s_gs.dmp", baseName);
1199 DumpShaderData(fileName, compileOutput.pGSDump);
1200
1201 sprintf_s(fileName, GSH_DUMP_FILENAME_SIZE, "%s_ps.dmp", baseName);
1202 DumpShaderData(fileName, compileOutput.pPSDump);
1203
1204 sprintf_s(fileName, GSH_DUMP_FILENAME_SIZE, "%s_cs.dmp", baseName);
1205 DumpShaderData(fileName, compileOutput.pCSDump);
1206 }
1207
1208 if (sourceInfo.istats)
1209 {
1210 char baseName[GSH_DUMP_FILENAME_SIZE];
1211 char fileName[GSH_DUMP_FILENAME_SIZE];
1212 char* pDot;
1213
1214 strncpy_s(baseName, GSH_DUMP_FILENAME_SIZE, sourceInfo.pOutFilename,
1215 strlen(sourceInfo.pOutFilename));
1216 // search for the last "." in the output name and replace it with a NULL char to terminate
1217 // the string.
1218 pDot = strrchr(baseName, '.');
1219 if (pDot != NULL)
1220 {
1221 *pDot = '\0';
1222 }
1223
1224 // Dump the shader debug data
1225 sprintf_s(fileName, GSH_DUMP_FILENAME_SIZE, "%s_vs.stat", baseName);
1226 DumpShaderStats(fileName, compileSetup.vs_stats);
1227
1228 sprintf_s(fileName, GSH_DUMP_FILENAME_SIZE, "%s_gs.stat", baseName);
1229 DumpShaderStats(fileName, compileSetup.gs_stats);
1230
1231 sprintf_s(fileName, GSH_DUMP_FILENAME_SIZE, "%s_ps.stat", baseName);
1232 DumpShaderStats(fileName, compileSetup.ps_stats);
1233
1234 sprintf_s(fileName, GSH_DUMP_FILENAME_SIZE, "%s_cs.stat", baseName);
1235 DumpShaderStats(fileName, compileSetup.cs_stats);
1236 }
1237
1238 if(sourceInfo.ascode)
1239 {
1240 // Write gx2 shaders to file as code
1241 if(!WriteFileShaderAsCode(&fpGFD, sourceInfo.pOutFilename,
1242 (sourceInfo.endianbugfix) ? GFD_ENDIAN_SWAP_MODE_8_IN_32 : GFD_ENDIAN_SWAP_MODE_DEFAULT,
1243 &shaders))
1244 {
1245 retCode = EC_OUTPUTFILEERROR;
1246 }
1247 }
1248 else
1249 {
1250 if(!sourceInfo.append)
1251 {
1252 // Write gx2 shaders to file
1253 if (!WriteFileShader(&fpGFD, sourceInfo.pOutFilename,
1254 (sourceInfo.gpu == GPU_VERSION_1) ? GFD_GPU_VERSION_1 : GFD_GPU_VERSION_GPU7,
1255 (sourceInfo.endianbugfix) ? GFD_ENDIAN_SWAP_MODE_8_IN_32 : GFD_ENDIAN_SWAP_MODE_DEFAULT,
1256 (sourceInfo.outfilealign) ? GFD_ALIGN_MODE_ENABLE : GFD_ALIGN_MODE_DISABLE,
1257 1,
1258 &shaders))
1259 {
1260 retCode = EC_OUTPUTFILEERROR;
1261 }
1262 }
1263 else
1264 {
1265 // Append write gx2 shaders to existing file
1266 if (!AppendWriteFileShader(&fpGFD, sourceInfo.pOutFilename,
1267 (sourceInfo.gpu == GPU_VERSION_1) ? GFD_GPU_VERSION_1 : GFD_GPU_VERSION_GPU7,
1268 (sourceInfo.endianbugfix) ? GFD_ENDIAN_SWAP_MODE_8_IN_32 : GFD_ENDIAN_SWAP_MODE_DEFAULT,
1269 (sourceInfo.outfilealign) ? GFD_ALIGN_MODE_ENABLE : GFD_ALIGN_MODE_DISABLE,
1270 1,
1271 &shaders))
1272 {
1273 retCode = EC_OUTPUTFILEERROR;
1274 }
1275 }
1276 }
1277 }
1278 else
1279 {
1280
1281 retCode = EC_COMPILEFAILED;
1282 }
1283
1284 // Print warnings and errors if they exist in the info log.
1285 if (compileOutput.pInfoLog)
1286 {
1287 // printf("%s\n", compileOutput.pInfoLog);
1288 fprintf(stderr, "%s\n", compileOutput.pInfoLog);
1289 }
1290
1291 // Cleanup
1292 fpGSH2.DestroyGX2Program3(hShaderUtils, &compileOutput.gx2Program);
1293 fpGSH2.Destroy(hShaderUtils);
1294 Destroy(&sourceInfo);
1295 FreeDLLs(&hShaderUtilDLL, &hGfdDLL);
1296 return retCode;
1297 }
1298