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