void HlslLinker::emitInputStructParam(GlslSymbol* sym, EShLanguage lang, std::stringstream& attrib, std::stringstream& varying, std::stringstream& preamble, std::stringstream& call) { GlslStruct* str = sym->getStruct(); assert(str); // temporary variable for the struct const std::string tempVar = "xlt_" + sym->getName(); preamble << " " << str->getName() << " "; preamble << tempVar <<";\n"; call << tempVar; emitInputStruct(str, "xlt_" + sym->getName() + ".", lang, attrib, varying, preamble); }
void HlslLinker::emitMainStart(const HlslCrossCompiler* compiler, const EGlslSymbolType retType, GlslFunction* funcMain, unsigned options, bool usePrecision, std::stringstream& preamble, const std::vector<GlslSymbol*>& constants) { preamble << "void main() {\n"; // initialize mutable uniforms with the original uniform values const unsigned n_constants = constants.size(); for (unsigned i = 0; i != n_constants; ++i) { GlslSymbol* s = constants[i]; if (s->getIsMutable()) { s->writeDecl(preamble, GlslSymbol::kWriteDeclMutableInit); preamble << ";\n"; } } std::string arrayInit = compiler->m_DeferredArrayInit.str(); if (!arrayInit.empty()) { const bool emit_120_arrays = (m_Target >= ETargetGLSL_120); const bool emit_old_arrays = !emit_120_arrays || (options & ETranslateOpEmitGLSL120ArrayInitWorkaround); const bool emit_both = emit_120_arrays && emit_old_arrays; if (emit_both) preamble << "#if defined(HLSL2GLSL_ENABLE_ARRAY_120_WORKAROUND)" << std::endl; preamble << arrayInit; if (emit_both) preamble << "\n#endif" << std::endl; } std::string matrixInit = compiler->m_DeferredMatrixInit.str(); if (!matrixInit.empty()) { preamble << matrixInit; } if (retType == EgstStruct) { GlslStruct* retStruct = funcMain->getStruct(); 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"; } }
void HlslLinker::emitOutputStructParam(GlslSymbol* sym, EShLanguage lang, bool usePrecision, EAttribSemantic attrSem, std::stringstream& varying, std::stringstream& preamble, std::stringstream& postamble, std::stringstream& call) { //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 StructMember ¤t = Struct->getMember(ii); std::string name, ctor; int pad; if (!getArgumentData2( ¤t, lang==EShLangVertex ? EClassVarOut : EClassRes, name, ctor, pad, -1)) { //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"; continue; } postamble << " "; postamble << name << " = "; emitSymbolWithPad (postamble, ctor, tempVar+"."+current.name, pad); postamble << ";\n"; // In vertex shader, add to varyings if (lang == EShLangVertex) AddVertexOutput (varying, m_Target, current.precision, ctor, name); } }
bool TGlslOutputTraverser::traverseBinary( bool preVisit, TIntermBinary *node, TIntermTraverser *it ) { TString op = "??"; TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it); GlslFunction *current = goit->current; std::stringstream& out = current->getActiveOutput(); bool infix = true; bool assign = false; bool needsParens = true; switch (node->getOp()) { case EOpAssign: op = "="; infix = true; needsParens = false; break; case EOpAddAssign: op = "+="; infix = true; needsParens = false; break; case EOpSubAssign: op = "-="; infix = true; needsParens = false; break; case EOpMulAssign: op = "*="; infix = true; needsParens = false; break; case EOpVectorTimesMatrixAssign: op = "*="; infix = true; needsParens = false; break; case EOpVectorTimesScalarAssign: op = "*="; infix = true; needsParens = false; break; case EOpMatrixTimesScalarAssign: op = "*="; infix = true; needsParens = false; break; case EOpMatrixTimesMatrixAssign: op = "*="; infix = true; needsParens = false; break; case EOpDivAssign: op = "/="; infix = true; needsParens = false; break; case EOpModAssign: op = "%="; infix = true; needsParens = false; break; case EOpAndAssign: op = "&="; infix = true; needsParens = false; break; case EOpInclusiveOrAssign: op = "|="; infix = true; needsParens = false; break; case EOpExclusiveOrAssign: op = "^="; infix = true; needsParens = false; break; case EOpLeftShiftAssign: op = "<<="; infix = true; needsParens = false; break; case EOpRightShiftAssign: op = "??="; infix = true; needsParens = false; break; case EOpIndexDirect: { TIntermTyped *left = node->getLeft(); TIntermTyped *right = node->getRight(); assert( left && right); current->beginStatement(); if (Check2DMatrixIndex (goit, out, left, right)) return false; if (left->isMatrix() && !left->isArray()) { if (right->getAsConstant()) { current->addLibFunction (EOpMatrixIndex); out << "xll_matrixindex ("; left->traverse(goit); out << ", "; right->traverse(goit); out << ")"; return false; } else { current->addLibFunction (EOpTranspose); current->addLibFunction (EOpMatrixIndex); current->addLibFunction (EOpMatrixIndexDynamic); out << "xll_matrixindexdynamic ("; left->traverse(goit); out << ", "; right->traverse(goit); out << ")"; return false; } } left->traverse(goit); // Special code for handling a vector component select (this improves readability) if (left->isVector() && !left->isArray() && right->getAsConstant()) { char swiz[] = "xyzw"; goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant; goit->generatingCode = false; right->traverse(goit); assert( goit->indexList.size() == 1); assert( goit->indexList[0] < 4); out << "." << swiz[goit->indexList[0]]; goit->indexList.clear(); goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion; goit->generatingCode = true; } else { out << "["; right->traverse(goit); out << "]"; } return false; } case EOpIndexIndirect: { TIntermTyped *left = node->getLeft(); TIntermTyped *right = node->getRight(); current->beginStatement(); if (Check2DMatrixIndex (goit, out, left, right)) return false; if (left && right && left->isMatrix() && !left->isArray()) { if (right->getAsConstant()) { current->addLibFunction (EOpMatrixIndex); out << "xll_matrixindex ("; left->traverse(goit); out << ", "; right->traverse(goit); out << ")"; return false; } else { current->addLibFunction (EOpTranspose); current->addLibFunction (EOpMatrixIndex); current->addLibFunction (EOpMatrixIndexDynamic); out << "xll_matrixindexdynamic ("; left->traverse(goit); out << ", "; right->traverse(goit); out << ")"; return false; } } if (left) left->traverse(goit); out << "["; if (right) right->traverse(goit); out << "]"; return false; } case EOpIndexDirectStruct: { current->beginStatement(); GlslStruct *s = goit->createStructFromType(node->getLeft()->getTypePointer()); if (node->getLeft()) node->getLeft()->traverse(goit); // The right child is always an offset into the struct, switch to get an // immediate constant, and put it back afterwords goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant; goit->generatingCode = false; if (node->getRight()) { node->getRight()->traverse(goit); assert( goit->indexList.size() == 1); assert( goit->indexList[0] < s->memberCount()); out << "." << s->getMember(goit->indexList[0]).name; } goit->indexList.clear(); goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion; goit->generatingCode = true; } return false; case EOpVectorSwizzle: current->beginStatement(); if (node->getLeft()) node->getLeft()->traverse(goit); goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant; goit->generatingCode = false; if (node->getRight()) { node->getRight()->traverse(goit); assert( goit->indexList.size() <= 4); out << '.'; const char fields[] = "xyzw"; for (int ii = 0; ii < (int)goit->indexList.size(); ii++) { int val = goit->indexList[ii]; assert( val >= 0); assert( val < 4); out << fields[val]; } } goit->indexList.clear(); goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion; goit->generatingCode = true; return false; case EOpMatrixSwizzle: // This presently only works for swizzles as rhs operators if (node->getRight()) { goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant; goit->generatingCode = false; node->getRight()->traverse(goit); goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion; goit->generatingCode = true; std::vector<int> elements = goit->indexList; goit->indexList.clear(); if (elements.size() > 4 || elements.size() < 1) { goit->infoSink.info << "Matrix swizzle operations can must contain at least 1 and at most 4 element selectors."; return true; } unsigned column[4] = {0}, row[4] = {0}; for (unsigned i = 0; i != elements.size(); ++i) { unsigned val = elements[i]; column[i] = val % 4; row[i] = val / 4; } bool sameColumn = true; for (unsigned i = 1; i != elements.size(); ++i) sameColumn &= column[i] == column[i-1]; static const char* fields = "xyzw"; if (sameColumn) { //select column, then swizzle row if (node->getLeft()) node->getLeft()->traverse(goit); out << "[" << column[0] << "]."; for (unsigned i = 0; i < elements.size(); ++i) out << fields[row[i]]; } else { // Insert constructor, and dereference individually // Might need to account for different types here assert( elements.size() != 1); //should have hit same collumn case out << "vec" << elements.size() << "("; if (node->getLeft()) node->getLeft()->traverse(goit); out << "[" << column[0] << "]."; out << fields[row[0]]; for (unsigned i = 1; i < elements.size(); ++i) { out << ", "; if (node->getLeft()) node->getLeft()->traverse(goit); out << "[" << column[i] << "]."; out << fields[row[i]]; } out << ")"; } } return false; case EOpAdd: op = "+"; infix = true; break; case EOpSub: op = "-"; infix = true; break; case EOpMul: op = "*"; infix = true; break; case EOpDiv: op = "/"; infix = true; break; case EOpMod: op = "mod"; infix = false; break; case EOpRightShift: op = "<<"; infix = true; break; case EOpLeftShift: op = ">>"; infix = true; break; case EOpAnd: op = "&"; infix = true; break; case EOpInclusiveOr: op = "|"; infix = true; break; case EOpExclusiveOr: op = "^"; infix = true; break; case EOpEqual: writeComparison ( "==", "equal", node, goit ); return false; case EOpNotEqual: writeComparison ( "!=", "notEqual", node, goit ); return false; case EOpLessThan: writeComparison ( "<", "lessThan", node, goit ); return false; case EOpGreaterThan: writeComparison ( ">", "greaterThan", node, goit ); return false; case EOpLessThanEqual: writeComparison ( "<=", "lessThanEqual", node, goit ); return false; case EOpGreaterThanEqual: writeComparison ( ">=", "greaterThanEqual", node, goit ); return false; case EOpVectorTimesScalar: op = "*"; infix = true; break; case EOpVectorTimesMatrix: op = "*"; infix = true; break; case EOpMatrixTimesVector: op = "*"; infix = true; break; case EOpMatrixTimesScalar: op = "*"; infix = true; break; case EOpMatrixTimesMatrix: op = "*"; infix = true; break; case EOpLogicalOr: op = "||"; infix = true; break; case EOpLogicalXor: op = "^^"; infix = true; break; case EOpLogicalAnd: op = "&&"; infix = true; break; default: assert(0); } current->beginStatement(); if (infix) { // special case for swizzled matrix assignment if (node->getOp() == EOpAssign && node->getLeft() && node->getRight()) { TIntermBinary* lval = node->getLeft()->getAsBinaryNode(); if (lval && lval->getOp() == EOpMatrixSwizzle) { static const char* vec_swizzles = "xyzw"; TIntermTyped* rval = node->getRight(); TIntermTyped* lexp = lval->getLeft(); goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant; goit->generatingCode = false; lval->getRight()->traverse(goit); goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion; goit->generatingCode = true; std::vector<int> swizzles = goit->indexList; goit->indexList.clear(); char temp_rval[128]; unsigned n_swizzles = swizzles.size(); if (n_swizzles > 1) { snprintf(temp_rval, 128, "xlat_swiztemp%d", goit->swizzleAssignTempCounter++); current->beginStatement(); out << "vec" << n_swizzles << " " << temp_rval << " = "; rval->traverse(goit); current->endStatement(); } for (unsigned i = 0; i != n_swizzles; ++i) { unsigned col = swizzles[i] / 4; unsigned row = swizzles[i] % 4; current->beginStatement(); lexp->traverse(goit); out << "[" << row << "][" << col << "] = "; if (n_swizzles > 1) out << temp_rval << "." << vec_swizzles[i]; else rval->traverse(goit); current->endStatement(); } return false; } } if (needsParens) out << '('; if (node->getLeft()) node->getLeft()->traverse(goit); out << ' ' << op << ' '; if (node->getRight()) node->getRight()->traverse(goit); if (needsParens) out << ')'; } else { if (assign) { // Need to traverse the left child twice to allow for the assign and the op // This is OK, because we know it is an lvalue if (node->getLeft()) node->getLeft()->traverse(goit); out << " = " << op << '('; if (node->getLeft()) node->getLeft()->traverse(goit); out << ", "; if (node->getRight()) node->getRight()->traverse(goit); out << ')'; } else { out << op << '('; if (node->getLeft()) node->getLeft()->traverse(goit); out << ", "; if (node->getRight()) node->getRight()->traverse(goit); out << ')'; } } return false; }
GlslStruct *TGlslOutputTraverser::createStructFromType (TType *type) { GlslStruct *s = 0; std::string structName = type->getTypeName().c_str(); //check for anonymous structures if (structName.size() == 0) { std::stringstream temp; TTypeList &tList = *type->getStruct(); //build a mangled name that is hopefully mangled enough to prevent collisions temp << "anonStruct"; for (TTypeList::iterator it = tList.begin(); it != tList.end(); it++) { TString typeString; it->type->buildMangledName(typeString); temp << "_" << typeString.c_str(); } structName = temp.str(); } //try to find the struct name if ( structMap.find(structName) == structMap.end() ) { //This is a new structure, build a type for it TTypeList &tList = *type->getStruct(); s = new GlslStruct(structName, type->getLine()); for (TTypeList::iterator it = tList.begin(); it != tList.end(); it++) { GlslStruct::member m; m.name = it->type->getFieldName().c_str(); if (it->type->hasSemantic()) m.semantic = it->type->getSemantic().c_str(); if (it->type->getBasicType() == EbtStruct) { m.structType = createStructFromType(it->type); } else m.structType = NULL; m.type = translateType( it->type); m.arraySize = it->type->isArray() ? it->type->getArraySize() : 0; m.precision = m_UsePrecision ? it->type->getPrecision() : EbpUndefined; s->addMember(m); } //add it to the list structMap[structName] = s; structList.push_back(s); } else { s = structMap[structName]; } return s; }
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 ¤t = 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 ¤t = 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 ¤t = 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; }