TX11GL.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TX11GL.cxx 34245 2010-06-30 13:36:29Z brun $
00002 // Author: Timur Pocheptsov (TX11GLManager) / Valeriy Onuchin (TX11GL)
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include <deque>
00013 #include <map>
00014 #include <stdlib.h>
00015 #include <string.h>
00016 
00017 #include "TVirtualViewer3D.h"
00018 #include "TVirtualX.h"
00019 #include "TGLViewer.h"
00020 #include "TGLManip.h"
00021 #include "TX11GL.h"
00022 #include "TError.h"
00023 #include "TROOT.h"
00024 
00025 //////////////////////////////////////////////////////////////////////////
00026 //                                                                      //
00027 // TX11GLManager                                                        //
00028 //                                                                      //
00029 // The TX11GLManager is X11 implementation of TGLManager.               //
00030 //                                                                      //
00031 //////////////////////////////////////////////////////////////////////////
00032 
00033 struct TX11GLManager::TGLContext_t {
00034    //these are numbers returned by gVirtualX->AddWindow and gVirtualX->AddPixmap
00035    TGLContext_t() : fWindowIndex(-1), fPixmapIndex(-1), fX11Pixmap(0), fW(0),
00036                   fH(0), fX(0), fY(0), fGLXContext(0), fDirect(kFALSE),
00037                   fXImage(0), fNextFreeContext(0), fDirectGC(0), fPixmapGC(0)
00038    {
00039    }//FIXME
00040    Int_t                fWindowIndex;
00041    Int_t                fPixmapIndex;
00042    //X11 pixmap
00043    Pixmap               fX11Pixmap;
00044    //
00045    UInt_t               fW;
00046    UInt_t               fH;
00047    //
00048    Int_t                fX;
00049    Int_t                fY;
00050    //
00051    GLXContext           fGLXContext;
00052    Bool_t               fDirect;
00053    //GL buffer is read into XImage
00054    XImage              *fXImage;
00055    std::vector<UChar_t> fBUBuffer;//gl buffer is read from bottom to top.
00056    //
00057    TGLContext_t        *fNextFreeContext;
00058    GC                   fDirectGC;
00059    GC                   fPixmapGC;
00060 };
00061 
00062 namespace {
00063 
00064    typedef std::deque<TX11GLManager::TGLContext_t> DeviceTable_t;
00065    typedef DeviceTable_t::size_type SizeType_t;
00066    typedef std::map<Int_t, XVisualInfo *> WinTable_t;
00067    XSetWindowAttributes dummyAttr;
00068 
00069    //RAII class for Pixmap
00070    class TX11PixGuard {
00071    private:
00072       Display *fDpy;
00073       Pixmap   fPix;
00074 
00075    public:
00076       TX11PixGuard(Display *dpy, Pixmap pix) : fDpy(dpy), fPix(pix) {}
00077       ~TX11PixGuard(){if (fPix) XFreePixmap(fDpy, fPix);}
00078       void Stop(){fPix = 0;}
00079 
00080    private:
00081       TX11PixGuard(const TX11PixGuard &);
00082       TX11PixGuard &operator = (const TX11PixGuard &);
00083    };
00084 
00085    //RAII class for GLXContext
00086    class TGLXCtxGuard {
00087    private:
00088       Display    *fDpy;
00089       GLXContext  fCtx;
00090 
00091    public:
00092       TGLXCtxGuard(Display *dpy, GLXContext ctx) : fDpy(dpy), fCtx(ctx) {}
00093       ~TGLXCtxGuard(){if (fCtx) glXDestroyContext(fDpy, fCtx);}
00094       void Stop(){fCtx = 0;}
00095 
00096    private:
00097       TGLXCtxGuard(const TGLXCtxGuard &);
00098       TGLXCtxGuard &operator = (const TGLXCtxGuard &);
00099    };
00100 
00101    // RAII class for XImage.
00102    class TXImageGuard {
00103    private:
00104       XImage *fImage;
00105 
00106       TXImageGuard(const TXImageGuard &);
00107       TXImageGuard &operator = (const TXImageGuard &);
00108 
00109    public:
00110       explicit TXImageGuard(XImage *im) : fImage(im) {}
00111       ~TXImageGuard(){if (fImage) XDestroyImage(fImage);}
00112       void Stop(){fImage = 0;}
00113    };
00114 
00115 }
00116 
00117 // Attriblist for glXChooseVisual (double-buffered visual).
00118 const Int_t dblBuff[] =
00119    {
00120       GLX_DOUBLEBUFFER,
00121       GLX_RGBA,
00122       GLX_DEPTH_SIZE, 16,
00123       GLX_RED_SIZE, 1,
00124       GLX_GREEN_SIZE, 1,
00125       GLX_BLUE_SIZE, 1,
00126       None
00127    };
00128 
00129 // Attriblist for glxChooseVisual (single-buffered visual).
00130 const Int_t *snglBuff = dblBuff + 1;
00131 
00132 class TX11GLManager::TX11GLImpl {
00133 public:
00134    TX11GLImpl();
00135    ~TX11GLImpl();
00136 
00137    WinTable_t      fGLWindows;
00138    DeviceTable_t   fGLContexts;
00139    Display        *fDpy;
00140    TGLContext_t     *fNextFreeContext;
00141 
00142 private:
00143    TX11GLImpl(const TX11GLImpl &);
00144    TX11GLImpl &operator = (const TX11GLImpl &);
00145 };
00146 
00147 
00148 ClassImp(TX11GLManager)
00149 
00150 
00151 //______________________________________________________________________________
00152 TX11GLManager::TX11GLImpl::TX11GLImpl() : fDpy(0), fNextFreeContext(0)
00153 {
00154    // Constructor.
00155 
00156    fDpy = reinterpret_cast<Display *>(gVirtualX->GetDisplay());
00157 }
00158 
00159 
00160 //______________________________________________________________________________
00161 TX11GLManager::TX11GLImpl::~TX11GLImpl()
00162 {
00163    // Destructor.
00164    // Destroys only GL contexts and XImages pixmaps and windows must be
00165    // closed through gVirtualX
00166 
00167    for (SizeType_t i = 0,  e = fGLContexts.size(); i < e; ++i) {
00168       TGLContext_t &ctx = fGLContexts[i];
00169 
00170       if (ctx.fGLXContext) {
00171          ::Warning("TX11GLManager::~TX11GLManager", "opengl device with index %ld was not destroyed", (Long_t)i);
00172          glXDestroyContext(fDpy, ctx.fGLXContext);
00173 
00174          if (ctx.fPixmapIndex != -1) {
00175             gVirtualX->SelectWindow(ctx.fPixmapIndex);
00176             gVirtualX->ClosePixmap();
00177             if (ctx.fXImage)
00178                XDestroyImage(ctx.fXImage);
00179          }
00180       }
00181    }
00182 }
00183 
00184 
00185 //______________________________________________________________________________
00186 TX11GLManager::TX11GLManager() : fPimpl(new TX11GLImpl)
00187 {
00188    // Constructor.
00189 
00190    gGLManager = this;
00191    gROOT->GetListOfSpecials()->Add(this);
00192 }
00193 
00194 
00195 //______________________________________________________________________________
00196 TX11GLManager::~TX11GLManager()
00197 {
00198    // Destructor.
00199 
00200    delete fPimpl;
00201 }
00202 
00203 
00204 //______________________________________________________________________________
00205 Int_t TX11GLManager::InitGLWindow(Window_t winID)
00206 {
00207    // Try to find correct visual.
00208 
00209    XVisualInfo *visInfo = glXChooseVisual(
00210                                           fPimpl->fDpy, DefaultScreen(fPimpl->fDpy),
00211                                           const_cast<Int_t *>(dblBuff)
00212                                          );
00213 
00214    if (!visInfo) {
00215       Error("InitGLWindow", "No good visual found!\n");
00216       return -1;
00217    }
00218 
00219    Int_t  x = 0, y = 0;
00220    UInt_t w = 0, h = 0, b = 0, d = 0;
00221    Window root = 0;
00222    XGetGeometry(fPimpl->fDpy, winID, &root, &x, &y, &w, &h, &b, &d);
00223 
00224    XSetWindowAttributes attr(dummyAttr);
00225    attr.colormap = XCreateColormap(fPimpl->fDpy, root, visInfo->visual, AllocNone); // ???
00226    attr.event_mask = NoEventMask;
00227    attr.backing_store = Always;
00228    attr.bit_gravity = NorthWestGravity;
00229 
00230    ULong_t mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWBackingStore | CWBitGravity;
00231 
00232    // Create window with specific visual.
00233    Window glWin = XCreateWindow(
00234                                 fPimpl->fDpy, winID,
00235                                 x, y, w, h,
00236                                 0, visInfo->depth, InputOutput,
00237                                 visInfo->visual, mask, &attr
00238                                );
00239 
00240    // Check results.
00241    XMapWindow(fPimpl->fDpy, glWin);
00242 
00243    // Register window for gVirtualX.
00244    Int_t x11Ind = gVirtualX->AddWindow(glWin,  w, h);
00245 
00246    // Register this window for GL manager.
00247    fPimpl->fGLWindows[x11Ind] = visInfo;
00248 
00249    return x11Ind;
00250 }
00251 
00252 
00253 //______________________________________________________________________________
00254 Int_t TX11GLManager::CreateGLContext(Int_t winInd)
00255 {
00256    // Context creation requires Display * and XVisualInfo
00257    // (was saved for such winInd).
00258    GLXContext glxCtx = glXCreateContext(fPimpl->fDpy, fPimpl->fGLWindows[winInd], None, True);
00259 
00260    if (!glxCtx) {
00261       Error("CreateContext", "glXCreateContext failed\n");
00262       return -1;
00263    }
00264 
00265    // Register new context now.
00266    if (TGLContext_t *ctx = fPimpl->fNextFreeContext) {
00267       Int_t ind = ctx->fWindowIndex;
00268       ctx->fWindowIndex = winInd;
00269       ctx->fGLXContext = glxCtx;
00270       fPimpl->fNextFreeContext = fPimpl->fNextFreeContext->fNextFreeContext;
00271       return ind;
00272    } else {
00273       TGLXCtxGuard glxCtxGuard(fPimpl->fDpy, glxCtx);
00274       TGLContext_t newDev;
00275       newDev.fWindowIndex = winInd;
00276       newDev.fGLXContext = glxCtx;
00277 
00278       fPimpl->fGLContexts.push_back(newDev);
00279       glxCtxGuard.Stop();
00280 
00281       return Int_t(fPimpl->fGLContexts.size()) - 1;
00282    }
00283 }
00284 
00285 
00286 //______________________________________________________________________________
00287 Bool_t TX11GLManager::MakeCurrent(Int_t ctxInd)
00288 {
00289    // Make GL context current.
00290    TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
00291    return glXMakeCurrent(fPimpl->fDpy, gVirtualX->GetWindowID(ctx.fWindowIndex), ctx.fGLXContext);
00292 }
00293 
00294 
00295 //______________________________________________________________________________
00296 void TX11GLManager::Flush(Int_t ctxInd)
00297 {
00298    // Swaps buffers or copy pixmap.
00299 
00300    TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
00301    Window winID = gVirtualX->GetWindowID(ctx.fWindowIndex);
00302 
00303    if (ctx.fPixmapIndex == -1)
00304       glXSwapBuffers(fPimpl->fDpy, winID);
00305    else if (ctx.fXImage && ctx.fDirect) {
00306       if (!ctx.fDirectGC)
00307          ctx.fDirectGC = XCreateGC(fPimpl->fDpy, winID, 0, 0);
00308 
00309       if (!ctx.fDirectGC) {
00310          Error("Flush", "XCreateGC failed while copying pixmap\n");
00311          ctx.fDirect = kFALSE;
00312          return;
00313       }
00314 
00315       XCopyArea(fPimpl->fDpy, ctx.fX11Pixmap, winID, ctx.fDirectGC, 0, 0, ctx.fW, ctx.fH, ctx.fX, ctx.fY);
00316    }
00317 }
00318 
00319 
00320 //______________________________________________________________________________
00321 Bool_t TX11GLManager::CreateGLPixmap(TGLContext_t &ctx)
00322 {
00323    // Create GL pixmap.
00324 
00325    // Create new x11 pixmap and XImage.
00326    Pixmap x11Pix = XCreatePixmap(fPimpl->fDpy, gVirtualX->GetWindowID(ctx.fWindowIndex), ctx.fW,
00327                                  ctx.fH, fPimpl->fGLWindows[ctx.fWindowIndex]->depth);
00328 
00329    if (!x11Pix) {
00330       Error("CreateGLPixmap", "XCreatePixmap failed\n");
00331       return kFALSE;
00332    }
00333 
00334    TX11PixGuard pixGuard(fPimpl->fDpy, x11Pix);
00335 
00336    // XImage part here.
00337    XVisualInfo *visInfo = fPimpl->fGLWindows[ctx.fWindowIndex];
00338    XImage *testIm = XCreateImage(fPimpl->fDpy, visInfo->visual, visInfo->depth, ZPixmap, 0, 0, ctx.fW, ctx.fH, 32, 0);
00339 
00340    if (testIm) {
00341       TXImageGuard imGuard(testIm);
00342       testIm->data = static_cast<Char_t *>(malloc(testIm->bytes_per_line * testIm->height));
00343 
00344       if (!testIm->data) {
00345          Error("CreateGLPixmap", "Cannot malloc XImage data\n");
00346          return kFALSE;
00347       }
00348 
00349       if (XInitImage(testIm)) {
00350          ctx.fPixmapIndex = gVirtualX->AddPixmap(x11Pix, ctx.fW, ctx.fH);
00351          ctx.fBUBuffer.resize(testIm->bytes_per_line * testIm->height);
00352          ctx.fX11Pixmap = x11Pix;
00353          ctx.fXImage = testIm;
00354          pixGuard.Stop();
00355          imGuard.Stop();
00356          return kTRUE;
00357       } else
00358          Error("CreateGLPixmap", "XInitImage error!\n");
00359    } else
00360       Error("CreateGLPixmap", "XCreateImage error!\n");
00361 
00362    return kFALSE;
00363 }
00364 
00365 
00366 //______________________________________________________________________________
00367 Bool_t TX11GLManager::AttachOffScreenDevice(Int_t ctxInd, Int_t x, Int_t y, UInt_t w, UInt_t h)
00368 {
00369    // Attach off screen device.
00370 
00371    // Create pixmap and XImage for GL context ctxInd.
00372    TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
00373    TGLContext_t newCtx;
00374    newCtx.fWindowIndex = ctx.fWindowIndex;
00375    newCtx.fW = w, newCtx.fH = h, newCtx.fX = x, newCtx.fY = y;
00376    newCtx.fGLXContext = ctx.fGLXContext;
00377 
00378    if (CreateGLPixmap(newCtx)) {
00379       ctx.fPixmapIndex = newCtx.fPixmapIndex;
00380       ctx.fX11Pixmap = newCtx.fX11Pixmap;
00381       ctx.fW = w, ctx.fH = h, ctx.fX = x, ctx.fY = y;
00382       ctx.fDirect = kFALSE;
00383       ctx.fXImage = newCtx.fXImage;
00384       ctx.fBUBuffer.swap(newCtx.fBUBuffer);
00385       return kTRUE;
00386    }
00387 
00388    return kFALSE;
00389 }
00390 
00391 
00392 //______________________________________________________________________________
00393 Bool_t TX11GLManager::ResizeOffScreenDevice(Int_t ctxInd, Int_t x, Int_t y, UInt_t w, UInt_t h)
00394 {
00395    // Resize off screen devive.
00396 
00397    // Create a new pixmap and a new XImage if needed.
00398    TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
00399 
00400    if (ctx.fPixmapIndex != -1) {
00401       if (TMath::Abs(Int_t(w) - Int_t(ctx.fW)) > 1 || TMath::Abs(Int_t(h) - Int_t(ctx.fH)) > 1) {
00402          TGLContext_t newCtx;
00403          newCtx.fWindowIndex = ctx.fWindowIndex;
00404          newCtx.fW = w, newCtx.fH = h, newCtx.fX = x, newCtx.fY = y;
00405          newCtx.fGLXContext = ctx.fGLXContext;
00406 
00407          if (CreateGLPixmap(newCtx)) {
00408             gVirtualX->SelectWindow(ctx.fPixmapIndex);
00409             gVirtualX->ClosePixmap();
00410             ctx.fPixmapIndex = newCtx.fPixmapIndex;
00411             ctx.fX11Pixmap = newCtx.fX11Pixmap;
00412             ctx.fW = w, ctx.fH = h, ctx.fX = x, ctx.fY = y;
00413             ctx.fDirect = kFALSE;
00414             if (ctx.fXImage) XDestroyImage(ctx.fXImage);
00415             ctx.fXImage = newCtx.fXImage;
00416             ctx.fBUBuffer.swap(newCtx.fBUBuffer);
00417             return kTRUE;
00418          } else
00419             Error("ResizeOffScreenDevice", "Resize failed\n");
00420       } else {
00421          ctx.fX = x;
00422          ctx.fY = y;
00423       }
00424    }
00425 
00426    return kFALSE;
00427 }
00428 
00429 
00430 //______________________________________________________________________________
00431 void TX11GLManager::SelectOffScreenDevice(Int_t ctxInd)
00432 {
00433    // Selects off-screen device to make it accessible by gVirtualX.
00434 
00435    gVirtualX->SelectWindow(fPimpl->fGLContexts[ctxInd].fPixmapIndex);
00436 }
00437 
00438 
00439 //______________________________________________________________________________
00440 void TX11GLManager::MarkForDirectCopy(Int_t ctxInd, Bool_t dir)
00441 {
00442    // Selection-rotation support for TPad/TCanvas.
00443 
00444    if (fPimpl->fGLContexts[ctxInd].fPixmapIndex != -1)
00445       fPimpl->fGLContexts[ctxInd].fDirect = dir;
00446 }
00447 
00448 
00449 //______________________________________________________________________________
00450 void TX11GLManager::ReadGLBuffer(Int_t ctxInd)
00451 {
00452    // GL buffer is read info buffer, after that lines are reordered
00453    // into XImage, XImage copied into pixmap.
00454 
00455    TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
00456 
00457    if (ctx.fPixmapIndex != -1 && ctx.fXImage) {
00458       // Read GL buffer.
00459       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00460       glReadBuffer(GL_BACK);
00461       glReadPixels(0, 0, ctx.fW, ctx.fH, GL_BGRA, GL_UNSIGNED_BYTE, &ctx.fBUBuffer[0]);
00462 
00463       if (!ctx.fPixmapGC)
00464          ctx.fPixmapGC = XCreateGC(fPimpl->fDpy, ctx.fX11Pixmap, 0, 0);
00465       if (ctx.fPixmapGC) {
00466          // GL buffer read operation gives bottom-up order of pixels, but XImage
00467               // require top-down. So, change RGB lines first.
00468          char *dest = ctx.fXImage->data;
00469          const UChar_t *src = &ctx.fBUBuffer[ctx.fW * 4 * (ctx.fH - 1)];
00470          for (UInt_t i = 0, e = ctx.fH; i < e; ++i) {
00471             memcpy(dest, src, ctx.fW * 4);
00472             dest += ctx.fW * 4;
00473             src -= ctx.fW * 4;
00474          }
00475          XPutImage(fPimpl->fDpy, ctx.fX11Pixmap, ctx.fPixmapGC, ctx.fXImage, 0, 0, 0, 0, ctx.fW, ctx.fH);
00476       } else
00477          Error("ReadGLBuffer", "XCreateGC error while attempt to copy XImage\n");
00478    }
00479 }
00480 
00481 
00482 //______________________________________________________________________________
00483 void TX11GLManager::DeleteGLContext(Int_t ctxInd)
00484 {
00485    // Deletes GLX context and frees pixmap and image (if any).
00486 
00487    TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
00488 
00489    // Free GL context.
00490    glXDestroyContext(fPimpl->fDpy, ctx.fGLXContext);
00491    ctx.fGLXContext = 0;
00492 
00493    // If the pixmap exists it is destroyed.
00494    if (ctx.fPixmapIndex != -1) {
00495       gVirtualX->SelectWindow(ctx.fPixmapIndex);
00496       gVirtualX->ClosePixmap();
00497       ctx.fPixmapIndex = -1;
00498       if(ctx.fXImage) {
00499          XDestroyImage(ctx.fXImage);
00500          ctx.fXImage = 0;
00501       }
00502       if (ctx.fDirectGC)
00503          XFreeGC(fPimpl->fDpy, ctx.fDirectGC), ctx.fDirectGC = 0;
00504       if (ctx.fPixmapGC)
00505          XFreeGC(fPimpl->fDpy, ctx.fPixmapGC), ctx.fPixmapGC = 0;
00506    }
00507 
00508    ctx.fNextFreeContext = fPimpl->fNextFreeContext;
00509    fPimpl->fNextFreeContext = &ctx;
00510    ctx.fWindowIndex = ctxInd;
00511 }
00512 
00513 
00514 //______________________________________________________________________________
00515 Int_t TX11GLManager::GetVirtualXInd(Int_t ctxInd)
00516 {
00517    // Returns an index suitable for gVirtualX.
00518 
00519    return fPimpl->fGLContexts[ctxInd].fPixmapIndex;
00520 }
00521 
00522 
00523 //______________________________________________________________________________
00524 void TX11GLManager::ExtractViewport(Int_t ctxInd, Int_t *viewport)
00525 {
00526    // Returns the current dimensions of a GL pixmap.
00527 
00528    TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
00529 
00530    if (ctx.fPixmapIndex != -1) {
00531       viewport[0] = 0;
00532       viewport[1] = 0;
00533       viewport[2] = ctx.fW;
00534       viewport[3] = ctx.fH;
00535    }
00536 }
00537 
00538 
00539 //______________________________________________________________________________
00540 void TX11GLManager::PaintSingleObject(TVirtualGLPainter *p)
00541 {
00542    // Paint a single object.
00543 
00544    p->Paint();
00545 }
00546 
00547 
00548 //______________________________________________________________________________
00549 void TX11GLManager::PrintViewer(TVirtualViewer3D *vv)
00550 {
00551    // Print viewer.
00552 
00553    vv->PrintObjects();
00554 }
00555 
00556 //______________________________________________________________________________
00557 Bool_t TX11GLManager::SelectManip(TVirtualGLManip *manip, const TGLCamera * camera, const TGLRect * rect, const TGLBoundingBox * sceneBox)
00558 {
00559    // Select manipulator.
00560 
00561    return manip->Select(*camera, *rect, *sceneBox);
00562 }
00563 
00564 
00565 //______________________________________________________________________________
00566 void TX11GLManager::PanObject(TVirtualGLPainter *o, Int_t x, Int_t y)
00567 {
00568    // Pan objects.
00569 
00570    return o->Pan(x, y);
00571 }
00572 
00573 //______________________________________________________________________________
00574 Bool_t TX11GLManager::PlotSelected(TVirtualGLPainter *plot, Int_t px, Int_t py)
00575 {
00576    //Analog of TObject::DistancetoPrimitive
00577    return plot->PlotSelected(px, py);
00578 }
00579 
00580 //______________________________________________________________________________
00581 char *TX11GLManager::GetPlotInfo(TVirtualGLPainter *plot, Int_t px, Int_t py)
00582 {
00583    //Analog of TObject::GetObjectInfo
00584    return plot->GetPlotInfo(px, py);
00585 }

Generated on Tue Jul 5 14:18:10 2011 for ROOT_528-00b_version by  doxygen 1.5.1