PCMProcess.cpp

Go to the documentation of this file.
00001 //
00002 // This source file is a part of ParCompMark
00003 // Parallel Compositing Benchmark Framework
00004 //
00005 // for latest info see http://parcompmark.sourceforge.net
00006 
00007 //
00008 // Copyright (C) 2006 IT2 ParCompMark Dev. Team
00009 // 
00010 // This program is free software; you can redistribute it and/or
00011 // modify it under the terms of the GNU General Public License
00012 // as published by the Free Software Foundation; either version 2
00013 // of the License, or (at your option) any later version.
00014 // 
00015 // This program 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
00018 // GNU General Public License for more details.
00019 // 
00020 // You should have received a copy of the GNU General Public License
00021 // along with this program; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023 
00024 //
00025 // Inner includes
00026 //
00027 
00028 #include "../include/PCMProcess.h"
00029 
00030 #include "../include/PCMApplication.h"
00031 
00032 #include "../include/PCMNode.h"
00033 
00034 #include "../include/PCMHost.h"
00035 
00036 #include "../include/PCMStringConverter.h"
00037 
00038 #include "../include/PCMOpenGLExtensionLoader.h"
00039 
00040 //
00041 // Outer includes
00042 //
00043 
00044 #include <GL/glu.h>
00045 
00046 namespace ParCompMark
00047 {
00048 
00049   //
00050   // Class constants
00051   //
00052 
00053   const std::string Process::PROCESSINITNUT = "scripts/framework/process-init.nut";
00054   const std::string Process::DEFAULTEXPORTPATTERN = "%06d.png";
00055 
00056   //
00057   // Constructors & destructor
00058   //
00059 
00060    Process::Process():
00061         // Parent class initializer 
00062    Thread("invalid host"        /* Name of the host */
00063         )
00064         // You have to initialize the following attributes:
00065         // - mContexts
00066         // - mProcessType
00067         // - mParent
00068         // - mRenderWindow
00069         // - mRenderingEngine
00070         // - mSqVM
00071         // - mInitProcCode
00072         // - mRunningProcCode
00073         // - mBuffer
00074         // - mInitialized
00075         // - mSortOrder
00076         // - mStopID
00077         // - mOperate
00078         // - mDisplayOutput
00079         // - mGatherStatistics
00080         // - mFrameNumber
00081         // - mFrameTime
00082         // - mStartTime
00083         // - mStop
00084         // - mStopAble
00085         // - mCountedStop
00086         // - mOutputDocument
00087         // - mShowFrameletIcon
00088         // - mExportFrameStep
00089         // - mFrameFilenamePattern
00090   {
00091         Except(INVALID_OPERATION_ERROR, "Process::Process()",
00092            "Default constructor for Squirrel compatibility. Calling this constructor always raises an exception.");
00093   }
00094 
00095  /*----------------------------------------------------------------------*/
00096 
00097   Process::Process(const std::string & name, Node * parent):
00098         // Parent class initializer 
00099    Thread(name          /* Name of the host */
00100   ),
00101         // Parent class initializer 
00102    Name(name                    /* Name of the node */
00103   ),
00104         // Initialize parent node 
00105    mParent(parent               /* Parent node */
00106         )
00107         // You have to initialize the following attributes:
00108         // - mContexts
00109         // - mProcessType
00110         // - mParent
00111         // - mRenderWindow
00112         // - mRenderingEngine
00113         // - mSqVM
00114         // - mInitProcCode
00115         // - mRunningProcCode
00116         // - mBuffer
00117         // - mInitialized
00118         // - mSortOrder
00119         // - mStopID
00120         // - mOperate
00121         // - mDisplayOutput
00122         // - mGatherStatistics
00123         // - mFrameNumber
00124         // - mFrameTime
00125         // - mStartTime
00126         // - mStop
00127         // - mStopAble
00128         // - mCountedStop
00129         // - mOutputDocument
00130         // - mShowFrameletIcon
00131         // - mExportFrameStep
00132         // - mFrameFilenamePattern
00133   {
00134         Assert(parent, NULL_POINTER_ERROR, "Process::Process()");
00135 
00136         mProcessType = RENDER;
00137 
00138         // mBuffer is autoinitialized
00139 
00140         // Create context by default
00141 
00142         //mContexts
00143 
00144         // No squirrel operation by default
00145         mInitProcCode = "";
00146         mRunningProcCode = "";
00147 
00148         mInitialized = false;
00149 
00150         mStopID = 0;
00151 
00152         // By default this process is an ideal good-working man saying nothing
00153         mOperate = true;
00154         mDisplayOutput = false;
00155         mGatherStatistics = true;
00156 
00157         mFrameNumber = 0;
00158         mFrameTime = 0.0;
00159 
00160         mStop = false;
00161         mStopAble = false;
00162         mCountedStop = false;
00163 
00164         mStartTime = Timer::getSystemTime();
00165 
00166         // Create output document
00167         mOutputDocument = new OutputNode("process", OutputNode::INFORMATION);
00168         mOutputDocument->setAttribute("name", mName);
00169 
00170         // Show framelet icon by default
00171         mShowFrameletIcon = true;
00172 
00173         // Frame exporting
00174         mExportFrameStep = 0;
00175         mFrameFilenamePattern = (char *) (DEFAULTEXPORTPATTERN.c_str());
00176 
00177         Logger::getInstance()->log(Logger::NOTICE, "Process `" + mName + "\' has been created.");
00178   }
00179 
00180  /*----------------------------------------------------------------------*/
00181 
00182   Process::~Process()
00183   {
00184         if(mInitProcCode)
00185          delete mInitProcCode;
00186 
00187         if(mRunningProcCode)
00188          delete mRunningProcCode;
00189 
00190         if(mFrameFilenamePattern && mFrameFilenamePattern != DEFAULTEXPORTPATTERN.c_str())
00191          delete mFrameFilenamePattern;
00192 
00193         Logger::getInstance()->log(Logger::NOTICE, "Process `" + mName + "\' has been destroyed.");
00194   }
00195 
00196  /*----------------------------------------------------------------------*/
00197 
00198   //
00199   // Methods
00200   //
00201 
00202   void Process::threadInitialize()
00203   {
00204 
00205         //fprintf(stderr, "threadInit start: %s\n", mName.c_str());
00206 
00207         Assert(!mInitialized, INVALID_OPERATION_ERROR, "Process::initialize()");
00208 
00209         // Create virtual machine
00210         mSqVM = new SqVM(mName + "-VM");
00211 
00212         // TODO: every Process opens a window (offline rendering)
00213         openRenderWindow(mThreadName, "", false, 0, GLXRenderWindow::DEFAULTWINDOWWIDTH,
00214                          GLXRenderWindow::DEFAULTWINDOWHEIGHT);
00215 
00216         // Create rendering engine
00217         mRenderingEngine = new OpenGLRenderingEngine(this);
00218 
00219         // Initialize process from squirrel
00220         mSqVM.lock();
00221         // Load PC API, ParCompMark API, and utils
00222         mSqVM->runScriptFromFile(FileSystemManager::getInstance()->getPathDataFile(Application::PCAPINUT),
00223                                  SqVM::NOMAINMETHOD);
00224         mSqVM->runScriptFromFile(FileSystemManager::getInstance()->getPathDataFile(Application::PARCOMPMARKNUT),
00225                                  SqVM::NOMAINMETHOD);
00226         mSqVM->runScriptFromFile(FileSystemManager::getInstance()->getPathDataFile(Application::UTILSNUT),
00227                                  SqVM::NOMAINMETHOD);
00228         std::list < std::string > params;
00229         params.push_back(StringConverter::toString((void *) mRenderingEngine.getPtr()));
00230         mSqVM->runScriptFromFile(FileSystemManager::getInstance()->getPathDataFile(PROCESSINITNUT), "main", params);
00231         mSqVM.unlock();
00232 
00233         // Load queued extensions
00234         mRenderWindow.lock();
00235         mRenderWindow->setCurrent();
00236         OpenGLExtensionLoader::loadDelayed();
00237         mRenderWindow.unlock();
00238 
00239         // Process initialization
00240         initProcess();
00241 
00242         // PC initialization
00243         initPC();
00244 
00245         // Actualize GLX render window on PC information 
00246         actualizeRenderWindow();
00247 
00248         // Disable framelet ico
00249         if(Application::getInstance()->getConfigOptions()->testString("frameletIcon", "false"))
00250          mShowFrameletIcon = false;
00251 
00252         //TODO: hack
00253         if(mProcessType == COMPOSITE)
00254         {
00255          mStopAble = true;
00256         }
00257 
00258         if(mStopID != 0 && Application::getInstance()->getCommanderMode())
00259         {
00260          mCountedStop = true;
00261         }
00262         // Re-reset window to get the most accurate window statistics
00263         mRenderWindow.lock();
00264         mRenderWindow->resetStatistics();
00265         mRenderWindow.unlock();
00266 
00267         mInitialized = true;
00268         Logger::getInstance()->log(Logger::DEBUG, "Process `" + mName + "\' has been initialized.");
00269   }
00270 
00271  /*----------------------------------------------------------------------*/
00272 
00273   void Process::threadFinalize()
00274   {
00275 
00276         //if(mSqVM->getInitialized())
00277         // mSqVM->finalize();
00278         mSqVM.kill();
00279         mRenderingEngine.kill();
00280 
00281         for(ContextListIterator i = mContexts.begin(); i != mContexts.end(); i++)
00282          (*i)->finalize();
00283 
00284         mRenderWindow.kill();
00285 
00286         Host::IntPointer intP = Host::getInstance()->getEndProcessCount();
00287 
00288         intP.lock();
00289         (*intP.getPtr())++;
00290 
00291         if(*intP.getPtr() == Host::getInstance()->getProcessCount())
00292         {
00293          if(mCountedStop)
00294                 Application::getInstance()->_pseudoStop();
00295         }
00296 
00297         intP.unlock();
00298 
00299         mInitialized = false;
00300         Logger::getInstance()->log(Logger::DEBUG, "Process `" + mName + "\' has been finalized.");
00301   }
00302 
00303  /*----------------------------------------------------------------------*/
00304 
00305   void Process::start()
00306   {
00307         startThread();
00308   }
00309 
00310  /*----------------------------------------------------------------------*/
00311 
00312   u32 Process::stop()
00313   {
00314         if(mStopAble)
00315         {
00316          mStop = true;
00317          wait();
00318          //Timer::sleep(1.5);
00319          return (*mContexts.begin())->getFrameID();
00320         } else
00321         {
00322          return 0;
00323         }
00324   }
00325 
00326  /*----------------------------------------------------------------------*/
00327 
00328   Context *Process::addContext()
00329   {
00330 
00331         Context::Pointer context = Context::Pointer(new Context(this));
00332 
00333         mContexts.push_back(context);
00334 
00335         return context.getPtr();
00336 
00337   }
00338 
00339  /*----------------------------------------------------------------------*/
00340 
00341   void Process::initPC()
00342   {
00343         // Initialize context if neeeded
00344 
00345         for(ContextListIterator i = mContexts.begin(); i != mContexts.end(); i++)
00346          if(!(*i)->getInitialized())
00347                 (*i)->initialize();
00348 
00349         if(mProcessType == COMPOSITE)
00350         {
00351          Assert(mContexts.size() == 1, INVALID_VALUE_ERROR, "Process::initPC()");
00352          if(PCerr err =
00353            pcContextSetInteger((*mContexts.begin())->getContext(), PC_OUTPUT_WIDTH,
00354                                  (*mContexts.begin())->getHostIndex(), mBuffer->getWidth()) != PC_NO_ERROR)
00355                 Except(INTERNAL_ERROR, "Process::initPC()", pcGetErrorString(err));
00356 
00357          if(PCerr err =
00358            pcContextSetInteger((*mContexts.begin())->getContext(), PC_OUTPUT_X_OFFSET,
00359                                  (*mContexts.begin())->getHostIndex(), mBuffer->getLeft()) != PC_NO_ERROR)
00360                 Except(INTERNAL_ERROR, "Process::initPC()", pcGetErrorString(err));
00361 
00362          if(PCerr err =
00363            pcContextSetInteger((*mContexts.begin())->getContext(), PC_OUTPUT_HEIGHT,
00364                                  (*mContexts.begin())->getHostIndex(), mBuffer->getHeight()) != PC_NO_ERROR)
00365                 Except(INTERNAL_ERROR, "Process::initPC()", pcGetErrorString(err));
00366 
00367          if(PCerr err =
00368            pcContextSetInteger((*mContexts.begin())->getContext(), PC_OUTPUT_Y_OFFSET,
00369                                  (*mContexts.begin())->getHostIndex(), mBuffer->getTop()) != PC_NO_ERROR)
00370                 Except(INTERNAL_ERROR, "Process::initPC()", pcGetErrorString(err));
00371         }
00372         // Set default sort order
00373         mSortOrder = (*mContexts.begin())->getHostIndex();
00374   }
00375 
00376  /*----------------------------------------------------------------------*/
00377 
00378   void Process::openRenderWindow(const std::string caption, const std::string & displayName,
00379                                  const bool & fullScreen, const u32 & colourDepth,
00380                                  const u32 & width, const u32 & height, const s32 & left,
00381                                  const s32 & top, const u32 & fsaaSamples)
00382   {
00383 
00384         // Get display
00385         XDisplay::Pointer display(getParent()->getParent()->openXDisplay(displayName));
00386 
00387         // Create window
00388         mRenderWindow =
00389          new GLXRenderWindow(display, this, caption, fullScreen, colourDepth, width, height, left, top, fsaaSamples);
00390 
00391         // Show window
00392         mRenderWindow.lock();
00393         mRenderWindow->initialize();
00394         mRenderWindow->setVisible(true);
00395         mRenderWindow->setCurrent();
00396         mRenderWindow.unlock();
00397 
00398         // If no multi-threading is supported wait for a while and pray :)
00399         if(!display->getXMTSupported())
00400         {
00401          Logger::getInstance()->log(Logger::WARNING,
00402                                    "Since multi-threading is not supported for your Xlib, wait a second to avoid crashes. Some pray might be also useful :)");
00403          Timer::sleep(1.0);
00404         }
00405 
00406         Logger::getInstance()->log(Logger::DEBUG,
00407                                  "Process `" + mName + "\' has opened render window `" + caption + "\'");
00408   }
00409 
00410  /*----------------------------------------------------------------------*/
00411 
00412   void Process::actualizeRenderWindow()
00413   {
00414         mRenderWindow.lock();
00415         mRenderWindow->resize(mBuffer->getWidth(), mBuffer->getHeight());
00416         mRenderWindow->reposition(GLXRenderWindow::CENTERED, GLXRenderWindow::CENTERED);
00417         //glViewport(0, 0, mRenderWindow->getWidth(), mRenderWindow->getHeight());
00418         mRenderWindow.unlock();
00419 
00420         // Resize the canvas of the custom renderers
00421         mRenderingEngine->resizeRenderers(mBuffer->getWidth(), mBuffer->getHeight());
00422   }
00423 
00424  /*----------------------------------------------------------------------*/
00425 
00426   void Process::setViewportForRendering()
00427   {
00428         //never mind which context, because RENDER process render the same frame to several contexts
00429         double Xn0 =
00430          (2.0 / (*mContexts.begin())->getFrameWidth() * mBuffer->getLeft() -
00431           1.0) * (*mContexts.begin())->getProcessCount();
00432         double Xnw =
00433          (2.0 * mBuffer->getWidth() / (*mContexts.begin())->getFrameWidth()) *
00434          (*mContexts.begin())->getProcessCount();
00435         double Yn0 =
00436          (2.0 / (*mContexts.begin())->getFrameHeight() * mBuffer->getTop() -
00437           1.0) * (*mContexts.begin())->getProcessCount();
00438         double Ynw =
00439          (2.0 * mBuffer->getHeight() / (*mContexts.begin())->getFrameHeight()) *
00440          (*mContexts.begin())->getProcessCount();
00441 
00442         double viewportLeft = -(Xn0 + 1.0) / Xnw;
00443         double viewportTop = -(Yn0 + 1.0) / Ynw;
00444         double viewportWidth = 2.0 / Xnw;
00445         double viewportHeight = 2.0 / Ynw;
00446 
00447         mRenderingEngine->viewport(viewportLeft, viewportTop, viewportWidth, viewportHeight);
00448   }
00449 
00450  /*----------------------------------------------------------------------*/
00451 
00452   void Process::displayFrameletIcon()
00453   {
00454         mRenderingEngine->viewport(0.0, 0.0, 1.0, 1.0);
00455 
00456         // Setup pixel operations
00457         glDisable(GL_TEXTURE_2D);
00458         glDisable(GL_DEPTH_TEST);
00459         glEnable(GL_BLEND);
00460         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00461 
00462         // Get window sizes
00463         Real winWidth = (Real) mRenderWindow->getWidth();
00464         Real winHeight = (Real) mRenderWindow->getHeight();
00465 
00466         // Setup 2D projection mode
00467         glMatrixMode(GL_PROJECTION);
00468         glLoadIdentity();
00469         gluOrtho2D(0.0, winWidth, winHeight, 0.0);
00470         glMatrixMode(GL_MODELVIEW);
00471         glLoadIdentity();
00472 
00473         // Get frame sizes, never mind which context beacuse RENDER process render the same frame in several contexts
00474         Real frameWidth = (Real) (*mContexts.begin())->getFrameWidth();
00475         Real frameHeight = (Real) (*mContexts.begin())->getFrameHeight();
00476 
00477         // Get framelet sizes
00478         Real frameletLeft = (Real) mBuffer->getLeft();
00479         Real frameletTop = (Real) mBuffer->getTop();
00480         Real frameletWidth = (Real) mBuffer->getWidth();
00481         Real frameletHeight = (Real) mBuffer->getHeight();
00482 
00483         // Frame icons position and sizes
00484         Real frameIconLeft = 10.0;
00485         Real frameIconTop = 10.0;
00486         Real frameIconWidth = 32.0;
00487         Real frameIconHeight = frameHeight / frameWidth * 32.0;
00488 
00489         // Framelet icons position and sizes
00490         Real frameletIconLeft = 10.0 + frameletLeft / frameWidth * frameIconWidth;
00491         Real frameletIconTop = 10.0 + frameletTop / frameHeight * frameIconHeight;
00492         Real frameletIconWidth = frameletWidth / frameWidth * frameIconWidth;
00493         Real frameletIconHeight = frameletHeight / frameHeight * frameIconHeight;
00494 
00495         glBegin(GL_QUADS);
00496         {
00497          // Draw frame icon
00498          glColor4f(1.0, 1.0, 1.0, 0.1);
00499          glVertex2f(frameIconLeft + frameIconWidth, frameIconTop);
00500          glVertex2f(frameIconLeft, frameIconTop);
00501          glVertex2f(frameIconLeft, frameIconTop + frameIconHeight);
00502          glVertex2f(frameIconLeft + frameIconWidth, frameIconTop + frameIconHeight);
00503 
00504          // Draw framelet icon
00505          glColor4f(1.0, 1.0, 1.0, 0.4);
00506          glVertex2f(frameletIconLeft + frameletIconWidth, frameletIconTop);
00507          glVertex2f(frameletIconLeft, frameletIconTop);
00508          glVertex2f(frameletIconLeft, frameletIconTop + frameletIconHeight);
00509          glVertex2f(frameletIconLeft + frameletIconWidth, frameletIconTop + frameletIconHeight);
00510         }
00511         glEnd();
00512 
00513         glBegin(GL_LINE_LOOP);
00514         {
00515          // Draw frame icon border
00516          glColor4f(1.0, 1.0, 1.0, 0.4);
00517          glVertex2f(frameIconLeft, frameIconTop);
00518          glVertex2f(frameIconLeft + frameIconWidth, frameIconTop);
00519          glVertex2f(frameIconLeft + frameIconWidth, frameIconTop + frameIconHeight);
00520          glVertex2f(frameIconLeft, frameIconTop + frameIconHeight);
00521         }
00522         glEnd();
00523 
00524         glEnable(GL_DEPTH_TEST);
00525         glDisable(GL_BLEND);
00526   }
00527 
00528  /*----------------------------------------------------------------------*/
00529 
00530   void Process::initProcess()
00531   {
00532         // If the process has a window, do initialization
00533         if(mRenderWindow.isNotNull() && strlen(mInitProcCode))
00534         {
00535          // Run squirrel code
00536          mSqVM.lock();
00537          mSqVM->runScriptFromString(mInitProcCode, "initProc", "initProc");
00538          mSqVM.unlock();
00539         }
00540 
00541         Logger::getInstance()->log(Logger::DEBUG, "Process `" + mName + "\' has executed its initProcess method.");
00542   }
00543 
00544  /*----------------------------------------------------------------------*/
00545 
00546   void Process::runningProcess()
00547   {
00548         mRenderWindow.lock();
00549 
00550         // Start a new frame
00551         mRenderWindow->startFrame();
00552 
00553         // Frame number and elapsed time since the start of the benchmark
00554         mFrameNumber = mRenderWindow->getWindowStatistics().frameCount;
00555         mFrameTime = Timer::getSystemTime() - mStartTime;
00556 
00557         // TODO: should not be here
00558         setViewportForRendering();
00559 
00560         // Clear output
00561         glClearColor(0.0, 0.2, 0.4, 0.0);
00562         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00563 
00564         switch (mProcessType)
00565         {
00566          case RENDER:
00567                 {
00568                  glEnable(GL_DEPTH_TEST);
00569 
00570                  // The automatic renderings are done before the explicit runningProc method
00571                  mRenderingEngine->doAutoRendering();
00572 
00573                  // Execture squirrel task if specified
00574                  if(strlen(mRunningProcCode))
00575                  {
00576                         // Create parameters (time and number of current frame)
00577                         std::list < std::string > params;
00578                         params.push_back(StringConverter::toString(mFrameTime));
00579                         params.push_back(StringConverter::toString(mFrameNumber));
00580 
00581                         // Run squirrel code
00582                         mSqVM.lock();
00583                         mSqVM->runScriptFromString(mRunningProcCode, "runningProc", "runningProc", params);
00584                         mSqVM.unlock();
00585                  }
00586 
00587                  break;
00588                 }
00589          case COMPOSITE:
00590                 {
00591                  // Blit composited output to the screen (if specified)
00592                  if(mDisplayOutput)
00593                  {
00594                         glDisable(GL_DEPTH_TEST);
00595                         glPixelStorei(GL_UNPACK_ROW_LENGTH, mBuffer->getOutputRowPixel());
00596                         glDrawPixels(mBuffer->getWidth(), mBuffer->getHeight(), GL_BGRA, GL_UNSIGNED_BYTE,
00597                                   mBuffer->getColour());
00598                  }
00599                 }
00600                 break;
00601         }
00602 
00603         // Finish the frame now on composite type process
00604         // (render type process will finish after calling pcFrameAdd*Framelet)
00605         if(mProcessType == COMPOSITE)
00606         {
00607          mRenderWindow->finishFrame();
00608          mRenderWindow.unlock();
00609         }
00610 
00611   }
00612 
00613  /*----------------------------------------------------------------------*/
00614 
00615   void Process::setBufferByName(const char *name)
00616   {
00617         mBuffer = mParent->getBuffer(name);
00618   }
00619 
00620  /*----------------------------------------------------------------------*/
00621 
00622   void Process::setFinito(const u32 & frameID)
00623   {
00624         if(frameID != 0)
00625         {
00626          mStopID = frameID;
00627          mStop = false;
00628         }
00629 
00638   }
00639 
00640  /*----------------------------------------------------------------------*/
00641 
00642   void Process::task()
00643   {
00644         switch (mProcessType)
00645         {
00646          case RENDER:
00647 
00648                 // If this rendering process operates, start a normal frame
00649                 if(mOperate)
00650                 {
00651 
00652                  // Refresh sort order
00653                  refreshSortOrder();
00654 
00655                  for(ContextListIterator i = mContexts.begin(); i != mContexts.end(); i++)
00656                  {
00657 
00658                         if(PCerr err =
00659                          pcFrameBegin((*i)->getContext(), &(*mContexts.begin())->getFrameID(), 1,
00660                                         (PCuint *) & mBuffer->getLeft(), (PCuint *) & mBuffer->getTop(),
00661                                         (PCuint *) & mBuffer->getWidth(), (PCuint *) & mBuffer->getHeight(),
00662                                         &mSortOrder) != PC_NO_ERROR)
00663                          Except(INTERNAL_ERROR, "Process::task()", pcGetErrorString(err));
00664 
00665                  }
00666 
00667                  // Call running process
00668                  runningProcess();
00669 
00670                  for(ContextListIterator i = mContexts.begin(); i != mContexts.end(); i++)
00671                  {
00672 
00673                         if(!(*i)->getUseGLFrameletEXT())
00674                         {
00675 
00676                          // Read back data
00677                          PCuint *colour = mBuffer->getColour();
00678                          void *depth = mBuffer->getDepth();
00679 
00680                          glPixelStorei(GL_PACK_ROW_LENGTH, mBuffer->getWidth());
00681                          glReadPixels(0, 0, mBuffer->getWidth(), mBuffer->getHeight(), GL_BGRA, GL_UNSIGNED_BYTE,
00682                                          colour);
00683                          if(glGetError() != GL_NO_ERROR)
00684                                 Except(INTERNAL_ERROR, "Process::task()",
00685                                    "glReadPixels colour channel failed on process `" + mName + "\'");
00686                          glReadPixels(0, 0, mBuffer->getWidth(), mBuffer->getHeight(), GL_DEPTH_COMPONENT,
00687                                          GL_UNSIGNED_INT, depth);
00688                          if(glGetError() != GL_NO_ERROR)
00689                                 Except(INTERNAL_ERROR, "Process::task()",
00690                                    "glReadPixels depth channel failed on process `" + mName + "\'");
00691 
00692                          if(PCerr err =
00693                            pcFrameAddFramelet((*i)->getContext(), (*mContexts.begin())->getFrameID(),
00694                                                 mBuffer->getColour(), mBuffer->getDepth()) != PC_NO_ERROR)
00695                                 Except(INTERNAL_ERROR, "Process::task()", pcGetErrorString(err));
00696                         }
00697 
00698                         else
00699                         {
00700 #ifdef PC_EXT_CUR_GFX_CTX
00701                          if(PCerr err =
00702                            pcFrameAddGLFrameletEXT((*i)->getContext(), (*mContexts.begin())->getFrameID(), 0,
00703                                                    0) != PC_NO_ERROR)
00704                                 Except(INTERNAL_ERROR, "Process::task()", pcGetErrorString(err));
00705 #else
00706                          Except(INTERNAL_ERROR, "Process::task()",
00707                                  "PC_EXT_CUR_GFX_CTX extension is not present in your PC interface, cannot call pcFrameAddGLFrameletEXT.");
00708 #endif
00709                         }
00710                  }
00711                  // Display small icon on to top-left corner of the GLX window indicating 
00712                  // the frame/framelet relationship for this process.
00713                  if(mShowFrameletIcon)
00714                         displayFrameletIcon();
00715 
00716                  // Finish frame now
00717                  mRenderWindow->finishFrame();
00718                  mRenderWindow.unlock();
00719 
00720                 }
00721                 // Only start an empty frame (just like compositing process)
00722                 else
00723                 {
00724                  for(ContextListIterator i = mContexts.begin(); i != mContexts.end(); i++)
00725                  {
00726                         if(PCerr err =
00727                          pcFrameBegin((*i)->getContext(), &(*mContexts.begin())->getFrameID(), 0, 0, 0, 0, 0,
00728                                         0) != PC_NO_ERROR)
00729                          Except(INTERNAL_ERROR, "Process::task()", pcGetErrorString(err));
00730                  }
00731                 }
00732 
00733                 break;
00734          case COMPOSITE:
00735                 Assert(mContexts.size() == 1, INVALID_VALUE_ERROR, "Proccess::task");
00736                 if(PCerr err =
00737                  pcFrameBegin((*mContexts.begin())->getContext(), &(*mContexts.begin())->getFrameID(), 0, 0, 0, 0, 0,
00738                                 0) != PC_NO_ERROR)
00739                  Except(INTERNAL_ERROR, "Process::task()", pcGetErrorString(err));
00740                 break;
00741         }
00742 
00743         for(ContextListIterator i = mContexts.begin(); i != mContexts.end(); i++)
00744         {
00745 
00746          if(PCerr err = pcFrameEnd((*i)->getContext(), (*mContexts.begin())->getFrameID()) != PC_NO_ERROR)
00747                 Except(INTERNAL_ERROR, "Process::task()", pcGetErrorString(err));
00748         }
00749 
00750         if(mStop && mStopAble)
00751         {
00752 
00753          go();
00754 
00755          wait();
00756 
00757         }
00758 
00759         if(mStopID && (*mContexts.begin())->getFrameID() >= mStopID)
00760         {
00761          stopThread();
00762         }
00763 
00764         else
00765         {
00766 
00767          if(mProcessType == COMPOSITE)
00768          {
00769                 Assert(mContexts.size() == 1, INVALID_VALUE_ERROR, "Process::task");
00770 
00771                 mBuffer.lock();
00772 
00773                 PCchannel channel;
00774 
00775                 if(PCerr err =
00776                  pcFrameResultChannel((*mContexts.begin())->getContext(), (*mContexts.begin())->getFrameID(),
00777                                         mBuffer->getLeft(), mBuffer->getTop(), mBuffer->getWidth(),
00778                                         mBuffer->getHeight(), PC_CHANNEL_COLOR, &channel) != PC_NO_ERROR)
00779                  Except(INTERNAL_ERROR, "Process::task()", pcGetErrorString(err));
00780 
00781                 mBuffer->setColour((PCuint *) channel.address);
00782                 mBuffer->setOutputRowPixel(channel.rowLength);
00783 
00784                 // Call running process
00785                 runningProcess();
00786 
00787                 // Export actual frame
00788                 if(mExportFrameStep && !(mFrameNumber % mExportFrameStep))
00789                 {
00790                  // TODO: this can cause memory fault
00791                  char *filename = new char[strlen(mFrameFilenamePattern) + 16];
00792 
00793                  sprintf(filename, mFrameFilenamePattern, mFrameNumber);
00794                  mBuffer->saveToFile(filename);
00795 
00796                  delete[]filename;
00797                 }
00798 
00799                 mBuffer.unlock();
00800          }
00801          // Gather statistics
00802          if(mGatherStatistics)
00803                 gatherStatistics();
00804         }
00805   }
00806 
00807  /*----------------------------------------------------------------------*/
00808 
00809   void Process::refreshSortOrder()
00810   {
00811         // Refresh sort order from rendering plugins, if have
00812         int order = mRenderingEngine->getSortOrderFromRenderers();
00813 
00814         if(order != -1)
00815          mSortOrder = order;
00816   }
00817 
00818  /*----------------------------------------------------------------------*/
00819 
00820   void Process::gatherStatistics()
00821   {
00822         GLXRenderWindow::WindowStatistics w = mRenderWindow->getWindowStatistics();
00823 
00824         OutputNode::Pointer statistics(new OutputNode("frame", OutputNode::STATISTICS));
00825         statistics->setAttribute("frame-id", StringConverter::toString((*mContexts.begin())->getFrameID()));
00826         statistics->setAttribute("time", StringConverter::toString(w.renderingTime));
00827         statistics->setAttribute("last-fps", StringConverter::toString(w.lastFPS));
00828         statistics->setAttribute("average-fps", StringConverter::toString(w.avgFPS));
00829         statistics->setAttribute("best-fps", StringConverter::toString(w.bestFPS));
00830         statistics->setAttribute("worst-fps", StringConverter::toString(w.worstFPS));
00831         statistics->setAttribute("frame-begin-time",
00832                                  StringConverter::toString(w.frameBeginTime, StringConverter::DEFAULTFIELDWIDTH, 6));
00833         statistics->setAttribute("frame-end-time",
00834                                  StringConverter::toString(w.frameEndTime, StringConverter::DEFAULTFIELDWIDTH, 6));
00835         statistics->setAttribute("last-frame-time", StringConverter::toString(w.lastFrameTime));
00836         statistics->setAttribute("best-frame-time", StringConverter::toString(w.bestFrameTime));
00837         statistics->setAttribute("worst-frame-time", StringConverter::toString(w.worstFrameTime));
00838         statistics->setAttribute("last-triangle-count", StringConverter::toString(w.lastTriangleCount));
00839         statistics->setAttribute("average-triangle-count", StringConverter::toString(w.avgTriangleCount));
00840         statistics->setAttribute("minimal-triangle-count", StringConverter::toString(w.minTriangleCount));
00841         statistics->setAttribute("maximal-triangle-count", StringConverter::toString(w.maxTriangleCount));
00842 
00843 #ifdef PC_EXT_IO_COUNT
00844         int write,
00845         read;
00846 
00847         if(PCerr err =
00848          pcContextGetInteger((*mContexts.begin())->getContext(), PC_WRITE_COUNT_EXT,
00849                            (*mContexts.begin())->getHostIndex(), &write) != PC_NO_ERROR)
00850          Except(INTERNAL_ERROR, "Process::initPC()", pcGetErrorString(err));
00851         statistics->setAttribute("write-count", StringConverter::toString(write));
00852 
00853         if(PCerr err =
00854          pcContextGetInteger((*mContexts.begin())->getContext(), PC_READ_COUNT_EXT,
00855                            (*mContexts.begin())->getHostIndex(), &read) != PC_NO_ERROR)
00856          Except(INTERNAL_ERROR, "Process::initPC()", pcGetErrorString(err));
00857         statistics->setAttribute("read-count", StringConverter::toString(read));
00858 #endif
00859 
00860         mOutputDocument->addChildNode(statistics);
00861   }
00862 
00863  /*----------------------------------------------------------------------*/
00864 
00865 }