GlPipe.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-11-07 18:59:25 -0600 (Tue, 07 Nov 2006) $
00028  * Version:       $Revision: 19418 $
00029  * -----------------------------------------------------------------
00030  *
00031  *************** <auto-copyright.pl END do not edit this line> ***************/
00032 
00033 #include <vrj/Draw/OGL/Config.h>
00034 
00035 #include <vpr/vpr.h>
00036 
00037 #ifdef VPR_OS_Darwin
00038 #   include <OpenGL/gl.h>
00039 #else
00040 #   include <GL/gl.h>
00041 #endif
00042 
00043 #include <vrj/Kernel/Kernel.h>
00044 #include <vrj/Draw/OGL/GlPipe.h>
00045 #include <vrj/Draw/OGL/GlApp.h>
00046 #include <vpr/Thread/Thread.h>
00047 #include <vpr/Sync/Guard.h>
00048 #include <vrj/Util/Debug.h>
00049 
00050 #include <vrj/Display/SurfaceViewport.h>
00051 #include <vrj/Display/SimViewport.h>
00052 #include <vrj/Draw/OGL/GlSimInterface.h>
00053 #include <boost/concept_check.hpp>
00054 
00055 namespace vrj
00056 {
00057 
00058 GlPipe::~GlPipe()
00059 {
00060    if ( NULL != mActiveThread )
00061    {
00062       delete mActiveThread;
00063       mActiveThread = NULL;
00064    }
00065 
00066    if ( NULL != mControlFunctor )
00067    {
00068       delete mControlFunctor;
00069       mControlFunctor = NULL;
00070    }
00071 }
00072 
00077 int GlPipe::start()
00078 {
00079     vprASSERT(mThreadRunning == false);        // We should not be running yet
00080 
00081     // Create a new thread to call the control loop
00082     mControlFunctor =
00083       new vpr::ThreadMemberFunctor<GlPipe>(this, &GlPipe::controlLoop, NULL);
00084 
00085     mActiveThread = new vpr::Thread(mControlFunctor);
00086 
00087     vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CONFIG_LVL)
00088        << "[vrj::GlPipe::start()] Started control loop. " << mActiveThread
00089        << std::endl << vprDEBUG_FLUSH;
00090     return 1;        // XXX: Is this always true?
00091 }
00092 
00097 void GlPipe::triggerRender()
00098 {
00099    //vprASSERT(mThreadRunning == true);      // We must be running
00100    while (!mThreadRunning)
00101    {
00102       vprDEBUG(vrjDBG_DRAW_MGR,vprDBG_HVERB_LVL) << "Waiting in for thread to start triggerRender.\n" << vprDEBUG_FLUSH;
00103       vpr::Thread::yield();
00104    }
00105 
00106    mRenderTriggerSema.release();
00107 }
00108 
00113 void GlPipe::completeRender()
00114 {
00115    vprASSERT(mThreadRunning == true);      // We must be running
00116 
00117    mRenderCompleteSema.acquire();
00118 }
00119 
00121 void GlPipe::triggerSwap()
00122 {
00123    vprASSERT(mThreadRunning == true);
00124    mSwapTriggerSema.release();
00125 }
00126 
00128 void GlPipe::completeSwap()
00129 {
00130    vprASSERT(mThreadRunning == true);
00131    mSwapCompleteSema.acquire();
00132 }
00133 
00134 
00139 void GlPipe::addWindow(GlWindow* win)
00140 {
00141    vpr::Guard<vpr::Mutex> guardNew(mNewWinLock);       // Protect the data
00142    vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_STATE_LVL)
00143       << "[vrj::GlPipe::addWindow()] Pipe: " << mPipeNum
00144       << " adding window (to new wins):\n" << win
00145       << std::endl << vprDEBUG_FLUSH;
00146    mNewWins.push_back(win);
00147 }
00148 
00153 void GlPipe::removeWindow(GlWindow* win)
00154 {
00155    vpr::Guard<vpr::Mutex> guardClosing(mClosingWinLock);
00156    vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_STATE_LVL)
00157       << "[vrj::GlPipe::removeWindow()] Pipe: " << mPipeNum
00158       << " window added to closingWins.\n" << win
00159       << std::endl << vprDEBUG_FLUSH;
00160    mClosingWins.push_back(win);
00161 }
00162 
00163 
00164 // The main loop routine
00165 // while running <br>
00166 // - Check for windows to open/close <br>
00167 // - Wait for render signal <br>
00168 // - Render all the windows <br>
00169 // - Signal render completed <br>
00170 // - Wait for swap signal <br>
00171 // - Swap all windows <br>
00172 // - Signal swap completed <br>
00173 //
00174 void GlPipe::controlLoop(void* nullParam)
00175 {
00176    boost::ignore_unused_variable_warning(nullParam);
00177    mThreadRunning = true;     // We are running so set flag
00178    // Loop until flag set
00179    while (!mControlExit)
00180    {
00181       // --- handle EVENTS for the windows --- //
00182       // XXX: This may have to be here because of need to get open window event (Win32)
00183       // otherwise I would like to move it to being after the swap to get better performance
00184       {
00185          for (unsigned int winId=0;winId<mOpenWins.size();winId++)
00186          {
00187             mOpenWins[winId]->checkEvents();
00188          }
00189       }
00190 
00191       // --- RENDER the windows ---- //
00192       {
00193          mRenderTriggerSema.acquire();
00194 
00195          GlApp* the_app = mGlDrawManager->getApp();
00196 
00197          // --- pipe PRE-draw function ---- //
00198          the_app->pipePreDraw();      // Can't get a context since I may not be guaranteed a window
00199 
00200          // Render the windows
00201          for (unsigned int winId = 0 ; winId < mOpenWins.size() ; winId++)
00202          {
00203             renderWindow(mOpenWins[winId]);
00204          }
00205          mRenderCompleteSema.release();
00206       }
00207 
00208       // ----- SWAP the windows ------ //
00209       {
00210          mSwapTriggerSema.acquire();
00211 
00212          // Swap all the windows
00213          for (unsigned int winId = 0 ; winId < mOpenWins.size() ; winId++)
00214          {
00215             swapWindowBuffers(mOpenWins[winId]);
00216          }
00217 
00218          mSwapCompleteSema.release();
00219       }
00220       checkForWindowsToClose();  // Checks for closing windows
00221       checkForNewWindows();      // Checks for new windows to open
00222    }
00223 
00224    mThreadRunning = false;     // We are not running
00225 }
00226 
00227 void GlPipe::stop()
00228 {
00229    // Close all open windows/contexts.
00230    std::vector<GlWindow*> windows = getOpenWindows();
00231    for ( std::vector<GlWindow*>::iterator itr = windows.begin();
00232          itr != windows.end();
00233          ++itr )
00234    {
00235       removeWindow(*itr);
00236    }
00237 
00238    mControlExit = 1;     // Set the control loop exit flag
00239    
00240    // We don't actually need to call completeRender() or completeSwap()
00241    // since we don't care about when they complete. We only care about
00242    // joining the thread
00243    triggerRender();
00244    //completeRender();
00245    triggerSwap();
00246    //completeSwap();
00247 
00248    mActiveThread->join();
00249 }
00250 
00257 void GlPipe::checkForWindowsToClose()
00258 {
00259    if (mClosingWins.size() > 0)   // If there are windows to close
00260    {
00261       vpr::Guard<vpr::Mutex> guardClosing(mClosingWinLock);
00262       vpr::Guard<vpr::Mutex> guardNew(mNewWinLock);
00263       vpr::Guard<vpr::Mutex> guardOpen(mOpenWinLock);
00264 
00265       for (unsigned int i=0;i<mClosingWins.size();i++)
00266       {
00267          GlWindow* win = mClosingWins[i];
00268         
00269          vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CONFIG_LVL)
00270             << "[vrj::GlPipe::checkForNewWindows()] Just closed window: "
00271             << mClosingWins[i]->getDisplay()->getName() << std::endl
00272             << *(mClosingWins[i]) << std::endl << vprDEBUG_FLUSH;
00273 
00274          // Call contextClose
00275          GlApp* the_app = mGlDrawManager->getApp();               // Get application for easy access
00276          //Display* the_display = win->getDisplay();         // Get the display for easy access
00277          mGlDrawManager->setCurrentContext(win->getId());        // Set TS data of context id
00278          mGlDrawManager->currentUserData()->setUser(NULL);       // Set user data
00279          mGlDrawManager->currentUserData()->setProjection(NULL);
00280          mGlDrawManager->currentUserData()->setViewport(NULL);   // Set vp data
00281          mGlDrawManager->currentUserData()->setGlWindow(win);    // Set the gl window
00282 
00283          win->makeCurrent();              // Make the context current
00284          the_app->contextClose();          // Call context close function
00285 
00286          // Close the window
00287          win->close();
00288 
00289          // Remove it from the lists
00290          mNewWins.erase(std::remove(mNewWins.begin(), mNewWins.end(), win), mNewWins.end());
00291          mOpenWins.erase(std::remove(mOpenWins.begin(), mOpenWins.end(), win), mOpenWins.end());
00292 
00293          // Delete the window
00294          delete win;
00295          mClosingWins[i] = NULL;
00296       }
00297 
00298       mClosingWins.erase(mClosingWins.begin(), mClosingWins.end());
00299       vprASSERT(mClosingWins.size() == 0);;
00300    }
00301 }
00302 
00307 void GlPipe::checkForNewWindows()
00308 {
00309    if (mNewWins.size() > 0)  // If there are new windows added
00310    {
00311       // Cross-pipe lock to prevent a window from opening on another pipe
00312       // while we are opening ours.
00313       vpr::Guard<vpr::Mutex> guard_draw_mgr(*mDrawMgrWinLock);
00314       // Pipe-specific lock to prevent mNewWins from being modified while
00315       // the new windows are being opened.
00316       vpr::Guard<vpr::Mutex> guard_new(mNewWinLock);
00317       // Pipe-specific lock to prevent checkForWindowsToClose() from doing
00318       // any work while new windows are being opened.
00319       vpr::Guard<vpr::Mutex> guard_open(mOpenWinLock);
00320 
00321       for (unsigned int winNum=0; winNum<mNewWins.size(); winNum++)
00322       {
00323           if (mNewWins[winNum]->open())
00324           {
00325               mNewWins[winNum]->makeCurrent();
00326               vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CONFIG_LVL)
00327                  << "[vrj::GlPipe::checkForNewWindows()] Just opened window: "
00328                  << mNewWins[winNum]->getDisplay()->getName() << std::endl
00329                  << *(mNewWins[winNum]) << std::endl << vprDEBUG_FLUSH;
00330               mNewWins[winNum]->finishSetup();        // Complete any window open stuff
00331               mOpenWins.push_back(mNewWins[winNum]);
00332           }
00333           else
00334           {
00335               vprDEBUG(vprDBG_ALL, vprDBG_CRITICAL_LVL)
00336                  << clrOutBOLD(clrRED,"ERROR:")
00337                  << " vrj::GlPipe::checkForNewWindows(): Failed to open window: "
00338                  << mNewWins[winNum]->getDisplay()->getName().c_str()
00339                  << std::endl << vprDEBUG_FLUSH;
00340               // XXX: We should handle this error more gracefully
00341           }   // Done
00342       }
00343 
00344       mNewWins.erase(mNewWins.begin(), mNewWins.end());
00345       vprASSERT(mNewWins.size() == 0);
00346    }
00347 }
00348 
00353 void GlPipe::renderWindow(GlWindow* win)
00354 {
00355    float vp_ox, vp_oy, vp_sx, vp_sy;            // Viewport origin and size
00356    Viewport::View  view;                      // The view for the active viewport
00357 
00358    GlApp* the_app = mGlDrawManager->getApp();       // Get application for easy access
00359    Display* the_display = win->getDisplay();   // Get the display for easy access
00360 
00361    // Update the projections for the display using the current app's scale factor
00362    // NOTE: This relies upon no other thread trying to update this display at the same time
00363    float scale_factor = the_app->getDrawScaleFactor();
00364    the_display->updateProjections(scale_factor);
00365 
00366    mGlDrawManager->setCurrentContext(win->getId());     // Set TSS data of context id
00367    mGlDrawManager->currentUserData()->setGlWindow(win);
00368 
00369    vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_HVERB_LVL)
00370       << "[vrj::GlPipe::renderWindow()] Set context to: "
00371       << GlDrawManager::instance()->getCurrentContext()
00372       << std::endl << vprDEBUG_FLUSH;
00373 
00374    // --- SET CONTEXT --- //
00375    win->makeCurrent();
00376  
00377 
00378    // VIEWPORT cleaning
00379    if (win->hasDirtyViewport())
00380    {
00381       win->updateViewport();
00382    }
00383 
00384    // CONTEXT INIT(): Check if we need to call contextInit()
00385    // - Must call when context is new OR application is new
00386    if (win->hasDirtyContext())
00387    {
00388       // Have dirty context
00389       mGlDrawManager->currentUserData()->setUser(NULL);         // Set user data
00390       mGlDrawManager->currentUserData()->setProjection(NULL);
00391       mGlDrawManager->currentUserData()->setViewport(NULL);     // Set vp data
00392       mGlDrawManager->currentUserData()->setGlWindow(win);      // Set the gl window
00393 
00394       the_app->contextInit();              // Call context init function
00395       win->setDirtyContext(false);        // All clean now
00396    }
00397 
00398    // BUFFER PRE DRAW: Check if we need to clear stereo buffers
00399    if (win->isStereo())
00400    {
00401       win->setViewBuffer(Viewport::RIGHT_EYE);
00402       the_app->bufferPreDraw();
00403       win->setViewBuffer(Viewport::LEFT_EYE);
00404       the_app->bufferPreDraw();
00405    }
00406    else
00407    {
00408       the_app->bufferPreDraw();
00409    }
00410 
00411    the_app->contextPreDraw();                 // Do any context pre-drawing
00412 
00413    // --- FOR EACH VIEWPORT -- //
00414    Viewport* viewport = NULL;
00415    size_t num_vps = the_display->getNumViewports();
00416    for ( size_t vp_num = 0; vp_num < num_vps; ++vp_num )
00417    {
00418       viewport = the_display->getViewport(vp_num);
00419 
00420       // Should viewport be rendered???
00421       if (viewport->isActive())
00422       {
00423          view = viewport->getView();
00424 
00425          // Set the glViewport to draw within
00426          viewport->getOriginAndSize(vp_ox, vp_oy, vp_sx, vp_sy);
00427          win->setViewport(vp_ox, vp_oy, vp_sx, vp_sy);
00428 
00429          // Set user information
00430          mGlDrawManager->currentUserData()->setUser(viewport->getUser());       // Set user data
00431          mGlDrawManager->currentUserData()->setViewport(viewport);              // Set the viewport
00432 
00433          // ---- SURFACE & Simulator --- //
00434          // if (viewport->isSurface())
00435          {
00436             SimViewport*      sim_vp(NULL);
00437             GlSimInterface*   draw_sim_i(NULL);
00438 
00439             if (viewport->isSimulator())
00440             {
00441                sim_vp = dynamic_cast<SimViewport*>(viewport);
00442                vprASSERT(NULL != sim_vp);
00443                if (NULL != sim_vp)
00444                {
00445                   draw_sim_i = dynamic_cast<GlSimInterface*>(sim_vp->getDrawSimInterface());
00446                }
00447             }
00448 
00449             if ((Viewport::STEREO == view) || (Viewport::LEFT_EYE == view))      // LEFT EYE
00450             {
00451                win->setViewBuffer(Viewport::LEFT_EYE);
00452                win->setProjection(viewport->getLeftProj());
00453                mGlDrawManager->currentUserData()->setProjection(viewport->getLeftProj());
00454 
00455                the_app->draw();
00456 
00457                if (NULL != draw_sim_i)
00458                {
00459                   draw_sim_i->draw(scale_factor);
00460                }
00461             }
00462             if ((Viewport::STEREO == view) || (Viewport::RIGHT_EYE == view))    // RIGHT EYE
00463             {
00464                win->setViewBuffer(Viewport::RIGHT_EYE);
00465                win->setProjection(viewport->getRightProj());
00466                mGlDrawManager->currentUserData()->setProjection(viewport->getRightProj());
00467 
00468                the_app->draw();
00469 
00470                if (NULL != draw_sim_i)
00471                {
00472                   draw_sim_i->draw(scale_factor);
00473                }
00474             }
00475          }
00476       }  // should viewport be rendered
00477    }     // for each viewport
00478 
00479    // -- Post context stuff --- //
00480    the_app->contextPostDraw();
00481 }
00482 
00487 void GlPipe::swapWindowBuffers(GlWindow* win)
00488 {
00489    win->makeCurrent();           // Set correct context
00490    win->swapBuffers();           // Implicitly calls a glFlush
00491 }
00492 
00493 }

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