Support for shader program attributes in effects
Also, use a hash table for the effect shader program cache.
This commit is contained in:
@@ -30,8 +30,11 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <boost/tr1/unordered_map.hpp>
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/functional/hash.hpp>
|
||||||
#include <boost/tuple/tuple.hpp>
|
#include <boost/tuple/tuple.hpp>
|
||||||
#include <boost/tuple/tuple_comparison.hpp>
|
#include <boost/tuple/tuple_comparison.hpp>
|
||||||
|
|
||||||
@@ -539,10 +542,50 @@ InstallAttributeBuilder<AlphaTestBuilder> installAlphaTest("alpha-test");
|
|||||||
|
|
||||||
InstallAttributeBuilder<TextureUnitBuilder> textureUnitBuilder("texture-unit");
|
InstallAttributeBuilder<TextureUnitBuilder> textureUnitBuilder("texture-unit");
|
||||||
|
|
||||||
typedef map<string, ref_ptr<Program> > ProgramMap;
|
// Shader key, used both for shaders with relative and absolute names
|
||||||
|
typedef pair<string, Shader::Type> ShaderKey;
|
||||||
|
|
||||||
|
struct ProgramKey
|
||||||
|
{
|
||||||
|
typedef pair<string, int> AttribKey;
|
||||||
|
osgDB::FilePathList paths;
|
||||||
|
vector<ShaderKey> shaders;
|
||||||
|
vector<AttribKey> 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<ProgramKey, ref_ptr<Program>,
|
||||||
|
boost::hash<ProgramKey>, ProgramKey::EqualTo>
|
||||||
|
ProgramMap;
|
||||||
ProgramMap programMap;
|
ProgramMap programMap;
|
||||||
|
|
||||||
typedef map<string, ref_ptr<Shader> > ShaderMap;
|
typedef tr1::unordered_map<ShaderKey, ref_ptr<Shader>, boost::hash<ShaderKey> >
|
||||||
|
ShaderMap;
|
||||||
ShaderMap shaderMap;
|
ShaderMap shaderMap;
|
||||||
|
|
||||||
void reload_shaders()
|
void reload_shaders()
|
||||||
@@ -550,7 +593,7 @@ void reload_shaders()
|
|||||||
for(ShaderMap::iterator sitr = shaderMap.begin(); sitr != shaderMap.end(); ++sitr)
|
for(ShaderMap::iterator sitr = shaderMap.begin(); sitr != shaderMap.end(); ++sitr)
|
||||||
{
|
{
|
||||||
Shader *shader = sitr->second.get();
|
Shader *shader = sitr->second.get();
|
||||||
string fileName = osgDB::findDataFile(sitr->first);
|
string fileName = osgDB::findDataFile(sitr->first.first);
|
||||||
if (!fileName.empty()) {
|
if (!fileName.empty()) {
|
||||||
shader->loadShaderSourceFromFile(fileName);
|
shader->loadShaderSourceFromFile(fileName);
|
||||||
}
|
}
|
||||||
@@ -568,34 +611,47 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
|
|||||||
const osgDB::ReaderWriter::Options*
|
const osgDB::ReaderWriter::Options*
|
||||||
options)
|
options)
|
||||||
{
|
{
|
||||||
|
using namespace boost;
|
||||||
if (!isAttributeActive(effect, prop))
|
if (!isAttributeActive(effect, prop))
|
||||||
return;
|
return;
|
||||||
PropertyList pVertShaders = prop->getChildren("vertex-shader");
|
PropertyList pVertShaders = prop->getChildren("vertex-shader");
|
||||||
PropertyList pFragShaders = prop->getChildren("fragment-shader");
|
PropertyList pFragShaders = prop->getChildren("fragment-shader");
|
||||||
string programKey;
|
PropertyList pAttributes = prop->getChildren("attribute");
|
||||||
|
ProgramKey prgKey;
|
||||||
for (PropertyList::iterator itr = pVertShaders.begin(),
|
for (PropertyList::iterator itr = pVertShaders.begin(),
|
||||||
e = pVertShaders.end();
|
e = pVertShaders.end();
|
||||||
itr != e;
|
itr != e;
|
||||||
++itr)
|
++itr)
|
||||||
{
|
prgKey.shaders.push_back(ShaderKey((*itr)->getStringValue(),
|
||||||
programKey += (*itr)->getStringValue();
|
Shader::VERTEX));
|
||||||
programKey += ";";
|
|
||||||
}
|
|
||||||
for (PropertyList::iterator itr = pFragShaders.begin(),
|
for (PropertyList::iterator itr = pFragShaders.begin(),
|
||||||
e = pFragShaders.end();
|
e = pFragShaders.end();
|
||||||
itr != e;
|
itr != e;
|
||||||
++itr)
|
++itr)
|
||||||
{
|
prgKey.shaders.push_back(ShaderKey((*itr)->getStringValue(),
|
||||||
programKey += (*itr)->getStringValue();
|
Shader::FRAGMENT));
|
||||||
programKey += ";";
|
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<int>()));
|
||||||
}
|
}
|
||||||
|
if (options)
|
||||||
|
prgKey.paths = options->getDatabasePathList();
|
||||||
Program* program = 0;
|
Program* program = 0;
|
||||||
ProgramMap::iterator pitr = programMap.find(programKey);
|
ProgramMap::iterator pitr = programMap.find(prgKey);
|
||||||
if (pitr != programMap.end()) {
|
if (pitr != programMap.end()) {
|
||||||
program = pitr->second.get();
|
program = pitr->second.get();
|
||||||
} else {
|
} else {
|
||||||
program = new Program;
|
program = new Program;
|
||||||
program->setName(programKey);
|
|
||||||
// Add vertex shaders, then fragment shaders
|
// Add vertex shaders, then fragment shaders
|
||||||
PropertyList& pvec = pVertShaders;
|
PropertyList& pvec = pVertShaders;
|
||||||
Shader::Type stype = Shader::VERTEX;
|
Shader::Type stype = Shader::VERTEX;
|
||||||
@@ -604,24 +660,29 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
|
|||||||
nameItr != e;
|
nameItr != e;
|
||||||
++nameItr) {
|
++nameItr) {
|
||||||
string shaderName = (*nameItr)->getStringValue();
|
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()) {
|
if (sitr != shaderMap.end()) {
|
||||||
program->addShader(sitr->second.get());
|
program->addShader(sitr->second.get());
|
||||||
} else {
|
} else {
|
||||||
string fileName = osgDB::findDataFile(shaderName, options);
|
ref_ptr<Shader> shader = new Shader(stype);
|
||||||
if (!fileName.empty()) {
|
if (shader->loadShaderSourceFromFile(fileName)) {
|
||||||
ref_ptr<Shader> shader = new Shader(stype);
|
program->addShader(shader.get());
|
||||||
if (shader->loadShaderSourceFromFile(fileName)) {
|
shaderMap.insert(ShaderMap::value_type(skey, shader));
|
||||||
program->addShader(shader.get());
|
|
||||||
shaderMap.insert(make_pair(shaderName, shader));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pvec = pFragShaders;
|
pvec = pFragShaders;
|
||||||
stype = Shader::FRAGMENT;
|
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);
|
pass->setAttributeAndModes(program);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user