blob: cf58ed695b9d86c8569fdd44799a38094d02eb1a [file] [log] [blame]
John Kessenicha0af4732012-12-12 21:15:54 +00001//
2//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
John Kessenichbd0747d2013-02-17 06:01:50 +00003//Copyright (C) 2013 LunarG, Inc.
4//
John Kessenicha0af4732012-12-12 21:15:54 +00005//All rights reserved.
6//
7//Redistribution and use in source and binary forms, with or without
8//modification, are permitted provided that the following conditions
9//are met:
10//
11// Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following
16// disclaimer in the documentation and/or other materials provided
17// with the distribution.
18//
19// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20// contributors may be used to endorse or promote products derived
21// from this software without specific prior written permission.
22//
23//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34//POSSIBILITY OF SUCH DAMAGE.
35//
36#include "./../glslang/Include/ShHandle.h"
37#include "./../glslang/Public/ShaderLang.h"
38#include <string.h>
John Kessenichcfd643e2013-03-08 23:14:42 +000039#include <stdlib.h>
John Kessenicha0af4732012-12-12 21:15:54 +000040#include <math.h>
41
42#ifdef _WIN32
43 #include <windows.h>
44 #include <psapi.h>
45#endif
46
47extern "C" {
48 SH_IMPORT_EXPORT void ShOutputHtml();
49}
50
John Kessenicha0af4732012-12-12 21:15:54 +000051//
52// Return codes from main.
53//
54enum TFailCode {
55 ESuccess = 0,
56 EFailUsage,
57 EFailCompile,
58 EFailLink,
59 EFailCompilerCreate,
60 EFailLinkerCreate
61};
62
63//
64// Just placeholders for testing purposes. The stand-alone environment
65// can't actually do a full link without something specifying real
66// attribute bindings.
67//
68ShBinding FixedAttributeBindings[] = {
69 { "gl_Vertex", 15 },
70 { "gl_Color", 10 },
71 { "gl_Normal", 7 },
72};
73
74ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
75
76static EShLanguage FindLanguage(char *lang);
John Kessenich52ac67e2013-05-05 23:46:22 +000077bool CompileFile(const char *fileName, ShHandle, int options, const TBuiltInResource*);
John Kessenicha0af4732012-12-12 21:15:54 +000078void usage();
79void FreeFileData(char **data);
John Kessenich54d8cda2013-02-11 22:36:01 +000080char** ReadFileData(const char *fileName);
81void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenicha0af4732012-12-12 21:15:54 +000082//Added to accomodate the multiple strings.
83int OutputMultipleStrings = 1;
84
85//
86// Set up the per compile resources
87//
88void GenerateResources(TBuiltInResource& resources)
John Kessenichb51f62c2013-04-11 16:31:09 +000089{
John Kessenicha0af4732012-12-12 21:15:54 +000090 resources.maxLights = 32;
91 resources.maxClipPlanes = 6;
92 resources.maxTextureUnits = 32;
93 resources.maxTextureCoords = 32;
94 resources.maxVertexAttribs = 64;
95 resources.maxVertexUniformComponents = 4096;
96 resources.maxVaryingFloats = 64;
97 resources.maxVertexTextureImageUnits = 32;
98 resources.maxCombinedTextureImageUnits = 32;
99 resources.maxTextureImageUnits = 32;
100 resources.maxFragmentUniformComponents = 4096;
101 resources.maxDrawBuffers = 32;
John Kessenichbd0747d2013-02-17 06:01:50 +0000102 resources.maxVertexUniformVectors = 128;
103 resources.maxVaryingVectors = 8;
104 resources.maxFragmentUniformVectors = 16;
105 resources.maxVertexOutputVectors = 16;
John Kessenich1f2a36b2013-02-20 04:42:42 +0000106 resources.maxFragmentInputVectors = 15;
John Kessenichbd0747d2013-02-17 06:01:50 +0000107 resources.minProgramTexelOffset = -8;
108 resources.maxProgramTexelOffset = 7;
John Kessenicha0af4732012-12-12 21:15:54 +0000109}
110
111int C_DECL main(int argc, char* argv[])
112{
113 bool delay = false;
114 int numCompilers = 0;
115 bool compileFailed = false;
116 bool linkFailed = false;
117 int debugOptions = 0;
118 int i;
119
120 ShHandle linker = 0;
121 ShHandle uniformMap = 0;
122 ShHandle compilers[EShLangCount];
123
124 ShInitialize();
125
126#ifdef _WIN32
127 __try {
128#endif
129 argc--;
130 argv++;
131 for (; argc >= 1; argc--, argv++) {
John Kessenichd7c120f2013-03-12 17:52:59 +0000132 if (argv[0][0] == '-') {
John Kessenicha0af4732012-12-12 21:15:54 +0000133 switch (argv[0][1]) {
John Kessenich8df53cc2013-04-14 19:23:50 +0000134 case 'd':
135 delay = true;
136 break;
137 case 'i':
138 debugOptions |= EDebugOpIntermediate;
139 break;
140 case 'a':
141 debugOptions |= EDebugOpAssembly;
142 break;
143 case 'l':
144 debugOptions |= EDebugOpMemoryLeakMode;
145 break;
John Kessenich52ac67e2013-05-05 23:46:22 +0000146 case 'r':
147 debugOptions |= EDebugOpRelaxedErrors;
148 break;
John Kessenich8df53cc2013-04-14 19:23:50 +0000149 case 's':
150 debugOptions |= EDebugOpSuppressInfolog;
151 break;
152 case 't':
153 debugOptions |= EDebugOpTexturePrototypes;
154 break;
155 default:
156 usage();
157 return EFailUsage;
John Kessenicha0af4732012-12-12 21:15:54 +0000158 }
159 } else {
160 compilers[numCompilers] = ShConstructCompiler(FindLanguage(argv[0]), debugOptions);
161 if (compilers[numCompilers] == 0)
162 return EFailCompilerCreate;
163 ++numCompilers;
164
165 TBuiltInResource resources;
166 GenerateResources(resources);
167 if (! CompileFile(argv[0], compilers[numCompilers-1], debugOptions, &resources))
168 compileFailed = true;
169 }
170 }
171
172 if (!numCompilers) {
173 usage();
174 return EFailUsage;
175 }
176
177 linker = ShConstructLinker(EShExVertexFragment, debugOptions);
178 if (linker == 0)
179 return EFailLinkerCreate;
180
181 uniformMap = ShConstructUniformMap();
182 if (uniformMap == 0)
183 return EFailLinkerCreate;
184
185 if (numCompilers > 0) {
186 ShSetFixedAttributeBindings(linker, &FixedAttributeTable);
187 if (! ShLink(linker, compilers, numCompilers, uniformMap, 0, 0))
188 linkFailed = true;
189 }
190
John Kessenich8df53cc2013-04-14 19:23:50 +0000191 if (! (debugOptions & EDebugOpSuppressInfolog)) {
192 for (i = 0; i < numCompilers; ++i) {
193 InfoLogMsg("BEGIN", "COMPILER", i);
194 puts(ShGetInfoLog(compilers[i]));
195 InfoLogMsg("END", "COMPILER", i);
196 }
John Kessenicha0af4732012-12-12 21:15:54 +0000197
John Kessenich8df53cc2013-04-14 19:23:50 +0000198 InfoLogMsg("BEGIN", "LINKER", -1);
199 puts(ShGetInfoLog(linker));
200 InfoLogMsg("END", "LINKER", -1);
201 }
John Kessenicha0af4732012-12-12 21:15:54 +0000202
203#ifdef _WIN32
204 } __finally {
205#endif
206 for (i = 0; i < numCompilers; ++i)
207 ShDestruct(compilers[i]);
208
209 ShDestruct(linker);
210 ShDestruct(uniformMap);
211
212#ifdef _WIN32
213 if (delay)
214 Sleep(1000000);
215
216 }
217#endif
218
219 if (compileFailed)
220 return EFailCompile;
221 if (linkFailed)
222 return EFailLink;
223
224 return 0;
225}
226
227//
228// Deduce the language from the filename. Files must end in one of the
229// following extensions:
230//
231// .frag* = fragment programs
232// .vert* = vertex programs
John Kessenicha0af4732012-12-12 21:15:54 +0000233//
234static EShLanguage FindLanguage(char *name)
235{
236 if (!name)
John Kesseniche95ecc52012-12-12 21:34:14 +0000237 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000238
239 char *ext = strrchr(name, '.');
240
241 if (ext && strcmp(ext, ".sl") == 0)
242 for (; ext > name && ext[0] != '.'; ext--);
243
244 if (ext = strrchr(name, '.')) {
245 if (strncmp(ext, ".frag", 4) == 0) return EShLangFragment;
John Kessenicha0af4732012-12-12 21:15:54 +0000246 }
247
John Kesseniche95ecc52012-12-12 21:34:14 +0000248 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000249}
250
251
252//
253// Read a file's data into a string, and compile it using ShCompile
254//
John Kessenich54d8cda2013-02-11 22:36:01 +0000255bool CompileFile(const char *fileName, ShHandle compiler, int debugOptions, const TBuiltInResource *resources)
John Kessenicha0af4732012-12-12 21:15:54 +0000256{
257 int ret;
258 char **data = ReadFileData(fileName);
John Kessenich09da79e2013-04-17 19:34:23 +0000259
260#ifdef _WIN32
John Kessenich8df53cc2013-04-14 19:23:50 +0000261 PROCESS_MEMORY_COUNTERS counters; // just for memory leak testing
John Kessenich09da79e2013-04-17 19:34:23 +0000262#endif
John Kessenicha0af4732012-12-12 21:15:54 +0000263
264 if (!data)
265 return false;
266
John Kessenich52ac67e2013-05-05 23:46:22 +0000267 EShMessages messages = EShMsgDefault;
268 if (debugOptions & EDebugOpRelaxedErrors)
269 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
John Kessenich8df53cc2013-04-14 19:23:50 +0000270 for (int i = 0; i < ((debugOptions & EDebugOpMemoryLeakMode) ? 100 : 1); ++i) {
271 for (int j = 0; j < ((debugOptions & EDebugOpMemoryLeakMode) ? 100 : 1); ++j)
John Kessenich52ac67e2013-05-05 23:46:22 +0000272 ret = ShCompile(compiler, data, OutputMultipleStrings, EShOptNone, resources, debugOptions, 100, false, messages);
John Kessenicha0af4732012-12-12 21:15:54 +0000273
John Kessenich09da79e2013-04-17 19:34:23 +0000274#ifdef _WIN32
John Kessenich8df53cc2013-04-14 19:23:50 +0000275 if (debugOptions & EDebugOpMemoryLeakMode) {
276 GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters));
277 printf("Working set size: %d\n", counters.WorkingSetSize);
278 }
John Kessenich09da79e2013-04-17 19:34:23 +0000279#endif
John Kessenicha0af4732012-12-12 21:15:54 +0000280 }
John Kessenicha0af4732012-12-12 21:15:54 +0000281
282 FreeFileData(data);
283
284 return ret ? true : false;
285}
286
287
288//
289// print usage to stdout
290//
291void usage()
292{
John Kessenich8df53cc2013-04-14 19:23:50 +0000293 printf("Usage: standalone [ options ] filename\n"
294 "Where: filename = filename ending in .frag* or .vert*\n"
295 "-i: intermediate (glslang AST)\n"
296 "-a: assembly dump (LLVM IR)\n"
297 "-d: delay end (keeps output up in debugger, WIN32)\n"
298 "-l: memory leak mode\n"
John Kessenich52ac67e2013-05-05 23:46:22 +0000299 "-s: silent mode (no info log)\n"
300 "-r: relaxed semantic error checking mode\n");
John Kessenicha0af4732012-12-12 21:15:54 +0000301}
302
John Kessenichcfd643e2013-03-08 23:14:42 +0000303#ifndef _WIN32
304
305#include <errno.h>
306
307int fopen_s(
308 FILE** pFile,
309 const char *filename,
310 const char *mode
311)
312{
313 if (!pFile || !filename || !mode) {
314 return EINVAL;
315 }
316
317 FILE* f = fopen(filename, mode);
318 if (! f) {
319 if (errno != 0) {
320 return errno;
321 } else {
322 return ENOENT;
323 }
324 }
325 *pFile = f;
326
327 return 0;
328}
329
330#endif
331
John Kessenicha0af4732012-12-12 21:15:54 +0000332//
333// Malloc a string of sufficient size and read a string into it.
334//
John Kessenich54d8cda2013-02-11 22:36:01 +0000335char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000336{
John Kessenich200b2732012-12-12 21:21:23 +0000337 FILE *in;
338 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000339 char *fdata;
340 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000341 const int maxSourceStrings = 5;
342 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000343
344 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000345 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000346 printf("Error: unable to open input file: %s\n", fileName);
347 return 0;
348 }
349
350 while (fgetc(in) != EOF)
351 count++;
352
353 fseek(in, 0, SEEK_SET);
354
355
356 if (!(fdata = (char *)malloc(count+2))) {
357 printf("Error allocating memory\n");
358 return 0;
359 }
360 if (fread(fdata,1,count, in)!=count) {
361 printf("Error reading input file: %s\n", fileName);
362 return 0;
363 }
364 fdata[count] = '\0';
365 fclose(in);
366 if(count==0){
367 return_data[0]=(char*)malloc(count+2);
368 return_data[0][0]='\0';
369 OutputMultipleStrings=0;
370 return return_data;
371 }
372
373 int len = (int)(ceil)((float)count/(float)OutputMultipleStrings);
374 int ptr_len=0,i=0;
375 while(count>0){
376 return_data[i]=(char*)malloc(len+2);
377 memcpy(return_data[i],fdata+ptr_len,len);
378 return_data[i][len]='\0';
379 count-=(len);
380 ptr_len+=(len);
381 if(count<len){
382 if(count==0){
383 OutputMultipleStrings=(i+1);
384 break;
385 }
386 len = count;
387 }
388 ++i;
389 }
390 return return_data;
391}
392
393
394
395void FreeFileData(char **data)
396{
397 for(int i=0;i<OutputMultipleStrings;i++)
398 free(data[i]);
399}
400
401
402
John Kessenich54d8cda2013-02-11 22:36:01 +0000403void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000404{
405 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
406 "#### %s %s INFO LOG ####\n", msg, name, num);
407}