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