Home | History | Annotate | Download | only in compiler
      1 //
      2 // Copyright (c) 2002-2012 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/InitializeDll.h"
     15 #include "compiler/preprocessor/length_limits.h"
     16 #include "compiler/ShHandle.h"
     17 #include "compiler/TranslatorHLSL.h"
     18 
     19 //
     20 // This is the platform independent interface between an OGL driver
     21 // and the shading language compiler.
     22 //
     23 
     24 static bool checkActiveUniformAndAttribMaxLengths(const ShHandle handle,
     25                                                   size_t expectedValue)
     26 {
     27     size_t activeUniformLimit = 0;
     28     ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
     29     size_t activeAttribLimit = 0;
     30     ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
     31     return (expectedValue == activeUniformLimit && expectedValue == activeAttribLimit);
     32 }
     33 
     34 static bool checkMappedNameMaxLength(const ShHandle handle, size_t expectedValue)
     35 {
     36     size_t mappedNameMaxLength = 0;
     37     ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
     38     return (expectedValue == mappedNameMaxLength);
     39 }
     40 
     41 static void getVariableInfo(ShShaderInfo varType,
     42                             const ShHandle handle,
     43                             int index,
     44                             size_t* length,
     45                             int* size,
     46                             ShDataType* type,
     47                             char* name,
     48                             char* mappedName)
     49 {
     50     if (!handle || !size || !type || !name)
     51         return;
     52     ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
     53            (varType == SH_ACTIVE_UNIFORMS));
     54 
     55     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
     56     TCompiler* compiler = base->getAsCompiler();
     57     if (compiler == 0)
     58         return;
     59 
     60     const TVariableInfoList& varList = varType == SH_ACTIVE_ATTRIBUTES ?
     61         compiler->getAttribs() : compiler->getUniforms();
     62     if (index < 0 || index >= static_cast<int>(varList.size()))
     63         return;
     64 
     65     const TVariableInfo& varInfo = varList[index];
     66     if (length) *length = varInfo.name.size();
     67     *size = varInfo.size;
     68     *type = varInfo.type;
     69 
     70     // This size must match that queried by
     71     // SH_ACTIVE_UNIFORM_MAX_LENGTH and SH_ACTIVE_ATTRIBUTE_MAX_LENGTH
     72     // in ShGetInfo, below.
     73     size_t activeUniformAndAttribLength = 1 + MAX_SYMBOL_NAME_LEN;
     74     ASSERT(checkActiveUniformAndAttribMaxLengths(handle, activeUniformAndAttribLength));
     75     strncpy(name, varInfo.name.c_str(), activeUniformAndAttribLength);
     76     name[activeUniformAndAttribLength - 1] = 0;
     77     if (mappedName) {
     78         // This size must match that queried by
     79         // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
     80         size_t maxMappedNameLength = 1 + MAX_SYMBOL_NAME_LEN;
     81         ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength));
     82         strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength);
     83         mappedName[maxMappedNameLength - 1] = 0;
     84     }
     85 }
     86 
     87 //
     88 // Driver must call this first, once, before doing any other compiler operations.
     89 // Subsequent calls to this function are no-op.
     90 //
     91 int ShInitialize()
     92 {
     93     static const bool kInitialized = InitProcess();
     94     return kInitialized ? 1 : 0;
     95 }
     96 
     97 //
     98 // Cleanup symbol tables
     99 //
    100 int ShFinalize()
    101 {
    102     DetachProcess();
    103     return 1;
    104 }
    105 
    106 //
    107 // Initialize built-in resources with minimum expected values.
    108 //
    109 void ShInitBuiltInResources(ShBuiltInResources* resources)
    110 {
    111     // Constants.
    112     resources->MaxVertexAttribs = 8;
    113     resources->MaxVertexUniformVectors = 128;
    114     resources->MaxVaryingVectors = 8;
    115     resources->MaxVertexTextureImageUnits = 0;
    116     resources->MaxCombinedTextureImageUnits = 8;
    117     resources->MaxTextureImageUnits = 8;
    118     resources->MaxFragmentUniformVectors = 16;
    119     resources->MaxDrawBuffers = 1;
    120 
    121     // Extensions.
    122     resources->OES_standard_derivatives = 0;
    123     resources->OES_EGL_image_external = 0;
    124     resources->ARB_texture_rectangle = 0;
    125     resources->EXT_draw_buffers = 0;
    126     resources->EXT_frag_depth = 0;
    127 
    128     // Disable highp precision in fragment shader by default.
    129     resources->FragmentPrecisionHigh = 0;
    130 
    131     // Disable name hashing by default.
    132     resources->HashFunction = NULL;
    133 
    134     resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
    135 }
    136 
    137 //
    138 // Driver calls these to create and destroy compiler objects.
    139 //
    140 ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
    141                              ShShaderOutput output,
    142                              const ShBuiltInResources* resources)
    143 {
    144     TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
    145     TCompiler* compiler = base->getAsCompiler();
    146     if (compiler == 0)
    147         return 0;
    148 
    149     // Generate built-in symbol table.
    150     if (!compiler->Init(*resources)) {
    151         ShDestruct(base);
    152         return 0;
    153     }
    154 
    155     return reinterpret_cast<void*>(base);
    156 }
    157 
    158 void ShDestruct(ShHandle handle)
    159 {
    160     if (handle == 0)
    161         return;
    162 
    163     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    164 
    165     if (base->getAsCompiler())
    166         DeleteCompiler(base->getAsCompiler());
    167 }
    168 
    169 //
    170 // Do an actual compile on the given strings.  The result is left
    171 // in the given compile object.
    172 //
    173 // Return:  The return value of ShCompile is really boolean, indicating
    174 // success or failure.
    175 //
    176 int ShCompile(
    177     const ShHandle handle,
    178     const char* const shaderStrings[],
    179     size_t numStrings,
    180     int compileOptions)
    181 {
    182     if (handle == 0)
    183         return 0;
    184 
    185     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
    186     TCompiler* compiler = base->getAsCompiler();
    187     if (compiler == 0)
    188         return 0;
    189 
    190     bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
    191     return success ? 1 : 0;
    192 }
    193 
    194 void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params)
    195 {
    196     if (!handle || !params)
    197         return;
    198 
    199     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    200     TCompiler* compiler = base->getAsCompiler();
    201     if (!compiler) return;
    202 
    203     switch(pname)
    204     {
    205     case SH_INFO_LOG_LENGTH:
    206         *params = compiler->getInfoSink().info.size() + 1;
    207         break;
    208     case SH_OBJECT_CODE_LENGTH:
    209         *params = compiler->getInfoSink().obj.size() + 1;
    210         break;
    211     case SH_ACTIVE_UNIFORMS:
    212         *params = compiler->getUniforms().size();
    213         break;
    214     case SH_ACTIVE_UNIFORM_MAX_LENGTH:
    215         *params = 1 +  MAX_SYMBOL_NAME_LEN;
    216         break;
    217     case SH_ACTIVE_ATTRIBUTES:
    218         *params = compiler->getAttribs().size();
    219         break;
    220     case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
    221         *params = 1 + MAX_SYMBOL_NAME_LEN;
    222         break;
    223     case SH_MAPPED_NAME_MAX_LENGTH:
    224         // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
    225         // handle array and struct dereferences.
    226         *params = 1 + MAX_SYMBOL_NAME_LEN;
    227         break;
    228     case SH_NAME_MAX_LENGTH:
    229         *params = 1 + MAX_SYMBOL_NAME_LEN;
    230         break;
    231     case SH_HASHED_NAME_MAX_LENGTH:
    232         if (compiler->getHashFunction() == NULL) {
    233             *params = 0;
    234         } else {
    235             // 64 bits hashing output requires 16 bytes for hex
    236             // representation.
    237             const char HashedNamePrefix[] = HASHED_NAME_PREFIX;
    238             *params = 16 + sizeof(HashedNamePrefix);
    239         }
    240         break;
    241     case SH_HASHED_NAMES_COUNT:
    242         *params = compiler->getNameMap().size();
    243         break;
    244     default: UNREACHABLE();
    245     }
    246 }
    247 
    248 //
    249 // Return any compiler log of messages for the application.
    250 //
    251 void ShGetInfoLog(const ShHandle handle, char* infoLog)
    252 {
    253     if (!handle || !infoLog)
    254         return;
    255 
    256     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    257     TCompiler* compiler = base->getAsCompiler();
    258     if (!compiler) return;
    259 
    260     TInfoSink& infoSink = compiler->getInfoSink();
    261     strcpy(infoLog, infoSink.info.c_str());
    262 }
    263 
    264 //
    265 // Return any object code.
    266 //
    267 void ShGetObjectCode(const ShHandle handle, char* objCode)
    268 {
    269     if (!handle || !objCode)
    270         return;
    271 
    272     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    273     TCompiler* compiler = base->getAsCompiler();
    274     if (!compiler) return;
    275 
    276     TInfoSink& infoSink = compiler->getInfoSink();
    277     strcpy(objCode, infoSink.obj.c_str());
    278 }
    279 
    280 void ShGetActiveAttrib(const ShHandle handle,
    281                        int index,
    282                        size_t* length,
    283                        int* size,
    284                        ShDataType* type,
    285                        char* name,
    286                        char* mappedName)
    287 {
    288     getVariableInfo(SH_ACTIVE_ATTRIBUTES,
    289                     handle, index, length, size, type, name, mappedName);
    290 }
    291 
    292 void ShGetActiveUniform(const ShHandle handle,
    293                         int index,
    294                         size_t* length,
    295                         int* size,
    296                         ShDataType* type,
    297                         char* name,
    298                         char* mappedName)
    299 {
    300     getVariableInfo(SH_ACTIVE_UNIFORMS,
    301                     handle, index, length, size, type, name, mappedName);
    302 }
    303 
    304 void ShGetNameHashingEntry(const ShHandle handle,
    305                            int index,
    306                            char* name,
    307                            char* hashedName)
    308 {
    309     if (!handle || !name || !hashedName || index < 0)
    310         return;
    311 
    312     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    313     TCompiler* compiler = base->getAsCompiler();
    314     if (!compiler) return;
    315 
    316     const NameMap& nameMap = compiler->getNameMap();
    317     if (index >= static_cast<int>(nameMap.size()))
    318         return;
    319 
    320     NameMap::const_iterator it = nameMap.begin();
    321     for (int i = 0; i < index; ++i)
    322         ++it;
    323 
    324     size_t len = it->first.length() + 1;
    325     size_t max_len = 0;
    326     ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len);
    327     if (len > max_len) {
    328         ASSERT(false);
    329         len = max_len;
    330     }
    331     strncpy(name, it->first.c_str(), len);
    332     // To be on the safe side in case the source is longer than expected.
    333     name[len - 1] = '\0';
    334 
    335     len = it->second.length() + 1;
    336     max_len = 0;
    337     ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len);
    338     if (len > max_len) {
    339         ASSERT(false);
    340         len = max_len;
    341     }
    342     strncpy(hashedName, it->second.c_str(), len);
    343     // To be on the safe side in case the source is longer than expected.
    344     hashedName[len - 1] = '\0';
    345 }
    346 
    347 void ShGetInfoPointer(const ShHandle handle, ShShaderInfo pname, void** params)
    348 {
    349     if (!handle || !params)
    350         return;
    351 
    352     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
    353     TranslatorHLSL* translator = base->getAsTranslatorHLSL();
    354     if (!translator) return;
    355 
    356     switch(pname)
    357     {
    358     case SH_ACTIVE_UNIFORMS_ARRAY:
    359         *params = (void*)&translator->getUniforms();
    360         break;
    361     default: UNREACHABLE();
    362     }
    363 }
    364