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 #include <osg/Depth>
20 #include <osg/ColorMask>
21 #include <osg/ApplicationUsage>
22 
23 #include <OpenThreads/ScopedLock>
24 
25 #include <algorithm>
26 #include <iterator>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 namespace osgUtil
31 {
32 
33 
34 // TODO
35 // priority of CompileSets
36 // isCompiled
37 // time estimation
38 // early completion
39 // needs compile given time slot
40 // custom CompileData elements
41 // pruneOldRequestsAndCheckIfEmpty()
42 // Use? :
43 //                     #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
44 //                        GLint p;
45 //                        glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_RESIDENT, &p);
46 //                    #endif
47 
48 static osg::ApplicationUsageProxy ICO_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MINIMUM_COMPILE_TIME_PER_FRAME <float>","minimum compile time alloted to compiling OpenGL objects per frame in database pager.");
49 static osg::ApplicationUsageProxy UCO_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME <int>","maximum number of OpenGL objects to compile per frame in database pager.");
50 static osg::ApplicationUsageProxy UCO_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FORCE_TEXTURE_DOWNLOAD <ON/OFF>","should the texture compiles be forced to download using a dummy Geometry.");
51 
52 /////////////////////////////////////////////////////////////////
53 //
54 // CollectStateToCompile
55 //
StateToCompile(GLObjectsVisitor::Mode mode,osg::Object * markerObject)56 StateToCompile::StateToCompile(GLObjectsVisitor::Mode mode, osg::Object* markerObject):
57     osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
58     _mode(mode),
59     _assignPBOToImages(false),
60     _markerObject(markerObject)
61 {
62 }
63 
apply(osg::Node & node)64 void StateToCompile::apply(osg::Node& node)
65 {
66     if (node.getStateSet())
67     {
68         apply(*(node.getStateSet()));
69     }
70 
71     traverse(node);
72 }
73 
apply(osg::Drawable & drawable)74 void StateToCompile::apply(osg::Drawable& drawable)
75 {
76     if (_drawablesHandled.count(&drawable)!=0) return;
77 
78     _drawablesHandled.insert(&drawable);
79 
80     if (!_markerObject || _markerObject.get()!=drawable.getUserData())
81     {
82         if (drawable.getDataVariance()!=osg::Object::STATIC)
83         {
84             if (_mode&GLObjectsVisitor::SWITCH_OFF_DISPLAY_LISTS)
85             {
86                 drawable.setUseDisplayList(false);
87             }
88 
89             if (_mode&GLObjectsVisitor::SWITCH_ON_DISPLAY_LISTS)
90             {
91                 drawable.setUseDisplayList(true);
92             }
93 
94             if (_mode&GLObjectsVisitor::SWITCH_ON_VERTEX_BUFFER_OBJECTS)
95             {
96                 drawable.setUseVertexBufferObjects(true);
97             }
98 
99             if (_mode&GLObjectsVisitor::SWITCH_OFF_VERTEX_BUFFER_OBJECTS)
100             {
101                 drawable.setUseVertexBufferObjects(false);
102             }
103         }
104 
105         if (_mode&GLObjectsVisitor::COMPILE_DISPLAY_LISTS &&
106             (drawable.getUseDisplayList() || drawable.getUseVertexBufferObjects()))
107         {
108             _drawables.insert(&drawable);
109         }
110 
111         if (drawable.getStateSet())
112         {
113             apply(*(drawable.getStateSet()));
114         }
115 
116         // mark the drawable as visited
117         if (_markerObject.valid() && drawable.getUserData()==0) drawable.setUserData(_markerObject.get());
118     }
119 }
120 
apply(osg::StateSet & stateset)121 void StateToCompile::apply(osg::StateSet& stateset)
122 {
123     if (_statesetsHandled.count(&stateset)!=0) return;
124 
125     _statesetsHandled.insert(&stateset);
126 
127     if ((_mode & GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES)!=0 &&
128         (!_markerObject || _markerObject.get()!=stateset.getUserData()))
129     {
130         osg::Program* program = dynamic_cast<osg::Program*>(stateset.getAttribute(osg::StateAttribute::PROGRAM));
131         if (program && (!_markerObject || _markerObject.get()!=program->getUserData()))
132         {
133             _programs.insert(program);
134 
135             // mark the stateset as visited
136             if (_markerObject.valid() && program->getUserData()==0) program->setUserData(_markerObject.get());
137         }
138 
139         const osg::StateSet::TextureAttributeList& tal = stateset.getTextureAttributeList();
140 
141         for(osg::StateSet::TextureAttributeList::const_iterator itr = tal.begin();
142             itr != tal.end();
143             ++itr)
144         {
145             const osg::StateSet::AttributeList& al = *itr;
146             osg::StateAttribute::TypeMemberPair tmp(osg::StateAttribute::TEXTURE,0);
147             osg::StateSet::AttributeList::const_iterator texItr = al.find(tmp);
148             if (texItr != al.end())
149             {
150                 osg::Texture* texture = dynamic_cast<osg::Texture*>(texItr->second.first.get());
151                 if (texture)
152                 {
153                     if (_textures.count(texture)==0)
154                     {
155                         apply(*texture);
156                     }
157                 }
158             }
159         }
160 
161         // mark the stateset as visited
162         if (_markerObject.valid() && stateset.getUserData()==0) stateset.setUserData(_markerObject.get());
163     }
164 }
165 
apply(osg::Texture & texture)166 void StateToCompile::apply(osg::Texture& texture)
167 {
168     // don't make any changes if Texture already processed
169     if (_markerObject.valid() && _markerObject.get()==texture.getUserData()) return;
170 
171     if (_assignPBOToImages)
172     {
173         unsigned int numRequringPBO = 0;
174         osg::ref_ptr<osg::PixelBufferObject> pbo = 0;
175         for(unsigned int i=0; i<texture.getNumImages(); ++i)
176         {
177             osg::Image* image = texture.getImage(i);
178             if (image)
179             {
180                 if (image->getPixelBufferObject())
181                 {
182                     pbo = image->getPixelBufferObject();
183                 }
184                 else
185                 {
186                     ++numRequringPBO;
187                 }
188             }
189         }
190         if (numRequringPBO>0)
191         {
192             // assign pbo
193             if (!pbo)
194             {
195                 if (!_pbo) _pbo = new osg::PixelBufferObject;
196                 pbo = _pbo;
197             }
198 
199             for(unsigned int i=0; i<texture.getNumImages(); ++i)
200             {
201                 osg::Image* image = texture.getImage(i);
202                 if (image)
203                 {
204                     if (!image->getPixelBufferObject())
205                     {
206                         //OSG_NOTICE<<"Assigning PBO"<<std::endl;
207                         pbo->setCopyDataAndReleaseGLBufferObject(true);
208                         pbo->setUsage(GL_DYNAMIC_DRAW_ARB);
209                         image->setPixelBufferObject(pbo.get());
210                     }
211                 }
212             }
213         }
214     }
215 
216     if (_markerObject.valid() && texture.getUserData()==0) texture.setUserData(_markerObject.get());
217 
218     _textures.insert(&texture);
219 }
220 
221 /////////////////////////////////////////////////////////////////
222 //
223 // CompileOps
224 //
CompileDrawableOp(osg::Drawable * drawable)225 IncrementalCompileOperation::CompileDrawableOp::CompileDrawableOp(osg::Drawable* drawable):
226     _drawable(drawable)
227 {
228 }
229 
estimatedTimeForCompile(CompileInfo & compileInfo) const230 double IncrementalCompileOperation::CompileDrawableOp::estimatedTimeForCompile(CompileInfo& compileInfo) const
231 {
232     osg::GraphicsCostEstimator* gce = compileInfo.getState()->getGraphicsCostEstimator();
233     osg::Geometry* geometry = _drawable->asGeometry();
234     if (gce && geometry)
235     {
236         return gce->estimateCompileCost(geometry).first;
237     }
238     else return 0.0;
239 }
240 
compile(CompileInfo & compileInfo)241 bool IncrementalCompileOperation::CompileDrawableOp::compile(CompileInfo& compileInfo)
242 {
243     //OSG_NOTICE<<"CompileDrawableOp::compile(..)"<<std::endl;
244     _drawable->compileGLObjects(compileInfo);
245     return true;
246 }
247 
CompileTextureOp(osg::Texture * texture)248 IncrementalCompileOperation::CompileTextureOp::CompileTextureOp(osg::Texture* texture):
249     _texture(texture)
250 {
251 }
252 
estimatedTimeForCompile(CompileInfo & compileInfo) const253 double IncrementalCompileOperation::CompileTextureOp::estimatedTimeForCompile(CompileInfo& compileInfo) const
254 {
255     osg::GraphicsCostEstimator* gce = compileInfo.getState()->getGraphicsCostEstimator();
256     if (gce) return gce->estimateCompileCost(_texture.get()).first;
257     else return 0.0;
258 }
259 
compile(CompileInfo & compileInfo)260 bool IncrementalCompileOperation::CompileTextureOp::compile(CompileInfo& compileInfo)
261 {
262     //OSG_NOTICE<<"CompileTextureOp::compile(..)"<<std::endl;
263     osg::Geometry* forceDownloadGeometry = compileInfo.incrementalCompileOperation->getForceTextureDownloadGeometry();
264     if (forceDownloadGeometry)
265     {
266 
267         //OSG_NOTICE<<"Force texture download"<<std::endl;
268         if (forceDownloadGeometry->getStateSet())
269         {
270             compileInfo.getState()->apply(forceDownloadGeometry->getStateSet());
271         }
272 
273         compileInfo.getState()->applyTextureMode(0, _texture->getTextureTarget(), true);
274         compileInfo.getState()->applyTextureAttribute(0, _texture.get());
275 
276         forceDownloadGeometry->draw(compileInfo);
277     }
278     else
279     {
280         _texture->apply(*compileInfo.getState());
281     }
282     return true;
283 }
284 
CompileProgramOp(osg::Program * program)285 IncrementalCompileOperation::CompileProgramOp::CompileProgramOp(osg::Program* program):
286     _program(program)
287 {
288 }
289 
estimatedTimeForCompile(CompileInfo & compileInfo) const290 double IncrementalCompileOperation::CompileProgramOp::estimatedTimeForCompile(CompileInfo& compileInfo) const
291 {
292     osg::GraphicsCostEstimator* gce = compileInfo.getState()->getGraphicsCostEstimator();
293     if (gce) return gce->estimateCompileCost(_program.get()).first;
294     else return 0.0;
295 }
296 
compile(CompileInfo & compileInfo)297 bool IncrementalCompileOperation::CompileProgramOp::compile(CompileInfo& compileInfo)
298 {
299     //OSG_NOTICE<<"CompileProgramOp::compile(..)"<<std::endl;
300     _program->compileGLObjects(*compileInfo.getState());
301     return true;
302 }
303 
CompileInfo(osg::GraphicsContext * context,IncrementalCompileOperation * ico)304 IncrementalCompileOperation::CompileInfo::CompileInfo(osg::GraphicsContext* context, IncrementalCompileOperation* ico):
305     compileAll(false),
306     maxNumObjectsToCompile(0),
307     allocatedTime(0)
308 {
309     setState(context->getState());
310     incrementalCompileOperation = ico;
311 }
312 
313 
314 /////////////////////////////////////////////////////////////////
315 //
316 // CompileList
317 //
CompileList()318 IncrementalCompileOperation::CompileList::CompileList()
319 {
320 }
321 
~CompileList()322 IncrementalCompileOperation::CompileList::~CompileList()
323 {
324 }
325 
add(CompileOp * compileOp)326 void IncrementalCompileOperation::CompileList::add(CompileOp* compileOp)
327 {
328     _compileOps.push_back(compileOp);
329 }
330 
estimatedTimeForCompile(CompileInfo & compileInfo) const331 double IncrementalCompileOperation::CompileList::estimatedTimeForCompile(CompileInfo& compileInfo) const
332 {
333     double estimateTime = 0.0;
334     for(CompileOps::const_iterator itr = _compileOps.begin();
335         itr != _compileOps.end();
336         ++itr)
337     {
338         estimateTime += (*itr)->estimatedTimeForCompile(compileInfo);
339     }
340     return estimateTime;
341 }
342 
compile(CompileInfo & compileInfo)343 bool IncrementalCompileOperation::CompileList::compile(CompileInfo& compileInfo)
344 {
345 //#define USE_TIME_ESTIMATES
346 
347     for(CompileOps::iterator itr = _compileOps.begin();
348         itr != _compileOps.end() && compileInfo.okToCompile();
349     )
350     {
351         #ifdef USE_TIME_ESTIMATES
352         double estimatedCompileCost = (*itr)->estimatedTimeForCompile(compileInfo);
353         #endif
354 
355         --compileInfo.maxNumObjectsToCompile;
356 
357         #ifdef USE_TIME_ESTIMATES
358         osg::ElapsedTime timer;
359         #endif
360 
361         CompileOps::iterator saved_itr(itr);
362         ++itr;
363         if ((*saved_itr)->compile(compileInfo))
364         {
365             _compileOps.erase(saved_itr);
366         }
367 
368         #ifdef USE_TIME_ESTIMATES
369         double actualCompileCost = timer.elapsedTime();
370         OSG_NOTICE<<"IncrementalCompileOperation::CompileList::compile() estimatedTimForCompile = "<<estimatedCompileCost*1000.0<<"ms, actual = "<<actualCompileCost*1000.0<<"ms";
371         if (estimatedCompileCost>0.0) OSG_NOTICE<<", ratio="<<(actualCompileCost/estimatedCompileCost);
372         OSG_NOTICE<<std::endl;
373         #endif
374     }
375     return empty();
376 }
377 
378 /////////////////////////////////////////////////////////////////
379 //
380 // CompileSet
381 //
buildCompileMap(ContextSet & contexts,StateToCompile & stc)382 void IncrementalCompileOperation::CompileSet::buildCompileMap(ContextSet& contexts, StateToCompile& stc)
383 {
384     if (contexts.empty() || stc.empty()) return;
385 
386     if (stc.empty()) return;
387 
388     for(ContextSet::iterator itr = contexts.begin();
389         itr != contexts.end();
390         ++itr)
391     {
392         // increment the number of compile lists that will need to compile
393         ++_numberCompileListsToCompile;
394 
395         CompileList& cl = _compileMap[*itr];
396         for(StateToCompile::DrawableSet::iterator ditr = stc._drawables.begin();
397             ditr != stc._drawables.end();
398             ++ditr)
399         {
400             cl.add(*ditr);
401         }
402 
403         for(StateToCompile::TextureSet::iterator titr = stc._textures.begin();
404             titr != stc._textures.end();
405             ++titr)
406         {
407             cl.add(*titr);
408         }
409 
410         for(StateToCompile::ProgramSet::iterator pitr = stc._programs.begin();
411             pitr != stc._programs.end();
412             ++pitr)
413         {
414             cl.add(*pitr);
415         }
416     }
417 }
418 
buildCompileMap(ContextSet & contexts,GLObjectsVisitor::Mode mode)419 void IncrementalCompileOperation::CompileSet::buildCompileMap(ContextSet& contexts, GLObjectsVisitor::Mode mode)
420 {
421     if (contexts.empty() || !_subgraphToCompile) return;
422 
423     StateToCompile stc(mode);
424     _subgraphToCompile->accept(stc);
425 
426     buildCompileMap(contexts, stc);
427 }
428 
compile(CompileInfo & compileInfo)429 bool IncrementalCompileOperation::CompileSet::compile(CompileInfo& compileInfo)
430 {
431     CompileList& compileList = _compileMap[compileInfo.getState()->getGraphicsContext()];
432     if (!compileList.empty())
433     {
434         if (compileList.compile(compileInfo))
435         {
436             --_numberCompileListsToCompile;
437             return _numberCompileListsToCompile==0;
438         }
439     }
440     return _numberCompileListsToCompile==0;
441 }
442 
443 /////////////////////////////////////////////////////////////////
444 //
445 // IncrementalCompileOperation
446 //
IncrementalCompileOperation()447 IncrementalCompileOperation::IncrementalCompileOperation():
448     osg::Referenced(true),
449     osg::GraphicsOperation("IncrementalCompileOperation",true),
450     _flushTimeRatio(0.5),
451     _conservativeTimeRatio(0.5),
452     _currentFrameNumber(0),
453     _compileAllTillFrameNumber(0)
454 {
455     _markerObject = new osg::DummyObject;
456     _markerObject->setName("HasBeenProcessedByStateToCompile");
457 
458     _targetFrameRate = 100.0;
459     _minimumTimeAvailableForGLCompileAndDeletePerFrame = 0.001; // 1ms.
460     _maximumNumOfObjectsToCompilePerFrame = 20;
461     const char* ptr = 0;
462     if( (ptr = getenv("OSG_MINIMUM_COMPILE_TIME_PER_FRAME")) != 0)
463     {
464         _minimumTimeAvailableForGLCompileAndDeletePerFrame = osg::asciiToDouble(ptr);
465     }
466 
467     if( (ptr = getenv("OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME")) != 0)
468     {
469         _maximumNumOfObjectsToCompilePerFrame = atoi(ptr);
470     }
471 
472     bool useForceTextureDownload = false;
473     if( (ptr = getenv("OSG_FORCE_TEXTURE_DOWNLOAD")) != 0)
474     {
475         useForceTextureDownload = strcmp(ptr,"yes")==0 || strcmp(ptr,"YES")==0 ||
476                                   strcmp(ptr,"on")==0 || strcmp(ptr,"ON")==0;
477 
478         OSG_NOTICE<<"OSG_FORCE_TEXTURE_DOWNLOAD set to "<<useForceTextureDownload<<std::endl;
479     }
480 
481     if (useForceTextureDownload)
482     {
483         assignForceTextureDownloadGeometry();
484     }
485 
486 }
487 
~IncrementalCompileOperation()488 IncrementalCompileOperation::~IncrementalCompileOperation()
489 {
490 }
491 
assignForceTextureDownloadGeometry()492 void IncrementalCompileOperation::assignForceTextureDownloadGeometry()
493 {
494     osg::Geometry* geometry = new osg::Geometry;
495 
496     osg::Vec3Array* vertices = new osg::Vec3Array;
497     vertices->push_back(osg::Vec3(0.0f,0.0f,0.0f));
498     geometry->setVertexArray(vertices);
499 
500     osg::Vec4Array* texcoords = new osg::Vec4Array;
501     texcoords->push_back(osg::Vec4(0.0f,0.0f,0.0f,0.0f));
502     geometry->setTexCoordArray(0, texcoords);
503 
504     geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS,0,1));
505 
506     osg::StateSet* stateset = geometry->getOrCreateStateSet();
507     stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
508 
509     osg::Depth* depth = new osg::Depth;
510     depth->setWriteMask(false);
511     stateset->setAttribute(depth);
512 
513     osg::ColorMask* colorMask = new osg::ColorMask(false,false,false,false);
514     stateset->setAttribute(colorMask);
515 
516     _forceTextureDownloadGeometry = geometry;
517 }
518 
assignContexts(Contexts & contexts)519 void IncrementalCompileOperation::assignContexts(Contexts& contexts)
520 {
521     for(Contexts::iterator itr = contexts.begin();
522         itr != contexts.end();
523         ++itr)
524     {
525         osg::GraphicsContext* gc = *itr;
526         addGraphicsContext(gc);
527     }
528 }
529 
removeContexts(Contexts & contexts)530 void IncrementalCompileOperation::removeContexts(Contexts& contexts)
531 {
532     for(Contexts::iterator itr = contexts.begin();
533         itr != contexts.end();
534         ++itr)
535     {
536         osg::GraphicsContext* gc = *itr;
537         removeGraphicsContext(gc);
538     }
539 }
540 
541 
addGraphicsContext(osg::GraphicsContext * gc)542 void IncrementalCompileOperation::addGraphicsContext(osg::GraphicsContext* gc)
543 {
544     if (_contexts.count(gc)==0)
545     {
546         gc->add(this);
547         _contexts.insert(gc);
548     }
549 }
550 
removeGraphicsContext(osg::GraphicsContext * gc)551 void IncrementalCompileOperation::removeGraphicsContext(osg::GraphicsContext* gc)
552 {
553     if (_contexts.count(gc)!=0)
554     {
555         gc->remove(this);
556         _contexts.erase(gc);
557     }
558 }
559 
requiresCompile(StateToCompile & stateToCompile)560 bool IncrementalCompileOperation::requiresCompile(StateToCompile& stateToCompile)
561 {
562     return isActive() && !stateToCompile.empty();
563 }
564 
add(osg::Node * subgraphToCompile)565 void IncrementalCompileOperation::add(osg::Node* subgraphToCompile)
566 {
567     OSG_INFO<<"IncrementalCompileOperation::add("<<subgraphToCompile<<")"<<std::endl;
568     add(new CompileSet(subgraphToCompile));
569 }
570 
add(osg::Group * attachmentPoint,osg::Node * subgraphToCompile)571 void IncrementalCompileOperation::add(osg::Group* attachmentPoint, osg::Node* subgraphToCompile)
572 {
573     OSG_INFO<<"IncrementalCompileOperation::add("<<attachmentPoint<<", "<<subgraphToCompile<<")"<<std::endl;
574     add(new CompileSet(attachmentPoint, subgraphToCompile));
575 }
576 
577 
add(CompileSet * compileSet,bool callBuildCompileMap)578 void IncrementalCompileOperation::add(CompileSet* compileSet, bool callBuildCompileMap)
579 {
580     if (!compileSet) return;
581 
582     if (compileSet->_subgraphToCompile.valid())
583     {
584         // force a compute of the bound of the subgraph to avoid the update traversal from having to do this work
585         // and reducing the change of frame drop.
586         compileSet->_subgraphToCompile->getBound();
587     }
588 
589     if (callBuildCompileMap) compileSet->buildCompileMap(_contexts);
590 
591     OSG_INFO<<"IncrementalCompileOperation::add(CompileSet = "<<compileSet<<", "<<", "<<callBuildCompileMap<<")"<<std::endl;
592 
593     OpenThreads::ScopedLock<OpenThreads::Mutex>  lock(_toCompileMutex);
594     _toCompile.push_back(compileSet);
595 }
596 
remove(CompileSet * compileSet)597 void IncrementalCompileOperation::remove(CompileSet* compileSet)
598 {
599     // OSG_NOTICE<<"IncrementalCompileOperation::remove(CompileSet* compileSet)"<<std::endl;
600 
601     if (!compileSet) return;
602 
603     // remove CompileSet from _toCompile list if it's present.
604     {
605         OpenThreads::ScopedLock<OpenThreads::Mutex>  lock(_toCompileMutex);
606         for(CompileSets::iterator itr = _toCompile.begin();
607             itr != _toCompile.end();
608             ++itr)
609         {
610             if (*itr == compileSet)
611             {
612                 _toCompile.erase(itr);
613                 return;
614             }
615         }
616     }
617 
618     // remove CompileSet from _compiled list if it's present.
619     {
620         OpenThreads::ScopedLock<OpenThreads::Mutex>  lock(_compiledMutex);
621         for(CompileSets::iterator itr = _compiled.begin();
622             itr != _compiled.end();
623             ++itr)
624         {
625             if (*itr == compileSet)
626             {
627                 _compiled.erase(itr);
628                 return;
629             }
630         }
631     }
632 }
633 
634 
mergeCompiledSubgraphs(const osg::FrameStamp * frameStamp)635 void IncrementalCompileOperation::mergeCompiledSubgraphs(const osg::FrameStamp* frameStamp)
636 {
637     // OSG_INFO<<"IncrementalCompileOperation::mergeCompiledSubgraphs()"<<std::endl;
638 
639     OpenThreads::ScopedLock<OpenThreads::Mutex>  compilded_lock(_compiledMutex);
640 
641     if (frameStamp) _currentFrameNumber = frameStamp->getFrameNumber();
642 
643     for(CompileSets::iterator itr = _compiled.begin();
644         itr != _compiled.end();
645         ++itr)
646     {
647         CompileSet* cs = itr->get();
648         osg::ref_ptr<osg::Group> group;
649         if (cs->_attachmentPoint.lock(group))
650         {
651             group->addChild(cs->_subgraphToCompile.get());
652         }
653     }
654 
655     _compiled.clear();
656 }
657 
658 
operator ()(osg::GraphicsContext * context)659 void IncrementalCompileOperation::operator () (osg::GraphicsContext* context)
660 {
661     osg::NotifySeverity level = osg::INFO;
662 
663     //glFinish();
664     //glFlush();
665 
666     double targetFrameRate = _targetFrameRate;
667     double minimumTimeAvailableForGLCompileAndDeletePerFrame = _minimumTimeAvailableForGLCompileAndDeletePerFrame;
668 
669     double targetFrameTime = 1.0/targetFrameRate;
670 
671     const osg::FrameStamp* fs = context->getState()->getFrameStamp();
672     double currentTime = fs ? fs->getReferenceTime() : 0.0;
673 
674     double currentElapsedFrameTime = context->getTimeSinceLastClear();
675 
676     OSG_NOTIFY(level)<<"IncrementalCompileOperation()"<<std::endl;
677     OSG_NOTIFY(level)<<"    currentTime = "<<currentTime<<std::endl;
678     OSG_NOTIFY(level)<<"    currentElapsedFrameTime = "<<currentElapsedFrameTime<<std::endl;
679 
680     double _flushTimeRatio(0.5);
681     double _conservativeTimeRatio(0.5);
682 
683     double availableTime = std::max((targetFrameTime - currentElapsedFrameTime)*_conservativeTimeRatio,
684                                     minimumTimeAvailableForGLCompileAndDeletePerFrame);
685 
686     double flushTime = availableTime * _flushTimeRatio;
687     double compileTime = availableTime - flushTime;
688 
689 #if 1
690     OSG_NOTIFY(level)<<"    availableTime = "<<availableTime*1000.0<<std::endl;
691     OSG_NOTIFY(level)<<"    flushTime     = "<<flushTime*1000.0<<std::endl;
692     OSG_NOTIFY(level)<<"    compileTime   = "<<compileTime*1000.0<<std::endl;
693 #endif
694 
695     //level = osg::NOTICE;
696 
697     CompileInfo compileInfo(context, this);
698     compileInfo.maxNumObjectsToCompile = _maximumNumOfObjectsToCompilePerFrame;
699     compileInfo.allocatedTime = compileTime;
700     compileInfo.compileAll = (_compileAllTillFrameNumber > _currentFrameNumber);
701 
702     CompileSets toCompileCopy;
703     {
704         OpenThreads::ScopedLock<OpenThreads::Mutex>  toCompile_lock(_toCompileMutex);
705         std::copy(_toCompile.begin(),_toCompile.end(),std::back_inserter<CompileSets>(toCompileCopy));
706     }
707 
708     if (!toCompileCopy.empty())
709     {
710         compileSets(toCompileCopy, compileInfo);
711     }
712 
713     osg::flushDeletedGLObjects(context->getState()->getContextID(), currentTime, flushTime);
714 
715     if (!toCompileCopy.empty() && compileInfo.maxNumObjectsToCompile>0)
716     {
717         compileInfo.allocatedTime += flushTime;
718 
719         // if any time left over from flush add on this remaining time to a second pass of compiling.
720         if (compileInfo.okToCompile())
721         {
722             OSG_NOTIFY(level)<<"    Passing on "<<flushTime<<" to second round of compileSets(..)"<<std::endl;
723             compileSets(toCompileCopy, compileInfo);
724         }
725     }
726 
727     //glFush();
728     //glFinish();
729 }
730 
compileSets(CompileSets & toCompile,CompileInfo & compileInfo)731 void IncrementalCompileOperation::compileSets(CompileSets& toCompile, CompileInfo& compileInfo)
732 {
733     osg::NotifySeverity level = osg::INFO;
734 
735     for(CompileSets::iterator itr = toCompile.begin();
736         itr != toCompile.end() && compileInfo.okToCompile();
737         )
738     {
739         CompileSet* cs = itr->get();
740         if (cs->compile(compileInfo))
741         {
742             {
743                 OpenThreads::ScopedLock<OpenThreads::Mutex>  toCompile_lock(_toCompileMutex);
744 
745                 CompileSets::iterator cs_itr = std::find(_toCompile.begin(), _toCompile.end(), *itr);
746                 if (cs_itr != _toCompile.end())
747                 {
748                     OSG_NOTIFY(level)<<"    Erasing from list"<<std::endl;
749 
750                     // remove from the _toCompile list, note cs won't be deleted here as the tempoary
751                     // toCompile_Copy list will retain a reference.
752                     _toCompile.erase(cs_itr);
753                 }
754             }
755             if (cs->_compileCompletedCallback.valid() && cs->_compileCompletedCallback->compileCompleted(cs))
756             {
757                 // callback will handle merging of subgraph so no need to place CompileSet in merge.
758             }
759             else
760             {
761                 OpenThreads::ScopedLock<OpenThreads::Mutex>  compilded_lock(_compiledMutex);
762                 _compiled.push_back(cs);
763             }
764 
765             // remove entry from list.
766             itr = toCompile.erase(itr);
767         }
768         else
769         {
770             ++itr;
771         }
772     }
773 
774 }
775 
776 
compileAllForNextFrame(unsigned int numFramesToDoCompileAll)777 void IncrementalCompileOperation::compileAllForNextFrame(unsigned int numFramesToDoCompileAll)
778 {
779     _compileAllTillFrameNumber = _currentFrameNumber+numFramesToDoCompileAll;
780 }
781 
782 
783 } // end of namespace osgUtil
784