Added FBO deletion support, and better FBO querry and fallback mechansim in RenderStage.

This commit is contained in:
Robert Osfield
2005-11-24 15:18:12 +00:00
parent 09bfbeec8b
commit 736a8433ca
5 changed files with 229 additions and 38 deletions

View File

@@ -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<FBOExtensions *> _instances;
FBOExtensions *ext = _instances[contextID];
@@ -148,7 +152,7 @@ namespace osg
public:
RenderBuffer();
RenderBuffer(int width, int height, GLenum internalFormat);
RenderBuffer(const RenderBuffer &copy, const CopyOp &copyop = 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 &copy);
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 &copy);
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<GLenum, FrameBufferAttachment> AttachmentMap;
FrameBufferObject();
FrameBufferObject(const FrameBufferObject &copy, const CopyOp &copyop = 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();

View File

@@ -22,6 +22,7 @@
#include <osg/TextureCubeMap>
#include <osg/TextureRectangle>
#include <osg/Notify>
#include <osg/Timer>
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<GLuint> RenderBufferHandleList;
typedef std::map<unsigned int, RenderBufferHandleList> DeletedRenderBufferCache;
static OpenThreads::Mutex s_mutex_deletedRenderBufferCache;
static DeletedRenderBufferCache s_deletedRenderBufferCache;
void RenderBuffer::deleteRenderBuffer(unsigned int contextID, GLuint rb)
{
if( rb )
{
OpenThreads::ScopedLock<OpenThreads::Mutex> 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<OpenThreads::Mutex> 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() && elapsedTime<availableTime;
)
{
extensions->glDeleteRenderbuffersEXT(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 &copy, const CopyOp &copyop)
{
}
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<GLuint> FrameBufferObjectHandleList;
typedef std::map<unsigned int, FrameBufferObjectHandleList> DeletedFrameBufferObjectCache;
static OpenThreads::Mutex s_mutex_deletedFrameBufferObjectCache;
static DeletedFrameBufferObjectCache s_deletedFrameBufferObjectCache;
void FrameBufferObject::deleteFrameBufferObject(unsigned int contextID, GLuint rb)
{
if( rb )
{
OpenThreads::ScopedLock<OpenThreads::Mutex> 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<OpenThreads::Mutex> 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() && elapsedTime<availableTime;
)
{
extensions->glDeleteFramebuffersEXT(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 &copy, 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();

View File

@@ -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<renderTargetFallback)
renderTargetImplemntation = renderTargetFallback;
else
renderTargetImplemntation = osg::CameraNode::PIXEL_BUFFER_RTT;
}
else if (!_fbo)
if (fbo_supported && !_fbo)
{
osg::notify(osg::INFO)<<"Setting up osg::CameraNode::FRAME_BUFFER_OBJECT"<<std::endl;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*(_camera->getDataChangeMutex()));
_fbo = new osg::FrameBufferObject;
setDrawBuffer(GL_NONE);
setReadBuffer(GL_NONE);
osg::ref_ptr<osg::FrameBufferObject> 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"<<std::hex<<status<<std::endl;
fbo_supported = false;
fbo_ext->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 (renderTargetImplemntation<renderTargetFallback)
renderTargetImplemntation = renderTargetFallback;
else
renderTargetImplemntation = osg::CameraNode::PIXEL_BUFFER_RTT;
}
}

View File

@@ -749,6 +749,8 @@ void SceneView::flushAllDeletedGLObjects()
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::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()

View File

@@ -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);