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