void HlslLinker::buildUniformReflection(const std::vector<GlslSymbol*>& constants) { const unsigned n_constants = constants.size(); for (unsigned i = 0; i != n_constants; ++i) { GlslSymbol* s = constants[i]; ShUniformInfo info; const std::string& name = s->getName(false); info.name = new char[name.size()+1]; strcpy(info.name, name.c_str()); if (s->getSemantic() != "") { info.semantic = new char[s->getSemantic().size()+1]; strcpy(info.semantic, s->getSemantic().c_str()); } else info.semantic = 0; info.type = (EShType)s->getType(); info.arraySize = s->getArraySize(); info.init = 0; uniforms.push_back(info); } }
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; }