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

Revision 7209, 17.5 kB (checked in by robert, 10 years ago)

Refactored the way the Scene is used in Viewer and CompositeViewer? to ensure
that only on Scene exists per scene graph.

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::INFO)
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//  Renderer
123
124Renderer::Renderer(osg::Camera* camera):
125    osg::GraphicsOperation("Renderer",true),
126    OpenGLQuerySupport(),
127    _camera(camera),
128    _done(false),
129    _graphicsThreadDoesCull(true)
130{
131
132    DEBUG_MESSAGE<<"Render::Render() "<<this<<std::endl;
133
134    _lockHeld[0]  = false;
135    _lockHeld[1]  = false;
136
137    _sceneView[0] = new osgUtil::SceneView;
138    _sceneView[1] = new osgUtil::SceneView;
139
140    unsigned int sceneViewOptions = osgUtil::SceneView::HEADLIGHT;
141
142    osg::Camera* masterCamera = _camera->getView() ? _camera->getView()->getCamera() : camera;
143    osg::StateSet* stateset = masterCamera->getOrCreateStateSet();
144    osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
145
146    osg::DisplaySettings* ds = _camera->getDisplaySettings() ?  _camera->getDisplaySettings() :
147                               ((view &&view->getDisplaySettings()) ?  view->getDisplaySettings() :  osg::DisplaySettings::instance());
148
149    _sceneView[0]->setGlobalStateSet(stateset);
150    _sceneView[1]->setGlobalStateSet(stateset);
151   
152    _sceneView[0]->setDefaults(sceneViewOptions);
153    _sceneView[1]->setDefaults(sceneViewOptions);
154
155    _sceneView[0]->setDisplaySettings(ds);
156    _sceneView[1]->setDisplaySettings(ds);
157
158    _sceneView[0]->setCamera(_camera.get(), false);
159    _sceneView[1]->setCamera(_camera.get(), false);
160
161    _currentCull = 0;
162    _currentDraw = 0;
163
164    // lock the mutex for the current cull SceneView to
165    // prevent the draw traversal from reading from it before the cull traversal has been completed.
166    if (!_graphicsThreadDoesCull)
167    {
168         _mutex[_currentCull].lock();
169         _lockHeld[_currentCull] = true;
170    }
171
172    _flushOperation = new osg::FlushDeletedGLObjectsOperation(0.1);
173}
174
175Renderer::~Renderer()
176{
177    DEBUG_MESSAGE<<"Render::~Render() "<<this<<std::endl;
178}
179
180void Renderer::setGraphicsThreadDoesCull(bool flag)
181{
182    if (_graphicsThreadDoesCull==flag) return;
183
184    _graphicsThreadDoesCull = flag;
185
186    _currentCull = 0;
187    _currentDraw = 0;
188
189    if (_graphicsThreadDoesCull)
190    {
191        // need to disable any locks held by the cull
192        if (_lockHeld[0])
193        {
194            _lockHeld[0] = false;
195            _mutex[0].unlock();
196        }
197
198        if (_lockHeld[1])
199        {
200            _lockHeld[1] = false;
201            _mutex[1].unlock();
202        }
203
204        DEBUG_MESSAGE<<"Disabling locks in Renderer"<<std::endl;
205    }
206    else
207    {
208        DEBUG_MESSAGE<<"Enable locks in Renderer"<<std::endl;
209   
210        // need to set a lock for cull
211        _mutex[_currentCull].lock();
212        _lockHeld[_currentCull] = true;
213    }
214}
215
216void Renderer::updateSceneView(osgUtil::SceneView* sceneView)
217{
218    osg::Camera* masterCamera = _camera->getView() ? _camera->getView()->getCamera() : _camera.get();
219    osg::StateSet* stateset = masterCamera->getOrCreateStateSet();
220
221    if (sceneView->getGlobalStateSet()!=stateset)
222    {
223        sceneView->setGlobalStateSet(stateset);
224    }
225   
226    osg::GraphicsContext* context = _camera->getGraphicsContext();
227    osg::State* state = context ? context->getState() : 0;
228    if (sceneView->getState()!=state)
229    {
230        sceneView->setState(state);
231    }
232
233    osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
234    osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0;
235    sceneView->getCullVisitor()->setDatabaseRequestHandler(databasePager);
236   
237    sceneView->setFrameStamp(view ? view->getFrameStamp() : state->getFrameStamp());
238   
239    if (databasePager) databasePager->setCompileGLObjectsForContextID(state->getContextID(), true);
240   
241    osg::DisplaySettings* ds = _camera->getDisplaySettings() ?  _camera->getDisplaySettings() :
242                               ((view &&view->getDisplaySettings()) ?  view->getDisplaySettings() :  osg::DisplaySettings::instance());
243
244    sceneView->setDisplaySettings(ds);
245
246    if (view) _startTick = view->getStartTick();
247}
248
249
250void Renderer::cull()
251{
252    DEBUG_MESSAGE<<"cull()"<<std::endl;
253
254    if (_done || _graphicsThreadDoesCull) return;
255
256    // note we assume lock has already been aquired.
257    osgUtil::SceneView* sceneView = _sceneView[_currentCull].get();
258
259    if (sceneView)
260    {
261        updateSceneView(sceneView);
262
263        // osg::notify(osg::NOTICE)<<"Culling buffer "<<_currentCull<<std::endl;
264
265        // pass on the fusion distance settings from the View to the SceneView
266        osgViewer::View* view = dynamic_cast<osgViewer::View*>(sceneView->getCamera()->getView());
267        if (view) sceneView->setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue());
268
269        osg::Stats* stats = sceneView->getCamera()->getStats();
270        osg::State* state = sceneView->getState();
271        const osg::FrameStamp* fs = state->getFrameStamp();
272        int frameNumber = fs ? fs->getFrameNumber() : 0;
273
274        _frameNumber[_currentCull] = frameNumber;
275
276        // do cull taversal
277        osg::Timer_t beforeCullTick = osg::Timer::instance()->tick();
278
279        sceneView->inheritCullSettings(*(sceneView->getCamera()));
280        sceneView->cull();
281
282        osg::Timer_t afterCullTick = osg::Timer::instance()->tick();
283
284#if 0
285        if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback())
286        {
287            // osg::notify(osg::NOTICE)<<"Completed in cull"<<std::endl;
288            state->getDynamicObjectRenderingCompletedCallback()->completed(state);
289        }
290#endif
291        if (stats && stats->collectStats("rendering"))
292        {
293            DEBUG_MESSAGE<<"Collecting rendering stats"<<std::endl;
294       
295            stats->setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick));
296            stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick));
297            stats->setAttribute(frameNumber, "Cull traversal time taken", osg::Timer::instance()->delta_s(beforeCullTick, afterCullTick));
298        }
299    }
300
301
302    // relase the mutex associated with this cull traversal, let the draw commence.
303    _lockHeld[_currentCull] = false;
304    _mutex[_currentCull].unlock();
305
306    // swap which SceneView we need to do cull traversal on next.
307    _currentCull = 1 - _currentCull;
308
309    // aquire the lock for it for the new cull traversal
310    _mutex[_currentCull].lock();
311    _lockHeld[_currentCull] = true;
312
313    DEBUG_MESSAGE<<"end cull() "<<this<<std::endl;
314}
315
316void Renderer::draw()
317{
318    DEBUG_MESSAGE<<"draw() "<<this<<std::endl;
319
320    osgUtil::SceneView* sceneView = _sceneView[_currentDraw].get();
321
322    osg::GraphicsContext* compileContext = osg::GraphicsContext::getCompileContext(sceneView->getState()->getContextID());
323    osg::GraphicsThread* compileThread = compileContext ? compileContext->getGraphicsThread() : 0;
324
325    if (sceneView || _done)
326    {
327        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex[_currentDraw]);
328
329        osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
330        osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0;
331
332        // osg::notify(osg::NOTICE)<<"Drawing buffer "<<_currentDraw<<std::endl;
333
334        if (_done)
335        {
336            osg::notify(osg::INFO)<<"Renderer::release() causing draw to exit"<<std::endl;
337            return;
338        }
339
340        if (_graphicsThreadDoesCull)
341        {
342            osg::notify(osg::INFO)<<"Renderer::draw() completing early due to change in _graphicsThreadDoesCull flag."<<std::endl;
343            return;
344        }
345
346        // osg::notify(osg::NOTICE)<<"RenderingOperation"<<std::endl;
347
348        osg::Stats* stats = sceneView->getCamera()->getStats();
349        osg::State* state = sceneView->getState();
350        int frameNumber = _frameNumber[_currentDraw];
351
352        if (!_initialized)
353        {
354            initialize(state);
355        }
356
357        state->setDynamicObjectCount(sceneView->getDynamicObjectCount());
358
359        if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback())
360        {
361            // osg::notify(osg::NOTICE)<<"Completed in cull"<<std::endl;
362            state->getDynamicObjectRenderingCompletedCallback()->completed(state);
363        }
364
365        osg::Timer_t beforeDrawTick = osg::Timer::instance()->tick();
366
367        bool aquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu");
368
369        if (aquireGPUStats)
370        {
371            checkQuery(stats);
372        }
373
374        // do draw traveral
375        if (aquireGPUStats)
376        {
377            checkQuery(stats);
378            beginQuery(frameNumber);
379        }
380
381        sceneView->draw();
382
383        double availableTime = 0.004; // 4 ms
384        if (databasePager && databasePager->requiresExternalCompileGLObjects(sceneView->getState()->getContextID()))
385        {
386            databasePager->compileGLObjects(*(sceneView->getState()), availableTime);
387        }
388
389        if (compileThread)
390        {
391            compileThread->add(_flushOperation.get());
392        }
393        else
394        {
395            sceneView->flushDeletedGLObjects(availableTime);
396        }
397
398        if (aquireGPUStats)
399        {
400            endQuery();
401            checkQuery(stats);
402        }
403
404        glFlush();
405
406
407        osg::Timer_t afterDrawTick = osg::Timer::instance()->tick();
408
409        if (stats && stats->collectStats("rendering"))
410        {
411            stats->setAttribute(frameNumber, "Draw traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeDrawTick));
412            stats->setAttribute(frameNumber, "Draw traversal end time", osg::Timer::instance()->delta_s(_startTick, afterDrawTick));
413            stats->setAttribute(frameNumber, "Draw traversal time taken", osg::Timer::instance()->delta_s(beforeDrawTick, afterDrawTick));
414        }
415    }
416
417    _currentDraw = 1-_currentDraw;
418
419    DEBUG_MESSAGE<<"end draw() "<<this<<std::endl;
420}
421
422void Renderer::cull_draw()
423{
424    DEBUG_MESSAGE<<"cull_draw() "<<this<<std::endl;
425
426    osgUtil::SceneView* sceneView = _sceneView[_currentDraw].get();
427    if (!sceneView || _done) return;
428
429    updateSceneView(sceneView);
430
431    osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
432    osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0;
433
434    osg::GraphicsContext* compileContext = osg::GraphicsContext::getCompileContext(sceneView->getState()->getContextID());
435    osg::GraphicsThread* compileThread = compileContext ? compileContext->getGraphicsThread() : 0;
436
437    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex[_currentDraw]);
438
439    if (_done)
440    {
441        osg::notify(osg::INFO)<<"Render::release() causing cull_draw to exit"<<std::endl;
442        return;
443    }
444
445    // osg::notify(osg::NOTICE)<<"RenderingOperation"<<std::endl;
446
447    // pass on the fusion distance settings from the View to the SceneView
448    if (view) sceneView->setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue());
449
450    osg::Stats* stats = sceneView->getCamera()->getStats();
451    osg::State* state = sceneView->getState();
452    const osg::FrameStamp* fs = state->getFrameStamp();
453    int frameNumber = fs ? fs->getFrameNumber() : 0;
454
455    if (!_initialized)
456    {
457        initialize(state);
458    }
459
460    bool aquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu");
461
462    if (aquireGPUStats)
463    {
464        checkQuery(stats);
465    }
466
467    // do cull taversal
468    osg::Timer_t beforeCullTick = osg::Timer::instance()->tick();
469
470    sceneView->inheritCullSettings(*(sceneView->getCamera()));
471    sceneView->cull();
472
473    osg::Timer_t afterCullTick = osg::Timer::instance()->tick();
474
475#if 0
476    if (state->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback())
477    {
478        state->getDynamicObjectRenderingCompletedCallback()->completed(state);
479    }
480#endif
481
482    // do draw traveral
483    if (aquireGPUStats)
484    {
485        checkQuery(stats);
486        beginQuery(frameNumber);
487    }
488
489    sceneView->draw();
490
491    double availableTime = 0.004; // 4 ms
492    if (databasePager && databasePager->requiresExternalCompileGLObjects(sceneView->getState()->getContextID()))
493    {
494        databasePager->compileGLObjects(*(sceneView->getState()), availableTime);
495    }
496
497    if (compileThread)
498    {
499        compileThread->add(_flushOperation.get());
500    }
501    else
502    {
503        sceneView->flushDeletedGLObjects(availableTime);
504    }
505
506    if (aquireGPUStats)
507    {
508        endQuery();
509        checkQuery(stats);
510    }
511
512    osg::Timer_t afterDrawTick = osg::Timer::instance()->tick();
513
514    if (stats && stats->collectStats("rendering"))
515    {
516        DEBUG_MESSAGE<<"Collecting rendering stats"<<std::endl;
517
518        stats->setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick));
519        stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick));
520        stats->setAttribute(frameNumber, "Cull traversal time taken", osg::Timer::instance()->delta_s(beforeCullTick, afterCullTick));
521
522        stats->setAttribute(frameNumber, "Draw traversal begin time", osg::Timer::instance()->delta_s(_startTick, afterCullTick));
523        stats->setAttribute(frameNumber, "Draw traversal end time", osg::Timer::instance()->delta_s(_startTick, afterDrawTick));
524        stats->setAttribute(frameNumber, "Draw traversal time taken", osg::Timer::instance()->delta_s(afterCullTick, afterDrawTick));
525    }
526
527    DEBUG_MESSAGE<<"end cull_draw() "<<this<<std::endl;
528
529}
530
531void Renderer::operator () (osg::Object* object)
532{
533    osg::GraphicsContext* context = dynamic_cast<osg::GraphicsContext*>(object);
534    if (context) operator()(context);
535
536    osg::Camera* camera = dynamic_cast<osg::Camera*>(object);
537    if (camera) cull();
538}
539
540void Renderer::operator () (osg::GraphicsContext* context)
541{
542    if (_graphicsThreadDoesCull)
543    {
544        cull_draw();
545    }
546    else
547    {
548        draw();
549    }
550}
551
552void Renderer::release()
553{
554    osg::notify(osg::INFO)<<"Renderer::release()"<<std::endl;
555    _done = true;
556
557    if (_lockHeld[0])
558    {
559        _lockHeld[0] = false;
560        _mutex[0].unlock();
561    }
562
563    if (_lockHeld[1])
564    {
565        _lockHeld[1] = false;
566        _mutex[1].unlock();
567    }
568}
Note: See TracBrowser for help on using the browser.