Introduced new shader composition approach that utilizes #pragma requires(), #pragma import_defines() and #ifdef in GLSL to enable multiple different versions of shaders based

on defines passed in from osg::StateSet::setDefine(..).



git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14681 16af8721-9629-0410-8352-f15c8da7e697
This commit is contained in:
Robert Osfield
2015-02-10 17:04:02 +00:00
parent bb637e73f3
commit b90503fdf5
14 changed files with 910 additions and 175 deletions

View File

@@ -247,8 +247,6 @@ void Program::compileGLObjects( osg::State& state ) const
{
if( isFixedFunction() ) return;
const unsigned int contextID = state.getContextID();
for( unsigned int i=0; i < _shaderList.size(); ++i )
{
_shaderList[i]->compileShader( state );
@@ -256,7 +254,7 @@ void Program::compileGLObjects( osg::State& state ) const
if(!_feedbackout.empty())
{
const PerContextProgram* pcp = getPCP(contextID);
const PerContextProgram* pcp = getPCP(state);
const GLExtensions* extensions = state.get<GLExtensions>();
unsigned int numfeedback = _feedbackout.size();
@@ -272,7 +270,7 @@ void Program::compileGLObjects( osg::State& state ) const
extensions->glTransformFeedbackVaryings( pcp->getHandle(), numfeedback, varyings, _feedbackmode);
delete [] varyings;
}
getPCP( contextID )->linkProgram(state);
getPCP( state )->linkProgram(state);
}
void Program::setThreadSafeRefUnref(bool threadSafe)
@@ -292,6 +290,20 @@ void Program::dirtyProgram()
{
if( _pcpList[cxt].valid() ) _pcpList[cxt]->requestLink();
}
// update list of defines required.
_shaderDefines.clear();
for(ShaderList::iterator itr = _shaderList.begin();
itr != _shaderList.end();
++itr)
{
Shader* shader = itr->get();
ShaderDefines& sd = shader->getShaderDefines();
_shaderDefines.insert(sd.begin(), sd.end());
ShaderDefines& sr = shader->getShaderRequirements();
_shaderDefines.insert(sr.begin(), sr.end());
}
}
@@ -376,14 +388,17 @@ void Program::setParameter( GLenum pname, GLint value )
{
switch( pname )
{
case GL_GEOMETRY_VERTICES_OUT:
case GL_GEOMETRY_VERTICES_OUT_EXT:
_geometryVerticesOut = value;
dirtyProgram();
break;
case GL_GEOMETRY_INPUT_TYPE:
case GL_GEOMETRY_INPUT_TYPE_EXT:
_geometryInputType = value;
dirtyProgram(); // needed?
break;
case GL_GEOMETRY_OUTPUT_TYPE:
case GL_GEOMETRY_OUTPUT_TYPE_EXT:
_geometryOutputType = value;
//dirtyProgram(); // needed?
@@ -401,9 +416,15 @@ GLint Program::getParameter( GLenum pname ) const
{
switch( pname )
{
case GL_GEOMETRY_VERTICES_OUT_EXT: return _geometryVerticesOut;
case GL_GEOMETRY_INPUT_TYPE_EXT: return _geometryInputType;
case GL_GEOMETRY_OUTPUT_TYPE_EXT: return _geometryOutputType;
case GL_GEOMETRY_VERTICES_OUT:
case GL_GEOMETRY_VERTICES_OUT_EXT:
return _geometryVerticesOut;
case GL_GEOMETRY_INPUT_TYPE:
case GL_GEOMETRY_INPUT_TYPE_EXT:
return _geometryInputType;
case GL_GEOMETRY_OUTPUT_TYPE:
case GL_GEOMETRY_OUTPUT_TYPE_EXT:
return _geometryOutputType;
}
OSG_WARN << "getParameter invalid param " << pname << std::endl;
return 0;
@@ -464,7 +485,6 @@ void Program::removeBindUniformBlock(const std::string& name)
#include <iostream>
void Program::apply( osg::State& state ) const
{
const unsigned int contextID = state.getContextID();
const GLExtensions* extensions = state.get<GLExtensions>();
if( ! extensions->isGlslSupported ) return;
@@ -475,7 +495,66 @@ void Program::apply( osg::State& state ) const
return;
}
PerContextProgram* pcp = getPCP( contextID );
#if 0
State::DefineMap& defMap = state.getDefineMap();
OSG_NOTICE<<"Program::apply() defMap.changed="<<defMap.changed<<std::endl;
for(State::DefineMap::DefineStackMap::const_iterator itr = defMap.map.begin();
itr != defMap.map.end();
++itr)
{
const State::DefineStack& ds = itr->second;
OSG_NOTICE<<" define ["<<itr->first<<"] ds.changed="<<ds.changed<<" ";
if (ds.defineVec.empty())
{
OSG_NOTICE<<" DefineStack empty "<<std::endl;
}
else
{
const StateSet::DefinePair& dp = ds.defineVec.back();
OSG_NOTICE<<" value = ["<<dp.first<<"], overridevalue = ["<<dp.second<<"]"<< std::endl;
}
}
if (defMap.changed) defMap.updateCurrentDefines();
std::string shaderDefineStr = state.getDefineString(getShaderDefines());
OSG_NOTICE<<"TailoredShaderDefineStr={"<<std::endl;
OSG_NOTICE<<shaderDefineStr;
OSG_NOTICE<<"}"<<std::endl;
shaderDefineStr.clear();
const StateSet::DefineList& currentDefines = defMap.currentDefines;
for(StateSet::DefineList::const_iterator itr = currentDefines.begin();
itr != currentDefines.end();
++itr)
{
const StateSet::DefinePair& dp = itr->second;
shaderDefineStr += "#define ";
shaderDefineStr += itr->first;
if (itr->second.first.empty())
{
shaderDefineStr += "\n";
}
else
{
shaderDefineStr += " ";
shaderDefineStr += itr->second.first;
shaderDefineStr += "\n";
}
OSG_NOTICE<<" active-define = ["<<itr->first<<"], value="<<itr->second.first<<", overridevalue = ["<<itr->second.second<<"]"<< std::endl;
}
OSG_NOTICE<<"FullShaderDefineStr={"<<std::endl;
OSG_NOTICE<<shaderDefineStr;
OSG_NOTICE<<"}"<<std::endl;
#endif
PerContextProgram* pcp = getPCP( state );
if( pcp->needsLink() ) compileGLObjects( state );
if( pcp->isLinked() )
{
@@ -497,20 +576,102 @@ void Program::apply( osg::State& state ) const
}
Program::PerContextProgram* Program::getPCP(unsigned int contextID) const
Program::ProgramObjects::ProgramObjects(const osg::Program* program, unsigned int contextID):
_contextID(contextID),
_program(program)
{
if( ! _pcpList[contextID].valid() )
{
_pcpList[contextID] = new PerContextProgram( this, contextID );
}
// attach all PCSs to this new PCP
for( unsigned int i=0; i < _shaderList.size(); ++i )
Program::PerContextProgram* Program::ProgramObjects::getPCP(const std::string& defineStr) const
{
for(PerContextPrograms::const_iterator itr = _perContextPrograms.begin();
itr != _perContextPrograms.end();
++itr)
{
if ((*itr)->getDefineString()==defineStr)
{
_pcpList[contextID]->addShaderToAttach( _shaderList[i].get() );
// OSG_NOTICE<<"Returning PCP "<<itr->get()<<" DefineString = "<<(*itr)->getDefineString()<<std::endl;
return itr->get();
}
}
return 0;
}
return _pcpList[contextID].get();
Program::PerContextProgram* Program::ProgramObjects::createPerContextProgram(const std::string& defineStr)
{
Program::PerContextProgram* pcp = new PerContextProgram( _program, _contextID );
_perContextPrograms.push_back( pcp );
pcp->setDefineString(defineStr);
// OSG_NOTICE<<"Creating PCP "<<pcp<<" PCP DefineString = ["<<pcp->getDefineString()<<"]"<<std::endl;
return pcp;
}
void Program::ProgramObjects::requestLink()
{
for(PerContextPrograms::iterator itr = _perContextPrograms.begin();
itr != _perContextPrograms.end();
++itr)
{
(*itr)->requestLink();
}
}
void Program::ProgramObjects::addShaderToAttach(Shader* shader)
{
for(PerContextPrograms::iterator itr = _perContextPrograms.begin();
itr != _perContextPrograms.end();
++itr)
{
(*itr)->addShaderToAttach(shader);
}
}
void Program::ProgramObjects::addShaderToDetach(Shader* shader)
{
for(PerContextPrograms::iterator itr = _perContextPrograms.begin();
itr != _perContextPrograms.end();
++itr)
{
(*itr)->addShaderToDetach(shader);
}
}
bool Program::ProgramObjects::getGlProgramInfoLog(std::string& log) const
{
bool result = false;
for(PerContextPrograms::const_iterator itr = _perContextPrograms.begin();
itr != _perContextPrograms.end();
++itr)
{
result = (*itr)->getInfoLog( log ) | result;
}
return result;
}
Program::PerContextProgram* Program::getPCP(State& state) const
{
unsigned int contextID = state.getContextID();
const std::string defineStr = state.getDefineString(getShaderDefines());
if( ! _pcpList[contextID].valid() )
{
_pcpList[contextID] = new ProgramObjects( this, contextID );
}
Program::PerContextProgram* pcp = _pcpList[contextID]->getPCP(defineStr);
if (pcp) return pcp;
pcp = _pcpList[contextID]->createPerContextProgram(defineStr);
// attach all PCSs to this new PCP
for( unsigned int i=0; i < _shaderList.size(); ++i )
{
pcp->addShaderToAttach( _shaderList[i].get() );
}
return pcp;
}
@@ -525,9 +686,11 @@ bool Program::isFixedFunction() const
bool Program::getGlProgramInfoLog(unsigned int contextID, std::string& log) const
{
return getPCP( contextID )->getInfoLog( log );
if (contextID<_pcpList.size()) return (_pcpList[ contextID ])->getGlProgramInfoLog( log );
else return false;
}
#if 0
const Program::ActiveUniformMap& Program::getActiveUniforms(unsigned int contextID) const
{
return getPCP( contextID )->getActiveUniforms();
@@ -542,6 +705,7 @@ const Program::UniformBlockMap& Program::getUniformBlocks(unsigned contextID) co
{
return getPCP( contextID )->getUniformBlocks();
}
#endif
///////////////////////////////////////////////////////////////////////////
// osg::Program::PerContextProgram
@@ -603,19 +767,20 @@ void Program::PerContextProgram::linkProgram(osg::State& state)
_loadedBinary = _isLinked = (linked == GL_TRUE);
}
if (!_loadedBinary && _extensions->isGeometryShader4Supported)
{
_extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_VERTICES_OUT_EXT, _program->_geometryVerticesOut );
_extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_INPUT_TYPE_EXT, _program->_geometryInputType );
_extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_OUTPUT_TYPE_EXT, _program->_geometryOutputType );
}
if (!_loadedBinary)
{
if (_extensions->isGeometryShader4Supported)
{
_extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_VERTICES_OUT_EXT, _program->_geometryVerticesOut );
_extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_INPUT_TYPE_EXT, _program->_geometryInputType );
_extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_OUTPUT_TYPE_EXT, _program->_geometryOutputType );
}
// Detach removed shaders
for( unsigned int i=0; i < _shadersToDetach.size(); ++i )
{
_shadersToDetach[i]->detachShader( _contextID, _glProgramHandle );
Shader::PerContextShader* pcs = _shadersToDetach[i]->getPCS(state);
if (pcs) _extensions->glDetachShader( _glProgramHandle, pcs->getHandle() );
}
}
_shadersToDetach.clear();
@@ -625,9 +790,12 @@ void Program::PerContextProgram::linkProgram(osg::State& state)
// Attach new shaders
for( unsigned int i=0; i < _shadersToAttach.size(); ++i )
{
_shadersToAttach[i]->attachShader( _contextID, _glProgramHandle );
Shader::PerContextShader* pcs = _shadersToAttach[i]->getPCS(state);
if (pcs) _extensions->glAttachShader( _glProgramHandle, pcs->getHandle() );
}
}
//state.checkGLErrors("After attaching shaders.");
_shadersToAttach.clear();
_uniformInfoMap.clear();
@@ -909,6 +1077,10 @@ void Program::PerContextProgram::linkProgram(osg::State& state)
delete [] name;
}
OSG_INFO << std::endl;
//state.checkGLErrors("After Program::PerContextProgram::linkProgram.");
}
bool Program::PerContextProgram::validateProgram()