root/OpenSceneGraph/trunk/src/osgViewer/Renderer.cpp @ 8121

Revision 8121, 20.1 kB (checked in by robert, 10 years ago)

Added new computation of time to allocate to flushing deleted and compiling OpenGL objects per frame.

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 <stdio.h>
15
16#include <osg/GLExtensions>
17
18#include <osgUtil/Optimizer>
19#include <osgUtil/GLObjectsVisitor>
20
21#include <osgViewer/Renderer>
22#include <osgViewer/View>
23
24#include <osgDB/DatabasePager>
25
26#include <osg/io_utils>
27
28#include <sstream>
29
30using namespace osgViewer;
31
32//#define DEBUG_MESSAGE osg::notify(osg::NOTICE)
33#define DEBUG_MESSAGE osg::notify(osg::DEBUG_FP)
34
35
36OpenGLQuerySupport::OpenGLQuerySupport():
37    _startTick(0),
38    _initialized(false),
39    _timerQuerySupported(false),
40    _extensions(0),
41    _previousQueryTime(0.0)
42{
43}
44
45void OpenGLQuerySupport::checkQuery(osg::Stats* stats)
46{
47    for(QueryFrameNumberList::iterator itr = _queryFrameNumberList.begin();
48        itr != _queryFrameNumberList.end();
49        )
50    {
51        GLuint query = itr->first;
52        GLint available = 0;
53        _extensions->glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &available);
54        if (available)
55        {
56            GLuint64EXT timeElapsed = 0;
57            _extensions->glGetQueryObjectui64v(query, GL_QUERY_RESULT, &timeElapsed);
58
59            double timeElapsedSeconds = double(timeElapsed)*1e-9;
60            double currentTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
61            double estimatedEndTime = (_previousQueryTime + currentTime) * 0.5;
62            double estimatedBeginTime = estimatedEndTime - timeElapsedSeconds;
63
64            stats->setAttribute(itr->second, "GPU draw begin time", estimatedBeginTime);
65            stats->setAttribute(itr->second, "GPU draw end time", estimatedEndTime);
66            stats->setAttribute(itr->second, "GPU draw time taken", timeElapsedSeconds);
67
68
69            itr = _queryFrameNumberList.erase(itr);
70            _availableQueryObjects.push_back(query);
71        }
72        else
73        {
74            ++itr;
75        }
76
77    }
78    _previousQueryTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
79}
80
81GLuint OpenGLQuerySupport::createQueryObject()
82{
83    if (_availableQueryObjects.empty())
84    {
85        GLuint query;
86        _extensions->glGenQueries(1, &query);
87        return query;
88    }
89    else
90    {
91        GLuint query = _availableQueryObjects.back();
92        _availableQueryObjects.pop_back();
93        return query;
94    }
95}
96
97void OpenGLQuerySupport::beginQuery(int frameNumber)
98{
99    GLuint query = createQueryObject();
100    _extensions->glBeginQuery(GL_TIME_ELAPSED, query);
101    _queryFrameNumberList.push_back(QueryFrameNumberPair(query, frameNumber));       
102}
103
104void OpenGLQuerySupport::endQuery()
105{
106    _extensions->glEndQuery(GL_TIME_ELAPSED);
107}
108
109void OpenGLQuerySupport::initialize(osg::State* state)
110{
111    if (_initialized) return;
112
113    _initialized = true;
114    _extensions = osg::Drawable::getExtensions(state->getContextID(),true);
115    _timerQuerySupported = _extensions && _extensions->isTimerQuerySupported();
116    _previousQueryTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
117}
118
119///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
120//
121//
122//  TheadSafeQueue
123
124Renderer::TheadSafeQueue::TheadSafeQueue()
125{
126    _block.set(false);
127}
128
129Renderer::TheadSafeQueue::~TheadSafeQueue()
130{
131}
132
133osgUtil::SceneView* Renderer::TheadSafeQueue::takeFront()
134{
135    if (_queue.empty()) _block.block();
136
137    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
138    if (_queue.empty()) return 0;
139
140    osgUtil::SceneView* front = _queue.front();
141    _queue.pop_front();
142
143    if (_queue.empty()) _block.set(false);
144   
145    return front;
146}
147
148void Renderer::TheadSafeQueue::add(osgUtil::SceneView* sv)
149{
150    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
151    _queue.push_back(sv);
152    _block.set(true);
153}
154
155static OpenThreads::Mutex s_drawSerializerMutex;
156
157///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
158//
159//
160//  Renderer
161Renderer::Renderer(osg::Camera* camera):
162    osg::GraphicsOperation("Renderer",true),
163    OpenGLQuerySupport(),
164    _targetFrameRate(100.0),
165    _minimumTimeAvailableForGLCompileAndDeletePerFrame(0.001),
166    _flushTimeRatio(0.5),
167    _conservativeTimeRatio(0.5),
168    _camera(camera),
169    _done(false),
170    _graphicsThreadDoesCull(true)
171{
172
173    DEBUG_MESSAGE<<"Render::Render() "<<this<<std::endl;
174
175    _sceneView[0] = new osgUtil::SceneView;
176    _sceneView[1] = new osgUtil::SceneView;
177
178    unsigned int sceneViewOptions = osgUtil::SceneView::HEADLIGHT;
179
180    osg::Camera* masterCamera = _camera->getView() ? _camera->getView()->getCamera() : camera;
181    osg::StateSet* stateset = masterCamera->getOrCreateStateSet();
182    osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
183
184    osg::DisplaySettings* ds = _camera->getDisplaySettings() ?  _camera->getDisplaySettings() :
185                               ((view && view->getDisplaySettings()) ?  view->getDisplaySettings() :  osg::DisplaySettings::instance());
186
187    _sceneView[0]->setGlobalStateSet(stateset);
188    _sceneView[1]->setGlobalStateSet(stateset);
189   
190    _sceneView[0]->setDefaults(sceneViewOptions);
191    _sceneView[1]->setDefaults(sceneViewOptions);
192
193    _sceneView[0]->setDisplaySettings(ds);
194    _sceneView[1]->setDisplaySettings(ds);
195
196    _sceneView[0]->setCamera(_camera.get(), false);
197    _sceneView[1]->setCamera(_camera.get(), false);
198
199    // lock the mutex for the current cull SceneView to
200    // prevent the draw traversal from reading from it before the cull traversal has been completed.
201    _availableQueue.add(_sceneView[0].get());
202    _availableQueue.add(_sceneView[1].get());
203       
204    DEBUG_MESSAGE<<"_availableQueue.size()="<<_availableQueue._queue.size()<<std::endl;
205
206    _flushOperation = new osg::FlushDeletedGLObjectsOperation(0.1);
207}
208
209Renderer::~Renderer()
210{
211    DEBUG_MESSAGE<<"Render::~Render() "<<this<<std::endl;
212}
213
214void Renderer::setGraphicsThreadDoesCull(bool flag)
215{
216    if (_graphicsThreadDoesCull==flag) return;
217
218    _graphicsThreadDoesCull = flag;
219}
220
221void Renderer::updateSceneView(osgUtil::SceneView* sceneView)
222{
223    osg::Camera* masterCamera = _camera->getView() ? _camera->getView()->getCamera() : _camera.get();
224    osg::StateSet* stateset = masterCamera->getOrCreateStateSet();
225
226    if (sceneView->getGlobalStateSet()!=stateset)
227    {
228        sceneView->setGlobalStateSet(stateset);
229    }
230   
231    osg::GraphicsContext* context = _camera->getGraphicsContext();
232    osg::State* state = context ? context->getState() : 0;
233    if (sceneView->getState()!=state)
234    {
235        sceneView->setState(state);
236    }
237
238    osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
239    osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0;
240    sceneView->getCullVisitor()->setDatabaseRequestHandler(databasePager);
241   
242    sceneView->setFrameStamp(view ? view->getFrameStamp() : state->getFrameStamp());
243   
244    if (databasePager) databasePager->setCompileGLObjectsForContextID(state->getContextID(), true);
245   
246    osg::DisplaySettings* ds = _camera->getDisplaySettings() ?  _camera->getDisplaySettings() :
247                               ((view &&view->getDisplaySettings()) ?  view->getDisplaySettings() :  osg::DisplaySettings::instance());
248
249    sceneView->setDisplaySettings(ds);
250
251    if (view) _startTick = view->getStartTick();
252}
253
254
255void Renderer::cull()
256{
257    DEBUG_MESSAGE<<"cull()"<<std::endl;
258
259    if (_done || _graphicsThreadDoesCull) return;
260
261    // note we assume lock has already been acquired.
262    osgUtil::SceneView* sceneView = _availableQueue.takeFront();
263
264    DEBUG_MESSAGE<<"cull() got SceneView "<<sceneView<<std::endl;
265
266    if (sceneView)
267    {
268        updateSceneView(sceneView);
269
270        // osg::notify(osg::NOTICE)<<"Culling buffer "<<_currentCull<<std::endl;
271
272        // pass on the fusion distance settings from the View to the SceneView
273        osgViewer::View* view = dynamic_cast<osgViewer::View*>(sceneView->getCamera()->getView());
274        if (view) sceneView->setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue());
275
276        osg::Stats* stats = sceneView->getCamera()->getStats();
277        osg::State* state = sceneView->getState();
278        const osg::FrameStamp* fs = state->getFrameStamp();
279        int frameNumber = fs ? fs->getFrameNumber() : 0;
280
281        // do cull traversal
282        osg::Timer_t beforeCullTick = osg::Timer::instance()->tick();
283
284        sceneView->inheritCullSettings(*(sceneView->getCamera()));
285        sceneView->cull();
286
287        osg::Timer_t afterCullTick = osg::Timer::instance()->tick();
288
289#if 0
290        if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback())
291        {
292            // osg::notify(osg::NOTICE)<<"Completed in cull"<<std::endl;
293            state->getDynamicObjectRenderingCompletedCallback()->completed(state);
294        }
295#endif
296        if (stats && stats->collectStats("rendering"))
297        {
298            DEBUG_MESSAGE<<"Collecting rendering stats"<<std::endl;
299       
300            stats->setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick));
301            stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick));
302            stats->setAttribute(frameNumber, "Cull traversal time taken", osg::Timer::instance()->delta_s(beforeCullTick, afterCullTick));
303        }
304
305        _drawQueue.add(sceneView);
306
307    }
308
309    DEBUG_MESSAGE<<"end cull() "<<this<<std::endl;
310}
311
312void Renderer::draw()
313{
314    DEBUG_MESSAGE<<"draw() "<<this<<std::endl;
315
316    osg::Timer_t startDrawTick = osg::Timer::instance()->tick();
317
318    osgUtil::SceneView* sceneView = _drawQueue.takeFront();
319
320    DEBUG_MESSAGE<<"draw() got SceneView "<<sceneView<<std::endl;
321
322    osg::GraphicsContext* compileContext = sceneView ? osg::GraphicsContext::getCompileContext(sceneView->getState()->getContextID()) : 0;
323    osg::GraphicsThread* compileThread = compileContext ? compileContext->getGraphicsThread() : 0;
324
325    if (sceneView || _done)
326    {
327        osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
328        osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0;
329
330        // osg::notify(osg::NOTICE)<<"Drawing buffer "<<_currentDraw<<std::endl;
331
332        if (_done)
333        {
334            osg::notify(osg::INFO)<<"Renderer::release() causing draw to exit"<<std::endl;
335            return;
336        }
337
338        if (_graphicsThreadDoesCull)
339        {
340            osg::notify(osg::INFO)<<"Renderer::draw() completing early due to change in _graphicsThreadDoesCull flag."<<std::endl;
341            return;
342        }
343
344        // osg::notify(osg::NOTICE)<<"RenderingOperation"<<std::endl;
345
346        osg::Stats* stats = sceneView->getCamera()->getStats();
347        osg::State* state = sceneView->getState();
348        int frameNumber = state->getFrameStamp()->getFrameNumber();
349
350        if (!_initialized)
351        {
352            initialize(state);
353        }
354
355        state->setDynamicObjectCount(sceneView->getDynamicObjectCount());
356
357        if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback())
358        {
359            // osg::notify(osg::NOTICE)<<"Completed in cull"<<std::endl;
360            state->getDynamicObjectRenderingCompletedCallback()->completed(state);
361        }
362
363        bool acquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu");
364
365        if (acquireGPUStats)
366        {
367            checkQuery(stats);
368        }
369
370        // do draw traversal
371        if (acquireGPUStats)
372        {
373            checkQuery(stats);
374            beginQuery(frameNumber);
375        }
376
377        osg::Timer_t beforeDrawTick;
378       
379       
380        bool serializeDraw = sceneView->getDisplaySettings()->getSerializeDrawDispatch();
381
382        if (serializeDraw)
383        {
384            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_drawSerializerMutex);
385            beforeDrawTick = osg::Timer::instance()->tick();
386            sceneView->draw();
387        }
388        else
389        {
390            beforeDrawTick = osg::Timer::instance()->tick();
391            sceneView->draw();
392        }
393
394        _availableQueue.add(sceneView);
395
396        osg::Timer_t afterDispatchTick = osg::Timer::instance()->tick();
397
398        double dispatchTime = osg::Timer::instance()->delta_s(beforeDrawTick, afterDispatchTick);
399
400        // now flush delete OpenGL objects and compile any objects as required by the DatabasePager
401        flushAndCompile(dispatchTime, sceneView, databasePager, compileThread);
402   
403        if (acquireGPUStats)
404        {
405            endQuery();
406            checkQuery(stats);
407        }
408
409        //glFlush();
410       
411        osg::Timer_t afterDrawTick = osg::Timer::instance()->tick();
412
413//        osg::notify(osg::NOTICE)<<"Time wait for draw = "<<osg::Timer::instance()->delta_m(startDrawTick, beforeDrawTick)<<std::endl;
414//        osg::notify(osg::NOTICE)<<"     time for draw = "<<osg::Timer::instance()->delta_m(beforeDrawTick, afterDrawTick)<<std::endl;
415
416        if (stats && stats->collectStats("rendering"))
417        {
418            stats->setAttribute(frameNumber, "Draw traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeDrawTick));
419            stats->setAttribute(frameNumber, "Draw traversal end time", osg::Timer::instance()->delta_s(_startTick, afterDrawTick));
420            stats->setAttribute(frameNumber, "Draw traversal time taken", osg::Timer::instance()->delta_s(beforeDrawTick, afterDrawTick));
421        }
422    }
423
424    DEBUG_MESSAGE<<"end draw() "<<this<<std::endl;
425}
426
427void Renderer::cull_draw()
428{
429    DEBUG_MESSAGE<<"cull_draw() "<<this<<std::endl;
430
431    osgUtil::SceneView* sceneView = _sceneView[0].get();
432    if (!sceneView || _done) return;
433
434    updateSceneView(sceneView);
435
436    osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
437    osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0;
438
439    osg::GraphicsContext* compileContext = osg::GraphicsContext::getCompileContext(sceneView->getState()->getContextID());
440    osg::GraphicsThread* compileThread = compileContext ? compileContext->getGraphicsThread() : 0;
441
442    if (_done)
443    {
444        osg::notify(osg::INFO)<<"Render::release() causing cull_draw to exit"<<std::endl;
445        return;
446    }
447
448    // osg::notify(osg::NOTICE)<<"RenderingOperation"<<std::endl;
449
450    // pass on the fusion distance settings from the View to the SceneView
451    if (view) sceneView->setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue());
452
453    osg::Stats* stats = sceneView->getCamera()->getStats();
454    osg::State* state = sceneView->getState();
455    const osg::FrameStamp* fs = state->getFrameStamp();
456    int frameNumber = fs ? fs->getFrameNumber() : 0;
457
458    if (!_initialized)
459    {
460        initialize(state);
461    }
462
463    bool acquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu");
464
465    if (acquireGPUStats)
466    {
467        checkQuery(stats);
468    }
469
470    // do cull traversal
471    osg::Timer_t beforeCullTick = osg::Timer::instance()->tick();
472
473    sceneView->inheritCullSettings(*(sceneView->getCamera()));
474    sceneView->cull();
475
476    osg::Timer_t afterCullTick = osg::Timer::instance()->tick();
477
478#if 0
479    if (state->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback())
480    {
481        state->getDynamicObjectRenderingCompletedCallback()->completed(state);
482    }
483#endif
484
485
486    // do draw traversal
487    if (acquireGPUStats)
488    {
489        checkQuery(stats);
490        beginQuery(frameNumber);
491    }
492
493    osg::Timer_t beforeDrawTick;
494
495    bool serializeDraw = sceneView->getDisplaySettings()->getSerializeDrawDispatch();
496
497    if (serializeDraw)
498    {
499        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_drawSerializerMutex);
500       
501        beforeDrawTick = osg::Timer::instance()->tick();
502        sceneView->draw();
503    }
504    else
505    {
506        beforeDrawTick = osg::Timer::instance()->tick();
507        sceneView->draw();
508    }
509
510    osg::Timer_t afterDispatchTick = osg::Timer::instance()->tick();
511    double cullAndDispatchTime = osg::Timer::instance()->delta_s(beforeCullTick, afterDispatchTick);
512
513    // now flush delete OpenGL objects and compile any objects as required by the DatabasePager
514    flushAndCompile(cullAndDispatchTime, sceneView, databasePager, compileThread);
515
516
517    if (acquireGPUStats)
518    {
519        endQuery();
520        checkQuery(stats);
521    }
522
523    osg::Timer_t afterDrawTick = osg::Timer::instance()->tick();
524
525    if (stats && stats->collectStats("rendering"))
526    {
527        DEBUG_MESSAGE<<"Collecting rendering stats"<<std::endl;
528
529        stats->setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick));
530        stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick));
531        stats->setAttribute(frameNumber, "Cull traversal time taken", osg::Timer::instance()->delta_s(beforeCullTick, afterCullTick));
532
533        stats->setAttribute(frameNumber, "Draw traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeDrawTick));
534        stats->setAttribute(frameNumber, "Draw traversal end time", osg::Timer::instance()->delta_s(_startTick, afterDrawTick));
535        stats->setAttribute(frameNumber, "Draw traversal time taken", osg::Timer::instance()->delta_s(beforeDrawTick, afterDrawTick));
536    }
537
538    DEBUG_MESSAGE<<"end cull_draw() "<<this<<std::endl;
539
540}
541
542void Renderer::flushAndCompile(double currentElapsedFrameTime, osgUtil::SceneView* sceneView, osgDB::DatabasePager* databasePager, osg::GraphicsThread* compileThread)
543{
544   
545    double targetFrameRate = _targetFrameRate;
546    double minimumTimeAvailableForGLCompileAndDeletePerFrame = _minimumTimeAvailableForGLCompileAndDeletePerFrame;
547
548    if (databasePager)
549    {
550        targetFrameRate = std::min(targetFrameRate, databasePager->getTargetFrameRate());
551        minimumTimeAvailableForGLCompileAndDeletePerFrame = std::min(minimumTimeAvailableForGLCompileAndDeletePerFrame, databasePager->getMinimumTimeAvailableForGLCompileAndDeletePerFrame());
552    }
553   
554    double targetFrameTime = 1.0/targetFrameRate;
555
556    double availableTime = std::max((targetFrameTime - currentElapsedFrameTime)*_conservativeTimeRatio,
557                                    minimumTimeAvailableForGLCompileAndDeletePerFrame);
558
559    double flushTime = availableTime * _flushTimeRatio;
560    double compileTime = availableTime - flushTime;
561
562#if 0
563    osg::notify(osg::NOTICE)<<"total availableTime = "<<availableTime*1000.0<<std::endl;
564    osg::notify(osg::NOTICE)<<"      flushTime     = "<<flushTime*1000.0<<std::endl;
565    osg::notify(osg::NOTICE)<<"      compileTime   = "<<compileTime*1000.0<<std::endl;
566#endif
567
568    if (compileThread)
569    {
570        compileThread->add(_flushOperation.get());
571    }
572    else
573    {
574        sceneView->flushDeletedGLObjects(flushTime);
575    }
576
577    // if any time left over from flush add this to compile time.       
578    if (flushTime>0.0) compileTime += flushTime;
579
580#if 0
581    osg::notify(osg::NOTICE)<<"      revised compileTime   = "<<compileTime*1000.0<<std::endl;
582#endif
583
584    if (databasePager && databasePager->requiresExternalCompileGLObjects(sceneView->getState()->getContextID()))
585    {
586        databasePager->compileGLObjects(*(sceneView->getState()), compileTime);
587    }
588}
589
590void Renderer::operator () (osg::Object* object)
591{
592    osg::GraphicsContext* context = dynamic_cast<osg::GraphicsContext*>(object);
593    if (context) operator()(context);
594
595    osg::Camera* camera = dynamic_cast<osg::Camera*>(object);
596    if (camera) cull();
597}
598
599void Renderer::operator () (osg::GraphicsContext* context)
600{
601    if (_graphicsThreadDoesCull)
602    {
603        cull_draw();
604    }
605    else
606    {
607        draw();
608    }
609}
610
611void Renderer::release()
612{
613    osg::notify(osg::INFO)<<"Renderer::release()"<<std::endl;
614    _done = true;
615
616    _availableQueue.release();
617    _drawQueue.release();
618}
Note: See TracBrowser for help on using the browser.