PCMGLXRenderWindow.cpp

Go to the documentation of this file.
00001 
00002 //
00003 // This source file is a part of ParCompMark
00004 // Parallel Compositing Benchmark Framework
00005 //
00006 // for latest info see http://parcompmark.sourceforge.net
00007 
00008 //
00009 // Copyright (C) 2006 IT2 ParCompMark Dev. Team
00010 // 
00011 // This program is free software; you can redistribute it and/or
00012 // modify it under the terms of the GNU General Public License
00013 // as published by the Free Software Foundation; either version 2
00014 // of the License, or (at your option) any later version.
00015 // 
00016 // This program is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 // GNU General Public License for more details.
00020 // 
00021 // You should have received a copy of the GNU General Public License
00022 // along with this program; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00024 
00025 //
00026 // Inner includes
00027 //
00028 
00029 #include "../include/PCMGLXRenderWindow.h"
00030 
00031 #include "../include/PCMProcess.h"
00032 
00033 #include "../include/PCMStringConverter.h"
00034 
00035 //
00036 // Outer includes
00037 //
00038 
00039 #include <GL/gl.h>
00040 #include <GL/glu.h>
00041 #if defined(HAVE_LIBXRANDR)
00042 #  include <X11/extensions/Xrandr.h>
00043 #endif
00044 
00045 namespace ParCompMark
00046 {
00047 
00048   //
00049   // Class constants
00050   //
00051 
00052   const s32 GLXRenderWindow::CENTERED = -1;
00053   const u32 GLXRenderWindow::MAXIMALSIZE = 0;
00054   const Real GLXRenderWindow::UNDEFINEDSTATISTICS = -1.0;
00055   const s32 GLXRenderWindow::UNDEFINEDXRRCONFIGURATION = -1;
00056   const u32 GLXRenderWindow::DEFAULTWINDOWWIDTH = 128;
00057   const u32 GLXRenderWindow::DEFAULTWINDOWHEIGHT = 128;
00058 
00059   //
00060   // Constructors & destructor
00061   //
00062 
00063    GLXRenderWindow::GLXRenderWindow(XDisplay::Pointer & display, Process * process, const std::string caption,
00064                                    const bool & fullScreen, const u32 & colourDepth,
00065                                    const u32 & width, const u32 & height, const s32 & left,
00066                                    const s32 & top, const u32 & fsaaSamples):
00067         // X Display pointer initializer 
00068    mDisplay(display             /* Corresponding X Display */
00069   ),
00070         // Process initializer 
00071    mProcess(process             /* Corresponding process */
00072         )
00073         // You have to initialize the following attributes:
00074         // - mDisplay
00075         // - mGLXGLContext
00076         // - mProcess
00077         // - mWindow
00078         // - mInitialized
00079         // - mVisible
00080         // - mFullScreen
00081         // - mCaption
00082         // - mLeft
00083         // - mTop
00084         // - mWidth
00085         // - mHeight
00086         // - mColourDepth
00087         // - mFSAASamples
00088         // - mOriginalXRRConfiguation
00089         // - mAtomDeleteWindow
00090         // - mWindowStatistics
00091         // - mRenderingBeginTime
00092         // - mFPSMeasuringBeginTime
00093         // - mFPSMeasuringFrameCount
00094         // - mSumTriangleCount
00095         // - mSumFPS
00096   {
00097         mWindow = 0;
00098         mInitialized = false;
00099         mVisible = false;
00100         mFullScreen = fullScreen;
00101         mCaption = caption;
00102         mLeft = left;
00103         mTop = top;
00104         mWidth = width;
00105         mHeight = height;
00106         mColourDepth = colourDepth;
00107         mFSAASamples = fsaaSamples;
00108         mOriginalXRRConfiguation = UNDEFINEDXRRCONFIGURATION;
00109 
00110         // Reset window stats
00111         resetStatistics();
00112   }
00113 
00114  /*----------------------------------------------------------------------*/
00115 
00116   GLXRenderWindow::~GLXRenderWindow()
00117   {
00118         if(mInitialized)
00119          finalize();
00120   }
00121 
00122  /*----------------------------------------------------------------------*/
00123 
00124   //
00125   // Methods
00126   //
00127 
00128   void GLXRenderWindow::setCurrent()
00129   {
00130         mGLXGLContext.lock();
00131         mGLXGLContext->setCurrent();
00132         mGLXGLContext.unlock();
00133   }
00134 
00135  /*----------------------------------------------------------------------*/
00136 
00137   void GLXRenderWindow::releaseCurrent()
00138   {
00139         mGLXGLContext.lock();
00140         mGLXGLContext->releaseCurrent();
00141         mGLXGLContext.unlock();
00142   }
00143 
00144  /*----------------------------------------------------------------------*/
00145 
00146   void GLXRenderWindow::initialize()
00147   {
00148         Assert(!mInitialized, INVALID_OPERATION_ERROR, "GLXRenderWindow::initalize()");
00149 
00150         // Create GLX window
00151         createWindow();
00152 
00153         // Reset accumulation attributes
00154         mSumTriangleCount = 0.0;
00155         mSumFPS = 0.0;
00156 
00157         // Init frame counter 
00158         mWindowStatistics.frameCount = 0;
00159 
00160         mInitialized = true;
00161   }
00162 
00163  /*----------------------------------------------------------------------*/
00164 
00165   void GLXRenderWindow::finalize()
00166   {
00167         Assert(mInitialized, INVALID_OPERATION_ERROR, "GLXRenderWindow::finalize()");
00168 
00169         // Finalize the glx context
00170 
00171         // Destroy GLX window
00172         destroyWindow();
00173 
00174         mGLXGLContext.lock();
00175         mGLXGLContext->finalize();
00176         mGLXGLContext.unlock();
00177 
00178         //TODO: VREGATH
00179         mGLXGLContext.kill();
00180 
00181         mInitialized = false;
00182 
00183   }
00184 
00185  /*----------------------------------------------------------------------*/
00186 
00187   void GLXRenderWindow::resetStatistics()
00188   {
00189         mWindowStatistics.lastTriangleCount = 0;
00190         mWindowStatistics.frameCount = 0;
00191 
00192         // Initialize window statistics with undefined values
00193         mWindowStatistics.lastFrameTime = UNDEFINEDSTATISTICS;
00194         mWindowStatistics.bestFrameTime = UNDEFINEDSTATISTICS;
00195         mWindowStatistics.worstFrameTime = UNDEFINEDSTATISTICS;
00196 
00197         mWindowStatistics.avgTriangleCount = UNDEFINEDSTATISTICS;
00198         mWindowStatistics.maxTriangleCount = UNDEFINEDSTATISTICS;
00199         mWindowStatistics.minTriangleCount = UNDEFINEDSTATISTICS;
00200 
00201         mWindowStatistics.lastFPS = UNDEFINEDSTATISTICS;
00202         mWindowStatistics.avgFPS = UNDEFINEDSTATISTICS;
00203         mWindowStatistics.bestFPS = UNDEFINEDSTATISTICS;
00204         mWindowStatistics.worstFPS = UNDEFINEDSTATISTICS;
00205 
00206         // Store frame staring time and the start of the rendering
00207         mRenderingBeginTime = mWindowStatistics.frameBeginTime = Timer::getSystemTime();
00208 
00209         // Initialize FPS calculation
00210         mFPSMeasuringBeginTime = Timer::getSystemTime();
00211         mFPSMeasuringFrameCount = 0;
00212   }
00213 
00214  /*----------------------------------------------------------------------*/
00215 
00216   void GLXRenderWindow::reportTriangles(const u32 & triangleCount)
00217   {
00218         mWindowStatistics.lastTriangleCount += triangleCount;
00219   }
00220 
00221  /*----------------------------------------------------------------------*/
00222 
00223   void GLXRenderWindow::createWindow()
00224   {
00225         mDisplay.lock();
00226 
00227         // Initialize display if needed
00228         if(!mDisplay->getInitialized())
00229          mDisplay->initialize();
00230 
00231         ::Display * display = mDisplay->getDisplay();
00232 
00233         // We will attempt to create new window on default screen op display 0
00234         // unless external window handle passed below
00235         int screen = DefaultScreen(display);
00236         int depth = DisplayPlanes(display, screen);
00237         Window rootWindow = RootWindow(display, screen);
00238         Window parentWindow = rootWindow;
00239 
00240         // Determine position and dimensions (consider special values)
00241         if(mWidth == MAXIMALSIZE)
00242          mWidth = mDisplay->getWidth();
00243         if(mHeight == MAXIMALSIZE)
00244          mWidth = mDisplay->getHeight();
00245         if(mLeft == CENTERED)
00246          mLeft = (mDisplay->getWidth() - mWidth) / 2;
00247         if(mTop == CENTERED)
00248          mTop = (mDisplay->getHeight() - mHeight) / 2;
00249 
00250         // Check for full screen mode if FSAA was asked for
00251         if(!mFullScreen && mFSAASamples > 0)
00252         {
00253          Logger::getInstance()->log(Logger::WARNING, "FSAA only supported in fullscreen mode");
00254          mFSAASamples = 0;
00255         }
00256 #ifdef HAVE_LIBXRANDR
00257         // Attempt mode switch for fullscreen -- only if RANDR extension is there
00258         int dummy;
00259 
00260         if(mFullScreen && !XQueryExtension(display, "RANDR", &dummy, &dummy, &dummy))
00261         {
00262          Logger::getInstance()->log(Logger::WARNING,
00263                                    "Could not switch to full screen mode: No XRANDR extension found");
00264         } else if(mFullScreen)
00265         {
00266          // Use Xrandr extension to switch video modes. This is much better than
00267          // XVidMode as you can't scroll away from the full-screen applications.
00268          XRRScreenConfiguration *config;
00269          XRRScreenSize *sizes;
00270          Rotation current_rotation;
00271          int nsizes;
00272 
00273          // Get current screen info
00274          config = XRRGetScreenInfo(display, rootWindow);
00275          // Get available sizes
00276          if(config)
00277                 sizes = XRRConfigSizes(config, &nsizes);
00278 
00279          if(config && nsizes > 0)
00280          {
00281                 // Get current size and rotation
00282                 mOriginalXRRConfiguation = XRRConfigCurrentConfiguration(config, &current_rotation);
00283                 // Find smallest matching mode
00284                 int mode = -1;
00285                 int mode_width = INT_MAX;
00286                 int mode_height = INT_MAX;
00287 
00288                 for(int i = 0; i < nsizes; i++)
00289                 {
00290                  if((u32) sizes[i].width >= mWidth && (u32) sizes[i].height >= mHeight && sizes[i].width < mode_width
00291                    && sizes[i].height < mode_height)
00292                  {
00293                         mode = i;
00294                         mode_width = sizes[i].width;
00295                         mode_height = sizes[i].height;
00296                  }
00297                 }
00298                 if(mode >= 0)
00299                 {
00300                  // Finally, set the screen configuration
00301                  Logger::getInstance()->log(Logger::NOTICE, "Entering full screen mode");
00302 
00303                  XRRSetScreenConfig(display, config, rootWindow, mode, current_rotation, CurrentTime);
00304                 } else
00305                 {
00306                  Logger::getInstance()->log(Logger::WARNING,
00307                                            "Could not switch to full screen mode: No conforming mode was found");
00308                 }
00309                 // Free configuration data
00310                 XRRFreeScreenConfigInfo(config);
00311          } else
00312          {
00313                 Logger::getInstance()->log(Logger::WARNING,
00314                                          "Could not switch to full screen mode: XRRGetScreenInfo failed");
00315          }
00316         }
00317 #endif
00318 
00319         XVisualInfo *visualInfo = NULL;
00320 
00321         // Apply some magic algorithm to get the best visual
00322         int best_visual = mDisplay->findBestVisual(screen, mFSAASamples);
00323 
00324         if(best_visual == -1)
00325         {
00326          best_visual = mDisplay->findBestVisual(screen);
00327          Logger::getInstance()->log(Logger::WARNING,
00328                                    "Requested FSAA was not acquirable, defaulting to first suitable visual");
00329         }
00330         // Get information about this so-called-best visual
00331         XVisualInfo templ;
00332         int nmatch;
00333 
00334         templ.visualid = best_visual;
00335         visualInfo = XGetVisualInfo(display, VisualIDMask, &templ, &nmatch);
00336         Assert(visualInfo && nmatch, INVALID_OPERATION_ERROR, "GLXRenderWindow::createWindow()");
00337 
00338         XSetWindowAttributes attr;
00339         unsigned long mask;
00340 
00341         attr.background_pixel = 0;
00342         attr.border_pixel = 0;
00343         attr.colormap = XCreateColormap(display, rootWindow, visualInfo->visual, AllocNone);
00344         attr.event_mask = StructureNotifyMask | VisibilityChangeMask;
00345         if(mFullScreen)
00346         {
00347          mask = CWBackPixel | CWColormap | CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWEventMask;
00348          attr.override_redirect = True;
00349          attr.backing_store = NotUseful;
00350          attr.save_under = False;
00351 
00352          // Fullscreen windows are always in the top left origin with full size
00353          mLeft = mTop = 0;
00354          mWidth = (u32) DisplayWidth(display, screen);
00355          mHeight = (u32) DisplayHeight(display, screen);
00356 
00357         } else
00358          mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
00359 
00360         // Create window on server
00361         mWindow =
00362          XCreateWindow(display, parentWindow, mLeft, mTop, mWidth, mHeight, 0, visualInfo->depth, InputOutput,
00363                         visualInfo->visual, mask, &attr);
00364         Assert(mWindow, INVALID_OPERATION_ERROR, "GLXRenderWindow::createWindow()");
00365 
00366         // Make sure the window is in normal state
00367         XWMHints *wm_hints;
00368 
00369         if((wm_hints = XAllocWMHints()) != NULL)
00370         {
00371          wm_hints->initial_state = NormalState;
00372          wm_hints->input = True;
00373          wm_hints->flags = StateHint | InputHint;
00374 
00375          // Check if we can give it an icon
00376          if(depth == 24 || depth == 32)
00377          {
00378                 // TODO: The right bit depth, we can load an icon
00379                 // if(GLXUtils::LoadIcon(display, rootWindow, "GLX_icon.png", &wm_hints->icon_pixmap, &wm_hints->icon_mask))
00380                 // wm_hints->flags |= IconPixmapHint | IconMaskHint;
00381          }
00382         }
00383         // Set size and location hints
00384         XSizeHints *size_hints;
00385 
00386         if((size_hints = XAllocSizeHints()) != NULL)
00387         {
00388          // Otherwise some window managers ignore our position request
00389          size_hints->flags = USPosition;
00390         }
00391         // Make text property from title
00392         XTextProperty titleprop;
00393         char *lst = (char *) mCaption.c_str();
00394 
00395         XStringListToTextProperty((char **) &lst, 1, &titleprop);
00396 
00397         XSetWMProperties(display, mWindow, &titleprop, NULL, NULL, 0, size_hints, wm_hints, NULL);
00398 
00399         // We don't like memory leaks. Free the clientside storage, but not the
00400         // pixmaps as they're still being used by the server.
00401         XFree(titleprop.value);
00402         XFree(wm_hints);
00403         XFree(size_hints);
00404 
00405         // TODO: not needed currently
00406         // Acquire atom to recognize window close events
00407         mAtomDeleteWindow = XInternAtom(display, "WM_DELETE_WINDOW", False);
00408         XSetWMProtocols(display, mWindow, &mAtomDeleteWindow, 1);
00409 
00410         // Map window unto screen and focus it.
00411         XMapWindow(display, mWindow);
00412 
00413         // Make sure the server is up to date and focus the window
00414         // TODO: causes error with remote X
00415         XFlush(display);
00416 
00417         // Unlock display (passing to glxcontext will need to lock it)
00418         mDisplay.unlock();
00419 
00420         // Create context for this window
00421         mGLXGLContext = new GLXGLContext(mDisplay, this, visualInfo);
00422         mGLXGLContext.lock();
00423         mGLXGLContext->initialize();
00424         mGLXGLContext.unlock();
00425 
00426         // Free visual info
00427         XFree(visualInfo);
00428 
00429         Logger::getInstance()->log(Logger::NOTICE,
00430                                  "GLX Window `" + mCaption + "\' has been created on display `" +
00431                                  mDisplay->getDisplayName() + "\'");
00432   }
00433 
00434  /*----------------------------------------------------------------------*/
00435 
00436   void GLXRenderWindow::destroyWindow()
00437   {
00438         Assert(mWindow, NULL_POINTER_ERROR, "GLXRenderWindow::destroyWindow()");
00439 
00440         mDisplay.lock();
00441         XDestroyWindow(mDisplay->getDisplay(), mWindow);
00442         mDisplay.unlock();
00443 
00444         Logger::getInstance()->log(Logger::NOTICE, "GLX Window: `" + mCaption + "\' has been destroyed.");
00445   }
00446 
00447  /*----------------------------------------------------------------------*/
00448 
00449   void GLXRenderWindow::updateStatistics()
00450   {
00451         mWindowStatistics.frameCount++;
00452         mWindowStatistics.renderingTime = mWindowStatistics.frameEndTime - mRenderingBeginTime;
00453 
00454         //
00455         // Frame times
00456         //
00457         mWindowStatistics.lastFrameTime = mWindowStatistics.frameEndTime - mWindowStatistics.frameBeginTime;
00458         if(mWindowStatistics.bestFrameTime == UNDEFINEDSTATISTICS)
00459         {
00460          mWindowStatistics.bestFrameTime = mWindowStatistics.lastFrameTime;
00461         } else
00462         {
00463          mWindowStatistics.bestFrameTime =
00464                 mWindowStatistics.lastFrameTime <
00465                 mWindowStatistics.bestFrameTime ? mWindowStatistics.lastFrameTime : mWindowStatistics.bestFrameTime;
00466         }
00467 
00468         if(mWindowStatistics.worstFrameTime == UNDEFINEDSTATISTICS)
00469         {
00470          mWindowStatistics.worstFrameTime = mWindowStatistics.lastFrameTime;
00471         } else
00472         {
00473          mWindowStatistics.worstFrameTime =
00474                 mWindowStatistics.lastFrameTime >
00475                 mWindowStatistics.worstFrameTime ? mWindowStatistics.lastFrameTime : mWindowStatistics.worstFrameTime;
00476         }
00477 
00478         //
00479         // Triangle count
00480         //
00481         if(mWindowStatistics.minTriangleCount == UNDEFINEDSTATISTICS)
00482         {
00483          mWindowStatistics.minTriangleCount = mWindowStatistics.lastTriangleCount;
00484         } else
00485         {
00486          mWindowStatistics.minTriangleCount =
00487                 mWindowStatistics.lastTriangleCount <
00488                 mWindowStatistics.minTriangleCount ? mWindowStatistics.lastTriangleCount : mWindowStatistics.
00489                 minTriangleCount;
00490         }
00491 
00492         if(mWindowStatistics.maxTriangleCount == UNDEFINEDSTATISTICS)
00493         {
00494          mWindowStatistics.maxTriangleCount = mWindowStatistics.lastTriangleCount;
00495         } else
00496         {
00497          mWindowStatistics.maxTriangleCount =
00498                 mWindowStatistics.lastTriangleCount >
00499                 mWindowStatistics.maxTriangleCount ? mWindowStatistics.lastTriangleCount : mWindowStatistics.
00500                 maxTriangleCount;
00501         }
00502 
00503         mSumTriangleCount += mWindowStatistics.lastTriangleCount;
00504         mWindowStatistics.avgTriangleCount = mSumTriangleCount / mWindowStatistics.frameCount;
00505 
00506         //
00507         // Frame rates
00508         //
00509         mFPSMeasuringFrameCount++;
00510         Real delay = Timer::getSystemTime() - mFPSMeasuringBeginTime;
00511 
00512         if(delay >= 1.0)
00513         {
00514          mWindowStatistics.lastFPS = mFPSMeasuringFrameCount / delay;
00515          mFPSMeasuringFrameCount = 0;
00516          mFPSMeasuringBeginTime = Timer::getSystemTime();
00517         }
00518 
00519         if(mWindowStatistics.bestFPS == UNDEFINEDSTATISTICS)
00520         {
00521          mWindowStatistics.bestFPS = mWindowStatistics.lastFPS;
00522         } else
00523         {
00524          mWindowStatistics.bestFPS =
00525                 mWindowStatistics.lastFPS >
00526                 mWindowStatistics.bestFPS ? mWindowStatistics.lastFPS : mWindowStatistics.bestFPS;
00527         }
00528 
00529         if(mWindowStatistics.worstFPS == UNDEFINEDSTATISTICS)
00530         {
00531          mWindowStatistics.worstFPS = mWindowStatistics.lastFPS;
00532         } else
00533         {
00534          mWindowStatistics.worstFPS =
00535                 mWindowStatistics.lastFPS <
00536                 mWindowStatistics.worstFPS ? mWindowStatistics.lastFPS : mWindowStatistics.worstFPS;
00537         }
00538 
00539         if(mWindowStatistics.renderingTime > Timer::EPSILONDELAY)
00540         {
00541          mWindowStatistics.avgFPS = mWindowStatistics.frameCount / mWindowStatistics.renderingTime;
00542         }
00543         //
00544         // Update caption
00545         //
00546         setCaption(mCaption);
00547   }
00548 
00549  /*----------------------------------------------------------------------*/
00550 
00551   void GLXRenderWindow::_setCaption()
00552   {
00553         mDisplay.lock();
00554         XStoreName(mDisplay->getDisplay(), mWindow,
00555                  (mCaption + " @" + StringConverter::toString(mWindowStatistics.lastFPS, 6, 2) + " fps, frame #" +
00556                  StringConverter::toString((*(mProcess->getContexts().begin()))->getFrameID())).c_str());
00557         mDisplay.unlock();
00558 
00559   }
00560 
00561  /*----------------------------------------------------------------------*/
00562 
00563 }