root/OpenSceneGraph/trunk/examples/osgcamera/osgcamera.cpp @ 4484

Revision 4484, 12.1 kB (checked in by robert, 9 years ago)

Disable the glFinishBarrierOp usage as glFinish was spin locking the CPU :-|

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// C++ source file - (C) 2003 Robert Osfield, released under the OSGPL.
2//
3// Simple example of use of Producer::RenderSurface to create an OpenGL
4// graphics window, and OSG for rendering.
5
6#include <osg/Timer>
7#include <osg/GraphicsContext>
8#include <osg/GraphicsThread>
9
10#include <osgUtil/UpdateVisitor>
11#include <osgUtil/CullVisitor>
12#include <osgUtil/SceneView>
13#include <osgUtil/GLObjectsVisitor>
14
15#include <osgDB/ReadFile>
16
17#include <map>
18#include <list>
19#include <iostream>
20
21
22
23////////////////////////////////////////////////////////////////////////////////
24//
25//
26//  **************** THIS IS AN EXPERIMENTAL IMPLEMENTATION ***************
27//  ************************** PLEASE DO NOT COPY  ************************
28//
29//
30///////////////////////////////////////////////////////////////////////////////
31
32
33// Compile operation, that compile OpenGL objects.
34struct CompileOperation : public osg::GraphicsThread::Operation
35{
36    CompileOperation(osg::Node* scene):
37        osg::GraphicsThread::Operation("Compile",false),
38        _scene(scene)
39    {
40    }
41   
42    virtual void operator () (osg::GraphicsContext* context)
43    {
44        std::cout<<"Compile"<<std::endl;
45   
46        osgUtil::GLObjectsVisitor compileVisitor;
47        compileVisitor.setState(context->getState());
48
49        // do the compile traversal
50        _scene->accept(compileVisitor);
51    }
52   
53    osg::ref_ptr<osg::Node> _scene;
54};
55
56// Cull operation, that does a cull on the scene graph.
57struct CullOperation : public osg::GraphicsThread::Operation
58{
59    CullOperation(osg::CameraNode* camera, osgUtil::SceneView* sceneView):
60        osg::GraphicsThread::Operation("Cull",true),
61        _camera(camera),
62        _sceneView(sceneView)
63    {
64    }
65   
66    virtual void operator () (osg::GraphicsContext* context)
67    {
68        _sceneView->setState(context->getState());
69        _sceneView->setProjectionMatrix(_camera->getProjectionMatrix());
70        _sceneView->setViewMatrix(_camera->getViewMatrix());
71        _sceneView->setViewport(_camera->getViewport());
72       
73        _sceneView->cull();
74    }
75   
76    osg::ref_ptr<osg::CameraNode>    _camera;
77    osg::ref_ptr<osgUtil::SceneView> _sceneView;
78};
79
80// Draw operation, that does a draw on the scene graph.
81struct DrawOperation : public osg::GraphicsThread::Operation
82{
83    DrawOperation(osgUtil::SceneView* sceneView):
84        osg::GraphicsThread::Operation("Draw",true),
85        _sceneView(sceneView)
86    {
87    }
88   
89    virtual void operator () (osg::GraphicsContext*)
90    {
91        _sceneView->draw();
92    }
93   
94    osg::ref_ptr<osgUtil::SceneView> _sceneView;
95};
96
97
98// main does the following steps to create a multi-thread, multiple camera/graphics context view of a scene graph.
99//
100// 1) load the scene graph
101//
102// 2) create a list of camera, each with their own graphis context, with a graphics thread for each context.
103//
104// 3) set up the graphic threads so that the do an initial compile OpenGL objects operation, this is done once, and then this compile op is disgarded
105//
106// 4) set up the graphics thread so that it has all the graphics ops required for the main loop, these ops are:
107// 4.a) frame begin barrair, syncronizes all the waiting graphic threads so they don't run while update is occuring
108// 4.b) frame operation - the cull and draw for each camera
109// 4.c) frame end barrier, releases the update thread once all graphic threads have dispatched all their OpenGL commands
110// 4.d) pre swap barrier, barrier which ensures that all graphics threads have sent their data down to the gfx card.
111// 4.e) swap buffers, do the swap buffers on all the graphics contexts.
112//
113// 5. The main loop:
114// 5.a) update
115// 5.b) join the frame begin barrrier, releasing all the graphics threads to do their stuff
116// 5.c) block on the frame end barrier, waiting till all the graphics threads have done their cull/draws.
117// 5.d) check to see if any of the windows has been closed.
118//
119int main( int argc, char **argv )
120{
121    if (argc<2)
122    {
123        std::cout << argv[0] <<": requires filename argument." << std::endl;
124        return 1;
125    }
126
127    // load the scene.
128    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile(argv[1]);
129    if (!loadedModel)
130    {
131        std::cout << argv[0] <<": No data loaded." << std::endl;
132        return 1;
133    }
134
135   
136    // set up the frame stamp for current frame to record the current time and frame number so that animtion code can advance correctly
137    osg::ref_ptr<osg::FrameStamp> frameStamp = new osg::FrameStamp;
138
139    unsigned int frameNum = 0;
140
141    osgUtil::UpdateVisitor updateVisitor;
142    updateVisitor.setFrameStamp(frameStamp.get());
143
144
145    unsigned int numberCameras = 1;
146    unsigned int xpos = 0;
147    unsigned int ypos = 400;
148    unsigned int width = 400;
149    unsigned int height = 400;
150   
151    typedef std::list< osg::ref_ptr<osg::CameraNode> > CameraList;
152    typedef std::set< osg::GraphicsContext* > GraphicsContextSet;
153
154    CameraList cameraList;
155    GraphicsContextSet graphicsContextSet;
156
157    // create the cameras, graphic contexts and graphic threads.
158    bool shareContexts = false;
159    osg::GraphicsContext* previousContext = 0;
160    for(unsigned int i=0; i< numberCameras; ++i)
161    {
162        osg::ref_ptr<osg::CameraNode> camera = new osg::CameraNode;
163        camera->addChild(loadedModel.get());
164
165        osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
166        traits->_windowName = "osgcamera";
167        traits->_x = xpos;
168        traits->_y = ypos;
169        traits->_width = width;
170        traits->_height = height;
171        traits->_windowDecoration = true;
172        traits->_doubleBuffer = true;
173        traits->_sharedContext = shareContexts ? previousContext : 0;
174       
175        xpos += width;
176
177        osg::ref_ptr<osg::GraphicsContext> gfxc = osg::GraphicsContext::createGraphicsContext(traits.get());
178
179        if (!gfxc)
180        {
181            std::cout<<"Unable to create window."<<std::endl;
182            return 1;
183        }
184
185        camera->setGraphicsContext(gfxc.get());
186
187        // initialize the view to look at the center of the scene graph
188        const osg::BoundingSphere& bs = loadedModel->getBound();
189        osg::Matrix viewMatrix;
190        viewMatrix.makeLookAt(bs.center()-osg::Vec3(0.0,2.0f*bs.radius(),0.0),bs.center(),osg::Vec3(0.0f,0.0f,1.0f));
191
192        camera->setViewport(0,0,traits->_width,traits->_height);
193        camera->setProjectionMatrixAsPerspective(50.0f,1.4f,1.0f,10000.0f);
194        camera->setViewMatrix(viewMatrix);
195
196        // graphics thread will realize the window.
197        gfxc->createGraphicsThread();
198
199        cameraList.push_back(camera);
200
201        previousContext = gfxc.get();
202    }
203
204
205    // build the list of unique graphics contexts.
206    CameraList::iterator citr;
207    for(citr = cameraList.begin();
208        citr != cameraList.end();
209        ++citr)
210    {
211        graphicsContextSet.insert(const_cast<osg::GraphicsContext*>((*citr)->getGraphicsContext()));
212    }
213
214
215    std::cout<<"Number of cameras = "<<cameraList.size()<<std::endl;
216    std::cout<<"Number of graphics contexts = "<<graphicsContextSet.size()<<std::endl;
217
218
219    // first the compile of the GL Objects, do it syncronously.
220    GraphicsContextSet::iterator gitr;
221    osg::ref_ptr<CompileOperation> compileOp = new CompileOperation(loadedModel.get());
222    for(gitr = graphicsContextSet.begin();
223        gitr != graphicsContextSet.end();
224        ++gitr)
225    {
226        osg::GraphicsContext* context = *gitr;
227        context->getGraphicsThread()->add(compileOp.get(), false);
228    }
229
230
231    // second the begin frame barrier to all graphics threads
232    osg::ref_ptr<osg::BarrierOperation> frameBeginBarrierOp = new osg::BarrierOperation(graphicsContextSet.size()+1, osg::BarrierOperation::NO_OPERATION);
233    for(gitr = graphicsContextSet.begin();
234        gitr != graphicsContextSet.end();
235        ++gitr)
236    {
237        osg::GraphicsContext* context = *gitr;
238        context->getGraphicsThread()->add(frameBeginBarrierOp.get(), false);
239    }
240
241    osg::ref_ptr<osg::BarrierOperation> glFinishBarrierOp = new osg::BarrierOperation(graphicsContextSet.size(), osg::BarrierOperation::GL_FINISH);
242
243    // we can put a finish in to gate rendering throughput, so that each new frame starts with a clean sheet.
244    // you should only enable one of these, doFinishBeforeNewDraw will allow for the better parallism of the two finish approaches
245    // note, both are disabled right now, as glFinish is spin locking the CPU, not something that we want...
246    bool doFinishBeforeNewDraw = false;
247    bool doFinishAfterSwap = false;
248
249    // third add the frame for each camera.
250    for(citr = cameraList.begin();
251        citr != cameraList.end();
252        ++citr)
253    {
254        osg::CameraNode* camera = citr->get();
255       
256        // create a scene view to do the cull and draw
257        osgUtil::SceneView* sceneView = new osgUtil::SceneView;
258        sceneView->setDefaults();
259        sceneView->setFrameStamp(frameStamp.get());
260           
261        if (camera->getNumChildren()>=1)
262        {
263            sceneView->setSceneData(camera->getChild(0));
264        }
265
266        // cull traversal operation
267        camera->getGraphicsContext()->getGraphicsThread()->add( new CullOperation(camera, sceneView), false);
268
269        // optionally add glFinish barrier to ensure that all OpenGL commands are completed before we start dispatching a new frame
270        if (doFinishBeforeNewDraw) camera->getGraphicsContext()->getGraphicsThread()->add( glFinishBarrierOp.get(), false);
271
272        // draw traversal operation.
273        camera->getGraphicsContext()->getGraphicsThread()->add( new DrawOperation(sceneView), false);
274    }
275
276    // fourth add the frame end barrier, the pre swap barrier and finally the swap buffers to each graphics thread.
277    // The frame end barrier tells the main thead that the draw dispatch/read phase of the scene graph is complete.
278    // The pre swap barrier is an optional extra, which does a flush before joining the barrier, using this all graphics threads
279    // are held back until they have all dispatched their fifo to the graphics hardware. 
280    // The swapOp just issues a swap buffers for each of the graphics contexts.
281    osg::ref_ptr<osg::BarrierOperation> frameEndBarrierOp = new osg::BarrierOperation(graphicsContextSet.size()+1, osg::BarrierOperation::NO_OPERATION);
282    osg::ref_ptr<osg::BarrierOperation> preSwapBarrierOp = new osg::BarrierOperation(graphicsContextSet.size(), osg::BarrierOperation::GL_FLUSH);
283    osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
284    for(gitr = graphicsContextSet.begin();
285        gitr != graphicsContextSet.end();
286        ++gitr)
287    {
288        osg::GraphicsContext* context = *gitr;
289
290        context->getGraphicsThread()->add(frameEndBarrierOp.get(), false);
291        // context->getGraphicsThread()->add(preSwapBarrierOp.get(), false);
292        context->getGraphicsThread()->add(swapOp.get(), false);
293       
294        // optionally add finish barrier to ensure that we don't do any other graphics work till the current OpenGL commands are complete.
295        if (doFinishAfterSwap) context->getGraphicsThread()->add(glFinishBarrierOp.get(), false);
296    }
297
298
299    // record the timer tick at the start of rendering.   
300    osg::Timer_t start_tick = osg::Timer::instance()->tick();
301    osg::Timer_t previous_tick = start_tick;
302   
303    bool done = false;   
304
305    // main loop -  update scene graph, dispatch frame, wait for frame done.
306    while( !done )
307    {
308
309        osg::Timer_t current_tick = osg::Timer::instance()->tick();
310
311        frameStamp->setReferenceTime(osg::Timer::instance()->delta_s(start_tick,current_tick));
312        frameStamp->setFrameNumber(frameNum++);
313       
314        //std::cout<<"Frame rate "<<1.0/osg::Timer::instance()->delta_s(previous_tick,current_tick)<<std::endl;
315        previous_tick = current_tick;
316
317
318        // do the update traversal.
319        loadedModel->accept(updateVisitor);
320
321        // dispatch the frame.
322        frameBeginBarrierOp->block();
323       
324        // wait till the frame is done.
325        frameEndBarrierOp->block();
326
327        // check if any of the windows are closed
328        for(gitr = graphicsContextSet.begin();
329            gitr != graphicsContextSet.end();
330            ++gitr)
331        {
332            osg::GraphicsContext* context = *gitr;
333            if (!context->isRealized()) done = true;
334        }
335
336    }
337    return 0;
338}
Note: See TracBrowser for help on using the browser.