/* -*-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 #include #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 "<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"<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"<glBindBuffer(_profile._target, _glObjectID); if (newTotalSize > _profile._size) { OSG_INFO<<"newTotalSize="<getModifiedCount(); _extensions->glBufferSubData(_profile._target, (GLintptrARB)entry.offset, (GLsizeiptrARB)entry.dataSize, entry.dataSource->getDataPointer()); } } } 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; _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"<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); } // 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()"< lock(_mutex); if (!_pendingOrphanedGLBufferObjects.empty()) { // OSG_NOTICE<<"GLBufferObjectSet::flushDeletedGLBufferObjects(..) handling orphans"< glbo = to; to = to->_next; _orphanedGLBufferObjects.push_back(glbo.get()); remove(glbo.get()); ++numOrphaned; ref_ptr 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()"< 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() { { OpenThreads::ScopedLock lock(_mutex); if (!_pendingOrphanedGLBufferObjects.empty()) { // OSG_NOTICE<<"GLBufferObjectSet::flushDeletedGLBufferObjects(..) handling orphans"<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()"< lock(_mutex); if (!_pendingOrphanedGLBufferObjects.empty()) { // OSG_NOTICE<<"GLBufferObjectSet::flushDeletedGLBufferObjects(..) handling orphans"<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 lock(_mutex); if (!_pendingOrphanedGLBufferObjects.empty()) { // OSG_NOTICE<<"GLBufferObjectSet::flushDeletedGLBufferObjects(..) handling orphans"<getCurrGLBufferObjectPoolSize()<=_parent->getMaxGLBufferObjectPoolSize()) { OSG_INFO<<"Plenty of space in GLBufferObject pool"<getCurrGLBufferObjectPoolSize() - _parent->getMaxGLBufferObjectPoolSize(); unsigned int maxNumObjectsToDelete = static_cast(ceil(double(sizeRequired) / double(_profile._size))); OSG_INFO<<"_parent->getCurrGLBufferObjectPoolSize()="<<_parent->getCurrGLBufferObjectPoolSize() <<" _parent->getMaxGLBufferObjectPoolSize()="<< _parent->getMaxGLBufferObjectPoolSize()<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) { { OpenThreads::ScopedLock lock(_mutex); if (!_pendingOrphanedGLBufferObjects.empty()) { // OSG_NOTICE<<"GLBufferSet::::makeSpace(..) handling orphans"<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 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="< 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 lock(_mutex); ref_ptr glbo = _head; ref_ptr original_BufferObject = glbo->getBufferObject(); if (original_BufferObject.valid()) { original_BufferObject->setGLBufferObject(_contextID,0); OSG_INFO<<"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); } 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="<getFrameNumber(); else ++_frameNumber; ++_numFrames; } void GLBufferObjectManager::reportStats(std::ostream& out) { double numFrames(_numFrames==0 ? 1.0 : _numFrames); out<<"GLBufferObjectMananger::reportStats()"<second.get(); numObjectsInLists += os->computeNumGLBufferObjectsInList(); numActive += os->getNumOfGLBufferObjects(); numOrphans += os->getNumOrphans(); numPendingOrphans += os->getNumPendingOrphans(); currentSize += os->getProfile()._size * (os->computeNumGLBufferObjectsInList()+os->getNumOrphans()); out<<" size="<getProfile()._size <<", os->computeNumGLBufferObjectsInList()"<computeNumGLBufferObjectsInList() <<", os->getNumOfGLBufferObjects()"<getNumOfGLBufferObjects() <<", os->getNumOrphans()"<getNumOrphans() <<", os->getNumPendingOrphans()"<getNumPendingOrphans() <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); dirty(); //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; } void BufferData::resizeGLObjectBuffers(unsigned int maxSize) { if (_bufferObject.valid()) { _bufferObject->resizeGLObjectBuffers(maxSize); } } void BufferData::releaseGLObjects(State* state) const { OSG_INFO<<"BufferData::releaseGLObjects("<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(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); } UniformBufferObject::UniformBufferObject() { setTarget(GL_UNIFORM_BUFFER); setUsage(GL_STREAM_DRAW_ARB); } UniformBufferObject::UniformBufferObject(const UniformBufferObject& ubo, const CopyOp& copyop) : BufferObject(ubo, copyop) { } UniformBufferObject::~UniformBufferObject() { }