From Mike Weiblen,
"updates for GLSL core integration: Code compiles and runs on win32. Basic functionality of Program and Shader in place. Program derived from StateAttribute. Uniform value propagation is not yet functional (in development) Includes some patches by Nathan Cournia. includes example testcase to demo use of new classes."
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
|
||||
* Copyright (C) 2003-2005 3Dlabs Inc. Ltd.
|
||||
* Copyright (C) 2004-2005 Nathan Cournia
|
||||
*
|
||||
* This application is open source and may be redistributed and/or modified
|
||||
* freely and without restriction, both in commericial and non commericial
|
||||
@@ -11,8 +12,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* file: src/osg/Program.cpp
|
||||
* author: Mike Weiblen 2005-02-20
|
||||
/* file: src/osg/Shader.cpp
|
||||
* author: Mike Weiblen 2005-03-23
|
||||
*/
|
||||
|
||||
// NOTICE: This code is CLOSED during construction and/or renovation!
|
||||
@@ -39,12 +40,61 @@
|
||||
|
||||
using namespace osg;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// static cache of glShaders flagged for deletion, which will actually
|
||||
// be deleted in the correct GL context.
|
||||
|
||||
typedef std::list<GLuint> GlShaderHandleList;
|
||||
typedef std::map<unsigned int, GlShaderHandleList> DeletedGlShaderCache;
|
||||
|
||||
static OpenThreads::Mutex s_mutex_deletedGL2ShaderCache;
|
||||
static OpenThreads::Mutex s_mutex_deletedGlShaderCache;
|
||||
static DeletedGlShaderCache s_deletedGlShaderCache;
|
||||
|
||||
void Shader::deleteGlShader(unsigned int contextID, GLuint shader)
|
||||
{
|
||||
if( shader )
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlShaderCache);
|
||||
|
||||
// add glShader to the cache for the appropriate context.
|
||||
s_deletedGlShaderCache[contextID].push_back(shader);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::flushDeletedGlShaders(unsigned int contextID,double /*currentTime*/, double& availableTime)
|
||||
{
|
||||
// if no time available don't try to flush objects.
|
||||
if (availableTime<=0.0) return;
|
||||
|
||||
const GL2Extensions* extensions = GL2Extensions::Get(contextID,true);
|
||||
if( ! extensions->isGlslSupported() ) return;
|
||||
|
||||
const osg::Timer& timer = *osg::Timer::instance();
|
||||
osg::Timer_t start_tick = timer.tick();
|
||||
double elapsedTime = 0.0;
|
||||
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlShaderCache);
|
||||
|
||||
DeletedGlShaderCache::iterator citr = s_deletedGlShaderCache.find(contextID);
|
||||
if( citr != s_deletedGlShaderCache.end() )
|
||||
{
|
||||
GlShaderHandleList& pList = citr->second;
|
||||
for(GlShaderHandleList::iterator titr=pList.begin();
|
||||
titr!=pList.end() && elapsedTime<availableTime;
|
||||
)
|
||||
{
|
||||
extensions->glDeleteShader( *titr );
|
||||
titr = pList.erase( titr );
|
||||
elapsedTime = timer.delta_s(start_tick,timer.tick());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
availableTime -= elapsedTime;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// osg::Shader
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -55,54 +105,49 @@ Shader::Shader(Type type, const char* sourceText) :
|
||||
setShaderSource( sourceText );
|
||||
}
|
||||
|
||||
Shader::Shader(const Shader& rhs, const osg::CopyOp& copyop):
|
||||
Object( rhs, copyop ),
|
||||
_type(rhs._type)
|
||||
Shader::Shader() :
|
||||
_type(VERTEX)
|
||||
{
|
||||
// TODO this default constructor is inappropriate for the Shader class.
|
||||
// It exists for now because it is required by META_OBject
|
||||
osg::notify(osg::FATAL) << "how got here?" << std::endl;
|
||||
}
|
||||
|
||||
Shader::Shader(const Shader& rhs, const osg::CopyOp& copyop):
|
||||
osg::Object( rhs, copyop ),
|
||||
_type(rhs._type),
|
||||
_name(rhs._name),
|
||||
_shaderSource(rhs._shaderSource)
|
||||
{
|
||||
/*TODO*/
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
/*TODO*/
|
||||
}
|
||||
|
||||
|
||||
int Shader::compare(const Shader& rhs) const
|
||||
{
|
||||
if( this == &rhs ) return 0;
|
||||
|
||||
if( getComment() < rhs.getComment() ) return -1;
|
||||
if( rhs.getComment() < getComment() ) return 1;
|
||||
if( getType() < rhs.getType() ) return -1;
|
||||
if( rhs.getType() < getType() ) return 1;
|
||||
|
||||
if( getName() < rhs.getName() ) return -1;
|
||||
if( rhs.getName() < getName() ) return 1;
|
||||
|
||||
if( getShaderSource() < rhs.getShaderSource() ) return -1;
|
||||
if( rhs.getShaderSource() < getShaderSource() ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Shader::dirtyShader()
|
||||
{
|
||||
// mark each PCSO as needing a recompile
|
||||
for( unsigned int cxt=0; cxt < _pcsoList.size(); ++cxt )
|
||||
{
|
||||
if( ! _pcsoList[cxt] ) continue;
|
||||
|
||||
PerContextShaderObj* pcso = _pcsoList[cxt].get();
|
||||
pcso->markAsDirty();
|
||||
}
|
||||
|
||||
// also mark-as-dirty the Programs we're attach to
|
||||
for( unsigned int i=0; i < _programList.size(); ++i )
|
||||
{
|
||||
_programList[i]->dirtyProgram();
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::setShaderSource( const char* sourceText )
|
||||
{
|
||||
_shaderSource = ( sourceText ? sourceText : "" );
|
||||
dirtyShader();
|
||||
}
|
||||
|
||||
|
||||
bool Shader::loadShaderSourceFromFile( const char* fileName )
|
||||
{
|
||||
std::ifstream sourceFile;
|
||||
@@ -143,97 +188,138 @@ const char* Shader::getTypename() const
|
||||
|
||||
void Shader::compileShader( unsigned int contextID ) const
|
||||
{
|
||||
PerContextShaderObj* pcso = getPCSO( contextID );
|
||||
if( pcso->isDirty() ) pcso->compileShader();
|
||||
getPCS( contextID )->compileShader();
|
||||
}
|
||||
|
||||
|
||||
Shader::PerContextShaderObj* Shader::getPCSO(unsigned int contextID) const
|
||||
Shader::PerContextShader* Shader::getPCS(unsigned int contextID) const
|
||||
{
|
||||
if( ! _pcsoList[contextID].valid() )
|
||||
if( ! _pcsList[contextID].valid() )
|
||||
{
|
||||
_pcsoList[contextID] = new PerContextShaderObj( this, contextID );
|
||||
_pcsList[contextID] = new PerContextShader( this, contextID );
|
||||
}
|
||||
return _pcsoList[contextID].get();
|
||||
return _pcsList[contextID].get();
|
||||
}
|
||||
|
||||
|
||||
void Shader::attachShader(unsigned int contextID, GLuint program) const
|
||||
{
|
||||
getPCSO( contextID )->attachShader( program );
|
||||
getPCS( contextID )->attachShader( program );
|
||||
}
|
||||
|
||||
|
||||
void Shader::addProgObjRef( Program* program )
|
||||
void Shader::getGlShaderInfoLog(unsigned int contextID, std::string& log) const
|
||||
{
|
||||
_programList.push_back( program );
|
||||
getPCS( contextID )->getInfoLog( log );
|
||||
}
|
||||
|
||||
|
||||
void Shader::deleteShader(unsigned int contextID, GLuint shader)
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// A Shader stores pointers to the osg::Programs to which it is attached,
|
||||
// so that if the Shader is marked for recompilation with
|
||||
// Shader::dirtyShader(), the upstream Program can be marked for relinking.
|
||||
// _programSet does not use ref_ptrs, as that would cause a cyclical
|
||||
// dependency, and neither the Program nor the Shader would be deleted.
|
||||
|
||||
bool Shader::addProgramRef( Program* program )
|
||||
{
|
||||
if( shader )
|
||||
ProgramSet::iterator itr = _programSet.find(program);
|
||||
if( itr != _programSet.end() ) return false;
|
||||
|
||||
_programSet.insert( program );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Shader::removeProgramRef( Program* program )
|
||||
{
|
||||
ProgramSet::iterator itr = _programSet.find(program);
|
||||
if( itr == _programSet.end() ) return false;
|
||||
|
||||
_programSet.erase( itr );
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shader::dirtyShader()
|
||||
{
|
||||
// Mark our PCSs as needing recompilation.
|
||||
for( unsigned int cxt=0; cxt < _pcsList.size(); ++cxt )
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGL2ShaderCache);
|
||||
if( _pcsList[cxt].valid() ) _pcsList[cxt]->requestCompile();
|
||||
}
|
||||
|
||||
// add shader to the cache for the appropriate context.
|
||||
s_deletedGlShaderCache[contextID].push_back(shader);
|
||||
// Also mark Programs that depend on us as needing relink.
|
||||
for( ProgramSet::iterator itr = _programSet.begin();
|
||||
itr != _programSet.end(); ++itr )
|
||||
{
|
||||
(*itr)->dirtyProgram();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// osg::Shader::PerContextShaderObj
|
||||
// PCSO is the OSG abstraction of the per-context glShader
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// osg::Shader::PerContextShader
|
||||
// PCS is the OSG abstraction of the per-context glShader
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Shader::PerContextShaderObj::PerContextShaderObj(const Shader* shader, unsigned int contextID) :
|
||||
Shader::PerContextShader::PerContextShader(const Shader* shader, unsigned int contextID) :
|
||||
osg::Referenced(),
|
||||
_contextID( contextID )
|
||||
{
|
||||
_shader = shader;
|
||||
_extensions = GL2Extensions::Get( _contextID, true );
|
||||
_glShaderHandle = _extensions->glCreateShader( shader->getType() );
|
||||
markAsDirty();
|
||||
requestCompile();
|
||||
}
|
||||
|
||||
Shader::PerContextShaderObj::PerContextShaderObj(const PerContextShaderObj& rhs) :
|
||||
osg::Referenced(),
|
||||
_contextID( rhs._contextID )
|
||||
|
||||
Shader::PerContextShader::~PerContextShader()
|
||||
{
|
||||
_shader = rhs._shader;
|
||||
_extensions = rhs._extensions;
|
||||
_glShaderHandle = rhs._glShaderHandle;
|
||||
_dirty = rhs._dirty;
|
||||
Shader::deleteGlShader( _contextID, _glShaderHandle );
|
||||
}
|
||||
|
||||
Shader::PerContextShaderObj::~PerContextShaderObj()
|
||||
|
||||
void Shader::PerContextShader::requestCompile()
|
||||
{
|
||||
_needsCompile = true;
|
||||
_isCompiled = false;
|
||||
}
|
||||
|
||||
void Shader::PerContextShaderObj::compileShader()
|
||||
|
||||
void Shader::PerContextShader::compileShader()
|
||||
{
|
||||
if( ! _needsCompile ) return;
|
||||
_needsCompile = false;
|
||||
|
||||
GLint compiled;
|
||||
const char* sourceText = _shader->getShaderSource().c_str();
|
||||
|
||||
_extensions->glShaderSource( _glShaderHandle, 1, &sourceText, NULL );
|
||||
_extensions->glCompileShader( _glShaderHandle );
|
||||
_extensions->glGetShaderiv( _glShaderHandle, GL_COMPILE_STATUS, &compiled );
|
||||
_dirty = (compiled == 0);
|
||||
|
||||
if( _dirty )
|
||||
_isCompiled = (compiled == GL_TRUE);
|
||||
if( ! _isCompiled )
|
||||
{
|
||||
// _still_ dirty, something went wrong
|
||||
// compile failed
|
||||
std::string infoLog;
|
||||
_extensions->getShaderInfoLog( _glShaderHandle, infoLog );
|
||||
getInfoLog( infoLog );
|
||||
osg::notify(osg::WARN) << _shader->getTypename() <<
|
||||
" glCompileShader FAILED:\n" << infoLog << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::PerContextShaderObj::attachShader(GLuint program) const
|
||||
void Shader::PerContextShader::getInfoLog( std::string& infoLog ) const
|
||||
{
|
||||
_extensions->getShaderInfoLog( _glShaderHandle, infoLog );
|
||||
}
|
||||
|
||||
void Shader::PerContextShader::attachShader(GLuint program) const
|
||||
{
|
||||
_extensions->glAttachShader( program, _glShaderHandle );
|
||||
}
|
||||
|
||||
void Shader::PerContextShader::detachShader(GLuint program) const
|
||||
{
|
||||
_extensions->glDetachShader( program, _glShaderHandle );
|
||||
}
|
||||
|
||||
/*EOF*/
|
||||
|
||||
Reference in New Issue
Block a user