OpenSceneGraph/src/osg/BufferObject.cpp

1671 lines
52 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/GL2Extensions>
#include <osg/Timer>
#include <osg/Image>
#include <osg/State>
#include <osg/PrimitiveSet>
#include <osg/Array>
#include <OpenThreads/ScopedLock>
#include <OpenThreads/Mutex>
#if 0
#define CHECK_CONSISTENCY checkConsistency();
#else
#define CHECK_CONSISTENCY
#endif
using namespace osg;
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GLBufferObject
//
GLBufferObject::GLBufferObject(unsigned int contextID, BufferObject* bufferObject, unsigned int glObjectID):
_contextID(contextID),
_glObjectID(glObjectID),
_profile(0,0,0),
_allocatedSize(0),
_dirty(true),
_bufferObject(0),
_set(0),
_previous(0),
_next(0),
_frameLastUsed(0),
_extensions(0)
{
assign(bufferObject);
_extensions = GLBufferObject::getExtensions(contextID, true);
if (glObjectID==0)
{
_extensions->glGenBuffers(1, &_glObjectID);
}
// OSG_NOTICE<<"Constucting BufferObject "<<this<<std::endl;
}
GLBufferObject::~GLBufferObject()
{
//OSG_NOTICE<<"Destucting BufferObject "<<this<<std::endl;
}
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;
unsigned int bufferAlignment = 4;
unsigned int 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())
{
unsigned int previousEndOfBufferDataMarker = computeBufferAlignment(entry.offset + entry.dataSize, bufferAlignment);
// 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
{
newTotalSize = computeBufferAlignment(newTotalSize + entry.dataSize, bufferAlignment);
}
}
else
{
BufferEntry entry;
entry.offset = newTotalSize;
entry.modifiedCount = 0xffffff;
entry.dataSize = bd ? bd->getTotalDataSize() : 0;
entry.dataSource = bd;
#if 0
OSG_NOTICE<<"entry"<<std::endl;
OSG_NOTICE<<" offset "<<entry.offset<<std::endl;
OSG_NOTICE<<" dataSize "<<entry.dataSize<<std::endl;
OSG_NOTICE<<" dataSource "<<entry.dataSource<<std::endl;
OSG_NOTICE<<" modifiedCount "<<entry.modifiedCount<<std::endl;
#endif
newTotalSize = computeBufferAlignment(newTotalSize + entry.dataSize, bufferAlignment);
_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_INFO<<"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);
compileAll = true;
}
for(BufferEntries::iterator itr = _bufferEntries.begin();
itr != _bufferEntries.end();
++itr)
{
BufferEntry& entry = *itr;
if (entry.dataSource && (compileAll || entry.modifiedCount != entry.dataSource->getModifiedCount()))
{
// OSG_NOTICE<<"GLBufferObject::compileBuffer(..) downloading BufferEntry "<<&entry<<std::endl;
entry.modifiedCount = entry.dataSource->getModifiedCount();
_extensions->glBufferSubData(_profile._target, (GLintptrARB)entry.offset, (GLsizeiptrARB)entry.dataSize, entry.dataSource->getDataPointer());
}
}
}
void GLBufferObject::deleteGLObject()
{
OSG_INFO<<"GLBufferObject::deleteGLObject() "<<_glObjectID<<std::endl;
if (_glObjectID!=0)
{
_extensions->glDeleteBuffers(1, &_glObjectID);
_glObjectID = 0;
_allocatedSize = 0;
_bufferEntries.clear();
}
}
//////////////////////////////////////////////////////////////////////////////
//
// 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;
_glBindBufferRange = rhs._glBindBufferRange;
_glBindBufferBase = rhs._glBindBufferBase;
}
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;
if (!rhs._glBindBufferRange) _glBindBufferRange = rhs._glBindBufferRange;
if (!rhs._glBindBufferBase) _glBindBufferBase = rhs._glBindBufferBase;
_isPBOSupported = rhs._isPBOSupported;
_isUniformBufferObjectSupported = rhs._isUniformBufferObjectSupported;
}
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");
setGLExtensionFuncPtr(_glBindBufferRange, "glBindBufferRange");
setGLExtensionFuncPtr(_glBindBufferBase, "glBindBufferBase");
_isPBOSupported = OSG_GL3_FEATURES || osg::isGLExtensionSupported(contextID,"GL_ARB_pixel_buffer_object");
_isUniformBufferObjectSupported = osg::isGLExtensionSupported(contextID, "GL_ARB_uniform_buffer_object");
}
void GLBufferObject::Extensions::glGenBuffers(GLsizei n, GLuint *buffers) const
{
if (_glGenBuffers) _glGenBuffers(n, buffers);
else OSG_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 OSG_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 OSG_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 OSG_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 OSG_WARN<<"Error: glBufferData not supported by OpenGL driver"<<std::endl;
}
GLboolean GLBufferObject::Extensions::glIsBuffer (GLuint buffer) const
{
if (_glIsBuffer) return _glIsBuffer(buffer);
else
{
OSG_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 OSG_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
{
OSG_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
{
OSG_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 OSG_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 OSG_WARN<<"Error: glGetBufferPointerv not supported by OpenGL driver"<<std::endl;
}
void GLBufferObject::Extensions::glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
{
if (_glBindBufferRange) _glBindBufferRange(target, index, buffer, offset, size);
else OSG_WARN<<"Error: glBindBufferRange not supported by OpenGL driver\n";
}
void GLBufferObject::Extensions::glBindBufferBase (GLenum target, GLuint index, GLuint buffer)
{
if (_glBindBufferBase) _glBindBufferBase(target, index, buffer);
else OSG_WARN<<"Error: glBindBufferBase not supported by OpenGL driver\n";
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GLBufferObjectSet
//
GLBufferObjectSet::GLBufferObjectSet(GLBufferObjectManager* parent, const BufferObjectProfile& profile):
_parent(parent),
_contextID(parent->getContextID()),
_profile(profile),
_numOfGLBufferObjects(0),
_head(0),
_tail(0)
{
OSG_INFO<<"GLBufferObjectSet::GLBufferObjectSet _profile._size="<<_profile._size<<std::endl;
}
GLBufferObjectSet::~GLBufferObjectSet()
{
#if 0
OSG_NOTICE<<"GLBufferObjectSet::~GLBufferObjectSet(), _numOfGLBufferObjects="<<_numOfGLBufferObjects<<std::endl;
OSG_NOTICE<<" _orphanedGLBufferObjects = "<<_orphanedGLBufferObjects.size()<<std::endl;
OSG_NOTICE<<" _head = "<<_head<<std::endl;
OSG_NOTICE<<" _tail = "<<_tail<<std::endl;
#endif
}
bool GLBufferObjectSet::checkConsistency() const
{
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_NOTICE<<"GLBufferObjectSet::checkConsistency() : Error (to->_next)->_previous != to "<<std::endl;
return false;
}
}
else
{
if (_tail != to)
{
OSG_NOTICE<<"GLBufferObjectSet::checkConsistency() : Error _trail != to"<<std::endl;
return false;
}
}
to = to->_next;
}
unsigned int totalNumber = numInList + _orphanedGLBufferObjects.size();
if (totalNumber != _numOfGLBufferObjects)
{
OSG_NOTICE<<"Error numInList + _orphanedGLBufferObjects.size() != _numOfGLBufferObjects"<<std::endl;
OSG_NOTICE<<" numInList = "<<numInList<<std::endl;
OSG_NOTICE<<" _orphanedGLBufferObjects.size() = "<<_orphanedGLBufferObjects.size()<<std::endl;
OSG_NOTICE<<" _pendingOrphanedGLBufferObjects.size() = "<<_pendingOrphanedGLBufferObjects.size()<<std::endl;
OSG_NOTICE<<" _numOfGLBufferObjects = "<<_numOfGLBufferObjects<<std::endl;
return false;
}
return true;
}
void GLBufferObjectSet::handlePendingOrphandedGLBufferObjects()
{
// 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);
}
// update the GLBufferObjectManager's running total of active + orphaned GLBufferObjects
_parent->getNumberOrphanedGLBufferObjects() += numOrphaned;
_parent->getNumberActiveGLBufferObjects() -= numOrphaned;
_pendingOrphanedGLBufferObjects.clear();
CHECK_CONSISTENCY
}
void GLBufferObjectSet::deleteAllGLBufferObjects()
{
// OSG_NOTICE<<"GLBufferObjectSet::deleteAllGLBufferObjects()"<<std::endl;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
if (!_pendingOrphanedGLBufferObjects.empty())
{
// OSG_NOTICE<<"GLBufferObjectSet::flushDeletedGLBufferObjects(..) handling orphans"<<std::endl;
handlePendingOrphandedGLBufferObjects();
}
}
CHECK_CONSISTENCY
unsigned int numOrphaned = 0;
GLBufferObject* to = _head;
while(to!=0)
{
ref_ptr<GLBufferObject> glbo = to;
to = to->_next;
_orphanedGLBufferObjects.push_back(glbo.get());
remove(glbo.get());
++numOrphaned;
ref_ptr<BufferObject> original_BufferObject = glbo->getBufferObject();
if (original_BufferObject.valid())
{
// detect the GLBufferObject from the BufferObject
original_BufferObject->setGLBufferObject(_contextID,0);
}
}
_parent->getNumberOrphanedGLBufferObjects() += numOrphaned;
_parent->getNumberActiveGLBufferObjects() -= numOrphaned;
// do the actual delete.
flushAllDeletedGLBufferObjects();
// OSG_NOTICE<<"done GLBufferObjectSet::deleteAllGLBufferObjects()"<<std::endl;
}
void GLBufferObjectSet::discardAllGLBufferObjects()
{
// OSG_NOTICE<<"GLBufferObjectSet::discardAllGLBufferObjects()"<<std::endl;
GLBufferObject* to = _head;
while(to!=0)
{
ref_ptr<GLBufferObject> glbo = to;
to = to->_next;
ref_ptr<BufferObject> original_BufferObject = glbo->getBufferObject();
if (original_BufferObject.valid())
{
// detect the GLBufferObject from the BufferObject
original_BufferObject->setGLBufferObject(_contextID,0);
}
}
// the linked list should now be empty
_head = 0;
_tail = 0;
_pendingOrphanedGLBufferObjects.clear();
_orphanedGLBufferObjects.clear();
unsigned int numDeleted = _numOfGLBufferObjects;
_numOfGLBufferObjects = 0;
// update the GLBufferObjectManager's running total of current pool size
_parent->getCurrGLBufferObjectPoolSize() -= numDeleted*_profile._size;
_parent->getNumberOrphanedGLBufferObjects() -= numDeleted;
_parent->getNumberDeleted() += numDeleted;
}
void GLBufferObjectSet::flushAllDeletedGLBufferObjects()
{
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
if (!_pendingOrphanedGLBufferObjects.empty())
{
// OSG_NOTICE<<"GLBufferObjectSet::flushDeletedGLBufferObjects(..) handling orphans"<<std::endl;
handlePendingOrphandedGLBufferObjects();
}
}
for(GLBufferObjectList::iterator itr = _orphanedGLBufferObjects.begin();
itr != _orphanedGLBufferObjects.end();
++itr)
{
(*itr)->deleteGLObject();
}
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()
{
// OSG_NOTICE<<"GLBufferObjectSet::discardAllDeletedGLBufferObjects()"<<std::endl;
// clean up the pending orphans.
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
if (!_pendingOrphanedGLBufferObjects.empty())
{
// OSG_NOTICE<<"GLBufferObjectSet::flushDeletedGLBufferObjects(..) handling orphans"<<std::endl;
handlePendingOrphandedGLBufferObjects();
}
}
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 GLBufferObjects
_parent->getNumberOrphanedGLBufferObjects() -= numDiscarded;
_parent->getNumberActiveGLBufferObjects() += numDiscarded;
_parent->getNumberDeleted() += numDiscarded;
// 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)
{
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
if (!_pendingOrphanedGLBufferObjects.empty())
{
// OSG_NOTICE<<"GLBufferObjectSet::flushDeletedGLBufferObjects(..) handling orphans"<<std::endl;
handlePendingOrphandedGLBufferObjects();
}
}
if (_parent->getCurrGLBufferObjectPoolSize()<=_parent->getMaxGLBufferObjectPoolSize())
{
OSG_INFO<<"Plenty of space in GLBufferObject pool"<<std::endl;
return;
}
// if nothing to delete return
if (_orphanedGLBufferObjects.empty()) return;
// if no time available don't try to flush objects.
if (availableTime<=0.0) return;
unsigned int numDeleted = 0;
unsigned int sizeRequired = _parent->getCurrGLBufferObjectPoolSize() - _parent->getMaxGLBufferObjectPoolSize();
unsigned int maxNumObjectsToDelete = static_cast<unsigned int>(ceil(double(sizeRequired) / double(_profile._size)));
OSG_INFO<<"_parent->getCurrGLBufferObjectPoolSize()="<<_parent->getCurrGLBufferObjectPoolSize() <<" _parent->getMaxGLBufferObjectPoolSize()="<< _parent->getMaxGLBufferObjectPoolSize()<<std::endl;
OSG_INFO<<"Looking to reclaim "<<sizeRequired<<", going to look to remove "<<maxNumObjectsToDelete<<" from "<<_orphanedGLBufferObjects.size()<<" orhpans"<<std::endl;
ElapsedTime timer;
GLBufferObjectList::iterator itr = _orphanedGLBufferObjects.begin();
for(;
itr != _orphanedGLBufferObjects.end() && timer.elapsedTime()<availableTime && numDeleted<maxNumObjectsToDelete;
++itr)
{
(*itr)->deleteGLObject();
++numDeleted;
}
// OSG_NOTICE<<"Size before = "<<_orphanedGLBufferObjects.size();
_orphanedGLBufferObjects.erase(_orphanedGLBufferObjects.begin(), itr);
// 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)
{
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
if (!_pendingOrphanedGLBufferObjects.empty())
{
// OSG_NOTICE<<"GLBufferSet::::makeSpace(..) handling orphans"<<std::endl;
handlePendingOrphandedGLBufferObjects();
}
}
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 GLBufferObject
glbo->assign(bufferObject);
glbo->setProfile(_profile);
// update the number of active and orphaned GLBufferObjects
_parent->getNumberOrphanedGLBufferObjects() -= 1;
_parent->getNumberActiveGLBufferObjects() += 1;
// place at back of active list
addToBack(glbo.get());
//OSG_NOTICE<<"Reusing orphaned GLBufferObject, _numOfGLBufferObjects="<<_numOfGLBufferObjects<<" target="<<std::hex<<_profile._target<<std::dec<<std::endl;
return glbo.release();
}
GLBufferObject* GLBufferObjectSet::takeOrGenerate(BufferObject* bufferObject)
{
// see if we can recyle GLBufferObject from the orphan list
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
if (!_pendingOrphanedGLBufferObjects.empty())
{
handlePendingOrphandedGLBufferObjects();
return takeFromOrphans(bufferObject);
}
}
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_INFO<<"GLBufferObjectSet="<<this<<": Reusing an active GLBufferObject "<<glbo.get()<<" _numOfGLBufferObjects="<<_numOfGLBufferObjects<<" size="<<_profile._size<<std::endl;
}
else
{
OSG_INFO<<"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_NOTICE<<"Created new GLBufferObject, _numOfGLBufferObjects "<<_numOfGLBufferObjects<<std::endl;
return glbo;
}
void GLBufferObjectSet::moveToBack(GLBufferObject* to)
{
#if 0
OSG_NOTICE<<"GLBufferObjectSet::moveToBack("<<to<<")"<<std::endl;
OSG_NOTICE<<" before _head = "<<_head<<std::endl;
OSG_NOTICE<<" before _tail = "<<_tail<<std::endl;
OSG_NOTICE<<" before to->_previous = "<<to->_previous<<std::endl;
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_NOTICE<<"Error ***************** Should not get here !!!!!!!!!"<<std::endl;
_head = to;
_tail = to;
return;
}
if (to->_next==0)
{
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_NOTICE<<" m2B after _head = "<<_head<<std::endl;
OSG_NOTICE<<" m2B after _tail = "<<_tail<<std::endl;
OSG_NOTICE<<" m2B after to->_previous = "<<to->_previous<<std::endl;
OSG_NOTICE<<" m2B after to->_next = "<<to->_next<<std::endl;
#endif
CHECK_CONSISTENCY
}
void GLBufferObjectSet::addToBack(GLBufferObject* to)
{
#if 0
OSG_NOTICE<<"GLBufferObjectSet::addToBack("<<to<<")"<<std::endl;
OSG_NOTICE<<" before _head = "<<_head<<std::endl;
OSG_NOTICE<<" before _tail = "<<_tail<<std::endl;
OSG_NOTICE<<" before to->_previous = "<<to->_previous<<std::endl;
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_NOTICE<<" a2B after _head = "<<_head<<std::endl;
OSG_NOTICE<<" a2B after _tail = "<<_tail<<std::endl;
OSG_NOTICE<<" a2B after to->_previous = "<<to->_previous<<std::endl;
OSG_NOTICE<<" a2B after to->_next = "<<to->_next<<std::endl;
#endif
CHECK_CONSISTENCY
}
void GLBufferObjectSet::orphan(GLBufferObject* to)
{
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);
}
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);
}
unsigned int GLBufferObjectSet::computeNumGLBufferObjectsInList() const
{
unsigned int num=0;
GLBufferObject* obj = _head;
while(obj!=NULL)
{
++num;
obj = obj->_next;
}
return num;
}
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_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_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::deleteAllGLBufferObjects()
{
ElapsedTime elapsedTime(&(getDeleteTime()));
for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin();
itr != _glBufferObjectSetMap.end();
++itr)
{
(*itr).second->deleteAllGLBufferObjects();
}
}
void GLBufferObjectManager::discardAllGLBufferObjects()
{
for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin();
itr != _glBufferObjectSetMap.end();
++itr)
{
(*itr).second->discardAllGLBufferObjects();
}
}
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_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(std::ostream& out)
{
double numFrames(_numFrames==0 ? 1.0 : _numFrames);
out<<"GLBufferObjectMananger::reportStats()"<<std::endl;
out<<" total _numOfGLBufferObjects="<<_numActiveGLBufferObjects<<", _numOrphanedGLBufferObjects="<<_numOrphanedGLBufferObjects<<" _currGLBufferObjectPoolSize="<<_currGLBufferObjectPoolSize<<std::endl;
out<<" total _numGenerated="<<_numGenerated<<", _generateTime="<<_generateTime<<", averagePerFrame="<<_generateTime/numFrames*1000.0<<"ms"<<std::endl;
out<<" total _numDeleted="<<_numDeleted<<", _deleteTime="<<_deleteTime<<", averagePerFrame="<<_deleteTime/numFrames*1000.0<<"ms"<<std::endl;
out<<" total _numApplied="<<_numApplied<<", _applyTime="<<_applyTime<<", averagePerFrame="<<_applyTime/numFrames*1000.0<<"ms"<<std::endl;
out<<" getMaxGLBufferObjectPoolSize()="<<getMaxGLBufferObjectPoolSize()<<" current/max size = "<<double(_currGLBufferObjectPoolSize)/double(getMaxGLBufferObjectPoolSize())<<std::endl;;
recomputeStats(out);
}
void GLBufferObjectManager::resetStats()
{
_numFrames = 0;
_numDeleted = 0;
_deleteTime = 0;
_numGenerated = 0;
_generateTime = 0;
_numApplied = 0;
_applyTime = 0;
}
void GLBufferObjectManager::recomputeStats(std::ostream& out)
{
out<<"GLBufferObjectMananger::recomputeStats()"<<std::endl;
unsigned int numObjectsInLists = 0;
unsigned int numActive = 0;
unsigned int numOrphans = 0;
unsigned int numPendingOrphans = 0;
unsigned int currentSize = 0;
for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin();
itr != _glBufferObjectSetMap.end();
++itr)
{
GLBufferObjectSet* os = itr->second.get();
numObjectsInLists += os->computeNumGLBufferObjectsInList();
numActive += os->getNumOfGLBufferObjects();
numOrphans += os->getNumOrphans();
numPendingOrphans += os->getNumPendingOrphans();
currentSize += os->getProfile()._size * (os->computeNumGLBufferObjectsInList()+os->getNumOrphans());
out<<" size="<<os->getProfile()._size
<<", os->computeNumGLBufferObjectsInList()"<<os->computeNumGLBufferObjectsInList()
<<", os->getNumOfGLBufferObjects()"<<os->getNumOfGLBufferObjects()
<<", os->getNumOrphans()"<<os->getNumOrphans()
<<", os->getNumPendingOrphans()"<<os->getNumPendingOrphans()
<<std::endl;
}
out<<" numObjectsInLists="<<numObjectsInLists<<", numActive="<<numActive<<", numOrphans="<<numOrphans<<" currentSize="<<currentSize<<std::endl;
out<<" getMaxGLBufferObjectPoolSize()="<<getMaxGLBufferObjectPoolSize()<<" current/max size = "<<double(currentSize)/double(getMaxGLBufferObjectPoolSize())<<std::endl;
}
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::deleteAllBufferObjects(unsigned int contextID)
{
GLBufferObjectManager::getGLBufferObjectManager(contextID)->deleteAllGLBufferObjects();
}
void GLBufferObject::discardAllBufferObjects(unsigned int contextID)
{
GLBufferObjectManager::getGLBufferObjectManager(contextID)->discardAllGLBufferObjects();
}
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():
_copyDataAndReleaseGLBufferObject(false)
{
}
BufferObject::BufferObject(const BufferObject& bo,const CopyOp& copyop):
Object(bo,copyop),
_copyDataAndReleaseGLBufferObject(bo._copyDataAndReleaseGLBufferObject)
{
}
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
{
OSG_INFO<<"BufferObject::releaseGLObjects("<<state<<")"<<std::endl;
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())
{
// OSG_NOTICE<<" GLBufferObject::releaseGLBufferObject("<<i<<", _glBufferObjects["<<i<<"]="<<_glBufferObjects[i].get()<<")"<<std::endl;
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);
dirty();
//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_WARN<<"Error "<<className()<<"::removeBufferData("<<index<<") out of range."<<std::endl;
return;
}
//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_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;
if (bd) newTotalSize += bd->getTotalDataSize();
else
{
OSG_NOTICE<<"BufferObject::"<<this<<":"<<className()<<"::BufferObject::computeRequiredBufferSize() error, BufferData is 0x0"<<std::endl;
}
}
//OSG_NOTICE<<"BufferObject::"<<this<<":"<<className()<<"::BufferObject::computeRequiredBufferSize() size="<<newTotalSize<<std::endl;
return newTotalSize;
}
void BufferObject::deleteBufferObject(unsigned int contextID,GLuint globj)
{
// implement deleteBufferObject for backwards compatibility by adding
// a GLBufferObject for the globj id to BufferObjectManager/Set for the specified context.
osg::ref_ptr<GLBufferObjectManager>& bufferObjectManager = GLBufferObjectManager::getGLBufferObjectManager(contextID);
if (!bufferObjectManager)
{
OSG_NOTICE<<"Warning::BufferObject::deleteBufferObject("<<contextID<<", "<<globj<<") unable to get GLBufferObjectManager for context."<<std::endl;
return;
}
osg::ref_ptr<GLBufferObject> glBufferObject = new GLBufferObject(contextID, 0, globj);
GLBufferObjectSet* bufferObjectSet = bufferObjectManager->getGLBufferObjectSet(glBufferObject->getProfile());
if (!bufferObjectSet)
{
OSG_NOTICE<<"Warning::BufferObject::deleteBufferObject("<<contextID<<", "<<globj<<") unable to get GLBufferObjectSet for context."<<std::endl;
return;
}
// do the adding of the wrapper buffer object.
bufferObjectSet->orphan(glBufferObject.get());
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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;
}
void BufferData::resizeGLObjectBuffers(unsigned int maxSize)
{
if (_bufferObject.valid())
{
_bufferObject->resizeGLObjectBuffers(maxSize);
}
}
void BufferData::releaseGLObjects(State* state) const
{
OSG_INFO<<"BufferData::releaseGLObjects("<<state<<")"<<std::endl;
if (_bufferObject.valid())
{
_bufferObject->releaseGLObjects(state);
}
}
//////////////////////////////////////////////////////////////////////////////////
//
// 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_INFO<<"Constructing PixelBufferObject for image="<<image<<std::endl;
if (image) 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);
setUsage(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);
}
UniformBufferObject::UniformBufferObject()
{
setTarget(GL_UNIFORM_BUFFER);
setUsage(GL_STREAM_DRAW_ARB);
}
UniformBufferObject::UniformBufferObject(const UniformBufferObject& ubo, const CopyOp& copyop)
: BufferObject(ubo, copyop)
{
}
UniformBufferObject::~UniformBufferObject()
{
}