diff --git a/include/osg/VertexProgram b/include/osg/VertexProgram index ba135e8ec..7537e06d9 100644 --- a/include/osg/VertexProgram +++ b/include/osg/VertexProgram @@ -152,7 +152,12 @@ class SG_EXPORT VertexProgram : public StateAttribute /** Set the vertex program using C++ style string.*/ inline void setVertexProgram( const std::string& program ) { _vertexProgram = program; } /** Set the vertex program using a C style string.*/ - inline void setVertexProgram( const char* program ) { _vertexProgram = program; } + inline void setVertexProgram( const char* program ) + { + _vertexProgram = program; + + dirtyVertexProgramObject(); + } /** Get the vertex program.*/ inline const std::string& getVertexProgram() const { return _vertexProgram; } @@ -168,6 +173,19 @@ class SG_EXPORT VertexProgram : public StateAttribute _matrixList[mode] = matrix; } + /** Force a recompile on next apply() of associated OpenGL vertex program objects.*/ + void dirtyVertexProgramObject(); + + /** use deleteVertexProgramObject instead of glDeletePrograms to allow + * OpenGL Vertex Program objects to cached until they can be deleted + * by the OpenGL context in which they were created, specified + * by contextID.*/ + static void deleteVertexProgramObject(unsigned int contextID,GLuint handle); + + /** flush all the cached vertex programs which need to be deleted + * in the OpenGL context related to contextID.*/ + static void flushDeletedVertexProgramObjects(unsigned int contextID); + virtual void apply(State& state) const; virtual void compile(State& state) const { apply(state); } @@ -191,6 +209,7 @@ class SG_EXPORT VertexProgram : public StateAttribute void glBindProgram(GLenum target, GLuint id) const; void glGenPrograms(GLsizei n, GLuint *programs) const; + void glDeletePrograms(GLsizei n, GLuint *programs) const; void glProgramString(GLenum target, GLenum format, GLsizei len, const void *string) const; void glProgramLocalParameter4fv(GLenum target, GLuint index, const GLfloat *params) const; @@ -202,6 +221,7 @@ class SG_EXPORT VertexProgram : public StateAttribute void* _glBindProgram; void* _glGenPrograms; + void *_glDeletePrograms; void* _glProgramString; void* _glProgramLocalParameter4fv; diff --git a/src/osg/VertexProgram.cpp b/src/osg/VertexProgram.cpp index 7b5685b02..aad1f3fc5 100644 --- a/src/osg/VertexProgram.cpp +++ b/src/osg/VertexProgram.cpp @@ -17,6 +17,47 @@ using namespace osg; +// static cache of deleted vertex programs which can only +// by completely deleted once the appropriate OpenGL context +// is set. +typedef std::vector VertexProgramObjectVector; +typedef std::map DeletedVertexProgramObjectCache; +static DeletedVertexProgramObjectCache s_deletedVertexProgramObjectCache; + +void VertexProgram::deleteVertexProgramObject(unsigned int contextID,GLuint handle) +{ + if (handle!=0) + { + // insert the handle into the cache for the appropriate context. + s_deletedVertexProgramObjectCache[contextID].push_back(handle); + } +} + + +void VertexProgram::flushDeletedVertexProgramObjects(unsigned int contextID) +{ + const Extensions* extensions = getExtensions(contextID,true); + + if (!extensions->isVertexProgramSupported()) + return; + + DeletedVertexProgramObjectCache::iterator citr = s_deletedVertexProgramObjectCache.find(contextID); + if (citr!=s_deletedVertexProgramObjectCache.end()) + { + VertexProgramObjectVector vpObjectSet; + + // this swap will transfer the content of and empty citr->second + // in one quick pointer change. + vpObjectSet.swap(citr->second); + for(VertexProgramObjectVector::iterator titr=vpObjectSet.begin(); + titr!=vpObjectSet.end(); + ++titr) + { + extensions->glDeletePrograms( 1L, &(*titr ) ); + } + } +} + VertexProgram::VertexProgram() { @@ -25,12 +66,40 @@ VertexProgram::VertexProgram() VertexProgram::VertexProgram(const VertexProgram& vp,const CopyOp& copyop): osg::StateAttribute(vp,copyop) -{} +{ + _vertexProgram = vp._vertexProgram; + + for( LocalParamList::const_iterator itr = vp._programLocalParameters.begin(); + itr != vp._programLocalParameters.end(); ++itr ) + { + _programLocalParameters[itr->first] = itr->second; + } + + for( MatrixList::const_iterator mitr = vp._matrixList.begin(); + mitr != vp._matrixList.end(); ++mitr ) + { + _matrixList[mitr->first] = mitr->second; + } +} // virtual VertexProgram::~VertexProgram() -{} +{ + dirtyVertexProgramObject(); +} + +void VertexProgram::dirtyVertexProgramObject() +{ + for(unsigned int i=0;i<_vertexProgramIDList.size();++i) + { + if (_vertexProgramIDList[i] != 0) + { + VertexProgram::deleteVertexProgramObject(i,_vertexProgramIDList[i]); + _vertexProgramIDList[i] = 0; + } + } +} void VertexProgram::apply(State& state) const { @@ -125,6 +194,7 @@ VertexProgram::Extensions::Extensions(const Extensions& rhs): _isVertexProgramSupported = rhs._isVertexProgramSupported; _glBindProgram = rhs._glBindProgram; _glGenPrograms = rhs._glGenPrograms; + _glDeletePrograms = rhs._glDeletePrograms; _glProgramString = rhs._glProgramString; _glProgramLocalParameter4fv = rhs._glProgramLocalParameter4fv; } @@ -136,6 +206,7 @@ void VertexProgram::Extensions::lowestCommonDenominator(const Extensions& rhs) if (!rhs._glBindProgram) _glBindProgram = 0; if (!rhs._glGenPrograms) _glGenPrograms = 0; + if (!rhs._glDeletePrograms) _glDeletePrograms = 0; if (!rhs._glProgramString) _glProgramString = 0; if (!rhs._glProgramLocalParameter4fv) _glProgramLocalParameter4fv = 0; @@ -147,6 +218,7 @@ void VertexProgram::Extensions::setupGLExtenions() _glBindProgram = osg::getGLExtensionFuncPtr("glBindProgramARB"); _glGenPrograms = osg::getGLExtensionFuncPtr("glGenProgramsARB"); + _glDeletePrograms = osg::getGLExtensionFuncPtr("glDeleteProgramsARB"); _glProgramString = osg::getGLExtensionFuncPtr("glProgramStringARB"); _glProgramLocalParameter4fv = osg::getGLExtensionFuncPtr("glProgramLocalParameter4fvARB"); } @@ -177,6 +249,19 @@ void VertexProgram::Extensions::glGenPrograms(GLsizei n, GLuint *programs) const } } +void VertexProgram::Extensions::glDeletePrograms(GLsizei n, GLuint *programs) const +{ + if (_glDeletePrograms) + { + typedef void (APIENTRY * DeleteProgramsProc) (GLsizei n, GLuint *programs); + ((DeleteProgramsProc)_glDeletePrograms)(n,programs); + } + else + { + notify(WARN)<<"Error: glDeletePrograms not supported by OpenGL driver"< #include +#include #include #include #include @@ -564,6 +565,7 @@ void SceneView::draw() // context we are in so can flush the appropriate caches. osg::Drawable::flushDeletedDisplayLists(_state->getContextID()); osg::Texture::flushDeletedTextureObjects(_state->getContextID()); + osg::VertexProgram::flushDeletedVertexProgramObjects(_state->getContextID()); RenderLeaf* previous = NULL; if (_displaySettings.valid() && _displaySettings->getStereo())