Show
Ignore:
Timestamp:
12/22/06 18:46:21 (7 years ago)
Author:
robert
Message:

Implemented perliminary multi-threading support in osgViewer::Viewer

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/examples/osgcamera/osgcamera.cpp

    r5838 r5843  
    44// graphics window, and OSG for rendering. 
    55 
    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> 
    146 
    157#include <osgDB/ReadFile> 
    16 #include <osgDB/DynamicLibrary> 
    17 #include <osgDB/Registry> 
    18  
    19 #include <osgViewer/View> 
    20  
    21 #include <map> 
    22 #include <list> 
     8#include <osgViewer/Viewer> 
     9#include <osgGA/TrackballManipulator> 
    2310#include <iostream> 
    24  
    25  
    26 #if !defined(_WIN32) 
    27  
    28 #include <osgViewer/Viewer> 
    29  
    30 #include <osgGA/TrackballManipulator> 
    31  
    32 void renderCamera(osg::Camera* camera) 
    33 { 
    34     osg::GraphicsContext* gc = camera->getGraphicsContext(); 
    35     if (!gc) return; 
    36      
    37     osgUtil::SceneView* sceneView = dynamic_cast<osgUtil::SceneView*>(camera->getRenderingCache(0)); 
    38     if (!sceneView) return; 
    39  
    40     gc->makeCurrent(); 
    41      
    42     sceneView->cull(); 
    43     sceneView->draw(); 
    44      
    45     gc->swapBuffers(); 
    46 } 
    47  
    48 void setUpFrameStamp(osg::Camera* camera, osg::FrameStamp* frameStamp, osg::Node* loadedModel) 
    49 { 
    50     osgUtil::SceneView* sceneView = dynamic_cast<osgUtil::SceneView*>(camera->getRenderingCache(0)); 
    51     if (!sceneView) return; 
    52      
    53     sceneView->setFrameStamp(frameStamp); 
    54      
    55     sceneView->setSceneData(loadedModel); 
    56      
    57 } 
    5811 
    5912int main( int argc, char **argv ) 
     
    6417        return 1; 
    6518    } 
     19 
     20 
     21    osg::DisplaySettings::instance()->setMaxNumberOfGraphicsContexts(2); 
     22    osg::Referenced::setThreadSafeReferenceCounting(true); 
    6623 
    6724    // load the scene. 
     
    8845    } 
    8946 
    90 } 
    91  
    92  
    93 #else 
    94  
    95  
    96 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    97 //   
    98 //  ORIGINAL osgcamera example code. 
    99  
    100 //////////////////////////////////////////////////////////////////////////////// 
    101 // 
    102 // 
    103 //  **************** THIS IS AN EXPERIMENTAL IMPLEMENTATION *************** 
    104 //  ************************** PLEASE DO NOT COPY  ************************ 
    105 // 
    106 // 
    107 /////////////////////////////////////////////////////////////////////////////// 
    108  
    109  
    110 // Compile operation, that compile OpenGL objects. 
    111 struct CompileOperation : public osg::GraphicsThread::Operation 
    112 { 
    113     CompileOperation(osg::Node* scene): 
    114         osg::GraphicsThread::Operation("Compile",false), 
    115         _scene(scene) 
    116     { 
    117     } 
    118      
    119     virtual void operator () (osg::GraphicsContext* context) 
    120     { 
    121         std::cout<<"Compile"<<std::endl; 
    122      
    123         osgUtil::GLObjectsVisitor compileVisitor; 
    124         compileVisitor.setState(context->getState()); 
    125  
    126         // do the compile traversal 
    127         _scene->accept(compileVisitor); 
    128     } 
    129      
    130     osg::ref_ptr<osg::Node> _scene; 
    131 }; 
    132  
    133 // Cull operation, that does a cull on the scene graph. 
    134 struct CullOperation : public osg::GraphicsThread::Operation 
    135 { 
    136     CullOperation(osgUtil::SceneView* sceneView): 
    137         osg::GraphicsThread::Operation("Cull",true), 
    138         _sceneView(sceneView) 
    139     { 
    140     } 
    141      
    142     virtual void operator () (osg::GraphicsContext* context) 
    143     { 
    144         _sceneView->setState(context->getState()); 
    145         _sceneView->cull(); 
    146     } 
    147      
    148     osg::ref_ptr<osgUtil::SceneView> _sceneView; 
    149 }; 
    150  
    151 // Draw operation, that does a draw on the scene graph. 
    152 struct DrawOperation : public osg::GraphicsThread::Operation 
    153 { 
    154     DrawOperation(osgUtil::SceneView* sceneView): 
    155         osg::GraphicsThread::Operation("Draw",true), 
    156         _sceneView(sceneView) 
    157     { 
    158     } 
    159      
    160     virtual void operator () (osg::GraphicsContext*) 
    161     { 
    162         _sceneView->draw(); 
    163     } 
    164      
    165     osg::ref_ptr<osgUtil::SceneView> _sceneView; 
    166 }; 
    167  
    168 struct CleanUpOperation : public osg::GraphicsThread::Operation 
    169 { 
    170     CleanUpOperation(osgUtil::SceneView* sceneView): 
    171         osg::GraphicsThread::Operation("CleanUp",false), 
    172         _sceneView(sceneView) 
    173     { 
    174     } 
    175      
    176     virtual void operator () (osg::GraphicsContext*) 
    177     { 
    178         _sceneView->releaseAllGLObjects(); 
    179         _sceneView->flushAllDeletedGLObjects(); 
    180     } 
    181      
    182     osg::ref_ptr<osgUtil::SceneView> _sceneView; 
    183 }; 
    184  
    185 // main does the following steps to create a multi-thread, multiple camera/graphics context view of a scene graph. 
    186 // 
    187 // 1) load the scene graph 
    188 // 
    189 // 2) create a list of camera, each with their own graphis context, with a graphics thread for each context. 
    190 // 
    191 // 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 
    192 // 
    193 // 4) set up the graphics thread so that it has all the graphics ops required for the main loop, these ops are: 
    194 // 4.a) frame begin barrair, syncronizes all the waiting graphic threads so they don't run while update is occuring 
    195 // 4.b) frame operation - the cull and draw for each camera 
    196 // 4.c) frame end barrier, releases the update thread once all graphic threads have dispatched all their OpenGL commands 
    197 // 4.d) pre swap barrier, barrier which ensures that all graphics threads have sent their data down to the gfx card. 
    198 // 4.e) swap buffers, do the swap buffers on all the graphics contexts. 
    199 // 
    200 // 5. The main loop: 
    201 // 5.a) update 
    202 // 5.b) join the frame begin barrrier, releasing all the graphics threads to do their stuff 
    203 // 5.c) block on the frame end barrier, waiting till all the graphics threads have done their cull/draws. 
    204 // 5.d) check to see if any of the windows has been closed.  
    205 // 
    206 int main( int argc, char **argv ) 
    207 { 
    208     osg::Referenced::setThreadSafeReferenceCounting(true); 
    209  
    210     // use an ArgumentParser object to manage the program arguments. 
    211     osg::ArgumentParser arguments(&argc,argv); 
    212  
    213     std::string windowingLibrary("osgProducer"); 
    214     while (arguments.read("--windowing",windowingLibrary)) {} 
    215  
    216     // load the osgProducer library manually. 
    217     osg::ref_ptr<osgDB::DynamicLibrary> windowingLib = 
    218         osgDB::DynamicLibrary::loadLibrary(osgDB::Registry::instance()->createLibraryNameForNodeKit(windowingLibrary)); 
    219  
    220  
    221     if (!windowingLib) 
    222     { 
    223         std::cout<<"Error: failed to loading windowing library: "<<windowingLibrary<<std::endl; 
    224     } 
    225  
    226     osg::GraphicsContext::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface(); 
    227     if (!wsi)  
    228     { 
    229         std::cout<<"No WindowSystemInterface available, cannot create windows."<<std::endl; 
    230         return 1; 
    231     } 
    232  
    233  
    234     osg::ref_ptr<osgViewer::View> view = new osgViewer::View; 
    235     view->setUpViewAcrossAllScreens(); 
    236  
    237  
    238  
    239  
    240     unsigned int numScreens = wsi->getNumScreens(); 
    241  
    242     unsigned int numberCameras = numScreens; 
    243     while (arguments.read("--cameras",numberCameras)) {} 
    244  
    245     unsigned int xpos = 0; 
    246     unsigned int ypos = 400; 
    247     unsigned int width = 400; 
    248     unsigned int height = 400; 
    249  
    250     while (arguments.read("--xpos",xpos)) {} 
    251     while (arguments.read("--ypos",ypos)) {} 
    252     while (arguments.read("--height",height)) {} 
    253     while (arguments.read("--width",width)) {} 
    254  
    255     unsigned int maxNumFrames = 1000; 
    256     while (arguments.read("--max-num-frames",maxNumFrames)) {} 
    257  
    258     // load the scene. 
    259     osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments); 
    260     if (!loadedModel)  
    261     { 
    262         std::cout << argv[0] <<": No data loaded." << std::endl; 
    263         return 1; 
    264     } 
    265  
    266      
    267     // set up the frame stamp for current frame to record the current time and frame number so that animtion code can advance correctly 
    268     osg::ref_ptr<osg::FrameStamp> frameStamp = new osg::FrameStamp; 
    269  
    270     unsigned int frameNum = 0; 
    271  
    272     osgUtil::UpdateVisitor updateVisitor; 
    273     updateVisitor.setFrameStamp(frameStamp.get()); 
    274      
    275     typedef std::list< osg::ref_ptr<osg::Camera> > CameraList; 
    276     typedef std::set< osg::GraphicsContext* > GraphicsContextSet; 
    277  
    278     CameraList cameraList; 
    279     GraphicsContextSet graphicsContextSet; 
    280      
    281      
    282  
    283     // create the cameras, graphic contexts and graphic threads. 
    284     bool shareContexts = false; 
    285     osg::GraphicsContext* previousContext = 0; 
    286     for(unsigned int i=0; i< numberCameras; ++i) 
    287     { 
    288         osg::ref_ptr<osg::Camera> camera = new osg::Camera; 
    289         camera->addChild(loadedModel.get()); 
    290  
    291         osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; 
    292         traits->_windowName = "osgcamera"; 
    293         traits->_screenNum = i % numScreens; 
    294         traits->_x = xpos; 
    295         traits->_y = ypos; 
    296         traits->_width = width; 
    297         traits->_height = height; 
    298         traits->_windowDecoration = true; 
    299         traits->_doubleBuffer = true; 
    300         traits->_sharedContext = shareContexts ? previousContext : 0; 
    301          
    302         xpos += width; 
    303  
    304         osg::ref_ptr<osg::GraphicsContext> gfxc = osg::GraphicsContext::createGraphicsContext(traits.get()); 
    305  
    306         if (!gfxc) 
    307         { 
    308             std::cout<<"Unable to create window."<<std::endl; 
    309             return 1; 
    310         } 
    311  
    312         camera->setGraphicsContext(gfxc.get()); 
    313  
    314         // initialize the view to look at the center of the scene graph 
    315         const osg::BoundingSphere& bs = loadedModel->getBound(); 
    316         osg::Matrix viewMatrix; 
    317         viewMatrix.makeLookAt(bs.center()-osg::Vec3(0.0,2.0f*bs.radius(),0.0),bs.center(),osg::Vec3(0.0f,0.0f,1.0f)); 
    318  
    319         camera->setViewport(0,0,traits->_width,traits->_height); 
    320         camera->setProjectionMatrixAsPerspective(50.0f,1.4f,1.0f,10000.0f); 
    321         camera->setViewMatrix(viewMatrix); 
    322  
    323         // graphics thread will realize the window. 
    324         gfxc->createGraphicsThread(); 
    325  
    326         cameraList.push_back(camera); 
    327  
    328         previousContext = gfxc.get(); 
    329     } 
    330  
    331  
    332     // build the list of unique graphics contexts. 
    333     CameraList::iterator citr; 
    334     for(citr = cameraList.begin(); 
    335         citr != cameraList.end(); 
    336         ++citr) 
    337     { 
    338         graphicsContextSet.insert(const_cast<osg::GraphicsContext*>((*citr)->getGraphicsContext())); 
    339     } 
    340  
    341  
    342     std::cout<<"Number of cameras = "<<cameraList.size()<<std::endl; 
    343     std::cout<<"Number of graphics contexts = "<<graphicsContextSet.size()<<std::endl; 
    344  
    345  
    346     // first the compile of the GL Objects, do it syncronously. 
    347     GraphicsContextSet::iterator gitr; 
    348     osg::ref_ptr<CompileOperation> compileOp = new CompileOperation(loadedModel.get()); 
    349     for(gitr = graphicsContextSet.begin(); 
    350         gitr != graphicsContextSet.end(); 
    351         ++gitr) 
    352     { 
    353         osg::GraphicsContext* context = *gitr; 
    354         context->getGraphicsThread()->add(compileOp.get(), false); 
    355     } 
    356  
    357  
    358     // second the begin frame barrier to all graphics threads 
    359     osg::ref_ptr<osg::BarrierOperation> frameBeginBarrierOp = new osg::BarrierOperation(graphicsContextSet.size()+1, osg::BarrierOperation::NO_OPERATION); 
    360     for(gitr = graphicsContextSet.begin(); 
    361         gitr != graphicsContextSet.end(); 
    362         ++gitr) 
    363     { 
    364         osg::GraphicsContext* context = *gitr; 
    365         context->getGraphicsThread()->add(frameBeginBarrierOp.get(), false); 
    366     } 
    367  
    368     osg::ref_ptr<osg::BarrierOperation> glFinishBarrierOp = new osg::BarrierOperation(graphicsContextSet.size(), osg::BarrierOperation::GL_FINISH); 
    369  
    370     // we can put a finish in to gate rendering throughput, so that each new frame starts with a clean sheet. 
    371     // you should only enable one of these, doFinishBeforeNewDraw will allow for the better parallism of the two finish approaches 
    372     // note, both are disabled right now, as glFinish is spin locking the CPU, not something that we want... 
    373     bool doFinishBeforeNewDraw = false; 
    374     bool doFinishAfterSwap = false; 
    375  
    376     // third add the frame for each camera. 
    377     for(citr = cameraList.begin(); 
    378         citr != cameraList.end(); 
    379         ++citr) 
    380     { 
    381         osg::Camera* camera = citr->get(); 
    382         osg::GraphicsThread* graphicsThread = camera->getGraphicsContext()->getGraphicsThread(); 
    383          
    384         // create a scene view to do the cull and draw 
    385         osgUtil::SceneView* sceneView = new osgUtil::SceneView; 
    386         sceneView->setDefaults(); 
    387         sceneView->setFrameStamp(frameStamp.get()); 
    388         sceneView->setCamera(camera);     
    389  
    390         // cull traversal operation 
    391         graphicsThread->add( new CullOperation(sceneView), false);  
    392  
    393         // optionally add glFinish barrier to ensure that all OpenGL commands are completed before we start dispatching a new frame 
    394         if (doFinishBeforeNewDraw) graphicsThread->add( glFinishBarrierOp.get(), false);  
    395  
    396         // draw traversal operation. 
    397         graphicsThread->add( new DrawOperation(sceneView), false);  
    398     } 
    399  
    400     // fourth add the frame end barrier, the pre swap barrier and finally the swap buffers to each graphics thread. 
    401     // The frame end barrier tells the main thead that the draw dispatch/read phase of the scene graph is complete. 
    402     // The pre swap barrier is an optional extra, which does a flush before joining the barrier, using this all graphics threads 
    403     // are held back until they have all dispatched their fifo to the graphics hardware.   
    404     // The swapOp just issues a swap buffers for each of the graphics contexts. 
    405     osg::ref_ptr<osg::BarrierOperation> frameEndBarrierOp = new osg::BarrierOperation(graphicsContextSet.size()+1, osg::BarrierOperation::NO_OPERATION); 
    406     osg::ref_ptr<osg::BarrierOperation> preSwapBarrierOp = new osg::BarrierOperation(graphicsContextSet.size(), osg::BarrierOperation::GL_FLUSH); 
    407     osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation(); 
    408     for(gitr = graphicsContextSet.begin(); 
    409         gitr != graphicsContextSet.end(); 
    410         ++gitr) 
    411     { 
    412         osg::GraphicsContext* context = *gitr; 
    413  
    414         context->getGraphicsThread()->add(frameEndBarrierOp.get(), false); 
    415         // context->getGraphicsThread()->add(preSwapBarrierOp.get(), false); 
    416         context->getGraphicsThread()->add(swapOp.get(), false); 
    417          
    418         // optionally add finish barrier to ensure that we don't do any other graphics work till the current OpenGL commands are complete. 
    419         if (doFinishAfterSwap) context->getGraphicsThread()->add(glFinishBarrierOp.get(), false); 
    420     } 
    421  
    422  
    423     // record the timer tick at the start of rendering.     
    424     osg::Timer_t start_tick = osg::Timer::instance()->tick(); 
    425     osg::Timer_t previous_tick = start_tick; 
    426      
    427     bool done = false; 
    428  
    429     // main loop -  update scene graph, dispatch frame, wait for frame done. 
    430     while( !done && frameNum<maxNumFrames) 
    431     { 
    432  
    433         osg::Timer_t current_tick = osg::Timer::instance()->tick(); 
    434  
    435         frameStamp->setReferenceTime(osg::Timer::instance()->delta_s(start_tick,current_tick)); 
    436         frameStamp->setFrameNumber(frameNum++); 
    437          
    438         //std::cout<<"Frame rate "<<1.0/osg::Timer::instance()->delta_s(previous_tick,current_tick)<<std::endl; 
    439         previous_tick = current_tick; 
    440  
    441  
    442         // do the update traversal. 
    443         loadedModel->accept(updateVisitor); 
    444  
    445         // dispatch the frame. 
    446         frameBeginBarrierOp->block(); 
    447          
    448         // wait till the frame is done. 
    449         frameEndBarrierOp->block(); 
    450  
    451         // check if any of the windows are closed 
    452         for(gitr = graphicsContextSet.begin(); 
    453             gitr != graphicsContextSet.end(); 
    454             ++gitr) 
    455         { 
    456             osg::GraphicsContext* context = *gitr; 
    457             if (!context->isRealized()) done = true; 
    458         } 
    459  
    460     } 
    461  
    462      
    463     std::cout<<"Exiting application"<<std::endl; 
    464  
    465     // start clean up. 
    466     for(gitr = graphicsContextSet.begin(); 
    467         gitr != graphicsContextSet.end(); 
    468         ++gitr) 
    469     { 
    470         osg::GraphicsContext* context = *gitr; 
    471         osg::GraphicsThread* thread = context->getGraphicsThread(); 
    472         if (thread) 
    473         { 
    474             thread->removeAllOperations(); 
    475             thread->setDone(true); 
    476         } 
    477     } 
    478  
    479     std::cout<<"Removed all operations"<<std::endl; 
    480  
    48147    return 0; 
    48248} 
    483  
    484 #endif