blob: 8e240c62cfd1860b1336e3a8ced6dd94ed9222ce [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//
John Kessenich05a70632013-09-17 19:26:08 +000036
37// this only applies to the standalone wrapper, not the front end in general
38#define _CRT_SECURE_NO_WARNINGS
39
John Kessenich2b07c7e2013-07-31 18:44:13 +000040#include "Worklist.h"
John Kessenicha0af4732012-12-12 21:15:54 +000041#include "./../glslang/Include/ShHandle.h"
42#include "./../glslang/Public/ShaderLang.h"
43#include <string.h>
John Kessenichcfd643e2013-03-08 23:14:42 +000044#include <stdlib.h>
John Kessenicha0af4732012-12-12 21:15:54 +000045#include <math.h>
46
John Kessenich2b07c7e2013-07-31 18:44:13 +000047#include "osinclude.h"
John Kessenicha0af4732012-12-12 21:15:54 +000048
49extern "C" {
50 SH_IMPORT_EXPORT void ShOutputHtml();
51}
52
John Kessenich94a81fb2013-08-31 02:41:30 +000053// Command-line options
54enum TOptions {
55 EOptionNone = 0x000,
56 EOptionIntermediate = 0x001,
57 EOptionSuppressInfolog = 0x002,
58 EOptionMemoryLeakMode = 0x004,
59 EOptionRelaxedErrors = 0x008,
60 EOptionGiveWarnings = 0x010,
61 EOptionsLinkProgram = 0x020,
John Kessenich38f3b892013-09-06 19:52:57 +000062 EOptionMultiThreaded = 0x040,
John Kessenich05a70632013-09-17 19:26:08 +000063 EOptionDumpConfig = 0x080,
John Kessenich11f9fc72013-11-07 01:06:34 +000064 EOptionDumpReflection = 0x100,
John Kessenichb0a7eb52013-11-07 17:44:20 +000065 EOptionSuppressWarnings = 0x200,
John Kessenich94a81fb2013-08-31 02:41:30 +000066};
67
John Kessenicha0af4732012-12-12 21:15:54 +000068//
69// Return codes from main.
70//
71enum TFailCode {
72 ESuccess = 0,
73 EFailUsage,
74 EFailCompile,
75 EFailLink,
76 EFailCompilerCreate,
John Kessenich2b07c7e2013-07-31 18:44:13 +000077 EFailThreadCreate,
John Kessenicha0af4732012-12-12 21:15:54 +000078 EFailLinkerCreate
79};
80
81//
82// Just placeholders for testing purposes. The stand-alone environment
83// can't actually do a full link without something specifying real
84// attribute bindings.
85//
86ShBinding FixedAttributeBindings[] = {
87 { "gl_Vertex", 15 },
88 { "gl_Color", 10 },
89 { "gl_Normal", 7 },
90};
91
92ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
93
John Kessenichb603f912013-08-29 00:39:25 +000094EShLanguage FindLanguage(const std::string& name);
John Kessenichc999ba22013-11-07 23:33:24 +000095void CompileFile(const char *fileName, ShHandle);
John Kessenicha0af4732012-12-12 21:15:54 +000096void usage();
John Kessenichea869fb2013-10-28 18:12:06 +000097void FreeFileData(char** data);
98char** ReadFileData(const char* fileName);
John Kessenich54d8cda2013-02-11 22:36:01 +000099void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +0000100
John Kessenichc999ba22013-11-07 23:33:24 +0000101// Globally track if any compile or link failure.
102bool CompileFailed = false;
103bool LinkFailed = false;
104
John Kessenich05a70632013-09-17 19:26:08 +0000105// Use to test breaking up a single shader file into multiple strings.
John Kessenichea869fb2013-10-28 18:12:06 +0000106int NumShaderStrings;
John Kessenicha0af4732012-12-12 21:15:54 +0000107
John Kessenich05a70632013-09-17 19:26:08 +0000108TBuiltInResource Resources;
109std::string ConfigFile;
110
John Kessenicha0af4732012-12-12 21:15:54 +0000111//
John Kessenich05a70632013-09-17 19:26:08 +0000112// These are the default resources for TBuiltInResources, used for both
113// - parsing this string for the case where the user didn't supply one
114// - dumping out a template for user construction of a config file
John Kessenicha0af4732012-12-12 21:15:54 +0000115//
John Kessenich284231c2013-10-22 01:50:39 +0000116const char* DefaultConfig =
117 "MaxLights 32\n"
118 "MaxClipPlanes 6\n"
119 "MaxTextureUnits 32\n"
120 "MaxTextureCoords 32\n"
121 "MaxVertexAttribs 64\n"
122 "MaxVertexUniformComponents 4096\n"
123 "MaxVaryingFloats 64\n"
124 "MaxVertexTextureImageUnits 32\n"
125 "MaxCombinedTextureImageUnits 32\n"
126 "MaxTextureImageUnits 32\n"
127 "MaxFragmentUniformComponents 4096\n"
128 "MaxDrawBuffers 32\n"
129 "MaxVertexUniformVectors 128\n"
130 "MaxVaryingVectors 8\n"
131 "MaxFragmentUniformVectors 16\n"
132 "MaxVertexOutputVectors 16\n"
133 "MaxFragmentInputVectors 15\n"
134 "MinProgramTexelOffset -8\n"
135 "MaxProgramTexelOffset 7\n"
136 "MaxClipDistances 8\n"
137 "MaxComputeWorkGroupCountX 65535\n"
138 "MaxComputeWorkGroupCountY 65535\n"
139 "MaxComputeWorkGroupCountZ 65535\n"
140 "MaxComputeWorkGroupSizeX 1024\n"
141 "MaxComputeWorkGroupSizeX 1024\n"
142 "MaxComputeWorkGroupSizeZ 64\n"
143 "MaxComputeUniformComponents 1024\n"
144 "MaxComputeTextureImageUnits 16\n"
145 "MaxComputeImageUniforms 8\n"
146 "MaxComputeAtomicCounters 8\n"
147 "MaxComputeAtomicCounterBuffers 1\n"
148 "MaxVaryingComponents 60\n"
149 "MaxVertexOutputComponents 64\n"
150 "MaxGeometryInputComponents 64\n"
151 "MaxGeometryOutputComponents 128\n"
152 "MaxFragmentInputComponents 128\n"
153 "MaxImageUnits 8\n"
154 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
155 "MaxImageSamples 0\n"
156 "MaxVertexImageUniforms 0\n"
157 "MaxTessControlImageUniforms 0\n"
158 "MaxTessEvaluationImageUniforms 0\n"
159 "MaxGeometryImageUniforms 0\n"
160 "MaxFragmentImageUniforms 8\n"
161 "MaxCombinedImageUniforms 8\n"
162 "MaxGeometryTextureImageUnits 16\n"
163 "MaxGeometryOutputVertices 256\n"
164 "MaxGeometryTotalOutputComponents 1024\n"
165 "MaxGeometryUniformComponents 1024\n"
166 "MaxGeometryVaryingComponents 64\n"
167 "MaxTessControlInputComponents 128\n"
168 "MaxTessControlOutputComponents 128\n"
169 "MaxTessControlTextureImageUnits 16\n"
170 "MaxTessControlUniformComponents 1024\n"
171 "MaxTessControlTotalOutputComponents 4096\n"
172 "MaxTessEvaluationInputComponents 128\n"
173 "MaxTessEvaluationOutputComponents 128\n"
174 "MaxTessEvaluationTextureImageUnits 16\n"
175 "MaxTessEvaluationUniformComponents 1024\n"
176 "MaxTessPatchComponents 120\n"
177 "MaxPatchVertices 32\n"
178 "MaxTessGenLevel 64\n"
179 "MaxViewports 16\n"
180 "MaxVertexAtomicCounters 0\n"
181 "MaxTessControlAtomicCounters 0\n"
182 "MaxTessEvaluationAtomicCounters 0\n"
183 "MaxGeometryAtomicCounters 0\n"
184 "MaxFragmentAtomicCounters 8\n"
185 "MaxCombinedAtomicCounters 8\n"
186 "MaxAtomicCounterBindings 1\n"
187 "MaxVertexAtomicCounterBuffers 0\n"
188 "MaxTessControlAtomicCounterBuffers 0\n"
189 "MaxTessEvaluationAtomicCounterBuffers 0\n"
190 "MaxGeometryAtomicCounterBuffers 0\n"
191 "MaxFragmentAtomicCounterBuffers 1\n"
192 "MaxCombinedAtomicCounterBuffers 1\n"
193 "MaxAtomicCounterBufferSize 16384\n"
194
195 "nonInductiveForLoops 1\n"
196 "whileLoops 1\n"
197 "doWhileLoops 1\n"
198 "generalUniformIndexing 1\n"
199 "generalAttributeMatrixVectorIndexing 1\n"
200 "generalVaryingIndexing 1\n"
201 "generalSamplerIndexing 1\n"
202 "generalVariableIndexing 1\n"
203 "generalConstantMatrixVectorIndexing 1\n"
204 ;
John Kessenich05a70632013-09-17 19:26:08 +0000205
206//
207// Parse either a .conf file provided by the user or the default string above.
208//
209void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000210{
John Kessenich05a70632013-09-17 19:26:08 +0000211 char** configStrings = 0;
212 char *config = 0;
213 if (ConfigFile.size() > 0) {
John Kessenichea869fb2013-10-28 18:12:06 +0000214 configStrings = ReadFileData(ConfigFile.c_str());
John Kessenich05a70632013-09-17 19:26:08 +0000215 if (configStrings)
216 config = *configStrings;
217 else {
218 printf("Error opening configuration file; will instead use the default configuration\n");
219 usage();
220 }
221 }
222
223 if (config == 0) {
224 config = new char[strlen(DefaultConfig)];
225 strcpy(config, DefaultConfig);
226 }
227
228 const char* delims = " \t\n\r";
229 const char* token = strtok(config, delims);
230 while (token) {
231 const char* valueStr = strtok(0, delims);
232 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
233 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
234 return;
235 }
236 int value = atoi(valueStr);
237
238 if (strcmp(token, "MaxLights") == 0)
239 Resources.maxLights = value;
240 else if (strcmp(token, "MaxClipPlanes") == 0)
241 Resources.maxClipPlanes = value;
242 else if (strcmp(token, "MaxTextureUnits") == 0)
243 Resources.maxTextureUnits = value;
244 else if (strcmp(token, "MaxTextureCoords") == 0)
245 Resources.maxTextureCoords = value;
246 else if (strcmp(token, "MaxVertexAttribs") == 0)
247 Resources.maxVertexAttribs = value;
248 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
249 Resources.maxVertexUniformComponents = value;
250 else if (strcmp(token, "MaxVaryingFloats") == 0)
251 Resources.maxVaryingFloats = value;
252 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
253 Resources.maxVertexTextureImageUnits = value;
254 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
255 Resources.maxCombinedTextureImageUnits = value;
256 else if (strcmp(token, "MaxTextureImageUnits") == 0)
257 Resources.maxTextureImageUnits = value;
258 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
259 Resources.maxFragmentUniformComponents = value;
260 else if (strcmp(token, "MaxDrawBuffers") == 0)
261 Resources.maxDrawBuffers = value;
262 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
263 Resources.maxVertexUniformVectors = value;
264 else if (strcmp(token, "MaxVaryingVectors") == 0)
265 Resources.maxVaryingVectors = value;
266 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
267 Resources.maxFragmentUniformVectors = value;
268 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
269 Resources.maxVertexOutputVectors = value;
270 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
271 Resources.maxFragmentInputVectors = value;
272 else if (strcmp(token, "MinProgramTexelOffset") == 0)
273 Resources.minProgramTexelOffset = value;
274 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
275 Resources.maxProgramTexelOffset = value;
John Kesseniche7c59c12013-10-16 22:28:35 +0000276 else if (strcmp(token, "MaxClipDistances") == 0)
277 Resources.maxClipDistances = value;
John Kessenich284231c2013-10-22 01:50:39 +0000278 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
279 Resources.maxComputeWorkGroupCountX = value;
280 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
281 Resources.maxComputeWorkGroupCountY = value;
282 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
283 Resources.maxComputeWorkGroupCountZ = value;
284 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
285 Resources.maxComputeWorkGroupSizeX = value;
286 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
287 Resources.maxComputeWorkGroupSizeY = value;
288 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
289 Resources.maxComputeWorkGroupSizeZ = value;
290 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
291 Resources.maxComputeUniformComponents = value;
292 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
293 Resources.maxComputeTextureImageUnits = value;
294 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
295 Resources.maxComputeImageUniforms = value;
296 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
297 Resources.maxComputeAtomicCounters = value;
298 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
299 Resources.maxComputeAtomicCounterBuffers = value;
300 else if (strcmp(token, "MaxVaryingComponents") == 0)
301 Resources.maxVaryingComponents = value;
302 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
303 Resources.maxVertexOutputComponents = value;
304 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
305 Resources.maxGeometryInputComponents = value;
306 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
307 Resources.maxGeometryOutputComponents = value;
308 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
309 Resources.maxFragmentInputComponents = value;
310 else if (strcmp(token, "MaxImageUnits") == 0)
311 Resources.maxImageUnits = value;
312 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
313 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
314 else if (strcmp(token, "MaxImageSamples") == 0)
315 Resources.maxImageSamples = value;
316 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
317 Resources.maxVertexImageUniforms = value;
318 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
319 Resources.maxTessControlImageUniforms = value;
320 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
321 Resources.maxTessEvaluationImageUniforms = value;
322 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
323 Resources.maxGeometryImageUniforms = value;
324 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
325 Resources.maxFragmentImageUniforms = value;
326 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
327 Resources.maxCombinedImageUniforms = value;
328 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
329 Resources.maxGeometryTextureImageUnits = value;
330 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
331 Resources.maxGeometryOutputVertices = value;
332 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
333 Resources.maxGeometryTotalOutputComponents = value;
334 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
335 Resources.maxGeometryUniformComponents = value;
336 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
337 Resources.maxGeometryVaryingComponents = value;
338 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
339 Resources.maxTessControlInputComponents = value;
340 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
341 Resources.maxTessControlOutputComponents = value;
342 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
343 Resources.maxTessControlTextureImageUnits = value;
344 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
345 Resources.maxTessControlUniformComponents = value;
346 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
347 Resources.maxTessControlTotalOutputComponents = value;
348 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
349 Resources.maxTessEvaluationInputComponents = value;
350 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
351 Resources.maxTessEvaluationOutputComponents = value;
352 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
353 Resources.maxTessEvaluationTextureImageUnits = value;
354 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
355 Resources.maxTessEvaluationUniformComponents = value;
356 else if (strcmp(token, "MaxTessPatchComponents") == 0)
357 Resources.maxTessPatchComponents = value;
358 else if (strcmp(token, "MaxPatchVertices") == 0)
359 Resources.maxPatchVertices = value;
360 else if (strcmp(token, "MaxTessGenLevel") == 0)
361 Resources.maxTessGenLevel = value;
362 else if (strcmp(token, "MaxViewports") == 0)
363 Resources.maxViewports = value;
364 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
365 Resources.maxVertexAtomicCounters = value;
366 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
367 Resources.maxTessControlAtomicCounters = value;
368 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
369 Resources.maxTessEvaluationAtomicCounters = value;
370 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
371 Resources.maxGeometryAtomicCounters = value;
372 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
373 Resources.maxFragmentAtomicCounters = value;
374 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
375 Resources.maxCombinedAtomicCounters = value;
376 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
377 Resources.maxAtomicCounterBindings = value;
378 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
379 Resources.maxVertexAtomicCounterBuffers = value;
380 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
381 Resources.maxTessControlAtomicCounterBuffers = value;
382 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
383 Resources.maxTessEvaluationAtomicCounterBuffers = value;
384 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
385 Resources.maxGeometryAtomicCounterBuffers = value;
386 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
387 Resources.maxFragmentAtomicCounterBuffers = value;
388 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
389 Resources.maxCombinedAtomicCounterBuffers = value;
390 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
391 Resources.maxAtomicCounterBufferSize = value;
392
John Kessenicha5830df2013-10-02 05:10:48 +0000393 else if (strcmp(token, "nonInductiveForLoops") == 0)
394 Resources.limits.nonInductiveForLoops = (value != 0);
395 else if (strcmp(token, "whileLoops") == 0)
396 Resources.limits.whileLoops = (value != 0);
397 else if (strcmp(token, "doWhileLoops") == 0)
398 Resources.limits.doWhileLoops = (value != 0);
399 else if (strcmp(token, "generalUniformIndexing") == 0)
400 Resources.limits.generalUniformIndexing = (value != 0);
401 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
402 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
403 else if (strcmp(token, "generalVaryingIndexing") == 0)
404 Resources.limits.generalVaryingIndexing = (value != 0);
405 else if (strcmp(token, "generalSamplerIndexing") == 0)
406 Resources.limits.generalSamplerIndexing = (value != 0);
407 else if (strcmp(token, "generalVariableIndexing") == 0)
408 Resources.limits.generalVariableIndexing = (value != 0);
409 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
410 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
John Kessenich05a70632013-09-17 19:26:08 +0000411 else
412 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
413
414 token = strtok(0, delims);
415 }
416 if (configStrings)
417 FreeFileData(configStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000418}
419
John Kessenich38f3b892013-09-06 19:52:57 +0000420// thread-safe list of shaders to asynchronously grab and compile
John Kessenich2b07c7e2013-07-31 18:44:13 +0000421glslang::TWorklist Worklist;
John Kessenich38f3b892013-09-06 19:52:57 +0000422
423// array of unique places to leave the shader names and infologs for the asynchronous compiles
424glslang::TWorkItem **Work = 0;
425int NumWorkItems = 0;
426
John Kessenich94a81fb2013-08-31 02:41:30 +0000427int Options = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000428bool Delay = false;
John Kessenich38f3b892013-09-06 19:52:57 +0000429const char* ExecutableName;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000430
John Kessenich05a70632013-09-17 19:26:08 +0000431//
432// *.conf => this is a config file that can set limits/resources
433//
434bool SetConfigFile(const std::string& name)
435{
436 if (name.size() < 5)
437 return false;
438
John Kessenich4c706852013-10-11 16:28:43 +0000439 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000440 ConfigFile = name;
441 return true;
442 }
443
444 return false;
445}
446
John Kessenich2b07c7e2013-07-31 18:44:13 +0000447bool ProcessArguments(int argc, char* argv[])
448{
John Kessenich38f3b892013-09-06 19:52:57 +0000449 ExecutableName = argv[0];
450 NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
451 Work = new glslang::TWorkItem*[NumWorkItems];
452 Work[0] = 0;
453
John Kessenich2b07c7e2013-07-31 18:44:13 +0000454 argc--;
455 argv++;
456 for (; argc >= 1; argc--, argv++) {
John Kessenich05a70632013-09-17 19:26:08 +0000457 Work[argc] = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000458 if (argv[0][0] == '-') {
459 switch (argv[0][1]) {
John Kessenich05a70632013-09-17 19:26:08 +0000460 case 'c':
461 Options |= EOptionDumpConfig;
462 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000463 case 'd':
464 Delay = true;
465 break;
John Kessenich05a70632013-09-17 19:26:08 +0000466 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000467 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000468 break;
469 case 'l':
John Kessenich94a81fb2013-08-31 02:41:30 +0000470 Options |= EOptionsLinkProgram;
471 break;
472 case 'm':
473 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000474 break;
John Kessenich11f9fc72013-11-07 01:06:34 +0000475 case 'q':
476 Options |= EOptionDumpReflection;
477 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000478 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000479 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000480 break;
481 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000482 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000483 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000484 case 't':
485 #ifdef _WIN32
John Kessenichb0a7eb52013-11-07 17:44:20 +0000486 Options |= EOptionMultiThreaded;
John Kessenich38f3b892013-09-06 19:52:57 +0000487 #endif
488 break;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000489 case 'w':
490 Options |= EOptionSuppressWarnings;
491 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000492 default:
John Kessenich2b07c7e2013-07-31 18:44:13 +0000493 return false;
494 }
John Kessenich38f3b892013-09-06 19:52:57 +0000495 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000496 std::string name(argv[0]);
497 if (! SetConfigFile(name)) {
498 Work[argc] = new glslang::TWorkItem(name);
499 Worklist.add(Work[argc]);
500 }
John Kessenich38f3b892013-09-06 19:52:57 +0000501 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000502 }
503
504 return true;
505}
506
John Kessenichb0a7eb52013-11-07 17:44:20 +0000507void SetMessageOptions(EShMessages& messages)
508{
509 if (Options & EOptionRelaxedErrors)
510 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
511 if (Options & EOptionIntermediate)
512 messages = (EShMessages)(messages | EShMsgAST);
513 if (Options & EOptionSuppressWarnings)
514 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
515}
516
John Kessenich69f4b512013-09-04 21:19:27 +0000517// Thread entry point, for non-linking asynchronous mode.
John Kessenichc999ba22013-11-07 23:33:24 +0000518//
519// Return 0 for failure, 1 for success.
520//
John Kessenichee6a9c82013-07-31 23:19:17 +0000521unsigned int
522#ifdef _WIN32
523 __stdcall
524#endif
John Kessenich94a81fb2013-08-31 02:41:30 +0000525CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000526{
John Kessenich38f3b892013-09-06 19:52:57 +0000527 glslang::TWorkItem* workItem;
528 while (Worklist.remove(workItem)) {
529 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000530 if (compiler == 0)
John Kessenichc999ba22013-11-07 23:33:24 +0000531 return 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000532
John Kessenichb0a7eb52013-11-07 17:44:20 +0000533 CompileFile(workItem->name.c_str(), compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000534
John Kessenich94a81fb2013-08-31 02:41:30 +0000535 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000536 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000537
538 ShDestruct(compiler);
539 }
540
541 return 0;
542}
543
John Kessenich69f4b512013-09-04 21:19:27 +0000544//
545// For linking mode: Will independently parse each item in the worklist, but then put them
546// in the same program and link them together.
547//
548// Uses the new C++ interface instead of the old handle-based interface.
549//
550void CompileAndLinkShaders()
551{
552 // keep track of what to free
553 std::list<glslang::TShader*> shaders;
John Kessenichbf63ef02013-11-14 00:16:43 +0000554
555 //printf("%s\n", glslang::GetEsslVersionString());
556 //printf("%s\n", glslang::GetGlslVersionString());
John Kessenich69f4b512013-09-04 21:19:27 +0000557
558 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000559 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000560
John Kessenich69f4b512013-09-04 21:19:27 +0000561 //
562 // Per-shader processing...
563 //
564
John Kessenich5b0f13a2013-11-01 03:08:40 +0000565 glslang::TProgram& program = *new glslang::TProgram;
John Kessenich38f3b892013-09-06 19:52:57 +0000566 glslang::TWorkItem* workItem;
567 while (Worklist.remove(workItem)) {
568 EShLanguage stage = FindLanguage(workItem->name);
John Kessenich69f4b512013-09-04 21:19:27 +0000569 glslang::TShader* shader = new glslang::TShader(stage);
570 shaders.push_back(shader);
571
John Kessenich38f3b892013-09-06 19:52:57 +0000572 char** shaderStrings = ReadFileData(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000573 if (! shaderStrings) {
574 usage();
575 return;
576 }
577
578 shader->setStrings(shaderStrings, 1);
579
John Kessenichc999ba22013-11-07 23:33:24 +0000580 if (! shader->parse(&Resources, 100, false, messages))
581 CompileFailed = true;
John Kessenich69f4b512013-09-04 21:19:27 +0000582
583 program.addShader(shader);
584
585 if (! (Options & EOptionSuppressInfolog)) {
John Kessenich38f3b892013-09-06 19:52:57 +0000586 puts(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000587 puts(shader->getInfoLog());
588 puts(shader->getInfoDebugLog());
589 }
590
591 FreeFileData(shaderStrings);
592 }
593
594 //
595 // Program-level processing...
596 //
597
John Kessenichc999ba22013-11-07 23:33:24 +0000598 if (! program.link(messages))
599 LinkFailed = true;
600
John Kessenich69f4b512013-09-04 21:19:27 +0000601 if (! (Options & EOptionSuppressInfolog)) {
602 puts(program.getInfoLog());
603 puts(program.getInfoDebugLog());
604 }
605
John Kessenich11f9fc72013-11-07 01:06:34 +0000606 if (Options & EOptionDumpReflection) {
607 program.buildReflection();
608 program.dumpReflection();
609 }
610
John Kessenich5b0f13a2013-11-01 03:08:40 +0000611 // Free everything up, program has to go before the shaders
612 // because it might have merged stuff from the shaders, and
613 // the stuff from the shaders has to have its destructors called
614 // before the pools holding the memory in the shaders is freed.
615 delete &program;
John Kessenich69f4b512013-09-04 21:19:27 +0000616 while (shaders.size() > 0) {
617 delete shaders.back();
618 shaders.pop_back();
619 }
John Kessenich69f4b512013-09-04 21:19:27 +0000620}
621
John Kessenicha0af4732012-12-12 21:15:54 +0000622int C_DECL main(int argc, char* argv[])
623{
John Kessenich54f6e562013-08-03 00:04:10 +0000624 if (! ProcessArguments(argc, argv)) {
625 usage();
John Kessenich2b07c7e2013-07-31 18:44:13 +0000626 return EFailUsage;
John Kessenich54f6e562013-08-03 00:04:10 +0000627 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000628
John Kessenich05a70632013-09-17 19:26:08 +0000629 if (Options & EOptionDumpConfig) {
630 printf("%s", DefaultConfig);
631 if (Worklist.empty())
632 return ESuccess;
633 }
634
635 if (Worklist.empty()) {
636 usage();
637 return EFailUsage;
638 }
639
640 ProcessConfigFile();
641
John Kessenich69f4b512013-09-04 21:19:27 +0000642 //
643 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000644 // 1) linking all arguments together, single-threaded, new C++ interface
645 // 2) independent arguments, can be tackled by multiple asynchronous threads, for testing thread safety, using the old handle interface
John Kessenich69f4b512013-09-04 21:19:27 +0000646 //
John Kessenichc36e1d82013-11-01 17:41:52 +0000647 if (Options & EOptionsLinkProgram) {
648 glslang::InitializeProcess();
John Kessenich38f3b892013-09-06 19:52:57 +0000649 CompileAndLinkShaders();
John Kessenichc36e1d82013-11-01 17:41:52 +0000650 glslang::FinalizeProcess();
651 } else {
652 ShInitialize();
653
John Kessenich38f3b892013-09-06 19:52:57 +0000654 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000655
John Kessenich38f3b892013-09-06 19:52:57 +0000656 if (Options & EOptionMultiThreaded) {
657 const int NumThreads = 16;
658 void* threads[NumThreads];
659 for (int t = 0; t < NumThreads; ++t) {
660 threads[t] = glslang::OS_CreateThread(&CompileShaders);
661 if (! threads[t]) {
662 printf("Failed to create thread\n");
663 return EFailThreadCreate;
664 }
John Kessenicha0af4732012-12-12 21:15:54 +0000665 }
John Kessenich38f3b892013-09-06 19:52:57 +0000666 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenichc999ba22013-11-07 23:33:24 +0000667 } else
668 CompileShaders(0);
John Kessenich38f3b892013-09-06 19:52:57 +0000669
670 // Print out all the resulting infologs
671 for (int w = 0; w < NumWorkItems; ++w) {
672 if (Work[w]) {
673 if (printShaderNames)
674 puts(Work[w]->name.c_str());
675 puts(Work[w]->results.c_str());
676 delete Work[w];
677 }
678 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000679
680 ShFinalize();
John Kessenicha0af4732012-12-12 21:15:54 +0000681 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000682
683 if (Delay)
684 glslang::OS_Sleep(1000000);
John Kessenicha0af4732012-12-12 21:15:54 +0000685
John Kessenichc999ba22013-11-07 23:33:24 +0000686 if (CompileFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000687 return EFailCompile;
John Kessenichc999ba22013-11-07 23:33:24 +0000688 if (LinkFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000689 return EFailLink;
690
691 return 0;
692}
693
694//
695// Deduce the language from the filename. Files must end in one of the
696// following extensions:
697//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000698// .vert = vertex
699// .tesc = tessellation control
700// .tese = tessellation evaluation
701// .geom = geometry
702// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000703// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000704//
John Kessenichb603f912013-08-29 00:39:25 +0000705EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000706{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000707 size_t ext = name.rfind('.');
708 if (ext == std::string::npos) {
709 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000710 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000711 }
712
John Kessenich2b07c7e2013-07-31 18:44:13 +0000713 std::string suffix = name.substr(ext + 1, std::string::npos);
714 if (suffix == "vert")
715 return EShLangVertex;
716 else if (suffix == "tesc")
717 return EShLangTessControl;
718 else if (suffix == "tese")
719 return EShLangTessEvaluation;
720 else if (suffix == "geom")
721 return EShLangGeometry;
722 else if (suffix == "frag")
723 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000724 else if (suffix == "comp")
725 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000726
727 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000728 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000729}
730
John Kessenicha0af4732012-12-12 21:15:54 +0000731//
John Kessenich69f4b512013-09-04 21:19:27 +0000732// Read a file's data into a string, and compile it using the old interface ShCompile,
733// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000734//
John Kessenichc999ba22013-11-07 23:33:24 +0000735void CompileFile(const char *fileName, ShHandle compiler)
John Kessenicha0af4732012-12-12 21:15:54 +0000736{
737 int ret;
John Kessenich41cf6b52013-06-25 18:10:05 +0000738 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000739 if (! shaderStrings) {
740 usage();
John Kessenichc999ba22013-11-07 23:33:24 +0000741 CompileFailed = true;
742 return;
John Kessenichdb4cd542013-06-26 22:42:55 +0000743 }
744
John Kessenich41cf6b52013-06-25 18:10:05 +0000745 int* lengths = new int[NumShaderStrings];
746
747 // move to length-based strings, rather than null-terminated strings
748 for (int s = 0; s < NumShaderStrings; ++s)
749 lengths[s] = strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000750
John Kessenichc999ba22013-11-07 23:33:24 +0000751 if (! shaderStrings) {
752 CompileFailed = true;
753 return;
754 }
John Kessenicha0af4732012-12-12 21:15:54 +0000755
John Kessenich52ac67e2013-05-05 23:46:22 +0000756 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000757 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000758
John Kessenich94a81fb2013-08-31 02:41:30 +0000759 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
760 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich05a70632013-09-17 19:26:08 +0000761 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, 100, false, messages);
762 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenichea869fb2013-10-28 18:12:06 +0000763 //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
764 // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
765 // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
John Kessenich41cf6b52013-06-25 18:10:05 +0000766 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenichea869fb2013-10-28 18:12:06 +0000767 //ret = ShCompile(compiler, multi, 7, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000768 }
John Kessenicha0af4732012-12-12 21:15:54 +0000769
John Kessenich94a81fb2013-08-31 02:41:30 +0000770 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000771 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +0000772 }
John Kessenicha0af4732012-12-12 21:15:54 +0000773
John Kessenich41cf6b52013-06-25 18:10:05 +0000774 delete [] lengths;
775 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000776
John Kessenichc999ba22013-11-07 23:33:24 +0000777 if (ret == 0)
778 CompileFailed = true;
John Kessenicha0af4732012-12-12 21:15:54 +0000779}
780
John Kessenicha0af4732012-12-12 21:15:54 +0000781//
782// print usage to stdout
783//
784void usage()
785{
John Kessenich38f3b892013-09-06 19:52:57 +0000786 printf("Usage: glslangValidator [ options ] filename\n"
John Kessenichc0275792013-08-09 17:14:49 +0000787 "Where: filename is a name ending in\n"
John Kessenich05a70632013-09-17 19:26:08 +0000788 " .conf provides an optional config file that replaces the default configuration\n"
789 " (see -c option below for generating a template)\n"
John Kessenichc0275792013-08-09 17:14:49 +0000790 " .vert for a vertex shader\n"
791 " .tesc for a tessellation control shader\n"
792 " .tese for a tessellation evaluation shader\n"
793 " .geom for a geometry shader\n"
794 " .frag for a fragment shader\n"
795 " .comp for a compute shader\n\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000796 "Compilation warnings and errors will be printed to stdout.\n"
797 "To get other information, use one of the following options:\n"
John Kessenich05a70632013-09-17 19:26:08 +0000798 "-c: configuration dump; use to create default configuration file (redirect to a .conf file)\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000799 "-i: intermediate tree (glslang AST) is printed out\n"
John Kessenich94a81fb2013-08-31 02:41:30 +0000800 "-l: link validation of all input files\n"
801 "-m: memory leak mode\n"
John Kessenich11f9fc72013-11-07 01:06:34 +0000802 "-q: dump reflection query database\n"
John Kessenich38f3b892013-09-06 19:52:57 +0000803 "-r: relaxed semantic error-checking mode\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000804 "-s: silent mode\n"
John Kessenichb0a7eb52013-11-07 17:44:20 +0000805 "-t: multi-threaded mode\n"
806 "-w: suppress warnings (except as required by #extension : warn)\n"
807 );
John Kessenicha0af4732012-12-12 21:15:54 +0000808}
809
John Kessenichcfd643e2013-03-08 23:14:42 +0000810#ifndef _WIN32
811
812#include <errno.h>
813
814int fopen_s(
815 FILE** pFile,
816 const char *filename,
817 const char *mode
818)
819{
820 if (!pFile || !filename || !mode) {
821 return EINVAL;
822 }
823
824 FILE* f = fopen(filename, mode);
825 if (! f) {
826 if (errno != 0) {
827 return errno;
828 } else {
829 return ENOENT;
830 }
831 }
832 *pFile = f;
833
834 return 0;
835}
836
837#endif
838
John Kessenicha0af4732012-12-12 21:15:54 +0000839//
840// Malloc a string of sufficient size and read a string into it.
841//
John Kessenich54d8cda2013-02-11 22:36:01 +0000842char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000843{
John Kessenich200b2732012-12-12 21:21:23 +0000844 FILE *in;
845 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000846 char *fdata;
847 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000848 const int maxSourceStrings = 5;
849 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000850
851 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000852 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000853 printf("Error: unable to open input file: %s\n", fileName);
854 return 0;
855 }
856
857 while (fgetc(in) != EOF)
858 count++;
859
860 fseek(in, 0, SEEK_SET);
861
862
863 if (!(fdata = (char *)malloc(count+2))) {
864 printf("Error allocating memory\n");
865 return 0;
866 }
867 if (fread(fdata,1,count, in)!=count) {
868 printf("Error reading input file: %s\n", fileName);
869 return 0;
870 }
871 fdata[count] = '\0';
872 fclose(in);
John Kessenichea869fb2013-10-28 18:12:06 +0000873 if (count == 0) {
John Kessenicha0af4732012-12-12 21:15:54 +0000874 return_data[0]=(char*)malloc(count+2);
875 return_data[0][0]='\0';
John Kessenichea869fb2013-10-28 18:12:06 +0000876 NumShaderStrings = 0;
John Kessenicha0af4732012-12-12 21:15:54 +0000877 return return_data;
John Kessenichea869fb2013-10-28 18:12:06 +0000878 } else
879 NumShaderStrings = 1;
John Kessenicha0af4732012-12-12 21:15:54 +0000880
John Kessenich41cf6b52013-06-25 18:10:05 +0000881 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000882 int ptr_len=0,i=0;
883 while(count>0){
884 return_data[i]=(char*)malloc(len+2);
885 memcpy(return_data[i],fdata+ptr_len,len);
886 return_data[i][len]='\0';
887 count-=(len);
888 ptr_len+=(len);
889 if(count<len){
890 if(count==0){
John Kessenich41cf6b52013-06-25 18:10:05 +0000891 NumShaderStrings=(i+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000892 break;
893 }
894 len = count;
895 }
896 ++i;
897 }
898 return return_data;
899}
900
John Kessenicha0af4732012-12-12 21:15:54 +0000901void FreeFileData(char **data)
902{
John Kessenich41cf6b52013-06-25 18:10:05 +0000903 for(int i=0;i<NumShaderStrings;i++)
John Kessenicha0af4732012-12-12 21:15:54 +0000904 free(data[i]);
905}
906
John Kessenich54d8cda2013-02-11 22:36:01 +0000907void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000908{
909 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
910 "#### %s %s INFO LOG ####\n", msg, name, num);
911}