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

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

Updated wrappers

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.