root/OpenSceneGraph/trunk/src/osgUtil/IncrementalCompileOperation.cpp @ 9917

Revision 9917, 13.8 kB (checked in by robert, 5 years ago)

Moved IncrementalCompileOperation? out of include-src/osgUtil/GLObjectVisitor into their own files.

Added support to IncrementCompileOperation? for controlling how much time is alloted to compilation and flush

Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13#include <osgUtil/IncrementalCompileOperation>
14
15#include <osg/Drawable>
16#include <osg/Notify>
17#include <osg/Timer>
18#include <osg/GLObjects>
19
20#include <OpenThreads/ScopedLock>
21
22#include <algorithm>
23
24namespace osgUtil
25{
26
27IncrementalCompileOperation::IncrementalCompileOperation():
28    osg::GraphicsOperation("IncrementalCompileOperation",true),
29    _flushTimeRatio(0.5),
30    _conservativeTimeRatio(0.5)
31{
32    _targetFrameRate = 100.0;
33    _minimumTimeAvailableForGLCompileAndDeletePerFrame = 0.001; // 1ms.
34    _maximumNumOfObjectsToCompilePerFrame = 20;
35    const char* ptr = 0;
36    if( (ptr = getenv("OSG_MINIMUM_COMPILE_TIME_PER_FRAME")) != 0)
37    {
38        _minimumTimeAvailableForGLCompileAndDeletePerFrame = atof(ptr);
39    }
40
41    if( (ptr = getenv("OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME")) != 0)
42    {
43        _maximumNumOfObjectsToCompilePerFrame = atoi(ptr);
44    }
45}
46
47IncrementalCompileOperation::~IncrementalCompileOperation()
48{
49}
50
51void IncrementalCompileOperation::assignContexts(Contexts& contexts)
52{
53    for(Contexts::iterator itr = contexts.begin();
54        itr != contexts.end();
55        ++itr)
56    {
57        osg::GraphicsContext* gc = *itr;
58        addGraphicsContext(gc);
59    }
60}
61
62void IncrementalCompileOperation::removeContexts(Contexts& contexts)
63{
64    for(Contexts::iterator itr = contexts.begin();
65        itr != contexts.end();
66        ++itr)
67    {
68        osg::GraphicsContext* gc = *itr;
69        removeGraphicsContext(gc);
70    }
71}
72
73
74void IncrementalCompileOperation::addGraphicsContext(osg::GraphicsContext* gc)
75{
76    if (_contexts.count(gc)==0)
77    {
78        gc->add(this);
79        _contexts.insert(gc);
80    }
81}
82
83void IncrementalCompileOperation::removeGraphicsContext(osg::GraphicsContext* gc)
84{
85    if (_contexts.count(gc)!=0)
86    {
87        gc->remove(this);
88        _contexts.erase(gc);
89    }
90}
91
92void IncrementalCompileOperation::add(osg::Node* subgraphToCompile)
93{
94    osg::notify(osg::INFO)<<"IncrementalCompileOperation::add("<<subgraphToCompile<<")"<<std::endl;
95    add(new CompileSet(subgraphToCompile));
96}
97
98void IncrementalCompileOperation::add(osg::Group* attachmentPoint, osg::Node* subgraphToCompile)
99{
100    osg::notify(osg::INFO)<<"IncrementalCompileOperation::add("<<attachmentPoint<<", "<<subgraphToCompile<<")"<<std::endl;
101    add(new CompileSet(attachmentPoint, subgraphToCompile));
102}
103
104
105void IncrementalCompileOperation::add(CompileSet* compileSet, bool callBuildCompileMap)
106{
107    if (!compileSet) return;
108
109    if (compileSet->_subgraphToCompile.valid())
110    {
111        // force a compute of the bound of the subgraph to avoid the update traversal from having to do this work
112        // and reducing the change of frame drop.
113        compileSet->_subgraphToCompile->getBound();
114    }
115   
116    if (callBuildCompileMap) compileSet->buildCompileMap(_contexts);
117
118    osg::notify(osg::INFO)<<"IncrementalCompileOperation::add(CompileSet = "<<compileSet<<", "<<", "<<callBuildCompileMap<<")"<<std::endl;
119
120    OpenThreads::ScopedLock<OpenThreads::Mutex>  lock(_toCompileMutex);
121    _toCompile.push_back(compileSet);
122}
123
124void IncrementalCompileOperation::mergeCompiledSubgraphs()
125{
126    // osg::notify(osg::INFO)<<"IncrementalCompileOperation::mergeCompiledSubgraphs()"<<std::endl;
127
128    OpenThreads::ScopedLock<OpenThreads::Mutex>  compilded_lock(_compiledMutex);
129   
130    for(CompileSets::iterator itr = _compiled.begin();
131        itr != _compiled.end();
132        ++itr)
133    {
134        CompileSet* cs = itr->get();
135        if (cs->_attachmentPoint.valid())
136        {
137            cs->_attachmentPoint->addChild(cs->_subgraphToCompile.get());
138        }
139    }
140   
141    _compiled.clear();
142}
143
144class IncrementalCompileOperation::CollectStateToCompile : public osg::NodeVisitor
145{
146public:
147
148    CollectStateToCompile(GLObjectsVisitor::Mode mode):
149        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
150        _mode(mode) {}
151   
152    GLObjectsVisitor::Mode _mode;
153
154    typedef std::set<osg::Drawable*> DrawableSet;
155    typedef std::set<osg::StateSet*> StateSetSet;
156    typedef std::set<osg::Texture*> TextureSet;
157    typedef std::set<osg::Program*> ProgramSet;
158
159    DrawableSet _drawablesHandled;
160    StateSetSet _statesetsHandled;
161   
162    DrawableSet _drawables;
163    TextureSet _textures;
164    ProgramSet _programs;
165
166    void apply(osg::Node& node)
167    {
168        if (node.getStateSet())
169        {
170            apply(*(node.getStateSet()));
171        }
172
173        traverse(node);
174    }
175
176    void apply(osg::Geode& node)
177    {
178        if (node.getStateSet())
179        {
180            apply(*(node.getStateSet()));
181        }
182
183        for(unsigned int i=0;i<node.getNumDrawables();++i)
184        {
185            osg::Drawable* drawable = node.getDrawable(i);
186            if (drawable)
187            {
188                apply(*drawable);
189                if (drawable->getStateSet())
190                {
191                    apply(*(drawable->getStateSet()));
192                }
193            }
194        }
195    }
196
197    void apply(osg::Drawable& drawable)
198    {
199        if (_drawablesHandled.count(&drawable)!=0) return;
200
201        _drawablesHandled.insert(&drawable);
202
203        if (_mode&GLObjectsVisitor::SWITCH_OFF_DISPLAY_LISTS)
204        {
205            drawable.setUseDisplayList(false);
206        }
207
208        if (_mode&GLObjectsVisitor::SWITCH_ON_DISPLAY_LISTS)
209        {
210            drawable.setUseDisplayList(true);
211        }
212
213        if (_mode&GLObjectsVisitor::SWITCH_ON_VERTEX_BUFFER_OBJECTS)
214        {
215            drawable.setUseVertexBufferObjects(true);
216        }
217
218        if (_mode&GLObjectsVisitor::SWITCH_OFF_VERTEX_BUFFER_OBJECTS)
219        {
220            drawable.setUseVertexBufferObjects(false);
221        }
222
223        if (_mode&GLObjectsVisitor::COMPILE_DISPLAY_LISTS)
224        {
225            _drawables.insert(&drawable);
226        }
227
228    }
229
230    void apply(osg::StateSet& stateset)
231    {
232        if (_statesetsHandled.count(&stateset)!=0) return;
233
234        _statesetsHandled.insert(&stateset);
235
236        if (_mode & GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES)
237        {
238            osg::Program* program = dynamic_cast<osg::Program*>(stateset.getAttribute(osg::StateAttribute::PROGRAM));
239            if (program)
240            {
241                _programs.insert(program);
242            }
243           
244            osg::StateSet::TextureAttributeList& tal = stateset.getTextureAttributeList();
245            for(osg::StateSet::TextureAttributeList::iterator itr = tal.begin();
246                itr != tal.end();
247                ++itr)
248            {
249                osg::StateSet::AttributeList& al = *itr;
250                osg::StateAttribute::TypeMemberPair tmp(osg::StateAttribute::TEXTURE,0);
251                osg::StateSet::AttributeList::iterator texItr = al.find(tmp);
252                if (texItr != al.end())
253                {
254                    osg::Texture* texture = dynamic_cast<osg::Texture*>(texItr->second.first.get());
255                    if (texture) _textures.insert(texture);
256                }
257            }
258        }
259    }
260   
261};
262
263
264void IncrementalCompileOperation::CompileSet::buildCompileMap(ContextSet& contexts, GLObjectsVisitor::Mode mode)
265{
266    if (contexts.empty() || !_subgraphToCompile) return;
267   
268    CollectStateToCompile cstc(mode);
269    _subgraphToCompile->accept(cstc);
270   
271    if (cstc._textures.empty() &&  cstc._programs.empty() && cstc._drawables.empty()) return;
272   
273    for(ContextSet::iterator itr = contexts.begin();
274        itr != contexts.end();
275        ++itr)
276    {
277        CompileData& cd = _compileMap[*itr];
278        std::copy(cstc._textures.begin(), cstc._textures.end(), std::back_inserter<CompileData::Textures>(cd._textures));
279        std::copy(cstc._programs.begin(), cstc._programs.end(), std::back_inserter<CompileData::Programs>(cd._programs));
280        std::copy(cstc._drawables.begin(), cstc._drawables.end(), std::back_inserter<CompileData::Drawables>(cd._drawables));
281    }
282   
283}
284
285void IncrementalCompileOperation::operator () (osg::GraphicsContext* context)
286{
287    // osg::notify(osg::NOTICE)<<"IncrementalCompileOperation::operator () ("<<context<<")"<<std::endl;
288
289    osg::NotifySeverity level = osg::INFO;
290
291    double targetFrameRate = _targetFrameRate;
292    double minimumTimeAvailableForGLCompileAndDeletePerFrame = _minimumTimeAvailableForGLCompileAndDeletePerFrame;
293
294    double targetFrameTime = 1.0/targetFrameRate;
295   
296    const osg::FrameStamp* fs = context->getState()->getFrameStamp();
297    double currentTime = fs ? fs->getReferenceTime() : 0.0;
298
299    double currentElapsedFrameTime = context->getTimeSinceLastClear();
300   
301    osg::notify(level)<<"currentTime = "<<currentTime<<std::endl;
302    osg::notify(level)<<"currentElapsedFrameTime = "<<currentElapsedFrameTime<<std::endl;
303   
304    double _flushTimeRatio(0.5);
305    double _conservativeTimeRatio(0.5);
306
307    double availableTime = std::max((targetFrameTime - currentElapsedFrameTime)*_conservativeTimeRatio,
308                                    minimumTimeAvailableForGLCompileAndDeletePerFrame);
309
310    double flushTime = availableTime * _flushTimeRatio;
311    double compileTime = availableTime - flushTime;
312
313#if 1
314    osg::notify(level)<<"total availableTime = "<<availableTime*1000.0<<std::endl;
315    osg::notify(level)<<"      flushTime     = "<<flushTime*1000.0<<std::endl;
316    osg::notify(level)<<"      compileTime   = "<<compileTime*1000.0<<std::endl;
317#endif
318
319    osg::flushDeletedGLObjects(context->getState()->getContextID(), currentTime, flushTime);
320
321    // if any time left over from flush add this to compile time.       
322    if (flushTime>0.0) compileTime += flushTime;
323
324#if 1
325    osg::notify(level)<<"      revised compileTime   = "<<compileTime*1000.0<<std::endl;
326#endif
327
328
329    osg::RenderInfo renderInfo;
330    renderInfo.setState(context->getState());
331
332
333    CompileSets toCompileCopy;
334    {
335        OpenThreads::ScopedLock<OpenThreads::Mutex>  toCompile_lock(_toCompileMutex);
336        std::copy(_toCompile.begin(),_toCompile.end(),std::back_inserter<CompileSets>(toCompileCopy));
337    }
338
339    osg::Timer_t startTick = osg::Timer::instance()->tick();
340
341    for(CompileSets::iterator itr = toCompileCopy.begin();
342        itr != toCompileCopy.end();
343        ++itr)
344    {
345        CompileSet* cs = itr->get();
346        CompileMap& cm = cs->_compileMap;
347        CompileData& cd = cm[context];
348       
349        if (!cd.empty())
350        {
351            osg::notify(level)<<"cd._drawables.size()="<<cd._drawables.size()<<std::endl;
352            osg::notify(level)<<"cd._textures.size()="<<cd._textures.size()<<std::endl;
353            osg::notify(level)<<"cd._programs.size()="<<cd._programs.size()<<std::endl;
354   
355           
356            while(!cd._drawables.empty() &&
357                  osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()) < compileTime)
358            {
359                cd._drawables.back()->compileGLObjects(renderInfo);
360                cd._drawables.pop_back();
361            }
362           
363            while(!cd._textures.empty() &&
364                  osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()) < compileTime)
365            {
366                cd._textures.back()->apply(*renderInfo.getState());
367                cd._textures.pop_back();
368            }
369
370           
371            if (!cd._programs.empty())
372            {
373                // compile programs
374                while(!cd._programs.empty() &&
375                      osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()) < compileTime)
376                {
377                    cd._programs.back()->apply(*renderInfo.getState());
378                    cd._programs.pop_back();
379                }
380               
381                // switch off Program,
382                osg::GL2Extensions* extensions = osg::GL2Extensions::Get(renderInfo.getState()->getContextID(), true);
383                extensions->glUseProgram(0);
384                renderInfo.getState()->setLastAppliedProgramObject(0);
385            }
386        }
387               
388        if (cd.empty())
389        {
390            bool csCompleted = false;
391            {
392                OpenThreads::ScopedLock<OpenThreads::Mutex>  toCompile_lock(_toCompileMutex);
393
394                if (cs->compileCompleted())
395                {                   
396                    CompileSets::iterator cs_itr = std::find(_toCompile.begin(), _toCompile.end(), *itr);
397                    if (cs_itr != _toCompile.end())
398                    {
399                        osg::notify(level)<<"Erasing from list"<<std::endl;
400                       
401                        // remove from the _toCompile list, note cs won't be deleted here as the tempoary
402                        // toCompile_Copy list will retain a reference.
403                        _toCompile.erase(cs_itr);
404                       
405                        // signal that we need to do clean up operations/pass cs on to _compile list.
406                        csCompleted = true;
407                    }
408                }
409            }
410       
411            if (csCompleted && cs->_compileCompletedCallback.valid())
412            {
413                if (cs->_compileCompletedCallback->compileCompleted(cs))
414                {
415                    // callback will handle merging of subgraph so no need to place CompileSet in merge.
416                }
417                else
418                {
419                    OpenThreads::ScopedLock<OpenThreads::Mutex>  compilded_lock(_compiledMutex);
420                    _compiled.push_back(cs);
421                }
422            }
423           
424        }
425    }
426}
427
428} // end of namespace osgUtil
Note: See TracBrowser for help on using the browser.