// Called recursively and appends (to list) any symbols that have semantic sem.
void HlslLinker::appendDuplicatedInSemantics(GlslSymbolOrStructMemberBase* sym, EAttribSemantic sem, std::vector<GlslSymbolOrStructMemberBase*>& list)
{
	EGlslQualifier qual = sym->getQualifier();
	// fields in structures in structures can have EqtNone as a qualifier.
	if ( (qual == EqtIn || qual == EqtInOut || qual == EqtNone) && parseAttributeSemantic(sym->getSemantic()) == sem )
		list.push_back(sym);
	else if (sym->getStruct())
	{
		int mc = sym->getStruct()->memberCount();
		for (int i = 0; i < mc; ++i)
			appendDuplicatedInSemantics(const_cast<StructMember*>(&sym->getStruct()->getMember(i)),sem,list);
	}
}
Exemple #2
0
bool HlslLinker::link(HlslCrossCompiler* compiler, const char* entryFunc, bool usePrecision)
{
	std::vector<GlslFunction*> globalList;
	std::vector<GlslFunction*> functionList;
	std::string entryPoint;
	GlslFunction* funcMain = NULL;
	FunctionSet calledFunctions;
	std::set<TOperator> libFunctions;
	std::map<std::string,GlslSymbol*> globalSymMap;
	std::map<std::string,GlslStruct*> structMap;

	if (!compiler)
	{
		infoSink.info << "No shader compiler provided\n";
		return false;
	}

	EShLanguage lang = compiler->getLanguage();

	if (!entryFunc)
	{
		infoSink.info << "No shader entry function provided\n";
		return false;
	}

	entryPoint = GetEntryName (entryFunc);

	//build the list of functions
	HlslCrossCompiler *comp = static_cast<HlslCrossCompiler*>(compiler);

	std::vector<GlslFunction*> &fl = comp->functionList;

	for ( std::vector<GlslFunction*>::iterator fit = fl.begin(); fit < fl.end(); fit++)
	{
		if ( (*fit)->getName() == "__global__")
			globalList.push_back( *fit);
		else
			functionList.push_back( *fit);

		if ((*fit)->getName() == entryPoint)
		{
			if (funcMain)
			{
				infoSink.info << kShaderTypeNames[lang] << " entry function cannot be overloaded\n";
				return false;
			}
			funcMain = *fit;
		}
	}

	// check to ensure that we found the entry function
	if (!funcMain)
	{
		infoSink.info << "Failed to find entry function: '" << entryPoint <<"'\n";
		return false;
	}

	//add all the called functions to the list
	calledFunctions.push_back (funcMain);
	if (!addCalledFunctions (funcMain, calledFunctions, functionList))
	{
		infoSink.info << "Failed to resolve all called functions in the " << kShaderTypeNames[lang] << " shader\n";
	}

	//iterate over the functions, building a global list of structure declaractions and symbols
	// assume a single compilation unit for expediency (eliminates name clashes, as type checking
	// withing a single compilation unit has been performed)
	for (FunctionSet::iterator it=calledFunctions.begin(); it != calledFunctions.end(); it++)
	{
		//get each symbol and each structure, and add them to the map
		// checking that any previous entries are equivalent
		const std::vector<GlslSymbol*> &symList = (*it)->getSymbols();

		for (std::vector<GlslSymbol*>::const_iterator cit = symList.begin(); cit < symList.end(); cit++)
		{
			if ( (*cit)->getIsGlobal())
			{
				//should check for already added ones here
				globalSymMap[(*cit)->getName()] = *cit;
			}
		}

		//take each referenced library function, and add it to the set
		const std::set<TOperator> &libSet = (*it)->getLibFunctions();

		libFunctions.insert( libSet.begin(), libSet.end());
	}


	// The following code is what is used to generate the actual shader and "main"
	// function. The process is to take all the components collected above, and
	// write them to the appropriate code stream. Finally, a main function is
	// generated that calls the specified entrypoint. That main function uses
	// semantics on the arguments and return values to connect items appropriately.

	//
	// Write Library Functions & required extensions
	std::string shaderExtensions, shaderLibFunctions;
	if (!libFunctions.empty())
	{
		for (std::set<TOperator>::iterator it = libFunctions.begin(); it != libFunctions.end(); it++)
		{
			const std::string &func = getHLSLSupportCode(*it, shaderExtensions, lang==EShLangVertex);
			if (!func.empty())
			{
				shaderLibFunctions += func;
				shaderLibFunctions += '\n';
			}
		}
	}
	shader << shaderExtensions;
	shader << shaderLibFunctions;

	//
	//Structure addition hack
	// Presently, structures are not tracked per function, just dump them all
	// This could be improved by building a complete list of structures for the
	// shaders based on the variables in each function
	//
	{
		HlslCrossCompiler *comp = static_cast<HlslCrossCompiler*>(compiler);
		std::vector<GlslStruct*> &sList = comp->structList;

		if (!sList.empty())
		{
			for (std::vector<GlslStruct*>::iterator it = sList.begin(); it < sList.end(); it++)
			{
				shader << (*it)->getDecl() << "\n";
			}
		}
	}

	//
	// Write global variables
	//

	if (!globalSymMap.empty())
	{
		for (std::map<std::string,GlslSymbol*>::iterator sit = globalSymMap.begin(); sit != globalSymMap.end(); sit++)
		{
			sit->second->writeDecl(shader,false,false);
			shader << ";\n";

			if ( sit->second->getIsMutable() )
			{
				sit->second->writeDecl(shader, true, false);
				shader << ";\n";
			}         
		}
	}

	//
	// Write function declarations and definitions
	//
	EmitCalledFunctions (shader, calledFunctions);

	// 
	// Gather the uniforms into the uniform list
	//
	for (std::map<std::string, GlslSymbol*>::iterator it = globalSymMap.begin(); it != globalSymMap.end(); it++)
	{
		if (it->second->getQualifier() != EqtUniform)
			continue;

		ShUniformInfo infoStruct;
		infoStruct.name = new char[it->first.size()+1];
		strcpy( infoStruct.name, it->first.c_str());
		if (it->second->getSemantic() != "")
		{
			infoStruct.semantic = new char[it->second->getSemantic().size()+1];
			strcpy( infoStruct.semantic, it->second->getSemantic().c_str());
		}
		else
			infoStruct.semantic = 0;

		//gigantic hack, the enumerations are kept in alignment
		infoStruct.type = (EShType)it->second->getType();
		infoStruct.arraySize = it->second->getArraySize();

		if ( it->second->hasInitializer() )
		{
			int initSize = it->second->initializerSize();
			infoStruct.init = new float[initSize];
			memcpy( infoStruct.init, it->second->getInitializer(), sizeof(float) * initSize);
		}
		else
			infoStruct.init = 0;

		//TODO: need to add annotation

		uniforms.push_back( infoStruct);
	}

	//
	// Generate the main function
	//

		std::stringstream attrib;
		std::stringstream uniform;
		std::stringstream preamble;
		std::stringstream postamble;
		std::stringstream varying;
		std::stringstream call;
		const int pCount = funcMain->getParameterCount();

		preamble << "void main() {\n";
		const EGlslSymbolType retType = funcMain->getReturnType();
		GlslStruct *retStruct = funcMain->getStruct();
		if (  retType == EgstStruct)
		{
			assert(retStruct);
			preamble << "    " << retStruct->getName() << " xl_retval;\n";
		}
		else
		{
			if ( retType != EgstVoid)
			{
				preamble << "    ";
				writeType (preamble, retType, NULL, usePrecision?funcMain->getPrecision():EbpUndefined);
				preamble << " xl_retval;\n";
			}
		}

		// Write all mutable initializations
		if ( calledFunctions.size() > 0 )
		{
			for (FunctionSet::iterator fit = calledFunctions.begin(); fit != calledFunctions.end(); fit++)
			{
				std::string mutableDecls = (*fit)->getMutableDecls(1, calledFunctions.begin(), fit);

				if ( mutableDecls.size() > 0 )
				{
					preamble << mutableDecls;
				}
			}
		}

		call << "    ";
		if (retType != EgstVoid)
			call << "xl_retval = " << funcMain->getName() << "( ";
		else
			call << funcMain->getName() << "( ";

		// pass main function parameters
		for (int ii=0; ii<pCount; ii++)
		{
			GlslSymbol *sym = funcMain->getParameter(ii);
			EAttribSemantic attrSem = parseAttributeSemantic( sym->getSemantic());

			switch (sym->getQualifier())
			{

			// -------- IN & OUT parameters
			case EqtIn:
			case EqtInOut:
				if ( sym->getType() != EgstStruct)
				{
					std::string name, ctor;
					int pad;

					if ( getArgumentData( sym, lang==EShLangVertex ? EClassAttrib : EClassVarIn, name, ctor, pad) )
					{
						// In fragment shader, pass zero for POSITION inputs
						bool ignoredPositionInFragment = false;
						if (lang == EShLangFragment && attrSem == EAttrSemPosition)
						{
							call << ctor << "(0.0)";
							ignoredPositionInFragment = true;
						}
						// For "in" parameters, just call directly to the main
						else if ( sym->getQualifier() != EqtInOut )
						{
							call << ctor << "(" << name;
							for (int ii = 0; ii<pad; ii++)
								call << ", 0.0";
							call << ")";
						}
						// For "inout" parameters, declare a temp and initialize the temp
						else
						{
							preamble << "    ";
							writeType (preamble, sym->getType(), NULL, usePrecision?sym->getPrecision():EbpUndefined);
							preamble << " xlt_" << sym->getName() << " = ";
							preamble << ctor << "(" << name;
							for (int ii = 0; ii<pad; ii++)
								preamble << ", 0.0";
							preamble << ");\n";
						}

						if (lang == EShLangVertex) // vertex shader: deal with gl_ attributes
						{
							if ( strncmp( name.c_str(), "gl_", 3))
							{
								int typeOffset = 0;

								// If the type is integer or bool based, we must convert to a float based
								// type.  This is because GLSL does not allow int or bool based vertex attributes.
								if ( sym->getType() >= EgstInt && sym->getType() <= EgstInt4)
								{
									typeOffset += 4;
								}

								if ( sym->getType() >= EgstBool && sym->getType() <= EgstBool4)
								{
									typeOffset += 8;
								}

								// This is an undefined attribute
								attrib << "attribute " << getTypeString((EGlslSymbolType)(sym->getType() + typeOffset)) << " " << name << ";\n";
							}
						}

						if (lang == EShLangFragment) // deal with varyings
						{
							if (!ignoredPositionInFragment)
								AddToVaryings (varying, sym->getPrecision(), ctor, name);
						}
					}
					else
					{
						//should deal with fall through cases here
						assert(0);
						infoSink.info << "Unsupported type for shader entry parameter (";
						infoSink.info << getTypeString(sym->getType()) << ")\n";
					}
				}
				else
				{
					//structs must pass the struct, then process per element
					GlslStruct *Struct = sym->getStruct();
					assert(Struct);

					//first create the temp
					std::string tempVar = "xlt_" + sym->getName();
					preamble << "    " << Struct->getName() << " ";
					preamble << tempVar <<";\n";
					call << tempVar;

					const int elem = Struct->memberCount();
					for (int jj=0; jj<elem; jj++)
					{
						const GlslStruct::member &current = Struct->getMember(jj);
						EAttribSemantic memberSem = parseAttributeSemantic (current.semantic);
						std::string name, ctor;
						int pad;
						int numArrayElements = 1;
						bool bIsArray = false;

						// If it is an array, loop over each member
						if ( current.arraySize > 0 )
						{
							numArrayElements = current.arraySize;
							bIsArray = true;
						}

						for ( int arrayIndex = 0; arrayIndex <  numArrayElements; arrayIndex++ )
						{
							if ( getArgumentData2( current.name, current.semantic, current.type,
								lang==EShLangVertex ? EClassAttrib : EClassVarIn, name, ctor, pad, arrayIndex ) )
							{

								preamble << "    ";
								preamble << tempVar << "." << current.name;

								if ( bIsArray )
									preamble << "[" << arrayIndex << "]";

								// In fragment shader, pass zero for POSITION inputs
								bool ignoredPositionInFragment = false;
								if (lang == EShLangFragment && memberSem == EAttrSemPosition)
								{
									preamble << " = " << ctor << "(0.0);\n";
									ignoredPositionInFragment = true;
								}
								else
								{
									preamble << " = " << ctor << "( " << name;
									for (int ii = 0; ii<pad; ii++)
										preamble << ", 0.0";
									preamble << ");\n";
								}

								if (lang == EShLangVertex) // vertex shader: gl_ attributes
								{
									if ( strncmp( name.c_str(), "gl_", 3))
									{

										int typeOffset = 0;

										// If the type is integer or bool based, we must convert to a float based
										// type.  This is because GLSL does not allow int or bool based vertex attributes.
										if ( current.type >= EgstInt && current.type <= EgstInt4)
										{
											typeOffset += 4;
										}

										if ( current.type >= EgstBool && current.type <= EgstBool4)
										{
											typeOffset += 8;
										}

										// This is an undefined attribute
										attrib << "attribute " << getTypeString((EGlslSymbolType)(current.type + typeOffset)) << " " << name << ";\n";

									}
								}
								
								if (lang == EShLangFragment) // deal with varyings
								{
									if (!ignoredPositionInFragment)
										AddToVaryings (varying, current.precision, ctor, name);
								}
							}
							else
							{
								//should deal with fall through cases here
								assert(0);
								infoSink.info << "Unsupported type for struct element in shader entry parameter (";
								infoSink.info << getTypeString(current.type) << ")\n";
							}
						}
					}
				}

				//
				// NOTE: This check only breaks out of the case if we have an "in" parameter, for
				//       "inout" it will fallthrough to the next case
				//
				if ( sym->getQualifier() != EqtInOut )
				{
					break;
				}


			// -------- OUT parameters; also fall-through for INOUT (see the check above)
			case EqtOut:

				if ( sym->getType() != EgstStruct)
				{
					std::string name, ctor;
					int pad;

					if ( getArgumentData( sym, lang==EShLangVertex ? EClassVarOut : EClassRes, name, ctor, pad) )
					{
						// For "inout" parameters, the preamble was already written so no need to do it here.
						if ( sym->getQualifier() != EqtInOut )
						{
							preamble << "    ";
							writeType (preamble, sym->getType(), NULL, usePrecision?sym->getPrecision():EbpUndefined);
							preamble << " xlt_" << sym->getName() << ";\n";                     
						}
						
						if (lang == EShLangVertex) // deal with varyings
						{
							AddToVaryings (varying, sym->getPrecision(), ctor, name);
						}

						call << "xlt_" << sym->getName();

						postamble << "    ";
						postamble << name << " = " << ctor << "( xlt_" <<sym->getName();
						for (int ii = 0; ii<pad; ii++)
							postamble << ", 0.0";

						postamble << ");\n";
					}
					else
					{
						//should deal with fall through cases here
						assert(0);
						infoSink.info << "Unsupported type for shader entry parameter (";
						infoSink.info << getTypeString(sym->getType()) << ")\n";
					}
				}
				else
				{
					//structs must pass the struct, then process per element
					GlslStruct *Struct = sym->getStruct();
					assert(Struct);

					//first create the temp
					std::string tempVar = "xlt_" + sym->getName();

					// For "inout" parmaeters the preamble and call were already written, no need to do it here
					if ( sym->getQualifier() != EqtInOut )
					{
						preamble << "    " << Struct->getName() << " ";
						preamble << tempVar <<";\n";
						call << tempVar;
					}

					const int elem = Struct->memberCount();
					for (int ii=0; ii<elem; ii++)
					{
						const GlslStruct::member &current = Struct->getMember(ii);
						std::string name, ctor;
						int pad;

						if ( getArgumentData2( current.name, current.semantic, current.type, lang==EShLangVertex ? EClassVarOut : EClassRes, name, ctor, pad, 0) )
						{
							postamble << "    ";
							postamble << name << " = " << ctor;
							postamble << "( " << tempVar << "." << current.name;
							for (int ii = 0; ii<pad; ii++)
								postamble << ", 0.0";

							postamble << ");\n";

							if (lang == EShLangVertex) // deal with varyings
							{
								AddToVaryings (varying, current.precision, ctor, name);
							}
						}
						else
						{
							//should deal with fall through cases here
							assert(0);
							infoSink.info << "Unsupported type in struct element for shader entry parameter (";
							infoSink.info << getTypeString(current.type) << ")\n";
						}
					}
				}
				break;

			case EqtUniform:
				uniform << "uniform ";
				writeType (uniform, sym->getType(), NULL, usePrecision?sym->getPrecision():EbpUndefined);
				uniform << " xlu_" << sym->getName() << ";\n";
				call << "xlu_" << sym->getName();
				break;

			default:
				assert(0);
			};
			if (ii != pCount -1)
				call << ", ";
		}

		call << ");\n";


		// -------- return value of main entry point
		if (retType != EgstVoid)
		{

			if (retType != EgstStruct)
			{
				std::string name, ctor;
				int pad;

				if ( getArgumentData2( "", funcMain->getSemantic(), retType, lang==EShLangVertex ? EClassVarOut : EClassRes,
					name, ctor, pad, 0) )
				{

					postamble << "    ";
					postamble << name << " = " << ctor << "( xl_retval";
					for (int ii = 0; ii<pad; ii++)
						postamble << ", 0.0";

					postamble << ");\n";

					if (lang == EShLangVertex) // deal with varyings
					{
						AddToVaryings (varying, funcMain->getPrecision(), ctor, name);
					}
				}
				else
				{
					//should deal with fall through cases here
					assert(0);
					infoSink.info << (lang==EShLangVertex ? "Unsupported type for shader return value (" : "Unsupported return type for shader entry function (");
					infoSink.info << getTypeString(retType) << ")\n";
				}
			}
			else
			{
				const int elem = retStruct->memberCount();
				for (int ii=0; ii<elem; ii++)
				{
					const GlslStruct::member &current = retStruct->getMember(ii);
					std::string name, ctor;
					int pad;
					int numArrayElements = 1;
					bool bIsArray = false;

					if (lang == EShLangVertex) // vertex shader
					{
						// If it is an array, loop over each member
						if ( current.arraySize > 0 )
						{
							numArrayElements = current.arraySize;
							bIsArray = true;
						}
					}

					for ( int arrayIndex = 0; arrayIndex < numArrayElements; arrayIndex++ )
					{

						if ( getArgumentData2( current.name, current.semantic, current.type, lang==EShLangVertex ? EClassVarOut : EClassRes, name, ctor, pad, arrayIndex) )
						{
							postamble << "    ";
							postamble << name;                                                            
							postamble << " = " << ctor;
							postamble << "( xl_retval." << current.name;
							if ( bIsArray )
							{
								postamble << "[" << arrayIndex << "]";
							}
							for (int ii = 0; ii<pad; ii++)
								postamble << ", 0.0";

							postamble << ");\n";

							if (lang == EShLangVertex) // deal with varyings
							{
								AddToVaryings (varying, current.precision, ctor, name);
							}
						}
						else
						{
							//should deal with fall through cases here
							//assert(0);
							infoSink.info << (lang==EShLangVertex ? "Unsupported element type in struct for shader return value (" : "Unsupported struct element type in return type for shader entry function (");
							infoSink.info << getTypeString(current.type) << ")\n";
							return false;
						}
					}
				}
			}
		}
		else
		{
			if (lang == EShLangFragment) // fragment shader
			{
				// If no return type, close off the output
				postamble << ";\n";
			}
		}

		postamble << "}\n\n";

		EmitIfNotEmpty (shader, uniform);
		EmitIfNotEmpty (shader, attrib);
		EmitIfNotEmpty (shader, varying);

		shader << preamble.str() << "\n";
		shader << call.str() << "\n";
		shader << postamble.str() << "\n";

	return true;
}
Exemple #3
0
bool HlslLinker::getArgumentData2( const std::string &name, const std::string &semantic, EGlslSymbolType type,
								 EClassifier c, std::string &outName, std::string &ctor, int &pad, int semanticOffset)
{
	int size;
	EGlslSymbolType base = EgstVoid;
	EAttribSemantic sem = parseAttributeSemantic( semantic );

	// Offset the semantic for the case of an array
	sem = static_cast<EAttribSemantic>( (int)sem + semanticOffset );

	//clear the return values
	outName = "";
	ctor = "";
	pad = 0;

	//compute the # of elements in the type
	switch (type)
	{
	case EgstBool:
	case EgstBool2:
	case EgstBool3:
	case EgstBool4:
		base = EgstBool;
		size = type - EgstBool + 1;
		break;

	case EgstInt:
	case EgstInt2:
	case EgstInt3:
	case EgstInt4:
		base = EgstInt;
		size = type - EgstInt + 1;
		break;

	case EgstFloat:
	case EgstFloat2:
	case EgstFloat3:
	case EgstFloat4:
		base = EgstFloat;
		size = type - EgstFloat + 1;
		break;

    default:
        return false;
	};

	if ( c != EClassUniform)
	{

		ctor = getTypeString( (EGlslSymbolType)((int)base + size - 1)); //default constructor
		pad = 0;

		switch (c)
		{
		case EClassNone:
			return false;

		case EClassAttrib:
			// If the user has specified a user attrib name, use a user attribute
			if ( userAttribString[sem][0] != '\0')
			{
				outName = userAttribString[sem];
			}
			// Otherwise, use the built-in attribute name
			else
			{
				outName = attribString[sem];
				if (sem == EAttrSemNormal && size == 4)
					pad = 1;
				else if ( sem == EAttrSemUnknown || outName[0] == '\0' )
				{
					//handle the blind data
					outName = "xlat_attrib_";
					outName += semantic;
				}
			}
			break;

		case EClassVarOut:
			// If using user varyings, create a user varying name
			if ( (bUserVaryings && sem != EAttrSemPosition) || varOutString[sem][0] == 0 )
			{
				outName = kUserVaryingPrefix;
				outName += semantic;
				// If an array element, add the semantic offset to the name
				if ( semanticOffset != 0 )
				{
					outName += "_";
					outName += ( semanticOffset + '0' );
				}
			}
			else
			{
				// Use built-in varying name
				outName = varOutString[sem];                
			}
			break;

		case EClassVarIn:
			// If using user varyings, create a user varying name
			if ( (bUserVaryings && sem != EAttrSemVPos && sem != EAttrSemVFace) || varInString[sem][0] == 0 )
			{
				outName = kUserVaryingPrefix;
				outName += stripSemanticModifier ( semantic, false );
				// If an array element, add the semantic offset to the name
				if ( semanticOffset != 0 )
				{
					outName += "_";
					outName += ( semanticOffset + '0' );
				}
			}
			else
			{
				// Use built-in varying name
				outName = varInString[sem];
			}                
			break;

		case EClassRes:
			outName = resultString[sem];
			if ( sem != EAttrSemDepth)
			{
				pad = 4 - size;
				ctor = "vec4";
			}
			else
			{
				ctor = "float";
			}
			break;

		case EClassUniform:
			assert(0); // this should have been stripped
			return false; 
		};


	}
	else
	{
		//these should always match exactly
		outName = "xlu_";
		outName += name;
	}

	return true;
}
bool HlslLinker::getArgumentData2( GlslSymbolOrStructMemberBase const* symOrStructMember,
								 EClassifier c, std::string &outName, std::string &ctor, int &pad, int semanticOffset)
{
	int size;
	EGlslSymbolType base = EgstVoid;
	// Get the type before suppression because we may not want all of the elements.
	// note, suppressedBy should *never* be smaller than the suppressed.
	EGlslSymbolType type = symOrStructMember->type;
	GlslSymbolOrStructMemberBase const* suppressedBy = symOrStructMember->outputSuppressedBy();
	if (suppressedBy)
		symOrStructMember = suppressedBy;
	EAttribSemantic sem = parseAttributeSemantic( symOrStructMember->semantic );
	const std::string& semantic = symOrStructMember->semantic;

	// Offset the semantic for the case of an array
	if ( semanticOffset > 0 )
		sem = static_cast<EAttribSemantic>( (int)sem + semanticOffset );

	//clear the return values
	outName = "";
	ctor = "";
	pad = 0;

	//compute the # of elements in the type
	switch (type)
	{
	case EgstBool:
	case EgstBool2:
	case EgstBool3:
	case EgstBool4:
		base = EgstBool;
		size = type - EgstBool + 1;
		break;

	case EgstInt:
	case EgstInt2:
	case EgstInt3:
	case EgstInt4:
		base = EgstInt;
		size = type - EgstInt + 1;
		break;

	case EgstFloat:
	case EgstFloat2:
	case EgstFloat3:
	case EgstFloat4:
		base = EgstFloat;
		size = type - EgstFloat + 1;
		break;

    default:
        return false;
	};

	if ( c != EClassUniform)
	{

		ctor = getTypeString( (EGlslSymbolType)((int)base + size - 1)); //default constructor
		pad = 0;

		switch (c)
		{
		case EClassNone:
			return false;

		case EClassAttrib:
			getAttributeName( symOrStructMember, outName, sem, semanticOffset );
			if (outName == "gl_Normal" && size == 4)
				pad = 1;
			break;

		case EClassVarOut:
			// If using user varyings, create a user varying name
			// WHY ON EARTH such funny if
			if ( (bUserVaryings && sem != EAttrSemPosition && sem != EAttrSemPrimitiveID && sem != EAttrSemPSize) || varOutString[sem][0] == 0 )
			{
				outName = kUserVaryingPrefix;
				outName += semantic;
				// If an array element, add the semantic offset to the name
				if ( semanticOffset > 0 )
				{
					outName += "_";
					outName += ( semanticOffset + '0' );
				}
			}
			else
			{
				// Use built-in varying name
				outName = varOutString[sem];

				// Always pad built-in varying outputs to 4 elements
				// exception: psize must be kept float1
				if(sem != EAttrSemPSize)
				{
					pad = 4 - size;
					ctor = "vec4";
				}
			}
			break;

		case EClassVarIn:
			// inout COLORn variables translate to framebuffer fetch for GLES
			if (IsArgumentForFramebufferFetch(symOrStructMember, sem, m_Target))
			{
				int index = sem - EAttrSemColor0;
				outName = (m_Target == ETargetGLSL_ES_100 ? "gl_LastFragData" : "gl_FragData");
				outName += '[';
				outName += char('0'+index);
				outName += ']';
				m_Extensions.insert("GL_EXT_shader_framebuffer_fetch");
			}
			// If using user varyings, create a user varying name
			else if ( (bUserVaryings && sem != EAttrSemVPos && sem != EAttrSemVFace && sem != EAttrSemPrimitiveID) || varInString[sem][0] == 0 )
			{
				outName = kUserVaryingPrefix;
				outName += stripSemanticModifier (semantic, false);
				// If an array element, add the semantic offset to the name
				if ( semanticOffset > 0 )
				{
					outName += "_";
					outName += ( semanticOffset + '0' );
				}
			}
			else
			{
				// Use built-in varying name
				outName = varInString[sem];
			}                
			break;

		case EClassRes:
			outName = resultString[sem];
			if (sem == EAttrSemDepth)
			{
				if (m_Target == ETargetGLSL_ES_100)
				{
					outName = "gl_FragDepthEXT";
					m_Extensions.insert("GL_EXT_frag_depth");
				}
				ctor = "float";
			}
			else if (sem == EAttrSemCoverage)
				ctor = "int";
			else
			{
				pad = 4 - size;
				ctor = "vec4";
			}
			break;

		case EClassUniform:
			assert(0); // this should have been stripped
			return false; 
		};


	}
	else
	{
		//these should always match exactly
		outName = "xlu_";
		outName += symOrStructMember->name;
	}

	return true;
}
bool HlslLinker::link(HlslCrossCompiler* compiler, const char* entryFunc, ETargetVersion targetVersion, unsigned options)
{
	m_Target = targetVersion;
	m_Options = options;
	m_Extensions.clear();
	if (!linkerSanityCheck(compiler, entryFunc))
		return false;
	
	const bool usePrecision = Hlsl2Glsl_VersionUsesPrecision(targetVersion);
	
	EShLanguage lang = compiler->getLanguage();
	std::string entryPoint = GetEntryName (entryFunc);
	
	
	// figure out all relevant functions
	GlslFunction* globalFunction = NULL;
	std::vector<GlslFunction*> functionList;
	FunctionSet calledFunctions;
	GlslFunction* funcMain = NULL;
	if (!buildFunctionLists(compiler, lang, entryPoint, globalFunction, functionList, calledFunctions, funcMain))
		return false;
	assert(globalFunction);
	assert(funcMain);
	
	// uniforms and used built-in functions
	std::vector<GlslSymbol*> constants;
	std::set<TOperator> libFunctions;
	buildUniformsAndLibFunctions(calledFunctions, constants, libFunctions);
	// add built-in functions possibly used by uniform initializers
	const std::set<TOperator>& referencedGlobalFunctions = globalFunction->getLibFunctions();
	libFunctions.insert (referencedGlobalFunctions.begin(), referencedGlobalFunctions.end());
	
	buildUniformReflection (constants);


	// print all the components collected above.

	emitLibraryFunctions (libFunctions, lang, usePrecision);
	emitStructs(compiler);
	emitGlobals (globalFunction, constants);
	EmitCalledFunctions (shader, calledFunctions);

	
	// Generate a main function that calls the specified entrypoint.
	// That main function uses semantics on the arguments and return values to
	// connect items appropriately.	
	
	std::stringstream attrib;
	std::stringstream uniform;
	std::stringstream preamble;
	std::stringstream postamble;
	std::stringstream varying;
	std::stringstream call;

	markDuplicatedInSemantics(funcMain);

	// Declare return value
	const EGlslSymbolType retType = funcMain->getReturnType();
	emitMainStart(compiler, retType, funcMain, m_Options, usePrecision, preamble, constants);
	

	// Call the entry point
	call << "    ";
	if (retType != EgstVoid)
		call << "xl_retval = ";
	call << funcMain->getName() << "( ";
	

	// Entry point parameters
	const int pCount = funcMain->getParameterCount();
	for (int ii=0; ii<pCount; ii++)
	{
		GlslSymbol *sym = funcMain->getParameter(ii);
		EAttribSemantic attrSem = parseAttributeSemantic( sym->getSemantic());
		
		add_extension_from_semantic(attrSem, m_Target, m_Extensions);

		switch (sym->getQualifier())
		{

		// -------- IN & OUT parameters
		case EqtIn:
		case EqtInOut:
		case EqtConst:
			if (sym->getType() != EgstStruct)
			{
				emitInputNonStructParam(sym, lang, usePrecision, attrSem, attrib, varying, preamble, call);
			}
			else
			{
				emitInputStructParam(sym, lang, attrib, varying, preamble, call);
			}

			// NOTE: for "inout" parameters need to fallthrough to the next case
			if (sym->getQualifier() != EqtInOut)
			{
				break;
			}


		// -------- OUT parameters; also fall-through for INOUT (see the check above)
		case EqtOut:

			if ( sym->getType() != EgstStruct)
			{
				emitOutputNonStructParam(sym, lang, usePrecision, attrSem, varying, preamble, postamble, call);
			}
			else
			{
				emitOutputStructParam(sym, lang, usePrecision, attrSem, varying, preamble, postamble, call);
			}
			break;

		case EqtUniform:
			uniform << "uniform ";
			writeType (uniform, sym->getType(), NULL, usePrecision?sym->getPrecision():EbpUndefined);
			uniform << " xlu_" << sym->getName();
			if(sym->getArraySize())
				uniform << "[" << sym->getArraySize() << "]";
			uniform << ";\n";
			call << "xlu_" << sym->getName();
			break;

		default:
			assert(0);
		};
		if (ii != pCount -1)
			call << ", ";
	}

	call << ");\n";


	// Entry point return value
	if (!emitReturnValue(retType, funcMain, lang, varying, postamble))
		return false;

	postamble << "}\n\n";
	
	
	// Generate final code of the pieces above.
	{
		shaderPrefix << kTargetVersionStrings[targetVersion];
		ExtensionSet::const_iterator it = m_Extensions.begin(), end = m_Extensions.end();
		for (; it != end; ++it)
			shaderPrefix << "#extension " << *it << " : require" << std::endl;
	}

	EmitIfNotEmpty (shader, uniform);
	EmitIfNotEmpty (shader, attrib);
	EmitIfNotEmpty (shader, varying);

	shader << preamble.str() << "\n";
	shader << call.str() << "\n";
	shader << postamble.str() << "\n";

	return true;
}
// This function calls itself recursively if it finds structs in structs.
bool HlslLinker::emitInputStruct(const GlslStruct* str, std::string parentName, EShLanguage lang, std::stringstream& attrib, std::stringstream& varying, std::stringstream& preamble)
{
	// process struct members
	const int elem = str->memberCount();
	for (int jj=0; jj<elem; jj++)
	{
		const StructMember &current = str->getMember(jj);
		EAttribSemantic memberSem = parseAttributeSemantic (current.semantic);
		
		add_extension_from_semantic(memberSem, m_Target, m_Extensions);
		
		// if member of the struct is an array, we have to loop over all array elements
		int arraySize = 1;
		bool isArray = false;
		if (current.arraySize > 0)
		{
			arraySize = current.arraySize;
			isArray = true;
		}
		
		std::string name, ctor;
		for (int idx = 0; idx < arraySize; ++idx)
		{
			int pad;
			if (!getArgumentData2 (&current, lang==EShLangVertex ? EClassAttrib : EClassVarIn, name, ctor, pad, isArray?idx:-1))
			{
				const GlslStruct* subStruct = current.structType;
				if (subStruct)
				{
					//should deal with fall through cases here
					emitInputStruct(subStruct, parentName+current.name+std::string("."), lang, attrib, varying, preamble);
					continue;
				}
				else
				{
					infoSink.info << "Unsupported type for struct element in shader entry parameter (";
					infoSink.info << getTypeString(current.type) << ")\n";
					return false;
				}
			}

			preamble << "    ";
			preamble << parentName << current.name;
			
			if (isArray)
				preamble << "[" << idx << "]";
			
			// In fragment shader, pass zero for POSITION inputs
			if (lang == EShLangFragment && memberSem == EAttrSemPosition)
			{
				preamble << " = " << ctor << "(0.0);\n";
				continue; // nothing more to do
			}
			else
			{
				preamble << " = ";
				emitSymbolWithPad (preamble, ctor, name, pad);
				preamble << ";\n";
			}

			if (!current.outputSuppressedBy())
				emitSingleInputVariable (lang, m_Target, name, ctor, current.type, current.precision, attrib, varying);
		}
	}
	return true;
}