root/OpenSceneGraph/trunk/src/osgViewer/ViewerBase.cpp @ 9131

Revision 9131, 22.6 kB (checked in by robert, 6 years ago)

From Csaba Halasz, fix for hang when running in CullThreadPerCameraDrawThreadPerContext? threading model.

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
14#include <stdlib.h>
15#include <string.h>
16
17#include <osgViewer/ViewerBase>
18#include <osgViewer/View>
19#include <osgViewer/Renderer>
20
21#include <osg/io_utils>
22
23#include <osg/TextureCubeMap>
24#include <osg/TextureRectangle>
25#include <osg/TexMat>
26#include <osg/DeleteHandler>
27
28#include <osgUtil/Optimizer>
29#include <osgUtil/IntersectionVisitor>
30
31static osg::ApplicationUsageProxy ViewerBase_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_CONFIG_FILE <filename>","Specify a viewer configuration file to load by default.");
32static osg::ApplicationUsageProxy ViewerBase_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREADING <value>","Set the threading model using by Viewer, <value> can be SingleThreaded, CullDrawThreadPerContext, DrawThreadPerContext or CullThreadPerCameraDrawThreadPerContext.");
33static osg::ApplicationUsageProxy ViewerBase_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_SCREEN <value>","Set the default screen that windows should open up on.");
34static osg::ApplicationUsageProxy ViewerBase_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WINDOW x y width height","Set the default window dimensions that windows should open up on.");
35
36
37using namespace osgViewer;
38
39ViewerBase::ViewerBase():
40    osg::Object(true)
41{
42    _firstFrame = true;
43    _done = false;
44    _keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape;
45    _quitEventSetsDone = true;
46    _releaseContextAtEndOfFrameHint = true;
47    _threadingModel = AutomaticSelection;
48    _threadsRunning = false;
49    _endBarrierPosition = AfterSwapBuffers;
50}
51
52ViewerBase::ViewerBase(const ViewerBase& base):
53    osg::Object(true)
54{
55    _firstFrame = true;
56    _done = false;
57    _keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape;
58    _quitEventSetsDone = true;
59    _releaseContextAtEndOfFrameHint = true;
60    _threadingModel = AutomaticSelection;
61    _threadsRunning = false;
62    _endBarrierPosition = AfterSwapBuffers;
63}
64
65void ViewerBase::setThreadingModel(ThreadingModel threadingModel)
66{
67    if (_threadingModel == threadingModel) return;
68   
69    if (_threadsRunning) stopThreading();
70   
71    _threadingModel = threadingModel;
72
73    if (isRealized() && _threadingModel!=SingleThreaded) startThreading();
74}
75
76ViewerBase::ThreadingModel ViewerBase::suggestBestThreadingModel()
77{
78    const char* str = getenv("OSG_THREADING");
79    if (str)
80    {
81        if (strcmp(str,"SingleThreaded")==0) return SingleThreaded;
82        else if (strcmp(str,"CullDrawThreadPerContext")==0) return CullDrawThreadPerContext;
83        else if (strcmp(str,"DrawThreadPerContext")==0) return DrawThreadPerContext;
84        else if (strcmp(str,"CullThreadPerCameraDrawThreadPerContext")==0) return CullThreadPerCameraDrawThreadPerContext;
85    }
86
87    Contexts contexts;
88    getContexts(contexts);
89   
90    if (contexts.empty()) return SingleThreaded;
91
92#if 0
93    // temporary hack to disable multi-threading under Windows till we find good solutions for
94    // crashes that users are seeing.
95    return SingleThreaded;
96#endif
97
98    Cameras cameras;
99    getCameras(cameras);
100
101    if (cameras.empty()) return SingleThreaded;
102
103
104    int numProcessors = OpenThreads::GetNumberOfProcessors();
105
106    if (contexts.size()==1)
107    {
108        if (numProcessors==1) return SingleThreaded;
109        else return DrawThreadPerContext;
110    }
111   
112#if 1
113    if (numProcessors >= static_cast<int>(cameras.size()+contexts.size()))
114    {
115        return CullThreadPerCameraDrawThreadPerContext;
116    }
117#endif
118
119    return DrawThreadPerContext;
120}
121
122void ViewerBase::setUpThreading()
123{
124    Contexts contexts;
125    getContexts(contexts);
126
127    if (_threadingModel==SingleThreaded)
128    {
129        if (_threadsRunning) stopThreading();
130        else
131        {
132            // we'll set processor affinity here to help single threaded apps
133            // with multiple processor cores, and using the database pager.
134            int numProcessors = OpenThreads::GetNumberOfProcessors();
135            bool affinity = numProcessors>1;   
136            if (affinity)
137            {
138                OpenThreads::SetProcessorAffinityOfCurrentThread(0);
139
140                Scenes scenes;
141                getScenes(scenes);
142               
143                for(Scenes::iterator itr = scenes.begin();
144                    itr != scenes.end();
145                    ++itr)
146                {
147                    Scene* scene = *itr;
148                    osgDB::DatabasePager* dp = scene->getDatabasePager();
149                    if (dp)
150                    {
151                        for(unsigned int i=0; i<dp->getNumDatabaseThreads(); ++i)
152                        {
153                            osgDB::DatabasePager::DatabaseThread* dt = dp->getDatabaseThread(i);
154                            dt->setProcessorAffinity(1);
155                        }
156                    }
157                }
158           
159            }
160        }
161    }
162    else
163    {
164        if (!_threadsRunning) startThreading();
165    }
166   
167}
168
169void ViewerBase::setEndBarrierPosition(BarrierPosition bp)
170{
171    if (_endBarrierPosition == bp) return;
172   
173    if (_threadsRunning) stopThreading();
174   
175    _endBarrierPosition = bp;
176
177    if (_threadingModel!=SingleThreaded) startThreading();
178}
179
180
181void ViewerBase::stopThreading()
182{
183    if (!_threadsRunning) return;
184
185    osg::notify(osg::INFO)<<"ViewerBase::stopThreading() - stopping threading"<<std::endl;
186
187    Contexts contexts;
188    getContexts(contexts);
189
190    Cameras cameras;
191    getCameras(cameras);
192
193    Contexts::iterator gcitr;
194    Cameras::iterator citr;
195
196    for(Cameras::iterator camItr = cameras.begin();
197        camItr != cameras.end();
198        ++camItr)
199    {
200        osg::Camera* camera = *camItr;
201        Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
202        if (renderer) renderer->release();
203    }
204
205    // delete all the graphics threads.   
206    for(gcitr = contexts.begin();
207        gcitr != contexts.end();
208        ++gcitr)
209    {
210        (*gcitr)->setGraphicsThread(0);
211    }
212
213    // delete all the camera threads.   
214    for(citr = cameras.begin();
215        citr != cameras.end();
216        ++citr)
217    {
218        (*citr)->setCameraThread(0);
219    }
220
221    for(Cameras::iterator camItr = cameras.begin();
222        camItr != cameras.end();
223        ++camItr)
224    {
225        osg::Camera* camera = *camItr;
226        Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
227        if (renderer)
228        {
229            renderer->setGraphicsThreadDoesCull( true );
230            renderer->setDone(false);
231        }
232    }
233
234
235    _threadsRunning = false;
236    _startRenderingBarrier = 0;
237    _endRenderingDispatchBarrier = 0;
238    _endDynamicDrawBlock = 0;
239
240    osg::notify(osg::INFO)<<"Viewer::stopThreading() - stopped threading."<<std::endl;
241}
242
243void ViewerBase::startThreading()
244{
245    if (_threadsRunning) return;
246   
247    osg::notify(osg::INFO)<<"Viewer::startThreading() - starting threading"<<std::endl;
248   
249    // release any context held by the main thread.
250    releaseContext();
251
252    _threadingModel = _threadingModel==AutomaticSelection ? suggestBestThreadingModel() : _threadingModel;
253
254    Contexts contexts;
255    getContexts(contexts);
256   
257    osg::notify(osg::INFO)<<"Viewer::startThreading() - contexts.size()="<<contexts.size()<<std::endl;
258
259    Cameras cameras;
260    getCameras(cameras);
261   
262    unsigned int numThreadsOnStartBarrier = 0;
263    unsigned int numThreadsOnEndBarrier = 0;
264    switch(_threadingModel)
265    {
266        case(SingleThreaded):
267            numThreadsOnStartBarrier = 1;
268            numThreadsOnEndBarrier = 1;
269            return;
270        case(CullDrawThreadPerContext):
271            numThreadsOnStartBarrier = contexts.size()+1;
272            numThreadsOnEndBarrier = contexts.size()+1;
273            break;
274        case(DrawThreadPerContext):
275            numThreadsOnStartBarrier = 1;
276            numThreadsOnEndBarrier = 1;
277            break;
278        case(CullThreadPerCameraDrawThreadPerContext):
279            numThreadsOnStartBarrier = cameras.size()+1;
280            numThreadsOnEndBarrier = 1;
281            break;
282        default:
283            osg::notify(osg::NOTICE)<<"Error: Threading model not selected"<<std::endl;
284            return;
285    }
286
287    // using multi-threading so make sure that new objects are allocated with thread safe ref/unref
288    osg::Referenced::setThreadSafeReferenceCounting(true);
289
290    Scenes scenes;
291    getScenes(scenes);
292    for(Scenes::iterator scitr = scenes.begin();
293        scitr != scenes.end();
294        ++scitr)
295    {
296        if ((*scitr)->getSceneData())
297        {
298            osg::notify(osg::INFO)<<"Making scene thread safe"<<std::endl;
299
300            // make sure that existing scene graph objects are allocated with thread safe ref/unref
301            (*scitr)->getSceneData()->setThreadSafeRefUnref(true);
302
303            // update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it.
304            (*scitr)->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts());
305        }
306    }
307       
308    int numProcessors = OpenThreads::GetNumberOfProcessors();
309    bool affinity = numProcessors>1;   
310   
311    Contexts::iterator citr;
312
313    unsigned int numViewerDoubleBufferedRenderingOperation = 0;
314
315    bool graphicsThreadsDoesCull = _threadingModel == CullDrawThreadPerContext || _threadingModel==SingleThreaded;
316
317    for(Cameras::iterator camItr = cameras.begin();
318        camItr != cameras.end();
319        ++camItr)
320    {
321        osg::Camera* camera = *camItr;
322        Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
323        if (renderer)
324        {
325            renderer->setGraphicsThreadDoesCull(graphicsThreadsDoesCull);
326            renderer->setDone(false);
327            ++numViewerDoubleBufferedRenderingOperation;
328        }
329    }
330
331    if (_threadingModel==CullDrawThreadPerContext)
332    {
333        _startRenderingBarrier = 0;
334        _endRenderingDispatchBarrier = 0;
335        _endDynamicDrawBlock = 0;
336    }
337    else if (_threadingModel==DrawThreadPerContext ||
338             _threadingModel==CullThreadPerCameraDrawThreadPerContext)
339    {
340        _startRenderingBarrier = 0;
341        _endRenderingDispatchBarrier = 0;
342        _endDynamicDrawBlock = new osg::EndOfDynamicDrawBlock(numViewerDoubleBufferedRenderingOperation);
343       
344#ifndef OSGUTIL_RENDERBACKEND_USE_REF_PTR
345        if (!osg::Referenced::getDeleteHandler()) osg::Referenced::setDeleteHandler(new osg::DeleteHandler(2));
346        else osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(2);
347#endif
348    }
349   
350    if (numThreadsOnStartBarrier>1)
351    {
352        _startRenderingBarrier = new osg::BarrierOperation(numThreadsOnStartBarrier, osg::BarrierOperation::NO_OPERATION);
353    }
354
355    if (numThreadsOnEndBarrier>1)
356    {
357        _endRenderingDispatchBarrier = new osg::BarrierOperation(numThreadsOnEndBarrier, osg::BarrierOperation::NO_OPERATION);
358    }
359
360
361    osg::ref_ptr<osg::BarrierOperation> swapReadyBarrier = contexts.empty() ? 0 : new osg::BarrierOperation(contexts.size(), osg::BarrierOperation::NO_OPERATION);
362
363    osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
364
365    typedef std::map<OpenThreads::Thread*, int> ThreadAffinityMap;
366    ThreadAffinityMap threadAffinityMap;
367
368    unsigned int processNum = 1;
369    for(citr = contexts.begin();
370        citr != contexts.end();
371        ++citr, ++processNum)
372    {
373        osg::GraphicsContext* gc = (*citr);
374       
375        if (!gc->isRealized())
376        {
377            osg::notify(osg::INFO)<<"ViewerBase::startThreading() : Realizng window "<<gc<<std::endl;
378            gc->realize();
379        }
380       
381        gc->getState()->setDynamicObjectRenderingCompletedCallback(_endDynamicDrawBlock.get());
382
383        // create the a graphics thread for this context
384        gc->createGraphicsThread();
385
386        if (affinity) gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
387        threadAffinityMap[gc->getGraphicsThread()] = processNum % numProcessors;
388
389        // add the startRenderingBarrier
390        if (_threadingModel==CullDrawThreadPerContext && _startRenderingBarrier.valid()) gc->getGraphicsThread()->add(_startRenderingBarrier.get());
391
392        // add the rendering operation itself.
393        gc->getGraphicsThread()->add(new osg::RunOperations());
394
395        if (_threadingModel==CullDrawThreadPerContext && _endBarrierPosition==BeforeSwapBuffers && _endRenderingDispatchBarrier.valid())
396        {
397            // add the endRenderingDispatchBarrier
398            gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
399        }
400
401        if (swapReadyBarrier.valid()) gc->getGraphicsThread()->add(swapReadyBarrier.get());
402
403        // add the swap buffers
404        gc->getGraphicsThread()->add(swapOp.get());
405
406        if (_threadingModel==CullDrawThreadPerContext && _endBarrierPosition==AfterSwapBuffers && _endRenderingDispatchBarrier.valid())
407        {
408            // add the endRenderingDispatchBarrier
409            gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
410        }
411
412    }
413
414    if (_threadingModel==CullThreadPerCameraDrawThreadPerContext && numThreadsOnStartBarrier>1)
415    {
416        Cameras::iterator camItr;
417
418        for(camItr = cameras.begin();
419            camItr != cameras.end();
420            ++camItr, ++processNum)
421        {
422            osg::Camera* camera = *camItr;
423            camera->createCameraThread();
424
425            if (affinity) camera->getCameraThread()->setProcessorAffinity(processNum % numProcessors);
426            threadAffinityMap[camera->getCameraThread()] = processNum % numProcessors;
427
428            osg::GraphicsContext* gc = camera->getGraphicsContext();
429
430            // add the startRenderingBarrier
431            if (_startRenderingBarrier.valid()) camera->getCameraThread()->add(_startRenderingBarrier.get());
432
433            Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
434            renderer->setGraphicsThreadDoesCull(false);
435            camera->getCameraThread()->add(renderer);
436           
437            if (_endRenderingDispatchBarrier.valid())
438            {
439                // add the endRenderingDispatchBarrier
440                gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
441            }
442
443        }
444
445        for(camItr = cameras.begin();
446            camItr != cameras.end();
447            ++camItr)
448        {
449            osg::Camera* camera = *camItr;
450            if (camera->getCameraThread() && !camera->getCameraThread()->isRunning())
451            {
452                osg::notify(osg::INFO)<<"  camera->getCameraThread()-> "<<camera->getCameraThread()<<std::endl;
453                camera->getCameraThread()->startThread();
454            }
455        }
456    }
457
458#if 0   
459    if (affinity)
460    {
461        OpenThreads::SetProcessorAffinityOfCurrentThread(0);
462        if (_scene.valid() && _scene->getDatabasePager())
463        {
464#if 0       
465            _scene->getDatabasePager()->setProcessorAffinity(1);
466#else
467            _scene->getDatabasePager()->setProcessorAffinity(0);
468#endif
469        }
470    }
471#endif
472
473#if 0
474    if (affinity)
475    {
476        for(ThreadAffinityMap::iterator titr = threadAffinityMap.begin();
477            titr != threadAffinityMap.end();
478            ++titr)
479        {
480            titr->first->setProcessorAffinity(titr->second);
481        }
482    }
483#endif
484
485
486    for(citr = contexts.begin();
487        citr != contexts.end();
488        ++citr)
489    {
490        osg::GraphicsContext* gc = (*citr);
491        if (gc->getGraphicsThread() && !gc->getGraphicsThread()->isRunning())
492        {
493            osg::notify(osg::INFO)<<"  gc->getGraphicsThread()->startThread() "<<gc->getGraphicsThread()<<std::endl;
494            gc->getGraphicsThread()->startThread();
495            // OpenThreads::Thread::YieldCurrentThread();
496        }
497    }
498
499    _threadsRunning = true;
500
501    osg::notify(osg::INFO)<<"Set up threading"<<std::endl;
502}
503
504void ViewerBase::getWindows(Windows& windows, bool onlyValid)
505{
506    windows.clear();
507
508    Contexts contexts;
509    getContexts(contexts, onlyValid);
510   
511    for(Contexts::iterator itr = contexts.begin();
512        itr != contexts.end();
513        ++itr)
514    {
515        osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(*itr);
516        if (gw) windows.push_back(gw);
517    }
518}
519
520void ViewerBase::checkWindowStatus()
521{
522    Contexts contexts;
523    getContexts(contexts);
524   
525    // osg::notify(osg::NOTICE)<<"Viewer::checkWindowStatus() - "<<contexts.size()<<std::endl;
526   
527    if (contexts.size()==0)
528    {
529        _done = true;
530        if (areThreadsRunning()) stopThreading();
531    }
532}
533
534void ViewerBase::addUpdateOperation(osg::Operation* operation)
535{
536    if (!operation) return;
537
538    if (!_updateOperations) _updateOperations = new osg::OperationQueue;
539   
540    _updateOperations->add(operation);
541}
542
543void ViewerBase::removeUpdateOperation(osg::Operation* operation)
544{
545    if (!operation) return;
546
547    if (_updateOperations.valid())
548    {
549        _updateOperations->remove(operation);
550    }
551}
552
553int ViewerBase::run()
554{
555    if (!isRealized())
556    {
557        realize();
558    }
559
560#if 0
561    while (!done())
562    {
563        frame();
564    }
565#else
566
567    const char* str = getenv("OSG_RUN_FRAME_COUNT");
568    if (str)
569    {
570        int runTillFrameNumber = atoi(str);
571        while (!done() && getViewerFrameStamp()->getFrameNumber()<runTillFrameNumber)
572        {
573            frame();
574        }
575    }
576    else
577    {
578        while (!done())
579        {
580            frame();
581        }
582    }
583#endif   
584    return 0;
585}
586
587void ViewerBase::frame(double simulationTime)
588{
589    if (_done) return;
590
591    // osg::notify(osg::NOTICE)<<std::endl<<"CompositeViewer::frame()"<<std::endl<<std::endl;
592
593    if (_firstFrame)
594    {
595        viewerInit();
596       
597        if (!isRealized())
598        {
599            realize();
600        }
601       
602        _firstFrame = false;
603    }
604    advance(simulationTime);
605   
606    eventTraversal();
607    updateTraversal();
608    renderingTraversals();
609}
610
611
612void ViewerBase::renderingTraversals()
613{
614    bool _outputMasterCameraLocation = false;
615    if (_outputMasterCameraLocation)
616    {
617        Views views;
618        getViews(views);
619
620        for(Views::iterator itr = views.begin();
621            itr != views.end();
622            ++itr)
623        {
624            osgViewer::View* view = *itr;
625            if (view)
626            {
627                const osg::Matrixd& m = view->getCamera()->getInverseViewMatrix();
628                osg::notify(osg::NOTICE)<<"View "<<view<<", Master Camera position("<<m.getTrans()<<"), rotation("<<m.getRotate()<<")"<<std::endl;
629            }
630        }
631    }
632       
633    // check to see if windows are still valid
634    checkWindowStatus();
635
636    if (_done) return;
637
638    double beginRenderingTraversals = elapsedTime();
639
640    osg::FrameStamp* frameStamp = getViewerFrameStamp();
641
642    Scenes scenes;
643    getScenes(scenes);
644   
645    for(Scenes::iterator sitr = scenes.begin();
646        sitr != scenes.end();
647        ++sitr)
648    {
649        Scene* scene = *sitr;
650        osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0;
651        if (dp)
652        {
653            dp->signalBeginFrame(frameStamp);
654        }
655       
656        if (scene->getSceneData())
657        {
658            // fire off a build of the bounding volumes while we
659            // are still running single threaded.
660            scene->getSceneData()->getBound();
661        }
662    }
663
664    // osg::notify(osg::NOTICE)<<std::endl<<"Start frame"<<std::endl;
665   
666
667    Contexts contexts;
668    getContexts(contexts);
669
670    Cameras cameras;
671    getCameras(cameras);
672   
673    Contexts::iterator itr;
674   
675    bool doneMakeCurrentInThisThread = false;
676
677    if (_endDynamicDrawBlock.valid())
678    {
679        _endDynamicDrawBlock->reset();
680    }
681   
682    // dispatch the rendering threads
683    if (_startRenderingBarrier.valid()) _startRenderingBarrier->block();
684
685    // reset any double buffer graphics objects
686    for(Cameras::iterator camItr = cameras.begin();
687        camItr != cameras.end();
688        ++camItr)
689    {
690        osg::Camera* camera = *camItr;
691        Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
692        if (renderer)
693        {
694            if (!renderer->getGraphicsThreadDoesCull() && !(camera->getCameraThread()))
695            {
696                renderer->cull();
697            }
698        }
699    }
700
701    for(itr = contexts.begin();
702        itr != contexts.end();
703        ++itr)
704    {
705        if (_done) return;
706        if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
707        {
708            doneMakeCurrentInThisThread = true;
709            makeCurrent(*itr);
710            (*itr)->runOperations();
711        }
712    }
713
714    // osg::notify(osg::NOTICE)<<"Joing _endRenderingDispatchBarrier block "<<_endRenderingDispatchBarrier.get()<<std::endl;
715
716    // wait till the rendering dispatch is done.
717    if (_endRenderingDispatchBarrier.valid()) _endRenderingDispatchBarrier->block();
718
719    for(itr = contexts.begin();
720        itr != contexts.end();
721        ++itr)
722    {
723        if (_done) return;
724
725        if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
726        {
727            doneMakeCurrentInThisThread = true;
728            makeCurrent(*itr);
729            (*itr)->swapBuffers();
730        }
731    }
732
733    for(Scenes::iterator sitr = scenes.begin();
734        sitr != scenes.end();
735        ++sitr)
736    {
737        Scene* scene = *sitr;
738        osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0;
739        if (dp)
740        {
741            dp->signalEndFrame();
742        }
743    }
744
745    // wait till the dynamic draw is complete.
746    if (_endDynamicDrawBlock.valid())
747    {
748        // osg::Timer_t startTick = osg::Timer::instance()->tick();
749        _endDynamicDrawBlock->block();
750        // osg::notify(osg::NOTICE)<<"Time waiting "<<osg::Timer::instance()->delta_m(startTick, osg::Timer::instance()->tick())<<std::endl;;
751    }
752   
753    if (_releaseContextAtEndOfFrameHint && doneMakeCurrentInThisThread)
754    {
755        //osg::notify(osg::NOTICE)<<"Doing release context"<<std::endl;
756        releaseContext();
757    }
758
759    if (getStats() && getStats()->collectStats("update"))
760    {
761        double endRenderingTraversals = elapsedTime();
762
763        // update current frames stats
764        getStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals begin time ", beginRenderingTraversals);
765        getStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals end time ", endRenderingTraversals);
766        getStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals time taken", endRenderingTraversals-beginRenderingTraversals);
767    }
768}
Note: See TracBrowser for help on using the browser.