/* -*-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. */ #ifndef OSGUTIL_INCREMENTALCOMPILEOPERATOR #define OSGUTIL_INCREMENTALCOMPILEOPERATOR #include #include namespace osgUtil { class CompileData : public osg::Referenced { public: CompileData() {} typedef std::set< osg::ref_ptr > Drawables; typedef std::set< osg::ref_ptr > Textures; typedef std::set< osg::ref_ptr > Programs; bool empty() const { return _drawables.empty() && _textures.empty() && _programs.empty(); } void reset() { _drawables.clear(); _textures.clear(); _programs.clear(); } Drawables _drawables; Textures _textures; Programs _programs; }; class OSGUTIL_EXPORT CompileStats : public osg::Referenced { public: CompileStats(); void add(const std::string& name,double size, double time); double estimateTime(const std::string& name, double size) const; double estimateTime2(const std::string& name, double size) const; double estimateTime3(const std::string& name, double size) const; double estimateTime4(const std::string& name, double size) const; double averageTime(const std::string& name) const; void print(std::ostream& out) const; protected: struct OSGUTIL_EXPORT Values { Values(): totalSize(0.0), totalTime(0.0), totalNum(0.0), minSize(0.0), minTime(0.0), a(0.0), b(0.0), m(0.0), n(0.0), o(0.0), p(0.0) {} void add(double size, double time); double estimateTime(double size) const { return a + b * size; } double estimateTime2(double size) const { return (totalTime/totalSize) * size; } double estimateTime3(double size) const { if (size StatsMap; StatsMap _statsMap; }; class OSGUTIL_EXPORT CompileOperator : public osg::Referenced { public: CompileOperator(); /** Assign a geometry and associated StateSet than is applied after each texture compile to atttempt to force the OpenGL * drive to download the texture object to OpenGL graphics card.*/ void assignForceTextureDownloadGeometry(); /** Set the osg::Geometry to apply after each texture compile to atttempt to force the OpenGL * drive to download the texture object to OpenGL graphics card.*/ void setForceTextureDownloadGeometry(osg::Geometry* geom) { _forceTextureDownloadGeometry = geom; } osg::Geometry* getForceTextureDownloadGeometry() { return _forceTextureDownloadGeometry.get(); } const osg::Geometry* getForceTextureDownloadGeometry() const { return _forceTextureDownloadGeometry.get(); } /** Compile as many elements in the CompileData container as possible within specified time. * return true if all have been compiled. */ virtual bool compile(osg::RenderInfo& renderInfo, CompileData& compileData, unsigned int& maxNumObjectsToCompile, double& availableTime); /** Compile all the elements in the CompileData container. */ void compileAll(osg::RenderInfo& renderInfo, CompileData& compileData) { unsigned int maxNumObjectsToCompile = 32768; double availableTime = DBL_MAX; compile(renderInfo, compileData, maxNumObjectsToCompile, availableTime); } CompileStats* getCompileStats() { return _compileStats.get(); } const CompileStats* getCompileStats() const { return _compileStats.get(); } protected: void runTimingTests(osg::RenderInfo& renderInfo); double timeCompile(osg::RenderInfo& renderInfo, osg::Geometry* geometry) const; double timeCompile(osg::RenderInfo& renderInfo, osg::StateSet* stateset) const; osg::Geometry* createTestGeometry(unsigned int numVertices, bool vbo) const; osg::StateSet* createTestStateSet(unsigned int imageSize, bool mipmapped) const; osg::ref_ptr _forceTextureDownloadGeometry; osg::ref_ptr _compileStats; bool _timingTestsCompleted; }; class OSGUTIL_EXPORT IncrementalCompileOperation : public osg::GraphicsOperation { public: IncrementalCompileOperation(); /** Set the target frame rate that the IncrementalCompileOperation should assume. * Typically one would set this to the value refresh rate of your display system i.e. 60Hz. * Default value is 100. * Usage notes. The TargetFrameRate and the MinimumTimeAvailableForGLCompileAndDeletePerFrame * parameters are not directly used by IncrementalCompileOperation, but are should be used as a guide for how * long to set aside per frame for compiling and deleting OpenGL objects. The longer amount of * time to set aside the faster databases will be paged in but with increased chance of frame drops, * the lower the amount of time the set aside the slower databases will paged it but with better * chance of avoid any frame drops. The default values are chosen to achieve the later when running * on a modern mid to high end PC. * The way to compute the amount of available time use a scheme such as : * availableTime = maximum(1.0/targetFrameRate - timeTakenDuringUpdateCullAndDraw, minimumTimeAvailableForGLCompileAndDeletePerFrame). */ void setTargetFrameRate(double tfr) { _targetFrameRate = tfr; } /** Get the target frame rate that the IncrementalCompileOperation should assume.*/ double getTargetFrameRate() const { return _targetFrameRate; } /** Set the minimum amount of time (in seconds) that should be made available for compiling and delete OpenGL objects per frame. * Default value is 0.001 (1 millisecond). * For usage see notes in setTargetFrameRate.*/ void setMinimumTimeAvailableForGLCompileAndDeletePerFrame(double ta) { _minimumTimeAvailableForGLCompileAndDeletePerFrame = ta; } /** Get the minimum amount of time that should be made available for compiling and delete OpenGL objects per frame. * For usage see notes in setTargetFrameRate.*/ double getMinimumTimeAvailableForGLCompileAndDeletePerFrame() const { return _minimumTimeAvailableForGLCompileAndDeletePerFrame; } /** Set the maximum number of OpenGL objects that the page should attempt to compile per frame. * Note, Lower values reduces chances of a frame drop but lower the rate that database will be paged in at. * Default value is 8. */ void setMaximumNumOfObjectsToCompilePerFrame(unsigned int num) { _maximumNumOfObjectsToCompilePerFrame = num; } /** Get the maximum number of OpenGL objects that the page should attempt to compile per frame.*/ unsigned int getMaximumNumOfObjectsToCompilePerFrame() const { return _maximumNumOfObjectsToCompilePerFrame; } /** FlushTimeRatio governs how much of the spare time in each frame is used for flushing deleted OpenGL objects. * Default value is 0.5, valid range is 0.1 to 0.9.*/ void setFlushTimeRatio(double ratio) { _flushTimeRatio = ratio; } double getFlushTimeRatio() const { return _flushTimeRatio; } /** ConservativeTimeRatio governs how much of the measured spare time in each frame is used for flushing deleted and compile new OpenGL objects. * Default value is 0.5, valid range is 0.1 to 1.0. * A ratio near 1.0 will lead to paged databases being compiled and merged quicker but increase the chances of frame drop. * A ratio near 0.1 will lead to paged databases being compiled and merged closer but reduse the chances of frame drop.*/ void setConservativeTimeRatio(double ratio) { _conservativeTimeRatio = ratio; } double getConservativeTimeRatio() const { return _conservativeTimeRatio; } typedef std::vector Contexts; void assignContexts(Contexts& contexts); void removeContexts(Contexts& contexts); void addGraphicsContext(osg::GraphicsContext* gc); void removeGraphicsContext(osg::GraphicsContext* gc); /** Merge subgraphs that have been compiled.*/ void mergeCompiledSubgraphs(); virtual void operator () (osg::GraphicsContext* context); class CompileSet; typedef std::set ContextSet; typedef std::map CompileMap; struct CompileCompletedCallback : public virtual osg::Referenced { /// return true if the callback assumes responsibility for merging any associated subgraphs with the main scene graph /// return false if callback doesn't handle the merge, and instead requires the IncrementalCompileOperation to handle this for us virtual bool compileCompleted(CompileSet* compileSet) = 0; }; class OSGUTIL_EXPORT CompileSet : public osg::Referenced { public: CompileSet() {} CompileSet(osg::Node*subgraphToCompile): _subgraphToCompile(subgraphToCompile) {} CompileSet(osg::Group* attachmentPoint, osg::Node*subgraphToCompile): _attachmentPoint(attachmentPoint), _subgraphToCompile(subgraphToCompile) {} void buildCompileMap(ContextSet& context, GLObjectsVisitor::Mode mode=GLObjectsVisitor::COMPILE_DISPLAY_LISTS|GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES); bool compileCompleted() const { for(CompileMap::const_iterator itr = _compileMap.begin(); itr != _compileMap.end(); ++itr) { if (!(itr->second.empty())) return false; } return true; } osg::observer_ptr _attachmentPoint; osg::ref_ptr _subgraphToCompile; osg::ref_ptr _compileCompletedCallback; CompileMap _compileMap; // protected: virtual ~CompileSet() {} }; typedef std::list< osg::ref_ptr > CompileSets; /** Add a subgraph to be compiled.*/ void add(osg::Node* subgraphToCompile); /** Add a subgraph to be compiled and add automatically to attachPoint on call to mergeCompiledSubgraphs.*/ void add(osg::Group* attachmentPoint, osg::Node* subgraphToCompile); /** Add a CompileSet to be compiled.*/ void add(CompileSet* compileSet, bool callBuildCompileMap=true); /** Remove CompileSet from list.*/ void remove(CompileSet* compileSet); OpenThreads::Mutex* getToCompiledMutex() { return &_toCompileMutex; } CompileSets& getToCompile() { return _toCompile; } OpenThreads::Mutex* getCompiledMutex() { return &_compiledMutex; } CompileSets& getCompiled() { return _compiled; } void setCompileOperator(CompileOperator* compileOperator) { _compileOperator = compileOperator; } CompileOperator* getCompileOperator() { return _compileOperator.get(); } const CompileOperator* getCompileOperator() const { return _compileOperator.get(); } /** Assign a geometry and associated StateSet than is applied after each texture compile to atttempt to force the OpenGL * drive to download the texture object to OpenGL graphics card.*/ void assignForceTextureDownloadGeometry(); protected: virtual ~IncrementalCompileOperation(); // forward declare to keep within class namespace class CollectStateToCompile; double _targetFrameRate; double _minimumTimeAvailableForGLCompileAndDeletePerFrame; unsigned int _maximumNumOfObjectsToCompilePerFrame; double _flushTimeRatio; double _conservativeTimeRatio; osg::ref_ptr _compileOperator; OpenThreads::Mutex _toCompileMutex; CompileSets _toCompile; OpenThreads::Mutex _compiledMutex; CompileSets _compiled; ContextSet _contexts; }; } #endif