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, bool mapLongVariableNames); 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 int numAttribs = 0, numUniforms = 0; 70 ShShaderSpec spec = SH_GLES2_SPEC; 71 ShShaderOutput output = SH_ESSL_OUTPUT; 72 73 ShInitialize(); 74 75 ShBuiltInResources resources; 76 GenerateResources(&resources); 77 78 argc--; 79 argv++; 80 for (; (argc >= 1) && (failCode == ESuccess); argc--, argv++) { 81 if (argv[0][0] == '-') { 82 switch (argv[0][1]) { 83 case 'i': compileOptions |= SH_INTERMEDIATE_TREE; break; 84 case 'm': compileOptions |= SH_MAP_LONG_VARIABLE_NAMES; break; 85 case 'o': compileOptions |= SH_OBJECT_CODE; break; 86 case 'u': compileOptions |= SH_ATTRIBUTES_UNIFORMS; break; 87 case 'l': compileOptions |= SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX; break; 88 case 'e': compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS; break; 89 case 'd': compileOptions |= SH_DEPENDENCY_GRAPH; break; 90 case 't': compileOptions |= SH_TIMING_RESTRICTIONS; break; 91 case 's': 92 if (argv[0][2] == '=') { 93 switch (argv[0][3]) { 94 case 'e': spec = SH_GLES2_SPEC; break; 95 case 'w': spec = SH_WEBGL_SPEC; break; 96 case 'c': spec = SH_CSS_SHADERS_SPEC; break; 97 default: failCode = EFailUsage; 98 } 99 } else { 100 failCode = EFailUsage; 101 } 102 break; 103 case 'b': 104 if (argv[0][2] == '=') { 105 switch (argv[0][3]) { 106 case 'e': output = SH_ESSL_OUTPUT; break; 107 case 'g': output = SH_GLSL_OUTPUT; break; 108 case 'h': 109 if (argv[0][4] == '1' && argv[0][5] == '1') 110 { 111 output = SH_HLSL11_OUTPUT; 112 } 113 else 114 { 115 output = SH_HLSL9_OUTPUT; 116 } 117 break; 118 default: failCode = EFailUsage; 119 } 120 } else { 121 failCode = EFailUsage; 122 } 123 break; 124 case 'x': 125 if (argv[0][2] == '=') { 126 switch (argv[0][3]) { 127 case 'i': resources.OES_EGL_image_external = 1; break; 128 case 'd': resources.OES_standard_derivatives = 1; break; 129 case 'r': resources.ARB_texture_rectangle = 1; break; 130 default: failCode = EFailUsage; 131 } 132 } else { 133 failCode = EFailUsage; 134 } 135 break; 136 default: failCode = EFailUsage; 137 } 138 } else { 139 ShHandle compiler = 0; 140 switch (FindShaderType(argv[0])) { 141 case SH_VERTEX_SHADER: 142 if (vertexCompiler == 0) 143 vertexCompiler = ShConstructCompiler( 144 SH_VERTEX_SHADER, spec, output, &resources); 145 compiler = vertexCompiler; 146 break; 147 case SH_FRAGMENT_SHADER: 148 if (fragmentCompiler == 0) 149 fragmentCompiler = ShConstructCompiler( 150 SH_FRAGMENT_SHADER, spec, output, &resources); 151 compiler = fragmentCompiler; 152 break; 153 default: break; 154 } 155 if (compiler) { 156 bool compiled = CompileFile(argv[0], compiler, compileOptions); 157 158 LogMsg("BEGIN", "COMPILER", numCompiles, "INFO LOG"); 159 ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &bufferLen); 160 buffer = (char*) realloc(buffer, bufferLen * sizeof(char)); 161 ShGetInfoLog(compiler, buffer); 162 puts(buffer); 163 LogMsg("END", "COMPILER", numCompiles, "INFO LOG"); 164 printf("\n\n"); 165 166 if (compiled && (compileOptions & SH_OBJECT_CODE)) { 167 LogMsg("BEGIN", "COMPILER", numCompiles, "OBJ CODE"); 168 ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &bufferLen); 169 buffer = (char*) realloc(buffer, bufferLen * sizeof(char)); 170 ShGetObjectCode(compiler, buffer); 171 puts(buffer); 172 LogMsg("END", "COMPILER", numCompiles, "OBJ CODE"); 173 printf("\n\n"); 174 } 175 if (compiled && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) { 176 LogMsg("BEGIN", "COMPILER", numCompiles, "ACTIVE ATTRIBS"); 177 PrintActiveVariables(compiler, SH_ACTIVE_ATTRIBUTES, (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) != 0); 178 LogMsg("END", "COMPILER", numCompiles, "ACTIVE ATTRIBS"); 179 printf("\n\n"); 180 181 LogMsg("BEGIN", "COMPILER", numCompiles, "ACTIVE UNIFORMS"); 182 PrintActiveVariables(compiler, SH_ACTIVE_UNIFORMS, (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) != 0); 183 LogMsg("END", "COMPILER", numCompiles, "ACTIVE UNIFORMS"); 184 printf("\n\n"); 185 } 186 if (!compiled) 187 failCode = EFailCompile; 188 ++numCompiles; 189 } else { 190 failCode = EFailCompilerCreate; 191 } 192 } 193 } 194 195 if ((vertexCompiler == 0) && (fragmentCompiler == 0)) 196 failCode = EFailUsage; 197 if (failCode == EFailUsage) 198 usage(); 199 200 if (vertexCompiler) 201 ShDestruct(vertexCompiler); 202 if (fragmentCompiler) 203 ShDestruct(fragmentCompiler); 204 if (buffer) 205 free(buffer); 206 ShFinalize(); 207 208 return failCode; 209 } 210 211 // 212 // print usage to stdout 213 // 214 void usage() 215 { 216 printf("Usage: translate [-i -m -o -u -l -e -b=e -b=g -b=h -x=i -x=d] file1 file2 ...\n" 217 "Where: filename : filename ending in .frag or .vert\n" 218 " -i : print intermediate tree\n" 219 " -m : map long variable names\n" 220 " -o : print translated code\n" 221 " -u : print active attribs and uniforms\n" 222 " -l : unroll for-loops with integer indices\n" 223 " -e : emulate certain built-in functions (workaround for driver bugs)\n" 224 " -t : enforce experimental timing restrictions\n" 225 " -d : print dependency graph used to enforce timing restrictions\n" 226 " -s=e : use GLES2 spec (this is by default)\n" 227 " -s=w : use WebGL spec\n" 228 " -s=c : use CSS Shaders spec\n" 229 " -b=e : output GLSL ES code (this is by default)\n" 230 " -b=g : output GLSL code\n" 231 " -b=h9 : output HLSL9 code\n" 232 " -b=h11 : output HLSL11 code\n" 233 " -x=i : enable GL_OES_EGL_image_external\n" 234 " -x=d : enable GL_OES_EGL_standard_derivatives\n" 235 " -x=r : enable ARB_texture_rectangle\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, bool mapLongVariableNames) 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 char* mappedName = NULL; 299 if (mapLongVariableNames) { 300 size_t mappedNameSize = 0; 301 ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameSize); 302 mappedName = new char[mappedNameSize]; 303 } 304 305 size_t activeVars = 0; 306 int size = 0; 307 ShDataType type = SH_NONE; 308 const char* typeName = NULL; 309 ShGetInfo(compiler, varType, &activeVars); 310 for (size_t i = 0; i < activeVars; ++i) { 311 switch (varType) { 312 case SH_ACTIVE_ATTRIBUTES: 313 ShGetActiveAttrib(compiler, static_cast<int>(i), NULL, &size, &type, name, mappedName); 314 break; 315 case SH_ACTIVE_UNIFORMS: 316 ShGetActiveUniform(compiler, static_cast<int>(i), NULL, &size, &type, name, mappedName); 317 break; 318 default: assert(0); 319 } 320 switch (type) { 321 case SH_FLOAT: typeName = "GL_FLOAT"; break; 322 case SH_FLOAT_VEC2: typeName = "GL_FLOAT_VEC2"; break; 323 case SH_FLOAT_VEC3: typeName = "GL_FLOAT_VEC3"; break; 324 case SH_FLOAT_VEC4: typeName = "GL_FLOAT_VEC4"; break; 325 case SH_INT: typeName = "GL_INT"; break; 326 case SH_INT_VEC2: typeName = "GL_INT_VEC2"; break; 327 case SH_INT_VEC3: typeName = "GL_INT_VEC3"; break; 328 case SH_INT_VEC4: typeName = "GL_INT_VEC4"; break; 329 case SH_BOOL: typeName = "GL_BOOL"; break; 330 case SH_BOOL_VEC2: typeName = "GL_BOOL_VEC2"; break; 331 case SH_BOOL_VEC3: typeName = "GL_BOOL_VEC3"; break; 332 case SH_BOOL_VEC4: typeName = "GL_BOOL_VEC4"; break; 333 case SH_FLOAT_MAT2: typeName = "GL_FLOAT_MAT2"; break; 334 case SH_FLOAT_MAT3: typeName = "GL_FLOAT_MAT3"; break; 335 case SH_FLOAT_MAT4: typeName = "GL_FLOAT_MAT4"; break; 336 case SH_SAMPLER_2D: typeName = "GL_SAMPLER_2D"; break; 337 case SH_SAMPLER_CUBE: typeName = "GL_SAMPLER_CUBE"; break; 338 case SH_SAMPLER_EXTERNAL_OES: typeName = "GL_SAMPLER_EXTERNAL_OES"; break; 339 default: assert(0); 340 } 341 printf("%u: name:%s type:%s size:%d", i, name, typeName, size); 342 if (mapLongVariableNames) 343 printf(" mapped name:%s", mappedName); 344 printf("\n"); 345 } 346 delete [] name; 347 if (mappedName) 348 delete [] mappedName; 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 int 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 int 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