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

Revision 7274, 18.2 kB (checked in by robert, 10 years ago)

Addd control for serializing draw dispatch.

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