michael@0: // michael@0: // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // michael@0: michael@0: // michael@0: // Implement the top-level of interface to the compiler, michael@0: // as defined in ShaderLang.h michael@0: // michael@0: michael@0: #include "GLSLANG/ShaderLang.h" michael@0: michael@0: #include "compiler/InitializeDll.h" michael@0: #include "compiler/preprocessor/length_limits.h" michael@0: #include "compiler/ShHandle.h" michael@0: #include "compiler/TranslatorHLSL.h" michael@0: michael@0: // michael@0: // This is the platform independent interface between an OGL driver michael@0: // and the shading language compiler. michael@0: // michael@0: michael@0: static bool checkActiveUniformAndAttribMaxLengths(const ShHandle handle, michael@0: size_t expectedValue) michael@0: { michael@0: size_t activeUniformLimit = 0; michael@0: ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit); michael@0: size_t activeAttribLimit = 0; michael@0: ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit); michael@0: return (expectedValue == activeUniformLimit && expectedValue == activeAttribLimit); michael@0: } michael@0: michael@0: static bool checkMappedNameMaxLength(const ShHandle handle, size_t expectedValue) michael@0: { michael@0: size_t mappedNameMaxLength = 0; michael@0: ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength); michael@0: return (expectedValue == mappedNameMaxLength); michael@0: } michael@0: michael@0: static void getVariableInfo(ShShaderInfo varType, michael@0: const ShHandle handle, michael@0: int index, michael@0: size_t* length, michael@0: int* size, michael@0: ShDataType* type, michael@0: char* name, michael@0: char* mappedName) michael@0: { michael@0: if (!handle || !size || !type || !name) michael@0: return; michael@0: ASSERT((varType == SH_ACTIVE_ATTRIBUTES) || michael@0: (varType == SH_ACTIVE_UNIFORMS)); michael@0: michael@0: TShHandleBase* base = reinterpret_cast(handle); michael@0: TCompiler* compiler = base->getAsCompiler(); michael@0: if (compiler == 0) michael@0: return; michael@0: michael@0: const TVariableInfoList& varList = varType == SH_ACTIVE_ATTRIBUTES ? michael@0: compiler->getAttribs() : compiler->getUniforms(); michael@0: if (index < 0 || index >= static_cast(varList.size())) michael@0: return; michael@0: michael@0: const TVariableInfo& varInfo = varList[index]; michael@0: if (length) *length = varInfo.name.size(); michael@0: *size = varInfo.size; michael@0: *type = varInfo.type; michael@0: michael@0: // This size must match that queried by michael@0: // SH_ACTIVE_UNIFORM_MAX_LENGTH and SH_ACTIVE_ATTRIBUTE_MAX_LENGTH michael@0: // in ShGetInfo, below. michael@0: size_t activeUniformAndAttribLength = 1 + MAX_SYMBOL_NAME_LEN; michael@0: ASSERT(checkActiveUniformAndAttribMaxLengths(handle, activeUniformAndAttribLength)); michael@0: strncpy(name, varInfo.name.c_str(), activeUniformAndAttribLength); michael@0: name[activeUniformAndAttribLength - 1] = 0; michael@0: if (mappedName) { michael@0: // This size must match that queried by michael@0: // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below. michael@0: size_t maxMappedNameLength = 1 + MAX_SYMBOL_NAME_LEN; michael@0: ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength)); michael@0: strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength); michael@0: mappedName[maxMappedNameLength - 1] = 0; michael@0: } michael@0: } michael@0: michael@0: // michael@0: // Driver must call this first, once, before doing any other compiler operations. michael@0: // Subsequent calls to this function are no-op. michael@0: // michael@0: int ShInitialize() michael@0: { michael@0: static const bool kInitialized = InitProcess(); michael@0: return kInitialized ? 1 : 0; michael@0: } michael@0: michael@0: // michael@0: // Cleanup symbol tables michael@0: // michael@0: int ShFinalize() michael@0: { michael@0: DetachProcess(); michael@0: return 1; michael@0: } michael@0: michael@0: // michael@0: // Initialize built-in resources with minimum expected values. michael@0: // michael@0: void ShInitBuiltInResources(ShBuiltInResources* resources) michael@0: { michael@0: // Constants. michael@0: resources->MaxVertexAttribs = 8; michael@0: resources->MaxVertexUniformVectors = 128; michael@0: resources->MaxVaryingVectors = 8; michael@0: resources->MaxVertexTextureImageUnits = 0; michael@0: resources->MaxCombinedTextureImageUnits = 8; michael@0: resources->MaxTextureImageUnits = 8; michael@0: resources->MaxFragmentUniformVectors = 16; michael@0: resources->MaxDrawBuffers = 1; michael@0: michael@0: // Extensions. michael@0: resources->OES_standard_derivatives = 0; michael@0: resources->OES_EGL_image_external = 0; michael@0: resources->ARB_texture_rectangle = 0; michael@0: resources->EXT_draw_buffers = 0; michael@0: resources->EXT_frag_depth = 0; michael@0: michael@0: // Disable highp precision in fragment shader by default. michael@0: resources->FragmentPrecisionHigh = 0; michael@0: michael@0: // Disable name hashing by default. michael@0: resources->HashFunction = NULL; michael@0: michael@0: resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC; michael@0: } michael@0: michael@0: // michael@0: // Driver calls these to create and destroy compiler objects. michael@0: // michael@0: ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec, michael@0: ShShaderOutput output, michael@0: const ShBuiltInResources* resources) michael@0: { michael@0: TShHandleBase* base = static_cast(ConstructCompiler(type, spec, output)); michael@0: TCompiler* compiler = base->getAsCompiler(); michael@0: if (compiler == 0) michael@0: return 0; michael@0: michael@0: // Generate built-in symbol table. michael@0: if (!compiler->Init(*resources)) { michael@0: ShDestruct(base); michael@0: return 0; michael@0: } michael@0: michael@0: return reinterpret_cast(base); michael@0: } michael@0: michael@0: void ShDestruct(ShHandle handle) michael@0: { michael@0: if (handle == 0) michael@0: return; michael@0: michael@0: TShHandleBase* base = static_cast(handle); michael@0: michael@0: if (base->getAsCompiler()) michael@0: DeleteCompiler(base->getAsCompiler()); michael@0: } michael@0: michael@0: // michael@0: // Do an actual compile on the given strings. The result is left michael@0: // in the given compile object. michael@0: // michael@0: // Return: The return value of ShCompile is really boolean, indicating michael@0: // success or failure. michael@0: // michael@0: int ShCompile( michael@0: const ShHandle handle, michael@0: const char* const shaderStrings[], michael@0: size_t numStrings, michael@0: int compileOptions) michael@0: { michael@0: if (handle == 0) michael@0: return 0; michael@0: michael@0: TShHandleBase* base = reinterpret_cast(handle); michael@0: TCompiler* compiler = base->getAsCompiler(); michael@0: if (compiler == 0) michael@0: return 0; michael@0: michael@0: bool success = compiler->compile(shaderStrings, numStrings, compileOptions); michael@0: return success ? 1 : 0; michael@0: } michael@0: michael@0: void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params) michael@0: { michael@0: if (!handle || !params) michael@0: return; michael@0: michael@0: TShHandleBase* base = static_cast(handle); michael@0: TCompiler* compiler = base->getAsCompiler(); michael@0: if (!compiler) return; michael@0: michael@0: switch(pname) michael@0: { michael@0: case SH_INFO_LOG_LENGTH: michael@0: *params = compiler->getInfoSink().info.size() + 1; michael@0: break; michael@0: case SH_OBJECT_CODE_LENGTH: michael@0: *params = compiler->getInfoSink().obj.size() + 1; michael@0: break; michael@0: case SH_ACTIVE_UNIFORMS: michael@0: *params = compiler->getUniforms().size(); michael@0: break; michael@0: case SH_ACTIVE_UNIFORM_MAX_LENGTH: michael@0: *params = 1 + MAX_SYMBOL_NAME_LEN; michael@0: break; michael@0: case SH_ACTIVE_ATTRIBUTES: michael@0: *params = compiler->getAttribs().size(); michael@0: break; michael@0: case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: michael@0: *params = 1 + MAX_SYMBOL_NAME_LEN; michael@0: break; michael@0: case SH_MAPPED_NAME_MAX_LENGTH: michael@0: // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to michael@0: // handle array and struct dereferences. michael@0: *params = 1 + MAX_SYMBOL_NAME_LEN; michael@0: break; michael@0: case SH_NAME_MAX_LENGTH: michael@0: *params = 1 + MAX_SYMBOL_NAME_LEN; michael@0: break; michael@0: case SH_HASHED_NAME_MAX_LENGTH: michael@0: if (compiler->getHashFunction() == NULL) { michael@0: *params = 0; michael@0: } else { michael@0: // 64 bits hashing output requires 16 bytes for hex michael@0: // representation. michael@0: const char HashedNamePrefix[] = HASHED_NAME_PREFIX; michael@0: *params = 16 + sizeof(HashedNamePrefix); michael@0: } michael@0: break; michael@0: case SH_HASHED_NAMES_COUNT: michael@0: *params = compiler->getNameMap().size(); michael@0: break; michael@0: default: UNREACHABLE(); michael@0: } michael@0: } michael@0: michael@0: // michael@0: // Return any compiler log of messages for the application. michael@0: // michael@0: void ShGetInfoLog(const ShHandle handle, char* infoLog) michael@0: { michael@0: if (!handle || !infoLog) michael@0: return; michael@0: michael@0: TShHandleBase* base = static_cast(handle); michael@0: TCompiler* compiler = base->getAsCompiler(); michael@0: if (!compiler) return; michael@0: michael@0: TInfoSink& infoSink = compiler->getInfoSink(); michael@0: strcpy(infoLog, infoSink.info.c_str()); michael@0: } michael@0: michael@0: // michael@0: // Return any object code. michael@0: // michael@0: void ShGetObjectCode(const ShHandle handle, char* objCode) michael@0: { michael@0: if (!handle || !objCode) michael@0: return; michael@0: michael@0: TShHandleBase* base = static_cast(handle); michael@0: TCompiler* compiler = base->getAsCompiler(); michael@0: if (!compiler) return; michael@0: michael@0: TInfoSink& infoSink = compiler->getInfoSink(); michael@0: strcpy(objCode, infoSink.obj.c_str()); michael@0: } michael@0: michael@0: void ShGetActiveAttrib(const ShHandle handle, michael@0: int index, michael@0: size_t* length, michael@0: int* size, michael@0: ShDataType* type, michael@0: char* name, michael@0: char* mappedName) michael@0: { michael@0: getVariableInfo(SH_ACTIVE_ATTRIBUTES, michael@0: handle, index, length, size, type, name, mappedName); michael@0: } michael@0: michael@0: void ShGetActiveUniform(const ShHandle handle, michael@0: int index, michael@0: size_t* length, michael@0: int* size, michael@0: ShDataType* type, michael@0: char* name, michael@0: char* mappedName) michael@0: { michael@0: getVariableInfo(SH_ACTIVE_UNIFORMS, michael@0: handle, index, length, size, type, name, mappedName); michael@0: } michael@0: michael@0: void ShGetNameHashingEntry(const ShHandle handle, michael@0: int index, michael@0: char* name, michael@0: char* hashedName) michael@0: { michael@0: if (!handle || !name || !hashedName || index < 0) michael@0: return; michael@0: michael@0: TShHandleBase* base = static_cast(handle); michael@0: TCompiler* compiler = base->getAsCompiler(); michael@0: if (!compiler) return; michael@0: michael@0: const NameMap& nameMap = compiler->getNameMap(); michael@0: if (index >= static_cast(nameMap.size())) michael@0: return; michael@0: michael@0: NameMap::const_iterator it = nameMap.begin(); michael@0: for (int i = 0; i < index; ++i) michael@0: ++it; michael@0: michael@0: size_t len = it->first.length() + 1; michael@0: size_t max_len = 0; michael@0: ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len); michael@0: if (len > max_len) { michael@0: ASSERT(false); michael@0: len = max_len; michael@0: } michael@0: strncpy(name, it->first.c_str(), len); michael@0: // To be on the safe side in case the source is longer than expected. michael@0: name[len - 1] = '\0'; michael@0: michael@0: len = it->second.length() + 1; michael@0: max_len = 0; michael@0: ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len); michael@0: if (len > max_len) { michael@0: ASSERT(false); michael@0: len = max_len; michael@0: } michael@0: strncpy(hashedName, it->second.c_str(), len); michael@0: // To be on the safe side in case the source is longer than expected. michael@0: hashedName[len - 1] = '\0'; michael@0: } michael@0: michael@0: void ShGetInfoPointer(const ShHandle handle, ShShaderInfo pname, void** params) michael@0: { michael@0: if (!handle || !params) michael@0: return; michael@0: michael@0: TShHandleBase* base = static_cast(handle); michael@0: TranslatorHLSL* translator = base->getAsTranslatorHLSL(); michael@0: if (!translator) return; michael@0: michael@0: switch(pname) michael@0: { michael@0: case SH_ACTIVE_UNIFORMS_ARRAY: michael@0: *params = (void*)&translator->getUniforms(); michael@0: break; michael@0: default: UNREACHABLE(); michael@0: } michael@0: }