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 21namespace 22{ 23 24enum ShaderVariableType 25{ 26 SHADERVAR_UNIFORM, 27 SHADERVAR_VARYING, 28 SHADERVAR_ATTRIBUTE, 29 SHADERVAR_OUTPUTVARIABLE, 30 SHADERVAR_INTERFACEBLOCK 31}; 32 33bool isInitialized = false; 34 35// 36// This is the platform independent interface between an OGL driver 37// and the shading language compiler. 38// 39 40static 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 54bool 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 61template <typename VarT> 62const 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 72const 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 88ShPrecisionType 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 106template <typename VarT> 107const std::vector<VarT> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType); 108 109template <> 110const std::vector<sh::Uniform> *GetVariableList(const TCompiler *compiler, ShaderVariableType) 111{ 112 return &compiler->getUniforms(); 113} 114 115template <> 116const std::vector<sh::Varying> *GetVariableList(const TCompiler *compiler, ShaderVariableType) 117{ 118 return &compiler->getVaryings(); 119} 120 121template <> 122const std::vector<sh::Attribute> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType) 123{ 124 return (variableType == SHADERVAR_ATTRIBUTE ? 125 &compiler->getAttributes() : 126 &compiler->getOutputVariables()); 127} 128 129template <> 130const std::vector<sh::InterfaceBlock> *GetVariableList(const TCompiler *compiler, ShaderVariableType) 131{ 132 return &compiler->getInterfaceBlocks(); 133} 134 135template <typename VarT> 136const 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// 159int ShInitialize() 160{ 161 if (!isInitialized) 162 { 163 isInitialized = InitProcess(); 164 } 165 return isInitialized ? 1 : 0; 166} 167 168// 169// Cleanup symbol tables 170// 171int 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// 184void 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// 225ShHandle 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 243void 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 254void 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// 278int 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 296void 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// 369void 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// 385void 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 398void 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 450void 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 493const std::vector<sh::Uniform> *ShGetUniforms(const ShHandle handle) 494{ 495 return GetShaderVariables<sh::Uniform>(handle, SHADERVAR_UNIFORM); 496} 497 498const std::vector<sh::Varying> *ShGetVaryings(const ShHandle handle) 499{ 500 return GetShaderVariables<sh::Varying>(handle, SHADERVAR_VARYING); 501} 502 503const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle) 504{ 505 return GetShaderVariables<sh::Attribute>(handle, SHADERVAR_ATTRIBUTE); 506} 507 508const std::vector<sh::Attribute> *ShGetOutputVariables(const ShHandle handle) 509{ 510 return GetShaderVariables<sh::Attribute>(handle, SHADERVAR_OUTPUTVARIABLE); 511} 512 513const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle) 514{ 515 return GetShaderVariables<sh::InterfaceBlock>(handle, SHADERVAR_INTERFACEBLOCK); 516} 517 518int 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 534bool 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 559bool 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