changed: auto add updateData callback to stages so that stagedata can be updated...
[opensg.git] / Source / WindowSystem / X / testParCullDraw.cpp
bloba8f20576c415699d7061421a83c527e00588d58a
1 // Parallel Culling/Drawing
2 // This is a very ugly hack and more a tesbed than an actually usable
3 // application. For that it's much too brittle...
5 #define OSG_LOG_MODULE "testParCullDraw"
7 #include <fstream>
9 // GLUT is used for window handling
10 #include "OSGGLUT.h"
12 // General OpenSG configuration, needed everywhere
13 #include "OSGConfig.h"
15 #include "OSGXWindow.h"
16 #include "OSGPassiveWindow.h"
18 // A little helper to simplify scene management and interaction
19 #include "OSGSimpleSceneManager.h"
21 // Methods to create simple geometry: boxes, spheres, tori etc.
22 #include "OSGSimpleGeometry.h"
24 #include "OSGGradientBackground.h"
26 #include "OSGImageFileHandler.h"
27 #include "OSGPathHandler.h"
29 #include "OSGSceneFileHandler.h"
30 #include "OSGThread.h"
31 #include "OSGBarrier.h"
33 #include "OSGRenderAction.h"
36 OSG::SimpleSceneManager *mgr;
37 OSG::XWindowRecPtr xwin;
38 OSG::PassiveWindowRecPtr pwin;
40 OSG::NodeRecPtr scene = NULL;
42 // Threading stuff
44 bool doThreading = true;
45 bool doParDraw = true;
47 OSG::UInt16 numBuf = 2;
49 // The three threads
50 OSG::Thread *appthread, *cullthread, *drawthread;
52 // barriers to sync app, cull and draw
53 OSG::Barrier *cullenter, *cullleave;
54 OSG::Barrier *drawenter;
55 OSG::Barrier *exitB;
57 // Action to use
58 OSG::RenderAction *rentravact;
60 bool doExit = false;
61 OSG::UInt16 numthreads;
63 // Do the drawing for one frame
64 // extra function to test in sequential
66 #if 0
67 void doDraw(void)
69 static int curBuf = 0;
71 pwin->frameInit();
72 FNOTICE(("doDraw:start Draw buf %d\n", curBuf));
73 rentravact->drawBuffer(curBuf);
74 FNOTICE(("doDraw:finished Draw buf %d\n", curBuf));
75 xwin->swap();
76 pwin->frameExit();
77 FNOTICE(("doDraw:swapped buf %d\n", curBuf));
79 if(0)
81 std::string stats;
83 if(rentravact->getStatCollector() != NULL)
84 rentravact->getStatCollector()->putToString(stats);
86 std::cout << stats << std::endl;
89 curBuf = (curBuf + 1) % numBuf;
92 // Drawer function executed in a third thread
94 void draw(void* data)
96 // need my own Display connection
97 Display *dpy = XOpenDisplay(NULL);
98 xwin->setDisplay(dpy);
99 xwin->init();
101 while(!doExit)
103 FNOTICE(("draw:enter Barrier\n"));
104 // Wait for the cull thread to finish culling
105 drawenter->enter(2);
106 FNOTICE(("draw:left Barrier\n"));
108 // Do the drawing
109 doDraw();
111 FNOTICE(("draw: waiting for exit\n"));
112 exitB->enter(numthreads);
113 FNOTICE(("draw: exit\n"));
116 // Do the culling for one frame
117 // extra function to test in sequential
119 void doCull(void)
121 static int curBuf = 0;
123 rentravact->setCurrentBuffer(curBuf);
124 FNOTICE(("doCull:start culling buf %d\n", curBuf));
125 pwin->renderAllViewports(rentravact);
126 FNOTICE(("doCull:done culling buf %d\n", curBuf));
128 curBuf = (curBuf + 1) % numBuf;
131 // Culler function executed in a second thread
133 void cull(void* data)
135 appthread->getChangeList()->applyAndClear();
136 if(!doParDraw)
138 // need my own Display connection
139 Display *dpy = XOpenDisplay(NULL);
140 xwin->setDisplay(dpy);
141 xwin->init();
143 else
145 drawthread = Thread::get("drawThread");
146 drawthread->runFunction(draw, 1, NULL);
149 while(!doExit)
151 // Wait for the app thread to commit changes
152 FNOTICE(("cull:enter barrier\n"));
153 cullenter->enter(2);
155 //Sync them into my aspect
156 FNOTICE(("cull:start sync\n"));
157 appthread->getChangeList()->applyAndClear();
158 Thread::getCurrentChangeList()->commitChanges();
159 FNOTICE(("cull:finished sync\n"));
160 // Tell the App thread to continue
161 cullleave->enter(2);
163 // Do the culling
164 doCull();
166 // Now draw
167 if(doParDraw)
169 // Wait for drawer to finish last frame
170 FNOTICE(("cull:wait for draw\n"));
171 drawenter->enter(2);
172 FNOTICE(("cull:got draw\n"));
174 else
176 doDraw();
179 FNOTICE(("cull: waiting for exit\n"));
180 exitB->enter(numthreads);
181 FNOTICE(("cull: exit\n"));
184 // Standard GLUT callback functions
185 void display( void )
187 Thread::getCurrentChangeList()->commitChanges();
188 mgr->update();
189 if(doThreading)
191 // Wait for the cull thrad to finish culling the last frame
192 cullenter->enter(2);
193 // Wait for it to do the sync
194 cullleave->enter(2);
195 // Now continue apping
197 else
199 doCull();
200 doDraw();
204 void reshape( int w, int h )
206 mgr->resize( w, h );
209 void
210 motion(int x, int y)
212 mgr->mouseMove( x, y );
215 void
216 mouse(int button, int state, int x, int y)
218 if ( state )
219 mgr->mouseButtonRelease( button, x, y );
220 else
221 mgr->mouseButtonPress( button, x, y );
225 // Open X Window
227 int wait_for_map_notify(Display *, XEvent *event, char *arg)
229 return( event->type == MapNotify && event->xmap.window == ::Window(arg) );
232 #ifdef OSG_DEBUG_OLD_C_CASTS
233 #ifdef DefaultScreen
234 #undef DefaultScreen
235 #endif
236 #ifdef ScreenOfDisplay
237 #undef ScreenOfDisplay
238 #endif
240 #define DefaultScreen(dpy)((reinterpret_cast<_XPrivDisplay>(dpy))->default_screen)
242 #define ScreenOfDisplay(dpy, scr)(&(reinterpret_cast<_XPrivDisplay>(dpy))->screens[scr])
243 #endif
245 Display *openWindow(XWindow *xwin, char **argv, int &argc)
247 static int dblBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER,
248 None};
249 static int snglBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16, None};
251 DisplayP dpy;
252 X11Window hwin;
254 XVisualInfo *vi;
255 Colormap cmap;
256 XEvent event;
257 XSetWindowAttributes swa;
259 dpy = XOpenDisplay(NULL);
260 if (dpy == NULL)
262 std::cerr << "Error: Could not open display!" << std::endl;
265 int dummy;
266 if( ! glXQueryExtension( dpy, &dummy, &dummy ) )
268 std::cerr << "Error: X server has no OpenGL GLX extension" << std::endl;
271 vi = glXChooseVisual( dpy, DefaultScreen(dpy), dblBuf );
272 if ( vi == NULL )
275 vi = glXChooseVisual( dpy, DefaultScreen(dpy), snglBuf );
276 if (vi == NULL)
278 std::cerr << "no RGB visual with depth buffer" << std::endl;
281 if (vi->c_class != TrueColor)
283 std::cerr << "TrueColor visual required for this program" << std::endl;
286 cmap = XCreateColormap( dpy,
287 RootWindow(dpy, vi->screen),
288 vi->visual,
289 AllocNone );
290 swa.colormap = cmap;
291 swa.border_pixel = 0;
292 swa.event_mask = ExposureMask |
293 ButtonPressMask |
294 ButtonReleaseMask |
295 KeyPressMask |
296 Button1MotionMask |
297 Button2MotionMask |
298 Button3MotionMask |
299 StructureNotifyMask;
301 // Create Window
303 // Create a Window and connect it to the main display dpy
304 hwin = XCreateWindow( dpy,
305 RootWindow(dpy, vi->screen),
306 0, 0, 300, 300,
308 vi->depth,
309 InputOutput,
310 vi->visual,
311 CWBorderPixel | CWColormap | CWEventMask,
312 &swa );
314 XSetStandardProperties(dpy, hwin, "testWindowX", "testWindowX", None, argv, argc, NULL);
316 xwin->setDisplay ( dpy );
317 xwin->setWindow ( hwin );
319 XMapWindow(dpy, hwin);
320 XIfEvent(dpy, &event, wait_for_map_notify, reinterpret_cast<char *>(hwin));
322 return dpy;
325 // Initialize GLUT & OpenSG and set up the scene
326 int main (int argc, char **argv)
328 // OSG init
329 osgInit(argc,argv);
331 // Add Timestamps to log output
332 osgLog().addHeaderElem(LOG_TIMESTAMP_HEADER);
334 // Passive Window for culling
335 pwin = PassiveWindow::create();
337 Real32 cnear = -1., cfar = -1.;
339 // check command line options
340 while(argc > 1 && argv[1][0] == '-')
342 switch(argv[1][1])
344 case 's': doThreading = false;
345 break;
346 case 'c': doParDraw = false;
347 break;
348 case 'n': cnear = atof(argv[2]);
349 argc --;
350 argv ++;
351 break;
352 case 'f': cfar = atof(argv[2]);
353 argc --;
354 argv ++;
355 break;
356 default: FFATAL(("Unknown option '%s'!\n", argv[1]));
357 exit(1);
359 argc --;
360 argv ++;
363 // create the scene
365 const char *fileName = (argc > 1) ? argv[1] : "None";
367 FNOTICE(("Reading file %s...\n",fileName));
369 scene = SceneFileHandler::the()->read(fileName, NULL);
371 FNOTICE(("File read\n"));
373 if(scene == NULL)
375 std::cerr << "Error loading " << fileName << "!" << std::endl;
377 scene = makeCoredNode<Group>();
379 SimpleMaterialUnrecPtr sm = SimpleMaterial::create();
381 sm->setDiffuse(Color3f(0,1,1));
382 sm->setSpecular(Color3f(1,1,1));
383 sm->setTransparency(.5);
385 GeometryUnrecPtr geo = makeTorusGeo( .5, 2, 16, 16 );
386 geo->setMaterial(sm);
387 scene->addChild(makeNodeFor(geo));
389 geo = makeTorusGeo( .3, .5, 16, 16 );
390 geo->setMaterial(sm);
391 scene->addChild(makeNodeFor(geo));
394 //scene->dump();
395 Thread::getCurrentChangeList()->commitChanges();
397 // file out test.
398 //SceneFileHandler::the()->write(scene, "torus2.osb");
401 // X init
402 xwin = XWindow::create();
403 Display *dpy = openWindow(xwin, argv, argc);
405 // create the SimpleSceneManager helper
406 mgr = new SimpleSceneManager;
408 mgr->setWindow( pwin );
409 mgr->setRoot( scene );
411 mgr->showAll();
413 if(cnear != -1)
414 mgr->getCamera()->setNear(mgr->getCamera()->getNear() * cnear);
416 if(cfar != -1)
417 mgr->getCamera()->setFar(mgr->getCamera()->getFar() * cfar);
419 // We'll be using the new style action here
420 rentravact = RenderAction::create();
422 rentravact->setDoCullOnly(true);
423 rentravact->setNumBuffers(numBuf);
425 #if 0
426 // create a gradient background.
427 GradientBackgroundPtr gback = GradientBackground::create();
428 gback->clearLines();
429 gback->addLine(Color3f(0.7, 0.7, 0.8), 0);
430 gback->addLine(Color3f(0.0, 0.1, 0.3), 1);
432 WindowPtr win = mgr->getWindow();
433 for(int i=0;i<win->getPort().size();++i)
435 ViewportPtr vp = win->getPort()[i];
436 vp->setBackground(gback);
438 #endif
440 // Start threading
442 if(doThreading)
444 // Create barriers for syncing
445 cullenter = Barrier::create();
446 cullleave = Barrier::create();
447 drawenter = Barrier::create();
448 exitB = Barrier::create();
450 numthreads = 1 + (doThreading?1:0) + (doParDraw?1:0);
452 appthread = Thread::getCurrent();
454 cullthread = Thread::get("cullThread");
455 cullthread->runFunction(cull, 1, NULL);
457 else
459 xwin->init();
462 // main loop ( event dispatching )
464 bool stopIt = false;
465 // First redraw
466 display();
468 while ( !stopIt )
470 XEvent event;
471 bool needRedraw = false;
475 XNextEvent(dpy, &event);
476 switch (event.type)
478 case KeyPress:
479 FINFO(("Key pressed: %d \n",event.xkey.keycode));
480 switch ( event.xkey.keycode )
482 case 9:
483 stopIt = true;
484 doExit = true;
485 // need to render a frame to get the other threads
486 // out of their barriers
487 FNOTICE(("app: Display for exit\n"));
488 display();
489 FNOTICE(("app: Waiting for exit\n"));
490 exitB->enter(numthreads);
491 FNOTICE(("app: Got exit\n"));
494 delete mgr;
496 xwin = NULL;
497 pwin = NULL;
498 scene = NULL;
500 osgExit();
502 exit(0);
504 break;
506 case ButtonPress:
507 FINFO(("Button pressed: %d\n", event.xbutton.button));
508 mouse(event.xbutton.button - 1, 0, event.xbutton.x,
509 event.xbutton.y);
510 break;
512 case ButtonRelease:
513 FINFO(("Button released: %d\n", event.xbutton.button));
514 mouse(event.xbutton.button - 1, 1, event.xbutton.x,
515 event.xbutton.y);
516 break;
518 case MotionNotify:
519 FINFO(("MotionNotify %d %d\n",event.xmotion.x,
520 event.xmotion.y));
522 motion(event.xmotion.x, event.xmotion.y);
523 needRedraw = true;
524 break;
526 case ConfigureNotify:
527 FINFO(("ConfigureNotify\n"));
528 reshape(event.xconfigure.width, event.xconfigure.height );
529 needRedraw = true;
530 break;
532 case Expose:
533 needRedraw = true;
534 break;
538 while ( XPending(dpy) );
539 if(needRedraw)
540 display();
542 return 0;
544 #else
545 int main (int argc, char **argv)
547 return 0;
549 #endif