blob: ba910f82b43a442b681bf042ac88f914bfc52e03 [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 Kessenich319de232013-12-04 04:43:40 +000066 EOptionDumpVersions = 0x400,
John Kessenich94a81fb2013-08-31 02:41:30 +000067};
68
John Kessenicha0af4732012-12-12 21:15:54 +000069//
70// Return codes from main.
71//
72enum TFailCode {
73 ESuccess = 0,
74 EFailUsage,
75 EFailCompile,
76 EFailLink,
77 EFailCompilerCreate,
John Kessenich2b07c7e2013-07-31 18:44:13 +000078 EFailThreadCreate,
John Kessenicha0af4732012-12-12 21:15:54 +000079 EFailLinkerCreate
80};
81
82//
83// Just placeholders for testing purposes. The stand-alone environment
84// can't actually do a full link without something specifying real
85// attribute bindings.
86//
87ShBinding FixedAttributeBindings[] = {
88 { "gl_Vertex", 15 },
89 { "gl_Color", 10 },
90 { "gl_Normal", 7 },
91};
92
93ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
94
John Kessenichb603f912013-08-29 00:39:25 +000095EShLanguage FindLanguage(const std::string& name);
John Kessenichc999ba22013-11-07 23:33:24 +000096void CompileFile(const char *fileName, ShHandle);
John Kessenicha0af4732012-12-12 21:15:54 +000097void usage();
John Kessenichea869fb2013-10-28 18:12:06 +000098void FreeFileData(char** data);
99char** ReadFileData(const char* fileName);
John Kessenich54d8cda2013-02-11 22:36:01 +0000100void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +0000101
John Kessenichc999ba22013-11-07 23:33:24 +0000102// Globally track if any compile or link failure.
103bool CompileFailed = false;
104bool LinkFailed = false;
105
John Kessenich05a70632013-09-17 19:26:08 +0000106// Use to test breaking up a single shader file into multiple strings.
John Kessenichea869fb2013-10-28 18:12:06 +0000107int NumShaderStrings;
John Kessenicha0af4732012-12-12 21:15:54 +0000108
John Kessenich05a70632013-09-17 19:26:08 +0000109TBuiltInResource Resources;
110std::string ConfigFile;
111
John Kessenicha0af4732012-12-12 21:15:54 +0000112//
John Kessenich05a70632013-09-17 19:26:08 +0000113// These are the default resources for TBuiltInResources, used for both
114// - parsing this string for the case where the user didn't supply one
115// - dumping out a template for user construction of a config file
John Kessenicha0af4732012-12-12 21:15:54 +0000116//
John Kessenich284231c2013-10-22 01:50:39 +0000117const char* DefaultConfig =
118 "MaxLights 32\n"
119 "MaxClipPlanes 6\n"
120 "MaxTextureUnits 32\n"
121 "MaxTextureCoords 32\n"
122 "MaxVertexAttribs 64\n"
123 "MaxVertexUniformComponents 4096\n"
124 "MaxVaryingFloats 64\n"
125 "MaxVertexTextureImageUnits 32\n"
126 "MaxCombinedTextureImageUnits 32\n"
127 "MaxTextureImageUnits 32\n"
128 "MaxFragmentUniformComponents 4096\n"
129 "MaxDrawBuffers 32\n"
130 "MaxVertexUniformVectors 128\n"
131 "MaxVaryingVectors 8\n"
132 "MaxFragmentUniformVectors 16\n"
133 "MaxVertexOutputVectors 16\n"
134 "MaxFragmentInputVectors 15\n"
135 "MinProgramTexelOffset -8\n"
136 "MaxProgramTexelOffset 7\n"
137 "MaxClipDistances 8\n"
138 "MaxComputeWorkGroupCountX 65535\n"
139 "MaxComputeWorkGroupCountY 65535\n"
140 "MaxComputeWorkGroupCountZ 65535\n"
141 "MaxComputeWorkGroupSizeX 1024\n"
142 "MaxComputeWorkGroupSizeX 1024\n"
143 "MaxComputeWorkGroupSizeZ 64\n"
144 "MaxComputeUniformComponents 1024\n"
145 "MaxComputeTextureImageUnits 16\n"
146 "MaxComputeImageUniforms 8\n"
147 "MaxComputeAtomicCounters 8\n"
148 "MaxComputeAtomicCounterBuffers 1\n"
149 "MaxVaryingComponents 60\n"
150 "MaxVertexOutputComponents 64\n"
151 "MaxGeometryInputComponents 64\n"
152 "MaxGeometryOutputComponents 128\n"
153 "MaxFragmentInputComponents 128\n"
154 "MaxImageUnits 8\n"
155 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
156 "MaxImageSamples 0\n"
157 "MaxVertexImageUniforms 0\n"
158 "MaxTessControlImageUniforms 0\n"
159 "MaxTessEvaluationImageUniforms 0\n"
160 "MaxGeometryImageUniforms 0\n"
161 "MaxFragmentImageUniforms 8\n"
162 "MaxCombinedImageUniforms 8\n"
163 "MaxGeometryTextureImageUnits 16\n"
164 "MaxGeometryOutputVertices 256\n"
165 "MaxGeometryTotalOutputComponents 1024\n"
166 "MaxGeometryUniformComponents 1024\n"
167 "MaxGeometryVaryingComponents 64\n"
168 "MaxTessControlInputComponents 128\n"
169 "MaxTessControlOutputComponents 128\n"
170 "MaxTessControlTextureImageUnits 16\n"
171 "MaxTessControlUniformComponents 1024\n"
172 "MaxTessControlTotalOutputComponents 4096\n"
173 "MaxTessEvaluationInputComponents 128\n"
174 "MaxTessEvaluationOutputComponents 128\n"
175 "MaxTessEvaluationTextureImageUnits 16\n"
176 "MaxTessEvaluationUniformComponents 1024\n"
177 "MaxTessPatchComponents 120\n"
178 "MaxPatchVertices 32\n"
179 "MaxTessGenLevel 64\n"
180 "MaxViewports 16\n"
181 "MaxVertexAtomicCounters 0\n"
182 "MaxTessControlAtomicCounters 0\n"
183 "MaxTessEvaluationAtomicCounters 0\n"
184 "MaxGeometryAtomicCounters 0\n"
185 "MaxFragmentAtomicCounters 8\n"
186 "MaxCombinedAtomicCounters 8\n"
187 "MaxAtomicCounterBindings 1\n"
188 "MaxVertexAtomicCounterBuffers 0\n"
189 "MaxTessControlAtomicCounterBuffers 0\n"
190 "MaxTessEvaluationAtomicCounterBuffers 0\n"
191 "MaxGeometryAtomicCounterBuffers 0\n"
192 "MaxFragmentAtomicCounterBuffers 1\n"
193 "MaxCombinedAtomicCounterBuffers 1\n"
194 "MaxAtomicCounterBufferSize 16384\n"
195
196 "nonInductiveForLoops 1\n"
197 "whileLoops 1\n"
198 "doWhileLoops 1\n"
199 "generalUniformIndexing 1\n"
200 "generalAttributeMatrixVectorIndexing 1\n"
201 "generalVaryingIndexing 1\n"
202 "generalSamplerIndexing 1\n"
203 "generalVariableIndexing 1\n"
204 "generalConstantMatrixVectorIndexing 1\n"
205 ;
John Kessenich05a70632013-09-17 19:26:08 +0000206
207//
208// Parse either a .conf file provided by the user or the default string above.
209//
210void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000211{
John Kessenich05a70632013-09-17 19:26:08 +0000212 char** configStrings = 0;
213 char *config = 0;
214 if (ConfigFile.size() > 0) {
John Kessenichea869fb2013-10-28 18:12:06 +0000215 configStrings = ReadFileData(ConfigFile.c_str());
John Kessenich05a70632013-09-17 19:26:08 +0000216 if (configStrings)
217 config = *configStrings;
218 else {
219 printf("Error opening configuration file; will instead use the default configuration\n");
220 usage();
221 }
222 }
223
224 if (config == 0) {
225 config = new char[strlen(DefaultConfig)];
226 strcpy(config, DefaultConfig);
227 }
228
229 const char* delims = " \t\n\r";
230 const char* token = strtok(config, delims);
231 while (token) {
232 const char* valueStr = strtok(0, delims);
233 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
234 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
235 return;
236 }
237 int value = atoi(valueStr);
238
239 if (strcmp(token, "MaxLights") == 0)
240 Resources.maxLights = value;
241 else if (strcmp(token, "MaxClipPlanes") == 0)
242 Resources.maxClipPlanes = value;
243 else if (strcmp(token, "MaxTextureUnits") == 0)
244 Resources.maxTextureUnits = value;
245 else if (strcmp(token, "MaxTextureCoords") == 0)
246 Resources.maxTextureCoords = value;
247 else if (strcmp(token, "MaxVertexAttribs") == 0)
248 Resources.maxVertexAttribs = value;
249 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
250 Resources.maxVertexUniformComponents = value;
251 else if (strcmp(token, "MaxVaryingFloats") == 0)
252 Resources.maxVaryingFloats = value;
253 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
254 Resources.maxVertexTextureImageUnits = value;
255 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
256 Resources.maxCombinedTextureImageUnits = value;
257 else if (strcmp(token, "MaxTextureImageUnits") == 0)
258 Resources.maxTextureImageUnits = value;
259 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
260 Resources.maxFragmentUniformComponents = value;
261 else if (strcmp(token, "MaxDrawBuffers") == 0)
262 Resources.maxDrawBuffers = value;
263 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
264 Resources.maxVertexUniformVectors = value;
265 else if (strcmp(token, "MaxVaryingVectors") == 0)
266 Resources.maxVaryingVectors = value;
267 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
268 Resources.maxFragmentUniformVectors = value;
269 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
270 Resources.maxVertexOutputVectors = value;
271 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
272 Resources.maxFragmentInputVectors = value;
273 else if (strcmp(token, "MinProgramTexelOffset") == 0)
274 Resources.minProgramTexelOffset = value;
275 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
276 Resources.maxProgramTexelOffset = value;
John Kesseniche7c59c12013-10-16 22:28:35 +0000277 else if (strcmp(token, "MaxClipDistances") == 0)
278 Resources.maxClipDistances = value;
John Kessenich284231c2013-10-22 01:50:39 +0000279 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
280 Resources.maxComputeWorkGroupCountX = value;
281 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
282 Resources.maxComputeWorkGroupCountY = value;
283 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
284 Resources.maxComputeWorkGroupCountZ = value;
285 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
286 Resources.maxComputeWorkGroupSizeX = value;
287 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
288 Resources.maxComputeWorkGroupSizeY = value;
289 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
290 Resources.maxComputeWorkGroupSizeZ = value;
291 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
292 Resources.maxComputeUniformComponents = value;
293 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
294 Resources.maxComputeTextureImageUnits = value;
295 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
296 Resources.maxComputeImageUniforms = value;
297 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
298 Resources.maxComputeAtomicCounters = value;
299 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
300 Resources.maxComputeAtomicCounterBuffers = value;
301 else if (strcmp(token, "MaxVaryingComponents") == 0)
302 Resources.maxVaryingComponents = value;
303 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
304 Resources.maxVertexOutputComponents = value;
305 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
306 Resources.maxGeometryInputComponents = value;
307 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
308 Resources.maxGeometryOutputComponents = value;
309 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
310 Resources.maxFragmentInputComponents = value;
311 else if (strcmp(token, "MaxImageUnits") == 0)
312 Resources.maxImageUnits = value;
313 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
314 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
315 else if (strcmp(token, "MaxImageSamples") == 0)
316 Resources.maxImageSamples = value;
317 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
318 Resources.maxVertexImageUniforms = value;
319 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
320 Resources.maxTessControlImageUniforms = value;
321 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
322 Resources.maxTessEvaluationImageUniforms = value;
323 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
324 Resources.maxGeometryImageUniforms = value;
325 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
326 Resources.maxFragmentImageUniforms = value;
327 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
328 Resources.maxCombinedImageUniforms = value;
329 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
330 Resources.maxGeometryTextureImageUnits = value;
331 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
332 Resources.maxGeometryOutputVertices = value;
333 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
334 Resources.maxGeometryTotalOutputComponents = value;
335 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
336 Resources.maxGeometryUniformComponents = value;
337 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
338 Resources.maxGeometryVaryingComponents = value;
339 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
340 Resources.maxTessControlInputComponents = value;
341 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
342 Resources.maxTessControlOutputComponents = value;
343 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
344 Resources.maxTessControlTextureImageUnits = value;
345 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
346 Resources.maxTessControlUniformComponents = value;
347 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
348 Resources.maxTessControlTotalOutputComponents = value;
349 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
350 Resources.maxTessEvaluationInputComponents = value;
351 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
352 Resources.maxTessEvaluationOutputComponents = value;
353 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
354 Resources.maxTessEvaluationTextureImageUnits = value;
355 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
356 Resources.maxTessEvaluationUniformComponents = value;
357 else if (strcmp(token, "MaxTessPatchComponents") == 0)
358 Resources.maxTessPatchComponents = value;
359 else if (strcmp(token, "MaxPatchVertices") == 0)
360 Resources.maxPatchVertices = value;
361 else if (strcmp(token, "MaxTessGenLevel") == 0)
362 Resources.maxTessGenLevel = value;
363 else if (strcmp(token, "MaxViewports") == 0)
364 Resources.maxViewports = value;
365 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
366 Resources.maxVertexAtomicCounters = value;
367 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
368 Resources.maxTessControlAtomicCounters = value;
369 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
370 Resources.maxTessEvaluationAtomicCounters = value;
371 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
372 Resources.maxGeometryAtomicCounters = value;
373 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
374 Resources.maxFragmentAtomicCounters = value;
375 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
376 Resources.maxCombinedAtomicCounters = value;
377 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
378 Resources.maxAtomicCounterBindings = value;
379 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
380 Resources.maxVertexAtomicCounterBuffers = value;
381 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
382 Resources.maxTessControlAtomicCounterBuffers = value;
383 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
384 Resources.maxTessEvaluationAtomicCounterBuffers = value;
385 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
386 Resources.maxGeometryAtomicCounterBuffers = value;
387 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
388 Resources.maxFragmentAtomicCounterBuffers = value;
389 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
390 Resources.maxCombinedAtomicCounterBuffers = value;
391 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
392 Resources.maxAtomicCounterBufferSize = value;
393
John Kessenicha5830df2013-10-02 05:10:48 +0000394 else if (strcmp(token, "nonInductiveForLoops") == 0)
395 Resources.limits.nonInductiveForLoops = (value != 0);
396 else if (strcmp(token, "whileLoops") == 0)
397 Resources.limits.whileLoops = (value != 0);
398 else if (strcmp(token, "doWhileLoops") == 0)
399 Resources.limits.doWhileLoops = (value != 0);
400 else if (strcmp(token, "generalUniformIndexing") == 0)
401 Resources.limits.generalUniformIndexing = (value != 0);
402 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
403 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
404 else if (strcmp(token, "generalVaryingIndexing") == 0)
405 Resources.limits.generalVaryingIndexing = (value != 0);
406 else if (strcmp(token, "generalSamplerIndexing") == 0)
407 Resources.limits.generalSamplerIndexing = (value != 0);
408 else if (strcmp(token, "generalVariableIndexing") == 0)
409 Resources.limits.generalVariableIndexing = (value != 0);
410 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
411 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
John Kessenich05a70632013-09-17 19:26:08 +0000412 else
413 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
414
415 token = strtok(0, delims);
416 }
417 if (configStrings)
418 FreeFileData(configStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000419}
420
John Kessenich38f3b892013-09-06 19:52:57 +0000421// thread-safe list of shaders to asynchronously grab and compile
John Kessenich2b07c7e2013-07-31 18:44:13 +0000422glslang::TWorklist Worklist;
John Kessenich38f3b892013-09-06 19:52:57 +0000423
424// array of unique places to leave the shader names and infologs for the asynchronous compiles
425glslang::TWorkItem **Work = 0;
426int NumWorkItems = 0;
427
John Kessenich94a81fb2013-08-31 02:41:30 +0000428int Options = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000429bool Delay = false;
John Kessenich38f3b892013-09-06 19:52:57 +0000430const char* ExecutableName;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000431
John Kessenich05a70632013-09-17 19:26:08 +0000432//
433// *.conf => this is a config file that can set limits/resources
434//
435bool SetConfigFile(const std::string& name)
436{
437 if (name.size() < 5)
438 return false;
439
John Kessenich4c706852013-10-11 16:28:43 +0000440 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000441 ConfigFile = name;
442 return true;
443 }
444
445 return false;
446}
447
John Kessenich2b07c7e2013-07-31 18:44:13 +0000448bool ProcessArguments(int argc, char* argv[])
449{
John Kessenich38f3b892013-09-06 19:52:57 +0000450 ExecutableName = argv[0];
451 NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
452 Work = new glslang::TWorkItem*[NumWorkItems];
453 Work[0] = 0;
454
John Kessenich2b07c7e2013-07-31 18:44:13 +0000455 argc--;
456 argv++;
457 for (; argc >= 1; argc--, argv++) {
John Kessenich05a70632013-09-17 19:26:08 +0000458 Work[argc] = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000459 if (argv[0][0] == '-') {
460 switch (argv[0][1]) {
John Kessenich05a70632013-09-17 19:26:08 +0000461 case 'c':
462 Options |= EOptionDumpConfig;
463 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000464 case 'd':
465 Delay = true;
466 break;
John Kessenich05a70632013-09-17 19:26:08 +0000467 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000468 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000469 break;
470 case 'l':
John Kessenich94a81fb2013-08-31 02:41:30 +0000471 Options |= EOptionsLinkProgram;
472 break;
473 case 'm':
474 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000475 break;
John Kessenich11f9fc72013-11-07 01:06:34 +0000476 case 'q':
477 Options |= EOptionDumpReflection;
478 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000479 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000480 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000481 break;
482 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000483 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000484 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000485 case 't':
486 #ifdef _WIN32
John Kessenichb0a7eb52013-11-07 17:44:20 +0000487 Options |= EOptionMultiThreaded;
John Kessenich38f3b892013-09-06 19:52:57 +0000488 #endif
489 break;
John Kessenich319de232013-12-04 04:43:40 +0000490 case 'v':
491 Options |= EOptionDumpVersions;
492 break;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000493 case 'w':
494 Options |= EOptionSuppressWarnings;
495 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000496 default:
John Kessenich2b07c7e2013-07-31 18:44:13 +0000497 return false;
498 }
John Kessenich38f3b892013-09-06 19:52:57 +0000499 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000500 std::string name(argv[0]);
501 if (! SetConfigFile(name)) {
502 Work[argc] = new glslang::TWorkItem(name);
503 Worklist.add(Work[argc]);
504 }
John Kessenich38f3b892013-09-06 19:52:57 +0000505 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000506 }
507
508 return true;
509}
510
John Kessenichb0a7eb52013-11-07 17:44:20 +0000511void SetMessageOptions(EShMessages& messages)
512{
513 if (Options & EOptionRelaxedErrors)
514 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
515 if (Options & EOptionIntermediate)
516 messages = (EShMessages)(messages | EShMsgAST);
517 if (Options & EOptionSuppressWarnings)
518 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
519}
520
John Kessenich69f4b512013-09-04 21:19:27 +0000521// Thread entry point, for non-linking asynchronous mode.
John Kessenichc999ba22013-11-07 23:33:24 +0000522//
523// Return 0 for failure, 1 for success.
524//
John Kessenichee6a9c82013-07-31 23:19:17 +0000525unsigned int
526#ifdef _WIN32
527 __stdcall
528#endif
John Kessenich94a81fb2013-08-31 02:41:30 +0000529CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000530{
John Kessenich38f3b892013-09-06 19:52:57 +0000531 glslang::TWorkItem* workItem;
532 while (Worklist.remove(workItem)) {
533 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000534 if (compiler == 0)
John Kessenichc999ba22013-11-07 23:33:24 +0000535 return 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000536
John Kessenichb0a7eb52013-11-07 17:44:20 +0000537 CompileFile(workItem->name.c_str(), compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000538
John Kessenich94a81fb2013-08-31 02:41:30 +0000539 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000540 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000541
542 ShDestruct(compiler);
543 }
544
545 return 0;
546}
547
John Kessenich69f4b512013-09-04 21:19:27 +0000548//
549// For linking mode: Will independently parse each item in the worklist, but then put them
550// in the same program and link them together.
551//
552// Uses the new C++ interface instead of the old handle-based interface.
553//
554void CompileAndLinkShaders()
555{
556 // keep track of what to free
557 std::list<glslang::TShader*> shaders;
John Kessenichbf63ef02013-11-14 00:16:43 +0000558
John Kessenich69f4b512013-09-04 21:19:27 +0000559 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000560 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000561
John Kessenich69f4b512013-09-04 21:19:27 +0000562 //
563 // Per-shader processing...
564 //
565
John Kessenich5b0f13a2013-11-01 03:08:40 +0000566 glslang::TProgram& program = *new glslang::TProgram;
John Kessenich38f3b892013-09-06 19:52:57 +0000567 glslang::TWorkItem* workItem;
568 while (Worklist.remove(workItem)) {
569 EShLanguage stage = FindLanguage(workItem->name);
John Kessenich69f4b512013-09-04 21:19:27 +0000570 glslang::TShader* shader = new glslang::TShader(stage);
571 shaders.push_back(shader);
572
John Kessenich38f3b892013-09-06 19:52:57 +0000573 char** shaderStrings = ReadFileData(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000574 if (! shaderStrings) {
575 usage();
576 return;
577 }
578
579 shader->setStrings(shaderStrings, 1);
580
John Kessenichc999ba22013-11-07 23:33:24 +0000581 if (! shader->parse(&Resources, 100, false, messages))
582 CompileFailed = true;
John Kessenich69f4b512013-09-04 21:19:27 +0000583
584 program.addShader(shader);
585
586 if (! (Options & EOptionSuppressInfolog)) {
John Kessenich38f3b892013-09-06 19:52:57 +0000587 puts(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000588 puts(shader->getInfoLog());
589 puts(shader->getInfoDebugLog());
590 }
591
592 FreeFileData(shaderStrings);
593 }
594
595 //
596 // Program-level processing...
597 //
598
John Kessenichc999ba22013-11-07 23:33:24 +0000599 if (! program.link(messages))
600 LinkFailed = true;
601
John Kessenich69f4b512013-09-04 21:19:27 +0000602 if (! (Options & EOptionSuppressInfolog)) {
603 puts(program.getInfoLog());
604 puts(program.getInfoDebugLog());
605 }
606
John Kessenich11f9fc72013-11-07 01:06:34 +0000607 if (Options & EOptionDumpReflection) {
608 program.buildReflection();
609 program.dumpReflection();
610 }
611
John Kessenich5b0f13a2013-11-01 03:08:40 +0000612 // Free everything up, program has to go before the shaders
613 // because it might have merged stuff from the shaders, and
614 // the stuff from the shaders has to have its destructors called
615 // before the pools holding the memory in the shaders is freed.
616 delete &program;
John Kessenich69f4b512013-09-04 21:19:27 +0000617 while (shaders.size() > 0) {
618 delete shaders.back();
619 shaders.pop_back();
620 }
John Kessenich69f4b512013-09-04 21:19:27 +0000621}
622
John Kessenicha0af4732012-12-12 21:15:54 +0000623int C_DECL main(int argc, char* argv[])
624{
John Kessenich54f6e562013-08-03 00:04:10 +0000625 if (! ProcessArguments(argc, argv)) {
626 usage();
John Kessenich2b07c7e2013-07-31 18:44:13 +0000627 return EFailUsage;
John Kessenich54f6e562013-08-03 00:04:10 +0000628 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000629
John Kessenich05a70632013-09-17 19:26:08 +0000630 if (Options & EOptionDumpConfig) {
631 printf("%s", DefaultConfig);
632 if (Worklist.empty())
633 return ESuccess;
634 }
635
John Kessenich319de232013-12-04 04:43:40 +0000636 if (Options & EOptionDumpVersions) {
637 printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
638 printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
639 if (Worklist.empty())
640 return ESuccess;
641 }
642
John Kessenich05a70632013-09-17 19:26:08 +0000643 if (Worklist.empty()) {
644 usage();
645 return EFailUsage;
646 }
647
648 ProcessConfigFile();
649
John Kessenich69f4b512013-09-04 21:19:27 +0000650 //
651 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000652 // 1) linking all arguments together, single-threaded, new C++ interface
653 // 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 +0000654 //
John Kessenichc36e1d82013-11-01 17:41:52 +0000655 if (Options & EOptionsLinkProgram) {
656 glslang::InitializeProcess();
John Kessenich38f3b892013-09-06 19:52:57 +0000657 CompileAndLinkShaders();
John Kessenichc36e1d82013-11-01 17:41:52 +0000658 glslang::FinalizeProcess();
659 } else {
660 ShInitialize();
661
John Kessenich38f3b892013-09-06 19:52:57 +0000662 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000663
John Kessenich38f3b892013-09-06 19:52:57 +0000664 if (Options & EOptionMultiThreaded) {
665 const int NumThreads = 16;
666 void* threads[NumThreads];
667 for (int t = 0; t < NumThreads; ++t) {
668 threads[t] = glslang::OS_CreateThread(&CompileShaders);
669 if (! threads[t]) {
670 printf("Failed to create thread\n");
671 return EFailThreadCreate;
672 }
John Kessenicha0af4732012-12-12 21:15:54 +0000673 }
John Kessenich38f3b892013-09-06 19:52:57 +0000674 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenichc999ba22013-11-07 23:33:24 +0000675 } else
676 CompileShaders(0);
John Kessenich38f3b892013-09-06 19:52:57 +0000677
678 // Print out all the resulting infologs
679 for (int w = 0; w < NumWorkItems; ++w) {
680 if (Work[w]) {
681 if (printShaderNames)
682 puts(Work[w]->name.c_str());
683 puts(Work[w]->results.c_str());
684 delete Work[w];
685 }
686 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000687
688 ShFinalize();
John Kessenicha0af4732012-12-12 21:15:54 +0000689 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000690
691 if (Delay)
692 glslang::OS_Sleep(1000000);
John Kessenicha0af4732012-12-12 21:15:54 +0000693
John Kessenichc999ba22013-11-07 23:33:24 +0000694 if (CompileFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000695 return EFailCompile;
John Kessenichc999ba22013-11-07 23:33:24 +0000696 if (LinkFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000697 return EFailLink;
698
699 return 0;
700}
701
702//
703// Deduce the language from the filename. Files must end in one of the
704// following extensions:
705//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000706// .vert = vertex
707// .tesc = tessellation control
708// .tese = tessellation evaluation
709// .geom = geometry
710// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000711// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000712//
John Kessenichb603f912013-08-29 00:39:25 +0000713EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000714{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000715 size_t ext = name.rfind('.');
716 if (ext == std::string::npos) {
717 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000718 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000719 }
720
John Kessenich2b07c7e2013-07-31 18:44:13 +0000721 std::string suffix = name.substr(ext + 1, std::string::npos);
722 if (suffix == "vert")
723 return EShLangVertex;
724 else if (suffix == "tesc")
725 return EShLangTessControl;
726 else if (suffix == "tese")
727 return EShLangTessEvaluation;
728 else if (suffix == "geom")
729 return EShLangGeometry;
730 else if (suffix == "frag")
731 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000732 else if (suffix == "comp")
733 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000734
735 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000736 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000737}
738
John Kessenicha0af4732012-12-12 21:15:54 +0000739//
John Kessenich69f4b512013-09-04 21:19:27 +0000740// Read a file's data into a string, and compile it using the old interface ShCompile,
741// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000742//
John Kessenichc999ba22013-11-07 23:33:24 +0000743void CompileFile(const char *fileName, ShHandle compiler)
John Kessenicha0af4732012-12-12 21:15:54 +0000744{
745 int ret;
John Kessenich41cf6b52013-06-25 18:10:05 +0000746 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000747 if (! shaderStrings) {
748 usage();
John Kessenichc999ba22013-11-07 23:33:24 +0000749 CompileFailed = true;
750 return;
John Kessenichdb4cd542013-06-26 22:42:55 +0000751 }
752
John Kessenich41cf6b52013-06-25 18:10:05 +0000753 int* lengths = new int[NumShaderStrings];
754
755 // move to length-based strings, rather than null-terminated strings
756 for (int s = 0; s < NumShaderStrings; ++s)
757 lengths[s] = strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000758
John Kessenichc999ba22013-11-07 23:33:24 +0000759 if (! shaderStrings) {
760 CompileFailed = true;
761 return;
762 }
John Kessenicha0af4732012-12-12 21:15:54 +0000763
John Kessenich52ac67e2013-05-05 23:46:22 +0000764 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000765 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000766
John Kessenich94a81fb2013-08-31 02:41:30 +0000767 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
768 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich05a70632013-09-17 19:26:08 +0000769 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, 100, false, messages);
770 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenichea869fb2013-10-28 18:12:06 +0000771 //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
772 // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
773 // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
John Kessenich41cf6b52013-06-25 18:10:05 +0000774 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenichea869fb2013-10-28 18:12:06 +0000775 //ret = ShCompile(compiler, multi, 7, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000776 }
John Kessenicha0af4732012-12-12 21:15:54 +0000777
John Kessenich94a81fb2013-08-31 02:41:30 +0000778 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000779 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +0000780 }
John Kessenicha0af4732012-12-12 21:15:54 +0000781
John Kessenich41cf6b52013-06-25 18:10:05 +0000782 delete [] lengths;
783 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000784
John Kessenichc999ba22013-11-07 23:33:24 +0000785 if (ret == 0)
786 CompileFailed = true;
John Kessenicha0af4732012-12-12 21:15:54 +0000787}
788
John Kessenicha0af4732012-12-12 21:15:54 +0000789//
790// print usage to stdout
791//
792void usage()
793{
John Kessenich319de232013-12-04 04:43:40 +0000794 printf("Usage: glslangValidator [option]... [file]...\n"
795 "\n"
796 "Where: each 'file' ends in\n"
797 " .conf to provide an optional config file that replaces the default configuration\n"
John Kessenich05a70632013-09-17 19:26:08 +0000798 " (see -c option below for generating a template)\n"
John Kessenichc0275792013-08-09 17:14:49 +0000799 " .vert for a vertex shader\n"
800 " .tesc for a tessellation control shader\n"
801 " .tese for a tessellation evaluation shader\n"
802 " .geom for a geometry shader\n"
803 " .frag for a fragment shader\n"
John Kessenich319de232013-12-04 04:43:40 +0000804 " .comp for a compute shader\n"
805 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000806 "Compilation warnings and errors will be printed to stdout.\n"
John Kessenich319de232013-12-04 04:43:40 +0000807 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000808 "To get other information, use one of the following options:\n"
John Kessenich319de232013-12-04 04:43:40 +0000809 "(Each option must be specified separately, but can go anywhere in the command line.)\n"
810 " -c configuration dump; use to create default configuration file (redirect to a .conf file)\n"
811 " -i intermediate tree (glslang AST) is printed out\n"
812 " -l link validation of all input files\n"
813 " -m memory leak mode\n"
814 " -q dump reflection query database\n"
815 " -r relaxed semantic error-checking mode\n"
816 " -s silent mode\n"
817 " -t multi-threaded mode\n"
818 " -v print version strings\n"
819 " -w suppress warnings (except as required by #extension : warn)\n"
John Kessenichb0a7eb52013-11-07 17:44:20 +0000820 );
John Kessenicha0af4732012-12-12 21:15:54 +0000821}
822
John Kessenichcfd643e2013-03-08 23:14:42 +0000823#ifndef _WIN32
824
825#include <errno.h>
826
827int fopen_s(
828 FILE** pFile,
829 const char *filename,
830 const char *mode
831)
832{
833 if (!pFile || !filename || !mode) {
834 return EINVAL;
835 }
836
837 FILE* f = fopen(filename, mode);
838 if (! f) {
839 if (errno != 0) {
840 return errno;
841 } else {
842 return ENOENT;
843 }
844 }
845 *pFile = f;
846
847 return 0;
848}
849
850#endif
851
John Kessenicha0af4732012-12-12 21:15:54 +0000852//
853// Malloc a string of sufficient size and read a string into it.
854//
John Kessenich54d8cda2013-02-11 22:36:01 +0000855char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000856{
John Kessenich200b2732012-12-12 21:21:23 +0000857 FILE *in;
858 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000859 char *fdata;
860 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000861 const int maxSourceStrings = 5;
862 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000863
864 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000865 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000866 printf("Error: unable to open input file: %s\n", fileName);
867 return 0;
868 }
869
870 while (fgetc(in) != EOF)
871 count++;
872
873 fseek(in, 0, SEEK_SET);
874
875
876 if (!(fdata = (char *)malloc(count+2))) {
877 printf("Error allocating memory\n");
878 return 0;
879 }
880 if (fread(fdata,1,count, in)!=count) {
881 printf("Error reading input file: %s\n", fileName);
882 return 0;
883 }
884 fdata[count] = '\0';
885 fclose(in);
John Kessenichea869fb2013-10-28 18:12:06 +0000886 if (count == 0) {
John Kessenicha0af4732012-12-12 21:15:54 +0000887 return_data[0]=(char*)malloc(count+2);
888 return_data[0][0]='\0';
John Kessenichea869fb2013-10-28 18:12:06 +0000889 NumShaderStrings = 0;
John Kessenicha0af4732012-12-12 21:15:54 +0000890 return return_data;
John Kessenichea869fb2013-10-28 18:12:06 +0000891 } else
892 NumShaderStrings = 1;
John Kessenicha0af4732012-12-12 21:15:54 +0000893
John Kessenich41cf6b52013-06-25 18:10:05 +0000894 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000895 int ptr_len=0,i=0;
896 while(count>0){
897 return_data[i]=(char*)malloc(len+2);
898 memcpy(return_data[i],fdata+ptr_len,len);
899 return_data[i][len]='\0';
900 count-=(len);
901 ptr_len+=(len);
902 if(count<len){
903 if(count==0){
John Kessenich41cf6b52013-06-25 18:10:05 +0000904 NumShaderStrings=(i+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000905 break;
906 }
907 len = count;
908 }
909 ++i;
910 }
911 return return_data;
912}
913
John Kessenicha0af4732012-12-12 21:15:54 +0000914void FreeFileData(char **data)
915{
John Kessenich41cf6b52013-06-25 18:10:05 +0000916 for(int i=0;i<NumShaderStrings;i++)
John Kessenicha0af4732012-12-12 21:15:54 +0000917 free(data[i]);
918}
919
John Kessenich54d8cda2013-02-11 22:36:01 +0000920void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000921{
922 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
923 "#### %s %s INFO LOG ####\n", msg, name, num);
924}