/* -*-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 #include #include #include #include #include #include #include #include #include #include #include #include // #define CHECK_CONSISTENCY 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 BufferObjectMap; typedef osg::buffered_object DeletedBufferObjectCache; static OpenThreads::Mutex s_mutex_deletedBufferObjectCache; static DeletedBufferObjectCache s_deletedBufferObjectCache; unsigned int s_minimumNumberOfGLBufferObjectsToRetainInCache = 1000; ////////////////////////////////////////////////////////////////////////////////////////////////////// // // 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), _extensions(0) { assign(bufferObject); _extensions = GLBufferObject::getExtensions(contextID, true); if (glObjectID==0) { _extensions->glGenBuffers(1, &_glObjectID); } // OSG_NOTICE<<"Constucting 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 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 = entry.offset + entry.dataSize; // OSG_NOTICE<<"GLBufferObject::compileBuffer(..) updating BufferEntry"<getTotalDataSize(); entry.dataSource = bd; newTotalSize += entry.dataSize; if (previousEndOfBufferDataMarker!=newTotalSize) { offsetChanged = true; } } else newTotalSize += entry.dataSize; } else { BufferEntry entry; entry.offset = newTotalSize; entry.modifiedCount = 0xffffff; entry.dataSize = bd->getTotalDataSize(); entry.dataSource = bd; #if 0 OSG_NOTICE<<"entry"<glBindBuffer(_profile._target, _glObjectID); if (newTotalSize > _profile._size) { OSG_INFO<<"newTotalSize="<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() { OSG_INFO<<"GLBufferObject::deleteGLObject() "<<_glObjectID<glDeleteBuffers(1, &_glObjectID); _glObjectID = 0; _allocatedSize = 0; _bufferEntries.clear(); } } ////////////////////////////////////////////////////////////////////////////// // // Extension support // typedef buffered_value< ref_ptr > 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_GL3_FEATURES || osg::isGLExtensionSupported(contextID,"GL_ARB_pixel_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"<getContextID()), _profile(profile), _numOfGLBufferObjects(0), _head(0), _tail(0) { OSG_INFO<<"GLBufferObjectSet::GLBufferObjectSet _profile._size="<<_profile._size<_next) { if ((to->_next)->_previous != to) { OSG_NOTICE<<"GLBufferObjectSet::checkConsistency() : Error (to->_next)->_previous != to "<_next; } unsigned int totalNumber = numInList + _orphanedGLBufferObjects.size(); if (totalNumber != _numOfGLBufferObjects) { OSG_NOTICE<<"Error numInList + _orphanedGLBufferObjects.size() != _numOfGLBufferObjects"<get(); _orphanedGLBufferObjects.push_back(to); remove(to); #if 0 OSG_NOTICE<<" HPOTO after _head = "<<_head<_previous = "<_previous<_next = "<_next<getNumberOrphanedGLBufferObjects() += numOrphaned; _parent->getNumberActiveGLBufferObjects() -= numOrphaned; _pendingOrphanedGLBufferObjects.clear(); checkConsistency(); } void GLBufferObjectSet::deleteAllGLBufferObjects() { // OSG_NOTICE<<"GLBufferObjectSet::deleteAllGLBufferObjects()"< glbo = to; to = to->_next; _orphanedGLBufferObjects.push_back(glbo.get()); remove(glbo.get()); ref_ptr original_BufferObject = glbo->getBufferObject(); if (original_BufferObject.valid()) { // detect the GLBufferObject from the BufferObject original_BufferObject->setGLBufferObject(_contextID,0); } } _head = 0; _tail = 0; // clean up the pending orphans. handlePendingOrphandedGLBufferObjects(); // do the actual delete. flushAllDeletedGLBufferObjects(); // OSG_NOTICE<<"done GLBufferObjectSet::deleteAllGLBufferObjects()"< glbo = to; to = to->_next; ref_ptr 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() { 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()"<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()deleteGLObject(); ++numDeleted; } // OSG_NOTICE<<"Size before = "<<_orphanedGLBufferObjects.size(); _orphanedGLBufferObjects.erase(_orphanedGLBufferObjects.begin(), itr); //OSG_NOTICE<<", after = "<<_orphanedGLBufferObjects.size()<<" numDeleted = "<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 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_NOTICE<<"Reusing orhpahned GLBufferObject, _numOfGLBufferObjects="<<_numOfGLBufferObjects< 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 lock(_mutex); ref_ptr glbo = _head; ref_ptr original_BufferObject = glbo->getBufferObject(); if (original_BufferObject.valid()) { original_BufferObject->setGLBufferObject(_contextID,0); // OSG_NOTICE<<"GLBufferObjectSet="<setBufferObject(bufferObject); glbo->setProfile(_profile); return glbo.release(); } // GLBufferObject* glbo = new GLBufferObject(_contextID, const_cast(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<_previous = "<_previous<_next = "<_next<_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 !!!!!!!!!"<_next==0) { OSG_NOTICE<<"Error ***************** Should not get here either !!!!!!!!!"<_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<_previous = "<_previous<_next = "<_next<_previous = "<_previous<_next = "<_next<_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<_previous = "<_previous<_next = "<_next< 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); } 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="<getFrameNumber(); else ++_frameNumber; ++_numFrames; } void GLBufferObjectManager::reportStats() { double numFrames(_numFrames==0 ? 1.0 : _numFrames); OSG_NOTICE<<"GLBufferObjectMananger::reportStats()"<& GLBufferObjectManager::getGLBufferObjectManager(unsigned int contextID) { typedef osg::buffered_object< ref_ptr > 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() { } 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 { // OSG_NOTICE<<"BufferObject::releaseGLObjects("<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("<getBufferIndex(); } // bd->setBufferIndex(_bufferDataList.size()); _bufferDataList.push_back(bd); // OSG_NOTICE<<"BufferObject "< glBufferObject = new GLBufferObject(contextID, 0, globj); GLBufferObjectSet* bufferObjectSet = bufferObjectManager->getGLBufferObjectSet(glBufferObject->getProfile()); if (!bufferObjectSet) { OSG_NOTICE<<"Warning::BufferObject::deleteBufferObject("<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; } ////////////////////////////////////////////////////////////////////////////////// // // 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(getBufferData(i)); } const Array* VertexBufferObject::getArray(unsigned int i) const { return dynamic_cast(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(getBufferData(i)); } const DrawElements* ElementBufferObject::getDrawElements(unsigned int i) const { return dynamic_cast(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="<(getBufferData(0)); } const Image* PixelBufferObject::getImage() const { return dynamic_cast(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); }