From: Tim Moore Date: Thu, 26 Nov 2009 10:39:34 +0000 (+0100) Subject: Support for shader program attributes in effects X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=7f5df1fb66b3f13ad1453b80b705f5be4c7c994f;p=simgear.git Support for shader program attributes in effects Also, use a hash table for the effect shader program cache. --- diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx index b18f4c62..940b1f18 100644 --- a/simgear/scene/material/Effect.cxx +++ b/simgear/scene/material/Effect.cxx @@ -30,8 +30,11 @@ #include #include #include +#include +#include #include +#include #include #include @@ -539,10 +542,50 @@ InstallAttributeBuilder installAlphaTest("alpha-test"); InstallAttributeBuilder textureUnitBuilder("texture-unit"); -typedef map > ProgramMap; +// Shader key, used both for shaders with relative and absolute names +typedef pair ShaderKey; + +struct ProgramKey +{ + typedef pair AttribKey; + osgDB::FilePathList paths; + vector shaders; + vector attributes; + struct EqualTo + { + bool operator()(const ProgramKey& lhs, const ProgramKey& rhs) const + { + return (lhs.paths.size() == rhs.paths.size() + && equal(lhs.paths.begin(), lhs.paths.end(), + rhs.paths.begin()) + && lhs.shaders.size() == rhs.shaders.size() + && equal (lhs.shaders.begin(), lhs.shaders.end(), + rhs.shaders.begin()) + && lhs.attributes.size() == rhs.attributes.size() + && equal(lhs.attributes.begin(), lhs.attributes.end(), + rhs.attributes.begin())); + } + }; +}; + +size_t hash_value(const ProgramKey& key) +{ + size_t seed = 0; + boost::hash_range(seed, key.paths.begin(), key.paths.end()); + boost::hash_range(seed, key.shaders.begin(), key.shaders.end()); + boost::hash_range(seed, key.attributes.begin(), key.attributes.end()); + return seed; +} + +// XXX Should these be protected by a mutex? Probably + +typedef tr1::unordered_map, + boost::hash, ProgramKey::EqualTo> +ProgramMap; ProgramMap programMap; -typedef map > ShaderMap; +typedef tr1::unordered_map, boost::hash > +ShaderMap; ShaderMap shaderMap; void reload_shaders() @@ -550,7 +593,7 @@ void reload_shaders() for(ShaderMap::iterator sitr = shaderMap.begin(); sitr != shaderMap.end(); ++sitr) { Shader *shader = sitr->second.get(); - string fileName = osgDB::findDataFile(sitr->first); + string fileName = osgDB::findDataFile(sitr->first.first); if (!fileName.empty()) { shader->loadShaderSourceFromFile(fileName); } @@ -568,34 +611,47 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass, const osgDB::ReaderWriter::Options* options) { + using namespace boost; if (!isAttributeActive(effect, prop)) return; PropertyList pVertShaders = prop->getChildren("vertex-shader"); PropertyList pFragShaders = prop->getChildren("fragment-shader"); - string programKey; + PropertyList pAttributes = prop->getChildren("attribute"); + ProgramKey prgKey; for (PropertyList::iterator itr = pVertShaders.begin(), e = pVertShaders.end(); itr != e; ++itr) - { - programKey += (*itr)->getStringValue(); - programKey += ";"; - } + prgKey.shaders.push_back(ShaderKey((*itr)->getStringValue(), + Shader::VERTEX)); for (PropertyList::iterator itr = pFragShaders.begin(), e = pFragShaders.end(); itr != e; ++itr) - { - programKey += (*itr)->getStringValue(); - programKey += ";"; + prgKey.shaders.push_back(ShaderKey((*itr)->getStringValue(), + Shader::FRAGMENT)); + for (PropertyList::iterator itr = pAttributes.begin(), + e = pAttributes.end(); + itr != e; + ++itr) { + const SGPropertyNode* pName = getEffectPropertyChild(effect, *itr, + "name"); + const SGPropertyNode* pIndex = getEffectPropertyChild(effect, *itr, + "index"); + if (!pName || ! pIndex) + throw BuilderException("malformed attribute property"); + prgKey.attributes + .push_back(ProgramKey::AttribKey(pName->getStringValue(), + pIndex->getValue())); } + if (options) + prgKey.paths = options->getDatabasePathList(); Program* program = 0; - ProgramMap::iterator pitr = programMap.find(programKey); + ProgramMap::iterator pitr = programMap.find(prgKey); if (pitr != programMap.end()) { program = pitr->second.get(); } else { program = new Program; - program->setName(programKey); // Add vertex shaders, then fragment shaders PropertyList& pvec = pVertShaders; Shader::Type stype = Shader::VERTEX; @@ -604,24 +660,29 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass, nameItr != e; ++nameItr) { string shaderName = (*nameItr)->getStringValue(); - ShaderMap::iterator sitr = shaderMap.find(shaderName); + string fileName = osgDB::findDataFile(shaderName, options); + if (fileName.empty()) + throw BuilderException(string("couldn't find shader ") + + shaderName); + ShaderKey skey(fileName, stype); + ShaderMap::iterator sitr = shaderMap.find(skey); if (sitr != shaderMap.end()) { program->addShader(sitr->second.get()); } else { - string fileName = osgDB::findDataFile(shaderName, options); - if (!fileName.empty()) { - ref_ptr shader = new Shader(stype); - if (shader->loadShaderSourceFromFile(fileName)) { - program->addShader(shader.get()); - shaderMap.insert(make_pair(shaderName, shader)); - } + ref_ptr shader = new Shader(stype); + if (shader->loadShaderSourceFromFile(fileName)) { + program->addShader(shader.get()); + shaderMap.insert(ShaderMap::value_type(skey, shader)); } } } pvec = pFragShaders; stype = Shader::FRAGMENT; } - programMap.insert(make_pair(programKey, program)); + BOOST_FOREACH(const ProgramKey::AttribKey& key, prgKey.attributes) { + program->addBindAttribLocation(key.first, key.second); + } + programMap.insert(ProgramMap::value_type(prgKey, program)); } pass->setAttributeAndModes(program); }