/* -*-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 namespace osgUtil { IncrementalCompileOperation::IncrementalCompileOperation(): osg::GraphicsOperation("IncrementalCompileOperation",true), _flushTimeRatio(0.5), _conservativeTimeRatio(0.5) { _targetFrameRate = 100.0; _minimumTimeAvailableForGLCompileAndDeletePerFrame = 0.001; // 1ms. _maximumNumOfObjectsToCompilePerFrame = 20; const char* ptr = 0; if( (ptr = getenv("OSG_MINIMUM_COMPILE_TIME_PER_FRAME")) != 0) { _minimumTimeAvailableForGLCompileAndDeletePerFrame = osg::asciiToDouble(ptr); } if( (ptr = getenv("OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME")) != 0) { _maximumNumOfObjectsToCompilePerFrame = atoi(ptr); } } IncrementalCompileOperation::~IncrementalCompileOperation() { } void IncrementalCompileOperation::assignForceTextureDownloadGeometry() { osg::Geometry* geometry = new osg::Geometry; osg::Vec3Array* vertices = new osg::Vec3Array; vertices->push_back(osg::Vec3(0.0f,0.0f,0.0f)); geometry->setVertexArray(vertices); osg::Vec2Array* texcoords = new osg::Vec2Array; texcoords->push_back(osg::Vec2(0.0f,0.0f)); geometry->setTexCoordArray(0, texcoords); geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS,0,1)); osg::StateSet* stateset = geometry->getOrCreateStateSet(); stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); osg::Depth* depth = new osg::Depth; depth->setWriteMask(false); stateset->setAttribute(depth); osg::ColorMask* colorMask = new osg::ColorMask(false,false,false,false); stateset->setAttribute(colorMask); _forceTextureDownloadGeometry = geometry; } void IncrementalCompileOperation::assignContexts(Contexts& contexts) { for(Contexts::iterator itr = contexts.begin(); itr != contexts.end(); ++itr) { osg::GraphicsContext* gc = *itr; addGraphicsContext(gc); } } void IncrementalCompileOperation::removeContexts(Contexts& contexts) { for(Contexts::iterator itr = contexts.begin(); itr != contexts.end(); ++itr) { osg::GraphicsContext* gc = *itr; removeGraphicsContext(gc); } } void IncrementalCompileOperation::addGraphicsContext(osg::GraphicsContext* gc) { if (_contexts.count(gc)==0) { gc->add(this); _contexts.insert(gc); } } void IncrementalCompileOperation::removeGraphicsContext(osg::GraphicsContext* gc) { if (_contexts.count(gc)!=0) { gc->remove(this); _contexts.erase(gc); } } void IncrementalCompileOperation::add(osg::Node* subgraphToCompile) { OSG_INFO<<"IncrementalCompileOperation::add("<_subgraphToCompile.valid()) { // force a compute of the bound of the subgraph to avoid the update traversal from having to do this work // and reducing the change of frame drop. compileSet->_subgraphToCompile->getBound(); } if (callBuildCompileMap) compileSet->buildCompileMap(_contexts); OSG_INFO<<"IncrementalCompileOperation::add(CompileSet = "< lock(_toCompileMutex); _toCompile.push_back(compileSet); } void IncrementalCompileOperation::mergeCompiledSubgraphs() { // OSG_INFO<<"IncrementalCompileOperation::mergeCompiledSubgraphs()"< compilded_lock(_compiledMutex); for(CompileSets::iterator itr = _compiled.begin(); itr != _compiled.end(); ++itr) { CompileSet* cs = itr->get(); if (cs->_attachmentPoint.valid()) { cs->_attachmentPoint->addChild(cs->_subgraphToCompile.get()); } } _compiled.clear(); } class IncrementalCompileOperation::CollectStateToCompile : public osg::NodeVisitor { public: CollectStateToCompile(GLObjectsVisitor::Mode mode): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _mode(mode) {} GLObjectsVisitor::Mode _mode; typedef std::set DrawableSet; typedef std::set StateSetSet; typedef std::set TextureSet; typedef std::set ProgramSet; DrawableSet _drawablesHandled; StateSetSet _statesetsHandled; DrawableSet _drawables; TextureSet _textures; ProgramSet _programs; void apply(osg::Node& node) { if (node.getStateSet()) { apply(*(node.getStateSet())); } traverse(node); } void apply(osg::Geode& node) { if (node.getStateSet()) { apply(*(node.getStateSet())); } for(unsigned int i=0;igetStateSet()) { apply(*(drawable->getStateSet())); } } } } void apply(osg::Drawable& drawable) { if (_drawablesHandled.count(&drawable)!=0) return; _drawablesHandled.insert(&drawable); if (_mode&GLObjectsVisitor::SWITCH_OFF_DISPLAY_LISTS) { drawable.setUseDisplayList(false); } if (_mode&GLObjectsVisitor::SWITCH_ON_DISPLAY_LISTS) { drawable.setUseDisplayList(true); } if (_mode&GLObjectsVisitor::SWITCH_ON_VERTEX_BUFFER_OBJECTS) { drawable.setUseVertexBufferObjects(true); } if (_mode&GLObjectsVisitor::SWITCH_OFF_VERTEX_BUFFER_OBJECTS) { drawable.setUseVertexBufferObjects(false); } if (_mode&GLObjectsVisitor::COMPILE_DISPLAY_LISTS) { _drawables.insert(&drawable); } } void apply(osg::StateSet& stateset) { if (_statesetsHandled.count(&stateset)!=0) return; _statesetsHandled.insert(&stateset); if (_mode & GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES) { osg::Program* program = dynamic_cast(stateset.getAttribute(osg::StateAttribute::PROGRAM)); if (program) { _programs.insert(program); } osg::StateSet::TextureAttributeList& tal = stateset.getTextureAttributeList(); for(osg::StateSet::TextureAttributeList::iterator itr = tal.begin(); itr != tal.end(); ++itr) { osg::StateSet::AttributeList& al = *itr; osg::StateAttribute::TypeMemberPair tmp(osg::StateAttribute::TEXTURE,0); osg::StateSet::AttributeList::iterator texItr = al.find(tmp); if (texItr != al.end()) { osg::Texture* texture = dynamic_cast(texItr->second.first.get()); if (texture) _textures.insert(texture); } } } } }; void IncrementalCompileOperation::CompileSet::buildCompileMap(ContextSet& contexts, GLObjectsVisitor::Mode mode) { if (contexts.empty() || !_subgraphToCompile) return; CollectStateToCompile cstc(mode); _subgraphToCompile->accept(cstc); if (cstc._textures.empty() && cstc._programs.empty() && cstc._drawables.empty()) return; for(ContextSet::iterator itr = contexts.begin(); itr != contexts.end(); ++itr) { CompileData& cd = _compileMap[*itr]; std::copy(cstc._textures.begin(), cstc._textures.end(), std::back_inserter(cd._textures)); std::copy(cstc._programs.begin(), cstc._programs.end(), std::back_inserter(cd._programs)); std::copy(cstc._drawables.begin(), cstc._drawables.end(), std::back_inserter(cd._drawables)); } } void IncrementalCompileOperation::operator () (osg::GraphicsContext* context) { // OSG_NOTICE<<"IncrementalCompileOperation::operator () ("<getState()->getFrameStamp(); double currentTime = fs ? fs->getReferenceTime() : 0.0; double currentElapsedFrameTime = context->getTimeSinceLastClear(); OSG_NOTIFY(level)<<"currentTime = "<_compileCompletedCallback.valid() && cs->_compileCompletedCallback->compileCompleted(cs)) { // callback will handle merging of subgraph so no need to place CompileSet in merge. } else { OpenThreads::ScopedLock compilded_lock(_compiledMutex); _compiled.push_back(cs); } } } } } } // end of namespace osgUtil