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

Revision 10764, 13.8 kB (checked in by robert, 4 years ago)

<iterator>, <stdlib.h> and <ctype.h> includes required for QNX compiler

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