OpenSceneGraph/src/osg/BufferObject.cpp

1455 lines
45 KiB
C++

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <osg/BufferObject>
#include <osg/Notify>
#include <osg/GLExtensions>
#include <osg/Timer>
#include <osg/Image>
#include <osg/State>
#include <osg/PrimitiveSet>
#include <osg/Array>
#include <OpenThreads/ScopedLock>
#include <OpenThreads/Mutex>
using namespace osg;
// static cache of deleted buffer object lists which can only
// by completely deleted once the appropriate OpenGL context
// is set. Used osg::BufferObject::deleteBufferObject(..) and flushDeletedBufferObjects(..) below.
typedef std::multimap<unsigned int,GLuint> BufferObjectMap;
typedef osg::buffered_object<BufferObjectMap> DeletedBufferObjectCache;
static OpenThreads::Mutex s_mutex_deletedBufferObjectCache;
static DeletedBufferObjectCache s_deletedBufferObjectCache;
unsigned int s_minimumNumberOfGLBufferObjectsToRetainInCache = 1000;
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GLBufferObject
//
GLBufferObject::GLBufferObject(unsigned int contextID, BufferObject* bufferObject):
_contextID(contextID),
_glObjectID(0),
_profile(0,0,0),
_allocatedSize(0),
_dirty(true),
_bufferObject(0),
_set(0),
_previous(0),
_next(0),
_extensions(0)
{
assign(bufferObject);
_extensions = GLBufferObject::getExtensions(contextID, true);
_extensions->glGenBuffers(1, &_glObjectID);
}
GLBufferObject::~GLBufferObject()
{
}
void GLBufferObject::bindBuffer()
{
_extensions->glBindBuffer(_profile._target,_glObjectID);
if (_set) _set->moveToBack(this);
}
void GLBufferObject::setBufferObject(BufferObject* bufferObject)
{
assign(bufferObject);
}
void GLBufferObject::assign(BufferObject* bufferObject)
{
_bufferObject = bufferObject;
if (_bufferObject)
{
_profile = bufferObject->getProfile();
_dirty = true;
_bufferEntries.clear();
}
else
{
_profile.setProfile(0,0,0);
// clear all previous entries;
_bufferEntries.clear();
}
}
void GLBufferObject::clear()
{
_bufferEntries.clear();
_dirty = true;
}
void GLBufferObject::compileBuffer()
{
_dirty = false;
_bufferEntries.reserve(_bufferObject->getNumBufferData());
bool compileAll = false;
bool offsetChanged = false;
GLsizeiptrARB newTotalSize = 0;
unsigned int i=0;
for(; i<_bufferObject->getNumBufferData(); ++i)
{
BufferData* bd = _bufferObject->getBufferData(i);
if (i<_bufferEntries.size())
{
BufferEntry& entry = _bufferEntries[i];
if (offsetChanged ||
entry.dataSource != bd ||
entry.dataSize != bd->getTotalDataSize())
{
GLsizeiptrARB previousEndOfBufferDataMarker = GLsizeiptrARB(entry.offset) + entry.dataSize;
// osg::notify(osg::NOTICE)<<"GLBufferObject::compileBuffer(..) updating BufferEntry"<<std::endl;
entry.offset = newTotalSize;
entry.modifiedCount = 0xffffff;
entry.dataSize = bd->getTotalDataSize();
entry.dataSource = bd;
newTotalSize += entry.dataSize;
if (previousEndOfBufferDataMarker==newTotalSize)
{
offsetChanged = true;
}
}
}
else
{
BufferEntry entry;
entry.offset = newTotalSize;
entry.modifiedCount = 0xffffff;
entry.dataSize = bd->getTotalDataSize();
entry.dataSource = bd;
#if 0
osg::notify(osg::NOTICE)<<"entry"<<std::endl;
osg::notify(osg::NOTICE)<<" offset "<<entry.offset<<std::endl;
osg::notify(osg::NOTICE)<<" dataSize "<<entry.dataSize<<std::endl;
osg::notify(osg::NOTICE)<<" dataSource "<<entry.dataSource<<std::endl;
osg::notify(osg::NOTICE)<<" modifiedCount "<<entry.modifiedCount<<std::endl;
#endif
newTotalSize += entry.dataSize;
_bufferEntries.push_back(entry);
}
}
if (i<_bufferEntries.size())
{
// triming end of bufferEntries as the source data is has less entries than the originally held.
_bufferEntries.erase(_bufferEntries.begin()+i, _bufferEntries.end());
}
_extensions->glBindBuffer(_profile._target, _glObjectID);
if (newTotalSize > _profile._size)
{
osg::notify(osg::NOTICE)<<"newTotalSize="<<newTotalSize<<", _profile._size="<<_profile._size<<std::endl;
_profile._size = newTotalSize;
if (_set)
{
_set->moveToSet(this, _set->getParent()->getGLBufferObjectSet(_profile));
}
}
if (_allocatedSize != _profile._size)
{
_allocatedSize = _profile._size;
_extensions->glBufferData(_profile._target, _profile._size, NULL, _profile._usage);
}
char* vboMemory = 0;
#if 0
vboMemory = extensions->glMapBuffer(_target, GL_WRITE_ONLY_ARB);
#endif
for(BufferEntries::iterator itr = _bufferEntries.begin();
itr != _bufferEntries.end();
++itr)
{
BufferEntry& entry = *itr;
if (compileAll || entry.modifiedCount != entry.dataSource->getModifiedCount())
{
// osg::notify(osg::NOTICE)<<"GLBufferObject::compileBuffer(..) downloading BufferEntry "<<&entry<<std::endl;
entry.modifiedCount = entry.dataSource->getModifiedCount();
if (vboMemory)
memcpy(vboMemory + (GLsizeiptrARB)entry.offset, entry.dataSource->getDataPointer(), entry.dataSize);
else
_extensions->glBufferSubData(_profile._target, (GLintptrARB)entry.offset, (GLsizeiptrARB)entry.dataSize, entry.dataSource->getDataPointer());
}
}
// Unmap the texture image buffer
if (vboMemory) _extensions->glUnmapBuffer(_profile._target);
}
void GLBufferObject::deleteGLObject()
{
if (_glObjectID!=0)
{
_extensions->glDeleteBuffers(1, &_glObjectID);
_glObjectID = 0;
_allocatedSize = 0;
_bufferEntries.clear();
}
}
void GLBufferObject::deleteBufferObject(unsigned int contextID,GLuint globj)
{
osg::notify(osg::NOTICE)<<"GLBufferObject::deleteBufferObject("<<std::endl;
}
#if 0
void GLBufferObject::flushDeletedBufferObjects(unsigned int contextID,double /*currentTime*/, double& availableTime)
{
// if no time available don't try to flush objects.
if (availableTime<=0.0) 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_deletedBufferObjectCache);
const Extensions* extensions = getExtensions(contextID,true);
unsigned int noDeleted = 0;
BufferObjectMap& dll = s_deletedBufferObjectCache[contextID];
BufferObjectMap::iterator ditr=dll.begin();
for(;
ditr!=dll.end() && elapsedTime<availableTime;
++ditr)
{
extensions->glDeleteBuffers(1,&(ditr->second));
elapsedTime = timer.delta_s(start_tick,timer.tick());
++noDeleted;
}
if (ditr!=dll.begin()) dll.erase(dll.begin(),ditr);
// if (noDeleted!=0) notify(osg::NOTICE)<<"Number VBOs deleted = "<<noDeleted<<" BO's left"<<dll.size()<<std::endl;
}
availableTime -= elapsedTime;
}
void GLBufferObject::discardDeletedBufferObjects(unsigned int contextID)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedBufferObjectCache);
BufferObjectMap& dll = s_deletedBufferObjectCache[contextID];
dll.clear();
}
#endif
//////////////////////////////////////////////////////////////////////////////
//
// Extension support
//
typedef buffered_value< ref_ptr<GLBufferObject::Extensions> > BufferedExtensions;
static BufferedExtensions s_extensions;
GLBufferObject::Extensions* GLBufferObject::getExtensions(unsigned int contextID,bool createIfNotInitalized)
{
if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new GLBufferObject::Extensions(contextID);
return s_extensions[contextID].get();
}
void GLBufferObject::setExtensions(unsigned int contextID,Extensions* extensions)
{
s_extensions[contextID] = extensions;
}
GLBufferObject::Extensions::Extensions(unsigned int contextID)
{
setupGLExtensions(contextID);
}
GLBufferObject::Extensions::Extensions(const Extensions& rhs):
Referenced()
{
_glGenBuffers = rhs._glGenBuffers;
_glBindBuffer = rhs._glBindBuffer;
_glBufferData = rhs._glBufferData;
_glBufferSubData = rhs._glBufferSubData;
_glDeleteBuffers = rhs._glDeleteBuffers;
_glIsBuffer = rhs._glIsBuffer;
_glGetBufferSubData = rhs._glGetBufferSubData;
_glMapBuffer = rhs._glMapBuffer;
_glUnmapBuffer = rhs._glUnmapBuffer;
_glGetBufferParameteriv = rhs._glGetBufferParameteriv;
_glGetBufferPointerv = rhs._glGetBufferPointerv;
}
void GLBufferObject::Extensions::lowestCommonDenominator(const Extensions& rhs)
{
if (!rhs._glGenBuffers) _glGenBuffers = rhs._glGenBuffers;
if (!rhs._glBindBuffer) _glBindBuffer = rhs._glBindBuffer;
if (!rhs._glBufferData) _glBufferData = rhs._glBufferData;
if (!rhs._glBufferSubData) _glBufferSubData = rhs._glBufferSubData;
if (!rhs._glDeleteBuffers) _glDeleteBuffers = rhs._glDeleteBuffers;
if (!rhs._glIsBuffer) _glIsBuffer = rhs._glIsBuffer;
if (!rhs._glGetBufferSubData) _glGetBufferSubData = rhs._glGetBufferSubData;
if (!rhs._glMapBuffer) _glMapBuffer = rhs._glMapBuffer;
if (!rhs._glUnmapBuffer) _glUnmapBuffer = rhs._glUnmapBuffer;
if (!rhs._glGetBufferParameteriv) _glGetBufferParameteriv = rhs._glGetBufferParameteriv;
if (!rhs._glGetBufferParameteriv) _glGetBufferPointerv = rhs._glGetBufferPointerv;
}
void GLBufferObject::Extensions::setupGLExtensions(unsigned int contextID)
{
setGLExtensionFuncPtr(_glGenBuffers, "glGenBuffers","glGenBuffersARB");
setGLExtensionFuncPtr(_glBindBuffer, "glBindBuffer","glBindBufferARB");
setGLExtensionFuncPtr(_glBufferData, "glBufferData","glBufferDataARB");
setGLExtensionFuncPtr(_glBufferSubData, "glBufferSubData","glBufferSubDataARB");
setGLExtensionFuncPtr(_glDeleteBuffers, "glDeleteBuffers","glDeleteBuffersARB");
setGLExtensionFuncPtr(_glIsBuffer, "glIsBuffer","glIsBufferARB");
setGLExtensionFuncPtr(_glGetBufferSubData, "glGetBufferSubData","glGetBufferSubDataARB");
setGLExtensionFuncPtr(_glMapBuffer, "glMapBuffer","glMapBufferARB");
setGLExtensionFuncPtr(_glUnmapBuffer, "glUnmapBuffer","glUnmapBufferARB");
setGLExtensionFuncPtr(_glGetBufferParameteriv, "glGetBufferParameteriv","glGetBufferParameterivARB");
setGLExtensionFuncPtr(_glGetBufferPointerv, "glGetBufferPointerv","glGetBufferPointervARB");
_isPBOSupported = osg::isGLExtensionSupported(contextID,"GL_ARB_pixel_buffer_object");
}
void GLBufferObject::Extensions::glGenBuffers(GLsizei n, GLuint *buffers) const
{
if (_glGenBuffers) _glGenBuffers(n, buffers);
else notify(WARN)<<"Error: glGenBuffers not supported by OpenGL driver"<<std::endl;
}
void GLBufferObject::Extensions::glBindBuffer(GLenum target, GLuint buffer) const
{
if (_glBindBuffer) _glBindBuffer(target, buffer);
else notify(WARN)<<"Error: glBindBuffer not supported by OpenGL driver"<<std::endl;
}
void GLBufferObject::Extensions::glBufferData(GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage) const
{
if (_glBufferData) _glBufferData(target, size, data, usage);
else notify(WARN)<<"Error: glBufferData not supported by OpenGL driver"<<std::endl;
}
void GLBufferObject::Extensions::glBufferSubData(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data) const
{
if (_glBufferSubData) _glBufferSubData(target, offset, size, data);
else notify(WARN)<<"Error: glBufferData not supported by OpenGL driver"<<std::endl;
}
void GLBufferObject::Extensions::glDeleteBuffers(GLsizei n, const GLuint *buffers) const
{
if (_glDeleteBuffers) _glDeleteBuffers(n, buffers);
else notify(WARN)<<"Error: glBufferData not supported by OpenGL driver"<<std::endl;
}
GLboolean GLBufferObject::Extensions::glIsBuffer (GLuint buffer) const
{
if (_glIsBuffer) return _glIsBuffer(buffer);
else
{
notify(WARN)<<"Error: glIsBuffer not supported by OpenGL driver"<<std::endl;
return GL_FALSE;
}
}
void GLBufferObject::Extensions::glGetBufferSubData (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data) const
{
if (_glGetBufferSubData) _glGetBufferSubData(target,offset,size,data);
else notify(WARN)<<"Error: glGetBufferSubData not supported by OpenGL driver"<<std::endl;
}
GLvoid* GLBufferObject::Extensions::glMapBuffer (GLenum target, GLenum access) const
{
if (_glMapBuffer) return _glMapBuffer(target,access);
else
{
notify(WARN)<<"Error: glMapBuffer not supported by OpenGL driver"<<std::endl;
return 0;
}
}
GLboolean GLBufferObject::Extensions::glUnmapBuffer (GLenum target) const
{
if (_glUnmapBuffer) return _glUnmapBuffer(target);
else
{
notify(WARN)<<"Error: glUnmapBuffer not supported by OpenGL driver"<<std::endl;
return GL_FALSE;
}
}
void GLBufferObject::Extensions::glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params) const
{
if (_glGetBufferParameteriv) _glGetBufferParameteriv(target,pname,params);
else notify(WARN)<<"Error: glGetBufferParameteriv not supported by OpenGL driver"<<std::endl;
}
void GLBufferObject::Extensions::glGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params) const
{
if (_glGetBufferPointerv) _glGetBufferPointerv(target,pname,params);
else notify(WARN)<<"Error: glGetBufferPointerv not supported by OpenGL driver"<<std::endl;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GLBufferObjectSet
//
GLBufferObjectSet::GLBufferObjectSet(GLBufferObjectManager* parent, const BufferObjectProfile& profile):
_parent(parent),
_contextID(parent->getContextID()),
_profile(profile),
_numOfGLBufferObjects(0),
_head(0),
_tail(0)
{
osg::notify(osg::NOTICE)<<"GLBufferObjectSet::GLBufferObjectSet _profile._size="<<_profile._size<<std::endl;
}
GLBufferObjectSet::~GLBufferObjectSet()
{
#if 0
osg::notify(osg::NOTICE)<<"GLBufferObjectSet::~GLBufferObjectSet(), _numOfGLBufferObjects="<<_numOfGLBufferObjects<<std::endl;
osg::notify(osg::NOTICE)<<" _orphanedGLBufferObjects = "<<_orphanedGLBufferObjects.size()<<std::endl;
osg::notify(osg::NOTICE)<<" _head = "<<_head<<std::endl;
osg::notify(osg::NOTICE)<<" _tail = "<<_tail<<std::endl;
#endif
}
bool GLBufferObjectSet::checkConsistency() const
{
return true;
// osg::notify(osg::NOTICE)<<"GLBufferObjectSet::checkConsistency()"<<std::endl;
// check consistency of linked list.
unsigned int numInList = 0;
GLBufferObject* to = _head;
while(to!=0)
{
++numInList;
if (to->_next)
{
if ((to->_next)->_previous != to)
{
osg::notify(osg::NOTICE)<<"Error (to->_next)->_previous != to "<<std::endl;
throw "Error (to->_next)->_previous != to ";
}
}
else
{
if (_tail != to)
{
osg::notify(osg::NOTICE)<<"Error _trail != to"<<std::endl;
throw "Error _trail != to";
}
}
to = to->_next;
}
unsigned int totalNumber = numInList + _orphanedGLBufferObjects.size();
if (totalNumber != _numOfGLBufferObjects)
{
osg::notify(osg::NOTICE)<<"Error numInList + _orphanedGLBufferObjects.size() != _numOfGLBufferObjects"<<std::endl;
osg::notify(osg::NOTICE)<<" numInList = "<<numInList<<std::endl;
osg::notify(osg::NOTICE)<<" _orphanedGLBufferObjects.size() = "<<_orphanedGLBufferObjects.size()<<std::endl;
osg::notify(osg::NOTICE)<<" _pendingOrphanedGLBufferObjects.size() = "<<_pendingOrphanedGLBufferObjects.size()<<std::endl;
osg::notify(osg::NOTICE)<<" _numOfGLBufferObjects = "<<_numOfGLBufferObjects<<std::endl;
throw "Error numInList + _orphanedGLBufferObjects.size() != _numOfGLBufferObjects";
}
return true;
}
void GLBufferObjectSet::handlePendingOrphandedGLBufferObjects()
{
// osg::notify(osg::NOTICE)<<"handlePendingOrphandedGLBufferObjects()"<<_pendingOrphanedGLBufferObjects.size()<<std::endl;
if (_pendingOrphanedGLBufferObjects.empty()) return;
unsigned int numOrphaned = _pendingOrphanedGLBufferObjects.size();
for(GLBufferObjectList::iterator itr = _pendingOrphanedGLBufferObjects.begin();
itr != _pendingOrphanedGLBufferObjects.end();
++itr)
{
GLBufferObject* to = itr->get();
_orphanedGLBufferObjects.push_back(to);
remove(to);
#if 0
osg::notify(osg::NOTICE)<<" HPOTO after _head = "<<_head<<std::endl;
osg::notify(osg::NOTICE)<<" HPOTO after _tail = "<<_tail<<std::endl;
osg::notify(osg::NOTICE)<<" HPOTO after to->_previous = "<<to->_previous<<std::endl;
osg::notify(osg::NOTICE)<<" HPOTO after to->_next = "<<to->_next<<std::endl;
#endif
}
// update the GLBufferObjectManager's running total of active + orphaned GLBufferObjects
_parent->getNumberOrphanedGLBufferObjects() += numOrphaned;
_parent->getNumberActiveGLBufferObjects() -= numOrphaned;
_pendingOrphanedGLBufferObjects.clear();
checkConsistency();
}
void GLBufferObjectSet::flushAllDeletedGLBufferObjects()
{
for(GLBufferObjectList::iterator itr = _orphanedGLBufferObjects.begin();
itr != _orphanedGLBufferObjects.end();
++itr)
{
(*itr)->deleteGLObject();
osg::notify(osg::NOTICE)<<"Deleting textureobject id="<<(*itr)->getGLObjectID()<<std::endl;
}
unsigned int numDeleted = _orphanedGLBufferObjects.size();
_numOfGLBufferObjects -= numDeleted;
// update the GLBufferObjectManager's running total of current pool size
_parent->getCurrGLBufferObjectPoolSize() -= numDeleted*_profile._size;
_parent->getNumberOrphanedGLBufferObjects() -= numDeleted;
_parent->getNumberDeleted() += numDeleted;
_orphanedGLBufferObjects.clear();
}
void GLBufferObjectSet::discardAllDeletedGLBufferObjects()
{
unsigned int numDiscarded = _orphanedGLBufferObjects.size();
_numOfGLBufferObjects -= numDiscarded;
// update the GLBufferObjectManager's running total of current pool size
_parent->setCurrGLBufferObjectPoolSize( _parent->getCurrGLBufferObjectPoolSize() - numDiscarded*_profile._size );
// update the number of active and orphaned TextureOjects
_parent->getNumberOrphanedGLBufferObjects() -= 1;
_parent->getNumberActiveGLBufferObjects() += 1;
_parent->getNumberDeleted() += 1;
// just clear the list as there is nothing else we can do with them when discarding them
_orphanedGLBufferObjects.clear();
}
void GLBufferObjectSet::flushDeletedGLBufferObjects(double currentTime, double& availableTime)
{
// if nothing to delete return
if (_orphanedGLBufferObjects.empty()) return;
// if no time available don't try to flush objects.
if (availableTime<=0.0) return;
// if we don't have too many orphaned texture objects then don't bother deleting them, as we can potentially reuse them later.
if (_parent->getNumberOrphanedGLBufferObjects()<=s_minimumNumberOfGLBufferObjectsToRetainInCache) return;
unsigned int numDeleted = 0;
unsigned int maxNumObjectsToDelete = _parent->getNumberOrphanedGLBufferObjects()-s_minimumNumberOfGLBufferObjectsToRetainInCache;
if (maxNumObjectsToDelete>4) maxNumObjectsToDelete = 4;
ElapsedTime timer;
GLBufferObjectList::iterator itr = _orphanedGLBufferObjects.begin();
for(;
itr != _orphanedGLBufferObjects.end() && timer.elapsedTime()<availableTime && numDeleted<maxNumObjectsToDelete;
++itr)
{
osg::notify(osg::NOTICE)<<"Deleting textureobject id="<<itr->get()<<std::endl;
(*itr)->deleteGLObject();
++numDeleted;
}
// osg::notify(osg::NOTICE)<<"Size before = "<<_orphanedGLBufferObjects.size();
_orphanedGLBufferObjects.erase(_orphanedGLBufferObjects.begin(), itr);
//osg::notify(osg::NOTICE)<<", after = "<<_orphanedGLBufferObjects.size()<<" numDeleted = "<<numDeleted<<std::endl;
// update the number of TO's in this GLBufferObjectSet
_numOfGLBufferObjects -= numDeleted;
_parent->setCurrGLBufferObjectPoolSize( _parent->getCurrGLBufferObjectPoolSize() - numDeleted*_profile._size );
// update the number of active and orphaned TextureOjects
_parent->getNumberOrphanedGLBufferObjects() -= numDeleted;
_parent->getNumberActiveGLBufferObjects() += numDeleted;
_parent->getNumberDeleted() += numDeleted;
availableTime -= timer.elapsedTime();
}
bool GLBufferObjectSet::makeSpace(unsigned int& size)
{
if (!_orphanedGLBufferObjects.empty())
{
unsigned int sizeAvailable = _orphanedGLBufferObjects.size() * _profile._size;
if (size>sizeAvailable) size -= sizeAvailable;
else size = 0;
flushAllDeletedGLBufferObjects();
}
return size==0;
}
GLBufferObject* GLBufferObjectSet::takeFromOrphans(BufferObject* bufferObject)
{
// take front of orphaned list.
ref_ptr<GLBufferObject> glbo = _orphanedGLBufferObjects.front();
// remove from orphan list.
_orphanedGLBufferObjects.pop_front();
// assign to new texture
glbo->assign(bufferObject);
glbo->setProfile(_profile);
// update the number of active and orphaned TextureOjects
_parent->getNumberOrphanedGLBufferObjects() -= 1;
_parent->getNumberActiveGLBufferObjects() += 1;
// place at back of active list
addToBack(glbo.get());
// osg::notify(osg::NOTICE)<<"Reusing orhpahned GLBufferObject, _numOfGLBufferObjects="<<_numOfGLBufferObjects<<std::endl;
return glbo.release();
}
GLBufferObject* GLBufferObjectSet::takeOrGenerate(BufferObject* bufferObject)
{
// see if we can recyle GLBufferObject from the orphane list
if (!_pendingOrphanedGLBufferObjects.empty())
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
handlePendingOrphandedGLBufferObjects();
return takeFromOrphans(bufferObject);
}
else if (!_orphanedGLBufferObjects.empty())
{
return takeFromOrphans(bufferObject);
}
unsigned int minFrameNumber = _parent->getFrameNumber();
// see if we can reuse GLBufferObject by taking the least recently used active GLBufferObject
if ((_parent->getMaxGLBufferObjectPoolSize()!=0) &&
(!_parent->hasSpace(_profile._size)) &&
(_numOfGLBufferObjects>1) &&
(_head != 0) &&
(_head->_frameLastUsed<minFrameNumber))
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
ref_ptr<GLBufferObject> glbo = _head;
ref_ptr<BufferObject> original_BufferObject = glbo->getBufferObject();
if (original_BufferObject.valid())
{
original_BufferObject->setGLBufferObject(_contextID,0);
// osg::notify(osg::NOTICE)<<"GLBufferObjectSet="<<this<<": Reusing an active GLBufferObject "<<glbo.get()<<" _numOfGLBufferObjects="<<_numOfGLBufferObjects<<" size="<<_profile._size<<std::endl;
}
else
{
// osg::notify(osg::NOTICE)<<"Reusing a recently orphaned active GLBufferObject "<<glbo.get()<<std::endl;
}
moveToBack(glbo.get());
// assign to new texture
glbo->setBufferObject(bufferObject);
glbo->setProfile(_profile);
return glbo.release();
}
//
GLBufferObject* glbo = new GLBufferObject(_contextID, const_cast<BufferObject*>(bufferObject));
glbo->setProfile(_profile);
glbo->_set = this;
++_numOfGLBufferObjects;
// update the current texture pool size
_parent->getCurrGLBufferObjectPoolSize() += _profile._size;
_parent->getNumberActiveGLBufferObjects() += 1;
addToBack(glbo);
// osg::notify(osg::NOTICE)<<"Created new GLBufferObject, _numOfGLBufferObjects "<<_numOfGLBufferObjects<<std::endl;
return glbo;
}
void GLBufferObjectSet::moveToBack(GLBufferObject* to)
{
#if 0
osg::notify(osg::NOTICE)<<"GLBufferObjectSet::moveToBack("<<to<<")"<<std::endl;
osg::notify(osg::NOTICE)<<" before _head = "<<_head<<std::endl;
osg::notify(osg::NOTICE)<<" before _tail = "<<_tail<<std::endl;
osg::notify(osg::NOTICE)<<" before to->_previous = "<<to->_previous<<std::endl;
osg::notify(osg::NOTICE)<<" before to->_next = "<<to->_next<<std::endl;
#endif
to->_frameLastUsed = _parent->getFrameNumber();
// nothing to do if we are already tail
if (to==_tail) return;
// if no tail exists then assign 'to' as tail and head
if (_tail==0)
{
osg::notify(osg::NOTICE)<<"Error ***************** Should not get here !!!!!!!!!"<<std::endl;
_head = to;
_tail = to;
return;
}
if (to->_next==0)
{
osg::notify(osg::NOTICE)<<"Error ***************** Should not get here either !!!!!!!!!"<<std::endl;
return;
}
if (to->_previous)
{
(to->_previous)->_next = to->_next;
}
else
{
// 'to' is the head, so moving it to the back will mean we need a new head
if (to->_next)
{
_head = to->_next;
}
}
(to->_next)->_previous = to->_previous;
_tail->_next = to;
to->_previous = _tail;
to->_next = 0;
_tail = to;
#if 0
osg::notify(osg::NOTICE)<<" m2B after _head = "<<_head<<std::endl;
osg::notify(osg::NOTICE)<<" m2B after _tail = "<<_tail<<std::endl;
osg::notify(osg::NOTICE)<<" m2B after to->_previous = "<<to->_previous<<std::endl;
osg::notify(osg::NOTICE)<<" m2B after to->_next = "<<to->_next<<std::endl;
#endif
checkConsistency();
}
void GLBufferObjectSet::addToBack(GLBufferObject* to)
{
#if 0
osg::notify(osg::NOTICE)<<"GLBufferObjectSet::addToBack("<<to<<")"<<std::endl;
osg::notify(osg::NOTICE)<<" before _head = "<<_head<<std::endl;
osg::notify(osg::NOTICE)<<" before _tail = "<<_tail<<std::endl;
osg::notify(osg::NOTICE)<<" before to->_previous = "<<to->_previous<<std::endl;
osg::notify(osg::NOTICE)<<" before to->_next = "<<to->_next<<std::endl;
#endif
if (to->_previous !=0 || to->_next !=0)
{
moveToBack(to);
}
else
{
to->_frameLastUsed = _parent->getFrameNumber();
if (_tail) _tail->_next = to;
to->_previous = _tail;
if (!_head) _head = to;
_tail = to;
}
#if 0
osg::notify(osg::NOTICE)<<" a2B after _head = "<<_head<<std::endl;
osg::notify(osg::NOTICE)<<" a2B after _tail = "<<_tail<<std::endl;
osg::notify(osg::NOTICE)<<" a2B after to->_previous = "<<to->_previous<<std::endl;
osg::notify(osg::NOTICE)<<" a2B after to->_next = "<<to->_next<<std::endl;
#endif
checkConsistency();
}
void GLBufferObjectSet::orphan(GLBufferObject* to)
{
// osg::notify(osg::NOTICE)<<"GLBufferObjectSet::orphan("<<to<<")"<<std::endl;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
// disconnect from original texture
to->setBufferObject(0);
// add orphan 'to' to the pending list of orphans, these will then be
// handled in the handlePendingOrphandedGLBufferObjects() where the TO's
// will be removed from the active list, and then placed in the orhpanGLBufferObject
// list. This double buffered approach to handling orphaned TO's is used
// to avoid having to mutex the process of appling active TO's.
_pendingOrphanedGLBufferObjects.push_back(to);
#if 0
osg::notify(osg::NOTICE)<<"GLBufferObjectSet::orphan("<<to<<") _pendingOrphanedGLBufferObjects.size()="<<_pendingOrphanedGLBufferObjects.size()<<std::endl;
osg::notify(osg::NOTICE)<<" _orphanedGLBufferObjects.size()="<<_orphanedGLBufferObjects.size()<<std::endl;
#endif
}
void GLBufferObjectSet::remove(GLBufferObject* to)
{
if (to->_previous!=0)
{
(to->_previous)->_next = to->_next;
}
else
{
// 'to' was head so assign _head to the next in list
_head = to->_next;
}
if (to->_next!=0)
{
(to->_next)->_previous = to->_previous;
}
else
{
// 'to' was tail so assing tail to the previous in list
_tail = to->_previous;
}
// reset the 'to' list pointers as it's no longer in the active list.
to->_next = 0;
to->_previous = 0;
}
void GLBufferObjectSet::moveToSet(GLBufferObject* to, GLBufferObjectSet* set)
{
if (set==this) return;
if (!set) return;
// remove 'to' from original set
--_numOfGLBufferObjects;
remove(to);
// register 'to' with new set.
to->_set = set;
++set->_numOfGLBufferObjects;
set->addToBack(to);
}
GLBufferObjectManager::GLBufferObjectManager(unsigned int contextID):
_contextID(contextID),
_numActiveGLBufferObjects(0),
_numOrphanedGLBufferObjects(0),
_currGLBufferObjectPoolSize(0),
_maxGLBufferObjectPoolSize(0),
_frameNumber(0),
_numFrames(0),
_numDeleted(0),
_deleteTime(0.0),
_numGenerated(0),
_generateTime(0.0),
_numApplied(0),
_applyTime(0.0)
{
}
void GLBufferObjectManager::setMaxGLBufferObjectPoolSize(unsigned int size)
{
if (_maxGLBufferObjectPoolSize == size) return;
if (size<_currGLBufferObjectPoolSize)
{
osg::notify(osg::NOTICE)<<"Warning: new MaxGLBufferObjectPoolSize="<<size<<" is smaller than current GLBufferObjectPoolSize="<<_currGLBufferObjectPoolSize<<std::endl;
}
_maxGLBufferObjectPoolSize = size;
}
bool GLBufferObjectManager::makeSpace(unsigned int size)
{
for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin();
itr != _glBufferObjectSetMap.end() && size>0;
++itr)
{
if ((*itr).second->makeSpace(size)) return true;
}
return size==0;
}
GLBufferObject* GLBufferObjectManager::generateGLBufferObject(const BufferObject* bufferObject)
{
ElapsedTime elapsedTime(&(getGenerateTime()));
++getNumberGenerated();
BufferObjectProfile profile(bufferObject->getTarget(), bufferObject->getUsage(), bufferObject->computeRequiredBufferSize());
// osg::notify(osg::NOTICE)<<"GLBufferObjectManager::generateGLBufferObject size="<<bufferObject->computeRequiredBufferSize()<<std::endl;
GLBufferObjectSet* glbos = getGLBufferObjectSet(profile);
return glbos->takeOrGenerate(const_cast<BufferObject*>(bufferObject));
}
GLBufferObjectSet* GLBufferObjectManager::getGLBufferObjectSet(const BufferObjectProfile& profile)
{
osg::ref_ptr<GLBufferObjectSet>& tos = _glBufferObjectSetMap[profile];
if (!tos) tos = new GLBufferObjectSet(this, profile);
return tos.get();
}
void GLBufferObjectManager::handlePendingOrphandedGLBufferObjects()
{
for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin();
itr != _glBufferObjectSetMap.end();
++itr)
{
(*itr).second->handlePendingOrphandedGLBufferObjects();
}
}
void GLBufferObjectManager::flushAllDeletedGLBufferObjects()
{
ElapsedTime elapsedTime(&(getDeleteTime()));
for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin();
itr != _glBufferObjectSetMap.end();
++itr)
{
(*itr).second->flushAllDeletedGLBufferObjects();
}
}
void GLBufferObjectManager::discardAllDeletedGLBufferObjects()
{
for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin();
itr != _glBufferObjectSetMap.end();
++itr)
{
(*itr).second->discardAllDeletedGLBufferObjects();
}
}
void GLBufferObjectManager::flushDeletedGLBufferObjects(double currentTime, double& availableTime)
{
ElapsedTime elapsedTime(&(getDeleteTime()));
for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin();
(itr != _glBufferObjectSetMap.end()) && (availableTime > 0.0);
++itr)
{
(*itr).second->flushDeletedGLBufferObjects(currentTime, availableTime);
}
}
void GLBufferObjectManager::releaseGLBufferObject(GLBufferObject* to)
{
if (to->_set) to->_set->orphan(to);
else osg::notify(osg::NOTICE)<<"GLBufferObjectManager::releaseGLBufferObject(GLBufferObject* to) Not implemented yet"<<std::endl;
}
void GLBufferObjectManager::newFrame(osg::FrameStamp* fs)
{
if (fs) _frameNumber = fs->getFrameNumber();
else ++_frameNumber;
++_numFrames;
}
void GLBufferObjectManager::reportStats()
{
double numFrames(_numFrames==0 ? 1.0 : _numFrames);
osg::notify(osg::NOTICE)<<"GLBufferObjectMananger::reportStats()"<<std::endl;
osg::notify(osg::NOTICE)<<" total _numOfGLBufferObjects="<<_numActiveGLBufferObjects<<", _numOrphanedGLBufferObjects="<<_numOrphanedGLBufferObjects<<" _currGLBufferObjectPoolSize="<<_currGLBufferObjectPoolSize<<std::endl;
osg::notify(osg::NOTICE)<<" total _numGenerated="<<_numGenerated<<", _generateTime="<<_generateTime<<", averagePerFrame="<<_generateTime/numFrames*1000.0<<"ms"<<std::endl;
osg::notify(osg::NOTICE)<<" total _numDeleted="<<_numDeleted<<", _deleteTime="<<_deleteTime<<", averagePerFrame="<<_deleteTime/numFrames*1000.0<<"ms"<<std::endl;
osg::notify(osg::NOTICE)<<" total _numApplied="<<_numApplied<<", _applyTime="<<_applyTime<<", averagePerFrame="<<_applyTime/numFrames*1000.0<<"ms"<<std::endl;
}
void GLBufferObjectManager::resetStats()
{
_numFrames = 0;
_numDeleted = 0;
_deleteTime = 0;
_numGenerated = 0;
_generateTime = 0;
_numApplied = 0;
_applyTime = 0;
}
osg::ref_ptr<GLBufferObjectManager>& GLBufferObjectManager::getGLBufferObjectManager(unsigned int contextID)
{
typedef osg::buffered_object< ref_ptr<GLBufferObjectManager> > GLBufferObjectManagerBuffer;
static GLBufferObjectManagerBuffer s_GLBufferObjectManager;
if (!s_GLBufferObjectManager[contextID]) s_GLBufferObjectManager[contextID] = new GLBufferObjectManager(contextID);
return s_GLBufferObjectManager[contextID];
}
GLBufferObject* GLBufferObject::createGLBufferObject(unsigned int contextID, const BufferObject* bufferObject)
{
return GLBufferObjectManager::getGLBufferObjectManager(contextID)->generateGLBufferObject(bufferObject);
}
void GLBufferObject::flushAllDeletedBufferObjects(unsigned int contextID)
{
GLBufferObjectManager::getGLBufferObjectManager(contextID)->flushAllDeletedGLBufferObjects();
}
void GLBufferObject::discardAllDeletedBufferObjects(unsigned int contextID)
{
GLBufferObjectManager::getGLBufferObjectManager(contextID)->discardAllDeletedGLBufferObjects();
}
void GLBufferObject::flushDeletedBufferObjects(unsigned int contextID,double currentTime, double& availbleTime)
{
GLBufferObjectManager::getGLBufferObjectManager(contextID)->flushDeletedGLBufferObjects(currentTime, availbleTime);
}
void GLBufferObject::releaseGLBufferObject(unsigned int contextID, GLBufferObject* to)
{
GLBufferObjectManager::getGLBufferObjectManager(contextID)->releaseGLBufferObject(to);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// BufferObject
//
BufferObject::BufferObject()
{
}
BufferObject::BufferObject(const BufferObject& bo,const CopyOp& copyop):
Object(bo,copyop)
{
}
BufferObject::~BufferObject()
{
releaseGLObjects(0);
}
void BufferObject::setBufferData(unsigned int index, BufferData* bd)
{
if (index>=_bufferDataList.size()) _bufferDataList.resize(index+1);
_bufferDataList[index] = bd;
}
void BufferObject::dirty()
{
for(unsigned int i=0; i<_glBufferObjects.size(); ++i)
{
if (_glBufferObjects[i].valid()) _glBufferObjects[i]->dirty();
}
}
void BufferObject::resizeGLObjectBuffers(unsigned int maxSize)
{
_glBufferObjects.resize(maxSize);
}
void BufferObject::releaseGLObjects(State* state) const
{
if (state)
{
unsigned int contextID = state->getContextID();
if (_glBufferObjects[contextID].valid())
{
GLBufferObject::releaseGLBufferObject(contextID, _glBufferObjects[contextID].get());
_glBufferObjects[contextID] = 0;
}
}
else
{
for(unsigned int i=0; i<_glBufferObjects.size();++i)
{
if (_glBufferObjects[i].valid())
{
GLBufferObject::releaseGLBufferObject(i, _glBufferObjects[i].get());
_glBufferObjects[i] = 0;
}
}
}
}
unsigned int BufferObject::addBufferData(BufferData* bd)
{
if (!bd) return 0;
// check to see if bd exists in BufferObject already, is so return without doing anything
for(BufferDataList::iterator itr = _bufferDataList.begin();
itr != _bufferDataList.end();
++itr)
{
if (*itr == bd) return bd->getBufferIndex();
}
// bd->setBufferIndex(_bufferDataList.size());
_bufferDataList.push_back(bd);
// osg::notify(osg::NOTICE)<<"BufferObject "<<this<<":"<<className()<<"::addBufferData("<<bd<<"), bufferIndex= "<<_bufferDataList.size()-1<<std::endl;
return _bufferDataList.size()-1;
}
void BufferObject::removeBufferData(unsigned int index)
{
if (index>=_bufferDataList.size())
{
osg::notify(osg::WARN)<<"Error "<<className()<<"::removeBufferData("<<index<<") out of range."<<std::endl;
return;
}
// osg::notify(osg::NOTICE)<<"BufferObject::"<<this<<":"<<className()<<"::removeBufferData("<<index<<"), size= "<<_bufferDataList.size()<<std::endl;
// alter the indices of the BufferData after the entry to be removed so their indices are correctly placed.
for(unsigned int i=index+1; i<_bufferDataList.size(); ++i)
{
_bufferDataList[i]->setBufferIndex(i-1);
}
// remove the entry
_bufferDataList.erase(_bufferDataList.begin() + index);
for(unsigned int i=0; i<_glBufferObjects.size(); ++i)
{
if (_glBufferObjects[i].valid()) _glBufferObjects[i]->clear();
}
}
void BufferObject::removeBufferData(BufferData* bd)
{
// osg::notify(osg::NOTICE)<<"BufferObject::"<<this<<":"<<className()<<"::removeBufferData("<<bd<<"), index="<<bd->getBufferIndex()<<" size= "<<_bufferDataList.size()<<std::endl;
if (!bd || bd->getBufferObject()!=this) return;
removeBufferData(bd->getBufferIndex());
}
unsigned int BufferObject::computeRequiredBufferSize() const
{
unsigned int newTotalSize = 0;
for(BufferDataList::const_iterator itr = _bufferDataList.begin();
itr != _bufferDataList.end();
++itr)
{
BufferData* bd = *itr;
newTotalSize += bd->getTotalDataSize();
}
return newTotalSize;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// BufferData
//
BufferData::~BufferData()
{
setBufferObject(0);
}
void BufferData::setBufferObject(BufferObject* bufferObject)
{
if (_bufferObject==bufferObject) return;
if (_bufferObject.valid())
{
_bufferObject->removeBufferData(_bufferIndex);
}
_bufferObject = bufferObject;
_bufferIndex = _bufferObject.valid() ? _bufferObject->addBufferData(this) : 0;
}
//////////////////////////////////////////////////////////////////////////////////
//
// VertexBufferObject
//
VertexBufferObject::VertexBufferObject()
{
setTarget(GL_ARRAY_BUFFER_ARB);
setUsage(GL_STATIC_DRAW_ARB);
// _usage = GL_DYNAMIC_DRAW_ARB;
// _usage = GL_STREAM_DRAW_ARB;
}
VertexBufferObject::VertexBufferObject(const VertexBufferObject& vbo,const CopyOp& copyop):
BufferObject(vbo,copyop)
{
}
VertexBufferObject::~VertexBufferObject()
{
}
unsigned int VertexBufferObject::addArray(osg::Array* array)
{
return addBufferData(array);
}
void VertexBufferObject::removeArray(osg::Array* array)
{
removeBufferData(array);
}
void VertexBufferObject::setArray(unsigned int i, Array* array)
{
setBufferData(i,array);
}
Array* VertexBufferObject::getArray(unsigned int i)
{
return dynamic_cast<osg::Array*>(getBufferData(i));
}
const Array* VertexBufferObject::getArray(unsigned int i) const
{
return dynamic_cast<const osg::Array*>(getBufferData(i));
}
//////////////////////////////////////////////////////////////////////////////////
//
// ElementBufferObject
//
ElementBufferObject::ElementBufferObject()
{
setTarget(GL_ELEMENT_ARRAY_BUFFER_ARB);
setUsage(GL_STATIC_DRAW_ARB);
}
ElementBufferObject::ElementBufferObject(const ElementBufferObject& vbo,const CopyOp& copyop):
BufferObject(vbo,copyop)
{
}
ElementBufferObject::~ElementBufferObject()
{
}
unsigned int ElementBufferObject::addDrawElements(osg::DrawElements* drawElements)
{
return addBufferData(drawElements);
}
void ElementBufferObject::removeDrawElements(osg::DrawElements* drawElements)
{
removeBufferData(drawElements);
}
void ElementBufferObject::setDrawElements(unsigned int i, DrawElements* drawElements)
{
setBufferData(i,drawElements);
}
DrawElements* ElementBufferObject::getDrawElements(unsigned int i)
{
return dynamic_cast<DrawElements*>(getBufferData(i));
}
const DrawElements* ElementBufferObject::getDrawElements(unsigned int i) const
{
return dynamic_cast<const DrawElements*>(getBufferData(i));
}
//////////////////////////////////////////////////////////////////////////////////
//
// PixelBufferObject
//
PixelBufferObject::PixelBufferObject(osg::Image* image):
BufferObject()
{
setTarget(GL_PIXEL_UNPACK_BUFFER_ARB);
setUsage(GL_STREAM_DRAW_ARB);
osg::notify(osg::NOTICE)<<"Constructing PixelBufferObject for image="<<image<<std::endl;
setBufferData(0, image);
}
PixelBufferObject::PixelBufferObject(const PixelBufferObject& buffer,const CopyOp& copyop):
BufferObject(buffer,copyop)
{
}
PixelBufferObject::~PixelBufferObject()
{
}
void PixelBufferObject::setImage(osg::Image* image)
{
setBufferData(0, image);
}
Image* PixelBufferObject::getImage()
{
return dynamic_cast<Image*>(getBufferData(0));
}
const Image* PixelBufferObject::getImage() const
{
return dynamic_cast<const Image*>(getBufferData(0));
}
//////////////////////////////////////////////////////////////////////////////////
//
// PixelDataBufferObject
//
//--------------------------------------------------------------------------------
PixelDataBufferObject::PixelDataBufferObject()
{
setTarget(GL_ARRAY_BUFFER_ARB);
setTarget(GL_DYNAMIC_DRAW_ARB);
}
//--------------------------------------------------------------------------------
PixelDataBufferObject::PixelDataBufferObject(const PixelDataBufferObject& buffer,const CopyOp& copyop):
BufferObject(buffer,copyop)
{
}
//--------------------------------------------------------------------------------
PixelDataBufferObject::~PixelDataBufferObject()
{
}
//--------------------------------------------------------------------------------
void PixelDataBufferObject::compileBuffer(State& state) const
{
unsigned int contextID = state.getContextID();
if ( _profile._size == 0) return;
GLBufferObject* bo = getOrCreateGLBufferObject(contextID);
if (!bo || !bo->isDirty()) return;
bo->_extensions->glBindBuffer(_profile._target, bo->getGLObjectID());
bo->_extensions->glBufferData(_profile._target, _profile._size, NULL, _profile._usage);
bo->_extensions->glBindBuffer(_profile._target, 0);
}
//--------------------------------------------------------------------------------
void PixelDataBufferObject::bindBufferInReadMode(State& state)
{
unsigned int contextID = state.getContextID();
GLBufferObject* bo = getOrCreateGLBufferObject(contextID);
if (!bo) return;
if (bo->isDirty()) compileBuffer(state);
bo->_extensions->glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, bo->getGLObjectID());
_mode[contextID] = READ;
}
//--------------------------------------------------------------------------------
void PixelDataBufferObject::bindBufferInWriteMode(State& state)
{
unsigned int contextID = state.getContextID();
GLBufferObject* bo = getOrCreateGLBufferObject(contextID);
if (!bo) return;
if (bo->isDirty()) compileBuffer(state);
bo->_extensions->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, bo->getGLObjectID());
_mode[contextID] = WRITE;
}
//--------------------------------------------------------------------------------
void PixelDataBufferObject::unbindBuffer(unsigned int contextID) const
{
GLBufferObject::Extensions* extensions = GLBufferObject::getExtensions(contextID,true);
switch(_mode[contextID])
{
case READ:
extensions->glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB,0);
break;
case WRITE:
extensions->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB,0);
break;
default:
extensions->glBindBuffer(_profile._target,0);
break;
}
_mode[contextID] = NONE;
}
//--------------------------------------------------------------------------------
void PixelDataBufferObject::resizeGLObjectBuffers(unsigned int maxSize)
{
BufferObject::resizeGLObjectBuffers(maxSize);
_mode.resize(maxSize);
}