/* -*-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 #include #include #include using namespace osg; static unsigned int s_minimumNumberOfDisplayListsToRetainInCache = 0; void Drawable::setMinimumNumberOfDisplayListsToRetainInCache(unsigned int minimum) { s_minimumNumberOfDisplayListsToRetainInCache = minimum; } unsigned int Drawable::getMinimumNumberOfDisplayListsToRetainInCache() { return s_minimumNumberOfDisplayListsToRetainInCache; } class DisplayListManager : public GraphicsObjectManager { public: DisplayListManager(unsigned int contextID): GraphicsObjectManager("DisplayListManager", contextID), _numberDrawablesReusedLastInLastFrame(0), _numberNewDrawablesInLastFrame(0), _numberDeletedDrawablesInLastFrame(0) { } virtual void flushDeletedGLObjects(double, double& availableTime) { #ifdef OSG_GL_DISPLAYLISTS_AVAILABLE // OSG_NOTICE<<"void DisplayListManager::flushDeletedGLObjects(, "< lock(_mutex_deletedDisplayListCache); unsigned int prev_size = _displayListMap.size(); // trim from front DisplayListMap::iterator ditr=_displayListMap.begin(); unsigned int maxNumToDelete = (_displayListMap.size() > s_minimumNumberOfDisplayListsToRetainInCache) ? _displayListMap.size()-s_minimumNumberOfDisplayListsToRetainInCache : 0; for(; ditr!=_displayListMap.end() && elapsedTimesecond,1); elapsedTime = timer.delta_s(start_tick,timer.tick()); ++noDeleted; ++_numberDeletedDrawablesInLastFrame; } if (ditr!=_displayListMap.begin()) _displayListMap.erase(_displayListMap.begin(),ditr); if (noDeleted+_displayListMap.size() != prev_size) { OSG_WARN<<"Error in delete"< lock(_mutex_deletedDisplayListCache); for(DisplayListMap::iterator ditr=_displayListMap.begin(); ditr!=_displayListMap.end(); ++ditr) { glDeleteLists(ditr->second,1); } _displayListMap.clear(); #else OSG_INFO<<"Warning: Drawable::deleteDisplayList(..) - not supported."< lock(_mutex_deletedDisplayListCache); _displayListMap.clear(); } void deleteDisplayList(GLuint globj, unsigned int sizeHint) { #ifdef OSG_GL_DISPLAYLISTS_AVAILABLE if (globj!=0) { OpenThreads::ScopedLock lock(_mutex_deletedDisplayListCache); // insert the globj into the cache for the appropriate context. _displayListMap.insert(DisplayListMap::value_type(sizeHint,globj)); } #else OSG_INFO<<"Warning: Drawable::deleteDisplayList(..) - not supported."< lock(_mutex_deletedDisplayListCache); if (_displayListMap.empty()) { ++_numberNewDrawablesInLastFrame; return glGenLists( 1 ); } else { DisplayListMap::iterator itr = _displayListMap.lower_bound(sizeHint); if (itr!=_displayListMap.end()) { // OSG_NOTICE<<"Reusing a display list of size = "<first<<" for requested size = "<second; _displayListMap.erase(itr); return globj; } else { // OSG_NOTICE<<"Creating a new display list of size = "< DisplayListMap; OpenThreads::Mutex _mutex_deletedDisplayListCache; DisplayListMap _displayListMap; }; GLuint Drawable::generateDisplayList(unsigned int contextID, unsigned int sizeHint) { return osg::get(contextID)->generateDisplayList(sizeHint); } void Drawable::deleteDisplayList(unsigned int contextID,GLuint globj, unsigned int sizeHint) { osg::get(contextID)->deleteDisplayList(globj, sizeHint); } Drawable::Drawable() { // Note, if your are defining a subclass from drawable which is // dynamically updated then you should set both the following to // to false in your constructor. This will prevent any display // lists from being automatically created and safeguard the // dynamic updating of data. #ifdef OSG_GL_DISPLAYLISTS_AVAILABLE _supportsDisplayList = true; _useDisplayList = true; #else _supportsDisplayList = false; _useDisplayList = false; #endif #if 0 _supportsVertexBufferObjects = false; //_useVertexBufferObjects = false; _useVertexBufferObjects = false; #else _supportsVertexBufferObjects = true; _useVertexBufferObjects = true; #endif _useVertexArrayObject = false; } Drawable::Drawable(const Drawable& drawable,const CopyOp& copyop): Node(drawable,copyop), _initialBound(drawable._initialBound), _computeBoundCallback(drawable._computeBoundCallback), _boundingBox(drawable._boundingBox), _shape(copyop(drawable._shape.get())), _supportsDisplayList(drawable._supportsDisplayList), _useDisplayList(drawable._useDisplayList), _supportsVertexBufferObjects(drawable._supportsVertexBufferObjects), _useVertexBufferObjects(drawable._useVertexBufferObjects), _useVertexArrayObject(drawable._useVertexArrayObject), _drawCallback(drawable._drawCallback), _createVertexArrayStateCallback(drawable._createVertexArrayStateCallback) { setStateSet(copyop(drawable._stateset.get())); } Drawable::~Drawable() { dirtyGLObjects(); } osg::MatrixList Drawable::getWorldMatrices(const osg::Node* haltTraversalAtNode) const { osg::MatrixList matrices; for(ParentList::const_iterator itr = _parents.begin(); itr != _parents.end(); ++itr) { osg::MatrixList localMatrices = (*itr)->getWorldMatrices(haltTraversalAtNode); matrices.insert(matrices.end(), localMatrices.begin(), localMatrices.end()); } return matrices; } void Drawable::computeDataVariance() { if (getDataVariance() != UNSPECIFIED) return; bool dynamic = false; if (getUpdateCallback() || getEventCallback() || getCullCallback()) { dynamic = true; } setDataVariance(dynamic ? DYNAMIC : STATIC); } void Drawable::setThreadSafeRefUnref(bool threadSafe) { Object::setThreadSafeRefUnref(threadSafe); if (_stateset.valid()) _stateset->setThreadSafeRefUnref(threadSafe); if (_drawCallback.valid()) _drawCallback->setThreadSafeRefUnref(threadSafe); } void Drawable::resizeGLObjectBuffers(unsigned int maxSize) { if (_stateset.valid()) _stateset->resizeGLObjectBuffers(maxSize); if (_drawCallback.valid()) _drawCallback->resizeGLObjectBuffers(maxSize); _globjList.resize(maxSize); _vertexArrayStateList.resize(maxSize); } void Drawable::releaseGLObjects(State* state) const { if (_stateset.valid()) _stateset->releaseGLObjects(state); if (_drawCallback.valid()) _drawCallback->releaseGLObjects(state); if (state) { // get the contextID (user defined ID of 0 upwards) for the // current OpenGL context. unsigned int contextID = state->getContextID(); if (_useDisplayList) { // get the globj for the current contextID. GLuint& globj = _globjList[contextID]; // call the globj if already set otherwise compile and execute. if( globj != 0 ) { Drawable::deleteDisplayList(contextID,globj, getGLObjectSizeHint()); globj = 0; } } VertexArrayState* vas = contextID <_vertexArrayStateList.size() ? _vertexArrayStateList[contextID].get() : 0; if (vas) { vas->release(); _vertexArrayStateList[contextID] = 0; } } else { const_cast(this)->dirtyGLObjects(); } } void Drawable::setSupportsDisplayList(bool flag) { // if value unchanged simply return. if (_supportsDisplayList==flag) return; #ifdef OSG_GL_DISPLAYLISTS_AVAILABLE // if previously set to true then need to check about display lists. if (_supportsDisplayList) { if (_useDisplayList) { // used to support display lists and display lists switched // on so now delete them and turn useDisplayList off. dirtyGLObjects(); _useDisplayList = false; } } // set with new value. _supportsDisplayList=flag; #else _supportsDisplayList=false; #endif } void Drawable::setUseDisplayList(bool flag) { // if value unchanged simply return. if (_useDisplayList==flag) return; #ifdef OSG_GL_DISPLAYLISTS_AVAILABLE // if was previously set to true, remove display list. if (_useDisplayList) { dirtyGLObjects(); } if (_supportsDisplayList) { // set with new value. _useDisplayList = flag; } else // does not support display lists. { if (flag) { OSG_WARN<<"Warning: attempt to setUseDisplayList(true) on a drawable with does not support display lists."<dirty(); } } struct ComputeBound : public PrimitiveFunctor { ComputeBound() { _vertices2f = 0; _vertices3f = 0; _vertices4f = 0; _vertices2d = 0; _vertices3d = 0; _vertices4d = 0; } virtual void setVertexArray(unsigned int,const Vec2* vertices) { _vertices2f = vertices; } virtual void setVertexArray(unsigned int,const Vec3* vertices) { _vertices3f = vertices; } virtual void setVertexArray(unsigned int,const Vec4* vertices) { _vertices4f = vertices; } virtual void setVertexArray(unsigned int,const Vec2d* vertices) { _vertices2d = vertices; } virtual void setVertexArray(unsigned int,const Vec3d* vertices) { _vertices3d = vertices; } virtual void setVertexArray(unsigned int,const Vec4d* vertices) { _vertices4d = vertices; } template void _drawArrays(T* vert, T* end) { for(;vert void _drawElements(T* vert, I* indices, I* end) { for(;indices(this); non_const_this->accept(cb); #if 0 OSG_NOTICE<<"computeBound() "<useVertexBufferObject(_supportsVertexBufferObjects && _useVertexBufferObjects) && _useDisplayList) { // get the contextID (user defined ID of 0 upwards) for the // current OpenGL context. unsigned int contextID = renderInfo.getContextID(); // get the globj for the current contextID. GLuint& globj = _globjList[contextID]; // call the globj if already set otherwise compile and execute. if( globj != 0 ) { glDeleteLists( globj, 1 ); } globj = generateDisplayList(contextID, getGLObjectSizeHint()); glNewList( globj, GL_COMPILE ); drawInner(renderInfo); glEndList(); } #endif } #ifndef INLINE_DRAWABLE_DRAW void Drawable::draw(RenderInfo& renderInfo) const { State& state = *renderInfo.getState(); bool useVertexArrayObject = state.useVertexArrayObject(_useVertexArrayObject); if (useVertexArrayObject) { unsigned int contextID = renderInfo.getContextID(); VertexArrayState* vas = _vertexArrayStateList[contextID].get(); if (!vas) { _vertexArrayStateList[contextID] = vas = createVertexArrayState(renderInfo); } else { // vas->setRequiresSetArrays(getDataVariance()==osg::Object::DYNAMIC); } State::SetCurrentVertexArrayStateProxy setVASProxy(state, vas); state.bindVertexArrayObject(vas); drawInner(renderInfo); vas->setRequiresSetArrays(getDataVariance()==osg::Object::DYNAMIC); return; } // TODO, add check against whether VAO is active and supported if (state.getCurrentVertexArrayState()) { //OSG_NOTICE<<"state.getCurrentVertexArrayState()->getVertexArrayObject()="<< state.getCurrentVertexArrayState()->getVertexArrayObject()<assignAllDispatchers(); return vos; }