1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "GLSLANG/ShaderLang.h"
8
9 #include <assert.h>
10 #include <math.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sstream>
15 #include <vector>
16 #include "angle_gl.h"
17
18 #if defined(ANGLE_ENABLE_VULKAN)
19 // SPIR-V tools include for disassembly.
20 # include <spirv-tools/libspirv.hpp>
21 #endif
22
23 //
24 // Return codes from main.
25 //
26 enum TFailCode
27 {
28 ESuccess = 0,
29 EFailUsage,
30 EFailCompile,
31 EFailCompilerCreate,
32 };
33
34 static void usage();
35 static sh::GLenum FindShaderType(const char *fileName);
36 static bool CompileFile(char *fileName, ShHandle compiler, ShCompileOptions compileOptions);
37 static void LogMsg(const char *msg, const char *name, const int num, const char *logName);
38 static void PrintVariable(const std::string &prefix, size_t index, const sh::ShaderVariable &var);
39 static void PrintActiveVariables(ShHandle compiler);
40
41 // If NUM_SOURCE_STRINGS is set to a value > 1, the input file data is
42 // broken into that many chunks. This will affect file/line numbering in
43 // the preprocessor.
44 const unsigned int NUM_SOURCE_STRINGS = 1;
45 typedef std::vector<char *> ShaderSource;
46 static bool ReadShaderSource(const char *fileName, ShaderSource &source);
47 static void FreeShaderSource(ShaderSource &source);
48
49 static bool ParseGLSLOutputVersion(const std::string &, ShShaderOutput *outResult);
50 static bool ParseIntValue(const std::string &, int emptyDefault, int *outValue);
51
52 static void PrintSpirv(const sh::BinaryBlob &blob);
53
54 //
55 // Set up the per compile resources
56 //
GenerateResources(ShBuiltInResources * resources)57 void GenerateResources(ShBuiltInResources *resources)
58 {
59 sh::InitBuiltInResources(resources);
60
61 resources->MaxVertexAttribs = 8;
62 resources->MaxVertexUniformVectors = 128;
63 resources->MaxVaryingVectors = 8;
64 resources->MaxVertexTextureImageUnits = 0;
65 resources->MaxCombinedTextureImageUnits = 8;
66 resources->MaxTextureImageUnits = 8;
67 resources->MaxFragmentUniformVectors = 16;
68 resources->MaxDrawBuffers = 1;
69 resources->MaxDualSourceDrawBuffers = 1;
70
71 resources->OES_standard_derivatives = 0;
72 resources->OES_EGL_image_external = 0;
73 resources->EXT_geometry_shader = 1;
74 resources->ANGLE_texture_multisample = 0;
75 resources->APPLE_clip_distance = 0;
76 }
77
main(int argc,char * argv[])78 int main(int argc, char *argv[])
79 {
80 TFailCode failCode = ESuccess;
81
82 ShCompileOptions compileOptions = 0;
83 int numCompiles = 0;
84 ShHandle vertexCompiler = 0;
85 ShHandle fragmentCompiler = 0;
86 ShHandle computeCompiler = 0;
87 ShHandle geometryCompiler = 0;
88 ShShaderSpec spec = SH_GLES2_SPEC;
89 ShShaderOutput output = SH_ESSL_OUTPUT;
90
91 #if defined(ANGLE_ENABLE_VULKAN)
92 sh::InitializeGlslang();
93 #endif
94 sh::Initialize();
95
96 ShBuiltInResources resources;
97 GenerateResources(&resources);
98
99 argc--;
100 argv++;
101 for (; (argc >= 1) && (failCode == ESuccess); argc--, argv++)
102 {
103 if (argv[0][0] == '-')
104 {
105 switch (argv[0][1])
106 {
107 case 'i':
108 compileOptions |= SH_INTERMEDIATE_TREE;
109 break;
110 case 'o':
111 compileOptions |= SH_OBJECT_CODE;
112 break;
113 case 'u':
114 compileOptions |= SH_VARIABLES;
115 break;
116 case 's':
117 if (argv[0][2] == '=')
118 {
119 switch (argv[0][3])
120 {
121 case 'e':
122 if (argv[0][4] == '3')
123 {
124 if (argv[0][5] == '1')
125 {
126 spec = SH_GLES3_1_SPEC;
127 }
128 else
129 {
130 spec = SH_GLES3_SPEC;
131 }
132 }
133 else
134 {
135 spec = SH_GLES2_SPEC;
136 }
137 break;
138 case 'w':
139 if (argv[0][4] == '3')
140 {
141 spec = SH_WEBGL3_SPEC;
142 }
143 else if (argv[0][4] == '2')
144 {
145 spec = SH_WEBGL2_SPEC;
146 }
147 else if (argv[0][4] == 'n')
148 {
149 spec = SH_WEBGL_SPEC;
150 }
151 else
152 {
153 spec = SH_WEBGL_SPEC;
154 resources.FragmentPrecisionHigh = 1;
155 }
156 break;
157 case 'd':
158 if (argv[0][4] == 'c')
159 {
160 spec = SH_GL_COMPATIBILITY_SPEC;
161 }
162 else
163 {
164 spec = SH_GL_CORE_SPEC;
165 }
166 break;
167 default:
168 failCode = EFailUsage;
169 }
170 }
171 else
172 {
173 failCode = EFailUsage;
174 }
175 break;
176 case 'b':
177 if (argv[0][2] == '=')
178 {
179 switch (argv[0][3])
180 {
181 case 'e':
182 output = SH_ESSL_OUTPUT;
183 compileOptions |= SH_INITIALIZE_UNINITIALIZED_LOCALS;
184 break;
185 case 'g':
186 if (!ParseGLSLOutputVersion(&argv[0][sizeof("-b=g") - 1], &output))
187 {
188 failCode = EFailUsage;
189 }
190 compileOptions |= SH_INITIALIZE_UNINITIALIZED_LOCALS;
191 break;
192 case 'v':
193 output = SH_SPIRV_VULKAN_OUTPUT;
194 compileOptions |= SH_INITIALIZE_UNINITIALIZED_LOCALS;
195 break;
196 case 'h':
197 if (argv[0][4] == '1' && argv[0][5] == '1')
198 {
199 output = SH_HLSL_4_1_OUTPUT;
200 }
201 else
202 {
203 output = SH_HLSL_3_0_OUTPUT;
204 }
205 break;
206 default:
207 failCode = EFailUsage;
208 }
209 }
210 else
211 {
212 failCode = EFailUsage;
213 }
214 break;
215 case 'x':
216 if (argv[0][2] == '=')
217 {
218 // clang-format off
219 switch (argv[0][3])
220 {
221 case 'i': resources.OES_EGL_image_external = 1; break;
222 case 'd': resources.OES_standard_derivatives = 1; break;
223 case 'r': resources.ARB_texture_rectangle = 1; break;
224 case 'b':
225 if (ParseIntValue(&argv[0][sizeof("-x=b") - 1], 1,
226 &resources.MaxDualSourceDrawBuffers))
227 {
228 resources.EXT_blend_func_extended = 1;
229 }
230 else
231 {
232 failCode = EFailUsage;
233 }
234 break;
235 case 'w':
236 if (ParseIntValue(&argv[0][sizeof("-x=w") - 1], 1,
237 &resources.MaxDrawBuffers))
238 {
239 resources.EXT_draw_buffers = 1;
240 }
241 else
242 {
243 failCode = EFailUsage;
244 }
245 break;
246 case 'g': resources.EXT_frag_depth = 1; break;
247 case 'l': resources.EXT_shader_texture_lod = 1; break;
248 case 'f': resources.EXT_shader_framebuffer_fetch = 1; break;
249 case 'n': resources.NV_shader_framebuffer_fetch = 1; break;
250 case 'a': resources.ARM_shader_framebuffer_fetch = 1; break;
251 case 'm':
252 resources.OVR_multiview2 = 1;
253 resources.OVR_multiview = 1;
254 compileOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW;
255 compileOptions |= SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER;
256 break;
257 case 'y': resources.EXT_YUV_target = 1; break;
258 case 's': resources.OES_sample_variables = 1; break;
259 default: failCode = EFailUsage;
260 }
261 // clang-format on
262 }
263 else
264 {
265 failCode = EFailUsage;
266 }
267 break;
268 default:
269 failCode = EFailUsage;
270 }
271 }
272 else
273 {
274 if (spec != SH_GLES2_SPEC && spec != SH_WEBGL_SPEC)
275 {
276 resources.MaxDrawBuffers = 8;
277 resources.MaxVertexTextureImageUnits = 16;
278 resources.MaxTextureImageUnits = 16;
279 }
280 ShHandle compiler = 0;
281 switch (FindShaderType(argv[0]))
282 {
283 case GL_VERTEX_SHADER:
284 if (vertexCompiler == 0)
285 {
286 vertexCompiler =
287 sh::ConstructCompiler(GL_VERTEX_SHADER, spec, output, &resources);
288 }
289 compiler = vertexCompiler;
290 break;
291 case GL_FRAGMENT_SHADER:
292 if (fragmentCompiler == 0)
293 {
294 fragmentCompiler =
295 sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
296 }
297 compiler = fragmentCompiler;
298 break;
299 case GL_COMPUTE_SHADER:
300 if (computeCompiler == 0)
301 {
302 computeCompiler =
303 sh::ConstructCompiler(GL_COMPUTE_SHADER, spec, output, &resources);
304 }
305 compiler = computeCompiler;
306 break;
307 case GL_GEOMETRY_SHADER_EXT:
308 if (geometryCompiler == 0)
309 {
310 geometryCompiler =
311 sh::ConstructCompiler(GL_GEOMETRY_SHADER_EXT, spec, output, &resources);
312 }
313 compiler = geometryCompiler;
314 break;
315 default:
316 break;
317 }
318 if (compiler)
319 {
320 switch (output)
321 {
322 case SH_HLSL_3_0_OUTPUT:
323 case SH_HLSL_4_1_OUTPUT:
324 case SH_HLSL_4_0_FL9_3_OUTPUT:
325 compileOptions &= ~SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER;
326 break;
327 default:
328 break;
329 }
330
331 bool compiled = CompileFile(argv[0], compiler, compileOptions);
332
333 LogMsg("BEGIN", "COMPILER", numCompiles, "INFO LOG");
334 std::string log = sh::GetInfoLog(compiler);
335 puts(log.c_str());
336 LogMsg("END", "COMPILER", numCompiles, "INFO LOG");
337 printf("\n\n");
338
339 if (compiled && (compileOptions & SH_OBJECT_CODE))
340 {
341 LogMsg("BEGIN", "COMPILER", numCompiles, "OBJ CODE");
342 if (output != SH_SPIRV_VULKAN_OUTPUT)
343 {
344 const std::string &code = sh::GetObjectCode(compiler);
345 puts(code.c_str());
346 }
347 else
348 {
349 const sh::BinaryBlob &blob = sh::GetObjectBinaryBlob(compiler);
350 PrintSpirv(blob);
351 }
352 LogMsg("END", "COMPILER", numCompiles, "OBJ CODE");
353 printf("\n\n");
354 }
355 if (compiled && (compileOptions & SH_VARIABLES))
356 {
357 LogMsg("BEGIN", "COMPILER", numCompiles, "VARIABLES");
358 PrintActiveVariables(compiler);
359 LogMsg("END", "COMPILER", numCompiles, "VARIABLES");
360 printf("\n\n");
361 }
362 if (!compiled)
363 failCode = EFailCompile;
364 ++numCompiles;
365 }
366 else
367 {
368 failCode = EFailCompilerCreate;
369 }
370 }
371 }
372
373 if ((vertexCompiler == 0) && (fragmentCompiler == 0) && (computeCompiler == 0) &&
374 (geometryCompiler == 0))
375 failCode = EFailUsage;
376 if (failCode == EFailUsage)
377 usage();
378
379 if (vertexCompiler)
380 sh::Destruct(vertexCompiler);
381 if (fragmentCompiler)
382 sh::Destruct(fragmentCompiler);
383 if (computeCompiler)
384 sh::Destruct(computeCompiler);
385 if (geometryCompiler)
386 sh::Destruct(geometryCompiler);
387
388 sh::Finalize();
389 #if defined(ANGLE_ENABLE_VULKAN)
390 sh::FinalizeGlslang();
391 #endif
392
393 return failCode;
394 }
395
396 //
397 // print usage to stdout
398 //
usage()399 void usage()
400 {
401 // clang-format off
402 printf(
403 "Usage: translate [-i -o -u -l -b=e -b=g -b=h9 -x=i -x=d] file1 file2 ...\n"
404 "Where: filename : filename ending in .frag or .vert\n"
405 " -i : print intermediate tree\n"
406 " -o : print translated code\n"
407 " -u : print active attribs, uniforms, varyings and program outputs\n"
408 " -s=e2 : use GLES2 spec (this is by default)\n"
409 " -s=e3 : use GLES3 spec\n"
410 " -s=e31 : use GLES31 spec (in development)\n"
411 " -s=w : use WebGL 1.0 spec\n"
412 " -s=wn : use WebGL 1.0 spec with no highp support in fragment shaders\n"
413 " -s=w2 : use WebGL 2.0 spec\n"
414 " -s=d : use Desktop Core spec (in development)\n"
415 " -s=dc : use Desktop Compatibility spec (in development)\n"
416 " -b=e : output GLSL ES code (this is by default)\n"
417 " -b=g : output GLSL code (compatibility profile)\n"
418 " -b=g[NUM]: output GLSL code (NUM can be 130, 140, 150, 330, 400, 410, 420, 430, "
419 "440, 450)\n"
420 " -b=v : output Vulkan SPIR-V code\n"
421 " -b=h9 : output HLSL9 code\n"
422 " -b=h11 : output HLSL11 code\n"
423 " -x=i : enable GL_OES_EGL_image_external\n"
424 " -x=d : enable GL_OES_EGL_standard_derivatives\n"
425 " -x=r : enable ARB_texture_rectangle\n"
426 " -x=b[NUM]: enable EXT_blend_func_extended (NUM default 1)\n"
427 " -x=w[NUM]: enable EXT_draw_buffers (NUM default 1)\n"
428 " -x=g : enable EXT_frag_depth\n"
429 " -x=l : enable EXT_shader_texture_lod\n"
430 " -x=f : enable EXT_shader_framebuffer_fetch\n"
431 " -x=n : enable NV_shader_framebuffer_fetch\n"
432 " -x=a : enable ARM_shader_framebuffer_fetch\n"
433 " -x=m : enable OVR_multiview\n"
434 " -x=y : enable YUV_target\n"
435 " -x=s : enable OES_sample_variables\n");
436 // clang-format on
437 }
438
439 //
440 // Deduce the shader type from the filename. Files must end in one of the
441 // following extensions:
442 //
443 // .frag* = fragment shader
444 // .vert* = vertex shader
445 //
FindShaderType(const char * fileName)446 sh::GLenum FindShaderType(const char *fileName)
447 {
448 assert(fileName);
449
450 const char *ext = strrchr(fileName, '.');
451
452 if (ext && strcmp(ext, ".sl") == 0)
453 for (; ext > fileName && ext[0] != '.'; ext--)
454 ;
455
456 ext = strrchr(fileName, '.');
457 if (ext)
458 {
459 if (strncmp(ext, ".frag", 5) == 0)
460 return GL_FRAGMENT_SHADER;
461 if (strncmp(ext, ".vert", 5) == 0)
462 return GL_VERTEX_SHADER;
463 if (strncmp(ext, ".comp", 5) == 0)
464 return GL_COMPUTE_SHADER;
465 if (strncmp(ext, ".geom", 5) == 0)
466 return GL_GEOMETRY_SHADER_EXT;
467 }
468
469 return GL_FRAGMENT_SHADER;
470 }
471
472 //
473 // Read a file's data into a string, and compile it using sh::Compile
474 //
CompileFile(char * fileName,ShHandle compiler,ShCompileOptions compileOptions)475 bool CompileFile(char *fileName, ShHandle compiler, ShCompileOptions compileOptions)
476 {
477 ShaderSource source;
478 if (!ReadShaderSource(fileName, source))
479 return false;
480
481 int ret = sh::Compile(compiler, &source[0], source.size(), compileOptions);
482
483 FreeShaderSource(source);
484 return ret ? true : false;
485 }
486
LogMsg(const char * msg,const char * name,const int num,const char * logName)487 void LogMsg(const char *msg, const char *name, const int num, const char *logName)
488 {
489 printf("#### %s %s %d %s ####\n", msg, name, num, logName);
490 }
491
PrintVariable(const std::string & prefix,size_t index,const sh::ShaderVariable & var)492 void PrintVariable(const std::string &prefix, size_t index, const sh::ShaderVariable &var)
493 {
494 std::string typeName;
495 switch (var.type)
496 {
497 case GL_FLOAT:
498 typeName = "GL_FLOAT";
499 break;
500 case GL_FLOAT_VEC2:
501 typeName = "GL_FLOAT_VEC2";
502 break;
503 case GL_FLOAT_VEC3:
504 typeName = "GL_FLOAT_VEC3";
505 break;
506 case GL_FLOAT_VEC4:
507 typeName = "GL_FLOAT_VEC4";
508 break;
509 case GL_INT:
510 typeName = "GL_INT";
511 break;
512 case GL_INT_VEC2:
513 typeName = "GL_INT_VEC2";
514 break;
515 case GL_INT_VEC3:
516 typeName = "GL_INT_VEC3";
517 break;
518 case GL_INT_VEC4:
519 typeName = "GL_INT_VEC4";
520 break;
521 case GL_UNSIGNED_INT:
522 typeName = "GL_UNSIGNED_INT";
523 break;
524 case GL_UNSIGNED_INT_VEC2:
525 typeName = "GL_UNSIGNED_INT_VEC2";
526 break;
527 case GL_UNSIGNED_INT_VEC3:
528 typeName = "GL_UNSIGNED_INT_VEC3";
529 break;
530 case GL_UNSIGNED_INT_VEC4:
531 typeName = "GL_UNSIGNED_INT_VEC4";
532 break;
533 case GL_BOOL:
534 typeName = "GL_BOOL";
535 break;
536 case GL_BOOL_VEC2:
537 typeName = "GL_BOOL_VEC2";
538 break;
539 case GL_BOOL_VEC3:
540 typeName = "GL_BOOL_VEC3";
541 break;
542 case GL_BOOL_VEC4:
543 typeName = "GL_BOOL_VEC4";
544 break;
545 case GL_FLOAT_MAT2:
546 typeName = "GL_FLOAT_MAT2";
547 break;
548 case GL_FLOAT_MAT3:
549 typeName = "GL_FLOAT_MAT3";
550 break;
551 case GL_FLOAT_MAT4:
552 typeName = "GL_FLOAT_MAT4";
553 break;
554 case GL_FLOAT_MAT2x3:
555 typeName = "GL_FLOAT_MAT2x3";
556 break;
557 case GL_FLOAT_MAT3x2:
558 typeName = "GL_FLOAT_MAT3x2";
559 break;
560 case GL_FLOAT_MAT4x2:
561 typeName = "GL_FLOAT_MAT4x2";
562 break;
563 case GL_FLOAT_MAT2x4:
564 typeName = "GL_FLOAT_MAT2x4";
565 break;
566 case GL_FLOAT_MAT3x4:
567 typeName = "GL_FLOAT_MAT3x4";
568 break;
569 case GL_FLOAT_MAT4x3:
570 typeName = "GL_FLOAT_MAT4x3";
571 break;
572
573 case GL_SAMPLER_2D:
574 typeName = "GL_SAMPLER_2D";
575 break;
576 case GL_SAMPLER_3D:
577 typeName = "GL_SAMPLER_3D";
578 break;
579 case GL_SAMPLER_CUBE:
580 typeName = "GL_SAMPLER_CUBE";
581 break;
582 case GL_SAMPLER_CUBE_SHADOW:
583 typeName = "GL_SAMPLER_CUBE_SHADOW";
584 break;
585 case GL_SAMPLER_2D_SHADOW:
586 typeName = "GL_SAMPLER_2D_ARRAY_SHADOW";
587 break;
588 case GL_SAMPLER_2D_ARRAY:
589 typeName = "GL_SAMPLER_2D_ARRAY";
590 break;
591 case GL_SAMPLER_2D_ARRAY_SHADOW:
592 typeName = "GL_SAMPLER_2D_ARRAY_SHADOW";
593 break;
594 case GL_SAMPLER_2D_MULTISAMPLE:
595 typeName = "GL_SAMPLER_2D_MULTISAMPLE";
596 break;
597 case GL_IMAGE_2D:
598 typeName = "GL_IMAGE_2D";
599 break;
600 case GL_IMAGE_3D:
601 typeName = "GL_IMAGE_3D";
602 break;
603 case GL_IMAGE_CUBE:
604 typeName = "GL_IMAGE_CUBE";
605 break;
606 case GL_IMAGE_2D_ARRAY:
607 typeName = "GL_IMAGE_2D_ARRAY";
608 break;
609
610 case GL_INT_SAMPLER_2D:
611 typeName = "GL_INT_SAMPLER_2D";
612 break;
613 case GL_INT_SAMPLER_3D:
614 typeName = "GL_INT_SAMPLER_3D";
615 break;
616 case GL_INT_SAMPLER_CUBE:
617 typeName = "GL_INT_SAMPLER_CUBE";
618 break;
619 case GL_INT_SAMPLER_2D_ARRAY:
620 typeName = "GL_INT_SAMPLER_2D_ARRAY";
621 break;
622 case GL_INT_SAMPLER_2D_MULTISAMPLE:
623 typeName = "GL_INT_SAMPLER_2D_MULTISAMPLE";
624 break;
625 case GL_INT_IMAGE_2D:
626 typeName = "GL_INT_IMAGE_2D";
627 break;
628 case GL_INT_IMAGE_3D:
629 typeName = "GL_INT_IMAGE_3D";
630 break;
631 case GL_INT_IMAGE_CUBE:
632 typeName = "GL_INT_IMAGE_CUBE";
633 break;
634 case GL_INT_IMAGE_2D_ARRAY:
635 typeName = "GL_INT_IMAGE_2D_ARRAY";
636 break;
637
638 case GL_UNSIGNED_INT_SAMPLER_2D:
639 typeName = "GL_UNSIGNED_INT_SAMPLER_2D";
640 break;
641 case GL_UNSIGNED_INT_SAMPLER_3D:
642 typeName = "GL_UNSIGNED_INT_SAMPLER_3D";
643 break;
644 case GL_UNSIGNED_INT_SAMPLER_CUBE:
645 typeName = "GL_UNSIGNED_INT_SAMPLER_CUBE";
646 break;
647 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
648 typeName = "GL_UNSIGNED_INT_SAMPLER_2D_ARRAY";
649 break;
650 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
651 typeName = "GL_UNSIGNED_INT_ATOMIC_COUNTER";
652 break;
653 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
654 typeName = "GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE";
655 break;
656 case GL_UNSIGNED_INT_IMAGE_2D:
657 typeName = "GL_UNSIGNED_INT_IMAGE_2D";
658 break;
659 case GL_UNSIGNED_INT_IMAGE_3D:
660 typeName = "GL_UNSIGNED_INT_IMAGE_3D";
661 break;
662 case GL_UNSIGNED_INT_IMAGE_CUBE:
663 typeName = "GL_UNSIGNED_INT_IMAGE_CUBE";
664 break;
665 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
666 typeName = "GL_UNSIGNED_INT_IMAGE_2D_ARRAY";
667 break;
668
669 case GL_SAMPLER_EXTERNAL_OES:
670 typeName = "GL_SAMPLER_EXTERNAL_OES";
671 break;
672 case GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT:
673 typeName = "GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT";
674 break;
675 default:
676 typeName = "UNKNOWN";
677 break;
678 }
679
680 printf("%s %u : name=%s, mappedName=%s, type=%s, arraySizes=", prefix.c_str(),
681 static_cast<unsigned int>(index), var.name.c_str(), var.mappedName.c_str(),
682 typeName.c_str());
683 for (unsigned int arraySize : var.arraySizes)
684 {
685 printf("%u ", arraySize);
686 }
687 printf("\n");
688 if (var.fields.size())
689 {
690 std::string structPrefix;
691 for (size_t i = 0; i < prefix.size(); ++i)
692 structPrefix += ' ';
693 printf("%s struct %s\n", structPrefix.c_str(), var.structOrBlockName.c_str());
694 structPrefix += " field";
695 for (size_t i = 0; i < var.fields.size(); ++i)
696 PrintVariable(structPrefix, i, var.fields[i]);
697 }
698 }
699
PrintActiveVariables(ShHandle compiler)700 static void PrintActiveVariables(ShHandle compiler)
701 {
702 const std::vector<sh::ShaderVariable> *uniforms = sh::GetUniforms(compiler);
703 const std::vector<sh::ShaderVariable> *inputVaryings = sh::GetInputVaryings(compiler);
704 const std::vector<sh::ShaderVariable> *outputVaryings = sh::GetOutputVaryings(compiler);
705 const std::vector<sh::ShaderVariable> *attributes = sh::GetAttributes(compiler);
706 const std::vector<sh::ShaderVariable> *outputs = sh::GetOutputVariables(compiler);
707 for (size_t varCategory = 0; varCategory < 5; ++varCategory)
708 {
709 size_t numVars = 0;
710 std::string varCategoryName;
711 if (varCategory == 0)
712 {
713 numVars = uniforms->size();
714 varCategoryName = "uniform";
715 }
716 else if (varCategory == 1)
717 {
718 numVars = inputVaryings->size();
719 varCategoryName = "input varying";
720 }
721 else if (varCategory == 2)
722 {
723 numVars = outputVaryings->size();
724 varCategoryName = "output varying";
725 }
726 else if (varCategory == 3)
727 {
728 numVars = attributes->size();
729 varCategoryName = "attribute";
730 }
731 else
732 {
733 numVars = outputs->size();
734 varCategoryName = "output";
735 }
736
737 for (size_t i = 0; i < numVars; ++i)
738 {
739 const sh::ShaderVariable *var;
740 if (varCategory == 0)
741 var = &((*uniforms)[i]);
742 else if (varCategory == 1)
743 var = &((*inputVaryings)[i]);
744 else if (varCategory == 2)
745 var = &((*outputVaryings)[i]);
746 else if (varCategory == 3)
747 var = &((*attributes)[i]);
748 else
749 var = &((*outputs)[i]);
750
751 PrintVariable(varCategoryName, i, *var);
752 }
753 printf("\n");
754 }
755 }
756
ReadShaderSource(const char * fileName,ShaderSource & source)757 static bool ReadShaderSource(const char *fileName, ShaderSource &source)
758 {
759 FILE *in = fopen(fileName, "rb");
760 if (!in)
761 {
762 printf("Error: unable to open input file: %s\n", fileName);
763 return false;
764 }
765
766 // Obtain file size.
767 fseek(in, 0, SEEK_END);
768 size_t count = ftell(in);
769 rewind(in);
770
771 int len = (int)ceil((float)count / (float)NUM_SOURCE_STRINGS);
772 source.reserve(NUM_SOURCE_STRINGS);
773 // Notice the usage of do-while instead of a while loop here.
774 // It is there to handle empty files in which case a single empty
775 // string is added to vector.
776 do
777 {
778 char *data = new char[len + 1];
779 size_t nread = fread(data, 1, len, in);
780 data[nread] = '\0';
781 source.push_back(data);
782
783 count -= nread;
784 } while (count > 0);
785
786 fclose(in);
787 return true;
788 }
789
FreeShaderSource(ShaderSource & source)790 static void FreeShaderSource(ShaderSource &source)
791 {
792 for (ShaderSource::size_type i = 0; i < source.size(); ++i)
793 {
794 delete[] source[i];
795 }
796 source.clear();
797 }
798
ParseGLSLOutputVersion(const std::string & num,ShShaderOutput * outResult)799 static bool ParseGLSLOutputVersion(const std::string &num, ShShaderOutput *outResult)
800 {
801 if (num.length() == 0)
802 {
803 *outResult = SH_GLSL_COMPATIBILITY_OUTPUT;
804 return true;
805 }
806 std::istringstream input(num);
807 int value;
808 if (!(input >> value && input.eof()))
809 {
810 return false;
811 }
812
813 switch (value)
814 {
815 case 130:
816 *outResult = SH_GLSL_130_OUTPUT;
817 return true;
818 case 140:
819 *outResult = SH_GLSL_140_OUTPUT;
820 return true;
821 case 150:
822 *outResult = SH_GLSL_150_CORE_OUTPUT;
823 return true;
824 case 330:
825 *outResult = SH_GLSL_330_CORE_OUTPUT;
826 return true;
827 case 400:
828 *outResult = SH_GLSL_400_CORE_OUTPUT;
829 return true;
830 case 410:
831 *outResult = SH_GLSL_410_CORE_OUTPUT;
832 return true;
833 case 420:
834 *outResult = SH_GLSL_420_CORE_OUTPUT;
835 return true;
836 case 430:
837 *outResult = SH_GLSL_430_CORE_OUTPUT;
838 return true;
839 case 440:
840 *outResult = SH_GLSL_440_CORE_OUTPUT;
841 return true;
842 case 450:
843 *outResult = SH_GLSL_450_CORE_OUTPUT;
844 return true;
845 default:
846 break;
847 }
848 return false;
849 }
850
ParseIntValue(const std::string & num,int emptyDefault,int * outValue)851 static bool ParseIntValue(const std::string &num, int emptyDefault, int *outValue)
852 {
853 if (num.length() == 0)
854 {
855 *outValue = emptyDefault;
856 return true;
857 }
858
859 std::istringstream input(num);
860 int value;
861 if (!(input >> value && input.eof()))
862 {
863 return false;
864 }
865 *outValue = value;
866 return true;
867 }
868
PrintSpirv(const sh::BinaryBlob & blob)869 static void PrintSpirv(const sh::BinaryBlob &blob)
870 {
871 #if defined(ANGLE_ENABLE_VULKAN)
872 spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
873
874 std::string readableSpirv;
875 spirvTools.Disassemble(blob, &readableSpirv, 0);
876
877 puts(readableSpirv.c_str());
878 #endif
879 }
880