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