Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OpenGLPbufferDisplayDevice.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2019 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 /***************************************************************************
00009  * RCS INFORMATION:
00010  *
00011  *      $RCSfile: OpenGLPbufferDisplayDevice.C,v $
00012  *      $Author: johns $        $Locker:  $             $State: Exp $
00013  *      $Revision: 1.29 $       $Date: 2021/08/24 16:49:04 $
00014  *
00015  ***************************************************************************/
00027 #include <stdlib.h>
00028 #include <math.h>
00029 #include <GL/gl.h>
00030 
00031 #if defined(VMDGLXPBUFFER)
00032 #include <GL/glx.h>
00033 #include <X11/Xlib.h>
00034 #endif
00035 
00036 #include "OpenGLPbufferDisplayDevice.h"
00037 #include "Inform.h"
00038 #include "utilities.h"
00039 #include "config.h"   // VMD version strings etc
00040 #include "VMDApp.h"
00041 #include "VideoStream.h" 
00042 
00043 // Request a Pbuffer just larger than standard Ultra-HD "4K" resolution
00044 #define DEF_PBUFFER_XRES 4096
00045 #define DEF_PBUFFER_YRES 2400
00046 
00047 // static data for this object
00048 static const char *glStereoNameStr[OPENGL_STEREO_MODES] =
00049  { "Off",
00050    "QuadBuffered",
00051    "HDTV SideBySide",
00052    "Checkerboard",
00053    "ColumnInterleaved",
00054    "RowInterleaved",
00055    "Anaglyph",
00056    "SideBySide",
00057    "AboveBelow",
00058    "Left",
00059    "Right" };
00060 
00061 static const char *glRenderNameStr[OPENGL_RENDER_MODES] = 
00062 { "Normal",
00063   "GLSL",
00064   "Acrobat3D" };
00065 
00066 static const char *glCacheNameStr[OPENGL_CACHE_MODES] = 
00067 { "Off",
00068   "On" };
00069 
00070 
00071 //
00072 // GLX-related static helper functions
00073 //
00074 #if defined(VMDGLXPBUFFER)
00075 
00076 // determine if all of the ARB multisample extension routines are available
00077 // when using GLX APIs
00078 #if defined(GL_ARB_multisample) && defined(GLX_SAMPLES_ARB) && defined(GLX_SAMPLE_BUFFERS_ARB)
00079 #define USEARBMULTISAMPLE 1
00080 #endif
00081 
00082 static GLXFBConfig * vmd_get_glx_fbconfig(glxpbufferdata *glxsrv, int *stereo, int *msamp, int *numsamples) {
00083   // we want double-buffered RGB with a Z buffer (possibly with stereo)
00084   int ns, dsize;
00085   int simplegraphics = 0;
00086   int disablestereo = 0;
00087   GLXFBConfig *fbc = NULL;
00088   int nfbc = 0;
00089 
00090   *numsamples = 0;
00091   *msamp = FALSE; 
00092   *stereo = FALSE;
00093 
00094   if (getenv("VMDSIMPLEGRAPHICS")) {
00095     simplegraphics = 1;
00096   }
00097 
00098   if (getenv("VMDDISABLESTEREO")) {
00099     disablestereo = 1;
00100   } 
00101 
00102   // check for user-override of maximum antialiasing sample count
00103   int maxaasamples=4;
00104   const char *maxaasamplestr = getenv("VMDMAXAASAMPLES");
00105   if (maxaasamplestr) {
00106     int aatmp;
00107     if (sscanf(maxaasamplestr, "%d", &aatmp) == 1) {
00108       if (aatmp >= 0) {
00109         maxaasamples=aatmp;
00110         msgInfo << "User-requested OpenGL antialiasing sample depth: " 
00111                 << maxaasamples << sendmsg;
00112 
00113         if (maxaasamples < 2) {
00114           maxaasamples=1; 
00115           msgInfo << "OpenGL antialiasing disabled by user override."
00116                   << sendmsg;
00117         }
00118       } else {
00119         msgErr << "Ignoring user-requested OpenGL antialiasing sample depth: " 
00120                << aatmp << sendmsg;
00121       }
00122     } else {
00123       msgErr << "Unable to parse override of OpenGL antialiasing" << sendmsg;
00124       msgErr << "sample depth: '" << maxaasamplestr << "'" << sendmsg;
00125     }
00126   }
00127 
00128 
00129   // loop over a big range of depth buffer sizes, starting with biggest 
00130   // and working our way down from there.
00131   for (dsize=32; dsize >= 16; dsize-=4) { 
00132 
00133 // Try the OpenGL ARB multisample extension if available
00134 #if defined(USEARBMULTISAMPLE) 
00135     if (!simplegraphics && !disablestereo && (!fbc && nfbc < 1)) {
00136       // Stereo, multisample antialising, stencil buffer
00137       for (ns=maxaasamples; ns>1; ns--) {
00138         int conf[]  = {GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
00139                        GLX_DOUBLEBUFFER, 1,
00140                        GLX_RENDER_TYPE, GLX_RGBA_BIT,
00141                        GLX_DEPTH_SIZE, dsize, 
00142                        GLX_STEREO, 1,
00143                        GLX_STENCIL_SIZE, 1, 
00144                        GLX_SAMPLE_BUFFERS_ARB, 1, 
00145                        GLX_SAMPLES_ARB, ns, 
00146                        GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8,
00147                        None};
00148 
00149         fbc = glXChooseFBConfig(glxsrv->dpy, glxsrv->dpyScreen, conf, &nfbc);
00150 
00151         if (fbc && nfbc > 0) {
00152           *numsamples = ns;
00153           *msamp = TRUE;
00154           *stereo = TRUE;
00155           break; // exit loop if we got a good visual
00156         } 
00157       }
00158     }
00159 #endif
00160 
00161     if (getenv("VMDPREFERSTEREO") != NULL && !disablestereo) {
00162       // The preferred 24-bit color, quad buffered stereo mode.
00163       // This hack allows NVidia Quadro users to avoid the mutually-exclusive
00164       // antialiasing/stereo options on their cards with current drivers.
00165       // This forces VMD to skip looking for multisample antialiasing capable
00166       // X visuals and look for stereo instead.
00167       if (!simplegraphics && (!fbc && nfbc < 1)) {
00168         int conf[]  = {GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
00169                        GLX_DOUBLEBUFFER, 1,
00170                        GLX_RENDER_TYPE, GLX_RGBA_BIT,
00171                        GLX_DEPTH_SIZE, dsize, 
00172                        GLX_STEREO, 1,
00173                        GLX_STENCIL_SIZE, 1, 
00174                        GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8,
00175                        None};
00176 
00177         fbc = glXChooseFBConfig(glxsrv->dpy, glxsrv->dpyScreen, conf, &nfbc);
00178 
00179         ns = 0; // no multisample antialiasing
00180         *numsamples = ns;
00181         *msamp = FALSE; 
00182         *stereo = TRUE; 
00183       }
00184     } 
00185 #if defined(USEARBMULTISAMPLE) 
00186     else {
00187       // Try the OpenGL ARB multisample extension if available
00188       if (!simplegraphics && (!fbc && nfbc < 1)) {
00189         // Non-Stereo, multisample antialising, stencil buffer
00190         for (ns=maxaasamples; ns>1; ns--) {
00191           int conf[]  = {GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
00192                          GLX_DOUBLEBUFFER, 1,
00193                          GLX_RENDER_TYPE, GLX_RGBA_BIT,
00194                          GLX_DEPTH_SIZE, dsize, 
00195                          GLX_STENCIL_SIZE, 1, 
00196                          GLX_SAMPLE_BUFFERS_ARB, 1, 
00197                          GLX_SAMPLES_ARB, ns, 
00198                          GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8,
00199                          None};
00200 
00201           fbc = glXChooseFBConfig(glxsrv->dpy, glxsrv->dpyScreen, conf, &nfbc);
00202     
00203           if (fbc && nfbc > 0) {
00204             *numsamples = ns;
00205             *msamp = TRUE;
00206             *stereo = FALSE; 
00207             break; // exit loop if we got a good visual
00208           } 
00209         }
00210       }
00211     }
00212 #endif
00213 
00214   } // end of loop over a wide range of depth buffer sizes
00215 
00216   // Ideally we should fall back to accumulation buffer based antialiasing
00217   // here, but not currently implemented.  At this point no multisample
00218   // antialiasing mode is available.
00219 
00220   // The preferred 24-bit color, quad buffered stereo mode
00221   if (!simplegraphics && !disablestereo && (!fbc && nfbc < 1)) {
00222     int conf[]  = {GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
00223                    GLX_DOUBLEBUFFER, 1,
00224                    GLX_RENDER_TYPE, GLX_RGBA_BIT,
00225                    GLX_DEPTH_SIZE, 16, 
00226                    GLX_STEREO, 1,
00227                    GLX_STENCIL_SIZE, 1, 
00228                    GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8,
00229                    None};
00230 
00231     fbc = glXChooseFBConfig(glxsrv->dpy, glxsrv->dpyScreen, conf, &nfbc);
00232     
00233     ns = 0; // no multisample antialiasing
00234     *numsamples = ns;
00235     *msamp = FALSE; 
00236     *stereo = TRUE; 
00237   }
00238 
00239   // Mode for machines that provide stereo only in modes with 16-bit color.
00240   if (!simplegraphics && !disablestereo && (!fbc && nfbc < 1)) {
00241     int conf[]  = {GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
00242                    GLX_DOUBLEBUFFER, 1,
00243                    GLX_RENDER_TYPE, GLX_RGBA_BIT,
00244                    GLX_DEPTH_SIZE, 16, 
00245                    GLX_STEREO, 1,
00246                    GLX_STENCIL_SIZE, 1, 
00247                    GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
00248                    None};
00249 
00250     fbc = glXChooseFBConfig(glxsrv->dpy, glxsrv->dpyScreen, conf, &nfbc);
00251 
00252     ns = 0; // no multisample antialiasing
00253     *numsamples = ns;
00254     *msamp = FALSE; 
00255     *stereo = TRUE; 
00256   }
00257 
00258   // Mode for machines that provide stereo only without a stencil buffer, 
00259   // and with reduced color precision.  Examples of this are the SGI Octane2
00260   // machines with V6 graphics, with recent IRIX patch levels.
00261   // Without this configuration attempt, these machines won't get stereo.
00262   if (!simplegraphics && !disablestereo && (!fbc && nfbc < 1)) {
00263     int conf[]  = {GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
00264                    GLX_DOUBLEBUFFER, 1,
00265                    GLX_RENDER_TYPE, GLX_RGBA_BIT,
00266                    GLX_DEPTH_SIZE, 16, 
00267                    GLX_STEREO, 1,
00268                    GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
00269                    None};
00270 
00271     fbc = glXChooseFBConfig(glxsrv->dpy, glxsrv->dpyScreen, conf, &nfbc);
00272 
00273     ns = 0; // no multisample antialiasing
00274     *numsamples = ns;
00275     *msamp = FALSE; 
00276     *stereo = TRUE; 
00277   }
00278 
00279   // This mode gives up on trying to get stereo, and goes back to trying
00280   // to get a high quality non-stereo visual.
00281   if (!simplegraphics && (!fbc && nfbc < 1)) {
00282     int conf[]  = {GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
00283                    GLX_DOUBLEBUFFER, 1,
00284                    GLX_RENDER_TYPE, GLX_RGBA_BIT,
00285                    GLX_DEPTH_SIZE, 16, 
00286                    GLX_STENCIL_SIZE, 1, 
00287                    GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8,
00288                    None};
00289 
00290     fbc = glXChooseFBConfig(glxsrv->dpy, glxsrv->dpyScreen, conf, &nfbc);
00291 
00292     ns = 0; // no multisample antialiasing
00293     *numsamples = ns;
00294     *msamp = FALSE; 
00295     *stereo = FALSE;
00296   }
00297   
00298   // check if we have a TrueColor visual.
00299   if (!fbc && nfbc < 1) {
00300     // still no TrueColor.  Try again, with a very basic request ...
00301     // This is a catch all, we're desperate for any truecolor
00302     // visual by this point.  We've given up hoping for 24-bit
00303     // color or stereo by this time.
00304     int conf[]  = {GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
00305                    GLX_DOUBLEBUFFER, 1,
00306                    GLX_RENDER_TYPE, GLX_RGBA_BIT,
00307                    GLX_DEPTH_SIZE, 16, 
00308                    GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8,
00309                    None};
00310 
00311     fbc = glXChooseFBConfig(glxsrv->dpy, glxsrv->dpyScreen, conf, &nfbc);
00312 
00313     ns = 0; // no multisample antialiasing
00314     *numsamples = ns;
00315     *msamp = FALSE; 
00316     *stereo = FALSE;
00317   }
00318 
00319   if (!fbc && nfbc < 1) {
00320     // complete failure
00321     ns = 0; // no multisample antialiasing
00322     *numsamples = ns;
00323     *msamp = FALSE; 
00324     *stereo = FALSE;
00325   }
00326 
00327   // return NULL if the config count is less than one
00328   if (nfbc < 1)
00329     return NULL;
00330 
00331   return fbc;
00332 }
00333 
00334 #endif
00335 
00336 
00337 //
00338 // EGL-related static helper functions
00339 //
00340 #if defined(VMDEGLPBUFFER)
00341 
00342 // determine if all of the ARB multisample extension routines are available
00343 // when using EGL APIs
00344 #if defined(GL_ARB_multisample)
00345 #define USEARBMULTISAMPLE 1
00346 #endif
00347 
00348 static int vmd_get_egl_fbconfig(eglpbufferdata *eglsrv, int *stereo, int *msamp, int *numsamples) {
00349   // we want double-buffered RGB with a Z buffer (possibly with stereo)
00350   int ns, dsize;
00351   int simplegraphics = 0;
00352   // XXX standard EGL doesn't support stereo visuals at present,
00353   // int disablestereo = 0;
00354   int fbc = 0;
00355   int nfbc = 0;
00356 
00357   *numsamples = 0;
00358   *msamp = FALSE; 
00359   *stereo = FALSE;
00360 
00361   if (getenv("VMDSIMPLEGRAPHICS")) {
00362     simplegraphics = 1;
00363   }
00364 
00365   // XXX standard EGL doesn't support stereo visuals at present,
00366   // if (getenv("VMDDISABLESTEREO")) {
00367   //   disablestereo = 1;
00368   // } 
00369 
00370   // check for user-override of maximum antialiasing sample count
00371   int maxaasamples=4;
00372   const char *maxaasamplestr = getenv("VMDMAXAASAMPLES");
00373   if (maxaasamplestr) {
00374     int aatmp;
00375     if (sscanf(maxaasamplestr, "%d", &aatmp) == 1) {
00376       if (aatmp >= 0) {
00377         maxaasamples=aatmp;
00378         msgInfo << "User-requested OpenGL antialiasing sample depth: " 
00379                 << maxaasamples << sendmsg;
00380 
00381         if (maxaasamples < 2) {
00382           maxaasamples=1; 
00383           msgInfo << "OpenGL antialiasing disabled by user override."
00384                   << sendmsg;
00385         }
00386       } else {
00387         msgErr << "Ignoring user-requested OpenGL antialiasing sample depth: " 
00388                << aatmp << sendmsg;
00389       }
00390     } else {
00391       msgErr << "Unable to parse override of OpenGL antialiasing" << sendmsg;
00392       msgErr << "sample depth: '" << maxaasamplestr << "'" << sendmsg;
00393     }
00394   }
00395 
00396 
00397   // loop over a big range of depth buffer sizes, starting with biggest 
00398   // and working our way down from there.
00399   for (dsize=32; dsize >= 16; dsize-=4) { 
00400     //
00401     // XXX standard EGL doesn't support stereo visuals at present,
00402     // so the tsts we would normally do for stereo are omitted here
00403     //
00404 
00405 // Try the OpenGL ARB multisample extension if available
00406 #if defined(USEARBMULTISAMPLE) 
00407     if (!simplegraphics && (!fbc && nfbc < 1)) {
00408       // Non-Stereo, multisample antialising, stencil buffer
00409       for (ns=maxaasamples; ns>1; ns--) {
00410         int conf[]  = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
00411                        EGL_DEPTH_SIZE, dsize, 
00412                        EGL_STENCIL_SIZE, 1, 
00413                        EGL_SAMPLE_BUFFERS, 1, 
00414                        EGL_SAMPLES, ns, 
00415                        EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
00416                        EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE };
00417 
00418         if (eglChooseConfig(eglsrv->dpy, conf, &eglsrv->conf, 1, &nfbc) == EGL_TRUE) {
00419           if (nfbc > 0) {
00420             fbc=1; // flag that we got a config
00421             *numsamples = ns;
00422             *msamp = TRUE;
00423             *stereo = FALSE; // XXX EGL doesn't support stereo at present
00424             break; // exit loop if we got a good visual
00425           } 
00426         }
00427       }
00428     }
00429 #endif
00430 
00431     //
00432     // XXX standard EGL doesn't support stereo visuals at present,
00433     // so the tsts we would normally do for stereo are omitted here
00434     //
00435   } // end of loop over a wide range of depth buffer sizes
00436 
00437   // Ideally we should fall back to accumulation buffer based antialiasing
00438   // here, but not currently implemented.  At this point no multisample
00439   // antialiasing mode is available.
00440 
00441   //
00442   // XXX standard EGL doesn't support stereo visuals at present,
00443   // so the tests we would normally do for stereo are omitted here
00444   //
00445 
00446   // This mode gives up on trying to get stereo, and goes back to trying
00447   // to get a high quality non-stereo visual.
00448   if (!simplegraphics && (!fbc && nfbc < 1)) {
00449     int conf[]  = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
00450                    EGL_DEPTH_SIZE, 16, 
00451                    EGL_STENCIL_SIZE, 1, 
00452                    EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
00453                    EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE };
00454 
00455     if (eglChooseConfig(eglsrv->dpy, conf, &eglsrv->conf, 1, &nfbc) == EGL_TRUE) {
00456       if (nfbc > 0) {
00457         fbc=1; // flag that we got a config
00458         ns = 0; // no multisample antialiasing
00459         *numsamples = ns;
00460         *msamp = FALSE; 
00461         *stereo = FALSE; // XXX EGL doesn't support stereo at present
00462       } 
00463     }
00464   }
00465   
00466   // check if we have a TrueColor visual.
00467   if (!fbc && nfbc < 1) {
00468     // still no TrueColor.  Try again, with a very basic request ...
00469     // This is a catch all, we're desperate for any truecolor
00470     // visual by this point.  We've given up hoping for 24-bit
00471     // color or stereo by this time.
00472     int conf[]  = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
00473                    EGL_DEPTH_SIZE, 16, 
00474                    EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
00475                    EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE };
00476 
00477     if (eglChooseConfig(eglsrv->dpy, conf, &eglsrv->conf, 1, &nfbc) == EGL_TRUE) {
00478       if (nfbc > 0) {
00479         fbc=1; // flag that we got a config
00480         ns = 0; // no multisample antialiasing
00481         *numsamples = ns;
00482         *msamp = FALSE; 
00483         *stereo = FALSE; // XXX EGL doesn't support stereo at present
00484       } 
00485     }
00486   }
00487 
00488   if (!fbc && nfbc < 1) {
00489     // complete failure
00490     ns = 0; // no multisample antialiasing
00491     *numsamples = ns;
00492     *msamp = FALSE; 
00493     *stereo = FALSE; // XXX EGL doesn't support stereo at present
00494   }
00495 
00496   // return false if the config count is less than one
00497   if (nfbc < 1)
00498     return 0;
00499 
00500   return 1;
00501 }
00502 
00503 #endif
00504 
00505 
00506 
00507 
00508 
00509 
00510 
00511 
00512 
00514 
00515 OpenGLPbufferDisplayDevice::OpenGLPbufferDisplayDevice()
00516 : OpenGLRenderer((char *) "VMD " VMDVERSION " OpenGL Display") {
00517   // set up data possible before opening window
00518   stereoNames = glStereoNameStr;
00519   stereoModes = OPENGL_STEREO_MODES;
00520 
00521   renderNames = glRenderNameStr;
00522   renderModes = OPENGL_RENDER_MODES;
00523 
00524   cacheNames = glCacheNameStr;
00525   cacheModes = OPENGL_CACHE_MODES;
00526 
00527 #if defined(VMDEGLPBUFFER)
00528   memset(&eglsrv, 0, sizeof(eglsrv));
00529 #endif
00530 #if defined(VMDGLXPBUFFER)
00531   memset(&glxsrv, 0, sizeof(glxsrv));
00532   glxsrv.dpy = NULL;
00533   glxsrv.dpyScreen = 0;
00534 #endif
00535 
00536   have_window = FALSE;
00537   screenX = screenY = 0;
00538 }
00539 
00540 
00541 int OpenGLPbufferDisplayDevice::init(int argc, char **argv, VMDApp *app, int *size, int *loc) {
00542   vmdapp = app; // save VMDApp handle for use by drag-and-drop handlers
00543                 // and GPU memory management routines
00544 
00545   // Try and create a pbuffer using GLX first, and if that doesn't work or
00546   // the code is compiled with EGL only, then we fall back to EGL.
00547 
00548 #if defined(VMDGLXPBUFFER)
00549   int haveglxwin = 0;
00550   haveglxwin = glx_open_window(name, size, loc, argc, argv);
00551   if (haveglxwin)
00552     msgInfo << "Created GLX OpenGL Pbuffer for off-screen rendering" << sendmsg;
00553 #endif
00554 
00555 #if defined(VMDEGLPBUFFER)
00556   int haveeglwin = 0;
00557 #if defined(VMDGLXPBUFFER) 
00558   if (!haveglxwin)
00559 #endif
00560     haveeglwin = egl_open_window(name, size, loc, argc, argv);
00561 
00562   if (haveeglwin)
00563     msgInfo << "Created EGL OpenGL Pbuffer for off-screen rendering" << sendmsg;
00564 #endif
00565 
00566   if (!have_window) return FALSE;
00567 
00568   // set flags for the capabilities of this display
00569   // whether we can do antialiasing or not.
00570   if (ext->hasmultisample) 
00571     aaAvailable = TRUE;  // we use multisampling over other methods
00572   else
00573     aaAvailable = FALSE; // no non-multisample implementation yet
00574 
00575   // set default settings
00576   if (ext->hasmultisample) {
00577     aa_on();  // enable fast multisample based antialiasing by default
00578               // other antialiasing techniques are slow, so only multisample
00579               // makes sense to enable by default.
00580   } 
00581 
00582   cueingAvailable = TRUE;
00583   cueing_on(); // leave depth cueing on by default, despite the speed hit.
00584 
00585   cullingAvailable = TRUE;
00586   culling_off();
00587 
00588   set_sphere_mode(sphereMode);
00589   set_sphere_res(sphereRes);
00590   set_line_width(lineWidth);
00591   set_line_style(lineStyle);
00592 
00593   // reshape and clear the display, which initializes some other variables
00594   reshape();
00595   normal();
00596   clear();
00597   update();
00598 
00599   // We have a window, return success.
00600   return TRUE;
00601 }
00602 
00603 // destructor ... close the window
00604 OpenGLPbufferDisplayDevice::~OpenGLPbufferDisplayDevice(void) {
00605   if (have_window) {
00606     free_opengl_ctx(); // free display lists, textures, etc
00607 
00608     // close and delete windows, contexts, and display connections
00609 #if defined(VMDEGLPBUFFER)
00610 #endif
00611 #if defined(VMDGLXPBUFFER)
00612     if (glxsrv.cx) {
00613       glXDestroyContext(glxsrv.dpy, glxsrv.cx);
00614       XCloseDisplay(glxsrv.dpy);
00615     }
00616 #endif
00617 
00618   }
00619 }
00620 
00621 
00623 
00624 
00625 #if defined(VMDEGLPBUFFER)
00626 
00627 // static helper fctn to convert error state into a human readable mesg string
00628 static const char* vmd_get_egl_errorstring(void) {    
00629   EGLint errcode = eglGetError();
00630   switch (errcode) {
00631     case EGL_SUCCESS:              return "No error"; break;
00632     case EGL_NOT_INITIALIZED:      return "EGL not initialized"; break;
00633     case EGL_BAD_ACCESS:           return "EGL bad access"; break;
00634     case EGL_BAD_ALLOC:            return "EGL bad alloc"; break;
00635     case EGL_BAD_ATTRIBUTE:        return "EGL bad attribute"; break;
00636     case EGL_BAD_CONTEXT:          return "EGL bad context"; break;
00637     case EGL_BAD_CONFIG:           return "EGL bad config"; break;
00638     case EGL_BAD_CURRENT_SURFACE:  return "EGL bad cur context"; break;
00639     case EGL_BAD_DISPLAY:          return "EGL bad display"; break;
00640     case EGL_BAD_SURFACE:          return "EGL bad surface"; break;
00641     case EGL_BAD_MATCH:            return "EGL bad match"; break;
00642     case EGL_BAD_PARAMETER:        return "EGL bad parameter"; break;
00643     case EGL_BAD_NATIVE_PIXMAP:    return "EGL bad native pixmap"; break;
00644     case EGL_BAD_NATIVE_WINDOW:    return "EGL bad native window"; break;
00645     case EGL_CONTEXT_LOST:         return "EGL context lost"; break;
00646     default:
00647       return "Unrecognized EGL error"; break;
00648   }
00649 }
00650 
00651 
00652 // create a new window and set it's characteristics
00653 int OpenGLPbufferDisplayDevice::egl_open_window(char *nm, int *size, int *loc,
00654                                                 int argc, char** argv) {
00655   // Clear display before we try and attach
00656   eglsrv.dpy = EGL_NO_DISPLAY;
00657   eglsrv.numdevices = 0;
00658   eglsrv.devindex = 0;
00659 
00660 #if defined(EGL_EXT_platform_base) && (EGL_EGLEXT_VERSION >= 20160000)
00661   // 
00662   // enumerate all GPUs and bind to the one that matches our MPI node rank
00663   // 
00664 
00665   // load the function pointers for the device,platform extensions            
00666   PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
00667   PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
00668   eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC) eglGetProcAddress("eglQueryDevicesEXT");     
00669   eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT");     
00670 
00671   // try and bind to a non-default display if we have all required fctn ptrs
00672   if (eglQueryDevicesEXT != NULL && eglGetPlatformDisplayEXT != NULL) {
00673     static const int MAX_DEVICES = 16;
00674     EGLDeviceEXT devicelist[MAX_DEVICES];
00675     eglQueryDevicesEXT(MAX_DEVICES, devicelist, &eglsrv.numdevices);
00676 
00677     // compute EGL device index to use via round-robin assignment
00678     eglsrv.devindex = vmdapp->noderank % eglsrv.numdevices;
00679     eglsrv.dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, devicelist[eglsrv.devindex], 0);
00680   }
00681 #endif
00682 
00683   // emit console message with node rank and bound EGL device
00684   if (eglsrv.dpy != EGL_NO_DISPLAY) {
00685     printf("Info) EGL: node[%d] bound to display[%d], %d %s total\n", 
00686             vmdapp->noderank, eglsrv.devindex, eglsrv.numdevices, 
00687             (eglsrv.numdevices == 1) ? "display" : "displays");
00688   } else {
00689     // use default display
00690     eglsrv.dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
00691   
00692     if (eglsrv.dpy != EGL_NO_DISPLAY)
00693       msgInfo << "EGL context bound to default display." << sendmsg;
00694   }
00695 
00696   // if we still have no display, we have no choice but to abort
00697   if (eglsrv.dpy == EGL_NO_DISPLAY) {
00698     msgErr << "Exiting due to EGL Pbuffer creation failure." << sendmsg;
00699     return 0; 
00700   }
00701 
00702   EGLint eglmaj, eglmin;
00703   if (eglInitialize(eglsrv.dpy, &eglmaj, &eglmin) == EGL_FALSE) {
00704     msgErr << "Exiting due to EGL initialization failure." << sendmsg;
00705     msgErr << "  " << vmd_get_egl_errorstring() << sendmsg;
00706     return 0; 
00707   } 
00708   msgInfo << "EGL version " << eglmaj << "." << eglmin << sendmsg;
00709 
00710   int fbc = vmd_get_egl_fbconfig(&eglsrv, &ext->hasstereo, &ext->hasmultisample, &ext->nummultisamples);
00711   if (!fbc) {
00712     msgErr << "Exiting due to EGL config failure." << sendmsg;
00713     msgErr << "  " << vmd_get_egl_errorstring() << sendmsg;
00714     return 0; 
00715   }
00716 
00717   EGLint vid;
00718   if (eglGetConfigAttrib(eglsrv.dpy, eglsrv.conf, EGL_NATIVE_VISUAL_ID, &vid) == EGL_FALSE) {
00719     msgErr << "Exiting due to eglGetConfigAttrib() failure." << sendmsg;
00720     msgErr << "  " << vmd_get_egl_errorstring() << sendmsg;
00721     return 0; 
00722   }
00723 
00724   // bind to OpenGL API since some implementations don't do this by default
00725   if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
00726     msgErr << "Exiting due to EGL OpenGL binding failure." << sendmsg;
00727     msgErr << "  " << vmd_get_egl_errorstring() << sendmsg;
00728     return 0; 
00729   }
00730 
00731   eglsrv.ctx = eglCreateContext(eglsrv.dpy, eglsrv.conf, EGL_NO_CONTEXT, NULL);
00732 
00733   // create the size we ask for, or fail
00734   static const EGLint pbuffer_fixedsz_attribs[] = {
00735     EGL_WIDTH, DEF_PBUFFER_XRES,
00736     EGL_HEIGHT, DEF_PBUFFER_YRES,
00737     EGL_NONE,
00738   };
00739 
00740   // if we don't get the size we ask for, try for the max size and
00741   // then tell VMD what it ended up being.  We probably need a sanity
00742   // check in the case we get a really lame small size buffer back.
00743   static const EGLint pbuffer_defsz_attribs[] = {
00744     EGL_WIDTH, DEF_PBUFFER_XRES,
00745     EGL_HEIGHT, DEF_PBUFFER_YRES,
00746     EGL_LARGEST_PBUFFER, EGL_TRUE,
00747     EGL_NONE,
00748   };
00749 
00750   // Try for a HUGE size and then tell VMD what it ended up being.  
00751   static const EGLint pbuffer_maxsz_attribs[] = {
00752     EGL_WIDTH, 10000,
00753     EGL_HEIGHT, 10000,
00754     EGL_LARGEST_PBUFFER, EGL_TRUE,
00755     EGL_NONE,
00756   };
00757 
00758   // Demonstrate bugs in implementations that don't do the right thing
00759   // with the EGL_LARGEST_BUFFER parameter
00760   static const EGLint pbuffer_hugesz_attribs[] = {
00761     EGL_WIDTH, 30000,
00762     EGL_HEIGHT, 30000,
00763     EGL_LARGEST_PBUFFER, EGL_TRUE,
00764     EGL_NONE,
00765   };
00766 
00767   EGLint const *pbuffer_attrs = pbuffer_defsz_attribs;
00768   if (getenv("VMDEGLUSEFIXEDSZ") != NULL) {
00769     pbuffer_attrs = pbuffer_fixedsz_attribs;
00770   }
00771   if (getenv("VMDEGLUSEMAXSZ") != NULL) {
00772     pbuffer_attrs = pbuffer_maxsz_attribs;
00773   }
00774   if (getenv("VMDEGLUSEHUGESZ") != NULL) {
00775     pbuffer_attrs = pbuffer_hugesz_attribs;
00776   }
00777 
00778   eglsrv.surf = eglCreatePbufferSurface(eglsrv.dpy, eglsrv.conf, pbuffer_attrs);
00779   if (eglsrv.surf == EGL_NO_SURFACE) {
00780     msgErr << "Exiting due to EGL Pbuffer surface creation failure." << sendmsg;
00781     msgErr << "  " << vmd_get_egl_errorstring() << sendmsg;
00782     return 0; 
00783   }
00784 
00785   EGLint surface_xsize, surface_ysize;
00786   if ((eglQuerySurface(eglsrv.dpy, eglsrv.surf, EGL_WIDTH, &surface_xsize) != EGL_TRUE) ||
00787       (eglQuerySurface(eglsrv.dpy, eglsrv.surf, EGL_HEIGHT, &surface_ysize) != EGL_TRUE)) {
00788     msgErr << "Exiting due to EGL Pbuffer surface dimensions query failure." << sendmsg;
00789     msgErr << "  " << vmd_get_egl_errorstring() << sendmsg;
00790     return 0; 
00791   }
00792 
00793   // set maximum allowable rendered image size for the Pbuffer
00794   // that was actually allocated, which may be smaller than we hoped...
00795   PbufferMaxXsz = surface_xsize;
00796   PbufferMaxYsz = surface_ysize;
00797 
00798   msgInfo << "OpenGL Pbuffer size: " 
00799           << PbufferMaxXsz << "x"
00800           << PbufferMaxYsz << sendmsg;
00801 
00802   // set default image size to incoming values, when possible.
00803   xSize = size[0];
00804   ySize = size[1];
00805   if (xSize < 0 || xSize > PbufferMaxXsz || 
00806       ySize < 0 || ySize > PbufferMaxYsz) {
00807     msgWarn << "Ignored out-of-range OpenGL Pbuffer image dimension request: " 
00808             << xSize << "x" << ySize 
00809             << " (max: " 
00810             << PbufferMaxXsz << "x" << PbufferMaxYsz << ")" << sendmsg;
00811     xSize = PbufferMaxXsz;
00812     ySize = PbufferMaxYsz;
00813   }
00814 
00815   EGLBoolean ctxstatus = EGL_FALSE;
00816   ctxstatus = eglMakeCurrent(eglsrv.dpy, eglsrv.surf, eglsrv.surf, eglsrv.ctx);
00817   if (ctxstatus != EGL_TRUE) {
00818     msgErr << "Exiting due to EGL failure during eglMakeCurrent()." << sendmsg;
00819     msgErr << "  " << vmd_get_egl_errorstring() << sendmsg;
00820     return 0;
00821   }
00822 
00823 
00824   EGLint Context_RendererType=0;
00825   eglQueryContext(eglsrv.dpy, eglsrv.ctx, EGL_CONTEXT_CLIENT_TYPE, &Context_RendererType);
00826 
00827 #if 0
00828   const char *glstring="uninitialized";
00829   char buf[1024];
00830   switch (Context_RendererType) {
00831     case    EGL_OPENGL_API: glstring = "OpenGL"; break;
00832     case EGL_OPENGL_ES_API: glstring = "OpenGL ES"; break;
00833     case    EGL_OPENVG_API: glstring = "OpenVG???"; break;
00834     default:
00835       sprintf(buf, "Unknown API: %x", Context_RendererType);
00836       glstring=buf;
00837       break;
00838   }
00839   msgInfo << "EGL_CONTEXT_CLIENT_TYPE: %s\n", glstring);
00840 #endif
00841 
00842   // If we have acquired a multisample buffer with GLX, we
00843   // still need to test to see if we can actually use it.
00844   if (ext->hasmultisample) {
00845     int msampeext = 0;
00846 
00847     // check for ARB multisampling
00848     if (ext->vmdQueryExtension("GL_ARB_multisample")) {
00849       msampeext = 1;
00850     }
00851 
00852     if (!msampeext) {
00853       ext->hasmultisample = FALSE;
00854       ext->nummultisamples = 0;
00855     }
00856   }
00857 
00858   // (9) configure the rendering properly
00859   setup_initial_opengl_state();  // setup initial OpenGL state
00860 
00861   // normal return: window was successfully created
00862   have_window = TRUE;
00863 
00864   return 1; // return success
00865 }
00866 #endif
00867 
00868 
00869 
00870 #if defined(VMDGLXPBUFFER)
00871 
00872 // create a new window and set it's characteristics
00873 int OpenGLPbufferDisplayDevice::glx_open_window(char *nm, int *size, int *loc,
00874                                                 int argc, char** argv) {
00875   char *dispname;
00876   if ((dispname = getenv("VMDGDISPLAY")) == NULL)
00877     dispname = getenv("DISPLAY");
00878 
00879   if(!(glxsrv.dpy = XOpenDisplay(dispname))) {
00880     msgErr << "Exiting due to X-Windows GLX/OpenGL Pbuffer creation failure." << sendmsg;
00881     if (dispname != NULL) {
00882       msgErr << "Failed to open display: " << dispname << sendmsg;
00883     }
00884     return 0; 
00885   }
00886 
00887   //
00888   // get info about root window
00889   //
00890   glxsrv.dpyScreen = DefaultScreen(glxsrv.dpy);
00891   glxsrv.rootWindowID = RootWindow(glxsrv.dpy, glxsrv.dpyScreen);
00892   screenX = DisplayWidth(glxsrv.dpy, glxsrv.dpyScreen);
00893   screenY = DisplayHeight(glxsrv.dpy, glxsrv.dpyScreen);
00894 
00895   // (3) make sure the GLX extension is available
00896   if (!glXQueryExtension(glxsrv.dpy, NULL, NULL)) {
00897     msgErr << "The X server does not support the OpenGL GLX extension." 
00898            << "   Exiting ..." << sendmsg;
00899     XCloseDisplay(glxsrv.dpy);
00900     return 0;
00901   }
00902 
00903   ext->hasstereo = TRUE;         // stereo on until we find out otherwise.
00904   ext->stereodrawforced = FALSE; // no need for force stereo draws initially
00905   ext->hasmultisample = TRUE;    // multisample on until we find out otherwise.
00906 
00907   // Find the best matching OpenGL framebuffer config for our purposes
00908   GLXFBConfig *fbc;
00909   fbc = vmd_get_glx_fbconfig(&glxsrv, &ext->hasstereo, &ext->hasmultisample, &ext->nummultisamples);
00910   if (fbc == NULL) {
00911     msgErr << "No OpenGL Pbuffer configurations available" << sendmsg;
00912     return 0;
00913   }
00914 
00915   // Create the OpenGL Pbuffer and associated GLX context
00916   const int pbconf[] = {GLX_PBUFFER_WIDTH, DEF_PBUFFER_XRES, 
00917                         GLX_PBUFFER_HEIGHT, DEF_PBUFFER_YRES,
00918                         GLX_LARGEST_PBUFFER, 1,
00919                         GLX_PRESERVED_CONTENTS, 1, 
00920                         None};
00921   GLXPbuffer PBuffer = glXCreatePbuffer(glxsrv.dpy, fbc[0], pbconf);
00922   glxsrv.cx = glXCreateNewContext(glxsrv.dpy, fbc[0], GLX_RGBA_TYPE, 0, GL_TRUE);
00923   if (PBuffer == 0 || glxsrv.cx == NULL) {
00924     msgErr << "A TrueColor OpenGL Pbuffer is required, but not available." << sendmsg;
00925     msgErr << "The X server is not capable of displaying double-buffered," << sendmsg;
00926     msgErr << "RGB images with a Z buffer.   Exiting ..." << sendmsg;
00927     XCloseDisplay(glxsrv.dpy);
00928     return 0;
00929   }
00930 
00931   // set maximum allowable rendered image size for the Pbuffer
00932   // that was actually allocated, which may be smaller than we hoped...
00933   PbufferMaxXsz = DEF_PBUFFER_XRES;
00934   PbufferMaxYsz = DEF_PBUFFER_YRES;
00935   glXQueryDrawable(glxsrv.dpy, PBuffer, GLX_WIDTH,  &PbufferMaxXsz);
00936   glXQueryDrawable(glxsrv.dpy, PBuffer, GLX_HEIGHT, &PbufferMaxYsz);
00937 
00938   msgInfo << "OpenGL Pbuffer size: " 
00939           << PbufferMaxXsz << "x"
00940           << PbufferMaxYsz << sendmsg;
00941 
00942   // set default image size to incoming values, when possible.
00943   xSize = size[0];
00944   ySize = size[1];
00945   if (xSize < 0 || xSize > PbufferMaxXsz || 
00946       ySize < 0 || ySize > PbufferMaxYsz) {
00947     msgWarn << "Ignored out-of-range OpenGL Pbuffer image dimension request: " 
00948             << xSize << "x" << ySize 
00949             << " (max: " 
00950             << PbufferMaxXsz << "x" << PbufferMaxYsz << ")" << sendmsg;
00951     xSize = PbufferMaxXsz;
00952     ySize = PbufferMaxYsz;
00953   }
00954 
00955   // make the Pbuffer active
00956   glXMakeContextCurrent(glxsrv.dpy, PBuffer, PBuffer, glxsrv.cx);
00957   glXMakeCurrent(glxsrv.dpy, PBuffer, glxsrv.cx);
00958 
00959   // If we have acquired a multisample buffer with GLX, we
00960   // still need to test to see if we can actually use it.
00961   if (ext->hasmultisample) {
00962     int msampeext = 0;
00963 
00964     // check for ARB multisampling
00965     if (ext->vmdQueryExtension("GL_ARB_multisample")) {
00966       msampeext = 1;
00967     }
00968 
00969     if (!msampeext) {
00970       ext->hasmultisample = FALSE;
00971       ext->nummultisamples = 0;
00972     }
00973   }
00974 
00975   // (9) configure the rendering properly
00976   setup_initial_opengl_state();  // setup initial OpenGL state
00977 
00978   // normal return: window was successfully created
00979   have_window = TRUE;
00980 
00981   // set window id
00982   glxsrv.windowID = PBuffer;
00983 
00984   return 1; // return success
00985 }
00986 #endif
00987 
00988 
00990 
00991 //
00992 // virtual routines for preparing to draw, drawing, and finishing drawing
00993 //
00994 void OpenGLPbufferDisplayDevice::do_resize_window(int w, int h) {
00995   if ((w > 0) && (w <= ((int) PbufferMaxXsz))) {
00996     xSize = w;
00997   } else {
00998     msgWarn << "Ignored out-of-range OpenGL Pbuffer X dimension request: " 
00999             << w << " (max: " << PbufferMaxXsz << ")" << sendmsg;
01000   }
01001   if ((h > 0) && (h <= ((int) PbufferMaxYsz))) {
01002     ySize = h;
01003   } else {
01004     msgWarn << "Ignored out-of-range OpenGL Pbuffer Y dimension request: " 
01005             << h << " (max: " << PbufferMaxYsz << ")" << sendmsg;
01006   }
01007 
01008   // force OpenGL frustum recalc
01009   reshape();
01010 
01011   // display now needs to be redrawn from scratch
01012   _needRedraw = 1;
01013 }
01014 
01015 
01016 // reshape the display after a shape change
01017 void OpenGLPbufferDisplayDevice::reshape(void) {
01018   switch (inStereo) {
01019     case OPENGL_STEREO_SIDE:
01020       set_screen_pos(0.5f * (float)xSize / (float)ySize);
01021       break;
01022 
01023     case OPENGL_STEREO_ABOVEBELOW:
01024       set_screen_pos(2.0f * (float)xSize / (float)ySize);
01025       break;
01026 
01027     case OPENGL_STEREO_STENCIL_CHECKERBOARD:
01028     case OPENGL_STEREO_STENCIL_COLUMNS:
01029     case OPENGL_STEREO_STENCIL_ROWS:
01030       enable_stencil_stereo(inStereo);
01031       set_screen_pos((float)xSize / (float)ySize);
01032       break;
01033  
01034     default:
01035       set_screen_pos((float)xSize / (float)ySize);
01036       break;
01037   }
01038 }
01039 
01040 
01041 unsigned char * OpenGLPbufferDisplayDevice::readpixels_rgb3u(int &xs, int &ys) {
01042   unsigned char * img = NULL;
01043   xs = xSize;
01044   ys = ySize;
01045 
01046   // fall back to normal glReadPixels() if better methods fail
01047   if ((img = (unsigned char *) malloc(xs * ys * 3)) != NULL) {
01048     glPixelStorei(GL_PACK_ALIGNMENT, 1);
01049     glReadPixels(0, 0, xs, ys, GL_RGB, GL_UNSIGNED_BYTE, img);
01050     return img; 
01051   }
01052 
01053   // else bail out
01054   xs = 0;
01055   ys = 0;
01056   return NULL;
01057 }
01058 
01059 unsigned char * OpenGLPbufferDisplayDevice::readpixels_rgba4u(int &xs, int &ys) {
01060   unsigned char * img = NULL;
01061   xs = xSize;
01062   ys = ySize;
01063 
01064   // fall back to normal glReadPixels() if better methods fail
01065   if ((img = (unsigned char *) malloc(xs * ys * 4)) != NULL) {
01066     glPixelStorei(GL_PACK_ALIGNMENT, 1);
01067     glReadPixels(0, 0, xs, ys, GL_RGBA, GL_UNSIGNED_BYTE, img);
01068     return img; 
01069   }
01070 
01071   // else bail out
01072   xs = 0;
01073   ys = 0;
01074   return NULL;
01075 }
01076 
01077 
01078 // update after drawing
01079 void OpenGLPbufferDisplayDevice::update(int do_update) {
01080   if (wiregl) {
01081     glFinish(); // force cluster to synchronize before buffer swap, 
01082                 // this gives much better results than if the 
01083                 // synchronization is done implicitly by glXSwapBuffers.
01084   }
01085 
01086 #if 1
01087   // push latest frame into the video streaming pipeline
01088   // and pump the event handling mechanism afterwards
01089   if (vmdapp->uivs && vmdapp->uivs->srv_connected()) {
01090     // if no frame was provided, we grab the GL framebuffer
01091     int xs, ys;
01092     unsigned char *img = NULL;
01093     img = readpixels_rgba4u(xs, ys);
01094     if (img != NULL) {
01095       // srv_send_frame(img, xs * 4, xs, ys, vs_forceIframe);
01096       vmdapp->uivs->video_frame_pending(img, xs, ys);
01097       vmdapp->uivs->check_event();
01098       free(img);
01099     }
01100   }
01101 #endif
01102 
01103 #if defined(VMDEGLPBUFFER)
01104 #if 1
01105   if (do_update)
01106     eglSwapBuffers(eglsrv.dpy, eglsrv.surf);
01107 #else
01108   EGLBoolean eglrc = EGL_TRUE;
01109   if (do_update)
01110     eglrc = eglSwapBuffers(eglsrv.dpy, eglsrv.surf);
01111 
01112   if (eglrc != EGL_TRUE) {
01113     printf("eglSwapBuffers(): EGLrc: %d\n", eglrc);
01114   }
01115 #endif
01116 #endif
01117 
01118 #if defined(VMDGLXPBUFFER)
01119   if (do_update)
01120     glXSwapBuffers(glxsrv.dpy, glxsrv.windowID);
01121 #endif
01122 
01123   glDrawBuffer(GL_BACK);
01124 }
01125 

Generated on Fri Apr 19 02:44:46 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002