diff --git a/include/osg/FrameBufferObject b/include/osg/FrameBufferObject index ef306e46d..63e4410d8 100644 --- a/include/osg/FrameBufferObject +++ b/include/osg/FrameBufferObject @@ -95,9 +95,11 @@ namespace osg { public: typedef void APIENTRY TglBindRenderbufferEXT(GLenum, GLuint); + typedef void APIENTRY TglDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers); typedef void APIENTRY TglGenRenderbuffersEXT(GLsizei, GLuint *); typedef void APIENTRY TglRenderbufferStorageEXT(GLenum, GLenum, GLsizei, GLsizei); typedef void APIENTRY TglBindFramebufferEXT(GLenum, GLuint); + typedef void APIENTRY TglDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers); typedef void APIENTRY TglGenFramebuffersEXT(GLsizei, GLuint *); typedef GLenum APIENTRY TglCheckFramebufferStatusEXT(GLenum); typedef void APIENTRY TglFramebufferTexture1DEXT(GLenum, GLenum, GLenum, GLuint, GLint); @@ -106,19 +108,21 @@ namespace osg typedef void APIENTRY TglFramebufferRenderbufferEXT(GLenum, GLenum, GLenum, GLuint); typedef void APIENTRY TglGenerateMipmapEXT(GLenum); - TglBindRenderbufferEXT *glBindRenderbufferEXT; - TglGenRenderbuffersEXT *glGenRenderbuffersEXT; - TglRenderbufferStorageEXT *glRenderbufferStorageEXT; - TglBindFramebufferEXT *glBindFramebufferEXT; - TglGenFramebuffersEXT *glGenFramebuffersEXT; - TglCheckFramebufferStatusEXT *glCheckFramebufferStatusEXT; - TglFramebufferTexture1DEXT *glFramebufferTexture1DEXT; - TglFramebufferTexture2DEXT *glFramebufferTexture2DEXT; - TglFramebufferTexture3DEXT *glFramebufferTexture3DEXT; - TglFramebufferRenderbufferEXT *glFramebufferRenderbufferEXT; - TglGenerateMipmapEXT *glGenerateMipmapEXT; + TglBindRenderbufferEXT* glBindRenderbufferEXT; + TglGenRenderbuffersEXT* glGenRenderbuffersEXT; + TglDeleteRenderbuffersEXT* glDeleteRenderbuffersEXT; + TglRenderbufferStorageEXT* glRenderbufferStorageEXT; + TglBindFramebufferEXT* glBindFramebufferEXT; + TglDeleteFramebuffersEXT* glDeleteFramebuffersEXT; + TglGenFramebuffersEXT* glGenFramebuffersEXT; + TglCheckFramebufferStatusEXT* glCheckFramebufferStatusEXT; + TglFramebufferTexture1DEXT* glFramebufferTexture1DEXT; + TglFramebufferTexture2DEXT* glFramebufferTexture2DEXT; + TglFramebufferTexture3DEXT* glFramebufferTexture3DEXT; + TglFramebufferRenderbufferEXT* glFramebufferRenderbufferEXT; + TglGenerateMipmapEXT* glGenerateMipmapEXT; - static FBOExtensions *instance(unsigned contextID) + static FBOExtensions* instance(unsigned contextID) { static buffered_object _instances; FBOExtensions *ext = _instances[contextID]; @@ -148,7 +152,7 @@ namespace osg public: RenderBuffer(); RenderBuffer(int width, int height, GLenum internalFormat); - RenderBuffer(const RenderBuffer ©, const CopyOp ©op = CopyOp::SHALLOW_COPY); + RenderBuffer(const RenderBuffer& copy, const CopyOp& copyop = CopyOp::SHALLOW_COPY); META_Object(osg, RenderBuffer); @@ -163,8 +167,18 @@ namespace osg GLuint getObjectID(unsigned int contextID, const FBOExtensions *ext) const; inline int compare(const RenderBuffer &rb) const; + /** Mark internal RenderBuffer for deletion. + * Deletion requests are queued until they can be executed + * in the proper GL context. */ + static void deleteRenderBuffer(unsigned int contextID, GLuint rb); + + /** flush all the cached RenderBuffers which need to be deleted + * in the OpenGL context related to contextID.*/ + static void flushDeletedRenderBuffers(unsigned int contextID,double currentTime, double& availableTime); + + protected: - virtual ~RenderBuffer() {} + virtual ~RenderBuffer(); RenderBuffer &operator=(const RenderBuffer &) { return *this; } inline void dirtyAll() const; @@ -249,7 +263,7 @@ namespace osg { public: FrameBufferAttachment(); - FrameBufferAttachment(const FrameBufferAttachment ©); + FrameBufferAttachment(const FrameBufferAttachment& copy); explicit FrameBufferAttachment(RenderBuffer* target); explicit FrameBufferAttachment(Texture1D* target, int level = 0); @@ -261,9 +275,9 @@ namespace osg ~FrameBufferAttachment(); - FrameBufferAttachment &operator = (const FrameBufferAttachment ©); + FrameBufferAttachment&operator = (const FrameBufferAttachment& copy); - void createRequiredTexturesAndApplyGenerateMipMap(State &state, const FBOExtensions* ext) const; + void createRequiredTexturesAndApplyGenerateMipMap(State& state, const FBOExtensions* ext) const; void attach(State &state, GLenum attachment_point, const FBOExtensions* ext) const; int compare(const FrameBufferAttachment &fa) const; @@ -283,7 +297,7 @@ namespace osg typedef std::map AttachmentMap; FrameBufferObject(); - FrameBufferObject(const FrameBufferObject ©, const CopyOp ©op = CopyOp::SHALLOW_COPY); + FrameBufferObject(const FrameBufferObject& copy, const CopyOp& copyop = CopyOp::SHALLOW_COPY); META_StateAttribute(osg, FrameBufferObject, (StateAttribute::Type)0x101010/*FrameBufferObject*/); @@ -295,9 +309,18 @@ namespace osg int compare(const StateAttribute &sa) const; void apply(State &state) const; + /** Mark internal FBO for deletion. + * Deletion requests are queued until they can be executed + * in the proper GL context. */ + static void deleteFrameBufferObject(unsigned int contextID, GLuint program); + + /** flush all the cached FBOs which need to be deleted + * in the OpenGL context related to contextID.*/ + static void flushDeletedFrameBufferObjects(unsigned int contextID,double currentTime, double& availableTime); + protected: - virtual ~FrameBufferObject() {} - FrameBufferObject &operator=(const FrameBufferObject &) { return *this; } + virtual ~FrameBufferObject(); + FrameBufferObject& operator = (const FrameBufferObject&) { return *this; } inline void dirtyAll(); diff --git a/src/osg/FrameBufferObject.cpp b/src/osg/FrameBufferObject.cpp index 089b89b2e..67158c178 100644 --- a/src/osg/FrameBufferObject.cpp +++ b/src/osg/FrameBufferObject.cpp @@ -22,6 +22,7 @@ #include #include #include +#include using namespace osg; @@ -39,8 +40,10 @@ FBOExtensions::FBOExtensions(unsigned int contextID) LOAD_FBO_EXT(glBindRenderbufferEXT); LOAD_FBO_EXT(glGenRenderbuffersEXT); + LOAD_FBO_EXT(glDeleteRenderbuffersEXT); LOAD_FBO_EXT(glRenderbufferStorageEXT); LOAD_FBO_EXT(glBindFramebufferEXT); + LOAD_FBO_EXT(glDeleteFramebuffersEXT); LOAD_FBO_EXT(glGenFramebuffersEXT); LOAD_FBO_EXT(glCheckFramebufferStatusEXT); LOAD_FBO_EXT(glFramebufferTexture1DEXT); @@ -51,9 +54,11 @@ FBOExtensions::FBOExtensions(unsigned int contextID) _supported = glBindRenderbufferEXT != 0 && + glDeleteRenderbuffersEXT != 0 && glGenRenderbuffersEXT != 0 && glRenderbufferStorageEXT != 0 && glBindFramebufferEXT != 0 && + glDeleteFramebuffersEXT != 0 && glGenFramebuffersEXT != 0 && glCheckFramebufferStatusEXT != 0 && glFramebufferTexture1DEXT != 0 && @@ -68,6 +73,61 @@ FBOExtensions::FBOExtensions(unsigned int contextID) * RenderBuffer **************************************************************************/ +/////////////////////////////////////////////////////////////////////////// +// static cache of glRenderbuffers flagged for deletion, which will actually +// be deleted in the correct GL context. + +typedef std::list RenderBufferHandleList; +typedef std::map DeletedRenderBufferCache; + +static OpenThreads::Mutex s_mutex_deletedRenderBufferCache; +static DeletedRenderBufferCache s_deletedRenderBufferCache; + +void RenderBuffer::deleteRenderBuffer(unsigned int contextID, GLuint rb) +{ + if( rb ) + { + OpenThreads::ScopedLock lock(s_mutex_deletedRenderBufferCache); + + // add glProgram to the cache for the appropriate context. + s_deletedRenderBufferCache[contextID].push_back(rb); + } +} + +void RenderBuffer::flushDeletedRenderBuffers(unsigned int contextID,double /*currentTime*/, double& availableTime) +{ + // if no time available don't try to flush objects. + if (availableTime<=0.0) return; + + const FBOExtensions* extensions = FBOExtensions::instance(contextID); + if(!extensions || !extensions->isSupported() ) return; + + const osg::Timer& timer = *osg::Timer::instance(); + osg::Timer_t start_tick = timer.tick(); + double elapsedTime = 0.0; + + { + OpenThreads::ScopedLock lock(s_mutex_deletedRenderBufferCache); + + DeletedRenderBufferCache::iterator citr = s_deletedRenderBufferCache.find(contextID); + if( citr != s_deletedRenderBufferCache.end() ) + { + RenderBufferHandleList& pList = citr->second; + for(RenderBufferHandleList::iterator titr=pList.begin(); + titr!=pList.end() && elapsedTimeglDeleteRenderbuffersEXT(1, &(*titr) ); + titr = pList.erase( titr ); + elapsedTime = timer.delta_s(start_tick,timer.tick()); + } + } + } + + availableTime -= elapsedTime; +} + + RenderBuffer::RenderBuffer() : Object(), _internalFormat(GL_DEPTH_COMPONENT24), @@ -92,6 +152,14 @@ RenderBuffer::RenderBuffer(const RenderBuffer ©, const CopyOp ©op) { } +RenderBuffer::~RenderBuffer() +{ + for(unsigned i=0; i<_objectID.size(); ++i) + { + if (_objectID[i]) deleteRenderBuffer(i, _objectID[i]); + } +} + GLuint RenderBuffer::getObjectID(unsigned int contextID, const FBOExtensions *ext) const { GLuint &objectID = _objectID[contextID]; @@ -385,6 +453,62 @@ int FrameBufferAttachment::compare(const FrameBufferAttachment &fa) const * FrameBufferObject **************************************************************************/ +/////////////////////////////////////////////////////////////////////////// +// static cache of glRenderbuffers flagged for deletion, which will actually +// be deleted in the correct GL context. + +typedef std::list FrameBufferObjectHandleList; +typedef std::map DeletedFrameBufferObjectCache; + +static OpenThreads::Mutex s_mutex_deletedFrameBufferObjectCache; +static DeletedFrameBufferObjectCache s_deletedFrameBufferObjectCache; + +void FrameBufferObject::deleteFrameBufferObject(unsigned int contextID, GLuint rb) +{ + if( rb ) + { + OpenThreads::ScopedLock lock(s_mutex_deletedFrameBufferObjectCache); + + // add glProgram to the cache for the appropriate context. + s_deletedFrameBufferObjectCache[contextID].push_back(rb); + } +} + +void FrameBufferObject::flushDeletedFrameBufferObjects(unsigned int contextID,double /*currentTime*/, double& availableTime) +{ + // if no time available don't try to flush objects. + if (availableTime<=0.0) return; + + const FBOExtensions* extensions = FBOExtensions::instance(contextID); + if(!extensions || !extensions->isSupported() ) return; + + const osg::Timer& timer = *osg::Timer::instance(); + osg::Timer_t start_tick = timer.tick(); + double elapsedTime = 0.0; + + { + OpenThreads::ScopedLock lock(s_mutex_deletedFrameBufferObjectCache); + + DeletedFrameBufferObjectCache::iterator citr = s_deletedFrameBufferObjectCache.find(contextID); + if( citr != s_deletedFrameBufferObjectCache.end() ) + { + FrameBufferObjectHandleList& pList = citr->second; + for(FrameBufferObjectHandleList::iterator titr=pList.begin(); + titr!=pList.end() && elapsedTimeglDeleteFramebuffersEXT(1, &(*titr) ); + titr = pList.erase( titr ); + elapsedTime = timer.delta_s(start_tick,timer.tick()); + } + } + } + + availableTime -= elapsedTime; +} + + + FrameBufferObject::FrameBufferObject() : StateAttribute() { @@ -396,6 +520,14 @@ FrameBufferObject::FrameBufferObject(const FrameBufferObject ©, const CopyOp { } +FrameBufferObject::~FrameBufferObject() +{ + for(unsigned i=0; i<_fboID.size(); ++i) + { + if (_fboID[i]) deleteFrameBufferObject(i, _fboID[i]); + } +} + void FrameBufferObject::apply(State &state) const { unsigned int contextID = state.getContextID(); diff --git a/src/osgUtil/RenderStage.cpp b/src/osgUtil/RenderStage.cpp index b3cb949c3..aa07381ce 100644 --- a/src/osgUtil/RenderStage.cpp +++ b/src/osgUtil/RenderStage.cpp @@ -274,24 +274,14 @@ void RenderStage::runCameraSetUp(osg::State& state) { osg::FBOExtensions* fbo_ext = osg::FBOExtensions::instance(state.getContextID()); bool fbo_supported = fbo_ext && fbo_ext->isSupported(); - - if (!fbo_supported) - { - if (renderTargetImplemntation lock(*(_camera->getDataChangeMutex())); - _fbo = new osg::FrameBufferObject; - - setDrawBuffer(GL_NONE); - setReadBuffer(GL_NONE); + osg::ref_ptr fbo = new osg::FrameBufferObject; bool colorAttached = false; bool depthAttached = false; @@ -308,19 +298,19 @@ void RenderStage::runCameraSetUp(osg::State& state) { case(osg::CameraNode::DEPTH_BUFFER): { - _fbo->setAttachment(GL_DEPTH_ATTACHMENT_EXT, osg::FrameBufferAttachment(attachment)); + fbo->setAttachment(GL_DEPTH_ATTACHMENT_EXT, osg::FrameBufferAttachment(attachment)); depthAttached = true; break; } case(osg::CameraNode::STENCIL_BUFFER): { - _fbo->setAttachment(GL_STENCIL_ATTACHMENT_EXT, osg::FrameBufferAttachment(attachment)); + fbo->setAttachment(GL_STENCIL_ATTACHMENT_EXT, osg::FrameBufferAttachment(attachment)); stencilAttached = true; break; } default: { - _fbo->setAttachment(GL_COLOR_ATTACHMENT0_EXT+(buffer-osg::CameraNode::COLOR_BUFFER0), osg::FrameBufferAttachment(attachment)); + fbo->setAttachment(GL_COLOR_ATTACHMENT0_EXT+(buffer-osg::CameraNode::COLOR_BUFFER0), osg::FrameBufferAttachment(attachment)); colorAttached = true; break; } @@ -330,13 +320,51 @@ void RenderStage::runCameraSetUp(osg::State& state) if (!depthAttached) { - _fbo->setAttachment(GL_DEPTH_ATTACHMENT_EXT, osg::FrameBufferAttachment(new osg::RenderBuffer(_viewport->width(), _viewport->height(), GL_DEPTH_COMPONENT24))); + fbo->setAttachment(GL_DEPTH_ATTACHMENT_EXT, osg::FrameBufferAttachment(new osg::RenderBuffer(_viewport->width(), _viewport->height(), GL_DEPTH_COMPONENT24))); } if (!colorAttached) { - _fbo->setAttachment(GL_COLOR_ATTACHMENT0_EXT, osg::FrameBufferAttachment(new osg::RenderBuffer(_viewport->width(), _viewport->height(), GL_RGB))); + fbo->setAttachment(GL_COLOR_ATTACHMENT0_EXT, osg::FrameBufferAttachment(new osg::RenderBuffer(_viewport->width(), _viewport->height(), GL_RGB))); } + + fbo->apply(state); + + GLenum status = fbo_ext->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + osg::notify(osg::INFO)<<"RenderStage::runCameraSetUp(), FBO setup failed, FBO status= 0x"<glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + fbo = 0; + + // clean up. + double availableTime = 100.0f; + double currentTime = state.getFrameStamp()?state.getFrameStamp()->getReferenceTime():0.0; + osg::RenderBuffer::flushDeletedRenderBuffers(state.getContextID(),currentTime,availableTime); + osg::FrameBufferObject::flushDeletedFrameBufferObjects(state.getContextID(),currentTime,availableTime); + + + } + else + { + setDrawBuffer(GL_NONE); + setReadBuffer(GL_NONE); + + _fbo = fbo; + } + + + } + + if (!fbo_supported) + { + if (renderTargetImplemntationgetContextID(),currentTime,availableTime); osg::Program::flushDeletedGlPrograms(_state->getContextID(),currentTime,availableTime); osg::Shader::flushDeletedGlShaders(_state->getContextID(),currentTime,availableTime); + osg::RenderBuffer::flushDeletedRenderBuffers(_state->getContextID(),currentTime,availableTime); + osg::FrameBufferObject::flushDeletedFrameBufferObjects(_state->getContextID(),currentTime,availableTime); } void SceneView::flushDeletedGLObjects(double& availableTime) @@ -763,6 +765,8 @@ void SceneView::flushDeletedGLObjects(double& availableTime) osg::FragmentProgram::flushDeletedFragmentProgramObjects(_state->getContextID(),currentTime,availableTime); osg::Program::flushDeletedGlPrograms(_state->getContextID(),currentTime,availableTime); osg::Shader::flushDeletedGlShaders(_state->getContextID(),currentTime,availableTime); + osg::RenderBuffer::flushDeletedRenderBuffers(_state->getContextID(),currentTime,availableTime); + osg::FrameBufferObject::flushDeletedFrameBufferObjects(_state->getContextID(),currentTime,availableTime); } void SceneView::draw() diff --git a/src/osgWrappers/osg/FrameBufferObject.cpp b/src/osgWrappers/osg/FrameBufferObject.cpp index ee7a093bb..3ba62735b 100644 --- a/src/osgWrappers/osg/FrameBufferObject.cpp +++ b/src/osgWrappers/osg/FrameBufferObject.cpp @@ -31,12 +31,16 @@ TYPE_NAME_ALIAS(void , osg::FBOExtensions::TglBindRenderbufferEXT); +TYPE_NAME_ALIAS(void , osg::FBOExtensions::TglDeleteRenderbuffersEXT); + TYPE_NAME_ALIAS(void , osg::FBOExtensions::TglGenRenderbuffersEXT); TYPE_NAME_ALIAS(void , osg::FBOExtensions::TglRenderbufferStorageEXT); TYPE_NAME_ALIAS(void , osg::FBOExtensions::TglBindFramebufferEXT); +TYPE_NAME_ALIAS(void , osg::FBOExtensions::TglDeleteFramebuffersEXT); + TYPE_NAME_ALIAS(void , osg::FBOExtensions::TglGenFramebuffersEXT); TYPE_NAME_ALIAS(GLenum , osg::FBOExtensions::TglCheckFramebufferStatusEXT);