Home | History | Annotate | Download | only in translator
      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 //
      8 // Implement the top-level of interface to the compiler,
      9 // as defined in ShaderLang.h
     10 //
     11 
     12 #include "GLSLANG/ShaderLang.h"
     13 
     14 #include "compiler/translator/Compiler.h"
     15 #include "compiler/translator/InitializeDll.h"
     16 #include "compiler/translator/length_limits.h"
     17 #include "compiler/translator/TranslatorHLSL.h"
     18 #include "compiler/translator/VariablePacker.h"
     19 #include "angle_gl.h"
     20 
     21 namespace
     22 {
     23 
     24 enum ShaderVariableType
     25 {
     26     SHADERVAR_UNIFORM,
     27     SHADERVAR_VARYING,
     28     SHADERVAR_ATTRIBUTE,
     29     SHADERVAR_OUTPUTVARIABLE,
     30     SHADERVAR_INTERFACEBLOCK
     31 };
     32 
     33 bool isInitialized = false;
     34 
     35 //
     36 // This is the platform independent interface between an OGL driver
     37 // and the shading language compiler.
     38 //
     39 
     40 static bool CheckVariableMaxLengths(const ShHandle handle,
     41                                     size_t expectedValue)
     42 {
     43     size_t activeUniformLimit = 0;
     44     ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
     45     size_t activeAttribLimit = 0;
     46     ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
     47     size_t varyingLimit = 0;
     48     ShGetInfo(handle, SH_VARYING_MAX_LENGTH, &varyingLimit);
     49     return (expectedValue == activeUniformLimit &&
     50             expectedValue == activeAttribLimit &&
     51             expectedValue == varyingLimit);
     52 }
     53 
     54 bool CheckMappedNameMaxLength(const ShHandle handle, size_t expectedValue)
     55 {
     56     size_t mappedNameMaxLength = 0;
     57     ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
     58     return (expectedValue == mappedNameMaxLength);
     59 }
     60 
     61 template <typename VarT>
     62 const sh::ShaderVariable *ReturnVariable(const std::vector<VarT> &infoList, int index)
     63 {
     64     if (index < 0 || static_cast<size_t>(index) >= infoList.size())
     65     {
     66         return NULL;
     67     }
     68 
     69     return &infoList[index];
     70 }
     71 
     72 const sh::ShaderVariable *GetVariable(const TCompiler *compiler, ShShaderInfo varType, int index)
     73 {
     74     switch (varType)
     75     {
     76       case SH_ACTIVE_ATTRIBUTES:
     77         return ReturnVariable(compiler->getAttributes(), index);
     78       case SH_ACTIVE_UNIFORMS:
     79         return ReturnVariable(compiler->getExpandedUniforms(), index);
     80       case SH_VARYINGS:
     81         return ReturnVariable(compiler->getExpandedVaryings(), index);
     82       default:
     83         UNREACHABLE();
     84         return NULL;
     85     }
     86 }
     87 
     88 ShPrecisionType ConvertPrecision(sh::GLenum precision)
     89 {
     90     switch (precision)
     91     {
     92       case GL_HIGH_FLOAT:
     93       case GL_HIGH_INT:
     94         return SH_PRECISION_HIGHP;
     95       case GL_MEDIUM_FLOAT:
     96       case GL_MEDIUM_INT:
     97         return SH_PRECISION_MEDIUMP;
     98       case GL_LOW_FLOAT:
     99       case GL_LOW_INT:
    100         return SH_PRECISION_LOWP;
    101       default:
    102         return SH_PRECISION_UNDEFINED;
    103     }
    104 }
    105 
    106 template <typename VarT>
    107 const std::vector<VarT> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType);
    108 
    109 template <>
    110 const std::vector<sh::Uniform> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
    111 {
    112     return &compiler->getUniforms();
    113 }
    114 
    115 template <>
    116 const std::vector<sh::Varying> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
    117 {
    118     return &compiler->getVaryings();
    119 }
    120 
    121 template <>
    122 const std::vector<sh::Attribute> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType)
    123 {
    124     return (variableType == SHADERVAR_ATTRIBUTE ?
    125         &compiler->getAttributes() :
    126         &compiler->getOutputVariables());
    127 }
    128 
    129 template <>
    130 const std::vector<sh::InterfaceBlock> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
    131 {
    132     return &compiler->getInterfaceBlocks();
    133 }
    134 
    135 template <typename VarT>
    136 const std::vector<VarT> *GetShaderVariables(const ShHandle handle, ShaderVariableType variableType)
    137 {
    138     if (!handle)
    139     {
    140         return NULL;
    141     }
    142 
    143     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    144     TCompiler* compiler = base->getAsCompiler();
    145     if (!compiler)
    146     {
    147         return NULL;
    148     }
    149 
    150     return GetVariableList<VarT>(compiler, variableType);
    151 }
    152 
    153 }
    154 
    155 //
    156 // Driver must call this first, once, before doing any other compiler operations.
    157 // Subsequent calls to this function are no-op.
    158 //
    159 int ShInitialize()
    160 {
    161     if (!isInitialized)
    162     {
    163         isInitialized = InitProcess();
    164     }
    165     return isInitialized ? 1 : 0;
    166 }
    167 
    168 //
    169 // Cleanup symbol tables
    170 //
    171 int ShFinalize()
    172 {
    173     if (isInitialized)
    174     {
    175         DetachProcess();
    176         isInitialized = false;
    177     }
    178     return 1;
    179 }
    180 
    181 //
    182 // Initialize built-in resources with minimum expected values.
    183 //
    184 void ShInitBuiltInResources(ShBuiltInResources* resources)
    185 {
    186     // Constants.
    187     resources->MaxVertexAttribs = 8;
    188     resources->MaxVertexUniformVectors = 128;
    189     resources->MaxVaryingVectors = 8;
    190     resources->MaxVertexTextureImageUnits = 0;
    191     resources->MaxCombinedTextureImageUnits = 8;
    192     resources->MaxTextureImageUnits = 8;
    193     resources->MaxFragmentUniformVectors = 16;
    194     resources->MaxDrawBuffers = 1;
    195 
    196     // Extensions.
    197     resources->OES_standard_derivatives = 0;
    198     resources->OES_EGL_image_external = 0;
    199     resources->ARB_texture_rectangle = 0;
    200     resources->EXT_draw_buffers = 0;
    201     resources->EXT_frag_depth = 0;
    202     resources->EXT_shader_texture_lod = 0;
    203 
    204     // Disable highp precision in fragment shader by default.
    205     resources->FragmentPrecisionHigh = 0;
    206 
    207     // GLSL ES 3.0 constants.
    208     resources->MaxVertexOutputVectors = 16;
    209     resources->MaxFragmentInputVectors = 15;
    210     resources->MinProgramTexelOffset = -8;
    211     resources->MaxProgramTexelOffset = 7;
    212 
    213     // Disable name hashing by default.
    214     resources->HashFunction = NULL;
    215 
    216     resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
    217 
    218     resources->MaxExpressionComplexity = 256;
    219     resources->MaxCallStackDepth = 256;
    220 }
    221 
    222 //
    223 // Driver calls these to create and destroy compiler objects.
    224 //
    225 ShHandle ShConstructCompiler(sh::GLenum type, ShShaderSpec spec,
    226                              ShShaderOutput output,
    227                              const ShBuiltInResources* resources)
    228 {
    229     TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
    230     TCompiler* compiler = base->getAsCompiler();
    231     if (compiler == 0)
    232         return 0;
    233 
    234     // Generate built-in symbol table.
    235     if (!compiler->Init(*resources)) {
    236         ShDestruct(base);
    237         return 0;
    238     }
    239 
    240     return reinterpret_cast<void*>(base);
    241 }
    242 
    243 void ShDestruct(ShHandle handle)
    244 {
    245     if (handle == 0)
    246         return;
    247 
    248     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    249 
    250     if (base->getAsCompiler())
    251         DeleteCompiler(base->getAsCompiler());
    252 }
    253 
    254 void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outString)
    255 {
    256     if (!handle || !outString)
    257     {
    258         return;
    259     }
    260 
    261     TShHandleBase *base = static_cast<TShHandleBase*>(handle);
    262     TCompiler *compiler = base->getAsCompiler();
    263     if (!compiler)
    264     {
    265         return;
    266     }
    267 
    268     strncpy(outString, compiler->getBuiltInResourcesString().c_str(), outStringLen);
    269     outString[outStringLen - 1] = '\0';
    270 }
    271 //
    272 // Do an actual compile on the given strings.  The result is left
    273 // in the given compile object.
    274 //
    275 // Return:  The return value of ShCompile is really boolean, indicating
    276 // success or failure.
    277 //
    278 int ShCompile(
    279     const ShHandle handle,
    280     const char* const shaderStrings[],
    281     size_t numStrings,
    282     int compileOptions)
    283 {
    284     if (handle == 0)
    285         return 0;
    286 
    287     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
    288     TCompiler* compiler = base->getAsCompiler();
    289     if (compiler == 0)
    290         return 0;
    291 
    292     bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
    293     return success ? 1 : 0;
    294 }
    295 
    296 void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params)
    297 {
    298     if (!handle || !params)
    299         return;
    300 
    301     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    302     TCompiler* compiler = base->getAsCompiler();
    303     if (!compiler) return;
    304 
    305     switch(pname)
    306     {
    307     case SH_INFO_LOG_LENGTH:
    308         *params = compiler->getInfoSink().info.size() + 1;
    309         break;
    310     case SH_OBJECT_CODE_LENGTH:
    311         *params = compiler->getInfoSink().obj.size() + 1;
    312         break;
    313     case SH_ACTIVE_UNIFORMS:
    314         *params = compiler->getExpandedUniforms().size();
    315         break;
    316     case SH_ACTIVE_UNIFORM_MAX_LENGTH:
    317         *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
    318         break;
    319     case SH_ACTIVE_ATTRIBUTES:
    320         *params = compiler->getAttributes().size();
    321         break;
    322     case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
    323         *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
    324         break;
    325     case SH_VARYINGS:
    326         *params = compiler->getExpandedVaryings().size();
    327         break;
    328     case SH_VARYING_MAX_LENGTH:
    329         *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
    330         break;
    331     case SH_MAPPED_NAME_MAX_LENGTH:
    332         // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
    333         // handle array and struct dereferences.
    334         *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
    335         break;
    336     case SH_NAME_MAX_LENGTH:
    337         *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
    338         break;
    339     case SH_HASHED_NAME_MAX_LENGTH:
    340         if (compiler->getHashFunction() == NULL) {
    341             *params = 0;
    342         } else {
    343             // 64 bits hashing output requires 16 bytes for hex
    344             // representation.
    345             const char HashedNamePrefix[] = HASHED_NAME_PREFIX;
    346             (void)HashedNamePrefix;
    347             *params = 16 + sizeof(HashedNamePrefix);
    348         }
    349         break;
    350     case SH_HASHED_NAMES_COUNT:
    351         *params = compiler->getNameMap().size();
    352         break;
    353     case SH_SHADER_VERSION:
    354         *params = compiler->getShaderVersion();
    355         break;
    356     case SH_RESOURCES_STRING_LENGTH:
    357         *params = compiler->getBuiltInResourcesString().length() + 1;
    358         break;
    359     case SH_OUTPUT_TYPE:
    360         *params = compiler->getOutputType();
    361         break;
    362     default: UNREACHABLE();
    363     }
    364 }
    365 
    366 //
    367 // Return any compiler log of messages for the application.
    368 //
    369 void ShGetInfoLog(const ShHandle handle, char* infoLog)
    370 {
    371     if (!handle || !infoLog)
    372         return;
    373 
    374     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    375     TCompiler* compiler = base->getAsCompiler();
    376     if (!compiler) return;
    377 
    378     TInfoSink& infoSink = compiler->getInfoSink();
    379     strcpy(infoLog, infoSink.info.c_str());
    380 }
    381 
    382 //
    383 // Return any object code.
    384 //
    385 void ShGetObjectCode(const ShHandle handle, char* objCode)
    386 {
    387     if (!handle || !objCode)
    388         return;
    389 
    390     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    391     TCompiler* compiler = base->getAsCompiler();
    392     if (!compiler) return;
    393 
    394     TInfoSink& infoSink = compiler->getInfoSink();
    395     strcpy(objCode, infoSink.obj.c_str());
    396 }
    397 
    398 void ShGetVariableInfo(const ShHandle handle,
    399                        ShShaderInfo varType,
    400                        int index,
    401                        size_t* length,
    402                        int* size,
    403                        sh::GLenum* type,
    404                        ShPrecisionType* precision,
    405                        int* staticUse,
    406                        char* name,
    407                        char* mappedName)
    408 {
    409     if (!handle || !size || !type || !precision || !staticUse || !name)
    410         return;
    411     ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
    412            (varType == SH_ACTIVE_UNIFORMS) ||
    413            (varType == SH_VARYINGS));
    414 
    415     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
    416     TCompiler* compiler = base->getAsCompiler();
    417     if (compiler == 0)
    418         return;
    419 
    420     const sh::ShaderVariable *varInfo = GetVariable(compiler, varType, index);
    421     if (!varInfo)
    422     {
    423         return;
    424     }
    425 
    426     if (length) *length = varInfo->name.size();
    427     *size = varInfo->elementCount();
    428     *type = varInfo->type;
    429     *precision = ConvertPrecision(varInfo->precision);
    430     *staticUse = varInfo->staticUse ? 1 : 0;
    431 
    432     // This size must match that queried by
    433     // SH_ACTIVE_UNIFORM_MAX_LENGTH, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_VARYING_MAX_LENGTH
    434     // in ShGetInfo, below.
    435     size_t variableLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
    436     ASSERT(CheckVariableMaxLengths(handle, variableLength));
    437     strncpy(name, varInfo->name.c_str(), variableLength);
    438     name[variableLength - 1] = 0;
    439     if (mappedName)
    440     {
    441         // This size must match that queried by
    442         // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
    443         size_t maxMappedNameLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
    444         ASSERT(CheckMappedNameMaxLength(handle, maxMappedNameLength));
    445         strncpy(mappedName, varInfo->mappedName.c_str(), maxMappedNameLength);
    446         mappedName[maxMappedNameLength - 1] = 0;
    447     }
    448 }
    449 
    450 void ShGetNameHashingEntry(const ShHandle handle,
    451                            int index,
    452                            char* name,
    453                            char* hashedName)
    454 {
    455     if (!handle || !name || !hashedName || index < 0)
    456         return;
    457 
    458     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    459     TCompiler* compiler = base->getAsCompiler();
    460     if (!compiler) return;
    461 
    462     const NameMap& nameMap = compiler->getNameMap();
    463     if (index >= static_cast<int>(nameMap.size()))
    464         return;
    465 
    466     NameMap::const_iterator it = nameMap.begin();
    467     for (int i = 0; i < index; ++i)
    468         ++it;
    469 
    470     size_t len = it->first.length() + 1;
    471     size_t max_len = 0;
    472     ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len);
    473     if (len > max_len) {
    474         ASSERT(false);
    475         len = max_len;
    476     }
    477     strncpy(name, it->first.c_str(), len);
    478     // To be on the safe side in case the source is longer than expected.
    479     name[len - 1] = '\0';
    480 
    481     len = it->second.length() + 1;
    482     max_len = 0;
    483     ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len);
    484     if (len > max_len) {
    485         ASSERT(false);
    486         len = max_len;
    487     }
    488     strncpy(hashedName, it->second.c_str(), len);
    489     // To be on the safe side in case the source is longer than expected.
    490     hashedName[len - 1] = '\0';
    491 }
    492 
    493 const std::vector<sh::Uniform> *ShGetUniforms(const ShHandle handle)
    494 {
    495     return GetShaderVariables<sh::Uniform>(handle, SHADERVAR_UNIFORM);
    496 }
    497 
    498 const std::vector<sh::Varying> *ShGetVaryings(const ShHandle handle)
    499 {
    500     return GetShaderVariables<sh::Varying>(handle, SHADERVAR_VARYING);
    501 }
    502 
    503 const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle)
    504 {
    505     return GetShaderVariables<sh::Attribute>(handle, SHADERVAR_ATTRIBUTE);
    506 }
    507 
    508 const std::vector<sh::Attribute> *ShGetOutputVariables(const ShHandle handle)
    509 {
    510     return GetShaderVariables<sh::Attribute>(handle, SHADERVAR_OUTPUTVARIABLE);
    511 }
    512 
    513 const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle)
    514 {
    515     return GetShaderVariables<sh::InterfaceBlock>(handle, SHADERVAR_INTERFACEBLOCK);
    516 }
    517 
    518 int ShCheckVariablesWithinPackingLimits(
    519     int maxVectors, ShVariableInfo* varInfoArray, size_t varInfoArraySize)
    520 {
    521     if (varInfoArraySize == 0)
    522         return 1;
    523     ASSERT(varInfoArray);
    524     std::vector<sh::ShaderVariable> variables;
    525     for (size_t ii = 0; ii < varInfoArraySize; ++ii)
    526     {
    527         sh::ShaderVariable var(varInfoArray[ii].type, varInfoArray[ii].size);
    528         variables.push_back(var);
    529     }
    530     VariablePacker packer;
    531     return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0;
    532 }
    533 
    534 bool ShGetInterfaceBlockRegister(const ShHandle handle,
    535                                  const char *interfaceBlockName,
    536                                  unsigned int *indexOut)
    537 {
    538     if (!handle || !interfaceBlockName || !indexOut)
    539     {
    540         return false;
    541     }
    542 
    543     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    544     TranslatorHLSL* translator = base->getAsTranslatorHLSL();
    545     if (!translator)
    546     {
    547         return false;
    548     }
    549 
    550     if (!translator->hasInterfaceBlock(interfaceBlockName))
    551     {
    552         return false;
    553     }
    554 
    555     *indexOut = translator->getInterfaceBlockRegister(interfaceBlockName);
    556     return true;
    557 }
    558 
    559 bool ShGetUniformRegister(const ShHandle handle,
    560                           const char *uniformName,
    561                           unsigned int *indexOut)
    562 {
    563     if (!handle || !uniformName || !indexOut)
    564     {
    565         return false;
    566     }
    567 
    568     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    569     TranslatorHLSL* translator = base->getAsTranslatorHLSL();
    570     if (!translator)
    571     {
    572         return false;
    573     }
    574 
    575     if (!translator->hasUniform(uniformName))
    576     {
    577         return false;
    578     }
    579 
    580     *indexOut = translator->getUniformRegister(uniformName);
    581     return true;
    582 }
    583