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"
9 // GLUT is used for window handling
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
;
44 bool doThreading
= true;
45 bool doParDraw
= true;
47 OSG::UInt16 numBuf
= 2;
50 OSG::Thread
*appthread
, *cullthread
, *drawthread
;
52 // barriers to sync app, cull and draw
53 OSG::Barrier
*cullenter
, *cullleave
;
54 OSG::Barrier
*drawenter
;
58 OSG::RenderAction
*rentravact
;
61 OSG::UInt16 numthreads
;
63 // Do the drawing for one frame
64 // extra function to test in sequential
69 static int curBuf
= 0;
72 FNOTICE(("doDraw:start Draw buf %d\n", curBuf
));
73 rentravact
->drawBuffer(curBuf
);
74 FNOTICE(("doDraw:finished Draw buf %d\n", curBuf
));
77 FNOTICE(("doDraw:swapped buf %d\n", curBuf
));
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
96 // need my own Display connection
97 Display
*dpy
= XOpenDisplay(NULL
);
98 xwin
->setDisplay(dpy
);
103 FNOTICE(("draw:enter Barrier\n"));
104 // Wait for the cull thread to finish culling
106 FNOTICE(("draw:left Barrier\n"));
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
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();
138 // need my own Display connection
139 Display
*dpy
= XOpenDisplay(NULL
);
140 xwin
->setDisplay(dpy
);
145 drawthread
= Thread::get("drawThread");
146 drawthread
->runFunction(draw
, 1, NULL
);
151 // Wait for the app thread to commit changes
152 FNOTICE(("cull:enter barrier\n"));
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
169 // Wait for drawer to finish last frame
170 FNOTICE(("cull:wait for draw\n"));
172 FNOTICE(("cull:got draw\n"));
179 FNOTICE(("cull: waiting for exit\n"));
180 exitB
->enter(numthreads
);
181 FNOTICE(("cull: exit\n"));
184 // Standard GLUT callback functions
187 Thread::getCurrentChangeList()->commitChanges();
191 // Wait for the cull thrad to finish culling the last frame
193 // Wait for it to do the sync
195 // Now continue apping
204 void reshape( int w
, int h
)
212 mgr
->mouseMove( x
, y
);
216 mouse(int button
, int state
, int x
, int y
)
219 mgr
->mouseButtonRelease( button
, x
, y
);
221 mgr
->mouseButtonPress( button
, x
, y
);
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
236 #ifdef ScreenOfDisplay
237 #undef ScreenOfDisplay
240 #define DefaultScreen(dpy)((reinterpret_cast<_XPrivDisplay>(dpy))->default_screen)
242 #define ScreenOfDisplay(dpy, scr)(&(reinterpret_cast<_XPrivDisplay>(dpy))->screens[scr])
245 Display
*openWindow(XWindow
*xwin
, char **argv
, int &argc
)
247 static int dblBuf
[] = {GLX_RGBA
, GLX_DEPTH_SIZE
, 16, GLX_DOUBLEBUFFER
,
249 static int snglBuf
[] = {GLX_RGBA
, GLX_DEPTH_SIZE
, 16, None
};
257 XSetWindowAttributes swa
;
259 dpy
= XOpenDisplay(NULL
);
262 std::cerr
<< "Error: Could not open display!" << std::endl
;
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
);
275 vi
= glXChooseVisual( dpy
, DefaultScreen(dpy
), snglBuf
);
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
),
291 swa
.border_pixel
= 0;
292 swa
.event_mask
= ExposureMask
|
303 // Create a Window and connect it to the main display dpy
304 hwin
= XCreateWindow( dpy
,
305 RootWindow(dpy
, vi
->screen
),
311 CWBorderPixel
| CWColormap
| CWEventMask
,
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
));
325 // Initialize GLUT & OpenSG and set up the scene
326 int main (int argc
, char **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] == '-')
344 case 's': doThreading
= false;
346 case 'c': doParDraw
= false;
348 case 'n': cnear
= atof(argv
[2]);
352 case 'f': cfar
= atof(argv
[2]);
356 default: FFATAL(("Unknown option '%s'!\n", argv
[1]));
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"));
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
));
395 Thread::getCurrentChangeList()->commitChanges();
398 //SceneFileHandler::the()->write(scene, "torus2.osb");
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
);
414 mgr
->getCamera()->setNear(mgr
->getCamera()->getNear() * cnear
);
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
);
426 // create a gradient background.
427 GradientBackgroundPtr gback
= GradientBackground::create();
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
);
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
);
462 // main loop ( event dispatching )
471 bool needRedraw
= false;
475 XNextEvent(dpy
, &event
);
479 FINFO(("Key pressed: %d \n",event
.xkey
.keycode
));
480 switch ( event
.xkey
.keycode
)
485 // need to render a frame to get the other threads
486 // out of their barriers
487 FNOTICE(("app: Display for exit\n"));
489 FNOTICE(("app: Waiting for exit\n"));
490 exitB
->enter(numthreads
);
491 FNOTICE(("app: Got exit\n"));
507 FINFO(("Button pressed: %d\n", event
.xbutton
.button
));
508 mouse(event
.xbutton
.button
- 1, 0, event
.xbutton
.x
,
513 FINFO(("Button released: %d\n", event
.xbutton
.button
));
514 mouse(event
.xbutton
.button
- 1, 1, event
.xbutton
.x
,
519 FINFO(("MotionNotify %d %d\n",event
.xmotion
.x
,
522 motion(event
.xmotion
.x
, event
.xmotion
.y
);
526 case ConfigureNotify
:
527 FINFO(("ConfigureNotify\n"));
528 reshape(event
.xconfigure
.width
, event
.xconfigure
.height
);
538 while ( XPending(dpy
) );
545 int main (int argc
, char **argv
)