| // |
| // Copyright 2002 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| #include "GLSLANG/ShaderLang.h" |
| |
| #include <assert.h> |
| #include <math.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sstream> |
| #include <vector> |
| #include "angle_gl.h" |
| |
| #if defined(ANGLE_ENABLE_VULKAN) |
| // SPIR-V tools include for disassembly. |
| # include <spirv-tools/libspirv.hpp> |
| #endif |
| |
| // |
| // Return codes from main. |
| // |
| enum TFailCode |
| { |
| ESuccess = 0, |
| EFailUsage, |
| EFailCompile, |
| EFailCompilerCreate, |
| }; |
| |
| static void usage(); |
| static sh::GLenum FindShaderType(const char *fileName); |
| static bool CompileFile(char *fileName, ShHandle compiler, ShCompileOptions compileOptions); |
| static void LogMsg(const char *msg, const char *name, const int num, const char *logName); |
| static void PrintVariable(const std::string &prefix, size_t index, const sh::ShaderVariable &var); |
| static void PrintActiveVariables(ShHandle compiler); |
| |
| // If NUM_SOURCE_STRINGS is set to a value > 1, the input file data is |
| // broken into that many chunks. This will affect file/line numbering in |
| // the preprocessor. |
| const unsigned int NUM_SOURCE_STRINGS = 1; |
| typedef std::vector<char *> ShaderSource; |
| static bool ReadShaderSource(const char *fileName, ShaderSource &source); |
| static void FreeShaderSource(ShaderSource &source); |
| |
| static bool ParseGLSLOutputVersion(const std::string &, ShShaderOutput *outResult); |
| static bool ParseIntValue(const std::string &, int emptyDefault, int *outValue); |
| |
| static void PrintSpirv(const sh::BinaryBlob &blob); |
| |
| // |
| // Set up the per compile resources |
| // |
| void GenerateResources(ShBuiltInResources *resources) |
| { |
| sh::InitBuiltInResources(resources); |
| |
| resources->MaxVertexAttribs = 8; |
| resources->MaxVertexUniformVectors = 128; |
| resources->MaxVaryingVectors = 8; |
| resources->MaxVertexTextureImageUnits = 0; |
| resources->MaxCombinedTextureImageUnits = 8; |
| resources->MaxTextureImageUnits = 8; |
| resources->MaxFragmentUniformVectors = 16; |
| resources->MaxDrawBuffers = 1; |
| resources->MaxDualSourceDrawBuffers = 1; |
| |
| resources->OES_standard_derivatives = 0; |
| resources->OES_EGL_image_external = 0; |
| resources->EXT_geometry_shader = 1; |
| resources->ANGLE_texture_multisample = 0; |
| resources->APPLE_clip_distance = 0; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| TFailCode failCode = ESuccess; |
| |
| ShCompileOptions compileOptions = 0; |
| int numCompiles = 0; |
| ShHandle vertexCompiler = 0; |
| ShHandle fragmentCompiler = 0; |
| ShHandle computeCompiler = 0; |
| ShHandle geometryCompiler = 0; |
| ShShaderSpec spec = SH_GLES2_SPEC; |
| ShShaderOutput output = SH_ESSL_OUTPUT; |
| |
| #if defined(ANGLE_ENABLE_VULKAN) |
| sh::InitializeGlslang(); |
| #endif |
| sh::Initialize(); |
| |
| ShBuiltInResources resources; |
| GenerateResources(&resources); |
| |
| argc--; |
| argv++; |
| for (; (argc >= 1) && (failCode == ESuccess); argc--, argv++) |
| { |
| if (argv[0][0] == '-') |
| { |
| switch (argv[0][1]) |
| { |
| case 'i': |
| compileOptions |= SH_INTERMEDIATE_TREE; |
| break; |
| case 'o': |
| compileOptions |= SH_OBJECT_CODE; |
| break; |
| case 'u': |
| compileOptions |= SH_VARIABLES; |
| break; |
| case 's': |
| if (argv[0][2] == '=') |
| { |
| switch (argv[0][3]) |
| { |
| case 'e': |
| if (argv[0][4] == '3') |
| { |
| if (argv[0][5] == '1') |
| { |
| spec = SH_GLES3_1_SPEC; |
| } |
| else |
| { |
| spec = SH_GLES3_SPEC; |
| } |
| } |
| else |
| { |
| spec = SH_GLES2_SPEC; |
| } |
| break; |
| case 'w': |
| if (argv[0][4] == '3') |
| { |
| spec = SH_WEBGL3_SPEC; |
| } |
| else if (argv[0][4] == '2') |
| { |
| spec = SH_WEBGL2_SPEC; |
| } |
| else if (argv[0][4] == 'n') |
| { |
| spec = SH_WEBGL_SPEC; |
| } |
| else |
| { |
| spec = SH_WEBGL_SPEC; |
| resources.FragmentPrecisionHigh = 1; |
| } |
| break; |
| case 'd': |
| if (argv[0][4] == 'c') |
| { |
| spec = SH_GL_COMPATIBILITY_SPEC; |
| } |
| else |
| { |
| spec = SH_GL_CORE_SPEC; |
| } |
| break; |
| default: |
| failCode = EFailUsage; |
| } |
| } |
| else |
| { |
| failCode = EFailUsage; |
| } |
| break; |
| case 'b': |
| if (argv[0][2] == '=') |
| { |
| switch (argv[0][3]) |
| { |
| case 'e': |
| output = SH_ESSL_OUTPUT; |
| compileOptions |= SH_INITIALIZE_UNINITIALIZED_LOCALS; |
| break; |
| case 'g': |
| if (!ParseGLSLOutputVersion(&argv[0][sizeof("-b=g") - 1], &output)) |
| { |
| failCode = EFailUsage; |
| } |
| compileOptions |= SH_INITIALIZE_UNINITIALIZED_LOCALS; |
| break; |
| case 'v': |
| output = SH_SPIRV_VULKAN_OUTPUT; |
| compileOptions |= SH_INITIALIZE_UNINITIALIZED_LOCALS; |
| break; |
| case 'h': |
| if (argv[0][4] == '1' && argv[0][5] == '1') |
| { |
| output = SH_HLSL_4_1_OUTPUT; |
| } |
| else |
| { |
| output = SH_HLSL_3_0_OUTPUT; |
| } |
| break; |
| default: |
| failCode = EFailUsage; |
| } |
| } |
| else |
| { |
| failCode = EFailUsage; |
| } |
| break; |
| case 'x': |
| if (argv[0][2] == '=') |
| { |
| // clang-format off |
| switch (argv[0][3]) |
| { |
| case 'i': resources.OES_EGL_image_external = 1; break; |
| case 'd': resources.OES_standard_derivatives = 1; break; |
| case 'r': resources.ARB_texture_rectangle = 1; break; |
| case 'b': |
| if (ParseIntValue(&argv[0][sizeof("-x=b") - 1], 1, |
| &resources.MaxDualSourceDrawBuffers)) |
| { |
| resources.EXT_blend_func_extended = 1; |
| } |
| else |
| { |
| failCode = EFailUsage; |
| } |
| break; |
| case 'w': |
| if (ParseIntValue(&argv[0][sizeof("-x=w") - 1], 1, |
| &resources.MaxDrawBuffers)) |
| { |
| resources.EXT_draw_buffers = 1; |
| } |
| else |
| { |
| failCode = EFailUsage; |
| } |
| break; |
| case 'g': resources.EXT_frag_depth = 1; break; |
| case 'l': resources.EXT_shader_texture_lod = 1; break; |
| case 'f': resources.EXT_shader_framebuffer_fetch = 1; break; |
| case 'n': resources.NV_shader_framebuffer_fetch = 1; break; |
| case 'a': resources.ARM_shader_framebuffer_fetch = 1; break; |
| case 'm': |
| resources.OVR_multiview2 = 1; |
| resources.OVR_multiview = 1; |
| compileOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW; |
| compileOptions |= SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER; |
| break; |
| case 'y': resources.EXT_YUV_target = 1; break; |
| case 's': resources.OES_sample_variables = 1; break; |
| default: failCode = EFailUsage; |
| } |
| // clang-format on |
| } |
| else |
| { |
| failCode = EFailUsage; |
| } |
| break; |
| default: |
| failCode = EFailUsage; |
| } |
| } |
| else |
| { |
| if (spec != SH_GLES2_SPEC && spec != SH_WEBGL_SPEC) |
| { |
| resources.MaxDrawBuffers = 8; |
| resources.MaxVertexTextureImageUnits = 16; |
| resources.MaxTextureImageUnits = 16; |
| } |
| ShHandle compiler = 0; |
| switch (FindShaderType(argv[0])) |
| { |
| case GL_VERTEX_SHADER: |
| if (vertexCompiler == 0) |
| { |
| vertexCompiler = |
| sh::ConstructCompiler(GL_VERTEX_SHADER, spec, output, &resources); |
| } |
| compiler = vertexCompiler; |
| break; |
| case GL_FRAGMENT_SHADER: |
| if (fragmentCompiler == 0) |
| { |
| fragmentCompiler = |
| sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources); |
| } |
| compiler = fragmentCompiler; |
| break; |
| case GL_COMPUTE_SHADER: |
| if (computeCompiler == 0) |
| { |
| computeCompiler = |
| sh::ConstructCompiler(GL_COMPUTE_SHADER, spec, output, &resources); |
| } |
| compiler = computeCompiler; |
| break; |
| case GL_GEOMETRY_SHADER_EXT: |
| if (geometryCompiler == 0) |
| { |
| geometryCompiler = |
| sh::ConstructCompiler(GL_GEOMETRY_SHADER_EXT, spec, output, &resources); |
| } |
| compiler = geometryCompiler; |
| break; |
| default: |
| break; |
| } |
| if (compiler) |
| { |
| switch (output) |
| { |
| case SH_HLSL_3_0_OUTPUT: |
| case SH_HLSL_4_1_OUTPUT: |
| case SH_HLSL_4_0_FL9_3_OUTPUT: |
| compileOptions &= ~SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER; |
| break; |
| default: |
| break; |
| } |
| |
| bool compiled = CompileFile(argv[0], compiler, compileOptions); |
| |
| LogMsg("BEGIN", "COMPILER", numCompiles, "INFO LOG"); |
| std::string log = sh::GetInfoLog(compiler); |
| puts(log.c_str()); |
| LogMsg("END", "COMPILER", numCompiles, "INFO LOG"); |
| printf("\n\n"); |
| |
| if (compiled && (compileOptions & SH_OBJECT_CODE)) |
| { |
| LogMsg("BEGIN", "COMPILER", numCompiles, "OBJ CODE"); |
| if (output != SH_SPIRV_VULKAN_OUTPUT) |
| { |
| const std::string &code = sh::GetObjectCode(compiler); |
| puts(code.c_str()); |
| } |
| else |
| { |
| const sh::BinaryBlob &blob = sh::GetObjectBinaryBlob(compiler); |
| PrintSpirv(blob); |
| } |
| LogMsg("END", "COMPILER", numCompiles, "OBJ CODE"); |
| printf("\n\n"); |
| } |
| if (compiled && (compileOptions & SH_VARIABLES)) |
| { |
| LogMsg("BEGIN", "COMPILER", numCompiles, "VARIABLES"); |
| PrintActiveVariables(compiler); |
| LogMsg("END", "COMPILER", numCompiles, "VARIABLES"); |
| printf("\n\n"); |
| } |
| if (!compiled) |
| failCode = EFailCompile; |
| ++numCompiles; |
| } |
| else |
| { |
| failCode = EFailCompilerCreate; |
| } |
| } |
| } |
| |
| if ((vertexCompiler == 0) && (fragmentCompiler == 0) && (computeCompiler == 0) && |
| (geometryCompiler == 0)) |
| failCode = EFailUsage; |
| if (failCode == EFailUsage) |
| usage(); |
| |
| if (vertexCompiler) |
| sh::Destruct(vertexCompiler); |
| if (fragmentCompiler) |
| sh::Destruct(fragmentCompiler); |
| if (computeCompiler) |
| sh::Destruct(computeCompiler); |
| if (geometryCompiler) |
| sh::Destruct(geometryCompiler); |
| |
| sh::Finalize(); |
| #if defined(ANGLE_ENABLE_VULKAN) |
| sh::FinalizeGlslang(); |
| #endif |
| |
| return failCode; |
| } |
| |
| // |
| // print usage to stdout |
| // |
| void usage() |
| { |
| // clang-format off |
| printf( |
| "Usage: translate [-i -o -u -l -b=e -b=g -b=h9 -x=i -x=d] file1 file2 ...\n" |
| "Where: filename : filename ending in .frag or .vert\n" |
| " -i : print intermediate tree\n" |
| " -o : print translated code\n" |
| " -u : print active attribs, uniforms, varyings and program outputs\n" |
| " -s=e2 : use GLES2 spec (this is by default)\n" |
| " -s=e3 : use GLES3 spec\n" |
| " -s=e31 : use GLES31 spec (in development)\n" |
| " -s=w : use WebGL 1.0 spec\n" |
| " -s=wn : use WebGL 1.0 spec with no highp support in fragment shaders\n" |
| " -s=w2 : use WebGL 2.0 spec\n" |
| " -s=d : use Desktop Core spec (in development)\n" |
| " -s=dc : use Desktop Compatibility spec (in development)\n" |
| " -b=e : output GLSL ES code (this is by default)\n" |
| " -b=g : output GLSL code (compatibility profile)\n" |
| " -b=g[NUM]: output GLSL code (NUM can be 130, 140, 150, 330, 400, 410, 420, 430, " |
| "440, 450)\n" |
| " -b=v : output Vulkan SPIR-V code\n" |
| " -b=h9 : output HLSL9 code\n" |
| " -b=h11 : output HLSL11 code\n" |
| " -x=i : enable GL_OES_EGL_image_external\n" |
| " -x=d : enable GL_OES_EGL_standard_derivatives\n" |
| " -x=r : enable ARB_texture_rectangle\n" |
| " -x=b[NUM]: enable EXT_blend_func_extended (NUM default 1)\n" |
| " -x=w[NUM]: enable EXT_draw_buffers (NUM default 1)\n" |
| " -x=g : enable EXT_frag_depth\n" |
| " -x=l : enable EXT_shader_texture_lod\n" |
| " -x=f : enable EXT_shader_framebuffer_fetch\n" |
| " -x=n : enable NV_shader_framebuffer_fetch\n" |
| " -x=a : enable ARM_shader_framebuffer_fetch\n" |
| " -x=m : enable OVR_multiview\n" |
| " -x=y : enable YUV_target\n" |
| " -x=s : enable OES_sample_variables\n"); |
| // clang-format on |
| } |
| |
| // |
| // Deduce the shader type from the filename. Files must end in one of the |
| // following extensions: |
| // |
| // .frag* = fragment shader |
| // .vert* = vertex shader |
| // |
| sh::GLenum FindShaderType(const char *fileName) |
| { |
| assert(fileName); |
| |
| const char *ext = strrchr(fileName, '.'); |
| |
| if (ext && strcmp(ext, ".sl") == 0) |
| for (; ext > fileName && ext[0] != '.'; ext--) |
| ; |
| |
| ext = strrchr(fileName, '.'); |
| if (ext) |
| { |
| if (strncmp(ext, ".frag", 5) == 0) |
| return GL_FRAGMENT_SHADER; |
| if (strncmp(ext, ".vert", 5) == 0) |
| return GL_VERTEX_SHADER; |
| if (strncmp(ext, ".comp", 5) == 0) |
| return GL_COMPUTE_SHADER; |
| if (strncmp(ext, ".geom", 5) == 0) |
| return GL_GEOMETRY_SHADER_EXT; |
| } |
| |
| return GL_FRAGMENT_SHADER; |
| } |
| |
| // |
| // Read a file's data into a string, and compile it using sh::Compile |
| // |
| bool CompileFile(char *fileName, ShHandle compiler, ShCompileOptions compileOptions) |
| { |
| ShaderSource source; |
| if (!ReadShaderSource(fileName, source)) |
| return false; |
| |
| int ret = sh::Compile(compiler, &source[0], source.size(), compileOptions); |
| |
| FreeShaderSource(source); |
| return ret ? true : false; |
| } |
| |
| void LogMsg(const char *msg, const char *name, const int num, const char *logName) |
| { |
| printf("#### %s %s %d %s ####\n", msg, name, num, logName); |
| } |
| |
| void PrintVariable(const std::string &prefix, size_t index, const sh::ShaderVariable &var) |
| { |
| std::string typeName; |
| switch (var.type) |
| { |
| case GL_FLOAT: |
| typeName = "GL_FLOAT"; |
| break; |
| case GL_FLOAT_VEC2: |
| typeName = "GL_FLOAT_VEC2"; |
| break; |
| case GL_FLOAT_VEC3: |
| typeName = "GL_FLOAT_VEC3"; |
| break; |
| case GL_FLOAT_VEC4: |
| typeName = "GL_FLOAT_VEC4"; |
| break; |
| case GL_INT: |
| typeName = "GL_INT"; |
| break; |
| case GL_INT_VEC2: |
| typeName = "GL_INT_VEC2"; |
| break; |
| case GL_INT_VEC3: |
| typeName = "GL_INT_VEC3"; |
| break; |
| case GL_INT_VEC4: |
| typeName = "GL_INT_VEC4"; |
| break; |
| case GL_UNSIGNED_INT: |
| typeName = "GL_UNSIGNED_INT"; |
| break; |
| case GL_UNSIGNED_INT_VEC2: |
| typeName = "GL_UNSIGNED_INT_VEC2"; |
| break; |
| case GL_UNSIGNED_INT_VEC3: |
| typeName = "GL_UNSIGNED_INT_VEC3"; |
| break; |
| case GL_UNSIGNED_INT_VEC4: |
| typeName = "GL_UNSIGNED_INT_VEC4"; |
| break; |
| case GL_BOOL: |
| typeName = "GL_BOOL"; |
| break; |
| case GL_BOOL_VEC2: |
| typeName = "GL_BOOL_VEC2"; |
| break; |
| case GL_BOOL_VEC3: |
| typeName = "GL_BOOL_VEC3"; |
| break; |
| case GL_BOOL_VEC4: |
| typeName = "GL_BOOL_VEC4"; |
| break; |
| case GL_FLOAT_MAT2: |
| typeName = "GL_FLOAT_MAT2"; |
| break; |
| case GL_FLOAT_MAT3: |
| typeName = "GL_FLOAT_MAT3"; |
| break; |
| case GL_FLOAT_MAT4: |
| typeName = "GL_FLOAT_MAT4"; |
| break; |
| case GL_FLOAT_MAT2x3: |
| typeName = "GL_FLOAT_MAT2x3"; |
| break; |
| case GL_FLOAT_MAT3x2: |
| typeName = "GL_FLOAT_MAT3x2"; |
| break; |
| case GL_FLOAT_MAT4x2: |
| typeName = "GL_FLOAT_MAT4x2"; |
| break; |
| case GL_FLOAT_MAT2x4: |
| typeName = "GL_FLOAT_MAT2x4"; |
| break; |
| case GL_FLOAT_MAT3x4: |
| typeName = "GL_FLOAT_MAT3x4"; |
| break; |
| case GL_FLOAT_MAT4x3: |
| typeName = "GL_FLOAT_MAT4x3"; |
| break; |
| |
| case GL_SAMPLER_2D: |
| typeName = "GL_SAMPLER_2D"; |
| break; |
| case GL_SAMPLER_3D: |
| typeName = "GL_SAMPLER_3D"; |
| break; |
| case GL_SAMPLER_CUBE: |
| typeName = "GL_SAMPLER_CUBE"; |
| break; |
| case GL_SAMPLER_CUBE_SHADOW: |
| typeName = "GL_SAMPLER_CUBE_SHADOW"; |
| break; |
| case GL_SAMPLER_2D_SHADOW: |
| typeName = "GL_SAMPLER_2D_ARRAY_SHADOW"; |
| break; |
| case GL_SAMPLER_2D_ARRAY: |
| typeName = "GL_SAMPLER_2D_ARRAY"; |
| break; |
| case GL_SAMPLER_2D_ARRAY_SHADOW: |
| typeName = "GL_SAMPLER_2D_ARRAY_SHADOW"; |
| break; |
| case GL_SAMPLER_2D_MULTISAMPLE: |
| typeName = "GL_SAMPLER_2D_MULTISAMPLE"; |
| break; |
| case GL_IMAGE_2D: |
| typeName = "GL_IMAGE_2D"; |
| break; |
| case GL_IMAGE_3D: |
| typeName = "GL_IMAGE_3D"; |
| break; |
| case GL_IMAGE_CUBE: |
| typeName = "GL_IMAGE_CUBE"; |
| break; |
| case GL_IMAGE_2D_ARRAY: |
| typeName = "GL_IMAGE_2D_ARRAY"; |
| break; |
| |
| case GL_INT_SAMPLER_2D: |
| typeName = "GL_INT_SAMPLER_2D"; |
| break; |
| case GL_INT_SAMPLER_3D: |
| typeName = "GL_INT_SAMPLER_3D"; |
| break; |
| case GL_INT_SAMPLER_CUBE: |
| typeName = "GL_INT_SAMPLER_CUBE"; |
| break; |
| case GL_INT_SAMPLER_2D_ARRAY: |
| typeName = "GL_INT_SAMPLER_2D_ARRAY"; |
| break; |
| case GL_INT_SAMPLER_2D_MULTISAMPLE: |
| typeName = "GL_INT_SAMPLER_2D_MULTISAMPLE"; |
| break; |
| case GL_INT_IMAGE_2D: |
| typeName = "GL_INT_IMAGE_2D"; |
| break; |
| case GL_INT_IMAGE_3D: |
| typeName = "GL_INT_IMAGE_3D"; |
| break; |
| case GL_INT_IMAGE_CUBE: |
| typeName = "GL_INT_IMAGE_CUBE"; |
| break; |
| case GL_INT_IMAGE_2D_ARRAY: |
| typeName = "GL_INT_IMAGE_2D_ARRAY"; |
| break; |
| |
| case GL_UNSIGNED_INT_SAMPLER_2D: |
| typeName = "GL_UNSIGNED_INT_SAMPLER_2D"; |
| break; |
| case GL_UNSIGNED_INT_SAMPLER_3D: |
| typeName = "GL_UNSIGNED_INT_SAMPLER_3D"; |
| break; |
| case GL_UNSIGNED_INT_SAMPLER_CUBE: |
| typeName = "GL_UNSIGNED_INT_SAMPLER_CUBE"; |
| break; |
| case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: |
| typeName = "GL_UNSIGNED_INT_SAMPLER_2D_ARRAY"; |
| break; |
| case GL_UNSIGNED_INT_ATOMIC_COUNTER: |
| typeName = "GL_UNSIGNED_INT_ATOMIC_COUNTER"; |
| break; |
| case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: |
| typeName = "GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE"; |
| break; |
| case GL_UNSIGNED_INT_IMAGE_2D: |
| typeName = "GL_UNSIGNED_INT_IMAGE_2D"; |
| break; |
| case GL_UNSIGNED_INT_IMAGE_3D: |
| typeName = "GL_UNSIGNED_INT_IMAGE_3D"; |
| break; |
| case GL_UNSIGNED_INT_IMAGE_CUBE: |
| typeName = "GL_UNSIGNED_INT_IMAGE_CUBE"; |
| break; |
| case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: |
| typeName = "GL_UNSIGNED_INT_IMAGE_2D_ARRAY"; |
| break; |
| |
| case GL_SAMPLER_EXTERNAL_OES: |
| typeName = "GL_SAMPLER_EXTERNAL_OES"; |
| break; |
| case GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT: |
| typeName = "GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT"; |
| break; |
| default: |
| typeName = "UNKNOWN"; |
| break; |
| } |
| |
| printf("%s %u : name=%s, mappedName=%s, type=%s, arraySizes=", prefix.c_str(), |
| static_cast<unsigned int>(index), var.name.c_str(), var.mappedName.c_str(), |
| typeName.c_str()); |
| for (unsigned int arraySize : var.arraySizes) |
| { |
| printf("%u ", arraySize); |
| } |
| printf("\n"); |
| if (var.fields.size()) |
| { |
| std::string structPrefix; |
| for (size_t i = 0; i < prefix.size(); ++i) |
| structPrefix += ' '; |
| printf("%s struct %s\n", structPrefix.c_str(), var.structOrBlockName.c_str()); |
| structPrefix += " field"; |
| for (size_t i = 0; i < var.fields.size(); ++i) |
| PrintVariable(structPrefix, i, var.fields[i]); |
| } |
| } |
| |
| static void PrintActiveVariables(ShHandle compiler) |
| { |
| const std::vector<sh::ShaderVariable> *uniforms = sh::GetUniforms(compiler); |
| const std::vector<sh::ShaderVariable> *inputVaryings = sh::GetInputVaryings(compiler); |
| const std::vector<sh::ShaderVariable> *outputVaryings = sh::GetOutputVaryings(compiler); |
| const std::vector<sh::ShaderVariable> *attributes = sh::GetAttributes(compiler); |
| const std::vector<sh::ShaderVariable> *outputs = sh::GetOutputVariables(compiler); |
| for (size_t varCategory = 0; varCategory < 5; ++varCategory) |
| { |
| size_t numVars = 0; |
| std::string varCategoryName; |
| if (varCategory == 0) |
| { |
| numVars = uniforms->size(); |
| varCategoryName = "uniform"; |
| } |
| else if (varCategory == 1) |
| { |
| numVars = inputVaryings->size(); |
| varCategoryName = "input varying"; |
| } |
| else if (varCategory == 2) |
| { |
| numVars = outputVaryings->size(); |
| varCategoryName = "output varying"; |
| } |
| else if (varCategory == 3) |
| { |
| numVars = attributes->size(); |
| varCategoryName = "attribute"; |
| } |
| else |
| { |
| numVars = outputs->size(); |
| varCategoryName = "output"; |
| } |
| |
| for (size_t i = 0; i < numVars; ++i) |
| { |
| const sh::ShaderVariable *var; |
| if (varCategory == 0) |
| var = &((*uniforms)[i]); |
| else if (varCategory == 1) |
| var = &((*inputVaryings)[i]); |
| else if (varCategory == 2) |
| var = &((*outputVaryings)[i]); |
| else if (varCategory == 3) |
| var = &((*attributes)[i]); |
| else |
| var = &((*outputs)[i]); |
| |
| PrintVariable(varCategoryName, i, *var); |
| } |
| printf("\n"); |
| } |
| } |
| |
| static bool ReadShaderSource(const char *fileName, ShaderSource &source) |
| { |
| FILE *in = fopen(fileName, "rb"); |
| if (!in) |
| { |
| printf("Error: unable to open input file: %s\n", fileName); |
| return false; |
| } |
| |
| // Obtain file size. |
| fseek(in, 0, SEEK_END); |
| size_t count = ftell(in); |
| rewind(in); |
| |
| int len = (int)ceil((float)count / (float)NUM_SOURCE_STRINGS); |
| source.reserve(NUM_SOURCE_STRINGS); |
| // Notice the usage of do-while instead of a while loop here. |
| // It is there to handle empty files in which case a single empty |
| // string is added to vector. |
| do |
| { |
| char *data = new char[len + 1]; |
| size_t nread = fread(data, 1, len, in); |
| data[nread] = '\0'; |
| source.push_back(data); |
| |
| count -= nread; |
| } while (count > 0); |
| |
| fclose(in); |
| return true; |
| } |
| |
| static void FreeShaderSource(ShaderSource &source) |
| { |
| for (ShaderSource::size_type i = 0; i < source.size(); ++i) |
| { |
| delete[] source[i]; |
| } |
| source.clear(); |
| } |
| |
| static bool ParseGLSLOutputVersion(const std::string &num, ShShaderOutput *outResult) |
| { |
| if (num.length() == 0) |
| { |
| *outResult = SH_GLSL_COMPATIBILITY_OUTPUT; |
| return true; |
| } |
| std::istringstream input(num); |
| int value; |
| if (!(input >> value && input.eof())) |
| { |
| return false; |
| } |
| |
| switch (value) |
| { |
| case 130: |
| *outResult = SH_GLSL_130_OUTPUT; |
| return true; |
| case 140: |
| *outResult = SH_GLSL_140_OUTPUT; |
| return true; |
| case 150: |
| *outResult = SH_GLSL_150_CORE_OUTPUT; |
| return true; |
| case 330: |
| *outResult = SH_GLSL_330_CORE_OUTPUT; |
| return true; |
| case 400: |
| *outResult = SH_GLSL_400_CORE_OUTPUT; |
| return true; |
| case 410: |
| *outResult = SH_GLSL_410_CORE_OUTPUT; |
| return true; |
| case 420: |
| *outResult = SH_GLSL_420_CORE_OUTPUT; |
| return true; |
| case 430: |
| *outResult = SH_GLSL_430_CORE_OUTPUT; |
| return true; |
| case 440: |
| *outResult = SH_GLSL_440_CORE_OUTPUT; |
| return true; |
| case 450: |
| *outResult = SH_GLSL_450_CORE_OUTPUT; |
| return true; |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| static bool ParseIntValue(const std::string &num, int emptyDefault, int *outValue) |
| { |
| if (num.length() == 0) |
| { |
| *outValue = emptyDefault; |
| return true; |
| } |
| |
| std::istringstream input(num); |
| int value; |
| if (!(input >> value && input.eof())) |
| { |
| return false; |
| } |
| *outValue = value; |
| return true; |
| } |
| |
| static void PrintSpirv(const sh::BinaryBlob &blob) |
| { |
| #if defined(ANGLE_ENABLE_VULKAN) |
| spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1); |
| |
| std::string readableSpirv; |
| spirvTools.Disassemble(blob, &readableSpirv, 0); |
| |
| puts(readableSpirv.c_str()); |
| #endif |
| } |