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

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

From Mathias Froehlich, "We are currently getting issues with locale settings and some osg plugins.
Therefore I have changed all the occurances of atof by asciiToFloat or
asciiToDouble.

I believe that it is safe to do so at least for all the plugins.
Included here are also asciiToFloat conversion of environment variables. One
might argue that these should be locale dependent. But IMO these should be
set and interpreted by osg independent of the current locale.
"

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>
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    {
[10415]38        _minimumTimeAvailableForGLCompileAndDeletePerFrame = osg::asciiToDouble(ptr);
[9917]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.