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/InitializeDll.h" 15#include "compiler/translator/length_limits.h" 16#include "compiler/translator/ShHandle.h" 17#include "compiler/translator/TranslatorHLSL.h" 18#include "compiler/translator/VariablePacker.h" 19 20static bool isInitialized = false; 21 22// 23// This is the platform independent interface between an OGL driver 24// and the shading language compiler. 25// 26 27static bool checkVariableMaxLengths(const ShHandle handle, 28 size_t expectedValue) 29{ 30 size_t activeUniformLimit = 0; 31 ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit); 32 size_t activeAttribLimit = 0; 33 ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit); 34 size_t varyingLimit = 0; 35 ShGetInfo(handle, SH_VARYING_MAX_LENGTH, &varyingLimit); 36 return (expectedValue == activeUniformLimit && 37 expectedValue == activeAttribLimit && 38 expectedValue == varyingLimit); 39} 40 41static bool checkMappedNameMaxLength(const ShHandle handle, size_t expectedValue) 42{ 43 size_t mappedNameMaxLength = 0; 44 ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength); 45 return (expectedValue == mappedNameMaxLength); 46} 47 48// 49// Driver must call this first, once, before doing any other compiler operations. 50// Subsequent calls to this function are no-op. 51// 52int ShInitialize() 53{ 54 if (!isInitialized) 55 { 56 isInitialized = InitProcess(); 57 } 58 return isInitialized ? 1 : 0; 59} 60 61// 62// Cleanup symbol tables 63// 64int ShFinalize() 65{ 66 if (isInitialized) 67 { 68 DetachProcess(); 69 isInitialized = false; 70 } 71 return 1; 72} 73 74// 75// Initialize built-in resources with minimum expected values. 76// 77void ShInitBuiltInResources(ShBuiltInResources* resources) 78{ 79 // Constants. 80 resources->MaxVertexAttribs = 8; 81 resources->MaxVertexUniformVectors = 128; 82 resources->MaxVaryingVectors = 8; 83 resources->MaxVertexTextureImageUnits = 0; 84 resources->MaxCombinedTextureImageUnits = 8; 85 resources->MaxTextureImageUnits = 8; 86 resources->MaxFragmentUniformVectors = 16; 87 resources->MaxDrawBuffers = 1; 88 89 // Extensions. 90 resources->OES_standard_derivatives = 0; 91 resources->OES_EGL_image_external = 0; 92 resources->ARB_texture_rectangle = 0; 93 resources->EXT_draw_buffers = 0; 94 resources->EXT_frag_depth = 0; 95 resources->EXT_shader_texture_lod = 0; 96 97 // Disable highp precision in fragment shader by default. 98 resources->FragmentPrecisionHigh = 0; 99 100 // GLSL ES 3.0 constants. 101 resources->MaxVertexOutputVectors = 16; 102 resources->MaxFragmentInputVectors = 15; 103 resources->MinProgramTexelOffset = -8; 104 resources->MaxProgramTexelOffset = 7; 105 106 // Disable name hashing by default. 107 resources->HashFunction = NULL; 108 109 resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC; 110 111 resources->MaxExpressionComplexity = 256; 112 resources->MaxCallStackDepth = 256; 113} 114 115// 116// Driver calls these to create and destroy compiler objects. 117// 118ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec, 119 ShShaderOutput output, 120 const ShBuiltInResources* resources) 121{ 122 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output)); 123 TCompiler* compiler = base->getAsCompiler(); 124 if (compiler == 0) 125 return 0; 126 127 // Generate built-in symbol table. 128 if (!compiler->Init(*resources)) { 129 ShDestruct(base); 130 return 0; 131 } 132 133 return reinterpret_cast<void*>(base); 134} 135 136void ShDestruct(ShHandle handle) 137{ 138 if (handle == 0) 139 return; 140 141 TShHandleBase* base = static_cast<TShHandleBase*>(handle); 142 143 if (base->getAsCompiler()) 144 DeleteCompiler(base->getAsCompiler()); 145} 146 147void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outString) 148{ 149 if (!handle || !outString) 150 { 151 return; 152 } 153 154 TShHandleBase *base = static_cast<TShHandleBase*>(handle); 155 TCompiler *compiler = base->getAsCompiler(); 156 if (!compiler) 157 { 158 return; 159 } 160 161 strncpy(outString, compiler->getBuiltInResourcesString().c_str(), outStringLen); 162 outString[outStringLen - 1] = '\0'; 163} 164// 165// Do an actual compile on the given strings. The result is left 166// in the given compile object. 167// 168// Return: The return value of ShCompile is really boolean, indicating 169// success or failure. 170// 171int ShCompile( 172 const ShHandle handle, 173 const char* const shaderStrings[], 174 size_t numStrings, 175 int compileOptions) 176{ 177 if (handle == 0) 178 return 0; 179 180 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle); 181 TCompiler* compiler = base->getAsCompiler(); 182 if (compiler == 0) 183 return 0; 184 185 bool success = compiler->compile(shaderStrings, numStrings, compileOptions); 186 return success ? 1 : 0; 187} 188 189void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params) 190{ 191 if (!handle || !params) 192 return; 193 194 TShHandleBase* base = static_cast<TShHandleBase*>(handle); 195 TCompiler* compiler = base->getAsCompiler(); 196 if (!compiler) return; 197 198 switch(pname) 199 { 200 case SH_INFO_LOG_LENGTH: 201 *params = compiler->getInfoSink().info.size() + 1; 202 break; 203 case SH_OBJECT_CODE_LENGTH: 204 *params = compiler->getInfoSink().obj.size() + 1; 205 break; 206 case SH_ACTIVE_UNIFORMS: 207 *params = compiler->getUniforms().size(); 208 break; 209 case SH_ACTIVE_UNIFORM_MAX_LENGTH: 210 *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); 211 break; 212 case SH_ACTIVE_ATTRIBUTES: 213 *params = compiler->getAttribs().size(); 214 break; 215 case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: 216 *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); 217 break; 218 case SH_VARYINGS: 219 *params = compiler->getVaryings().size(); 220 break; 221 case SH_VARYING_MAX_LENGTH: 222 *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); 223 break; 224 case SH_MAPPED_NAME_MAX_LENGTH: 225 // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to 226 // handle array and struct dereferences. 227 *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); 228 break; 229 case SH_NAME_MAX_LENGTH: 230 *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); 231 break; 232 case SH_HASHED_NAME_MAX_LENGTH: 233 if (compiler->getHashFunction() == NULL) { 234 *params = 0; 235 } else { 236 // 64 bits hashing output requires 16 bytes for hex 237 // representation. 238 const char HashedNamePrefix[] = HASHED_NAME_PREFIX; 239 (void)HashedNamePrefix; 240 *params = 16 + sizeof(HashedNamePrefix); 241 } 242 break; 243 case SH_HASHED_NAMES_COUNT: 244 *params = compiler->getNameMap().size(); 245 break; 246 case SH_SHADER_VERSION: 247 *params = compiler->getShaderVersion(); 248 break; 249 case SH_RESOURCES_STRING_LENGTH: 250 *params = compiler->getBuiltInResourcesString().length() + 1; 251 break; 252 case SH_OUTPUT_TYPE: 253 *params = compiler->getOutputType(); 254 break; 255 default: UNREACHABLE(); 256 } 257} 258 259// 260// Return any compiler log of messages for the application. 261// 262void ShGetInfoLog(const ShHandle handle, char* infoLog) 263{ 264 if (!handle || !infoLog) 265 return; 266 267 TShHandleBase* base = static_cast<TShHandleBase*>(handle); 268 TCompiler* compiler = base->getAsCompiler(); 269 if (!compiler) return; 270 271 TInfoSink& infoSink = compiler->getInfoSink(); 272 strcpy(infoLog, infoSink.info.c_str()); 273} 274 275// 276// Return any object code. 277// 278void ShGetObjectCode(const ShHandle handle, char* objCode) 279{ 280 if (!handle || !objCode) 281 return; 282 283 TShHandleBase* base = static_cast<TShHandleBase*>(handle); 284 TCompiler* compiler = base->getAsCompiler(); 285 if (!compiler) return; 286 287 TInfoSink& infoSink = compiler->getInfoSink(); 288 strcpy(objCode, infoSink.obj.c_str()); 289} 290 291void ShGetVariableInfo(const ShHandle handle, 292 ShShaderInfo varType, 293 int index, 294 size_t* length, 295 int* size, 296 ShDataType* type, 297 ShPrecisionType* precision, 298 int* staticUse, 299 char* name, 300 char* mappedName) 301{ 302 if (!handle || !size || !type || !precision || !staticUse || !name) 303 return; 304 ASSERT((varType == SH_ACTIVE_ATTRIBUTES) || 305 (varType == SH_ACTIVE_UNIFORMS) || 306 (varType == SH_VARYINGS)); 307 308 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle); 309 TCompiler* compiler = base->getAsCompiler(); 310 if (compiler == 0) 311 return; 312 313 const TVariableInfoList& varList = 314 varType == SH_ACTIVE_ATTRIBUTES ? compiler->getAttribs() : 315 (varType == SH_ACTIVE_UNIFORMS ? compiler->getUniforms() : 316 compiler->getVaryings()); 317 if (index < 0 || index >= static_cast<int>(varList.size())) 318 return; 319 320 const TVariableInfo& varInfo = varList[index]; 321 if (length) *length = varInfo.name.size(); 322 *size = varInfo.size; 323 *type = varInfo.type; 324 switch (varInfo.precision) { 325 case EbpLow: 326 *precision = SH_PRECISION_LOWP; 327 break; 328 case EbpMedium: 329 *precision = SH_PRECISION_MEDIUMP; 330 break; 331 case EbpHigh: 332 *precision = SH_PRECISION_HIGHP; 333 break; 334 default: 335 // Some types does not support precision, for example, boolean. 336 *precision = SH_PRECISION_UNDEFINED; 337 break; 338 } 339 *staticUse = varInfo.staticUse ? 1 : 0; 340 341 // This size must match that queried by 342 // SH_ACTIVE_UNIFORM_MAX_LENGTH, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_VARYING_MAX_LENGTH 343 // in ShGetInfo, below. 344 size_t variableLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); 345 ASSERT(checkVariableMaxLengths(handle, variableLength)); 346 strncpy(name, varInfo.name.c_str(), variableLength); 347 name[variableLength - 1] = 0; 348 if (mappedName) { 349 // This size must match that queried by 350 // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below. 351 size_t maxMappedNameLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); 352 ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength)); 353 strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength); 354 mappedName[maxMappedNameLength - 1] = 0; 355 } 356} 357 358void ShGetNameHashingEntry(const ShHandle handle, 359 int index, 360 char* name, 361 char* hashedName) 362{ 363 if (!handle || !name || !hashedName || index < 0) 364 return; 365 366 TShHandleBase* base = static_cast<TShHandleBase*>(handle); 367 TCompiler* compiler = base->getAsCompiler(); 368 if (!compiler) return; 369 370 const NameMap& nameMap = compiler->getNameMap(); 371 if (index >= static_cast<int>(nameMap.size())) 372 return; 373 374 NameMap::const_iterator it = nameMap.begin(); 375 for (int i = 0; i < index; ++i) 376 ++it; 377 378 size_t len = it->first.length() + 1; 379 size_t max_len = 0; 380 ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len); 381 if (len > max_len) { 382 ASSERT(false); 383 len = max_len; 384 } 385 strncpy(name, it->first.c_str(), len); 386 // To be on the safe side in case the source is longer than expected. 387 name[len - 1] = '\0'; 388 389 len = it->second.length() + 1; 390 max_len = 0; 391 ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len); 392 if (len > max_len) { 393 ASSERT(false); 394 len = max_len; 395 } 396 strncpy(hashedName, it->second.c_str(), len); 397 // To be on the safe side in case the source is longer than expected. 398 hashedName[len - 1] = '\0'; 399} 400 401void ShGetInfoPointer(const ShHandle handle, ShShaderInfo pname, void** params) 402{ 403 if (!handle || !params) 404 return; 405 406 TShHandleBase* base = static_cast<TShHandleBase*>(handle); 407 TranslatorHLSL* translator = base->getAsTranslatorHLSL(); 408 if (!translator) return; 409 410 switch(pname) 411 { 412 case SH_ACTIVE_UNIFORMS_ARRAY: 413 *params = (void*)&translator->getUniforms(); 414 break; 415 case SH_ACTIVE_INTERFACE_BLOCKS_ARRAY: 416 *params = (void*)&translator->getInterfaceBlocks(); 417 break; 418 case SH_ACTIVE_OUTPUT_VARIABLES_ARRAY: 419 *params = (void*)&translator->getOutputVariables(); 420 break; 421 case SH_ACTIVE_ATTRIBUTES_ARRAY: 422 *params = (void*)&translator->getAttributes(); 423 break; 424 case SH_ACTIVE_VARYINGS_ARRAY: 425 *params = (void*)&translator->getVaryings(); 426 break; 427 default: UNREACHABLE(); 428 } 429} 430 431int ShCheckVariablesWithinPackingLimits( 432 int maxVectors, ShVariableInfo* varInfoArray, size_t varInfoArraySize) 433{ 434 if (varInfoArraySize == 0) 435 return 1; 436 ASSERT(varInfoArray); 437 TVariableInfoList variables; 438 for (size_t ii = 0; ii < varInfoArraySize; ++ii) 439 { 440 TVariableInfo var(varInfoArray[ii].type, varInfoArray[ii].size); 441 variables.push_back(var); 442 } 443 VariablePacker packer; 444 return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0; 445} 446