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