GlDrawManager.cpp

Go to the documentation of this file.
00001 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
00002  *
00003  * VR Juggler is (C) Copyright 1998-2005 by Iowa State University
00004  *
00005  * Original Authors:
00006  *   Allen Bierbaum, Christopher Just,
00007  *   Patrick Hartling, Kevin Meinert,
00008  *   Carolina Cruz-Neira, Albert Baker
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Library General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2 of the License, or (at your option) any later version.
00014  *
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Library General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Library General Public
00021  * License along with this library; if not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00023  * Boston, MA 02111-1307, USA.
00024  *
00025  * -----------------------------------------------------------------
00026  * File:          $RCSfile$
00027  * Date modified: $Date: 2006-12-18 18:00:29 -0600 (Mon, 18 Dec 2006) $
00028  * Version:       $Revision: 19704 $
00029  * -----------------------------------------------------------------
00030  *
00031  *************** <auto-copyright.pl END do not edit this line> ***************/
00032 
00033 #include <vrj/Draw/OGL/Config.h>
00034 
00035 #include <stdlib.h>
00036 #include <boost/concept_check.hpp>
00037 
00038 #include <jccl/Config/ConfigElement.h>
00039 
00040 #include <cluster/ClusterManager.h>
00041 
00042 #include <vrj/Display/DisplayManager.h>
00043 #include <vrj/Kernel/Kernel.h>
00044 #include <vrj/Kernel/KernelExceptions.h>
00045 
00046 #include <vrj/Display/Display.h>
00047 #include <vrj/Display/Viewport.h>
00048 #include <vrj/Display/SimViewport.h>
00049 #include <vrj/Display/SurfaceViewport.h>
00050 
00051 #include <vrj/Draw/OGL/GlApp.h>
00052 
00053 #include <vrj/Draw/OGL/GlPipe.h>
00054 #include <vrj/Draw/OGL/GlWindow.h>
00055 #include <vrj/Draw/OGL/GlSimInterfaceFactory.h>
00056 
00057 #include <gmtl/Vec.h>
00058 #include <gmtl/Output.h>
00059 
00060 //#include <gadget/Type/Glove.h>
00061 //#include <gadget/Type/GloveProxy.h>
00062 
00063 #include <vrj/Draw/OGL/GlDrawManager.h>
00064 
00065 
00066 namespace vrj
00067 {
00068 
00069 vprSingletonImp(GlDrawManager);
00070 
00071 GlDrawManager::GlDrawManager()
00072    : mApp(NULL)
00073    , drawTriggerSema(0)
00074    , drawDoneSema(0)
00075    , mRunning(false)
00076    , mMemberFunctor(NULL)
00077    , mControlThread(NULL)
00078 {
00079 }
00080 
00081 GlDrawManager::~GlDrawManager()
00082 {
00083    if ( mRunning )
00084    {
00085       closeAPI();
00086       mControlThread->join();
00087    }
00088 
00089    if ( NULL != mControlThread )
00090    {
00091       delete mControlThread;
00092       mControlThread = NULL;
00093    }
00094 
00095    if ( NULL != mMemberFunctor )
00096    {
00097       delete mMemberFunctor;
00098       mMemberFunctor = NULL;
00099    }
00100 }
00101 
00103 void GlDrawManager::setApp(App* _app)
00104 {
00105    mApp = dynamic_cast<GlApp*>(_app);
00106 
00107    // We have a new app, so the contexts must be re-initialized
00108    // so... dirty them all.
00109    dirtyAllWindows();
00110 
00111    if ( NULL == mApp )
00112    {
00113       vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00114          << clrOutBOLD(clrRED, "ERROR:")
00115          << " [vrj::GlDrawManager::setApp()] Failed to downcast "
00116          << std::endl << vprDEBUG_FLUSH;
00117       vprDEBUG_NEXT(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00118          << "application object from vrj::App to vrj::GlApp!" << std::endl
00119          << vprDEBUG_FLUSH;
00120       vprDEBUG_NEXT(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00121          << "Type of object " << std::hex << _app << std::dec << " is "
00122          << typeid(_app).name() << std::endl << vprDEBUG_FLUSH;
00123 
00124       throw vrj::DrawMgrException("Object not of type vrj::GlApp");
00125    }
00126 }
00127 
00129 GlApp* GlDrawManager::getApp()
00130 {
00131    return mApp;
00132 }
00133 
00135 void GlDrawManager::start()
00136 {
00137    // --- Setup Multi-Process stuff --- //
00138    // Create a new thread to handle the control
00139    mRunning = true;
00140 
00141    mMemberFunctor =
00142       new vpr::ThreadMemberFunctor<GlDrawManager>(this, &GlDrawManager::main,
00143                                                   NULL);
00144    mControlThread = new vpr::Thread(mMemberFunctor);
00145 
00146    vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CONFIG_LVL)
00147       << "vrj::GlDrawManager started (thread: " << mControlThread << ")\n"
00148       << vprDEBUG_FLUSH;
00149 }
00150 
00151 
00152     // Enable a frame to be drawn
00153     // Trigger draw
00154 void GlDrawManager::draw()
00155 {
00156    drawTriggerSema.release();
00157 }
00158 
00159 
00164 void GlDrawManager::sync()
00165 {
00166    drawDoneSema.acquire();
00167 }
00168 
00169 
00171 void GlDrawManager::main(void* nullParam)
00172 {
00173    boost::ignore_unused_variable_warning(nullParam);
00174    bool stop_requested(false);
00175 
00176    while ( ! stop_requested )
00177    {
00178       //**// Runtime config will happen sometime after
00179       // drawDoneSema.release() because the kernel is the only one that
00180       // can trigger it
00181 
00182       // Wait for trigger
00183       drawTriggerSema.acquire();
00184 
00185       // To properly stop this thread we must allow it to fall through the
00186       // semaphore and not execute drawAllPipes(). Test mRunning here only
00187       // and not outside of drawTriggerSema.acquire() / drawDoneSema.release()
00188       // so we know we will always reach drawTriggerSema.acquire() when
00189       // closing, since closeAPI() expects a final drawTriggerSema.acquire()
00190       // and drawDoneSema.release().
00191       if (mRunning)
00192       {
00193          // THEN --- Do Rendering --- //
00194          drawAllPipes();
00195       }
00196       else
00197       {
00198          stop_requested = true;
00199       }
00200 
00201       // -- Done rendering --- //
00202       drawDoneSema.release();
00203    }
00204 }
00205 
00206 void GlDrawManager::drawAllPipes()
00207 {
00208    vprDEBUG_OutputGuard(vrjDBG_DRAW_MGR, vprDBG_HVERB_LVL,
00209                         "vrj::GLDrawManager::drawAllPipes()\n",
00210                         "vrj::GLDrawManager::drawAllPipes() done.\n");
00211    unsigned int pipe_num;
00212 
00213    // RENDER
00214    // Start rendering all the pipes
00215    for (pipe_num = 0; pipe_num < pipes.size(); ++pipe_num)
00216    {
00217       pipes[pipe_num]->triggerRender();
00218    }
00219 
00220       // Wait for rendering to finish on all the pipes
00221    for (pipe_num = 0; pipe_num < pipes.size(); ++pipe_num)
00222    {
00223       pipes[pipe_num]->completeRender();
00224    }
00225 
00226    // Barrier for Cluster
00227    //vprDEBUG(vprDBG_ALL, vprDBG_STATE_LVL) <<  "BARRIER: Going to sleep for: " << num << std::endl << vprDEBUG_FLUSH;
00228    cluster::ClusterManager::instance()->createBarrier();
00229    //vprDEBUG(vprDBG_ALL, vprDBG_STATE_LVL) <<  "BARRIER: IS DONE" << std::endl << vprDEBUG_FLUSH;
00230 
00231 
00232    // SWAP
00233    // Start swapping all the pipes
00234    for (pipe_num = 0; pipe_num < pipes.size(); ++pipe_num)
00235    {
00236       pipes[pipe_num]->triggerSwap();
00237    }
00238 
00239    // Wait for swapping to finish on all the pipes
00240    for (pipe_num = 0; pipe_num < pipes.size(); ++pipe_num)
00241    {
00242       pipes[pipe_num]->completeSwap();
00243    }
00244 }
00245 
00250 void GlDrawManager::initAPI()
00251 {
00252    start();
00253 }
00254 
00255 
00265 void GlDrawManager::addDisplay(Display* disp)
00266 {
00267    vprASSERT(disp != NULL);    // Can't add a null display
00268 
00269    vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_STATE_LVL)
00270       << "vrj::GlDrawManager::addDisplay: " << disp
00271       << std::endl << vprDEBUG_FLUSH;
00272 
00273 
00274    // -- Finish Simulator setup
00275    std::vector<vrj::Viewport*>::size_type num_vp(disp->getNumViewports());
00276    std::vector<vrj::Viewport*>::size_type i;
00277 
00278    for ( i = 0 ; i < num_vp ; ++i )
00279    {
00280       Viewport* vp = disp->getViewport(i);
00281 
00282       if (vp->isSimulator())
00283       {
00284          jccl::ConfigElementPtr vp_element = vp->getConfigElement();
00285 
00286          SimViewport* sim_vp(NULL);
00287          sim_vp = dynamic_cast<SimViewport*>(vp);
00288          vprASSERT(NULL != sim_vp);
00289 
00290          sim_vp->setDrawSimInterface(NULL);
00291 
00292          // Create the simulator stuff
00293          vprASSERT(1 == vp_element->getNum("simulator_plugin") && "You must supply a simulator plugin.");
00294 
00295          // Create the simulator stuff
00296          jccl::ConfigElementPtr sim_element =
00297             vp_element->getProperty<jccl::ConfigElementPtr>("simulator_plugin");
00298 
00299          vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CONFIG_LVL)
00300             << "GlDrawManager::addDisplay() creating simulator of type '"
00301             << sim_element->getID() << "'\n" << vprDEBUG_FLUSH;
00302 
00303          DrawSimInterface* new_sim_i =
00304             GlSimInterfaceFactory::instance()->createObject(sim_element->getID());
00305 
00306          // XXX: Change this to an error once the new simulator loading code is
00307          // more robust.  -PH (4/13/2003)
00308          vprASSERT(NULL != new_sim_i && "Failed to create draw simulator");
00309          sim_vp->setDrawSimInterface(new_sim_i);
00310          new_sim_i->initialize(sim_vp);
00311          new_sim_i->config(sim_element);
00312       }
00313    }
00314 
00315 
00316    // -- Create a window for new display
00317    // -- Store the window in the wins vector
00318    // Create the gl window object.  NOTE: The glPipe actually "creates" the opengl window and context later
00319    GlWindow* new_win = getGLWindow();
00320    new_win->configWindow(disp);                                            // Configure it
00321    mWins.push_back(new_win);                                         // Add to our local window list
00322 
00323    // -- Create any needed Pipes & Start them
00324    unsigned int pipe_num = new_win->getDisplay()->getPipe();    // Find pipe to add it too
00325 
00326    if (pipes.size() < (pipe_num+1))           // ASSERT: Max index of pipes is < our pipe
00327    {                                         // +1 because if pipeNum = 0, I still need size() == 1
00328       while (pipes.size() < (pipe_num+1))     // While we need more pipes
00329       {
00330          GlPipe* new_pipe = new GlPipe(pipes.size(), this,
00331                                        &mCreateWindowMutex);  // Create a new pipe to use
00332          pipes.push_back(new_pipe);                          // Add the pipe
00333          new_pipe->start();                                  // Start the pipe running
00334                                                              // NOTE: Run pipe even if no windows.  Then it waits for windows.
00335       }
00336    }
00337 
00338    // -- Add window to the correct pipe
00339    GlPipe* pipe;                           // The pipe to assign it to
00340    pipe = pipes[pipe_num];                 // ASSERT: pipeNum is in the valid range
00341    pipe->addWindow(new_win);               // Window has been added
00342 
00343    vprASSERT(isValidWindow(new_win));      // Make sure it was added to draw manager
00344 }
00345 
00346 
00352 void GlDrawManager::removeDisplay(Display* disp)
00353 {
00354    GlPipe* pipe;  pipe = NULL;
00355    GlWindow* win; win = NULL;     // Window to remove
00356 
00357    vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_STATE_LVL)
00358       << "vrj::GlDrawManager::removeDisplay: " << disp
00359       << std::endl << vprDEBUG_FLUSH;
00360 
00361    for (unsigned int i=0;i<mWins.size();i++)
00362    {
00363       if (mWins[i]->getDisplay() == disp)      // FOUND it
00364       {
00365          win = mWins[i];
00366          pipe = pipes[win->getDisplay()->getPipe()];
00367       }
00368    }
00369 
00370    // Remove the window from the pipe and our local list
00371    if (win != NULL)
00372    {
00373       vprASSERT(pipe != NULL);
00374       vprASSERT(isValidWindow(win));
00375       pipe->removeWindow(win);                                                   // Remove from pipe
00376       mWins.erase(std::remove(mWins.begin(),mWins.end(),win), mWins.end());      // Remove from draw manager
00377       vprASSERT(!isValidWindow(win));
00378    }
00379    else
00380    {
00381       vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL) << clrOutNORM(clrRED,"ERROR:")
00382          << "vrj::GlDrawManager::removeDisplay: Attempted to remove a display that was not found.\n"
00383          << vprDEBUG_FLUSH;
00384       vprASSERT(false);
00385    }
00386 
00387 }
00388 
00389 
00391 void GlDrawManager::closeAPI()
00392 {
00393    vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_STATE_LVL) << "vrj::GlDrawManager::closeAPI\n" << vprDEBUG_FLUSH;
00394 
00395    mRunning = false;
00396    
00397    // We must allow our control thread to fall through and die naturally.
00398    drawTriggerSema.release();     
00399    drawDoneSema.acquire();
00400    mControlThread->join();
00401 
00402    // Stop and delete all pipes
00403    unsigned int pipe_num;
00404    
00405    for (pipe_num = 0; pipe_num < pipes.size(); ++pipe_num)
00406    {
00407       pipes[pipe_num]->stop();
00408       
00409       vrj::GlPipe* old_pipe = pipes[pipe_num];
00410       
00411       pipes.erase(std::remove(pipes.begin(), pipes.end(), old_pipe));
00412       delete old_pipe;
00413    }
00414 
00415    // TODO: We must fix the closing of EventWindows and GlWindows before we can do this.
00416    // Close and delete all glWindows
00417 }
00418 
00424 bool GlDrawManager::configAdd(jccl::ConfigElementPtr element)
00425 {
00426    boost::ignore_unused_variable_warning(element);
00427    return false;
00428 }
00429 
00435 bool GlDrawManager::configRemove(jccl::ConfigElementPtr element)
00436 {
00437    boost::ignore_unused_variable_warning(element);
00438    return false;
00439 }
00440 
00445 bool GlDrawManager::configCanHandle(jccl::ConfigElementPtr element)
00446 {
00447    boost::ignore_unused_variable_warning(element);
00448    return false;
00449 }
00450 
00451 GlUserData* GlDrawManager::currentUserData()
00452 {
00453    return &(*mUserData);
00454 }
00455 
00456 int GlDrawManager::getCurrentContext()
00457 {
00458    return (*mContextId);
00459 }
00460 
00461 void GlDrawManager::setCurrentContext(int val)
00462 {
00463    (*mContextId) = val;
00464 }
00465 
00470 void GlDrawManager::dirtyAllWindows()
00471 {
00472     // Create Pipes & Add all windows to the correct pipe
00473    for (unsigned int winId=0;winId<mWins.size();winId++)   // For each window we created
00474    {
00475       mWins[winId]->setDirtyContext(true);
00476    }
00477 }
00478 
00479 
00480 bool GlDrawManager::isValidWindow(GlWindow* win)
00481 {
00482    bool ret_val = false;
00483    for (unsigned int i=0;i<mWins.size();i++)
00484    {
00485       if (mWins[i] == win)
00486       {
00487          ret_val = true;
00488       }
00489    }
00490 
00491    return ret_val;
00492 }
00493 
00494 
00496 void GlDrawManager::outStream(std::ostream& out)
00497 {
00498     out     << clrSetNORM(clrGREEN)
00499             << "========== GlDrawManager: " << (void*)this << " ========="
00500             << clrRESET << std::endl
00501             << clrOutNORM(clrCYAN,"\tapp: ") << (void*)mApp << std::endl
00502             << clrOutNORM(clrCYAN,"\tWindow count: ") << mWins.size()
00503             << std::endl << std::flush;
00504 
00505     for (unsigned int i = 0; i < mWins.size(); i++)
00506     {
00507        vprASSERT(mWins[i] != NULL);
00508        out << clrOutNORM(clrCYAN,"\tGlWindow:\n") << *(mWins[i]) << std::endl;
00509     }
00510     out << "=======================================" << std::endl;
00511 }
00512 
00513 } // end vrj namespace
00514 
00515 
00516 #if  defined(VPR_OS_Windows)
00517 #  include <vrj/Draw/OGL/GlWindowWin32.h>
00518 #elif defined(VPR_OS_Darwin) && ! defined(VRJ_USE_X11)
00519 #  include <vrj/Draw/OGL/GlWindowOSX.h>
00520 #else
00521 #  include <vrj/Draw/OGL/GlWindowXWin.h>
00522 #endif
00523 
00524 namespace vrj
00525 {
00526 
00527 vrj::GlWindow* GlDrawManager::getGLWindow()
00528 {
00529 #if  defined(VPR_OS_Windows)
00530    return new vrj::GlWindowWin32;
00531 #elif defined(VPR_OS_Darwin) && ! defined(VRJ_USE_X11)
00532    return new vrj::GlWindowOSX;
00533 #else
00534    return new vrj::GlWindowXWin;
00535 #endif
00536 }
00537 
00538 } // end vrj namespace

Generated on Thu Jan 4 10:56:51 2007 for VR Juggler by  doxygen 1.5.1