1 // 2 // Copyright (c) 2002-2013 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 <vector> 15 16 // 17 // Return codes from main. 18 // 19 enum TFailCode { 20 ESuccess = 0, 21 EFailUsage, 22 EFailCompile, 23 EFailCompilerCreate, 24 }; 25 26 static void usage(); 27 static ShShaderType FindShaderType(const char* fileName); 28 static bool CompileFile(char* fileName, ShHandle compiler, int compileOptions); 29 static void LogMsg(const char* msg, const char* name, const int num, const char* logName); 30 static void PrintActiveVariables(ShHandle compiler, ShShaderInfo varType); 31 32 // If NUM_SOURCE_STRINGS is set to a value > 1, the input file data is 33 // broken into that many chunks. 34 const unsigned int NUM_SOURCE_STRINGS = 2; 35 typedef std::vector<char*> ShaderSource; 36 static bool ReadShaderSource(const char* fileName, ShaderSource& source); 37 static void FreeShaderSource(ShaderSource& source); 38 39 // 40 // Set up the per compile resources 41 // 42 void GenerateResources(ShBuiltInResources* resources) 43 { 44 ShInitBuiltInResources(resources); 45 46 resources->MaxVertexAttribs = 8; 47 resources->MaxVertexUniformVectors = 128; 48 resources->MaxVaryingVectors = 8; 49 resources->MaxVertexTextureImageUnits = 0; 50 resources->MaxCombinedTextureImageUnits = 8; 51 resources->MaxTextureImageUnits = 8; 52 resources->MaxFragmentUniformVectors = 16; 53 resources->MaxDrawBuffers = 1; 54 55 resources->OES_standard_derivatives = 0; 56 resources->OES_EGL_image_external = 0; 57 } 58 59 int main(int argc, char* argv[]) 60 { 61 TFailCode failCode = ESuccess; 62 63 int compileOptions = 0; 64 int numCompiles = 0; 65 ShHandle vertexCompiler = 0; 66 ShHandle fragmentCompiler = 0; 67 char* buffer = 0; 68 size_t bufferLen = 0; 69 ShShaderSpec spec = SH_GLES2_SPEC; 70 ShShaderOutput output = SH_ESSL_OUTPUT; 71 72 ShInitialize(); 73 74 ShBuiltInResources resources; 75 GenerateResources(&resources); 76 77 argc--; 78 argv++; 79 for (; (argc >= 1) && (failCode == ESuccess); argc--, argv++) { 80 if (argv[0][0] == '-') { 81 switch (argv[0][1]) { 82 case 'i': compileOptions |= SH_INTERMEDIATE_TREE; break; 83 case 'o': compileOptions |= SH_OBJECT_CODE; break; 84 case 'u': compileOptions |= SH_VARIABLES; break; 85 case 'l': compileOptions |= SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX; break; 86 case 'e': compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS; break; 87 case 'd': compileOptions |= SH_DEPENDENCY_GRAPH; break; 88 case 't': compileOptions |= SH_TIMING_RESTRICTIONS; break; 89 case 's': 90 if (argv[0][2] == '=') { 91 switch (argv[0][3]) { 92 case 'e': spec = SH_GLES2_SPEC; break; 93 case 'w': spec = SH_WEBGL_SPEC; break; 94 case 'c': spec = SH_CSS_SHADERS_SPEC; break; 95 default: failCode = EFailUsage; 96 } 97 } else { 98 failCode = EFailUsage; 99 } 100 break; 101 case 'b': 102 if (argv[0][2] == '=') { 103 switch (argv[0][3]) { 104 case 'e': output = SH_ESSL_OUTPUT; break; 105 case 'g': output = SH_GLSL_OUTPUT; break; 106 case 'h': 107 if (argv[0][4] == '1' && argv[0][5] == '1') 108 { 109 output = SH_HLSL11_OUTPUT; 110 } 111 else 112 { 113 output = SH_HLSL9_OUTPUT; 114 } 115 break; 116 default: failCode = EFailUsage; 117 } 118 } else { 119 failCode = EFailUsage; 120 } 121 break; 122 case 'x': 123 if (argv[0][2] == '=') { 124 switch (argv[0][3]) { 125 case 'i': resources.OES_EGL_image_external = 1; break; 126 case 'd': resources.OES_standard_derivatives = 1; break; 127 case 'r': resources.ARB_texture_rectangle = 1; break; 128 case 'l': resources.EXT_shader_texture_lod = 1; break; 129 default: failCode = EFailUsage; 130 } 131 } else { 132 failCode = EFailUsage; 133 } 134 break; 135 default: failCode = EFailUsage; 136 } 137 } else { 138 ShHandle compiler = 0; 139 switch (FindShaderType(argv[0])) { 140 case SH_VERTEX_SHADER: 141 if (vertexCompiler == 0) 142 vertexCompiler = ShConstructCompiler( 143 SH_VERTEX_SHADER, spec, output, &resources); 144 compiler = vertexCompiler; 145 break; 146 case SH_FRAGMENT_SHADER: 147 if (fragmentCompiler == 0) 148 fragmentCompiler = ShConstructCompiler( 149 SH_FRAGMENT_SHADER, spec, output, &resources); 150 compiler = fragmentCompiler; 151 break; 152 default: break; 153 } 154 if (compiler) { 155 bool compiled = CompileFile(argv[0], compiler, compileOptions); 156 157 LogMsg("BEGIN", "COMPILER", numCompiles, "INFO LOG"); 158 ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &bufferLen); 159 buffer = (char*) realloc(buffer, bufferLen * sizeof(char)); 160 ShGetInfoLog(compiler, buffer); 161 puts(buffer); 162 LogMsg("END", "COMPILER", numCompiles, "INFO LOG"); 163 printf("\n\n"); 164 165 if (compiled && (compileOptions & SH_OBJECT_CODE)) { 166 LogMsg("BEGIN", "COMPILER", numCompiles, "OBJ CODE"); 167 ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &bufferLen); 168 buffer = (char*) realloc(buffer, bufferLen * sizeof(char)); 169 ShGetObjectCode(compiler, buffer); 170 puts(buffer); 171 LogMsg("END", "COMPILER", numCompiles, "OBJ CODE"); 172 printf("\n\n"); 173 } 174 if (compiled && (compileOptions & SH_VARIABLES)) { 175 LogMsg("BEGIN", "COMPILER", numCompiles, "ACTIVE ATTRIBS"); 176 PrintActiveVariables(compiler, SH_ACTIVE_ATTRIBUTES); 177 LogMsg("END", "COMPILER", numCompiles, "ACTIVE ATTRIBS"); 178 printf("\n\n"); 179 180 LogMsg("BEGIN", "COMPILER", numCompiles, "ACTIVE UNIFORMS"); 181 PrintActiveVariables(compiler, SH_ACTIVE_UNIFORMS); 182 LogMsg("END", "COMPILER", numCompiles, "ACTIVE UNIFORMS"); 183 printf("\n\n"); 184 } 185 if (!compiled) 186 failCode = EFailCompile; 187 ++numCompiles; 188 } else { 189 failCode = EFailCompilerCreate; 190 } 191 } 192 } 193 194 if ((vertexCompiler == 0) && (fragmentCompiler == 0)) 195 failCode = EFailUsage; 196 if (failCode == EFailUsage) 197 usage(); 198 199 if (vertexCompiler) 200 ShDestruct(vertexCompiler); 201 if (fragmentCompiler) 202 ShDestruct(fragmentCompiler); 203 if (buffer) 204 free(buffer); 205 ShFinalize(); 206 207 return failCode; 208 } 209 210 // 211 // print usage to stdout 212 // 213 void usage() 214 { 215 printf("Usage: translate [-i -m -o -u -l -e -b=e -b=g -b=h -x=i -x=d] file1 file2 ...\n" 216 "Where: filename : filename ending in .frag or .vert\n" 217 " -i : print intermediate tree\n" 218 " -m : map long variable names\n" 219 " -o : print translated code\n" 220 " -u : print active attribs and uniforms\n" 221 " -l : unroll for-loops with integer indices\n" 222 " -e : emulate certain built-in functions (workaround for driver bugs)\n" 223 " -t : enforce experimental timing restrictions\n" 224 " -d : print dependency graph used to enforce timing restrictions\n" 225 " -s=e : use GLES2 spec (this is by default)\n" 226 " -s=w : use WebGL spec\n" 227 " -s=c : use CSS Shaders spec\n" 228 " -b=e : output GLSL ES code (this is by default)\n" 229 " -b=g : output GLSL code\n" 230 " -b=h9 : output HLSL9 code\n" 231 " -b=h11 : output HLSL11 code\n" 232 " -x=i : enable GL_OES_EGL_image_external\n" 233 " -x=d : enable GL_OES_EGL_standard_derivatives\n" 234 " -x=r : enable ARB_texture_rectangle\n" 235 " -x=l : enable EXT_shader_texture_lod\n"); 236 } 237 238 // 239 // Deduce the shader type from the filename. Files must end in one of the 240 // following extensions: 241 // 242 // .frag* = fragment shader 243 // .vert* = vertex shader 244 // 245 ShShaderType FindShaderType(const char* fileName) 246 { 247 assert(fileName); 248 249 const char* ext = strrchr(fileName, '.'); 250 251 if (ext && strcmp(ext, ".sl") == 0) 252 for (; ext > fileName && ext[0] != '.'; ext--); 253 254 ext = strrchr(fileName, '.'); 255 if (ext) { 256 if (strncmp(ext, ".frag", 4) == 0) return SH_FRAGMENT_SHADER; 257 if (strncmp(ext, ".vert", 4) == 0) return SH_VERTEX_SHADER; 258 } 259 260 return SH_FRAGMENT_SHADER; 261 } 262 263 // 264 // Read a file's data into a string, and compile it using ShCompile 265 // 266 bool CompileFile(char* fileName, ShHandle compiler, int compileOptions) 267 { 268 ShaderSource source; 269 if (!ReadShaderSource(fileName, source)) 270 return false; 271 272 int ret = ShCompile(compiler, &source[0], source.size(), compileOptions); 273 274 FreeShaderSource(source); 275 return ret ? true : false; 276 } 277 278 void LogMsg(const char* msg, const char* name, const int num, const char* logName) 279 { 280 printf("#### %s %s %d %s ####\n", msg, name, num, logName); 281 } 282 283 void PrintActiveVariables(ShHandle compiler, ShShaderInfo varType) 284 { 285 size_t nameSize = 0; 286 switch (varType) { 287 case SH_ACTIVE_ATTRIBUTES: 288 ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &nameSize); 289 break; 290 case SH_ACTIVE_UNIFORMS: 291 ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &nameSize); 292 break; 293 default: assert(0); 294 } 295 if (nameSize <= 1) return; 296 char* name = new char[nameSize]; 297 298 size_t activeVars = 0; 299 int size = 0; 300 ShDataType type = SH_NONE; 301 ShPrecisionType precision = SH_PRECISION_UNDEFINED; 302 int staticUse = 0; 303 const char* typeName = NULL; 304 ShGetInfo(compiler, varType, &activeVars); 305 for (size_t i = 0; i < activeVars; ++i) { 306 switch (varType) { 307 case SH_ACTIVE_ATTRIBUTES: 308 ShGetVariableInfo(compiler, SH_ACTIVE_ATTRIBUTES, static_cast<int>(i), NULL, &size, &type, &precision, &staticUse, name, NULL); 309 break; 310 case SH_ACTIVE_UNIFORMS: 311 ShGetVariableInfo(compiler, SH_ACTIVE_UNIFORMS, static_cast<int>(i), NULL, &size, &type, &precision, &staticUse, name, NULL); 312 break; 313 default: assert(0); 314 } 315 switch (type) { 316 case SH_FLOAT: typeName = "GL_FLOAT"; break; 317 case SH_FLOAT_VEC2: typeName = "GL_FLOAT_VEC2"; break; 318 case SH_FLOAT_VEC3: typeName = "GL_FLOAT_VEC3"; break; 319 case SH_FLOAT_VEC4: typeName = "GL_FLOAT_VEC4"; break; 320 case SH_INT: typeName = "GL_INT"; break; 321 case SH_INT_VEC2: typeName = "GL_INT_VEC2"; break; 322 case SH_INT_VEC3: typeName = "GL_INT_VEC3"; break; 323 case SH_INT_VEC4: typeName = "GL_INT_VEC4"; break; 324 case SH_UNSIGNED_INT: typeName = "GL_UNSIGNED_INT"; break; 325 case SH_UNSIGNED_INT_VEC2: typeName = "GL_UNSIGNED_INT_VEC2"; break; 326 case SH_UNSIGNED_INT_VEC3: typeName = "GL_UNSIGNED_INT_VEC3"; break; 327 case SH_UNSIGNED_INT_VEC4: typeName = "GL_UNSIGNED_INT_VEC4"; break; 328 case SH_BOOL: typeName = "GL_BOOL"; break; 329 case SH_BOOL_VEC2: typeName = "GL_BOOL_VEC2"; break; 330 case SH_BOOL_VEC3: typeName = "GL_BOOL_VEC3"; break; 331 case SH_BOOL_VEC4: typeName = "GL_BOOL_VEC4"; break; 332 case SH_FLOAT_MAT2: typeName = "GL_FLOAT_MAT2"; break; 333 case SH_FLOAT_MAT3: typeName = "GL_FLOAT_MAT3"; break; 334 case SH_FLOAT_MAT4: typeName = "GL_FLOAT_MAT4"; break; 335 case SH_FLOAT_MAT2x3: typeName = "GL_FLOAT_MAT2x3"; break; 336 case SH_FLOAT_MAT3x2: typeName = "GL_FLOAT_MAT3x2"; break; 337 case SH_FLOAT_MAT4x2: typeName = "GL_FLOAT_MAT4x2"; break; 338 case SH_FLOAT_MAT2x4: typeName = "GL_FLOAT_MAT2x4"; break; 339 case SH_FLOAT_MAT3x4: typeName = "GL_FLOAT_MAT3x4"; break; 340 case SH_FLOAT_MAT4x3: typeName = "GL_FLOAT_MAT4x3"; break; 341 case SH_SAMPLER_2D: typeName = "GL_SAMPLER_2D"; break; 342 case SH_SAMPLER_CUBE: typeName = "GL_SAMPLER_CUBE"; break; 343 case SH_SAMPLER_EXTERNAL_OES: typeName = "GL_SAMPLER_EXTERNAL_OES"; break; 344 default: assert(0); 345 } 346 printf("%lu: name:%s type:%s size:%d\n", i, name, typeName, size); 347 } 348 delete [] name; 349 } 350 351 static bool ReadShaderSource(const char* fileName, ShaderSource& source) { 352 FILE* in = fopen(fileName, "rb"); 353 if (!in) { 354 printf("Error: unable to open input file: %s\n", fileName); 355 return false; 356 } 357 358 // Obtain file size. 359 fseek(in, 0, SEEK_END); 360 size_t count = ftell(in); 361 rewind(in); 362 363 int len = (int)ceil((float)count / (float)NUM_SOURCE_STRINGS); 364 source.reserve(NUM_SOURCE_STRINGS); 365 // Notice the usage of do-while instead of a while loop here. 366 // It is there to handle empty files in which case a single empty 367 // string is added to vector. 368 do { 369 char* data = new char[len + 1]; 370 size_t nread = fread(data, 1, len, in); 371 data[nread] = '\0'; 372 source.push_back(data); 373 374 count -= nread; 375 } while (count > 0); 376 377 fclose(in); 378 return true; 379 } 380 381 static void FreeShaderSource(ShaderSource& source) { 382 for (ShaderSource::size_type i = 0; i < source.size(); ++i) { 383 delete [] source[i]; 384 } 385 source.clear(); 386 } 387 388