Added FBO deletion support, and better FBO querry and fallback mechansim in RenderStage.
This commit is contained in:
@@ -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 ©, 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<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 ©, 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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user