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
|
||||
@@ -12,7 +13,7 @@
|
||||
*/
|
||||
|
||||
/* file: src/osg/Program.cpp
|
||||
* author: Mike Weiblen 2005-02-20
|
||||
* author: Mike Weiblen 2005-03-23
|
||||
*/
|
||||
|
||||
// NOTICE: This code is CLOSED during construction and/or renovation!
|
||||
@@ -28,11 +29,11 @@
|
||||
#include <osg/Notify>
|
||||
#include <osg/State>
|
||||
#include <osg/Timer>
|
||||
#include <osg/FrameStamp>
|
||||
#include <osg/buffered_value>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Program>
|
||||
#include <osg/Shader>
|
||||
#include <osg/Uniform>
|
||||
#include <osg/GLExtensions>
|
||||
|
||||
#include <OpenThreads/ScopedLock>
|
||||
@@ -41,15 +42,7 @@
|
||||
using namespace osg;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// static cache of GL objects flagged for deletion, which will actually
|
||||
// be deleted in the correct GL context.
|
||||
|
||||
typedef std::list<GLuint> GlProgramHandleList;
|
||||
typedef std::map<unsigned int, GlProgramHandleList> DeletedGlProgramCache;
|
||||
|
||||
static OpenThreads::Mutex s_mutex_deletedGL2ObjectCache;
|
||||
static DeletedGlProgramCache s_deletedGlProgramCache;
|
||||
|
||||
// Extension function pointers for OpenGL v2.0
|
||||
|
||||
GL2Extensions::GL2Extensions()
|
||||
{
|
||||
@@ -1855,19 +1848,28 @@ bool GL2Extensions::getShaderInfoLog( GLuint shader, std::string& result ) const
|
||||
return (strLen > 0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// static cache of glPrograms flagged for deletion, which will actually
|
||||
// be deleted in the correct GL context.
|
||||
|
||||
void Program::deleteProgram(unsigned int contextID, GLuint program)
|
||||
typedef std::list<GLuint> GlProgramHandleList;
|
||||
typedef std::map<unsigned int, GlProgramHandleList> DeletedGlProgramCache;
|
||||
|
||||
static OpenThreads::Mutex s_mutex_deletedGlProgramCache;
|
||||
static DeletedGlProgramCache s_deletedGlProgramCache;
|
||||
|
||||
void Program::deleteGlProgram(unsigned int contextID, GLuint program)
|
||||
{
|
||||
if( program )
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGL2ObjectCache);
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlProgramCache);
|
||||
|
||||
// add program to the cache for the appropriate context.
|
||||
// add glProgram to the cache for the appropriate context.
|
||||
s_deletedGlProgramCache[contextID].push_back(program);
|
||||
}
|
||||
}
|
||||
|
||||
void Program::flushDeletedGlslObjects(unsigned int contextID,double /*currentTime*/, double& availableTime)
|
||||
void Program::flushDeletedGlPrograms(unsigned int contextID,double /*currentTime*/, double& availableTime)
|
||||
{
|
||||
// if no time available don't try to flush objects.
|
||||
if (availableTime<=0.0) return;
|
||||
@@ -1880,7 +1882,7 @@ void Program::flushDeletedGlslObjects(unsigned int contextID,double /*currentTim
|
||||
double elapsedTime = 0.0;
|
||||
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGL2ObjectCache);
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlProgramCache);
|
||||
|
||||
DeletedGlProgramCache::iterator citr = s_deletedGlProgramCache.find(contextID);
|
||||
if( citr != s_deletedGlProgramCache.end() )
|
||||
@@ -1912,7 +1914,7 @@ Program::Program()
|
||||
|
||||
|
||||
Program::Program(const Program& rhs, const osg::CopyOp& copyop):
|
||||
osg::Object(rhs, copyop)
|
||||
osg::StateAttribute(rhs, copyop)
|
||||
{
|
||||
osg::notify(osg::FATAL) << "how got here?" << std::endl;
|
||||
}
|
||||
@@ -1920,19 +1922,15 @@ Program::Program(const Program& rhs, const osg::CopyOp& copyop):
|
||||
|
||||
Program::~Program()
|
||||
{
|
||||
for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt )
|
||||
// inform any attached Shaders that we're going away
|
||||
for( unsigned int i=0; i < _shaderList.size(); ++i )
|
||||
{
|
||||
if( ! _pcpoList[cxt] ) continue;
|
||||
|
||||
PerContextProgObj* pcpo = _pcpoList[cxt].get();
|
||||
|
||||
deleteProgram( cxt, pcpo->getHandle() );
|
||||
// TODO add shader objects to delete list.
|
||||
_pcpoList[cxt] = 0;
|
||||
_shaderList[i]->removeProgramRef( this );
|
||||
}
|
||||
}
|
||||
|
||||
int Program::compare(const osg::Program& sa) const
|
||||
|
||||
int Program::compare(const osg::StateAttribute& sa) const
|
||||
{
|
||||
// check the types are equal and then create the rhs variable
|
||||
// used by the COMPARE_StateAttribute_Paramter macro's below.
|
||||
@@ -1941,8 +1939,8 @@ int Program::compare(const osg::Program& sa) const
|
||||
if( _shaderList.size() < rhs._shaderList.size() ) return -1;
|
||||
if( rhs._shaderList.size() < _shaderList.size() ) return 1;
|
||||
|
||||
if( getComment() < rhs.getComment() ) return -1;
|
||||
if( rhs.getComment() < getComment() ) return 1;
|
||||
if( getName() < rhs.getName() ) return -1;
|
||||
if( rhs.getName() < getName() ) return 1;
|
||||
|
||||
ShaderList::const_iterator litr=_shaderList.begin();
|
||||
ShaderList::const_iterator ritr=rhs._shaderList.begin();
|
||||
@@ -1954,73 +1952,79 @@ int Program::compare(const osg::Program& sa) const
|
||||
if (result!=0) return result;
|
||||
}
|
||||
|
||||
// TODO should Program comparison depend on the values of
|
||||
// its uniforms? I'd assert not.
|
||||
|
||||
return 0; // passed all the above comparison macro's, must be equal.
|
||||
}
|
||||
|
||||
|
||||
void Program::compileGLObjects( osg::State& state ) const
|
||||
{
|
||||
if( _shaderList.empty() ) return;
|
||||
if( isFixedFunction() ) return;
|
||||
|
||||
const unsigned int contextID = state.getContextID();
|
||||
const GL2Extensions* extensions = GL2Extensions::Get(contextID,true);
|
||||
if( ! extensions->isGlslSupported() )
|
||||
{
|
||||
osg::notify(osg::WARN) << "GLSL not supported by OpenGL driver" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
PerContextProgObj* pcpo = getPCPO( contextID );
|
||||
for( unsigned int i=0; i < _shaderList.size() ; ++i )
|
||||
for( unsigned int i=0; i < _shaderList.size(); ++i )
|
||||
{
|
||||
_shaderList[i]->compileShader( contextID );
|
||||
}
|
||||
pcpo->linkProgram();
|
||||
|
||||
// TODO pcpo->releaseActiveUniformList();
|
||||
// TODO pcpo->buildActiveUniformList;
|
||||
|
||||
// TODO regenerate pcpo->_activeAttribList;
|
||||
getPCP( contextID )->linkProgram();
|
||||
}
|
||||
|
||||
|
||||
void Program::dirtyProgram()
|
||||
{
|
||||
// mark all PCPOs as needing a relink
|
||||
for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt )
|
||||
// mark our PCPs as needing relink
|
||||
for( unsigned int cxt=0; cxt < _pcpList.size(); ++cxt )
|
||||
{
|
||||
if( ! _pcpoList[cxt] ) continue;
|
||||
|
||||
PerContextProgObj* pcpo = _pcpoList[cxt].get();
|
||||
pcpo->markAsDirty();
|
||||
if( _pcpList[cxt].valid() ) _pcpList[cxt]->requestLink();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Program::dirtyShaders()
|
||||
{
|
||||
// mark all attached Shaders as needing a rebuild
|
||||
for( unsigned int i=0; i < _shaderList.size() ; ++i )
|
||||
{
|
||||
_shaderList[i]->dirtyShader();
|
||||
}
|
||||
}
|
||||
|
||||
void Program::releaseGLObjects(osg::State* state) const
|
||||
{
|
||||
if (!state) const_cast<Program*>(this)->dirtyShaders();
|
||||
else
|
||||
{
|
||||
unsigned int contextID = state->getContextID();
|
||||
const_cast<Program*>(this)->_shaderList[contextID]->dirtyShader();
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
void Program::addShader( Shader* shader )
|
||||
bool Program::addShader( Shader* shader )
|
||||
{
|
||||
// Shader can only be added once to a Program
|
||||
for( unsigned int i=0; i < _shaderList.size(); ++i )
|
||||
{
|
||||
if( shader == _shaderList[i].get() ) return false;
|
||||
}
|
||||
|
||||
shader->addProgramRef( this );
|
||||
_shaderList.push_back( shader );
|
||||
shader->addProgObjRef( this );
|
||||
dirtyProgram();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Program::removeShader( Shader* shader )
|
||||
{
|
||||
// Shader must exist to be removed.
|
||||
for( unsigned int i=0; i < _shaderList.size(); ++i )
|
||||
{
|
||||
if( shader == _shaderList[i].get() )
|
||||
{
|
||||
shader->removeProgramRef( this );
|
||||
_shaderList[i] = 0;
|
||||
dirtyProgram();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Program::bindAttribLocation( GLuint index, const char* name )
|
||||
{
|
||||
// TODO add to binding list
|
||||
dirtyProgram();
|
||||
}
|
||||
|
||||
@@ -2031,44 +2035,55 @@ void Program::apply( osg::State& state ) const
|
||||
const GL2Extensions* extensions = GL2Extensions::Get(contextID,true);
|
||||
if( ! extensions->isGlslSupported() ) return;
|
||||
|
||||
// A Program object having no attached Shaders is a special
|
||||
// case: it indicates that programmable shading is to be disabled,
|
||||
// and thus use GL 1.x "fixed functionality" rendering.
|
||||
if( _shaderList.empty() )
|
||||
if( isFixedFunction() )
|
||||
{
|
||||
extensions->glUseProgram( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
PerContextProgObj* pcpo = getPCPO( contextID );
|
||||
if( pcpo->isDirty() ) compileGLObjects( state );
|
||||
|
||||
if( pcpo->isDirty() )
|
||||
PerContextProgram* pcp = getPCP( contextID );
|
||||
if( pcp->needsLink() ) compileGLObjects( state );
|
||||
if( pcp->isLinked() )
|
||||
{
|
||||
// _still_ dirty, something went wrong
|
||||
extensions->glUseProgram( 0 );
|
||||
pcp->useProgram();
|
||||
pcp->applyUniforms( state );
|
||||
}
|
||||
else
|
||||
{
|
||||
pcpo->useProgram();
|
||||
pcpo->applyUniforms( state );
|
||||
// program not usable, fallback to fixed function.
|
||||
extensions->glUseProgram( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Program::PerContextProgObj* Program::getPCPO(unsigned int contextID) const
|
||||
Program::PerContextProgram* Program::getPCP(unsigned int contextID) const
|
||||
{
|
||||
if( ! _pcpoList[contextID].valid() )
|
||||
if( ! _pcpList[contextID].valid() )
|
||||
{
|
||||
_pcpoList[contextID] = new PerContextProgObj( this, contextID );
|
||||
_pcpList[contextID] = new PerContextProgram( this, contextID );
|
||||
|
||||
// attach all PCSOs to this new PCPO
|
||||
for( unsigned int i=0; i < _shaderList.size() ; ++i )
|
||||
// attach all PCSs to this new PCP
|
||||
for( unsigned int i=0; i < _shaderList.size(); ++i )
|
||||
{
|
||||
_shaderList[i]->attachShader( contextID, _pcpoList[contextID]->getHandle() );
|
||||
_shaderList[i]->attachShader( contextID, _pcpList[contextID]->getHandle() );
|
||||
}
|
||||
}
|
||||
return _pcpoList[contextID].get();
|
||||
return _pcpList[contextID].get();
|
||||
}
|
||||
|
||||
|
||||
bool Program::isFixedFunction() const
|
||||
{
|
||||
// A Program object having no attached Shaders is a special case:
|
||||
// it indicates that programmable shading is to be disabled,
|
||||
// and thus use GL 1.x "fixed functionality" rendering.
|
||||
return _shaderList.empty();
|
||||
}
|
||||
|
||||
|
||||
void Program::getGlProgramInfoLog(unsigned int contextID, std::string& log) const
|
||||
{
|
||||
getPCP( contextID )->getInfoLog( log );
|
||||
}
|
||||
|
||||
|
||||
@@ -2083,67 +2098,69 @@ Program::ActiveUniform::ActiveUniform( const GLchar* name, GLenum type ) :
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// osg::Program::PerContextProgObj
|
||||
// PCPO is an OSG abstraction of the per-context glProgram
|
||||
// osg::Program::PerContextProgram
|
||||
// PCP is an OSG abstraction of the per-context glProgram
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Program::PerContextProgObj::PerContextProgObj(const Program* program, unsigned int contextID ) :
|
||||
Program::PerContextProgram::PerContextProgram(const Program* program, unsigned int contextID ) :
|
||||
osg::Referenced(),
|
||||
_contextID( contextID )
|
||||
{
|
||||
_program = program;
|
||||
_extensions = GL2Extensions::Get( _contextID, true );
|
||||
_glProgramHandle = _extensions->glCreateProgram();
|
||||
markAsDirty();
|
||||
requestLink();
|
||||
}
|
||||
|
||||
Program::PerContextProgObj::PerContextProgObj(const PerContextProgObj& rhs) :
|
||||
osg::Referenced(),
|
||||
_contextID( rhs._contextID )
|
||||
{
|
||||
_program = rhs._program;
|
||||
_extensions = rhs._extensions;
|
||||
_glProgramHandle = rhs._glProgramHandle ;
|
||||
_dirty = rhs._dirty;
|
||||
}
|
||||
|
||||
Program::PerContextProgObj::~PerContextProgObj()
|
||||
Program::PerContextProgram::~PerContextProgram()
|
||||
{
|
||||
Program::deleteGlProgram( _contextID, _glProgramHandle );
|
||||
}
|
||||
|
||||
|
||||
void Program::PerContextProgObj::markAsDirty()
|
||||
void Program::PerContextProgram::requestLink()
|
||||
{
|
||||
// TODO releaseActiveUniformList();
|
||||
_dirty = true;
|
||||
_needsLink = true;
|
||||
_isLinked = false;
|
||||
}
|
||||
|
||||
|
||||
void Program::PerContextProgObj::linkProgram()
|
||||
void Program::PerContextProgram::linkProgram()
|
||||
{
|
||||
if( ! _needsLink ) return;
|
||||
_needsLink = false;
|
||||
|
||||
// TODO for( each itr in binding list )
|
||||
// {
|
||||
// _extensions->glBindAttribLocation( _glProgramHandle, index, name );
|
||||
// }
|
||||
|
||||
GLint linked;
|
||||
|
||||
_extensions->glLinkProgram( _glProgramHandle );
|
||||
_extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked );
|
||||
_dirty = (linked == 0);
|
||||
|
||||
if( _dirty )
|
||||
_isLinked = (linked == GL_TRUE);
|
||||
if( ! _isLinked )
|
||||
{
|
||||
// _still_ dirty, something went wrong
|
||||
// link failed
|
||||
std::string infoLog;
|
||||
_extensions->getProgramInfoLog( _glProgramHandle, infoLog );
|
||||
getInfoLog( infoLog );
|
||||
osg::notify(osg::WARN) << "glLinkProgram FAILED:\n" << infoLog << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Program::PerContextProgram::getInfoLog( std::string& infoLog ) const
|
||||
{
|
||||
_extensions->getProgramInfoLog( _glProgramHandle, infoLog );
|
||||
}
|
||||
|
||||
void Program::PerContextProgObj::useProgram() const
|
||||
void Program::PerContextProgram::useProgram() const
|
||||
{
|
||||
_extensions->glUseProgram( _glProgramHandle );
|
||||
}
|
||||
|
||||
|
||||
void Program::PerContextProgObj::applyUniforms( osg::State& /*state*/ ) const
|
||||
void Program::PerContextProgram::applyUniforms( osg::State& /*state*/ ) const
|
||||
{
|
||||
bool uniformDoesNeedSetting = true;
|
||||
|
||||
@@ -2161,3 +2178,5 @@ void Program::PerContextProgObj::applyUniforms( osg::State& /*state*/ ) const
|
||||
// TODO set the uniform value on the currently active glProgram.
|
||||
}
|
||||
}
|
||||
|
||||
/*EOF*/
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include <set>
|
||||
|
||||
|
||||
using namespace osg;
|
||||
|
||||
// local class to help porting from OSG0.8.x to 0.9.x
|
||||
@@ -113,7 +112,22 @@ StateSet::StateSet(const StateSet& rhs,const CopyOp& copyop):Object(rhs,copyop)
|
||||
if (attr) lhs_attributeList[typemember]=RefAttributePair(attr,rap.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0 //[ TODO
|
||||
// copy uniform values
|
||||
for(UniformList::const_iterator rhs_uitr = rhs._uniformList.begin();
|
||||
rhs_uitr != rhs._uniformList.end();
|
||||
++rhs_uitr)
|
||||
{
|
||||
const std::string& name = rhs_uitr->first;
|
||||
const RefUniformPair& rup = rhs_uitr->second;
|
||||
Uniform* uni = copyop(rup.first.get());
|
||||
if( uni ) _uniformList[name] = RefUniformPair(uni, rup.second);
|
||||
}
|
||||
|
||||
Program* prog = copyop( rhs._program );
|
||||
if( prog ) _program = prog;
|
||||
#endif //]
|
||||
|
||||
_renderingHint = rhs._renderingHint;
|
||||
|
||||
@@ -410,6 +424,9 @@ void StateSet::clear()
|
||||
|
||||
_textureModeList.clear();
|
||||
_textureAttributeList.clear();
|
||||
|
||||
_uniformList.clear();
|
||||
_program = 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -521,6 +538,29 @@ void StateSet::merge(const StateSet& rhs)
|
||||
}
|
||||
}
|
||||
|
||||
// merge the uniforms of rhs into this,
|
||||
// this overrides rhs if OVERRIDE defined in this.
|
||||
for(UniformList::const_iterator rhs_uitr = rhs._uniformList.begin();
|
||||
rhs_uitr != rhs._uniformList.end();
|
||||
++rhs_uitr)
|
||||
{
|
||||
UniformList::iterator lhs_uitr = _uniformList.find(rhs_uitr->first);
|
||||
if (lhs_uitr!=_uniformList.end())
|
||||
{
|
||||
if (!(lhs_uitr->second.second & StateAttribute::OVERRIDE))
|
||||
{
|
||||
// override isn't on in rhs, so overrite it with incomming
|
||||
// value.
|
||||
lhs_uitr->second = rhs_uitr->second;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// entry doesn't exist so insert it.
|
||||
_uniformList.insert(*rhs_uitr);
|
||||
}
|
||||
}
|
||||
|
||||
// need to merge rendering hints
|
||||
// but will need to think how best to do this first
|
||||
// RO, Nov. 2001.
|
||||
@@ -662,7 +702,7 @@ const StateSet::RefAttributePair* StateSet::getAttributePair(StateAttribute::Typ
|
||||
return getAttributePair(_attributeList,type,member);
|
||||
}
|
||||
|
||||
void StateSet::setUniform(Uniform* uniform, StateAttribute::OverrideValue value)
|
||||
void StateSet::addUniform(Uniform* uniform, StateAttribute::OverrideValue value)
|
||||
{
|
||||
if (uniform)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
/* file: src/osg/Uniform.cpp
|
||||
* author: Mike Weiblen 2005-02-20
|
||||
* author: Mike Weiblen 2005-03-23
|
||||
*/
|
||||
|
||||
// NOTICE: This code is CLOSED during construction and/or renovation!
|
||||
@@ -368,6 +368,13 @@ Uniform::Uniform( const char* name, Value::Type type ) :
|
||||
{}
|
||||
|
||||
|
||||
Uniform::Uniform( const Uniform& gu, const CopyOp& copyop ) :
|
||||
Object(gu,copyop),
|
||||
_value( gu._value )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Uniform::Uniform( const char* name, float f ) :
|
||||
_value( name, Value::FLOAT )
|
||||
{
|
||||
@@ -423,13 +430,6 @@ Uniform::Uniform( const char* name, int i ) :
|
||||
//TODO Uniform::Uniform( const char* name, bool b0, bool b1, bool b2, bool b3 )
|
||||
|
||||
|
||||
Uniform::Uniform( const Uniform& gu, const CopyOp& copyop ) :
|
||||
Object(gu,copyop),
|
||||
_value( gu._value )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool Uniform::set( float f )
|
||||
{
|
||||
if( ! isCompatibleType( Value::FLOAT ) ) return false;
|
||||
@@ -503,5 +503,4 @@ bool Uniform::isCompatibleType( Value::Type t ) const
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*EOF*/
|
||||
|
||||
Reference in New Issue
Block a user